Add SMB protocol support for streaminfo.
authorJames Peach <jpeach@apple.com>
Mon, 15 Oct 2007 21:35:23 +0000 (14:35 -0700)
committerJames Peach <jpeach@apple.com>
Mon, 15 Oct 2007 21:35:23 +0000 (14:35 -0700)
This patch implements the SMB protocol support for the streaminfo
call. It also alters the SMB filesystem capabilities call to correctly
report whether NTFS streams are supported.

source/smbd/trans2.c

index 6b633cfe4b3f63be93624c97e0377dcc38ac2697..d266b95e5450d5e80bc33b949dc890fec9596b22 100644 (file)
@@ -5,7 +5,7 @@
    Copyright (C) Stefan (metze) Metzmacher     2003
    Copyright (C) Volker Lendecke               2005
    Copyright (C) Steve French                  2005
-   Copyright (C) James Peach                   2007
+   Copyright (C) James Peach                   2006-2007
 
    Extensively modified by Andrew Tridgell, 1995
 
@@ -2235,7 +2235,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
        const char *vname = volume_label(SNUM(conn));
        int snum = SNUM(conn);
        char *fstype = lp_fstype(SNUM(conn));
-       int quota_flag = 0;
+       int fs_attribute_flags = 0;
 
        if (total_params < 2) {
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
@@ -2319,14 +2319,23 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsi
                case SMB_QUERY_FS_ATTRIBUTE_INFO:
                case SMB_FS_ATTRIBUTE_INFORMATION:
 
+                       fs_attribute_flags =
+                               FILE_CASE_SENSITIVE_SEARCH |
+                               FILE_CASE_PRESERVED_NAMES;
 
 #if defined(HAVE_SYS_QUOTAS)
-                       quota_flag = FILE_VOLUME_QUOTAS;
+                       fs_attribute_flags |= FILE_VOLUME_QUOTAS;
 #endif
+                       if (lp_stream_support(SNUM(conn)) &&
+                           (conn->fs_capabilities & FILE_NAMED_STREAMS)) {
+                               fs_attribute_flags |= FILE_NAMED_STREAMS;
+                       }
+
+                       if (lp_nt_acl_support(SNUM(conn)) ) {
+                               fs_attribute_flags |= FILE_PERSISTENT_ACLS;
+                       }
 
-                       SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
-                               (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)|
-                               quota_flag); /* FS ATTRIBUTES */
+                       SIVAL(pdata, 0, fs_attribute_flags); /* FS ATTRIBUTES */
 
                        SIVAL(pdata,4,255); /* Max filename component length */
                        /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
@@ -2675,7 +2684,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                         * Thursby MAC extension... ONLY on NTFS filesystems
                         * once we do streams then we don't need this
                         */
-                       if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
+                       if (!lp_stream_support(SNUM(conn)) &&
+                           strequal(lp_fstype(SNUM(conn)),"NTFS")) {
                                data_len = 88;
                                SIVAL(pdata,84,0x100); /* Don't support mac... */
                                break;
@@ -3139,6 +3149,104 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
        return pdata;
 }
 
