bool acl;
bool settimes;
bool recalls;
+ struct {
+ bool gpfs_fstat_x;
+ } pathref_ok;
};
struct gpfs_fsp_extension {
return result;
}
-static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
- uint32_t share_access, uint32_t access_mask)
+static int vfs_gpfs_filesystem_sharemode(vfs_handle_struct *handle,
+ files_struct *fsp,
+ uint32_t share_access,
+ uint32_t access_mask)
{
struct gpfs_config_data *config;
int ret = 0;
- START_PROFILE(syscall_kernel_flock);
-
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct gpfs_config_data,
return -1);
/*
* A named stream fsp will have the basefile open in the fsp
* fd, so lacking a distinct fd for the stream we have to skip
- * kernel_flock and set_gpfs_sharemode for stream.
+ * set_gpfs_sharemode for stream.
*/
- if (is_named_stream(fsp->fsp_name)) {
+ if (fsp_is_alternate_stream(fsp)) {
DBG_NOTICE("Not requesting GPFS sharemode on stream: %s/%s\n",
fsp->conn->connectpath,
fsp_str_dbg(fsp));
return 0;
}
- kernel_flock(fsp_get_io_fd(fsp), share_access, access_mask);
-
ret = set_gpfs_sharemode(fsp, access_mask, share_access);
- END_PROFILE(syscall_kernel_flock);
-
return ret;
}
return SMB_VFS_NEXT_CLOSE(handle, fsp);
}
+#ifdef HAVE_KERNEL_OPLOCKS_LINUX
static int lease_type_to_gpfs(int leasetype)
{
if (leasetype == F_RDLCK) {
return ret;
}
-static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
- const struct smb_filename *path,
- const char *name,
- TALLOC_CTX *mem_ctx,
- char **found_name)
+#else /* HAVE_KERNEL_OPLOCKS_LINUX */
+
+static int vfs_gpfs_setlease(vfs_handle_struct *handle,
+ files_struct *fsp,
+ int leasetype)
+{
+ return ENOSYS;
+}
+#endif /* HAVE_KERNEL_OPLOCKS_LINUX */
+
+static NTSTATUS vfs_gpfs_get_real_filename_at(struct vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const char *name,
+ TALLOC_CTX *mem_ctx,
+ char **found_name)
{
int result;
char *full_path = NULL;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct gpfs_config_data,
- return -1);
+ return NT_STATUS_INTERNAL_ERROR);
if (!config->getrealfilename) {
- return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
- mem_ctx, found_name);
+ return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
+ handle, dirfsp, name, mem_ctx, found_name);
}
mangled = mangle_is_mangled(name, handle->conn->params);
if (mangled) {
- return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
- mem_ctx, found_name);
+ return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
+ handle, dirfsp, name, mem_ctx, found_name);
}
- full_path_len = full_path_tos(path->base_name, name,
+ full_path_len = full_path_tos(dirfsp->fsp_name->base_name, name,
tmpbuf, sizeof(tmpbuf),
&full_path, &to_free);
if (full_path_len == -1) {
- errno = ENOMEM;
- return -1;
+ return NT_STATUS_NO_MEMORY;
}
buflen = sizeof(real_pathname) - 1;
TALLOC_FREE(to_free);
if ((result == -1) && (errno == ENOSYS)) {
- return SMB_VFS_NEXT_GET_REAL_FILENAME(
- handle, path, name, mem_ctx, found_name);
+ return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
+ handle, dirfsp, name, mem_ctx, found_name);
}
if (result == -1) {
DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
strerror(errno)));
- return -1;
+ return map_nt_error_from_unix(errno);
}
/*
real_pathname[sizeof(real_pathname)-1] = '\0';
}
- DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
- path->base_name, name, real_pathname));
+ DBG_DEBUG("%s/%s -> %s\n",
+ fsp_str_dbg(dirfsp),
+ name,
+ real_pathname);
name = strrchr_m(real_pathname, '/');
if (name == NULL) {
- errno = ENOENT;
- return -1;
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
*found_name = talloc_strdup(mem_ctx, name+1);
if (*found_name == NULL) {
- errno = ENOMEM;
- return -1;
+ return NT_STATUS_NO_MEMORY;
}
- return 0;
+ return NT_STATUS_OK;
}
static void sd2gpfs_control(uint16_t control, struct gpfs_acl *gacl)
}
}
-static int gpfs_getacl_with_capability(const char *fname, int flags, void *buf)
+static int gpfs_getacl_with_capability(struct files_struct *fsp,
+ int flags,
+ void *buf)
{
int ret, saved_errno;
set_effective_capability(DAC_OVERRIDE_CAPABILITY);
- ret = gpfswrap_getacl(fname, flags, buf);
+ ret = gpfswrap_fgetacl(fsp_get_pathref_fd(fsp), flags, buf);
saved_errno = errno;
drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
*
*/
static void *vfs_gpfs_getacl(TALLOC_CTX *mem_ctx,
- const char *fname,
+ struct files_struct *fsp,
const bool raw,
const gpfs_aclType_t type)
{
-
+ const char *fname = fsp->fsp_name->base_name;
void *aclbuf;
size_t size = 512;
int ret, flags;
*len = size;
if (use_capability) {
- ret = gpfs_getacl_with_capability(fname, flags, aclbuf);
+ ret = gpfs_getacl_with_capability(fsp, flags, aclbuf);
} else {
- ret = gpfswrap_getacl(fname, flags, aclbuf);
+ ret = gpfswrap_fgetacl(fsp_get_pathref_fd(fsp), flags, aclbuf);
if ((ret != 0) && (errno == EACCES)) {
DBG_DEBUG("Retry with DAC capability for %s\n", fname);
use_capability = true;
- ret = gpfs_getacl_with_capability(fname, flags, aclbuf);
+ ret = gpfs_getacl_with_capability(fsp, flags, aclbuf);
}
}
* On failure returns -1 if there is system (GPFS) error, check errno.
* Returns 0 on success
*/
-static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname,
+static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx,
+ struct files_struct *fsp,
struct SMB4ACL_T **ppacl)
{
+ const char *fname = fsp->fsp_name->base_name;
gpfs_aclCount_t i;
struct gpfs_acl *gacl = NULL;
DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
/* Get the ACL */
- gacl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(), fname,
+ gacl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(), fsp,
false, 0);
if (gacl == NULL) {
DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
return status;
}
- result = gpfs_get_nfs4_acl(frame, fsp->fsp_name->base_name, &pacl);
+ result = gpfs_get_nfs4_acl(frame, fsp, &pacl);
if (result == 0) {
status = smb_fget_nt_acl_nfs4(fsp, &config->nfs4_params,
return map_nt_error_from_unix(errno);
}
-static NTSTATUS gpfsacl_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)
-{
- struct SMB4ACL_T *pacl = NULL;
- int result;
- struct gpfs_config_data *config;
- TALLOC_CTX *frame = talloc_stackframe();
- NTSTATUS status;
-
- SMB_ASSERT(dirfsp == handle->conn->cwd_fsp);
-
- *ppdesc = NULL;
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct gpfs_config_data,
- return NT_STATUS_INTERNAL_ERROR);
-
- if (!config->acl) {
- status = SMB_VFS_NEXT_GET_NT_ACL_AT(handle,
- dirfsp,
- smb_fname,
- security_info,
- mem_ctx, ppdesc);
- TALLOC_FREE(frame);
- return status;
- }
-
- result = gpfs_get_nfs4_acl(frame, smb_fname->base_name, &pacl);
-
- if (result == 0) {
- status = smb_get_nt_acl_nfs4(handle->conn, smb_fname,
- &config->nfs4_params,
- security_info, mem_ctx, ppdesc,
- pacl);
- TALLOC_FREE(frame);
- return status;
- }
-
- if (result > 0) {
- DEBUG(10, ("retrying with posix acl...\n"));
- status = posix_get_nt_acl(handle->conn, smb_fname,
- security_info, mem_ctx, ppdesc);
- TALLOC_FREE(frame);
- return status;
- }
-
- /* GPFS ACL was not read, something wrong happened, error code is set in errno */
- TALLOC_FREE(frame);
- return map_nt_error_from_unix(errno);
-}
-
static bool vfs_gpfs_nfs4_ace_to_gpfs_ace(SMB_ACE4PROP_T *nfs4_ace,
struct gpfs_ace_v4 *gace,
uid_t owner_uid)
NTSTATUS result = NT_STATUS_ACCESS_DENIED;
acl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(),
- fsp->fsp_name->base_name,
+ fsp,
false, 0);
if (acl == NULL) {
return map_nt_error_from_unix(errno);
if (acl->acl_version == GPFS_ACL_VERSION_NFS4) {
struct gpfs_config_data *config;
- if (lp_parm_bool(fsp->conn->params->service, "gpfs",
- "refuse_dacl_protected", false)
- && (psd->type&SEC_DESC_DACL_PROTECTED)) {
- DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
- talloc_free(acl);
- return NT_STATUS_NOT_SUPPORTED;
- }
-
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct gpfs_config_data,
return NT_STATUS_INTERNAL_ERROR);
return result;
}
-static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type,
+static SMB_ACL_T gpfsacl_get_posix_acl(struct files_struct *fsp,
+ gpfs_aclType_t type,
TALLOC_CTX *mem_ctx)
{
struct gpfs_acl *pacl;
SMB_ACL_T result = NULL;
- pacl = vfs_gpfs_getacl(talloc_tos(), path, false, type);
+ pacl = vfs_gpfs_getacl(talloc_tos(), fsp, false, type);
if (pacl == NULL) {
- DEBUG(10, ("vfs_gpfs_getacl failed for %s with %s\n",
- path, strerror(errno)));
+ DBG_DEBUG("vfs_gpfs_getacl failed for %s with %s\n",
+ fsp_str_dbg(fsp), strerror(errno));
if (errno == 0) {
errno = EINVAL;
}
return result;
}
-static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- SMB_ACL_TYPE_T type,
- TALLOC_CTX *mem_ctx)
+static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_TYPE_T type,
+ TALLOC_CTX *mem_ctx)
{
gpfs_aclType_t gpfs_type;
struct gpfs_config_data *config;
return NULL);
if (!config->acl) {
- return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
- type, mem_ctx);
+ return SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, type, mem_ctx);
}
switch(type) {
DEBUG(0, ("Got invalid type: %d\n", type));
smb_panic("exiting");
}
-
- return gpfsacl_get_posix_acl(smb_fname->base_name, gpfs_type, mem_ctx);
-}
-
-static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- TALLOC_CTX *mem_ctx)
-{
- struct gpfs_config_data *config;
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct gpfs_config_data,
- return NULL);
-
- if (!config->acl) {
- return SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
- }
-
- return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
- GPFS_ACL_TYPE_ACCESS, mem_ctx);
-}
-
-static int gpfsacl_sys_acl_blob_get_file(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- TALLOC_CTX *mem_ctx,
- char **blob_description,
- DATA_BLOB *blob)
-{
- struct gpfs_config_data *config;
- struct gpfs_opaque_acl *acl = NULL;
- DATA_BLOB aclblob;
- int result;
- const char *path_p = smb_fname->base_name;
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct gpfs_config_data,
- return -1);
-
- if (!config->acl) {
- return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE(handle, smb_fname,
- mem_ctx,
- blob_description,
- blob);
- }
-
- errno = 0;
- acl = (struct gpfs_opaque_acl *)
- vfs_gpfs_getacl(mem_ctx,
- path_p,
- true,
- GPFS_ACL_TYPE_NFS4);
-
- if (errno) {
- DEBUG(5, ("vfs_gpfs_getacl finished with errno %d: %s\n",
- errno, strerror(errno)));
-
- /* EINVAL means POSIX ACL, bail out on other cases */
- if (errno != EINVAL) {
- return -1;
- }
- }
-
- if (acl != NULL) {
- /*
- * file has NFSv4 ACL
- *
- * we only need the actual ACL blob here
- * acl_version will always be NFS4 because we asked
- * for NFS4
- * acl_type is only used for POSIX ACLs
- */
- aclblob.data = (uint8_t*) acl->acl_var_data;
- aclblob.length = acl->acl_buffer_len;
-
- *blob_description = talloc_strdup(mem_ctx, "gpfs_nfs4_acl");
- if (!*blob_description) {
- talloc_free(acl);
- errno = ENOMEM;
- return -1;
- }
-
- result = non_posix_sys_acl_blob_get_file_helper(handle, smb_fname,
- aclblob,
- mem_ctx, blob);
-
- talloc_free(acl);
- return result;
- }
-
- /* fall back to POSIX ACL */
- return posix_sys_acl_blob_get_file(handle, smb_fname, mem_ctx,
- blob_description, blob);
+ return gpfsacl_get_posix_acl(fsp, gpfs_type, mem_ctx);
}
static int gpfsacl_sys_acl_blob_get_fd(vfs_handle_struct *handle,
errno = 0;
acl = (struct gpfs_opaque_acl *) vfs_gpfs_getacl(mem_ctx,
- fsp->fsp_name->base_name,
+ fsp,
true,
GPFS_ACL_TYPE_NFS4);
}
static int gpfsacl_emu_chmod(vfs_handle_struct *handle,
- const struct smb_filename *fname, mode_t mode)
+ struct files_struct *fsp,
+ mode_t mode)
{
- char *path = fname->base_name;
+ struct smb_filename *fname = fsp->fsp_name;
+ char *path = fsp->fsp_name->base_name;
struct SMB4ACL_T *pacl = NULL;
int result;
bool haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
- result = gpfs_get_nfs4_acl(frame, path, &pacl);
+ result = gpfs_get_nfs4_acl(frame, fsp, &pacl);
if (result) {
TALLOC_FREE(frame);
return result;
static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
- SMB_STRUCT_STAT st;
- int rc;
+ SMB_STRUCT_STAT st;
+ int rc;
- if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
- return -1;
- }
+ rc = SMB_VFS_NEXT_FSTAT(handle, fsp, &st);
+ if (rc != 0) {
+ return -1;
+ }
- /* avoid chmod() if possible, to preserve acls */
- if ((st.st_ex_mode & ~S_IFMT) == mode) {
- return 0;
- }
+ /* avoid chmod() if possible, to preserve acls */
+ if ((st.st_ex_mode & ~S_IFMT) == mode) {
+ return 0;
+ }
- rc = gpfsacl_emu_chmod(handle, fsp->fsp_name,
- mode);
- if (rc == 1)
- return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
- return rc;
+ rc = gpfsacl_emu_chmod(handle, fsp, mode);
+ if (rc == 1) {
+ return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+ }
+ return rc;
}
static uint32_t vfs_gpfs_winattrs_to_dosmode(unsigned int winattrs)
return winattrs;
}
-static NTSTATUS vfs_gpfs_get_file_id(struct gpfs_iattr64 *iattr,
- uint64_t *fileid)
-{
- uint8_t input[sizeof(gpfs_ino64_t) +
- sizeof(gpfs_gen64_t) +
- sizeof(gpfs_snapid64_t)];
- uint8_t digest[gnutls_hash_get_len(GNUTLS_DIG_SHA1)];
- int rc;
-
- DBG_DEBUG("ia_inode 0x%llx, ia_gen 0x%llx, ia_modsnapid 0x%llx\n",
- iattr->ia_inode, iattr->ia_gen, iattr->ia_modsnapid);
-
- SBVAL(input,
- 0, iattr->ia_inode);
- SBVAL(input,
- sizeof(gpfs_ino64_t), iattr->ia_gen);
- SBVAL(input,
- sizeof(gpfs_ino64_t) + sizeof(gpfs_gen64_t), iattr->ia_modsnapid);
-
- GNUTLS_FIPS140_SET_LAX_MODE();
- rc = gnutls_hash_fast(GNUTLS_DIG_SHA1, input, sizeof(input), &digest);
- GNUTLS_FIPS140_SET_STRICT_MODE();
-
- if (rc != 0) {
- return gnutls_error_to_ntstatus(rc,
- NT_STATUS_HASH_NOT_SUPPORTED);
- }
-
- memcpy(fileid, &digest, sizeof(*fileid));
- DBG_DEBUG("file_id 0x%" PRIx64 "\n", *fileid);
-
- return NT_STATUS_OK;
-}
-
static struct timespec gpfs_timestruc64_to_timespec(struct gpfs_timestruc64 g)
{
return (struct timespec) { .tv_sec = g.tv_sec, .tv_nsec = g.tv_nsec };
uint32_t *dosmode)
{
struct gpfs_config_data *config;
+ int fd = fsp_get_pathref_fd(fsp);
+ struct sys_proc_fd_path_buf buf;
+ const char *p = NULL;
struct gpfs_iattr64 iattr = { };
- unsigned int litemask;
+ unsigned int litemask = 0;
struct timespec ts;
- uint64_t file_id;
- NTSTATUS status;
int ret;
SMB_VFS_HANDLE_GET_DATA(handle, config,
return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
}
- ret = gpfswrap_fstat_x(fsp_get_pathref_fd(fsp), &litemask, &iattr, sizeof(iattr));
+ if (fsp->fsp_flags.is_pathref && !config->pathref_ok.gpfs_fstat_x) {
+ if (fsp->fsp_flags.have_proc_fds) {
+ p = sys_proc_fd_path(fd, &buf);
+ } else {
+ p = fsp->fsp_name->base_name;
+ }
+ }
+
+ if (p != NULL) {
+ ret = gpfswrap_stat_x(p, &litemask, &iattr, sizeof(iattr));
+ } else {
+ ret = gpfswrap_fstat_x(fd, &litemask, &iattr, sizeof(iattr));
+ }
if (ret == -1 && errno == ENOSYS) {
return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
}
set_effective_capability(DAC_OVERRIDE_CAPABILITY);
- ret = gpfswrap_fstat_x(fsp_get_pathref_fd(fsp), &litemask,
- &iattr, sizeof(iattr));
+ if (p != NULL) {
+ ret = gpfswrap_stat_x(p,
+ &litemask,
+ &iattr,
+ sizeof(iattr));
+ } else {
+ ret = gpfswrap_fstat_x(fd,
+ &litemask,
+ &iattr,
+ sizeof(iattr));
+ }
if (ret == -1) {
saved_errno = errno;
}
return map_nt_error_from_unix(errno);
}
- ZERO_STRUCT(file_id);
- status = vfs_gpfs_get_file_id(&iattr, &file_id);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
ts = gpfs_timestruc64_to_timespec(iattr.ia_createtime);
*dosmode |= vfs_gpfs_winattrs_to_dosmode(iattr.ia_winflags);
update_stat_ex_create_time(&fsp->fsp_name->st, ts);
- update_stat_ex_file_id(&fsp->fsp_name->st, file_id);
return NT_STATUS_OK;
}
}
attrs.winAttrs = vfs_gpfs_dosmode_to_winattrs(dosmode);
- ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp),
- GPFS_WINATTR_SET_ATTRS, &attrs);
- if (ret == -1 && errno == ENOSYS) {
- return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
+ if (!fsp->fsp_flags.is_pathref) {
+ ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp),
+ GPFS_WINATTR_SET_ATTRS, &attrs);
+ if (ret == -1) {
+ DBG_WARNING("Setting winattrs failed for %s: %s\n",
+ fsp_str_dbg(fsp), strerror(errno));
+ return map_nt_error_from_unix(errno);
+ }
+ return NT_STATUS_OK;
}
+ if (fsp->fsp_flags.have_proc_fds) {
+ int fd = fsp_get_pathref_fd(fsp);
+ struct sys_proc_fd_path_buf buf;
+
+ ret = gpfswrap_set_winattrs_path(sys_proc_fd_path(fd, &buf),
+ GPFS_WINATTR_SET_ATTRS,
+ &attrs);
+ if (ret == -1) {
+ DBG_WARNING("Setting winattrs failed for "
+ "[%s][%s]: %s\n",
+ buf.buf,
+ fsp_str_dbg(fsp),
+ strerror(errno));
+ return map_nt_error_from_unix(errno);
+ }
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * This is no longer a handle based call.
+ */
+ ret = gpfswrap_set_winattrs_path(fsp->fsp_name->base_name,
+ GPFS_WINATTR_SET_ATTRS,
+ &attrs);
if (ret == -1) {
- DBG_WARNING("Setting winattrs failed for %s: %s\n",
- fsp->fsp_name->base_name, strerror(errno));
+ DBG_WARNING("Setting winattrs failed for [%s]: %s\n",
+ fsp_str_dbg(fsp), strerror(errno));
return map_nt_error_from_unix(errno);
}
return NT_STATUS_OK;
}
-static int stat_with_capability(struct vfs_handle_struct *handle,
- struct smb_filename *smb_fname, int flag)
+static int timespec_to_gpfs_time(
+ struct timespec ts, gpfs_timestruc_t *gt, int idx, int *flags)
{
-#if defined(HAVE_FSTATAT)
- int fd = -1;
- NTSTATUS status;
- struct smb_filename *dir_name = NULL;
- struct smb_filename *rel_name = NULL;
- struct stat st;
- int ret = -1;
-
- status = SMB_VFS_PARENT_PATHNAME(handle->conn,
- talloc_tos(),
- smb_fname,
- &dir_name,
- &rel_name);
- if (!NT_STATUS_IS_OK(status)) {
- errno = map_errno_from_nt_status(status);
- return -1;
+ if (is_omit_timespec(&ts)) {
+ return 0;
}
- fd = open(dir_name->base_name, O_RDONLY, 0);
- if (fd == -1) {
- TALLOC_FREE(dir_name);
+ if (ts.tv_sec < 0 || ts.tv_sec > UINT32_MAX) {
+ DBG_NOTICE("GPFS uses 32-bit unsigned timestamps "
+ "and cannot handle %jd.\n",
+ (intmax_t)ts.tv_sec);
+ errno = ERANGE;
return -1;
}
- set_effective_capability(DAC_OVERRIDE_CAPABILITY);
- ret = fstatat(fd, rel_name->base_name, &st, flag);
- drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
-
- TALLOC_FREE(dir_name);
- close(fd);
+ *flags |= 1 << idx;
+ gt[idx].tv_sec = ts.tv_sec;
+ gt[idx].tv_nsec = ts.tv_nsec;
+ DBG_DEBUG("Setting GPFS time %d, flags 0x%x\n", idx, *flags);
- if (ret == 0) {
- init_stat_ex_from_stat(
- &smb_fname->st, &st,
- lp_fake_directory_create_times(SNUM(handle->conn)));
- }
-
- return ret;
-#else
- return -1;
-#endif
-}
-
-static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
- struct smb_filename *smb_fname)
-{
- int ret;
- struct gpfs_config_data *config;
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct gpfs_config_data,
- return -1);
-
- ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
- if (ret == -1 && errno == EACCES) {
- DEBUG(10, ("Trying stat with capability for %s\n",
- smb_fname->base_name));
- ret = stat_with_capability(handle, smb_fname, 0);
- }
- return ret;
-}
-
-static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
- struct smb_filename *smb_fname)
-{
- int ret;
- struct gpfs_config_data *config;
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct gpfs_config_data,
- return -1);
-
- ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
- if (ret == -1 && errno == EACCES) {
- DEBUG(10, ("Trying lstat with capability for %s\n",
- smb_fname->base_name));
- ret = stat_with_capability(handle, smb_fname,
- AT_SYMLINK_NOFOLLOW);
- }
- return ret;
-}
-
-static void timespec_to_gpfs_time(struct timespec ts, gpfs_timestruc_t *gt,
- int idx, int *flags)
-{
- if (!is_omit_timespec(&ts)) {
- *flags |= 1 << idx;
- gt[idx].tv_sec = ts.tv_sec;
- gt[idx].tv_nsec = ts.tv_nsec;
- DEBUG(10, ("Setting GPFS time %d, flags 0x%x\n", idx, *flags));
- }
+ return 0;
}
-static int smbd_gpfs_set_times(int fd, char *path, struct smb_file_time *ft)
+static int smbd_gpfs_set_times(struct files_struct *fsp,
+ struct smb_file_time *ft)
{
gpfs_timestruc_t gpfs_times[4];
int flags = 0;
int rc;
ZERO_ARRAY(gpfs_times);
- timespec_to_gpfs_time(ft->atime, gpfs_times, 0, &flags);
- timespec_to_gpfs_time(ft->mtime, gpfs_times, 1, &flags);
+ rc = timespec_to_gpfs_time(ft->atime, gpfs_times, 0, &flags);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = timespec_to_gpfs_time(ft->mtime, gpfs_times, 1, &flags);
+ if (rc != 0) {
+ return rc;
+ }
+
/* No good mapping from LastChangeTime to ctime, not storing */
- timespec_to_gpfs_time(ft->create_time, gpfs_times, 3, &flags);
+ rc = timespec_to_gpfs_time(ft->create_time, gpfs_times, 3, &flags);
+ if (rc != 0) {
+ return rc;
+ }
if (!flags) {
DBG_DEBUG("nothing to do, return to avoid EINVAL\n");
return 0;
}
- rc = gpfswrap_set_times(fd, flags, gpfs_times);
+ if (!fsp->fsp_flags.is_pathref) {
+ rc = gpfswrap_set_times(fsp_get_io_fd(fsp), flags, gpfs_times);
+ if (rc != 0) {
+ DBG_WARNING("gpfs_set_times(%s) failed: %s\n",
+ fsp_str_dbg(fsp), strerror(errno));
+ }
+ return rc;
+ }
+
+
+ if (fsp->fsp_flags.have_proc_fds) {
+ int fd = fsp_get_pathref_fd(fsp);
+ struct sys_proc_fd_path_buf buf;
- if (rc != 0 && errno != ENOSYS) {
- DBG_WARNING("gpfs_set_times() returned with error %s for %s\n",
- strerror(errno),
- path);
+ rc = gpfswrap_set_times_path(sys_proc_fd_path(fd, &buf),
+ flags,
+ gpfs_times);
+ if (rc != 0) {
+ DBG_WARNING("gpfs_set_times_path(%s,%s) failed: %s\n",
+ fsp_str_dbg(fsp),
+ buf.buf,
+ strerror(errno));
+ }
+ return rc;
}
+ /*
+ * This is no longer a handle based call.
+ */
+
+ rc = gpfswrap_set_times_path(fsp->fsp_name->base_name,
+ flags,
+ gpfs_times);
+ if (rc != 0) {
+ DBG_WARNING("gpfs_set_times_path(%s) failed: %s\n",
+ fsp_str_dbg(fsp), strerror(errno));
+ }
return rc;
}
/* Try to use gpfs_set_times if it is enabled and available */
if (config->settimes) {
- ret = smbd_gpfs_set_times(fsp_get_io_fd(fsp),
- fsp->fsp_name->base_name,
- ft);
- if (ret == 0 || (ret == -1 && errno != ENOSYS)) {
- return ret;
- }
+ return smbd_gpfs_set_times(fsp, ft);
}
DBG_DEBUG("gpfs_set_times() not available or disabled, "
if (ret == -1) {
/* don't complain if access was denied */
if (errno != EPERM && errno != EACCES) {
- DBG_WARNING("SMB_VFS_NEXT_FNTIMES failed: %s",
+ DBG_WARNING("SMB_VFS_NEXT_FNTIMES failed: %s\n",
strerror(errno));
}
return -1;
attrs.creationTime.tv_sec = ft->create_time.tv_sec;
attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
- ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp),
- GPFS_WINATTR_SET_CREATION_TIME,
- &attrs);
+ if (!fsp->fsp_flags.is_pathref) {
+ ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp),
+ GPFS_WINATTR_SET_CREATION_TIME,
+ &attrs);
+ if (ret == -1 && errno != ENOSYS) {
+ DBG_WARNING("Set GPFS ntimes failed %d\n", ret);
+ return -1;
+ }
+ return ret;
+ }
+
+ if (fsp->fsp_flags.have_proc_fds) {
+ int fd = fsp_get_pathref_fd(fsp);
+ struct sys_proc_fd_path_buf buf;
+
+ ret = gpfswrap_set_winattrs_path(
+ sys_proc_fd_path(fd, &buf),
+ GPFS_WINATTR_SET_CREATION_TIME,
+ &attrs);
+ if (ret == -1 && errno != ENOSYS) {
+ DBG_WARNING("Set GPFS ntimes failed %d\n", ret);
+ return -1;
+ }
+ return ret;
+ }
+
+ /*
+ * This is no longer a handle based call.
+ */
+ ret = gpfswrap_set_winattrs_path(fsp->fsp_name->base_name,
+ GPFS_WINATTR_SET_CREATION_TIME,
+ &attrs);
if (ret == -1 && errno != ENOSYS) {
DBG_WARNING("Set GPFS ntimes failed %d\n", ret);
return -1;
}
static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
- const struct smb_filename *fname,
+ struct files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
struct gpfs_winattr attrs;
return false;
}
- ret = gpfswrap_get_winattrs_path(fname->base_name, &attrs);
+ ret = gpfswrap_get_winattrs(fsp_get_pathref_fd(fsp), &attrs);
if (ret == -1) {
return false;
}
if ((attrs.winAttrs & GPFS_WINATTR_OFFLINE) != 0) {
- DBG_DEBUG("%s is offline\n", fname->base_name);
+ DBG_DEBUG("%s is offline\n", fsp_str_dbg(fsp));
return true;
}
- DBG_DEBUG("%s is online\n", fname->base_name);
+ DBG_DEBUG("%s is online\n", fsp_str_dbg(fsp));
return false;
}
/*
* Something bad happened, always ask.
*/
- return vfs_gpfs_is_offline(handle, fsp->fsp_name,
+ return vfs_gpfs_is_offline(handle, fsp,
&fsp->fsp_name->st);
}
/*
* As long as it's offline, ask.
*/
- ext->offline = vfs_gpfs_is_offline(handle, fsp->fsp_name,
+ ext->offline = vfs_gpfs_is_offline(handle, fsp,
&fsp->fsp_name->st);
}
return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
}
+#ifdef O_PATH
+static int vfs_gpfs_check_pathref_fstat_x(struct gpfs_config_data *config,
+ struct connection_struct *conn)
+{
+ struct gpfs_iattr64 iattr = {0};
+ unsigned int litemask = 0;
+ int saved_errno;
+ int fd;
+ int ret;
+
+ fd = open(conn->connectpath, O_PATH);
+ if (fd == -1) {
+ DBG_ERR("openat() of share with O_PATH failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ ret = gpfswrap_fstat_x(fd, &litemask, &iattr, sizeof(iattr));
+ if (ret == 0) {
+ close(fd);
+ config->pathref_ok.gpfs_fstat_x = true;
+ return 0;
+ }
+
+ saved_errno = errno;
+ ret = close(fd);
+ if (ret != 0) {
+ DBG_ERR("close failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (saved_errno != EBADF) {
+ DBG_ERR("gpfswrap_fstat_x() of O_PATH handle failed: %s\n",
+ strerror(saved_errno));
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+static int vfs_gpfs_check_pathref(struct gpfs_config_data *config,
+ struct connection_struct *conn)
+{
+#ifndef O_PATH
+ /*
+ * This code path leaves all struct gpfs_config_data.pathref_ok members
+ * initialized to false.
+ */
+ return 0;
+#else
+ int ret;
+
+ ret = vfs_gpfs_check_pathref_fstat_x(config, conn);
+ if (ret != 0) {
+ return -1;
+ }
+
+ return 0;
+#endif
+}
+
static int vfs_gpfs_connect(struct vfs_handle_struct *handle,
const char *service, const char *user)
{
int ret;
bool check_fstype;
- gpfswrap_lib_init(0);
+ ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (IS_IPC(handle->conn)) {
+ return 0;
+ }
+
+ ret = gpfswrap_init();
+ if (ret < 0) {
+ DBG_ERR("Could not load GPFS library.\n");
+ return ret;
+ }
+
+ ret = gpfswrap_lib_init(0);
+ if (ret < 0) {
+ DBG_ERR("Could not open GPFS device file: %s\n",
+ strerror(errno));
+ return ret;
+ }
+
+ ret = gpfswrap_register_cifs_export();
+ if (ret < 0) {
+ DBG_ERR("Failed to register with GPFS: %s\n", strerror(errno));
+ return ret;
+ }
config = talloc_zero(handle->conn, struct gpfs_config_data);
if (!config) {
return -1;
}
- ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
- if (ret < 0) {
- TALLOC_FREE(config);
- return ret;
- }
-
check_fstype = lp_parm_bool(SNUM(handle->conn), "gpfs",
"check_fstype", true);
- if (check_fstype && !IS_IPC(handle->conn)) {
+ if (check_fstype) {
const char *connectpath = handle->conn->connectpath;
struct statfs buf = { 0 };
config->recalls = lp_parm_bool(SNUM(handle->conn), "gpfs",
"recalls", true);
+ ret = vfs_gpfs_check_pathref(config, handle->conn);
+ if (ret != 0) {
+ DBG_ERR("vfs_gpfs_check_pathref() on [%s] failed\n",
+ handle->conn->connectpath);
+ TALLOC_FREE(config);
+ return -1;
+ }
+
SMB_VFS_HANDLE_SET_DATA(handle, config,
NULL, struct gpfs_config_data,
return -1);
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)
{
+ struct vfs_open_how how = *_how;
struct gpfs_config_data *config = NULL;
struct gpfs_fsp_extension *ext = NULL;
int ret;
return -1);
if (config->hsm && !config->recalls &&
+ !fsp->fsp_flags.is_pathref &&
vfs_gpfs_fsp_is_offline(handle, fsp))
{
DBG_DEBUG("Refusing access to offline file %s\n",
}
if (config->syncio) {
- flags |= O_SYNC;
+ how.flags |= O_SYNC;
}
ext = VFS_ADD_FSP_EXTENSION(handle, fsp, struct gpfs_fsp_extension,
*/
*ext = (struct gpfs_fsp_extension) { .offline = true };
- ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
+ ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, &how);
if (ret == -1) {
VFS_REMOVE_FSP_EXTENSION(handle, fsp);
}
.disk_free_fn = vfs_gpfs_disk_free,
.get_quota_fn = vfs_gpfs_get_quota,
.fs_capabilities_fn = vfs_gpfs_capabilities,
- .kernel_flock_fn = vfs_gpfs_kernel_flock,
+ .filesystem_sharemode_fn = vfs_gpfs_filesystem_sharemode,
.linux_setlease_fn = vfs_gpfs_setlease,
- .get_real_filename_fn = vfs_gpfs_get_real_filename,
+ .get_real_filename_at_fn = vfs_gpfs_get_real_filename_at,
.get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
.get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
.fget_dos_attributes_fn = vfs_gpfs_fget_dos_attributes,
.fset_dos_attributes_fn = vfs_gpfs_fset_dos_attributes,
.fget_nt_acl_fn = gpfsacl_fget_nt_acl,
- .get_nt_acl_at_fn = gpfsacl_get_nt_acl_at,
.fset_nt_acl_fn = gpfsacl_fset_nt_acl,
- .sys_acl_get_file_fn = gpfsacl_sys_acl_get_file,
.sys_acl_get_fd_fn = gpfsacl_sys_acl_get_fd,
- .sys_acl_blob_get_file_fn = gpfsacl_sys_acl_blob_get_file,
.sys_acl_blob_get_fd_fn = gpfsacl_sys_acl_blob_get_fd,
.sys_acl_set_fd_fn = gpfsacl_sys_acl_set_fd,
.sys_acl_delete_def_fd_fn = gpfsacl_sys_acl_delete_def_fd,
.fchmod_fn = vfs_gpfs_fchmod,
.close_fn = vfs_gpfs_close,
- .stat_fn = vfs_gpfs_stat,
- .lstat_fn = vfs_gpfs_lstat,
+ .stat_fn = nfs4_acl_stat,
+ .fstat_fn = nfs4_acl_fstat,
+ .lstat_fn = nfs4_acl_lstat,
+ .fstatat_fn = nfs4_acl_fstatat,
.fntimes_fn = vfs_gpfs_fntimes,
.aio_force_fn = vfs_gpfs_aio_force,
.sendfile_fn = vfs_gpfs_sendfile,
static_decl_vfs;
NTSTATUS vfs_gpfs_init(TALLOC_CTX *ctx)
{
- int ret;
-
- ret = gpfswrap_init();
- if (ret != 0) {
- DEBUG(1, ("Could not initialize GPFS library wrapper\n"));
- }
-
return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
&vfs_gpfs_fns);
}