]>
git.saurik.com Git - apple/xnu.git/blob - bsd/isofs/cd9660/cd9660_node.c
   2  * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  28 /*      $NetBSD: cd9660_node.c,v 1.13 1994/12/24 15:30:07 cgd Exp $     */ 
  31  * Copyright (c) 1982, 1986, 1989, 1994 
  32  *      The Regents of the University of California.  All rights reserved. 
  34  * This code is derived from software contributed to Berkeley 
  35  * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension 
  36  * Support code is derived from software contributed to Berkeley 
  37  * by Atsushi Murai (amurai@spec.co.jp). 
  39  * Redistribution and use in source and binary forms, with or without 
  40  * modification, are permitted provided that the following conditions 
  42  * 1. Redistributions of source code must retain the above copyright 
  43  *    notice, this list of conditions and the following disclaimer. 
  44  * 2. Redistributions in binary form must reproduce the above copyright 
  45  *    notice, this list of conditions and the following disclaimer in the 
  46  *    documentation and/or other materials provided with the distribution. 
  47  * 3. All advertising materials mentioning features or use of this software 
  48  *    must display the following acknowledgement: 
  49  *      This product includes software developed by the University of 
  50  *      California, Berkeley and its contributors. 
  51  * 4. Neither the name of the University nor the names of its contributors 
  52  *    may be used to endorse or promote products derived from this software 
  53  *    without specific prior written permission. 
  55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 
  56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 
  59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  67  *      @(#)cd9660_node.c       8.5 (Berkeley) 12/5/94 
  72  * 22-Jan-98    radar 1669467 - ISO 9660 CD support - jwc 
  73  * 17-Feb-98    radar 1669467 - changed lock protocols to use the lock manager - chw 
  77 #include <sys/param.h> 
  78 #include <sys/systm.h> 
  79 #include <sys/mount.h> 
  83 #include <sys/vnode.h> 
  84 #include <sys/kernel.h> 
  85 #include <sys/malloc.h> 
  88 #include <sys/namei.h> 
  90 #include <isofs/cd9660/iso.h> 
  91 #include <isofs/cd9660/cd9660_node.h> 
  92 #include <isofs/cd9660/iso_rrip.h> 
  93 #include <isofs/cd9660/cd9660_mount.h> 
  96  * Structures associated with iso_node caching. 
  98 struct iso_node 
**isohashtbl
; 
 100 #define INOHASH(device, inum)   (((device) + ((inum)>>12)) & isohash) 
 103 struct iso_node 
**idvhashtbl
; 
 105 #define DNOHASH(device, inum)   (((device) + ((inum)>>12)) & idvhash) 
 108 /* defined in bsd/vfs/vfs_subr.c */ 
 109 extern int prtactive
;   /* 1 => print out reclaim of active vnodes */ 
 111 extern u_char isonullname
[]; 
 113  * Initialize hash links for inodes and dnodes. 
 116 cd9660_init(__unused 
struct vfsconf 
*cp
) 
 122 cd9660_hashinit(void) 
 125                 isohashtbl 
= hashinit(desiredvnodes
, M_ISOFSMNT
, &isohash
); 
 128                 idvhashtbl 
= hashinit(desiredvnodes 
/ 8, M_ISOFSMNT
, &idvhash
); 
 135  * Enter a new node into the device hash list 
 138 iso_dmap(dev_t device
, ino_t inum
, int create
) 
 140         register struct iso_dnode 
**dpp
, *dp
, *dq
; 
 142         dpp 
= &idvhashtbl
[DNOHASH(device
, inum
)]; 
 143         for (dp 
= *dpp
;; dp 
= dp
->d_next
) { 
 146                 if (inum 
== dp
->i_number 
&& device 
== dp
->i_dev
) 
 152         MALLOC(dp
, struct iso_dnode 
*, sizeof(struct iso_dnode
), M_CACHE
, 
 158                 dq
->d_prev 
= dp
->d_next
; 
 167 iso_dunmap(dev_t device
) 
 169         struct iso_dnode 
**dpp
, *dp
, *dq
; 
 171         for (dpp 
= idvhashtbl
; dpp 
<= idvhashtbl 
+ idvhash
; dpp
++) { 
 172                 for (dp 
= *dpp
; dp 
!= NULL
; dp 
= dq
) 
 174                         if (device 
== dp
->i_dev
) { 
 176                                         dq
->d_prev 
= dp
->d_prev
; 
 186  * Use the device/inum pair to find the incore inode, and return a pointer 
 187  * to it. If it is in core, but locked, wait for it. 
 190 cd9660_ihashget(dev_t device
, ino_t inum
, __unused 
struct proc 
*p
) 
 192         register struct iso_node 
*ip
; 
 197         for (ip 
= isohashtbl
[INOHASH(device
, inum
)]; ip
; ip 
= ip
->i_next
) { 
 198                 if (inum 
== ip
->i_number 
&& device 
== ip
->i_dev
) { 
 200                         if (ISSET(ip
->i_flag
, ISO_INALLOC
)) { 
 202                                  * inode is being created... wait for it 
 203                                  * to be ready for consumption 
 205                                 SET(ip
->i_flag
, ISO_INWALLOC
); 
 206                                 tsleep((caddr_t
)ip
, PINOD
, "cd9960_ihashget", 0); 
 211                          * the vid needs to be grabbed before we drop 
 212                          * lock protecting the hash 
 217                          * we currently depend on running under the FS funnel 
 218                          * when we do proper locking and advertise ourselves 
 219                          * as thread safe, we'll need a lock to protect the 
 220                          * hash lookup... this is where we would drop it 
 222                         if (vnode_getwithvid(vp
, vid
)) { 
 224                                  * If vnode is being reclaimed, or has 
 225                                  * already changed identity, no need to wait 
 236  * Insert the inode into the hash table, and return it locked. 
 239 cd9660_ihashins(struct iso_node 
*ip
) 
 241         struct iso_node 
**ipp
, *iq
; 
 243         /* lock the inode, then put it on the appropriate hash list */ 
 245         ipp 
= &isohashtbl
[INOHASH(ip
->i_dev
, ip
->i_number
)]; 
 247                 iq
->i_prev 
= &ip
->i_next
; 
 254  * Remove the inode from the hash table. 
 257 cd9660_ihashrem(register struct iso_node 
*ip
) 
 259         register struct iso_node 
*iq
; 
 261         if ((iq 
= ip
->i_next
)) 
 262                 iq
->i_prev 
= ip
->i_prev
; 
 264 #if 1 /* was ifdef DIAGNOSTIC */ 
 271  * Last reference to an inode... if we're done with 
 272  * it, go ahead and recycle it for other use 
 275 cd9660_inactive(struct vnop_inactive_args 
*ap
) 
 277         vnode_t vp 
= ap
->a_vp
; 
 278         struct iso_node 
*ip 
= VTOI(vp
); 
 281          * If we are done with the inode, reclaim it 
 282          * so that it can be reused immediately. 
 284         if (ip
->inode
.iso_mode 
== 0) 
 291  * Reclaim an inode so that it can be used for other purposes. 
 294 cd9660_reclaim(struct vnop_reclaim_args 
*ap
) 
 296         vnode_t vp 
= ap
->a_vp
; 
 297         struct iso_node 
*ip 
= VTOI(vp
); 
 299         vnode_removefsref(vp
); 
 301          * Remove the inode from its hash chain. 
 306                 vnode_t devvp 
= ip
->i_devvp
; 
 310         vnode_clearfsnode(vp
); 
 312         if (ip
->i_namep 
!= isonullname
) 
 313                 FREE(ip
->i_namep
, M_TEMP
); 
 314         if (ip
->i_riff 
!= NULL
) 
 315                 FREE(ip
->i_riff
, M_TEMP
); 
 316         FREE_ZONE(ip
, sizeof(struct iso_node
), M_ISOFSNODE
); 
 325 cd9660_defattr(struct iso_directory_record 
*isodir
, struct iso_node 
*inop
, 
 328         struct buf 
*bp2 
= NULL
; 
 330         struct iso_extended_attributes 
*ap 
= NULL
; 
 333         if ( isonum_711(isodir
->flags
) & directoryBit 
) { 
 334                 inop
->inode
.iso_mode 
= S_IFDIR
; 
 336                  * If we return 2, fts() will assume there are no subdirectories 
 337                  * (just links for the path and .), so instead we return 1. 
 339                 inop
->inode
.iso_links 
= 1; 
 341                 inop
->inode
.iso_mode 
= S_IFREG
; 
 342                 inop
->inode
.iso_links 
= 1; 
 345             && ((imp 
= inop
->i_mnt
)->im_flags 
& ISOFSMNT_EXTATT
) 
 346             && (off 
= isonum_711(isodir
->ext_attr_length
))) { 
 347                 cd9660_blkatoff(ITOV(inop
), (off_t
)-(off 
<< imp
->im_bshift
), NULL
, &bp2
); 
 351                 ap 
= (struct iso_extended_attributes 
*)((char *)0 + buf_dataptr(bp
)); 
 353                 if (isonum_711(ap
->version
) == 1) { 
 354                         if (!(ap
->perm
[0]&0x40)) 
 355                                 inop
->inode
.iso_mode 
|= VEXEC 
>> 6; 
 356                         if (!(ap
->perm
[0]&0x10)) 
 357                                 inop
->inode
.iso_mode 
|= VREAD 
>> 6; 
 358                         if (!(ap
->perm
[0]&4)) 
 359                                 inop
->inode
.iso_mode 
|= VEXEC 
>> 3; 
 360                         if (!(ap
->perm
[0]&1)) 
 361                                 inop
->inode
.iso_mode 
|= VREAD 
>> 3; 
 362                         if (!(ap
->perm
[1]&0x40)) 
 363                                 inop
->inode
.iso_mode 
|= VEXEC
; 
 364                         if (!(ap
->perm
[1]&0x10)) 
 365                                 inop
->inode
.iso_mode 
|= VREAD
; 
 366                         inop
->inode
.iso_uid 
= isonum_723(ap
->owner
); /* what about 0? */ 
 367                         inop
->inode
.iso_gid 
= isonum_723(ap
->group
); /* what about 0? */ 
 372                 inop
->inode
.iso_mode 
|= VREAD
|VWRITE
|VEXEC
|(VREAD
|VEXEC
)>>3|(VREAD
|VEXEC
)>>6; 
 373                 inop
->inode
.iso_uid 
= ISO_UNKNOWNUID
; 
 374                 inop
->inode
.iso_gid 
= ISO_UNKNOWNGID
; 
 384 cd9660_deftstamp(struct iso_directory_record 
*isodir
, struct iso_node 
*inop
, 
 387         struct buf 
*bp2 
= NULL
; 
 389         struct iso_extended_attributes 
*ap 
= NULL
; 
 393             && ((imp 
= inop
->i_mnt
)->im_flags 
& ISOFSMNT_EXTATT
) 
 394             && (off 
= isonum_711(isodir
->ext_attr_length
)))  
 396                 cd9660_blkatoff(ITOV(inop
), (off_t
)-(off 
<< imp
->im_bshift
), NULL
, &bp2
); 
 400                 ap 
= (struct iso_extended_attributes 
*)((char *)0 + buf_dataptr(bp
)); 
 402                 if (isonum_711(ap
->version
) == 1) { 
 403                         if (!cd9660_tstamp_conv17(ap
->ftime
,&inop
->inode
.iso_atime
)) 
 404                                 cd9660_tstamp_conv17(ap
->ctime
,&inop
->inode
.iso_atime
); 
 405                         if (!cd9660_tstamp_conv17(ap
->ctime
,&inop
->inode
.iso_ctime
)) 
 406                                 inop
->inode
.iso_ctime 
= inop
->inode
.iso_atime
; 
 407                         if (!cd9660_tstamp_conv17(ap
->mtime
,&inop
->inode
.iso_mtime
)) 
 408                                 inop
->inode
.iso_mtime 
= inop
->inode
.iso_ctime
; 
 413                 cd9660_tstamp_conv7(isodir
->date
,&inop
->inode
.iso_ctime
); 
 414                 inop
->inode
.iso_atime 
= inop
->inode
.iso_ctime
; 
 415                 inop
->inode
.iso_mtime 
= inop
->inode
.iso_ctime
; 
 422 cd9660_tstamp_conv7(u_char 
*pi
, struct timespec 
*pu
) 
 425         int y
, m
, d
, hour
, minute
, second
, mytz
; 
 441                 /* computes day number relative to Sept. 19th,1989 */ 
 442                 /* don't even *THINK* about changing formula. It works! */ 
 443                 days 
= 367*(y
-1980)-7*(y
+(m
+9)/12)/4-3*((y
+(m
-9)/7)/100+1)/4+275*m
/9+d
-100; 
 446                  * Changed :-) to make it relative to Jan. 1st, 1970 
 447                  * and to disambiguate negative division 
 449                 days 
= 367*(y
-1960)-7*(y
+(m
+9)/12)/4-3*((y
+(m
+9)/12-1)/100+1)/4+275*m
/9+d
-239; 
 451                 crtime 
= ((((days 
* 24) + hour
) * 60 + minute
) * 60) + second
; 
 453                 /* timezone offset is unreliable on some disks */ 
 454                 if (-48 <= mytz 
&& mytz 
<= 52) 
 455                         crtime 
-= mytz 
* 15 * 60; 
 463 cd9660_chars2ui(u_char 
*begin
, int len
) 
 467         for (rc 
= 0; --len 
>= 0;) { 
 469                 rc 
+= *begin
++ - '0'; 
 475 cd9660_tstamp_conv17(u_char 
*pi
, struct timespec 
*pu
) 
 479         /* year:"0001"-"9999" -> -1900  */ 
 480         buf
[0] = cd9660_chars2ui(pi
,4) - 1900; 
 482         /* month: " 1"-"12"      -> 1 - 12 */ 
 483         buf
[1] = cd9660_chars2ui(pi 
+ 4,2); 
 485         /* day:   " 1"-"31"      -> 1 - 31 */ 
 486         buf
[2] = cd9660_chars2ui(pi 
+ 6,2); 
 488         /* hour:  " 0"-"23"      -> 0 - 23 */ 
 489         buf
[3] = cd9660_chars2ui(pi 
+ 8,2); 
 491         /* minute:" 0"-"59"      -> 0 - 59 */ 
 492         buf
[4] = cd9660_chars2ui(pi 
+ 10,2); 
 494         /* second:" 0"-"59"      -> 0 - 59 */ 
 495         buf
[5] = cd9660_chars2ui(pi 
+ 12,2); 
 497         /* difference of GMT */ 
 500         return cd9660_tstamp_conv7(buf
,pu
); 
 504 isodirino(struct iso_directory_record 
*isodir
, struct iso_mnt 
*imp
) 
 508         ino 
= (isonum_733(isodir
->extent
) + isonum_711(isodir
->ext_attr_length
))