blob: 2d7a7058abc0344d35a25ecacd423b5977ebf6b8
1 | /** |
2 | * dir.c - Directory handling code. Originated from the Linux-NTFS project. |
3 | * |
4 | * Copyright (c) 2002-2005 Anton Altaparmakov |
5 | * Copyright (c) 2004-2005 Richard Russon |
6 | * Copyright (c) 2004-2008 Szabolcs Szakacsits |
7 | * Copyright (c) 2005-2007 Yura Pakhuchiy |
8 | * Copyright (c) 2008-2010 Jean-Pierre Andre |
9 | * |
10 | * This program/include file is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU General Public License as published |
12 | * by the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. |
14 | * |
15 | * This program/include file is distributed in the hope that it will be |
16 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
17 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program (in the main directory of the NTFS-3G |
22 | * distribution in the file COPYING); if not, write to the Free Software |
23 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ |
25 | |
26 | #ifdef HAVE_CONFIG_H |
27 | #include "config.h" |
28 | #endif |
29 | |
30 | #ifdef HAVE_STDLIB_H |
31 | #include <stdlib.h> |
32 | #endif |
33 | #ifdef HAVE_ERRNO_H |
34 | #include <errno.h> |
35 | #endif |
36 | #ifdef HAVE_STRING_H |
37 | #include <string.h> |
38 | #endif |
39 | #ifdef HAVE_SYS_STAT_H |
40 | #include <sys/stat.h> |
41 | #endif |
42 | |
43 | #ifdef HAVE_SYS_SYSMACROS_H |
44 | #include <sys/sysmacros.h> |
45 | #endif |
46 | |
47 | #include <strings.h> |
48 | #include "param.h" |
49 | #include "types.h" |
50 | #include "debug.h" |
51 | #include "attrib.h" |
52 | #include "inode.h" |
53 | #include "dir.h" |
54 | #include "volume.h" |
55 | #include "mft.h" |
56 | #include "index.h" |
57 | #include "ntfstime.h" |
58 | #include "lcnalloc.h" |
59 | #include "logging.h" |
60 | #include "cache.h" |
61 | #include "misc.h" |
62 | #include "security.h" |
63 | #include "reparse.h" |
64 | #include "object_id.h" |
65 | |
66 | #ifdef HAVE_SETXATTR |
67 | #include <sys/xattr.h> |
68 | #endif |
69 | |
70 | /* |
71 | * The little endian Unicode strings "$I30", "$SII", "$SDH", "$O" |
72 | * and "$Q" as global constants. |
73 | */ |
74 | ntfschar NTFS_INDEX_I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'), |
75 | const_cpu_to_le16('3'), const_cpu_to_le16('0'), |
76 | const_cpu_to_le16('\0') }; |
77 | ntfschar NTFS_INDEX_SII[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'), |
78 | const_cpu_to_le16('I'), const_cpu_to_le16('I'), |
79 | const_cpu_to_le16('\0') }; |
80 | ntfschar NTFS_INDEX_SDH[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'), |
81 | const_cpu_to_le16('D'), const_cpu_to_le16('H'), |
82 | const_cpu_to_le16('\0') }; |
83 | ntfschar NTFS_INDEX_O[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('O'), |
84 | const_cpu_to_le16('\0') }; |
85 | ntfschar NTFS_INDEX_Q[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('Q'), |
86 | const_cpu_to_le16('\0') }; |
87 | ntfschar NTFS_INDEX_R[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('R'), |
88 | const_cpu_to_le16('\0') }; |
89 | |
90 | #if CACHE_INODE_SIZE |
91 | |
92 | /* |
93 | * Pathname hashing |
94 | * |
95 | * Based on first char and second char (which may be '\0') |
96 | */ |
97 | |
98 | int ntfs_dir_inode_hash(const struct CACHED_GENERIC *cached) |
99 | { |
100 | const char *path; |
101 | const unsigned char *name; |
102 | |
103 | path = (const char*)cached->variable; |
104 | if (!path) { |
105 | ntfs_log_error("Bad inode cache entry\n"); |
106 | return (-1); |
107 | } |
108 | name = (const unsigned char*)strrchr(path,'/'); |
109 | if (!name) |
110 | name = (const unsigned char*)path; |
111 | return (((name[0] << 1) + name[1] + strlen((const char*)name)) |
112 | % (2*CACHE_INODE_SIZE)); |
113 | } |
114 | |
115 | /* |
116 | * Pathname comparing for entering/fetching from cache |
117 | */ |
118 | |
119 | static int inode_cache_compare(const struct CACHED_GENERIC *cached, |
120 | const struct CACHED_GENERIC *wanted) |
121 | { |
122 | return (!cached->variable |
123 | || strcmp(cached->variable, wanted->variable)); |
124 | } |
125 | |
126 | /* |
127 | * Pathname comparing for invalidating entries in cache |
128 | * |
129 | * A partial path is compared in order to invalidate all paths |
130 | * related to a renamed directory |
131 | * inode numbers are also checked, as deleting a long name may |
132 | * imply deleting a short name and conversely |
133 | * |
134 | * Only use associated with a CACHE_NOHASH flag |
135 | */ |
136 | |
137 | static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached, |
138 | const struct CACHED_GENERIC *wanted) |
139 | { |
140 | int len; |
141 | BOOL different; |
142 | const struct CACHED_INODE *w; |
143 | const struct CACHED_INODE *c; |
144 | |
145 | w = (const struct CACHED_INODE*)wanted; |
146 | c = (const struct CACHED_INODE*)cached; |
147 | if (w->pathname) { |
148 | len = strlen(w->pathname); |
149 | different = !cached->variable |
150 | || ((w->inum != MREF(c->inum)) |
151 | && (strncmp(c->pathname, w->pathname, len) |
152 | || ((c->pathname[len] != '\0') |
153 | && (c->pathname[len] != '/')))); |
154 | } else |
155 | different = !c->pathname |
156 | || (w->inum != MREF(c->inum)); |
157 | return (different); |
158 | } |
159 | |
160 | #endif |
161 | |
162 | #if CACHE_LOOKUP_SIZE |
163 | |
164 | /* |
165 | * File name comparing for entering/fetching from lookup cache |
166 | */ |
167 | |
168 | static int lookup_cache_compare(const struct CACHED_GENERIC *cached, |
169 | const struct CACHED_GENERIC *wanted) |
170 | { |
171 | const struct CACHED_LOOKUP *c = (const struct CACHED_LOOKUP*) cached; |
172 | const struct CACHED_LOOKUP *w = (const struct CACHED_LOOKUP*) wanted; |
173 | return (!c->name |
174 | || (c->parent != w->parent) |
175 | || (c->namesize != w->namesize) |
176 | || memcmp(c->name, w->name, c->namesize)); |
177 | } |
178 | |
179 | /* |
180 | * Inode number comparing for invalidating lookup cache |
181 | * |
182 | * All entries with designated inode number are invalidated |
183 | * |
184 | * Only use associated with a CACHE_NOHASH flag |
185 | */ |
186 | |
187 | static int lookup_cache_inv_compare(const struct CACHED_GENERIC *cached, |
188 | const struct CACHED_GENERIC *wanted) |
189 | { |
190 | const struct CACHED_LOOKUP *c = (const struct CACHED_LOOKUP*) cached; |
191 | const struct CACHED_LOOKUP *w = (const struct CACHED_LOOKUP*) wanted; |
192 | return (!c->name |
193 | || (c->parent != w->parent) |
194 | || (MREF(c->inum) != MREF(w->inum))); |
195 | } |
196 | |
197 | /* |
198 | * Lookup hashing |
199 | * |
200 | * Based on first, second and and last char |
201 | */ |
202 | |
203 | int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached) |
204 | { |
205 | const unsigned char *name; |
206 | int count; |
207 | unsigned int val; |
208 | |
209 | name = (const unsigned char*)cached->variable; |
210 | count = cached->varsize; |
211 | if (!name || !count) { |
212 | ntfs_log_error("Bad lookup cache entry\n"); |
213 | return (-1); |
214 | } |
215 | val = (name[0] << 2) + (name[1] << 1) + name[count - 1] + count; |
216 | return (val % (2*CACHE_LOOKUP_SIZE)); |
217 | } |
218 | |
219 | #endif |
220 | |
221 | /** |
222 | * ntfs_inode_lookup_by_name - find an inode in a directory given its name |
223 | * @dir_ni: ntfs inode of the directory in which to search for the name |
224 | * @uname: Unicode name for which to search in the directory |
225 | * @uname_len: length of the name @uname in Unicode characters |
226 | * |
227 | * Look for an inode with name @uname in the directory with inode @dir_ni. |
228 | * ntfs_inode_lookup_by_name() walks the contents of the directory looking for |
229 | * the Unicode name. If the name is found in the directory, the corresponding |
230 | * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it |
231 | * is a 64-bit number containing the sequence number. |
232 | * |
233 | * On error, return -1 with errno set to the error code. If the inode is is not |
234 | * found errno is ENOENT. |
235 | * |
236 | * Note, @uname_len does not include the (optional) terminating NULL character. |
237 | * |
238 | * Note, we look for a case sensitive match first but we also look for a case |
239 | * insensitive match at the same time. If we find a case insensitive match, we |
240 | * save that for the case that we don't find an exact match, where we return |
241 | * the mft reference of the case insensitive match. |
242 | * |
243 | * If the volume is mounted with the case sensitive flag set, then we only |
244 | * allow exact matches. |
245 | */ |
246 | u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, |
247 | const ntfschar *uname, const int uname_len) |
248 | { |
249 | VCN vcn; |
250 | u64 mref = 0; |
251 | s64 br; |
252 | ntfs_volume *vol = dir_ni->vol; |
253 | ntfs_attr_search_ctx *ctx; |
254 | INDEX_ROOT *ir; |
255 | INDEX_ENTRY *ie; |
256 | INDEX_ALLOCATION *ia; |
257 | IGNORE_CASE_BOOL case_sensitivity; |
258 | u8 *index_end; |
259 | ntfs_attr *ia_na; |
260 | int eo, rc; |
261 | u32 index_block_size; |
262 | u8 index_vcn_size_bits; |
263 | |
264 | ntfs_log_trace("Entering\n"); |
265 | |
266 | if (!dir_ni || !dir_ni->mrec || !uname || uname_len <= 0) { |
267 | errno = EINVAL; |
268 | return -1; |
269 | } |
270 | |
271 | ctx = ntfs_attr_get_search_ctx(dir_ni, NULL); |
272 | if (!ctx) |
273 | return -1; |
274 | |
275 | /* Find the index root attribute in the mft record. */ |
276 | if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, |
277 | 0, ctx)) { |
278 | ntfs_log_perror("Index root attribute missing in directory inode " |
279 | "%lld", (unsigned long long)dir_ni->mft_no); |
280 | goto put_err_out; |
281 | } |
282 | case_sensitivity = (NVolCaseSensitive(vol) ? CASE_SENSITIVE : IGNORE_CASE); |
283 | /* Get to the index root value. */ |
284 | ir = (INDEX_ROOT*)((u8*)ctx->attr + |
285 | le16_to_cpu(ctx->attr->value_offset)); |
286 | index_block_size = le32_to_cpu(ir->index_block_size); |
287 | if (index_block_size < NTFS_BLOCK_SIZE || |
288 | index_block_size & (index_block_size - 1)) { |
289 | ntfs_log_error("Index block size %u is invalid.\n", |
290 | (unsigned)index_block_size); |
291 | goto put_err_out; |
292 | } |
293 | index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); |
294 | /* The first index entry. */ |
295 | ie = (INDEX_ENTRY*)((u8*)&ir->index + |
296 | le32_to_cpu(ir->index.entries_offset)); |
297 | /* |
298 | * Loop until we exceed valid memory (corruption case) or until we |
299 | * reach the last entry. |
300 | */ |
301 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
302 | /* Bounds checks. */ |
303 | if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + |
304 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
305 | (u8*)ie + le16_to_cpu(ie->key_length) > |
306 | index_end) { |
307 | ntfs_log_error("Index entry out of bounds in inode %lld" |
308 | "\n", (unsigned long long)dir_ni->mft_no); |
309 | goto put_err_out; |
310 | } |
311 | /* |
312 | * The last entry cannot contain a name. It can however contain |
313 | * a pointer to a child node in the B+tree so we just break out. |
314 | */ |
315 | if (ie->ie_flags & INDEX_ENTRY_END) |
316 | break; |
317 | |
318 | if (!le16_to_cpu(ie->length)) { |
319 | ntfs_log_error("Zero length index entry in inode %lld" |
320 | "\n", (unsigned long long)dir_ni->mft_no); |
321 | goto put_err_out; |
322 | } |
323 | /* |
324 | * Not a perfect match, need to do full blown collation so we |
325 | * know which way in the B+tree we have to go. |
326 | */ |
327 | rc = ntfs_names_full_collate(uname, uname_len, |
328 | (ntfschar*)&ie->key.file_name.file_name, |
329 | ie->key.file_name.file_name_length, |
330 | case_sensitivity, vol->upcase, vol->upcase_len); |
331 | /* |
332 | * If uname collates before the name of the current entry, there |
333 | * is definitely no such name in this index but we might need to |
334 | * descend into the B+tree so we just break out of the loop. |
335 | */ |
336 | if (rc == -1) |
337 | break; |
338 | /* The names are not equal, continue the search. */ |
339 | if (rc) |
340 | continue; |
341 | /* |
342 | * Perfect match, this will never happen as the |
343 | * ntfs_are_names_equal() call will have gotten a match but we |
344 | * still treat it correctly. |
345 | */ |
346 | mref = le64_to_cpu(ie->indexed_file); |
347 | ntfs_attr_put_search_ctx(ctx); |
348 | return mref; |
349 | } |
350 | /* |
351 | * We have finished with this index without success. Check for the |
352 | * presence of a child node and if not present return error code |
353 | * ENOENT, unless we have got the mft reference of a matching name |
354 | * cached in mref in which case return mref. |
355 | */ |
356 | if (!(ie->ie_flags & INDEX_ENTRY_NODE)) { |
357 | ntfs_attr_put_search_ctx(ctx); |
358 | if (mref) |
359 | return mref; |
360 | ntfs_log_debug("Entry not found - between root entries.\n"); |
361 | errno = ENOENT; |
362 | return -1; |
363 | } /* Child node present, descend into it. */ |
364 | |
365 | /* Open the index allocation attribute. */ |
366 | ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); |
367 | if (!ia_na) { |
368 | ntfs_log_perror("Failed to open index allocation (inode %lld)", |
369 | (unsigned long long)dir_ni->mft_no); |
370 | goto put_err_out; |
371 | } |
372 | |
373 | /* Allocate a buffer for the current index block. */ |
374 | ia = ntfs_malloc(index_block_size); |
375 | if (!ia) { |
376 | ntfs_attr_close(ia_na); |
377 | goto put_err_out; |
378 | } |
379 | |
380 | /* Determine the size of a vcn in the directory index. */ |
381 | if (vol->cluster_size <= index_block_size) { |
382 | index_vcn_size_bits = vol->cluster_size_bits; |
383 | } else { |
384 | index_vcn_size_bits = NTFS_BLOCK_SIZE_BITS; |
385 | } |
386 | |
387 | /* Get the starting vcn of the index_block holding the child node. */ |
388 | vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8); |
389 | |
390 | descend_into_child_node: |
391 | |
392 | /* Read the index block starting at vcn. */ |
393 | br = ntfs_attr_mst_pread(ia_na, vcn << index_vcn_size_bits, 1, |
394 | index_block_size, ia); |
395 | if (br != 1) { |
396 | if (br != -1) |
397 | errno = EIO; |
398 | ntfs_log_perror("Failed to read vcn 0x%llx", |
399 | (unsigned long long)vcn); |
400 | goto close_err_out; |
401 | } |
402 | |
403 | if (sle64_to_cpu(ia->index_block_vcn) != vcn) { |
404 | ntfs_log_error("Actual VCN (0x%llx) of index buffer is different " |
405 | "from expected VCN (0x%llx).\n", |
406 | (long long)sle64_to_cpu(ia->index_block_vcn), |
407 | (long long)vcn); |
408 | errno = EIO; |
409 | goto close_err_out; |
410 | } |
411 | if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { |
412 | ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode 0x%llx " |
413 | "has a size (%u) differing from the directory " |
414 | "specified size (%u).\n", (long long)vcn, |
415 | (unsigned long long)dir_ni->mft_no, |
416 | (unsigned) le32_to_cpu(ia->index.allocated_size) + 0x18, |
417 | (unsigned)index_block_size); |
418 | errno = EIO; |
419 | goto close_err_out; |
420 | } |
421 | index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); |
422 | if (index_end > (u8*)ia + index_block_size) { |
423 | ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode " |
424 | "0x%llx exceeds maximum size.\n", |
425 | (long long)vcn, (unsigned long long)dir_ni->mft_no); |
426 | errno = EIO; |
427 | goto close_err_out; |
428 | } |
429 | |
430 | /* The first index entry. */ |
431 | ie = (INDEX_ENTRY*)((u8*)&ia->index + |
432 | le32_to_cpu(ia->index.entries_offset)); |
433 | /* |
434 | * Iterate similar to above big loop but applied to index buffer, thus |
435 | * loop until we exceed valid memory (corruption case) or until we |
436 | * reach the last entry. |
437 | */ |
438 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
439 | /* Bounds check. */ |
440 | if ((u8*)ie < (u8*)ia || (u8*)ie + |
441 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
442 | (u8*)ie + le16_to_cpu(ie->key_length) > |
443 | index_end) { |
444 | ntfs_log_error("Index entry out of bounds in directory " |
445 | "inode %lld.\n", |
446 | (unsigned long long)dir_ni->mft_no); |
447 | errno = EIO; |
448 | goto close_err_out; |
449 | } |
450 | /* |
451 | * The last entry cannot contain a name. It can however contain |
452 | * a pointer to a child node in the B+tree so we just break out. |
453 | */ |
454 | if (ie->ie_flags & INDEX_ENTRY_END) |
455 | break; |
456 | |
457 | if (!le16_to_cpu(ie->length)) { |
458 | errno = EIO; |
459 | ntfs_log_error("Zero length index entry in inode %lld" |
460 | "\n", (unsigned long long)dir_ni->mft_no); |
461 | goto close_err_out; |
462 | } |
463 | /* |
464 | * Not a perfect match, need to do full blown collation so we |
465 | * know which way in the B+tree we have to go. |
466 | */ |
467 | rc = ntfs_names_full_collate(uname, uname_len, |
468 | (ntfschar*)&ie->key.file_name.file_name, |
469 | ie->key.file_name.file_name_length, |
470 | case_sensitivity, vol->upcase, vol->upcase_len); |
471 | /* |
472 | * If uname collates before the name of the current entry, there |
473 | * is definitely no such name in this index but we might need to |
474 | * descend into the B+tree so we just break out of the loop. |
475 | */ |
476 | if (rc == -1) |
477 | break; |
478 | /* The names are not equal, continue the search. */ |
479 | if (rc) |
480 | continue; |
481 | mref = le64_to_cpu(ie->indexed_file); |
482 | free(ia); |
483 | ntfs_attr_close(ia_na); |
484 | ntfs_attr_put_search_ctx(ctx); |
485 | return mref; |
486 | } |
487 | /* |
488 | * We have finished with this index buffer without success. Check for |
489 | * the presence of a child node. |
490 | */ |
491 | if (ie->ie_flags & INDEX_ENTRY_NODE) { |
492 | if ((ia->index.ih_flags & NODE_MASK) == LEAF_NODE) { |
493 | ntfs_log_error("Index entry with child node found in a leaf " |
494 | "node in directory inode %lld.\n", |
495 | (unsigned long long)dir_ni->mft_no); |
496 | errno = EIO; |
497 | goto close_err_out; |
498 | } |
499 | /* Child node present, descend into it. */ |
500 | vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8); |
501 | if (vcn >= 0) |
502 | goto descend_into_child_node; |
503 | ntfs_log_error("Negative child node vcn in directory inode " |
504 | "0x%llx.\n", (unsigned long long)dir_ni->mft_no); |
505 | errno = EIO; |
506 | goto close_err_out; |
507 | } |
508 | free(ia); |
509 | ntfs_attr_close(ia_na); |
510 | ntfs_attr_put_search_ctx(ctx); |
511 | /* |
512 | * No child node present, return error code ENOENT, unless we have got |
513 | * the mft reference of a matching name cached in mref in which case |
514 | * return mref. |
515 | */ |
516 | if (mref) |
517 | return mref; |
518 | ntfs_log_debug("Entry not found.\n"); |
519 | errno = ENOENT; |
520 | return -1; |
521 | put_err_out: |
522 | eo = EIO; |
523 | ntfs_log_debug("Corrupt directory. Aborting lookup.\n"); |
524 | eo_put_err_out: |
525 | ntfs_attr_put_search_ctx(ctx); |
526 | errno = eo; |
527 | return -1; |
528 | close_err_out: |
529 | eo = errno; |
530 | free(ia); |
531 | ntfs_attr_close(ia_na); |
532 | goto eo_put_err_out; |
533 | } |
534 | |
535 | /* |
536 | * Lookup a file in a directory from its UTF-8 name |
537 | * |
538 | * The name is first fetched from cache if one is defined |
539 | * |
540 | * Returns the inode number |
541 | * or -1 if not possible (errno tells why) |
542 | */ |
543 | |
544 | u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name) |
545 | { |
546 | int uname_len; |
547 | ntfschar *uname = (ntfschar*)NULL; |
548 | u64 inum; |
549 | char *cached_name; |
550 | const char *const_name; |
551 | |
552 | if (!NVolCaseSensitive(dir_ni->vol)) { |
553 | cached_name = ntfs_uppercase_mbs(name, |
554 | dir_ni->vol->upcase, dir_ni->vol->upcase_len); |
555 | const_name = cached_name; |
556 | } else { |
557 | cached_name = (char*)NULL; |
558 | const_name = name; |
559 | } |
560 | if (const_name) { |
561 | #if CACHE_LOOKUP_SIZE |
562 | |
563 | /* |
564 | * fetch inode from cache |
565 | */ |
566 | |
567 | if (dir_ni->vol->lookup_cache) { |
568 | struct CACHED_LOOKUP item; |
569 | struct CACHED_LOOKUP *cached; |
570 | |
571 | item.name = const_name; |
572 | item.namesize = strlen(const_name) + 1; |
573 | item.parent = dir_ni->mft_no; |
574 | cached = (struct CACHED_LOOKUP*)ntfs_fetch_cache( |
575 | dir_ni->vol->lookup_cache, |
576 | GENERIC(&item), lookup_cache_compare); |
577 | if (cached) { |
578 | inum = cached->inum; |
579 | if (inum == (u64)-1) |
580 | errno = ENOENT; |
581 | } else { |
582 | /* Generate unicode name. */ |
583 | uname_len = ntfs_mbstoucs(name, &uname); |
584 | if (uname_len >= 0) { |
585 | inum = ntfs_inode_lookup_by_name(dir_ni, |
586 | uname, uname_len); |
587 | item.inum = inum; |
588 | /* enter into cache, even if not found */ |
589 | ntfs_enter_cache(dir_ni->vol->lookup_cache, |
590 | GENERIC(&item), |
591 | lookup_cache_compare); |
592 | free(uname); |
593 | } else |
594 | inum = (s64)-1; |
595 | } |
596 | } else |
597 | #endif |
598 | { |
599 | /* Generate unicode name. */ |
600 | uname_len = ntfs_mbstoucs(cached_name, &uname); |
601 | if (uname_len >= 0) |
602 | inum = ntfs_inode_lookup_by_name(dir_ni, |
603 | uname, uname_len); |
604 | else |
605 | inum = (s64)-1; |
606 | } |
607 | if (cached_name) |
608 | free(cached_name); |
609 | } else |
610 | inum = (s64)-1; |
611 | return (inum); |
612 | } |
613 | |
614 | /* |
615 | * Update a cache lookup record when a name has been defined |
616 | * |
617 | * The UTF-8 name is required |
618 | */ |
619 | |
620 | void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, u64 inum) |
621 | { |
622 | #if CACHE_LOOKUP_SIZE |
623 | struct CACHED_LOOKUP item; |
624 | struct CACHED_LOOKUP *cached; |
625 | char *cached_name; |
626 | |
627 | if (dir_ni->vol->lookup_cache) { |
628 | if (!NVolCaseSensitive(dir_ni->vol)) { |
629 | cached_name = ntfs_uppercase_mbs(name, |
630 | dir_ni->vol->upcase, dir_ni->vol->upcase_len); |
631 | item.name = cached_name; |
632 | } else { |
633 | cached_name = (char*)NULL; |
634 | item.name = name; |
635 | } |
636 | if (item.name) { |
637 | item.namesize = strlen(item.name) + 1; |
638 | item.parent = dir_ni->mft_no; |
639 | item.inum = inum; |
640 | cached = (struct CACHED_LOOKUP*)ntfs_enter_cache( |
641 | dir_ni->vol->lookup_cache, |
642 | GENERIC(&item), lookup_cache_compare); |
643 | if (cached) |
644 | cached->inum = inum; |
645 | if (cached_name) |
646 | free(cached_name); |
647 | } |
648 | } |
649 | #endif |
650 | } |
651 | |
652 | /** |
653 | * ntfs_pathname_to_inode - Find the inode which represents the given pathname |
654 | * @vol: An ntfs volume obtained from ntfs_mount |
655 | * @parent: A directory inode to begin the search (may be NULL) |
656 | * @pathname: Pathname to be located |
657 | * |
658 | * Take an ASCII pathname and find the inode that represents it. The function |
659 | * splits the path and then descends the directory tree. If @parent is NULL, |
660 | * then the root directory '.' will be used as the base for the search. |
661 | * |
662 | * Return: inode Success, the pathname was valid |
663 | * NULL Error, the pathname was invalid, or some other error occurred |
664 | */ |
665 | ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, |
666 | const char *pathname) |
667 | { |
668 | u64 inum; |
669 | int len, err = 0; |
670 | char *p, *q; |
671 | ntfs_inode *ni; |
672 | ntfs_inode *result = NULL; |
673 | ntfschar *unicode = NULL; |
674 | char *ascii = NULL; |
675 | #if CACHE_INODE_SIZE |
676 | struct CACHED_INODE item; |
677 | struct CACHED_INODE *cached; |
678 | char *fullname; |
679 | #endif |
680 | |
681 | if (!vol || !pathname) { |
682 | errno = EINVAL; |
683 | return NULL; |
684 | } |
685 | |
686 | ntfs_log_trace("path: '%s'\n", pathname); |
687 | |
688 | ascii = strdup(pathname); |
689 | if (!ascii) { |
690 | ntfs_log_error("Out of memory.\n"); |
691 | err = ENOMEM; |
692 | goto out; |
693 | } |
694 | |
695 | p = ascii; |
696 | /* Remove leading /'s. */ |
697 | while (p && *p && *p == PATH_SEP) |
698 | p++; |
699 | #if CACHE_INODE_SIZE |
700 | fullname = p; |
701 | if (p[0] && (p[strlen(p)-1] == PATH_SEP)) |
702 | ntfs_log_error("Unnormalized path %s\n",ascii); |
703 | #endif |
704 | if (parent) { |
705 | ni = parent; |
706 | } else { |
707 | #if CACHE_INODE_SIZE |
708 | /* |
709 | * fetch inode for full path from cache |
710 | */ |
711 | if (*fullname) { |
712 | item.pathname = fullname; |
713 | item.varsize = strlen(fullname) + 1; |
714 | cached = (struct CACHED_INODE*)ntfs_fetch_cache( |
715 | vol->xinode_cache, GENERIC(&item), |
716 | inode_cache_compare); |
717 | } else |
718 | cached = (struct CACHED_INODE*)NULL; |
719 | if (cached) { |
720 | /* |
721 | * return opened inode if found in cache |
722 | */ |
723 | inum = MREF(cached->inum); |
724 | ni = ntfs_inode_open(vol, inum); |
725 | if (!ni) { |
726 | ntfs_log_debug("Cannot open inode %llu: %s.\n", |
727 | (unsigned long long)inum, p); |
728 | err = EIO; |
729 | } |
730 | result = ni; |
731 | goto out; |
732 | } |
733 | #endif |
734 | ni = ntfs_inode_open(vol, FILE_root); |
735 | if (!ni) { |
736 | ntfs_log_debug("Couldn't open the inode of the root " |
737 | "directory.\n"); |
738 | err = EIO; |
739 | result = (ntfs_inode*)NULL; |
740 | goto out; |
741 | } |
742 | } |
743 | |
744 | while (p && *p) { |
745 | /* Find the end of the first token. */ |
746 | q = strchr(p, PATH_SEP); |
747 | if (q != NULL) { |
748 | *q = '\0'; |
749 | } |
750 | #if CACHE_INODE_SIZE |
751 | /* |
752 | * fetch inode for partial path from cache |
753 | */ |
754 | cached = (struct CACHED_INODE*)NULL; |
755 | if (!parent) { |
756 | item.pathname = fullname; |
757 | item.varsize = strlen(fullname) + 1; |
758 | cached = (struct CACHED_INODE*)ntfs_fetch_cache( |
759 | vol->xinode_cache, GENERIC(&item), |
760 | inode_cache_compare); |
761 | if (cached) { |
762 | inum = cached->inum; |
763 | } |
764 | } |
765 | /* |
766 | * if not in cache, translate, search, then |
767 | * insert into cache if found |
768 | */ |
769 | if (!cached) { |
770 | len = ntfs_mbstoucs(p, &unicode); |
771 | if (len < 0) { |
772 | ntfs_log_perror("Could not convert filename to Unicode:" |
773 | " '%s'", p); |
774 | err = errno; |
775 | goto close; |
776 | } else if (len > NTFS_MAX_NAME_LEN) { |
777 | err = ENAMETOOLONG; |
778 | goto close; |
779 | } |
780 | inum = ntfs_inode_lookup_by_name(ni, unicode, len); |
781 | if (!parent && (inum != (u64) -1)) { |
782 | item.inum = inum; |
783 | ntfs_enter_cache(vol->xinode_cache, |
784 | GENERIC(&item), |
785 | inode_cache_compare); |
786 | } |
787 | } |
788 | #else |
789 | len = ntfs_mbstoucs(p, &unicode); |
790 | if (len < 0) { |
791 | ntfs_log_perror("Could not convert filename to Unicode:" |
792 | " '%s'", p); |
793 | err = errno; |
794 | goto close; |
795 | } else if (len > NTFS_MAX_NAME_LEN) { |
796 | err = ENAMETOOLONG; |
797 | goto close; |
798 | } |
799 | inum = ntfs_inode_lookup_by_name(ni, unicode, len); |
800 | #endif |
801 | if (inum == (u64) -1) { |
802 | ntfs_log_debug("Couldn't find name '%s' in pathname " |
803 | "'%s'.\n", p, pathname); |
804 | err = ENOENT; |
805 | goto close; |
806 | } |
807 | |
808 | if (ni != parent) |
809 | if (ntfs_inode_close(ni)) { |
810 | err = errno; |
811 | goto out; |
812 | } |
813 | |
814 | inum = MREF(inum); |
815 | ni = ntfs_inode_open(vol, inum); |
816 | if (!ni) { |
817 | ntfs_log_debug("Cannot open inode %llu: %s.\n", |
818 | (unsigned long long)inum, p); |
819 | err = EIO; |
820 | goto close; |
821 | } |
822 | |
823 | free(unicode); |
824 | unicode = NULL; |
825 | |
826 | if (q) *q++ = PATH_SEP; /* JPA */ |
827 | p = q; |
828 | while (p && *p && *p == PATH_SEP) |
829 | p++; |
830 | } |
831 | |
832 | result = ni; |
833 | ni = NULL; |
834 | close: |
835 | if (ni && (ni != parent)) |
836 | if (ntfs_inode_close(ni) && !err) |
837 | err = errno; |
838 | out: |
839 | free(ascii); |
840 | free(unicode); |
841 | if (err) |
842 | errno = err; |
843 | return result; |
844 | } |
845 | |
846 | /* |
847 | * The little endian Unicode string ".." for ntfs_readdir(). |
848 | */ |
849 | static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), |
850 | const_cpu_to_le16('.'), |
851 | const_cpu_to_le16('\0') }; |
852 | |
853 | /* |
854 | * union index_union - |
855 | * More helpers for ntfs_readdir(). |
856 | */ |
857 | typedef union { |
858 | INDEX_ROOT *ir; |
859 | INDEX_ALLOCATION *ia; |
860 | } index_union __attribute__((__transparent_union__)); |
861 | |
862 | /** |
863 | * enum INDEX_TYPE - |
864 | * More helpers for ntfs_readdir(). |
865 | */ |
866 | typedef enum { |
867 | INDEX_TYPE_ROOT, /* index root */ |
868 | INDEX_TYPE_ALLOCATION, /* index allocation */ |
869 | } INDEX_TYPE; |
870 | |
871 | /* |
872 | * Decode Interix file types |
873 | * |
874 | * Non-Interix types are returned as plain files, because a |
875 | * Windows user may force patterns very similar to Interix, |
876 | * and most metadata files have such similar patters. |
877 | */ |
878 | |
879 | static u32 ntfs_interix_types(ntfs_inode *ni) |
880 | { |
881 | ntfs_attr *na; |
882 | u32 dt_type; |
883 | le64 magic; |
884 | |
885 | dt_type = NTFS_DT_UNKNOWN; |
886 | na = ntfs_attr_open(ni, AT_DATA, NULL, 0); |
887 | if (na) { |
888 | /* Unrecognized patterns (eg HID + SYST) are plain files */ |
889 | dt_type = NTFS_DT_REG; |
890 | if (na->data_size <= 1) { |
891 | if (!(ni->flags & FILE_ATTR_HIDDEN)) |
892 | dt_type = (na->data_size ? |
893 | NTFS_DT_SOCK : NTFS_DT_FIFO); |
894 | } else { |
895 | if ((na->data_size >= (s64)sizeof(magic)) |
896 | && (ntfs_attr_pread(na, 0, sizeof(magic), &magic) |
897 | == sizeof(magic))) { |
898 | if (magic == INTX_SYMBOLIC_LINK) |
899 | dt_type = NTFS_DT_LNK; |
900 | else if (magic == INTX_BLOCK_DEVICE) |
901 | dt_type = NTFS_DT_BLK; |
902 | else if (magic == INTX_CHARACTER_DEVICE) |
903 | dt_type = NTFS_DT_CHR; |
904 | } |
905 | } |
906 | ntfs_attr_close(na); |
907 | } |
908 | return (dt_type); |
909 | } |
910 | |
911 | /* |
912 | * Decode file types |
913 | * |
914 | * Better only use for Interix types and junctions, |
915 | * unneeded complexity when used for plain files or directories |
916 | * |
917 | * Error cases are logged and returned as unknown. |
918 | */ |
919 | |
920 | static u32 ntfs_dir_entry_type(ntfs_inode *dir_ni, MFT_REF mref, |
921 | FILE_ATTR_FLAGS attributes) |
922 | { |
923 | ntfs_inode *ni; |
924 | u32 dt_type; |
925 | |
926 | dt_type = NTFS_DT_UNKNOWN; |
927 | ni = ntfs_inode_open(dir_ni->vol, mref); |
928 | if (ni) { |
929 | if ((attributes & FILE_ATTR_REPARSE_POINT) |
930 | && ntfs_possible_symlink(ni)) |
931 | dt_type = NTFS_DT_LNK; |
932 | else |
933 | if ((attributes & FILE_ATTR_SYSTEM) |
934 | && !(attributes & FILE_ATTR_I30_INDEX_PRESENT)) |
935 | dt_type = ntfs_interix_types(ni); |
936 | else |
937 | dt_type = (attributes |
938 | & FILE_ATTR_I30_INDEX_PRESENT |
939 | ? NTFS_DT_DIR : NTFS_DT_REG); |
940 | if (ntfs_inode_close(ni)) { |
941 | /* anything special worth doing ? */ |
942 | ntfs_log_error("Failed to close inode %lld\n", |
943 | (long long)MREF(mref)); |
944 | } |
945 | } |
946 | if (dt_type == NTFS_DT_UNKNOWN) |
947 | ntfs_log_error("Could not decode the type of inode %lld\n", |
948 | (long long)MREF(mref)); |
949 | return (dt_type); |
950 | } |
951 | |
952 | /** |
953 | * ntfs_filldir - ntfs specific filldir method |
954 | * @dir_ni: ntfs inode of current directory |
955 | * @pos: current position in directory |
956 | * @ivcn_bits: log(2) of index vcn size |
957 | * @index_type: specifies whether @iu is an index root or an index allocation |
958 | * @iu: index root or index block to which @ie belongs |
959 | * @ie: current index entry |
960 | * @dirent: context for filldir callback supplied by the caller |
961 | * @filldir: filldir callback supplied by the caller |
962 | * |
963 | * Pass information specifying the current directory entry @ie to the @filldir |
964 | * callback. |
965 | */ |
966 | static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, |
967 | const INDEX_TYPE index_type, index_union iu, INDEX_ENTRY *ie, |
968 | void *dirent, ntfs_filldir_t filldir) |
969 | { |
970 | FILE_NAME_ATTR *fn = &ie->key.file_name; |
971 | unsigned dt_type; |
972 | BOOL metadata; |
973 | ntfschar *loname; |
974 | int res; |
975 | MFT_REF mref; |
976 | |
977 | ntfs_log_trace("Entering.\n"); |
978 | |
979 | /* Advance the position even if going to skip the entry. */ |
980 | if (index_type == INDEX_TYPE_ALLOCATION) |
981 | *pos = (u8*)ie - (u8*)iu.ia + (sle64_to_cpu( |
982 | iu.ia->index_block_vcn) << ivcn_bits) + |
983 | dir_ni->vol->mft_record_size; |
984 | else /* if (index_type == INDEX_TYPE_ROOT) */ |
985 | *pos = (u8*)ie - (u8*)iu.ir; |
986 | mref = le64_to_cpu(ie->indexed_file); |
987 | metadata = (MREF(mref) != FILE_root) && (MREF(mref) < FILE_first_user); |
988 | /* Skip root directory self reference entry. */ |
989 | if (MREF_LE(ie->indexed_file) == FILE_root) |
990 | return 0; |
991 | if ((ie->key.file_name.file_attributes |
992 | & (FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYSTEM)) |
993 | && !metadata) |
994 | dt_type = ntfs_dir_entry_type(dir_ni, mref, |
995 | ie->key.file_name.file_attributes); |
996 | else if (ie->key.file_name.file_attributes |
997 | & FILE_ATTR_I30_INDEX_PRESENT) |
998 | dt_type = NTFS_DT_DIR; |
999 | else |
1000 | dt_type = NTFS_DT_REG; |
1001 | |
1002 | /* return metadata files and hidden files if requested */ |
1003 | if ((!metadata && (NVolShowHidFiles(dir_ni->vol) |
1004 | || !(fn->file_attributes & FILE_ATTR_HIDDEN))) |
1005 | || (NVolShowSysFiles(dir_ni->vol) && (NVolShowHidFiles(dir_ni->vol) |
1006 | || metadata))) { |
1007 | if (NVolCaseSensitive(dir_ni->vol)) { |
1008 | res = filldir(dirent, fn->file_name, |
1009 | fn->file_name_length, |
1010 | fn->file_name_type, *pos, |
1011 | mref, dt_type); |
1012 | } else { |
1013 | loname = (ntfschar*)ntfs_malloc(2*fn->file_name_length); |
1014 | if (loname) { |
1015 | memcpy(loname, fn->file_name, |
1016 | 2*fn->file_name_length); |
1017 | ntfs_name_locase(loname, fn->file_name_length, |
1018 | dir_ni->vol->locase, |
1019 | dir_ni->vol->upcase_len); |
1020 | res = filldir(dirent, loname, |
1021 | fn->file_name_length, |
1022 | fn->file_name_type, *pos, |
1023 | mref, dt_type); |
1024 | free(loname); |
1025 | } else |
1026 | res = -1; |
1027 | } |
1028 | } else |
1029 | res = 0; |
1030 | return (res); |
1031 | } |
1032 | |
1033 | /** |
1034 | * ntfs_mft_get_parent_ref - find mft reference of parent directory of an inode |
1035 | * @ni: ntfs inode whose parent directory to find |
1036 | * |
1037 | * Find the parent directory of the ntfs inode @ni. To do this, find the first |
1038 | * file name attribute in the mft record of @ni and return the parent mft |
1039 | * reference from that. |
1040 | * |
1041 | * Note this only makes sense for directories, since files can be hard linked |
1042 | * from multiple directories and there is no way for us to tell which one is |
1043 | * being looked for. |
1044 | * |
1045 | * Technically directories can have hard links, too, but we consider that as |
1046 | * illegal as Linux/UNIX do not support directory hard links. |
1047 | * |
1048 | * Return the mft reference of the parent directory on success or -1 on error |
1049 | * with errno set to the error code. |
1050 | */ |
1051 | static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni) |
1052 | { |
1053 | MFT_REF mref; |
1054 | ntfs_attr_search_ctx *ctx; |
1055 | FILE_NAME_ATTR *fn; |
1056 | int eo; |
1057 | |
1058 | ntfs_log_trace("Entering.\n"); |
1059 | |
1060 | if (!ni) { |
1061 | errno = EINVAL; |
1062 | return ERR_MREF(-1); |
1063 | } |
1064 | |
1065 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1066 | if (!ctx) |
1067 | return ERR_MREF(-1); |
1068 | if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { |
1069 | ntfs_log_error("No file name found in inode %lld\n", |
1070 | (unsigned long long)ni->mft_no); |
1071 | goto err_out; |
1072 | } |
1073 | if (ctx->attr->non_resident) { |
1074 | ntfs_log_error("File name attribute must be resident (inode " |
1075 | "%lld)\n", (unsigned long long)ni->mft_no); |
1076 | goto io_err_out; |
1077 | } |
1078 | fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + |
1079 | le16_to_cpu(ctx->attr->value_offset)); |
1080 | if ((u8*)fn + le32_to_cpu(ctx->attr->value_length) > |
1081 | (u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) { |
1082 | ntfs_log_error("Corrupt file name attribute in inode %lld.\n", |
1083 | (unsigned long long)ni->mft_no); |
1084 | goto io_err_out; |
1085 | } |
1086 | mref = le64_to_cpu(fn->parent_directory); |
1087 | ntfs_attr_put_search_ctx(ctx); |
1088 | return mref; |
1089 | io_err_out: |
1090 | errno = EIO; |
1091 | err_out: |
1092 | eo = errno; |
1093 | ntfs_attr_put_search_ctx(ctx); |
1094 | errno = eo; |
1095 | return ERR_MREF(-1); |
1096 | } |
1097 | |
1098 | /** |
1099 | * ntfs_readdir - read the contents of an ntfs directory |
1100 | * @dir_ni: ntfs inode of current directory |
1101 | * @pos: current position in directory |
1102 | * @dirent: context for filldir callback supplied by the caller |
1103 | * @filldir: filldir callback supplied by the caller |
1104 | * |
1105 | * Parse the index root and the index blocks that are marked in use in the |
1106 | * index bitmap and hand each found directory entry to the @filldir callback |
1107 | * supplied by the caller. |
1108 | * |
1109 | * Return 0 on success or -1 on error with errno set to the error code. |
1110 | * |
1111 | * Note: Index blocks are parsed in ascending vcn order, from which follows |
1112 | * that the directory entries are not returned sorted. |
1113 | */ |
1114 | int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, |
1115 | void *dirent, ntfs_filldir_t filldir) |
1116 | { |
1117 | s64 i_size, br, ia_pos, bmp_pos, ia_start; |
1118 | ntfs_volume *vol; |
1119 | ntfs_attr *ia_na, *bmp_na = NULL; |
1120 | ntfs_attr_search_ctx *ctx = NULL; |
1121 | u8 *index_end, *bmp = NULL; |
1122 | INDEX_ROOT *ir; |
1123 | INDEX_ENTRY *ie; |
1124 | INDEX_ALLOCATION *ia = NULL; |
1125 | int rc, ir_pos, bmp_buf_size, bmp_buf_pos, eo; |
1126 | u32 index_block_size; |
1127 | u8 index_block_size_bits, index_vcn_size_bits; |
1128 | |
1129 | ntfs_log_trace("Entering.\n"); |
1130 | |
1131 | if (!dir_ni || !pos || !filldir) { |
1132 | errno = EINVAL; |
1133 | return -1; |
1134 | } |
1135 | |
1136 | if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { |
1137 | errno = ENOTDIR; |
1138 | return -1; |
1139 | } |
1140 | |
1141 | vol = dir_ni->vol; |
1142 | |
1143 | ntfs_log_trace("Entering for inode %lld, *pos 0x%llx.\n", |
1144 | (unsigned long long)dir_ni->mft_no, (long long)*pos); |
1145 | |
1146 | /* Open the index allocation attribute. */ |
1147 | ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); |
1148 | if (!ia_na) { |
1149 | if (errno != ENOENT) { |
1150 | ntfs_log_perror("Failed to open index allocation attribute. " |
1151 | "Directory inode %lld is corrupt or bug", |
1152 | (unsigned long long)dir_ni->mft_no); |
1153 | return -1; |
1154 | } |
1155 | i_size = 0; |
1156 | } else |
1157 | i_size = ia_na->data_size; |
1158 | |
1159 | rc = 0; |
1160 | |
1161 | /* Are we at end of dir yet? */ |
1162 | if (*pos >= i_size + vol->mft_record_size) |
1163 | goto done; |
1164 | |
1165 | /* Emulate . and .. for all directories. */ |
1166 | if (!*pos) { |
1167 | rc = filldir(dirent, dotdot, 1, FILE_NAME_POSIX, *pos, |
1168 | MK_MREF(dir_ni->mft_no, |
1169 | le16_to_cpu(dir_ni->mrec->sequence_number)), |
1170 | NTFS_DT_DIR); |
1171 | if (rc) |
1172 | goto err_out; |
1173 | ++*pos; |
1174 | } |
1175 | if (*pos == 1) { |
1176 | MFT_REF parent_mref; |
1177 | |
1178 | parent_mref = ntfs_mft_get_parent_ref(dir_ni); |
1179 | if (parent_mref == ERR_MREF(-1)) { |
1180 | ntfs_log_perror("Parent directory not found"); |
1181 | goto dir_err_out; |
1182 | } |
1183 | |
1184 | rc = filldir(dirent, dotdot, 2, FILE_NAME_POSIX, *pos, |
1185 | parent_mref, NTFS_DT_DIR); |
1186 | if (rc) |
1187 | goto err_out; |
1188 | ++*pos; |
1189 | } |
1190 | |
1191 | ctx = ntfs_attr_get_search_ctx(dir_ni, NULL); |
1192 | if (!ctx) |
1193 | goto err_out; |
1194 | |
1195 | /* Get the offset into the index root attribute. */ |
1196 | ir_pos = (int)*pos; |
1197 | /* Find the index root attribute in the mft record. */ |
1198 | if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, |
1199 | 0, ctx)) { |
1200 | ntfs_log_perror("Index root attribute missing in directory inode " |
1201 | "%lld", (unsigned long long)dir_ni->mft_no); |
1202 | goto dir_err_out; |
1203 | } |
1204 | /* Get to the index root value. */ |
1205 | ir = (INDEX_ROOT*)((u8*)ctx->attr + |
1206 | le16_to_cpu(ctx->attr->value_offset)); |
1207 | |
1208 | /* Determine the size of a vcn in the directory index. */ |
1209 | index_block_size = le32_to_cpu(ir->index_block_size); |
1210 | if (index_block_size < NTFS_BLOCK_SIZE || |
1211 | index_block_size & (index_block_size - 1)) { |
1212 | ntfs_log_error("Index block size %u is invalid.\n", |
1213 | (unsigned)index_block_size); |
1214 | goto dir_err_out; |
1215 | } |
1216 | index_block_size_bits = ffs(index_block_size) - 1; |
1217 | if (vol->cluster_size <= index_block_size) { |
1218 | index_vcn_size_bits = vol->cluster_size_bits; |
1219 | } else { |
1220 | index_vcn_size_bits = NTFS_BLOCK_SIZE_BITS; |
1221 | } |
1222 | |
1223 | /* Are we jumping straight into the index allocation attribute? */ |
1224 | if (*pos >= vol->mft_record_size) { |
1225 | ntfs_attr_put_search_ctx(ctx); |
1226 | ctx = NULL; |
1227 | goto skip_index_root; |
1228 | } |
1229 | |
1230 | index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); |
1231 | /* The first index entry. */ |
1232 | ie = (INDEX_ENTRY*)((u8*)&ir->index + |
1233 | le32_to_cpu(ir->index.entries_offset)); |
1234 | /* |
1235 | * Loop until we exceed valid memory (corruption case) or until we |
1236 | * reach the last entry or until filldir tells us it has had enough |
1237 | * or signals an error (both covered by the rc test). |
1238 | */ |
1239 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
1240 | ntfs_log_debug("In index root, offset %d.\n", (int)((u8*)ie - (u8*)ir)); |
1241 | /* Bounds checks. */ |
1242 | if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + |
1243 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
1244 | (u8*)ie + le16_to_cpu(ie->key_length) > |
1245 | index_end) |
1246 | goto dir_err_out; |
1247 | /* The last entry cannot contain a name. */ |
1248 | if (ie->ie_flags & INDEX_ENTRY_END) |
1249 | break; |
1250 | |
1251 | if (!le16_to_cpu(ie->length)) |
1252 | goto dir_err_out; |
1253 | |
1254 | /* Skip index root entry if continuing previous readdir. */ |
1255 | if (ir_pos > (u8*)ie - (u8*)ir) |
1256 | continue; |
1257 | /* |
1258 | * Submit the directory entry to ntfs_filldir(), which will |
1259 | * invoke the filldir() callback as appropriate. |
1260 | */ |
1261 | rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits, |
1262 | INDEX_TYPE_ROOT, ir, ie, dirent, filldir); |
1263 | if (rc) { |
1264 | ntfs_attr_put_search_ctx(ctx); |
1265 | ctx = NULL; |
1266 | goto err_out; |
1267 | } |
1268 | } |
1269 | ntfs_attr_put_search_ctx(ctx); |
1270 | ctx = NULL; |
1271 | |
1272 | /* If there is no index allocation attribute we are finished. */ |
1273 | if (!ia_na) |
1274 | goto EOD; |
1275 | |
1276 | /* Advance *pos to the beginning of the index allocation. */ |
1277 | *pos = vol->mft_record_size; |
1278 | |
1279 | skip_index_root: |
1280 | |
1281 | if (!ia_na) |
1282 | goto done; |
1283 | |
1284 | /* Allocate a buffer for the current index block. */ |
1285 | ia = ntfs_malloc(index_block_size); |
1286 | if (!ia) |
1287 | goto err_out; |
1288 | |
1289 | bmp_na = ntfs_attr_open(dir_ni, AT_BITMAP, NTFS_INDEX_I30, 4); |
1290 | if (!bmp_na) { |
1291 | ntfs_log_perror("Failed to open index bitmap attribute"); |
1292 | goto dir_err_out; |
1293 | } |
1294 | |
1295 | /* Get the offset into the index allocation attribute. */ |
1296 | ia_pos = *pos - vol->mft_record_size; |
1297 | |
1298 | bmp_pos = ia_pos >> index_block_size_bits; |
1299 | if (bmp_pos >> 3 >= bmp_na->data_size) { |
1300 | ntfs_log_error("Current index position exceeds index bitmap " |
1301 | "size.\n"); |
1302 | goto dir_err_out; |
1303 | } |
1304 | |
1305 | bmp_buf_size = min(bmp_na->data_size - (bmp_pos >> 3), 4096); |
1306 | bmp = ntfs_malloc(bmp_buf_size); |
1307 | if (!bmp) |
1308 | goto err_out; |
1309 | |
1310 | br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp); |
1311 | if (br != bmp_buf_size) { |
1312 | if (br != -1) |
1313 | errno = EIO; |
1314 | ntfs_log_perror("Failed to read from index bitmap attribute"); |
1315 | goto err_out; |
1316 | } |
1317 | |
1318 | bmp_buf_pos = 0; |
1319 | /* If the index block is not in use find the next one that is. */ |
1320 | while (!(bmp[bmp_buf_pos >> 3] & (1 << (bmp_buf_pos & 7)))) { |
1321 | find_next_index_buffer: |
1322 | bmp_pos++; |
1323 | bmp_buf_pos++; |
1324 | /* If we have reached the end of the bitmap, we are done. */ |
1325 | if (bmp_pos >> 3 >= bmp_na->data_size) |
1326 | goto EOD; |
1327 | ia_pos = bmp_pos << index_block_size_bits; |
1328 | if (bmp_buf_pos >> 3 < bmp_buf_size) |
1329 | continue; |
1330 | /* Read next chunk from the index bitmap. */ |
1331 | bmp_buf_pos = 0; |
1332 | if ((bmp_pos >> 3) + bmp_buf_size > bmp_na->data_size) |
1333 | bmp_buf_size = bmp_na->data_size - (bmp_pos >> 3); |
1334 | br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp); |
1335 | if (br != bmp_buf_size) { |
1336 | if (br != -1) |
1337 | errno = EIO; |
1338 | ntfs_log_perror("Failed to read from index bitmap attribute"); |
1339 | goto err_out; |
1340 | } |
1341 | } |
1342 | |
1343 | ntfs_log_debug("Handling index block 0x%llx.\n", (long long)bmp_pos); |
1344 | |
1345 | /* Read the index block starting at bmp_pos. */ |
1346 | br = ntfs_attr_mst_pread(ia_na, bmp_pos << index_block_size_bits, 1, |
1347 | index_block_size, ia); |
1348 | if (br != 1) { |
1349 | if (br != -1) |
1350 | errno = EIO; |
1351 | ntfs_log_perror("Failed to read index block"); |
1352 | goto err_out; |
1353 | } |
1354 | |
1355 | ia_start = ia_pos & ~(s64)(index_block_size - 1); |
1356 | if (sle64_to_cpu(ia->index_block_vcn) != ia_start >> |
1357 | index_vcn_size_bits) { |
1358 | ntfs_log_error("Actual VCN (0x%llx) of index buffer is different " |
1359 | "from expected VCN (0x%llx) in inode 0x%llx.\n", |
1360 | (long long)sle64_to_cpu(ia->index_block_vcn), |
1361 | (long long)ia_start >> index_vcn_size_bits, |
1362 | (unsigned long long)dir_ni->mft_no); |
1363 | goto dir_err_out; |
1364 | } |
1365 | if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { |
1366 | ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode %lld " |
1367 | "has a size (%u) differing from the directory " |
1368 | "specified size (%u).\n", (long long)ia_start >> |
1369 | index_vcn_size_bits, |
1370 | (unsigned long long)dir_ni->mft_no, |
1371 | (unsigned) le32_to_cpu(ia->index.allocated_size) |
1372 | + 0x18, (unsigned)index_block_size); |
1373 | goto dir_err_out; |
1374 | } |
1375 | index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); |
1376 | if (index_end > (u8*)ia + index_block_size) { |
1377 | ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode " |
1378 | "%lld exceeds maximum size.\n", |
1379 | (long long)ia_start >> index_vcn_size_bits, |
1380 | (unsigned long long)dir_ni->mft_no); |
1381 | goto dir_err_out; |
1382 | } |
1383 | /* The first index entry. */ |
1384 | ie = (INDEX_ENTRY*)((u8*)&ia->index + |
1385 | le32_to_cpu(ia->index.entries_offset)); |
1386 | /* |
1387 | * Loop until we exceed valid memory (corruption case) or until we |
1388 | * reach the last entry or until ntfs_filldir tells us it has had |
1389 | * enough or signals an error (both covered by the rc test). |
1390 | */ |
1391 | for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { |
1392 | ntfs_log_debug("In index allocation, offset 0x%llx.\n", |
1393 | (long long)ia_start + ((u8*)ie - (u8*)ia)); |
1394 | /* Bounds checks. */ |
1395 | if ((u8*)ie < (u8*)ia || (u8*)ie + |
1396 | sizeof(INDEX_ENTRY_HEADER) > index_end || |
1397 | (u8*)ie + le16_to_cpu(ie->key_length) > |
1398 | index_end) { |
1399 | ntfs_log_error("Index entry out of bounds in directory inode " |
1400 | "%lld.\n", (unsigned long long)dir_ni->mft_no); |
1401 | goto dir_err_out; |
1402 | } |
1403 | /* The last entry cannot contain a name. */ |
1404 | if (ie->ie_flags & INDEX_ENTRY_END) |
1405 | break; |
1406 | |
1407 | if (!le16_to_cpu(ie->length)) |
1408 | goto dir_err_out; |
1409 | |
1410 | /* Skip index entry if continuing previous readdir. */ |
1411 | if (ia_pos - ia_start > (u8*)ie - (u8*)ia) |
1412 | continue; |
1413 | /* |
1414 | * Submit the directory entry to ntfs_filldir(), which will |
1415 | * invoke the filldir() callback as appropriate. |
1416 | */ |
1417 | rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits, |
1418 | INDEX_TYPE_ALLOCATION, ia, ie, dirent, filldir); |
1419 | if (rc) |
1420 | goto err_out; |
1421 | } |
1422 | goto find_next_index_buffer; |
1423 | EOD: |
1424 | /* We are finished, set *pos to EOD. */ |
1425 | *pos = i_size + vol->mft_record_size; |
1426 | done: |
1427 | free(ia); |
1428 | free(bmp); |
1429 | if (bmp_na) |
1430 | ntfs_attr_close(bmp_na); |
1431 | if (ia_na) |
1432 | ntfs_attr_close(ia_na); |
1433 | ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", (long long)*pos); |
1434 | return 0; |
1435 | dir_err_out: |
1436 | errno = EIO; |
1437 | err_out: |
1438 | eo = errno; |
1439 | ntfs_log_trace("failed.\n"); |
1440 | if (ctx) |
1441 | ntfs_attr_put_search_ctx(ctx); |
1442 | free(ia); |
1443 | free(bmp); |
1444 | if (bmp_na) |
1445 | ntfs_attr_close(bmp_na); |
1446 | if (ia_na) |
1447 | ntfs_attr_close(ia_na); |
1448 | errno = eo; |
1449 | return -1; |
1450 | } |
1451 | |
1452 | |
1453 | /** |
1454 | * __ntfs_create - create object on ntfs volume |
1455 | * @dir_ni: ntfs inode for directory in which create new object |
1456 | * @securid: id of inheritable security descriptor, 0 if none |
1457 | * @name: unicode name of new object |
1458 | * @name_len: length of the name in unicode characters |
1459 | * @type: type of the object to create |
1460 | * @dev: major and minor device numbers (obtained from makedev()) |
1461 | * @target: target in unicode (only for symlinks) |
1462 | * @target_len: length of target in unicode characters |
1463 | * |
1464 | * Internal, use ntfs_create{,_device,_symlink} wrappers instead. |
1465 | * |
1466 | * @type can be: |
1467 | * S_IFREG to create regular file |
1468 | * S_IFDIR to create directory |
1469 | * S_IFBLK to create block device |
1470 | * S_IFCHR to create character device |
1471 | * S_IFLNK to create symbolic link |
1472 | * S_IFIFO to create FIFO |
1473 | * S_IFSOCK to create socket |
1474 | * other values are invalid. |
1475 | * |
1476 | * @dev is used only if @type is S_IFBLK or S_IFCHR, in other cases its value |
1477 | * ignored. |
1478 | * |
1479 | * @target and @target_len are used only if @type is S_IFLNK, in other cases |
1480 | * their value ignored. |
1481 | * |
1482 | * Return opened ntfs inode that describes created object on success or NULL |
1483 | * on error with errno set to the error code. |
1484 | */ |
1485 | static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid, |
1486 | const ntfschar *name, u8 name_len, mode_t type, dev_t dev, |
1487 | const ntfschar *target, int target_len) |
1488 | { |
1489 | ntfs_inode *ni; |
1490 | int rollback_data = 0, rollback_sd = 0; |
1491 | FILE_NAME_ATTR *fn = NULL; |
1492 | STANDARD_INFORMATION *si = NULL; |
1493 | int err, fn_len, si_len; |
1494 | |
1495 | ntfs_log_trace("Entering.\n"); |
1496 | |
1497 | /* Sanity checks. */ |
1498 | if (!dir_ni || !name || !name_len) { |
1499 | ntfs_log_error("Invalid arguments.\n"); |
1500 | errno = EINVAL; |
1501 | return NULL; |
1502 | } |
1503 | |
1504 | if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { |
1505 | errno = EOPNOTSUPP; |
1506 | return NULL; |
1507 | } |
1508 | |
1509 | ni = ntfs_mft_record_alloc(dir_ni->vol, NULL); |
1510 | if (!ni) |
1511 | return NULL; |
1512 | #if CACHE_NIDATA_SIZE |
1513 | ntfs_inode_invalidate(dir_ni->vol, ni->mft_no); |
1514 | #endif |
1515 | /* |
1516 | * Create STANDARD_INFORMATION attribute. |
1517 | * JPA Depending on available inherited security descriptor, |
1518 | * Write STANDARD_INFORMATION v1.2 (no inheritance) or v3 |
1519 | */ |
1520 | if (securid) |
1521 | si_len = sizeof(STANDARD_INFORMATION); |
1522 | else |
1523 | si_len = offsetof(STANDARD_INFORMATION, v1_end); |
1524 | si = ntfs_calloc(si_len); |
1525 | if (!si) { |
1526 | err = errno; |
1527 | goto err_out; |
1528 | } |
1529 | si->creation_time = ni->creation_time; |
1530 | si->last_data_change_time = ni->last_data_change_time; |
1531 | si->last_mft_change_time = ni->last_mft_change_time; |
1532 | si->last_access_time = ni->last_access_time; |
1533 | if (securid) { |
1534 | set_nino_flag(ni, v3_Extensions); |
1535 | ni->owner_id = si->owner_id = 0; |
1536 | ni->security_id = si->security_id = securid; |
1537 | ni->quota_charged = si->quota_charged = const_cpu_to_le64(0); |
1538 | ni->usn = si->usn = const_cpu_to_le64(0); |
1539 | } else |
1540 | clear_nino_flag(ni, v3_Extensions); |
1541 | if (!S_ISREG(type) && !S_ISDIR(type)) { |
1542 | si->file_attributes = FILE_ATTR_SYSTEM; |
1543 | ni->flags = FILE_ATTR_SYSTEM; |
1544 | } |
1545 | ni->flags |= FILE_ATTR_ARCHIVE; |
1546 | if (NVolHideDotFiles(dir_ni->vol) |
1547 | && (name_len > 1) |
1548 | && (name[0] == const_cpu_to_le16('.')) |
1549 | && (name[1] != const_cpu_to_le16('.'))) |
1550 | ni->flags |= FILE_ATTR_HIDDEN; |
1551 | /* |
1552 | * Set compression flag according to parent directory |
1553 | * unless NTFS version < 3.0 or cluster size > 4K |
1554 | * or compression has been disabled |
1555 | */ |
1556 | if ((dir_ni->flags & FILE_ATTR_COMPRESSED) |
1557 | && (dir_ni->vol->major_ver >= 3) |
1558 | && NVolCompression(dir_ni->vol) |
1559 | && (dir_ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) |
1560 | && (S_ISREG(type) || S_ISDIR(type))) |
1561 | ni->flags |= FILE_ATTR_COMPRESSED; |
1562 | /* Add STANDARD_INFORMATION to inode. */ |
1563 | if (ntfs_attr_add(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, |
1564 | (u8*)si, si_len)) { |
1565 | err = errno; |
1566 | ntfs_log_error("Failed to add STANDARD_INFORMATION " |
1567 | "attribute.\n"); |
1568 | goto err_out; |
1569 | } |
1570 | |
1571 | if (!securid) { |
1572 | if (ntfs_sd_add_everyone(ni)) { |
1573 | err = errno; |
1574 | goto err_out; |
1575 | } |
1576 | } |
1577 | rollback_sd = 1; |
1578 | |
1579 | if (S_ISDIR(type)) { |
1580 | INDEX_ROOT *ir = NULL; |
1581 | INDEX_ENTRY *ie; |
1582 | int ir_len, index_len; |
1583 | |
1584 | /* Create INDEX_ROOT attribute. */ |
1585 | index_len = sizeof(INDEX_HEADER) + sizeof(INDEX_ENTRY_HEADER); |
1586 | ir_len = offsetof(INDEX_ROOT, index) + index_len; |
1587 | ir = ntfs_calloc(ir_len); |
1588 | if (!ir) { |
1589 | err = errno; |
1590 | goto err_out; |
1591 | } |
1592 | ir->type = AT_FILE_NAME; |
1593 | ir->collation_rule = COLLATION_FILE_NAME; |
1594 | ir->index_block_size = cpu_to_le32(ni->vol->indx_record_size); |
1595 | if (ni->vol->cluster_size <= ni->vol->indx_record_size) |
1596 | ir->clusters_per_index_block = |
1597 | ni->vol->indx_record_size >> |
1598 | ni->vol->cluster_size_bits; |
1599 | else |
1600 | ir->clusters_per_index_block = |
1601 | ni->vol->indx_record_size >> |
1602 | NTFS_BLOCK_SIZE_BITS; |
1603 | ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER)); |
1604 | ir->index.index_length = cpu_to_le32(index_len); |
1605 | ir->index.allocated_size = cpu_to_le32(index_len); |
1606 | ie = (INDEX_ENTRY*)((u8*)ir + sizeof(INDEX_ROOT)); |
1607 | ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER)); |
1608 | ie->key_length = 0; |
1609 | ie->ie_flags = INDEX_ENTRY_END; |
1610 | /* Add INDEX_ROOT attribute to inode. */ |
1611 | if (ntfs_attr_add(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4, |
1612 | (u8*)ir, ir_len)) { |
1613 | err = errno; |
1614 | free(ir); |
1615 | ntfs_log_error("Failed to add INDEX_ROOT attribute.\n"); |
1616 | goto err_out; |
1617 | } |
1618 | free(ir); |
1619 | } else { |
1620 | INTX_FILE *data; |
1621 | int data_len; |
1622 | |
1623 | switch (type) { |
1624 | case S_IFBLK: |
1625 | case S_IFCHR: |
1626 | data_len = offsetof(INTX_FILE, device_end); |
1627 | data = ntfs_malloc(data_len); |
1628 | if (!data) { |
1629 | err = errno; |
1630 | goto err_out; |
1631 | } |
1632 | data->major = cpu_to_le64(major(dev)); |
1633 | data->minor = cpu_to_le64(minor(dev)); |
1634 | if (type == S_IFBLK) |
1635 | data->magic = INTX_BLOCK_DEVICE; |
1636 | if (type == S_IFCHR) |
1637 | data->magic = INTX_CHARACTER_DEVICE; |
1638 | break; |
1639 | case S_IFLNK: |
1640 | data_len = sizeof(INTX_FILE_TYPES) + |
1641 | target_len * sizeof(ntfschar); |
1642 | data = ntfs_malloc(data_len); |
1643 | if (!data) { |
1644 | err = errno; |
1645 | goto err_out; |
1646 | } |
1647 | data->magic = INTX_SYMBOLIC_LINK; |
1648 | memcpy(data->target, target, |
1649 | target_len * sizeof(ntfschar)); |
1650 | break; |
1651 | case S_IFSOCK: |
1652 | data = NULL; |
1653 | data_len = 1; |
1654 | break; |
1655 | default: /* FIFO or regular file. */ |
1656 | data = NULL; |
1657 | data_len = 0; |
1658 | break; |
1659 | } |
1660 | /* Add DATA attribute to inode. */ |
1661 | if (ntfs_attr_add(ni, AT_DATA, AT_UNNAMED, 0, (u8*)data, |
1662 | data_len)) { |
1663 | err = errno; |
1664 | ntfs_log_error("Failed to add DATA attribute.\n"); |
1665 | free(data); |
1666 | goto err_out; |
1667 | } |
1668 | rollback_data = 1; |
1669 | free(data); |
1670 | } |
1671 | /* Create FILE_NAME attribute. */ |
1672 | fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); |
1673 | fn = ntfs_calloc(fn_len); |
1674 | if (!fn) { |
1675 | err = errno; |
1676 | goto err_out; |
1677 | } |
1678 | fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, |
1679 | le16_to_cpu(dir_ni->mrec->sequence_number)); |
1680 | fn->file_name_length = name_len; |
1681 | fn->file_name_type = FILE_NAME_POSIX; |
1682 | if (S_ISDIR(type)) |
1683 | fn->file_attributes = FILE_ATTR_I30_INDEX_PRESENT; |
1684 | if (!S_ISREG(type) && !S_ISDIR(type)) |
1685 | fn->file_attributes = FILE_ATTR_SYSTEM; |
1686 | else |
1687 | fn->file_attributes |= ni->flags & FILE_ATTR_COMPRESSED; |
1688 | fn->file_attributes |= FILE_ATTR_ARCHIVE; |
1689 | fn->file_attributes |= ni->flags & FILE_ATTR_HIDDEN; |
1690 | fn->creation_time = ni->creation_time; |
1691 | fn->last_data_change_time = ni->last_data_change_time; |
1692 | fn->last_mft_change_time = ni->last_mft_change_time; |
1693 | fn->last_access_time = ni->last_access_time; |
1694 | if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) |
1695 | fn->data_size = fn->allocated_size = const_cpu_to_le64(0); |
1696 | else { |
1697 | fn->data_size = cpu_to_sle64(ni->data_size); |
1698 | fn->allocated_size = cpu_to_sle64(ni->allocated_size); |
1699 | } |
1700 | memcpy(fn->file_name, name, name_len * sizeof(ntfschar)); |
1701 | /* Add FILE_NAME attribute to inode. */ |
1702 | if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) { |
1703 | err = errno; |
1704 | ntfs_log_error("Failed to add FILE_NAME attribute.\n"); |
1705 | goto err_out; |
1706 | } |
1707 | /* Add FILE_NAME attribute to index. */ |
1708 | if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no, |
1709 | le16_to_cpu(ni->mrec->sequence_number)))) { |
1710 | err = errno; |
1711 | ntfs_log_perror("Failed to add entry to the index"); |
1712 | goto err_out; |
1713 | } |
1714 | /* Set hard links count and directory flag. */ |
1715 | ni->mrec->link_count = cpu_to_le16(1); |
1716 | if (S_ISDIR(type)) |
1717 | ni->mrec->flags |= MFT_RECORD_IS_DIRECTORY; |
1718 | ntfs_inode_mark_dirty(ni); |
1719 | /* Done! */ |
1720 | free(fn); |
1721 | free(si); |
1722 | ntfs_log_trace("Done.\n"); |
1723 | return ni; |
1724 | err_out: |
1725 | ntfs_log_trace("Failed.\n"); |
1726 | |
1727 | if (rollback_sd) |
1728 | ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0); |
1729 | |
1730 | if (rollback_data) |
1731 | ntfs_attr_remove(ni, AT_DATA, AT_UNNAMED, 0); |
1732 | /* |
1733 | * Free extent MFT records (should not exist any with current |
1734 | * ntfs_create implementation, but for any case if something will be |
1735 | * changed in the future). |
1736 | */ |
1737 | while (ni->nr_extents) |
1738 | if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) { |
1739 | err = errno; |
1740 | ntfs_log_error("Failed to free extent MFT record. " |
1741 | "Leaving inconsistent metadata.\n"); |
1742 | } |
1743 | if (ntfs_mft_record_free(ni->vol, ni)) |
1744 | ntfs_log_error("Failed to free MFT record. " |
1745 | "Leaving inconsistent metadata. Run chkdsk.\n"); |
1746 | free(fn); |
1747 | free(si); |
1748 | errno = err; |
1749 | return NULL; |
1750 | } |
1751 | |
1752 | /** |
1753 | * Some wrappers around __ntfs_create() ... |
1754 | */ |
1755 | |
1756 | ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, const ntfschar *name, |
1757 | u8 name_len, mode_t type) |
1758 | { |
1759 | if (type != S_IFREG && type != S_IFDIR && type != S_IFIFO && |
1760 | type != S_IFSOCK) { |
1761 | ntfs_log_error("Invalid arguments.\n"); |
1762 | return NULL; |
1763 | } |
1764 | return __ntfs_create(dir_ni, securid, name, name_len, type, 0, NULL, 0); |
1765 | } |
1766 | |
1767 | ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid, |
1768 | const ntfschar *name, u8 name_len, mode_t type, dev_t dev) |
1769 | { |
1770 | if (type != S_IFCHR && type != S_IFBLK) { |
1771 | ntfs_log_error("Invalid arguments.\n"); |
1772 | return NULL; |
1773 | } |
1774 | return __ntfs_create(dir_ni, securid, name, name_len, type, dev, NULL, 0); |
1775 | } |
1776 | |
1777 | ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid, |
1778 | const ntfschar *name, u8 name_len, const ntfschar *target, |
1779 | int target_len) |
1780 | { |
1781 | if (!target || !target_len) { |
1782 | ntfs_log_error("%s: Invalid argument (%p, %d)\n", __FUNCTION__, |
1783 | target, target_len); |
1784 | return NULL; |
1785 | } |
1786 | return __ntfs_create(dir_ni, securid, name, name_len, S_IFLNK, 0, |
1787 | target, target_len); |
1788 | } |
1789 | |
1790 | int ntfs_check_empty_dir(ntfs_inode *ni) |
1791 | { |
1792 | ntfs_attr *na; |
1793 | int ret = 0; |
1794 | |
1795 | if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) |
1796 | return 0; |
1797 | |
1798 | na = ntfs_attr_open(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4); |
1799 | if (!na) { |
1800 | errno = EIO; |
1801 | ntfs_log_perror("Failed to open directory"); |
1802 | return -1; |
1803 | } |
1804 | |
1805 | /* Non-empty directory? */ |
1806 | if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){ |
1807 | /* Both ENOTEMPTY and EEXIST are ok. We use the more common. */ |
1808 | errno = ENOTEMPTY; |
1809 | ntfs_log_debug("Directory is not empty\n"); |
1810 | ret = -1; |
1811 | } |
1812 | |
1813 | ntfs_attr_close(na); |
1814 | return ret; |
1815 | } |
1816 | |
1817 | static int ntfs_check_unlinkable_dir(ntfs_inode *ni, FILE_NAME_ATTR *fn) |
1818 | { |
1819 | int link_count = le16_to_cpu(ni->mrec->link_count); |
1820 | int ret; |
1821 | |
1822 | ret = ntfs_check_empty_dir(ni); |
1823 | if (!ret || errno != ENOTEMPTY) |
1824 | return ret; |
1825 | /* |
1826 | * Directory is non-empty, so we can unlink only if there is more than |
1827 | * one "real" hard link, i.e. links aren't different DOS and WIN32 names |
1828 | */ |
1829 | if ((link_count == 1) || |
1830 | (link_count == 2 && fn->file_name_type == FILE_NAME_DOS)) { |
1831 | errno = ENOTEMPTY; |
1832 | ntfs_log_debug("Non-empty directory without hard links\n"); |
1833 | goto no_hardlink; |
1834 | } |
1835 | |
1836 | ret = 0; |
1837 | no_hardlink: |
1838 | return ret; |
1839 | } |
1840 | |
1841 | /** |
1842 | * ntfs_delete - delete file or directory from ntfs volume |
1843 | * @ni: ntfs inode for object to delte |
1844 | * @dir_ni: ntfs inode for directory in which delete object |
1845 | * @name: unicode name of the object to delete |
1846 | * @name_len: length of the name in unicode characters |
1847 | * |
1848 | * @ni is always closed after the call to this function (even if it failed), |
1849 | * user does not need to call ntfs_inode_close himself. |
1850 | * |
1851 | * Return 0 on success or -1 on error with errno set to the error code. |
1852 | */ |
1853 | int ntfs_delete(ntfs_volume *vol, const char *pathname, |
1854 | ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name, |
1855 | u8 name_len) |
1856 | { |
1857 | ntfs_attr_search_ctx *actx = NULL; |
1858 | FILE_NAME_ATTR *fn = NULL; |
1859 | BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE; |
1860 | BOOL case_sensitive_match = TRUE; |
1861 | int err = 0; |
1862 | #if CACHE_NIDATA_SIZE |
1863 | int i; |
1864 | #endif |
1865 | #if CACHE_INODE_SIZE |
1866 | struct CACHED_INODE item; |
1867 | const char *p; |
1868 | u64 inum = (u64)-1; |
1869 | int count; |
1870 | #endif |
1871 | #if CACHE_LOOKUP_SIZE |
1872 | struct CACHED_LOOKUP lkitem; |
1873 | #endif |
1874 | |
1875 | ntfs_log_trace("Entering.\n"); |
1876 | |
1877 | if (!ni || !dir_ni || !name || !name_len) { |
1878 | ntfs_log_error("Invalid arguments.\n"); |
1879 | errno = EINVAL; |
1880 | goto err_out; |
1881 | } |
1882 | if (ni->nr_extents == -1) |
1883 | ni = ni->base_ni; |
1884 | if (dir_ni->nr_extents == -1) |
1885 | dir_ni = dir_ni->base_ni; |
1886 | /* |
1887 | * Search for FILE_NAME attribute with such name. If it's in POSIX or |
1888 | * WIN32_AND_DOS namespace, then simply remove it from index and inode. |
1889 | * If filename in DOS or in WIN32 namespace, then remove DOS name first, |
1890 | * only then remove WIN32 name. |
1891 | */ |
1892 | actx = ntfs_attr_get_search_ctx(ni, NULL); |
1893 | if (!actx) |
1894 | goto err_out; |
1895 | search: |
1896 | while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, |
1897 | 0, NULL, 0, actx)) { |
1898 | char *s; |
1899 | IGNORE_CASE_BOOL case_sensitive = IGNORE_CASE; |
1900 | |
1901 | errno = 0; |
1902 | fn = (FILE_NAME_ATTR*)((u8*)actx->attr + |
1903 | le16_to_cpu(actx->attr->value_offset)); |
1904 | s = ntfs_attr_name_get(fn->file_name, fn->file_name_length); |
1905 | ntfs_log_trace("name: '%s' type: %d dos: %d win32: %d " |
1906 | "case: %d\n", s, fn->file_name_type, |
1907 | looking_for_dos_name, looking_for_win32_name, |
1908 | case_sensitive_match); |
1909 | ntfs_attr_name_free(&s); |
1910 | if (looking_for_dos_name) { |
1911 | if (fn->file_name_type == FILE_NAME_DOS) |
1912 | break; |
1913 | else |
1914 | continue; |
1915 | } |
1916 | if (looking_for_win32_name) { |
1917 | if (fn->file_name_type == FILE_NAME_WIN32) |
1918 | break; |
1919 | else |
1920 | continue; |
1921 | } |
1922 | |
1923 | /* Ignore hard links from other directories */ |
1924 | if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) { |
1925 | ntfs_log_debug("MFT record numbers don't match " |
1926 | "(%llu != %llu)\n", |
1927 | (long long unsigned)dir_ni->mft_no, |
1928 | (long long unsigned)MREF_LE(fn->parent_directory)); |
1929 | continue; |
1930 | } |
1931 | if (case_sensitive_match |
1932 | || ((fn->file_name_type == FILE_NAME_POSIX) |
1933 | && NVolCaseSensitive(ni->vol))) |
1934 | case_sensitive = CASE_SENSITIVE; |
1935 | |
1936 | if (ntfs_names_are_equal(fn->file_name, fn->file_name_length, |
1937 | name, name_len, case_sensitive, |
1938 | ni->vol->upcase, ni->vol->upcase_len)){ |
1939 | |
1940 | if (fn->file_name_type == FILE_NAME_WIN32) { |
1941 | looking_for_dos_name = TRUE; |
1942 | ntfs_attr_reinit_search_ctx(actx); |
1943 | continue; |
1944 | } |
1945 | if (fn->file_name_type == FILE_NAME_DOS) |
1946 | looking_for_dos_name = TRUE; |
1947 | break; |
1948 | } |
1949 | } |
1950 | if (errno) { |
1951 | /* |
1952 | * If case sensitive search failed, then try once again |
1953 | * ignoring case. |
1954 | */ |
1955 | if (errno == ENOENT && case_sensitive_match) { |
1956 | case_sensitive_match = FALSE; |
1957 | ntfs_attr_reinit_search_ctx(actx); |
1958 | goto search; |
1959 | } |
1960 | goto err_out; |
1961 | } |
1962 | |
1963 | if (ntfs_check_unlinkable_dir(ni, fn) < 0) |
1964 | goto err_out; |
1965 | |
1966 | if (ntfs_index_remove(dir_ni, ni, fn, le32_to_cpu(actx->attr->value_length))) |
1967 | goto err_out; |
1968 | |
1969 | /* |
1970 | * Keep the last name in place, this is useful for undeletion |
1971 | * (Windows also does so), however delete the name if it were |
1972 | * in an extent, to avoid leaving an attribute list. |
1973 | */ |
1974 | if ((ni->mrec->link_count == cpu_to_le16(1)) && !actx->base_ntfs_ino) { |
1975 | /* make sure to not loop to another search */ |
1976 | looking_for_dos_name = FALSE; |
1977 | } else { |
1978 | if (ntfs_attr_record_rm(actx)) |
1979 | goto err_out; |
1980 | } |
1981 | |
1982 | ni->mrec->link_count = cpu_to_le16(le16_to_cpu( |
1983 | ni->mrec->link_count) - 1); |
1984 | |
1985 | ntfs_inode_mark_dirty(ni); |
1986 | if (looking_for_dos_name) { |
1987 | looking_for_dos_name = FALSE; |
1988 | looking_for_win32_name = TRUE; |
1989 | ntfs_attr_reinit_search_ctx(actx); |
1990 | goto search; |
1991 | } |
1992 | /* TODO: Update object id, quota and securiry indexes if required. */ |
1993 | /* |
1994 | * If hard link count is not equal to zero then we are done. In other |
1995 | * case there are no reference to this inode left, so we should free all |
1996 | * non-resident attributes and mark all MFT record as not in use. |
1997 | */ |
1998 | #if CACHE_LOOKUP_SIZE |
1999 | /* invalidate entry in lookup cache */ |
2000 | lkitem.name = (const char*)NULL; |
2001 | lkitem.namesize = 0; |
2002 | lkitem.inum = ni->mft_no; |
2003 | lkitem.parent = dir_ni->mft_no; |
2004 | ntfs_invalidate_cache(vol->lookup_cache, GENERIC(&lkitem), |
2005 | lookup_cache_inv_compare, CACHE_NOHASH); |
2006 | #endif |
2007 | #if CACHE_INODE_SIZE |
2008 | inum = ni->mft_no; |
2009 | if (pathname) { |
2010 | /* invalide cache entry, even if there was an error */ |
2011 | /* Remove leading /'s. */ |
2012 | p = pathname; |
2013 | while (*p == PATH_SEP) |
2014 | p++; |
2015 | if (p[0] && (p[strlen(p)-1] == PATH_SEP)) |
2016 | ntfs_log_error("Unnormalized path %s\n",pathname); |
2017 | item.pathname = p; |
2018 | item.varsize = strlen(p); |
2019 | } else { |
2020 | item.pathname = (const char*)NULL; |
2021 | item.varsize = 0; |
2022 | } |
2023 | item.inum = inum; |
2024 | count = ntfs_invalidate_cache(vol->xinode_cache, GENERIC(&item), |
2025 | inode_cache_inv_compare, CACHE_NOHASH); |
2026 | if (pathname && !count) |
2027 | ntfs_log_error("Could not delete inode cache entry for %s\n", |
2028 | pathname); |
2029 | #endif |
2030 | if (ni->mrec->link_count) { |
2031 | ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME); |
2032 | goto ok; |
2033 | } |
2034 | if (ntfs_delete_reparse_index(ni)) { |
2035 | /* |
2036 | * Failed to remove the reparse index : proceed anyway |
2037 | * This is not a critical error, the entry is useless |
2038 | * because of sequence_number, and stopping file deletion |
2039 | * would be much worse as the file is not referenced now. |
2040 | */ |
2041 | err = errno; |
2042 | } |
2043 | if (ntfs_delete_object_id_index(ni)) { |
2044 | /* |
2045 | * Failed to remove the object id index : proceed anyway |
2046 | * This is not a critical error. |
2047 | */ |
2048 | err = errno; |
2049 | } |
2050 | ntfs_attr_reinit_search_ctx(actx); |
2051 | while (!ntfs_attrs_walk(actx)) { |
2052 | if (actx->attr->non_resident) { |
2053 | runlist *rl; |
2054 | |
2055 | rl = ntfs_mapping_pairs_decompress(ni->vol, actx->attr, |
2056 | NULL); |
2057 | if (!rl) { |
2058 | err = errno; |
2059 | ntfs_log_error("Failed to decompress runlist. " |
2060 | "Leaving inconsistent metadata.\n"); |
2061 | continue; |
2062 | } |
2063 | if (ntfs_cluster_free_from_rl(ni->vol, rl)) { |
2064 | err = errno; |
2065 | ntfs_log_error("Failed to free clusters. " |
2066 | "Leaving inconsistent metadata.\n"); |
2067 | continue; |
2068 | } |
2069 | free(rl); |
2070 | } |
2071 | } |
2072 | if (errno != ENOENT) { |
2073 | err = errno; |
2074 | ntfs_log_error("Attribute enumeration failed. " |
2075 | "Probably leaving inconsistent metadata.\n"); |
2076 | } |
2077 | /* All extents should be attached after attribute walk. */ |
2078 | #if CACHE_NIDATA_SIZE |
2079 | /* |
2080 | * Disconnect extents before deleting them, so they are |
2081 | * not wrongly moved to cache through the chainings |
2082 | */ |
2083 | for (i=ni->nr_extents-1; i>=0; i--) { |
2084 | ni->extent_nis[i]->base_ni = (ntfs_inode*)NULL; |
2085 | ni->extent_nis[i]->nr_extents = 0; |
2086 | if (ntfs_mft_record_free(ni->vol, ni->extent_nis[i])) { |
2087 | err = errno; |
2088 | ntfs_log_error("Failed to free extent MFT record. " |
2089 | "Leaving inconsistent metadata.\n"); |
2090 | } |
2091 | } |
2092 | free(ni->extent_nis); |
2093 | ni->nr_extents = 0; |
2094 | ni->extent_nis = (ntfs_inode**)NULL; |
2095 | #else |
2096 | while (ni->nr_extents) |
2097 | if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) { |
2098 | err = errno; |
2099 | ntfs_log_error("Failed to free extent MFT record. " |
2100 | "Leaving inconsistent metadata.\n"); |
2101 | } |
2102 | #endif |
2103 | debug_double_inode(ni->mft_no,0); |
2104 | if (ntfs_mft_record_free(ni->vol, ni)) { |
2105 | err = errno; |
2106 | ntfs_log_error("Failed to free base MFT record. " |
2107 | "Leaving inconsistent metadata.\n"); |
2108 | } |
2109 | ni = NULL; |
2110 | ok: |
2111 | ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME); |
2112 | out: |
2113 | if (actx) |
2114 | ntfs_attr_put_search_ctx(actx); |
2115 | if (ntfs_inode_close(dir_ni) && !err) |
2116 | err = errno; |
2117 | if (ntfs_inode_close(ni) && !err) |
2118 | err = errno; |
2119 | if (err) { |
2120 | errno = err; |
2121 | ntfs_log_debug("Could not delete file: %s\n", strerror(errno)); |
2122 | return -1; |
2123 | } |
2124 | ntfs_log_trace("Done.\n"); |
2125 | return 0; |
2126 | err_out: |
2127 | err = errno; |
2128 | goto out; |
2129 | } |
2130 | |
2131 | /** |
2132 | * ntfs_link - create hard link for file or directory |
2133 | * @ni: ntfs inode for object to create hard link |
2134 | * @dir_ni: ntfs inode for directory in which new link should be placed |
2135 | * @name: unicode name of the new link |
2136 | * @name_len: length of the name in unicode characters |
2137 | * |
2138 | * NOTE: At present we allow creating hardlinks to directories, we use them |
2139 | * in a temporary state during rename. But it's defenitely bad idea to have |
2140 | * hard links to directories as a result of operation. |
2141 | * FIXME: Create internal __ntfs_link that allows hard links to a directories |
2142 | * and external ntfs_link that do not. Write ntfs_rename that uses __ntfs_link. |
2143 | * |
2144 | * Return 0 on success or -1 on error with errno set to the error code. |
2145 | */ |
2146 | static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name, |
2147 | u8 name_len, FILE_NAME_TYPE_FLAGS nametype) |
2148 | { |
2149 | FILE_NAME_ATTR *fn = NULL; |
2150 | int fn_len, err; |
2151 | |
2152 | ntfs_log_trace("Entering.\n"); |
2153 | |
2154 | if (!ni || !dir_ni || !name || !name_len || |
2155 | ni->mft_no == dir_ni->mft_no) { |
2156 | err = EINVAL; |
2157 | ntfs_log_perror("ntfs_link wrong arguments"); |
2158 | goto err_out; |
2159 | } |
2160 | |
2161 | if ((ni->flags & FILE_ATTR_REPARSE_POINT) |
2162 | && !ntfs_possible_symlink(ni)) { |
2163 | err = EOPNOTSUPP; |
2164 | goto err_out; |
2165 | } |
2166 | if (NVolHideDotFiles(dir_ni->vol)) { |
2167 | /* Set hidden flag according to the latest name */ |
2168 | if ((name_len > 1) |
2169 | && (name[0] == const_cpu_to_le16('.')) |
2170 | && (name[1] != const_cpu_to_le16('.'))) |
2171 | ni->flags |= FILE_ATTR_HIDDEN; |
2172 | else |
2173 | ni->flags &= ~FILE_ATTR_HIDDEN; |
2174 | } |
2175 | |
2176 | /* Create FILE_NAME attribute. */ |
2177 | fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); |
2178 | fn = ntfs_calloc(fn_len); |
2179 | if (!fn) { |
2180 | err = errno; |
2181 | goto err_out; |
2182 | } |
2183 | fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, |
2184 | le16_to_cpu(dir_ni->mrec->sequence_number)); |
2185 | fn->file_name_length = name_len; |
2186 | fn->file_name_type = nametype; |
2187 | fn->file_attributes = ni->flags; |
2188 | if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { |
2189 | fn->file_attributes |= FILE_ATTR_I30_INDEX_PRESENT; |
2190 | fn->data_size = fn->allocated_size = const_cpu_to_le64(0); |
2191 | } else { |
2192 | fn->allocated_size = cpu_to_sle64(ni->allocated_size); |
2193 | fn->data_size = cpu_to_sle64(ni->data_size); |
2194 | } |
2195 | fn->creation_time = ni->creation_time; |
2196 | fn->last_data_change_time = ni->last_data_change_time; |
2197 | fn->last_mft_change_time = ni->last_mft_change_time; |
2198 | fn->last_access_time = ni->last_access_time; |
2199 | memcpy(fn->file_name, name, name_len * sizeof(ntfschar)); |
2200 | /* Add FILE_NAME attribute to index. */ |
2201 | if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no, |
2202 | le16_to_cpu(ni->mrec->sequence_number)))) { |
2203 | err = errno; |
2204 | ntfs_log_perror("Failed to add filename to the index"); |
2205 | goto err_out; |
2206 | } |
2207 | /* Add FILE_NAME attribute to inode. */ |
2208 | if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) { |
2209 | ntfs_log_error("Failed to add FILE_NAME attribute.\n"); |
2210 | err = errno; |
2211 | /* Try to remove just added attribute from index. */ |
2212 | if (ntfs_index_remove(dir_ni, ni, fn, fn_len)) |
2213 | goto rollback_failed; |
2214 | goto err_out; |
2215 | } |
2216 | /* Increment hard links count. */ |
2217 | ni->mrec->link_count = cpu_to_le16(le16_to_cpu( |
2218 | ni->mrec->link_count) + 1); |
2219 | /* Done! */ |
2220 | ntfs_inode_mark_dirty(ni); |
2221 | free(fn); |
2222 | ntfs_log_trace("Done.\n"); |
2223 | return 0; |
2224 | rollback_failed: |
2225 | ntfs_log_error("Rollback failed. Leaving inconsistent metadata.\n"); |
2226 | err_out: |
2227 | free(fn); |
2228 | errno = err; |
2229 | return -1; |
2230 | } |
2231 | |
2232 | int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name, |
2233 | u8 name_len) |
2234 | { |
2235 | return (ntfs_link_i(ni, dir_ni, name, name_len, FILE_NAME_POSIX)); |
2236 | } |
2237 | |
2238 | /* |
2239 | * Get a parent directory from an inode entry |
2240 | * |
2241 | * This is only used in situations where the path used to access |
2242 | * the current file is not known for sure. The result may be different |
2243 | * from the path when the file is linked in several parent directories. |
2244 | * |
2245 | * Currently this is only used for translating ".." in the target |
2246 | * of a Vista relative symbolic link |
2247 | */ |
2248 | |
2249 | ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni) |
2250 | { |
2251 | ntfs_inode *dir_ni = (ntfs_inode*)NULL; |
2252 | u64 inum; |
2253 | FILE_NAME_ATTR *fn; |
2254 | ntfs_attr_search_ctx *ctx; |
2255 | |
2256 | if (ni->mft_no != FILE_root) { |
2257 | /* find the name in the attributes */ |
2258 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
2259 | if (!ctx) |
2260 | return ((ntfs_inode*)NULL); |
2261 | |
2262 | if (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, |
2263 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
2264 | /* We know this will always be resident. */ |
2265 | fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + |
2266 | le16_to_cpu(ctx->attr->value_offset)); |
2267 | inum = le64_to_cpu(fn->parent_directory); |
2268 | if (inum != (u64)-1) { |
2269 | dir_ni = ntfs_inode_open(ni->vol, MREF(inum)); |
2270 | } |
2271 | } |
2272 | ntfs_attr_put_search_ctx(ctx); |
2273 | } |
2274 | return (dir_ni); |
2275 | } |
2276 | |
2277 | #ifdef HAVE_SETXATTR |
2278 | |
2279 | #define MAX_DOS_NAME_LENGTH 12 |
2280 | |
2281 | /* |
2282 | * Get a DOS name for a file in designated directory |
2283 | * |
2284 | * Not allowed if there are several non-dos names (EMLINK) |
2285 | * |
2286 | * Returns size if found |
2287 | * 0 if not found |
2288 | * -1 if there was an error (described by errno) |
2289 | */ |
2290 | |
2291 | static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname) |
2292 | { |
2293 | size_t outsize = 0; |
2294 | int namecount = 0; |
2295 | FILE_NAME_ATTR *fn; |
2296 | ntfs_attr_search_ctx *ctx; |
2297 | |
2298 | /* find the name in the attributes */ |
2299 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
2300 | if (!ctx) |
2301 | return -1; |
2302 | |
2303 | while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, |
2304 | 0, NULL, 0, ctx)) { |
2305 | /* We know this will always be resident. */ |
2306 | fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + |
2307 | le16_to_cpu(ctx->attr->value_offset)); |
2308 | |
2309 | if (fn->file_name_type != FILE_NAME_DOS) |
2310 | namecount++; |
2311 | if ((fn->file_name_type & FILE_NAME_DOS) |
2312 | && (MREF_LE(fn->parent_directory) == dnum)) { |
2313 | /* |
2314 | * Found a DOS or WIN32+DOS name for the entry |
2315 | * copy name, after truncation for safety |
2316 | */ |
2317 | outsize = fn->file_name_length; |
2318 | /* TODO : reject if name is too long ? */ |
2319 | if (outsize > MAX_DOS_NAME_LENGTH) |
2320 | outsize = MAX_DOS_NAME_LENGTH; |
2321 | memcpy(dosname,fn->file_name,outsize*sizeof(ntfschar)); |
2322 | } |
2323 | } |
2324 | ntfs_attr_put_search_ctx(ctx); |
2325 | if ((outsize > 0) && (namecount > 1)) { |
2326 | outsize = -1; |
2327 | errno = EMLINK; /* this error implies there is a dos name */ |
2328 | } |
2329 | return (outsize); |
2330 | } |
2331 | |
2332 | |
2333 | /* |
2334 | * Get a long name for a file in designated directory |
2335 | * |
2336 | * Not allowed if there are several non-dos names (EMLINK) |
2337 | * |
2338 | * Returns size if found |
2339 | * 0 if not found |
2340 | * -1 if there was an error (described by errno) |
2341 | */ |
2342 | |
2343 | static int get_long_name(ntfs_inode *ni, u64 dnum, ntfschar *longname) |
2344 | { |
2345 | size_t outsize = 0; |
2346 | int namecount = 0; |
2347 | FILE_NAME_ATTR *fn; |
2348 | ntfs_attr_search_ctx *ctx; |
2349 | |
2350 | /* find the name in the attributes */ |
2351 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
2352 | if (!ctx) |
2353 | return -1; |
2354 | |
2355 | /* first search for WIN32 or DOS+WIN32 names */ |
2356 | while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, |
2357 | 0, NULL, 0, ctx)) { |
2358 | /* We know this will always be resident. */ |
2359 | fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + |
2360 | le16_to_cpu(ctx->attr->value_offset)); |
2361 | |
2362 | if (fn->file_name_type != FILE_NAME_DOS) |
2363 | namecount++; |
2364 | if ((fn->file_name_type & FILE_NAME_WIN32) |
2365 | && (MREF_LE(fn->parent_directory) == dnum)) { |
2366 | /* |
2367 | * Found a WIN32 or WIN32+DOS name for the entry |
2368 | * copy name |
2369 | */ |
2370 | outsize = fn->file_name_length; |
2371 | memcpy(longname,fn->file_name,outsize*sizeof(ntfschar)); |
2372 | } |
2373 | } |
2374 | if (namecount > 1) { |
2375 | ntfs_attr_put_search_ctx(ctx); |
2376 | errno = EMLINK; |
2377 | return -1; |
2378 | } |
2379 | /* if not found search for POSIX names */ |
2380 | if (!outsize) { |
2381 | ntfs_attr_reinit_search_ctx(ctx); |
2382 | while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, |
2383 | 0, NULL, 0, ctx)) { |
2384 | /* We know this will always be resident. */ |
2385 | fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + |
2386 | le16_to_cpu(ctx->attr->value_offset)); |
2387 | |
2388 | if ((fn->file_name_type == FILE_NAME_POSIX) |
2389 | && (MREF_LE(fn->parent_directory) == dnum)) { |
2390 | /* |
2391 | * Found a POSIX name for the entry |
2392 | * copy name |
2393 | */ |
2394 | outsize = fn->file_name_length; |
2395 | memcpy(longname,fn->file_name,outsize*sizeof(ntfschar)); |
2396 | } |
2397 | } |
2398 | } |
2399 | ntfs_attr_put_search_ctx(ctx); |
2400 | return (outsize); |
2401 | } |
2402 | |
2403 | |
2404 | /* |
2405 | * Get the ntfs DOS name into an extended attribute |
2406 | */ |
2407 | |
2408 | int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, |
2409 | char *value, size_t size) |
2410 | { |
2411 | int outsize = 0; |
2412 | char *outname = (char*)NULL; |
2413 | u64 dnum; |
2414 | int doslen; |
2415 | ntfschar dosname[MAX_DOS_NAME_LENGTH]; |
2416 | |
2417 | dnum = dir_ni->mft_no; |
2418 | doslen = get_dos_name(ni, dnum, dosname); |
2419 | if (doslen > 0) { |
2420 | /* |
2421 | * Found a DOS name for the entry, make |
2422 | * uppercase and encode into the buffer |
2423 | * if there is enough space |
2424 | */ |
2425 | ntfs_name_upcase(dosname, doslen, |
2426 | ni->vol->upcase, ni->vol->upcase_len); |
2427 | if (ntfs_ucstombs(dosname, doslen, &outname, size) < 0) { |
2428 | ntfs_log_error("Cannot represent dosname in current locale.\n"); |
2429 | outsize = -errno; |
2430 | } else { |
2431 | outsize = strlen(outname); |
2432 | if (value && (outsize <= (int)size)) |
2433 | memcpy(value, outname, outsize); |
2434 | else |
2435 | if (size && (outsize > (int)size)) |
2436 | outsize = -ERANGE; |
2437 | free(outname); |
2438 | } |
2439 | } else { |
2440 | if (doslen == 0) |
2441 | errno = ENODATA; |
2442 | outsize = -errno; |
2443 | } |
2444 | return (outsize); |
2445 | } |
2446 | |
2447 | /* |
2448 | * Change the name space of an existing file or directory |
2449 | * |
2450 | * Returns the old namespace if successful |
2451 | * -1 if an error occurred (described by errno) |
2452 | */ |
2453 | |
2454 | static int set_namespace(ntfs_inode *ni, ntfs_inode *dir_ni, |
2455 | const ntfschar *name, int len, |
2456 | FILE_NAME_TYPE_FLAGS nametype) |
2457 | { |
2458 | ntfs_attr_search_ctx *actx; |
2459 | ntfs_index_context *icx; |
2460 | FILE_NAME_ATTR *fnx; |
2461 | FILE_NAME_ATTR *fn = NULL; |
2462 | BOOL found; |
2463 | int lkup; |
2464 | int ret; |
2465 | |
2466 | ret = -1; |
2467 | actx = ntfs_attr_get_search_ctx(ni, NULL); |
2468 | if (actx) { |
2469 | found = FALSE; |
2470 | do { |
2471 | lkup = ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, |
2472 | CASE_SENSITIVE, 0, NULL, 0, actx); |
2473 | if (!lkup) { |
2474 | fn = (FILE_NAME_ATTR*)((u8*)actx->attr + |
2475 | le16_to_cpu(actx->attr->value_offset)); |
2476 | found = (MREF_LE(fn->parent_directory) |
2477 | == dir_ni->mft_no) |
2478 | && !memcmp(fn->file_name, name, |
2479 | len*sizeof(ntfschar)); |
2480 | } |
2481 | } while (!lkup && !found); |
2482 | if (found) { |
2483 | icx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); |
2484 | if (icx) { |
2485 | lkup = ntfs_index_lookup((char*)fn, len, icx); |
2486 | if (!lkup && icx->data && icx->data_len) { |
2487 | fnx = (FILE_NAME_ATTR*)icx->data; |
2488 | ret = fn->file_name_type; |
2489 | fn->file_name_type = nametype; |
2490 | fnx->file_name_type = nametype; |
2491 | ntfs_inode_mark_dirty(ni); |
2492 | ntfs_index_entry_mark_dirty(icx); |
2493 | } |
2494 | ntfs_index_ctx_put(icx); |
2495 | } |
2496 | } |
2497 | ntfs_attr_put_search_ctx(actx); |
2498 | } |
2499 | return (ret); |
2500 | } |
2501 | |
2502 | /* |
2503 | * Set a DOS name to a file and adjust name spaces |
2504 | * |
2505 | * If the new names are collapsible (same uppercased chars) : |
2506 | * |
2507 | * - the existing DOS name or DOS+Win32 name is made Posix |
2508 | * - if it was a real DOS name, the existing long name is made DOS+Win32 |
2509 | * and the existing DOS name is deleted |
2510 | * - finally the existing long name is made DOS+Win32 unless already done |
2511 | * |
2512 | * If the new names are not collapsible : |
2513 | * |
2514 | * - insert the short name as a DOS name |
2515 | * - delete the old long name or existing short name |
2516 | * - insert the new long name (as a Win32 or DOS+Win32 name) |
2517 | * |
2518 | * Deleting the old long name will not delete the file |
2519 | * provided the old name was in the Posix name space, |
2520 | * because the alternate name has been set before. |
2521 | * |
2522 | * The inodes of file and parent directory are always closed |
2523 | * |
2524 | * Returns 0 if successful |
2525 | * -1 if failed |
2526 | */ |
2527 | |
2528 | static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, |
2529 | const ntfschar *shortname, int shortlen, |
2530 | const ntfschar *longname, int longlen, |
2531 | const ntfschar *deletename, int deletelen, BOOL existed) |
2532 | { |
2533 | unsigned int linkcount; |
2534 | ntfs_volume *vol; |
2535 | BOOL collapsible; |
2536 | BOOL deleted; |
2537 | BOOL done; |
2538 | FILE_NAME_TYPE_FLAGS oldnametype; |
2539 | u64 dnum; |
2540 | u64 fnum; |
2541 | int res; |
2542 | |
2543 | res = -1; |
2544 | vol = ni->vol; |
2545 | dnum = dir_ni->mft_no; |
2546 | fnum = ni->mft_no; |
2547 | /* save initial link count */ |
2548 | linkcount = le16_to_cpu(ni->mrec->link_count); |
2549 | |
2550 | /* check whether the same name may be used as DOS and WIN32 */ |
2551 | collapsible = ntfs_collapsible_chars(ni->vol, shortname, shortlen, |
2552 | longname, longlen); |
2553 | if (collapsible) { |
2554 | deleted = FALSE; |
2555 | done = FALSE; |
2556 | if (existed) { |
2557 | oldnametype = set_namespace(ni, dir_ni, deletename, |
2558 | deletelen, FILE_NAME_POSIX); |
2559 | if (oldnametype == FILE_NAME_DOS) { |
2560 | if (set_namespace(ni, dir_ni, longname, longlen, |
2561 | FILE_NAME_WIN32_AND_DOS) >= 0) { |
2562 | if (!ntfs_delete(vol, |
2563 | (const char*)NULL, ni, dir_ni, |
2564 | deletename, deletelen)) |
2565 | res = 0; |
2566 | deleted = TRUE; |
2567 | } else |
2568 | done = TRUE; |
2569 | } |
2570 | } |
2571 | if (!deleted) { |
2572 | if (!done && (set_namespace(ni, dir_ni, |
2573 | longname, longlen, |
2574 | FILE_NAME_WIN32_AND_DOS) >= 0)) |
2575 | res = 0; |
2576 | ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME); |
2577 | ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME); |
2578 | if (ntfs_inode_close_in_dir(ni,dir_ni) && !res) |
2579 | res = -1; |
2580 | if (ntfs_inode_close(dir_ni) && !res) |
2581 | res = -1; |
2582 | } |
2583 | } else { |
2584 | if (!ntfs_link_i(ni, dir_ni, shortname, shortlen, |
2585 | FILE_NAME_DOS) |
2586 | /* make sure a new link was recorded */ |
2587 | && (le16_to_cpu(ni->mrec->link_count) > linkcount)) { |
2588 | /* delete the existing long name or short name */ |
2589 | // is it ok to not provide the path ? |
2590 | if (!ntfs_delete(vol, (char*)NULL, ni, dir_ni, |
2591 | deletename, deletelen)) { |
2592 | /* delete closes the inodes, so have to open again */ |
2593 | dir_ni = ntfs_inode_open(vol, dnum); |
2594 | if (dir_ni) { |
2595 | ni = ntfs_inode_open(vol, fnum); |
2596 | if (ni) { |
2597 | if (!ntfs_link_i(ni, dir_ni, |
2598 | longname, longlen, |
2599 | FILE_NAME_WIN32)) |
2600 | res = 0; |
2601 | if (ntfs_inode_close_in_dir(ni, |
2602 | dir_ni) |
2603 | && !res) |
2604 | res = -1; |
2605 | } |
2606 | if (ntfs_inode_close(dir_ni) && !res) |
2607 | res = -1; |
2608 | } |
2609 | } |
2610 | } else { |
2611 | ntfs_inode_close_in_dir(ni,dir_ni); |
2612 | ntfs_inode_close(dir_ni); |
2613 | } |
2614 | } |
2615 | return (res); |
2616 | } |
2617 | |
2618 | |
2619 | /* |
2620 | * Set the ntfs DOS name into an extended attribute |
2621 | * |
2622 | * The DOS name will be added as another file name attribute |
2623 | * using the existing file name information from the original |
2624 | * name or overwriting the DOS Name if one exists. |
2625 | * |
2626 | * The inode of the file is always closed |
2627 | */ |
2628 | |
2629 | int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, |
2630 | const char *value, size_t size, int flags) |
2631 | { |
2632 | int res = 0; |
2633 | int longlen = 0; |
2634 | int shortlen = 0; |
2635 | char newname[3*MAX_DOS_NAME_LENGTH + 1]; |
2636 | ntfschar oldname[MAX_DOS_NAME_LENGTH]; |
2637 | int oldlen; |
2638 | u64 dnum; |
2639 | BOOL closed = FALSE; |
2640 | ntfschar *shortname = NULL; |
2641 | ntfschar longname[NTFS_MAX_NAME_LEN]; |
2642 | |
2643 | /* copy the string to insert a null char, and truncate */ |
2644 | if (size > 3*MAX_DOS_NAME_LENGTH) |
2645 | size = 3*MAX_DOS_NAME_LENGTH; |
2646 | strncpy(newname, value, size); |
2647 | /* a long name may be truncated badly and be untranslatable */ |
2648 | newname[size] = 0; |
2649 | /* convert the string to the NTFS wide chars, and truncate */ |
2650 | shortlen = ntfs_mbstoucs(newname, &shortname); |
2651 | if (shortlen > MAX_DOS_NAME_LENGTH) |
2652 | shortlen = MAX_DOS_NAME_LENGTH; |
2653 | /* make sure the short name has valid chars */ |
2654 | if ((shortlen < 0) || ntfs_forbidden_chars(shortname,shortlen)) { |
2655 | ntfs_inode_close_in_dir(ni,dir_ni); |
2656 | ntfs_inode_close(dir_ni); |
2657 | res = -errno; |
2658 | return res; |
2659 | } |
2660 | dnum = dir_ni->mft_no; |
2661 | longlen = get_long_name(ni, dnum, longname); |
2662 | if (longlen > 0) { |
2663 | oldlen = get_dos_name(ni, dnum, oldname); |
2664 | if ((oldlen >= 0) |
2665 | && !ntfs_forbidden_chars(longname, longlen)) { |
2666 | if (oldlen > 0) { |
2667 | if (flags & XATTR_CREATE) { |
2668 | res = -1; |
2669 | errno = EEXIST; |
2670 | } else |
2671 | if ((shortlen == oldlen) |
2672 | && !memcmp(shortname,oldname, |
2673 | oldlen*sizeof(ntfschar))) |
2674 | /* already set, done */ |
2675 | res = 0; |
2676 | else { |
2677 | res = set_dos_name(ni, dir_ni, |
2678 | shortname, shortlen, |
2679 | longname, longlen, |
2680 | oldname, oldlen, TRUE); |
2681 | closed = TRUE; |
2682 | } |
2683 | } else { |
2684 | if (flags & XATTR_REPLACE) { |
2685 | res = -1; |
2686 | errno = ENODATA; |
2687 | } else { |
2688 | res = set_dos_name(ni, dir_ni, |
2689 | shortname, shortlen, |
2690 | longname, longlen, |
2691 | longname, longlen, FALSE); |
2692 | closed = TRUE; |
2693 | } |
2694 | } |
2695 | } else |
2696 | res = -1; |
2697 | } else { |
2698 | res = -1; |
2699 | if (!longlen) |
2700 | errno = ENOENT; |
2701 | } |
2702 | free(shortname); |
2703 | if (!closed) { |
2704 | ntfs_inode_close_in_dir(ni,dir_ni); |
2705 | ntfs_inode_close(dir_ni); |
2706 | } |
2707 | return (res ? -1 : 0); |
2708 | } |
2709 | |
2710 | /* |
2711 | * Delete the ntfs DOS name |
2712 | */ |
2713 | |
2714 | int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni) |
2715 | { |
2716 | int res; |
2717 | int oldnametype; |
2718 | int longlen = 0; |
2719 | int shortlen; |
2720 | u64 dnum; |
2721 | ntfs_volume *vol; |
2722 | BOOL deleted = FALSE; |
2723 | ntfschar shortname[MAX_DOS_NAME_LENGTH]; |
2724 | ntfschar longname[NTFS_MAX_NAME_LEN]; |
2725 | |
2726 | res = -1; |
2727 | vol = ni->vol; |
2728 | dnum = dir_ni->mft_no; |
2729 | longlen = get_long_name(ni, dnum, longname); |
2730 | if (longlen > 0) { |
2731 | shortlen = get_dos_name(ni, dnum, shortname); |
2732 | if (shortlen >= 0) { |
2733 | /* migrate the long name as Posix */ |
2734 | oldnametype = set_namespace(ni,dir_ni,longname,longlen, |
2735 | FILE_NAME_POSIX); |
2736 | switch (oldnametype) { |
2737 | case FILE_NAME_WIN32_AND_DOS : |
2738 | /* name was Win32+DOS : done */ |
2739 | res = 0; |
2740 | break; |
2741 | case FILE_NAME_DOS : |
2742 | /* name was DOS, make it back to DOS */ |
2743 | set_namespace(ni,dir_ni,longname,longlen, |
2744 | FILE_NAME_DOS); |
2745 | errno = ENOENT; |
2746 | break; |
2747 | case FILE_NAME_WIN32 : |
2748 | /* name was Win32, make it Posix and delete */ |
2749 | if (set_namespace(ni,dir_ni,shortname,shortlen, |
2750 | FILE_NAME_POSIX) >= 0) { |
2751 | if (!ntfs_delete(vol, |
2752 | (const char*)NULL, ni, |
2753 | dir_ni, shortname, |
2754 | shortlen)) |
2755 | res = 0; |
2756 | deleted = TRUE; |
2757 | } else { |
2758 | /* |
2759 | * DOS name has been found, but cannot |
2760 | * migrate to Posix : something bad |
2761 | * has happened |
2762 | */ |
2763 | errno = EIO; |
2764 | ntfs_log_error("Could not change" |
2765 | " DOS name of inode %lld to Posix\n", |
2766 | (long long)ni->mft_no); |
2767 | } |
2768 | break; |
2769 | default : |
2770 | /* name was Posix or not found : error */ |
2771 | errno = ENOENT; |
2772 | break; |
2773 | } |
2774 | } |
2775 | } else { |
2776 | if (!longlen) |
2777 | errno = ENOENT; |
2778 | res = -1; |
2779 | } |
2780 | if (!deleted) { |
2781 | ntfs_inode_close_in_dir(ni,dir_ni); |
2782 | ntfs_inode_close(dir_ni); |
2783 | } |
2784 | return (res); |
2785 | } |
2786 | |
2787 | #endif |
2788 |