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 | 121 +++++++++++++++++++++++++++++++++++++---- include/config.h.in | 3 + 4 files changed, 120 insertions(+), 11 deletions(-)
diff --git a/configure b/configure index a0937b39a4e..1b78fe7bcc9 100755 --- a/configure +++ b/configure @@ -7993,6 +7993,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 93abc2064e4..3eb38d4c01e 100644 --- a/configure.ac +++ b/configure.ac @@ -439,6 +439,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 fa85b99899a..1c3cfa96cac 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -34,6 +34,7 @@ #include <stdarg.h> #include <string.h> #include <stdlib.h> +#include <stdint.h> #include <stdio.h> #include <limits.h> #include <unistd.h> @@ -86,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 @@ -1552,11 +1556,43 @@ static BOOL fd_is_mount_point( int fd, const struct stat *st ) }
+#ifdef HAVE_LINUX_MSDOS_FS_H +static BOOL fd_get_fat_attr( int fd, ULONG *attr ) +{ + uint32_t fat_attr; + + if (ioctl( fd, FAT_IOCTL_GET_ATTRIBUTES, &fat_attr ) == 0) + { + if (fat_attr & ATTR_HIDDEN) *attr |= FILE_ATTRIBUTE_HIDDEN; + if (fat_attr & ATTR_SYS) *attr |= FILE_ATTRIBUTE_SYSTEM; + return TRUE; + } + + return FALSE; +} +#endif + + +static BOOL fd_get_xattr_dos_attrib( int fd, ULONG *attr ) +{ + char hexattr[11]; + int len; + + len = xattr_fget( fd, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); + if (len != -1) + { + *attr |= get_file_xattr( hexattr, len ); + return TRUE; + } + + 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 hexattr[11]; - int len, ret; + int ret;
*attr = 0; ret = fstat( fd, st ); @@ -1566,15 +1602,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;
- len = xattr_fget( fd, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); - if (len != -1) - *attr |= get_file_xattr( hexattr, len ); +#ifdef HAVE_LINUX_MSDOS_FS_H + /* try retrieving FAT file attributes */ + fd_get_fat_attr( fd, attr ); +#endif + + /* 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_attr( int fd, ULONG attr ) +{ + uint32_t fat_attr = 0; + if (attr & FILE_ATTRIBUTE_HIDDEN) fat_attr |= ATTR_HIDDEN; + if (attr & FILE_ATTRIBUTE_SYSTEM) fat_attr |= ATTR_SYS; + return ioctl( fd, FAT_IOCTL_SET_ATTRIBUTES, &fat_attr ); +} +#endif + + +static int fd_set_xattr_dos_attrib( int fd, ULONG attr ) { /* do not store everything, but keep everything Samba can use */ attr &= ~FILE_ATTRIBUTE_NORMAL; @@ -1589,6 +1640,18 @@ 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_attr( fd, attr ); +#endif + + /* try setting DOS attributes into extended attributes */ + fd_set_xattr_dos_attrib( fd, attr ); +} + + /* set the stat info and file attributes for a file (by file descriptor) */ NTSTATUS fd_set_file_info( int fd, ULONG attr ) { @@ -1615,12 +1678,44 @@ NTSTATUS fd_set_file_info( int fd, ULONG attr ) }
+#ifdef HAVE_LINUX_MSDOS_FS_H +static BOOL get_fat_attr( const char *path, ULONG *attr ) +{ + BOOL ret = FALSE; + int fd = open( path, O_PATH ); + + if (fd) + { + if (fd_get_fat_attr( fd, attr )) ret = TRUE; + close( fd ); + } + + return ret; +} +#endif + + +static BOOL get_xattr_dos_attrib( const char *path, ULONG *attr ) +{ + char hexattr[11]; + int len; + + len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); + if (len != -1) + { + *attr |= get_file_xattr( hexattr, len ); + return TRUE; + } + + 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 hexattr[11]; - int len, ret; + int ret;
*attr = 0; ret = lstat( path, st ); @@ -1647,9 +1742,13 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) } *attr |= get_file_attributes( st );
- len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); - if (len != -1) - *attr |= get_file_xattr( hexattr, len ); +#ifdef HAVE_LINUX_MSDOS_FS_H + /* try retrieving FAT file attributes */ + get_fat_attr( path, attr ); +#endif + + /* try retrieving DOS attributes from extended attributes */ + get_xattr_dos_attrib( path, attr );
return ret; } diff --git a/include/config.h.in b/include/config.h.in index 782d6b2a056..286697fef23 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -212,6 +212,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