diff --git a/include/ntfs-3g/index.h b/include/ntfs-3g/index.h index aab16506..4c8ff51a 100644 --- a/include/ntfs-3g/index.h +++ b/include/ntfs-3g/index.h @@ -143,7 +143,8 @@ extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref); -extern int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen); +extern int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni, + const void *key, const int keylen); extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr); diff --git a/include/ntfs-3g/reparse.h b/include/ntfs-3g/reparse.h index 3c7a5c90..21de4077 100644 --- a/include/ntfs-3g/reparse.h +++ b/include/ntfs-3g/reparse.h @@ -24,7 +24,8 @@ #ifndef REPARSE_H #define REPARSE_H -char *ntfs_junction_point(ntfs_volume *vol, const char *org_path, - ntfs_inode *ni, int *pattr_size); +char *ntfs_make_symlink(const char *org_path, + ntfs_inode *ni, int *pattr_size); +BOOL ntfs_possible_symlink(ntfs_inode *ni); #endif /* REPARSE_H */ diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index e2ed1a43..e5fbb85f 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -57,6 +57,7 @@ #include "logging.h" #include "misc.h" #include "security.h" +#include "reparse.h" /* * The little endian Unicode strings "$I30", "$SII", "$SDH", "$O" @@ -1594,7 +1595,7 @@ search: if (ntfs_check_unlinkable_dir(ni, fn) < 0) goto err_out; - if (ntfs_index_remove(dir_ni, fn, le32_to_cpu(actx->attr->value_length))) + if (ntfs_index_remove(dir_ni, ni, fn, le32_to_cpu(actx->attr->value_length))) goto err_out; if (ntfs_attr_record_rm(actx)) @@ -1725,7 +1726,8 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) goto err_out; } - if (ni->flags & FILE_ATTR_REPARSE_POINT) { + if ((ni->flags & FILE_ATTR_REPARSE_POINT) + && !ntfs_possible_symlink(ni)) { err = EOPNOTSUPP; goto err_out; } @@ -1763,7 +1765,7 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) ntfs_log_error("Failed to add FILE_NAME attribute.\n"); err = errno; /* Try to remove just added attribute from index. */ - if (ntfs_index_remove(dir_ni, fn, fn_len)) + if (ntfs_index_remove(dir_ni, ni, fn, fn_len)) goto rollback_failed; goto err_out; } diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c index 209a39cb..3ffc17c1 100644 --- a/libntfs-3g/index.c +++ b/libntfs-3g/index.c @@ -45,6 +45,7 @@ #include "dir.h" #include "logging.h" #include "bitmap.h" +#include "reparse.h" #include "misc.h" /** @@ -1813,12 +1814,13 @@ err_out: goto out; } -int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen) +int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni, + const void *key, const int keylen) { int ret = STATUS_ERROR; ntfs_index_context *icx; - icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); + icx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); if (!icx) return -1; @@ -1827,8 +1829,9 @@ int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen) if (ntfs_index_lookup(key, keylen, icx)) goto err_out; - if (((FILE_NAME_ATTR *)icx->data)->file_attributes & - FILE_ATTR_REPARSE_POINT) { + if ((((FILE_NAME_ATTR *)icx->data)->file_attributes & + FILE_ATTR_REPARSE_POINT) + && !ntfs_possible_symlink(ni)) { errno = EOPNOTSUPP; goto err_out; } diff --git a/libntfs-3g/reparse.c b/libntfs-3g/reparse.c index 5751d4e5..e56047e1 100644 --- a/libntfs-3g/reparse.c +++ b/libntfs-3g/reparse.c @@ -59,27 +59,38 @@ /* the definitions in layout.h are wrong, we use names defined in http://msdn.microsoft.com/en-us/library/aa365740(VS.85).aspx */ -#undef IO_REPARSE_TAG_MOUNT_POINT -#define IO_REPARSE_TAG_MOUNT_POINT const_cpu_to_le32(0xA0000003) -#define IO_REPARSE_TAG_SYMLINK const_cpu_to_le32(0xA000000C) -struct MOUNT_POINT_REPARSE_DATA { - u16 subst_name_offset; - u16 subst_name_length; - u16 print_name_offset; - u16 print_name_length; +#define IO_REPARSE_TAG_DFS const_cpu_to_le32(0x8000000A) +#define IO_REPARSE_TAG_DFSR const_cpu_to_le32(0x80000012) +#define IO_REPARSE_TAG_HSM const_cpu_to_le32(0xC0000004) +#define IO_REPARSE_TAG_HSM2 const_cpu_to_le32(0x80000006) +#define IO_REPARSE_TAG_MOUNT_POINT const_cpu_to_le32(0xA0000003) +#define IO_REPARSE_TAG_SIS const_cpu_to_le32(0x80000007) +#define IO_REPARSE_TAG_SYMLINK const_cpu_to_le32(0xA000000C) + +struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */ + le16 subst_name_offset; + le16 subst_name_length; + le16 print_name_offset; + le16 print_name_length; char path_buffer[0]; /* above data assume this is char array */ } ; -struct SYMLINK_REPARSE_DATA { /* another format */ - u16 subst_name_offset; - u16 subst_name_length; - u16 print_name_offset; - u16 print_name_length; - u32 unknown; +struct SYMLINK_REPARSE_DATA { /* reparse data for symlinks */ + le16 subst_name_offset; + le16 subst_name_length; + le16 print_name_offset; + le16 print_name_length; + le32 flags; /* 1 for full target, otherwise 0 */ char path_buffer[0]; /* above data assume this is char array */ } ; +struct INODE_STACK { + struct INODE_STACK *previous; + struct INODE_STACK *next; + ntfs_inode *ni; +} ; + static const ntfschar dir_junction_head[] = { const_cpu_to_le16('\\'), const_cpu_to_le16('?'), @@ -112,7 +123,7 @@ static const char mappingdir[] = ".NTFS-3G/"; * If there some ambiguity, the name which collates first is returned. * * The name is converted to upper case and searched the usual way. - * The collation rules for file names are such as we should get the + * The collation rules for file names are such that we should get the * first candidate if any. */ @@ -126,62 +137,74 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname, int lkup; int olderrno; int i; + u32 cpuchar; FILE_NAME_ATTR *found; struct { FILE_NAME_ATTR attr; ntfschar file_name[NTFS_MAX_NAME_LEN + 1]; } find; - mref = (u64)-1; /* default return */ + mref = (u64)-1; /* default return (not found) */ icx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); - if (uname_len > NTFS_MAX_NAME_LEN) - uname_len = NTFS_MAX_NAME_LEN; - find.attr.file_name_length = uname_len; - for (i=0; iupcase_len) - find.attr.file_name[i] = vol->upcase[uname[i]]; - else - find.attr.file_name[i] = uname[i]; - olderrno = errno; - lkup = ntfs_index_lookup(&find, uname_len, icx); - if (errno == ENOENT) - errno = olderrno; - found = (FILE_NAME_ATTR*)icx->data; + if (icx) { + if (uname_len > NTFS_MAX_NAME_LEN) + uname_len = NTFS_MAX_NAME_LEN; + find.attr.file_name_length = uname_len; + for (i=0; iupcase_len) + find.attr.file_name[i] = vol->upcase[cpuchar]; + else + find.attr.file_name[i] = uname[i]; + } + olderrno = errno; + lkup = ntfs_index_lookup((char*)&find, uname_len, icx); + if (errno == ENOENT) + errno = olderrno; /* * We generally only get the first matching candidate, * so we still have to check whether this is a real match */ - if (icx && icx->data && icx->data_len) { - if (lkup - && !ntfs_names_collate(find.attr.file_name, find.attr.file_name_length, - found->file_name, found->file_name_length, - 1, TRUE /* IGNORE_CASE_BOOL */, - vol->upcase, vol->upcase_len)) - lkup = 0; - if (!lkup) { + if (icx->data && icx->data_len) { + found = (FILE_NAME_ATTR*)icx->data; + if (lkup + && !ntfs_names_collate(find.attr.file_name, find.attr.file_name_length, + found->file_name, found->file_name_length, + 1, IGNORE_CASE, + vol->upcase, vol->upcase_len)) + lkup = 0; + if (!lkup) { /* * name found : * fix original name and return inode */ - lemref = *(le64*)((char*)found->file_name - sizeof(INDEX_ENTRY_HEADER) - sizeof(FILE_NAME_ATTR)); - mref = le64_to_cpu(lemref); - for (i=0; ifile_name_length; i++) - uname[i] = found->file_name[i]; + lemref = *(le64*)((char*)found->file_name + - sizeof(INDEX_ENTRY_HEADER) + - sizeof(FILE_NAME_ATTR)); + mref = le64_to_cpu(lemref); + for (i=0; ifile_name_length; i++) + uname[i] = found->file_name[i]; + } } + ntfs_index_ctx_put(icx); } - ntfs_index_ctx_put(icx); - return (mref); } /* - * Search a directory junction along the target path + * Search for a directory junction or a symbolic link + * along the target path, with target defined as a full absolute path * * Returns the path translated to a Linux path - * or NULL if the path does not designate a valid directory + * or NULL if the path is not valid */ -static char *search_junction(ntfs_volume *vol, ntfschar *path, int count) +static char *search_absolute(ntfs_volume *vol, ntfschar *path, + int count, BOOL isdir) { ntfs_inode *ni; u64 inum; @@ -190,13 +213,13 @@ static char *search_junction(ntfs_volume *vol, ntfschar *path, int count) int len; target = (char*)NULL; /* default return */ - ni = ntfs_inode_open(vol, FILE_root); + ni = ntfs_inode_open(vol, (MFT_REF)FILE_root); if (ni) { start = 0; do { len = 0; while (((start + len) < count) - && path[len + start] != const_cpu_to_le16('\\')) + && (path[start + len] != const_cpu_to_le16('\\'))) len++; inum = ntfs_fix_file_name(ni, &path[start], len); ntfs_inode_close(ni); @@ -211,7 +234,8 @@ static char *search_junction(ntfs_volume *vol, ntfschar *path, int count) } while (ni && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) && (start < count)); - if (ni && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) + if (ni + && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir)) if (ntfs_ucstombs(path, count, &target, 0) < 0) { if (target) { free(target); @@ -224,6 +248,171 @@ static char *search_junction(ntfs_volume *vol, ntfschar *path, int count) return (target); } +/* + * Stack the next inode in the path + * + * Returns the new top of stack + * or NULL (with stack unchanged) if there is a problem + */ + +static struct INODE_STACK *stack_inode(struct INODE_STACK *topni, + ntfschar *name, int len, BOOL fix) +{ + struct INODE_STACK *curni; + u64 inum; + + if (fix) + inum = ntfs_fix_file_name(topni->ni, name, len); + else + inum = ntfs_inode_lookup_by_name(topni->ni, name, len); + if (inum != (u64)-1) { + inum = MREF(inum); + curni = (struct INODE_STACK*)malloc(sizeof(struct INODE_STACK)); + if (curni) { + curni->ni = ntfs_inode_open(topni->ni->vol, inum); + topni->next = curni; + curni->previous = topni; + curni->next = (struct INODE_STACK*)NULL; + } + } else + curni = (struct INODE_STACK*)NULL; + return (curni); +} + +/* + * Destack and close the current inode in the path + * + * Returns the new top of stack + * or NULL (with stack unchanged) if there is a problem + */ + +static struct INODE_STACK *pop_inode(struct INODE_STACK *topni) +{ + struct INODE_STACK *curni; + + curni = (struct INODE_STACK*)NULL; + if (topni->previous) { + if (!ntfs_inode_close(topni->ni)) { + curni = topni->previous; + free(topni); + curni->next = (struct INODE_STACK*)NULL; + } + } else { + /* ".." reached the root of fs */ + errno = ENOENT; + } + return (curni); +} + +/* + * Search for a symbolic link along the target path, + * with the target defined as a relative path + * + * Returns the path translated to a Linux path + * or NULL if the path is not valid + */ + +static char *search_relative(ntfs_volume *vol, ntfschar *path, int count, + const char *base, BOOL isdir) +{ + struct INODE_STACK *topni; + struct INODE_STACK *curni; + char *target; + ntfschar *unicode; + int unisz; + int start; + int len; + + target = (char*)NULL; /* default return */ + topni = (struct INODE_STACK*)malloc(sizeof(struct INODE_STACK)); + if (topni) { + topni->ni = ntfs_inode_open(vol, FILE_root); + topni->previous = (struct INODE_STACK*)NULL; + topni->next = (struct INODE_STACK*)NULL; + } + if (topni && topni->ni) { + /* + * Process the base path + */ + unicode = (ntfschar*)NULL; + unisz = ntfs_mbstoucs(base, &unicode); + if ((unisz > 0) && unicode) { + start = 1; + do { + len = 0; + while (((start + len) < unisz) + && (unicode[start + len] != const_cpu_to_le16('/'))) + len++; + curni = (struct INODE_STACK*)NULL; + if ((start + len) < unisz) { + curni = stack_inode(topni, &unicode[start], len, FALSE); + if (curni) + topni = curni; + } else + curni = topni; + start += len + 1; + } while (curni + && topni->ni + && (topni->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + && (start < unisz)); + free(unicode); + if (curni && topni->ni && (topni->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { + start = 0; + do { + len = 0; + while (((start + len) < count) + && (path[start + len] != const_cpu_to_le16('\\'))) + len++; + curni = (struct INODE_STACK*)NULL; + if ((path[start] == const_cpu_to_le16('.')) + && ((len == 1) + || ((len == 2) + && (path[start+1] + == const_cpu_to_le16('.'))))) { + /* leave the .. or . in the path */ + curni = topni; + if (len == 2) { + curni = pop_inode(topni); + if (curni) + topni = curni; + } + } else { + curni = stack_inode(topni, &path[start], len, TRUE); + if (curni) + topni = curni; + } + if (topni->ni) { + start += len; + if (start < count) + path[start++] = const_cpu_to_le16('/'); + } + } while (curni + && topni->ni + && (topni->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + && (start < count)); + if (curni + && topni->ni + && (topni->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir)) { + if (ntfs_ucstombs(path, count, &target, 0) < 0) { + if (target) { + free(target); + target = (char*)NULL; + } + } + } + } + } + do { + if (topni->ni) + ntfs_inode_close(topni->ni); + curni = topni; + topni = topni->previous; + free(curni); + } while (topni); + } + return (target); +} + /* * Check whether a drive letter has been defined in .NTFS-3G * @@ -267,19 +456,23 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter) } /* - * Check and translate the target of a junction point - * If the target is a directory junction or a volume junction, it - * redefined as a relative link, + * Check and translate the target of a junction point or + * a full absolute symbolic link. + * + * A full target definition begins with "\??\" or "\\?\" + * + * The fully defined target is redefined as a relative link, * - either to the target if found on the same device. * - or into the /.NTFS-3G directory for the user to define + * In the first situation, the target is translated to case-sensitive path. * * returns the target converted to a relative symlink - * or NULL if there were some problem described by errno + * or NULL if there were some problem, as described by errno */ -static char *ntfs_get_junction(ntfs_volume *vol, ntfschar *junction, - int count, const char *path) +static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction, + int count, const char *path, BOOL isdir) { char *target; char *fulltarget; @@ -322,13 +515,13 @@ static char *ntfs_get_junction(ntfs_volume *vol, ntfschar *junction, && (count >= 7) && junction[7] && !ntfs_drive_letter(vol, junction[4])) { - target = search_junction(vol,&junction[7],count - 7); + target = search_absolute(vol,&junction[7],count - 7, isdir); if (target) { level = 0; for (p=path; *p; p++) if (*p == '/') level++; - fulltarget = ntfs_malloc(3*level + strlen(target) + 1); + fulltarget = (char*)ntfs_malloc(3*level + strlen(target) + 1); if (fulltarget) { fulltarget[0] = 0; if (level > 1) { @@ -366,7 +559,7 @@ static char *ntfs_get_junction(ntfs_volume *vol, ntfschar *junction, for (p=path; *p; p++) if (*p == '/') level++; - fulltarget = ntfs_malloc(3*level + sizeof(mappingdir) + count - 4); + fulltarget = (char*)ntfs_malloc(3*level + sizeof(mappingdir) + count - 4); if (fulltarget) { fulltarget[0] = 0; if (level > 1) { @@ -385,29 +578,175 @@ static char *ntfs_get_junction(ntfs_volume *vol, ntfschar *junction, } /* - * Get the target for a directory or volume junction - * Should only be called for directories with reparse data + * Check and translate the target of an absolute symbolic link. * - * returns the target directory converted to a relative path - * or NULL if some error occurred, as described by errno - * errno is EOPNOTSUPP if the reparse point is not a valid - * directory junction + * An absolute target definition begins with "\" or "x:\" + * + * The absolute target is redefined as a relative link, + * - either to the target if found on the same device. + * - or into the /.NTFS-3G directory for the user to define + * In the first situation, the target is translated to case-sensitive path. + * + * returns the target converted to a relative symlink + * or NULL if there were some problem, as described by errno */ -char *ntfs_junction_point(ntfs_volume *vol, const char *org_path, +static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction, + int count, const char *path, BOOL isdir) +{ + char *target; + char *fulltarget; + int i; + int sz; + int level; + const char *p; + char *q; + enum { FULL_PATH, ABS_PATH, REJECTED_PATH } kind; + + target = (char*)NULL; + fulltarget = (char*)NULL; + /* + * For a full valid path we want x:\ + * where \ is an individual char and x a non-null char + */ + if ((count >= 3) + && junction[0] + && (junction[1] == const_cpu_to_le16(':')) + && (junction[2] == const_cpu_to_le16('\\'))) + kind = FULL_PATH; + else + /* + * For an absolute path we want an initial \ + */ + if ((count >= 0) + && (junction[0] == const_cpu_to_le16('\\'))) + kind = ABS_PATH; + else + kind = REJECTED_PATH; + /* + * Full path, with a drive letter and + * no specific definition for the drive letter : + * try to interpret as a target on the same volume. + * Do the same for an abs path with no drive letter. + */ + if (((kind == FULL_PATH) + && (count >= 3) + && junction[3] + && !ntfs_drive_letter(vol, junction[0])) + || (kind == ABS_PATH)) { + if (kind == ABS_PATH) + target = search_absolute(vol,&junction[1],count - 1, isdir); + else + target = search_absolute(vol,&junction[3],count - 3, isdir); + if (target) { + level = 0; + for (p=path; *p; p++) + if (*p == '/') + level++; + fulltarget = (char*)ntfs_malloc(3*level + strlen(target) + 1); + if (fulltarget) { + fulltarget[0] = 0; + if (level > 1) { + for (i=1; i 0) && target) { + /* reverse slashes */ + for (q=target; *q; q++) + if (*q == '\\') + *q = '/'; + /* force uppercase drive letter */ + if ((target[1] == ':') + && (target[0] >= 'a') + && (target[0] <= 'z')) + target[0] += 'A' - 'a'; + level = 0; + for (p=path; *p; p++) + if (*p == '/') + level++; + fulltarget = (char*)ntfs_malloc(3*level + sizeof(mappingdir) + count - 4); + if (fulltarget) { + fulltarget[0] = 0; + if (level > 1) { + for (i=1; imrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); + vol = ni->vol; reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni, AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size); if (reparse_attr && attr_size) { @@ -417,14 +756,15 @@ char *ntfs_junction_point(ntfs_volume *vol, const char *org_path, offs = le16_to_cpu(mount_point_data->subst_name_offset); lth = le16_to_cpu(mount_point_data->subst_name_length); /* consistency checks */ - if (((le16_to_cpu(reparse_attr->reparse_data_length) + if (isdir + && ((le16_to_cpu(reparse_attr->reparse_data_length) + 8) == attr_size) && ((int)((sizeof(REPARSE_POINT) + sizeof(struct MOUNT_POINT_REPARSE_DATA) + offs + lth)) <= attr_size)) { - target = ntfs_get_junction(vol, + target = ntfs_get_fulllink(vol, (ntfschar*)&mount_point_data->path_buffer[offs], - lth/2, org_path); + lth/2, org_path, isdir); if (target) bad = FALSE; } @@ -433,17 +773,58 @@ char *ntfs_junction_point(ntfs_volume *vol, const char *org_path, symlink_data = (struct SYMLINK_REPARSE_DATA*)reparse_attr->reparse_data; offs = le16_to_cpu(symlink_data->subst_name_offset); lth = le16_to_cpu(symlink_data->subst_name_length); + p = (ntfschar*)&symlink_data->path_buffer[offs]; + /* + * Predetermine the kind of target, + * the called function has to make a full check + */ + if (*p++ == const_cpu_to_le16('\\')) { + if ((*p == const_cpu_to_le16('?')) + || (*p == const_cpu_to_le16('\\'))) + kind = FULL_TARGET; + else + kind = ABS_TARGET; + } else + if (*p == const_cpu_to_le16(':')) + kind = ABS_TARGET; + else + kind = REL_TARGET; + p--; /* consistency checks */ if (((le16_to_cpu(reparse_attr->reparse_data_length) + 8) == attr_size) && ((int)((sizeof(REPARSE_POINT) + sizeof(struct SYMLINK_REPARSE_DATA) + offs + lth)) <= attr_size)) { - target = ntfs_get_junction(vol, - (ntfschar*)&symlink_data->path_buffer[offs], - lth/2, org_path); - if (target) - bad = FALSE; + switch (kind) { + case FULL_TARGET : + if (!(symlink_data->flags + & const_cpu_to_le32(1))) { + target = ntfs_get_fulllink(vol,p, + lth/2, org_path, isdir); + if (target) + bad = FALSE; + } + break; + case ABS_TARGET : + if (symlink_data->flags + & const_cpu_to_le32(1)) { + target = ntfs_get_abslink(vol,p, + lth/2, org_path, isdir); + if (target) + bad = FALSE; + } + break; + case REL_TARGET : + if (symlink_data->flags + & const_cpu_to_le32(1)) { + target = ntfs_get_rellink(vol,p, + lth/2, org_path, isdir); + if (target) + bad = FALSE; + } + break; + } } break; } @@ -454,3 +835,32 @@ char *ntfs_junction_point(ntfs_volume *vol, const char *org_path, errno = EOPNOTSUPP; return (target); } + +/* + * Check whether a reparse point looks like a junction point + * or a symbolic link. + * Should only be called for files or directories with reparse data + * + * The validity of the target is not checked. + */ + +BOOL ntfs_possible_symlink(ntfs_inode *ni) +{ + s64 attr_size = 0; + REPARSE_POINT *reparse_attr; + BOOL possible; + + possible = FALSE; + reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni, + AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size); + if (reparse_attr && attr_size) { + switch (reparse_attr->reparse_tag) { + case IO_REPARSE_TAG_MOUNT_POINT : + case IO_REPARSE_TAG_SYMLINK : + possible = TRUE; + default : ; + } + free(reparse_attr); + } + return (possible); +} diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index a0392228..eee483d0 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -413,14 +413,15 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) goto exit; } #endif - if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY && !stream_name_len) { + if (((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + || (ni->flags & FILE_ATTR_REPARSE_POINT)) + && !stream_name_len) { if (ni->flags & FILE_ATTR_REPARSE_POINT) { char *target; int attr_size; errno = 0; - target = ntfs_junction_point(ctx->vol,org_path, ni, - &attr_size); + target = ntfs_make_symlink(org_path, ni, &attr_size); /* * If the reparse point is not a valid * directory junction, and there is no error @@ -580,17 +581,15 @@ static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size) goto exit; } /* - * Directory and reparse point : analyze as a - * junction point + * Reparse point : analyze as a junction point */ - if ((ni->flags & FILE_ATTR_REPARSE_POINT) - && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { + if (ni->flags & FILE_ATTR_REPARSE_POINT) { char *target; int attr_size; errno = 0; res = 0; - target = ntfs_junction_point(ctx->vol,org_path, ni, &attr_size); + target = ntfs_make_symlink(org_path, ni, &attr_size); if (target) { strncpy(buf,target,buf_size); free(target);