diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/ntfs/namei.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/ntfs/namei.c')
-rw-r--r-- | fs/ntfs/namei.c | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c new file mode 100644 index 000000000000..7c7e13b43b2e --- /dev/null +++ b/fs/ntfs/namei.c | |||
@@ -0,0 +1,498 @@ | |||
1 | /* | ||
2 | * namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS | ||
3 | * project. | ||
4 | * | ||
5 | * Copyright (c) 2001-2004 Anton Altaparmakov | ||
6 | * | ||
7 | * This program/include file is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as published | ||
9 | * by the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program/include file is distributed in the hope that it will be | ||
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty | ||
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program (in the main directory of the Linux-NTFS | ||
19 | * distribution in the file COPYING); if not, write to the Free Software | ||
20 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/dcache.h> | ||
24 | #include <linux/security.h> | ||
25 | |||
26 | #include "attrib.h" | ||
27 | #include "debug.h" | ||
28 | #include "dir.h" | ||
29 | #include "mft.h" | ||
30 | #include "ntfs.h" | ||
31 | |||
32 | /** | ||
33 | * ntfs_lookup - find the inode represented by a dentry in a directory inode | ||
34 | * @dir_ino: directory inode in which to look for the inode | ||
35 | * @dent: dentry representing the inode to look for | ||
36 | * @nd: lookup nameidata | ||
37 | * | ||
38 | * In short, ntfs_lookup() looks for the inode represented by the dentry @dent | ||
39 | * in the directory inode @dir_ino and if found attaches the inode to the | ||
40 | * dentry @dent. | ||
41 | * | ||
42 | * In more detail, the dentry @dent specifies which inode to look for by | ||
43 | * supplying the name of the inode in @dent->d_name.name. ntfs_lookup() | ||
44 | * converts the name to Unicode and walks the contents of the directory inode | ||
45 | * @dir_ino looking for the converted Unicode name. If the name is found in the | ||
46 | * directory, the corresponding inode is loaded by calling ntfs_iget() on its | ||
47 | * inode number and the inode is associated with the dentry @dent via a call to | ||
48 | * d_splice_alias(). | ||
49 | * | ||
50 | * If the name is not found in the directory, a NULL inode is inserted into the | ||
51 | * dentry @dent via a call to d_add(). The dentry is then termed a negative | ||
52 | * dentry. | ||
53 | * | ||
54 | * Only if an actual error occurs, do we return an error via ERR_PTR(). | ||
55 | * | ||
56 | * In order to handle the case insensitivity issues of NTFS with regards to the | ||
57 | * dcache and the dcache requiring only one dentry per directory, we deal with | ||
58 | * dentry aliases that only differ in case in ->ntfs_lookup() while maintaining | ||
59 | * a case sensitive dcache. This means that we get the full benefit of dcache | ||
60 | * speed when the file/directory is looked up with the same case as returned by | ||
61 | * ->ntfs_readdir() but that a lookup for any other case (or for the short file | ||
62 | * name) will not find anything in dcache and will enter ->ntfs_lookup() | ||
63 | * instead, where we search the directory for a fully matching file name | ||
64 | * (including case) and if that is not found, we search for a file name that | ||
65 | * matches with different case and if that has non-POSIX semantics we return | ||
66 | * that. We actually do only one search (case sensitive) and keep tabs on | ||
67 | * whether we have found a case insensitive match in the process. | ||
68 | * | ||
69 | * To simplify matters for us, we do not treat the short vs long filenames as | ||
70 | * two hard links but instead if the lookup matches a short filename, we | ||
71 | * return the dentry for the corresponding long filename instead. | ||
72 | * | ||
73 | * There are three cases we need to distinguish here: | ||
74 | * | ||
75 | * 1) @dent perfectly matches (i.e. including case) a directory entry with a | ||
76 | * file name in the WIN32 or POSIX namespaces. In this case | ||
77 | * ntfs_lookup_inode_by_name() will return with name set to NULL and we | ||
78 | * just d_splice_alias() @dent. | ||
79 | * 2) @dent matches (not including case) a directory entry with a file name in | ||
80 | * the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return | ||
81 | * with name set to point to a kmalloc()ed ntfs_name structure containing | ||
82 | * the properly cased little endian Unicode name. We convert the name to the | ||
83 | * current NLS code page, search if a dentry with this name already exists | ||
84 | * and if so return that instead of @dent. At this point things are | ||
85 | * complicated by the possibility of 'disconnected' dentries due to NFS | ||
86 | * which we deal with appropriately (see the code comments). The VFS will | ||
87 | * then destroy the old @dent and use the one we returned. If a dentry is | ||
88 | * not found, we allocate a new one, d_splice_alias() it, and return it as | ||
89 | * above. | ||
90 | * 3) @dent matches either perfectly or not (i.e. we don't care about case) a | ||
91 | * directory entry with a file name in the DOS namespace. In this case | ||
92 | * ntfs_lookup_inode_by_name() will return with name set to point to a | ||
93 | * kmalloc()ed ntfs_name structure containing the mft reference (cpu endian) | ||
94 | * of the inode. We use the mft reference to read the inode and to find the | ||
95 | * file name in the WIN32 namespace corresponding to the matched short file | ||
96 | * name. We then convert the name to the current NLS code page, and proceed | ||
97 | * searching for a dentry with this name, etc, as in case 2), above. | ||
98 | * | ||
99 | * Locking: Caller must hold i_sem on the directory. | ||
100 | */ | ||
101 | static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, | ||
102 | struct nameidata *nd) | ||
103 | { | ||
104 | ntfs_volume *vol = NTFS_SB(dir_ino->i_sb); | ||
105 | struct inode *dent_inode; | ||
106 | ntfschar *uname; | ||
107 | ntfs_name *name = NULL; | ||
108 | MFT_REF mref; | ||
109 | unsigned long dent_ino; | ||
110 | int uname_len; | ||
111 | |||
112 | ntfs_debug("Looking up %s in directory inode 0x%lx.", | ||
113 | dent->d_name.name, dir_ino->i_ino); | ||
114 | /* Convert the name of the dentry to Unicode. */ | ||
115 | uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len, | ||
116 | &uname); | ||
117 | if (uname_len < 0) { | ||
118 | ntfs_error(vol->sb, "Failed to convert name to Unicode."); | ||
119 | return ERR_PTR(uname_len); | ||
120 | } | ||
121 | mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len, | ||
122 | &name); | ||
123 | kmem_cache_free(ntfs_name_cache, uname); | ||
124 | if (!IS_ERR_MREF(mref)) { | ||
125 | dent_ino = MREF(mref); | ||
126 | ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino); | ||
127 | dent_inode = ntfs_iget(vol->sb, dent_ino); | ||
128 | if (likely(!IS_ERR(dent_inode))) { | ||
129 | /* Consistency check. */ | ||
130 | if (is_bad_inode(dent_inode) || MSEQNO(mref) == | ||
131 | NTFS_I(dent_inode)->seq_no || | ||
132 | dent_ino == FILE_MFT) { | ||
133 | /* Perfect WIN32/POSIX match. -- Case 1. */ | ||
134 | if (!name) { | ||
135 | ntfs_debug("Done. (Case 1.)"); | ||
136 | return d_splice_alias(dent_inode, dent); | ||
137 | } | ||
138 | /* | ||
139 | * We are too indented. Handle imperfect | ||
140 | * matches and short file names further below. | ||
141 | */ | ||
142 | goto handle_name; | ||
143 | } | ||
144 | ntfs_error(vol->sb, "Found stale reference to inode " | ||
145 | "0x%lx (reference sequence number = " | ||
146 | "0x%x, inode sequence number = 0x%x), " | ||
147 | "returning -EIO. Run chkdsk.", | ||
148 | dent_ino, MSEQNO(mref), | ||
149 | NTFS_I(dent_inode)->seq_no); | ||
150 | iput(dent_inode); | ||
151 | dent_inode = ERR_PTR(-EIO); | ||
152 | } else | ||
153 | ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with " | ||
154 | "error code %li.", dent_ino, | ||
155 | PTR_ERR(dent_inode)); | ||
156 | if (name) | ||
157 | kfree(name); | ||
158 | /* Return the error code. */ | ||
159 | return (struct dentry *)dent_inode; | ||
160 | } | ||
161 | /* It is guaranteed that name is no longer allocated at this point. */ | ||
162 | if (MREF_ERR(mref) == -ENOENT) { | ||
163 | ntfs_debug("Entry was not found, adding negative dentry."); | ||
164 | /* The dcache will handle negative entries. */ | ||
165 | d_add(dent, NULL); | ||
166 | ntfs_debug("Done."); | ||
167 | return NULL; | ||
168 | } | ||
169 | ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error " | ||
170 | "code %i.", -MREF_ERR(mref)); | ||
171 | return ERR_PTR(MREF_ERR(mref)); | ||
172 | |||
173 | // TODO: Consider moving this lot to a separate function! (AIA) | ||
174 | handle_name: | ||
175 | { | ||
176 | struct dentry *real_dent, *new_dent; | ||
177 | MFT_RECORD *m; | ||
178 | ntfs_attr_search_ctx *ctx; | ||
179 | ntfs_inode *ni = NTFS_I(dent_inode); | ||
180 | int err; | ||
181 | struct qstr nls_name; | ||
182 | |||
183 | nls_name.name = NULL; | ||
184 | if (name->type != FILE_NAME_DOS) { /* Case 2. */ | ||
185 | ntfs_debug("Case 2."); | ||
186 | nls_name.len = (unsigned)ntfs_ucstonls(vol, | ||
187 | (ntfschar*)&name->name, name->len, | ||
188 | (unsigned char**)&nls_name.name, 0); | ||
189 | kfree(name); | ||
190 | } else /* if (name->type == FILE_NAME_DOS) */ { /* Case 3. */ | ||
191 | FILE_NAME_ATTR *fn; | ||
192 | |||
193 | ntfs_debug("Case 3."); | ||
194 | kfree(name); | ||
195 | |||
196 | /* Find the WIN32 name corresponding to the matched DOS name. */ | ||
197 | ni = NTFS_I(dent_inode); | ||
198 | m = map_mft_record(ni); | ||
199 | if (IS_ERR(m)) { | ||
200 | err = PTR_ERR(m); | ||
201 | m = NULL; | ||
202 | ctx = NULL; | ||
203 | goto err_out; | ||
204 | } | ||
205 | ctx = ntfs_attr_get_search_ctx(ni, m); | ||
206 | if (unlikely(!ctx)) { | ||
207 | err = -ENOMEM; | ||
208 | goto err_out; | ||
209 | } | ||
210 | do { | ||
211 | ATTR_RECORD *a; | ||
212 | u32 val_len; | ||
213 | |||
214 | err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, | ||
215 | NULL, 0, ctx); | ||
216 | if (unlikely(err)) { | ||
217 | ntfs_error(vol->sb, "Inode corrupt: No WIN32 " | ||
218 | "namespace counterpart to DOS " | ||
219 | "file name. Run chkdsk."); | ||
220 | if (err == -ENOENT) | ||
221 | err = -EIO; | ||
222 | goto err_out; | ||
223 | } | ||
224 | /* Consistency checks. */ | ||
225 | a = ctx->attr; | ||
226 | if (a->non_resident || a->flags) | ||
227 | goto eio_err_out; | ||
228 | val_len = le32_to_cpu(a->data.resident.value_length); | ||
229 | if (le16_to_cpu(a->data.resident.value_offset) + | ||
230 | val_len > le32_to_cpu(a->length)) | ||
231 | goto eio_err_out; | ||
232 | fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu( | ||
233 | ctx->attr->data.resident.value_offset)); | ||
234 | if ((u32)(fn->file_name_length * sizeof(ntfschar) + | ||
235 | sizeof(FILE_NAME_ATTR)) > val_len) | ||
236 | goto eio_err_out; | ||
237 | } while (fn->file_name_type != FILE_NAME_WIN32); | ||
238 | |||
239 | /* Convert the found WIN32 name to current NLS code page. */ | ||
240 | nls_name.len = (unsigned)ntfs_ucstonls(vol, | ||
241 | (ntfschar*)&fn->file_name, fn->file_name_length, | ||
242 | (unsigned char**)&nls_name.name, 0); | ||
243 | |||
244 | ntfs_attr_put_search_ctx(ctx); | ||
245 | unmap_mft_record(ni); | ||
246 | } | ||
247 | m = NULL; | ||
248 | ctx = NULL; | ||
249 | |||
250 | /* Check if a conversion error occurred. */ | ||
251 | if ((signed)nls_name.len < 0) { | ||
252 | err = (signed)nls_name.len; | ||
253 | goto err_out; | ||
254 | } | ||
255 | nls_name.hash = full_name_hash(nls_name.name, nls_name.len); | ||
256 | |||
257 | /* | ||
258 | * Note: No need for dent->d_lock lock as i_sem is held on the | ||
259 | * parent inode. | ||
260 | */ | ||
261 | |||
262 | /* Does a dentry matching the nls_name exist already? */ | ||
263 | real_dent = d_lookup(dent->d_parent, &nls_name); | ||
264 | /* If not, create it now. */ | ||
265 | if (!real_dent) { | ||
266 | real_dent = d_alloc(dent->d_parent, &nls_name); | ||
267 | kfree(nls_name.name); | ||
268 | if (!real_dent) { | ||
269 | err = -ENOMEM; | ||
270 | goto err_out; | ||
271 | } | ||
272 | new_dent = d_splice_alias(dent_inode, real_dent); | ||
273 | if (new_dent) | ||
274 | dput(real_dent); | ||
275 | else | ||
276 | new_dent = real_dent; | ||
277 | ntfs_debug("Done. (Created new dentry.)"); | ||
278 | return new_dent; | ||
279 | } | ||
280 | kfree(nls_name.name); | ||
281 | /* Matching dentry exists, check if it is negative. */ | ||
282 | if (real_dent->d_inode) { | ||
283 | if (unlikely(real_dent->d_inode != dent_inode)) { | ||
284 | /* This can happen because bad inodes are unhashed. */ | ||
285 | BUG_ON(!is_bad_inode(dent_inode)); | ||
286 | BUG_ON(!is_bad_inode(real_dent->d_inode)); | ||
287 | } | ||
288 | /* | ||
289 | * Already have the inode and the dentry attached, decrement | ||
290 | * the reference count to balance the ntfs_iget() we did | ||
291 | * earlier on. We found the dentry using d_lookup() so it | ||
292 | * cannot be disconnected and thus we do not need to worry | ||
293 | * about any NFS/disconnectedness issues here. | ||
294 | */ | ||
295 | iput(dent_inode); | ||
296 | ntfs_debug("Done. (Already had inode and dentry.)"); | ||
297 | return real_dent; | ||
298 | } | ||
299 | /* | ||
300 | * Negative dentry: instantiate it unless the inode is a directory and | ||
301 | * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED), | ||
302 | * in which case d_move() that in place of the found dentry. | ||
303 | */ | ||
304 | if (!S_ISDIR(dent_inode->i_mode)) { | ||
305 | /* Not a directory; everything is easy. */ | ||
306 | d_instantiate(real_dent, dent_inode); | ||
307 | ntfs_debug("Done. (Already had negative file dentry.)"); | ||
308 | return real_dent; | ||
309 | } | ||
310 | spin_lock(&dcache_lock); | ||
311 | if (list_empty(&dent_inode->i_dentry)) { | ||
312 | /* | ||
313 | * Directory without a 'disconnected' dentry; we need to do | ||
314 | * d_instantiate() by hand because it takes dcache_lock which | ||
315 | * we already hold. | ||
316 | */ | ||
317 | list_add(&real_dent->d_alias, &dent_inode->i_dentry); | ||
318 | real_dent->d_inode = dent_inode; | ||
319 | spin_unlock(&dcache_lock); | ||
320 | security_d_instantiate(real_dent, dent_inode); | ||
321 | ntfs_debug("Done. (Already had negative directory dentry.)"); | ||
322 | return real_dent; | ||
323 | } | ||
324 | /* | ||
325 | * Directory with a 'disconnected' dentry; get a reference to the | ||
326 | * 'disconnected' dentry. | ||
327 | */ | ||
328 | new_dent = list_entry(dent_inode->i_dentry.next, struct dentry, | ||
329 | d_alias); | ||
330 | dget_locked(new_dent); | ||
331 | spin_unlock(&dcache_lock); | ||
332 | /* Do security vodoo. */ | ||
333 | security_d_instantiate(real_dent, dent_inode); | ||
334 | /* Move new_dent in place of real_dent. */ | ||
335 | d_move(new_dent, real_dent); | ||
336 | /* Balance the ntfs_iget() we did above. */ | ||
337 | iput(dent_inode); | ||
338 | /* Throw away real_dent. */ | ||
339 | dput(real_dent); | ||
340 | /* Use new_dent as the actual dentry. */ | ||
341 | ntfs_debug("Done. (Already had negative, disconnected directory " | ||
342 | "dentry.)"); | ||
343 | return new_dent; | ||
344 | |||
345 | eio_err_out: | ||
346 | ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk."); | ||
347 | err = -EIO; | ||
348 | err_out: | ||
349 | if (ctx) | ||
350 | ntfs_attr_put_search_ctx(ctx); | ||
351 | if (m) | ||
352 | unmap_mft_record(ni); | ||
353 | iput(dent_inode); | ||
354 | ntfs_error(vol->sb, "Failed, returning error code %i.", err); | ||
355 | return ERR_PTR(err); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | /** | ||
360 | * Inode operations for directories. | ||
361 | */ | ||
362 | struct inode_operations ntfs_dir_inode_ops = { | ||
363 | .lookup = ntfs_lookup, /* VFS: Lookup directory. */ | ||
364 | }; | ||
365 | |||
366 | /** | ||
367 | * ntfs_get_parent - find the dentry of the parent of a given directory dentry | ||
368 | * @child_dent: dentry of the directory whose parent directory to find | ||
369 | * | ||
370 | * Find the dentry for the parent directory of the directory specified by the | ||
371 | * dentry @child_dent. This function is called from | ||
372 | * fs/exportfs/expfs.c::find_exported_dentry() which in turn is called from the | ||
373 | * default ->decode_fh() which is export_decode_fh() in the same file. | ||
374 | * | ||
375 | * The code is based on the ext3 ->get_parent() implementation found in | ||
376 | * fs/ext3/namei.c::ext3_get_parent(). | ||
377 | * | ||
378 | * Note: ntfs_get_parent() is called with @child_dent->d_inode->i_sem down. | ||
379 | * | ||
380 | * Return the dentry of the parent directory on success or the error code on | ||
381 | * error (IS_ERR() is true). | ||
382 | */ | ||
383 | struct dentry *ntfs_get_parent(struct dentry *child_dent) | ||
384 | { | ||
385 | struct inode *vi = child_dent->d_inode; | ||
386 | ntfs_inode *ni = NTFS_I(vi); | ||
387 | MFT_RECORD *mrec; | ||
388 | ntfs_attr_search_ctx *ctx; | ||
389 | ATTR_RECORD *attr; | ||
390 | FILE_NAME_ATTR *fn; | ||
391 | struct inode *parent_vi; | ||
392 | struct dentry *parent_dent; | ||
393 | unsigned long parent_ino; | ||
394 | int err; | ||
395 | |||
396 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); | ||
397 | /* Get the mft record of the inode belonging to the child dentry. */ | ||
398 | mrec = map_mft_record(ni); | ||
399 | if (IS_ERR(mrec)) | ||
400 | return (struct dentry *)mrec; | ||
401 | /* Find the first file name attribute in the mft record. */ | ||
402 | ctx = ntfs_attr_get_search_ctx(ni, mrec); | ||
403 | if (unlikely(!ctx)) { | ||
404 | unmap_mft_record(ni); | ||
405 | return ERR_PTR(-ENOMEM); | ||
406 | } | ||
407 | try_next: | ||
408 | err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL, | ||
409 | 0, ctx); | ||
410 | if (unlikely(err)) { | ||
411 | ntfs_attr_put_search_ctx(ctx); | ||
412 | unmap_mft_record(ni); | ||
413 | if (err == -ENOENT) | ||
414 | ntfs_error(vi->i_sb, "Inode 0x%lx does not have a " | ||
415 | "file name attribute. Run chkdsk.", | ||
416 | vi->i_ino); | ||
417 | return ERR_PTR(err); | ||
418 | } | ||
419 | attr = ctx->attr; | ||
420 | if (unlikely(attr->non_resident)) | ||
421 | goto try_next; | ||
422 | fn = (FILE_NAME_ATTR *)((u8 *)attr + | ||
423 | le16_to_cpu(attr->data.resident.value_offset)); | ||
424 | if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) > | ||
425 | (u8*)attr + le32_to_cpu(attr->length))) | ||
426 | goto try_next; | ||
427 | /* Get the inode number of the parent directory. */ | ||
428 | parent_ino = MREF_LE(fn->parent_directory); | ||
429 | /* Release the search context and the mft record of the child. */ | ||
430 | ntfs_attr_put_search_ctx(ctx); | ||
431 | unmap_mft_record(ni); | ||
432 | /* Get the inode of the parent directory. */ | ||
433 | parent_vi = ntfs_iget(vi->i_sb, parent_ino); | ||
434 | if (IS_ERR(parent_vi) || unlikely(is_bad_inode(parent_vi))) { | ||
435 | if (!IS_ERR(parent_vi)) | ||
436 | iput(parent_vi); | ||
437 | ntfs_error(vi->i_sb, "Failed to get parent directory inode " | ||
438 | "0x%lx of child inode 0x%lx.", parent_ino, | ||
439 | vi->i_ino); | ||
440 | return ERR_PTR(-EACCES); | ||
441 | } | ||
442 | /* Finally get a dentry for the parent directory and return it. */ | ||
443 | parent_dent = d_alloc_anon(parent_vi); | ||
444 | if (unlikely(!parent_dent)) { | ||
445 | iput(parent_vi); | ||
446 | return ERR_PTR(-ENOMEM); | ||
447 | } | ||
448 | ntfs_debug("Done for inode 0x%lx.", vi->i_ino); | ||
449 | return parent_dent; | ||
450 | } | ||
451 | |||
452 | /** | ||
453 | * ntfs_get_dentry - find a dentry for the inode from a file handle sub-fragment | ||
454 | * @sb: super block identifying the mounted ntfs volume | ||
455 | * @fh: the file handle sub-fragment | ||
456 | * | ||
457 | * Find a dentry for the inode given a file handle sub-fragment. This function | ||
458 | * is called from fs/exportfs/expfs.c::find_exported_dentry() which in turn is | ||
459 | * called from the default ->decode_fh() which is export_decode_fh() in the | ||
460 | * same file. The code is closely based on the default ->get_dentry() helper | ||
461 | * fs/exportfs/expfs.c::get_object(). | ||
462 | * | ||
463 | * The @fh contains two 32-bit unsigned values, the first one is the inode | ||
464 | * number and the second one is the inode generation. | ||
465 | * | ||
466 | * Return the dentry on success or the error code on error (IS_ERR() is true). | ||
467 | */ | ||
468 | struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh) | ||
469 | { | ||
470 | struct inode *vi; | ||
471 | struct dentry *dent; | ||
472 | unsigned long ino = ((u32 *)fh)[0]; | ||
473 | u32 gen = ((u32 *)fh)[1]; | ||
474 | |||
475 | ntfs_debug("Entering for inode 0x%lx, generation 0x%x.", ino, gen); | ||
476 | vi = ntfs_iget(sb, ino); | ||
477 | if (IS_ERR(vi)) { | ||
478 | ntfs_error(sb, "Failed to get inode 0x%lx.", ino); | ||
479 | return (struct dentry *)vi; | ||
480 | } | ||
481 | if (unlikely(is_bad_inode(vi) || vi->i_generation != gen)) { | ||
482 | /* We didn't find the right inode. */ | ||
483 | ntfs_error(sb, "Inode 0x%lx, bad count: %d %d or version 0x%x " | ||
484 | "0x%x.", vi->i_ino, vi->i_nlink, | ||
485 | atomic_read(&vi->i_count), vi->i_generation, | ||
486 | gen); | ||
487 | iput(vi); | ||
488 | return ERR_PTR(-ESTALE); | ||
489 | } | ||
490 | /* Now find a dentry. If possible, get a well-connected one. */ | ||
491 | dent = d_alloc_anon(vi); | ||
492 | if (unlikely(!dent)) { | ||
493 | iput(vi); | ||
494 | return ERR_PTR(-ENOMEM); | ||
495 | } | ||
496 | ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen); | ||
497 | return dent; | ||
498 | } | ||