diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 856a3311..13c29ebe 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -212,6 +212,7 @@ typedef struct { BOOL show_hid_files; BOOL hide_dot_files; BOOL ignore_case; + BOOL windows_names; BOOL silent; BOOL recover; BOOL hiberfile; @@ -1849,7 +1850,9 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name, /* Generate unicode filename. */ uname_len = ntfs_mbstoucs(name, &uname); - if (uname_len < 0) { + if ((uname_len < 0) + || (ctx->windows_names + && ntfs_forbidden_chars(uname,uname_len))) { res = -errno; goto exit; } @@ -2053,7 +2056,9 @@ static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)), /* Generate unicode filename. */ uname_len = ntfs_mbstoucs(newname, &uname); - if (uname_len < 0) { + if ((uname_len < 0) + || (ctx->windows_names + && ntfs_forbidden_chars(uname,uname_len))) { res = -errno; goto exit; } @@ -3271,7 +3276,9 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, } #endif lename_len = fix_xattr_prefix(name, namespace, &lename); - if (lename_len == -1) { + if ((lename_len == -1) + || (ctx->windows_names + && ntfs_forbidden_chars(lename,lename_len))) { res = -errno; goto exit; } @@ -3829,6 +3836,10 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "ignore_case")) goto err_exit; ctx->ignore_case = TRUE; + } else if (!strcmp(opt, "windows_names")) { + if (bogus_option_value(val, "windows_names")) + goto err_exit; + ctx->windows_names = TRUE; } else if (!strcmp(opt, "silent")) { if (bogus_option_value(val, "silent")) goto err_exit; diff --git a/src/ntfs-3g.8.in b/src/ntfs-3g.8.in index cf891c05..d476b58b 100644 --- a/src/ntfs-3g.8.in +++ b/src/ntfs-3g.8.in @@ -70,8 +70,8 @@ NTFS supports several filename namespaces: DOS, Win32 and POSIX. While the POSIX namespace for maximum portability and interoperability reasons. This means that filenames are case sensitive and all characters are allowed except '/' and '\\0'. This is perfectly legal on Windows, though -some application may get confused. If you find so then please report it -to the developer of the relevant Windows software. +some application may get confused. The option \fBwindows_names\fP may be +used to apply Windows restrictions to new file names. .SS Alternate Data Streams (ADS) NTFS stores all data in streams. Every file has exactly one unnamed data stream and can have many named data streams. The size of a file is the @@ -210,6 +210,13 @@ 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 windows_names +This option prevents files, directories and extended attributes to be +created with a name not allowed by windows, either because it contains +some not allowed character (which are the nine characters " * / : < > ? \ | and +those whose code is less than 0x20) or because the last character is a space. +Existing such files can still be read (and renamed). +.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 888edb99..10526bad 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -172,6 +172,7 @@ typedef struct { BOOL show_sys_files; BOOL show_hid_files; BOOL hide_dot_files; + BOOL windows_names; BOOL silent; BOOL recover; BOOL hiberfile; @@ -1617,12 +1618,15 @@ static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev, name = strrchr(dir_path, '/'); name++; uname_len = ntfs_mbstoucs(name, &uname); - if (uname_len < 0) { + if ((uname_len < 0) + || (ctx->windows_names + && ntfs_forbidden_chars(uname,uname_len))) { res = -errno; goto exit; } stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + /* stream name validity has been checked previously */ if (stream_name_len < 0) { res = stream_name_len; goto exit; @@ -1808,7 +1812,10 @@ static int ntfs_fuse_mknod_common(const char *org_path, mode_t mode, dev_t dev, stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; - if (stream_name_len && !S_ISREG(mode)) { + if (stream_name_len + && (!S_ISREG(mode) + || (ctx->windows_names + && ntfs_forbidden_chars(stream_name,stream_name_len)))) { res = -EINVAL; goto exit; } @@ -1875,7 +1882,9 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path) name = strrchr(path, '/'); name++; uname_len = ntfs_mbstoucs(name, &uname); - if (uname_len < 0) { + if ((uname_len < 0) + || (ctx->windows_names + && ntfs_forbidden_chars(uname,uname_len))) { res = -errno; goto exit; } @@ -3193,7 +3202,9 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, } #endif lename_len = fix_xattr_prefix(name, namespace, &lename); - if (lename_len == -1) { + if ((lename_len == -1) + || (ctx->windows_names + && ntfs_forbidden_chars(lename,lename_len))) { res = -errno; goto exit; } @@ -3771,6 +3782,10 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "hide_dot_files")) goto err_exit; ctx->hide_dot_files = TRUE; + } else if (!strcmp(opt, "windows_names")) { + if (bogus_option_value(val, "windows_names")) + goto err_exit; + ctx->windows_names = TRUE; } else if (!strcmp(opt, "silent")) { if (bogus_option_value(val, "silent")) goto err_exit;