X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fmodules%2Fvfs_default.c;h=b7e70a608b0d4a499b8398454efb590df1bfc4e8;hb=HEAD;hp=722a3424c3188762d0cdfa4f027bb37a7161991f;hpb=96f1af04ffce5e276443e390d5d6339dbf17a06d;p=samba.git diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 722a3424c31..48b5dd9e39f 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -49,7 +49,34 @@ static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user) { + bool bval; + handle->conn->have_proc_fds = sys_have_proc_fds(); +#ifdef DISABLE_PROC_FDS + handle->conn->have_proc_fds = false; +#endif + + /* + * assume the kernel will support openat2(), + * it will be reset on the first ENOSYS. + * + * Note that libreplace will always provide openat2(), + * but return -1/errno = ENOSYS... + * + * The option is only there to test the fallback code. + */ + bval = lp_parm_bool(SNUM(handle->conn), + "vfs_default", + "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS", + true); + if (bval) { + handle->conn->open_how_resolve |= + VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS; + } +#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS + handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS; +#endif + return 0; /* Return >= 0 for success */ } @@ -117,8 +144,8 @@ static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle, } static int vfswrap_statvfs(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - vfs_statvfs_struct *statbuf) + const struct smb_filename *smb_fname, + struct vfs_statvfs_struct *statbuf) { return sys_statvfs(smb_fname->base_name, statbuf); } @@ -179,12 +206,12 @@ static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle, *p_ts_res = TIMESTAMP_SET_SECONDS; #endif - DEBUG(10,("vfswrap_fs_capabilities: timestamp " + DBG_DEBUG("vfswrap_fs_capabilities: timestamp " "resolution of %s " "available on share %s, directory %s\n", *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec", lp_servicename(talloc_tos(), lp_sub, conn->params->service), - conn->connectpath )); + conn->connectpath ); } TALLOC_FREE(smb_fname_cpath); return caps; @@ -194,7 +221,7 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle, struct dfs_GetDFSReferral *r) { struct junction_map *junction = NULL; - int consumedcnt = 0; + size_t consumedcnt = 0; bool self_referral = false; char *pathnamep = NULL; char *local_dfs_path = NULL; @@ -202,7 +229,7 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle, size_t i; uint16_t max_referral_level = r->in.req.max_referral_level; - if (DEBUGLVL(10)) { + if (DEBUGLVL(DBGLVL_DEBUG)) { NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r); } @@ -237,7 +264,6 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle, pathnamep, handle->conn->sconn->remote_address, handle->conn->sconn->local_address, - !handle->conn->sconn->using_smb2, junction, &consumedcnt, &self_referral); if (!NT_STATUS_IS_OK(status)) { struct smb_filename connectpath_fname = { @@ -256,7 +282,7 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle, if (!self_referral) { pathnamep[consumedcnt] = '\0'; - if (DEBUGLVL(3)) { + if (DEBUGLVL(DBGLVL_INFO)) { dbgtext("Path %s to alternate path(s):", pathnamep); for (i=0; i < junction->referral_count; i++) { @@ -363,12 +389,12 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle, } break; default: - DEBUG(0,("Invalid dfs referral version: %d\n", - max_referral_level)); + DBG_ERR("Invalid dfs referral version: %d\n", + max_referral_level); return NT_STATUS_INVALID_LEVEL; } - if (DEBUGLVL(10)) { + if (DEBUGLVL(DBGLVL_DEBUG)) { NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r); } @@ -437,8 +463,6 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle, #endif int ret; - SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp); - if (is_named_stream(smb_fname)) { status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto err; @@ -459,7 +483,7 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle, } } - referral_len = readlinkat(fsp_get_io_fd(dirfsp), + referral_len = readlinkat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, link_target, bufsize - 1); @@ -474,10 +498,17 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle, status = NT_STATUS_OBJECT_TYPE_MISMATCH; } else { status = map_nt_error_from_unix(errno); - DBG_ERR("Error reading " - "msdfs link %s: %s\n", - smb_fname->base_name, - strerror(errno)); + if (errno == ENOENT) { + DBG_NOTICE("Error reading " + "msdfs link %s: %s\n", + smb_fname->base_name, + strerror(errno)); + } else { + DBG_ERR("Error reading " + "msdfs link %s: %s\n", + smb_fname->base_name, + strerror(errno)); + } } goto err; } @@ -492,9 +523,11 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle, goto err; } - ret = sys_lstat(smb_fname->base_name, - &smb_fname->st, - lp_fake_directory_create_times(SNUM(handle->conn))); + ret = sys_fstatat(fsp_get_pathref_fd(dirfsp), + smb_fname->base_name, + &smb_fname->st, + AT_SYMLINK_NOFOLLOW, + lp_fake_directory_create_times(SNUM(handle->conn))); if (ret < 0) { status = map_nt_error_from_unix(errno); goto err; @@ -567,67 +600,17 @@ static DIR *vfswrap_fdopendir(vfs_handle_struct *handle, return result; } - static struct dirent *vfswrap_readdir(vfs_handle_struct *handle, struct files_struct *dirfsp, - DIR *dirp, - SMB_STRUCT_STAT *sbuf) + DIR *dirp) { struct dirent *result; - bool do_stat = false; - bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn)); - int flags = AT_SYMLINK_NOFOLLOW; - struct stat st; - int ret; START_PROFILE(syscall_readdir); -#if defined(HAVE_DIRFD) && defined(HAVE_FSTATAT) - do_stat = true; -#endif - result = readdir(dirp); END_PROFILE(syscall_readdir); - if (sbuf == NULL) { - return result; - } - if (result == NULL) { - return NULL; - } - - /* - * Default Posix readdir() does not give us stat info. - * Set to invalid to indicate we didn't return this info. - */ - SET_STAT_INVALID(*sbuf); - - /* See if we can efficiently return this. */ - if (!do_stat) { - return result; - } - - ret = fstatat(dirfd(dirp), - result->d_name, - &st, - flags); - if (ret != 0) { - return result; - } - - /* - * As this is an optimization, ignore it if we stat'ed a - * symlink for non-POSIX context. Make the caller do it again - * as we don't know if they wanted the link info, or its - * target info. - */ - if (S_ISLNK(st.st_mode) && - !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH)) - { - return result; - } - init_stat_ex_from_stat(sbuf, &st, fake_ctime); - return result; } @@ -639,22 +622,6 @@ static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle, return NT_STATUS_NOT_SUPPORTED; } -static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset) -{ - START_PROFILE(syscall_seekdir); - seekdir(dirp, offset); - END_PROFILE(syscall_seekdir); -} - -static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp) -{ - long result; - START_PROFILE(syscall_telldir); - result = telldir(dirp); - END_PROFILE(syscall_telldir); - return result; -} - static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp) { START_PROFILE(syscall_rewinddir); @@ -693,28 +660,79 @@ static int vfswrap_openat(vfs_handle_struct *handle, const struct files_struct *dirfsp, const struct smb_filename *smb_fname, files_struct *fsp, - int flags, - mode_t mode) + const struct vfs_open_how *how) { + int flags = how->flags; + mode_t mode = how->mode; bool have_opath = false; bool became_root = false; int result; START_PROFILE(syscall_openat); - if (is_named_stream(smb_fname)) { - errno = ENOENT; + if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS | + VFS_OPEN_HOW_WITH_BACKUP_INTENT)) { + errno = ENOSYS; result = -1; goto out; } + SMB_ASSERT(!is_named_stream(smb_fname)); + #ifdef O_PATH have_opath = true; if (fsp->fsp_flags.is_pathref) { flags |= O_PATH; } + if (flags & O_PATH) { + /* + * From "man 2 openat": + * + * When O_PATH is specified in flags, flag bits other than + * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored. + * + * From "man 2 openat2": + * + * Whereas openat(2) ignores unknown bits in its flags + * argument, openat2() returns an error if unknown or + * conflicting flags are specified in how.flags. + * + * So we better clear ignored/invalid flags + * and only keep the expected ones. + */ + flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); + } #endif + if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) { + struct open_how linux_how = { + .flags = flags, + .mode = mode, + .resolve = RESOLVE_NO_SYMLINKS, + }; + + result = openat2(fsp_get_pathref_fd(dirfsp), + smb_fname->base_name, + &linux_how, + sizeof(linux_how)); + if (result == -1) { + if (errno == ENOSYS) { + /* + * The kernel doesn't support + * openat2(), so indicate to + * the callers that + * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS + * would just be a waste of time. + */ + fsp->conn->open_how_resolve &= + ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS; + } + goto out; + } + + goto done; + } + if (fsp->fsp_flags.is_pathref && !have_opath) { become_root(); became_root = true; @@ -726,10 +744,22 @@ static int vfswrap_openat(vfs_handle_struct *handle, mode); if (became_root) { + int err = errno; unbecome_root(); + errno = err; } - fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds; +done: + if (result >= 0) { + fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds; + } else { + /* + * "/proc/self/fd/-1" never exists. Indicate to upper + * layers that for this fsp a possible name-based + * fallback is the only way to go. + */ + fsp->fsp_flags.have_proc_fds = false; + } out: END_PROFILE(syscall_openat); @@ -737,6 +767,7 @@ out: } static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle, struct smb_request *req, + struct files_struct *dirfsp, struct smb_filename *smb_fname, uint32_t access_mask, uint32_t share_access, @@ -754,7 +785,7 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle, const struct smb2_create_blobs *in_context_blobs, struct smb2_create_blobs *out_context_blobs) { - return create_file_default(handle->conn, req, smb_fname, + return create_file_default(handle->conn, req, dirfsp, smb_fname, access_mask, share_access, create_disposition, create_options, file_attributes, oplock_request, lease, @@ -1252,17 +1283,14 @@ static int vfswrap_renameat(vfs_handle_struct *handle, START_PROFILE(syscall_renameat); - if (is_named_stream(smb_fname_src) || is_named_stream(smb_fname_dst)) { - errno = ENOENT; - goto out; - } + SMB_ASSERT(!is_named_stream(smb_fname_src)); + SMB_ASSERT(!is_named_stream(smb_fname_dst)); result = renameat(fsp_get_pathref_fd(srcfsp), smb_fname_src->base_name, fsp_get_pathref_fd(dstfsp), smb_fname_dst->base_name); - out: END_PROFILE(syscall_renameat); return result; } @@ -1274,14 +1302,11 @@ static int vfswrap_stat(vfs_handle_struct *handle, START_PROFILE(syscall_stat); - if (is_named_stream(smb_fname)) { - errno = ENOENT; - goto out; - } + SMB_ASSERT(!is_named_stream(smb_fname)); result = sys_stat(smb_fname->base_name, &smb_fname->st, lp_fake_directory_create_times(SNUM(handle->conn))); - out: + END_PROFILE(syscall_stat); return result; } @@ -1304,18 +1329,39 @@ static int vfswrap_lstat(vfs_handle_struct *handle, START_PROFILE(syscall_lstat); - if (is_named_stream(smb_fname)) { - errno = ENOENT; - goto out; - } + SMB_ASSERT(!is_named_stream(smb_fname)); result = sys_lstat(smb_fname->base_name, &smb_fname->st, lp_fake_directory_create_times(SNUM(handle->conn))); - out: + END_PROFILE(syscall_lstat); return result; } +static int vfswrap_fstatat( + struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + SMB_STRUCT_STAT *sbuf, + int flags) +{ + int result = -1; + + START_PROFILE(syscall_fstatat); + + SMB_ASSERT(!is_named_stream(smb_fname)); + + result = sys_fstatat( + fsp_get_pathref_fd(dirfsp), + smb_fname->base_name, + sbuf, + flags, + lp_fake_directory_create_times(SNUM(handle->conn))); + + END_PROFILE(syscall_fstatat); + return result; +} + static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle, const char *name, enum vfs_translate_direction direction, @@ -1325,6 +1371,63 @@ static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle, return NT_STATUS_NONE_MAPPED; } +/** + * Return allocated parent directory and basename of path + * + * Note: if requesting atname, it is returned as talloc child of the + * parent. Freeing the parent is thus sufficient to free both. + */ +static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + const struct smb_filename *smb_fname_in, + struct smb_filename **parent_dir_out, + struct smb_filename **atname_out) +{ + struct smb_filename *parent = NULL; + struct smb_filename *name = NULL; + char *p = NULL; + + parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in); + if (parent == NULL) { + return NT_STATUS_NO_MEMORY; + } + SET_STAT_INVALID(parent->st); + + p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */ + if (p == NULL) { + TALLOC_FREE(parent->base_name); + parent->base_name = talloc_strdup(parent, "."); + if (parent->base_name == NULL) { + TALLOC_FREE(parent); + return NT_STATUS_NO_MEMORY; + } + p = smb_fname_in->base_name; + } else { + *p = '\0'; + p++; + } + + if (atname_out == NULL) { + *parent_dir_out = parent; + return NT_STATUS_OK; + } + + name = synthetic_smb_fname( + parent, + p, + smb_fname_in->stream_name, + &smb_fname_in->st, + smb_fname_in->twrp, + smb_fname_in->flags); + if (name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + *parent_dir_out = parent; + *atname_out = name; + return NT_STATUS_OK; +} + /* * Implement the default fsctl operation. */ @@ -1345,6 +1448,14 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, char **out_data = (char **)_out_data; NTSTATUS status; + /* + * Currently all fsctls operate on the base + * file if given an alternate data stream. + * Revisit this if we implement fsctls later + * that need access to the ADS handle. + */ + fsp = metadata_fsp(fsp); + switch (function) { case FSCTL_SET_SPARSE: { @@ -1367,19 +1478,19 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, case FSCTL_CREATE_OR_GET_OBJECT_ID: { unsigned char objid[16]; - char *return_data = NULL; + uint8_t *return_data = NULL; /* This should return the object-id on this file. * I think I'll make this be the inode+dev. JRA. */ - DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n", - fsp_fnum_dbg(fsp))); + DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n", + fsp_fnum_dbg(fsp)); *out_len = MIN(max_out_len, 64); /* Hmmm, will this cause problems if less data asked for? */ - return_data = talloc_array(ctx, char, 64); + return_data = talloc_array(ctx, uint8_t, 64); if (return_data == NULL) { return NT_STATUS_NO_MEMORY; } @@ -1387,16 +1498,17 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, /* For backwards compatibility only store the dev/inode. */ push_file_id_16(return_data, &fsp->file_id); memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16); - push_file_id_16(return_data+32, &fsp->file_id); + push_file_id_16(return_data + 32, &fsp->file_id); memset(return_data+48, 0, 16); - *out_data = return_data; + *_out_data = return_data; return NT_STATUS_OK; } case FSCTL_GET_REPARSE_POINT: { + uint32_t tag; status = fsctl_get_reparse_point( - fsp, ctx, out_data, max_out_len, out_len); + fsp, ctx, &tag, _out_data, max_out_len, out_len); return status; } @@ -1431,8 +1543,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, char *cur_pdata = NULL; if (max_out_len < 16) { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n", - max_out_len)); + DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n", + max_out_len); return NT_STATUS_INVALID_PARAMETER; } @@ -1442,7 +1554,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, shadow_data = talloc_zero(ctx, struct shadow_copy_data); if (shadow_data == NULL) { - DEBUG(0,("TALLOC_ZERO() failed!\n")); + DBG_ERR("TALLOC_ZERO() failed!\n"); return NT_STATUS_NO_MEMORY; } @@ -1450,7 +1562,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, * Call the VFS routine to actually do the work. */ if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) { - int log_lev = 0; + int log_lev = DBGLVL_ERR; if (errno == 0) { /* broken module didn't set errno on error */ status = NT_STATUS_UNSUCCESSFUL; @@ -1458,7 +1570,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, status = map_nt_error_from_unix(errno); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { - log_lev = 5; + log_lev = DBGLVL_INFO; } } DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: " @@ -1479,8 +1591,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, } if (max_out_len < *out_len) { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n", - max_out_len, *out_len)); + DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n", + max_out_len, *out_len); TALLOC_FREE(shadow_data); return NT_STATUS_BUFFER_TOO_SMALL; } @@ -1506,8 +1618,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, cur_pdata += 12; - DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n", - shadow_data->num_volumes, fsp_str_dbg(fsp))); + DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n", + shadow_data->num_volumes, fsp_str_dbg(fsp)); if (labels && shadow_data->labels) { for (i=0; inum_volumes; i++) { size_t len = 0; @@ -1521,7 +1633,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, return status; } cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL); - DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i])); + DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i])); } } @@ -1544,8 +1656,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, uid_t uid; size_t sid_len; - DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n", - fsp_fnum_dbg(fsp))); + DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n", + fsp_fnum_dbg(fsp)); if (in_len < 8) { /* NT_STATUS_BUFFER_TOO_SMALL maybe? */ @@ -1561,13 +1673,13 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, if (ret == -1) { return NT_STATUS_INVALID_PARAMETER; } - DEBUGADD(10, ("for SID: %s\n", + DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n", dom_sid_str_buf(&sid, &buf))); if (!sid_to_uid(&sid, &uid)) { - DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n", + DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n", dom_sid_str_buf(&sid, &buf), - (unsigned long)sid_len)); + (unsigned long)sid_len); uid = (-1); } @@ -1608,14 +1720,14 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, char *out_data_tmp = NULL; if (in_len != 16) { - DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n", - in_len)); + DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n", + in_len); return NT_STATUS_INVALID_PARAMETER; } if (max_out_len < 16) { - DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n", - max_out_len)); + DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n", + max_out_len); return NT_STATUS_INVALID_PARAMETER; } @@ -1636,7 +1748,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, *out_len = 16; out_data_tmp = talloc_array(ctx, char, *out_len); if (out_data_tmp == NULL) { - DEBUG(10, ("unable to allocate memory for response\n")); + DBG_DEBUG("unable to allocate memory for response\n"); return NT_STATUS_NO_MEMORY; } @@ -1658,8 +1770,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, case FSCTL_IS_VOLUME_DIRTY: { - DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s " - "(but remotely not supported)\n", fsp_fnum_dbg(fsp))); + DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s " + "(but remotely not supported)\n", fsp_fnum_dbg(fsp)); /* * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx * says we have to respond with NT_STATUS_INVALID_PARAMETER @@ -1674,8 +1786,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, */ if (!vfswrap_logged_ioctl_message) { vfswrap_logged_ioctl_message = true; - DEBUG(2, ("%s (0x%x): Currently not implemented.\n", - __func__, function)); + DBG_NOTICE("%s (0x%x): Currently not implemented.\n", + __func__, function); } } @@ -1709,6 +1821,8 @@ static struct tevent_req *vfswrap_get_dos_attributes_send( struct tevent_req *subreq = NULL; struct vfswrap_get_dos_attributes_state *state = NULL; + SMB_ASSERT(!is_named_stream(smb_fname)); + req = tevent_req_create(mem_ctx, &state, struct vfswrap_get_dos_attributes_state); if (req == NULL) { @@ -1723,6 +1837,14 @@ static struct tevent_req *vfswrap_get_dos_attributes_send( .smb_fname = smb_fname, }; + if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) { + DBG_ERR("%s: \"smbd async dosmode\" enabled, but " + "\"store dos attributes\" is disabled\n", + dir_fsp->conn->connectpath); + tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + return tevent_req_post(req, ev); + } + subreq = SMB_VFS_GETXATTRAT_SEND(state, ev, dir_fsp, @@ -1857,6 +1979,8 @@ static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle, { bool offline; + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + offline = vfswrap_is_offline(handle->conn, fsp->fsp_name); if (offline) { *dosmode |= FILE_ATTRIBUTE_OFFLINE; @@ -1869,6 +1993,8 @@ static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32_t dosmode) { + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode); } @@ -1928,6 +2054,8 @@ static struct tevent_req *vfswrap_offload_read_send( static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req, struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, + uint32_t *flags, + uint64_t *xferlen, DATA_BLOB *token) { struct vfswrap_offload_read_state *state = tevent_req_data( @@ -1939,6 +2067,8 @@ static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req, return status; } + *flags = 0; + *xferlen = 0; token->length = state->token.length; token->data = talloc_move(mem_ctx, &state->token.data); @@ -1959,6 +2089,7 @@ struct vfswrap_offload_write_state { off_t dst_off; off_t to_copy; off_t remaining; + off_t copied; size_t next_io_size; }; @@ -1978,6 +2109,7 @@ static void vfswrap_offload_write_cleanup(struct tevent_req *req, state->dst_fsp = NULL; } +static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req); static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req); static struct tevent_req *vfswrap_offload_write_send( @@ -2117,6 +2249,16 @@ static struct tevent_req *vfswrap_offload_write_send( return tevent_req_post(req, ev); } + status = vfswrap_offload_copy_file_range(req); + if (NT_STATUS_IS_OK(status)) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + state->buf = talloc_array(state, uint8_t, num); if (tevent_req_nomem(state->buf, req)) { return tevent_req_post(req, ev); @@ -2131,6 +2273,137 @@ static struct tevent_req *vfswrap_offload_write_send( return req; } +static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req) +{ + struct vfswrap_offload_write_state *state = tevent_req_data( + req, struct vfswrap_offload_write_state); + struct lock_struct lck; + ssize_t nwritten; + NTSTATUS status; + bool same_file; + bool ok; + static bool try_copy_file_range = true; + + if (!try_copy_file_range) { + return NT_STATUS_MORE_PROCESSING_REQUIRED; + } + + same_file = file_id_equal(&state->src_fsp->file_id, + &state->dst_fsp->file_id); + if (same_file && + sys_io_ranges_overlap(state->remaining, + state->src_off, + state->remaining, + state->dst_off)) + { + return NT_STATUS_MORE_PROCESSING_REQUIRED; + } + + if (fsp_is_alternate_stream(state->src_fsp) || + fsp_is_alternate_stream(state->dst_fsp)) + { + return NT_STATUS_MORE_PROCESSING_REQUIRED; + } + + init_strict_lock_struct(state->src_fsp, + state->src_fsp->op->global->open_persistent_id, + state->src_off, + state->remaining, + READ_LOCK, + lp_posix_cifsu_locktype(state->src_fsp), + &lck); + + ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn, + state->src_fsp, + &lck); + if (!ok) { + return NT_STATUS_FILE_LOCK_CONFLICT; + } + + ok = change_to_user_and_service_by_fsp(state->dst_fsp); + if (!ok) { + return NT_STATUS_INTERNAL_ERROR; + } + + init_strict_lock_struct(state->dst_fsp, + state->dst_fsp->op->global->open_persistent_id, + state->dst_off, + state->remaining, + WRITE_LOCK, + lp_posix_cifsu_locktype(state->dst_fsp), + &lck); + + ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn, + state->dst_fsp, + &lck); + if (!ok) { + return NT_STATUS_FILE_LOCK_CONFLICT; + } + + while (state->remaining > 0) { + nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp), + &state->src_off, + fsp_get_io_fd(state->dst_fsp), + &state->dst_off, + state->remaining, + 0); + if (nwritten == -1) { + DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] " + "n [%jd] failed: %s\n", + fsp_str_dbg(state->src_fsp), + (intmax_t)state->src_off, + fsp_str_dbg(state->dst_fsp), + (intmax_t)state->dst_off, + (intmax_t)state->remaining, + strerror(errno)); + switch (errno) { + case EOPNOTSUPP: + case ENOSYS: + try_copy_file_range = false; + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + break; + case EXDEV: + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + break; + default: + status = map_nt_error_from_unix(errno); + if (NT_STATUS_EQUAL( + status, + NT_STATUS_MORE_PROCESSING_REQUIRED)) + { + /* Avoid triggering the fallback */ + status = NT_STATUS_INTERNAL_ERROR; + } + break; + } + return status; + } + + if (state->remaining < nwritten) { + DBG_DEBUG("copy_file_range src [%s] dst [%s] " + "n [%jd] remaining [%jd]\n", + fsp_str_dbg(state->src_fsp), + fsp_str_dbg(state->dst_fsp), + (intmax_t)nwritten, + (intmax_t)state->remaining); + return NT_STATUS_INTERNAL_ERROR; + } + + if (nwritten == 0) { + break; + } + state->copied += nwritten; + state->remaining -= nwritten; + } + + /* + * Tell the req cleanup function there's no need to call + * change_to_user_and_service_by_fsp() on the dst handle. + */ + state->dst_fsp = NULL; + return NT_STATUS_OK; +} + static void vfswrap_offload_write_read_done(struct tevent_req *subreq); static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req) @@ -2152,6 +2425,7 @@ static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req) state->src_off, state->next_io_size, READ_LOCK, + lp_posix_cifsu_locktype(state->src_fsp), &read_lck); ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn, @@ -2215,6 +2489,7 @@ static void vfswrap_offload_write_read_done(struct tevent_req *subreq) state->dst_off, state->next_io_size, WRITE_LOCK, + lp_posix_cifsu_locktype(state->dst_fsp), &write_lck); ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn, @@ -2269,6 +2544,7 @@ static void vfswrap_offload_write_write_done(struct tevent_req *subreq) tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); return; } + state->copied += nwritten; state->remaining -= nwritten; if (state->remaining == 0) { tevent_req_done(req); @@ -2305,7 +2581,7 @@ static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle, return status; } - *copied = state->to_copy; + *copied = state->copied; DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied); tevent_req_received(req); @@ -2395,15 +2671,12 @@ static int vfswrap_unlinkat(vfs_handle_struct *handle, START_PROFILE(syscall_unlinkat); - if (is_named_stream(smb_fname)) { - errno = ENOENT; - goto out; - } + SMB_ASSERT(!is_named_stream(smb_fname)); + result = unlinkat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, flags); - out: END_PROFILE(syscall_unlinkat); return result; } @@ -2422,15 +2695,10 @@ static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t m if (fsp->fsp_flags.have_proc_fds) { int fd = fsp_get_pathref_fd(fsp); - const char *p = NULL; - char buf[PATH_MAX]; + struct sys_proc_fd_path_buf buf; + + result = chmod(sys_proc_fd_path(fd, &buf), mode); - p = sys_proc_fd_path(fd, buf, sizeof(buf)); - if (p != NULL) { - result = chmod(p, mode); - } else { - result = -1; - } END_PROFILE(syscall_fchmod); return result; } @@ -2450,7 +2718,26 @@ static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t ui int result; START_PROFILE(syscall_fchown); - result = fchown(fsp_get_io_fd(fsp), uid, gid); + if (!fsp->fsp_flags.is_pathref) { + result = fchown(fsp_get_io_fd(fsp), uid, gid); + END_PROFILE(syscall_fchown); + return result; + } + + if (fsp->fsp_flags.have_proc_fds) { + int fd = fsp_get_pathref_fd(fsp); + struct sys_proc_fd_path_buf buf; + + result = chown(sys_proc_fd_path(fd, &buf), uid, gid); + + END_PROFILE(syscall_fchown); + return result; + } + + /* + * This is no longer a handle based call. + */ + result = chown(fsp->fsp_name->base_name, uid, gid); END_PROFILE(syscall_fchown); return result; #else @@ -2526,7 +2813,7 @@ static int vfswrap_fntimes(vfs_handle_struct *handle, START_PROFILE(syscall_fntimes); - if (is_named_stream(fsp->fsp_name)) { + if (fsp_is_alternate_stream(fsp)) { errno = ENOENT; goto out; } @@ -2541,8 +2828,7 @@ static int vfswrap_fntimes(vfs_handle_struct *handle, } if (!is_omit_timespec(&ft->create_time)) { - set_create_timespec_ea(handle->conn, - fsp->fsp_name, + set_create_timespec_ea(fsp, ft->create_time); } @@ -2568,19 +2854,12 @@ static int vfswrap_fntimes(vfs_handle_struct *handle, if (fsp->fsp_flags.have_proc_fds) { int fd = fsp_get_pathref_fd(fsp); - const char *p = NULL; - char buf[PATH_MAX]; + struct sys_proc_fd_path_buf buf; - p = sys_proc_fd_path(fd, buf, sizeof(buf)); - if (p != NULL) { - /* - * The dirfd argument of utimensat is ignored when - * pathname is an absolute path - */ - result = utimensat(AT_FDCWD, p, times, 0); - } else { - result = -1; - } + result = utimensat(AT_FDCWD, + sys_proc_fd_path(fd, &buf), + times, + 0); goto out; } @@ -2651,8 +2930,8 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs if (ret == 0) { return 0; } - DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with " - "error %d. Falling back to slow manual allocation\n", errno)); + DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with " + "error %d. Falling back to slow manual allocation\n", errno); /* available disk space is enough or not? */ space_avail = @@ -2788,13 +3067,13 @@ static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, o return result; } -static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, - uint32_t share_access, uint32_t access_mask) +static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle, + files_struct *fsp, + uint32_t share_access, + uint32_t access_mask) { - START_PROFILE(syscall_kernel_flock); - kernel_flock(fsp_get_io_fd(fsp), share_access, access_mask); - END_PROFILE(syscall_kernel_flock); - return 0; + errno = ENOTSUP; + return -1; } static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd, @@ -2865,6 +3144,8 @@ static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, START_PROFILE(syscall_linux_setlease); + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + #ifdef HAVE_KERNEL_OPLOCKS_LINUX result = linux_setlease(fsp_get_io_fd(fsp), leasetype); #else @@ -2883,6 +3164,8 @@ static int vfswrap_symlinkat(vfs_handle_struct *handle, START_PROFILE(syscall_symlinkat); + SMB_ASSERT(!is_named_stream(new_smb_fname)); + result = symlinkat(link_target->base_name, fsp_get_pathref_fd(dirfsp), new_smb_fname->base_name); @@ -2900,6 +3183,8 @@ static int vfswrap_readlinkat(vfs_handle_struct *handle, START_PROFILE(syscall_readlinkat); + SMB_ASSERT(!is_named_stream(smb_fname)); + result = readlinkat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, buf, @@ -2920,6 +3205,9 @@ static int vfswrap_linkat(vfs_handle_struct *handle, START_PROFILE(syscall_linkat); + SMB_ASSERT(!is_named_stream(old_smb_fname)); + SMB_ASSERT(!is_named_stream(new_smb_fname)); + result = linkat(fsp_get_pathref_fd(srcfsp), old_smb_fname->base_name, fsp_get_pathref_fd(dstfsp), @@ -2940,6 +3228,8 @@ static int vfswrap_mknodat(vfs_handle_struct *handle, START_PROFILE(syscall_mknodat); + SMB_ASSERT(!is_named_stream(smb_fname)); + result = sys_mknodat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode, @@ -2971,12 +3261,29 @@ static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle, return result_fname; } -static int vfswrap_chflags(vfs_handle_struct *handle, - const struct smb_filename *smb_fname, +static int vfswrap_fchflags(vfs_handle_struct *handle, + struct files_struct *fsp, unsigned int flags) { -#ifdef HAVE_CHFLAGS - return chflags(smb_fname->base_name, flags); +#ifdef HAVE_FCHFLAGS + int fd = fsp_get_pathref_fd(fsp); + + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + + if (!fsp->fsp_flags.is_pathref) { + return fchflags(fd, flags); + } + + if (fsp->fsp_flags.have_proc_fds) { + struct sys_proc_fd_path_buf buf; + + return chflags(sys_proc_fd_path(fd, &buf), flags); + } + + /* + * This is no longer a handle based call. + */ + return chflags(fsp->fsp_name->base_name, flags); #else errno = ENOSYS; return -1; @@ -3004,10 +3311,6 @@ static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle, { uint64_t file_id; - if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) { - return psbuf->st_ex_file_id; - } - if (handle->conn->base_share_dev == psbuf->st_ex_dev) { return (uint64_t)psbuf->st_ex_ino; } @@ -3032,6 +3335,8 @@ static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle, struct stream_struct *streams = *pstreams; NTSTATUS status; + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + if (fsp->fsp_flags.is_directory) { /* * No default streams on directories @@ -3072,21 +3377,22 @@ static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle, return NT_STATUS_OK; } -static int vfswrap_get_real_filename(struct vfs_handle_struct *handle, - const struct smb_filename *path, - const char *name, - TALLOC_CTX *mem_ctx, - char **found_name) +static NTSTATUS vfswrap_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) { /* * Don't fall back to get_real_filename so callers can differentiate * between a full directory scan and an actual case-insensitive stat. */ - errno = EOPNOTSUPP; - return -1; + return NT_STATUS_NOT_SUPPORTED; } static const char *vfswrap_connectpath(struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, const struct smb_filename *smb_fname) { return handle->conn->connectpath; @@ -3132,39 +3438,23 @@ static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle, NTSTATUS result; START_PROFILE(fget_nt_acl); + + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + result = posix_fget_nt_acl(fsp, security_info, mem_ctx, ppdesc); END_PROFILE(fget_nt_acl); return result; } -static NTSTATUS vfswrap_get_nt_acl_at(vfs_handle_struct *handle, - struct files_struct *dirfsp, - const struct smb_filename *smb_fname, - uint32_t security_info, - TALLOC_CTX *mem_ctx, - struct security_descriptor **ppdesc) -{ - NTSTATUS result; - - START_PROFILE(get_nt_acl_at); - - SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp); - - result = posix_get_nt_acl(handle->conn, - smb_fname, - security_info, - mem_ctx, - ppdesc); - END_PROFILE(get_nt_acl_at); - return result; -} - static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd) { NTSTATUS result; START_PROFILE(fset_nt_acl); + + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + result = set_nt_acl(fsp, security_info_sent, psd); END_PROFILE(fset_nt_acl); return result; @@ -3179,19 +3469,14 @@ static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle, return NT_STATUS_OK; /* Nothing to do here ... */ } -static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - SMB_ACL_TYPE_T type, - TALLOC_CTX *mem_ctx) -{ - return sys_acl_get_file(handle, smb_fname, type, mem_ctx); -} - static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, + SMB_ACL_TYPE_T type, TALLOC_CTX *mem_ctx) { - return sys_acl_get_fd(handle, fsp, mem_ctx); + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + + return sys_acl_get_fd(handle, fsp, type, mem_ctx); } static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, @@ -3199,63 +3484,52 @@ static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, SMB_ACL_TYPE_T type, SMB_ACL_T theacl) { - if (!fsp->fsp_flags.is_pathref && - type == SMB_ACL_TYPE_ACCESS) - { - return sys_acl_set_fd(handle, fsp, theacl); - } + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); - if (fsp->fsp_flags.have_proc_fds) { - int fd = fsp_get_pathref_fd(fsp); - struct smb_filename smb_fname; - const char *p = NULL; - char buf[PATH_MAX]; - - p = sys_proc_fd_path(fd, buf, sizeof(buf)); - if (p == NULL) { - return -1; - } - - smb_fname = (struct smb_filename) { - .base_name = buf, - }; - - return sys_acl_set_file(handle, - &smb_fname, - type, - theacl); - } - - /* - * This is no longer a handle based call. - */ - return sys_acl_set_file(handle, - fsp->fsp_name, - type, - theacl); + return sys_acl_set_fd(handle, fsp, type, theacl); } -static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle, + files_struct *fsp) { - return sys_acl_delete_def_file(handle, smb_fname); + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + + return sys_acl_delete_def_fd(handle, fsp); } /**************************************************************** Extended attribute operations. *****************************************************************/ -static ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - const char *name, - void *value, - size_t size) +static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *name, + void *value, + size_t size) { - return getxattr(smb_fname->base_name, name, value, size); + int fd = fsp_get_pathref_fd(fsp); + + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + + if (!fsp->fsp_flags.is_pathref) { + return fgetxattr(fd, name, value, size); + } + + if (fsp->fsp_flags.have_proc_fds) { + struct sys_proc_fd_path_buf buf; + + return getxattr(sys_proc_fd_path(fd, &buf), name, value, size); + } + + /* + * This is no longer a handle based call. + */ + return getxattr(fsp->fsp_name->base_name, name, value, size); } struct vfswrap_getxattrat_state { struct tevent_context *ev; + struct vfs_handle_struct *handle; files_struct *dir_fsp; const struct smb_filename *smb_fname; @@ -3301,6 +3575,8 @@ static struct tevent_req *vfswrap_getxattrat_send( bool have_per_thread_creds = false; bool do_async = false; + SMB_ASSERT(!is_named_stream(smb_fname)); + req = tevent_req_create(mem_ctx, &state, struct vfswrap_getxattrat_state); if (req == NULL) { @@ -3308,6 +3584,7 @@ static struct tevent_req *vfswrap_getxattrat_send( } *state = (struct vfswrap_getxattrat_state) { .ev = ev, + .handle = handle, .dir_fsp = dir_fsp, .smb_fname = smb_fname, }; @@ -3351,7 +3628,7 @@ static struct tevent_req *vfswrap_getxattrat_send( /* * Now allocate all parameters from a memory context that won't go away - * no matter what. These paremeters will get used in threads and we + * no matter what. These parameters will get used in threads and we * can't reliably cancel threads, so all buffers passed to the threads * must not be freed before all referencing threads terminate. */ @@ -3406,31 +3683,14 @@ static void vfswrap_getxattrat_do_sync(struct tevent_req *req) { struct vfswrap_getxattrat_state *state = tevent_req_data( req, struct vfswrap_getxattrat_state); - char *path = NULL; - char *tofree = NULL; - char pathbuf[PATH_MAX+1]; - ssize_t pathlen; - int err; - - pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name, - state->smb_fname->base_name, - pathbuf, - sizeof(pathbuf), - &path, - &tofree); - if (pathlen == -1) { - tevent_req_error(req, ENOMEM); - return; - } - state->xattr_size = getxattr(path, - state->xattr_name, - state->xattr_value, - talloc_array_length(state->xattr_value)); - err = errno; - TALLOC_FREE(tofree); + state->xattr_size = vfswrap_fgetxattr(state->handle, + state->smb_fname->fsp, + state->xattr_name, + state->xattr_value, + talloc_array_length(state->xattr_value)); if (state->xattr_size == -1) { - tevent_req_error(req, err); + tevent_req_error(req, errno); return; } @@ -3467,17 +3727,11 @@ static void vfswrap_getxattrat_do_async(void *private_data) goto end_profile; } - ret = fchdir(fsp_get_pathref_fd(state->dir_fsp)); - if (ret == -1) { - state->xattr_size = -1; - state->vfs_aio_state.error = errno; - goto end_profile; - } - - state->xattr_size = getxattr(state->name, - state->xattr_name, - state->xattr_value, - talloc_array_length(state->xattr_value)); + state->xattr_size = vfswrap_fgetxattr(state->handle, + state->smb_fname->fsp, + state->xattr_name, + state->xattr_value, + talloc_array_length(state->xattr_value)); if (state->xattr_size == -1) { state->vfs_aio_state.error = errno; } @@ -3571,54 +3825,20 @@ static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req, return xattr_size; } -static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, - struct files_struct *fsp, - const char *name, - void *value, - size_t size) -{ - int fd = fsp_get_pathref_fd(fsp); - - if (!fsp->fsp_flags.is_pathref) { - return fgetxattr(fd, name, value, size); - } - - if (fsp->fsp_flags.have_proc_fds) { - const char *p = NULL; - char buf[PATH_MAX]; - - p = sys_proc_fd_path(fd, buf, sizeof(buf)); - if (p == NULL) { - return -1; - } - - return getxattr(p, name, value, size); - } - - /* - * This is no longer a handle based call. - */ - return getxattr(fsp->fsp_name->base_name, name, value, size); -} - static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size) { int fd = fsp_get_pathref_fd(fsp); + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + if (!fsp->fsp_flags.is_pathref) { return flistxattr(fd, list, size); } if (fsp->fsp_flags.have_proc_fds) { - const char *p = NULL; - char buf[PATH_MAX]; + struct sys_proc_fd_path_buf buf; - p = sys_proc_fd_path(fd, buf, sizeof(buf)); - if (p == NULL) { - return -1; - } - - return listxattr(p, list, size); + return listxattr(sys_proc_fd_path(fd, &buf), list, size); } /* @@ -3631,20 +3851,16 @@ static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_s { int fd = fsp_get_pathref_fd(fsp); + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + if (!fsp->fsp_flags.is_pathref) { return fremovexattr(fd, name); } if (fsp->fsp_flags.have_proc_fds) { - const char *p = NULL; - char buf[PATH_MAX]; + struct sys_proc_fd_path_buf buf; - p = sys_proc_fd_path(fd, buf, sizeof(buf)); - if (p == NULL) { - return -1; - } - - return removexattr(p, name); + return removexattr(sys_proc_fd_path(fd, &buf), name); } /* @@ -3657,20 +3873,20 @@ static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_stru { int fd = fsp_get_pathref_fd(fsp); + SMB_ASSERT(!fsp_is_alternate_stream(fsp)); + if (!fsp->fsp_flags.is_pathref) { return fsetxattr(fd, name, value, size, flags); } if (fsp->fsp_flags.have_proc_fds) { - const char *p = NULL; - char buf[PATH_MAX]; - - p = sys_proc_fd_path(fd, buf, sizeof(buf)); - if (p == NULL) { - return -1; - } + struct sys_proc_fd_path_buf buf; - return setxattr(p, name, value, size, flags); + return setxattr(sys_proc_fd_path(fd, &buf), + name, + value, + size, + flags); } /* @@ -3769,8 +3985,6 @@ static struct vfs_fn_pointers vfs_default_fns = { .fdopendir_fn = vfswrap_fdopendir, .readdir_fn = vfswrap_readdir, .freaddir_attr_fn = vfswrap_freaddir_attr, - .seekdir_fn = vfswrap_seekdir, - .telldir_fn = vfswrap_telldir, .rewind_dir_fn = vfswrap_rewinddir, .mkdirat_fn = vfswrap_mkdirat, .closedir_fn = vfswrap_closedir, @@ -3795,6 +4009,7 @@ static struct vfs_fn_pointers vfs_default_fns = { .stat_fn = vfswrap_stat, .fstat_fn = vfswrap_fstat, .lstat_fn = vfswrap_lstat, + .fstatat_fn = vfswrap_fstatat, .get_alloc_size_fn = vfswrap_get_alloc_size, .unlinkat_fn = vfswrap_unlinkat, .fchmod_fn = vfswrap_fchmod, @@ -3806,7 +4021,7 @@ static struct vfs_fn_pointers vfs_default_fns = { .ftruncate_fn = vfswrap_ftruncate, .fallocate_fn = vfswrap_fallocate, .lock_fn = vfswrap_lock, - .kernel_flock_fn = vfswrap_kernel_flock, + .filesystem_sharemode_fn = vfswrap_filesystem_sharemode, .fcntl_fn = vfswrap_fcntl, .linux_setlease_fn = vfswrap_linux_setlease, .getlock_fn = vfswrap_getlock, @@ -3815,16 +4030,17 @@ static struct vfs_fn_pointers vfs_default_fns = { .linkat_fn = vfswrap_linkat, .mknodat_fn = vfswrap_mknodat, .realpath_fn = vfswrap_realpath, - .chflags_fn = vfswrap_chflags, + .fchflags_fn = vfswrap_fchflags, .file_id_create_fn = vfswrap_file_id_create, .fs_file_id_fn = vfswrap_fs_file_id, .fstreaminfo_fn = vfswrap_fstreaminfo, - .get_real_filename_fn = vfswrap_get_real_filename, + .get_real_filename_at_fn = vfswrap_get_real_filename_at, .connectpath_fn = vfswrap_connectpath, .brl_lock_windows_fn = vfswrap_brl_lock_windows, .brl_unlock_windows_fn = vfswrap_brl_unlock_windows, .strict_lock_check_fn = vfswrap_strict_lock_check, .translate_name_fn = vfswrap_translate_name, + .parent_pathname_fn = vfswrap_parent_pathname, .fsctl_fn = vfswrap_fsctl, .fset_dos_attributes_fn = vfswrap_fset_dos_attributes, .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send, @@ -3840,21 +4056,17 @@ static struct vfs_fn_pointers vfs_default_fns = { /* NT ACL operations. */ .fget_nt_acl_fn = vfswrap_fget_nt_acl, - .get_nt_acl_at_fn = vfswrap_get_nt_acl_at, .fset_nt_acl_fn = vfswrap_fset_nt_acl, .audit_file_fn = vfswrap_audit_file, /* POSIX ACL operations. */ - .sys_acl_get_file_fn = vfswrap_sys_acl_get_file, .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd, - .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file, .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd, .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd, - .sys_acl_delete_def_file_fn = vfswrap_sys_acl_delete_def_file, + .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd, /* EA operations. */ - .getxattr_fn = vfswrap_getxattr, .getxattrat_send_fn = vfswrap_getxattrat_send, .getxattrat_recv_fn = vfswrap_getxattrat_recv, .fgetxattr_fn = vfswrap_fgetxattr,