diff --git a/configure b/configure index 3088184aade..2efb2a37011 100755 --- a/configure +++ b/configure @@ -8323,6 +8323,12 @@ if test "x$ac_cv_header_sys_vnode_h" = xyes then : printf "%s\n" "#define HAVE_SYS_VNODE_H 1" >>confdefs.h +fi +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 + fi ac_fn_c_check_header_compile "$LINENO" "syscall.h" "ac_cv_header_syscall_h" "$ac_includes_default" if test "x$ac_cv_header_syscall_h" = xyes @@ -9105,6 +9111,40 @@ then : fi +if test "x$ac_cv_header_sys_xattr_h" = xyes +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getxattr takes additional arguments" >&5 +printf %s "checking whether getxattr takes additional arguments... " >&6; } +if test ${wine_cv_xattr_extra_args+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ +getxattr("", "", "", 0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + wine_cv_xattr_extra_args=yes +else $as_nop + wine_cv_xattr_extra_args=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_xattr_extra_args" >&5 +printf "%s\n" "$wine_cv_xattr_extra_args" >&6; } + test $wine_cv_xattr_extra_args != yes || +printf "%s\n" "#define XATTR_ADDITIONAL_OPTIONS 1" >>confdefs.h + +fi + DLLFLAGS="" diff --git a/configure.ac b/configure.ac index 1e733962b75..41a29cee398 100644 --- a/configure.ac +++ b/configure.ac @@ -494,6 +494,7 @@ AC_CHECK_HEADERS(\ sys/user.h \ sys/utsname.h \ sys/vnode.h \ + sys/xattr.h \ syscall.h \ utime.h \ valgrind/memcheck.h \ @@ -635,6 +636,14 @@ AC_CHECK_HEADERS([libprocstat.h],,, #include #endif]) +if test "x$ac_cv_header_sys_xattr_h" = xyes +then + AC_CACHE_CHECK([whether getxattr takes additional arguments], wine_cv_xattr_extra_args, + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[getxattr("", "", "", 0, 0, 0);]])], + [wine_cv_xattr_extra_args=yes],[wine_cv_xattr_extra_args=no])]) + test $wine_cv_xattr_extra_args != yes || AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (macOS)]) +fi + dnl **** Check for working dll **** AC_SUBST(DLLFLAGS,"") diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 7eb8dbe7ad4..34bba9657b6 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,9 @@ #ifdef HAVE_SYS_STATFS_H #include #endif +#ifdef HAVE_SYS_XATTR_H +#include +#endif #include #include @@ -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 ) +{ +#ifdef HAVE_SYS_XATTR_H +# ifdef 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,27 @@ 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 ) +{ + char *end; + int val; + + if (len > 2 && data[0] == '0' && data[1] == 'x') + { + data[len] = 0; + val = strtol( data, &end, 16 ); + if (!*end) return val & XATTR_ATTRIBS_MASK; + } + else + { + static BOOL once; + if (!once++) FIXME( "Unhandled " SAMBA_XATTR_DOS_ATTRIB " extended attribute value.\n" ); + } + return 0; +} + + static BOOL fd_is_mount_point( int fd, const struct stat *st ) { struct stat parent; @@ -1479,7 +1523,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 +1550,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..694b11cf8c2 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -679,6 +679,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_VNODE_H +/* Define to 1 if you have the 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 (macOS) */ +#undef XATTR_ADDITIONAL_OPTIONS + /* Define to 1 if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING