On Linux, the FAT filesystem implementation allows DOS file attributes to be applied to files and queried through a family of ioctls. Note that these ioctls are not yet supported by the NTFS or CIFS drivers.
Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk
-- v2: ntdll: Add integration with Linux FAT file attributes
From: Joel Holdsworth joel@airwebreathe.org.uk
On Linux, the FAT filesystem implementation allows DOS file attributes to be applied to files and queried through a family of ioctls. Note that these ioctls are not yet supported by the NTFS or CIFS drivers.
Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- configure | 6 ++ configure.ac | 1 + dlls/ntdll/unix/file.c | 162 ++++++++++++++++++++++++++++++++--------- include/config.h.in | 3 + 4 files changed, 139 insertions(+), 33 deletions(-)
diff --git a/configure b/configure index aaebcc553f5..b755a36416a 100755 --- a/configure +++ b/configure @@ -8014,6 +8014,12 @@ if test "x$ac_cv_header_linux_major_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_MAJOR_H 1" >>confdefs.h
+fi +ac_fn_c_check_header_compile "$LINENO" "linux/msdos_fs.h" "ac_cv_header_linux_msdos_fs_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_msdos_fs_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_MSDOS_FS_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "linux/param.h" "ac_cv_header_linux_param_h" "$ac_includes_default" if test "x$ac_cv_header_linux_param_h" = xyes diff --git a/configure.ac b/configure.ac index fe6a773d1c3..5e7f963478f 100644 --- a/configure.ac +++ b/configure.ac @@ -437,6 +437,7 @@ AC_CHECK_HEADERS(\ linux/input.h \ linux/ioctl.h \ linux/major.h \ + linux/msdos_fs.h \ linux/param.h \ linux/serial.h \ linux/types.h \ diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index e80eb368e8a..4e860b6f0d8 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -87,6 +87,9 @@ #ifdef HAVE_LINUX_MAJOR_H # include <linux/major.h> #endif +#ifdef HAVE_LINUX_MSDOS_FS_H +# include <linux/msdos_fs.h> +#endif #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> #endif @@ -1570,11 +1573,51 @@ static BOOL fd_is_mount_point( int fd, const struct stat *st ) }
+#ifdef HAVE_LINUX_MSDOS_FS_H +static BOOL fd_get_fat_dos_attrib( int fd, ULONG *attr ) +{ + uint32_t fat_attrib; + + if (ioctl( fd, FAT_IOCTL_GET_ATTRIBUTES, &fat_attrib ) == 0) + { + if (fat_attrib & ATTR_HIDDEN) *attr |= FILE_ATTRIBUTE_HIDDEN; + if (fat_attrib & ATTR_SYS) *attr |= FILE_ATTRIBUTE_SYSTEM; + return TRUE; + } + + return FALSE; +} +#endif + + +static BOOL fd_get_xattr_dos_attrib( int fd, ULONG *attr ) +{ + char data[65]; + int len; + + len = xattr_fget( fd, SAMBA_XATTR_DOS_ATTRIB, data, sizeof(data)-1 ); + if (len != -1) + { + *attr |= parse_samba_dos_attrib_data( data, len ); + return TRUE; + } +#ifdef ENODATA + else if (errno == ENODATA) + return TRUE; +#endif + else if (errno == ENOTSUP) + return TRUE; + + WARN( "Failed to get extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)\n", + errno, strerror( errno ) ); + + return FALSE; +} + /* get the stat info and file attributes for a file (by file descriptor) */ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULONG *attr ) { - char attr_data[65]; - int attr_len, ret; + int ret;
*attr = 0; ret = fstat( fd, st ); @@ -1584,23 +1627,30 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
- attr_len = xattr_fget( fd, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); - if (attr_len != -1) - *attr |= parse_samba_dos_attrib_data( attr_data, attr_len ); - else - { - if (errno == ENOTSUP) return ret; -#ifdef ENODATA - if (errno == ENODATA) return ret; +#ifdef HAVE_LINUX_MSDOS_FS_H + /* try retrieving FAT file attributes */ + fd_get_fat_dos_attrib( fd, attr ); #endif - WARN( "Failed to get extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)\n", - errno, strerror( errno ) ); - } + + /* try retrieving DOS attributes from extended attributes */ + fd_get_xattr_dos_attrib( fd, attr ); + return ret; }
-static int fd_set_dos_attrib( int fd, ULONG attr ) +#ifdef HAVE_LINUX_MSDOS_FS_H +static int fd_set_fat_dos_attrib( int fd, ULONG attr ) +{ + uint32_t fat_attrib = 0; + if (attr & FILE_ATTRIBUTE_HIDDEN) fat_attrib |= ATTR_HIDDEN; + if (attr & FILE_ATTRIBUTE_SYSTEM) fat_attrib |= ATTR_SYS; + return ioctl( fd, FAT_IOCTL_SET_ATTRIBUTES, &fat_attrib ); +} +#endif + + +static int fd_set_xattr_dos_attrib( int fd, ULONG attr ) { /* we only store the HIDDEN and SYSTEM attributes */ attr &= XATTR_ATTRIBS_MASK; @@ -1617,6 +1667,20 @@ static int fd_set_dos_attrib( int fd, ULONG attr ) }
+static void fd_set_dos_attrib( int fd, ULONG attr ) +{ +#ifdef HAVE_LINUX_MSDOS_FS_H + /* try setting FAT file attributes */ + fd_set_fat_dos_attrib( fd, attr ); +#endif + + /* try setting DOS attributes into extended attributes */ + if (fd_set_xattr_dos_attrib( fd, attr ) == -1 && errno != ENOTSUP) + WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)\n", + errno, strerror( errno ) ); +} + + /* set the stat info and file attributes for a file (by file descriptor) */ NTSTATUS fd_set_file_info( int fd, ULONG attr ) { @@ -1637,20 +1701,58 @@ NTSTATUS fd_set_file_info( int fd, ULONG attr ) } if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno );
- if (fd_set_dos_attrib( fd, attr ) == -1 && errno != ENOTSUP) - WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)\n", - errno, strerror( errno ) ); + fd_set_dos_attrib( fd, attr );
return STATUS_SUCCESS; }
+#ifdef HAVE_LINUX_MSDOS_FS_H +static BOOL get_fat_dos_attrib( const char *path, ULONG *attr ) +{ + BOOL ret = FALSE; + int fd = open( path, O_PATH ); + + if (fd) + { + if (fd_get_fat_dos_attrib( fd, attr )) ret = TRUE; + close( fd ); + } + + return ret; +} +#endif + + +static BOOL get_xattr_dos_attrib( const char *path, ULONG *attr ) +{ + char data[65]; + int len; + + len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, data, sizeof(data)-1 ); + if (len != -1) + { + *attr |= parse_samba_dos_attrib_data( data, len ); + return TRUE; + } +#ifdef ENODATA + else if (errno == ENODATA) + return TRUE; +#endif + else if (errno == ENOTSUP) + return TRUE; + + WARN( "Failed to get extended attribute " SAMBA_XATTR_DOS_ATTRIB " from "%s". errno %d (%s)\n", + path, errno, strerror( errno ) ); + + return FALSE; +} + /* get the stat info and file attributes for a file (by name) */ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) { char *parent_path; - char attr_data[65]; - int attr_len, ret; + int ret;
*attr = 0; ret = lstat( path, st ); @@ -1677,18 +1779,14 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) } *attr |= get_file_attributes( st );
- attr_len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); - if (attr_len != -1) - *attr |= parse_samba_dos_attrib_data( attr_data, attr_len ); - else - { - if (errno == ENOTSUP) return ret; -#ifdef ENODATA - if (errno == ENODATA) return ret; +#ifdef HAVE_LINUX_MSDOS_FS_H + /* try retrieving FAT file attributes */ + get_fat_dos_attrib( path, attr ); #endif - WARN( "Failed to get extended attribute " SAMBA_XATTR_DOS_ATTRIB " from "%s". errno %d (%s)\n", - path, errno, strerror( errno ) ); - } + + /* try retrieving DOS attributes from extended attributes */ + get_xattr_dos_attrib( path, attr ); + return ret; }
@@ -4042,9 +4140,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU /* set any DOS extended attributes */ if (!server_get_unix_fd( *handle, 0, &fd, &needs_close, NULL, NULL )) { - if (fd_set_dos_attrib( fd, attributes ) == -1 && errno != ENOTSUP) - WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)", - errno, strerror( errno ) ); + fd_set_dos_attrib( fd, attributes ); if (needs_close) close( fd ); } } diff --git a/include/config.h.in b/include/config.h.in index 3a06d36bd02..763c1bf29f6 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -209,6 +209,9 @@ /* Define to 1 if you have the <linux/major.h> header file. */ #undef HAVE_LINUX_MAJOR_H
+/* Define to 1 if you have the <linux/msdos_fs.h> header file. */ +#undef HAVE_LINUX_MSDOS_FS_H + /* Define to 1 if you have the <linux/param.h> header file. */ #undef HAVE_LINUX_PARAM_H