summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/include/smb.h1
-rw-r--r--source4/include/smb_interfaces.h138
-rw-r--r--source4/libcli/raw/rawfile.c6
-rw-r--r--source4/libcli/raw/rawreadwrite.c12
-rw-r--r--source4/ntvfs/cifs/vfs_cifs.c36
-rw-r--r--source4/ntvfs/ipc/vfs_ipc.c171
-rw-r--r--source4/ntvfs/nbench/vfs_nbench.c4
-rw-r--r--source4/ntvfs/ntvfs_generic.c483
-rw-r--r--source4/ntvfs/posix/pvfs_lock.c43
-rw-r--r--source4/ntvfs/posix/pvfs_open.c201
-rw-r--r--source4/ntvfs/posix/pvfs_read.c7
-rw-r--r--source4/ntvfs/posix/pvfs_write.c84
-rw-r--r--source4/smb_server/reply.c41
-rw-r--r--source4/smb_server/search.c1
-rw-r--r--source4/smb_server/smb_server.h4
15 files changed, 741 insertions, 491 deletions
diff --git a/source4/include/smb.h b/source4/include/smb.h
index a616f94ea1..fe277ebb99 100644
--- a/source4/include/smb.h
+++ b/source4/include/smb.h
@@ -609,6 +609,7 @@ typedef struct nt_user_token {
/* a set of flags to control handling of request structures */
#define REQ_CONTROL_LARGE (1<<1) /* allow replies larger than max_xmit */
#define REQ_CONTROL_ASYNC (1<<2) /* the backend will answer this one later */
+#define REQ_CONTROL_MAY_ASYNC (1<<3) /* the backend is allowed to answer async */
/* passed to br lock code */
enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_READ_LOCK, PENDING_WRITE_LOCK};
diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h
index e9f51ba4d1..7a369a04cb 100644
--- a/source4/include/smb_interfaces.h
+++ b/source4/include/smb_interfaces.h
@@ -1245,7 +1245,9 @@ union smb_open {
-enum smb_read_level {RAW_READ_GENERIC, RAW_READ_READBRAW, RAW_READ_LOCKREAD, RAW_READ_READ, RAW_READ_READX};
+enum smb_read_level {RAW_READ_READBRAW, RAW_READ_LOCKREAD, RAW_READ_READ, RAW_READ_READX};
+
+#define RAW_READ_GENERIC RAW_READ_READX
/* union for read() backend call
@@ -1253,21 +1255,24 @@ enum smb_read_level {RAW_READ_GENERIC, RAW_READ_READBRAW, RAW_READ_LOCKREAD, RAW
called. It will be big enough to hold the maximum size asked for
*/
union smb_read {
- /* generic interface */
+ /* SMBreadX (and generic) interface */
struct {
enum smb_read_level level;
struct {
uint16_t fnum;
uint64_t offset;
- uint32_t size;
+ uint16_t mincnt;
+ uint16_t maxcnt;
+ uint16_t remaining;
} in;
struct {
char *data;
- uint32_t nread;
+ uint16_t remaining;
+ uint16_t compaction_mode;
+ uint16_t nread;
} out;
- } generic;
-
+ } readx, generic;
/* SMBreadbraw interface */
struct {
@@ -1318,50 +1323,34 @@ union smb_read {
uint16_t nread;
} out;
} read;
-
- /* SMBreadX interface */
- struct {
- enum smb_read_level level;
-
- struct {
- uint16_t fnum;
- uint64_t offset;
- uint16_t mincnt;
- uint16_t maxcnt;
- uint16_t remaining;
- } in;
- struct {
- char *data;
- uint16_t remaining;
- uint16_t compaction_mode;
- uint16_t nread;
- } out;
- } readx;
};
-enum smb_write_level {
- RAW_WRITE_GENERIC, RAW_WRITE_WRITEUNLOCK, RAW_WRITE_WRITE,
- RAW_WRITE_WRITEX, RAW_WRITE_WRITECLOSE, RAW_WRITE_SPLWRITE};
+enum smb_write_level {RAW_WRITE_WRITEUNLOCK, RAW_WRITE_WRITE,
+ RAW_WRITE_WRITEX, RAW_WRITE_WRITECLOSE, RAW_WRITE_SPLWRITE};
+
+#define RAW_WRITE_GENERIC RAW_WRITE_WRITEX
/* union for write() backend call
*/
union smb_write {
- /* generic interface */
+ /* SMBwriteX interface */
struct {
enum smb_write_level level;
struct {
uint16_t fnum;
uint64_t offset;
- uint32_t count;
+ uint16_t wmode;
+ uint16_t remaining;
+ uint32_t count;
const char *data;
} in;
struct {
uint32_t nwritten;
+ uint16_t remaining;
} out;
- } generic;
-
+ } writex, generic;
/* SMBwriteunlock interface */
struct {
@@ -1395,24 +1384,6 @@ union smb_write {
} out;
} write;
- /* SMBwriteX interface */
- struct {
- enum smb_write_level level;
-
- struct {
- uint16_t fnum;
- uint64_t offset;
- uint16_t wmode;
- uint16_t remaining;
- uint32_t count;
- const char *data;
- } in;
- struct {
- uint32_t nwritten;
- uint16_t remaining;
- } out;
- } writex;
-
/* SMBwriteclose interface */
struct {
enum smb_write_level level;
@@ -1442,42 +1413,15 @@ union smb_write {
};
-enum smb_lock_level {RAW_LOCK_GENERIC, RAW_LOCK_LOCK, RAW_LOCK_UNLOCK, RAW_LOCK_LOCKX};
+enum smb_lock_level {RAW_LOCK_LOCK, RAW_LOCK_UNLOCK, RAW_LOCK_LOCKX};
+
+/* the generic interface is defined to be equal to the lockingX interface */
+#define RAW_LOCK_GENERIC RAW_LOCK_LOCKX
/* union for lock() backend call
*/
union smb_lock {
- /* generic interface */
- struct {
- enum smb_lock_level level;
- struct {
- uint16_t fnum;
- } in;
- } generic;
-
- /* SMBlock interface */
- struct {
- enum smb_lock_level level;
-
- struct {
- uint16_t fnum;
- uint32_t count;
- uint32_t offset;
- } in;
- } lock;
-
- /* SMBunlock interface */
- struct {
- enum smb_lock_level level;
-
- struct {
- uint16_t fnum;
- uint32_t count;
- uint32_t offset;
- } in;
- } unlock;
-
- /* SMBlockingX interface */
+ /* SMBlockingX (and generic) interface */
struct {
enum smb_lock_level level;
@@ -1493,26 +1437,30 @@ union smb_lock {
uint64_t count;
} *locks; /* unlocks are first in the arrray */
} in;
- } lockx;
+ } lockx, generic;
+
+ /* SMBlock and SMBunlock interface */
+ struct {
+ enum smb_lock_level level;
+
+ struct {
+ uint16_t fnum;
+ uint32_t count;
+ uint32_t offset;
+ } in;
+ } lock, unlock;
};
-enum smb_close_level {RAW_CLOSE_GENERIC, RAW_CLOSE_CLOSE, RAW_CLOSE_SPLCLOSE};
+enum smb_close_level {RAW_CLOSE_CLOSE, RAW_CLOSE_SPLCLOSE};
+
+#define RAW_CLOSE_GENERIC RAW_CLOSE_CLOSE
/*
union for close() backend call
*/
union smb_close {
- /* generic interface */
- struct {
- enum smb_close_level level;
-
- struct {
- uint16_t fnum;
- } in;
- } generic;
-
- /* SMBclose interface */
+ /* SMBclose (and generic) interface */
struct {
enum smb_close_level level;
@@ -1520,7 +1468,7 @@ union smb_close {
uint16_t fnum;
time_t write_time;
} in;
- } close;
+ } close, generic;
/* SMBsplclose interface - empty! */
struct {
diff --git a/source4/libcli/raw/rawfile.c b/source4/libcli/raw/rawfile.c
index 1b858d489a..3eb2ab49b2 100644
--- a/source4/libcli/raw/rawfile.c
+++ b/source4/libcli/raw/rawfile.c
@@ -493,9 +493,6 @@ struct smbcli_request *smb_raw_close_send(struct smbcli_tree *tree, union smb_cl
struct smbcli_request *req = NULL;
switch (parms->generic.level) {
- case RAW_CLOSE_GENERIC:
- return NULL;
-
case RAW_CLOSE_CLOSE:
SETUP_REQUEST(SMBclose, 3, 0);
SSVAL(req->out.vwv, VWV(0), parms->close.in.fnum);
@@ -539,9 +536,6 @@ struct smbcli_request *smb_raw_lock_send(struct smbcli_tree *tree, union smb_loc
struct smbcli_request *req = NULL;
switch (parms->generic.level) {
- case RAW_LOCK_GENERIC:
- return NULL;
-
case RAW_LOCK_LOCK:
SETUP_REQUEST(SMBlock, 5, 0);
SSVAL(req->out.vwv, VWV(0), parms->lock.in.fnum);
diff --git a/source4/libcli/raw/rawreadwrite.c b/source4/libcli/raw/rawreadwrite.c
index dbca6fb7a5..e145ff9c10 100644
--- a/source4/libcli/raw/rawreadwrite.c
+++ b/source4/libcli/raw/rawreadwrite.c
@@ -36,9 +36,6 @@ struct smbcli_request *smb_raw_read_send(struct smbcli_tree *tree, union smb_rea
struct smbcli_request *req = NULL;
switch (parms->generic.level) {
- case RAW_READ_GENERIC:
- return NULL;
-
case RAW_READ_READBRAW:
if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) {
bigoffset = True;
@@ -115,10 +112,6 @@ NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms)
}
switch (parms->generic.level) {
- case RAW_READ_GENERIC:
- /* handled in _send() */
- break;
-
case RAW_READ_READBRAW:
parms->readbraw.out.nread = req->in.size - NBT_HDR_SIZE;
if (parms->readbraw.out.nread >
@@ -188,9 +181,6 @@ struct smbcli_request *smb_raw_write_send(struct smbcli_tree *tree, union smb_wr
struct smbcli_request *req = NULL;
switch (parms->generic.level) {
- case RAW_WRITE_GENERIC:
- return NULL;
-
case RAW_WRITE_WRITEUNLOCK:
SETUP_REQUEST(SMBwriteunlock, 5, 3 + parms->writeunlock.in.count);
SSVAL(req->out.vwv, VWV(0), parms->writeunlock.in.fnum);
@@ -284,8 +274,6 @@ NTSTATUS smb_raw_write_recv(struct smbcli_request *req, union smb_write *parms)
}
switch (parms->generic.level) {
- case RAW_WRITE_GENERIC:
- break;
case RAW_WRITE_WRITEUNLOCK:
SMBCLI_CHECK_WCT(req, 1);
parms->writeunlock.out.nwritten = SVAL(req->in.vwv, VWV(0));
diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c
index 5b10e72411..feacc063b4 100644
--- a/source4/ntvfs/cifs/vfs_cifs.c
+++ b/source4/ntvfs/cifs/vfs_cifs.c
@@ -214,7 +214,7 @@ static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
/* see if the front end will allow us to perform this
function asynchronously. */
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_unlink(private->tree, unl);
}
@@ -245,7 +245,7 @@ static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
/* see if the front end will allow us to perform this
function asynchronously. */
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_ioctl(private->tree, req, io);
}
@@ -263,7 +263,7 @@ static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_chkpath(private->tree, cp);
}
@@ -292,7 +292,7 @@ static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_pathinfo(private->tree, req, info);
}
@@ -321,7 +321,7 @@ static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_fileinfo(private->tree, req, info);
}
@@ -340,7 +340,7 @@ static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_setpathinfo(private->tree, st);
}
@@ -370,7 +370,7 @@ static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_open(private->tree, req, io);
}
@@ -388,7 +388,7 @@ static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_mkdir(private->tree, md);
}
@@ -406,7 +406,7 @@ static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_rmdir(private->tree, rd);
}
c_req = smb_raw_rmdir_send(private->tree, rd);
@@ -423,7 +423,7 @@ static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_rename(private->tree, ren);
}
@@ -461,7 +461,7 @@ static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_read(private->tree, rd);
}
@@ -490,7 +490,7 @@ static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_write(private->tree, wr);
}
@@ -526,7 +526,7 @@ static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_close(private->tree, io);
}
@@ -544,7 +544,7 @@ static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_exit(private->tree->session);
}
@@ -582,7 +582,7 @@ static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_lock(private->tree, lck);
}
@@ -600,7 +600,7 @@ static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_setfileinfo(private->tree, info);
}
c_req = smb_raw_setfileinfo_send(private->tree, info);
@@ -629,7 +629,7 @@ static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_fsinfo(private->tree, req, fs);
}
@@ -698,7 +698,7 @@ static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs,
struct cvfs_private *private = ntvfs->private_data;
struct smbcli_request *c_req;
- if (!req->async.send_fn) {
+ if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
return smb_raw_trans2(private->tree, req, trans2);
}
diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c
index 760cf07100..f4eb007235 100644
--- a/source4/ntvfs/ipc/vfs_ipc.c
+++ b/source4/ntvfs/ipc/vfs_ipc.c
@@ -31,13 +31,12 @@
ipc$ connection. It needs to keep information about all open
pipes */
struct ipc_private {
-
- uint16_t next_fnum;
- uint16_t num_open;
+ void *idtree_fnum;
/* a list of open pipes */
struct pipe_state {
struct pipe_state *next, *prev;
+ struct ipc_private *private;
const char *pipe_name;
uint16_t fnum;
struct dcesrv_connection *dce_conn;
@@ -55,55 +54,11 @@ struct ipc_private {
/*
- find the next fnum available on this connection
-*/
-static uint16_t find_next_fnum(struct ipc_private *ipc)
-{
- struct pipe_state *p;
- uint32_t ret;
-
- if (ipc->num_open == 0xFFFF) {
- return 0;
- }
-
-again:
- ret = ipc->next_fnum++;
-
- for (p=ipc->pipe_list; p; p=p->next) {
- if (p->fnum == ret) {
- goto again;
- }
- }
-
- return ret;
-}
-
-
-/*
- shutdown a single pipe. Called on a close or disconnect
-*/
-static void pipe_shutdown(struct ipc_private *private, struct pipe_state *p)
-{
- talloc_free(p->dce_conn);
- DLIST_REMOVE(private->pipe_list, p);
- talloc_destroy(p);
-}
-
-
-/*
find a open pipe give a file descriptor
*/
static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum)
{
- struct pipe_state *p;
-
- for (p=private->pipe_list; p; p=p->next) {
- if (p->fnum == fnum) {
- return p;
- }
- }
-
- return NULL;
+ return idr_find(private->idtree_fnum, fnum);
}
@@ -127,8 +82,11 @@ static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
ntvfs->private_data = private;
private->pipe_list = NULL;
- private->next_fnum = 1;
- private->num_open = 0;
+
+ private->idtree_fnum = idr_init(private);
+ if (private->idtree_fnum == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
return NT_STATUS_OK;
}
@@ -143,7 +101,7 @@ static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs,
/* close any pipes that are open. Discard any unread data */
while (private->pipe_list) {
- pipe_shutdown(private, private->pipe_list);
+ talloc_free(private->pipe_list);
}
return NT_STATUS_OK;
@@ -196,6 +154,18 @@ static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
}
+/*
+ destroy a open pipe structure
+*/
+static int ipc_fd_destructor(void *ptr)
+{
+ struct pipe_state *p = ptr;
+ idr_remove(p->private->idtree_fnum, p->fnum);
+ DLIST_REMOVE(p->private->pipe_list, p);
+ talloc_free(p->dce_conn);
+ return 0;
+}
+
/*
open a file backend - used for MSRPC pipes
@@ -209,8 +179,9 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
struct dcesrv_ep_description ep_description;
struct auth_session_info *session_info = NULL;
struct ipc_private *private = ntvfs->private_data;
+ int fnum;
- p = talloc_p(private, struct pipe_state);
+ p = talloc_p(req, struct pipe_state);
if (!p) {
return NT_STATUS_NO_MEMORY;
}
@@ -219,16 +190,15 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
if (!p->pipe_name) {
- talloc_free(p);
return NT_STATUS_NO_MEMORY;
}
- p->fnum = find_next_fnum(private);
- if (p->fnum == 0) {
- talloc_free(p);
+ fnum = idr_get_new(private->idtree_fnum, p, UINT16_MAX);
+ if (fnum == -1) {
return NT_STATUS_TOO_MANY_OPENED_FILES;
}
+ p->fnum = fnum;
p->ipc_state = 0x5ff;
/*
@@ -241,8 +211,6 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
will need to do that once the credentials infrastructure is
finalised for Samba4
*/
-
- printf("FINDING: %s\n", p->pipe_name);
ep_description.type = ENDPOINT_SMB;
ep_description.info.smb_pipe = p->pipe_name;
@@ -250,7 +218,6 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
if (req->session) {
/* The session info is refcount-increased in the
dcesrv_endpoint_search_connect() function */
-
session_info = req->session->session_info;
}
@@ -259,19 +226,22 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
session_info,
&p->dce_conn);
if (!NT_STATUS_IS_OK(status)) {
- talloc_free(p);
+ idr_remove(private->idtree_fnum, p->fnum);
return status;
}
- private->num_open++;
-
DLIST_ADD(private->pipe_list, p);
p->smbpid = req->smbpid;
p->session = req->session;
+ p->private = private;
*ps = p;
+ talloc_steal(private, p);
+
+ talloc_set_destructor(p, ipc_fd_destructor);
+
return NT_STATUS_OK;
}
@@ -390,21 +360,14 @@ static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
struct pipe_state *p;
NTSTATUS status;
- switch (rd->generic.level) {
- case RAW_READ_READ:
- fnum = rd->read.in.fnum;
- data.length = rd->read.in.count;
- data.data = rd->read.out.data;
- break;
- case RAW_READ_READX:
- fnum = rd->readx.in.fnum;
- data.length = rd->readx.in.maxcnt;
- data.data = rd->readx.out.data;
- break;
- default:
- return NT_STATUS_NOT_SUPPORTED;
+ if (rd->generic.level != RAW_READ_GENERIC) {
+ return ntvfs_map_read(req, rd, ntvfs);
}
+ fnum = rd->readx.in.fnum;
+ data.length = rd->readx.in.maxcnt;
+ data.data = rd->readx.out.data;
+
p = pipe_state_find(private, fnum);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
@@ -415,18 +378,9 @@ static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
return status;
}
- switch (rd->generic.level) {
- case RAW_READ_READ:
- rd->read.out.nread = data.length;
- break;
- case RAW_READ_READX:
- rd->readx.out.remaining = 0;
- rd->readx.out.compaction_mode = 0;
- rd->readx.out.nread = data.length;
- break;
- default:
- return NT_STATUS_NOT_SUPPORTED;
- }
+ rd->readx.out.remaining = 0;
+ rd->readx.out.compaction_mode = 0;
+ rd->readx.out.nread = data.length;
return status;
}
@@ -443,23 +397,14 @@ static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
struct pipe_state *p;
NTSTATUS status;
- switch (wr->generic.level) {
- case RAW_WRITE_WRITE:
- fnum = wr->write.in.fnum;
- data.data = discard_const_p(void, wr->write.in.data);
- data.length = wr->write.in.count;
- break;
-
- case RAW_WRITE_WRITEX:
- fnum = wr->writex.in.fnum;
- data.data = discard_const_p(void, wr->writex.in.data);
- data.length = wr->writex.in.count;
- break;
-
- default:
- return NT_STATUS_NOT_SUPPORTED;
+ if (wr->generic.level != RAW_WRITE_GENERIC) {
+ return ntvfs_map_write(req, wr, ntvfs);
}
+ fnum = wr->writex.in.fnum;
+ data.data = discard_const_p(void, wr->writex.in.data);
+ data.length = wr->writex.in.count;
+
p = pipe_state_find(private, fnum);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
@@ -470,17 +415,8 @@ static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
return status;
}
- switch (wr->generic.level) {
- case RAW_WRITE_WRITE:
- wr->write.out.nwritten = data.length;
- break;
- case RAW_WRITE_WRITEX:
- wr->writex.out.nwritten = data.length;
- wr->writex.out.remaining = 0;
- break;
- default:
- return NT_STATUS_NOT_SUPPORTED;
- }
+ wr->writex.out.nwritten = data.length;
+ wr->writex.out.remaining = 0;
return NT_STATUS_OK;
}
@@ -513,7 +449,7 @@ static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
struct pipe_state *p;
if (io->generic.level != RAW_CLOSE_CLOSE) {
- return NT_STATUS_ACCESS_DENIED;
+ return ntvfs_map_close(req, io, ntvfs);
}
p = pipe_state_find(private, io->close.in.fnum);
@@ -521,8 +457,7 @@ static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- pipe_shutdown(private, p);
- private->num_open--;
+ talloc_free(p);
return NT_STATUS_OK;
}
@@ -539,7 +474,7 @@ static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
for (p=private->pipe_list; p; p=next) {
next = p->next;
if (p->smbpid == req->smbpid) {
- pipe_shutdown(private, p);
+ talloc_free(p);
}
}
@@ -558,7 +493,7 @@ static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
for (p=private->pipe_list; p; p=next) {
next = p->next;
if (p->session == req->session) {
- pipe_shutdown(private, p);
+ talloc_free(p);
}
}
diff --git a/source4/ntvfs/nbench/vfs_nbench.c b/source4/ntvfs/nbench/vfs_nbench.c
index 6203c21506..482f0208a2 100644
--- a/source4/ntvfs/nbench/vfs_nbench.c
+++ b/source4/ntvfs/nbench/vfs_nbench.c
@@ -59,10 +59,8 @@ static void nbench_log(struct nbench_private *private,
status code and any result parameters much harder.
*/
#define PASS_THRU_REQ(ntvfs, req, op, args) do { \
- void *send_fn_saved = req->async.send_fn; \
- req->async.send_fn = NULL; \
+ req->control_flags &= ~REQ_CONTROL_MAY_ASYNC; \
status = ntvfs_next_##op args; \
- req->async.send_fn = send_fn_saved; \
} while (0)
diff --git a/source4/ntvfs/ntvfs_generic.c b/source4/ntvfs/ntvfs_generic.c
index 9e1d653465..b6f3d8e603 100644
--- a/source4/ntvfs/ntvfs_generic.c
+++ b/source4/ntvfs/ntvfs_generic.c
@@ -3,7 +3,7 @@
NTVFS generic level mapping code
- Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Tridgell 2003-2004
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
@@ -34,7 +34,8 @@
#include "includes.h"
/*
- see if a filename ends in EXE COM DLL or SYM. This is needed for the DENY_DOS mapping for OpenX
+ see if a filename ends in EXE COM DLL or SYM. This is needed for the
+ DENY_DOS mapping for OpenX
*/
static BOOL is_exe_file(const char *fname)
{
@@ -61,125 +62,133 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
struct ntvfs_module_context *ntvfs)
{
NTSTATUS status;
- union smb_open io2;
+ union smb_open *io2;
- if (io->generic.level == RAW_OPEN_GENERIC) {
- return NT_STATUS_INVALID_LEVEL;
+ io2 = talloc_p(req, union smb_open);
+ if (io2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
+ /* must be synchronous, or we won't be called to do the
+ translation */
+ req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
+
switch (io->generic.level) {
+ case RAW_OPEN_GENERIC:
+ return NT_STATUS_INVALID_LEVEL;
+
case RAW_OPEN_OPENX:
- ZERO_STRUCT(io2.generic.in);
- io2.generic.level = RAW_OPEN_GENERIC;
+ ZERO_STRUCT(io2->generic.in);
+ io2->generic.level = RAW_OPEN_GENERIC;
if (io->openx.in.flags & OPENX_FLAGS_REQUEST_OPLOCK) {
- io2.generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
}
if (io->openx.in.flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
- io2.generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
}
switch (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) {
case OPENX_MODE_ACCESS_READ:
- io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
+ io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
break;
case OPENX_MODE_ACCESS_WRITE:
- io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
+ io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
break;
case OPENX_MODE_ACCESS_RDWR:
case OPENX_MODE_ACCESS_FCB:
- io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
+ io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
break;
}
switch (io->openx.in.open_mode & OPENX_MODE_DENY_MASK) {
case OPENX_MODE_DENY_READ:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
break;
case OPENX_MODE_DENY_WRITE:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
break;
case OPENX_MODE_DENY_ALL:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
break;
case OPENX_MODE_DENY_NONE:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
break;
case OPENX_MODE_DENY_DOS:
/* DENY_DOS is quite strange - it depends on the filename! */
if (is_exe_file(io->openx.in.fname)) {
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
} else {
if ((io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) ==
OPENX_MODE_ACCESS_READ) {
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
} else {
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
}
}
break;
case OPENX_MODE_DENY_FCB:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
break;
}
switch (io->openx.in.open_func) {
case (OPENX_OPEN_FUNC_FAIL):
- io2.generic.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
break;
case (OPENX_OPEN_FUNC_OPEN):
- io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
break;
case (OPENX_OPEN_FUNC_TRUNC):
- io2.generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
break;
case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
- io2.generic.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
break;
case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
- io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
break;
case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
- io2.generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
break;
}
- io2.generic.in.alloc_size = io->openx.in.size;
- io2.generic.in.file_attr = io->openx.in.file_attrs;
- io2.generic.in.fname = io->openx.in.fname;
+ io2->generic.in.alloc_size = io->openx.in.size;
+ io2->generic.in.file_attr = io->openx.in.file_attrs;
+ io2->generic.in.fname = io->openx.in.fname;
- status = ntvfs->ops->open(ntvfs, req, &io2);
+ status = ntvfs->ops->open(ntvfs, req, io2);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
ZERO_STRUCT(io->openx.out);
- io->openx.out.fnum = io2.generic.out.fnum;
- io->openx.out.attrib = io2.generic.out.attrib;
- io->openx.out.write_time = nt_time_to_unix(io2.generic.out.write_time);
- io->openx.out.size = io2.generic.out.size;
+ io->openx.out.fnum = io2->generic.out.fnum;
+ io->openx.out.attrib = io2->generic.out.attrib;
+ io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
+ io->openx.out.size = io2->generic.out.size;
return NT_STATUS_OK;
case RAW_OPEN_OPEN:
- ZERO_STRUCT(io2.generic.in);
- io2.generic.level = RAW_OPEN_GENERIC;
- io2.generic.in.file_attr = io->open.in.search_attrs;
- io2.generic.in.fname = io->open.in.fname;
- io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN;
+ ZERO_STRUCT(io2->generic.in);
+ io2->generic.level = RAW_OPEN_GENERIC;
+ io2->generic.in.file_attr = io->open.in.search_attrs;
+ io2->generic.in.fname = io->open.in.fname;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
DEBUG(9,("ntvfs_map_open(OPEN): mapping flags=0x%x\n",
io->open.in.flags));
switch (io->open.in.flags & OPEN_FLAGS_MODE_MASK) {
case OPEN_FLAGS_OPEN_READ:
- io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
+ io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
io->open.out.rmode = DOS_OPEN_RDONLY;
break;
case OPEN_FLAGS_OPEN_WRITE:
- io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
+ io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
io->open.out.rmode = DOS_OPEN_WRONLY;
break;
case OPEN_FLAGS_OPEN_RDWR:
case 0xf: /* FCB mode */
- io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ |
+ io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ |
GENERIC_RIGHTS_FILE_WRITE;
io->open.out.rmode = DOS_OPEN_RDWR; /* assume we got r/w */
break;
@@ -194,31 +203,31 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
/* DENY_DOS is quite strange - it depends on the filename! */
/* REWRITE: is this necessary for OPEN? */
if (is_exe_file(io->open.in.fname)) {
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
} else {
if ((io->open.in.flags & OPEN_FLAGS_MODE_MASK) ==
OPEN_FLAGS_OPEN_READ) {
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
} else {
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
}
}
break;
case OPEN_FLAGS_DENY_ALL:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
break;
case OPEN_FLAGS_DENY_WRITE:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
break;
case OPEN_FLAGS_DENY_READ:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
break;
case OPEN_FLAGS_DENY_NONE:
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE |
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE |
NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE;
break;
case 0x70: /* FCB mode */
- io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
break;
default:
DEBUG(2,("ntvfs_map_open(OPEN): invalid DENY 0x%x\n",
@@ -226,18 +235,18 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
return NT_STATUS_INVALID_PARAMETER;
}
DEBUG(9,("ntvfs_map_open(OPEN): mapped flags=0x%x to access_mask=0x%x and share_access=0x%x\n",
- io->open.in.flags, io2.generic.in.access_mask, io2.generic.in.share_access));
+ io->open.in.flags, io2->generic.in.access_mask, io2->generic.in.share_access));
- status = ntvfs->ops->open(ntvfs, req, &io2);
+ status = ntvfs->ops->open(ntvfs, req, io2);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
ZERO_STRUCT(io->openx.out);
- io->open.out.fnum = io2.generic.out.fnum;
- io->open.out.attrib = io2.generic.out.attrib;
- io->open.out.write_time = nt_time_to_unix(io2.generic.out.write_time);
- io->open.out.size = io2.generic.out.size;
+ io->open.out.fnum = io2->generic.out.fnum;
+ io->open.out.attrib = io2->generic.out.attrib;
+ io->open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
+ io->open.out.size = io2->generic.out.size;
io->open.out.rmode = DOS_OPEN_RDWR;
return NT_STATUS_OK;
@@ -254,16 +263,21 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
struct ntvfs_module_context *ntvfs)
{
NTSTATUS status;
- union smb_fsinfo fs2;
+ union smb_fsinfo *fs2;
+
+ fs2 = talloc_p(req, union smb_fsinfo);
+ if (fs2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
if (fs->generic.level == RAW_QFS_GENERIC) {
return NT_STATUS_INVALID_LEVEL;
}
/* ask the backend for the generic info */
- fs2.generic.level = RAW_QFS_GENERIC;
+ fs2->generic.level = RAW_QFS_GENERIC;
- status = ntvfs->ops->fsinfo(ntvfs, req, &fs2);
+ status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -279,7 +293,7 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
/* we need to scale the sizes to fit */
for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
- if (fs2.generic.out.blocks_total * (double)fs2.generic.out.block_size < bpunit * 512 * 65535.0) {
+ if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
break;
}
}
@@ -287,9 +301,9 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
fs->dskattr.out.blocks_per_unit = bpunit;
fs->dskattr.out.block_size = 512;
fs->dskattr.out.units_total =
- (fs2.generic.out.blocks_total * (double)fs2.generic.out.block_size) / (bpunit * 512);
+ (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
fs->dskattr.out.units_free =
- (fs2.generic.out.blocks_free * (double)fs2.generic.out.block_size) / (bpunit * 512);
+ (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
/* we must return a maximum of 2G to old DOS systems, or they get very confused */
if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) {
@@ -301,63 +315,63 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
}
case RAW_QFS_ALLOCATION:
- fs->allocation.out.fs_id = fs2.generic.out.fs_id;
- fs->allocation.out.total_alloc_units = fs2.generic.out.blocks_total;
- fs->allocation.out.avail_alloc_units = fs2.generic.out.blocks_free;
+ fs->allocation.out.fs_id = fs2->generic.out.fs_id;
+ fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
+ fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
fs->allocation.out.sectors_per_unit = 1;
- fs->allocation.out.bytes_per_sector = fs2.generic.out.block_size;
+ fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
return NT_STATUS_OK;
case RAW_QFS_VOLUME:
- fs->volume.out.serial_number = fs2.generic.out.serial_number;
- fs->volume.out.volume_name.s = fs2.generic.out.volume_name;
+ fs->volume.out.serial_number = fs2->generic.out.serial_number;
+ fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
return NT_STATUS_OK;
case RAW_QFS_VOLUME_INFO:
case RAW_QFS_VOLUME_INFORMATION:
- fs->volume_info.out.create_time = fs2.generic.out.create_time;
- fs->volume_info.out.serial_number = fs2.generic.out.serial_number;
- fs->volume_info.out.volume_name.s = fs2.generic.out.volume_name;
+ fs->volume_info.out.create_time = fs2->generic.out.create_time;
+ fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
+ fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
return NT_STATUS_OK;
case RAW_QFS_SIZE_INFO:
case RAW_QFS_SIZE_INFORMATION:
- fs->size_info.out.total_alloc_units = fs2.generic.out.blocks_total;
- fs->size_info.out.avail_alloc_units = fs2.generic.out.blocks_free;
+ fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
+ fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
fs->size_info.out.sectors_per_unit = 1;
- fs->size_info.out.bytes_per_sector = fs2.generic.out.block_size;
+ fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
return NT_STATUS_OK;
case RAW_QFS_DEVICE_INFO:
case RAW_QFS_DEVICE_INFORMATION:
- fs->device_info.out.device_type = fs2.generic.out.device_type;
- fs->device_info.out.characteristics = fs2.generic.out.device_characteristics;
+ fs->device_info.out.device_type = fs2->generic.out.device_type;
+ fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
return NT_STATUS_OK;
case RAW_QFS_ATTRIBUTE_INFO:
case RAW_QFS_ATTRIBUTE_INFORMATION:
- fs->attribute_info.out.fs_attr = fs2.generic.out.fs_attr;
- fs->attribute_info.out.max_file_component_length = fs2.generic.out.max_file_component_length;
- fs->attribute_info.out.fs_type.s = fs2.generic.out.fs_type;
+ fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
+ fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
+ fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
return NT_STATUS_OK;
case RAW_QFS_QUOTA_INFORMATION:
ZERO_STRUCT(fs->quota_information.out.unknown);
- fs->quota_information.out.quota_soft = fs2.generic.out.quota_soft;
- fs->quota_information.out.quota_hard = fs2.generic.out.quota_hard;
- fs->quota_information.out.quota_flags = fs2.generic.out.quota_flags;
+ fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
+ fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
+ fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
return NT_STATUS_OK;
case RAW_QFS_FULL_SIZE_INFORMATION:
- fs->full_size_information.out.total_alloc_units = fs2.generic.out.blocks_total;
- fs->full_size_information.out.call_avail_alloc_units = fs2.generic.out.blocks_free;
- fs->full_size_information.out.actual_avail_alloc_units = fs2.generic.out.blocks_free;
+ fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
+ fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
+ fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
fs->full_size_information.out.sectors_per_unit = 1;
- fs->full_size_information.out.bytes_per_sector = fs2.generic.out.block_size;
+ fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
return NT_STATUS_OK;
case RAW_QFS_OBJECTID_INFORMATION:
- fs->objectid_information.out.guid = fs2.generic.out.guid;
+ fs->objectid_information.out.guid = fs2->generic.out.guid;
ZERO_STRUCT(fs->objectid_information.out.unknown);
return NT_STATUS_OK;
}
@@ -370,7 +384,8 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
/*
NTVFS fileinfo generic to any mapper
*/
-NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info, union smb_fileinfo *info2)
+NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
+ union smb_fileinfo *info2)
{
int i;
/* and convert it to the required level using results in info2 */
@@ -596,21 +611,26 @@ NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *inf
struct ntvfs_module_context *ntvfs)
{
NTSTATUS status;
- union smb_fileinfo info2;
+ union smb_fileinfo *info2;
+
+ info2 = talloc_p(req, union smb_fileinfo);
+ if (info2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
if (info->generic.level == RAW_FILEINFO_GENERIC) {
return NT_STATUS_INVALID_LEVEL;
}
/* ask the backend for the generic info */
- info2.generic.level = RAW_FILEINFO_GENERIC;
- info2.generic.in.fnum = info->generic.in.fnum;
+ info2->generic.level = RAW_FILEINFO_GENERIC;
+ info2->generic.in.fnum = info->generic.in.fnum;
- status = ntvfs->ops->qfileinfo(ntvfs, req, &info2);
+ status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- return ntvfs_map_fileinfo(req, info, &info2);
+ return ntvfs_map_fileinfo(req, info, info2);
}
/*
@@ -620,19 +640,286 @@ NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *inf
struct ntvfs_module_context *ntvfs)
{
NTSTATUS status;
- union smb_fileinfo info2;
+ union smb_fileinfo *info2;
+
+ info2 = talloc_p(req, union smb_fileinfo);
+ if (info2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
if (info->generic.level == RAW_FILEINFO_GENERIC) {
return NT_STATUS_INVALID_LEVEL;
}
/* ask the backend for the generic info */
- info2.generic.level = RAW_FILEINFO_GENERIC;
- info2.generic.in.fname = info->generic.in.fname;
+ info2->generic.level = RAW_FILEINFO_GENERIC;
+ info2->generic.in.fname = info->generic.in.fname;
+
+ /* must be synchronous, or we won't be called to do the
+ translation */
+ req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
- status = ntvfs->ops->qpathinfo(ntvfs, req, &info2);
+ status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- return ntvfs_map_fileinfo(req, info, &info2);
+ return ntvfs_map_fileinfo(req, info, info2);
+}
+
+
+/*
+ NTVFS lock generic to any mapper
+*/
+NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck,
+ struct ntvfs_module_context *ntvfs)
+{
+ union smb_lock *lck2;
+ struct smb_lock_entry *locks;
+
+ lck2 = talloc_p(req, union smb_lock);
+ if (lck2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ locks = talloc_array_p(lck2, struct smb_lock_entry, 1);
+ if (locks == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (lck->generic.level) {
+ case RAW_LOCK_LOCKX:
+ return NT_STATUS_INVALID_LEVEL;
+
+ case RAW_LOCK_LOCK:
+ lck2->generic.in.ulock_cnt = 0;
+ lck2->generic.in.lock_cnt = 1;
+ break;
+
+ case RAW_LOCK_UNLOCK:
+ lck2->generic.in.ulock_cnt = 1;
+ lck2->generic.in.lock_cnt = 0;
+ break;
+ }
+
+ lck2->generic.level = RAW_LOCK_GENERIC;
+ lck2->generic.in.fnum = lck->lock.in.fnum;
+ lck2->generic.in.mode = 0;
+ lck2->generic.in.timeout = 0;
+ lck2->generic.in.locks = locks;
+ locks->pid = req->smbpid;
+ locks->offset = lck->lock.in.offset;
+ locks->count = lck->lock.in.count;
+
+ return ntvfs->ops->lock(ntvfs, req, lck2);
+}
+
+
+/*
+ NTVFS write generic to any mapper
+*/
+NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
+ struct ntvfs_module_context *ntvfs)
+{
+ union smb_write *wr2;
+ union smb_lock *lck;
+ union smb_close *cl;
+ NTSTATUS status;
+
+ wr2 = talloc_p(req, union smb_write);
+ if (wr2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ wr2->generic.level = RAW_WRITE_GENERIC;
+
+ /* we can't map asynchronously */
+ req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
+
+ switch (wr->generic.level) {
+ case RAW_WRITE_WRITEX:
+ status = NT_STATUS_INVALID_LEVEL;
+ break;
+
+ case RAW_WRITE_WRITE:
+ wr2->generic.in.fnum = wr->write.in.fnum;
+ wr2->generic.in.offset = wr->write.in.offset;
+ wr2->generic.in.wmode = 0;
+ wr2->generic.in.remaining = wr->write.in.remaining;
+ wr2->generic.in.count = wr->write.in.count;
+ wr2->generic.in.data = wr->write.in.data;
+ status = ntvfs->ops->write(ntvfs, req, wr2);
+ wr->write.out.nwritten = wr2->generic.out.nwritten;
+ break;
+
+ case RAW_WRITE_WRITEUNLOCK:
+ lck = talloc_p(wr2, union smb_lock);
+ if (lck == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ wr2->generic.in.fnum = wr->writeunlock.in.fnum;
+ wr2->generic.in.offset = wr->writeunlock.in.offset;
+ wr2->generic.in.wmode = 0;
+ wr2->generic.in.remaining = wr->writeunlock.in.remaining;
+ wr2->generic.in.count = wr->writeunlock.in.count;
+ wr2->generic.in.data = wr->writeunlock.in.data;
+
+ lck->unlock.level = RAW_LOCK_UNLOCK;
+ lck->unlock.in.fnum = wr->writeunlock.in.fnum;
+ lck->unlock.in.count = wr->writeunlock.in.count;
+ lck->unlock.in.offset = wr->writeunlock.in.offset;
+
+ status = ntvfs->ops->write(ntvfs, req, wr2);
+
+ wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = ntvfs->ops->lock(ntvfs, req, lck);
+ }
+ break;
+
+ case RAW_WRITE_WRITECLOSE:
+ cl = talloc_p(wr2, union smb_close);
+ if (cl == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ wr2->generic.in.fnum = wr->writeclose.in.fnum;
+ wr2->generic.in.offset = wr->writeclose.in.offset;
+ wr2->generic.in.wmode = 0;
+ wr2->generic.in.remaining = 0;
+ wr2->generic.in.count = wr->writeclose.in.count;
+ wr2->generic.in.data = wr->writeclose.in.data;
+
+ cl->close.level = RAW_CLOSE_CLOSE;
+ cl->close.in.fnum = wr->writeclose.in.fnum;
+ cl->close.in.write_time = wr->writeclose.in.mtime;
+
+ status = ntvfs->ops->write(ntvfs, req, wr2);
+ wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = ntvfs->ops->close(ntvfs, req, cl);
+ }
+ break;
+
+ case RAW_WRITE_SPLWRITE:
+ wr2->generic.in.fnum = wr->splwrite.in.fnum;
+ wr2->generic.in.offset = 0;
+ wr2->generic.in.wmode = 0;
+ wr2->generic.in.remaining = 0;
+ wr2->generic.in.count = wr->splwrite.in.count;
+ wr2->generic.in.data = wr->splwrite.in.data;
+ status = ntvfs->ops->write(ntvfs, req, wr2);
+ break;
+ }
+
+
+ return status;
+}
+
+
+/*
+ NTVFS read generic to any mapper
+*/
+NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
+ struct ntvfs_module_context *ntvfs)
+{
+ union smb_read *rd2;
+ union smb_lock *lck;
+ NTSTATUS status;
+
+ rd2 = talloc_p(req, union smb_read);
+ if (rd2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rd2->generic.level = RAW_READ_GENERIC;
+
+ /* we can't map asynchronously */
+ req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
+
+ switch (rd->generic.level) {
+ case RAW_READ_READX:
+ status = NT_STATUS_INVALID_LEVEL;
+ break;
+
+ case RAW_READ_READ:
+ rd2->generic.in.fnum = rd->read.in.fnum;
+ rd2->generic.in.offset = rd->read.in.offset;
+ rd2->generic.in.mincnt = rd->read.in.count;
+ rd2->generic.in.maxcnt = rd->read.in.count;
+ rd2->generic.in.remaining = rd->read.in.remaining;
+ rd2->generic.out.data = rd->read.out.data;
+ status = ntvfs->ops->read(ntvfs, req, rd2);
+ rd->read.out.nread = rd2->generic.out.nread;
+ break;
+
+ case RAW_READ_READBRAW:
+ rd2->generic.in.fnum = rd->readbraw.in.fnum;
+ rd2->generic.in.offset = rd->readbraw.in.offset;
+ rd2->generic.in.mincnt = rd->readbraw.in.mincnt;
+ rd2->generic.in.maxcnt = rd->readbraw.in.maxcnt;
+ rd2->generic.in.remaining = 0;
+ rd2->generic.out.data = rd->readbraw.out.data;
+ status = ntvfs->ops->read(ntvfs, req, rd2);
+ rd->readbraw.out.nread = rd2->generic.out.nread;
+ break;
+
+ case RAW_READ_LOCKREAD:
+ lck = talloc_p(rd2, union smb_lock);
+ if (lck == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rd2->generic.in.fnum = rd->lockread.in.fnum;
+ rd2->generic.in.offset = rd->lockread.in.offset;
+ rd2->generic.in.mincnt = rd->lockread.in.count;
+ rd2->generic.in.maxcnt = rd->lockread.in.count;
+ rd2->generic.in.remaining = rd->lockread.in.remaining;
+ rd2->generic.out.data = rd->lockread.out.data;
+
+ lck->lock.level = RAW_LOCK_LOCK;
+ lck->lock.in.fnum = rd->lockread.in.fnum;
+ lck->lock.in.count = rd->lockread.in.count;
+ lck->lock.in.offset = rd->lockread.in.offset;
+
+ status = ntvfs->ops->lock(ntvfs, req, lck);
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = ntvfs->ops->read(ntvfs, req, rd2);
+ rd->lockread.out.nread = rd2->generic.out.nread;
+ }
+ break;
+ }
+
+
+ return status;
+}
+
+
+/*
+ NTVFS close generic to any mapper
+*/
+NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl,
+ struct ntvfs_module_context *ntvfs)
+{
+ union smb_close *cl2;
+
+ cl2 = talloc_p(req, union smb_close);
+ if (cl2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (cl2->generic.level) {
+ case RAW_CLOSE_CLOSE:
+ return NT_STATUS_INVALID_LEVEL;
+
+ case RAW_CLOSE_SPLCLOSE:
+ cl2->close.level = RAW_CLOSE_CLOSE;
+ cl2->close.in.fnum = cl->splclose.in.fnum;
+ break;
+ }
+
+ return ntvfs->ops->close(ntvfs, req, cl2);
}
diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c
index f52e68eeb1..4a4da34b60 100644
--- a/source4/ntvfs/posix/pvfs_lock.c
+++ b/source4/ntvfs/posix/pvfs_lock.c
@@ -273,48 +273,21 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
struct pvfs_pending_lock *pending = NULL;
NTSTATUS status;
- f = pvfs_find_fd(pvfs, req, lck->generic.in.fnum);
+ if (lck->generic.level != RAW_LOCK_GENERIC) {
+ return ntvfs_map_lock(req, lck, ntvfs);
+ }
+
+ f = pvfs_find_fd(pvfs, req, lck->lockx.in.fnum);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
- switch (lck->generic.level) {
- case RAW_LOCK_LOCK:
- status = brl_lock(pvfs->brl_context,
- &f->locking_key,
- req->smbpid,
- f->fnum,
- lck->lock.in.offset,
- lck->lock.in.count,
- WRITE_LOCK, NULL);
- if (NT_STATUS_IS_OK(status)) {
- f->lock_count++;
- }
- return status;
-
- case RAW_LOCK_UNLOCK:
- status = brl_unlock(pvfs->brl_context,
- &f->locking_key,
- req->smbpid,
- f->fnum,
- lck->lock.in.offset,
- lck->lock.in.count);
- if (NT_STATUS_IS_OK(status)) {
- f->lock_count--;
- }
- return status;
-
- case RAW_LOCK_GENERIC:
- return NT_STATUS_INVALID_LEVEL;
-
- case RAW_LOCK_LOCKX:
- /* fall through to the most complex case */
- break;
+ if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
}
- /* now the lockingX case, most common and also most complex */
if (lck->lockx.in.timeout != 0 &&
- req->async.send_fn) {
+ (req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
pending = talloc_p(req, struct pvfs_pending_lock);
if (pending == NULL) {
return NT_STATUS_NO_MEMORY;
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index fb81c86bcc..eb5b94e753 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -46,6 +46,120 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
return f;
}
+
+/*
+ cleanup a open directory handle
+*/
+static int pvfs_dir_fd_destructor(void *p)
+{
+ struct pvfs_file *f = p;
+ DLIST_REMOVE(f->pvfs->open_files, f);
+ idr_remove(f->pvfs->idtree_fnum, f->fnum);
+ return 0;
+}
+
+
+/*
+ open a directory
+*/
+static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
+ struct smbsrv_request *req,
+ struct pvfs_filename *name,
+ union smb_open *io)
+{
+ struct pvfs_file *f;
+ int fnum;
+ NTSTATUS status;
+
+ /* if the client says it must be a directory, and it isn't,
+ then fail */
+ if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
+ return NT_STATUS_NOT_A_DIRECTORY;
+ }
+
+ f = talloc_p(req, struct pvfs_file);
+ if (f == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
+ if (fnum == -1) {
+ talloc_free(f);
+ return NT_STATUS_TOO_MANY_OPENED_FILES;
+ }
+
+ f->fnum = fnum;
+ f->fd = -1;
+ f->name = talloc_steal(f, name);
+ f->session = req->session;
+ f->smbpid = req->smbpid;
+ f->pvfs = pvfs;
+ f->pending_list = NULL;
+ f->lock_count = 0;
+ f->locking_key = data_blob(NULL, 0);
+
+ /* setup a destructor to avoid leaks on abnormal termination */
+ talloc_set_destructor(f, pvfs_dir_fd_destructor);
+
+ switch (io->generic.in.open_disposition) {
+ case NTCREATEX_DISP_OPEN_IF:
+ break;
+
+ case NTCREATEX_DISP_OPEN:
+ if (!name->exists) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ break;
+
+ case NTCREATEX_DISP_CREATE:
+ if (name->exists) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+ break;
+
+ case NTCREATEX_DISP_OVERWRITE_IF:
+ case NTCREATEX_DISP_OVERWRITE:
+ case NTCREATEX_DISP_SUPERSEDE:
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!name->exists) {
+ if (mkdir(name->full_name, 0755) == -1) {
+ return pvfs_map_errno(pvfs,errno);
+ }
+ status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
+ PVFS_RESOLVE_NO_WILDCARD, &name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (!name->exists) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ DLIST_ADD(pvfs->open_files, f);
+
+ /* the open succeeded, keep this handle permanently */
+ talloc_steal(pvfs, f);
+
+ ZERO_STRUCT(io->generic.out);
+
+ io->generic.out.create_time = name->dos.create_time;
+ io->generic.out.access_time = name->dos.access_time;
+ io->generic.out.write_time = name->dos.write_time;
+ io->generic.out.change_time = name->dos.change_time;
+ io->generic.out.fnum = f->fnum;
+ io->generic.out.alloc_size = 0;
+ io->generic.out.size = 0;
+ io->generic.out.attrib = name->dos.attrib;
+ io->generic.out.is_directory = 1;
+
+ return NT_STATUS_OK;
+}
+
+
/*
by using a destructor we make sure that abnormal cleanup will not
leak file descriptors (assuming at least the top level pointer is freed, which
@@ -55,6 +169,8 @@ static int pvfs_fd_destructor(void *p)
{
struct pvfs_file *f = p;
+ DLIST_REMOVE(f->pvfs->open_files, f);
+
pvfs_lock_close(f->pvfs, f);
if (f->fd != -1) {
@@ -97,83 +213,79 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
return status;
}
+ /* directory opens are handled separately */
+ if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
+ (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
+ return pvfs_open_directory(pvfs, req, name, io);
+ }
+
+
switch (io->generic.in.open_disposition) {
case NTCREATEX_DISP_SUPERSEDE:
+ if (!name->exists) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ flags = O_TRUNC;
+ break;
+
case NTCREATEX_DISP_OVERWRITE_IF:
flags = O_CREAT | O_TRUNC;
break;
+
case NTCREATEX_DISP_OPEN:
+ if (!name->exists) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
flags = 0;
break;
+
case NTCREATEX_DISP_OVERWRITE:
+ if (!name->exists) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
flags = O_TRUNC;
break;
+
case NTCREATEX_DISP_CREATE:
+ if (name->exists) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
flags = O_CREAT | O_EXCL;
break;
+
case NTCREATEX_DISP_OPEN_IF:
flags = O_CREAT;
break;
- default:
- flags = 0;
- break;
- }
-
- flags |= O_RDWR;
-
-/* we need to do this differently to support systems without O_DIRECTORY */
-#ifndef O_DIRECTORY
-#define O_DIRECTORY 0
-#endif
- if (name->exists &&
- (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
- !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
- return NT_STATUS_NOT_A_DIRECTORY;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
}
- if ((name->exists && name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ||
- (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
- flags = O_RDONLY | O_DIRECTORY;
- if (pvfs->flags & PVFS_FLAG_READONLY) {
- goto do_open;
- }
- switch (io->generic.in.open_disposition) {
- case NTCREATEX_DISP_CREATE:
- if (mkdir(name->full_name, 0755) == -1) {
- return pvfs_map_errno(pvfs,errno);
- }
- break;
- case NTCREATEX_DISP_OPEN_IF:
- if (mkdir(name->full_name, 0755) == -1 && errno != EEXIST) {
- return pvfs_map_errno(pvfs,errno);
- }
- break;
- }
- }
+ flags |= O_RDWR;
- f = talloc_p(pvfs, struct pvfs_file);
+ f = talloc_p(req, struct pvfs_file);
if (f == NULL) {
return NT_STATUS_NO_MEMORY;
}
fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
if (fnum == -1) {
- talloc_free(f);
return NT_STATUS_TOO_MANY_OPENED_FILES;
}
-do_open:
fd = open(name->full_name, flags, 0644);
if (fd == -1) {
- if (errno == 0)
+ if (errno == 0) {
errno = ENOENT;
- return pvfs_map_errno(pvfs,errno);
+ }
+ idr_remove(pvfs->idtree_fnum, fnum);
+ return pvfs_map_errno(pvfs, errno);
}
/* re-resolve the open fd */
status = pvfs_resolve_name_fd(pvfs, fd, name);
if (!NT_STATUS_IS_OK(status)) {
+ idr_remove(pvfs->idtree_fnum, fnum);
return status;
}
@@ -210,6 +322,9 @@ do_open:
io->generic.out.attrib = name->dos.attrib;
io->generic.out.is_directory = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)?1:0;
+ /* success - keep the file handle */
+ talloc_steal(pvfs, f);
+
return NT_STATUS_OK;
}
@@ -225,8 +340,7 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
NTSTATUS status;
if (io->generic.level != RAW_CLOSE_CLOSE) {
- /* we need a mapping function */
- return NT_STATUS_INVALID_LEVEL;
+ return ntvfs_map_close(req, io, ntvfs);
}
f = pvfs_find_fd(pvfs, req, io->close.in.fnum);
@@ -234,15 +348,14 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- if (close(f->fd) != 0) {
+ if (f->fd != -1 &&
+ close(f->fd) != 0) {
status = pvfs_map_errno(pvfs, errno);
} else {
status = NT_STATUS_OK;
}
f->fd = -1;
- DLIST_REMOVE(pvfs->open_files, f);
-
/* the destructor takes care of the rest */
talloc_free(f);
diff --git a/source4/ntvfs/posix/pvfs_read.c b/source4/ntvfs/posix/pvfs_read.c
index 24142a81ee..7256fd8e16 100644
--- a/source4/ntvfs/posix/pvfs_read.c
+++ b/source4/ntvfs/posix/pvfs_read.c
@@ -35,15 +35,18 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs,
NTSTATUS status;
if (rd->generic.level != RAW_READ_READX) {
- return NT_STATUS_NOT_SUPPORTED;
+ return ntvfs_map_read(req, rd, ntvfs);
}
-
f = pvfs_find_fd(pvfs, req, rd->readx.in.fnum);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
+ if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+
status = pvfs_check_lock(pvfs, f, req->smbpid,
rd->readx.in.offset,
rd->readx.in.maxcnt,
diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c
index 80a3dae3a7..8bbb4f8605 100644
--- a/source4/ntvfs/posix/pvfs_write.c
+++ b/source4/ntvfs/posix/pvfs_write.c
@@ -35,63 +35,37 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
struct pvfs_file *f;
NTSTATUS status;
- switch (wr->generic.level) {
- case RAW_WRITE_WRITEX:
- f = pvfs_find_fd(pvfs, req, wr->writex.in.fnum);
- if (!f) {
- return NT_STATUS_INVALID_HANDLE;
- }
- status = pvfs_check_lock(pvfs, f, req->smbpid,
- wr->writex.in.offset,
- wr->writex.in.count,
- WRITE_LOCK);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- ret = pwrite(f->fd,
- wr->writex.in.data,
- wr->writex.in.count,
- wr->writex.in.offset);
- if (ret == -1) {
- return map_nt_error_from_unix(errno);
- }
-
- wr->writex.out.nwritten = ret;
- wr->writex.out.remaining = 0; /* should fill this in? */
-
- return NT_STATUS_OK;
-
- case RAW_WRITE_WRITE:
- f = pvfs_find_fd(pvfs, req, wr->write.in.fnum);
- if (!f) {
- return NT_STATUS_INVALID_HANDLE;
- }
- if (wr->write.in.count == 0) {
- /* a truncate! */
- ret = ftruncate(f->fd, wr->write.in.offset);
- } else {
- status = pvfs_check_lock(pvfs, f, req->smbpid,
- wr->write.in.offset,
- wr->write.in.count,
- WRITE_LOCK);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ if (wr->generic.level != RAW_WRITE_WRITEX) {
+ return ntvfs_map_write(req, wr, ntvfs);
+ }
- ret = pwrite(f->fd,
- wr->write.in.data,
- wr->write.in.count,
- wr->write.in.offset);
- }
- if (ret == -1) {
- return pvfs_map_errno(pvfs, errno);
- }
-
- wr->write.out.nwritten = ret;
+ f = pvfs_find_fd(pvfs, req, wr->writex.in.fnum);
+ if (!f) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
- return NT_STATUS_OK;
+ if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
}
- return NT_STATUS_NOT_SUPPORTED;
+ status = pvfs_check_lock(pvfs, f, req->smbpid,
+ wr->writex.in.offset,
+ wr->writex.in.count,
+ WRITE_LOCK);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ret = pwrite(f->fd,
+ wr->writex.in.data,
+ wr->writex.in.count,
+ wr->writex.in.offset);
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ wr->writex.out.nwritten = ret;
+ wr->writex.out.remaining = 0; /* should fill this in? */
+
+ return NT_STATUS_OK;
}
diff --git a/source4/smb_server/reply.c b/source4/smb_server/reply.c
index 2a5a7064bd..bc5eb4157b 100644
--- a/source4/smb_server/reply.c
+++ b/source4/smb_server/reply.c
@@ -236,6 +236,7 @@ void reply_ioctl(struct smbsrv_request *req)
io->ioctl.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
io->ioctl.in.request = IVAL(req->in.vwv, VWV(1));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_ioctl_send;
req->async.private = io;
@@ -257,6 +258,7 @@ void reply_chkpth(struct smbsrv_request *req)
req_pull_ascii4(req, &io->in.path, req->in.data, STR_TERMINATE);
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
req->async.status = ntvfs_chkpath(req, io);
@@ -304,6 +306,7 @@ void reply_getatr(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_getatr_send;
req->async.private = st;
@@ -336,6 +339,7 @@ void reply_setatr(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -379,6 +383,7 @@ void reply_dskattr(struct smbsrv_request *req)
fs->dskattr.level = RAW_QFS_DSKATTR;
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_dskattr_send;
req->async.private = fs;
@@ -433,6 +438,7 @@ void reply_open(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_open_send;
req->async.private = oi;
@@ -508,6 +514,7 @@ void reply_open_and_X(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_open_and_X_send;
req->async.private = oi;
@@ -558,6 +565,7 @@ void reply_mknew(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_mknew_send;
req->async.private = oi;
@@ -611,6 +619,7 @@ void reply_ctemp(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_ctemp_send;
req->async.private = oi;
@@ -636,6 +645,7 @@ void reply_unlink(struct smbsrv_request *req)
req_pull_ascii4(req, &unl->in.pattern, req->in.data, STR_TERMINATE);
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -659,8 +669,8 @@ void reply_readbraw(struct smbsrv_request *req)
io.readbraw.level = RAW_READ_READBRAW;
/* there are two variants, one with 10 and one with 8 command words */
- if (req->in.wct != 10) {
- REQ_CHECK_WCT(req, 8);
+ if (req->in.wct < 8) {
+ goto failed;
}
io.readbraw.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
@@ -696,7 +706,7 @@ void reply_readbraw(struct smbsrv_request *req)
req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
- req_send_reply(req);
+ req_send_reply_nosign(req);
return;
failed:
@@ -758,6 +768,7 @@ void reply_lockread(struct smbsrv_request *req)
/* tell the backend where to put the data */
io->lockread.out.data = req->out.data + 3;
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_lockread_send;
req->async.private = io;
@@ -816,6 +827,7 @@ void reply_read(struct smbsrv_request *req)
/* tell the backend where to put the data */
io->read.out.data = req->out.data + 3;
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_read_send;
req->async.private = io;
@@ -887,6 +899,7 @@ void reply_read_and_X(struct smbsrv_request *req)
/* tell the backend where to put the data. Notice the pad byte. */
io->readx.out.data = req->out.data + 1;
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_read_and_X_send;
req->async.private = io;
@@ -953,6 +966,7 @@ void reply_writeunlock(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_writeunlock_send;
req->async.private = io;
@@ -1010,6 +1024,7 @@ void reply_write(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_write_send;
req->async.private = io;
@@ -1076,6 +1091,7 @@ void reply_write_and_X(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_write_and_X_send;
req->async.private = io;
@@ -1117,6 +1133,7 @@ void reply_lseek(struct smbsrv_request *req)
io->in.mode = SVAL(req->in.vwv, VWV(1));
io->in.offset = IVALS(req->in.vwv, VWV(2));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_lseek_send;
req->async.private = io;
@@ -1139,6 +1156,7 @@ void reply_flush(struct smbsrv_request *req)
io->in.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1189,6 +1207,7 @@ void reply_close(struct smbsrv_request *req)
io->close.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1243,6 +1262,7 @@ void reply_writeclose(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_writeclose_send;
req->async.private = io;
@@ -1268,6 +1288,7 @@ void reply_lock(struct smbsrv_request *req)
lck->lock.in.count = IVAL(req->in.vwv, VWV(1));
lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1293,6 +1314,7 @@ void reply_unlock(struct smbsrv_request *req)
lck->unlock.in.count = IVAL(req->in.vwv, VWV(1));
lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1381,6 +1403,7 @@ void reply_printopen(struct smbsrv_request *req)
req_pull_ascii4(req, &oi->splopen.in.ident, req->in.data, STR_TERMINATE);
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_printopen_send;
req->async.private = oi;
@@ -1404,6 +1427,7 @@ void reply_printclose(struct smbsrv_request *req)
io->splclose.level = RAW_CLOSE_SPLCLOSE;
io->splclose.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1472,6 +1496,7 @@ void reply_printqueue(struct smbsrv_request *req)
lpq->retq.in.maxcount = SVAL(req->in.vwv, VWV(0));
lpq->retq.in.startidx = SVAL(req->in.vwv, VWV(1));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_printqueue_send;
req->async.private = lpq;
@@ -1510,6 +1535,7 @@ void reply_printwrite(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1533,6 +1559,7 @@ void reply_mkdir(struct smbsrv_request *req)
io->generic.level = RAW_MKDIR_MKDIR;
req_pull_ascii4(req, &io->mkdir.in.path, req->in.data, STR_TERMINATE);
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1555,6 +1582,7 @@ void reply_rmdir(struct smbsrv_request *req)
req_pull_ascii4(req, &io->in.path, req->in.data, STR_TERMINATE);
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1588,6 +1616,7 @@ void reply_mv(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1623,6 +1652,7 @@ void reply_ntrename(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1673,6 +1703,7 @@ void reply_copy(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_copy_send;
req->async.private = cp;
@@ -1773,6 +1804,7 @@ void reply_lockingX(struct smbsrv_request *req)
p += lck_size;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_lockingX_send;
req->async.private = lck;
@@ -1809,6 +1841,7 @@ void reply_setattrE(struct smbsrv_request *req)
info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
info->setattre.in.write_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_simple_send;
/* call backend */
@@ -1875,6 +1908,7 @@ void reply_getattrE(struct smbsrv_request *req)
info->getattr.level = RAW_FILEINFO_GETATTRE;
info->getattr.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_getattrE_send;
req->async.private = info;
@@ -2246,6 +2280,7 @@ void reply_ntcreate_and_X(struct smbsrv_request *req)
return;
}
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_ntcreate_and_X_send;
req->async.private = io;
diff --git a/source4/smb_server/search.c b/source4/smb_server/search.c
index 6a8653c749..fdfad5e182 100644
--- a/source4/smb_server/search.c
+++ b/source4/smb_server/search.c
@@ -268,6 +268,7 @@ void reply_fclose(struct smbsrv_request *req)
sc->fclose.in.id.client_cookie = IVAL(p, 17);
/* do a search close operation */
+ req->control_flags |= REQ_CONTROL_MAY_ASYNC;
req->async.send_fn = reply_fclose_send;
req->async.private = sc;
diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h
index 6b0994687c..666eb3491b 100644
--- a/source4/smb_server/smb_server.h
+++ b/source4/smb_server/smb_server.h
@@ -114,8 +114,8 @@ struct smbsrv_request {
control_flag on the request to indicate that it wishes to
delay the reply
- If async.send_fn is NULL then the backend cannot ask for a
- delayed reply for this request
+ If REQ_CONTROL_MAY_ASYNC is not set then the backend cannot
+ ask for a delayed reply for this request
note that the async.private pointer is private to the front
end not the backend. The backend must not change it.