This patch set is based upon [patches from Wine Staging](https://github.com/wine-staging/wine-staging/tree/master/patches/ntdll-DOS_A...) by Erich E. Hoover (@ehoover), and implements support for the `SYSTEM`, `HIDDEN` and `READONLY` DOS file attributes. These can implemented in various ways depending upon the capabilities of the operating system and the file system. However, this initial patch-set focusses on just one method: Samba-formatted Extended File Attributes.
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, and this patch-set implements a compatible mechanism.
Support for additional storage methods to increase operating system and filesystem compatibility is planned for later patch submissions.
This effort is part of a larger project I have been working on to get Msys2 and Cygwin working properly on Wine. The absence of DOS fule attribute support prevents one of the modes that Cygwin and Msys2 can use to emulate symbolic links from working correctly, which causes the Cygwin installer to fail: https://bugs.winehq.org/show_bug.cgi?id=15679
See Also
* https://bugs.winehq.org/show_bug.cgi?id=9158
-- v2: ntdll: Implement storing DOS attributes in NtCreateFile. ntdll: Implement retrieving DOS attributes in NtQueryInformationFile ntdll: Implement storing DOS attributes in NtSetInformationFile. ntdll: Implement retrieving DOS attributes in [fd_]get_file_info().
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 | 29 ++++++++++++++++++ configure.ac | 4 +++ dlls/ntdll/unix/file.c | 68 +++++++++++++++++++++++++++++++++++++++++- include/config.h.in | 6 ++++ 4 files changed, 106 insertions(+), 1 deletion(-)
diff --git a/configure b/configure index 3088184aade..0ff9e72c951 100755 --- a/configure +++ b/configure @@ -9105,6 +9105,35 @@ then : fi
+ 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 +
DLLFLAGS=""
diff --git a/configure.ac b/configure.ac index 1e733962b75..8264c170b87 100644 --- a/configure.ac +++ b/configure.ac @@ -635,6 +635,10 @@ AC_CHECK_HEADERS([libprocstat.h],,, #include <sys/queue.h> #endif])
+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,"") diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 7eb8dbe7ad4..4d58a251e66 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> @@ -98,6 +99,9 @@ #ifdef HAVE_SYS_STATFS_H #include <sys/statfs.h> #endif +#ifdef HAVE_SYS_XATTR_H +#include <sys/xattr.h> +#endif #include <time.h> #include <unistd.h>
@@ -167,6 +171,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 +362,22 @@ NTSTATUS errno_to_status( int err ) } }
+ +static int xattr_get( const char *path, const char *name, void *value, size_t size ) +{ +#if defined(HAVE_SYS_XATTR_H) +#if defined(XATTR_ADDITIONAL_OPTIONS) + return getxattr( path, name, value, size, 0, 0 ); +#else + return getxattr( path, name, value, size ); +#endif +#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 +1474,40 @@ static inline ULONG get_file_attributes( const struct stat *st ) }
+/* decode the xattr-stored DOS attributes */ +static int parse_samba_dos_attrib_data( char *data, int len ) +{ + size_t string_len = strnlen( data, len ); + + if (len > string_len + 3) + { + uint16_t version; + memcpy( &version, data + string_len + 1, 2 ); +#ifndef WORDS_BIGENDIAN + version = (version >> 8) | (version << 8); +#endif + if ( version != 3 ) + { + static BOOL warn = TRUE; + if (warn) + { + FIXME( "Unsupported Samba DOSATTRIB Extended Attribute version: %u\n", + version ); + warn = FALSE; + } + } + } + + if (string_len > 2 && data[0] == '0' && data[1] == 'x') + { + data[len] = 0; + return strtol( data+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 +1536,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 attr_data[65]; + int attr_len, ret;
*attr = 0; ret = lstat( path, st ); @@ -1505,6 +1563,14 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) free( parent_path ); } *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 != ENODATA && errno != ENOTSUP) + WARN( "Failed to get extended attribute " SAMBA_XATTR_DOS_ATTRIB " from "%s". errno %d (%s)\n", + path, errno, strerror( errno ) ); + return ret; }
diff --git a/include/config.h.in b/include/config.h.in index de1bf6c61eb..8f0c27bb265 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -679,6 +679,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
@@ -888,6 +891,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 --- dlls/ntdll/unix/file.c | 97 +++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 4d58a251e66..8709b4eb7ea 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -363,6 +363,36 @@ NTSTATUS errno_to_status( int err ) }
+static int xattr_fremove( int filedes, const char *name ) +{ +#if defined(HAVE_SYS_XATTR_H) +#if defined(XATTR_ADDITIONAL_OPTIONS) + return fremovexattr( filedes, name, 0 ); +#else + return fremovexattr( filedes, name ); +#endif +#else + errno = ENOSYS; + return -1; +#endif +} + + +static int xattr_fset( int filedes, const char *name, const void *value, size_t size ) +{ +#if defined(HAVE_SYS_XATTR_H) +#if defined(XATTR_ADDITIONAL_OPTIONS) + return fsetxattr( filedes, name, value, size, 0, 0 ); +#else + return fsetxattr( filedes, name, value, size, 0 ); +#endif +#else + errno = ENOSYS; + return -1; +#endif +} + + static int xattr_get( const char *path, const char *name, void *value, size_t size ) { #if defined(HAVE_SYS_XATTR_H) @@ -1532,6 +1562,52 @@ 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 ) +{ + /* we only store the HIDDEN and SYSTEM attributes */ + attr &= XATTR_ATTRIBS_MASK; + if (attr != 0) + { + /* encode the attribures in Samba 3 ASCII format. Samba 4 has extended + * this format with more features, but retains compatibility with the + * earlier format. */ + char data[11]; + int len = sprintf( data, "0x%x", attr ); + return xattr_fset( fd, SAMBA_XATTR_DOS_ATTRIB, data, 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 ) +{ + 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 ); + + 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 ) ); + + 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 ) { @@ -4429,7 +4505,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;
@@ -4443,25 +4518,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 | 26 +++++++++++++++++++++++++- 2 files changed, 29 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 8709b4eb7ea..2b00f719e7a 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -408,6 +408,21 @@ 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_SYS_XATTR_H) +#if defined(XATTR_ADDITIONAL_OPTIONS) + return fgetxattr( filedes, name, value, size, 0, 0 ); +#else + return fgetxattr( filedes, name, value, size ); +#endif +#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 ) { @@ -1549,7 +1564,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 attr_data[65]; + int attr_len, ret;
*attr = 0; ret = fstat( fd, st ); @@ -1558,6 +1574,14 @@ 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; + + 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 != ENODATA && errno != ENOTSUP) + WARN( "Failed to get extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)\n", + errno, strerror( errno ) ); + return ret; }
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 | 13 +++++++++++++ 2 files changed, 25 insertions(+), 13 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 2b00f719e7a..00968136266 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4016,6 +4016,19 @@ 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 ))) { + 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 ) ); + if (needs_close) close( fd ); + } + } } else if (status == STATUS_TOO_MANY_OPENED_FILES) {
Here is a new version of the patch-set with the following changes:
* Limited flag storage to `FILE_ATTRIBUTE_HIDDEN` and `FILE_ATTRIBUTE_SYSTEM` * `WARN` if we get something other than ENODATA or ENOTSUP * Handle Samba v4 metadata gracefully
On Thu Sep 29 21:54:26 2022 +0000, Joel Holdsworth wrote:
Here is a new version of the patch-set with the following changes:
- Limited flag storage to `FILE_ATTRIBUTE_HIDDEN` and `FILE_ATTRIBUTE_SYSTEM`
- `WARN` if we get something other than ENODATA or ENOTSUP
- Handle Samba v4 metadata gracefully and print a one-time warning.
@jhol I may be misinterpreting AJ's comment, but I believe that he would like it to not store the xattr (rather than masking the stored value) when the flags are not in the mask list. So, something more like: ``` static int fd_set_dos_attrib( int fd, ULONG attr ) { /* we only store the HIDDEN and SYSTEM attributes */ if ((attr & XATTR_ATTRIBS_MASK) == 0) return 0; ... ```
Joel Holdsworth (@jhol) commented about dlls/ntdll/unix/file.c:
}
+/* decode the xattr-stored DOS attributes */ +static int parse_samba_dos_attrib_data( char *data, int len ) +{
- size_t string_len = strnlen( data, len );
- if (len > string_len + 3)
- {
uint16_t version;
memcpy( &version, data + string_len + 1, 2 );
+#ifndef WORDS_BIGENDIAN
version = (version >> 8) | (version << 8);
+#endif
Ideally this would be done with `ntohs`, but I'm not sure there is a good way to pull it in here without causing chaos. We could `#include <winsock2.h>`, but that seems to conflict with `<sys/socket.h>` and friends.
On Thu Sep 29 21:54:26 2022 +0000, Erich Hoover wrote:
@jhol I may be misinterpreting AJ's comment, but I believe that he would like it to not store the xattr (rather than masking the stored value) when the flags are not in the mask list. So, something more like:
static int fd_set_dos_attrib( int fd, ULONG attr ) { /* we only store the HIDDEN and SYSTEM attributes */ if ((attr & XATTR_ATTRIBS_MASK) == 0) return 0; ...
I'm not sure I quite follow what you mean. This is the full definition of the function:
``` static int fd_set_dos_attrib( int fd, ULONG attr ) { /* we only store the HIDDEN and SYSTEM attributes */ attr &= XATTR_ATTRIBS_MASK; if (attr != 0) { /* encode the attribures in Samba 3 ASCII format. Samba 4 has extended * this format with more features, but retains compatibility with the * earlier format. */ char data[11]; int len = sprintf( data, "0x%x", attr ); return xattr_fset( fd, SAMBA_XATTR_DOS_ATTRIB, data, len ); } else return xattr_fremove( fd, SAMBA_XATTR_DOS_ATTRIB ); } ```
If, after masking out everything except `HIDDEN` and `SYSTEM`, the value of `attr` is now zero, the attribute will be removed from the file.
On Fri Sep 30 12:06:00 2022 +0000, Joel Holdsworth wrote:
I'm not sure I quite follow what you mean. This is the full definition of the function:
static int fd_set_dos_attrib( int fd, ULONG attr ) { /* we only store the HIDDEN and SYSTEM attributes */ attr &= XATTR_ATTRIBS_MASK; if (attr != 0) { /* encode the attribures in Samba 3 ASCII format. Samba 4 has extended * this format with more features, but retains compatibility with the * earlier format. */ char data[11]; int len = sprintf( data, "0x%x", attr ); return xattr_fset( fd, SAMBA_XATTR_DOS_ATTRIB, data, len ); } else return xattr_fremove( fd, SAMBA_XATTR_DOS_ATTRIB ); }
If, after masking out everything except `HIDDEN` and `SYSTEM`, the value of `attr` is now zero, the attribute will be removed from the file.
@jhol Apparently I did not read closely enough, sorry about that.
On Fri Sep 30 12:00:09 2022 +0000, Joel Holdsworth wrote:
Ideally this would be done with `ntohs`, but I'm not sure there is a good way to pull it in here without causing chaos. We could `#include <winsock2.h>`, but that seems to conflict with `<sys/socket.h>` and friends.
@jhol You are on the Unix side of the line, so for `ntohs` you want: ``` #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif ```