diff options
-rw-r--r-- | source3/include/vfs.h | 10 | ||||
-rw-r--r-- | source3/include/vfs_macros.h | 3 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 59 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 112 |
4 files changed, 171 insertions, 13 deletions
diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 3109a5c3e4..cda28a1680 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -104,6 +104,7 @@ /* 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. */ diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index dd30f977dc..1674f26326 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -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))) @@ -206,6 +207,7 @@ #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))) @@ -331,6 +333,7 @@ #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))) diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 31234f23ec..2e620d04cc 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -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. */ diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 53eff65b54..d56a0dab09 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -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")); |