1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project. |
4 | * |
5 | * Copyright (c) 2001-2007 Anton Altaparmakov |
6 | * Copyright (c) 2002 Richard Russon |
7 | */ |
8 | |
9 | #include <linux/buffer_head.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/blkdev.h> |
12 | |
13 | #include "dir.h" |
14 | #include "aops.h" |
15 | #include "attrib.h" |
16 | #include "mft.h" |
17 | #include "debug.h" |
18 | #include "ntfs.h" |
19 | |
20 | /* |
21 | * The little endian Unicode string $I30 as a global constant. |
22 | */ |
23 | ntfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'), |
24 | cpu_to_le16('3'), cpu_to_le16('0'), 0 }; |
25 | |
26 | /** |
27 | * ntfs_lookup_inode_by_name - find an inode in a directory given its name |
28 | * @dir_ni: ntfs inode of the directory in which to search for the name |
29 | * @uname: Unicode name for which to search in the directory |
30 | * @uname_len: length of the name @uname in Unicode characters |
31 | * @res: return the found file name if necessary (see below) |
32 | * |
33 | * Look for an inode with name @uname in the directory with inode @dir_ni. |
34 | * ntfs_lookup_inode_by_name() walks the contents of the directory looking for |
35 | * the Unicode name. If the name is found in the directory, the corresponding |
36 | * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it |
37 | * is a 64-bit number containing the sequence number. |
38 | * |
39 | * On error, a negative value is returned corresponding to the error code. In |
40 | * particular if the inode is not found -ENOENT is returned. Note that you |
41 | * can't just check the return value for being negative, you have to check the |
42 | * inode number for being negative which you can extract using MREC(return |
43 | * value). |
44 | * |
45 | * Note, @uname_len does not include the (optional) terminating NULL character. |
46 | * |
47 | * Note, we look for a case sensitive match first but we also look for a case |
48 | * insensitive match at the same time. If we find a case insensitive match, we |
49 | * save that for the case that we don't find an exact match, where we return |
50 | * the case insensitive match and setup @res (which we allocate!) with the mft |
51 | * reference, the file name type, length and with a copy of the little endian |
52 | * Unicode file name itself. If we match a file name which is in the DOS name |
53 | * space, we only return the mft reference and file name type in @res. |
54 | * ntfs_lookup() then uses this to find the long file name in the inode itself. |
55 | * This is to avoid polluting the dcache with short file names. We want them to |
56 | * work but we don't care for how quickly one can access them. This also fixes |
57 | * the dcache aliasing issues. |
58 | * |
59 | * Locking: - Caller must hold i_mutex on the directory. |
60 | * - Each page cache page in the index allocation mapping must be |
61 | * locked whilst being accessed otherwise we may find a corrupt |
62 | * page due to it being under ->writepage at the moment which |
63 | * applies the mst protection fixups before writing out and then |
64 | * removes them again after the write is complete after which it |
65 | * unlocks the page. |
66 | */ |
67 | MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname, |
68 | const int uname_len, ntfs_name **res) |
69 | { |
70 | ntfs_volume *vol = dir_ni->vol; |
71 | struct super_block *sb = vol->sb; |
72 | MFT_RECORD *m; |
73 | INDEX_ROOT *ir; |
74 | INDEX_ENTRY *ie; |
75 | INDEX_ALLOCATION *ia; |
76 | u8 *index_end; |
77 | u64 mref; |
78 | ntfs_attr_search_ctx *ctx; |
79 | int err, rc; |
80 | VCN vcn, old_vcn; |
81 | struct address_space *ia_mapping; |
82 | struct page *page; |
83 | u8 *kaddr; |
84 | ntfs_name *name = NULL; |
85 | |
86 | BUG_ON(!S_ISDIR(VFS_I(dir_ni)->i_mode)); |
87 | BUG_ON(NInoAttr(dir_ni)); |
88 | /* Get hold of the mft record for the directory. */ |
89 | m = map_mft_record(ni: dir_ni); |
90 | if (IS_ERR(ptr: m)) { |
91 | ntfs_error(sb, "map_mft_record() failed with error code %ld." , |
92 | -PTR_ERR(m)); |
93 | return ERR_MREF(PTR_ERR(m)); |
94 | } |
95 | ctx = ntfs_attr_get_search_ctx(ni: dir_ni, mrec: m); |
96 | if (unlikely(!ctx)) { |
97 | err = -ENOMEM; |
98 | goto err_out; |
99 | } |
100 | /* Find the index root attribute in the mft record. */ |
101 | err = ntfs_attr_lookup(type: AT_INDEX_ROOT, name: I30, name_len: 4, ic: CASE_SENSITIVE, lowest_vcn: 0, NULL, |
102 | val_len: 0, ctx); |
103 | if (unlikely(err)) { |
104 | if (err == -ENOENT) { |
105 | ntfs_error(sb, "Index root attribute missing in " |
106 | "directory inode 0x%lx." , |
107 | dir_ni->mft_no); |
108 | err = -EIO; |
109 | } |
110 | goto err_out; |
111 | } |
112 | /* Get to the index root value (it's been verified in read_inode). */ |
113 | ir = (INDEX_ROOT*)((u8*)ctx->attr + |
114 | le16_to_cpu(ctx->attr->data.resident.value_offset)); |
115 | index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); |
116 | /* The first index entry. */ |
117 | ie = (INDEX_ENTRY*)((u8*)&ir->index + |
118 | le32_to_cpu(ir->index.entries_offset)); |
119 | /* |
120 | * Loop until we exceed valid memory (corruption case) or until we |
121 | * reach the last entry. |
122 | */ |
123 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
124 | /* Bounds checks. */ |
125 | if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + |
126 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
127 | (u8*)ie + le16_to_cpu(ie->key_length) > |
128 | index_end) |
129 | goto dir_err_out; |
130 | /* |
131 | * The last entry cannot contain a name. It can however contain |
132 | * a pointer to a child node in the B+tree so we just break out. |
133 | */ |
134 | if (ie->flags & INDEX_ENTRY_END) |
135 | break; |
136 | /* |
137 | * We perform a case sensitive comparison and if that matches |
138 | * we are done and return the mft reference of the inode (i.e. |
139 | * the inode number together with the sequence number for |
140 | * consistency checking). We convert it to cpu format before |
141 | * returning. |
142 | */ |
143 | if (ntfs_are_names_equal(s1: uname, s1_len: uname_len, |
144 | s2: (ntfschar*)&ie->key.file_name.file_name, |
145 | s2_len: ie->key.file_name.file_name_length, |
146 | ic: CASE_SENSITIVE, upcase: vol->upcase, upcase_size: vol->upcase_len)) { |
147 | found_it: |
148 | /* |
149 | * We have a perfect match, so we don't need to care |
150 | * about having matched imperfectly before, so we can |
151 | * free name and set *res to NULL. |
152 | * However, if the perfect match is a short file name, |
153 | * we need to signal this through *res, so that |
154 | * ntfs_lookup() can fix dcache aliasing issues. |
155 | * As an optimization we just reuse an existing |
156 | * allocation of *res. |
157 | */ |
158 | if (ie->key.file_name.file_name_type == FILE_NAME_DOS) { |
159 | if (!name) { |
160 | name = kmalloc(size: sizeof(ntfs_name), |
161 | GFP_NOFS); |
162 | if (!name) { |
163 | err = -ENOMEM; |
164 | goto err_out; |
165 | } |
166 | } |
167 | name->mref = le64_to_cpu( |
168 | ie->data.dir.indexed_file); |
169 | name->type = FILE_NAME_DOS; |
170 | name->len = 0; |
171 | *res = name; |
172 | } else { |
173 | kfree(objp: name); |
174 | *res = NULL; |
175 | } |
176 | mref = le64_to_cpu(ie->data.dir.indexed_file); |
177 | ntfs_attr_put_search_ctx(ctx); |
178 | unmap_mft_record(ni: dir_ni); |
179 | return mref; |
180 | } |
181 | /* |
182 | * For a case insensitive mount, we also perform a case |
183 | * insensitive comparison (provided the file name is not in the |
184 | * POSIX namespace). If the comparison matches, and the name is |
185 | * in the WIN32 namespace, we cache the filename in *res so |
186 | * that the caller, ntfs_lookup(), can work on it. If the |
187 | * comparison matches, and the name is in the DOS namespace, we |
188 | * only cache the mft reference and the file name type (we set |
189 | * the name length to zero for simplicity). |
190 | */ |
191 | if (!NVolCaseSensitive(vol) && |
192 | ie->key.file_name.file_name_type && |
193 | ntfs_are_names_equal(s1: uname, s1_len: uname_len, |
194 | s2: (ntfschar*)&ie->key.file_name.file_name, |
195 | s2_len: ie->key.file_name.file_name_length, |
196 | ic: IGNORE_CASE, upcase: vol->upcase, upcase_size: vol->upcase_len)) { |
197 | int name_size = sizeof(ntfs_name); |
198 | u8 type = ie->key.file_name.file_name_type; |
199 | u8 len = ie->key.file_name.file_name_length; |
200 | |
201 | /* Only one case insensitive matching name allowed. */ |
202 | if (name) { |
203 | ntfs_error(sb, "Found already allocated name " |
204 | "in phase 1. Please run chkdsk " |
205 | "and if that doesn't find any " |
206 | "errors please report you saw " |
207 | "this message to " |
208 | "linux-ntfs-dev@lists." |
209 | "sourceforge.net." ); |
210 | goto dir_err_out; |
211 | } |
212 | |
213 | if (type != FILE_NAME_DOS) |
214 | name_size += len * sizeof(ntfschar); |
215 | name = kmalloc(size: name_size, GFP_NOFS); |
216 | if (!name) { |
217 | err = -ENOMEM; |
218 | goto err_out; |
219 | } |
220 | name->mref = le64_to_cpu(ie->data.dir.indexed_file); |
221 | name->type = type; |
222 | if (type != FILE_NAME_DOS) { |
223 | name->len = len; |
224 | memcpy(name->name, ie->key.file_name.file_name, |
225 | len * sizeof(ntfschar)); |
226 | } else |
227 | name->len = 0; |
228 | *res = name; |
229 | } |
230 | /* |
231 | * Not a perfect match, need to do full blown collation so we |
232 | * know which way in the B+tree we have to go. |
233 | */ |
234 | rc = ntfs_collate_names(name1: uname, name1_len: uname_len, |
235 | name2: (ntfschar*)&ie->key.file_name.file_name, |
236 | name2_len: ie->key.file_name.file_name_length, err_val: 1, |
237 | ic: IGNORE_CASE, upcase: vol->upcase, upcase_len: vol->upcase_len); |
238 | /* |
239 | * If uname collates before the name of the current entry, there |
240 | * is definitely no such name in this index but we might need to |
241 | * descend into the B+tree so we just break out of the loop. |
242 | */ |
243 | if (rc == -1) |
244 | break; |
245 | /* The names are not equal, continue the search. */ |
246 | if (rc) |
247 | continue; |
248 | /* |
249 | * Names match with case insensitive comparison, now try the |
250 | * case sensitive comparison, which is required for proper |
251 | * collation. |
252 | */ |
253 | rc = ntfs_collate_names(name1: uname, name1_len: uname_len, |
254 | name2: (ntfschar*)&ie->key.file_name.file_name, |
255 | name2_len: ie->key.file_name.file_name_length, err_val: 1, |
256 | ic: CASE_SENSITIVE, upcase: vol->upcase, upcase_len: vol->upcase_len); |
257 | if (rc == -1) |
258 | break; |
259 | if (rc) |
260 | continue; |
261 | /* |
262 | * Perfect match, this will never happen as the |
263 | * ntfs_are_names_equal() call will have gotten a match but we |
264 | * still treat it correctly. |
265 | */ |
266 | goto found_it; |
267 | } |
268 | /* |
269 | * We have finished with this index without success. Check for the |
270 | * presence of a child node and if not present return -ENOENT, unless |
271 | * we have got a matching name cached in name in which case return the |
272 | * mft reference associated with it. |
273 | */ |
274 | if (!(ie->flags & INDEX_ENTRY_NODE)) { |
275 | if (name) { |
276 | ntfs_attr_put_search_ctx(ctx); |
277 | unmap_mft_record(ni: dir_ni); |
278 | return name->mref; |
279 | } |
280 | ntfs_debug("Entry not found." ); |
281 | err = -ENOENT; |
282 | goto err_out; |
283 | } /* Child node present, descend into it. */ |
284 | /* Consistency check: Verify that an index allocation exists. */ |
285 | if (!NInoIndexAllocPresent(ni: dir_ni)) { |
286 | ntfs_error(sb, "No index allocation attribute but index entry " |
287 | "requires one. Directory inode 0x%lx is " |
288 | "corrupt or driver bug." , dir_ni->mft_no); |
289 | goto err_out; |
290 | } |
291 | /* Get the starting vcn of the index_block holding the child node. */ |
292 | vcn = sle64_to_cpup(x: (sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8)); |
293 | ia_mapping = VFS_I(ni: dir_ni)->i_mapping; |
294 | /* |
295 | * We are done with the index root and the mft record. Release them, |
296 | * otherwise we deadlock with ntfs_map_page(). |
297 | */ |
298 | ntfs_attr_put_search_ctx(ctx); |
299 | unmap_mft_record(ni: dir_ni); |
300 | m = NULL; |
301 | ctx = NULL; |
302 | descend_into_child_node: |
303 | /* |
304 | * Convert vcn to index into the index allocation attribute in units |
305 | * of PAGE_SIZE and map the page cache page, reading it from |
306 | * disk if necessary. |
307 | */ |
308 | page = ntfs_map_page(mapping: ia_mapping, index: vcn << |
309 | dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT); |
310 | if (IS_ERR(ptr: page)) { |
311 | ntfs_error(sb, "Failed to map directory index page, error %ld." , |
312 | -PTR_ERR(page)); |
313 | err = PTR_ERR(ptr: page); |
314 | goto err_out; |
315 | } |
316 | lock_page(page); |
317 | kaddr = (u8*)page_address(page); |
318 | fast_descend_into_child_node: |
319 | /* Get to the index allocation block. */ |
320 | ia = (INDEX_ALLOCATION*)(kaddr + ((vcn << |
321 | dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK)); |
322 | /* Bounds checks. */ |
323 | if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) { |
324 | ntfs_error(sb, "Out of bounds check failed. Corrupt directory " |
325 | "inode 0x%lx or driver bug." , dir_ni->mft_no); |
326 | goto unm_err_out; |
327 | } |
328 | /* Catch multi sector transfer fixup errors. */ |
329 | if (unlikely(!ntfs_is_indx_record(ia->magic))) { |
330 | ntfs_error(sb, "Directory index record with vcn 0x%llx is " |
331 | "corrupt. Corrupt inode 0x%lx. Run chkdsk." , |
332 | (unsigned long long)vcn, dir_ni->mft_no); |
333 | goto unm_err_out; |
334 | } |
335 | if (sle64_to_cpu(x: ia->index_block_vcn) != vcn) { |
336 | ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is " |
337 | "different from expected VCN (0x%llx). " |
338 | "Directory inode 0x%lx is corrupt or driver " |
339 | "bug." , (unsigned long long) |
340 | sle64_to_cpu(ia->index_block_vcn), |
341 | (unsigned long long)vcn, dir_ni->mft_no); |
342 | goto unm_err_out; |
343 | } |
344 | if (le32_to_cpu(ia->index.allocated_size) + 0x18 != |
345 | dir_ni->itype.index.block_size) { |
346 | ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode " |
347 | "0x%lx has a size (%u) differing from the " |
348 | "directory specified size (%u). Directory " |
349 | "inode is corrupt or driver bug." , |
350 | (unsigned long long)vcn, dir_ni->mft_no, |
351 | le32_to_cpu(ia->index.allocated_size) + 0x18, |
352 | dir_ni->itype.index.block_size); |
353 | goto unm_err_out; |
354 | } |
355 | index_end = (u8*)ia + dir_ni->itype.index.block_size; |
356 | if (index_end > kaddr + PAGE_SIZE) { |
357 | ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode " |
358 | "0x%lx crosses page boundary. Impossible! " |
359 | "Cannot access! This is probably a bug in the " |
360 | "driver." , (unsigned long long)vcn, |
361 | dir_ni->mft_no); |
362 | goto unm_err_out; |
363 | } |
364 | index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); |
365 | if (index_end > (u8*)ia + dir_ni->itype.index.block_size) { |
366 | ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory " |
367 | "inode 0x%lx exceeds maximum size." , |
368 | (unsigned long long)vcn, dir_ni->mft_no); |
369 | goto unm_err_out; |
370 | } |
371 | /* The first index entry. */ |
372 | ie = (INDEX_ENTRY*)((u8*)&ia->index + |
373 | le32_to_cpu(ia->index.entries_offset)); |
374 | /* |
375 | * Iterate similar to above big loop but applied to index buffer, thus |
376 | * loop until we exceed valid memory (corruption case) or until we |
377 | * reach the last entry. |
378 | */ |
379 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
380 | /* Bounds check. */ |
381 | if ((u8*)ie < (u8*)ia || (u8*)ie + |
382 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
383 | (u8*)ie + le16_to_cpu(ie->key_length) > |
384 | index_end) { |
385 | ntfs_error(sb, "Index entry out of bounds in " |
386 | "directory inode 0x%lx." , |
387 | dir_ni->mft_no); |
388 | goto unm_err_out; |
389 | } |
390 | /* |
391 | * The last entry cannot contain a name. It can however contain |
392 | * a pointer to a child node in the B+tree so we just break out. |
393 | */ |
394 | if (ie->flags & INDEX_ENTRY_END) |
395 | break; |
396 | /* |
397 | * We perform a case sensitive comparison and if that matches |
398 | * we are done and return the mft reference of the inode (i.e. |
399 | * the inode number together with the sequence number for |
400 | * consistency checking). We convert it to cpu format before |
401 | * returning. |
402 | */ |
403 | if (ntfs_are_names_equal(s1: uname, s1_len: uname_len, |
404 | s2: (ntfschar*)&ie->key.file_name.file_name, |
405 | s2_len: ie->key.file_name.file_name_length, |
406 | ic: CASE_SENSITIVE, upcase: vol->upcase, upcase_size: vol->upcase_len)) { |
407 | found_it2: |
408 | /* |
409 | * We have a perfect match, so we don't need to care |
410 | * about having matched imperfectly before, so we can |
411 | * free name and set *res to NULL. |
412 | * However, if the perfect match is a short file name, |
413 | * we need to signal this through *res, so that |
414 | * ntfs_lookup() can fix dcache aliasing issues. |
415 | * As an optimization we just reuse an existing |
416 | * allocation of *res. |
417 | */ |
418 | if (ie->key.file_name.file_name_type == FILE_NAME_DOS) { |
419 | if (!name) { |
420 | name = kmalloc(size: sizeof(ntfs_name), |
421 | GFP_NOFS); |
422 | if (!name) { |
423 | err = -ENOMEM; |
424 | goto unm_err_out; |
425 | } |
426 | } |
427 | name->mref = le64_to_cpu( |
428 | ie->data.dir.indexed_file); |
429 | name->type = FILE_NAME_DOS; |
430 | name->len = 0; |
431 | *res = name; |
432 | } else { |
433 | kfree(objp: name); |
434 | *res = NULL; |
435 | } |
436 | mref = le64_to_cpu(ie->data.dir.indexed_file); |
437 | unlock_page(page); |
438 | ntfs_unmap_page(page); |
439 | return mref; |
440 | } |
441 | /* |
442 | * For a case insensitive mount, we also perform a case |
443 | * insensitive comparison (provided the file name is not in the |
444 | * POSIX namespace). If the comparison matches, and the name is |
445 | * in the WIN32 namespace, we cache the filename in *res so |
446 | * that the caller, ntfs_lookup(), can work on it. If the |
447 | * comparison matches, and the name is in the DOS namespace, we |
448 | * only cache the mft reference and the file name type (we set |
449 | * the name length to zero for simplicity). |
450 | */ |
451 | if (!NVolCaseSensitive(vol) && |
452 | ie->key.file_name.file_name_type && |
453 | ntfs_are_names_equal(s1: uname, s1_len: uname_len, |
454 | s2: (ntfschar*)&ie->key.file_name.file_name, |
455 | s2_len: ie->key.file_name.file_name_length, |
456 | ic: IGNORE_CASE, upcase: vol->upcase, upcase_size: vol->upcase_len)) { |
457 | int name_size = sizeof(ntfs_name); |
458 | u8 type = ie->key.file_name.file_name_type; |
459 | u8 len = ie->key.file_name.file_name_length; |
460 | |
461 | /* Only one case insensitive matching name allowed. */ |
462 | if (name) { |
463 | ntfs_error(sb, "Found already allocated name " |
464 | "in phase 2. Please run chkdsk " |
465 | "and if that doesn't find any " |
466 | "errors please report you saw " |
467 | "this message to " |
468 | "linux-ntfs-dev@lists." |
469 | "sourceforge.net." ); |
470 | unlock_page(page); |
471 | ntfs_unmap_page(page); |
472 | goto dir_err_out; |
473 | } |
474 | |
475 | if (type != FILE_NAME_DOS) |
476 | name_size += len * sizeof(ntfschar); |
477 | name = kmalloc(size: name_size, GFP_NOFS); |
478 | if (!name) { |
479 | err = -ENOMEM; |
480 | goto unm_err_out; |
481 | } |
482 | name->mref = le64_to_cpu(ie->data.dir.indexed_file); |
483 | name->type = type; |
484 | if (type != FILE_NAME_DOS) { |
485 | name->len = len; |
486 | memcpy(name->name, ie->key.file_name.file_name, |
487 | len * sizeof(ntfschar)); |
488 | } else |
489 | name->len = 0; |
490 | *res = name; |
491 | } |
492 | /* |
493 | * Not a perfect match, need to do full blown collation so we |
494 | * know which way in the B+tree we have to go. |
495 | */ |
496 | rc = ntfs_collate_names(name1: uname, name1_len: uname_len, |
497 | name2: (ntfschar*)&ie->key.file_name.file_name, |
498 | name2_len: ie->key.file_name.file_name_length, err_val: 1, |
499 | ic: IGNORE_CASE, upcase: vol->upcase, upcase_len: vol->upcase_len); |
500 | /* |
501 | * If uname collates before the name of the current entry, there |
502 | * is definitely no such name in this index but we might need to |
503 | * descend into the B+tree so we just break out of the loop. |
504 | */ |
505 | if (rc == -1) |
506 | break; |
507 | /* The names are not equal, continue the search. */ |
508 | if (rc) |
509 | continue; |
510 | /* |
511 | * Names match with case insensitive comparison, now try the |
512 | * case sensitive comparison, which is required for proper |
513 | * collation. |
514 | */ |
515 | rc = ntfs_collate_names(name1: uname, name1_len: uname_len, |
516 | name2: (ntfschar*)&ie->key.file_name.file_name, |
517 | name2_len: ie->key.file_name.file_name_length, err_val: 1, |
518 | ic: CASE_SENSITIVE, upcase: vol->upcase, upcase_len: vol->upcase_len); |
519 | if (rc == -1) |
520 | break; |
521 | if (rc) |
522 | continue; |
523 | /* |
524 | * Perfect match, this will never happen as the |
525 | * ntfs_are_names_equal() call will have gotten a match but we |
526 | * still treat it correctly. |
527 | */ |
528 | goto found_it2; |
529 | } |
530 | /* |
531 | * We have finished with this index buffer without success. Check for |
532 | * the presence of a child node. |
533 | */ |
534 | if (ie->flags & INDEX_ENTRY_NODE) { |
535 | if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { |
536 | ntfs_error(sb, "Index entry with child node found in " |
537 | "a leaf node in directory inode 0x%lx." , |
538 | dir_ni->mft_no); |
539 | goto unm_err_out; |
540 | } |
541 | /* Child node present, descend into it. */ |
542 | old_vcn = vcn; |
543 | vcn = sle64_to_cpup(x: (sle64*)((u8*)ie + |
544 | le16_to_cpu(ie->length) - 8)); |
545 | if (vcn >= 0) { |
546 | /* If vcn is in the same page cache page as old_vcn we |
547 | * recycle the mapped page. */ |
548 | if (old_vcn << vol->cluster_size_bits >> |
549 | PAGE_SHIFT == vcn << |
550 | vol->cluster_size_bits >> |
551 | PAGE_SHIFT) |
552 | goto fast_descend_into_child_node; |
553 | unlock_page(page); |
554 | ntfs_unmap_page(page); |
555 | goto descend_into_child_node; |
556 | } |
557 | ntfs_error(sb, "Negative child node vcn in directory inode " |
558 | "0x%lx." , dir_ni->mft_no); |
559 | goto unm_err_out; |
560 | } |
561 | /* |
562 | * No child node present, return -ENOENT, unless we have got a matching |
563 | * name cached in name in which case return the mft reference |
564 | * associated with it. |
565 | */ |
566 | if (name) { |
567 | unlock_page(page); |
568 | ntfs_unmap_page(page); |
569 | return name->mref; |
570 | } |
571 | ntfs_debug("Entry not found." ); |
572 | err = -ENOENT; |
573 | unm_err_out: |
574 | unlock_page(page); |
575 | ntfs_unmap_page(page); |
576 | err_out: |
577 | if (!err) |
578 | err = -EIO; |
579 | if (ctx) |
580 | ntfs_attr_put_search_ctx(ctx); |
581 | if (m) |
582 | unmap_mft_record(ni: dir_ni); |
583 | if (name) { |
584 | kfree(objp: name); |
585 | *res = NULL; |
586 | } |
587 | return ERR_MREF(err); |
588 | dir_err_out: |
589 | ntfs_error(sb, "Corrupt directory. Aborting lookup." ); |
590 | goto err_out; |
591 | } |
592 | |
593 | #if 0 |
594 | |
595 | // TODO: (AIA) |
596 | // The algorithm embedded in this code will be required for the time when we |
597 | // want to support adding of entries to directories, where we require correct |
598 | // collation of file names in order not to cause corruption of the filesystem. |
599 | |
600 | /** |
601 | * ntfs_lookup_inode_by_name - find an inode in a directory given its name |
602 | * @dir_ni: ntfs inode of the directory in which to search for the name |
603 | * @uname: Unicode name for which to search in the directory |
604 | * @uname_len: length of the name @uname in Unicode characters |
605 | * |
606 | * Look for an inode with name @uname in the directory with inode @dir_ni. |
607 | * ntfs_lookup_inode_by_name() walks the contents of the directory looking for |
608 | * the Unicode name. If the name is found in the directory, the corresponding |
609 | * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it |
610 | * is a 64-bit number containing the sequence number. |
611 | * |
612 | * On error, a negative value is returned corresponding to the error code. In |
613 | * particular if the inode is not found -ENOENT is returned. Note that you |
614 | * can't just check the return value for being negative, you have to check the |
615 | * inode number for being negative which you can extract using MREC(return |
616 | * value). |
617 | * |
618 | * Note, @uname_len does not include the (optional) terminating NULL character. |
619 | */ |
620 | u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname, |
621 | const int uname_len) |
622 | { |
623 | ntfs_volume *vol = dir_ni->vol; |
624 | struct super_block *sb = vol->sb; |
625 | MFT_RECORD *m; |
626 | INDEX_ROOT *ir; |
627 | INDEX_ENTRY *ie; |
628 | INDEX_ALLOCATION *ia; |
629 | u8 *index_end; |
630 | u64 mref; |
631 | ntfs_attr_search_ctx *ctx; |
632 | int err, rc; |
633 | IGNORE_CASE_BOOL ic; |
634 | VCN vcn, old_vcn; |
635 | struct address_space *ia_mapping; |
636 | struct page *page; |
637 | u8 *kaddr; |
638 | |
639 | /* Get hold of the mft record for the directory. */ |
640 | m = map_mft_record(dir_ni); |
641 | if (IS_ERR(m)) { |
642 | ntfs_error(sb, "map_mft_record() failed with error code %ld." , |
643 | -PTR_ERR(m)); |
644 | return ERR_MREF(PTR_ERR(m)); |
645 | } |
646 | ctx = ntfs_attr_get_search_ctx(dir_ni, m); |
647 | if (!ctx) { |
648 | err = -ENOMEM; |
649 | goto err_out; |
650 | } |
651 | /* Find the index root attribute in the mft record. */ |
652 | err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, |
653 | 0, ctx); |
654 | if (unlikely(err)) { |
655 | if (err == -ENOENT) { |
656 | ntfs_error(sb, "Index root attribute missing in " |
657 | "directory inode 0x%lx." , |
658 | dir_ni->mft_no); |
659 | err = -EIO; |
660 | } |
661 | goto err_out; |
662 | } |
663 | /* Get to the index root value (it's been verified in read_inode). */ |
664 | ir = (INDEX_ROOT*)((u8*)ctx->attr + |
665 | le16_to_cpu(ctx->attr->data.resident.value_offset)); |
666 | index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); |
667 | /* The first index entry. */ |
668 | ie = (INDEX_ENTRY*)((u8*)&ir->index + |
669 | le32_to_cpu(ir->index.entries_offset)); |
670 | /* |
671 | * Loop until we exceed valid memory (corruption case) or until we |
672 | * reach the last entry. |
673 | */ |
674 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
675 | /* Bounds checks. */ |
676 | if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + |
677 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
678 | (u8*)ie + le16_to_cpu(ie->key_length) > |
679 | index_end) |
680 | goto dir_err_out; |
681 | /* |
682 | * The last entry cannot contain a name. It can however contain |
683 | * a pointer to a child node in the B+tree so we just break out. |
684 | */ |
685 | if (ie->flags & INDEX_ENTRY_END) |
686 | break; |
687 | /* |
688 | * If the current entry has a name type of POSIX, the name is |
689 | * case sensitive and not otherwise. This has the effect of us |
690 | * not being able to access any POSIX file names which collate |
691 | * after the non-POSIX one when they only differ in case, but |
692 | * anyone doing screwy stuff like that deserves to burn in |
693 | * hell... Doing that kind of stuff on NT4 actually causes |
694 | * corruption on the partition even when using SP6a and Linux |
695 | * is not involved at all. |
696 | */ |
697 | ic = ie->key.file_name.file_name_type ? IGNORE_CASE : |
698 | CASE_SENSITIVE; |
699 | /* |
700 | * If the names match perfectly, we are done and return the |
701 | * mft reference of the inode (i.e. the inode number together |
702 | * with the sequence number for consistency checking. We |
703 | * convert it to cpu format before returning. |
704 | */ |
705 | if (ntfs_are_names_equal(uname, uname_len, |
706 | (ntfschar*)&ie->key.file_name.file_name, |
707 | ie->key.file_name.file_name_length, ic, |
708 | vol->upcase, vol->upcase_len)) { |
709 | found_it: |
710 | mref = le64_to_cpu(ie->data.dir.indexed_file); |
711 | ntfs_attr_put_search_ctx(ctx); |
712 | unmap_mft_record(dir_ni); |
713 | return mref; |
714 | } |
715 | /* |
716 | * Not a perfect match, need to do full blown collation so we |
717 | * know which way in the B+tree we have to go. |
718 | */ |
719 | rc = ntfs_collate_names(uname, uname_len, |
720 | (ntfschar*)&ie->key.file_name.file_name, |
721 | ie->key.file_name.file_name_length, 1, |
722 | IGNORE_CASE, vol->upcase, vol->upcase_len); |
723 | /* |
724 | * If uname collates before the name of the current entry, there |
725 | * is definitely no such name in this index but we might need to |
726 | * descend into the B+tree so we just break out of the loop. |
727 | */ |
728 | if (rc == -1) |
729 | break; |
730 | /* The names are not equal, continue the search. */ |
731 | if (rc) |
732 | continue; |
733 | /* |
734 | * Names match with case insensitive comparison, now try the |
735 | * case sensitive comparison, which is required for proper |
736 | * collation. |
737 | */ |
738 | rc = ntfs_collate_names(uname, uname_len, |
739 | (ntfschar*)&ie->key.file_name.file_name, |
740 | ie->key.file_name.file_name_length, 1, |
741 | CASE_SENSITIVE, vol->upcase, vol->upcase_len); |
742 | if (rc == -1) |
743 | break; |
744 | if (rc) |
745 | continue; |
746 | /* |
747 | * Perfect match, this will never happen as the |
748 | * ntfs_are_names_equal() call will have gotten a match but we |
749 | * still treat it correctly. |
750 | */ |
751 | goto found_it; |
752 | } |
753 | /* |
754 | * We have finished with this index without success. Check for the |
755 | * presence of a child node. |
756 | */ |
757 | if (!(ie->flags & INDEX_ENTRY_NODE)) { |
758 | /* No child node, return -ENOENT. */ |
759 | err = -ENOENT; |
760 | goto err_out; |
761 | } /* Child node present, descend into it. */ |
762 | /* Consistency check: Verify that an index allocation exists. */ |
763 | if (!NInoIndexAllocPresent(dir_ni)) { |
764 | ntfs_error(sb, "No index allocation attribute but index entry " |
765 | "requires one. Directory inode 0x%lx is " |
766 | "corrupt or driver bug." , dir_ni->mft_no); |
767 | goto err_out; |
768 | } |
769 | /* Get the starting vcn of the index_block holding the child node. */ |
770 | vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8); |
771 | ia_mapping = VFS_I(dir_ni)->i_mapping; |
772 | /* |
773 | * We are done with the index root and the mft record. Release them, |
774 | * otherwise we deadlock with ntfs_map_page(). |
775 | */ |
776 | ntfs_attr_put_search_ctx(ctx); |
777 | unmap_mft_record(dir_ni); |
778 | m = NULL; |
779 | ctx = NULL; |
780 | descend_into_child_node: |
781 | /* |
782 | * Convert vcn to index into the index allocation attribute in units |
783 | * of PAGE_SIZE and map the page cache page, reading it from |
784 | * disk if necessary. |
785 | */ |
786 | page = ntfs_map_page(ia_mapping, vcn << |
787 | dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT); |
788 | if (IS_ERR(page)) { |
789 | ntfs_error(sb, "Failed to map directory index page, error %ld." , |
790 | -PTR_ERR(page)); |
791 | err = PTR_ERR(page); |
792 | goto err_out; |
793 | } |
794 | lock_page(page); |
795 | kaddr = (u8*)page_address(page); |
796 | fast_descend_into_child_node: |
797 | /* Get to the index allocation block. */ |
798 | ia = (INDEX_ALLOCATION*)(kaddr + ((vcn << |
799 | dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK)); |
800 | /* Bounds checks. */ |
801 | if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) { |
802 | ntfs_error(sb, "Out of bounds check failed. Corrupt directory " |
803 | "inode 0x%lx or driver bug." , dir_ni->mft_no); |
804 | goto unm_err_out; |
805 | } |
806 | /* Catch multi sector transfer fixup errors. */ |
807 | if (unlikely(!ntfs_is_indx_record(ia->magic))) { |
808 | ntfs_error(sb, "Directory index record with vcn 0x%llx is " |
809 | "corrupt. Corrupt inode 0x%lx. Run chkdsk." , |
810 | (unsigned long long)vcn, dir_ni->mft_no); |
811 | goto unm_err_out; |
812 | } |
813 | if (sle64_to_cpu(ia->index_block_vcn) != vcn) { |
814 | ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is " |
815 | "different from expected VCN (0x%llx). " |
816 | "Directory inode 0x%lx is corrupt or driver " |
817 | "bug." , (unsigned long long) |
818 | sle64_to_cpu(ia->index_block_vcn), |
819 | (unsigned long long)vcn, dir_ni->mft_no); |
820 | goto unm_err_out; |
821 | } |
822 | if (le32_to_cpu(ia->index.allocated_size) + 0x18 != |
823 | dir_ni->itype.index.block_size) { |
824 | ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode " |
825 | "0x%lx has a size (%u) differing from the " |
826 | "directory specified size (%u). Directory " |
827 | "inode is corrupt or driver bug." , |
828 | (unsigned long long)vcn, dir_ni->mft_no, |
829 | le32_to_cpu(ia->index.allocated_size) + 0x18, |
830 | dir_ni->itype.index.block_size); |
831 | goto unm_err_out; |
832 | } |
833 | index_end = (u8*)ia + dir_ni->itype.index.block_size; |
834 | if (index_end > kaddr + PAGE_SIZE) { |
835 | ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode " |
836 | "0x%lx crosses page boundary. Impossible! " |
837 | "Cannot access! This is probably a bug in the " |
838 | "driver." , (unsigned long long)vcn, |
839 | dir_ni->mft_no); |
840 | goto unm_err_out; |
841 | } |
842 | index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); |
843 | if (index_end > (u8*)ia + dir_ni->itype.index.block_size) { |
844 | ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory " |
845 | "inode 0x%lx exceeds maximum size." , |
846 | (unsigned long long)vcn, dir_ni->mft_no); |
847 | goto unm_err_out; |
848 | } |
849 | /* The first index entry. */ |
850 | ie = (INDEX_ENTRY*)((u8*)&ia->index + |
851 | le32_to_cpu(ia->index.entries_offset)); |
852 | /* |
853 | * Iterate similar to above big loop but applied to index buffer, thus |
854 | * loop until we exceed valid memory (corruption case) or until we |
855 | * reach the last entry. |
856 | */ |
857 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
858 | /* Bounds check. */ |
859 | if ((u8*)ie < (u8*)ia || (u8*)ie + |
860 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
861 | (u8*)ie + le16_to_cpu(ie->key_length) > |
862 | index_end) { |
863 | ntfs_error(sb, "Index entry out of bounds in " |
864 | "directory inode 0x%lx." , |
865 | dir_ni->mft_no); |
866 | goto unm_err_out; |
867 | } |
868 | /* |
869 | * The last entry cannot contain a name. It can however contain |
870 | * a pointer to a child node in the B+tree so we just break out. |
871 | */ |
872 | if (ie->flags & INDEX_ENTRY_END) |
873 | break; |
874 | /* |
875 | * If the current entry has a name type of POSIX, the name is |
876 | * case sensitive and not otherwise. This has the effect of us |
877 | * not being able to access any POSIX file names which collate |
878 | * after the non-POSIX one when they only differ in case, but |
879 | * anyone doing screwy stuff like that deserves to burn in |
880 | * hell... Doing that kind of stuff on NT4 actually causes |
881 | * corruption on the partition even when using SP6a and Linux |
882 | * is not involved at all. |
883 | */ |
884 | ic = ie->key.file_name.file_name_type ? IGNORE_CASE : |
885 | CASE_SENSITIVE; |
886 | /* |
887 | * If the names match perfectly, we are done and return the |
888 | * mft reference of the inode (i.e. the inode number together |
889 | * with the sequence number for consistency checking. We |
890 | * convert it to cpu format before returning. |
891 | */ |
892 | if (ntfs_are_names_equal(uname, uname_len, |
893 | (ntfschar*)&ie->key.file_name.file_name, |
894 | ie->key.file_name.file_name_length, ic, |
895 | vol->upcase, vol->upcase_len)) { |
896 | found_it2: |
897 | mref = le64_to_cpu(ie->data.dir.indexed_file); |
898 | unlock_page(page); |
899 | ntfs_unmap_page(page); |
900 | return mref; |
901 | } |
902 | /* |
903 | * Not a perfect match, need to do full blown collation so we |
904 | * know which way in the B+tree we have to go. |
905 | */ |
906 | rc = ntfs_collate_names(uname, uname_len, |
907 | (ntfschar*)&ie->key.file_name.file_name, |
908 | ie->key.file_name.file_name_length, 1, |
909 | IGNORE_CASE, vol->upcase, vol->upcase_len); |
910 | /* |
911 | * If uname collates before the name of the current entry, there |
912 | * is definitely no such name in this index but we might need to |
913 | * descend into the B+tree so we just break out of the loop. |
914 | */ |
915 | if (rc == -1) |
916 | break; |
917 | /* The names are not equal, continue the search. */ |
918 | if (rc) |
919 | continue; |
920 | /* |
921 | * Names match with case insensitive comparison, now try the |
922 | * case sensitive comparison, which is required for proper |
923 | * collation. |
924 | */ |
925 | rc = ntfs_collate_names(uname, uname_len, |
926 | (ntfschar*)&ie->key.file_name.file_name, |
927 | ie->key.file_name.file_name_length, 1, |
928 | CASE_SENSITIVE, vol->upcase, vol->upcase_len); |
929 | if (rc == -1) |
930 | break; |
931 | if (rc) |
932 | continue; |
933 | /* |
934 | * Perfect match, this will never happen as the |
935 | * ntfs_are_names_equal() call will have gotten a match but we |
936 | * still treat it correctly. |
937 | */ |
938 | goto found_it2; |
939 | } |
940 | /* |
941 | * We have finished with this index buffer without success. Check for |
942 | * the presence of a child node. |
943 | */ |
944 | if (ie->flags & INDEX_ENTRY_NODE) { |
945 | if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { |
946 | ntfs_error(sb, "Index entry with child node found in " |
947 | "a leaf node in directory inode 0x%lx." , |
948 | dir_ni->mft_no); |
949 | goto unm_err_out; |
950 | } |
951 | /* Child node present, descend into it. */ |
952 | old_vcn = vcn; |
953 | vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8); |
954 | if (vcn >= 0) { |
955 | /* If vcn is in the same page cache page as old_vcn we |
956 | * recycle the mapped page. */ |
957 | if (old_vcn << vol->cluster_size_bits >> |
958 | PAGE_SHIFT == vcn << |
959 | vol->cluster_size_bits >> |
960 | PAGE_SHIFT) |
961 | goto fast_descend_into_child_node; |
962 | unlock_page(page); |
963 | ntfs_unmap_page(page); |
964 | goto descend_into_child_node; |
965 | } |
966 | ntfs_error(sb, "Negative child node vcn in directory inode " |
967 | "0x%lx." , dir_ni->mft_no); |
968 | goto unm_err_out; |
969 | } |
970 | /* No child node, return -ENOENT. */ |
971 | ntfs_debug("Entry not found." ); |
972 | err = -ENOENT; |
973 | unm_err_out: |
974 | unlock_page(page); |
975 | ntfs_unmap_page(page); |
976 | err_out: |
977 | if (!err) |
978 | err = -EIO; |
979 | if (ctx) |
980 | ntfs_attr_put_search_ctx(ctx); |
981 | if (m) |
982 | unmap_mft_record(dir_ni); |
983 | return ERR_MREF(err); |
984 | dir_err_out: |
985 | ntfs_error(sb, "Corrupt directory. Aborting lookup." ); |
986 | goto err_out; |
987 | } |
988 | |
989 | #endif |
990 | |
991 | /** |
992 | * ntfs_filldir - ntfs specific filldir method |
993 | * @vol: current ntfs volume |
994 | * @ndir: ntfs inode of current directory |
995 | * @ia_page: page in which the index allocation buffer @ie is in resides |
996 | * @ie: current index entry |
997 | * @name: buffer to use for the converted name |
998 | * @actor: what to feed the entries to |
999 | * |
1000 | * Convert the Unicode @name to the loaded NLS and pass it to the @filldir |
1001 | * callback. |
1002 | * |
1003 | * If @ia_page is not NULL it is the locked page containing the index |
1004 | * allocation block containing the index entry @ie. |
1005 | * |
1006 | * Note, we drop (and then reacquire) the page lock on @ia_page across the |
1007 | * @filldir() call otherwise we would deadlock with NFSd when it calls ->lookup |
1008 | * since ntfs_lookup() will lock the same page. As an optimization, we do not |
1009 | * retake the lock if we are returning a non-zero value as ntfs_readdir() |
1010 | * would need to drop the lock immediately anyway. |
1011 | */ |
1012 | static inline int ntfs_filldir(ntfs_volume *vol, |
1013 | ntfs_inode *ndir, struct page *ia_page, INDEX_ENTRY *ie, |
1014 | u8 *name, struct dir_context *actor) |
1015 | { |
1016 | unsigned long mref; |
1017 | int name_len; |
1018 | unsigned dt_type; |
1019 | FILE_NAME_TYPE_FLAGS name_type; |
1020 | |
1021 | name_type = ie->key.file_name.file_name_type; |
1022 | if (name_type == FILE_NAME_DOS) { |
1023 | ntfs_debug("Skipping DOS name space entry." ); |
1024 | return 0; |
1025 | } |
1026 | if (MREF_LE(ie->data.dir.indexed_file) == FILE_root) { |
1027 | ntfs_debug("Skipping root directory self reference entry." ); |
1028 | return 0; |
1029 | } |
1030 | if (MREF_LE(ie->data.dir.indexed_file) < FILE_first_user && |
1031 | !NVolShowSystemFiles(vol)) { |
1032 | ntfs_debug("Skipping system file." ); |
1033 | return 0; |
1034 | } |
1035 | name_len = ntfs_ucstonls(vol, ins: (ntfschar*)&ie->key.file_name.file_name, |
1036 | ins_len: ie->key.file_name.file_name_length, outs: &name, |
1037 | outs_len: NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1); |
1038 | if (name_len <= 0) { |
1039 | ntfs_warning(vol->sb, "Skipping unrepresentable inode 0x%llx." , |
1040 | (long long)MREF_LE(ie->data.dir.indexed_file)); |
1041 | return 0; |
1042 | } |
1043 | if (ie->key.file_name.file_attributes & |
1044 | FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT) |
1045 | dt_type = DT_DIR; |
1046 | else |
1047 | dt_type = DT_REG; |
1048 | mref = MREF_LE(ie->data.dir.indexed_file); |
1049 | /* |
1050 | * Drop the page lock otherwise we deadlock with NFS when it calls |
1051 | * ->lookup since ntfs_lookup() will lock the same page. |
1052 | */ |
1053 | if (ia_page) |
1054 | unlock_page(page: ia_page); |
1055 | ntfs_debug("Calling filldir for %s with len %i, fpos 0x%llx, inode " |
1056 | "0x%lx, DT_%s." , name, name_len, actor->pos, mref, |
1057 | dt_type == DT_DIR ? "DIR" : "REG" ); |
1058 | if (!dir_emit(ctx: actor, name, namelen: name_len, ino: mref, type: dt_type)) |
1059 | return 1; |
1060 | /* Relock the page but not if we are aborting ->readdir. */ |
1061 | if (ia_page) |
1062 | lock_page(page: ia_page); |
1063 | return 0; |
1064 | } |
1065 | |
1066 | /* |
1067 | * We use the same basic approach as the old NTFS driver, i.e. we parse the |
1068 | * index root entries and then the index allocation entries that are marked |
1069 | * as in use in the index bitmap. |
1070 | * |
1071 | * While this will return the names in random order this doesn't matter for |
1072 | * ->readdir but OTOH results in a faster ->readdir. |
1073 | * |
1074 | * VFS calls ->readdir without BKL but with i_mutex held. This protects the VFS |
1075 | * parts (e.g. ->f_pos and ->i_size, and it also protects against directory |
1076 | * modifications). |
1077 | * |
1078 | * Locking: - Caller must hold i_mutex on the directory. |
1079 | * - Each page cache page in the index allocation mapping must be |
1080 | * locked whilst being accessed otherwise we may find a corrupt |
1081 | * page due to it being under ->writepage at the moment which |
1082 | * applies the mst protection fixups before writing out and then |
1083 | * removes them again after the write is complete after which it |
1084 | * unlocks the page. |
1085 | */ |
1086 | static int ntfs_readdir(struct file *file, struct dir_context *actor) |
1087 | { |
1088 | s64 ia_pos, ia_start, prev_ia_pos, bmp_pos; |
1089 | loff_t i_size; |
1090 | struct inode *bmp_vi, *vdir = file_inode(f: file); |
1091 | struct super_block *sb = vdir->i_sb; |
1092 | ntfs_inode *ndir = NTFS_I(inode: vdir); |
1093 | ntfs_volume *vol = NTFS_SB(sb); |
1094 | MFT_RECORD *m; |
1095 | INDEX_ROOT *ir = NULL; |
1096 | INDEX_ENTRY *ie; |
1097 | INDEX_ALLOCATION *ia; |
1098 | u8 *name = NULL; |
1099 | int rc, err, ir_pos, cur_bmp_pos; |
1100 | struct address_space *ia_mapping, *bmp_mapping; |
1101 | struct page *bmp_page = NULL, *ia_page = NULL; |
1102 | u8 *kaddr, *bmp, *index_end; |
1103 | ntfs_attr_search_ctx *ctx; |
1104 | |
1105 | ntfs_debug("Entering for inode 0x%lx, fpos 0x%llx." , |
1106 | vdir->i_ino, actor->pos); |
1107 | rc = err = 0; |
1108 | /* Are we at end of dir yet? */ |
1109 | i_size = i_size_read(inode: vdir); |
1110 | if (actor->pos >= i_size + vol->mft_record_size) |
1111 | return 0; |
1112 | /* Emulate . and .. for all directories. */ |
1113 | if (!dir_emit_dots(file, ctx: actor)) |
1114 | return 0; |
1115 | m = NULL; |
1116 | ctx = NULL; |
1117 | /* |
1118 | * Allocate a buffer to store the current name being processed |
1119 | * converted to format determined by current NLS. |
1120 | */ |
1121 | name = kmalloc(size: NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1, GFP_NOFS); |
1122 | if (unlikely(!name)) { |
1123 | err = -ENOMEM; |
1124 | goto err_out; |
1125 | } |
1126 | /* Are we jumping straight into the index allocation attribute? */ |
1127 | if (actor->pos >= vol->mft_record_size) |
1128 | goto skip_index_root; |
1129 | /* Get hold of the mft record for the directory. */ |
1130 | m = map_mft_record(ni: ndir); |
1131 | if (IS_ERR(ptr: m)) { |
1132 | err = PTR_ERR(ptr: m); |
1133 | m = NULL; |
1134 | goto err_out; |
1135 | } |
1136 | ctx = ntfs_attr_get_search_ctx(ni: ndir, mrec: m); |
1137 | if (unlikely(!ctx)) { |
1138 | err = -ENOMEM; |
1139 | goto err_out; |
1140 | } |
1141 | /* Get the offset into the index root attribute. */ |
1142 | ir_pos = (s64)actor->pos; |
1143 | /* Find the index root attribute in the mft record. */ |
1144 | err = ntfs_attr_lookup(type: AT_INDEX_ROOT, name: I30, name_len: 4, ic: CASE_SENSITIVE, lowest_vcn: 0, NULL, |
1145 | val_len: 0, ctx); |
1146 | if (unlikely(err)) { |
1147 | ntfs_error(sb, "Index root attribute missing in directory " |
1148 | "inode 0x%lx." , vdir->i_ino); |
1149 | goto err_out; |
1150 | } |
1151 | /* |
1152 | * Copy the index root attribute value to a buffer so that we can put |
1153 | * the search context and unmap the mft record before calling the |
1154 | * filldir() callback. We need to do this because of NFSd which calls |
1155 | * ->lookup() from its filldir callback() and this causes NTFS to |
1156 | * deadlock as ntfs_lookup() maps the mft record of the directory and |
1157 | * we have got it mapped here already. The only solution is for us to |
1158 | * unmap the mft record here so that a call to ntfs_lookup() is able to |
1159 | * map the mft record without deadlocking. |
1160 | */ |
1161 | rc = le32_to_cpu(ctx->attr->data.resident.value_length); |
1162 | ir = kmalloc(size: rc, GFP_NOFS); |
1163 | if (unlikely(!ir)) { |
1164 | err = -ENOMEM; |
1165 | goto err_out; |
1166 | } |
1167 | /* Copy the index root value (it has been verified in read_inode). */ |
1168 | memcpy(ir, (u8*)ctx->attr + |
1169 | le16_to_cpu(ctx->attr->data.resident.value_offset), rc); |
1170 | ntfs_attr_put_search_ctx(ctx); |
1171 | unmap_mft_record(ni: ndir); |
1172 | ctx = NULL; |
1173 | m = NULL; |
1174 | index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); |
1175 | /* The first index entry. */ |
1176 | ie = (INDEX_ENTRY*)((u8*)&ir->index + |
1177 | le32_to_cpu(ir->index.entries_offset)); |
1178 | /* |
1179 | * Loop until we exceed valid memory (corruption case) or until we |
1180 | * reach the last entry or until filldir tells us it has had enough |
1181 | * or signals an error (both covered by the rc test). |
1182 | */ |
1183 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
1184 | ntfs_debug("In index root, offset 0x%zx." , (u8*)ie - (u8*)ir); |
1185 | /* Bounds checks. */ |
1186 | if (unlikely((u8*)ie < (u8*)ir || (u8*)ie + |
1187 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
1188 | (u8*)ie + le16_to_cpu(ie->key_length) > |
1189 | index_end)) |
1190 | goto err_out; |
1191 | /* The last entry cannot contain a name. */ |
1192 | if (ie->flags & INDEX_ENTRY_END) |
1193 | break; |
1194 | /* Skip index root entry if continuing previous readdir. */ |
1195 | if (ir_pos > (u8*)ie - (u8*)ir) |
1196 | continue; |
1197 | /* Advance the position even if going to skip the entry. */ |
1198 | actor->pos = (u8*)ie - (u8*)ir; |
1199 | /* Submit the name to the filldir callback. */ |
1200 | rc = ntfs_filldir(vol, ndir, NULL, ie, name, actor); |
1201 | if (rc) { |
1202 | kfree(objp: ir); |
1203 | goto abort; |
1204 | } |
1205 | } |
1206 | /* We are done with the index root and can free the buffer. */ |
1207 | kfree(objp: ir); |
1208 | ir = NULL; |
1209 | /* If there is no index allocation attribute we are finished. */ |
1210 | if (!NInoIndexAllocPresent(ni: ndir)) |
1211 | goto EOD; |
1212 | /* Advance fpos to the beginning of the index allocation. */ |
1213 | actor->pos = vol->mft_record_size; |
1214 | skip_index_root: |
1215 | kaddr = NULL; |
1216 | prev_ia_pos = -1LL; |
1217 | /* Get the offset into the index allocation attribute. */ |
1218 | ia_pos = (s64)actor->pos - vol->mft_record_size; |
1219 | ia_mapping = vdir->i_mapping; |
1220 | ntfs_debug("Inode 0x%lx, getting index bitmap." , vdir->i_ino); |
1221 | bmp_vi = ntfs_attr_iget(base_vi: vdir, type: AT_BITMAP, name: I30, name_len: 4); |
1222 | if (IS_ERR(ptr: bmp_vi)) { |
1223 | ntfs_error(sb, "Failed to get bitmap attribute." ); |
1224 | err = PTR_ERR(ptr: bmp_vi); |
1225 | goto err_out; |
1226 | } |
1227 | bmp_mapping = bmp_vi->i_mapping; |
1228 | /* Get the starting bitmap bit position and sanity check it. */ |
1229 | bmp_pos = ia_pos >> ndir->itype.index.block_size_bits; |
1230 | if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) { |
1231 | ntfs_error(sb, "Current index allocation position exceeds " |
1232 | "index bitmap size." ); |
1233 | goto iput_err_out; |
1234 | } |
1235 | /* Get the starting bit position in the current bitmap page. */ |
1236 | cur_bmp_pos = bmp_pos & ((PAGE_SIZE * 8) - 1); |
1237 | bmp_pos &= ~(u64)((PAGE_SIZE * 8) - 1); |
1238 | get_next_bmp_page: |
1239 | ntfs_debug("Reading bitmap with page index 0x%llx, bit ofs 0x%llx" , |
1240 | (unsigned long long)bmp_pos >> (3 + PAGE_SHIFT), |
1241 | (unsigned long long)bmp_pos & |
1242 | (unsigned long long)((PAGE_SIZE * 8) - 1)); |
1243 | bmp_page = ntfs_map_page(mapping: bmp_mapping, |
1244 | index: bmp_pos >> (3 + PAGE_SHIFT)); |
1245 | if (IS_ERR(ptr: bmp_page)) { |
1246 | ntfs_error(sb, "Reading index bitmap failed." ); |
1247 | err = PTR_ERR(ptr: bmp_page); |
1248 | bmp_page = NULL; |
1249 | goto iput_err_out; |
1250 | } |
1251 | bmp = (u8*)page_address(bmp_page); |
1252 | /* Find next index block in use. */ |
1253 | while (!(bmp[cur_bmp_pos >> 3] & (1 << (cur_bmp_pos & 7)))) { |
1254 | find_next_index_buffer: |
1255 | cur_bmp_pos++; |
1256 | /* |
1257 | * If we have reached the end of the bitmap page, get the next |
1258 | * page, and put away the old one. |
1259 | */ |
1260 | if (unlikely((cur_bmp_pos >> 3) >= PAGE_SIZE)) { |
1261 | ntfs_unmap_page(page: bmp_page); |
1262 | bmp_pos += PAGE_SIZE * 8; |
1263 | cur_bmp_pos = 0; |
1264 | goto get_next_bmp_page; |
1265 | } |
1266 | /* If we have reached the end of the bitmap, we are done. */ |
1267 | if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= i_size)) |
1268 | goto unm_EOD; |
1269 | ia_pos = (bmp_pos + cur_bmp_pos) << |
1270 | ndir->itype.index.block_size_bits; |
1271 | } |
1272 | ntfs_debug("Handling index buffer 0x%llx." , |
1273 | (unsigned long long)bmp_pos + cur_bmp_pos); |
1274 | /* If the current index buffer is in the same page we reuse the page. */ |
1275 | if ((prev_ia_pos & (s64)PAGE_MASK) != |
1276 | (ia_pos & (s64)PAGE_MASK)) { |
1277 | prev_ia_pos = ia_pos; |
1278 | if (likely(ia_page != NULL)) { |
1279 | unlock_page(page: ia_page); |
1280 | ntfs_unmap_page(page: ia_page); |
1281 | } |
1282 | /* |
1283 | * Map the page cache page containing the current ia_pos, |
1284 | * reading it from disk if necessary. |
1285 | */ |
1286 | ia_page = ntfs_map_page(mapping: ia_mapping, index: ia_pos >> PAGE_SHIFT); |
1287 | if (IS_ERR(ptr: ia_page)) { |
1288 | ntfs_error(sb, "Reading index allocation data failed." ); |
1289 | err = PTR_ERR(ptr: ia_page); |
1290 | ia_page = NULL; |
1291 | goto err_out; |
1292 | } |
1293 | lock_page(page: ia_page); |
1294 | kaddr = (u8*)page_address(ia_page); |
1295 | } |
1296 | /* Get the current index buffer. */ |
1297 | ia = (INDEX_ALLOCATION*)(kaddr + (ia_pos & ~PAGE_MASK & |
1298 | ~(s64)(ndir->itype.index.block_size - 1))); |
1299 | /* Bounds checks. */ |
1300 | if (unlikely((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE)) { |
1301 | ntfs_error(sb, "Out of bounds check failed. Corrupt directory " |
1302 | "inode 0x%lx or driver bug." , vdir->i_ino); |
1303 | goto err_out; |
1304 | } |
1305 | /* Catch multi sector transfer fixup errors. */ |
1306 | if (unlikely(!ntfs_is_indx_record(ia->magic))) { |
1307 | ntfs_error(sb, "Directory index record with vcn 0x%llx is " |
1308 | "corrupt. Corrupt inode 0x%lx. Run chkdsk." , |
1309 | (unsigned long long)ia_pos >> |
1310 | ndir->itype.index.vcn_size_bits, vdir->i_ino); |
1311 | goto err_out; |
1312 | } |
1313 | if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos & |
1314 | ~(s64)(ndir->itype.index.block_size - 1)) >> |
1315 | ndir->itype.index.vcn_size_bits)) { |
1316 | ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is " |
1317 | "different from expected VCN (0x%llx). " |
1318 | "Directory inode 0x%lx is corrupt or driver " |
1319 | "bug. " , (unsigned long long) |
1320 | sle64_to_cpu(ia->index_block_vcn), |
1321 | (unsigned long long)ia_pos >> |
1322 | ndir->itype.index.vcn_size_bits, vdir->i_ino); |
1323 | goto err_out; |
1324 | } |
1325 | if (unlikely(le32_to_cpu(ia->index.allocated_size) + 0x18 != |
1326 | ndir->itype.index.block_size)) { |
1327 | ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode " |
1328 | "0x%lx has a size (%u) differing from the " |
1329 | "directory specified size (%u). Directory " |
1330 | "inode is corrupt or driver bug." , |
1331 | (unsigned long long)ia_pos >> |
1332 | ndir->itype.index.vcn_size_bits, vdir->i_ino, |
1333 | le32_to_cpu(ia->index.allocated_size) + 0x18, |
1334 | ndir->itype.index.block_size); |
1335 | goto err_out; |
1336 | } |
1337 | index_end = (u8*)ia + ndir->itype.index.block_size; |
1338 | if (unlikely(index_end > kaddr + PAGE_SIZE)) { |
1339 | ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode " |
1340 | "0x%lx crosses page boundary. Impossible! " |
1341 | "Cannot access! This is probably a bug in the " |
1342 | "driver." , (unsigned long long)ia_pos >> |
1343 | ndir->itype.index.vcn_size_bits, vdir->i_ino); |
1344 | goto err_out; |
1345 | } |
1346 | ia_start = ia_pos & ~(s64)(ndir->itype.index.block_size - 1); |
1347 | index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); |
1348 | if (unlikely(index_end > (u8*)ia + ndir->itype.index.block_size)) { |
1349 | ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory " |
1350 | "inode 0x%lx exceeds maximum size." , |
1351 | (unsigned long long)ia_pos >> |
1352 | ndir->itype.index.vcn_size_bits, vdir->i_ino); |
1353 | goto err_out; |
1354 | } |
1355 | /* The first index entry in this index buffer. */ |
1356 | ie = (INDEX_ENTRY*)((u8*)&ia->index + |
1357 | le32_to_cpu(ia->index.entries_offset)); |
1358 | /* |
1359 | * Loop until we exceed valid memory (corruption case) or until we |
1360 | * reach the last entry or until filldir tells us it has had enough |
1361 | * or signals an error (both covered by the rc test). |
1362 | */ |
1363 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
1364 | ntfs_debug("In index allocation, offset 0x%llx." , |
1365 | (unsigned long long)ia_start + |
1366 | (unsigned long long)((u8*)ie - (u8*)ia)); |
1367 | /* Bounds checks. */ |
1368 | if (unlikely((u8*)ie < (u8*)ia || (u8*)ie + |
1369 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
1370 | (u8*)ie + le16_to_cpu(ie->key_length) > |
1371 | index_end)) |
1372 | goto err_out; |
1373 | /* The last entry cannot contain a name. */ |
1374 | if (ie->flags & INDEX_ENTRY_END) |
1375 | break; |
1376 | /* Skip index block entry if continuing previous readdir. */ |
1377 | if (ia_pos - ia_start > (u8*)ie - (u8*)ia) |
1378 | continue; |
1379 | /* Advance the position even if going to skip the entry. */ |
1380 | actor->pos = (u8*)ie - (u8*)ia + |
1381 | (sle64_to_cpu(x: ia->index_block_vcn) << |
1382 | ndir->itype.index.vcn_size_bits) + |
1383 | vol->mft_record_size; |
1384 | /* |
1385 | * Submit the name to the @filldir callback. Note, |
1386 | * ntfs_filldir() drops the lock on @ia_page but it retakes it |
1387 | * before returning, unless a non-zero value is returned in |
1388 | * which case the page is left unlocked. |
1389 | */ |
1390 | rc = ntfs_filldir(vol, ndir, ia_page, ie, name, actor); |
1391 | if (rc) { |
1392 | /* @ia_page is already unlocked in this case. */ |
1393 | ntfs_unmap_page(page: ia_page); |
1394 | ntfs_unmap_page(page: bmp_page); |
1395 | iput(bmp_vi); |
1396 | goto abort; |
1397 | } |
1398 | } |
1399 | goto find_next_index_buffer; |
1400 | unm_EOD: |
1401 | if (ia_page) { |
1402 | unlock_page(page: ia_page); |
1403 | ntfs_unmap_page(page: ia_page); |
1404 | } |
1405 | ntfs_unmap_page(page: bmp_page); |
1406 | iput(bmp_vi); |
1407 | EOD: |
1408 | /* We are finished, set fpos to EOD. */ |
1409 | actor->pos = i_size + vol->mft_record_size; |
1410 | abort: |
1411 | kfree(objp: name); |
1412 | return 0; |
1413 | err_out: |
1414 | if (bmp_page) { |
1415 | ntfs_unmap_page(page: bmp_page); |
1416 | iput_err_out: |
1417 | iput(bmp_vi); |
1418 | } |
1419 | if (ia_page) { |
1420 | unlock_page(page: ia_page); |
1421 | ntfs_unmap_page(page: ia_page); |
1422 | } |
1423 | kfree(objp: ir); |
1424 | kfree(objp: name); |
1425 | if (ctx) |
1426 | ntfs_attr_put_search_ctx(ctx); |
1427 | if (m) |
1428 | unmap_mft_record(ni: ndir); |
1429 | if (!err) |
1430 | err = -EIO; |
1431 | ntfs_debug("Failed. Returning error code %i." , -err); |
1432 | return err; |
1433 | } |
1434 | |
1435 | /** |
1436 | * ntfs_dir_open - called when an inode is about to be opened |
1437 | * @vi: inode to be opened |
1438 | * @filp: file structure describing the inode |
1439 | * |
1440 | * Limit directory size to the page cache limit on architectures where unsigned |
1441 | * long is 32-bits. This is the most we can do for now without overflowing the |
1442 | * page cache page index. Doing it this way means we don't run into problems |
1443 | * because of existing too large directories. It would be better to allow the |
1444 | * user to read the accessible part of the directory but I doubt very much |
1445 | * anyone is going to hit this check on a 32-bit architecture, so there is no |
1446 | * point in adding the extra complexity required to support this. |
1447 | * |
1448 | * On 64-bit architectures, the check is hopefully optimized away by the |
1449 | * compiler. |
1450 | */ |
1451 | static int ntfs_dir_open(struct inode *vi, struct file *filp) |
1452 | { |
1453 | if (sizeof(unsigned long) < 8) { |
1454 | if (i_size_read(inode: vi) > MAX_LFS_FILESIZE) |
1455 | return -EFBIG; |
1456 | } |
1457 | return 0; |
1458 | } |
1459 | |
1460 | #ifdef NTFS_RW |
1461 | |
1462 | /** |
1463 | * ntfs_dir_fsync - sync a directory to disk |
1464 | * @filp: directory to be synced |
1465 | * @dentry: dentry describing the directory to sync |
1466 | * @datasync: if non-zero only flush user data and not metadata |
1467 | * |
1468 | * Data integrity sync of a directory to disk. Used for fsync, fdatasync, and |
1469 | * msync system calls. This function is based on file.c::ntfs_file_fsync(). |
1470 | * |
1471 | * Write the mft record and all associated extent mft records as well as the |
1472 | * $INDEX_ALLOCATION and $BITMAP attributes and then sync the block device. |
1473 | * |
1474 | * If @datasync is true, we do not wait on the inode(s) to be written out |
1475 | * but we always wait on the page cache pages to be written out. |
1476 | * |
1477 | * Note: In the past @filp could be NULL so we ignore it as we don't need it |
1478 | * anyway. |
1479 | * |
1480 | * Locking: Caller must hold i_mutex on the inode. |
1481 | * |
1482 | * TODO: We should probably also write all attribute/index inodes associated |
1483 | * with this inode but since we have no simple way of getting to them we ignore |
1484 | * this problem for now. We do write the $BITMAP attribute if it is present |
1485 | * which is the important one for a directory so things are not too bad. |
1486 | */ |
1487 | static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end, |
1488 | int datasync) |
1489 | { |
1490 | struct inode *bmp_vi, *vi = filp->f_mapping->host; |
1491 | int err, ret; |
1492 | ntfs_attr na; |
1493 | |
1494 | ntfs_debug("Entering for inode 0x%lx." , vi->i_ino); |
1495 | |
1496 | err = file_write_and_wait_range(file: filp, start, end); |
1497 | if (err) |
1498 | return err; |
1499 | inode_lock(inode: vi); |
1500 | |
1501 | BUG_ON(!S_ISDIR(vi->i_mode)); |
1502 | /* If the bitmap attribute inode is in memory sync it, too. */ |
1503 | na.mft_no = vi->i_ino; |
1504 | na.type = AT_BITMAP; |
1505 | na.name = I30; |
1506 | na.name_len = 4; |
1507 | bmp_vi = ilookup5(sb: vi->i_sb, hashval: vi->i_ino, test: ntfs_test_inode, data: &na); |
1508 | if (bmp_vi) { |
1509 | write_inode_now(bmp_vi, sync: !datasync); |
1510 | iput(bmp_vi); |
1511 | } |
1512 | ret = __ntfs_write_inode(vi, sync: 1); |
1513 | write_inode_now(vi, sync: !datasync); |
1514 | err = sync_blockdev(bdev: vi->i_sb->s_bdev); |
1515 | if (unlikely(err && !ret)) |
1516 | ret = err; |
1517 | if (likely(!ret)) |
1518 | ntfs_debug("Done." ); |
1519 | else |
1520 | ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " |
1521 | "%u." , datasync ? "data" : "" , vi->i_ino, -ret); |
1522 | inode_unlock(inode: vi); |
1523 | return ret; |
1524 | } |
1525 | |
1526 | #endif /* NTFS_RW */ |
1527 | |
1528 | WRAP_DIR_ITER(ntfs_readdir) // FIXME! |
1529 | const struct file_operations ntfs_dir_ops = { |
1530 | .llseek = generic_file_llseek, /* Seek inside directory. */ |
1531 | .read = generic_read_dir, /* Return -EISDIR. */ |
1532 | .iterate_shared = shared_ntfs_readdir, /* Read directory contents. */ |
1533 | #ifdef NTFS_RW |
1534 | .fsync = ntfs_dir_fsync, /* Sync a directory to disk. */ |
1535 | #endif /* NTFS_RW */ |
1536 | /*.ioctl = ,*/ /* Perform function on the |
1537 | mounted filesystem. */ |
1538 | .open = ntfs_dir_open, /* Open directory. */ |
1539 | }; |
1540 | |