#include "../libcli/smb/smb2_create_ctx.h"
#include "lib/util/tevent_ntstatus.h"
#include "lib/util/tevent_unix.h"
+#include "lib/util/util_file.h"
#include "offload_token.h"
#include "string_replace.h"
#include "hash_inode.h"
#include "lib/adouble.h"
#include "lib/util_macstreams.h"
+#include "source3/smbd/dir.h"
/*
* Enhanced OS X and Netatalk compatibility
const char *model;
bool time_machine;
off_t time_machine_max_size;
+ bool convert_adouble;
bool wipe_intentionally_left_blank_rfork;
bool delete_empty_adfiles;
+ bool validate_afpinfo;
/*
* Additional options, all enabled by default,
bool readdir_attr_rsize;
bool readdir_attr_finder_info;
bool readdir_attr_max_access;
+ /* Recursion guard. Will go away when we have STATX. */
+ bool in_openat_pathref_fsp;
};
static const struct enum_list fruit_rsrc[] = {
};
struct fio {
+ vfs_handle_struct *handle;
+ files_struct *fsp; /* backlink to itself */
+
/* tcon config handle */
struct fruit_config_data *config;
+ /* Backend fsp for AppleDouble file, can be NULL */
+ files_struct *ad_fsp;
+ /* link from adouble_open_from_base_fsp() to fio */
+ struct fio *real_fio;
+
/* Denote stream type, meta or rsrc */
adouble_type_t type;
- /* Whether the create created the stream */
- bool created;
-
/*
* AFP_AfpInfo stream created, but not written yet, thus still a fake
* pipe fd. This is set to true in fruit_open_meta if there was no
* Helper functions
*****************************************************************************/
+static struct adouble *ad_get_meta_fsp(TALLOC_CTX *ctx,
+ vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname)
+{
+ NTSTATUS status;
+ struct adouble *ad = NULL;
+ struct smb_filename *smb_fname_cp = NULL;
+ struct fruit_config_data *config = NULL;
+
+ if (smb_fname->fsp != NULL) {
+ return ad_get(ctx, handle, smb_fname, ADOUBLE_META);
+ }
+
+ SMB_VFS_HANDLE_GET_DATA(handle,
+ config,
+ struct fruit_config_data,
+ return NULL);
+
+ if (config->in_openat_pathref_fsp) {
+ return NULL;
+ }
+
+ smb_fname_cp = cp_smb_filename(ctx,
+ smb_fname);
+ if (smb_fname_cp == NULL) {
+ return NULL;
+ }
+ TALLOC_FREE(smb_fname_cp->stream_name);
+ config->in_openat_pathref_fsp = true;
+ status = openat_pathref_fsp(handle->conn->cwd_fsp,
+ smb_fname_cp);
+ config->in_openat_pathref_fsp = false;
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(smb_fname_cp);
+ return NULL;
+ }
+
+ ad = ad_get(ctx, handle, smb_fname_cp, ADOUBLE_META);
+ TALLOC_FREE(smb_fname_cp);
+ return ad;
+}
+
+static struct fio *fruit_get_complete_fio(vfs_handle_struct *handle,
+ files_struct *fsp)
+{
+ struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ if (fio == NULL) {
+ return NULL;
+ }
+
+ if (fio->real_fio != NULL) {
+ /*
+ * This is an fsp from adouble_open_from_base_fsp()
+ * we should just pass this to the next
+ * module.
+ */
+ return NULL;
+ }
+
+ return fio;
+}
+
/**
* Initialize config struct from our smb.conf config parameters
**/
static int init_fruit_config(vfs_handle_struct *handle)
{
struct fruit_config_data *config;
- int enumval;
+ int enumval = -1;
const char *tm_size_str = NULL;
config = talloc_zero(handle->conn, struct fruit_config_data);
return -1;
}
- /*
- * Versions up to Samba 4.5.x had a spelling bug in the
- * fruit:resource option calling lp_parm_enum with
- * "res*s*ource" (ie two s).
- *
- * In Samba 4.6 we accept both the wrong and the correct
- * spelling, in Samba 4.7 the bad spelling will be removed.
- */
enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "ressource", fruit_rsrc, FRUIT_RSRC_ADFILE);
- if (enumval == -1) {
- DEBUG(1, ("value for %s: resource type unknown\n",
- FRUIT_PARAM_TYPE_NAME));
- return -1;
- }
- config->rsrc = (enum fruit_rsrc)enumval;
-
- enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "resource", fruit_rsrc, enumval);
+ "resource", fruit_rsrc, FRUIT_RSRC_ADFILE);
if (enumval == -1) {
DEBUG(1, ("value for %s: resource type unknown\n",
FRUIT_PARAM_TYPE_NAME));
config->aapl_zero_file_id =
lp_parm_bool(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "zero_file_id", false);
+ "zero_file_id", true);
config->readdir_attr_rsize = lp_parm_bool(
SNUM(handle->conn), "readdir_attr", "aapl_rsize", true);
config->time_machine_max_size = conv_str_size(tm_size_str);
}
+ config->convert_adouble = lp_parm_bool(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "convert_adouble", true);
+
config->wipe_intentionally_left_blank_rfork = lp_parm_bool(
SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
"wipe_intentionally_left_blank_rfork", false);
SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
"delete_empty_adfiles", false);
+ config->validate_afpinfo = lp_parm_bool(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "validate_afpinfo", true);
+
SMB_VFS_HANDLE_SET_DATA(handle, config,
NULL, struct fruit_config_data,
return -1);
return;
}
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ ad = ad_get_meta_fsp(talloc_tos(), handle, smb_fname);
if (ad == NULL) {
return;
}
access_mask & FILE_WRITE_DATA ? "WRITE" : "-",
share_mode);
- if (fsp->fh->fd == -1) {
+ if (fsp_get_io_fd(fsp) == -1) {
return NT_STATUS_OK;
}
if (req_bitmap & SMB2_CRTCTX_AAPL_SERVER_CAPS) {
if ((client_caps & SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR) &&
- (handle->conn->tcon->compat->fs_capabilities & FILE_NAMED_STREAMS)) {
+ (handle->conn->fs_capabilities & FILE_NAMED_STREAMS)) {
server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR;
config->readdir_attr_enabled = true;
}
}
if (req_bitmap & SMB2_CRTCTX_AAPL_VOLUME_CAPS) {
- int val = lp_case_sensitive(SNUM(handle->conn->tcon->compat));
+ int val = lp_case_sensitive(SNUM(handle->conn));
uint64_t caps = 0;
switch (val) {
files_struct *fsp = NULL;
ssize_t nread;
NTSTATUS status;
- int ret;
bool ok;
uint8_t buf[AFP_INFO_SIZE];
- stream_name = synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- AFPINFO_STREAM_NAME,
- NULL,
- smb_fname->twrp,
- smb_fname->flags);
- if (stream_name == NULL) {
- return false;
- }
-
- ret = SMB_VFS_STAT(handle->conn, stream_name);
- if (ret != 0) {
+ status = synthetic_pathref(talloc_tos(),
+ handle->conn->cwd_fsp,
+ smb_fname->base_name,
+ AFPINFO_STREAM_NAME,
+ NULL,
+ smb_fname->twrp,
+ smb_fname->flags,
+ &stream_name);
+ if (!NT_STATUS_IS_OK(status)) {
return false;
}
status = SMB_VFS_CREATE_FILE(
handle->conn, /* conn */
NULL, /* req */
- &handle->conn->cwd_fsp, /* dirfsp */
+ NULL, /* dirfsp */
stream_name, /* fname */
FILE_READ_DATA, /* access_mask */
(FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
fail:
if (fsp != NULL) {
- close_file(NULL, fsp, NORMAL_CLOSE);
+ close_file_free(NULL, &fsp, NORMAL_CLOSE);
}
return ok;
struct adouble *ad = NULL;
char *p = NULL;
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ ad = ad_get_meta_fsp(talloc_tos(), handle, smb_fname);
if (ad == NULL) {
return false;
}
return rc;
}
-static int fruit_fake_fd(void)
+static void fio_ref_destroy_fn(void *p_data)
{
- int pipe_fds[2];
- int fd;
- int ret;
+ struct fio *ref_fio = (struct fio *)p_data;
+ if (ref_fio->real_fio != NULL) {
+ SMB_ASSERT(ref_fio->real_fio->ad_fsp == ref_fio->fsp);
+ ref_fio->real_fio->ad_fsp = NULL;
+ ref_fio->real_fio = NULL;
+ }
+}
- /*
- * Return a valid fd, but ensure any attempt to use it returns
- * an error (EPIPE). Once we get a write on the handle, we open
- * the real fd.
- */
- ret = pipe(pipe_fds);
- if (ret != 0) {
- return -1;
+static void fio_close_ad_fsp(struct fio *fio)
+{
+ if (fio->ad_fsp != NULL) {
+ fd_close(fio->ad_fsp);
+ file_free(NULL, fio->ad_fsp);
+ /* fio_ref_destroy_fn() should have cleared this */
+ SMB_ASSERT(fio->ad_fsp == NULL);
}
- fd = pipe_fds[0];
- close(pipe_fds[1]);
+}
- return fd;
+static void fio_destroy_fn(void *p_data)
+{
+ struct fio *fio = (struct fio *)p_data;
+ fio_close_ad_fsp(fio);
}
static int fruit_open_meta_stream(vfs_handle_struct *handle,
{
struct fruit_config_data *config = NULL;
struct fio *fio = NULL;
- int open_flags = flags & ~O_CREAT;
+ struct vfs_open_how how = {
+ .flags = flags & ~O_CREAT,
+ .mode = mode,
+ };
int fd;
DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
- fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
+ fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
+ fio->handle = handle;
+ fio->fsp = fsp;
fio->type = ADOUBLE_META;
fio->config = config;
dirfsp,
smb_fname,
fsp,
- open_flags,
- mode);
+ &how);
if (fd != -1) {
return fd;
}
return -1;
}
- fd = fruit_fake_fd();
+ fd = vfs_fake_fd();
if (fd == -1) {
VFS_REMOVE_FSP_EXTENSION(handle, fsp);
return -1;
DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ /*
+ * We know this is a stream open, so fsp->base_fsp must
+ * already be open.
+ */
+ SMB_ASSERT(fsp_is_alternate_stream(fsp));
+ SMB_ASSERT(fsp->base_fsp->fsp_name->fsp == fsp->base_fsp);
+
+ ad = ad_get(talloc_tos(), handle, fsp->base_fsp->fsp_name, ADOUBLE_META);
if (ad != NULL) {
meta_exists = true;
}
return -1;
}
- fd = fruit_fake_fd();
+ fd = vfs_fake_fd();
if (fd == -1) {
return -1;
}
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
- fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
+ fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
+ fio->handle = handle;
+ fio->fsp = fsp;
fio->type = ADOUBLE_META;
fio->config = config;
fio->fake_fd = true;
mode_t mode)
{
int rc = 0;
- struct adouble *ad = NULL;
- struct smb_filename *smb_fname_base = NULL;
struct fruit_config_data *config = NULL;
- int hostfd = -1;
+ struct files_struct *ad_fsp = NULL;
+ struct fio *fio = NULL;
+ struct fio *ref_fio = NULL;
+ NTSTATUS status;
+ int fd = -1;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
if ((!(flags & O_CREAT)) &&
S_ISDIR(fsp->base_fsp->fsp_name->st.st_ex_mode))
{
- /* sorry, but directories don't habe a resource fork */
+ /* sorry, but directories don't have a resource fork */
+ errno = ENOENT;
rc = -1;
goto exit;
}
- rc = adouble_path(talloc_tos(), smb_fname, &smb_fname_base);
- if (rc != 0) {
+ /*
+ * We return a fake_fd to the vfs modules above,
+ * while we open an internal backend fsp for the
+ * '._' file for the next vfs modules.
+ *
+ * Note that adouble_open_from_base_fsp() recurses
+ * into fruit_openat(), but it'll just pass to
+ * the next module as just opens a flat file on
+ * disk.
+ */
+
+ fd = vfs_fake_fd();
+ if (fd == -1) {
+ rc = fd;
goto exit;
}
- /* We always need read/write access for the metadata header too */
- flags &= ~(O_RDONLY | O_WRONLY);
- flags |= O_RDWR;
-
- hostfd = SMB_VFS_NEXT_OPENAT(handle,
- dirfsp,
- smb_fname_base,
- fsp,
- flags,
- mode);
- if (hostfd == -1) {
+ status = adouble_open_from_base_fsp(fsp->conn->cwd_fsp,
+ fsp->base_fsp,
+ ADOUBLE_RSRC,
+ flags,
+ mode,
+ &ad_fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = map_errno_from_nt_status(status);
rc = -1;
goto exit;
}
- if (flags & (O_CREAT | O_TRUNC)) {
- ad = ad_init(fsp, ADOUBLE_RSRC);
- if (ad == NULL) {
- rc = -1;
- goto exit;
- }
-
- fsp->fh->fd = hostfd;
+ /*
+ * Now we need to glue both handles together,
+ * so that they automatically detach each other
+ * on close.
+ */
+ fio = fruit_get_complete_fio(handle, fsp);
+ if (fio == NULL) {
+ DBG_ERR("fio=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ rc = -1;
+ goto exit;
+ }
- rc = ad_fset(handle, ad, fsp);
- fsp->fh->fd = -1;
- if (rc != 0) {
- rc = -1;
- goto exit;
- }
- TALLOC_FREE(ad);
+ ref_fio = VFS_ADD_FSP_EXTENSION(handle, ad_fsp,
+ struct fio,
+ fio_ref_destroy_fn);
+ if (ref_fio == NULL) {
+ int saved_errno = errno;
+ fd_close(ad_fsp);
+ file_free(NULL, ad_fsp);
+ ad_fsp = NULL;
+ errno = saved_errno;
+ rc = -1;
+ goto exit;
}
-exit:
+ SMB_ASSERT(ref_fio->fsp == NULL);
+ ref_fio->handle = handle;
+ ref_fio->fsp = ad_fsp;
+ ref_fio->type = ADOUBLE_RSRC;
+ ref_fio->config = config;
+ ref_fio->real_fio = fio;
+ SMB_ASSERT(fio->ad_fsp == NULL);
+ fio->ad_fsp = ad_fsp;
+ fio->fake_fd = true;
- TALLOC_FREE(smb_fname_base);
+exit:
- DEBUG(10, ("fruit_open resource fork: rc=%d, fd=%d\n", rc, hostfd));
+ DEBUG(10, ("fruit_open resource fork: rc=%d\n", rc));
if (rc != 0) {
int saved_errno = errno;
- if (hostfd >= 0) {
- /*
- * BUGBUGBUG -- we would need to call
- * fd_close_posix here, but we don't have a
- * full fsp yet
- */
- fsp->fh->fd = hostfd;
- SMB_VFS_CLOSE(fsp);
+ if (fd != -1) {
+ vfs_fake_fd_close(fd);
}
- hostfd = -1;
errno = saved_errno;
+ return rc;
}
- return hostfd;
+ return fd;
}
static int fruit_open_rsrc_xattr(vfs_handle_struct *handle,
/*
* As there's no attropenat() this is only going to work with AT_FDCWD.
*/
- SMB_ASSERT(dirfsp->fh->fd == AT_FDCWD);
+ SMB_ASSERT(fsp_get_pathref_fd(dirfsp) == AT_FDCWD);
fd = attropen(smb_fname->base_name,
AFPRESOURCE_EA_NETATALK,
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
+ fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
+ fio->handle = handle;
+ fio->fsp = fsp;
+ fio->type = ADOUBLE_RSRC;
+ fio->config = config;
+
switch (config->rsrc) {
- case FRUIT_RSRC_STREAM:
+ case FRUIT_RSRC_STREAM: {
+ struct vfs_open_how how = {
+ .flags = flags, .mode = mode,
+ };
fd = SMB_VFS_NEXT_OPENAT(handle,
dirfsp,
smb_fname,
fsp,
- flags,
- mode);
+ &how);
break;
+ }
case FRUIT_RSRC_ADFILE:
fd = fruit_open_rsrc_adouble(handle, dirfsp, smb_fname,
default:
DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
+ errno = EINVAL;
return -1;
}
return -1;
}
- fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
- fio->type = ADOUBLE_RSRC;
- fio->config = config;
-
return fd;
}
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 fd;
dirfsp,
smb_fname,
fsp,
- flags,
- mode);
+ how);
+ }
+
+ if (how->resolve != 0) {
+ errno = ENOSYS;
+ return -1;
}
+ SMB_ASSERT(fsp_is_alternate_stream(fsp));
+
if (is_afpinfo_stream(smb_fname->stream_name)) {
fd = fruit_open_meta(handle,
dirfsp,
smb_fname,
fsp,
- flags,
- mode);
+ how->flags,
+ how->mode);
} else if (is_afpresource_stream(smb_fname->stream_name)) {
fd = fruit_open_rsrc(handle,
dirfsp,
smb_fname,
fsp,
- flags,
- mode);
+ how->flags,
+ how->mode);
} else {
fd = SMB_VFS_NEXT_OPENAT(handle,
dirfsp,
smb_fname,
fsp,
- flags,
- mode);
+ how);
}
DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
+ /* Prevent reopen optimisation */
+ fsp->fsp_flags.have_proc_fds = false;
return fd;
}
switch (config->meta) {
case FRUIT_META_STREAM:
- ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ {
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
+ if (fio == NULL) {
+ return -1;
+ }
+ if (fio->fake_fd) {
+ ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
+ fsp_set_fd(fsp, -1);
+ } else {
+ ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ }
break;
-
+ }
case FRUIT_META_NETATALK:
- ret = close(fsp->fh->fd);
- fsp->fh->fd = -1;
+ ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
+ fsp_set_fd(fsp, -1);
break;
default:
switch (config->rsrc) {
case FRUIT_RSRC_STREAM:
- case FRUIT_RSRC_ADFILE:
ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
break;
+ case FRUIT_RSRC_ADFILE:
+ {
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
+ if (fio == NULL) {
+ return -1;
+ }
+ fio_close_ad_fsp(fio);
+ ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
+ fsp_set_fd(fsp, -1);
+ break;
+ }
+
case FRUIT_RSRC_XATTR:
- ret = close(fsp->fh->fd);
- fsp->fh->fd = -1;
+ ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
+ fsp_set_fd(fsp, -1);
break;
default:
int ret;
int fd;
- fd = fsp->fh->fd;
+ fd = fsp_get_pathref_fd(fsp);
DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(fsp->fsp_name), fd);
- if (!is_named_stream(fsp->fsp_name)) {
+ if (!fsp_is_alternate_stream(fsp)) {
return SMB_VFS_NEXT_CLOSE(handle, fsp);
}
static int fruit_unlink_meta_netatalk(vfs_handle_struct *handle,
const struct smb_filename *smb_fname)
{
- return SMB_VFS_REMOVEXATTR(handle->conn,
- smb_fname,
+ SMB_ASSERT(smb_fname->fsp != NULL);
+ SMB_ASSERT(fsp_is_alternate_stream(smb_fname->fsp));
+ return SMB_VFS_FREMOVEXATTR(smb_fname->fsp->base_fsp,
AFPINFO_EA_NETATALK);
}
int ret;
if (!force_unlink) {
- struct smb_filename *smb_fname_cp = NULL;
+ struct smb_filename *full_fname = NULL;
off_t size;
- smb_fname_cp = cp_smb_filename(talloc_tos(), smb_fname);
- if (smb_fname_cp == NULL) {
+ /*
+ * TODO: use SMB_VFS_STATX() once we have it.
+ */
+
+ full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+ dirfsp,
+ smb_fname);
+ if (full_fname == NULL) {
return -1;
}
* deletion doesn't remove the resourcefork stream.
*/
- ret = SMB_VFS_NEXT_STAT(handle, smb_fname_cp);
+ ret = SMB_VFS_NEXT_STAT(handle, full_fname);
if (ret != 0) {
- TALLOC_FREE(smb_fname_cp);
+ TALLOC_FREE(full_fname);
DBG_ERR("stat [%s] failed [%s]\n",
- smb_fname_str_dbg(smb_fname_cp), strerror(errno));
+ smb_fname_str_dbg(full_fname), strerror(errno));
return -1;
}
- size = smb_fname_cp->st.st_ex_size;
- TALLOC_FREE(smb_fname_cp);
+ size = full_fname->st.st_ex_size;
+ TALLOC_FREE(full_fname);
if (size > 0) {
/* OS X ignores resource fork stream delete requests */
struct smb_filename *adp_smb_fname = NULL;
if (!force_unlink) {
- ad = ad_get(talloc_tos(), handle, smb_fname,
+ struct smb_filename *full_fname = NULL;
+
+ full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+ dirfsp,
+ smb_fname);
+ if (full_fname == NULL) {
+ return -1;
+ }
+
+ ad = ad_get(talloc_tos(), handle, full_fname,
ADOUBLE_RSRC);
+ TALLOC_FREE(full_fname);
if (ad == NULL) {
errno = ENOENT;
return -1;
adp_smb_fname,
0);
TALLOC_FREE(adp_smb_fname);
- if ((rc != 0) && (errno == ENOENT) && force_unlink) {
+ if ((rc != 0) && (errno == ENOENT || errno == ENAMETOOLONG) && force_unlink) {
rc = 0;
}
return rc;
}
-static int fruit_chmod(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- mode_t mode)
+static int fruit_fchmod(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ mode_t mode)
{
int rc = -1;
struct fruit_config_data *config = NULL;
struct smb_filename *smb_fname_adp = NULL;
+ const struct smb_filename *smb_fname = NULL;
+ NTSTATUS status;
- rc = SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
+ rc = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
if (rc != 0) {
return rc;
}
+ smb_fname = fsp->fsp_name;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
return -1;
}
- DEBUG(10, ("fruit_chmod: %s\n", smb_fname_adp->base_name));
+ status = openat_pathref_fsp(handle->conn->cwd_fsp,
+ smb_fname_adp);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* detect ENOENT (mapped to OBJECT_NAME_NOT_FOUND) */
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND)){
+ rc = 0;
+ goto out;
+ }
+ rc = -1;
+ goto out;
+ }
+
+ DBG_DEBUG("%s\n", smb_fname_adp->base_name);
- rc = SMB_VFS_NEXT_CHMOD(handle, smb_fname_adp, mode);
+ rc = SMB_VFS_NEXT_FCHMOD(handle, smb_fname_adp->fsp, mode);
if (errno == ENOENT) {
rc = 0;
}
-
+out:
TALLOC_FREE(smb_fname_adp);
return rc;
}
struct smb_filename *rsrc_smb_fname = NULL;
int ret;
- SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
if (flags & AT_REMOVEDIR) {
return SMB_VFS_NEXT_UNLINKAT(handle,
dirfsp,
files_struct *fsp, void *data,
size_t n, off_t offset)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nread;
int ret;
+ if ((fio == NULL) || fio->fake_fd) {
+ return -1;
+ }
+
nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
if (nread == -1 || nread == n) {
return nread;
files_struct *fsp, void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nread;
ssize_t to_return;
}
if (fio == NULL) {
- DBG_ERR("Failed to fetch fsp extension");
+ DBG_ERR("Failed to fetch fsp extension\n");
return -1;
}
return -1;
}
- if (nread == -1 && fio->created) {
+ if (nread == -1 && fio->fake_fd) {
AfpInfo *ai = NULL;
char afpinfo_buf[AFP_INFO_SIZE];
files_struct *fsp, void *data,
size_t n, off_t offset)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
struct adouble *ad = NULL;
ssize_t nread;
- ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
+ if (fio == NULL || fio->ad_fsp == NULL) {
+ DBG_ERR("fio/ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ return -1;
+ }
+
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
if (ad == NULL) {
+ DBG_ERR("ad_fget [%s] failed [%s]\n",
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
return -1;
}
- nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n,
+ nread = SMB_VFS_NEXT_PREAD(handle, fio->ad_fsp, data, n,
offset + ad_getentryoff(ad, ADEID_RFORK));
TALLOC_FREE(ad);
files_struct *fsp, void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nread;
if (fio == NULL) {
files_struct *fsp, void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nread;
DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
struct fruit_pread_state *state = NULL;
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
req = tevent_req_create(mem_ctx, &state,
struct fruit_pread_state);
{
struct fruit_pread_state *state = tevent_req_data(
req, struct fruit_pread_state);
+ ssize_t retval = -1;
if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ tevent_req_received(req);
return -1;
}
*vfs_aio_state = state->vfs_aio_state;
- return state->nread;
+ retval = state->nread;
+ tevent_req_received(req);
+ return retval;
}
static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle,
- files_struct *fsp, const void *data,
+ files_struct *fsp, const void *indata,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
+ const void *data = indata;
+ char afpinfo_buf[AFP_INFO_SIZE];
AfpInfo *ai = NULL;
size_t nwritten;
int ret;
}
if (fio->fake_fd) {
- int fd;
+ struct vfs_open_how how = {
+ .flags = fio->flags, .mode = fio->mode,
+ };
+ int fd = fsp_get_pathref_fd(fsp);
- ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ ret = vfs_fake_fd_close(fd);
+ fsp_set_fd(fsp, -1);
if (ret != 0) {
DBG_ERR("Close [%s] failed: %s\n",
fsp_str_dbg(fsp), strerror(errno));
- fsp->fh->fd = -1;
return -1;
}
fd = SMB_VFS_NEXT_OPENAT(handle,
- fsp->dirfsp,
+ NULL, /* opening a stream */
fsp->fsp_name,
fsp,
- fio->flags,
- fio->mode);
+ &how);
if (fd == -1) {
DBG_ERR("On-demand create [%s] in write failed: %s\n",
fsp_str_dbg(fsp), strerror(errno));
return -1;
}
- fsp->fh->fd = fd;
+ fsp_set_fd(fsp, fd);
fio->fake_fd = false;
}
- ai = afpinfo_unpack(talloc_tos(), data);
+ ai = afpinfo_unpack(talloc_tos(), data, fio->config->validate_afpinfo);
if (ai == NULL) {
return -1;
}
return n;
}
+ if (!fio->config->validate_afpinfo) {
+ /*
+ * Ensure the buffer contains a valid header, so marshall
+ * the data from the afpinfo struck back into a buffer
+ * and write that instead of the possibly malformed data
+ * we got from the client.
+ */
+ nwritten = afpinfo_pack(ai, afpinfo_buf);
+ if (nwritten != AFP_INFO_SIZE) {
+ errno = EINVAL;
+ return -1;
+ }
+ data = afpinfo_buf;
+ }
+
nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
if (nwritten != n) {
return -1;
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
+ struct fruit_config_data *config = NULL;
struct adouble *ad = NULL;
AfpInfo *ai = NULL;
char *p = NULL;
int ret;
bool ok;
- ai = afpinfo_unpack(talloc_tos(), data);
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct fruit_config_data, return -1);
+
+ ai = afpinfo_unpack(talloc_tos(), data, config->validate_afpinfo);
if (ai == NULL) {
return -1;
}
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nwritten;
uint8_t buf[AFP_INFO_SIZE];
size_t to_write;
int cmp;
if (fio == NULL) {
- DBG_ERR("Failed to fetch fsp extension");
+ DBG_ERR("Failed to fetch fsp extension\n");
return -1;
}
return -1;
}
- cmp = memcmp(data, "AFP", 3);
- if (cmp != 0) {
- errno = EINVAL;
- return -1;
+ if (fio->config->validate_afpinfo) {
+ cmp = memcmp(data, "AFP", 3);
+ if (cmp != 0) {
+ errno = EINVAL;
+ return -1;
+ }
}
if (n <= AFP_OFF_FinderInfo) {
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
struct adouble *ad = NULL;
ssize_t nwritten;
int ret;
- ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
+ if (fio == NULL || fio->ad_fsp == NULL) {
+ DBG_ERR("fio/ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ return -1;
+ }
+
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
if (ad == NULL) {
- DBG_ERR("ad_get [%s] failed\n", fsp_str_dbg(fsp));
+ DBG_ERR("ad_fget [%s] failed [%s]\n",
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
return -1;
}
- nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n,
+ nwritten = SMB_VFS_NEXT_PWRITE(handle, fio->ad_fsp, data, n,
offset + ad_getentryoff(ad, ADEID_RFORK));
if (nwritten != n) {
DBG_ERR("Short write on [%s] [%zd/%zd]\n",
- fsp_str_dbg(fsp), nwritten, n);
+ fsp_str_dbg(fio->ad_fsp), nwritten, n);
TALLOC_FREE(ad);
return -1;
}
if ((n + offset) > ad_getentrylen(ad, ADEID_RFORK)) {
ad_setentrylen(ad, ADEID_RFORK, n + offset);
- ret = ad_fset(handle, ad, fsp);
+ ret = ad_fset(handle, ad, fio->ad_fsp);
if (ret != 0) {
- DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fsp));
+ DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fio->ad_fsp));
TALLOC_FREE(ad);
return -1;
}
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nwritten;
if (fio == NULL) {
- DBG_ERR("Failed to fetch fsp extension");
+ DBG_ERR("Failed to fetch fsp extension\n");
return -1;
}
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nwritten;
DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
struct fruit_pwrite_state *state = NULL;
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
req = tevent_req_create(mem_ctx, &state,
struct fruit_pwrite_state);
{
struct fruit_pwrite_state *state = tevent_req_data(
req, struct fruit_pwrite_state);
+ ssize_t retval = -1;
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ tevent_req_received(req);
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ retval = state->nwritten;
+ tevent_req_received(req);
+ return retval;
+}
+
+struct fruit_fsync_state {
+ int ret;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void fruit_fsync_done(struct tevent_req *subreq);
+
+static struct tevent_req *fruit_fsync_send(
+ struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct fruit_fsync_state *state = NULL;
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct fruit_fsync_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (fruit_must_handle_aio_stream(fio)) {
+ struct adouble *ad = NULL;
+
+ if (fio->type == ADOUBLE_META) {
+ /*
+ * We must never pass a fake_fd
+ * to lower level fsync calls.
+ * Everything is already done
+ * synchronously, so just return
+ * true.
+ */
+ SMB_ASSERT(fio->fake_fd);
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * We know the following must be true,
+ * as it's the condition for fruit_must_handle_aio_stream()
+ * to return true if fio->type == ADOUBLE_RSRC.
+ */
+ SMB_ASSERT(fio->config->rsrc == FRUIT_RSRC_ADFILE);
+ if (fio->ad_fsp == NULL) {
+ tevent_req_error(req, EBADF);
+ return tevent_req_post(req, ev);
+ }
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
+ if (ad == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return tevent_req_post(req, ev);
+ }
+ fsp = fio->ad_fsp;
+ }
+
+ subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
+ if (tevent_req_nomem(req, subreq)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, fruit_fsync_done, req);
+ return req;
+}
+
+static void fruit_fsync_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct fruit_fsync_state *state = tevent_req_data(
+ req, struct fruit_fsync_state);
+
+ state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+ if (state->ret != 0) {
+ tevent_req_error(req, errno);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static int fruit_fsync_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct fruit_fsync_state *state = tevent_req_data(
+ req, struct fruit_fsync_state);
+ int retval = -1;
if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ tevent_req_received(req);
return -1;
}
*vfs_aio_state = state->vfs_aio_state;
- return state->nwritten;
+ retval = state->ret;
+ tevent_req_received(req);
+ return retval;
}
/**
{
struct adouble *ad = NULL;
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ /* Populate the stat struct with info from the base file. */
+ if (fruit_stat_base(handle, smb_fname, follow_links) == -1) {
+ return -1;
+ }
+
+ ad = ad_get_meta_fsp(talloc_tos(), handle, smb_fname);
if (ad == NULL) {
DBG_INFO("fruit_stat_meta %s: %s\n",
smb_fname_str_dbg(smb_fname), strerror(errno));
}
TALLOC_FREE(ad);
- /* Populate the stat struct with info from the base file. */
- if (fruit_stat_base(handle, smb_fname, follow_links) == -1) {
- return -1;
- }
smb_fname->st.st_ex_size = AFP_INFO_SIZE;
smb_fname->st.st_ex_ino = hash_inode(&smb_fname->st,
smb_fname->stream_name);
files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
struct smb_filename smb_fname;
ino_t ino;
int ret;
files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
struct adouble *ad = NULL;
int ret;
+ if (fio == NULL || fio->ad_fsp == NULL) {
+ DBG_ERR("fio/ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ return -1;
+ }
+
/* Populate the stat struct with info from the base file. */
ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
if (ret == -1) {
return -1;
}
- ad = ad_get(talloc_tos(), handle,
- fsp->base_fsp->fsp_name,
- ADOUBLE_RSRC);
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
if (ad == NULL) {
- DBG_ERR("ad_get [%s] failed [%s]\n",
- fsp_str_dbg(fsp), strerror(errno));
+ DBG_ERR("ad_fget [%s] failed [%s]\n",
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
return -1;
}
static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
int rc;
if (fio == NULL) {
off_t size)
{
struct smb_filename *sname = NULL;
+ NTSTATUS status;
int ret;
bool ok;
return NT_STATUS_OK;
}
- sname = synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- AFPINFO_STREAM_NAME,
- NULL,
- smb_fname->twrp,
- 0);
- if (sname == NULL) {
+ status = synthetic_pathref(talloc_tos(),
+ handle->conn->cwd_fsp,
+ smb_fname->base_name,
+ AFPINFO_STREAM_NAME,
+ NULL,
+ smb_fname->twrp,
+ 0,
+ &sname);
+ if (!NT_STATUS_IS_OK(status)) {
return NT_STATUS_NO_MEMORY;
}
handle->conn->cwd_fsp,
sname,
0);
- TALLOC_FREE(sname);
if (ret != 0) {
DBG_ERR("Removing [%s] failed\n", smb_fname_str_dbg(sname));
+ TALLOC_FREE(sname);
return map_nt_error_from_unix(errno);
}
+ TALLOC_FREE(sname);
return NT_STATUS_OK;
}
}
}
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ ad = ad_get_meta_fsp(talloc_tos(), handle, smb_fname);
if (ad == NULL) {
return NT_STATUS_OK;
}
struct fruit_config_data *config = NULL;
NTSTATUS status;
+ if (S_ISDIR(smb_fname->st.st_ex_mode)) {
+ return NT_STATUS_OK;
+ }
+
SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
return NT_STATUS_INTERNAL_ERROR);
*pnum_streams = num_streams;
}
-static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
+static NTSTATUS fruit_fstreaminfo(vfs_handle_struct *handle,
struct files_struct *fsp,
- const struct smb_filename *smb_fname,
TALLOC_CTX *mem_ctx,
unsigned int *pnum_streams,
struct stream_struct **pstreams)
{
struct fruit_config_data *config = NULL;
+ const struct smb_filename *smb_fname = NULL;
NTSTATUS status;
+ smb_fname = fsp->fsp_name;
+
SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
return NT_STATUS_UNSUCCESSFUL);
DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
- status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname, mem_ctx,
+ status = SMB_VFS_NEXT_FSTREAMINFO(handle, fsp, mem_ctx,
pnum_streams, pstreams);
if (!NT_STATUS_IS_OK(status)) {
return status;
return NT_STATUS_OK;
}
-static int fruit_ntimes(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- struct smb_file_time *ft)
+static int fruit_fntimes(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct smb_file_time *ft)
{
int rc = 0;
struct adouble *ad = NULL;
if ((config->meta != FRUIT_META_NETATALK) ||
is_omit_timespec(&ft->create_time))
{
- return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
+ return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
}
- DEBUG(10,("set btime for %s to %s\n", smb_fname_str_dbg(smb_fname),
- time_to_asc(convert_timespec_to_time_t(ft->create_time))));
+ DBG_DEBUG("set btime for %s to %s", fsp_str_dbg(fsp),
+ time_to_asc(convert_timespec_to_time_t(ft->create_time)));
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
if (ad == NULL) {
goto exit;
}
ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX,
convert_time_t_to_uint32_t(ft->create_time.tv_sec));
- rc = ad_set(handle, ad, smb_fname);
+ rc = ad_fset(handle, ad, fsp);
exit:
TALLOC_FREE(ad);
if (rc != 0) {
- DEBUG(1, ("fruit_ntimes: %s\n", smb_fname_str_dbg(smb_fname)));
+ DBG_WARNING("%s\n", fsp_str_dbg(fsp));
return -1;
}
- return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
+ return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
}
static int fruit_fallocate(struct vfs_handle_struct *handle,
off_t offset,
off_t len)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
if (fio == NULL) {
return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
struct files_struct *fsp,
off_t offset)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
int rc;
struct adouble *ad = NULL;
off_t ad_off;
- ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
+ if (fio == NULL || fio->ad_fsp == NULL) {
+ DBG_ERR("fio/ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ return -1;
+ }
+
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
if (ad == NULL) {
- DBG_DEBUG("ad_get [%s] failed [%s]\n",
- fsp_str_dbg(fsp), strerror(errno));
+ DBG_ERR("ad_fget [%s] failed [%s]\n",
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
return -1;
}
ad_off = ad_getentryoff(ad, ADEID_RFORK);
- rc = ftruncate(fsp->fh->fd, offset + ad_off);
+ rc = SMB_VFS_NEXT_FTRUNCATE(handle, fio->ad_fsp, offset + ad_off);
if (rc != 0) {
TALLOC_FREE(ad);
return -1;
ad_setentrylen(ad, ADEID_RFORK, offset);
- rc = ad_fset(handle, ad, fsp);
+ rc = ad_fset(handle, ad, fio->ad_fsp);
if (rc != 0) {
DBG_ERR("ad_fset [%s] failed [%s]\n",
- fsp_str_dbg(fsp), strerror(errno));
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
TALLOC_FREE(ad);
return -1;
}
struct files_struct *fsp,
off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
int ret;
if (fio == NULL) {
- DBG_ERR("Failed to fetch fsp extension");
+ DBG_ERR("Failed to fetch fsp extension\n");
return -1;
}
off_t offset)
{
if (offset > 60) {
- DBG_WARNING("ftruncate %s to %jd",
+ DBG_WARNING("ftruncate %s to %jd\n",
fsp_str_dbg(fsp), (intmax_t)offset);
/* OS X returns NT_STATUS_ALLOTTED_SPACE_EXCEEDED */
errno = EOVERFLOW;
struct files_struct *fsp,
off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
int ret;
DBG_DEBUG("Path [%s] offset [%"PRIdMAX"]\n", fsp_str_dbg(fsp),
static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
struct smb_request *req,
- struct files_struct **dirfsp,
+ struct files_struct *dirfsp,
struct smb_filename *smb_fname,
uint32_t access_mask,
uint32_t share_access,
NTSTATUS status;
struct fruit_config_data *config = NULL;
files_struct *fsp = NULL;
- struct fio *fio = NULL;
bool internal_open = (oplock_request & INTERNAL_OPEN_ONLY);
int ret;
SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
return NT_STATUS_UNSUCCESSFUL);
- if (is_apple_stream(smb_fname->stream_name) && !internal_open) {
+ if (is_apple_stream(smb_fname->stream_name) &&
+ !internal_open &&
+ config->convert_adouble)
+ {
uint32_t conv_flags = 0;
if (config->wipe_intentionally_left_blank_rfork) {
}
ret = ad_convert(handle,
- handle->conn->cwd_fsp,
smb_fname,
macos_string_replace_map,
conv_flags);
if (ret != 0) {
- DBG_ERR("ad_convert() failed\n");
- return NT_STATUS_UNSUCCESSFUL;
+ DBG_ERR("ad_convert(\"%s\") failed\n",
+ smb_fname_str_dbg(smb_fname));
}
}
goto fail;
}
- fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
- if (fio != NULL && pinfo != NULL && *pinfo == FILE_WAS_CREATED) {
- fio->created = true;
- }
-
if (is_named_stream(smb_fname) || fsp->fsp_flags.is_directory) {
return status;
}
if ((config->locking == FRUIT_LOCKING_NETATALK) &&
- (fsp->op != NULL))
+ (fsp->op != NULL) &&
+ !fsp->fsp_flags.is_pathref)
{
status = fruit_check_access(
handle, *result,
DEBUG(10, ("fruit_create_file: %s\n", nt_errstr(status)));
if (fsp) {
- close_file(req, fsp, ERROR_CLOSE);
- *result = fsp = NULL;
+ close_file_free(req, &fsp, ERROR_CLOSE);
+ *result = NULL;
}
return status;
}
-static NTSTATUS fruit_readdir_attr(struct vfs_handle_struct *handle,
- const struct smb_filename *fname,
- TALLOC_CTX *mem_ctx,
- struct readdir_attr_data **pattr_data)
+static NTSTATUS fruit_freaddir_attr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ struct readdir_attr_data **pattr_data)
{
struct fruit_config_data *config = NULL;
struct readdir_attr_data *attr_data;
return NT_STATUS_UNSUCCESSFUL);
if (!global_fruit_config.nego_aapl) {
- return SMB_VFS_NEXT_READDIR_ATTR(handle, fname, mem_ctx, pattr_data);
+ return SMB_VFS_NEXT_FREADDIR_ATTR(handle,
+ fsp,
+ mem_ctx,
+ pattr_data);
}
- DEBUG(10, ("fruit_readdir_attr %s\n", fname->base_name));
+ DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
- if (config->wipe_intentionally_left_blank_rfork) {
- conv_flags |= AD_CONV_WIPE_BLANK;
- }
- if (config->delete_empty_adfiles) {
- conv_flags |= AD_CONV_DELETE;
- }
+ if (config->convert_adouble) {
+ if (config->wipe_intentionally_left_blank_rfork) {
+ conv_flags |= AD_CONV_WIPE_BLANK;
+ }
+ if (config->delete_empty_adfiles) {
+ conv_flags |= AD_CONV_DELETE;
+ }
- ret = ad_convert(handle,
- handle->conn->cwd_fsp,
- fname,
- macos_string_replace_map,
- conv_flags);
- if (ret != 0) {
- DBG_ERR("ad_convert() failed\n");
- return NT_STATUS_UNSUCCESSFUL;
+ ret = ad_convert(handle,
+ fsp->fsp_name,
+ macos_string_replace_map,
+ conv_flags);
+ if (ret != 0) {
+ DBG_ERR("ad_convert(\"%s\") failed\n",
+ fsp_str_dbg(fsp));
+ }
}
*pattr_data = talloc_zero(mem_ctx, struct readdir_attr_data);
if (*pattr_data == NULL) {
- return NT_STATUS_UNSUCCESSFUL;
+ return NT_STATUS_NO_MEMORY;
}
attr_data = *pattr_data;
attr_data->type = RDATTR_AAPL;
* Mac metadata: compressed FinderInfo, resource fork length
* and creation date
*/
- status = readdir_attr_macmeta(handle, fname, attr_data);
+ status = readdir_attr_macmeta(handle, fsp->fsp_name, attr_data);
if (!NT_STATUS_IS_OK(status)) {
/*
* Error handling is tricky: if we return failure from
* UNIX mode
*/
if (config->unix_info_enabled) {
- attr_data->attr_data.aapl.unix_mode = fname->st.st_ex_mode;
+ attr_data->attr_data.aapl.unix_mode =
+ fsp->fsp_name->st.st_ex_mode;
}
/*
if (!config->readdir_attr_max_access) {
attr_data->attr_data.aapl.max_access = FILE_GENERIC_ALL;
} else {
- status = smbd_calculate_access_mask(
- handle->conn,
- handle->conn->cwd_fsp,
- fname,
+ status = smbd_calculate_access_mask_fsp(fsp->conn->cwd_fsp,
+ fsp,
false,
SEC_FLAG_MAXIMUM_ALLOWED,
&attr_data->attr_data.aapl.max_access);
return NT_STATUS_OK;
fail:
- DEBUG(1, ("fruit_readdir_attr %s, error: %s\n",
- fname->base_name, nt_errstr(status)));
+ DBG_WARNING("Path [%s], error: %s\n", fsp_str_dbg(fsp),
+ nt_errstr(status));
TALLOC_FREE(*pattr_data);
return status;
}
struct tevent_context *ev;
files_struct *fsp;
uint32_t fsctl;
+ uint32_t flags;
+ uint64_t xferlen;
DATA_BLOB token;
};
status = SMB_VFS_NEXT_OFFLOAD_READ_RECV(subreq,
state->handle,
state,
+ &state->flags,
+ &state->xferlen,
&state->token);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
static NTSTATUS fruit_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 fruit_offload_read_state *state = tevent_req_data(
return status;
}
+ *flags = state->flags;
+ *xferlen = state->xferlen;
token->length = state->token.length;
token->data = talloc_move(mem_ctx, &state->token.data);
* streams, because we're in vfs_fruit. We don't do this async
* because streams are few and small.
*/
- status = vfs_streaminfo(state->handle->conn, state->src_fsp,
- state->src_fsp->fsp_name,
+ status = vfs_fstreaminfo(state->src_fsp,
req, &num_streams, &streams);
if (tevent_req_nterror(req, status)) {
return;
state->handle->conn,
src_fname_tmp,
dst_fname_tmp,
- OPENX_FILE_CREATE_IF_NOT_EXIST,
- 0, false);
+ FILE_CREATE);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("%s: copy %s to %s failed: %s\n", __func__,
smb_fname_str_dbg(src_fname_tmp),
status = SMB_VFS_NEXT_CREATE_FILE(
handle, /* conn */
NULL, /* req */
- &handle->conn->cwd_fsp, /* dirfsp */
+ NULL, /* dirfsp */
smb_fname, /* fname */
FILE_GENERIC_READ, /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
goto out;
}
- file_data = talloc_array(talloc_tos(), uint8_t, plist_file_size);
+ file_data = talloc_zero_array(talloc_tos(),
+ uint8_t,
+ plist_file_size + 1);
if (file_data == NULL) {
ok = false;
goto out;
}
- status = close_file(NULL, fsp, NORMAL_CLOSE);
- fsp = NULL;
+ status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("close_file failed: %s\n", nt_errstr(status));
ok = false;
out:
if (fsp != NULL) {
- status = close_file(NULL, fsp, NORMAL_CLOSE);
+ status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("close_file failed: %s\n", nt_errstr(status));
}
- fsp = NULL;
}
TALLOC_FREE(plist);
TALLOC_FREE(smb_fname);
struct smb_Dir *dir_hnd = NULL;
const char *dname = NULL;
char *talloced = NULL;
- long offset = 0;
size_t nbands;
+ NTSTATUS status;
path = talloc_asprintf(talloc_tos(),
"%s/%s/bands",
return false;
}
- dir_hnd = OpenDir(talloc_tos(), handle->conn, bands_dir, NULL, 0);
- if (dir_hnd == NULL) {
+ status = OpenDir(talloc_tos(),
+ handle->conn,
+ bands_dir,
+ NULL,
+ 0,
+ &dir_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(bands_dir);
+ errno = map_errno_from_nt_status(status);
return false;
}
nbands = 0;
- while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
- != NULL)
- {
+ while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
if (ISDOT(dname) || ISDOTDOT(dname)) {
continue;
}
struct smb_Dir *dir_hnd = NULL;
const char *dname = NULL;
char *talloced = NULL;
- long offset = 0;
uint64_t dfree;
uint64_t dsize;
bool ok;
+ NTSTATUS status;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data,
_dsize);
}
- dir_hnd = OpenDir(talloc_tos(), handle->conn, smb_fname, NULL, 0);
- if (dir_hnd == NULL) {
+ status = OpenDir(talloc_tos(),
+ handle->conn,
+ smb_fname,
+ NULL,
+ 0,
+ &dir_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = map_errno_from_nt_status(status);
return UINT64_MAX;
}
- while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
- != NULL)
- {
+ while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
ok = fruit_tmsize_do_dirent(handle, &state, dname);
if (!ok) {
TALLOC_FREE(talloced);
.disk_free_fn = fruit_disk_free,
/* File operations */
- .chmod_fn = fruit_chmod,
+ .fchmod_fn = fruit_fchmod,
.unlinkat_fn = fruit_unlinkat,
.renameat_fn = fruit_renameat,
.openat_fn = fruit_openat,
.pread_recv_fn = fruit_pread_recv,
.pwrite_send_fn = fruit_pwrite_send,
.pwrite_recv_fn = fruit_pwrite_recv,
+ .fsync_send_fn = fruit_fsync_send,
+ .fsync_recv_fn = fruit_fsync_recv,
.stat_fn = fruit_stat,
.lstat_fn = fruit_lstat,
.fstat_fn = fruit_fstat,
- .streaminfo_fn = fruit_streaminfo,
- .ntimes_fn = fruit_ntimes,
+ .fstreaminfo_fn = fruit_fstreaminfo,
+ .fntimes_fn = fruit_fntimes,
.ftruncate_fn = fruit_ftruncate,
.fallocate_fn = fruit_fallocate,
.create_file_fn = fruit_create_file,
- .readdir_attr_fn = fruit_readdir_attr,
+ .freaddir_attr_fn = fruit_freaddir_attr,
.offload_read_send_fn = fruit_offload_read_send,
.offload_read_recv_fn = fruit_offload_read_recv,
.offload_write_send_fn = fruit_offload_write_send,