|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* $NetBSD: cd9660_lookup.c,v 1.13 1994/12/24 15:30:03 cgd Exp $ */
23:
24: /*-
25: * Copyright (c) 1989, 1993, 1994
26: * The Regents of the University of California. All rights reserved.
27: *
28: * This code is derived from software contributed to Berkeley
29: * by Pace Willisson ([email protected]). The Rock Ridge Extension
30: * Support code is derived from software contributed to Berkeley
31: * by Atsushi Murai ([email protected]).
32: *
33: * Redistribution and use in source and binary forms, with or without
34: * modification, are permitted provided that the following conditions
35: * are met:
36: * 1. Redistributions of source code must retain the above copyright
37: * notice, this list of conditions and the following disclaimer.
38: * 2. Redistributions in binary form must reproduce the above copyright
39: * notice, this list of conditions and the following disclaimer in the
40: * documentation and/or other materials provided with the distribution.
41: * 3. All advertising materials mentioning features or use of this software
42: * must display the following acknowledgement:
43: * This product includes software developed by the University of
44: * California, Berkeley and its contributors.
45: * 4. Neither the name of the University nor the names of its contributors
46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: *
61: * from: @(#)ufs_lookup.c 7.33 (Berkeley) 5/19/91
62: *
63: * @(#)cd9660_lookup.c 8.5 (Berkeley) 12/5/94
64:
65:
66:
67: * HISTORY
68: * 22-Jan-98 radar 1669467 - ISO 9660 CD support - jwc
69:
70: */
71:
72: #include <sys/param.h>
73: #include <sys/namei.h>
74: #include <sys/buf.h>
75: #include <sys/file.h>
76: #include <sys/vnode.h>
77: #include <sys/mount.h>
78:
79: #include <isofs/cd9660/iso.h>
80: #include <isofs/cd9660/cd9660_node.h>
81: #include <isofs/cd9660/iso_rrip.h>
82: #include <isofs/cd9660/cd9660_rrip.h>
83:
84: struct nchstats iso_nchstats;
85:
86: /*
87: * Convert a component of a pathname into a pointer to a locked inode.
88: * This is a very central and rather complicated routine.
89: * If the file system is not maintained in a strict tree hierarchy,
90: * this can result in a deadlock situation (see comments in code below).
91: *
92: * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
93: * whether the name is to be looked up, created, renamed, or deleted.
94: * When CREATE, RENAME, or DELETE is specified, information usable in
95: * creating, renaming, or deleting a directory entry may be calculated.
96: * If flag has LOCKPARENT or'ed into it and the target of the pathname
97: * exists, lookup returns both the target and its parent directory locked.
98: * When creating or renaming and LOCKPARENT is specified, the target may
99: * not be ".". When deleting and LOCKPARENT is specified, the target may
100: * be "."., but the caller must check to ensure it does an vrele and iput
101: * instead of two iputs.
102: *
103: * Overall outline of ufs_lookup:
104: *
105: * check accessibility of directory
106: * look for name in cache, if found, then if at end of path
107: * and deleting or creating, drop it, else return name
108: * search for name in directory, to found or notfound
109: * notfound:
110: * if creating, return locked directory, leaving info on available slots
111: * else return error
112: * found:
113: * if at end of path and deleting, return information to allow delete
114: * if at end of path and rewriting (RENAME and LOCKPARENT), lock target
115: * inode and return info to allow rewrite
116: * if not at end, add name to cache; if at end and neither creating
117: * nor deleting, add name to cache
118: *
119: * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked.
120: */
121: int
122: cd9660_lookup(ap)
123: struct vop_lookup_args /* {
124: struct vnode *a_dvp;
125: struct vnode **a_vpp;
126: struct componentname *a_cnp;
127: } */ *ap;
128: {
129: register struct vnode *vdp; /* vnode for directory being searched */
130: register struct iso_node *dp; /* inode for directory being searched */
131: register struct iso_mnt *imp; /* file system that directory is in */
132: struct buf *bp; /* a buffer of directory entries */
133: struct iso_directory_record *ep = NULL;/* the current directory entry */
134: int entryoffsetinblock; /* offset of ep in bp's buffer */
135: int saveoffset = 0; /* offset of last directory entry in dir */
136: int numdirpasses; /* strategy for directory search */
137: doff_t endsearch; /* offset to end directory search */
138: struct vnode *pdp; /* saved dp during symlink work */
139: struct vnode *tdp; /* returned by cd9660_vget_internal */
140: u_long bmask; /* block offset mask */
141: int lockparent; /* 1 => lockparent flag is set */
142: int wantparent; /* 1 => wantparent or lockparent flag */
143: int error;
144: ino_t ino = 0;
145: int reclen;
146: u_short namelen;
147: char altname[NAME_MAX];
148: int res;
149: int assoc, len;
150: char *name;
151: struct vnode **vpp = ap->a_vpp;
152: struct componentname *cnp = ap->a_cnp;
153: struct ucred *cred = cnp->cn_cred;
154: int flags = cnp->cn_flags;
155: int nameiop = cnp->cn_nameiop;
156: #ifdef NeXT
157: int devBlockSize=0;
158: #endif /* NeXT */
159:
160: bp = NULL;
161: *vpp = NULL;
162: vdp = ap->a_dvp;
163: dp = VTOI(vdp);
164: imp = dp->i_mnt;
165: lockparent = flags & LOCKPARENT;
166: wantparent = flags & (LOCKPARENT|WANTPARENT);
167:
168: /*
169: * Check accessiblity of directory.
170: */
171: if (vdp->v_type != VDIR)
172: return (ENOTDIR);
173: if ( (error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) ) // radar 1669467 - fix compiler warning
174: return (error);
175:
176: /*
177: * We now have a segment name to search for, and a directory to search.
178: *
179: * Before tediously performing a linear scan of the directory,
180: * check the name cache to see if the directory/name pair
181: * we are looking for is known already.
182: */
183: if ( (error = cache_lookup(vdp, vpp, cnp)) ) { // radar 1669467 - fix compiler warning
184: int vpid; /* capability number of vnode */
185:
186: if (error == ENOENT)
187: return (error);
188: #ifdef PARANOID
189: if ((vdp->v_flag & VROOT) && (flags & ISDOTDOT))
190: panic("cd9660_lookup: .. through root");
191: #endif
192: /*
193: * Get the next vnode in the path.
194: * See comment below starting `Step through' for
195: * an explaination of the locking protocol.
196: */
197: pdp = vdp;
198: dp = VTOI(*vpp);
199: vdp = *vpp;
200: vpid = vdp->v_id;
201: if (pdp == vdp) {
202: VREF(vdp);
203: error = 0;
204: } else if (flags & ISDOTDOT) {
205: VOP_UNLOCK(pdp, 0, cnp->cn_proc);
206: error = vget(vdp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc);
207: if (!error && lockparent && (flags & ISLASTCN))
208: error = VOP_LOCK(pdp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc);
209: } else {
210: error = vget(vdp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc);
211: if (!lockparent || error || !(flags & ISLASTCN))
212: VOP_UNLOCK(pdp, 0, cnp->cn_proc);
213: }
214: /*
215: * Check that the capability number did not change
216: * while we were waiting for the lock.
217: */
218: if (!error) {
219: if (vpid == vdp->v_id)
220: return (0);
221: vput(vdp);
222: if (lockparent && pdp != vdp && (flags & ISLASTCN))
223: VOP_UNLOCK(pdp, 0, cnp->cn_proc);
224: }
225: if ( (error = VOP_LOCK(pdp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc)) ) // radar 1669467 - fix compiler warning
226: return (error);
227: vdp = pdp;
228: dp = VTOI(pdp);
229: *vpp = NULL;
230: }
231:
232: len = cnp->cn_namelen;
233: name = cnp->cn_nameptr;
234: /*
235: * A leading `=' means, we are looking for an associated file
236: */
237: if ( (assoc = (imp->iso_ftype != ISO_FTYPE_RRIP && *name == ASSOCCHAR)) ) { // radar 1669467 - fix compiler warning
238: len--;
239: name++;
240: }
241:
242: /*
243: * If there is cached information on a previous search of
244: * this directory, pick up where we last left off.
245: * We cache only lookups as these are the most common
246: * and have the greatest payoff. Caching CREATE has little
247: * benefit as it usually must search the entire directory
248: * to determine that the entry does not exist. Caching the
249: * location of the last DELETE or RENAME has not reduced
250: * profiling time and hence has been removed in the interest
251: * of simplicity.
252: */
253: bmask = imp->im_bmask;
254: if (nameiop != LOOKUP || dp->i_diroff == 0 ||
255: dp->i_diroff > dp->i_size) {
256: entryoffsetinblock = 0;
257: dp->i_offset = 0;
258: numdirpasses = 1;
259: } else {
260: dp->i_offset = dp->i_diroff;
261:
262: if ((entryoffsetinblock = dp->i_offset & bmask) &&
263: (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
264: return (error);
265: numdirpasses = 2;
266: iso_nchstats.ncs_2passes++;
267: }
268: endsearch = dp->i_size;
269:
270: searchloop:
271: while (dp->i_offset < endsearch) {
272: /*
273: * If offset is on a block boundary,
274: * read the next directory block.
275: * Release previous if it exists.
276: */
277: if ((dp->i_offset & bmask) == 0) {
278: if (bp != NULL)
279: brelse(bp);
280: if ( (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) ) // radar 1669467 - fix compiler warning
281: return (error);
282: entryoffsetinblock = 0;
283: }
284: /*
285: * Get pointer to next entry.
286: */
287: ep = (struct iso_directory_record *)
288: ((char *)bp->b_data + entryoffsetinblock);
289:
290: reclen = isonum_711(ep->length);
291: if (reclen == 0) {
292: /* skip to next block, if any */
293: dp->i_offset =
294: (dp->i_offset & ~bmask) + imp->logical_block_size;
295: continue;
296: }
297:
298: if (reclen < ISO_DIRECTORY_RECORD_SIZE)
299: /* illegal entry, stop */
300: break;
301:
302: if (entryoffsetinblock + reclen > imp->logical_block_size)
303: /* entries are not allowed to cross boundaries */
304: break;
305:
306: namelen = isonum_711(ep->name_len);
307:
308: if (reclen < ISO_DIRECTORY_RECORD_SIZE + namelen)
309: /* illegal entry, stop */
310: break;
311:
312: /*
313: * Check for a name match.
314: */
315: switch (imp->iso_ftype) {
316: default:
317: if ((!(isonum_711(ep->flags) & associatedBit)) == !assoc) {
318: if ((len == 1
319: && *name == '.')
320: || (flags & ISDOTDOT)) {
321: if (namelen == 1
322: && ep->name[0] == ((flags & ISDOTDOT) ? 1 : 0)) {
323: /*
324: * Save directory entry's inode number and
325: * release directory buffer.
326: */
327: dp->i_ino = isodirino(ep, imp);
328: goto found;
329: }
330: if (namelen != 1
331: || ep->name[0] != 0)
332: goto notfound;
333: } else if (!(res = isofncmp(name,len,
334: ep->name,namelen))) {
335: #if 1 // radar 1669467 - make it pretty
336: if ( isonum_711(ep->flags) & directoryBit )
337: #else
338: if (isonum_711(ep->flags)&2)
339: #endif // radar 1669467
340: ino = isodirino(ep, imp);
341: else
342: {
343: #if 1 // radar 1669467 - use im_bshift to convert block offset to byte offset
344: ino = (bp->b_blkno << imp->im_bshift) + entryoffsetinblock;
345: #else
346: ino = dbtob(bp->b_blkno) + entryoffsetinblock;
347: #endif // radar 1669467
348: }
349: saveoffset = dp->i_offset;
350: } else if (ino)
351: goto foundino;
352: #ifdef NOSORTBUG /* On some CDs directory entries are not sorted correctly */
353: else if (res < 0)
354: goto notfound;
355: else if (res > 0 && numdirpasses == 2)
356: numdirpasses++;
357: #endif
358: }
359: break;
360: case ISO_FTYPE_RRIP:
361: #if 1 // radar 1669467 - make it pretty
362: if ( isonum_711(ep->flags) & directoryBit )
363: #else
364: if (isonum_711(ep->flags)&2)
365: #endif // radar 1669467
366: ino = isodirino(ep, imp);
367: else
368: {
369: #if 1 // radar 1669467 - use im_bshift to convert block offset to byte offset
370: ino = (bp->b_blkno << imp->im_bshift) + entryoffsetinblock;
371: #else
372: ino = dbtob(bp->b_blkno) + entryoffsetinblock;
373: #endif // radar 1669467
374: }
375: dp->i_ino = ino;
376: cd9660_rrip_getname(ep,altname,&namelen,&dp->i_ino,imp);
377: if (namelen == cnp->cn_namelen
378: && !bcmp(name,altname,namelen))
379: goto found;
380: ino = 0;
381: break;
382: }
383: dp->i_offset += reclen;
384: entryoffsetinblock += reclen;
385: } // end of while (dp->i_offset < endsearch)
386:
387: if (ino) {
388: foundino:
389: dp->i_ino = ino;
390: if (saveoffset != dp->i_offset) {
391: if (lblkno(imp, dp->i_offset) !=
392: lblkno(imp, saveoffset)) {
393: if (bp != NULL)
394: brelse(bp);
395: if ( (error = VOP_BLKATOFF(vdp, (off_t)saveoffset, NULL, &bp)) ) // radar 1669467 - fix compiler warning
396: return (error);
397: }
398: entryoffsetinblock = saveoffset & bmask;
399: ep = (struct iso_directory_record *)
400: ((char *)bp->b_data + entryoffsetinblock);
401: dp->i_offset = saveoffset;
402: }
403: goto found;
404: }
405: notfound:
406: /*
407: * If we started in the middle of the directory and failed
408: * to find our target, we must check the beginning as well.
409: */
410: if (numdirpasses == 2) {
411: numdirpasses--;
412: dp->i_offset = 0;
413: endsearch = dp->i_diroff;
414: goto searchloop;
415: }
416: if (bp != NULL)
417: brelse(bp);
418:
419: /*
420: * Insert name into cache (as non-existent) if appropriate.
421: */
422: if (cnp->cn_flags & MAKEENTRY)
423: cache_enter(vdp, *vpp, cnp);
424: if (nameiop == CREATE || nameiop == RENAME)
425: {
426: // radar 1669467 return EROFS (NOT EJUSTRETURN). The caller will then unlock
427: // the parentfor us.
428: return (EROFS);
429: }
430: return (ENOENT);
431:
432: found:
433: if (numdirpasses == 2)
434: iso_nchstats.ncs_pass2++;
435:
436: /*
437: * Found component in pathname.
438: * If the final component of path name, save information
439: * in the cache as to where the entry was found.
440: */
441: if ((flags & ISLASTCN) && nameiop == LOOKUP)
442: dp->i_diroff = dp->i_offset;
443:
444: /*
445: * Step through the translation in the name. We do not `iput' the
446: * directory because we may need it again if a symbolic link
447: * is relative to the current directory. Instead we save it
448: * unlocked as "pdp". We must get the target inode before unlocking
449: * the directory to insure that the inode will not be removed
450: * before we get it. We prevent deadlock by always fetching
451: * inodes from the root, moving down the directory tree. Thus
452: * when following backward pointers ".." we must unlock the
453: * parent directory before getting the requested directory.
454: * There is a potential race condition here if both the current
455: * and parent directories are removed before the `iget' for the
456: * inode associated with ".." returns. We hope that this occurs
457: * infrequently since we cannot avoid this race condition without
458: * implementing a sophisticated deadlock detection algorithm.
459: * Note also that this simple deadlock detection scheme will not
460: * work if the file system has any hard links other than ".."
461: * that point backwards in the directory structure.
462: */
463: pdp = vdp;
464: /*
465: * If ino is different from dp->i_ino,
466: * it's a relocated directory.
467: */
468: if (flags & ISDOTDOT) {
469: VOP_UNLOCK(pdp, 0, cnp->cn_proc); /* race to get the inode */
470: error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp,
471: dp->i_ino != ino, ep, cnp->cn_proc);
472: VTOI(tdp)->i_parent = VTOI(pdp)->i_number;
473: brelse(bp);
474: if (error) {
475: VOP_LOCK(pdp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc);
476: return (error);
477: }
478: if (lockparent && (flags & ISLASTCN) &&
479: (error = VOP_LOCK(pdp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc))) {
480: vput(tdp);
481: return (error);
482: }
483: *vpp = tdp;
484: } else if (dp->i_number == dp->i_ino) {
485: brelse(bp);
486: VREF(vdp); /* we want ourself, ie "." */
487: *vpp = vdp;
488: } else {
489: error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp,
490: dp->i_ino != ino, ep, cnp->cn_proc);
491: VTOI(tdp)->i_parent = VTOI(pdp)->i_number; /* save parent inode number */
492: brelse(bp);
493: if (error)
494: return (error);
495: if (!lockparent || !(flags & ISLASTCN))
496: VOP_UNLOCK(pdp, 0, cnp->cn_proc);
497: *vpp = tdp;
498: }
499:
500: /*
501: * Insert name into cache if appropriate.
502: */
503: if (cnp->cn_flags & MAKEENTRY)
504: cache_enter(vdp, *vpp, cnp);
505:
506: return (0);
507: }
508:
509:
510: /*
511: * Return buffer with the contents of block "offset" from the beginning of
512: * directory "ip". If "res" is non-zero, fill it in with a pointer to the
513: * remaining space in the directory.
514: */
515: int
516: cd9660_blkatoff(ap)
517: struct vop_blkatoff_args /* {
518: struct vnode *a_vp;
519: off_t a_offset; // in bytes!!!!
520: char **a_res;
521: struct buf **a_bpp;
522: } */ *ap;
523: {
524: struct iso_node *ip;
525: register struct iso_mnt *imp;
526: struct buf *bp;
527: daddr_t lbn;
528: int bsize, error;
529:
530: ip = VTOI(ap->a_vp);
531: imp = ip->i_mnt;
532: lbn = lblkno(imp, ap->a_offset);
533: bsize = blksize(imp, ip, lbn);
534:
535: if ( (error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) ) { // radar 1669467 - fix compiler warning
536: brelse(bp);
537: *ap->a_bpp = NULL;
538: return (error);
539: }
540: if (ap->a_res)
541: *ap->a_res = (char *)bp->b_data + blkoff(imp, ap->a_offset);
542: *ap->a_bpp = bp;
543:
544: return (0);
545: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.