freebsd-dev/sys/isofs/cd9660/cd9660_node.c

429 lines
11 KiB
C
Raw Normal View History

1994-05-24 10:09:53 +00:00
/*-
* Copyright (c) 1982, 1986, 1989, 1994, 1995
1994-05-24 10:09:53 +00:00
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley
* by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
* Support code is derived from software contributed to Berkeley
* by Atsushi Murai (amurai@spec.co.jp).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)cd9660_node.c 8.2 (Berkeley) 1/23/94
Divorce "dev_t" from the "major|minor" bitmap, which is now called udev_t in the kernel but still called dev_t in userland. Provide functions to manipulate both types: major() umajor() minor() uminor() makedev() umakedev() dev2udev() udev2dev() For now they're functions, they will become in-line functions after one of the next two steps in this process. Return major/minor/makedev to macro-hood for userland. Register a name in cdevsw[] for the "filedescriptor" driver. In the kernel the udev_t appears in places where we have the major/minor number combination, (ie: a potential device: we may not have the driver nor the device), like in inodes, vattr, cdevsw registration and so on, whereas the dev_t appears where we carry around a reference to a actual device. In the future the cdevsw and the aliased-from vnode will be hung directly from the dev_t, along with up to two softc pointers for the device driver and a few houskeeping bits. This will essentially replace the current "alias" check code (same buck, bigger bang). A little stunt has been provided to try to catch places where the wrong type is being used (dev_t vs udev_t), if you see something not working, #undef DEVT_FASCIST in kern/kern_conf.c and see if it makes a difference. If it does, please try to track it down (many hands make light work) or at least try to reproduce it as simply as possible, and describe how to do that. Without DEVT_FASCIST I belive this patch is a no-op. Stylistic/posixoid comments about the userland view of the <sys/*.h> files welcome now, from userland they now contain the end result. Next planned step: make all dev_t's refer to the same devsw[] which means convert BLK's to CHR's at the perimeter of the vnodes and other places where they enter the game (bootdev, mknod, sysctl).
1999-05-11 19:55:07 +00:00
* $Id: cd9660_node.c,v 1.27 1999/01/27 21:49:54 dillon Exp $
1994-05-24 10:09:53 +00:00
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/stat.h>
#include <isofs/cd9660/iso.h>
#include <isofs/cd9660/cd9660_node.h>
#include <isofs/cd9660/cd9660_mount.h>
1994-05-24 10:09:53 +00:00
/*
* Structures associated with iso_node caching.
*/
1998-02-09 06:11:36 +00:00
static struct iso_node **isohashtbl;
static u_long isohash;
Divorce "dev_t" from the "major|minor" bitmap, which is now called udev_t in the kernel but still called dev_t in userland. Provide functions to manipulate both types: major() umajor() minor() uminor() makedev() umakedev() dev2udev() udev2dev() For now they're functions, they will become in-line functions after one of the next two steps in this process. Return major/minor/makedev to macro-hood for userland. Register a name in cdevsw[] for the "filedescriptor" driver. In the kernel the udev_t appears in places where we have the major/minor number combination, (ie: a potential device: we may not have the driver nor the device), like in inodes, vattr, cdevsw registration and so on, whereas the dev_t appears where we carry around a reference to a actual device. In the future the cdevsw and the aliased-from vnode will be hung directly from the dev_t, along with up to two softc pointers for the device driver and a few houskeeping bits. This will essentially replace the current "alias" check code (same buck, bigger bang). A little stunt has been provided to try to catch places where the wrong type is being used (dev_t vs udev_t), if you see something not working, #undef DEVT_FASCIST in kern/kern_conf.c and see if it makes a difference. If it does, please try to track it down (many hands make light work) or at least try to reproduce it as simply as possible, and describe how to do that. Without DEVT_FASCIST I belive this patch is a no-op. Stylistic/posixoid comments about the userland view of the <sys/*.h> files welcome now, from userland they now contain the end result. Next planned step: make all dev_t's refer to the same devsw[] which means convert BLK's to CHR's at the perimeter of the vnodes and other places where they enter the game (bootdev, mknod, sysctl).
1999-05-11 19:55:07 +00:00
#define INOHASH(device, inum) ((minor(device) + ((inum)>>12)) & isohash)
#ifndef NULL_SIMPLELOCKS
1998-02-09 06:11:36 +00:00
static struct simplelock cd9660_ihash_slock;
#endif
1997-11-18 14:40:36 +00:00
static void cd9660_ihashrem __P((struct iso_node *));
static unsigned cd9660_chars2ui __P((unsigned char *begin, int len));
1994-05-24 10:09:53 +00:00
/*
* Initialize hash links for inodes and dnodes.
*/
int
cd9660_init(vfsp)
struct vfsconf *vfsp;
1994-05-24 10:09:53 +00:00
{
isohashtbl = hashinit(desiredvnodes, M_ISOFSMNT, &isohash);
simple_lock_init(&cd9660_ihash_slock);
return (0);
1994-05-24 10:09:53 +00:00
}
/*
* Use the device/inum pair to find the incore inode, and return a pointer
* to it. If it is in core, but locked, wait for it.
1994-05-24 10:09:53 +00:00
*/
struct vnode *
cd9660_ihashget(dev, inum)
dev_t dev;
ino_t inum;
1994-05-24 10:09:53 +00:00
{
struct proc *p = curproc; /* XXX */
struct iso_node *ip;
struct vnode *vp;
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
loop:
simple_lock(&cd9660_ihash_slock);
for (ip = isohashtbl[INOHASH(dev, inum)]; ip; ip = ip->i_next) {
if (inum == ip->i_number && dev == ip->i_dev) {
vp = ITOV(ip);
simple_lock(&vp->v_interlock);
simple_unlock(&cd9660_ihash_slock);
if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p))
goto loop;
return (vp);
1994-05-24 10:09:53 +00:00
}
}
simple_unlock(&cd9660_ihash_slock);
return (NULL);
}
1995-05-30 08:16:23 +00:00
/*
* Insert the inode into the hash table, and return it locked.
*/
void
cd9660_ihashins(ip)
struct iso_node *ip;
{
struct proc *p = curproc; /* XXX */
struct iso_node **ipp, *iq;
simple_lock(&cd9660_ihash_slock);
ipp = &isohashtbl[INOHASH(ip->i_dev, ip->i_number)];
if ((iq = *ipp) != NULL)
iq->i_prev = &ip->i_next;
ip->i_next = iq;
ip->i_prev = ipp;
1994-05-24 10:09:53 +00:00
*ipp = ip;
simple_unlock(&cd9660_ihash_slock);
lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct simplelock *)0, p);
1994-05-24 10:09:53 +00:00
}
/*
* Remove the inode from the hash table.
1994-05-24 10:09:53 +00:00
*/
1997-11-18 14:40:36 +00:00
static void
cd9660_ihashrem(ip)
1994-05-24 10:09:53 +00:00
register struct iso_node *ip;
{
register struct iso_node *iq;
simple_lock(&cd9660_ihash_slock);
if ((iq = ip->i_next) != NULL)
iq->i_prev = ip->i_prev;
*ip->i_prev = iq;
#ifdef DIAGNOSTIC
ip->i_next = NULL;
ip->i_prev = NULL;
#endif
simple_unlock(&cd9660_ihash_slock);
1994-05-24 10:09:53 +00:00
}
/*
* Last reference to an inode, write the inode out and if necessary,
* truncate and deallocate the file.
*/
int
cd9660_inactive(ap)
struct vop_inactive_args /* {
struct vnode *a_vp;
struct proc *a_p;
1994-05-24 10:09:53 +00:00
} */ *ap;
{
struct vnode *vp = ap->a_vp;
struct proc *p = ap->a_p;
1994-05-24 10:09:53 +00:00
register struct iso_node *ip = VTOI(vp);
int error = 0;
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
if (prtactive && vp->v_usecount != 0)
vprint("cd9660_inactive: pushing active", vp);
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
ip->i_flag = 0;
VOP_UNLOCK(vp, 0, p);
1994-05-24 10:09:53 +00:00
/*
* If we are done with the inode, reclaim it
* so that it can be reused immediately.
*/
if (ip->inode.iso_mode == 0)
vrecycle(vp, (struct simplelock *)0, p);
1994-05-24 10:09:53 +00:00
return error;
}
/*
* Reclaim an inode so that it can be used for other purposes.
*/
int
cd9660_reclaim(ap)
struct vop_reclaim_args /* {
struct vnode *a_vp;
struct proc *a_p;
1994-05-24 10:09:53 +00:00
} */ *ap;
{
register struct vnode *vp = ap->a_vp;
register struct iso_node *ip = VTOI(vp);
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
if (prtactive && vp->v_usecount != 0)
vprint("cd9660_reclaim: pushing active", vp);
/*
* Remove the inode from its hash chain.
*/
cd9660_ihashrem(ip);
1994-05-24 10:09:53 +00:00
/*
* Purge old data structures associated with the inode.
*/
cache_purge(vp);
if (ip->i_devvp) {
vrele(ip->i_devvp);
ip->i_devvp = 0;
}
FREE(vp->v_data, M_ISOFSNODE);
vp->v_data = NULL;
return (0);
1994-05-24 10:09:53 +00:00
}
/*
* File attributes
*/
void
cd9660_defattr(isodir, inop, bp, ftype)
1994-05-24 10:09:53 +00:00
struct iso_directory_record *isodir;
struct iso_node *inop;
struct buf *bp;
enum ISO_FTYPE ftype;
1994-05-24 10:09:53 +00:00
{
struct buf *bp2 = NULL;
struct iso_mnt *imp;
struct iso_extended_attributes *ap = NULL;
int off;
1995-05-30 08:16:23 +00:00
/* high sierra does not have timezone data, flag is one byte ahead */
if (isonum_711(ftype == ISO_FTYPE_HIGH_SIERRA?
&isodir->date[6]: isodir->flags)&2) {
1994-05-24 10:09:53 +00:00
inop->inode.iso_mode = S_IFDIR;
/*
* If we return 2, fts() will assume there are no subdirectories
* (just links for the path and .), so instead we return 1.
*/
inop->inode.iso_links = 1;
} else {
inop->inode.iso_mode = S_IFREG;
inop->inode.iso_links = 1;
}
if (!bp
&& ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT)
1994-05-24 10:09:53 +00:00
&& (off = isonum_711(isodir->ext_attr_length))) {
cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL,
&bp2);
1994-05-24 10:09:53 +00:00
bp = bp2;
}
if (bp) {
ap = (struct iso_extended_attributes *)bp->b_data;
1994-05-24 10:09:53 +00:00
if (isonum_711(ap->version) == 1) {
if (!(ap->perm[0]&0x40))
inop->inode.iso_mode |= VEXEC >> 6;
if (!(ap->perm[0]&0x10))
inop->inode.iso_mode |= VREAD >> 6;
if (!(ap->perm[0]&4))
inop->inode.iso_mode |= VEXEC >> 3;
if (!(ap->perm[0]&1))
inop->inode.iso_mode |= VREAD >> 3;
if (!(ap->perm[1]&0x40))
inop->inode.iso_mode |= VEXEC;
if (!(ap->perm[1]&0x10))
inop->inode.iso_mode |= VREAD;
inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */
inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */
} else
ap = NULL;
}
if (!ap) {
inop->inode.iso_mode |= VREAD|VEXEC|(VREAD|VEXEC)>>3|(VREAD|VEXEC)>>6;
inop->inode.iso_uid = (uid_t)0;
inop->inode.iso_gid = (gid_t)0;
}
if (bp2)
brelse(bp2);
}
/*
* Time stamps
*/
void
cd9660_deftstamp(isodir,inop,bp,ftype)
1994-05-24 10:09:53 +00:00
struct iso_directory_record *isodir;
struct iso_node *inop;
struct buf *bp;
enum ISO_FTYPE ftype;
1994-05-24 10:09:53 +00:00
{
struct buf *bp2 = NULL;
struct iso_mnt *imp;
struct iso_extended_attributes *ap = NULL;
int off;
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
if (!bp
&& ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT)
1994-05-24 10:09:53 +00:00
&& (off = isonum_711(isodir->ext_attr_length))) {
cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL,
&bp2);
1994-05-24 10:09:53 +00:00
bp = bp2;
}
if (bp) {
ap = (struct iso_extended_attributes *)bp->b_data;
if (ftype != ISO_FTYPE_HIGH_SIERRA
&& isonum_711(ap->version) == 1) {
1994-05-24 10:09:53 +00:00
if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime))
cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime);
if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime))
inop->inode.iso_ctime = inop->inode.iso_atime;
if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime))
inop->inode.iso_mtime = inop->inode.iso_ctime;
} else
ap = NULL;
}
if (!ap) {
cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime,ftype);
1994-05-24 10:09:53 +00:00
inop->inode.iso_atime = inop->inode.iso_ctime;
inop->inode.iso_mtime = inop->inode.iso_ctime;
}
if (bp2)
brelse(bp2);
}
int
cd9660_tstamp_conv7(pi,pu,ftype)
u_char *pi;
struct timespec *pu;
enum ISO_FTYPE ftype;
1994-05-24 10:09:53 +00:00
{
int crtime, days;
int y, m, d, hour, minute, second, tz;
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
y = pi[0] + 1900;
m = pi[1];
d = pi[2];
hour = pi[3];
minute = pi[4];
second = pi[5];
if(ftype != ISO_FTYPE_HIGH_SIERRA)
tz = pi[6];
else
/* original high sierra misses timezone data */
tz = 0;
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
if (y < 1970) {
pu->tv_sec = 0;
pu->tv_nsec = 0;
1994-05-24 10:09:53 +00:00
return 0;
} else {
#ifdef ORIGINAL
/* computes day number relative to Sept. 19th,1989 */
/* don't even *THINK* about changing formula. It works! */
days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100;
#else
/*
* Changed :-) to make it relative to Jan. 1st, 1970
* and to disambiguate negative division
*/
days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239;
#endif
crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second;
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
/* timezone offset is unreliable on some disks */
if (-48 <= tz && tz <= 52)
crtime -= tz * 15 * 60;
1994-05-24 10:09:53 +00:00
}
pu->tv_sec = crtime;
pu->tv_nsec = 0;
1994-05-24 10:09:53 +00:00
return 1;
}
static u_int
1994-05-24 10:09:53 +00:00
cd9660_chars2ui(begin,len)
u_char *begin;
1994-05-24 10:09:53 +00:00
int len;
{
u_int rc;
1994-05-24 10:09:53 +00:00
for (rc = 0; --len >= 0;) {
rc *= 10;
rc += *begin++ - '0';
}
return rc;
}
int
cd9660_tstamp_conv17(pi,pu)
u_char *pi;
struct timespec *pu;
1994-05-24 10:09:53 +00:00
{
u_char buf[7];
/* year:"0001"-"9999" -> -1900 */
1994-05-24 10:09:53 +00:00
buf[0] = cd9660_chars2ui(pi,4) - 1900;
1995-05-30 08:16:23 +00:00
/* month: " 1"-"12" -> 1 - 12 */
1994-05-24 10:09:53 +00:00
buf[1] = cd9660_chars2ui(pi + 4,2);
1995-05-30 08:16:23 +00:00
/* day: " 1"-"31" -> 1 - 31 */
1994-05-24 10:09:53 +00:00
buf[2] = cd9660_chars2ui(pi + 6,2);
1995-05-30 08:16:23 +00:00
/* hour: " 0"-"23" -> 0 - 23 */
1994-05-24 10:09:53 +00:00
buf[3] = cd9660_chars2ui(pi + 8,2);
1995-05-30 08:16:23 +00:00
/* minute:" 0"-"59" -> 0 - 59 */
1994-05-24 10:09:53 +00:00
buf[4] = cd9660_chars2ui(pi + 10,2);
1995-05-30 08:16:23 +00:00
/* second:" 0"-"59" -> 0 - 59 */
1994-05-24 10:09:53 +00:00
buf[5] = cd9660_chars2ui(pi + 12,2);
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
/* difference of GMT */
buf[6] = pi[16];
1995-05-30 08:16:23 +00:00
return cd9660_tstamp_conv7(buf, pu, ISO_FTYPE_DEFAULT);
1994-05-24 10:09:53 +00:00
}
ino_t
isodirino(isodir, imp)
1994-05-24 10:09:53 +00:00
struct iso_directory_record *isodir;
struct iso_mnt *imp;
{
ino_t ino;
ino = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length))
<< imp->im_bshift;
return (ino);
1994-05-24 10:09:53 +00:00
}