+static unsigned int marshall_stream_info(connection_struct *conn,
+                           files_struct *fsp,
+                           const char *fname,
+                           int dosmode,
+                           SMB_BIG_UINT file_data_size,
+                           SMB_BIG_UINT file_data_allocation,
+                           char *pdata)
+{
+       unsigned int data_size = 0;
+       unsigned nextOffset = 0;
+       int count = 0;
+       int curr = 0;
+       char * namelist = NULL;
+       size_t * sizelist = NULL;
+
+       char * name;
+
+       size_t byte_len = 0;
+
+       if (!(dosmode & aDIR)) {
+           /* Don't show ::$DATA for directories. If we do, the XP copy engine
+            * tries to copy it, which results in all sorts of interesting
+            * phenomena.
+            */
+               byte_len += dos_PutUniCode(pdata + 24,"::$DATA",
+                                       (size_t)0xE, False);
+               SIVAL(pdata, nextOffset, 0); /* might overwrite this if
+                                                   more streams */
+               SIVAL(pdata,  4, byte_len); /* Byte length of unicode
+                                                   string ::$DATA */
+               SOFF_T(pdata, 8, file_data_size);
+               SIVAL(pdata, 16, file_data_allocation);
+               SIVAL(pdata, 20, 0); /* ??? */
+               data_size = 24 + byte_len;
+       }
+
+       count = SMB_VFS_STREAMINFO(conn, fsp, fname,
+                           &namelist, &sizelist);
+       if (count <= 0) {
+               return data_size;
+       }
+
+       DEBUG(4, ("streaminfo on %s gave %d streams\n",
+           fsp ? fsp->fsp_name : fname, count));
+
+       for (name = namelist, curr = 0; curr < count; ++curr ) {
+               size_t nlen = strlen(name);
+
+/* TDB_ALIGN, renamed to avoid clashes. */
+#define STREAMINFO_ALIGN(x, a) (((x) + (a)-1) & ~((a)-1))
+
+               /* update the previous record's next
+                * record offset ...
+                */
+               data_size = STREAMINFO_ALIGN(data_size, 8);
+               SIVAL(pdata, nextOffset, data_size - nextOffset);
+
+#undef STREAMINFO_ALIGN
+
+               DEBUG(4, ("pushing name=%s size=%u\n",
+                       name, (unsigned)sizelist[curr]));
+
+               /* remember where the next record offset
+                * field is for this record ...
+                */
+               nextOffset = data_size;
+               /* make sure it's clear ... */
+               SIVAL(pdata, nextOffset, 0);
+
+               /* now insert the new record .. */
+
+               byte_len = dos_PutUniCode(pdata + data_size + 24,
+                           name, nlen * 2, False);
+
+               /* add stream name length ... */
+               SIVAL(pdata, 4 + data_size, byte_len);
+
+               /* add stream size ... */
+               SOFF_T(pdata, 8 + data_size, (SMB_OFF_T)sizelist[curr]);
+
+               /* allocation size is the same as the
+                * stream size ...
+                */
+               SOFF_T(pdata,16 + data_size, (SMB_OFF_T)sizelist[curr]);
+               SIVAL(pdata, 20 + data_size, 0); /*??*/
+
+               data_size += 24 + byte_len;
+
+               /* Skip to next name. */
+               name += (nlen + 1);
+       }
+
+       SAFE_FREE(namelist);
+       SAFE_FREE(sizelist);
+
+       return data_size;
+}
+
 /****************************************************************************
  Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
  file name or file id).
@@ -3698,26 +3806,20 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        data_size = 4;
                        break;
 
-#if 0
                /*
-                * NT4 server just returns "invalid query" to this - if we try to answer
-                * it then NTws gets a BSOD! (tridge).
+                * NT4 server just returns "invalid query" to this - if we
+                * try to answer it then NTws gets a BSOD! (tridge).
                 * W2K seems to want this. JRA.
                 */
+               /* The first statement above is false - verified using Thursby
+                * client against NT4 -- gcolley.
+                */
                case SMB_QUERY_FILE_STREAM_INFO:
-#endif
                case SMB_FILE_STREAM_INFORMATION:
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STREAM_INFORMATION\n"));
-                       if (mode & aDIR) {
-                               data_size = 0;
-                       } else {
-                               size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", (size_t)0xE, False);
-                               SIVAL(pdata,0,0); /* ??? */
-                               SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
-                               SOFF_T(pdata,8,file_size);
-                               SOFF_T(pdata,16,allocation_size);
-                               data_size = 24 + byte_len;
-                       }
+                       data_size = marshall_stream_info(conn, fsp,
+                                               fname, mode, file_size,
+                                               allocation_size, pdata);
                        break;
 
                case SMB_QUERY_COMPRESSION_INFO: