]>
git.saurik.com Git - apple/hfs.git/blob - livefiles_hfs_plugin/lf_hfs_lookup.c
5 // Created by Yakov Ben Zaken on 25/03/2018.
9 #include "lf_hfs_lookup.h"
10 #include "lf_hfs_cnode.h"
11 #include "lf_hfs_vfsutils.h"
12 #include "lf_hfs_link.h"
15 hfs_lookup(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
, int *cnode_locked
)
17 struct cnode
*dcp
; /* cnode for directory being searched */
18 struct vnode
*tvp
; /* target vnode */
19 struct hfsmount
*hfsmp
;
24 struct cat_desc cndesc
;
28 int newvnode_flags
= 0;
37 nameiop
= cnp
->cn_nameiop
;
38 flags
= cnp
->cn_flags
;
39 bzero(&desc
, sizeof(desc
));
41 if (hfs_lock(VTOC(dvp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
) != 0) {
42 retval
= ENOENT
; /* The parent no longer exists ? */
48 * Need to understand if we need this check.. as we took exclusive lock..
50 if (dcp
->c_flag
& C_DIR_MODIFICATION
){
57 * We shouldn't need to go to the catalog if there are no children.
58 * However, in the face of a minor disk corruption where the valence of
59 * the directory is off, we could infinite loop here if we return ENOENT
60 * even though there are actually items in the directory. (create will
61 * see the ENOENT, try to create something, which will return with
62 * EEXIST over and over again). As a result, always check the catalog.
65 bzero(&cndesc
, sizeof(cndesc
));
66 cndesc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
67 cndesc
.cd_namelen
= cnp
->cn_namelen
;
68 cndesc
.cd_parentcnid
= dcp
->c_fileid
;
69 cndesc
.cd_hint
= dcp
->c_childhint
;
71 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
72 retval
= cat_lookup(hfsmp
, &cndesc
, 0, &desc
, &attr
, &fork
, NULL
);
73 hfs_systemfile_unlock(hfsmp
, lockflags
);
76 dcp
->c_childhint
= desc
.cd_hint
;
78 * Note: We must drop the parent lock here before calling
79 * hfs_getnewvnode (which takes the child lock).
84 /* Verify that the item just looked up isn't one of the hidden directories. */
85 if (desc
.cd_cnid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
||
86 desc
.cd_cnid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) {
93 if (retval
== HFS_ERESERVEDNAME
) {
95 * We found the name in the catalog, but it is unavailable
96 * to us. The exact error to return to our caller depends
97 * on the operation, and whether we've already reached the
98 * last path component. In all cases, avoid a negative
99 * cache entry, since someone else may be able to access
100 * the name if their lookup is configured differently.
103 cnp
->cn_flags
&= ~MAKEENTRY
;
105 if (((flags
& ISLASTCN
) == 0) || ((nameiop
== LOOKUP
) || (nameiop
== DELETE
))) {
106 /* A reserved name for a pure lookup is the same as the path not being present */
109 /* A reserved name with intent to create must be rejected as impossible */
113 if (retval
!= ENOENT
)
116 * This is a non-existing entry
118 * If creating, and at end of pathname and current
119 * directory has not been removed, then can consider
120 * allowing file to be created.
122 if ((nameiop
== CREATE
|| nameiop
== RENAME
) &&
123 (flags
& ISLASTCN
) &&
124 !(ISSET(dcp
->c_flag
, C_DELETED
| C_NOEXISTS
))) {
125 retval
= EJUSTRETURN
;
132 if (flags
& ISLASTCN
) {
135 cnp
->cn_flags
&= ~MAKEENTRY
;
139 cnp
->cn_flags
&= ~MAKEENTRY
;
146 int type
= (attr
.ca_mode
& S_IFMT
);
148 if (!(flags
& ISLASTCN
) && (type
!= S_IFDIR
) && (type
!= S_IFLNK
)) {
152 /* Don't cache directory hardlink names. */
153 if (attr
.ca_recflags
& kHFSHasLinkChainMask
) {
154 cnp
->cn_flags
&= ~MAKEENTRY
;
156 /* Names with composed chars are not cached. */
157 if (cnp
->cn_namelen
!= desc
.cd_namelen
)
158 cnp
->cn_flags
&= ~MAKEENTRY
;
160 retval
= hfs_getnewvnode(hfsmp
, dvp
, cnp
, &desc
, 0, &attr
, &fork
, &tvp
, &newvnode_flags
);
164 * If this was a create/rename operation lookup, then by this point
165 * we expected to see the item returned from hfs_getnewvnode above.
166 * In the create case, it would probably eventually bubble out an EEXIST
167 * because the item existed when we were trying to create it. In the
168 * rename case, it would let us know that we need to go ahead and
169 * delete it as part of the rename. However, if we hit the condition below
170 * then it means that we found the element during cat_lookup above, but
171 * it is now no longer there. We simply behave as though we never found
172 * the element at all and return EJUSTRETURN.
174 if ((retval
== ENOENT
) &&
175 ((cnp
->cn_nameiop
== CREATE
) || (cnp
->cn_nameiop
== RENAME
)) &&
176 (flags
& ISLASTCN
)) {
177 retval
= EJUSTRETURN
;
181 * If this was a straight lookup operation, we may need to redrive the entire
182 * lookup starting from cat_lookup if the element was deleted as the result of
183 * a rename operation. Since rename is supposed to guarantee atomicity, then
184 * lookups cannot fail because the underlying element is deleted as a result of
185 * the rename call -- either they returned the looked up element prior to rename
186 * or return the newer element. If we are in this region, then all we can do is add
187 * workarounds to guarantee the latter case. The element has already been deleted, so
188 * we just re-try the lookup to ensure the caller gets the most recent element.
190 if ((retval
== ENOENT
) && (cnp
->cn_nameiop
== LOOKUP
) &&
191 (newvnode_flags
& (GNV_CHASH_RENAMED
| GNV_CAT_DELETED
))) {
195 /* get rid of any name buffers that may have lingered from the cat_lookup call */
196 cat_releasedesc (&desc
);
200 /* Also, re-drive the lookup if the item we looked up was a hardlink, and the number
201 * or name of hardlinks has changed in the interim between the cat_lookup above, and
202 * our call to hfs_getnewvnode. hfs_getnewvnode will validate the cattr we passed it
203 * against what is actually in the catalog after the cnode is created. If there were
204 * any issues, it will bubble out ERECYCLE, which we need to swallow and use as the
205 * key to redrive as well. We need to special case this below because in this case,
206 * it needs to occur regardless of the type of lookup we're doing here.
208 if ((retval
== ERECYCLE
) && (newvnode_flags
& GNV_CAT_ATTRCHANGED
)) {
212 /* get rid of any name buffers that may have lingered from the cat_lookup call */
213 cat_releasedesc (&desc
);
217 /* skip to the error-handling code if we can't retry */
222 * Save the origin info for file and directory hardlinks. Directory hardlinks
223 * need the origin for '..' lookups, and file hardlinks need it to ensure that
224 * competing lookups do not cause us to vend different hardlinks than the ones requested.
226 if (ISSET(VTOC(tvp
)->c_flag
, C_HARDLINK
))
227 hfs_savelinkorigin(VTOC(tvp
), VTOC(dvp
)->c_fileid
);
236 cat_releasedesc(&desc
);
242 hfs_vnop_lookup(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
)
245 int cnode_locked
= 0;
248 error
= hfs_lookup(dvp
, vpp
, cnp
, &cnode_locked
);
251 hfs_unlock(VTOC(*vpp
));