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