summaryrefslogtreecommitdiff
path: root/source4/ntvfs/posix
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ntvfs/posix')
-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
4 files changed, 199 insertions, 136 deletions
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;
}