diff options
Diffstat (limited to 'source4/ntvfs/posix')
-rw-r--r-- | source4/ntvfs/posix/pvfs_lock.c | 43 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 201 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_read.c | 7 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_write.c | 84 |
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; } |