Add the STREAMINFO vfs call
authorVolker Lendecke <vl@samba.org>
Sat, 19 Jan 2008 19:41:15 +0000 (20:41 +0100)
committerVolker Lendecke <vl@samba.org>
Sat, 19 Jan 2008 21:58:17 +0000 (22:58 +0100)
Based on jpeach's work, modified the streaminfo prototype

Make use of it in trans2.c together with marshall_stream_info()
(This used to be commit c34d729c7c0600a8f11bf7e489a634a4e37fe88e)

source3/include/vfs.h
source3/include/vfs_macros.h
source3/modules/vfs_default.c
source3/smbd/trans2.c

index 3109a5c3e4d6a4348e2c5aabbb7168e58d785764..cda28a1680bd6352a7e28db982b3b5b7d4d7eb63 100644 (file)
 /* Leave at 22 - not yet released. Remove parameter fromfd from sendfile. - obnox */
 /* Leave at 22 - not yet released. Remove parameter fromfd from recvfile. - obnox */
 /* Leave at 22 - not yet released. Additional change: add operations for offline files -- ab */
+/* Leave at 22 - not yet released. Add the streaminfo call. -- jpeach, vl */
 
 #define SMB_VFS_INTERFACE_VERSION 22
 
@@ -198,6 +199,7 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_NOTIFY_WATCH,
        SMB_VFS_OP_CHFLAGS,
        SMB_VFS_OP_FILE_ID_CREATE,
+       SMB_VFS_OP_STREAMINFO,
 
        /* NT ACL operations. */
 
