summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2009-03-11 07:58:42 +1100
committerAndrew Bartlett <abartlet@samba.org>2009-03-11 07:58:42 +1100
commit3d0a727f575942b767e396b694f6529259528a17 (patch)
tree8ea6acdfe1b043abe06a0f3d78dcbc1b55d6f146 /source3
parentc218d3e1173355acf025471a10b4b6425b9c086b (diff)
parent3d280639c4652d6cd35577e333bcd46c2517754c (diff)
downloadsamba-3d0a727f575942b767e396b694f6529259528a17.tar.gz
samba-3d0a727f575942b767e396b694f6529259528a17.tar.bz2
samba-3d0a727f575942b767e396b694f6529259528a17.zip
Merge branch 'master' of ssh://git.samba.org/data/git/samba into wspp-schema
Diffstat (limited to 'source3')
-rw-r--r--source3/Makefile.in5
-rw-r--r--source3/client/client.c10
-rw-r--r--source3/configure.in3
-rw-r--r--source3/include/proto.h9
-rw-r--r--source3/lib/messages.c18
-rw-r--r--source3/libsmb/clireadwrite.c224
-rw-r--r--source3/modules/vfs_preopen.c456
-rw-r--r--source3/torture/torture.c8
8 files changed, 622 insertions, 111 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 6aabcf0c8d..76fd91a31e 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -667,6 +667,7 @@ VFS_READAHEAD_OBJ = modules/vfs_readahead.o
VFS_TSMSM_OBJ = modules/vfs_tsmsm.o
VFS_FILEID_OBJ = modules/vfs_fileid.o
VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o
+VFS_PREOPEN_OBJ = modules/vfs_preopen.o
VFS_SYNCOPS_OBJ = modules/vfs_syncops.o
VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o
VFS_ACL_TDB_OBJ = modules/vfs_acl_tdb.o
@@ -2567,6 +2568,10 @@ bin/aio_fork.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_FORK_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_AIO_FORK_OBJ)
+bin/preopen.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_PREOPEN_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_PREOPEN_OBJ)
+
bin/acl_xattr.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_ACL_XATTR_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_ACL_XATTR_OBJ)
diff --git a/source3/client/client.c b/source3/client/client.c
index aaa9e35d96..67a2458a94 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -220,7 +220,9 @@ struct push_state {
SMB_OFF_T nread;
};
-static size_t push_source(uint8_t *buf, size_t n, void *priv)
+static size_t push_source(uint8_t *inbuf, size_t n,
+ const uint8_t **outbuf,
+ void *priv)
{
struct push_state *state = (struct push_state *)priv;
int result;
@@ -229,7 +231,7 @@ static size_t push_source(uint8_t *buf, size_t n, void *priv)
return 0;
}
- result = readfile(buf, n, state->f);
+ result = readfile(inbuf, n, state->f);
state->nread += result;
return result;
}
@@ -1681,8 +1683,8 @@ static int do_put(const char *rname, const char *lname, bool reput)
state.f = f;
state.nread = 0;
- status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
- &state);
+ status = cli_push(targetcli, fnum, 0, 0, io_bufsize,
+ false, push_source, &state);
if (!NT_STATUS_IS_OK(status)) {
d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
}
diff --git a/source3/configure.in b/source3/configure.in
index e48ff34554..2af1545d58 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -417,7 +417,7 @@ dnl These have to be built static:
default_static_modules="pdb_smbpasswd pdb_tdbsam pdb_wbc_sam rpc_lsarpc rpc_samr rpc_winreg rpc_initshutdown rpc_dssetup rpc_wkssvc rpc_svcctl rpc_ntsvcs rpc_netlogon rpc_netdfs rpc_srvsvc rpc_spoolss2 rpc_eventlog auth_sam auth_unix auth_winbind auth_wbc auth_server auth_domain auth_builtin auth_netlogond vfs_default nss_info_template"
dnl These are preferably build shared, and static if dlopen() is not available
-default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb vfs_smb_traffic_analyzer"
+default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb vfs_smb_traffic_analyzer vfs_preopen"
if test "x$developer" = xyes; then
default_static_modules="$default_static_modules rpc_rpcecho"
@@ -6185,6 +6185,7 @@ SMB_MODULE(vfs_readahead, \$(VFS_READAHEAD_OBJ), "bin/readahead.$SHLIBEXT", VFS)
SMB_MODULE(vfs_tsmsm, \$(VFS_TSMSM_OBJ), "bin/tsmsm.$SHLIBEXT", VFS)
SMB_MODULE(vfs_fileid, \$(VFS_FILEID_OBJ), "bin/fileid.$SHLIBEXT", VFS)
SMB_MODULE(vfs_aio_fork, \$(VFS_AIO_FORK_OBJ), "bin/aio_fork.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_preopen, \$(VFS_PREOPEN_OBJ), "bin/preopen.$SHLIBEXT", VFS)
SMB_MODULE(vfs_syncops, \$(VFS_SYNCOPS_OBJ), "bin/syncops.$SHLIBEXT", VFS)
SMB_MODULE(vfs_zfsacl, \$(VFS_ZFSACL_OBJ), "bin/zfsacl.$SHLIBEXT", VFS)
SMB_MODULE(vfs_notify_fam, \$(VFS_NOTIFY_FAM_OBJ), "bin/notify_fam.$SHLIBEXT", VFS)
diff --git a/source3/include/proto.h b/source3/include/proto.h
index a1cafb6837..794a006a68 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -2790,13 +2790,18 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
struct cli_state *cli,
uint16_t fnum, uint16_t mode,
off_t start_offset, size_t window_size,
- size_t (*source)(uint8_t *buf, size_t n,
+ bool caller_buffers,
+ size_t (*source)(uint8_t *inbuf, size_t n,
+ const uint8_t **outbuf,
void *priv),
void *priv);
NTSTATUS cli_push_recv(struct async_req *req);
NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode,
off_t start_offset, size_t window_size,
- size_t (*source)(uint8_t *buf, size_t n, void *priv),
+ bool caller_buffers,
+ size_t (*source)(uint8_t *inbuf, size_t n,
+ const uint8_t **outbuf,
+ void *priv),
void *priv);
/* The following definitions come from libsmb/clisecdesc.c */
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index e4b20c7493..5e11dd4e25 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -286,7 +286,15 @@ NTSTATUS messaging_register(struct messaging_context *msg_ctx,
*/
for (cb = msg_ctx->callbacks; cb != NULL; cb = cb->next) {
- if (cb->msg_type == msg_type) {
+ /* we allow a second registration of the same message
+ type if it has a different private pointer. This is
+ needed in, for example, the internal notify code,
+ which creates a new notify context for each tree
+ connect, and expects to receive messages to each of
+ them. */
+ if (cb->msg_type == msg_type && private_data == cb->private_data) {
+ DEBUG(5,("Overriding messaging pointer for type %u - private_data=%p\n",
+ (unsigned)msg_type, private_data));
cb->fn = fn;
cb->private_data = private_data;
return NT_STATUS_OK;
@@ -317,6 +325,8 @@ void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type,
next = cb->next;
if ((cb->msg_type == msg_type)
&& (cb->private_data == private_data)) {
+ DEBUG(5,("Deregistering messaging pointer for type %u - private_data=%p\n",
+ (unsigned)msg_type, private_data));
DLIST_REMOVE(ctx->callbacks, cb);
TALLOC_FREE(cb);
}
@@ -362,7 +372,11 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx,
if (cb->msg_type == rec->msg_type) {
cb->fn(msg_ctx, cb->private_data, rec->msg_type,
rec->src, &rec->buf);
- return;
+ /* we continue looking for matching messages
+ after finding one. This matters for
+ subsystems like the internal notify code
+ which register more than one handler for
+ the same message type */
}
}
return;
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
index 9d17ff86a5..7e7cf0d682 100644
--- a/source3/libsmb/clireadwrite.c
+++ b/source3/libsmb/clireadwrite.c
@@ -915,181 +915,204 @@ static NTSTATUS cli_writeall_recv(struct async_req *req)
return async_req_simple_recv_ntstatus(req);
}
-struct cli_push_state {
- struct async_req *req;
+struct cli_push_write_state {
+ struct async_req *req;/* This is the main request! Not the subreq */
+ uint32_t idx;
+ off_t ofs;
+ uint8_t *buf;
+ size_t size;
+};
+struct cli_push_state {
struct event_context *ev;
struct cli_state *cli;
uint16_t fnum;
uint16_t mode;
off_t start_offset;
size_t window_size;
+ bool caller_buffers;
- size_t (*source)(uint8_t *buf, size_t n, void *priv);
+ size_t (*source)(uint8_t *inbuf, size_t n,
+ const uint8_t **outbuf,
+ void *priv);
void *priv;
- size_t chunk_size;
-
- size_t sent;
bool eof;
+ size_t chunk_size;
+ off_t next_offset;
+
/*
* Outstanding requests
*/
- int num_reqs;
- struct async_req **reqs;
-
- int pending;
-
- uint8_t *buf;
+ uint32_t pending;
+ uint32_t num_reqs;
+ struct cli_push_write_state **reqs;
};
static void cli_push_written(struct async_req *req);
+static bool cli_push_write_setup(struct async_req *req,
+ struct cli_push_state *state,
+ uint32_t idx)
+{
+ struct cli_push_write_state *substate;
+ struct async_req *subreq;
+
+ substate = talloc(state->reqs, struct cli_push_write_state);
+ if (!substate) {
+ return false;
+ }
+ substate->req = req;
+ substate->idx = idx;
+ substate->ofs = state->next_offset;
+ if (state->caller_buffers) {
+ substate->buf = NULL;
+ } else {
+ substate->buf = talloc_array(substate, uint8_t,
+ state->chunk_size);
+ if (!substate->buf) {
+ talloc_free(substate);
+ return false;
+ }
+ }
+
+ /* source function can overwrite substate->buf... */
+ substate->size = state->source(substate->buf,
+ state->chunk_size,
+ (const uint8_t **)&substate->buf,
+ state->priv);
+ if (substate->size == 0) {
+ state->eof = true;
+ /* nothing to send */
+ talloc_free(substate);
+ return true;
+ }
+
+ subreq = cli_writeall_send(substate,
+ state->ev, state->cli,
+ state->fnum, state->mode,
+ substate->buf,
+ substate->ofs,
+ substate->size);
+ if (!subreq) {
+ talloc_free(substate);
+ return false;
+ }
+ subreq->async.fn = cli_push_written;
+ subreq->async.priv = substate;
+
+ state->reqs[idx] = substate;
+ state->pending += 1;
+ state->next_offset += substate->size;
+
+ return true;
+}
+
struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
struct cli_state *cli,
uint16_t fnum, uint16_t mode,
off_t start_offset, size_t window_size,
- size_t (*source)(uint8_t *buf, size_t n,
+ bool caller_buffers,
+ size_t (*source)(uint8_t *inbuf, size_t n,
+ const uint8_t **outbuf,
void *priv),
void *priv)
{
- struct async_req *result;
+ struct async_req *req;
struct cli_push_state *state;
- int i;
+ uint32_t i;
- if (!async_req_setup(mem_ctx, &result, &state,
+ if (!async_req_setup(mem_ctx, &req, &state,
struct cli_push_state)) {
return NULL;
}
- state->req = result;
-
state->cli = cli;
state->ev = ev;
state->fnum = fnum;
state->start_offset = start_offset;
state->mode = mode;
+ state->caller_buffers = caller_buffers;
state->source = source;
state->priv = priv;
state->eof = false;
- state->sent = 0;
state->pending = 0;
+ state->next_offset = start_offset;
state->chunk_size = cli_write_max_bufsize(cli, mode);
- state->num_reqs = MAX(window_size/state->chunk_size, 1);
+ if (window_size == 0) {
+ window_size = cli->max_mux * state->chunk_size;
+ }
+ state->num_reqs = window_size/state->chunk_size;
+ if ((window_size % state->chunk_size) > 0) {
+ state->num_reqs += 1;
+ }
state->num_reqs = MIN(state->num_reqs, cli->max_mux);
+ state->num_reqs = MAX(state->num_reqs, 1);
- state->reqs = TALLOC_ZERO_ARRAY(state, struct async_req *,
+ state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_push_write_state *,
state->num_reqs);
if (state->reqs == NULL) {
goto failed;
}
- state->buf = TALLOC_ARRAY(
- state, uint8_t, state->chunk_size * state->num_reqs);
- if (state->buf == NULL) {
- goto failed;
- }
-
for (i=0; i<state->num_reqs; i++) {
- size_t to_write;
- uint8_t *buf = state->buf + i*state->chunk_size;
-
- to_write = state->source(buf, state->chunk_size, state->priv);
- if (to_write == 0) {
- state->eof = true;
- break;
- }
-
- state->reqs[i] = cli_writeall_send(
- state->reqs, state->ev, state->cli, state->fnum,
- state->mode, buf, state->start_offset + state->sent,
- to_write);
- if (state->reqs[i] == NULL) {
+ if (!cli_push_write_setup(req, state, i)) {
goto failed;
}
- state->reqs[i]->async.fn = cli_push_written;
- state->reqs[i]->async.priv = state;
-
- state->sent += to_write;
- state->pending += 1;
+ if (state->eof) {
+ break;
+ }
}
- if (i == 0) {
- if (!async_post_ntstatus(result, ev, NT_STATUS_OK)) {
+ if (state->pending == 0) {
+ if (!async_post_ntstatus(req, ev, NT_STATUS_OK)) {
goto failed;
}
- return result;
+ return req;
}
- return result;
+ return req;
failed:
- TALLOC_FREE(result);
+ TALLOC_FREE(req);
return NULL;
}
-static void cli_push_written(struct async_req *req)
+static void cli_push_written(struct async_req *subreq)
{
+ struct cli_push_write_state *substate = talloc_get_type_abort(
+ subreq->async.priv, struct cli_push_write_state);
+ struct async_req *req = substate->req;
struct cli_push_state *state = talloc_get_type_abort(
- req->async.priv, struct cli_push_state);
+ req->private_data, struct cli_push_state);
NTSTATUS status;
- int i;
- uint8_t *buf;
- size_t to_write;
-
- for (i=0; i<state->num_reqs; i++) {
- if (state->reqs[i] == req) {
- break;
- }
- }
-
- if (i == state->num_reqs) {
- async_req_nterror(state->req, NT_STATUS_INTERNAL_ERROR);
- return;
- }
-
- status = cli_writeall_recv(req);
- TALLOC_FREE(state->reqs[i]);
- req = NULL;
- if (!NT_STATUS_IS_OK(status)) {
- async_req_nterror(state->req, status);
- return;
- }
+ uint32_t idx = substate->idx;
+ state->reqs[idx] = NULL;
state->pending -= 1;
- if (state->pending == 0) {
- async_req_done(state->req);
- return;
- }
- if (state->eof) {
+ status = cli_writeall_recv(subreq);
+ TALLOC_FREE(subreq);
+ TALLOC_FREE(substate);
+ if (!NT_STATUS_IS_OK(status)) {
+ async_req_nterror(req, status);
return;
}
- buf = state->buf + i * state->chunk_size;
-
- to_write = state->source(buf, state->chunk_size, state->priv);
- if (to_write == 0) {
- state->eof = true;
- return;
+ if (!state->eof) {
+ if (!cli_push_write_setup(req, state, idx)) {
+ async_req_nomem(NULL, req);
+ return;
+ }
}
- state->reqs[i] = cli_writeall_send(
- state->reqs, state->ev, state->cli, state->fnum,
- state->mode, buf, state->start_offset + state->sent, to_write);
- if (state->reqs[i] == NULL) {
- async_req_nterror(state->req, NT_STATUS_NO_MEMORY);
+ if (state->pending == 0) {
+ async_req_done(req);
return;
}
-
- state->reqs[i]->async.fn = cli_push_written;
- state->reqs[i]->async.priv = state;
-
- state->sent += to_write;
- state->pending += 1;
}
NTSTATUS cli_push_recv(struct async_req *req)
@@ -1099,7 +1122,10 @@ NTSTATUS cli_push_recv(struct async_req *req)
NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode,
off_t start_offset, size_t window_size,
- size_t (*source)(uint8_t *buf, size_t n, void *priv),
+ bool caller_buffers,
+ size_t (*source)(uint8_t *inbuf, size_t n,
+ const uint8_t **outbuf,
+ void *priv),
void *priv)
{
TALLOC_CTX *frame = talloc_stackframe();
@@ -1120,7 +1146,7 @@ NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode,
}
req = cli_push_send(frame, ev, cli, fnum, mode, start_offset,
- window_size, source, priv);
+ window_size, caller_buffers, source, priv);
if (req == NULL) {
goto nomem;
}
diff --git a/source3/modules/vfs_preopen.c b/source3/modules/vfs_preopen.c
new file mode 100644
index 0000000000..25b9e7f3e4
--- /dev/null
+++ b/source3/modules/vfs_preopen.c
@@ -0,0 +1,456 @@
+/*
+ * Force a readahead of files by opening them and reading the first bytes
+ *
+ * Copyright (C) Volker Lendecke 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+struct preopen_state;
+
+struct preopen_helper {
+ struct preopen_state *state;
+ struct fd_event *fde;
+ pid_t pid;
+ int fd;
+ bool busy;
+};
+
+struct preopen_state {
+ int num_helpers;
+ struct preopen_helper *helpers;
+
+ size_t to_read; /* How many bytes to read in children? */
+ int queue_max;
+
+ char *template_fname; /* Filename to be sent to children */
+ size_t number_start; /* start offset into "template_fname" */
+ int num_digits; /* How many digits is the number long? */
+
+ int fnum_sent; /* last fname sent to children */
+
+ int fnum_queue_end; /* last fname to be sent, based on
+ * last open call + preopen:queuelen
+ */
+
+ name_compare_entry *preopen_names;
+};
+
+static void preopen_helper_destroy(struct preopen_helper *c)
+{
+ int status;
+ close(c->fd);
+ c->fd = -1;
+ kill(c->pid, SIGKILL);
+ waitpid(c->pid, &status, 0);
+ c->busy = true;
+}
+
+static void preopen_queue_run(struct preopen_state *state)
+{
+ char *pdelimiter;
+ char delimiter;
+
+ pdelimiter = state->template_fname + state->number_start
+ + state->num_digits;
+ delimiter = *pdelimiter;
+
+ while (state->fnum_sent < state->fnum_queue_end) {
+
+ ssize_t written;
+ size_t to_write;
+ int helper;
+
+ for (helper=0; helper<state->num_helpers; helper++) {
+ if (state->helpers[helper].busy) {
+ continue;
+ }
+ break;
+ }
+ if (helper == state->num_helpers) {
+ /* everyone is busy */
+ return;
+ }
+
+ snprintf(state->template_fname + state->number_start,
+ state->num_digits + 1,
+ "%.*lu", state->num_digits,
+ (long unsigned int)(state->fnum_sent + 1));
+ *pdelimiter = delimiter;
+
+ to_write = talloc_get_size(state->template_fname);
+ written = write_data(state->helpers[helper].fd,
+ state->template_fname, to_write);
+ state->helpers[helper].busy = true;
+
+ if (written != to_write) {
+ preopen_helper_destroy(&state->helpers[helper]);
+ }
+ state->fnum_sent += 1;
+ }
+}
+
+static void preopen_helper_readable(struct event_context *ev,
+ struct fd_event *fde, uint16_t flags,
+ void *priv)
+{
+ struct preopen_helper *helper = (struct preopen_helper *)priv;
+ struct preopen_state *state = helper->state;
+ ssize_t nread;
+ char c;
+
+ if ((flags & EVENT_FD_READ) == 0) {
+ return;
+ }
+
+ nread = read(helper->fd, &c, 1);
+ if (nread <= 0) {
+ preopen_helper_destroy(helper);
+ return;
+ }
+
+ helper->busy = false;
+
+ preopen_queue_run(state);
+}
+
+static int preopen_helpers_destructor(struct preopen_state *c)
+{
+ int i;
+
+ for (i=0; i<c->num_helpers; i++) {
+ if (c->helpers[i].fd == -1) {
+ continue;
+ }
+ preopen_helper_destroy(&c->helpers[i]);
+ }
+
+ return 0;
+}
+
+static bool preopen_helper_open_one(int sock_fd, char **pnamebuf,
+ size_t to_read, void *filebuf)
+{
+ char *namebuf = *pnamebuf;
+ ssize_t nwritten, nread;
+ char c = 0;
+ int fd;
+
+ nread = 0;
+
+ while ((nread == 0) || (namebuf[nread-1] != '\0')) {
+ ssize_t thistime;
+
+ thistime = read(sock_fd, namebuf + nread,
+ talloc_get_size(namebuf) - nread);
+ if (thistime <= 0) {
+ return false;
+ }
+
+ nread += thistime;
+
+ if (nread == talloc_get_size(namebuf)) {
+ namebuf = TALLOC_REALLOC_ARRAY(
+ NULL, namebuf, char,
+ talloc_get_size(namebuf) * 2);
+ if (namebuf == NULL) {
+ return false;
+ }
+ *pnamebuf = namebuf;
+ }
+ }
+
+ fd = open(namebuf, O_RDONLY);
+ if (fd == -1) {
+ goto done;
+ }
+ nread = read(fd, filebuf, to_read);
+ close(fd);
+
+ done:
+ nwritten = write(sock_fd, &c, 1);
+ return true;
+}
+
+static bool preopen_helper(int fd, size_t to_read)
+{
+ char *namebuf;
+ void *readbuf;
+
+ namebuf = TALLOC_ARRAY(NULL, char, 1024);
+ if (namebuf == NULL) {
+ return false;
+ }
+
+ readbuf = talloc_size(NULL, to_read);
+ if (readbuf == NULL) {
+ TALLOC_FREE(namebuf);
+ return false;
+ }
+
+ while (preopen_helper_open_one(fd, &namebuf, to_read, readbuf)) {
+ ;
+ }
+
+ TALLOC_FREE(readbuf);
+ TALLOC_FREE(namebuf);
+ return false;
+}
+
+static NTSTATUS preopen_init_helper(struct preopen_helper *h)
+{
+ int fdpair[2];
+ NTSTATUS status;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(10, ("socketpair() failed: %s\n", strerror(errno)));
+ return status;
+ }
+
+ h->pid = sys_fork();
+
+ if (h->pid == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (h->pid == 0) {
+ close(fdpair[0]);
+ preopen_helper(fdpair[1], h->state->to_read);
+ exit(0);
+ }
+ close(fdpair[1]);
+ h->fd = fdpair[0];
+ h->fde = event_add_fd(smbd_event_context(), h->state, h->fd,
+ EVENT_FD_READ, preopen_helper_readable, h);
+ if (h->fde == NULL) {
+ close(h->fd);
+ h->fd = -1;
+ return NT_STATUS_NO_MEMORY;
+ }
+ h->busy = false;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS preopen_init_helpers(TALLOC_CTX *mem_ctx, size_t to_read,
+ int num_helpers, int queue_max,
+ struct preopen_state **presult)
+{
+ struct preopen_state *result;
+ int i;
+
+ result = talloc(mem_ctx, struct preopen_state);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->num_helpers = num_helpers;
+ result->helpers = TALLOC_ARRAY(result, struct preopen_helper,
+ num_helpers);
+ if (result->helpers == NULL) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result->to_read = to_read;
+ result->queue_max = queue_max;
+ result->template_fname = NULL;
+ result->fnum_sent = 0;
+
+ for (i=0; i<num_helpers; i++) {
+ result->helpers[i].state = result;
+ result->helpers[i].fd = -1;
+ }
+
+ talloc_set_destructor(result, preopen_helpers_destructor);
+
+ for (i=0; i<num_helpers; i++) {
+ preopen_init_helper(&result->helpers[i]);
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+static void preopen_free_helpers(void **ptr)
+{
+ TALLOC_FREE(*ptr);
+}
+
+static struct preopen_state *preopen_state_get(vfs_handle_struct *handle)
+{
+ struct preopen_state *state;
+ NTSTATUS status;
+ const char *namelist;
+
+ if (SMB_VFS_HANDLE_TEST_DATA(handle)) {
+ SMB_VFS_HANDLE_GET_DATA(handle, state, struct preopen_state,
+ return NULL);
+ return state;
+ }
+
+ namelist = lp_parm_const_string(SNUM(handle->conn), "preopen", "names",
+ NULL);
+
+ if (namelist == NULL) {
+ return NULL;
+ }
+
+ status = preopen_init_helpers(
+ NULL,
+ lp_parm_int(SNUM(handle->conn), "preopen", "num_bytes", 1),
+ lp_parm_int(SNUM(handle->conn), "preopen", "helpers", 1),
+ lp_parm_int(SNUM(handle->conn), "preopen", "queuelen", 10),
+ &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ set_namearray(&state->preopen_names, (char *)namelist);
+
+ if (state->preopen_names == NULL) {
+ TALLOC_FREE(state);
+ return NULL;
+ }
+
+ if (!SMB_VFS_HANDLE_TEST_DATA(handle)) {
+ SMB_VFS_HANDLE_SET_DATA(handle, state, preopen_free_helpers,
+ struct preopen_state, return NULL);
+ }
+
+ return state;
+}
+
+static bool preopen_parse_fname(const char *fname, unsigned long *pnum,
+ size_t *pstart_idx, int *pnum_digits)
+{
+ const char *p, *q;
+ unsigned long num;
+
+ p = strrchr_m(fname, '/');
+ if (p == NULL) {
+ p = fname;
+ }
+
+ p += 1;
+ while (p[0] != '\0') {
+ if (isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2])) {
+ break;
+ }
+ p += 1;
+ }
+ if (*p == '\0') {
+ /* no digits around */
+ return false;
+ }
+
+ num = strtoul(p, (char **)&q, 10);
+
+ if (num+1 < num) {
+ /* overflow */
+ return false;
+ }
+
+ *pnum = num;
+ *pstart_idx = (p - fname);
+ *pnum_digits = (q - p);
+ return true;
+}
+
+static int preopen_open(vfs_handle_struct *handle, const char *fname,
+ files_struct *fsp, int flags, mode_t mode)
+{
+ struct preopen_state *state;
+ int res;
+ unsigned long num;
+
+ DEBUG(10, ("preopen_open called on %s\n", fname));
+
+ state = preopen_state_get(handle);
+ if (state == NULL) {
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ }
+
+ res = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ if (res == -1) {
+ return -1;
+ }
+
+ if (flags != O_RDONLY) {
+ return res;
+ }
+
+ if (!is_in_path(fname, state->preopen_names, true)) {
+ DEBUG(10, ("%s does not match the preopen:names list\n",
+ fname));
+ return res;
+ }
+
+ TALLOC_FREE(state->template_fname);
+ state->template_fname = talloc_asprintf(
+ state, "%s/%s", fsp->conn->connectpath, fname);
+
+ if (state->template_fname == NULL) {
+ return res;
+ }
+
+ if (!preopen_parse_fname(state->template_fname, &num,
+ &state->number_start, &state->num_digits)) {
+ TALLOC_FREE(state->template_fname);
+ return res;
+ }
+
+ if (num > state->fnum_sent) {
+ /*
+ * Helpers were too slow, there's no point in reading
+ * files in helpers that we already read in the
+ * parent.
+ */
+ state->fnum_sent = num;
+ }
+
+ if ((state->fnum_queue_end != 0) /* Something was started earlier */
+ && (num < (state->fnum_queue_end - state->queue_max))) {
+ /*
+ * "num" is before the queue we announced. This means
+ * a new run is started.
+ */
+ state->fnum_sent = num;
+ }
+
+ state->fnum_queue_end = num + state->queue_max;
+
+ preopen_queue_run(state);
+
+ return res;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple preopen_ops[] = {
+ {SMB_VFS_OP(preopen_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_preopen_init(void);
+NTSTATUS vfs_preopen_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ "preopen", preopen_ops);
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index db89b05603..a563557d5f 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -5004,7 +5004,9 @@ static bool run_chain1(int dummy)
return True;
}
-static size_t null_source(uint8_t *buf, size_t n, void *priv)
+static size_t null_source(uint8_t *inbuf, size_t n,
+ const uint8_t *outbuf,
+ void *priv)
{
size_t *to_pull = (size_t *)priv;
size_t thistime = *to_pull;
@@ -5014,7 +5016,7 @@ static size_t null_source(uint8_t *buf, size_t n, void *priv)
return 0;
}
- memset(buf, 0, thistime);
+ memset(inbuf, 0, thistime);
*to_pull -= thistime;
return thistime;
}
@@ -5057,7 +5059,7 @@ static bool run_windows_write(int dummy)
}
status = cli_push(cli1, fnum, 0, i * torture_blocksize, torture_blocksize,
- null_source, &to_pull);
+ false, null_source, &to_pull);
if (!NT_STATUS_IS_OK(status)) {
printf("cli_push returned: %s\n", nt_errstr(status));
goto fail;