From 29333aaab5e4d2b62741a8321382b24f1630eb70 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 20 Aug 2014 15:28:00 -0600
Subject: [PATCH] ntdll: Implement storing DOS attributes in NtCreateFile.

---
 dlls/ntdll/tests/directory.c | 24 +++++++++++-------------
 dlls/ntdll/unix/file.c       | 31 ++++++++++++++++++++++++++-----
 include/wine/port.h          |  2 ++
 libs/port/xattr.c            | 20 ++++++++++++++++++++
 4 files changed, 59 insertions(+), 18 deletions(-)

diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c
index 248ed99ab20..e0f4debc624 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,7 @@ 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 (%x), got %x (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 (%x), got %x (is your linux new enough?)\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 7ab1c130bf2..7c737edd22c 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3549,6 +3549,20 @@ void CDECL set_show_dot_files( BOOL enable )
     show_dot_files = enable;
 }
 
+NTSTATUS set_file_info( const char *path, ULONG attr )
+{
+    char hexattr[11];
+    int len;
+
+    /* Note: unix mode already set when called this way */
+    attr &= ~FILE_ATTRIBUTE_NORMAL; /* do not store everything, but keep everything Samba can use */
+    len = sprintf( hexattr, "0x%x", attr );
+    if (attr != 0)
+        xattr_set( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, len );
+    else
+        xattr_remove( path, SAMBA_XATTR_DOS_ATTRIB );
+    return STATUS_SUCCESS;
+}
 
 /******************************************************************************
  *              open_unix_file
@@ -3636,13 +3650,14 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
         io->u.Status = STATUS_SUCCESS;
     }
 
-    if (io->u.Status == STATUS_SUCCESS)
+    if (io->u.Status != STATUS_SUCCESS)
     {
-        io->u.Status = open_unix_file( handle, unix_name, access, 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 io->u.Status;
     }
-    else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status );
+
+    io->u.Status = open_unix_file( handle, unix_name, access, attr, attributes,
+                                   sharing, disposition, options, ea_buffer, ea_length );
 
     if (io->u.Status == STATUS_SUCCESS)
     {
@@ -3664,6 +3679,11 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
             io->Information = FILE_OVERWRITTEN;
             break;
         }
+        if (io->Information == FILE_CREATED)
+        {
+            /* set any DOS extended attributes */
+            set_file_info( unix_name, attributes );
+        }
     }
     else if (io->u.Status == STATUS_TOO_MANY_OPENED_FILES)
     {
@@ -3671,6 +3691,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
         if (!once++) ERR_(winediag)( "Too many open files, ulimit -n probably needs to be increased\n" );
     }
 
+    free( unix_name );
     return io->u.Status;
 }
 
diff --git a/include/wine/port.h b/include/wine/port.h
index e0249b4c59f..930efeeea1f 100644
--- a/include/wine/port.h
+++ b/include/wine/port.h
@@ -362,6 +362,8 @@ extern int xattr_fget( int filedes, const char *name, void *value, size_t size )
 extern int xattr_fremove( int filedes, const char *name );
 extern int xattr_fset( int filedes, const char *name, void *value, size_t size );
 extern int xattr_get( const char *path, const char *name, void *value, size_t size );
+extern int xattr_remove( const char *path, const char *name );
+extern int xattr_set( const char *path, const char *name, void *value, size_t size );
 
 #else /* NO_LIBWINE_PORT */
 
diff --git a/libs/port/xattr.c b/libs/port/xattr.c
index 6918c9956cc..683e7a615e2 100644
--- a/libs/port/xattr.c
+++ b/libs/port/xattr.c
@@ -67,3 +67,23 @@ int xattr_get( const char *path, const char *name, void *value, size_t size )
     return -1;
 #endif
 }
+
+int xattr_remove( const char *path, const char *name )
+{
+#if defined(HAVE_ATTR_XATTR_H)
+    return removexattr( path, name );
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int xattr_set( const char *path, const char *name, void *value, size_t size )
+{
+#if defined(HAVE_ATTR_XATTR_H)
+    return setxattr( path, name, value, size, 0 );
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
-- 
2.27.0