@@ -339,6 +341,13 @@ struct vfs_ops {
                int (*chflags)(struct vfs_handle_struct *handle, const char *path, unsigned int flags);
                struct file_id (*file_id_create)(struct vfs_handle_struct *handle, SMB_DEV_T dev, SMB_INO_T inode);
 
+               NTSTATUS (*streaminfo)(struct vfs_handle_struct *handle,
+                                      struct files_struct *fsp,
+                                      const char *fname,
+                                      TALLOC_CTX *mem_ctx,
+                                      unsigned int *num_streams,
+                                      struct stream_struct **streams);
+
                /* NT ACL operations. */
 
                NTSTATUS (*fget_nt_acl)(struct vfs_handle_struct *handle,
@@ -476,6 +485,7 @@ struct vfs_ops {
                struct vfs_handle_struct *notify_watch;
                struct vfs_handle_struct *chflags;
                struct vfs_handle_struct *file_id_create;
+               struct vfs_handle_struct *streaminfo;
 
                /* NT ACL operations. */
 
index dd30f977dc8adb5fbeb65da269e6f21d6b1c3ca9..1674f26326411d94fa012b91a882aab0b3a166f0 100644 (file)
@@ -82,6 +82,7 @@
 #define SMB_VFS_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs.ops.notify_watch((conn)->vfs.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 #define SMB_VFS_CHFLAGS(conn, path, flags) ((conn)->vfs.ops.chflags((conn)->vfs.handles.chflags, (path), (flags)))
 #define SMB_VFS_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops.file_id_create((conn)->vfs.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs.ops.streaminfo((conn)->vfs.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
 
 /* NT ACL operations. */
 #define SMB_VFS_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs.ops.fget_nt_acl((fsp)->conn->vfs.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
 #define SMB_VFS_OPAQUE_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_opaque.ops.notify_watch((conn)->vfs_opaque.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 #define SMB_VFS_OPAQUE_CHFLAGS(conn, path, flags) ((conn)->vfs_opaque.ops.chflags((conn)->vfs_opaque.handles.chflags, (path), (flags)))
 #define SMB_VFS_OPAQUE_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops_opaque.file_id_create((conn)->vfs_opaque.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_OPAQUE_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs_opaque.ops.streaminfo((conn)->vfs_opaque.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
 
 /* NT ACL operations. */
 #define SMB_VFS_OPAQUE_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs_opaque.ops.fget_nt_acl((fsp)->conn->vfs_opaque.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
 #define SMB_VFS_NEXT_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_next.ops.notify_watch((conn)->vfs_next.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 #define SMB_VFS_NEXT_CHFLAGS(handle, path, flags) ((handle)->vfs_next.ops.chflags((handle)->vfs_next.handles.chflags, (path), (flags)))
 #define SMB_VFS_NEXT_FILE_ID_CREATE(handle, dev, inode) ((handle)->vfs_next.ops.file_id_create((handle)->vfs_next.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, num_streams, streams) ((handle)->vfs.ops.streaminfo((handle)->vfs.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
 
 /* NT ACL operations. */
 #define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc) ((handle)->vfs_next.ops.fget_nt_acl((handle)->vfs_next.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
index 31234f23ecfc86b2edf66d9e62e69bfb216410b8..2e620d04cc0ecd4aea6e30ac520acef971cf474c 100644 (file)
@@ -942,6 +942,63 @@ static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, S
        return file_id_create_dev(dev, inode);
 }
 
+static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
+                                  struct files_struct *fsp,
+                                  const char *fname,
+                                  TALLOC_CTX *mem_ctx,
+                                  unsigned int *pnum_streams,
+                                  struct stream_struct **pstreams)
+{
+       SMB_STRUCT_STAT sbuf;
+       NTSTATUS status;
+       unsigned int num_streams = 0;
+       struct stream_struct *streams = NULL;
+       int ret;
+
+       if ((fsp != NULL) && (fsp->is_directory)) {
+               /*
+                * No default streams on directories
+                */
+               goto done;
+       }
+
+       if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+               ret = SMB_VFS_FSTAT(fsp, &sbuf);
+       }
+       else {
+               ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
+       }
+
+       if (ret == -1) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       if (S_ISDIR(sbuf.st_mode)) {
+               goto done;
+       }
+
+       streams = talloc(mem_ctx, struct stream_struct);
+
+       if (streams == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       streams->size = sbuf.st_size;
+       streams->alloc_size = get_allocation_size(handle->conn, fsp, &sbuf);
+
+       streams->name = talloc_strdup(streams, "::$DATA");
+       if (streams->name == NULL) {
+               TALLOC_FREE(streams);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       num_streams = 1;
+ done:
+       *pnum_streams = num_streams;
+       *pstreams = streams;
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
                                    files_struct *fsp,
                                    uint32 security_info, SEC_DESC **ppdesc)
@@ -1367,6 +1424,8 @@ static vfs_op_tuple vfs_default_ops[] = {
         SMB_VFS_LAYER_OPAQUE},
        {SMB_VFS_OP(vfswrap_file_id_create),    SMB_VFS_OP_FILE_ID_CREATE,
         SMB_VFS_LAYER_OPAQUE},
+       {SMB_VFS_OP(vfswrap_streaminfo),        SMB_VFS_OP_STREAMINFO,
+        SMB_VFS_LAYER_OPAQUE},
 
        /* NT ACL operations. */
 
index 53eff65b548f03ed8a2dfd9dab51a87e41ec86b1..d56a0dab09659e257b8c66899de8446e304062d7 100644 (file)
@@ -5,7 +5,7 @@
    Copyright (C) Stefan (metze) Metzmacher     2003
    Copyright (C) Volker Lendecke               2005-2007
    Copyright (C) Steve French                  2005
-   Copyright (C) James Peach                   2007
+   Copyright (C) James Peach                   2006-2007
 
    Extensively modified by Andrew Tridgell, 1995
 
@@ -3568,6 +3568,72 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
        return pdata;
 }
 
+static NTSTATUS marshall_stream_info(unsigned int num_streams,
+                                    const struct stream_struct *streams,
+                                    char *data,
+                                    unsigned int max_data_bytes,
+                                    unsigned int *data_size)
+{
+       unsigned int i;
+       unsigned int ofs = 0;
+
+       for (i=0; i<num_streams; i++) {
+               unsigned int next_offset;
+               size_t namelen;
+               smb_ucs2_t *namebuf;
+
+               namelen = push_ucs2_talloc(talloc_tos(), &namebuf,
+                                           streams[i].name);
+
+               if ((namelen == (size_t)-1) || (namelen <= 2)) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               /*
+                * name_buf is now null-terminated, we need to marshall as not
+                * terminated
+                */
+
+               namelen -= 2;
+
+               if (ofs + 24 + namelen > max_data_bytes) {
+                       TALLOC_FREE(namebuf);
+                       return NT_STATUS_BUFFER_TOO_SMALL;
+               }
+
+               SIVAL(data, ofs+4, namelen);
+               SOFF_T(data, ofs+8, streams[i].size);
+               SOFF_T(data, ofs+16, streams[i].alloc_size);
+               memcpy(data+ofs+24, namebuf, namelen);
+               TALLOC_FREE(namebuf);
+
+               next_offset = ofs + 24 + namelen;
+
+               if (i == num_streams-1) {
+                       SIVAL(data, ofs, 0);
+               }
+               else {
+                       unsigned int align = ndr_align_size(next_offset, 8);
+
+                       if (next_offset + align > max_data_bytes) {
+                               return NT_STATUS_BUFFER_TOO_SMALL;
+                       }
+
+                       memset(data+next_offset, 0, align);
+                       next_offset += align;
+
+                       SIVAL(data, ofs, next_offset - ofs);
+                       ofs = next_offset;
+               }
+
+               ofs = next_offset;
+       }
+
+       *data_size = ofs;
+
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Reply to a TRANSACT2_QFILEINFO on a PIPE !
 ****************************************************************************/
@@ -4273,20 +4339,40 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                 */
                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;
+               case SMB_FILE_STREAM_INFORMATION: {
+                       unsigned int num_streams;
+                       struct stream_struct *streams;
+                       NTSTATUS status;
+
+                       DEBUG(10,("call_trans2qfilepathinfo: "
+                                 "SMB_FILE_STREAM_INFORMATION\n"));
+
+                       status = SMB_VFS_STREAMINFO(
+                               conn, fsp, fname, talloc_tos(),
+                               &num_streams, &streams);
+
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(10, ("could not get stream info: %s\n",
+                                          nt_errstr(status)));
+                               reply_nterror(req, status);
+                               return;
                        }
-                       break;
 
+                       status = marshall_stream_info(num_streams, streams,
+                                                     pdata, max_data_bytes,
+                                                     &data_size);
+
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(10, ("marshall_stream_info failed: %s\n",
+                                          nt_errstr(status)));
+                               reply_nterror(req, status);
+                               return;
+                       }
+
+                       TALLOC_FREE(streams);
+
+                       break;
+               }
                case SMB_QUERY_COMPRESSION_INFO:
                case SMB_FILE_COMPRESSION_INFORMATION:
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));