]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfs_lookup.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_lookup.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
A
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
1c79356b
A
29 */
30/*
31 * Copyright (c) 1989, 1993
32 * The Regents of the University of California. All rights reserved.
33 * (c) UNIX System Laboratories, Inc.
34 * All or some portions of this file are derived from material licensed
35 * to the University of California by American Telephone and Telegraph
36 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
37 * the permission of UNIX System Laboratories, Inc.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
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.
54 *
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
65 * SUCH DAMAGE.
66 *
67 * @(#)hfs_lookup.c 1.0
68 * derived from @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95
69 *
70 * (c) 1998-1999 Apple Computer, Inc. All Rights Reserved
71 * (c) 1990, 1992 NeXT Computer, Inc. All Rights Reserved
72 *
73 *
74 * hfs_lookup.c -- code to handle directory traversal on HFS/HFS+ volume
1c79356b
A
75 */
76
77#include <sys/param.h>
1c79356b
A
78#include <sys/file.h>
79#include <sys/mount.h>
80#include <sys/vnode.h>
81#include <sys/malloc.h>
82#include <sys/paths.h>
91447636
A
83#include <sys/kdebug.h>
84#include <sys/kauth.h>
1c79356b 85
9bccf70c
A
86#include "hfs.h"
87#include "hfs_catalog.h"
88#include "hfs_cnode.h"
1c79356b 89
91447636 90#define LEGACY_FORK_NAMES 1
1c79356b 91
9bccf70c 92static int forkcomponent(struct componentname *cnp, int *rsrcfork);
1c79356b 93
9bccf70c 94#define _PATH_DATAFORKSPEC "/..namedfork/data"
1c79356b 95
91447636 96#if LEGACY_FORK_NAMES
9bccf70c 97#define LEGACY_RSRCFORKSPEC "/rsrc"
1c79356b
A
98#endif
99
1c79356b
A
100/*
101 * FROM FREEBSD 3.1
9bccf70c 102 * Convert a component of a pathname into a pointer to a locked cnode.
1c79356b
A
103 * This is a very central and rather complicated routine.
104 * If the file system is not maintained in a strict tree hierarchy,
105 * this can result in a deadlock situation (see comments in code below).
106 *
107 * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
108 * on whether the name is to be looked up, created, renamed, or deleted.
109 * When CREATE, RENAME, or DELETE is specified, information usable in
110 * creating, renaming, or deleting a directory entry may be calculated.
111 * Notice that these are the only operations that can affect the directory of the target.
112 *
1c79356b
A
113 * LOCKPARENT and WANTPARENT actually refer to the parent of the last item,
114 * so if ISLASTCN is not set, they should be ignored. Also they are mutually exclusive, or
115 * WANTPARENT really implies DONTLOCKPARENT. Either of them set means that the calling
116 * routine wants to access the parent of the target, locked or unlocked.
117 *
118 * Keeping the parent locked as long as possible protects from other processes
9bccf70c 119 * looking up the same item, so it has to be locked until the cnode is totally finished
1c79356b 120 *
1c79356b
A
121 * hfs_cache_lookup() performs the following for us:
122 * check that it is a directory
123 * check accessibility of directory
124 * check for modification attempts on read-only mounts
125 * if name found in cache
126 * if at end of path and deleting or creating
127 * drop it
128 * else
129 * return name.
91447636 130 * return hfs_lookup()
1c79356b
A
131 *
132 * Overall outline of hfs_lookup:
133 *
134 * handle simple cases of . and ..
135 * search for name in directory, to found or notfound
136 * notfound:
137 * if creating, return locked directory, leaving info on available slots
138 * else return error
139 * found:
140 * if at end of path and deleting, return information to allow delete
141 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target
9bccf70c 142 * cnode and return info to allow rewrite
1c79356b
A
143 * if not at end, add name to cache; if at end and neither creating
144 * nor deleting, add name to cache
145 */
146
91447636 147
1c79356b 148/*
91447636
A
149 * Lookup *cnp in directory *dvp, return it in *vpp.
150 * **vpp is held on exit.
9bccf70c 151 * We create a cnode for the file, but we do NOT open the file here.
1c79356b
A
152
153#% lookup dvp L ? ?
154#% lookup vpp - L -
155
156 IN struct vnode *dvp - Parent node of file;
9bccf70c
A
157 INOUT struct vnode **vpp - node of target file, its a new node if
158 the target vnode did not exist;
1c79356b
A
159 IN struct componentname *cnp - Name of file;
160
161 * When should we lock parent_hp in here ??
162 */
91447636
A
163static int
164hfs_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, vfs_context_t context, int *cnode_locked)
1c79356b 165{
9bccf70c
A
166 struct cnode *dcp; /* cnode for directory being searched */
167 struct vnode *tvp; /* target vnode */
168 struct hfsmount *hfsmp;
91447636 169 kauth_cred_t cred;
9bccf70c
A
170 struct proc *p;
171 int wantrsrc = 0;
172 int forknamelen = 0;
173 int flags;
9bccf70c
A
174 int nameiop;
175 int retval = 0;
176 int isDot;
91447636 177 struct cat_desc desc;
9bccf70c
A
178 struct cat_desc cndesc;
179 struct cat_attr attr;
180 struct cat_fork fork;
91447636 181 int lockflags;
9bccf70c 182
9bccf70c
A
183 dcp = VTOC(dvp);
184 hfsmp = VTOHFS(dvp);
185 *vpp = NULL;
91447636 186 *cnode_locked = 0;
9bccf70c
A
187 isDot = FALSE;
188 tvp = NULL;
189 nameiop = cnp->cn_nameiop;
9bccf70c 190 flags = cnp->cn_flags;
91447636
A
191 bzero(&desc, sizeof(desc));
192
193 cred = vfs_context_ucred(context);
194 p = vfs_context_proc(context);
1c79356b
A
195
196 /*
197 * First check to see if it is a . or .., else look it up.
198 */
9bccf70c 199 if (flags & ISDOTDOT) { /* Wanting the parent */
91447636 200 cnp->cn_flags &= ~MAKEENTRY;
9bccf70c
A
201 goto found; /* .. is always defined */
202 } else if ((cnp->cn_nameptr[0] == '.') && (cnp->cn_namelen == 1)) {
1c79356b 203 isDot = TRUE;
91447636 204 cnp->cn_flags &= ~MAKEENTRY;
9bccf70c
A
205 goto found; /* We always know who we are */
206 } else {
207 /* Check fork suffix to see if we want the resource fork */
208 forknamelen = forkcomponent(cnp, &wantrsrc);
91447636
A
209
210 /* Resource fork names are not cached. */
211 if (wantrsrc)
212 cnp->cn_flags &= ~MAKEENTRY;
213
214 if (hfs_lock(dcp, HFS_EXCLUSIVE_LOCK) != 0) {
215 goto notfound;
216 }
1c79356b 217
9bccf70c 218 /* No need to go to catalog if there are no children */
91447636
A
219 if (dcp->c_entries == 0) {
220 hfs_unlock(dcp);
9bccf70c 221 goto notfound;
91447636 222 }
1c79356b 223
9bccf70c
A
224 bzero(&cndesc, sizeof(cndesc));
225 cndesc.cd_nameptr = cnp->cn_nameptr;
226 cndesc.cd_namelen = cnp->cn_namelen;
227 cndesc.cd_parentcnid = dcp->c_cnid;
228 cndesc.cd_hint = dcp->c_childhint;
1c79356b 229
91447636
A
230 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
231
232 retval = cat_lookup(hfsmp, &cndesc, wantrsrc, &desc, &attr, &fork, NULL);
9bccf70c 233
91447636
A
234 hfs_systemfile_unlock(hfsmp, lockflags);
235
9bccf70c
A
236 if (retval == 0) {
237 dcp->c_childhint = desc.cd_hint;
91447636 238 hfs_unlock(dcp);
9bccf70c
A
239 goto found;
240 }
91447636 241 hfs_unlock(dcp);
9bccf70c 242notfound:
91447636
A
243 /* ENAMETOOLONG supersedes other errors */
244 if (((nameiop != CREATE) && (nameiop != RENAME)) &&
245 (retval != ENAMETOOLONG) &&
246 (cnp->cn_namelen > kHFSPlusMaxFileNameChars)) {
247 retval = ENAMETOOLONG;
248 } else if (retval == 0) {
249 retval = ENOENT;
250 }
9bccf70c
A
251 /*
252 * This is a non-existing entry
253 *
254 * If creating, and at end of pathname and current
255 * directory has not been removed, then can consider
256 * allowing file to be created.
257 */
258 if ((nameiop == CREATE || nameiop == RENAME ||
259 (nameiop == DELETE &&
91447636
A
260 (cnp->cn_flags & DOWHITEOUT) &&
261 (cnp->cn_flags & ISWHITEOUT))) &&
262 (flags & ISLASTCN) &&
263 (retval == ENOENT)) {
9bccf70c
A
264 retval = EJUSTRETURN;
265 goto exit;
1c79356b 266 }
1c79356b
A
267 /*
268 * Insert name into cache (as non-existent) if appropriate.
9bccf70c 269 *
55e303ae 270 * Only done for case-sensitive HFS+ volumes.
1c79356b 271 */
91447636
A
272 if ((retval == ENOENT) &&
273 (hfsmp->hfs_flags & HFS_CASE_SENSITIVE) &&
274 (cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) {
275 cache_enter(dvp, NULL, cnp);
276 }
9bccf70c 277 goto exit;
1c79356b 278 }
1c79356b 279
9bccf70c
A
280found:
281 /*
282 * Process any fork specifiers
283 */
284 if (forknamelen && S_ISREG(attr.ca_mode)) {
285 /* fork names are only for lookups */
286 if ((nameiop != LOOKUP) && (nameiop != CREATE)) {
287 retval = EPERM;
288 goto exit;
289 }
290 cnp->cn_consume = forknamelen;
291 flags |= ISLASTCN;
292 } else {
293 wantrsrc = 0;
294 forknamelen = 0;
295 }
91447636
A
296 if (flags & ISLASTCN) {
297 switch(nameiop) {
298 case DELETE:
299 cnp->cn_flags &= ~MAKEENTRY;
300 break;
301
302 case RENAME:
303 cnp->cn_flags &= ~MAKEENTRY;
304 if (isDot) {
305 retval = EISDIR;
9bccf70c 306 goto exit;
91447636
A
307 }
308 break;
1c79356b 309 }
91447636 310 }
9bccf70c 311
91447636
A
312 if (isDot) {
313 if ((retval = vnode_get(dvp)))
9bccf70c 314 goto exit;
91447636
A
315 *vpp = dvp;
316 } else if (flags & ISDOTDOT) {
317 if ((retval = hfs_vget(hfsmp, dcp->c_parentcnid, &tvp, 0)))
9bccf70c 318 goto exit;
91447636 319 *cnode_locked = 1;
9bccf70c 320 *vpp = tvp;
9bccf70c
A
321 } else {
322 int type = (attr.ca_mode & S_IFMT);
1c79356b 323
91447636 324 if (!(flags & ISLASTCN) && (type != S_IFDIR) && (type != S_IFLNK)) {
9bccf70c
A
325 retval = ENOTDIR;
326 goto exit;
1c79356b 327 }
1c79356b 328
91447636
A
329 /* Names with composed chars are not cached. */
330 if (cnp->cn_namelen != desc.cd_namelen)
331 cnp->cn_flags &= ~MAKEENTRY;
1c79356b 332
91447636
A
333 /* Resource fork vnode names include the fork specifier. */
334 if (wantrsrc && (flags & ISLASTCN))
335 cnp->cn_namelen += forknamelen;
1c79356b 336
91447636 337 retval = hfs_getnewvnode(hfsmp, dvp, cnp, &desc, wantrsrc, &attr, &fork, &tvp);
1c79356b 338
91447636
A
339 if (wantrsrc && (flags & ISLASTCN))
340 cnp->cn_namelen -= forknamelen;
55e303ae 341
91447636
A
342 if (retval)
343 goto exit;
344 *cnode_locked = 1;
345 *vpp = tvp;
55e303ae 346 }
9bccf70c
A
347exit:
348 cat_releasedesc(&desc);
1c79356b
A
349 return (retval);
350}
351
352
353
354/*
1c79356b
A
355 * Name caching works as follows:
356 *
357 * Names found by directory scans are retained in a cache
358 * for future reference. It is managed LRU, so frequently
359 * used names will hang around. Cache is indexed by hash value
360 * obtained from (vp, name) where vp refers to the directory
361 * containing name.
362 *
363 * If it is a "negative" entry, (i.e. for a name that is known NOT to
364 * exist) the vnode pointer will be NULL.
365 *
366 * Upon reaching the last segment of a path, if the reference
367 * is for DELETE, or NOCACHE is set (rewrite), and the
368 * name is located in the cache, it will be dropped.
369 *
1c79356b
A
370 */
371
55e303ae
A
372#define S_IXALL 0000111
373
9bccf70c 374__private_extern__
1c79356b 375int
91447636 376hfs_vnop_lookup(struct vnop_lookup_args *ap)
1c79356b 377{
91447636 378 struct vnode *dvp = ap->a_dvp;
9bccf70c
A
379 struct vnode *vp;
380 struct cnode *cp;
55e303ae 381 struct cnode *dcp;
1c79356b
A
382 int error;
383 struct vnode **vpp = ap->a_vpp;
9bccf70c 384 struct componentname *cnp = ap->a_cnp;
1c79356b 385 int flags = cnp->cn_flags;
91447636 386 int cnode_locked;
1c79356b 387
91447636 388 *vpp = NULL;
55e303ae 389 dcp = VTOC(dvp);
1c79356b
A
390
391 /*
392 * Lookup an entry in the cache
91447636
A
393 *
394 * If the lookup succeeds, the vnode is returned in *vpp,
395 * and a status of -1 is returned.
396 *
397 * If the lookup determines that the name does not exist
398 * (negative cacheing), a status of ENOENT is returned.
399 *
400 * If the lookup fails, a status of zero is returned.
1c79356b 401 */
9bccf70c 402 error = cache_lookup(dvp, vpp, cnp);
55e303ae 403 if (error != -1) {
91447636
A
404 if (error == ENOENT) /* found a negative cache entry */
405 goto exit;
406 goto lookup; /* did not find it in the cache */
9bccf70c 407 }
91447636
A
408 /*
409 * We have a name that matched
410 * cache_lookup returns the vp with an iocount reference already taken
411 */
412 error = 0;
9bccf70c 413 vp = *vpp;
9bccf70c 414
1c79356b
A
415 /*
416 * If this is a hard-link vnode then we need to update
9bccf70c
A
417 * the name (of the link), the parent ID, the cnid, the
418 * text encoding and the catalog hint. This enables
419 * getattrlist calls to return the correct link info.
1c79356b 420 */
9bccf70c 421 cp = VTOC(vp);
9bccf70c 422
91447636
A
423 if ((flags & ISLASTCN) && (cp->c_flag & C_HARDLINK)) {
424 hfs_lock(cp, HFS_FORCE_LOCK);
425 if ((cp->c_parentcnid != VTOC(dvp)->c_cnid) ||
426 (bcmp(cnp->cn_nameptr, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen) != 0)) {
427 struct cat_desc desc;
428 int lockflags;
1c79356b 429
91447636
A
430 /*
431 * Get an updated descriptor
432 */
433 bzero(&desc, sizeof(desc));
434 desc.cd_nameptr = cnp->cn_nameptr;
435 desc.cd_namelen = cnp->cn_namelen;
436 desc.cd_parentcnid = VTOC(dvp)->c_cnid;
437 desc.cd_hint = VTOC(dvp)->c_childhint;
438
439 lockflags = hfs_systemfile_lock(VTOHFS(dvp), SFL_CATALOG, HFS_SHARED_LOCK);
440 if (cat_lookup(VTOHFS(vp), &desc, 0, &desc, NULL, NULL, NULL) == 0)
441 replace_desc(cp, &desc);
442 hfs_systemfile_unlock(VTOHFS(dvp), lockflags);
443 }
444 hfs_unlock(cp);
445 }
446 if (dvp != vp && !(flags & ISDOTDOT)) {
447 if ((flags & ISLASTCN) == 0 && vnode_isreg(vp)) {
9bccf70c
A
448 int wantrsrc = 0;
449
450 cnp->cn_consume = forkcomponent(cnp, &wantrsrc);
55e303ae
A
451 if (cnp->cn_consume) {
452 flags |= ISLASTCN;
453 /* Fork names are only for lookups */
454 if (cnp->cn_nameiop != LOOKUP &&
455 cnp->cn_nameiop != CREATE) {
91447636 456 vnode_put(vp);
55e303ae 457 error = EPERM;
91447636 458 goto exit;
55e303ae
A
459 }
460 }
91447636
A
461 /*
462 * Use cnode's rsrcfork vnode if possible.
463 */
55e303ae 464 if (wantrsrc) {
91447636
A
465 int vid;
466
467 *vpp = NULL;
468
469 if (cp->c_rsrc_vp == NULL) {
470 vnode_put(vp);
471 goto lookup;
55e303ae 472 }
91447636
A
473 vid = vnode_vid(cp->c_rsrc_vp);
474
475 error = vnode_getwithvid(cp->c_rsrc_vp, vid);
476 if (error) {
477 vnode_put(vp);
478 goto lookup;
479 }
480 *vpp = cp->c_rsrc_vp;
481 vnode_put(vp);
482 vp = *vpp;
55e303ae
A
483 }
484 }
0b4e3aa0 485 }
91447636
A
486 return (error);
487
488lookup:
1c79356b 489 /*
91447636
A
490 * The vnode was not in the name cache or it was stale.
491 *
492 * So we need to do a real lookup.
1c79356b 493 */
91447636 494 cnode_locked = 0;
55e303ae 495
91447636
A
496 error = hfs_lookup(dvp, vpp, cnp, ap->a_context, &cnode_locked);
497
498 if (cnode_locked)
499 hfs_unlock(VTOC(*vpp));
500exit:
55e303ae 501 return (error);
1c79356b
A
502}
503
9bccf70c 504
1c79356b 505/*
9bccf70c
A
506 * forkcomponent - look for a fork suffix in the component name
507 *
1c79356b 508 */
9bccf70c
A
509static int
510forkcomponent(struct componentname *cnp, int *rsrcfork)
1c79356b 511{
9bccf70c
A
512 char *suffix = cnp->cn_nameptr + cnp->cn_namelen;
513 int consume = 0;
1c79356b 514
9bccf70c
A
515 *rsrcfork = 0;
516 if (*suffix == '\0')
517 return (0);
518 /*
519 * There are only 3 valid fork suffixes:
520 * "/..namedfork/rsrc"
521 * "/..namedfork/data"
522 * "/rsrc" (legacy)
523 */
524 if (bcmp(suffix, _PATH_RSRCFORKSPEC, sizeof(_PATH_RSRCFORKSPEC)) == 0) {
525 consume = sizeof(_PATH_RSRCFORKSPEC) - 1;
526 *rsrcfork = 1;
527 } else if (bcmp(suffix, _PATH_DATAFORKSPEC, sizeof(_PATH_DATAFORKSPEC)) == 0) {
528 consume = sizeof(_PATH_DATAFORKSPEC) - 1;
1c79356b
A
529 }
530
91447636 531#if LEGACY_FORK_NAMES
9bccf70c
A
532 else if (bcmp(suffix, LEGACY_RSRCFORKSPEC, sizeof(LEGACY_RSRCFORKSPEC)) == 0) {
533 consume = sizeof(LEGACY_RSRCFORKSPEC) - 1;
534 *rsrcfork = 1;
91447636 535 printf("HFS: /rsrc paths are deprecated (%s)\n", cnp->cn_nameptr);
1c79356b 536 }
9bccf70c
A
537#endif
538 return (consume);
1c79356b
A
539}
540