From 3745d0a1e35282b6f66fa4136cde6da5b4ac3875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Tue, 25 May 2010 09:58:36 +0200 Subject: [PATCH] marked files whose name has a dot initial as "hidden" if option hide_dot_files --- include/ntfs-3g/volume.h | 17 +++++++++++++++++ libntfs-3g/dir.c | 26 +++++++++++++++++++++++--- libntfs-3g/volume.c | 34 ++++++++++++++++++++++++++++++++++ src/lowntfs-3g.c | 30 +++++++++++++++++++++++++++--- src/ntfs-3g.8.in | 27 +++++++++++++++++++++------ src/ntfs-3g.c | 20 ++++++++++++++++---- 6 files changed, 138 insertions(+), 16 deletions(-) diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index 253e482b..140c6948 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -107,6 +107,9 @@ typedef enum { NV_ReadOnly, /* 1: Volume is read-only. */ NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */ NV_LogFileEmpty, /* 1: $logFile journal is empty. */ + NV_ShowSysFiles, /* 1: Show NTFS metafiles. */ + NV_ShowHidFiles, /* 1: Show files marked hidden. */ + NV_HideDotFiles, /* 1: Set hidden flag on dot files */ } ntfs_volume_state_bits; #define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state) @@ -125,6 +128,18 @@ typedef enum { #define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty) #define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty) +#define NVolShowSysFiles(nv) test_nvol_flag(nv, ShowSysFiles) +#define NVolSetShowSysFiles(nv) set_nvol_flag(nv, ShowSysFiles) +#define NVolClearShowSysFiles(nv) clear_nvol_flag(nv, ShowSysFiles) + +#define NVolShowHidFiles(nv) test_nvol_flag(nv, ShowHidFiles) +#define NVolSetShowHidFiles(nv) set_nvol_flag(nv, ShowHidFiles) +#define NVolClearShowHidFiles(nv) clear_nvol_flag(nv, ShowHidFiles) + +#define NVolHideDotFiles(nv) test_nvol_flag(nv, HideDotFiles) +#define NVolSetHideDotFiles(nv) set_nvol_flag(nv, HideDotFiles) +#define NVolClearHideDotFiles(nv) clear_nvol_flag(nv, HideDotFiles) + /* * NTFS version 1.1 and 1.2 are used by Windows NT4. * NTFS version 2.x is used by Windows 2000 Beta @@ -271,6 +286,8 @@ extern void ntfs_mount_error(const char *vol, const char *mntpoint, int err); extern int ntfs_volume_get_free_space(ntfs_volume *vol); +extern int ntfs_set_shown_files(ntfs_volume *vol, + BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files); extern int ntfs_set_locale(void); #endif /* defined _NTFS_VOLUME_H */ diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index 5505c9be..17bdc7b1 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -858,6 +858,9 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, { FILE_NAME_ATTR *fn = &ie->key.file_name; unsigned dt_type; + BOOL metadata; + int res; + MFT_REF mref; ntfs_log_trace("Entering.\n"); @@ -877,9 +880,20 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, dt_type = NTFS_DT_UNKNOWN; else dt_type = NTFS_DT_REG; - return filldir(dirent, fn->file_name, fn->file_name_length, - fn->file_name_type, *pos, - le64_to_cpu(ie->indexed_file), dt_type); + + /* return metadata files and hidden files if requested */ + mref = le64_to_cpu(ie->indexed_file); + metadata = (MREF(mref) != FILE_root) && (MREF(mref) < FILE_first_user); + if ((!metadata && (NVolShowHidFiles(dir_ni->vol) + || !(fn->file_attributes & FILE_ATTR_HIDDEN))) + || (NVolShowSysFiles(dir_ni->vol) && (NVolShowHidFiles(dir_ni->vol) + || metadata))) { + res = filldir(dirent, fn->file_name, fn->file_name_length, + fn->file_name_type, *pos, + mref, dt_type); + } else + res = 0; + return (res); } /** @@ -1397,6 +1411,11 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid, ni->flags = FILE_ATTR_SYSTEM; } ni->flags |= FILE_ATTR_ARCHIVE; + if (NVolHideDotFiles(dir_ni->vol) + && (name_len > 1) + && (name[0] == const_cpu_to_le16('.')) + && (name[1] != const_cpu_to_le16('.'))) + ni->flags |= FILE_ATTR_HIDDEN; /* * Set compression flag according to parent directory * unless NTFS version < 3.0 or cluster size > 4K @@ -1536,6 +1555,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid, else fn->file_attributes |= ni->flags & FILE_ATTR_COMPRESSED; fn->file_attributes |= FILE_ATTR_ARCHIVE; + fn->file_attributes |= ni->flags & FILE_ATTR_HIDDEN; fn->creation_time = ni->creation_time; fn->last_data_change_time = ni->last_data_change_time; fn->last_mft_change_time = ni->last_mft_change_time; diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c index ecacb181..585f9f6a 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -489,6 +489,10 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags) ntfs_upcase_table_build(vol->upcase, vol->upcase_len * sizeof(ntfschar)); + /* by default, all files are shown and not marked hidden */ + NVolSetShowSysFiles(vol); + NVolSetShowHidFiles(vol); + NVolClearHideDotFiles(vol); if (flags & MS_RDONLY) NVolSetReadOnly(vol); @@ -1195,6 +1199,36 @@ error_exit: return NULL; } +/* + * Set appropriate flags for showing NTFS metafiles + * or files marked as hidden. + * Not set in ntfs_mount() to avoid breaking existing tools. + */ + +int ntfs_set_shown_files(ntfs_volume *vol, + BOOL show_sys_files, BOOL show_hid_files, + BOOL hide_dot_files) +{ + int res; + + res = -1; + if (vol) { + NVolClearShowSysFiles(vol); + NVolClearShowHidFiles(vol); + NVolClearHideDotFiles(vol); + if (show_sys_files) + NVolSetShowSysFiles(vol); + if (show_hid_files) + NVolSetShowHidFiles(vol); + if (hide_dot_files) + NVolSetHideDotFiles(vol); + res = 0; + } + if (res) + ntfs_log_error("Failed to set file visibility\n"); + return (res); +} + /** * ntfs_mount - open ntfs volume * @name: name of device/file to open diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index b6cdafdb..96c0713b 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -209,6 +209,8 @@ typedef struct { ntfs_atime_t atime; BOOL ro; BOOL show_sys_files; + BOOL show_hid_files; + BOOL hide_dot_files; BOOL silent; BOOL recover; BOOL hiberfile; @@ -374,6 +376,11 @@ static u64 ntfs_fuse_inode_lookup(fuse_ino_t parent, const char *name) if (dir_ni) { /* Lookup file */ inum = ntfs_inode_lookup_by_mbsname(dir_ni, name); + /* never return inodes 0 and 1 */ + if (MREF(inum) <= 1) { + inum = (u64)-1; + errno = ENOENT; + } if (ntfs_inode_close(dir_ni) || (inum == (u64)-1)) ino = (u64)-1; @@ -878,6 +885,11 @@ static void ntfs_fuse_lookup(fuse_req_t req, fuse_ino_t parent, #endif iref = ntfs_inode_lookup_by_mbsname(dir_ni, name); + /* never return inodes 0 and 1 */ + if (MREF(iref) <= 1) { + iref = (u64)-1; + errno = ENOENT; + } ok = !ntfs_inode_close(dir_ni) && (iref != (u64)-1) && ntfs_fuse_fillstat( @@ -1002,9 +1014,8 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, (unsigned long long)MREF(mref)); return -1; } - - if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || - ctx->show_sys_files) { + /* never return inodes 0 and 1 */ + if (MREF(mref) > 1) { struct stat st = { .st_ino = MREF(mref) }; if (dt_type == NTFS_DT_REG) @@ -3638,6 +3649,9 @@ static int ntfs_open(const char *device) ntfs_log_perror("Failed to mount '%s'", device); goto err_out; } + if (ntfs_set_shown_files(ctx->vol, ctx->show_sys_files, + ctx->show_hid_files, ctx->hide_dot_files)) + goto err_out; ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na); if (ctx->vol->free_clusters < 0) { @@ -3802,6 +3816,14 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "show_sys_files")) goto err_exit; ctx->show_sys_files = TRUE; + } else if (!strcmp(opt, "show_hid_files")) { + if (bogus_option_value(val, "show_hid_files")) + goto err_exit; + ctx->show_hid_files = TRUE; + } else if (!strcmp(opt, "hide_dot_files")) { + if (bogus_option_value(val, "hide_dot_files")) + goto err_exit; + ctx->hide_dot_files = TRUE; } else if (!strcmp(opt, "silent")) { if (bogus_option_value(val, "silent")) goto err_exit; @@ -3911,6 +3933,8 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "efs_raw")) goto err_exit; ctx->efs_raw = TRUE; + /* show hidden files to archivers */ + ctx->show_hid_files = 1; #endif /* HAVE_SETXATTR */ } else { /* Probably FUSE option. */ if (strappend(&ret, opt)) diff --git a/src/ntfs-3g.8.in b/src/ntfs-3g.8.in index 3134d210..a828c8b6 100644 --- a/src/ntfs-3g.8.in +++ b/src/ntfs-3g.8.in @@ -184,14 +184,29 @@ if a file has been read since the last time it was modified. This is the default behaviour. .TP .B show_sys_files -Show the system files in directory listings. -Otherwise the default behaviour is to hide the system files. -Please note that even when this option is specified, "$MFT" -may not be visible due to a glibc bug. -Furthermore, irrespectively of show_sys_files, all -files are accessible by name, for example you can always do +Show the metafiles in directory listings. Otherwise the default behaviour is +to hide the metafiles, which are special files used to store the NTFS +structure. Please note that even when this option is specified, "$MFT" may +not be visible due to a glibc bug. Furthermore, irrespectively of +show_sys_files, all files are accessible by name, for example you can always +do "ls \-l '$UpCase'". .TP +.B show_hid_files +Show the hidden files and directories in directory listings, the hidden files +and directories being the ones whose NTFS attribute have the hidden flag set. +This flag has no effect on files and directory whose first character of +the name is a dot. Furthermore, irrespectively of show_hid_files, all files +and directories are accessible by name, for example you can always display +the Windows trash bin directory by : +"ls \-ld '$RECYCLE.BIN'". +.TP +.B hide_dot_files +Set the hidden flag in the NTFS attribute for created files and directories +whose first character of the name is a dot. Such files and directories +normally do not appear in directory listings, and when the flag is set +they do not appear in Windows directory displays either. +.TP .B allow_other This option overrides the security measure restricting file access to the user mounting the filesystem. This option is only diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 34b1634f..5737c5eb 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -170,6 +170,8 @@ typedef struct { ntfs_atime_t atime; BOOL ro; BOOL show_sys_files; + BOOL show_hid_files; + BOOL hide_dot_files; BOOL silent; BOOL recover; BOOL hiberfile; @@ -1028,10 +1030,7 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, filename, (unsigned long long)MREF(mref)); free(filename); return 0; - } - - if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || - ctx->show_sys_files) { + } else { struct stat st = { .st_ino = MREF(mref) }; if (dt_type == NTFS_DT_REG) @@ -3597,6 +3596,9 @@ static int ntfs_open(const char *device) ntfs_log_perror("Failed to mount '%s'", device); goto err_out; } + if (ntfs_set_shown_files(ctx->vol, ctx->show_sys_files, + ctx->show_hid_files, ctx->hide_dot_files)) + goto err_out; ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na); if (ctx->vol->free_clusters < 0) { @@ -3761,6 +3763,14 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "show_sys_files")) goto err_exit; ctx->show_sys_files = TRUE; + } else if (!strcmp(opt, "show_hid_files")) { + if (bogus_option_value(val, "show_hid_files")) + goto err_exit; + ctx->show_hid_files = TRUE; + } else if (!strcmp(opt, "hide_dot_files")) { + if (bogus_option_value(val, "hide_dot_files")) + goto err_exit; + ctx->hide_dot_files = TRUE; } else if (!strcmp(opt, "silent")) { if (bogus_option_value(val, "silent")) goto err_exit; @@ -3872,6 +3882,8 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "efs_raw")) goto err_exit; ctx->efs_raw = TRUE; + /* show hidden files to archivers */ + ctx->show_hid_files = 1; #endif /* HAVE_SETXATTR */ } else { /* Probably FUSE option. */ if (strappend(&ret, opt))