This patch set is based upon [patches from Wine Staging](https://github.com/wine-staging/wine-staging/tree/master/patches/ntdll-DOS_A...), and implements support for the `SYSTEM`, `HIDDEN` and `READONLY` DOS file attributes. These have been implemented in various ways depending upon the capabilities of the operating system and the file system.
# Storage Methods
## FAT MSDOS file attributes * Linux: [`ioctl_fat(2)`](https://www.man7.org/linux/man-pages/man2/ioctl_fat.2.html)
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.
## Extended File Attributes * Linux: [`xattr(7)`](https://www.man7.org/linux/man-pages/man7/xattr.7.html) * MacOS: [`getxattr(2)`](https://www.unix.com/man-page/osx/2/getxattr/), [`setxattr(2)`](https://www.unix.com/man-page/osx/2/setxattr/), [`removexattr(2)`](https://www.unix.com/man-page/osx/2/removexattr/) * FreeBSD, NetBSD: [`extattr(2)`](https://nixdoc.net/man-pages/FreeBSD/man2/extattr.2.html)
Modern filesystems generally support Extended File Attributes - auxiliary blobs of binary data that can be attached to a file. Samba uses the `user.DOSATTRIB` attribute to store DOS attribute information in the form of a hexadecimal value.
Note that although FreeBSD and NetBSD support the extended attribute system calls, these are not currently implemented in the operating system, or supported in any of their filesystem drivers.
## BSD File Flags * MacOS: [`fchflags(2)`](https://developer.apple.com/library/archive/documentation/System/Conceptual/...) * FreeBSD, NetBSD: [`fchflags(2)`](https://nixdoc.net/man-pages/FreeBSD/man2/fchflags.2.html)
On some BSD-like operating systems including MacOS, FreeBSD and NetBSD, the `struct stat` structure contains the `st_flags` member can carry flags of which the following can be used to represent DOS attributes:
* `UF_IMMUTABLE` can represent `FILE_ATTRIBUTE_READONLY` * `UF_HIDDEN` can reprent `FILE_ATTRIBUTE_HIDDEN` (not available on NetBSD)
# Design
The implementation is takes an opportunistic approach. It will attempt to store flags by any of the above mentioned methods, and will retrieve flags using any available method and will combine flags from multiple sources together.
# See Also
* https://bugs.winehq.org/show_bug.cgi?id=9158 * https://bugs.winehq.org/show_bug.cgi?id=15679
From: "Erich E. Hoover" erich.e.hoover@gmail.com
Co-authored-by: Joel Holdsworth joel@airwebreathe.org.uk Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- configure | 11 +++++++++++ configure.ac | 2 ++ dlls/ntdll/unix/file.c | 38 +++++++++++++++++++++++++++++++++++++- include/config.h.in | 3 +++ 4 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/configure b/configure index 6425e4da5f8..9c6fb443e1f 100755 --- a/configure +++ b/configure @@ -9105,6 +9105,17 @@ then : fi
+ for ac_header in attr/xattr.h +do : + ac_fn_c_check_header_compile "$LINENO" "attr/xattr.h" "ac_cv_header_attr_xattr_h" "$ac_includes_default" +if test "x$ac_cv_header_attr_xattr_h" = xyes +then : + printf "%s\n" "#define HAVE_ATTR_XATTR_H 1" >>confdefs.h + HAVE_XATTR=1 +fi + +done +
DLLFLAGS=""
diff --git a/configure.ac b/configure.ac index 1e733962b75..fd59bd6948d 100644 --- a/configure.ac +++ b/configure.ac @@ -635,6 +635,8 @@ AC_CHECK_HEADERS([libprocstat.h],,, #include <sys/queue.h> #endif])
+AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) + dnl **** Check for working dll ****
AC_SUBST(DLLFLAGS,"") diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 7eb8dbe7ad4..12d83bd9d0c 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -98,6 +98,9 @@ #ifdef HAVE_SYS_STATFS_H #include <sys/statfs.h> #endif +#ifdef HAVE_ATTR_XATTR_H +#include <attr/xattr.h> +#endif #include <time.h> #include <unistd.h>
@@ -167,6 +170,9 @@ typedef struct
#define MAX_IGNORED_FILES 4
+#define SAMBA_XATTR_DOS_ATTRIB "user.DOSATTRIB" +#define XATTR_ATTRIBS_MASK (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM) + struct file_identity { dev_t dev; @@ -355,6 +361,18 @@ NTSTATUS errno_to_status( int err ) } }
+ +static int xattr_get( const char *path, const char *name, void *value, size_t size ) +{ +#if defined(HAVE_ATTR_XATTR_H) + return getxattr( path, name, value, size ); +#else + errno = ENOSYS; + return -1; +#endif +} + + /* get space from the current directory data buffer, allocating a new one if necessary */ static void *get_dir_data_space( struct dir_data *data, unsigned int size ) { @@ -1451,6 +1469,18 @@ static inline ULONG get_file_attributes( const struct stat *st ) }
+/* decode the xattr-stored DOS attributes */ +static int get_file_xattr( char *hexattr, int attrlen ) +{ + if (attrlen > 2 && hexattr[0] == '0' && hexattr[1] == 'x') + { + hexattr[attrlen] = 0; + return strtol( hexattr+2, NULL, 16 ) & XATTR_ATTRIBS_MASK; + } + return 0; +} + + static BOOL fd_is_mount_point( int fd, const struct stat *st ) { struct stat parent; @@ -1479,7 +1509,8 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON static int get_file_info( const char *path, struct stat *st, ULONG *attr ) { char *parent_path; - int ret; + char hexattr[11]; + int len, ret;
*attr = 0; ret = lstat( path, st ); @@ -1505,6 +1536,11 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) free( parent_path ); } *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 ); + return ret; }
diff --git a/include/config.h.in b/include/config.h.in index de1bf6c61eb..25f09636b3a 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -25,6 +25,9 @@ /* Define to 1 if you have the <asm/user.h> header file. */ #undef HAVE_ASM_USER_H
+/* Define to 1 if you have the <attr/xattr.h> header file. */ +#undef HAVE_ATTR_XATTR_H + /* Define to 1 if you have the <capi20.h> header file. */ #undef HAVE_CAPI20_H
From: "Erich E. Hoover" erich.e.hoover@gmail.com
Co-authored-by: Joel Holdsworth joel@airwebreathe.org.uk Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- dlls/ntdll/unix/file.c | 78 +++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 12d83bd9d0c..fc8646b020f 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -362,6 +362,28 @@ NTSTATUS errno_to_status( int err ) }
+static int xattr_fremove( int filedes, const char *name ) +{ +#if defined(HAVE_ATTR_XATTR_H) + return fremovexattr( filedes, name ); +#else + errno = ENOSYS; + return -1; +#endif +} + + +static int xattr_fset( int filedes, const char *name, void *value, size_t size ) +{ +#if defined(HAVE_ATTR_XATTR_H) + return fsetxattr( filedes, name, value, size, 0 ); +#else + errno = ENOSYS; + return -1; +#endif +} + + static int xattr_get( const char *path, const char *name, void *value, size_t size ) { #if defined(HAVE_ATTR_XATTR_H) @@ -1505,6 +1527,41 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON }
+/* set the stat info and file attributes for a file (by file descriptor) */ +NTSTATUS fd_set_file_info( int fd, ULONG attr ) +{ + struct stat st; + + if (fstat( fd, &st ) == -1) return errno_to_status( errno ); + if (attr & FILE_ATTRIBUTE_READONLY) + { + if (S_ISDIR( st.st_mode)) + WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n"); + else + st.st_mode &= ~0222; /* clear write permission bits */ + } + else + { + /* add write permission only where we already have read permission */ + st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~start_umask); + } + if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno ); + + /* do not store everything, but keep everything Samba can use */ + attr &= ~FILE_ATTRIBUTE_NORMAL; + if (attr != 0) + { + char hexattr[11]; + int len = sprintf( hexattr, "0x%x", attr ); + xattr_fset( fd, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); + } + else + xattr_fremove( fd, SAMBA_XATTR_DOS_ATTRIB ); + + return STATUS_SUCCESS; +} + + /* 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 ) { @@ -4399,7 +4456,6 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, case FileBasicInformation: if (len >= sizeof(FILE_BASIC_INFORMATION)) { - struct stat st; const FILE_BASIC_INFORMATION *info = ptr; LARGE_INTEGER mtime, atime;
@@ -4413,25 +4469,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, status = set_file_times( fd, &mtime, &atime );
if (status == STATUS_SUCCESS && info->FileAttributes) - { - if (fstat( fd, &st ) == -1) status = errno_to_status( errno ); - else - { - if (info->FileAttributes & FILE_ATTRIBUTE_READONLY) - { - if (S_ISDIR( st.st_mode)) - WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n"); - else - st.st_mode &= ~0222; /* clear write permission bits */ - } - else - { - /* add write permission only where we already have read permission */ - st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~start_umask); - } - if (fchmod( fd, st.st_mode ) == -1) status = errno_to_status( errno ); - } - } + status = fd_set_file_info( fd, info->FileAttributes );
if (needs_close) close( fd ); }
From: Joel Holdsworth joel@airwebreathe.org.uk
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=9158 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=15679 Co-authored-by: Erich E. Hoover erich.e.hoover@gmail.com Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- dlls/ntdll/tests/file.c | 8 ++++---- dlls/ntdll/unix/file.c | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index dd0061b13d8..d49d4d5c26f 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1392,7 +1392,7 @@ static void test_file_basic_information(void) memset(&fbi, 0, sizeof(fbi)); res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); ok ( res == STATUS_SUCCESS, "can't get attributes\n"); - todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %lx not FILE_ATTRIBUTE_SYSTEM\n", fbi.FileAttributes ); + ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %lx not FILE_ATTRIBUTE_SYSTEM\n", fbi.FileAttributes );
/* Then HIDDEN */ memset(&fbi, 0, sizeof(fbi)); @@ -1405,7 +1405,7 @@ static void test_file_basic_information(void) memset(&fbi, 0, sizeof(fbi)); res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); ok ( res == STATUS_SUCCESS, "can't get attributes\n"); - todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %lx not FILE_ATTRIBUTE_HIDDEN\n", fbi.FileAttributes ); + ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %lx not FILE_ATTRIBUTE_HIDDEN\n", fbi.FileAttributes );
/* Check NORMAL last of all (to make sure we can clear attributes) */ memset(&fbi, 0, sizeof(fbi)); @@ -1462,7 +1462,7 @@ static void test_file_all_information(void) memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res); - todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %lx not FILE_ATTRIBUTE_SYSTEM\n", fai_buf.fai.BasicInformation.FileAttributes ); + ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %lx not FILE_ATTRIBUTE_SYSTEM\n", fai_buf.fai.BasicInformation.FileAttributes );
/* Then HIDDEN */ memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); @@ -1475,7 +1475,7 @@ static void test_file_all_information(void) memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); ok ( res == STATUS_SUCCESS, "can't get attributes\n"); - todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %lx not FILE_ATTRIBUTE_HIDDEN\n", fai_buf.fai.BasicInformation.FileAttributes ); + ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %lx not FILE_ATTRIBUTE_HIDDEN\n", fai_buf.fai.BasicInformation.FileAttributes );
/* Check NORMAL last of all (to make sure we can clear attributes) */ memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index fc8646b020f..1163287b433 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -395,6 +395,17 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si }
+static int xattr_fget( int filedes, const char *name, void *value, size_t size ) +{ +#if defined(HAVE_ATTR_XATTR_H) + return fgetxattr( filedes, name, value, size ); +#else + errno = ENOSYS; + return -1; +#endif +} + + /* get space from the current directory data buffer, allocating a new one if necessary */ static void *get_dir_data_space( struct dir_data *data, unsigned int size ) { @@ -1514,7 +1525,8 @@ static BOOL fd_is_mount_point( int fd, const struct stat *st ) /* 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 ) { - int ret; + char hexattr[11]; + int len, ret;
*attr = 0; ret = fstat( fd, st ); @@ -1523,6 +1535,11 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON /* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */ 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 ); + return ret; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=124165
Your paranoid android.
=== debian11 (32 bit report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit ar:MA report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit de report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit fr report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit he:IL report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit hi:IN report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit ja:JP report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit zh:CN report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit WoW report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (64 bit WoW report) ===
ntdll: file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
From: "Erich E. Hoover" erich.e.hoover@gmail.com
Co-authored-by: Joel Holdsworth joel@airwebreathe.org.uk Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- dlls/ntdll/tests/directory.c | 25 +++++++++--------- dlls/ntdll/unix/file.c | 49 +++++++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 28 deletions(-)
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index 2a5fedb4659..a5ea7900f8d 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -55,7 +55,6 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG *
/* The attribute sets to test */ static struct testfile_s { - BOOL todo; /* set if it doesn't work on wine yet */ BOOL attr_done; /* set if attributes were tested for this file already */ const DWORD attr; /* desired attribute */ WCHAR name[20]; /* filename to use */ @@ -63,16 +62,16 @@ static struct testfile_s { const char *description; /* for error messages */ int nfound; /* How many were found (expect 1) */ } testfiles[] = { - { 0, 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" }, - { 0, 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" }, - { 1, 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" }, - { 1, 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" }, - { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" }, - { 0, 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, - { 0, 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, - { 0, 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, - { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, - { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } + { 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" }, + { 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" }, + { 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" }, + { 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" }, + { 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, + { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } }; static const int test_dir_count = ARRAY_SIZE(testfiles); static const int max_test_dir_size = ARRAY_SIZE(testfiles) + 5; /* size of above plus some for .. etc */ @@ -162,8 +161,8 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info) if (namelen != len || memcmp(nameW, testfiles[i].name, len*sizeof(WCHAR))) continue; if (!testfiles[i].attr_done) { - todo_wine_if (testfiles[i].todo) - ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%lx), got %lx (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib); + ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%lx), got %lx\n", + wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib); testfiles[i].attr_done = TRUE; } testfiles[i].nfound++; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 1163287b433..08b21a86aba 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1544,6 +1544,21 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON }
+static int fd_set_dos_attrib( int fd, ULONG attr ) +{ + /* do not store everything, but keep everything Samba can use */ + attr &= ~FILE_ATTRIBUTE_NORMAL; + if (attr != 0) + { + char hexattr[11]; + int len = sprintf( hexattr, "0x%x", attr ); + return xattr_fset( fd, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); + } + else + return xattr_fremove( fd, SAMBA_XATTR_DOS_ATTRIB ); +} + + /* set the stat info and file attributes for a file (by file descriptor) */ NTSTATUS fd_set_file_info( int fd, ULONG attr ) { @@ -1564,16 +1579,7 @@ NTSTATUS fd_set_file_info( int fd, ULONG attr ) } if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno );
- /* do not store everything, but keep everything Samba can use */ - attr &= ~FILE_ATTRIBUTE_NORMAL; - if (attr != 0) - { - char hexattr[11]; - int len = sprintf( hexattr, "0x%x", attr ); - xattr_fset( fd, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); - } - else - xattr_fremove( fd, SAMBA_XATTR_DOS_ATTRIB ); + fd_set_dos_attrib(fd, attr);
return STATUS_SUCCESS; } @@ -3932,13 +3938,14 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU status = STATUS_SUCCESS; }
- if (status == STATUS_SUCCESS) + if (status != STATUS_SUCCESS) { - status = open_unix_file( handle, unix_name, access, &new_attr, attributes, - sharing, disposition, options, ea_buffer, ea_length ); - free( unix_name ); + WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status ); + return status; } - else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); + + status = open_unix_file( handle, unix_name, access, &new_attr, attributes, + sharing, disposition, options, ea_buffer, ea_length );
if (status == STATUS_SUCCESS) { @@ -3960,6 +3967,17 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU io->Information = FILE_OVERWRITTEN; break; } + + if (io->Information == FILE_CREATED) + { + int fd, needs_close; + + /* set any DOS extended attributes */ + if (!(status = server_get_unix_fd( *handle, 0, &fd, &needs_close, NULL, NULL ))) { + fd_set_dos_attrib( fd, attributes ); + if (needs_close) close( fd ); + } + } } else if (status == STATUS_TOO_MANY_OPENED_FILES) { @@ -3968,6 +3986,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU }
free( nt_name.Buffer ); + free( unix_name ); return io->u.Status = status; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=124166
Your paranoid android.
=== debian11 (32 bit report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0 file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit ar:MA report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0
=== debian11 (32 bit de report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0
=== debian11 (32 bit fr report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0
=== debian11 (32 bit he:IL report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0
=== debian11 (32 bit hi:IN report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0
=== debian11 (32 bit ja:JP report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0
=== debian11 (32 bit zh:CN report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0 file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (32 bit WoW report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0 file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
=== debian11 (64 bit WoW report) ===
ntdll: directory.c:164: Test failed: file L"h.tmp": expected (null) (2), got 0 directory.c:164: Test failed: file L"s.tmp": expected (null) (4), got 0 file.c:1395: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1408: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN file.c:1465: Test failed: attribute 20 not FILE_ATTRIBUTE_SYSTEM file.c:1478: Test failed: attribute 20 not FILE_ATTRIBUTE_HIDDEN
From: "Erich E. Hoover" erich.e.hoover@gmail.com
Co-authored-by: Joel Holdsworth joel@airwebreathe.org.uk Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- configure | 28 ++++++++++++++++++++++++++++ configure.ac | 3 +++ dlls/ntdll/unix/file.c | 19 +++++++++++++++---- include/config.h.in | 6 ++++++ 4 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/configure b/configure index 9c6fb443e1f..46f576c3b14 100755 --- a/configure +++ b/configure @@ -9114,6 +9114,34 @@ then : HAVE_XATTR=1 fi
+done + for ac_header in sys/xattr.h +do : + ac_fn_c_check_header_compile "$LINENO" "sys/xattr.h" "ac_cv_header_sys_xattr_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_xattr_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_XATTR_H 1" >>confdefs.h + HAVE_XATTR=1 + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/xattr.h> +int +main (void) +{ +getxattr("", "", "", 0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +printf "%s\n" "#define XATTR_ADDITIONAL_OPTIONS 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + done
diff --git a/configure.ac b/configure.ac index fd59bd6948d..2bd616d4e02 100644 --- a/configure.ac +++ b/configure.ac @@ -636,6 +636,9 @@ AC_CHECK_HEADERS([libprocstat.h],,, #endif])
AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) +AC_CHECK_HEADERS(sys/xattr.h, [HAVE_XATTR=1] + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/xattr.h>]], [[getxattr("", "", "", 0, 0, 0);]])], + [AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (Mac OS X)])])])
dnl **** Check for working dll ****
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 08b21a86aba..8d159ca4178 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -99,7 +99,10 @@ #include <sys/statfs.h> #endif #ifdef HAVE_ATTR_XATTR_H +#undef XATTR_ADDITIONAL_OPTIONS #include <attr/xattr.h> +#elif defined(HAVE_SYS_XATTR_H) +#include <sys/xattr.h> #endif #include <time.h> #include <unistd.h> @@ -364,7 +367,9 @@ NTSTATUS errno_to_status( int err )
static int xattr_fremove( int filedes, const char *name ) { -#if defined(HAVE_ATTR_XATTR_H) +#if defined(XATTR_ADDITIONAL_OPTIONS) + return fremovexattr( filedes, name, 0 ); +#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) return fremovexattr( filedes, name ); #else errno = ENOSYS; @@ -375,7 +380,9 @@ static int xattr_fremove( int filedes, const char *name )
static int xattr_fset( int filedes, const char *name, void *value, size_t size ) { -#if defined(HAVE_ATTR_XATTR_H) +#if defined(XATTR_ADDITIONAL_OPTIONS) + return fsetxattr( filedes, name, value, size, 0, 0 ); +#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) return fsetxattr( filedes, name, value, size, 0 ); #else errno = ENOSYS; @@ -386,7 +393,9 @@ static int xattr_fset( int filedes, const char *name, void *value, size_t size )
static int xattr_get( const char *path, const char *name, void *value, size_t size ) { -#if defined(HAVE_ATTR_XATTR_H) +#if defined(XATTR_ADDITIONAL_OPTIONS) + return getxattr( path, name, value, size, 0, 0 ); +#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) return getxattr( path, name, value, size ); #else errno = ENOSYS; @@ -397,7 +406,9 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si
static int xattr_fget( int filedes, const char *name, void *value, size_t size ) { -#if defined(HAVE_ATTR_XATTR_H) +#if defined(XATTR_ADDITIONAL_OPTIONS) + return fgetxattr( filedes, name, value, size, 0, 0 ); +#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) return fgetxattr( filedes, name, value, size ); #else errno = ENOSYS; diff --git a/include/config.h.in b/include/config.h.in index 25f09636b3a..f6988317641 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -682,6 +682,9 @@ /* Define to 1 if you have the <sys/vnode.h> header file. */ #undef HAVE_SYS_VNODE_H
+/* Define to 1 if you have the <sys/xattr.h> header file. */ +#undef HAVE_SYS_XATTR_H + /* Define to 1 if you have the `tcdrain' function. */ #undef HAVE_TCDRAIN
@@ -891,6 +894,9 @@ backward compatibility; new code need not use it. */ #undef STDC_HEADERS
+/* Define if xattr functions take additional arguments (Mac OS X) */ +#undef XATTR_ADDITIONAL_OPTIONS + /* Define to 1 if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING
From: "Erich E. Hoover" erich.e.hoover@gmail.com
Co-authored-by: Joel Holdsworth joel@airwebreathe.org.uk Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- configure | 11 +++++++---- configure.ac | 2 +- dlls/ntdll/unix/file.c | 21 ++++++++++++++++++++- include/config.h.in | 3 +++ 4 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/configure b/configure index 46f576c3b14..a0937b39a4e 100755 --- a/configure +++ b/configure @@ -9105,12 +9105,15 @@ then : fi
- for ac_header in attr/xattr.h + for ac_header in attr/xattr.h sys/extattr.h do : - ac_fn_c_check_header_compile "$LINENO" "attr/xattr.h" "ac_cv_header_attr_xattr_h" "$ac_includes_default" -if test "x$ac_cv_header_attr_xattr_h" = xyes + as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test "x$"$as_ac_Header"" = x"yes" then : - printf "%s\n" "#define HAVE_ATTR_XATTR_H 1" >>confdefs.h + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF HAVE_XATTR=1 fi
diff --git a/configure.ac b/configure.ac index 2bd616d4e02..93abc2064e4 100644 --- a/configure.ac +++ b/configure.ac @@ -635,7 +635,7 @@ AC_CHECK_HEADERS([libprocstat.h],,, #include <sys/queue.h> #endif])
-AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) +AC_CHECK_HEADERS(attr/xattr.h sys/extattr.h, [HAVE_XATTR=1]) AC_CHECK_HEADERS(sys/xattr.h, [HAVE_XATTR=1] [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/xattr.h>]], [[getxattr("", "", "", 0, 0, 0);]])], [AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (Mac OS X)])])]) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 8d159ca4178..fa85b99899a 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -104,6 +104,10 @@ #elif defined(HAVE_SYS_XATTR_H) #include <sys/xattr.h> #endif +#ifdef HAVE_SYS_EXTATTR_H +#undef XATTR_ADDITIONAL_OPTIONS +#include <sys/extattr.h> +#endif #include <time.h> #include <unistd.h>
@@ -173,7 +177,14 @@ typedef struct
#define MAX_IGNORED_FILES 4
-#define SAMBA_XATTR_DOS_ATTRIB "user.DOSATTRIB" +#ifndef XATTR_USER_PREFIX +# define XATTR_USER_PREFIX "user." +#endif +#ifndef XATTR_USER_PREFIX_LEN +# define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1) +#endif + +#define SAMBA_XATTR_DOS_ATTRIB XATTR_USER_PREFIX "DOSATTRIB" #define XATTR_ATTRIBS_MASK (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)
struct file_identity @@ -371,6 +382,8 @@ static int xattr_fremove( int filedes, const char *name ) return fremovexattr( filedes, name, 0 ); #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) return fremovexattr( filedes, name ); +#elif defined(HAVE_SYS_EXTATTR_H) + return extattr_delete_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN] ); #else errno = ENOSYS; return -1; @@ -384,6 +397,9 @@ static int xattr_fset( int filedes, const char *name, void *value, size_t size ) return fsetxattr( filedes, name, value, size, 0, 0 ); #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) return fsetxattr( filedes, name, value, size, 0 ); +#elif defined(HAVE_SYS_EXTATTR_H) + return extattr_set_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], + value, size ); #else errno = ENOSYS; return -1; @@ -397,6 +413,9 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si return getxattr( path, name, value, size, 0, 0 ); #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) return getxattr( path, name, value, size ); +#elif defined(HAVE_SYS_EXTATTR_H) + return extattr_get_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], + value, size ); #else errno = ENOSYS; return -1; diff --git a/include/config.h.in b/include/config.h.in index f6988317641..782d6b2a056 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -577,6 +577,9 @@ /* Define to 1 if you have the <sys/event.h> header file. */ #undef HAVE_SYS_EVENT_H
+/* Define to 1 if you have the <sys/extattr.h> header file. */ +#undef HAVE_SYS_EXTATTR_H + /* Define to 1 if you have the <sys/filio.h> header file. */ #undef HAVE_SYS_FILIO_H
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=124168
Your paranoid android.
=== debian11 (32 bit zh:CN report) ===
ntdll: pipe.c:1614: Test failed: pipe is not signaled
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
From: Joel Holdsworth joel@airwebreathe.org.uk
On some BSD-like operating systems including MacOS, FreeBSD and NetBSD, the struct stat structure contains the st_flags member can carry flags of which the following can be used to represent DOS attributes:
* UF_IMMUTABLE can represent FILE_ATTRIBUTE_READONLY * UF_HIDDEN can reprent FILE_ATTRIBUTE_HIDDEN (not available on NetBSD)
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=39366 Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- configure | 15 +++++++++++++++ configure.ac | 7 +++++-- dlls/ntdll/unix/file.c | 34 ++++++++++++++++++++++++++++++++++ include/config.h.in | 6 ++++++ 4 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/configure b/configure index 1b78fe7bcc9..8d2718c7d01 100755 --- a/configure +++ b/configure @@ -9154,6 +9154,7 @@ fi done
+ DLLFLAGS=""
LDDLLFLAGS="" @@ -19691,6 +19692,12 @@ if test "x$ac_cv_func_epoll_create" = xyes then : printf "%s\n" "#define HAVE_EPOLL_CREATE 1" >>confdefs.h
+fi +ac_fn_c_check_func "$LINENO" "fchflags" "ac_cv_func_fchflags" +if test "x$ac_cv_func_fchflags" = xyes +then : + printf "%s\n" "#define HAVE_FCHFLAGS 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "fstatfs" "ac_cv_func_fstatfs" if test "x$ac_cv_func_fstatfs" = xyes @@ -20716,6 +20723,14 @@ then : printf "%s\n" "#define HAVE_STRUCT_STAT___ST_BIRTHTIM 1" >>confdefs.h
+fi +ac_fn_c_check_member "$LINENO" "struct stat" "st_flags" "ac_cv_member_struct_stat_st_flags" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_flags" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_FLAGS 1" >>confdefs.h + + fi
diff --git a/configure.ac b/configure.ac index 3eb38d4c01e..96f89fc260c 100644 --- a/configure.ac +++ b/configure.ac @@ -641,6 +641,7 @@ AC_CHECK_HEADERS(sys/xattr.h, [HAVE_XATTR=1] [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/xattr.h>]], [[getxattr("", "", "", 0, 0, 0);]])], [AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (Mac OS X)])])])
+ dnl **** Check for working dll ****
AC_SUBST(DLLFLAGS,"") @@ -2005,6 +2006,7 @@ ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $BUILTINFLAG" AC_CHECK_FUNCS(\ epoll_create \ + fchflags \ fstatfs \ futimens \ futimes \ @@ -2176,7 +2178,7 @@ AC_CHECK_MEMBERS([struct mtget.mt_blksiz, struct mtget.mt_gstat, struct mtget.mt #include <sys/mtio.h> #endif])
-dnl Check for stat.st_blocks and ns-resolved times +dnl Check for stat.st_blocks, ns-resolved times and flags AC_CHECK_MEMBERS([ struct stat.st_mtim, struct stat.st_mtimespec, @@ -2188,7 +2190,8 @@ AC_CHECK_MEMBERS([ struct stat.st_birthtim, struct stat.st_birthtimespec, struct stat.__st_birthtime, - struct stat.__st_birthtim]) + struct stat.__st_birthtim, + struct stat.st_flags])
dnl Check for sin6_scope_id AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id],,, diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 1c3cfa96cac..c2941f00ef4 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1532,6 +1532,18 @@ static inline ULONG get_file_attributes( const struct stat *st ) attr = FILE_ATTRIBUTE_ARCHIVE; if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) attr |= FILE_ATTRIBUTE_READONLY; + +#ifdef HAVE_STRUCT_STAT_ST_FLAGS +#ifdef UF_HIDDEN + if (st->st_flags & UF_HIDDEN) + attr |= FILE_ATTRIBUTE_HIDDEN; +#endif +#ifdef UF_IMMUTABLE + if (st->st_flags & UF_IMMUTABLE) + attr |= FILE_ATTRIBUTE_READONLY; +#endif +#endif + return attr; }
@@ -1625,6 +1637,23 @@ static int fd_set_fat_attr( int fd, ULONG attr ) #endif
+#ifdef HAVE_FCHFLAGS +static int fd_set_flags( int fd, ULONG attr ) +{ + int flags = 0; +#ifdef UF_HIDDEN + if (attr & FILE_ATTRIBUTE_HIDDEN) + flags |= UF_HIDDEN; +#endif +#ifdef UF_IMMUTABLE + if (attr & FILE_ATTRIBUTE_READONLY) + flags |= UF_IMMUTABLE; +#endif + return fchflags( fd, flags ); +} +#endif + + static int fd_set_xattr_dos_attrib( int fd, ULONG attr ) { /* do not store everything, but keep everything Samba can use */ @@ -1647,6 +1676,11 @@ static void fd_set_dos_attrib( int fd, ULONG attr ) fd_set_fat_attr( fd, attr ); #endif
+#ifdef HAVE_FCHFLAGS + /* try setting equivalent flags on MacOS X and BSD */ + fd_set_flags( fd, attr); +#endif + /* try setting DOS attributes into extended attributes */ fd_set_xattr_dos_attrib( fd, attr ); } diff --git a/include/config.h.in b/include/config.h.in index 286697fef23..b90551c694b 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -65,6 +65,9 @@ /* Define to 1 if you have the `epoll_create' function. */ #undef HAVE_EPOLL_CREATE
+/* Define to 1 if you have the `fchflags' function. */ +#undef HAVE_FCHFLAGS + /* Define to 1 if you have the <float.h> header file. */ #undef HAVE_FLOAT_H
@@ -515,6 +518,9 @@ /* Define to 1 if `st_ctimespec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_CTIMESPEC
+/* Define to 1 if `st_flags' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_FLAGS + /* Define to 1 if `st_mtim' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIM
Hello Joel,
I haven't looked at these patches in detail, largely because there's still outstanding test failures, but I do have one high-level comment, which is that I'd recommend starting with the basic implementation (i.e. just the first four patches), and leave the rest for separate merge requests. Since merge requests can only be applied as a whole I think it makes sense to narrow this down to a more minimal set, and try to get one thing done at a time.