diff options
author | Tim Prouty <tprouty@samba.org> | 2009-06-22 15:26:56 -0700 |
---|---|---|
committer | Tim Prouty <tprouty@samba.org> | 2009-06-24 21:15:25 -0700 |
commit | e129384d7c1df664e447186673dd107e190e2894 (patch) | |
tree | 166c08e9d2ee0bbb8a88fb2ad76ed226a62f83dc /source3 | |
parent | 36c10191750c845a2a7cd6cc62149b1095c0b651 (diff) | |
download | samba-e129384d7c1df664e447186673dd107e190e2894.tar.gz samba-e129384d7c1df664e447186673dd107e190e2894.tar.bz2 samba-e129384d7c1df664e447186673dd107e190e2894.zip |
s3: Plumb smb_filename through SMB_VFS_STAT and SMB_VFS_LSTAT
This patch introduces two new temporary helper functions
vfs_stat_smb_fname and vfs_lstat_smb_fname. They basically allowed me
to call the new smb_filename version of stat, while avoiding plumbing
it through callers that are still too inconvenient. As the conversion
moves along, I will be able to remove callers of this, with the goal
being to remove all callers.
There was also a bug in create_synthetic_smb_fname_split (also a
temporary utility function) that caused it to incorrectly handle
filenames with ':'s in them when in posix mode. This is now fixed.
Diffstat (limited to 'source3')
36 files changed, 1142 insertions, 658 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index ffd2858594..d55d6c1976 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -3508,7 +3508,6 @@ bool release_posix_lock_posix_flavour(files_struct *fsp, /* The following definitions come from modules/vfs_default.c */ -int vfswrap_lstat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf); ssize_t vfswrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size); ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size); NTSTATUS vfs_default_init(void); @@ -6336,11 +6335,13 @@ NTSTATUS close_fake_file(struct smb_request *req, files_struct *fsp); /* The following definitions come from smbd/file_access.c */ bool can_access_file_acl(struct connection_struct *conn, - const char * fname, - uint32_t access_mask); + const struct smb_filename *smb_fname, + uint32_t access_mask); bool can_delete_file_in_directory(connection_struct *conn, - const struct smb_filename *smb_fname); -bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf, uint32 access_mask); + struct smb_filename *smb_fname); +bool can_access_file_data(connection_struct *conn, + const struct smb_filename *smb_fname, + uint32 access_mask); bool can_write_to_file(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf); bool directory_has_default_acl(connection_struct *conn, const char *fname); @@ -6366,12 +6367,16 @@ NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_f char **full_name); NTSTATUS create_synthetic_smb_fname(TALLOC_CTX *ctx, const char *base_name, const char *stream_name, - SMB_STRUCT_STAT *psbuf, + const SMB_STRUCT_STAT *psbuf, struct smb_filename **smb_fname_out); NTSTATUS create_synthetic_smb_fname_split(TALLOC_CTX *ctx, const char *fname, - SMB_STRUCT_STAT *psbuf, + const SMB_STRUCT_STAT *psbuf, struct smb_filename **smb_fname_out); +int vfs_stat_smb_fname(struct connection_struct *conn, const char *fname, + SMB_STRUCT_STAT *psbuf); +int vfs_lstat_smb_fname(struct connection_struct *conn, const char *fname, + SMB_STRUCT_STAT *psbuf); const char *smb_fname_str_dbg(const struct smb_filename *smb_fname); NTSTATUS copy_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname_in, @@ -7137,8 +7142,6 @@ void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp); void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp); void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp); bool smbd_vfs_init(connection_struct *conn); -bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st); -bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf); NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname); ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count); ssize_t vfs_pread_data(files_struct *fsp, char *buf, diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 53a4798d37..2a0c5ec805 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -118,7 +118,7 @@ /* Leave at 25 - not yet released. Add locking calls. -- zkirsch. */ /* Leave at 25 - not yet released. Add strict locking calls. -- drichards. */ /* Changed to version 26 - Plumb struct smb_filename to SMB_VFS_CREATE_FILE, - SMB_VFS_OPEN. */ + SMB_VFS_OPEN, SMB_VFS_STAT, SMB_VFS_LSTAT. */ #define SMB_VFS_INTERFACE_VERSION 26 @@ -359,9 +359,9 @@ struct vfs_ops { ssize_t (*recvfile)(struct vfs_handle_struct *handle, int fromfd, files_struct *tofsp, SMB_OFF_T offset, size_t count); int (*rename)(struct vfs_handle_struct *handle, const char *oldname, const char *newname); int (*fsync)(struct vfs_handle_struct *handle, struct files_struct *fsp); - int (*stat)(struct vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf); + int (*stat)(struct vfs_handle_struct *handle, struct smb_filename *smb_fname); int (*fstat)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_STAT *sbuf); - int (*lstat)(struct vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf); + int (*lstat)(struct vfs_handle_struct *handle, struct smb_filename *smb_filename); uint64_t (*get_alloc_size)(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_STAT *sbuf); int (*unlink)(struct vfs_handle_struct *handle, const char *path); int (*chmod)(struct vfs_handle_struct *handle, const char *path, mode_t mode); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index d888361dc4..b0a0737aac 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -60,9 +60,9 @@ #define SMB_VFS_RECVFILE(fromfd, tofsp, offset, count) ((tofsp)->conn->vfs.ops.recvfile((tofsp)->conn->vfs.handles.recvfile, (fromfd), (tofsp), (offset), (count))) #define SMB_VFS_RENAME(conn, old, new) ((conn)->vfs.ops.rename((conn)->vfs.handles.rename, (old), (new))) #define SMB_VFS_FSYNC(fsp) ((fsp)->conn->vfs.ops.fsync((fsp)->conn->vfs.handles.fsync, (fsp))) -#define SMB_VFS_STAT(conn, fname, sbuf) ((conn)->vfs.ops.stat((conn)->vfs.handles.stat, (fname), (sbuf))) +#define SMB_VFS_STAT(conn, smb_fname) ((conn)->vfs.ops.stat((conn)->vfs.handles.stat, (smb_fname))) #define SMB_VFS_FSTAT(fsp, sbuf) ((fsp)->conn->vfs.ops.fstat((fsp)->conn->vfs.handles.fstat, (fsp), (sbuf))) -#define SMB_VFS_LSTAT(conn, path, sbuf) ((conn)->vfs.ops.lstat((conn)->vfs.handles.lstat, (path), (sbuf))) +#define SMB_VFS_LSTAT(conn, smb_fname) ((conn)->vfs.ops.lstat((conn)->vfs.handles.lstat, (smb_fname))) #define SMB_VFS_GET_ALLOC_SIZE(conn, fsp, sbuf) ((conn)->vfs.ops.get_alloc_size((conn)->vfs.handles.get_alloc_size, (fsp), (sbuf))) #define SMB_VFS_UNLINK(conn, path) ((conn)->vfs.ops.unlink((conn)->vfs.handles.unlink, (path))) #define SMB_VFS_CHMOD(conn, path, mode) ((conn)->vfs.ops.chmod((conn)->vfs.handles.chmod, (path), (mode))) @@ -195,9 +195,9 @@ #define SMB_VFS_OPAQUE_RECVFILE(fromfd, tofsp, offset, count) ((tofsp)->conn->vfs_opaque.ops.recvfile((tofsp)->conn->vfs_opaque.handles.recvfile, (fromfd), (tofsp), (offset), (count))) #define SMB_VFS_OPAQUE_RENAME(conn, old, new) ((conn)->vfs_opaque.ops.rename((conn)->vfs_opaque.handles.rename, (old), (new))) #define SMB_VFS_OPAQUE_FSYNC(fsp) ((fsp)->conn->vfs_opaque.ops.fsync((fsp)->conn->vfs_opaque.handles.fsync, (fsp))) -#define SMB_VFS_OPAQUE_STAT(conn, fname, sbuf) ((conn)->vfs_opaque.ops.stat((conn)->vfs_opaque.handles.stat, (fname), (sbuf))) +#define SMB_VFS_OPAQUE_STAT(conn, smb_fname) ((conn)->vfs_opaque.ops.stat((conn)->vfs_opaque.handles.stat, (smb_fname))) #define SMB_VFS_OPAQUE_FSTAT(fsp, sbuf) ((fsp)->conn->vfs_opaque.ops.fstat((fsp)->conn->vfs_opaque.handles.fstat, (fsp), (sbuf))) -#define SMB_VFS_OPAQUE_LSTAT(conn, path, sbuf) ((conn)->vfs_opaque.ops.lstat((conn)->vfs_opaque.handles.lstat, (path), (sbuf))) +#define SMB_VFS_OPAQUE_LSTAT(conn, smb_fname) ((conn)->vfs_opaque.ops.lstat((conn)->vfs_opaque.handles.lstat, (smb_fname))) #define SMB_VFS_OPAQUE_GET_ALLOC_SIZE(conn, fsp, sbuf) ((conn)->vfs_opaque.ops.get_alloc_size((conn)->vfs_opaque.handles.get_alloc_size, (fsp), (sbuf))) #define SMB_VFS_OPAQUE_UNLINK(conn, path) ((conn)->vfs_opaque.ops.unlink((conn)->vfs_opaque.handles.unlink, (path))) #define SMB_VFS_OPAQUE_CHMOD(conn, path, mode) ((conn)->vfs_opaque.ops.chmod((conn)->vfs_opaque.handles.chmod, (path), (mode))) @@ -331,9 +331,9 @@ #define SMB_VFS_NEXT_RECVFILE(handle, fromfd, tofsp, offset, count) ((handle)->vfs_next.ops.recvfile((handle)->vfs_next.handles.recvfile, (fromfd), (tofsp), (offset), (count))) #define SMB_VFS_NEXT_RENAME(handle, old, new) ((handle)->vfs_next.ops.rename((handle)->vfs_next.handles.rename, (old), (new))) #define SMB_VFS_NEXT_FSYNC(handle, fsp) ((handle)->vfs_next.ops.fsync((handle)->vfs_next.handles.fsync, (fsp))) -#define SMB_VFS_NEXT_STAT(handle, fname, sbuf) ((handle)->vfs_next.ops.stat((handle)->vfs_next.handles.stat, (fname), (sbuf))) +#define SMB_VFS_NEXT_STAT(handle, smb_fname) ((handle)->vfs_next.ops.stat((handle)->vfs_next.handles.stat, (smb_fname))) #define SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf) ((handle)->vfs_next.ops.fstat((handle)->vfs_next.handles.fstat, (fsp), (sbuf))) -#define SMB_VFS_NEXT_LSTAT(handle, path, sbuf) ((handle)->vfs_next.ops.lstat((handle)->vfs_next.handles.lstat, (path), (sbuf))) +#define SMB_VFS_NEXT_LSTAT(handle, smb_fname) ((handle)->vfs_next.ops.lstat((handle)->vfs_next.handles.lstat, (smb_fname))) #define SMB_VFS_NEXT_GET_ALLOC_SIZE(conn, fsp, sbuf) ((conn)->vfs_next.ops.get_alloc_size((conn)->vfs_next.handles.get_alloc_size, (fsp), (sbuf))) #define SMB_VFS_NEXT_UNLINK(handle, path) ((handle)->vfs_next.ops.unlink((handle)->vfs_next.handles.unlink, (path))) #define SMB_VFS_NEXT_CHMOD(handle, path, mode) ((handle)->vfs_next.ops.chmod((handle)->vfs_next.handles.chmod, (path), (mode))) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 10a3733c14..320f9da337 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -168,7 +168,7 @@ static int smbacl4_GetFileOwner(struct connection_struct *conn, memset(psbuf, 0, sizeof(SMB_STRUCT_STAT)); /* Get the stat struct for the owner info. */ - if (SMB_VFS_STAT(conn, filename, psbuf) != 0) + if (vfs_stat_smb_fname(conn, filename, psbuf) != 0) { DEBUG(8, ("SMB_VFS_STAT failed with error %s\n", strerror(errno))); diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c index e0a5b14c67..9f0b0b317a 100644 --- a/source3/modules/vfs_acl_tdb.c +++ b/source3/modules/vfs_acl_tdb.c @@ -196,9 +196,9 @@ static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { if (fsp && fsp->posix_open) { - ret = SMB_VFS_LSTAT(handle->conn, name, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn, name, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn, name, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, name, &sbuf); } } @@ -288,9 +288,11 @@ static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle, ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(handle->conn, fsp->fsp_name, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn, fsp->fsp_name, + &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn, fsp->fsp_name, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, fsp->fsp_name, + &sbuf); } } @@ -338,9 +340,9 @@ static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle, return NT_STATUS_INTERNAL_DB_CORRUPTION); if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(handle->conn, fname, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn, fname, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, fname, &sbuf); } if (ret == -1) { @@ -514,9 +516,11 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { if (fsp && fsp->posix_open) { - ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn,fname, + &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); + ret = vfs_stat_smb_fname(handle->conn,fname, + &sbuf); } } if (ret == -1) { @@ -621,9 +625,9 @@ static int unlink_acl_tdb(vfs_handle_struct *handle, const char *path) SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn, path, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, path, &sbuf); } if (ret == -1) { @@ -670,9 +674,9 @@ static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path) SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn, path, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, path, &sbuf); } if (ret == -1) { @@ -774,9 +778,13 @@ static NTSTATUS fset_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp, } if (fsp->is_directory || fsp->fh->fd == -1) { if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); + ret = vfs_lstat_smb_fname(fsp->conn, + fsp->fsp_name, + &sbuf); } else { - ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + ret = vfs_stat_smb_fname(fsp->conn, + fsp->fsp_name, + &sbuf); } } else { ret = SMB_VFS_FSTAT(fsp, &sbuf); @@ -867,9 +875,9 @@ static int sys_acl_set_file_tdb(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn, path, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, path, &sbuf); } if (ret == -1) { @@ -904,9 +912,11 @@ static int sys_acl_set_fd_tdb(vfs_handle_struct *handle, if (fsp->is_directory || fsp->fh->fd == -1) { if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); + ret = vfs_lstat_smb_fname(fsp->conn,fsp->fsp_name, + &sbuf); } else { - ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + ret = vfs_stat_smb_fname(fsp->conn,fsp->fsp_name, + &sbuf); } } else { ret = SMB_VFS_FSTAT(fsp, &sbuf); diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c index efcc87740a..66bf21c4f7 100644 --- a/source3/modules/vfs_acl_xattr.c +++ b/source3/modules/vfs_acl_xattr.c @@ -382,9 +382,11 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { if (fsp && fsp->posix_open) { - ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn, fname, + &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, fname, + &sbuf); } } if (ret == -1) { @@ -574,9 +576,13 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, } if (fsp->is_directory || fsp->fh->fd == -1) { if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); + ret = vfs_lstat_smb_fname(fsp->conn, + fsp->fsp_name, + &sbuf); } else { - ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + ret = vfs_stat_smb_fname(fsp->conn, + fsp->fsp_name, + &sbuf); } } else { ret = SMB_VFS_FSTAT(fsp, &sbuf); diff --git a/source3/modules/vfs_afsacl.c b/source3/modules/vfs_afsacl.c index e537f01b03..55371c60f5 100644 --- a/source3/modules/vfs_afsacl.c +++ b/source3/modules/vfs_afsacl.c @@ -662,7 +662,7 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl, SMB_STRUCT_STAT sbuf; /* Get the stat struct for the owner info. */ - if(SMB_VFS_STAT(conn, name, &sbuf) != 0) { + if(vfs_stat_smb_fname(conn, name, &sbuf) != 0) { return 0; } diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c index 4525fa1da3..12a88750ee 100644 --- a/source3/modules/vfs_cap.c +++ b/source3/modules/vfs_cap.c @@ -144,26 +144,52 @@ static int cap_rename(vfs_handle_struct *handle, const char *oldname, const char return SMB_VFS_NEXT_RENAME(handle, capold, capnew); } -static int cap_stat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf) +static int cap_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname) { - char *cappath = capencode(talloc_tos(), path); + char *cappath; + char *tmp_base_name = NULL; + int ret; + + cappath = capencode(talloc_tos(), smb_fname->base_name); if (!cappath) { errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_STAT(handle, cappath, sbuf); + + tmp_base_name = smb_fname->base_name; + smb_fname->base_name = cappath; + + ret = SMB_VFS_NEXT_STAT(handle, smb_fname); + + smb_fname->base_name = tmp_base_name; + TALLOC_FREE(cappath); + + return ret; } -static int cap_lstat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf) +static int cap_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname) { - char *cappath = capencode(talloc_tos(), path); + char *cappath; + char *tmp_base_name = NULL; + int ret; + + cappath = capencode(talloc_tos(), smb_fname->base_name); if (!cappath) { errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_LSTAT(handle, cappath, sbuf); + + tmp_base_name = smb_fname->base_name; + smb_fname->base_name = cappath; + + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); + + smb_fname->base_name = tmp_base_name; + TALLOC_FREE(cappath); + + return ret; } static int cap_unlink(vfs_handle_struct *handle, const char *path) diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index 8d1c87a9fc..c8c340d0a5 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -177,27 +177,51 @@ static int catia_rename(vfs_handle_struct *handle, } static int catia_stat(vfs_handle_struct *handle, - const char *fname, SMB_STRUCT_STAT *sbuf) + struct smb_filename *smb_fname) { - char *name = to_unix(talloc_tos(), fname); + char *name; + char *tmp_base_name; + int ret; + name = to_unix(talloc_tos(), smb_fname->base_name); if (!name) { errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_STAT(handle, name, sbuf); + + tmp_base_name = smb_fname->base_name; + smb_fname->base_name = name; + + ret = SMB_VFS_NEXT_STAT(handle, smb_fname); + + smb_fname->base_name = tmp_base_name; + TALLOC_FREE(name); + + return ret; } static int catia_lstat(vfs_handle_struct *handle, - const char *path, SMB_STRUCT_STAT *sbuf) + struct smb_filename *smb_fname) { - char *name = to_unix(talloc_tos(), path); + char *name; + char *tmp_base_name; + int ret; + name = to_unix(talloc_tos(), smb_fname->base_name); if (!name) { errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_LSTAT(handle, name, sbuf); + + tmp_base_name = smb_fname->base_name; + smb_fname->base_name = name; + + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); + + smb_fname->base_name = tmp_base_name; + TALLOC_FREE(name); + + return ret; } static int catia_unlink(vfs_handle_struct *handle, const char *path) diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 0e7ba05632..cd792aba32 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -549,12 +549,26 @@ static int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp) #endif } -static int vfswrap_stat(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf) +static int vfswrap_stat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) { int result; + NTSTATUS status; + char *fname = NULL; START_PROFILE(syscall_stat); - result = sys_stat(fname, sbuf); + + status = get_full_smb_filename(talloc_tos(), smb_fname, + &fname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + result = sys_stat(fname, &smb_fname->st); + + TALLOC_FREE(fname); + END_PROFILE(syscall_stat); return result; } @@ -569,12 +583,26 @@ static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUC return result; } -int vfswrap_lstat(vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf) +static int vfswrap_lstat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) { int result; + NTSTATUS status; + char *fname = NULL; START_PROFILE(syscall_lstat); - result = sys_lstat(path, sbuf); + + status = get_full_smb_filename(talloc_tos(), smb_fname, + &fname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + result = sys_lstat(fname, &smb_fname->st); + + TALLOC_FREE(fname); + END_PROFILE(syscall_lstat); return result; } @@ -1097,7 +1125,7 @@ static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle, ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, fname, &sbuf); } if (ret == -1) { diff --git a/source3/modules/vfs_fake_perms.c b/source3/modules/vfs_fake_perms.c index cc3ab6220d..2740b612ca 100644 --- a/source3/modules/vfs_fake_perms.c +++ b/source3/modules/vfs_fake_perms.c @@ -26,19 +26,20 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS -static int fake_perms_stat(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf) +static int fake_perms_stat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) { int ret = -1; - ret = SMB_VFS_NEXT_STAT(handle, fname, sbuf); + ret = SMB_VFS_NEXT_STAT(handle, smb_fname); if (ret == 0) { - if (S_ISDIR(sbuf->st_ex_mode)) { - sbuf->st_ex_mode = S_IFDIR | S_IRWXU; + if (S_ISDIR(smb_fname->st.st_ex_mode)) { + smb_fname->st.st_ex_mode = S_IFDIR | S_IRWXU; } else { - sbuf->st_ex_mode = S_IRWXU; + smb_fname->st.st_ex_mode = S_IRWXU; } - sbuf->st_ex_uid = handle->conn->server_info->utok.uid; - sbuf->st_ex_gid = handle->conn->server_info->utok.gid; + smb_fname->st.st_ex_uid = handle->conn->server_info->utok.uid; + smb_fname->st.st_ex_gid = handle->conn->server_info->utok.gid; } return ret; diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 5558b2f9b5..e47609d0a9 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -151,11 +151,11 @@ static int smb_full_audit_rename(vfs_handle_struct *handle, const char *oldname, const char *newname); static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp); static int smb_full_audit_stat(vfs_handle_struct *handle, - const char *fname, SMB_STRUCT_STAT *sbuf); + struct smb_filename *smb_fname); static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf); static int smb_full_audit_lstat(vfs_handle_struct *handle, - const char *path, SMB_STRUCT_STAT *sbuf); + struct smb_filename *smb_fname); static int smb_full_audit_get_alloc_size(vfs_handle_struct *handle, files_struct *fsp, const SMB_STRUCT_STAT *sbuf); static int smb_full_audit_unlink(vfs_handle_struct *handle, @@ -1361,13 +1361,14 @@ static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp) } static int smb_full_audit_stat(vfs_handle_struct *handle, - const char *fname, SMB_STRUCT_STAT *sbuf) + struct smb_filename *smb_fname) { int result; - result = SMB_VFS_NEXT_STAT(handle, fname, sbuf); + result = SMB_VFS_NEXT_STAT(handle, smb_fname); - do_log(SMB_VFS_OP_STAT, (result >= 0), handle, "%s", fname); + do_log(SMB_VFS_OP_STAT, (result >= 0), handle, "%s", + smb_fname_str_dbg(smb_fname)); return result; } @@ -1385,13 +1386,14 @@ static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp, } static int smb_full_audit_lstat(vfs_handle_struct *handle, - const char *path, SMB_STRUCT_STAT *sbuf) + struct smb_filename *smb_fname) { int result; - result = SMB_VFS_NEXT_LSTAT(handle, path, sbuf); + result = SMB_VFS_NEXT_LSTAT(handle, smb_fname); - do_log(SMB_VFS_OP_LSTAT, (result >= 0), handle, "%s", path); + do_log(SMB_VFS_OP_LSTAT, (result >= 0), handle, "%s", + smb_fname_str_dbg(smb_fname)); return result; } diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 26f9688909..47858cb352 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -966,20 +966,28 @@ static size_t gpfs_get_xattr(struct vfs_handle_struct *handle, const char *path return size; } -static int vfs_gpfs_stat(struct vfs_handle_struct *handle, const char *fname, - SMB_STRUCT_STAT *sbuf) +static int vfs_gpfs_stat(struct vfs_handle_struct *handle, + struct smb_filename *smb_fname) { struct gpfs_winattr attrs; + char *fname = NULL; + NTSTATUS status; int ret; - ret = SMB_VFS_NEXT_STAT(handle, fname, sbuf); + ret = SMB_VFS_NEXT_STAT(handle, smb_fname); if (ret == -1) { return -1; } + status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); + if (!NT_STATUS_IS_OK) { + errno = map_errno_from_nt_status(status); + return -1; + } ret = get_gpfs_winattrs(CONST_DISCARD(char *, fname), &attrs); + TALLOC_FREE(fname); if (ret == 0) { - sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec; - sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec; + smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec; + smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec; } return 0; } @@ -1005,20 +1013,28 @@ static int vfs_gpfs_fstat(struct vfs_handle_struct *handle, return 0; } -static int vfs_gpfs_lstat(struct vfs_handle_struct *handle, const char *path, - SMB_STRUCT_STAT *sbuf) +static int vfs_gpfs_lstat(struct vfs_handle_struct *handle, + struct smb_filename *smb_fname) { struct gpfs_winattr attrs; + char *path = NULL; + NTSTATUS status; int ret; - ret = SMB_VFS_NEXT_LSTAT(handle, path, sbuf); + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); if (ret == -1) { return -1; } + status = get_full_smb_filename(talloc_tos(), smb_fname, &path); + if (!NT_STATUS_IS_OK) { + errno = map_errno_from_nt_status(status); + return -1; + } ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs); + TALLOC_FREE(path); if (ret == 0) { - sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec; - sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec; + smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec; + smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec; } return 0; } diff --git a/source3/modules/vfs_hpuxacl.c b/source3/modules/vfs_hpuxacl.c index 7d20a73d7b..35341a5c3e 100644 --- a/source3/modules/vfs_hpuxacl.c +++ b/source3/modules/vfs_hpuxacl.c @@ -248,7 +248,7 @@ int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle, * that has _not_ been specified in "type" from the file first * and concatenate it with the acl provided. */ - if (SMB_VFS_STAT(handle->conn, name, &s) != 0) { + if (vfs_stat_smb_fname(handle->conn, name, &s) != 0) { DEBUG(10, ("Error in stat call: %s\n", strerror(errno))); goto done; } diff --git a/source3/modules/vfs_recycle.c b/source3/modules/vfs_recycle.c index f1791aa6b1..f42fab72f7 100644 --- a/source3/modules/vfs_recycle.c +++ b/source3/modules/vfs_recycle.c @@ -214,7 +214,7 @@ static bool recycle_directory_exist(vfs_handle_struct *handle, const char *dname { SMB_STRUCT_STAT st; - if (SMB_VFS_NEXT_STAT(handle, dname, &st) == 0) { + if (vfs_stat_smb_fname(handle->conn, dname, &st) == 0) { if (S_ISDIR(st.st_ex_mode)) { return True; } @@ -227,7 +227,7 @@ static bool recycle_file_exist(vfs_handle_struct *handle, const char *fname) { SMB_STRUCT_STAT st; - if (SMB_VFS_NEXT_STAT(handle, fname, &st) == 0) { + if (vfs_stat_smb_fname(handle->conn, fname, &st) == 0) { if (S_ISREG(st.st_ex_mode)) { return True; } @@ -246,7 +246,7 @@ static SMB_OFF_T recycle_get_file_size(vfs_handle_struct *handle, const char *fn { SMB_STRUCT_STAT st; - if (SMB_VFS_NEXT_STAT(handle, fname, &st) != 0) { + if (vfs_stat_smb_fname(handle->conn, fname, &st) != 0) { DEBUG(0,("recycle: stat for %s returned %s\n", fname, strerror(errno))); return (SMB_OFF_T)0; } @@ -396,7 +396,7 @@ static void recycle_do_touch(vfs_handle_struct *handle, const char *fname, ZERO_STRUCT(ft); - if (SMB_VFS_NEXT_STAT(handle, fname, &st) != 0) { + if (vfs_stat_smb_fname(handle->conn, fname, &st) != 0) { DEBUG(0,("recycle: stat for %s returned %s\n", fname, strerror(errno))); return; diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 7b5b85d4be..03a8fd24ea 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -376,15 +376,19 @@ static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle, } static int shadow_copy2_stat(vfs_handle_struct *handle, - const char *fname, SMB_STRUCT_STAT *sbuf) + struct smb_filename *smb_fname) { - _SHADOW2_NEXT(STAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf)); + _SHADOW2_NEXT_SMB_FNAME(STAT, (handle, smb_fname), int, -1, + convert_sbuf(handle, smb_fname->base_name, + &smb_fname->st)); } static int shadow_copy2_lstat(vfs_handle_struct *handle, - const char *fname, SMB_STRUCT_STAT *sbuf) + struct smb_filename *smb_fname) { - _SHADOW2_NEXT(LSTAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf)); + _SHADOW2_NEXT_SMB_FNAME(LSTAT, (handle, smb_fname), int, -1, + convert_sbuf(handle, smb_fname->base_name, + &smb_fname->st)); } static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) diff --git a/source3/modules/vfs_solarisacl.c b/source3/modules/vfs_solarisacl.c index fbfe664c6e..dabb35c0c0 100644 --- a/source3/modules/vfs_solarisacl.c +++ b/source3/modules/vfs_solarisacl.c @@ -165,7 +165,7 @@ int solarisacl_sys_acl_set_file(vfs_handle_struct *handle, * that has not been specified in "type" from the file first * and concatenate it with the acl provided. */ - if (SMB_VFS_STAT(handle->conn, name, &s) != 0) { + if (vfs_stat_smb_fname(handle->conn, name, &s) != 0) { DEBUG(10, ("Error in stat call: %s\n", strerror(errno))); goto done; } diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index 7d37af0181..5f850174d8 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -115,12 +115,18 @@ static bool mark_file_valid(vfs_handle_struct *handle, const char *path, return true; } -static char *stream_dir(vfs_handle_struct *handle, const char *base_path, +/** + * Given an smb_filename, determine the stream directory using the file's + * base_name. + */ +static char *stream_dir(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, const SMB_STRUCT_STAT *base_sbuf, bool create_it) { uint32_t hash; + struct smb_filename *smb_fname_hash = NULL; char *result = NULL; - SMB_STRUCT_STAT sbuf; + SMB_STRUCT_STAT base_sbuf_tmp; uint8_t first, second; char *tmp; char *id_hex; @@ -128,6 +134,7 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, uint8 id_buf[16]; bool check_valid; const char *rootdir; + NTSTATUS status; check_valid = lp_parm_bool(SNUM(handle->conn), "streams_depot", "check_valid", true); @@ -143,17 +150,29 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, SNUM(handle->conn), "streams_depot", "directory", tmp); + /* Stat the base file if it hasn't already been done. */ if (base_sbuf == NULL) { - if (SMB_VFS_NEXT_STAT(handle, base_path, &sbuf) == -1) { - /* - * base file is not there - */ + struct smb_filename *smb_fname_base = NULL; + + status = create_synthetic_smb_fname(talloc_tos(), + smb_fname->base_name, + NULL, NULL, + &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto fail; + } + if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) { + TALLOC_FREE(smb_fname_base); goto fail; } - base_sbuf = &sbuf; + base_sbuf_tmp = smb_fname_base->st; + TALLOC_FREE(smb_fname_base); + } else { + base_sbuf_tmp = *base_sbuf; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, base_sbuf); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp); push_file_id_16((char *)id_buf, &id); @@ -179,15 +198,22 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, return NULL; } - if (SMB_VFS_NEXT_STAT(handle, result, &sbuf) == 0) { + status = create_synthetic_smb_fname(talloc_tos(), result, NULL, NULL, + &smb_fname_hash); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto fail; + } + + if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) { char *newname; - if (!S_ISDIR(sbuf.st_ex_mode)) { + if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) { errno = EINVAL; goto fail; } - if (file_is_valid(handle, base_path, check_valid)) { + if (file_is_valid(handle, smb_fname->base_name, check_valid)) { return result; } @@ -257,13 +283,15 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, goto fail; } - if (!mark_file_valid(handle, base_path, check_valid)) { + if (!mark_file_valid(handle, smb_fname->base_name, check_valid)) { goto fail; } + TALLOC_FREE(smb_fname_hash); return result; fail: + TALLOC_FREE(smb_fname_hash); TALLOC_FREE(result); return NULL; } @@ -282,7 +310,7 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle, *smb_fname_out = NULL; - dirname = stream_dir(handle, smb_fname->base_name, NULL, create_dir); + dirname = stream_dir(handle, smb_fname, NULL, create_dir); if (dirname == NULL) { status = map_nt_error_from_unix(errno); @@ -315,10 +343,8 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle, DEBUG(10, ("stream filename = %s\n", stream_fname)); /* Create an smb_filename with stream_name == NULL. */ - status = create_synthetic_smb_fname(talloc_tos(), - stream_fname, - NULL, NULL, - smb_fname_out); + status = create_synthetic_smb_fname(talloc_tos(), stream_fname, NULL, + NULL, smb_fname_out); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -331,58 +357,47 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle, return status; } +/* + * XXX: This function should be removed after the other vfs ops take + * smb_filename structs + */ static char *stream_name(vfs_handle_struct *handle, const char *fname, bool create_dir) { - char *base = NULL; + struct smb_filename *smb_fname = NULL; + struct smb_filename *smb_fname_stream = NULL; char *sname = NULL; - char *id_hex = NULL; - char *dirname, *stream_fname; - - if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname, - &base, &sname))) { - DEBUG(10, ("split_ntfs_stream_name failed\n")); - errno = ENOMEM; - goto fail; - } + NTSTATUS status; - /* if it's the ::$DATA stream just return the base file name */ - if (!sname) { - return base; + status = create_synthetic_smb_fname_split(talloc_tos(), fname, + NULL, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto out; } - dirname = stream_dir(handle, base, NULL, create_dir); - - if (dirname == NULL) { - goto fail; + status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, + create_dir); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto out; } - stream_fname = talloc_asprintf(talloc_tos(), "%s/:%s", dirname, sname); - - if (stream_fname == NULL) { - errno = ENOMEM; - goto fail; + status = get_full_smb_filename(talloc_tos(), smb_fname_stream, + &sname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto out; } + out: + TALLOC_FREE(smb_fname); + TALLOC_FREE(smb_fname_stream); - DEBUG(10, ("stream filename = %s\n", stream_fname)); - - TALLOC_FREE(base); - TALLOC_FREE(sname); - TALLOC_FREE(id_hex); - - return stream_fname; - - fail: - DEBUG(5, ("stream_name failed: %s\n", strerror(errno))); - TALLOC_FREE(base); - TALLOC_FREE(sname); - TALLOC_FREE(id_hex); - return NULL; + return sname; } static NTSTATUS walk_streams(vfs_handle_struct *handle, - const char *fname, - const SMB_STRUCT_STAT *sbuf, + struct smb_filename *smb_fname_base, char **pdirname, bool (*fn)(const char *dirname, const char *dirent, @@ -393,7 +408,8 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirhandle = NULL; char *dirent; - dirname = stream_dir(handle, fname, sbuf, false); + dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st, + false); if (dirname == NULL) { if (errno == ENOENT) { @@ -439,49 +455,99 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle, return NT_STATUS_OK; } -static int streams_depot_stat(vfs_handle_struct *handle, const char *fname, - SMB_STRUCT_STAT *sbuf) +/** + * Helper to stat/lstat the base file of an smb_fname. This will actually + * fills in the stat struct in smb_filename. + */ +static int streams_depot_stat_base(vfs_handle_struct *handle, + struct smb_filename *smb_fname, + bool follow_links) { - char *stream_fname; + char *tmp_stream_name; + int result; + + tmp_stream_name = smb_fname->stream_name; + smb_fname->stream_name = NULL; + if (follow_links) { + result = SMB_VFS_NEXT_STAT(handle, smb_fname); + } else { + result = SMB_VFS_NEXT_LSTAT(handle, smb_fname); + } + smb_fname->stream_name = tmp_stream_name; + return result; +} + +static int streams_depot_stat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) +{ + struct smb_filename *smb_fname_stream = NULL; + NTSTATUS status; int ret = -1; - DEBUG(10, ("streams_depot_stat called for [%s]\n", fname)); + DEBUG(10, ("streams_depot_stat called for [%s]\n", + smb_fname_str_dbg(smb_fname))); - if (!is_ntfs_stream_name(fname)) { - return SMB_VFS_NEXT_STAT(handle, fname, sbuf); + if (!is_ntfs_stream_smb_fname(smb_fname)) { + return SMB_VFS_NEXT_STAT(handle, smb_fname); } - stream_fname = stream_name(handle, fname, false); - if (stream_fname == NULL) { + /* If the default stream is requested, just stat the base file. */ + if (is_ntfs_default_stream_smb_fname(smb_fname)) { + return streams_depot_stat_base(handle, smb_fname, true); + } + + /* Stat the actual stream now. */ + status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, + false); + if (!NT_STATUS_IS_OK(status)) { + ret = -1; + errno = map_errno_from_nt_status(status); goto done; } - ret = SMB_VFS_NEXT_STAT(handle, stream_fname, sbuf); + ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream); + /* Update the original smb_fname with the stat info. */ + smb_fname->st = smb_fname_stream->st; done: - TALLOC_FREE(stream_fname); + TALLOC_FREE(smb_fname_stream); return ret; } -static int streams_depot_lstat(vfs_handle_struct *handle, const char *fname, - SMB_STRUCT_STAT *sbuf) + + +static int streams_depot_lstat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) { - char *stream_fname; + struct smb_filename *smb_fname_stream = NULL; + NTSTATUS status; int ret = -1; - if (!is_ntfs_stream_name(fname)) { - return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf); + DEBUG(10, ("streams_depot_lstat called for [%s]\n", + smb_fname_str_dbg(smb_fname))); + + if (!is_ntfs_stream_smb_fname(smb_fname)) { + return SMB_VFS_NEXT_LSTAT(handle, smb_fname); } - stream_fname = stream_name(handle, fname, false); - if (stream_fname == NULL) { + /* If the default stream is requested, just stat the base file. */ + if (is_ntfs_default_stream_smb_fname(smb_fname)) { + return streams_depot_stat_base(handle, smb_fname, false); + } + + /* Stat the actual stream now. */ + status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, + false); + if (!NT_STATUS_IS_OK(status)) { + ret = -1; + errno = map_errno_from_nt_status(status); goto done; } - ret = SMB_VFS_NEXT_LSTAT(handle, stream_fname, sbuf); + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream); done: - TALLOC_FREE(stream_fname); + TALLOC_FREE(smb_fname_stream); return ret; } @@ -490,7 +556,7 @@ static int streams_depot_open(vfs_handle_struct *handle, files_struct *fsp, int flags, mode_t mode) { struct smb_filename *smb_fname_stream = NULL; - SMB_STRUCT_STAT base_sbuf; + struct smb_filename *smb_fname_base = NULL; NTSTATUS status; int ret = -1; @@ -505,21 +571,29 @@ static int streams_depot_open(vfs_handle_struct *handle, tmp_stream_name = smb_fname->stream_name; smb_fname->stream_name = NULL; - ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); - smb_fname->stream_name = tmp_stream_name; return ret; } /* Ensure the base file still exists. */ - ret = SMB_VFS_NEXT_STAT(handle, smb_fname->base_name, &base_sbuf); + status = create_synthetic_smb_fname(talloc_tos(), + smb_fname->base_name, + NULL, NULL, + &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + ret = -1; + errno = map_errno_from_nt_status(status); + goto done; + } + ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base); if (ret == -1) { goto done; } + /* Determine the stream name, and then open it. */ status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, true); if (!NT_STATUS_IS_OK(status)) { ret = -1; @@ -531,13 +605,15 @@ static int streams_depot_open(vfs_handle_struct *handle, done: TALLOC_FREE(smb_fname_stream); + TALLOC_FREE(smb_fname_base); return ret; } static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname) { + struct smb_filename *smb_fname_base = NULL; + NTSTATUS status; int ret = -1; - SMB_STRUCT_STAT sbuf; DEBUG(10, ("streams_depot_unlink called for %s\n", fname)); @@ -559,18 +635,27 @@ static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname) * We potentially need to delete the per-inode streams directory */ + status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL, + &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + if (lp_posix_pathnames()) { - ret = SMB_VFS_NEXT_LSTAT(handle, fname, &sbuf); + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base); } else { - ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf); + ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base); } if (ret == -1) { + TALLOC_FREE(smb_fname_base); return -1; } - if (sbuf.st_ex_nlink == 1) { - char *dirname = stream_dir(handle, fname, &sbuf, false); + if (smb_fname_base->st.st_ex_nlink == 1) { + char *dirname = stream_dir(handle, smb_fname_base, + &smb_fname_base->st, false); if (dirname != NULL) { SMB_VFS_NEXT_RMDIR(handle, dirname); @@ -578,6 +663,8 @@ static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname) TALLOC_FREE(dirname); } + TALLOC_FREE(smb_fname_base); + return SMB_VFS_NEXT_UNLINK(handle, fname); } @@ -699,32 +786,48 @@ static bool collect_one_stream(const char *dirname, { struct streaminfo_state *state = (struct streaminfo_state *)private_data; - char *full_sname; - SMB_STRUCT_STAT sbuf; + struct smb_filename *smb_fname = NULL; + char *sname = NULL; + NTSTATUS status; + bool ret; - if (asprintf(&full_sname, "%s/%s", dirname, dirent) == -1) { + sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent); + if (sname == NULL) { state->status = NT_STATUS_NO_MEMORY; - return false; + ret = false; + goto out; } - if (SMB_VFS_NEXT_STAT(state->handle, full_sname, &sbuf) == -1) { - DEBUG(10, ("Could not stat %s: %s\n", full_sname, - strerror(errno))); - SAFE_FREE(full_sname); - return true; + + status = create_synthetic_smb_fname(talloc_tos(), sname, NULL, + NULL, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + state->status = status; + ret = false; + goto out; } - SAFE_FREE(full_sname); + if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) { + DEBUG(10, ("Could not stat %s: %s\n", sname, + strerror(errno))); + ret = true; + goto out; + } if (!add_one_stream(state->mem_ctx, &state->num_streams, &state->streams, - dirent, sbuf.st_ex_size, + dirent, smb_fname->st.st_ex_size, SMB_VFS_GET_ALLOC_SIZE(state->handle->conn, NULL, - &sbuf))) { + &smb_fname->st))) { state->status = NT_STATUS_NO_MEMORY; - return false; + ret = false; + goto out; } - return true; + ret = true; + out: + TALLOC_FREE(sname); + TALLOC_FREE(smb_fname); + return ret; } static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle, @@ -734,42 +837,50 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle, unsigned int *pnum_streams, struct stream_struct **pstreams) { - SMB_STRUCT_STAT sbuf; + struct smb_filename *smb_fname_base = NULL; int ret; NTSTATUS status; struct streaminfo_state state; + status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL, + &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if ((fsp != NULL) && (fsp->fh->fd != -1)) { if (is_ntfs_stream_name(fsp->fsp_name)) { return NT_STATUS_INVALID_PARAMETER; } - ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf); + ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st); } else { if (is_ntfs_stream_name(fname)) { return NT_STATUS_INVALID_PARAMETER; } if (lp_posix_pathnames()) { - ret = SMB_VFS_NEXT_LSTAT(handle, fname, &sbuf); + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base); } else { - ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf); + ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base); } } if (ret == -1) { - return map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); + goto out; } state.streams = NULL; state.num_streams = 0; - if (!S_ISDIR(sbuf.st_ex_mode)) { + if (!S_ISDIR(smb_fname_base->st.st_ex_mode)) { if (!add_one_stream(mem_ctx, &state.num_streams, &state.streams, - "::$DATA", sbuf.st_ex_size, + "::$DATA", smb_fname_base->st.st_ex_size, SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp, - &sbuf))) { - return NT_STATUS_NO_MEMORY; + &smb_fname_base->st))) { + status = NT_STATUS_NO_MEMORY; + goto out; } } @@ -777,22 +888,27 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle, state.handle = handle; state.status = NT_STATUS_OK; - status = walk_streams(handle, fname, &sbuf, NULL, collect_one_stream, + status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream, &state); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(state.streams); - return status; + goto out; } if (!NT_STATUS_IS_OK(state.status)) { TALLOC_FREE(state.streams); - return state.status; + status = state.status; + goto out; } *pnum_streams = state.num_streams; *pstreams = state.streams; - return NT_STATUS_OK; + status = NT_STATUS_OK; + + out: + TALLOC_FREE(smb_fname_base); + return status; } static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle) diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c index 715e1a7baf..e87d60ec60 100644 --- a/source3/modules/vfs_streams_xattr.c +++ b/source3/modules/vfs_streams_xattr.c @@ -169,9 +169,32 @@ static bool streams_xattr_recheck(struct stream_io *sio) return true; } +/** + * Helper to stat/lstat the base file of an smb_fname. + */ +static int streams_xattr_stat_base(vfs_handle_struct *handle, + struct smb_filename *smb_fname, + bool follow_links) +{ + char *tmp_stream_name; + int result; + + tmp_stream_name = smb_fname->stream_name; + smb_fname->stream_name = NULL; + if (follow_links) { + result = SMB_VFS_NEXT_STAT(handle, smb_fname); + } else { + result = SMB_VFS_NEXT_LSTAT(handle, smb_fname); + } + smb_fname->stream_name = tmp_stream_name; + return result; +} + static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) { + struct smb_filename *smb_fname_base = NULL; + NTSTATUS status; int ret = -1; struct stream_io *io = (struct stream_io *) VFS_FETCH_FSP_EXTENSION(handle, fsp); @@ -186,11 +209,23 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp, return -1; } + /* Create an smb_filename with stream_name == NULL. */ + status = create_synthetic_smb_fname(talloc_tos(), + io->base, + NULL, NULL, + &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(handle->conn, io->base, sbuf); + ret = SMB_VFS_LSTAT(handle->conn, smb_fname_base); } else { - ret = SMB_VFS_STAT(handle->conn, io->base, sbuf); + ret = SMB_VFS_STAT(handle->conn, smb_fname_base); } + *sbuf = smb_fname_base->st; + TALLOC_FREE(smb_fname_base); if (ret == -1) { return -1; @@ -212,105 +247,106 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp, return 0; } -static int streams_xattr_stat(vfs_handle_struct *handle, const char *fname, - SMB_STRUCT_STAT *sbuf) +static int streams_xattr_stat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) { NTSTATUS status; - char *base = NULL, *sname = NULL; int result = -1; - char *xattr_name; - - if (!is_ntfs_stream_name(fname)) { - return SMB_VFS_NEXT_STAT(handle, fname, sbuf); - } + char *xattr_name = NULL; - status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname); - if (!NT_STATUS_IS_OK(status)) { - errno = EINVAL; - return -1; + if (!is_ntfs_stream_smb_fname(smb_fname)) { + return SMB_VFS_NEXT_STAT(handle, smb_fname); } - if (sname == NULL){ - return SMB_VFS_NEXT_STAT(handle, base, sbuf); + /* If the default stream is requested, just stat the base file. */ + if (is_ntfs_default_stream_smb_fname(smb_fname)) { + return streams_xattr_stat_base(handle, smb_fname, true); } - if (SMB_VFS_STAT(handle->conn, base, sbuf) == -1) { - goto fail; + /* Populate the stat struct with info from the base file. */ + if (streams_xattr_stat_base(handle, smb_fname, true) == -1) { + return -1; } - xattr_name = talloc_asprintf(talloc_tos(), "%s%s", - SAMBA_XATTR_DOSSTREAM_PREFIX, sname); - if (xattr_name == NULL) { - errno = ENOMEM; - goto fail; + /* Derive the xattr name to lookup. */ + status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name, + &xattr_name); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; } - sbuf->st_ex_size = get_xattr_size(handle->conn, NULL, base, xattr_name); - if (sbuf->st_ex_size == -1) { + /* Augment the base file's stat information before returning. */ + smb_fname->st.st_ex_size = get_xattr_size(handle->conn, NULL, + smb_fname->base_name, + xattr_name); + if (smb_fname->st.st_ex_size == -1) { errno = ENOENT; + result = -1; goto fail; } - sbuf->st_ex_ino = stream_inode(sbuf, xattr_name); - sbuf->st_ex_mode &= ~S_IFMT; - sbuf->st_ex_mode |= S_IFREG; - sbuf->st_ex_blocks = sbuf->st_ex_size % STAT_ST_BLOCKSIZE + 1; + smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name); + smb_fname->st.st_ex_mode &= ~S_IFMT; + smb_fname->st.st_ex_mode |= S_IFREG; + smb_fname->st.st_ex_blocks = + smb_fname->st.st_ex_size % STAT_ST_BLOCKSIZE + 1; result = 0; fail: - TALLOC_FREE(base); - TALLOC_FREE(sname); + TALLOC_FREE(xattr_name); return result; } -static int streams_xattr_lstat(vfs_handle_struct *handle, const char *fname, - SMB_STRUCT_STAT *sbuf) +static int streams_xattr_lstat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) { NTSTATUS status; - char *base, *sname; int result = -1; - char *xattr_name; - - if (!is_ntfs_stream_name(fname)) { - return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf); - } + char *xattr_name = NULL; - status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname); - if (!NT_STATUS_IS_OK(status)) { - errno = EINVAL; - goto fail; + if (!is_ntfs_stream_smb_fname(smb_fname)) { + return SMB_VFS_NEXT_LSTAT(handle, smb_fname); } - if (sname == NULL){ - return SMB_VFS_NEXT_LSTAT(handle, base, sbuf); + /* If the default stream is requested, just stat the base file. */ + if (is_ntfs_default_stream_smb_fname(smb_fname)) { + return streams_xattr_stat_base(handle, smb_fname, false); } - if (SMB_VFS_LSTAT(handle->conn, base, sbuf) == -1) { - goto fail; + /* Populate the stat struct with info from the base file. */ + if (streams_xattr_stat_base(handle, smb_fname, false) == -1) { + return -1; } - xattr_name = talloc_asprintf(talloc_tos(), "%s%s", - SAMBA_XATTR_DOSSTREAM_PREFIX, sname); - if (xattr_name == NULL) { - errno = ENOMEM; - goto fail; + /* Derive the xattr name to lookup. */ + status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name, + &xattr_name); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; } - sbuf->st_ex_size = get_xattr_size(handle->conn, NULL, base, xattr_name); - if (sbuf->st_ex_size == -1) { + /* Augment the base file's stat information before returning. */ + smb_fname->st.st_ex_size = get_xattr_size(handle->conn, NULL, + smb_fname->base_name, + xattr_name); + if (smb_fname->st.st_ex_size == -1) { errno = ENOENT; + result = -1; goto fail; } - sbuf->st_ex_ino = stream_inode(sbuf, xattr_name); - sbuf->st_ex_mode &= ~S_IFMT; - sbuf->st_ex_mode |= S_IFREG; - sbuf->st_ex_blocks = sbuf->st_ex_size % STAT_ST_BLOCKSIZE + 1; + smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name); + smb_fname->st.st_ex_mode &= ~S_IFMT; + smb_fname->st.st_ex_mode |= S_IFREG; + smb_fname->st.st_ex_blocks = + smb_fname->st.st_ex_size % STAT_ST_BLOCKSIZE + 1; result = 0; + fail: - TALLOC_FREE(base); - TALLOC_FREE(sname); + TALLOC_FREE(xattr_name); return result; } @@ -776,9 +812,9 @@ static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle, return NT_STATUS_INVALID_PARAMETER; } if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(handle->conn, fname, &sbuf); + ret = vfs_lstat_smb_fname(handle->conn, fname, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + ret = vfs_stat_smb_fname(handle->conn, fname, &sbuf); } } diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c index 4e37ed6477..39adfdfe15 100644 --- a/source3/modules/vfs_xattr_tdb.c +++ b/source3/modules/vfs_xattr_tdb.c @@ -215,7 +215,7 @@ static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) { return -1; } @@ -337,7 +337,7 @@ static int xattr_tdb_setxattr(struct vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) { return -1; } @@ -442,7 +442,7 @@ static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) { return -1; } @@ -542,7 +542,7 @@ static int xattr_tdb_removexattr(struct vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) { return -1; } @@ -621,7 +621,7 @@ static int xattr_tdb_unlink(vfs_handle_struct *handle, const char *path) SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) { return -1; } @@ -660,7 +660,7 @@ static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path) SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) { return -1; } diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 760a2d520c..ad21cf1d40 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -377,9 +377,9 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, hasn't been renamed. */ if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf); + ret = vfs_lstat_smb_fname(conn,fsp->fsp_name,&sbuf); } else { - ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf); + ret = vfs_stat_smb_fname(conn,fsp->fsp_name,&sbuf); } if (ret != 0) { @@ -502,9 +502,11 @@ static NTSTATUS update_write_time_on_close(struct files_struct *fsp) ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name,&sbuf); + ret = vfs_lstat_smb_fname(fsp->conn, fsp->fsp_name, + &sbuf); } else { - ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name,&sbuf); + ret = vfs_stat_smb_fname(fsp->conn, fsp->fsp_name, + &sbuf); } } diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index fb246cdf8c..aff30a6967 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -574,11 +574,13 @@ char *dptr_ReadDirName(TALLOC_CTX *ctx, long *poffset, SMB_STRUCT_STAT *pst) { + struct smb_filename *smb_fname_base = NULL; char *name = NULL; char *pathreal = NULL; char *found_name = NULL; int ret; const char *name_temp = NULL; + NTSTATUS status; SET_STAT_INVALID(*pst); @@ -624,10 +626,20 @@ char *dptr_ReadDirName(TALLOC_CTX *ctx, if (!pathreal) return NULL; - if (SMB_VFS_STAT(dptr->conn, pathreal, pst) == 0) { + /* Create an smb_filename with stream_name == NULL. */ + status = create_synthetic_smb_fname(ctx, pathreal, NULL, NULL, + &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } + + if (SMB_VFS_STAT(dptr->conn, smb_fname_base) == 0) { + *pst = smb_fname_base->st; + TALLOC_FREE(smb_fname_base); name = talloc_strdup(ctx, dptr->wcard); goto clean; } else { + TALLOC_FREE(smb_fname_base); /* If we get any other error than ENOENT or ENOTDIR then the file exists we just can't stat it. */ if (errno != ENOENT && errno != ENOTDIR) { @@ -893,12 +905,32 @@ bool get_dir_entry(TALLOC_CTX *ctx, return False; } - if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) { - DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n", - pathreal, strerror(errno) )); - TALLOC_FREE(pathreal); - TALLOC_FREE(filename); - continue; + if (!VALID_STAT(sbuf)) { + struct smb_filename *smb_fname = NULL; + NTSTATUS status; + + /* Create smb_fname with NULL stream_name. */ + status = + create_synthetic_smb_fname(ctx, pathreal, + NULL, NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(pathreal); + TALLOC_FREE(filename); + return NULL; + } + + if ((SMB_VFS_STAT(conn, smb_fname)) != 0) { + DEBUG(5,("Couldn't stat 1 [%s]. Error " + "= %s\n", pathreal, + strerror(errno))); + TALLOC_FREE(smb_fname); + TALLOC_FREE(pathreal); + TALLOC_FREE(filename); + continue; + } + sbuf = smb_fname->st; + TALLOC_FREE(smb_fname); } *mode = dos_mode(conn,pathreal,&sbuf); @@ -953,7 +985,8 @@ bool get_dir_entry(TALLOC_CTX *ctx, use it for anything security sensitive. ********************************************************************/ -static bool user_can_read_file(connection_struct *conn, char *name) +static bool user_can_read_file(connection_struct *conn, + struct smb_filename *smb_fname) { /* * If user is a member of the Admin group @@ -964,7 +997,7 @@ static bool user_can_read_file(connection_struct *conn, char *name) return True; } - return can_access_file_acl(conn, name, FILE_READ_DATA); + return can_access_file_acl(conn, smb_fname, FILE_READ_DATA); } /******************************************************************* @@ -1029,6 +1062,10 @@ bool is_visible_file(connection_struct *conn, const char *dir_path, bool hide_unreadable = lp_hideunreadable(SNUM(conn)); bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn)); bool hide_special = lp_hide_special_files(SNUM(conn)); + char *entry = NULL; + struct smb_filename *smb_fname_base = NULL; + NTSTATUS status; + bool ret = false; if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) { return True; /* . and .. are always visible. */ @@ -1041,55 +1078,70 @@ bool is_visible_file(connection_struct *conn, const char *dir_path, } if (hide_unreadable || hide_unwriteable || hide_special) { - char *entry = NULL; - entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name); - if (!entry) - return false; + if (!entry) { + ret = false; + goto out; } /* If it's a dfs symlink, ignore _hide xxxx_ options */ if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) && is_msdfs_link(conn, entry, NULL)) { - TALLOC_FREE(entry); - return true; + ret = true; + goto out; + } + + /* Create an smb_filename with stream_name == NULL. */ + status = create_synthetic_smb_fname(talloc_tos(), entry, NULL, + NULL, &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + ret = false; + goto out; } /* If the file name does not exist, there's no point checking * the configuration options. We succeed, on the basis that the * checks *might* have passed if the file was present. */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, entry, pst) != 0)) + if (!VALID_STAT(*pst) && + (SMB_VFS_STAT(conn, smb_fname_base) != 0)) { - TALLOC_FREE(entry); - return true; + ret = true; + goto out; } + *pst = smb_fname_base->st; + /* Honour _hide unreadable_ option */ - if (hide_unreadable && !user_can_read_file(conn, entry)) { + if (hide_unreadable && + !user_can_read_file(conn, smb_fname_base)) { DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry )); - TALLOC_FREE(entry); - return false; + ret = false; + goto out; } /* Honour _hide unwriteable_ option */ if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) { DEBUG(10,("is_visible_file: file %s is unwritable.\n", entry )); - TALLOC_FREE(entry); - return false; + ret = false; + goto out; } /* Honour _hide_special_ option */ if (hide_special && file_is_special(conn, entry, pst)) { DEBUG(10,("is_visible_file: file %s is special.\n", entry )); - TALLOC_FREE(entry); - return false; + ret = false; + goto out; } - TALLOC_FREE(entry); } - return true; + + ret = true; + out: + TALLOC_FREE(smb_fname_base); + TALLOC_FREE(entry); + return ret; } static int smb_Dir_destructor(struct smb_Dir *dirp) diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index 8149eea7f5..afebb9efd0 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -81,7 +81,7 @@ mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname, DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname, inherit_from_dir)); - if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) { + if (vfs_stat_smb_fname(conn, inherit_from_dir, &sbuf) != 0) { DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname, inherit_from_dir, strerror(errno))); return(0); /* *** shouldn't happen! *** */ @@ -560,7 +560,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, } if (!VALID_STAT(*st)) { - if (SMB_VFS_STAT(conn,fname,st)) + if (vfs_stat_smb_fname(conn,fname,st)) return(-1); } diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c index 195f722471..87d45c5e7f 100644 --- a/source3/smbd/file_access.c +++ b/source3/smbd/file_access.c @@ -27,18 +27,26 @@ * Security descriptor / NT Token level access check function. */ bool can_access_file_acl(struct connection_struct *conn, - const char * fname, - uint32_t access_mask) + const struct smb_filename *smb_fname, + uint32_t access_mask) { NTSTATUS status; uint32_t access_granted; struct security_descriptor *secdesc = NULL; + char *fname = NULL; + bool ret; if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return true; } + status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + ret = false; + goto out; + } + status = SMB_VFS_GET_NT_ACL(conn, fname, (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | @@ -46,13 +54,17 @@ bool can_access_file_acl(struct connection_struct *conn, &secdesc); if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status))); - return false; + ret = false; + goto out; } status = se_access_check(secdesc, conn->server_info->ptok, access_mask, &access_granted); + ret = NT_STATUS_IS_OK(status); + out: + TALLOC_FREE(fname); TALLOC_FREE(secdesc); - return NT_STATUS_IS_OK(status); + return ret; } /**************************************************************************** @@ -61,11 +73,13 @@ bool can_access_file_acl(struct connection_struct *conn, ****************************************************************************/ bool can_delete_file_in_directory(connection_struct *conn, - const struct smb_filename *smb_fname) + struct smb_filename *smb_fname) { - SMB_STRUCT_STAT sbuf; TALLOC_CTX *ctx = talloc_tos(); char *dname = NULL; + struct smb_filename *smb_fname_parent = NULL; + NTSTATUS status; + bool ret; if (!CAN_WRITE(conn)) { return False; @@ -75,47 +89,49 @@ bool can_delete_file_in_directory(connection_struct *conn, if (!parent_dirname(ctx, smb_fname->base_name, &dname, NULL)) { return False; } - if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) { - return False; + + status = create_synthetic_smb_fname(ctx, dname, NULL, NULL, + &smb_fname_parent); + if (!NT_STATUS_IS_OK(status)) { + ret = false; + goto out; + } + + if(SMB_VFS_STAT(conn, smb_fname_parent) != 0) { + ret = false; + goto out; } /* fast paths first */ - if (!S_ISDIR(sbuf.st_ex_mode)) { - return False; + if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) { + ret = false; + goto out; } if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ - return True; + ret = true; + goto out; } #ifdef S_ISVTX /* sticky bit means delete only by owner of file or by root or * by owner of directory. */ - if (sbuf.st_ex_mode & S_ISVTX) { - SMB_STRUCT_STAT sbuf_file; - char *fname = NULL; - NTSTATUS status; - - status = get_full_smb_filename(talloc_tos(), smb_fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - return false; - } - if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) { - TALLOC_FREE(fname); + if (smb_fname_parent->st.st_ex_mode & S_ISVTX) { + if(SMB_VFS_STAT(conn, smb_fname) != 0) { if (errno == ENOENT) { /* If the file doesn't already exist then * yes we'll be able to delete it. */ - return True; + ret = true; + goto out; } DEBUG(10,("can_delete_file_in_directory: can't " "stat file %s (%s)", smb_fname_str_dbg(smb_fname), strerror(errno) )); - return False; + ret = false; + goto out; } - TALLOC_FREE(fname); /* * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com> @@ -125,12 +141,15 @@ bool can_delete_file_in_directory(connection_struct *conn, * or the owner of the directory as we have no possible * chance of deleting. Otherwise, go on and check the ACL. */ - if ((conn->server_info->utok.uid != sbuf.st_ex_uid) && - (conn->server_info->utok.uid != sbuf_file.st_ex_uid)) { + if ((conn->server_info->utok.uid != + smb_fname_parent->st.st_ex_uid) && + (conn->server_info->utok.uid != smb_fname->st.st_ex_uid)) { DEBUG(10,("can_delete_file_in_directory: not " "owner of file %s or directory %s", - smb_fname_str_dbg(smb_fname), dname)); - return False; + smb_fname_str_dbg(smb_fname), + smb_fname_str_dbg(smb_fname_parent))); + ret = false; + goto out; } } #endif @@ -146,7 +165,11 @@ bool can_delete_file_in_directory(connection_struct *conn, * check the file DELETE permission separately. */ - return can_access_file_acl(conn, dname, FILE_DELETE_CHILD); + ret = can_access_file_acl(conn, smb_fname_parent, FILE_DELETE_CHILD); + out: + TALLOC_FREE(dname); + TALLOC_FREE(smb_fname_parent); + return ret; } /**************************************************************************** @@ -155,7 +178,9 @@ bool can_delete_file_in_directory(connection_struct *conn, Note this doesn't take into account share write permissions. ****************************************************************************/ -bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf, uint32 access_mask) +bool can_access_file_data(connection_struct *conn, + const struct smb_filename *smb_fname, + uint32 access_mask) { if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) { return False; @@ -165,27 +190,31 @@ bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_ /* some fast paths first */ DEBUG(10,("can_access_file_data: requesting 0x%x on file %s\n", - (unsigned int)access_mask, fname )); + (unsigned int)access_mask, smb_fname_str_dbg(smb_fname))); if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return True; } - SMB_ASSERT(psbuf && VALID_STAT(*psbuf)); + SMB_ASSERT(VALID_STAT(smb_fname->st)); /* Check primary owner access. */ - if (conn->server_info->utok.uid == psbuf->st_ex_uid) { + if (conn->server_info->utok.uid == smb_fname->st.st_ex_uid) { switch (access_mask) { case FILE_READ_DATA: - return (psbuf->st_ex_mode & S_IRUSR) ? True : False; + return (smb_fname->st.st_ex_mode & S_IRUSR) ? + True : False; case FILE_WRITE_DATA: - return (psbuf->st_ex_mode & S_IWUSR) ? True : False; + return (smb_fname->st.st_ex_mode & S_IWUSR) ? + True : False; default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - if ((psbuf->st_ex_mode & (S_IWUSR|S_IRUSR)) == (S_IWUSR|S_IRUSR)) { + if ((smb_fname->st.st_ex_mode & + (S_IWUSR|S_IRUSR)) == + (S_IWUSR|S_IRUSR)) { return True; } else { return False; @@ -195,7 +224,7 @@ bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_ /* now for ACL checks */ - return can_access_file_acl(conn, fname, access_mask); + return can_access_file_acl(conn, smb_fname, access_mask); } /**************************************************************************** @@ -205,7 +234,21 @@ bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_ bool can_write_to_file(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf) { - return can_access_file_data(conn, fname, psbuf, FILE_WRITE_DATA); + struct smb_filename *smb_fname; + NTSTATUS status; + bool ret; + + status = create_synthetic_smb_fname_split(talloc_tos(), fname, psbuf, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + ret = can_access_file_data(conn, smb_fname, FILE_WRITE_DATA); + + TALLOC_FREE(smb_fname); + + return ret; } /**************************************************************************** diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index de5f83c868..843b3f9586 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -949,7 +949,7 @@ NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_throug int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst) { if (fsp->fh->fd == -1) { - return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst); + return vfs_stat_smb_fname(fsp->conn, fsp->fsp_name, pst); } else { return SMB_VFS_FSTAT(fsp, pst); } diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 9854407a70..bf12e86d53 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -110,7 +110,7 @@ NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_f */ NTSTATUS create_synthetic_smb_fname(TALLOC_CTX *ctx, const char *base_name, const char *stream_name, - SMB_STRUCT_STAT *psbuf, + const SMB_STRUCT_STAT *psbuf, struct smb_filename **smb_fname_out) { struct smb_filename smb_fname_loc; @@ -135,15 +135,18 @@ NTSTATUS create_synthetic_smb_fname(TALLOC_CTX *ctx, const char *base_name, */ NTSTATUS create_synthetic_smb_fname_split(TALLOC_CTX *ctx, const char *fname, - SMB_STRUCT_STAT *psbuf, + const SMB_STRUCT_STAT *psbuf, struct smb_filename **smb_fname_out) { NTSTATUS status; const char *stream_name = NULL; char *base_name = NULL; + if (!lp_posix_pathnames()) { + stream_name = strchr_m(fname, ':'); + } + /* Setup the base_name/stream_name. */ - stream_name = strchr_m(fname, ':'); if (stream_name) { base_name = talloc_strndup(ctx, fname, PTR_DIFF(stream_name, fname)); @@ -162,6 +165,60 @@ NTSTATUS create_synthetic_smb_fname_split(TALLOC_CTX *ctx, } /** + * XXX: This is temporary and there should be no callers of this once + * smb_filename is plumbed through all path based operations. + */ +int vfs_stat_smb_fname(struct connection_struct *conn, const char *fname, + SMB_STRUCT_STAT *psbuf) +{ + struct smb_filename *smb_fname = NULL; + NTSTATUS status; + int ret; + + status = create_synthetic_smb_fname_split(talloc_tos(), fname, NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + ret = SMB_VFS_STAT(conn, smb_fname); + if (ret != -1) { + *psbuf = smb_fname->st; + } + + TALLOC_FREE(smb_fname); + return ret; +} + +/** + * XXX: This is temporary and there should be no callers of this once + * smb_filename is plumbed through all path based operations. + */ +int vfs_lstat_smb_fname(struct connection_struct *conn, const char *fname, + SMB_STRUCT_STAT *psbuf) +{ + struct smb_filename *smb_fname = NULL; + NTSTATUS status; + int ret; + + status = create_synthetic_smb_fname_split(talloc_tos(), fname, NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + ret = SMB_VFS_LSTAT(conn, smb_fname); + if (ret != -1) { + *psbuf = smb_fname->st; + } + + TALLOC_FREE(smb_fname); + return ret; +} + +/** * Return a string using the debug_ctx() */ const char *smb_fname_str_dbg(const struct smb_filename *smb_fname) @@ -315,7 +372,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if (!(name = talloc_strdup(ctx,"."))) { return NT_STATUS_NO_MEMORY; } - if (SMB_VFS_STAT(conn,name,&st) == 0) { + if (vfs_stat_smb_fname(conn,name,&st) == 0) { smb_fname->st = st; } else { return map_nt_error_from_unix(errno); @@ -417,9 +474,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (posix_pathnames) { - ret = SMB_VFS_LSTAT(conn,name,&st); + ret = vfs_lstat_smb_fname(conn,name,&st); } else { - ret = SMB_VFS_STAT(conn,name,&st); + ret = vfs_stat_smb_fname(conn,name,&st); } if (ret == 0) { @@ -535,9 +592,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (posix_pathnames) { - ret = SMB_VFS_LSTAT(conn,name, &st); + ret = vfs_lstat_smb_fname(conn,name, &st); } else { - ret = SMB_VFS_STAT(conn,name, &st); + ret = vfs_stat_smb_fname(conn,name, &st); } if (ret == 0) { @@ -764,9 +821,11 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (posix_pathnames) { - ret = SMB_VFS_LSTAT(conn,name, &st); + ret = vfs_lstat_smb_fname(conn,name, + &st); } else { - ret = SMB_VFS_STAT(conn,name, &st); + ret = vfs_stat_smb_fname(conn,name, + &st); } if (ret == 0) { @@ -1073,17 +1132,11 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, const char *orig_path, struct smb_filename *smb_fname) { - char *result = NULL; NTSTATUS status; unsigned int i, num_streams; struct stream_struct *streams = NULL; - status = get_full_smb_filename(mem_ctx, smb_fname, &result); - if (!NT_STATUS_IS_OK(status)) { - return NT_STATUS_NO_MEMORY; - } - - if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) { + if (SMB_VFS_STAT(conn, smb_fname) == 0) { return NT_STATUS_OK; } @@ -1132,24 +1185,22 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, TALLOC_FREE(smb_fname->stream_name); smb_fname->stream_name = talloc_strdup(mem_ctx, streams[i].name); - TALLOC_FREE(result); - status = get_full_smb_filename(mem_ctx, smb_fname, &result); - if (!NT_STATUS_IS_OK(status)) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - SET_STAT_INVALID(smb_fname->st); - if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) { - stat_cache_add(orig_path, result, conn->case_sensitive); - } + if (SMB_VFS_STAT(conn, smb_fname) == 0) { + char *result = NULL; - TALLOC_FREE(streams); - return NT_STATUS_OK; + status = get_full_smb_filename(mem_ctx, smb_fname, &result); + if (!NT_STATUS_IS_OK(status)) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + stat_cache_add(orig_path, result, conn->case_sensitive); + TALLOC_FREE(result); + } + status = NT_STATUS_OK; fail: - TALLOC_FREE(result); TALLOC_FREE(streams); return status; } diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index e2f31f077c..e6f877cfbb 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -437,7 +437,7 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx, sbufp = &st; } - if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) { + if (vfs_lstat_smb_fname(conn, path, sbufp) != 0) { DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n", path)); goto err; diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index 12a75cc9f6..a242fc3ac0 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -341,25 +341,35 @@ void notify_fname(connection_struct *conn, uint32 action, uint32 filter, char *fullpath; char *parent; const char *name; - SMB_STRUCT_STAT sbuf; if (path[0] == '.' && path[1] == '/') { path += 2; } - if (asprintf(&fullpath, "%s/%s", conn->connectpath, path) == -1) { - DEBUG(0, ("asprintf failed\n")); - return; + if (parent_dirname(talloc_tos(), path, &parent, &name)) { + struct smb_filename *smb_fname_parent = NULL; + NTSTATUS status; + + status = create_synthetic_smb_fname(talloc_tos(), parent, NULL, + NULL, &smb_fname_parent); + if (!NT_STATUS_IS_OK(status)) { + return; + } + if (SMB_VFS_STAT(conn, smb_fname_parent) != -1) { + notify_onelevel(conn->notify_ctx, action, filter, + SMB_VFS_FILE_ID_CREATE(conn, &smb_fname_parent->st), + name); + } + TALLOC_FREE(smb_fname_parent); } - if (parent_dirname(talloc_tos(), path, &parent, &name) - && (SMB_VFS_STAT(conn, parent, &sbuf) != -1)) { - notify_onelevel(conn->notify_ctx, action, filter, - SMB_VFS_FILE_ID_CREATE(conn, &sbuf), - name); + fullpath = talloc_asprintf(talloc_tos(), "%s/%s", conn->connectpath, + path); + if (fullpath == NULL) { + DEBUG(0, ("asprintf failed\n")); + return; } - notify_trigger(conn->notify_ctx, action, filter, fullpath); - SAFE_FREE(fullpath); + TALLOC_FREE(fullpath); } static void notify_fsp(files_struct *fsp, uint32 action, const char *name) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 72370c8c7c..5b62ff022d 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -193,31 +193,41 @@ void change_file_owner_to_parent(connection_struct *conn, const char *inherit_from_dir, files_struct *fsp) { - SMB_STRUCT_STAT parent_st; + struct smb_filename *smb_fname_parent = NULL; + NTSTATUS status; int ret; - ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st); + status = create_synthetic_smb_fname(talloc_tos(), inherit_from_dir, + NULL, NULL, &smb_fname_parent); + if (!NT_STATUS_IS_OK(status)) { + return; + } + + ret = SMB_VFS_STAT(conn, smb_fname_parent); if (ret == -1) { DEBUG(0,("change_file_owner_to_parent: failed to stat parent " "directory %s. Error was %s\n", - inherit_from_dir, strerror(errno) )); + smb_fname_str_dbg(smb_fname_parent), + strerror(errno))); return; } become_root(); - ret = SMB_VFS_FCHOWN(fsp, parent_st.st_ex_uid, (gid_t)-1); + ret = SMB_VFS_FCHOWN(fsp, smb_fname_parent->st.st_ex_uid, (gid_t)-1); unbecome_root(); if (ret == -1) { DEBUG(0,("change_file_owner_to_parent: failed to fchown " "file %s to parent directory uid %u. Error " "was %s\n", fsp->fsp_name, - (unsigned int)parent_st.st_ex_uid, + (unsigned int)smb_fname_parent->st.st_ex_uid, strerror(errno) )); } DEBUG(10,("change_file_owner_to_parent: changed new file %s to " "parent directory uid %u.\n", fsp->fsp_name, - (unsigned int)parent_st.st_ex_uid )); + (unsigned int)smb_fname_parent->st.st_ex_uid)); + + TALLOC_FREE(smb_fname_parent); } NTSTATUS change_dir_owner_to_parent(connection_struct *conn, @@ -225,20 +235,27 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) { + struct smb_filename *smb_fname_parent = NULL; + struct smb_filename *smb_fname_cwd = NULL; char *saved_dir = NULL; - SMB_STRUCT_STAT sbuf; - SMB_STRUCT_STAT parent_st; TALLOC_CTX *ctx = talloc_tos(); NTSTATUS status = NT_STATUS_OK; int ret; - ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st); + status = create_synthetic_smb_fname(ctx, inherit_from_dir, NULL, NULL, + &smb_fname_parent); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + ret = SMB_VFS_STAT(conn, smb_fname_parent); if (ret == -1) { status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to stat parent " "directory %s. Error was %s\n", - inherit_from_dir, strerror(errno) )); - return status; + smb_fname_str_dbg(smb_fname_parent), + strerror(errno))); + goto out; } /* We've already done an lstat into psbuf, and we know it's a @@ -254,7 +271,7 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, DEBUG(0,("change_dir_owner_to_parent: failed to get " "current working directory. Error was %s\n", strerror(errno))); - return status; + goto out; } /* Chdir into the new path. */ @@ -263,47 +280,58 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, DEBUG(0,("change_dir_owner_to_parent: failed to change " "current working directory to %s. Error " "was %s\n", fname, strerror(errno) )); - goto out; + goto chdir; + } + + status = create_synthetic_smb_fname(ctx, ".", NULL, NULL, + &smb_fname_cwd); + if (!NT_STATUS_IS_OK(status)) { + return status; } - if (SMB_VFS_STAT(conn,".",&sbuf) == -1) { + ret = SMB_VFS_STAT(conn, smb_fname_cwd); + if (ret == -1) { status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to stat " "directory '.' (%s) Error was %s\n", fname, strerror(errno))); - goto out; + goto chdir; } /* Ensure we're pointing at the same place. */ - if (sbuf.st_ex_dev != psbuf->st_ex_dev || - sbuf.st_ex_ino != psbuf->st_ex_ino || - sbuf.st_ex_mode != psbuf->st_ex_mode ) { + if (smb_fname_cwd->st.st_ex_dev != psbuf->st_ex_dev || + smb_fname_cwd->st.st_ex_ino != psbuf->st_ex_ino || + smb_fname_cwd->st.st_ex_mode != psbuf->st_ex_mode ) { DEBUG(0,("change_dir_owner_to_parent: " "device/inode/mode on directory %s changed. " "Refusing to chown !\n", fname )); status = NT_STATUS_ACCESS_DENIED; - goto out; + goto chdir; } become_root(); - ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_ex_uid, (gid_t)-1); + ret = SMB_VFS_CHOWN(conn, ".", smb_fname_parent->st.st_ex_uid, + (gid_t)-1); unbecome_root(); if (ret == -1) { status = map_nt_error_from_unix(errno); DEBUG(10,("change_dir_owner_to_parent: failed to chown " "directory %s to parent directory uid %u. " "Error was %s\n", fname, - (unsigned int)parent_st.st_ex_uid, strerror(errno) )); - goto out; + (unsigned int)smb_fname_parent->st.st_ex_uid, + strerror(errno) )); + goto chdir; } DEBUG(10,("change_dir_owner_to_parent: changed ownership of new " "directory %s to parent directory uid %u.\n", - fname, (unsigned int)parent_st.st_ex_uid )); - - out: + fname, (unsigned int)smb_fname_parent->st.st_ex_uid )); + chdir: vfs_ChDir(conn,saved_dir); + out: + TALLOC_FREE(smb_fname_parent); + TALLOC_FREE(smb_fname_cwd); return status; } @@ -537,7 +565,7 @@ static NTSTATUS open_file(files_struct *fsp, int ret; if (fsp->fh->fd == -1) { - ret = SMB_VFS_STAT(conn, path, &smb_fname->st); + ret = SMB_VFS_STAT(conn, smb_fname); } else { ret = SMB_VFS_FSTAT(fsp, &smb_fname->st); /* If we have an fd, this stat should succeed. */ @@ -1857,8 +1885,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, can_access_mask = FILE_READ_DATA; } - if (((can_access_mask & FILE_WRITE_DATA) && !CAN_WRITE(conn)) || - !can_access_file_data(conn, fname, &smb_fname->st, can_access_mask)) { + if (((can_access_mask & FILE_WRITE_DATA) && + !CAN_WRITE(conn)) || + !can_access_file_data(conn, smb_fname, + can_access_mask)) { can_access = False; } @@ -2347,7 +2377,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn, /* Ensure we're checking for a symlink here.... */ /* We don't want to get caught by a symlink racer. */ - if (SMB_VFS_LSTAT(conn, name, psbuf) == -1) { + if (vfs_lstat_smb_fname(conn, name, psbuf) == -1) { DEBUG(2, ("Could not stat directory '%s' just created: %s\n", name, strerror(errno))); return map_nt_error_from_unix(errno); @@ -2471,7 +2501,7 @@ static NTSTATUS open_directory(connection_struct *conn, * We want to follow symlinks here. */ - if (SMB_VFS_STAT(conn, fname, &smb_dname->st) != 0) { + if (SMB_VFS_STAT(conn, smb_dname) != 0) { return map_nt_error_from_unix(errno); } @@ -2836,34 +2866,24 @@ NTSTATUS open_streams_for_delete(connection_struct *conn, for (i=0; i<num_streams; i++) { struct smb_filename *smb_fname = NULL; - char *streamname = NULL; - SMB_STRUCT_STAT sbuf; if (strequal(stream_info[i].name, "::$DATA")) { streams[i] = NULL; continue; } - streamname = talloc_asprintf(talloc_tos(), "%s%s", fname, - stream_info[i].name); - if (streamname == NULL) { - DEBUG(0, ("talloc_aprintf failed\n")); - status = NT_STATUS_NO_MEMORY; - } - - if (SMB_VFS_STAT(conn, streamname, &sbuf) == -1) { - SET_STAT_INVALID(sbuf); - } - - TALLOC_FREE(streamname); - status = create_synthetic_smb_fname(talloc_tos(), fname, stream_info[i].name, - &sbuf, &smb_fname); + NULL, &smb_fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } + if (SMB_VFS_STAT(conn, smb_fname) == -1) { + DEBUG(10, ("Unable to stat stream: %s\n", + smb_fname_str_dbg(smb_fname))); + } + status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ @@ -2999,7 +3019,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, && (share_access & FILE_SHARE_DELETE) && (access_mask & DELETE_ACCESS) && (!(can_delete_file_in_directory(conn, smb_fname) || - can_access_file_acl(conn, fname, DELETE_ACCESS)))) { + can_access_file_acl(conn, smb_fname, DELETE_ACCESS)))) { status = NT_STATUS_ACCESS_DENIED; DEBUG(10,("create_file_unixpath: open file %s " "for delete ACCESS_DENIED\n", @@ -3036,7 +3056,6 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) { uint32 base_create_disposition; struct smb_filename *smb_fname_base = NULL; - SMB_STRUCT_STAT sbuf; if (create_options & FILE_DIRECTORY_FILE) { status = NT_STATUS_NOT_A_DIRECTORY; @@ -3052,19 +3071,20 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, break; } - if (SMB_VFS_STAT(conn, smb_fname->base_name, &sbuf) == -1) { - SET_STAT_INVALID(sbuf); - } - /* Create an smb_filename with stream_name == NULL. */ status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name, - NULL, &sbuf, + NULL, NULL, &smb_fname_base); if (!NT_STATUS_IS_OK(status)) { goto fail; } + if (SMB_VFS_STAT(conn, smb_fname_base) == -1) { + DEBUG(10, ("Unable to stat stream: %s\n", + smb_fname_str_dbg(smb_fname_base))); + } + /* Open the base file. */ status = create_file_unixpath(conn, NULL, smb_fname_base, 0, FILE_SHARE_READ diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index bdd27fb794..437112c751 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -3351,7 +3351,7 @@ NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name, DEBUG(10,("posix_get_nt_acl: called for file %s\n", name )); /* Get the stat struct for the owner info. */ - if(SMB_VFS_STAT(conn, name, &sbuf) != 0) { + if(vfs_stat_smb_fname(conn, name, &sbuf) != 0) { return map_nt_error_from_unix(errno); } @@ -3432,7 +3432,7 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) return -1; } - if (SMB_VFS_STAT(conn,fname,&st)) { + if (vfs_stat_smb_fname(conn,fname,&st)) { return -1; } @@ -3685,7 +3685,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC */ if(fsp->is_directory || fsp->fh->fd == -1) { - if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) + if(vfs_stat_smb_fname(fsp->conn,fsp->fsp_name, &sbuf) != 0) return map_nt_error_from_unix(errno); } else { if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) @@ -3730,7 +3730,8 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC */ if(fsp->is_directory) { - if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) { + if(vfs_stat_smb_fname(fsp->conn, fsp->fsp_name, + &sbuf) != 0) { return map_nt_error_from_unix(errno); } } else { @@ -3738,7 +3739,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC int sret; if(fsp->fh->fd == -1) - sret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); + sret = vfs_stat_smb_fname(fsp->conn, + fsp->fsp_name, + &sbuf); else sret = SMB_VFS_FSTAT(fsp, &sbuf); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 9544b845da..8cc865edeb 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -1007,8 +1007,9 @@ void reply_checkpath(struct smb_request *req) } if (!VALID_STAT(smb_fname->st) && - (SMB_VFS_STAT(conn, name, &smb_fname->st) != 0)) { - DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno))); + (SMB_VFS_STAT(conn, smb_fname) != 0)) { + DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), strerror(errno))); status = map_nt_error_from_unix(errno); goto path_err; } @@ -1020,17 +1021,8 @@ void reply_checkpath(struct smb_request *req) } reply_outbuf(req, 0, 0); - out: - TALLOC_FREE(smb_fname); - END_PROFILE(SMBcheckpath); - return; path_err: - - TALLOC_FREE(smb_fname); - - END_PROFILE(SMBcheckpath); - /* We special case this - as when a Windows machine is parsing a path is steps through the components one at a time - if a component fails it expects @@ -1047,10 +1039,15 @@ void reply_checkpath(struct smb_request *req) */ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERRbadpath); - return; + goto out; } reply_nterror(req, status); + + out: + TALLOC_FREE(smb_fname); + END_PROFILE(SMBcheckpath); + return; } /**************************************************************************** @@ -1104,8 +1101,10 @@ void reply_getatr(struct smb_request *req) goto out; } if (!VALID_STAT(smb_fname->st) && - (SMB_VFS_STAT(conn, fname, &smb_fname->st) != 0)) { - DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno))); + (SMB_VFS_STAT(conn, smb_fname) != 0)) { + DEBUG(3,("reply_getatr: stat of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req, ERRDOS,ERRbadfile); goto out; } @@ -1133,10 +1132,12 @@ void reply_getatr(struct smb_request *req) SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME); } - DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) ); + DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", + smb_fname_str_dbg(smb_fname), mode, (unsigned int)size)); out: TALLOC_FREE(smb_fname); + TALLOC_FREE(fname); END_PROFILE(SMBgetatr); return; } @@ -2243,8 +2244,7 @@ void reply_ctemp(struct smb_request *req) goto out; } - SET_STAT_INVALID(smb_fname->st); - SMB_VFS_STAT(conn, smb_fname->base_name, &smb_fname->st); + SMB_VFS_STAT(conn, smb_fname); /* We should fail if file does not exist. */ status = SMB_VFS_CREATE_FILE( @@ -2377,16 +2377,16 @@ static NTSTATUS do_unlink(connection_struct *conn, return NT_STATUS_MEDIA_WRITE_PROTECTED; } + if (SMB_VFS_LSTAT(conn, smb_fname) != 0) { + return map_nt_error_from_unix(errno); + } + status = get_full_smb_filename(smb_fname, smb_fname, &fname); if (!NT_STATUS_IS_OK(status)) { return status; } - - if (SMB_VFS_LSTAT(conn, fname, &smb_fname->st) != 0) { - return map_nt_error_from_unix(errno); - } - fattr = dos_mode(conn, fname, &smb_fname->st); + TALLOC_FREE(fname); if (dirtype & FILE_ATTRIBUTE_NORMAL) { dirtype = aDIR|aARCH|aRONLY; @@ -5259,6 +5259,8 @@ static bool recursive_rmdir(TALLOC_CTX *ctx, while((dname = ReadDirName(dir_hnd, &offset, &st))) { char *fullname = NULL; + struct smb_filename *smb_fname = NULL; + NTSTATUS status; if (ISDOT(dname) || ISDOTDOT(dname)) { continue; @@ -5275,29 +5277,37 @@ static bool recursive_rmdir(TALLOC_CTX *ctx, dname); if (!fullname) { errno = ENOMEM; - ret = False; - break; + goto err_break; } - if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { - ret = False; - break; + status = create_synthetic_smb_fname(talloc_tos(), fullname, + NULL, NULL, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + goto err_break; + } + + if(SMB_VFS_LSTAT(conn, smb_fname) != 0) { + goto err_break; } - if(st.st_ex_mode & S_IFDIR) { + if(smb_fname->st.st_ex_mode & S_IFDIR) { if(!recursive_rmdir(ctx, conn, fullname)) { - ret = False; - break; + goto err_break; } if(SMB_VFS_RMDIR(conn,fullname) != 0) { - ret = False; - break; + goto err_break; } } else if(SMB_VFS_UNLINK(conn,fullname) != 0) { - ret = False; - break; + goto err_break; } + TALLOC_FREE(smb_fname); + TALLOC_FREE(fullname); + continue; + err_break: + TALLOC_FREE(smb_fname); TALLOC_FREE(fullname); + ret = false; + break; } TALLOC_FREE(dir_hnd); return ret; @@ -5315,13 +5325,13 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, SMB_STRUCT_STAT st; /* Might be a symlink. */ - if(SMB_VFS_LSTAT(conn, directory, &st) != 0) { + if(vfs_lstat_smb_fname(conn, directory, &st) != 0) { return map_nt_error_from_unix(errno); } if (S_ISLNK(st.st_ex_mode)) { /* Is what it points to a directory ? */ - if(SMB_VFS_STAT(conn, directory, &st) != 0) { + if(vfs_stat_smb_fname(conn, directory, &st) != 0) { return map_nt_error_from_unix(errno); } if (!(S_ISDIR(st.st_ex_mode))) { @@ -5398,7 +5408,7 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, break; } - if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { + if(vfs_lstat_smb_fname(conn,fullname, &st) != 0) { break; } if(st.st_ex_mode & S_IFDIR) { @@ -5817,10 +5827,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - /* - * Have vfs_object_exist also fill sbuf1 - */ - dst_exists = vfs_object_exist(conn, newname, &sbuf1); + dst_exists = vfs_stat_smb_fname(conn, newname, &sbuf1) == 0; if(!replace_if_exists && dst_exists) { DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n", @@ -5846,9 +5853,10 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, } else { int ret = -1; if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf); + ret = vfs_lstat_smb_fname(conn,fsp->fsp_name,&sbuf); } else { - ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf); + + ret = vfs_stat_smb_fname(conn,fsp->fsp_name,&sbuf); } if (ret == -1) { return map_nt_error_from_unix(errno); @@ -6005,7 +6013,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, if (!src_has_wild) { files_struct *fsp; - char *fname_src = NULL; char *fname_dst = NULL; /* @@ -6063,24 +6070,17 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, smb_fname_dst->base_name = fname_dst_mod; } - status = get_full_smb_filename(ctx, smb_fname_src, &fname_src); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - ZERO_STRUCT(smb_fname_src->st); if (posix_pathnames) { - SMB_VFS_LSTAT(conn, fname_src, &smb_fname_src->st); + SMB_VFS_LSTAT(conn, smb_fname_src); } else { - SMB_VFS_STAT(conn, fname_src, &smb_fname_src->st); + SMB_VFS_STAT(conn, smb_fname_src); } if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { create_options |= FILE_DIRECTORY_FILE; } - TALLOC_FREE(fname_src); - status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ @@ -6108,7 +6108,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, status = get_full_smb_filename(ctx, smb_fname_dst, &fname_dst); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(fname_src); goto out; } @@ -6159,7 +6158,6 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st))) { files_struct *fsp = NULL; - char *fname_src = NULL; char *fname_dst = NULL; char *destname = NULL; bool sysdir_entry = False; @@ -6212,20 +6210,13 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, TALLOC_FREE(smb_fname_dst->base_name); smb_fname_dst->base_name = destname; - status = get_full_smb_filename(ctx, smb_fname_src, &fname_src); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - ZERO_STRUCT(smb_fname_src->st); if (posix_pathnames) { - SMB_VFS_LSTAT(conn, fname_src, &smb_fname_src->st); + SMB_VFS_LSTAT(conn, smb_fname_src); } else { - SMB_VFS_STAT(conn, fname_src, &smb_fname_src->st); + SMB_VFS_STAT(conn, smb_fname_src); } - TALLOC_FREE(fname_src); - create_options = 0; if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { @@ -6416,7 +6407,6 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, { struct smb_filename *smb_fname_dst_tmp = NULL; char *fname_src = NULL; - char *fname_dst = NULL; SMB_OFF_T ret=-1; files_struct *fsp1,*fsp2; uint32 dosattrs; @@ -6502,17 +6492,10 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, TALLOC_FREE(fname_src); - status = get_full_smb_filename(talloc_tos(), smb_fname_dst_tmp, &fname_dst); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - if (SMB_VFS_STAT(conn, fname_dst, &smb_fname_dst_tmp->st) == -1) { + if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) { ZERO_STRUCTP(&smb_fname_dst_tmp->st); } - TALLOC_FREE(fname_dst); - /* Open the dst file for writing. */ status = SMB_VFS_CREATE_FILE( conn, /* conn */ @@ -7509,9 +7492,9 @@ void reply_setattrE(struct smb_request *req) int ret = -1; if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(conn, fsp->fsp_name, &sbuf); + ret = vfs_lstat_smb_fname(conn, fsp->fsp_name, &sbuf); } else { - ret = SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf); + ret = vfs_stat_smb_fname(conn, fsp->fsp_name, &sbuf); } if (ret == -1) { status = map_nt_error_from_unix(errno); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 508f71b44e..0124b2b047 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -643,7 +643,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, NTSTATUS *pstatus) { connection_struct *conn; - SMB_STRUCT_STAT st; + struct smb_filename *smb_fname_cpath = NULL; fstring dev; int ret; char addr[INET6_ADDRSTRLEN]; @@ -651,7 +651,6 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, NTSTATUS status; fstrcpy(dev, pdev); - SET_STAT_INVALID(st); if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) { return NULL; @@ -990,14 +989,21 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, /* Any error exit after here needs to call the disconnect hook. */ on_err_call_dis_hook = true; + status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath, + NULL, NULL, &smb_fname_cpath); + if (!NT_STATUS_IS_OK(status)) { + *pstatus = status; + goto err_root_exit; + } + /* win2000 does not check the permissions on the directory during the tree connect, instead relying on permission check during individual operations. To match this behaviour I have disabled this chdir check (tridge) */ /* the alternative is just to check the directory exists */ - if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 || - !S_ISDIR(st.st_ex_mode)) { - if (ret == 0 && !S_ISDIR(st.st_ex_mode)) { + if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 || + !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { + if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to " "[%s]\n", conn->connectpath, lp_servicename(snum))); @@ -1059,7 +1065,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, return(conn); err_root_exit: - + TALLOC_FREE(smb_fname_cpath); change_to_root_user(); if (on_err_call_dis_hook) { /* Call VFS disconnect hook */ diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index 2f7d16790d..daed9f8225 100644 --- a/source3/smbd/statcache.c +++ b/source3/smbd/statcache.c @@ -274,7 +274,7 @@ bool stat_cache_lookup(connection_struct *conn, "-> [%s]\n", chk_name, translated_path )); DO_PROFILE_INC(statcache_hits); - if (SMB_VFS_STAT(conn, translated_path, pst) != 0) { + if (vfs_stat_smb_fname(conn, translated_path, pst) != 0) { /* Discard this entry - it doesn't exist in the filesystem. */ memcache_delete(smbd_memcache(), STAT_CACHE, data_blob_const(chk_name, strlen(chk_name))); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index ca90c5ae69..a7d5c427d3 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1395,14 +1395,17 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, } if (INFO_LEVEL_IS_UNIX(info_level)) { - if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) { + if (vfs_lstat_smb_fname(conn, pathreal, + &sbuf) != 0) { DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n", pathreal,strerror(errno))); TALLOC_FREE(pathreal); TALLOC_FREE(fname); continue; } - } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) { + } else if (!VALID_STAT(sbuf) && + vfs_stat_smb_fname(conn, pathreal, + &sbuf) != 0) { /* Needed to show the msdfs symlinks as * directories */ @@ -2626,7 +2629,7 @@ static void call_trans2qfsinfo(connection_struct *conn, DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); - if(SMB_VFS_STAT(conn,".",&st)!=0) { + if(vfs_stat_smb_fname(conn,".",&st)!=0) { DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); reply_doserror(req, ERRSRV, ERRinvdevice); return; @@ -3871,13 +3874,13 @@ static void call_trans2qfilepathinfo(connection_struct *conn, char *lock_data = NULL; bool ms_dfs_link = false; TALLOC_CTX *ctx = talloc_tos(); + NTSTATUS status = NT_STATUS_OK; if (!params) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } - ZERO_STRUCT(sbuf); ZERO_STRUCT(write_time_ts); if (tran_call == TRANSACT2_QFILEINFO) { @@ -3915,6 +3918,13 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } + status = create_synthetic_smb_fname_split(talloc_tos(), fname, + NULL, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + if(fsp->fake_file_handle) { /* * This is actually for the QUOTA_FAKE_FILE --metze @@ -3931,18 +3941,25 @@ static void call_trans2qfilepathinfo(connection_struct *conn, if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + if (SMB_VFS_LSTAT(conn, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req,ERRDOS,ERRbadpath); return; } - } else if (SMB_VFS_STAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); + } else if (SMB_VFS_STAT(conn, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_STAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req, ERRDOS, ERRbadpath); return; } - fileid = vfs_file_id_from_sbuf(conn, &sbuf); + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); get_file_infos(fileid, &delete_pending, &write_time_ts); } else { /* @@ -3952,19 +3969,18 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } - if (SMB_VFS_FSTAT(fsp, &sbuf) != 0) { - DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); + if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { + DEBUG(3, ("fstat of fnum %d failed (%s)\n", + fsp->fnum, strerror(errno))); reply_unixerror(req, ERRDOS, ERRbadfid); return; } pos = fsp->fh->position_information; - fileid = vfs_file_id_from_sbuf(conn, &sbuf); + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); get_file_infos(fileid, &delete_pending, &write_time_ts); } } else { - NTSTATUS status = NT_STATUS_OK; - /* qpathinfo */ if (total_params < 7) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -4005,41 +4021,50 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } - sbuf = smb_fname->st; - + /* If this is a stream, check if there is a delete_pending. */ if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && is_ntfs_stream_name(fname)) { - char *base; - SMB_STRUCT_STAT bsbuf; - - status = split_ntfs_stream_name(talloc_tos(), fname, - &base, NULL); + && is_ntfs_stream_smb_fname(smb_fname)) { + struct smb_filename *smb_fname_base = NULL; + + /* Create an smb_filename with stream_name == NULL. */ + status = + create_synthetic_smb_fname(talloc_tos(), + smb_fname->base_name, + NULL, NULL, + &smb_fname_base); if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("create_file_unixpath: " - "split_ntfs_stream_name failed: %s\n", - nt_errstr(status))); reply_nterror(req, status); return; } - SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */ - if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn,base,&bsbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",base,strerror(errno))); + if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname_base), + strerror(errno))); + TALLOC_FREE(smb_fname_base); reply_unixerror(req,ERRDOS,ERRbadpath); return; } } else { - if (SMB_VFS_STAT(conn,base,&bsbuf) != 0) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",base,strerror(errno))); + if (SMB_VFS_STAT(conn, smb_fname_base) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: " + "fileinfo of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname_base), + strerror(errno))); + TALLOC_FREE(smb_fname_base); reply_unixerror(req,ERRDOS,ERRbadpath); return; } } - fileid = vfs_file_id_from_sbuf(conn, &bsbuf); + fileid = vfs_file_id_from_sbuf(conn, + &smb_fname_base->st); + TALLOC_FREE(smb_fname_base); get_file_infos(fileid, &delete_pending, NULL); if (delete_pending) { reply_nterror(req, NT_STATUS_DELETE_PENDING); @@ -4049,23 +4074,32 @@ static void call_trans2qfilepathinfo(connection_struct *conn, if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + if (SMB_VFS_LSTAT(conn, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req, ERRDOS, ERRbadpath); return; } - } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf) && (info_level != SMB_INFO_IS_NAME_VALID)) { - ms_dfs_link = check_msdfs_link(conn,fname,&sbuf); + } else if (!VALID_STAT(smb_fname->st) && + SMB_VFS_STAT(conn, smb_fname) && + (info_level != SMB_INFO_IS_NAME_VALID)) { + ms_dfs_link = check_msdfs_link(conn, fname, + &smb_fname->st); if (!ms_dfs_link) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_STAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req, ERRDOS, ERRbadpath); return; } } - fileid = vfs_file_id_from_sbuf(conn, &sbuf); + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); get_file_infos(fileid, &delete_pending, &write_time_ts); if (delete_pending) { reply_nterror(req, NT_STATUS_DELETE_PENDING); @@ -4073,6 +4107,9 @@ static void call_trans2qfilepathinfo(connection_struct *conn, } } + /* Set sbuf for use below. */ + sbuf = smb_fname->st; + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; @@ -4511,7 +4548,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_FILE_STREAM_INFORMATION: { unsigned int num_streams; struct stream_struct *streams; - NTSTATUS status; DEBUG(10,("call_trans2qfilepathinfo: " "SMB_FILE_STREAM_INFORMATION\n")); @@ -4738,7 +4774,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_POSIX_LOCK: { - NTSTATUS status = NT_STATUS_INVALID_LEVEL; uint64_t count; uint64_t offset; uint32 lock_pid; @@ -6024,7 +6059,7 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, TALLOC_FREE(parent); } - if (SMB_VFS_STAT(conn, fname, psbuf) != 0) { + if (vfs_stat_smb_fname(conn, fname, psbuf) != 0) { status = map_nt_error_from_unix(errno); SMB_VFS_UNLINK(conn,fname); return status; @@ -6742,8 +6777,6 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - ZERO_STRUCT(sbuf); - if (tran_call == TRANSACT2_SETFILEINFO) { if (total_params < 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -6763,6 +6796,13 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } + status = create_synthetic_smb_fname_split(talloc_tos(), fname, + NULL, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + if(fsp->is_directory || fsp->fh->fd == -1) { /* * This is actually a SETFILEINFO on a directory @@ -6771,14 +6811,21 @@ static void call_trans2setfilepathinfo(connection_struct *conn, */ if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + if (SMB_VFS_LSTAT(conn, smb_fname)) { + DEBUG(3,("call_trans2setfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req,ERRDOS,ERRbadpath); return; } } else { - if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); + if (SMB_VFS_STAT(conn, smb_fname) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: " + "fileinfo of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req,ERRDOS,ERRbadpath); return; } @@ -6809,8 +6856,10 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - if (SMB_VFS_FSTAT(fsp, &sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); + if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: fstat " + "of fnum %d failed (%s)\n", fsp->fnum, + strerror(errno))); reply_unixerror(req, ERRDOS, ERRbadfid); return; } @@ -6847,23 +6896,28 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - sbuf = smb_fname->st; - if (INFO_LEVEL_IS_UNIX(info_level)) { /* * For CIFS UNIX extensions the target name may not exist. */ /* Always do lstat for UNIX calls. */ - SMB_VFS_LSTAT(conn,fname,&sbuf); - - } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); + SMB_VFS_LSTAT(conn, smb_fname); + + } else if (!VALID_STAT(smb_fname->st) && + SMB_VFS_STAT(conn, smb_fname)) { + DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of " + "%s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req, ERRDOS, ERRbadpath); return; } } + /* Set sbuf for use below. */ + sbuf = smb_fname->st; + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 385454e587..2b4124bf7b 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -339,71 +339,18 @@ bool smbd_vfs_init(connection_struct *conn) } /******************************************************************* - Check if directory exists. -********************************************************************/ - -bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st) -{ - SMB_STRUCT_STAT st2; - bool ret; - - if (!st) - st = &st2; - - if (SMB_VFS_STAT(conn,dname,st) != 0) - return(False); - - ret = S_ISDIR(st->st_ex_mode); - if(!ret) - errno = ENOTDIR; - - return ret; -} - -/******************************************************************* - Check if an object exists in the vfs. -********************************************************************/ - -bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf) -{ - SMB_STRUCT_STAT st; - - if (!sbuf) - sbuf = &st; - - ZERO_STRUCTP(sbuf); - - if (SMB_VFS_STAT(conn,fname,sbuf) == -1) - return(False); - return True; -} - -/******************************************************************* Check if a file exists in the vfs. ********************************************************************/ NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname) { - char *fname = NULL; - NTSTATUS status; - - status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - if (SMB_VFS_STAT(conn, fname, &smb_fname->st) == -1) { - goto out; - } - /* Only return OK if stat was successful and S_ISREG */ - if (S_ISREG(smb_fname->st.st_ex_mode)) { - status = NT_STATUS_OK; + if ((SMB_VFS_STAT(conn, smb_fname) != -1) && + S_ISREG(smb_fname->st.st_ex_mode)) { + return NT_STATUS_OK; } - out: - TALLOC_FREE(fname); - return status; + + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /**************************************************************************** @@ -791,10 +738,12 @@ int vfs_ChDir(connection_struct *conn, const char *path) char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) { char s[PATH_MAX+1]; - SMB_STRUCT_STAT st, st2; - char *result; + char *result = NULL; DATA_BLOB cache_value; struct file_id key; + struct smb_filename *smb_fname_dot = NULL; + struct smb_filename *smb_fname_full = NULL; + NTSTATUS status; *s = 0; @@ -802,9 +751,14 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) goto nocache; } - SET_STAT_INVALID(st); + status = create_synthetic_smb_fname(ctx, ".", NULL, NULL, + &smb_fname_dot); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto out; + } - if (SMB_VFS_STAT(conn, ".",&st) == -1) { + if (SMB_VFS_STAT(conn, smb_fname_dot) == -1) { /* * Known to fail for root: the directory may be NFS-mounted * and exported with root_squash (so has no root access). @@ -814,7 +768,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) goto nocache; } - key = vfs_file_id_from_sbuf(conn, &st); + key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st); if (!memcache_lookup(smbd_memcache(), GETWD_CACHE, data_blob_const(&key, sizeof(key)), @@ -825,17 +779,25 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) SMB_ASSERT((cache_value.length > 0) && (cache_value.data[cache_value.length-1] == '\0')); - if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0) - && (st.st_ex_dev == st2.st_ex_dev) && (st.st_ex_ino == st2.st_ex_ino) - && (S_ISDIR(st.st_ex_mode))) { + status = create_synthetic_smb_fname(ctx, (char *)cache_value.data, + NULL, NULL, &smb_fname_full); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto out; + } + + if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) && + (smb_fname_dot->st.st_ex_dev == smb_fname_full->st.st_ex_dev) && + (smb_fname_dot->st.st_ex_ino == smb_fname_full->st.st_ex_ino) && + (S_ISDIR(smb_fname_dot->st.st_ex_mode))) { /* * Ok, we're done */ - result = talloc_strdup(ctx, (char *)cache_value.data); + result = talloc_strdup(ctx, smb_fname_full->base_name); if (result == NULL) { errno = ENOMEM; } - return result; + goto out; } nocache: @@ -849,11 +811,11 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) if (!SMB_VFS_GETWD(conn,s)) { DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n", strerror(errno))); - return NULL; + goto out; } - if (lp_getwd_cache() && VALID_STAT(st)) { - key = vfs_file_id_from_sbuf(conn, &st); + if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) { + key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st); memcache_add(smbd_memcache(), GETWD_CACHE, data_blob_const(&key, sizeof(key)), @@ -864,6 +826,10 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) if (result == NULL) { errno = ENOMEM; } + + out: + TALLOC_FREE(smb_fname_dot); + TALLOC_FREE(smb_fname_full); return result; } @@ -997,7 +963,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) #ifdef S_ISLNK if (!lp_symlinks(SNUM(conn))) { SMB_STRUCT_STAT statbuf; - if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) && + if ( (vfs_lstat_smb_fname(conn,fname,&statbuf) != -1) && (S_ISLNK(statbuf.st_ex_mode)) ) { if (free_resolved_name) { SAFE_FREE(resolved_name); diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c index f1f4aed77c..0a682c7fd9 100644 --- a/source3/torture/cmd_vfs.c +++ b/source3/torture/cmd_vfs.c @@ -554,19 +554,30 @@ static NTSTATUS cmd_stat(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, c const char *group; struct passwd *pwd = NULL; struct group *grp = NULL; + struct smb_filename *smb_fname = NULL; SMB_STRUCT_STAT st; time_t tmp_time; + NTSTATUS status; if (argc != 2) { printf("Usage: stat <fname>\n"); return NT_STATUS_OK; } - ret = SMB_VFS_STAT(vfs->conn, argv[1], &st); + status = create_synthetic_smb_fname_split(mem_ctx, argv[1], NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + ret = SMB_VFS_STAT(vfs->conn, smb_fname); if (ret == -1) { printf("stat: error=%d (%s)\n", errno, strerror(errno)); + TALLOC_FREE(smb_fname); return NT_STATUS_UNSUCCESSFUL; } + st = smb_fname->st; + TALLOC_FREE(smb_fname); pwd = sys_getpwuid(st.st_ex_uid); if (pwd != NULL) user = pwd->pw_name; @@ -684,18 +695,29 @@ static NTSTATUS cmd_lstat(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char *group; struct passwd *pwd = NULL; struct group *grp = NULL; + struct smb_filename *smb_fname = NULL; SMB_STRUCT_STAT st; time_t tmp_time; + NTSTATUS status; if (argc != 2) { printf("Usage: lstat <path>\n"); return NT_STATUS_OK; } - if (SMB_VFS_LSTAT(vfs->conn, argv[1], &st) == -1) { + status = create_synthetic_smb_fname_split(mem_ctx, argv[1], NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (SMB_VFS_LSTAT(vfs->conn, smb_fname) == -1) { printf("lstat: error=%d (%s)\n", errno, strerror(errno)); + TALLOC_FREE(smb_fname); return NT_STATUS_UNSUCCESSFUL; } + st = smb_fname->st; + TALLOC_FREE(smb_fname); pwd = sys_getpwuid(st.st_ex_uid); if (pwd != NULL) user = pwd->pw_name; |