diff --git a/include/ntfs-3g/layout.h b/include/ntfs-3g/layout.h index 98380de2..816be49b 100644 --- a/include/ntfs-3g/layout.h +++ b/include/ntfs-3g/layout.h @@ -1068,12 +1068,17 @@ typedef enum { FILE_NAME_WIN32 = 0x01, /* The standard WinNT/2k NTFS long filenames. Case insensitive. All Unicode chars except: '\0', '"', '*', '/', ':', '<', - '>', '?', '\' and '|'. Further, names cannot end with a '.' - or a space. */ + '>', '?', '\' and '|'. Trailing dots and spaces are allowed, + even though on Windows a filename with such a suffix can only + be created and accessed using a WinNT-style path, i.e. + \\?\-prefixed. (If a regular path is used, Windows will + strip the trailing dots and spaces, which makes such + filenames incompatible with most Windows software.) */ FILE_NAME_DOS = 0x02, /* The standard DOS filenames (8.3 format). Uppercase only. All 8-bit characters greater space, except: '"', '*', '+', - ',', '/', ':', ';', '<', '=', '>', '?' and '\'. */ + ',', '/', ':', ';', '<', '=', '>', '?' and '\'. Trailing + dots and spaces are forbidden. */ FILE_NAME_WIN32_AND_DOS = 0x03, /* 3 means that both the Win32 and the DOS filenames are identical and hence have been saved in this single filename diff --git a/include/ntfs-3g/unistr.h b/include/ntfs-3g/unistr.h index b6d428e3..28048ed7 100644 --- a/include/ntfs-3g/unistr.h +++ b/include/ntfs-3g/unistr.h @@ -68,9 +68,9 @@ extern ntfschar *ntfs_str2ucs(const char *s, int *len); extern void ntfs_ucsfree(ntfschar *ucs); -extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len); +extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len, BOOL strict); extern BOOL ntfs_forbidden_names(ntfs_volume *vol, - const ntfschar *name, int len); + const ntfschar *name, int len, BOOL strict); extern BOOL ntfs_collapsible_chars(ntfs_volume *vol, const ntfschar *shortname, int shortlen, const ntfschar *longname, int longlen); diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index fdc87faf..a66f807f 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -2654,9 +2654,12 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, shortlen = ntfs_mbstoucs(newname, &shortname); if (shortlen > MAX_DOS_NAME_LENGTH) shortlen = MAX_DOS_NAME_LENGTH; - /* make sure the short name has valid chars */ + + /* Make sure the short name has valid chars. + * Note: the short name cannot end with dot or space, but the + * corresponding long name can. */ if ((shortlen < 0) - || ntfs_forbidden_names(ni->vol,shortname,shortlen)) { + || ntfs_forbidden_names(ni->vol,shortname,shortlen,TRUE)) { ntfs_inode_close_in_dir(ni,dir_ni); ntfs_inode_close(dir_ni); res = -errno; @@ -2667,7 +2670,8 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, if (longlen > 0) { oldlen = get_dos_name(ni, dnum, oldname); if ((oldlen >= 0) - && !ntfs_forbidden_names(ni->vol, longname, longlen)) { + && !ntfs_forbidden_names(ni->vol, longname, longlen, + FALSE)) { if (oldlen > 0) { if (flags & XATTR_CREATE) { res = -1; diff --git a/libntfs-3g/unistr.c b/libntfs-3g/unistr.c index e70e3165..5854b3b7 100644 --- a/libntfs-3g/unistr.c +++ b/libntfs-3g/unistr.c @@ -1477,10 +1477,14 @@ void ntfs_ucsfree(ntfschar *ucs) * Check whether a name contains no chars forbidden * for DOS or Win32 use * + * If @strict is TRUE, then trailing dots and spaces are forbidden. + * These names are technically allowed in the Win32 namespace, but + * they can be problematic. See comment for FILE_NAME_WIN32. + * * If there is a bad char, errno is set to EINVAL */ -BOOL ntfs_forbidden_chars(const ntfschar *name, int len) +BOOL ntfs_forbidden_chars(const ntfschar *name, int len, BOOL strict) { BOOL forbidden; int ch; @@ -1493,9 +1497,9 @@ BOOL ntfs_forbidden_chars(const ntfschar *name, int len) | (1L << ('>' - 0x20)) | (1L << ('?' - 0x20)); - forbidden = (len == 0) - || (name[len-1] == const_cpu_to_le16(' ')) - || (name[len-1] == const_cpu_to_le16('.')); + forbidden = (len == 0) || + (strict && (name[len-1] == const_cpu_to_le16(' ') || + name[len-1] == const_cpu_to_le16('.'))); for (i=0; i= 3)) { /* * Rough hash check to tell whether the first couple of chars diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 4faf4f11..e48c43f7 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -2169,7 +2169,7 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name, uname_len = ntfs_mbstoucs(name, &uname); if ((uname_len < 0) || (ctx->windows_names - && ntfs_forbidden_names(ctx->vol,uname,uname_len))) { + && ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) { res = -errno; goto exit; } @@ -2390,7 +2390,7 @@ static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)), uname_len = ntfs_mbstoucs(newname, &uname); if ((uname_len < 0) || (ctx->windows_names - && ntfs_forbidden_names(ctx->vol,uname,uname_len))) { + && ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) { res = -errno; goto exit; } @@ -3571,7 +3571,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, lename_len = fix_xattr_prefix(name, namespace, &lename); if ((lename_len == -1) || (ctx->windows_names - && ntfs_forbidden_chars(lename,lename_len))) { + && ntfs_forbidden_chars(lename,lename_len,TRUE))) { res = -errno; goto exit; } diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 96b6d8ee..9140f1ee 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -1954,7 +1954,7 @@ static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev, uname_len = ntfs_mbstoucs(name, &uname); if ((uname_len < 0) || (ctx->windows_names - && ntfs_forbidden_names(ctx->vol,uname,uname_len))) { + && ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) { res = -errno; goto exit; } @@ -2162,7 +2162,7 @@ static int ntfs_fuse_mknod_common(const char *org_path, mode_t mode, dev_t dev, && (!S_ISREG(mode) || (ctx->windows_names && ntfs_forbidden_names(ctx->vol,stream_name, - stream_name_len)))) { + stream_name_len, TRUE)))) { res = -EINVAL; goto exit; } @@ -2231,7 +2231,7 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path) uname_len = ntfs_mbstoucs(name, &uname); if ((uname_len < 0) || (ctx->windows_names - && ntfs_forbidden_names(ctx->vol,uname,uname_len))) { + && ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) { res = -errno; goto exit; } @@ -3379,7 +3379,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, lename_len = fix_xattr_prefix(name, namespace, &lename); if ((lename_len == -1) || (ctx->windows_names - && ntfs_forbidden_chars(lename,lename_len))) { + && ntfs_forbidden_chars(lename,lename_len,TRUE))) { res = -errno; goto exit; }