diff options
Diffstat (limited to 'source4/ntvfs/posix/pvfs_open.c')
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c new file mode 100644 index 0000000000..74badb2443 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_open.c @@ -0,0 +1,175 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - open and close + + Copyright (C) Andrew Tridgell 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "include/includes.h" +#include "vfs_posix.h" + + +/* + find open file handle given fnum +*/ +struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs, uint16_t fnum) +{ + struct pvfs_file *f; + for (f=pvfs->open_files;f;f=f->next) { + if (f->fnum == fnum) { + return f; + } + } + return NULL; +} + +/* + open a file + TODO: this is a temporary implementation derived from the simple backend + its purpose is to allow other tests to run +*/ +NTSTATUS pvfs_open(struct smbsrv_request *req, union smb_open *io) +{ + struct pvfs_state *pvfs = req->tcon->ntvfs_private; + int fd, flags; + struct pvfs_filename *name; + struct pvfs_file *f; + NTSTATUS status; + + if (io->generic.level != RAW_OPEN_GENERIC) { + return ntvfs_map_open(req, io); + } + + /* resolve the cifs name to a posix name */ + status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, + PVFS_RESOLVE_NO_WILDCARD, &name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (io->generic.in.open_disposition) { + case NTCREATEX_DISP_SUPERSEDE: + case NTCREATEX_DISP_OVERWRITE_IF: + flags = O_CREAT | O_TRUNC; + break; + case NTCREATEX_DISP_OPEN: + case NTCREATEX_DISP_OVERWRITE: + flags = 0; + break; + case NTCREATEX_DISP_CREATE: + flags = O_CREAT | O_EXCL; + break; + case NTCREATEX_DISP_OPEN_IF: + flags = O_CREAT; + break; + default: + flags = 0; + break; + } + + flags |= O_RDWR; + + if (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; + } + } + +do_open: + fd = open(name->full_name, flags, 0644); + if (fd == -1) { + if (errno == 0) + errno = ENOENT; + return pvfs_map_errno(pvfs,errno); + } + + f = talloc_p(pvfs, struct pvfs_file); + if (f == NULL) { + close(fd); + return NT_STATUS_NO_MEMORY; + } + + /* re-resolve the open fd */ + status = pvfs_resolve_name_fd(pvfs, fd, name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + f->fnum = fd; + f->fd = fd; + f->name = talloc_steal(f, name); + + DLIST_ADD(pvfs->open_files, 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 = name->dos.alloc_size; + io->generic.out.size = name->st.st_size; + io->generic.out.attrib = name->dos.attrib; + io->generic.out.is_directory = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)?1:0; + + return NT_STATUS_OK; +} + + +/* + close a file +*/ +NTSTATUS pvfs_close(struct smbsrv_request *req, union smb_close *io) +{ + struct pvfs_state *pvfs = req->tcon->ntvfs_private; + struct pvfs_file *f; + + if (io->generic.level != RAW_CLOSE_CLOSE) { + /* we need a mapping function */ + return NT_STATUS_INVALID_LEVEL; + } + + f = pvfs_find_fd(pvfs, io->close.in.fnum); + if (!f) { + return NT_STATUS_INVALID_HANDLE; + } + + if (close(f->fd) != 0) { + return pvfs_map_errno(pvfs, errno); + } + + DLIST_REMOVE(pvfs->open_files, f); + talloc_free(f); + + return NT_STATUS_OK; +} + |