summaryrefslogtreecommitdiff
path: root/source4/ntvfs/posix/pvfs_open.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ntvfs/posix/pvfs_open.c')
-rw-r--r--source4/ntvfs/posix/pvfs_open.c201
1 files changed, 157 insertions, 44 deletions
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);