Allow IPv6 address entry in tools>ping - Loosens valid character check
[tomato/davidwu.git] / release / src / router / ntfs-3g / libntfs-3g / dir.c
blob2539586cacdeeb45f7d45481f79d1c1cf2743697
1 /**
2 * dir.c - Directory handling code. Originated from the Linux-NTFS project.
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
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.
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.
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
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
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
43 #ifdef HAVE_SYS_SYSMACROS_H
44 #include <sys/sysmacros.h>
45 #endif
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"
65 #ifdef HAVE_SETXATTR
66 #include <sys/xattr.h>
67 #endif
70 * The little endian Unicode strings "$I30", "$SII", "$SDH", "$O"
71 * and "$Q" as global constants.
73 ntfschar 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') };
76 ntfschar 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') };
79 ntfschar 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') };
82 ntfschar NTFS_INDEX_O[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('O'),
83 const_cpu_to_le16('\0') };
84 ntfschar NTFS_INDEX_Q[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('Q'),
85 const_cpu_to_le16('\0') };
86 ntfschar NTFS_INDEX_R[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('R'),
87 const_cpu_to_le16('\0') };
89 #if CACHE_INODE_SIZE
92 * Pathname hashing
94 * Based on first char and second char (which may be '\0')
97 int ntfs_dir_inode_hash(const struct CACHED_GENERIC *cached)
99 const char *path;
100 const unsigned char *name;
102 path = (const char*)cached->variable;
103 if (!path) {
104 ntfs_log_error("Bad inode cache entry\n");
105 return (-1);
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));
115 * Pathname comparing for entering/fetching from cache
118 static int inode_cache_compare(const struct CACHED_GENERIC *cached,
119 const struct CACHED_GENERIC *wanted)
121 return (!cached->variable
122 || strcmp(cached->variable, wanted->variable));
126 * Pathname comparing for invalidating entries in cache
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
133 * Only use associated with a CACHE_NOHASH flag
136 static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached,
137 const struct CACHED_GENERIC *wanted)
139 int len;
140 BOOL different;
141 const struct CACHED_INODE *w;
142 const struct CACHED_INODE *c;
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);
159 #endif
161 #if CACHE_LOOKUP_SIZE
164 * File name comparing for entering/fetching from lookup cache
167 static int lookup_cache_compare(const struct CACHED_GENERIC *cached,
168 const struct CACHED_GENERIC *wanted)
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));
179 * Inode number comparing for invalidating lookup cache
181 * All entries with designated inode number are invalidated
183 * Only use associated with a CACHE_NOHASH flag
186 static int lookup_cache_inv_compare(const struct CACHED_GENERIC *cached,
187 const struct CACHED_GENERIC *wanted)
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)));
197 * Lookup hashing
199 * Based on first, second and and last char
202 int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached)
204 const unsigned char *name;
205 int count;
206 unsigned int val;
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);
214 val = (name[0] << 2) + (name[1] << 1) + name[count - 1] + count;
215 return (val % (2*CACHE_LOOKUP_SIZE));
218 #endif
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
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.
232 * On error, return -1 with errno set to the error code. If the inode is is not
233 * found errno is ENOENT.
235 * Note, @uname_len does not include the (optional) terminating NULL character.
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.
242 * If the volume is mounted with the case sensitive flag set, then we only
243 * allow exact matches.
245 u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
246 const ntfschar *uname, const int uname_len)
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 IGNORE_CASE_BOOL case_sensitivity;
257 u8 *index_end;
258 ntfs_attr *ia_na;
259 int eo, rc;
260 u32 index_block_size;
261 u8 index_vcn_size_bits;
263 ntfs_log_trace("Entering\n");
265 if (!dir_ni || !dir_ni->mrec || !uname || uname_len <= 0) {
266 errno = EINVAL;
267 return -1;
270 ctx = ntfs_attr_get_search_ctx(dir_ni, NULL);
271 if (!ctx)
272 return -1;
274 /* Find the index root attribute in the mft record. */
275 if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL,
276 0, ctx)) {
277 ntfs_log_perror("Index root attribute missing in directory inode "
278 "%lld", (unsigned long long)dir_ni->mft_no);
279 goto put_err_out;
281 case_sensitivity = (NVolCaseSensitive(vol) ? CASE_SENSITIVE : IGNORE_CASE);
282 /* Get to the index root value. */
283 ir = (INDEX_ROOT*)((u8*)ctx->attr +
284 le16_to_cpu(ctx->attr->value_offset));
285 index_block_size = le32_to_cpu(ir->index_block_size);
286 if (index_block_size < NTFS_BLOCK_SIZE ||
287 index_block_size & (index_block_size - 1)) {
288 ntfs_log_error("Index block size %u is invalid.\n",
289 (unsigned)index_block_size);
290 goto put_err_out;
292 index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
293 /* The first index entry. */
294 ie = (INDEX_ENTRY*)((u8*)&ir->index +
295 le32_to_cpu(ir->index.entries_offset));
297 * Loop until we exceed valid memory (corruption case) or until we
298 * reach the last entry.
300 for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
301 /* Bounds checks. */
302 if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
303 sizeof(INDEX_ENTRY_HEADER) > index_end ||
304 (u8*)ie + le16_to_cpu(ie->key_length) >
305 index_end) {
306 ntfs_log_error("Index entry out of bounds in inode %lld"
307 "\n", (unsigned long long)dir_ni->mft_no);
308 goto put_err_out;
311 * The last entry cannot contain a name. It can however contain
312 * a pointer to a child node in the B+tree so we just break out.
314 if (ie->ie_flags & INDEX_ENTRY_END)
315 break;
317 if (!le16_to_cpu(ie->length)) {
318 ntfs_log_error("Zero length index entry in inode %lld"
319 "\n", (unsigned long long)dir_ni->mft_no);
320 goto put_err_out;
323 * Not a perfect match, need to do full blown collation so we
324 * know which way in the B+tree we have to go.
326 rc = ntfs_names_full_collate(uname, uname_len,
327 (ntfschar*)&ie->key.file_name.file_name,
328 ie->key.file_name.file_name_length,
329 case_sensitivity, vol->upcase, vol->upcase_len);
331 * If uname collates before the name of the current entry, there
332 * is definitely no such name in this index but we might need to
333 * descend into the B+tree so we just break out of the loop.
335 if (rc == -1)
336 break;
337 /* The names are not equal, continue the search. */
338 if (rc)
339 continue;
341 * Perfect match, this will never happen as the
342 * ntfs_are_names_equal() call will have gotten a match but we
343 * still treat it correctly.
345 mref = le64_to_cpu(ie->indexed_file);
346 ntfs_attr_put_search_ctx(ctx);
347 return mref;
350 * We have finished with this index without success. Check for the
351 * presence of a child node and if not present return error code
352 * ENOENT, unless we have got the mft reference of a matching name
353 * cached in mref in which case return mref.
355 if (!(ie->ie_flags & INDEX_ENTRY_NODE)) {
356 ntfs_attr_put_search_ctx(ctx);
357 if (mref)
358 return mref;
359 ntfs_log_debug("Entry not found - between root entries.\n");
360 errno = ENOENT;
361 return -1;
362 } /* Child node present, descend into it. */
364 /* Open the index allocation attribute. */
365 ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
366 if (!ia_na) {
367 ntfs_log_perror("Failed to open index allocation (inode %lld)",
368 (unsigned long long)dir_ni->mft_no);
369 goto put_err_out;
372 /* Allocate a buffer for the current index block. */
373 ia = ntfs_malloc(index_block_size);
374 if (!ia) {
375 ntfs_attr_close(ia_na);
376 goto put_err_out;
379 /* Determine the size of a vcn in the directory index. */
380 if (vol->cluster_size <= index_block_size) {
381 index_vcn_size_bits = vol->cluster_size_bits;
382 } else {
383 index_vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
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);
389 descend_into_child_node:
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;
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;
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;
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;
429 /* The first index entry. */
430 ie = (INDEX_ENTRY*)((u8*)&ia->index +
431 le32_to_cpu(ia->index.entries_offset));
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.
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;
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.
453 if (ie->ie_flags & INDEX_ENTRY_END)
454 break;
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;
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.
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_sensitivity, vol->upcase, vol->upcase_len);
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.
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;
487 * We have finished with this index buffer without success. Check for
488 * the presence of a child node.
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;
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;
507 free(ia);
508 ntfs_attr_close(ia_na);
509 ntfs_attr_put_search_ctx(ctx);
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.
515 if (mref)
516 return mref;
517 ntfs_log_debug("Entry not found.\n");
518 errno = ENOENT;
519 return -1;
520 put_err_out:
521 eo = EIO;
522 ntfs_log_debug("Corrupt directory. Aborting lookup.\n");
523 eo_put_err_out:
524 ntfs_attr_put_search_ctx(ctx);
525 errno = eo;
526 return -1;
527 close_err_out:
528 eo = errno;
529 free(ia);
530 ntfs_attr_close(ia_na);
531 goto eo_put_err_out;
535 * Lookup a file in a directory from its UTF-8 name
537 * The name is first fetched from cache if one is defined
539 * Returns the inode number
540 * or -1 if not possible (errno tells why)
543 u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name)
545 int uname_len;
546 ntfschar *uname = (ntfschar*)NULL;
547 u64 inum;
548 char *cached_name;
549 const char *const_name;
551 if (!NVolCaseSensitive(dir_ni->vol)) {
552 cached_name = ntfs_uppercase_mbs(name,
553 dir_ni->vol->upcase, dir_ni->vol->upcase_len);
554 const_name = cached_name;
555 } else {
556 cached_name = (char*)NULL;
557 const_name = name;
559 if (const_name) {
560 #if CACHE_LOOKUP_SIZE
563 * fetch inode from cache
566 if (dir_ni->vol->lookup_cache) {
567 struct CACHED_LOOKUP item;
568 struct CACHED_LOOKUP *cached;
570 item.name = const_name;
571 item.namesize = strlen(const_name) + 1;
572 item.parent = dir_ni->mft_no;
573 cached = (struct CACHED_LOOKUP*)ntfs_fetch_cache(
574 dir_ni->vol->lookup_cache,
575 GENERIC(&item), lookup_cache_compare);
576 if (cached) {
577 inum = cached->inum;
578 if (inum == (u64)-1)
579 errno = ENOENT;
580 } else {
581 /* Generate unicode name. */
582 uname_len = ntfs_mbstoucs(name, &uname);
583 if (uname_len >= 0) {
584 inum = ntfs_inode_lookup_by_name(dir_ni,
585 uname, uname_len);
586 item.inum = inum;
587 /* enter into cache, even if not found */
588 ntfs_enter_cache(dir_ni->vol->lookup_cache,
589 GENERIC(&item),
590 lookup_cache_compare);
591 free(uname);
592 } else
593 inum = (s64)-1;
595 } else
596 #endif
598 /* Generate unicode name. */
599 uname_len = ntfs_mbstoucs(cached_name, &uname);
600 if (uname_len >= 0)
601 inum = ntfs_inode_lookup_by_name(dir_ni,
602 uname, uname_len);
603 else
604 inum = (s64)-1;
606 if (cached_name)
607 free(cached_name);
608 } else
609 inum = (s64)-1;
610 return (inum);
614 * Update a cache lookup record when a name has been defined
616 * The UTF-8 name is required
619 void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, u64 inum)
621 #if CACHE_LOOKUP_SIZE
622 struct CACHED_LOOKUP item;
623 struct CACHED_LOOKUP *cached;
624 char *cached_name;
626 if (dir_ni->vol->lookup_cache) {
627 if (!NVolCaseSensitive(dir_ni->vol)) {
628 cached_name = ntfs_uppercase_mbs(name,
629 dir_ni->vol->upcase, dir_ni->vol->upcase_len);
630 item.name = cached_name;
631 } else {
632 cached_name = (char*)NULL;
633 item.name = name;
635 if (item.name) {
636 item.namesize = strlen(item.name) + 1;
637 item.parent = dir_ni->mft_no;
638 item.inum = inum;
639 cached = (struct CACHED_LOOKUP*)ntfs_enter_cache(
640 dir_ni->vol->lookup_cache,
641 GENERIC(&item), lookup_cache_compare);
642 if (cached)
643 cached->inum = inum;
644 if (cached_name)
645 free(cached_name);
648 #endif
652 * ntfs_pathname_to_inode - Find the inode which represents the given pathname
653 * @vol: An ntfs volume obtained from ntfs_mount
654 * @parent: A directory inode to begin the search (may be NULL)
655 * @pathname: Pathname to be located
657 * Take an ASCII pathname and find the inode that represents it. The function
658 * splits the path and then descends the directory tree. If @parent is NULL,
659 * then the root directory '.' will be used as the base for the search.
661 * Return: inode Success, the pathname was valid
662 * NULL Error, the pathname was invalid, or some other error occurred
664 ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
665 const char *pathname)
667 u64 inum;
668 int len, err = 0;
669 char *p, *q;
670 ntfs_inode *ni;
671 ntfs_inode *result = NULL;
672 ntfschar *unicode = NULL;
673 char *ascii = NULL;
674 #if CACHE_INODE_SIZE
675 struct CACHED_INODE item;
676 struct CACHED_INODE *cached;
677 char *fullname;
678 #endif
680 if (!vol || !pathname) {
681 errno = EINVAL;
682 return NULL;
685 ntfs_log_trace("path: '%s'\n", pathname);
687 ascii = strdup(pathname);
688 if (!ascii) {
689 ntfs_log_error("Out of memory.\n");
690 err = ENOMEM;
691 goto out;
694 p = ascii;
695 /* Remove leading /'s. */
696 while (p && *p && *p == PATH_SEP)
697 p++;
698 #if CACHE_INODE_SIZE
699 fullname = p;
700 if (p[0] && (p[strlen(p)-1] == PATH_SEP))
701 ntfs_log_error("Unnormalized path %s\n",ascii);
702 #endif
703 if (parent) {
704 ni = parent;
705 } else {
706 #if CACHE_INODE_SIZE
708 * fetch inode for full path from cache
710 if (*fullname) {
711 item.pathname = fullname;
712 item.varsize = strlen(fullname) + 1;
713 cached = (struct CACHED_INODE*)ntfs_fetch_cache(
714 vol->xinode_cache, GENERIC(&item),
715 inode_cache_compare);
716 } else
717 cached = (struct CACHED_INODE*)NULL;
718 if (cached) {
720 * return opened inode if found in cache
722 inum = MREF(cached->inum);
723 ni = ntfs_inode_open(vol, inum);
724 if (!ni) {
725 ntfs_log_debug("Cannot open inode %llu: %s.\n",
726 (unsigned long long)inum, p);
727 err = EIO;
729 result = ni;
730 goto out;
732 #endif
733 ni = ntfs_inode_open(vol, FILE_root);
734 if (!ni) {
735 ntfs_log_debug("Couldn't open the inode of the root "
736 "directory.\n");
737 err = EIO;
738 result = (ntfs_inode*)NULL;
739 goto out;
743 while (p && *p) {
744 /* Find the end of the first token. */
745 q = strchr(p, PATH_SEP);
746 if (q != NULL) {
747 *q = '\0';
749 #if CACHE_INODE_SIZE
751 * fetch inode for partial path from cache
753 cached = (struct CACHED_INODE*)NULL;
754 if (!parent) {
755 item.pathname = fullname;
756 item.varsize = strlen(fullname) + 1;
757 cached = (struct CACHED_INODE*)ntfs_fetch_cache(
758 vol->xinode_cache, GENERIC(&item),
759 inode_cache_compare);
760 if (cached) {
761 inum = cached->inum;
765 * if not in cache, translate, search, then
766 * insert into cache if found
768 if (!cached) {
769 len = ntfs_mbstoucs(p, &unicode);
770 if (len < 0) {
771 ntfs_log_perror("Could not convert filename to Unicode:"
772 " '%s'", p);
773 err = errno;
774 goto close;
775 } else if (len > NTFS_MAX_NAME_LEN) {
776 err = ENAMETOOLONG;
777 goto close;
779 inum = ntfs_inode_lookup_by_name(ni, unicode, len);
780 if (!parent && (inum != (u64) -1)) {
781 item.inum = inum;
782 ntfs_enter_cache(vol->xinode_cache,
783 GENERIC(&item),
784 inode_cache_compare);
787 #else
788 len = ntfs_mbstoucs(p, &unicode);
789 if (len < 0) {
790 ntfs_log_perror("Could not convert filename to Unicode:"
791 " '%s'", p);
792 err = errno;
793 goto close;
794 } else if (len > NTFS_MAX_NAME_LEN) {
795 err = ENAMETOOLONG;
796 goto close;
798 inum = ntfs_inode_lookup_by_name(ni, unicode, len);
799 #endif
800 if (inum == (u64) -1) {
801 ntfs_log_debug("Couldn't find name '%s' in pathname "
802 "'%s'.\n", p, pathname);
803 err = ENOENT;
804 goto close;
807 if (ni != parent)
808 if (ntfs_inode_close(ni)) {
809 err = errno;
810 goto out;
813 inum = MREF(inum);
814 ni = ntfs_inode_open(vol, inum);
815 if (!ni) {
816 ntfs_log_debug("Cannot open inode %llu: %s.\n",
817 (unsigned long long)inum, p);
818 err = EIO;
819 goto close;
822 free(unicode);
823 unicode = NULL;
825 if (q) *q++ = PATH_SEP; /* JPA */
826 p = q;
827 while (p && *p && *p == PATH_SEP)
828 p++;
831 result = ni;
832 ni = NULL;
833 close:
834 if (ni && (ni != parent))
835 if (ntfs_inode_close(ni) && !err)
836 err = errno;
837 out:
838 free(ascii);
839 free(unicode);
840 if (err)
841 errno = err;
842 return result;
846 * The little endian Unicode string ".." for ntfs_readdir().
848 static const ntfschar dotdot[3] = { const_cpu_to_le16('.'),
849 const_cpu_to_le16('.'),
850 const_cpu_to_le16('\0') };
853 * union index_union -
854 * More helpers for ntfs_readdir().
856 typedef union {
857 INDEX_ROOT *ir;
858 INDEX_ALLOCATION *ia;
859 } index_union __attribute__((__transparent_union__));
862 * enum INDEX_TYPE -
863 * More helpers for ntfs_readdir().
865 typedef enum {
866 INDEX_TYPE_ROOT, /* index root */
867 INDEX_TYPE_ALLOCATION, /* index allocation */
868 } INDEX_TYPE;
871 * Decode Interix file types
873 * Non-Interix types are returned as plain files, because a
874 * Windows user may force patterns very similar to Interix,
875 * and most metadata files have such similar patters.
878 static u32 ntfs_interix_types(ntfs_inode *ni)
880 ntfs_attr *na;
881 u32 dt_type;
882 le64 magic;
884 dt_type = NTFS_DT_UNKNOWN;
885 na = ntfs_attr_open(ni, AT_DATA, NULL, 0);
886 if (na) {
887 /* Unrecognized patterns (eg HID + SYST) are plain files */
888 dt_type = NTFS_DT_REG;
889 if (na->data_size <= 1) {
890 if (!(ni->flags & FILE_ATTR_HIDDEN))
891 dt_type = (na->data_size ?
892 NTFS_DT_SOCK : NTFS_DT_FIFO);
893 } else {
894 if ((na->data_size >= (s64)sizeof(magic))
895 && (ntfs_attr_pread(na, 0, sizeof(magic), &magic)
896 == sizeof(magic))) {
897 if (magic == INTX_SYMBOLIC_LINK)
898 dt_type = NTFS_DT_LNK;
899 else if (magic == INTX_BLOCK_DEVICE)
900 dt_type = NTFS_DT_BLK;
901 else if (magic == INTX_CHARACTER_DEVICE)
902 dt_type = NTFS_DT_CHR;
905 ntfs_attr_close(na);
907 return (dt_type);
911 * Decode file types
913 * Better only use for Interix types and junctions,
914 * unneeded complexity when used for plain files or directories
916 * Error cases are logged and returned as unknown.
919 static u32 ntfs_dir_entry_type(ntfs_inode *dir_ni, MFT_REF mref,
920 FILE_ATTR_FLAGS attributes)
922 ntfs_inode *ni;
923 u32 dt_type;
925 dt_type = NTFS_DT_UNKNOWN;
926 ni = ntfs_inode_open(dir_ni->vol, mref);
927 if (ni) {
928 if ((attributes & FILE_ATTR_REPARSE_POINT)
929 && ntfs_possible_symlink(ni))
930 dt_type = NTFS_DT_LNK;
931 else
932 if ((attributes & FILE_ATTR_SYSTEM)
933 && !(attributes & FILE_ATTR_I30_INDEX_PRESENT))
934 dt_type = ntfs_interix_types(ni);
935 else
936 dt_type = (attributes
937 & FILE_ATTR_I30_INDEX_PRESENT
938 ? NTFS_DT_DIR : NTFS_DT_REG);
939 if (ntfs_inode_close(ni)) {
940 /* anything special worth doing ? */
941 ntfs_log_error("Failed to close inode %lld\n",
942 (long long)MREF(mref));
945 if (dt_type == NTFS_DT_UNKNOWN)
946 ntfs_log_error("Could not decode the type of inode %lld\n",
947 (long long)MREF(mref));
948 return (dt_type);
952 * ntfs_filldir - ntfs specific filldir method
953 * @dir_ni: ntfs inode of current directory
954 * @pos: current position in directory
955 * @ivcn_bits: log(2) of index vcn size
956 * @index_type: specifies whether @iu is an index root or an index allocation
957 * @iu: index root or index block to which @ie belongs
958 * @ie: current index entry
959 * @dirent: context for filldir callback supplied by the caller
960 * @filldir: filldir callback supplied by the caller
962 * Pass information specifying the current directory entry @ie to the @filldir
963 * callback.
965 static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits,
966 const INDEX_TYPE index_type, index_union iu, INDEX_ENTRY *ie,
967 void *dirent, ntfs_filldir_t filldir)
969 FILE_NAME_ATTR *fn = &ie->key.file_name;
970 unsigned dt_type;
971 BOOL metadata;
972 ntfschar *loname;
973 int res;
974 MFT_REF mref;
976 ntfs_log_trace("Entering.\n");
978 /* Advance the position even if going to skip the entry. */
979 if (index_type == INDEX_TYPE_ALLOCATION)
980 *pos = (u8*)ie - (u8*)iu.ia + (sle64_to_cpu(
981 iu.ia->index_block_vcn) << ivcn_bits) +
982 dir_ni->vol->mft_record_size;
983 else /* if (index_type == INDEX_TYPE_ROOT) */
984 *pos = (u8*)ie - (u8*)iu.ir;
985 mref = le64_to_cpu(ie->indexed_file);
986 metadata = (MREF(mref) != FILE_root) && (MREF(mref) < FILE_first_user);
987 /* Skip root directory self reference entry. */
988 if (MREF_LE(ie->indexed_file) == FILE_root)
989 return 0;
990 if ((ie->key.file_name.file_attributes
991 & (FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYSTEM))
992 && !metadata)
993 dt_type = ntfs_dir_entry_type(dir_ni, mref,
994 ie->key.file_name.file_attributes);
995 else if (ie->key.file_name.file_attributes
996 & FILE_ATTR_I30_INDEX_PRESENT)
997 dt_type = NTFS_DT_DIR;
998 else
999 dt_type = NTFS_DT_REG;
1001 /* return metadata files and hidden files if requested */
1002 if ((!metadata && (NVolShowHidFiles(dir_ni->vol)
1003 || !(fn->file_attributes & FILE_ATTR_HIDDEN)))
1004 || (NVolShowSysFiles(dir_ni->vol) && (NVolShowHidFiles(dir_ni->vol)
1005 || metadata))) {
1006 if (NVolCaseSensitive(dir_ni->vol)) {
1007 res = filldir(dirent, fn->file_name,
1008 fn->file_name_length,
1009 fn->file_name_type, *pos,
1010 mref, dt_type);
1011 } else {
1012 loname = (ntfschar*)ntfs_malloc(2*fn->file_name_length);
1013 if (loname) {
1014 memcpy(loname, fn->file_name,
1015 2*fn->file_name_length);
1016 ntfs_name_locase(loname, fn->file_name_length,
1017 dir_ni->vol->locase,
1018 dir_ni->vol->upcase_len);
1019 res = filldir(dirent, loname,
1020 fn->file_name_length,
1021 fn->file_name_type, *pos,
1022 mref, dt_type);
1023 free(loname);
1024 } else
1025 res = -1;
1027 } else
1028 res = 0;
1029 return (res);
1033 * ntfs_mft_get_parent_ref - find mft reference of parent directory of an inode
1034 * @ni: ntfs inode whose parent directory to find
1036 * Find the parent directory of the ntfs inode @ni. To do this, find the first
1037 * file name attribute in the mft record of @ni and return the parent mft
1038 * reference from that.
1040 * Note this only makes sense for directories, since files can be hard linked
1041 * from multiple directories and there is no way for us to tell which one is
1042 * being looked for.
1044 * Technically directories can have hard links, too, but we consider that as
1045 * illegal as Linux/UNIX do not support directory hard links.
1047 * Return the mft reference of the parent directory on success or -1 on error
1048 * with errno set to the error code.
1050 static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
1052 MFT_REF mref;
1053 ntfs_attr_search_ctx *ctx;
1054 FILE_NAME_ATTR *fn;
1055 int eo;
1057 ntfs_log_trace("Entering.\n");
1059 if (!ni) {
1060 errno = EINVAL;
1061 return ERR_MREF(-1);
1064 ctx = ntfs_attr_get_search_ctx(ni, NULL);
1065 if (!ctx)
1066 return ERR_MREF(-1);
1067 if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
1068 ntfs_log_error("No file name found in inode %lld\n",
1069 (unsigned long long)ni->mft_no);
1070 goto err_out;
1072 if (ctx->attr->non_resident) {
1073 ntfs_log_error("File name attribute must be resident (inode "
1074 "%lld)\n", (unsigned long long)ni->mft_no);
1075 goto io_err_out;
1077 fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
1078 le16_to_cpu(ctx->attr->value_offset));
1079 if ((u8*)fn + le32_to_cpu(ctx->attr->value_length) >
1080 (u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) {
1081 ntfs_log_error("Corrupt file name attribute in inode %lld.\n",
1082 (unsigned long long)ni->mft_no);
1083 goto io_err_out;
1085 mref = le64_to_cpu(fn->parent_directory);
1086 ntfs_attr_put_search_ctx(ctx);
1087 return mref;
1088 io_err_out:
1089 errno = EIO;
1090 err_out:
1091 eo = errno;
1092 ntfs_attr_put_search_ctx(ctx);
1093 errno = eo;
1094 return ERR_MREF(-1);
1098 * ntfs_readdir - read the contents of an ntfs directory
1099 * @dir_ni: ntfs inode of current directory
1100 * @pos: current position in directory
1101 * @dirent: context for filldir callback supplied by the caller
1102 * @filldir: filldir callback supplied by the caller
1104 * Parse the index root and the index blocks that are marked in use in the
1105 * index bitmap and hand each found directory entry to the @filldir callback
1106 * supplied by the caller.
1108 * Return 0 on success or -1 on error with errno set to the error code.
1110 * Note: Index blocks are parsed in ascending vcn order, from which follows
1111 * that the directory entries are not returned sorted.
1113 int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
1114 void *dirent, ntfs_filldir_t filldir)
1116 s64 i_size, br, ia_pos, bmp_pos, ia_start;
1117 ntfs_volume *vol;
1118 ntfs_attr *ia_na, *bmp_na = NULL;
1119 ntfs_attr_search_ctx *ctx = NULL;
1120 u8 *index_end, *bmp = NULL;
1121 INDEX_ROOT *ir;
1122 INDEX_ENTRY *ie;
1123 INDEX_ALLOCATION *ia = NULL;
1124 int rc, ir_pos, bmp_buf_size, bmp_buf_pos, eo;
1125 u32 index_block_size;
1126 u8 index_block_size_bits, index_vcn_size_bits;
1128 ntfs_log_trace("Entering.\n");
1130 if (!dir_ni || !pos || !filldir) {
1131 errno = EINVAL;
1132 return -1;
1135 if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
1136 errno = ENOTDIR;
1137 return -1;
1140 vol = dir_ni->vol;
1142 ntfs_log_trace("Entering for inode %lld, *pos 0x%llx.\n",
1143 (unsigned long long)dir_ni->mft_no, (long long)*pos);
1145 /* Open the index allocation attribute. */
1146 ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
1147 if (!ia_na) {
1148 if (errno != ENOENT) {
1149 ntfs_log_perror("Failed to open index allocation attribute. "
1150 "Directory inode %lld is corrupt or bug",
1151 (unsigned long long)dir_ni->mft_no);
1152 return -1;
1154 i_size = 0;
1155 } else
1156 i_size = ia_na->data_size;
1158 rc = 0;
1160 /* Are we at end of dir yet? */
1161 if (*pos >= i_size + vol->mft_record_size)
1162 goto done;
1164 /* Emulate . and .. for all directories. */
1165 if (!*pos) {
1166 rc = filldir(dirent, dotdot, 1, FILE_NAME_POSIX, *pos,
1167 MK_MREF(dir_ni->mft_no,
1168 le16_to_cpu(dir_ni->mrec->sequence_number)),
1169 NTFS_DT_DIR);
1170 if (rc)
1171 goto err_out;
1172 ++*pos;
1174 if (*pos == 1) {
1175 MFT_REF parent_mref;
1177 parent_mref = ntfs_mft_get_parent_ref(dir_ni);
1178 if (parent_mref == ERR_MREF(-1)) {
1179 ntfs_log_perror("Parent directory not found");
1180 goto dir_err_out;
1183 rc = filldir(dirent, dotdot, 2, FILE_NAME_POSIX, *pos,
1184 parent_mref, NTFS_DT_DIR);
1185 if (rc)
1186 goto err_out;
1187 ++*pos;
1190 ctx = ntfs_attr_get_search_ctx(dir_ni, NULL);
1191 if (!ctx)
1192 goto err_out;
1194 /* Get the offset into the index root attribute. */
1195 ir_pos = (int)*pos;
1196 /* Find the index root attribute in the mft record. */
1197 if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL,
1198 0, ctx)) {
1199 ntfs_log_perror("Index root attribute missing in directory inode "
1200 "%lld", (unsigned long long)dir_ni->mft_no);
1201 goto dir_err_out;
1203 /* Get to the index root value. */
1204 ir = (INDEX_ROOT*)((u8*)ctx->attr +
1205 le16_to_cpu(ctx->attr->value_offset));
1207 /* Determine the size of a vcn in the directory index. */
1208 index_block_size = le32_to_cpu(ir->index_block_size);
1209 if (index_block_size < NTFS_BLOCK_SIZE ||
1210 index_block_size & (index_block_size - 1)) {
1211 ntfs_log_error("Index block size %u is invalid.\n",
1212 (unsigned)index_block_size);
1213 goto dir_err_out;
1215 index_block_size_bits = ffs(index_block_size) - 1;
1216 if (vol->cluster_size <= index_block_size) {
1217 index_vcn_size_bits = vol->cluster_size_bits;
1218 } else {
1219 index_vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
1222 /* Are we jumping straight into the index allocation attribute? */
1223 if (*pos >= vol->mft_record_size) {
1224 ntfs_attr_put_search_ctx(ctx);
1225 ctx = NULL;
1226 goto skip_index_root;
1229 index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
1230 /* The first index entry. */
1231 ie = (INDEX_ENTRY*)((u8*)&ir->index +
1232 le32_to_cpu(ir->index.entries_offset));
1234 * Loop until we exceed valid memory (corruption case) or until we
1235 * reach the last entry or until filldir tells us it has had enough
1236 * or signals an error (both covered by the rc test).
1238 for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
1239 ntfs_log_debug("In index root, offset %d.\n", (int)((u8*)ie - (u8*)ir));
1240 /* Bounds checks. */
1241 if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
1242 sizeof(INDEX_ENTRY_HEADER) > index_end ||
1243 (u8*)ie + le16_to_cpu(ie->key_length) >
1244 index_end)
1245 goto dir_err_out;
1246 /* The last entry cannot contain a name. */
1247 if (ie->ie_flags & INDEX_ENTRY_END)
1248 break;
1250 if (!le16_to_cpu(ie->length))
1251 goto dir_err_out;
1253 /* Skip index root entry if continuing previous readdir. */
1254 if (ir_pos > (u8*)ie - (u8*)ir)
1255 continue;
1257 * Submit the directory entry to ntfs_filldir(), which will
1258 * invoke the filldir() callback as appropriate.
1260 rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits,
1261 INDEX_TYPE_ROOT, ir, ie, dirent, filldir);
1262 if (rc) {
1263 ntfs_attr_put_search_ctx(ctx);
1264 ctx = NULL;
1265 goto err_out;
1268 ntfs_attr_put_search_ctx(ctx);
1269 ctx = NULL;
1271 /* If there is no index allocation attribute we are finished. */
1272 if (!ia_na)
1273 goto EOD;
1275 /* Advance *pos to the beginning of the index allocation. */
1276 *pos = vol->mft_record_size;
1278 skip_index_root:
1280 if (!ia_na)
1281 goto done;
1283 /* Allocate a buffer for the current index block. */
1284 ia = ntfs_malloc(index_block_size);
1285 if (!ia)
1286 goto err_out;
1288 bmp_na = ntfs_attr_open(dir_ni, AT_BITMAP, NTFS_INDEX_I30, 4);
1289 if (!bmp_na) {
1290 ntfs_log_perror("Failed to open index bitmap attribute");
1291 goto dir_err_out;
1294 /* Get the offset into the index allocation attribute. */
1295 ia_pos = *pos - vol->mft_record_size;
1297 bmp_pos = ia_pos >> index_block_size_bits;
1298 if (bmp_pos >> 3 >= bmp_na->data_size) {
1299 ntfs_log_error("Current index position exceeds index bitmap "
1300 "size.\n");
1301 goto dir_err_out;
1304 bmp_buf_size = min(bmp_na->data_size - (bmp_pos >> 3), 4096);
1305 bmp = ntfs_malloc(bmp_buf_size);
1306 if (!bmp)
1307 goto err_out;
1309 br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp);
1310 if (br != bmp_buf_size) {
1311 if (br != -1)
1312 errno = EIO;
1313 ntfs_log_perror("Failed to read from index bitmap attribute");
1314 goto err_out;
1317 bmp_buf_pos = 0;
1318 /* If the index block is not in use find the next one that is. */
1319 while (!(bmp[bmp_buf_pos >> 3] & (1 << (bmp_buf_pos & 7)))) {
1320 find_next_index_buffer:
1321 bmp_pos++;
1322 bmp_buf_pos++;
1323 /* If we have reached the end of the bitmap, we are done. */
1324 if (bmp_pos >> 3 >= bmp_na->data_size)
1325 goto EOD;
1326 ia_pos = bmp_pos << index_block_size_bits;
1327 if (bmp_buf_pos >> 3 < bmp_buf_size)
1328 continue;
1329 /* Read next chunk from the index bitmap. */
1330 bmp_buf_pos = 0;
1331 if ((bmp_pos >> 3) + bmp_buf_size > bmp_na->data_size)
1332 bmp_buf_size = bmp_na->data_size - (bmp_pos >> 3);
1333 br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp);
1334 if (br != bmp_buf_size) {
1335 if (br != -1)
1336 errno = EIO;
1337 ntfs_log_perror("Failed to read from index bitmap attribute");
1338 goto err_out;
1342 ntfs_log_debug("Handling index block 0x%llx.\n", (long long)bmp_pos);
1344 /* Read the index block starting at bmp_pos. */
1345 br = ntfs_attr_mst_pread(ia_na, bmp_pos << index_block_size_bits, 1,
1346 index_block_size, ia);
1347 if (br != 1) {
1348 if (br != -1)
1349 errno = EIO;
1350 ntfs_log_perror("Failed to read index block");
1351 goto err_out;
1354 ia_start = ia_pos & ~(s64)(index_block_size - 1);
1355 if (sle64_to_cpu(ia->index_block_vcn) != ia_start >>
1356 index_vcn_size_bits) {
1357 ntfs_log_error("Actual VCN (0x%llx) of index buffer is different "
1358 "from expected VCN (0x%llx) in inode 0x%llx.\n",
1359 (long long)sle64_to_cpu(ia->index_block_vcn),
1360 (long long)ia_start >> index_vcn_size_bits,
1361 (unsigned long long)dir_ni->mft_no);
1362 goto dir_err_out;
1364 if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) {
1365 ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode %lld "
1366 "has a size (%u) differing from the directory "
1367 "specified size (%u).\n", (long long)ia_start >>
1368 index_vcn_size_bits,
1369 (unsigned long long)dir_ni->mft_no,
1370 (unsigned) le32_to_cpu(ia->index.allocated_size)
1371 + 0x18, (unsigned)index_block_size);
1372 goto dir_err_out;
1374 index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
1375 if (index_end > (u8*)ia + index_block_size) {
1376 ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode "
1377 "%lld exceeds maximum size.\n",
1378 (long long)ia_start >> index_vcn_size_bits,
1379 (unsigned long long)dir_ni->mft_no);
1380 goto dir_err_out;
1382 /* The first index entry. */
1383 ie = (INDEX_ENTRY*)((u8*)&ia->index +
1384 le32_to_cpu(ia->index.entries_offset));
1386 * Loop until we exceed valid memory (corruption case) or until we
1387 * reach the last entry or until ntfs_filldir tells us it has had
1388 * enough or signals an error (both covered by the rc test).
1390 for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
1391 ntfs_log_debug("In index allocation, offset 0x%llx.\n",
1392 (long long)ia_start + ((u8*)ie - (u8*)ia));
1393 /* Bounds checks. */
1394 if ((u8*)ie < (u8*)ia || (u8*)ie +
1395 sizeof(INDEX_ENTRY_HEADER) > index_end ||
1396 (u8*)ie + le16_to_cpu(ie->key_length) >
1397 index_end) {
1398 ntfs_log_error("Index entry out of bounds in directory inode "
1399 "%lld.\n", (unsigned long long)dir_ni->mft_no);
1400 goto dir_err_out;
1402 /* The last entry cannot contain a name. */
1403 if (ie->ie_flags & INDEX_ENTRY_END)
1404 break;
1406 if (!le16_to_cpu(ie->length))
1407 goto dir_err_out;
1409 /* Skip index entry if continuing previous readdir. */
1410 if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
1411 continue;
1413 * Submit the directory entry to ntfs_filldir(), which will
1414 * invoke the filldir() callback as appropriate.
1416 rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits,
1417 INDEX_TYPE_ALLOCATION, ia, ie, dirent, filldir);
1418 if (rc)
1419 goto err_out;
1421 goto find_next_index_buffer;
1422 EOD:
1423 /* We are finished, set *pos to EOD. */
1424 *pos = i_size + vol->mft_record_size;
1425 done:
1426 free(ia);
1427 free(bmp);
1428 if (bmp_na)
1429 ntfs_attr_close(bmp_na);
1430 if (ia_na)
1431 ntfs_attr_close(ia_na);
1432 ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", (long long)*pos);
1433 return 0;
1434 dir_err_out:
1435 errno = EIO;
1436 err_out:
1437 eo = errno;
1438 ntfs_log_trace("failed.\n");
1439 if (ctx)
1440 ntfs_attr_put_search_ctx(ctx);
1441 free(ia);
1442 free(bmp);
1443 if (bmp_na)
1444 ntfs_attr_close(bmp_na);
1445 if (ia_na)
1446 ntfs_attr_close(ia_na);
1447 errno = eo;
1448 return -1;
1453 * __ntfs_create - create object on ntfs volume
1454 * @dir_ni: ntfs inode for directory in which create new object
1455 * @securid: id of inheritable security descriptor, 0 if none
1456 * @name: unicode name of new object
1457 * @name_len: length of the name in unicode characters
1458 * @type: type of the object to create
1459 * @dev: major and minor device numbers (obtained from makedev())
1460 * @target: target in unicode (only for symlinks)
1461 * @target_len: length of target in unicode characters
1463 * Internal, use ntfs_create{,_device,_symlink} wrappers instead.
1465 * @type can be:
1466 * S_IFREG to create regular file
1467 * S_IFDIR to create directory
1468 * S_IFBLK to create block device
1469 * S_IFCHR to create character device
1470 * S_IFLNK to create symbolic link
1471 * S_IFIFO to create FIFO
1472 * S_IFSOCK to create socket
1473 * other values are invalid.
1475 * @dev is used only if @type is S_IFBLK or S_IFCHR, in other cases its value
1476 * ignored.
1478 * @target and @target_len are used only if @type is S_IFLNK, in other cases
1479 * their value ignored.
1481 * Return opened ntfs inode that describes created object on success or NULL
1482 * on error with errno set to the error code.
1484 static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
1485 const ntfschar *name, u8 name_len, mode_t type, dev_t dev,
1486 const ntfschar *target, int target_len)
1488 ntfs_inode *ni;
1489 int rollback_data = 0, rollback_sd = 0;
1490 FILE_NAME_ATTR *fn = NULL;
1491 STANDARD_INFORMATION *si = NULL;
1492 int err, fn_len, si_len;
1494 ntfs_log_trace("Entering.\n");
1496 /* Sanity checks. */
1497 if (!dir_ni || !name || !name_len) {
1498 ntfs_log_error("Invalid arguments.\n");
1499 errno = EINVAL;
1500 return NULL;
1503 if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
1504 errno = EOPNOTSUPP;
1505 return NULL;
1508 ni = ntfs_mft_record_alloc(dir_ni->vol, NULL);
1509 if (!ni)
1510 return NULL;
1511 #if CACHE_NIDATA_SIZE
1512 ntfs_inode_invalidate(dir_ni->vol, ni->mft_no);
1513 #endif
1515 * Create STANDARD_INFORMATION attribute.
1516 * JPA Depending on available inherited security descriptor,
1517 * Write STANDARD_INFORMATION v1.2 (no inheritance) or v3
1519 if (securid)
1520 si_len = sizeof(STANDARD_INFORMATION);
1521 else
1522 si_len = offsetof(STANDARD_INFORMATION, v1_end);
1523 si = ntfs_calloc(si_len);
1524 if (!si) {
1525 err = errno;
1526 goto err_out;
1528 si->creation_time = ni->creation_time;
1529 si->last_data_change_time = ni->last_data_change_time;
1530 si->last_mft_change_time = ni->last_mft_change_time;
1531 si->last_access_time = ni->last_access_time;
1532 if (securid) {
1533 set_nino_flag(ni, v3_Extensions);
1534 ni->owner_id = si->owner_id = 0;
1535 ni->security_id = si->security_id = securid;
1536 ni->quota_charged = si->quota_charged = const_cpu_to_le64(0);
1537 ni->usn = si->usn = const_cpu_to_le64(0);
1538 } else
1539 clear_nino_flag(ni, v3_Extensions);
1540 if (!S_ISREG(type) && !S_ISDIR(type)) {
1541 si->file_attributes = FILE_ATTR_SYSTEM;
1542 ni->flags = FILE_ATTR_SYSTEM;
1544 ni->flags |= FILE_ATTR_ARCHIVE;
1545 if (NVolHideDotFiles(dir_ni->vol)
1546 && (name_len > 1)
1547 && (name[0] == const_cpu_to_le16('.'))
1548 && (name[1] != const_cpu_to_le16('.')))
1549 ni->flags |= FILE_ATTR_HIDDEN;
1551 * Set compression flag according to parent directory
1552 * unless NTFS version < 3.0 or cluster size > 4K
1553 * or compression has been disabled
1555 if ((dir_ni->flags & FILE_ATTR_COMPRESSED)
1556 && (dir_ni->vol->major_ver >= 3)
1557 && NVolCompression(dir_ni->vol)
1558 && (dir_ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE)
1559 && (S_ISREG(type) || S_ISDIR(type)))
1560 ni->flags |= FILE_ATTR_COMPRESSED;
1561 /* Add STANDARD_INFORMATION to inode. */
1562 if (ntfs_attr_add(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0,
1563 (u8*)si, si_len)) {
1564 err = errno;
1565 ntfs_log_error("Failed to add STANDARD_INFORMATION "
1566 "attribute.\n");
1567 goto err_out;
1570 if (!securid) {
1571 if (ntfs_sd_add_everyone(ni)) {
1572 err = errno;
1573 goto err_out;
1576 rollback_sd = 1;
1578 if (S_ISDIR(type)) {
1579 INDEX_ROOT *ir = NULL;
1580 INDEX_ENTRY *ie;
1581 int ir_len, index_len;
1583 /* Create INDEX_ROOT attribute. */
1584 index_len = sizeof(INDEX_HEADER) + sizeof(INDEX_ENTRY_HEADER);
1585 ir_len = offsetof(INDEX_ROOT, index) + index_len;
1586 ir = ntfs_calloc(ir_len);
1587 if (!ir) {
1588 err = errno;
1589 goto err_out;
1591 ir->type = AT_FILE_NAME;
1592 ir->collation_rule = COLLATION_FILE_NAME;
1593 ir->index_block_size = cpu_to_le32(ni->vol->indx_record_size);
1594 if (ni->vol->cluster_size <= ni->vol->indx_record_size)
1595 ir->clusters_per_index_block =
1596 ni->vol->indx_record_size >>
1597 ni->vol->cluster_size_bits;
1598 else
1599 ir->clusters_per_index_block =
1600 ni->vol->indx_record_size >>
1601 NTFS_BLOCK_SIZE_BITS;
1602 ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER));
1603 ir->index.index_length = cpu_to_le32(index_len);
1604 ir->index.allocated_size = cpu_to_le32(index_len);
1605 ie = (INDEX_ENTRY*)((u8*)ir + sizeof(INDEX_ROOT));
1606 ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER));
1607 ie->key_length = 0;
1608 ie->ie_flags = INDEX_ENTRY_END;
1609 /* Add INDEX_ROOT attribute to inode. */
1610 if (ntfs_attr_add(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4,
1611 (u8*)ir, ir_len)) {
1612 err = errno;
1613 free(ir);
1614 ntfs_log_error("Failed to add INDEX_ROOT attribute.\n");
1615 goto err_out;
1617 free(ir);
1618 } else {
1619 INTX_FILE *data;
1620 int data_len;
1622 switch (type) {
1623 case S_IFBLK:
1624 case S_IFCHR:
1625 data_len = offsetof(INTX_FILE, device_end);
1626 data = ntfs_malloc(data_len);
1627 if (!data) {
1628 err = errno;
1629 goto err_out;
1631 data->major = cpu_to_le64(major(dev));
1632 data->minor = cpu_to_le64(minor(dev));
1633 if (type == S_IFBLK)
1634 data->magic = INTX_BLOCK_DEVICE;
1635 if (type == S_IFCHR)
1636 data->magic = INTX_CHARACTER_DEVICE;
1637 break;
1638 case S_IFLNK:
1639 data_len = sizeof(INTX_FILE_TYPES) +
1640 target_len * sizeof(ntfschar);
1641 data = ntfs_malloc(data_len);
1642 if (!data) {
1643 err = errno;
1644 goto err_out;
1646 data->magic = INTX_SYMBOLIC_LINK;
1647 memcpy(data->target, target,
1648 target_len * sizeof(ntfschar));
1649 break;
1650 case S_IFSOCK:
1651 data = NULL;
1652 data_len = 1;
1653 break;
1654 default: /* FIFO or regular file. */
1655 data = NULL;
1656 data_len = 0;
1657 break;
1659 /* Add DATA attribute to inode. */
1660 if (ntfs_attr_add(ni, AT_DATA, AT_UNNAMED, 0, (u8*)data,
1661 data_len)) {
1662 err = errno;
1663 ntfs_log_error("Failed to add DATA attribute.\n");
1664 free(data);
1665 goto err_out;
1667 rollback_data = 1;
1668 free(data);
1670 /* Create FILE_NAME attribute. */
1671 fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
1672 fn = ntfs_calloc(fn_len);
1673 if (!fn) {
1674 err = errno;
1675 goto err_out;
1677 fn->parent_directory = MK_LE_MREF(dir_ni->mft_no,
1678 le16_to_cpu(dir_ni->mrec->sequence_number));
1679 fn->file_name_length = name_len;
1680 fn->file_name_type = FILE_NAME_POSIX;
1681 if (S_ISDIR(type))
1682 fn->file_attributes = FILE_ATTR_I30_INDEX_PRESENT;
1683 if (!S_ISREG(type) && !S_ISDIR(type))
1684 fn->file_attributes = FILE_ATTR_SYSTEM;
1685 else
1686 fn->file_attributes |= ni->flags & FILE_ATTR_COMPRESSED;
1687 fn->file_attributes |= FILE_ATTR_ARCHIVE;
1688 fn->file_attributes |= ni->flags & FILE_ATTR_HIDDEN;
1689 fn->creation_time = ni->creation_time;
1690 fn->last_data_change_time = ni->last_data_change_time;
1691 fn->last_mft_change_time = ni->last_mft_change_time;
1692 fn->last_access_time = ni->last_access_time;
1693 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
1694 fn->data_size = fn->allocated_size = const_cpu_to_le64(0);
1695 else {
1696 fn->data_size = cpu_to_sle64(ni->data_size);
1697 fn->allocated_size = cpu_to_sle64(ni->allocated_size);
1699 memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
1700 /* Add FILE_NAME attribute to inode. */
1701 if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
1702 err = errno;
1703 ntfs_log_error("Failed to add FILE_NAME attribute.\n");
1704 goto err_out;
1706 /* Add FILE_NAME attribute to index. */
1707 if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no,
1708 le16_to_cpu(ni->mrec->sequence_number)))) {
1709 err = errno;
1710 ntfs_log_perror("Failed to add entry to the index");
1711 goto err_out;
1713 /* Set hard links count and directory flag. */
1714 ni->mrec->link_count = cpu_to_le16(1);
1715 if (S_ISDIR(type))
1716 ni->mrec->flags |= MFT_RECORD_IS_DIRECTORY;
1717 ntfs_inode_mark_dirty(ni);
1718 /* Done! */
1719 free(fn);
1720 free(si);
1721 ntfs_log_trace("Done.\n");
1722 return ni;
1723 err_out:
1724 ntfs_log_trace("Failed.\n");
1726 if (rollback_sd)
1727 ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
1729 if (rollback_data)
1730 ntfs_attr_remove(ni, AT_DATA, AT_UNNAMED, 0);
1732 * Free extent MFT records (should not exist any with current
1733 * ntfs_create implementation, but for any case if something will be
1734 * changed in the future).
1736 while (ni->nr_extents)
1737 if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) {
1738 err = errno;
1739 ntfs_log_error("Failed to free extent MFT record. "
1740 "Leaving inconsistent metadata.\n");
1742 if (ntfs_mft_record_free(ni->vol, ni))
1743 ntfs_log_error("Failed to free MFT record. "
1744 "Leaving inconsistent metadata. Run chkdsk.\n");
1745 free(fn);
1746 free(si);
1747 errno = err;
1748 return NULL;
1752 * Some wrappers around __ntfs_create() ...
1755 ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, const ntfschar *name,
1756 u8 name_len, mode_t type)
1758 if (type != S_IFREG && type != S_IFDIR && type != S_IFIFO &&
1759 type != S_IFSOCK) {
1760 ntfs_log_error("Invalid arguments.\n");
1761 return NULL;
1763 return __ntfs_create(dir_ni, securid, name, name_len, type, 0, NULL, 0);
1766 ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
1767 const ntfschar *name, u8 name_len, mode_t type, dev_t dev)
1769 if (type != S_IFCHR && type != S_IFBLK) {
1770 ntfs_log_error("Invalid arguments.\n");
1771 return NULL;
1773 return __ntfs_create(dir_ni, securid, name, name_len, type, dev, NULL, 0);
1776 ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid,
1777 const ntfschar *name, u8 name_len, const ntfschar *target,
1778 int target_len)
1780 if (!target || !target_len) {
1781 ntfs_log_error("%s: Invalid argument (%p, %d)\n", __FUNCTION__,
1782 target, target_len);
1783 return NULL;
1785 return __ntfs_create(dir_ni, securid, name, name_len, S_IFLNK, 0,
1786 target, target_len);
1789 int ntfs_check_empty_dir(ntfs_inode *ni)
1791 ntfs_attr *na;
1792 int ret = 0;
1794 if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))
1795 return 0;
1797 na = ntfs_attr_open(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4);
1798 if (!na) {
1799 errno = EIO;
1800 ntfs_log_perror("Failed to open directory");
1801 return -1;
1804 /* Non-empty directory? */
1805 if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){
1806 /* Both ENOTEMPTY and EEXIST are ok. We use the more common. */
1807 errno = ENOTEMPTY;
1808 ntfs_log_debug("Directory is not empty\n");
1809 ret = -1;
1812 ntfs_attr_close(na);
1813 return ret;
1816 static int ntfs_check_unlinkable_dir(ntfs_inode *ni, FILE_NAME_ATTR *fn)
1818 int link_count = le16_to_cpu(ni->mrec->link_count);
1819 int ret;
1821 ret = ntfs_check_empty_dir(ni);
1822 if (!ret || errno != ENOTEMPTY)
1823 return ret;
1825 * Directory is non-empty, so we can unlink only if there is more than
1826 * one "real" hard link, i.e. links aren't different DOS and WIN32 names
1828 if ((link_count == 1) ||
1829 (link_count == 2 && fn->file_name_type == FILE_NAME_DOS)) {
1830 errno = ENOTEMPTY;
1831 ntfs_log_debug("Non-empty directory without hard links\n");
1832 goto no_hardlink;
1835 ret = 0;
1836 no_hardlink:
1837 return ret;
1841 * ntfs_delete - delete file or directory from ntfs volume
1842 * @ni: ntfs inode for object to delte
1843 * @dir_ni: ntfs inode for directory in which delete object
1844 * @name: unicode name of the object to delete
1845 * @name_len: length of the name in unicode characters
1847 * @ni is always closed after the call to this function (even if it failed),
1848 * user does not need to call ntfs_inode_close himself.
1850 * Return 0 on success or -1 on error with errno set to the error code.
1852 int ntfs_delete(ntfs_volume *vol, const char *pathname,
1853 ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
1854 u8 name_len)
1856 ntfs_attr_search_ctx *actx = NULL;
1857 FILE_NAME_ATTR *fn = NULL;
1858 BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
1859 BOOL case_sensitive_match = TRUE;
1860 int err = 0;
1861 #if CACHE_NIDATA_SIZE
1862 int i;
1863 #endif
1864 #if CACHE_INODE_SIZE
1865 struct CACHED_INODE item;
1866 const char *p;
1867 u64 inum = (u64)-1;
1868 int count;
1869 #endif
1870 #if CACHE_LOOKUP_SIZE
1871 struct CACHED_LOOKUP lkitem;
1872 #endif
1874 ntfs_log_trace("Entering.\n");
1876 if (!ni || !dir_ni || !name || !name_len) {
1877 ntfs_log_error("Invalid arguments.\n");
1878 errno = EINVAL;
1879 goto err_out;
1881 if (ni->nr_extents == -1)
1882 ni = ni->base_ni;
1883 if (dir_ni->nr_extents == -1)
1884 dir_ni = dir_ni->base_ni;
1886 * Search for FILE_NAME attribute with such name. If it's in POSIX or
1887 * WIN32_AND_DOS namespace, then simply remove it from index and inode.
1888 * If filename in DOS or in WIN32 namespace, then remove DOS name first,
1889 * only then remove WIN32 name.
1891 actx = ntfs_attr_get_search_ctx(ni, NULL);
1892 if (!actx)
1893 goto err_out;
1894 search:
1895 while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
1896 0, NULL, 0, actx)) {
1897 char *s;
1898 IGNORE_CASE_BOOL case_sensitive = IGNORE_CASE;
1900 errno = 0;
1901 fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
1902 le16_to_cpu(actx->attr->value_offset));
1903 s = ntfs_attr_name_get(fn->file_name, fn->file_name_length);
1904 ntfs_log_trace("name: '%s' type: %d dos: %d win32: %d "
1905 "case: %d\n", s, fn->file_name_type,
1906 looking_for_dos_name, looking_for_win32_name,
1907 case_sensitive_match);
1908 ntfs_attr_name_free(&s);
1909 if (looking_for_dos_name) {
1910 if (fn->file_name_type == FILE_NAME_DOS)
1911 break;
1912 else
1913 continue;
1915 if (looking_for_win32_name) {
1916 if (fn->file_name_type == FILE_NAME_WIN32)
1917 break;
1918 else
1919 continue;
1922 /* Ignore hard links from other directories */
1923 if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) {
1924 ntfs_log_debug("MFT record numbers don't match "
1925 "(%llu != %llu)\n",
1926 (long long unsigned)dir_ni->mft_no,
1927 (long long unsigned)MREF_LE(fn->parent_directory));
1928 continue;
1930 if (case_sensitive_match
1931 || ((fn->file_name_type == FILE_NAME_POSIX)
1932 && NVolCaseSensitive(ni->vol)))
1933 case_sensitive = CASE_SENSITIVE;
1935 if (ntfs_names_are_equal(fn->file_name, fn->file_name_length,
1936 name, name_len, case_sensitive,
1937 ni->vol->upcase, ni->vol->upcase_len)){
1939 if (fn->file_name_type == FILE_NAME_WIN32) {
1940 looking_for_dos_name = TRUE;
1941 ntfs_attr_reinit_search_ctx(actx);
1942 continue;
1944 if (fn->file_name_type == FILE_NAME_DOS)
1945 looking_for_dos_name = TRUE;
1946 break;
1949 if (errno) {
1951 * If case sensitive search failed, then try once again
1952 * ignoring case.
1954 if (errno == ENOENT && case_sensitive_match) {
1955 case_sensitive_match = FALSE;
1956 ntfs_attr_reinit_search_ctx(actx);
1957 goto search;
1959 goto err_out;
1962 if (ntfs_check_unlinkable_dir(ni, fn) < 0)
1963 goto err_out;
1965 if (ntfs_index_remove(dir_ni, ni, fn, le32_to_cpu(actx->attr->value_length)))
1966 goto err_out;
1969 * Keep the last name in place, this is useful for undeletion
1970 * (Windows also does so), however delete the name if it were
1971 * in an extent, to avoid leaving an attribute list.
1973 if ((ni->mrec->link_count == cpu_to_le16(1)) && !actx->base_ntfs_ino) {
1974 /* make sure to not loop to another search */
1975 looking_for_dos_name = FALSE;
1976 } else {
1977 if (ntfs_attr_record_rm(actx))
1978 goto err_out;
1981 ni->mrec->link_count = cpu_to_le16(le16_to_cpu(
1982 ni->mrec->link_count) - 1);
1984 ntfs_inode_mark_dirty(ni);
1985 if (looking_for_dos_name) {
1986 looking_for_dos_name = FALSE;
1987 looking_for_win32_name = TRUE;
1988 ntfs_attr_reinit_search_ctx(actx);
1989 goto search;
1991 /* TODO: Update object id, quota and securiry indexes if required. */
1993 * If hard link count is not equal to zero then we are done. In other
1994 * case there are no reference to this inode left, so we should free all
1995 * non-resident attributes and mark all MFT record as not in use.
1997 #if CACHE_LOOKUP_SIZE
1998 /* invalidate entry in lookup cache */
1999 lkitem.name = (const char*)NULL;
2000 lkitem.namesize = 0;
2001 lkitem.inum = ni->mft_no;
2002 lkitem.parent = dir_ni->mft_no;
2003 ntfs_invalidate_cache(vol->lookup_cache, GENERIC(&lkitem),
2004 lookup_cache_inv_compare, CACHE_NOHASH);
2005 #endif
2006 #if CACHE_INODE_SIZE
2007 inum = ni->mft_no;
2008 if (pathname) {
2009 /* invalide cache entry, even if there was an error */
2010 /* Remove leading /'s. */
2011 p = pathname;
2012 while (*p == PATH_SEP)
2013 p++;
2014 if (p[0] && (p[strlen(p)-1] == PATH_SEP))
2015 ntfs_log_error("Unnormalized path %s\n",pathname);
2016 item.pathname = p;
2017 item.varsize = strlen(p);
2018 } else {
2019 item.pathname = (const char*)NULL;
2020 item.varsize = 0;
2022 item.inum = inum;
2023 count = ntfs_invalidate_cache(vol->xinode_cache, GENERIC(&item),
2024 inode_cache_inv_compare, CACHE_NOHASH);
2025 if (pathname && !count)
2026 ntfs_log_error("Could not delete inode cache entry for %s\n",
2027 pathname);
2028 #endif
2029 if (ni->mrec->link_count) {
2030 ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME);
2031 goto ok;
2033 if (ntfs_delete_reparse_index(ni)) {
2035 * Failed to remove the reparse index : proceed anyway
2036 * This is not a critical error, the entry is useless
2037 * because of sequence_number, and stopping file deletion
2038 * would be much worse as the file is not referenced now.
2040 err = errno;
2042 if (ntfs_delete_object_id_index(ni)) {
2044 * Failed to remove the object id index : proceed anyway
2045 * This is not a critical error.
2047 err = errno;
2049 ntfs_attr_reinit_search_ctx(actx);
2050 while (!ntfs_attrs_walk(actx)) {
2051 if (actx->attr->non_resident) {
2052 runlist *rl;
2054 rl = ntfs_mapping_pairs_decompress(ni->vol, actx->attr,
2055 NULL);
2056 if (!rl) {
2057 err = errno;
2058 ntfs_log_error("Failed to decompress runlist. "
2059 "Leaving inconsistent metadata.\n");
2060 continue;
2062 if (ntfs_cluster_free_from_rl(ni->vol, rl)) {
2063 err = errno;
2064 ntfs_log_error("Failed to free clusters. "
2065 "Leaving inconsistent metadata.\n");
2066 continue;
2068 free(rl);
2071 if (errno != ENOENT) {
2072 err = errno;
2073 ntfs_log_error("Attribute enumeration failed. "
2074 "Probably leaving inconsistent metadata.\n");
2076 /* All extents should be attached after attribute walk. */
2077 #if CACHE_NIDATA_SIZE
2079 * Disconnect extents before deleting them, so they are
2080 * not wrongly moved to cache through the chainings
2082 for (i=ni->nr_extents-1; i>=0; i--) {
2083 ni->extent_nis[i]->base_ni = (ntfs_inode*)NULL;
2084 ni->extent_nis[i]->nr_extents = 0;
2085 if (ntfs_mft_record_free(ni->vol, ni->extent_nis[i])) {
2086 err = errno;
2087 ntfs_log_error("Failed to free extent MFT record. "
2088 "Leaving inconsistent metadata.\n");
2091 free(ni->extent_nis);
2092 ni->nr_extents = 0;
2093 ni->extent_nis = (ntfs_inode**)NULL;
2094 #else
2095 while (ni->nr_extents)
2096 if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) {
2097 err = errno;
2098 ntfs_log_error("Failed to free extent MFT record. "
2099 "Leaving inconsistent metadata.\n");
2101 #endif
2102 debug_double_inode(ni->mft_no,0);
2103 if (ntfs_mft_record_free(ni->vol, ni)) {
2104 err = errno;
2105 ntfs_log_error("Failed to free base MFT record. "
2106 "Leaving inconsistent metadata.\n");
2108 ni = NULL;
2109 ok:
2110 ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME);
2111 out:
2112 if (actx)
2113 ntfs_attr_put_search_ctx(actx);
2114 if (ntfs_inode_close(dir_ni) && !err)
2115 err = errno;
2116 if (ntfs_inode_close(ni) && !err)
2117 err = errno;
2118 if (err) {
2119 errno = err;
2120 ntfs_log_debug("Could not delete file: %s\n", strerror(errno));
2121 return -1;
2123 ntfs_log_trace("Done.\n");
2124 return 0;
2125 err_out:
2126 err = errno;
2127 goto out;
2131 * ntfs_link - create hard link for file or directory
2132 * @ni: ntfs inode for object to create hard link
2133 * @dir_ni: ntfs inode for directory in which new link should be placed
2134 * @name: unicode name of the new link
2135 * @name_len: length of the name in unicode characters
2137 * NOTE: At present we allow creating hardlinks to directories, we use them
2138 * in a temporary state during rename. But it's defenitely bad idea to have
2139 * hard links to directories as a result of operation.
2140 * FIXME: Create internal __ntfs_link that allows hard links to a directories
2141 * and external ntfs_link that do not. Write ntfs_rename that uses __ntfs_link.
2143 * Return 0 on success or -1 on error with errno set to the error code.
2145 static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
2146 u8 name_len, FILE_NAME_TYPE_FLAGS nametype)
2148 FILE_NAME_ATTR *fn = NULL;
2149 int fn_len, err;
2151 ntfs_log_trace("Entering.\n");
2153 if (!ni || !dir_ni || !name || !name_len ||
2154 ni->mft_no == dir_ni->mft_no) {
2155 err = EINVAL;
2156 ntfs_log_perror("ntfs_link wrong arguments");
2157 goto err_out;
2160 if ((ni->flags & FILE_ATTR_REPARSE_POINT)
2161 && !ntfs_possible_symlink(ni)) {
2162 err = EOPNOTSUPP;
2163 goto err_out;
2165 if (NVolHideDotFiles(dir_ni->vol)) {
2166 /* Set hidden flag according to the latest name */
2167 if ((name_len > 1)
2168 && (name[0] == const_cpu_to_le16('.'))
2169 && (name[1] != const_cpu_to_le16('.')))
2170 ni->flags |= FILE_ATTR_HIDDEN;
2171 else
2172 ni->flags &= ~FILE_ATTR_HIDDEN;
2175 /* Create FILE_NAME attribute. */
2176 fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
2177 fn = ntfs_calloc(fn_len);
2178 if (!fn) {
2179 err = errno;
2180 goto err_out;
2182 fn->parent_directory = MK_LE_MREF(dir_ni->mft_no,
2183 le16_to_cpu(dir_ni->mrec->sequence_number));
2184 fn->file_name_length = name_len;
2185 fn->file_name_type = nametype;
2186 fn->file_attributes = ni->flags;
2187 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
2188 fn->file_attributes |= FILE_ATTR_I30_INDEX_PRESENT;
2189 fn->data_size = fn->allocated_size = const_cpu_to_le64(0);
2190 } else {
2191 fn->allocated_size = cpu_to_sle64(ni->allocated_size);
2192 fn->data_size = cpu_to_sle64(ni->data_size);
2194 fn->creation_time = ni->creation_time;
2195 fn->last_data_change_time = ni->last_data_change_time;
2196 fn->last_mft_change_time = ni->last_mft_change_time;
2197 fn->last_access_time = ni->last_access_time;
2198 memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
2199 /* Add FILE_NAME attribute to index. */
2200 if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no,
2201 le16_to_cpu(ni->mrec->sequence_number)))) {
2202 err = errno;
2203 ntfs_log_perror("Failed to add filename to the index");
2204 goto err_out;
2206 /* Add FILE_NAME attribute to inode. */
2207 if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
2208 ntfs_log_error("Failed to add FILE_NAME attribute.\n");
2209 err = errno;
2210 /* Try to remove just added attribute from index. */
2211 if (ntfs_index_remove(dir_ni, ni, fn, fn_len))
2212 goto rollback_failed;
2213 goto err_out;
2215 /* Increment hard links count. */
2216 ni->mrec->link_count = cpu_to_le16(le16_to_cpu(
2217 ni->mrec->link_count) + 1);
2218 /* Done! */
2219 ntfs_inode_mark_dirty(ni);
2220 free(fn);
2221 ntfs_log_trace("Done.\n");
2222 return 0;
2223 rollback_failed:
2224 ntfs_log_error("Rollback failed. Leaving inconsistent metadata.\n");
2225 err_out:
2226 free(fn);
2227 errno = err;
2228 return -1;
2231 int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
2232 u8 name_len)
2234 return (ntfs_link_i(ni, dir_ni, name, name_len, FILE_NAME_POSIX));
2238 * Get a parent directory from an inode entry
2240 * This is only used in situations where the path used to access
2241 * the current file is not known for sure. The result may be different
2242 * from the path when the file is linked in several parent directories.
2244 * Currently this is only used for translating ".." in the target
2245 * of a Vista relative symbolic link
2248 ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni)
2250 ntfs_inode *dir_ni = (ntfs_inode*)NULL;
2251 u64 inum;
2252 FILE_NAME_ATTR *fn;
2253 ntfs_attr_search_ctx *ctx;
2255 if (ni->mft_no != FILE_root) {
2256 /* find the name in the attributes */
2257 ctx = ntfs_attr_get_search_ctx(ni, NULL);
2258 if (!ctx)
2259 return ((ntfs_inode*)NULL);
2261 if (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0,
2262 CASE_SENSITIVE, 0, NULL, 0, ctx)) {
2263 /* We know this will always be resident. */
2264 fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
2265 le16_to_cpu(ctx->attr->value_offset));
2266 inum = le64_to_cpu(fn->parent_directory);
2267 if (inum != (u64)-1) {
2268 dir_ni = ntfs_inode_open(ni->vol, MREF(inum));
2271 ntfs_attr_put_search_ctx(ctx);
2273 return (dir_ni);
2276 #ifdef HAVE_SETXATTR
2278 #define MAX_DOS_NAME_LENGTH 12
2281 * Get a DOS name for a file in designated directory
2283 * Not allowed if there are several non-dos names (EMLINK)
2285 * Returns size if found
2286 * 0 if not found
2287 * -1 if there was an error (described by errno)
2290 static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname)
2292 size_t outsize = 0;
2293 int namecount = 0;
2294 FILE_NAME_ATTR *fn;
2295 ntfs_attr_search_ctx *ctx;
2297 /* find the name in the attributes */
2298 ctx = ntfs_attr_get_search_ctx(ni, NULL);
2299 if (!ctx)
2300 return -1;
2302 while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
2303 0, NULL, 0, ctx)) {
2304 /* We know this will always be resident. */
2305 fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
2306 le16_to_cpu(ctx->attr->value_offset));
2308 if (fn->file_name_type != FILE_NAME_DOS)
2309 namecount++;
2310 if ((fn->file_name_type & FILE_NAME_DOS)
2311 && (MREF_LE(fn->parent_directory) == dnum)) {
2313 * Found a DOS or WIN32+DOS name for the entry
2314 * copy name, after truncation for safety
2316 outsize = fn->file_name_length;
2317 /* TODO : reject if name is too long ? */
2318 if (outsize > MAX_DOS_NAME_LENGTH)
2319 outsize = MAX_DOS_NAME_LENGTH;
2320 memcpy(dosname,fn->file_name,outsize*sizeof(ntfschar));
2323 ntfs_attr_put_search_ctx(ctx);
2324 if ((outsize > 0) && (namecount > 1)) {
2325 outsize = -1;
2326 errno = EMLINK; /* this error implies there is a dos name */
2328 return (outsize);
2333 * Get a long name for a file in designated directory
2335 * Not allowed if there are several non-dos names (EMLINK)
2337 * Returns size if found
2338 * 0 if not found
2339 * -1 if there was an error (described by errno)
2342 static int get_long_name(ntfs_inode *ni, u64 dnum, ntfschar *longname)
2344 size_t outsize = 0;
2345 int namecount = 0;
2346 FILE_NAME_ATTR *fn;
2347 ntfs_attr_search_ctx *ctx;
2349 /* find the name in the attributes */
2350 ctx = ntfs_attr_get_search_ctx(ni, NULL);
2351 if (!ctx)
2352 return -1;
2354 /* first search for WIN32 or DOS+WIN32 names */
2355 while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
2356 0, NULL, 0, ctx)) {
2357 /* We know this will always be resident. */
2358 fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
2359 le16_to_cpu(ctx->attr->value_offset));
2361 if (fn->file_name_type != FILE_NAME_DOS)
2362 namecount++;
2363 if ((fn->file_name_type & FILE_NAME_WIN32)
2364 && (MREF_LE(fn->parent_directory) == dnum)) {
2366 * Found a WIN32 or WIN32+DOS name for the entry
2367 * copy name
2369 outsize = fn->file_name_length;
2370 memcpy(longname,fn->file_name,outsize*sizeof(ntfschar));
2373 if (namecount > 1) {
2374 ntfs_attr_put_search_ctx(ctx);
2375 errno = EMLINK;
2376 return -1;
2378 /* if not found search for POSIX names */
2379 if (!outsize) {
2380 ntfs_attr_reinit_search_ctx(ctx);
2381 while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
2382 0, NULL, 0, ctx)) {
2383 /* We know this will always be resident. */
2384 fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
2385 le16_to_cpu(ctx->attr->value_offset));
2387 if ((fn->file_name_type == FILE_NAME_POSIX)
2388 && (MREF_LE(fn->parent_directory) == dnum)) {
2390 * Found a POSIX name for the entry
2391 * copy name
2393 outsize = fn->file_name_length;
2394 memcpy(longname,fn->file_name,outsize*sizeof(ntfschar));
2398 ntfs_attr_put_search_ctx(ctx);
2399 return (outsize);
2404 * Get the ntfs DOS name into an extended attribute
2407 int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
2408 char *value, size_t size)
2410 int outsize = 0;
2411 char *outname = (char*)NULL;
2412 u64 dnum;
2413 int doslen;
2414 ntfschar dosname[MAX_DOS_NAME_LENGTH];
2416 dnum = dir_ni->mft_no;
2417 doslen = get_dos_name(ni, dnum, dosname);
2418 if (doslen > 0) {
2420 * Found a DOS name for the entry, make
2421 * uppercase and encode into the buffer
2422 * if there is enough space
2424 ntfs_name_upcase(dosname, doslen,
2425 ni->vol->upcase, ni->vol->upcase_len);
2426 if (ntfs_ucstombs(dosname, doslen, &outname, size) < 0) {
2427 ntfs_log_error("Cannot represent dosname in current locale.\n");
2428 outsize = -errno;
2429 } else {
2430 outsize = strlen(outname);
2431 if (value && (outsize <= (int)size))
2432 memcpy(value, outname, outsize);
2433 else
2434 if (size && (outsize > (int)size))
2435 outsize = -ERANGE;
2436 free(outname);
2438 } else {
2439 if (doslen == 0)
2440 errno = ENODATA;
2441 outsize = -errno;
2443 return (outsize);
2447 * Change the name space of an existing file or directory
2449 * Returns the old namespace if successful
2450 * -1 if an error occurred (described by errno)
2453 static int set_namespace(ntfs_inode *ni, ntfs_inode *dir_ni,
2454 const ntfschar *name, int len,
2455 FILE_NAME_TYPE_FLAGS nametype)
2457 ntfs_attr_search_ctx *actx;
2458 ntfs_index_context *icx;
2459 FILE_NAME_ATTR *fnx;
2460 FILE_NAME_ATTR *fn = NULL;
2461 BOOL found;
2462 int lkup;
2463 int ret;
2465 ret = -1;
2466 actx = ntfs_attr_get_search_ctx(ni, NULL);
2467 if (actx) {
2468 found = FALSE;
2469 do {
2470 lkup = ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0,
2471 CASE_SENSITIVE, 0, NULL, 0, actx);
2472 if (!lkup) {
2473 fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
2474 le16_to_cpu(actx->attr->value_offset));
2475 found = (MREF_LE(fn->parent_directory)
2476 == dir_ni->mft_no)
2477 && !memcmp(fn->file_name, name,
2478 len*sizeof(ntfschar));
2480 } while (!lkup && !found);
2481 if (found) {
2482 icx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4);
2483 if (icx) {
2484 lkup = ntfs_index_lookup((char*)fn, len, icx);
2485 if (!lkup && icx->data && icx->data_len) {
2486 fnx = (FILE_NAME_ATTR*)icx->data;
2487 ret = fn->file_name_type;
2488 fn->file_name_type = nametype;
2489 fnx->file_name_type = nametype;
2490 ntfs_inode_mark_dirty(ni);
2491 ntfs_index_entry_mark_dirty(icx);
2493 ntfs_index_ctx_put(icx);
2496 ntfs_attr_put_search_ctx(actx);
2498 return (ret);
2502 * Set a DOS name to a file and adjust name spaces
2504 * If the new names are collapsible (same uppercased chars) :
2506 * - the existing DOS name or DOS+Win32 name is made Posix
2507 * - if it was a real DOS name, the existing long name is made DOS+Win32
2508 * and the existing DOS name is deleted
2509 * - finally the existing long name is made DOS+Win32 unless already done
2511 * If the new names are not collapsible :
2513 * - insert the short name as a DOS name
2514 * - delete the old long name or existing short name
2515 * - insert the new long name (as a Win32 or DOS+Win32 name)
2517 * Deleting the old long name will not delete the file
2518 * provided the old name was in the Posix name space,
2519 * because the alternate name has been set before.
2521 * The inodes of file and parent directory are always closed
2523 * Returns 0 if successful
2524 * -1 if failed
2527 static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
2528 const ntfschar *shortname, int shortlen,
2529 const ntfschar *longname, int longlen,
2530 const ntfschar *deletename, int deletelen, BOOL existed)
2532 unsigned int linkcount;
2533 ntfs_volume *vol;
2534 BOOL collapsible;
2535 BOOL deleted;
2536 BOOL done;
2537 FILE_NAME_TYPE_FLAGS oldnametype;
2538 u64 dnum;
2539 u64 fnum;
2540 int res;
2542 res = -1;
2543 vol = ni->vol;
2544 dnum = dir_ni->mft_no;
2545 fnum = ni->mft_no;
2546 /* save initial link count */
2547 linkcount = le16_to_cpu(ni->mrec->link_count);
2549 /* check whether the same name may be used as DOS and WIN32 */
2550 collapsible = ntfs_collapsible_chars(ni->vol, shortname, shortlen,
2551 longname, longlen);
2552 if (collapsible) {
2553 deleted = FALSE;
2554 done = FALSE;
2555 if (existed) {
2556 oldnametype = set_namespace(ni, dir_ni, deletename,
2557 deletelen, FILE_NAME_POSIX);
2558 if (oldnametype == FILE_NAME_DOS) {
2559 if (set_namespace(ni, dir_ni, longname, longlen,
2560 FILE_NAME_WIN32_AND_DOS) >= 0) {
2561 if (!ntfs_delete(vol,
2562 (const char*)NULL, ni, dir_ni,
2563 deletename, deletelen))
2564 res = 0;
2565 deleted = TRUE;
2566 } else
2567 done = TRUE;
2570 if (!deleted) {
2571 if (!done && (set_namespace(ni, dir_ni,
2572 longname, longlen,
2573 FILE_NAME_WIN32_AND_DOS) >= 0))
2574 res = 0;
2575 ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME);
2576 ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME);
2577 if (ntfs_inode_close_in_dir(ni,dir_ni) && !res)
2578 res = -1;
2579 if (ntfs_inode_close(dir_ni) && !res)
2580 res = -1;
2582 } else {
2583 if (!ntfs_link_i(ni, dir_ni, shortname, shortlen,
2584 FILE_NAME_DOS)
2585 /* make sure a new link was recorded */
2586 && (le16_to_cpu(ni->mrec->link_count) > linkcount)) {
2587 /* delete the existing long name or short name */
2588 // is it ok to not provide the path ?
2589 if (!ntfs_delete(vol, (char*)NULL, ni, dir_ni,
2590 deletename, deletelen)) {
2591 /* delete closes the inodes, so have to open again */
2592 dir_ni = ntfs_inode_open(vol, dnum);
2593 if (dir_ni) {
2594 ni = ntfs_inode_open(vol, fnum);
2595 if (ni) {
2596 if (!ntfs_link_i(ni, dir_ni,
2597 longname, longlen,
2598 FILE_NAME_WIN32))
2599 res = 0;
2600 if (ntfs_inode_close_in_dir(ni,
2601 dir_ni)
2602 && !res)
2603 res = -1;
2605 if (ntfs_inode_close(dir_ni) && !res)
2606 res = -1;
2609 } else {
2610 ntfs_inode_close_in_dir(ni,dir_ni);
2611 ntfs_inode_close(dir_ni);
2614 return (res);
2619 * Set the ntfs DOS name into an extended attribute
2621 * The DOS name will be added as another file name attribute
2622 * using the existing file name information from the original
2623 * name or overwriting the DOS Name if one exists.
2625 * The inode of the file is always closed
2628 int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
2629 const char *value, size_t size, int flags)
2631 int res = 0;
2632 int longlen = 0;
2633 int shortlen = 0;
2634 char newname[3*MAX_DOS_NAME_LENGTH + 1];
2635 ntfschar oldname[MAX_DOS_NAME_LENGTH];
2636 int oldlen;
2637 u64 dnum;
2638 BOOL closed = FALSE;
2639 ntfschar *shortname = NULL;
2640 ntfschar longname[NTFS_MAX_NAME_LEN];
2642 /* copy the string to insert a null char, and truncate */
2643 if (size > 3*MAX_DOS_NAME_LENGTH)
2644 size = 3*MAX_DOS_NAME_LENGTH;
2645 strncpy(newname, value, size);
2646 /* a long name may be truncated badly and be untranslatable */
2647 newname[size] = 0;
2648 /* convert the string to the NTFS wide chars, and truncate */
2649 shortlen = ntfs_mbstoucs(newname, &shortname);
2650 if (shortlen > MAX_DOS_NAME_LENGTH)
2651 shortlen = MAX_DOS_NAME_LENGTH;
2652 /* make sure the short name has valid chars */
2653 if ((shortlen < 0) || ntfs_forbidden_chars(shortname,shortlen)) {
2654 ntfs_inode_close_in_dir(ni,dir_ni);
2655 ntfs_inode_close(dir_ni);
2656 res = -errno;
2657 return res;
2659 dnum = dir_ni->mft_no;
2660 longlen = get_long_name(ni, dnum, longname);
2661 if (longlen > 0) {
2662 oldlen = get_dos_name(ni, dnum, oldname);
2663 if ((oldlen >= 0)
2664 && !ntfs_forbidden_chars(longname, longlen)) {
2665 if (oldlen > 0) {
2666 if (flags & XATTR_CREATE) {
2667 res = -1;
2668 errno = EEXIST;
2669 } else
2670 if ((shortlen == oldlen)
2671 && !memcmp(shortname,oldname,
2672 oldlen*sizeof(ntfschar)))
2673 /* already set, done */
2674 res = 0;
2675 else {
2676 res = set_dos_name(ni, dir_ni,
2677 shortname, shortlen,
2678 longname, longlen,
2679 oldname, oldlen, TRUE);
2680 closed = TRUE;
2682 } else {
2683 if (flags & XATTR_REPLACE) {
2684 res = -1;
2685 errno = ENODATA;
2686 } else {
2687 res = set_dos_name(ni, dir_ni,
2688 shortname, shortlen,
2689 longname, longlen,
2690 longname, longlen, FALSE);
2691 closed = TRUE;
2694 } else
2695 res = -1;
2696 } else {
2697 res = -1;
2698 if (!longlen)
2699 errno = ENOENT;
2701 free(shortname);
2702 if (!closed) {
2703 ntfs_inode_close_in_dir(ni,dir_ni);
2704 ntfs_inode_close(dir_ni);
2706 return (res ? -1 : 0);
2710 * Delete the ntfs DOS name
2713 int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni)
2715 int res;
2716 int oldnametype;
2717 int longlen = 0;
2718 int shortlen;
2719 u64 dnum;
2720 ntfs_volume *vol;
2721 BOOL deleted = FALSE;
2722 ntfschar shortname[MAX_DOS_NAME_LENGTH];
2723 ntfschar longname[NTFS_MAX_NAME_LEN];
2725 res = -1;
2726 vol = ni->vol;
2727 dnum = dir_ni->mft_no;
2728 longlen = get_long_name(ni, dnum, longname);
2729 if (longlen > 0) {
2730 shortlen = get_dos_name(ni, dnum, shortname);
2731 if (shortlen >= 0) {
2732 /* migrate the long name as Posix */
2733 oldnametype = set_namespace(ni,dir_ni,longname,longlen,
2734 FILE_NAME_POSIX);
2735 switch (oldnametype) {
2736 case FILE_NAME_WIN32_AND_DOS :
2737 /* name was Win32+DOS : done */
2738 res = 0;
2739 break;
2740 case FILE_NAME_DOS :
2741 /* name was DOS, make it back to DOS */
2742 set_namespace(ni,dir_ni,longname,longlen,
2743 FILE_NAME_DOS);
2744 errno = ENOENT;
2745 break;
2746 case FILE_NAME_WIN32 :
2747 /* name was Win32, make it Posix and delete */
2748 if (set_namespace(ni,dir_ni,shortname,shortlen,
2749 FILE_NAME_POSIX) >= 0) {
2750 if (!ntfs_delete(vol,
2751 (const char*)NULL, ni,
2752 dir_ni, shortname,
2753 shortlen))
2754 res = 0;
2755 deleted = TRUE;
2756 } else {
2758 * DOS name has been found, but cannot
2759 * migrate to Posix : something bad
2760 * has happened
2762 errno = EIO;
2763 ntfs_log_error("Could not change"
2764 " DOS name of inode %lld to Posix\n",
2765 (long long)ni->mft_no);
2767 break;
2768 default :
2769 /* name was Posix or not found : error */
2770 errno = ENOENT;
2771 break;
2774 } else {
2775 if (!longlen)
2776 errno = ENOENT;
2777 res = -1;
2779 if (!deleted) {
2780 ntfs_inode_close_in_dir(ni,dir_ni);
2781 ntfs_inode_close(dir_ni);
2783 return (res);
2786 #endif