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.
This patch implements a design where Wine ntdll will attempt to store attributes in every available storage locations (currently the Samba-style user.DOSATTRIB extended attribute, and the Linux FAT filesystem ioctl). DOS Attibute flags are then retrieved from every available storage location and OR'd together.
In future, additional filesystem and OS-specific storage locations can be added in similar fashion.
Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- configure | 6 ++ configure.ac | 1 + dlls/ntdll/unix/file.c | 190 ++++++++++++++++++++++++++++++++++------- include/config.h.in | 3 + 4 files changed, 167 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..133fb4d85ce 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,38 @@ 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 ) +{ + int ret; + uint32_t fat_attrib; + + /* read flags so that flags other than HIDDEN and SYSTEM e.g. READONLY can be preserved */ + ret = ioctl( fd, FAT_IOCTL_GET_ATTRIBUTES, &fat_attrib ); + if (ret != 0) + return ret; + + fat_attrib &= ~(ATTR_HIDDEN | ATTR_SYS); + 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 +1675,40 @@ 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 + int fat_errno = 0; +#endif + int xattr_errno = 0; + +#ifdef HAVE_LINUX_MSDOS_FS_H + /* try setting FAT file attributes */ + if (fd_set_fat_dos_attrib( fd, attr ) == -1) + fat_errno = errno; +#endif + + /* try setting DOS attributes into extended attributes */ + if (fd_set_xattr_dos_attrib( fd, attr ) == -1) + xattr_errno = errno; + + if ( +#ifdef HAVE_LINUX_MSDOS_FS_H + fat_errno || +#endif + xattr_errno) { + WARN( "No method was found to store DOS attributes. "); +#ifdef HAVE_LINUX_MSDOS_FS_H + WARN( "Storage with FAT_IOCTL_SET_ATTRIBUTES failed with errno %d (%s). ", + fat_errno, strerror( fat_errno ) ); +#endif + WARN( "Storage with " SAMBA_XATTR_DOS_ATTRIB + " extended attribute failed with errno %d (%s).\n", + xattr_errno, strerror( xattr_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 +1729,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 +1807,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 +4168,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