diff options
-rw-r--r-- | source4/ntvfs/config.mk | 7 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_fileinfo.c | 76 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_fsinfo.c | 65 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_mkdir.c | 85 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 175 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_qfileinfo.c | 129 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_read.c | 57 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_resolve.c | 46 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_search.c | 51 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_setfileinfo.c | 69 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_shortname.c | 7 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_unlink.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_write.c | 79 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.c | 112 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 50 |
15 files changed, 824 insertions, 186 deletions
diff --git a/source4/ntvfs/config.mk b/source4/ntvfs/config.mk index 2298fcd554..416b14a3b3 100644 --- a/source4/ntvfs/config.mk +++ b/source4/ntvfs/config.mk @@ -50,6 +50,13 @@ ADD_OBJ_FILES = \ ntvfs/posix/pvfs_dirlist.o \ ntvfs/posix/pvfs_fileinfo.o \ ntvfs/posix/pvfs_unlink.o \ + ntvfs/posix/pvfs_mkdir.o \ + ntvfs/posix/pvfs_open.o \ + ntvfs/posix/pvfs_read.o \ + ntvfs/posix/pvfs_write.o \ + ntvfs/posix/pvfs_fsinfo.o \ + ntvfs/posix/pvfs_qfileinfo.o \ + ntvfs/posix/pvfs_setfileinfo.o \ ntvfs/posix/pvfs_resolve.o \ ntvfs/posix/pvfs_shortname.o # End MODULE ntvfs_posix diff --git a/source4/ntvfs/posix/pvfs_fileinfo.c b/source4/ntvfs/posix/pvfs_fileinfo.c index 83a577d092..c5a3a1c666 100644 --- a/source4/ntvfs/posix/pvfs_fileinfo.c +++ b/source4/ntvfs/posix/pvfs_fileinfo.c @@ -87,42 +87,54 @@ static uint32_t unix_filetype(mode_t mode) } -/* - return all basic information about a file. This call is case-sensitive (it assumes that the - pathnames given have already had case conversion) -*/ -NTSTATUS pvfs_relative_file_info_cs(struct pvfs_state *pvfs, const char *dir_path, - const char *name, struct pvfs_file_info *finfo) +/**************************************************************************** + Change a unix mode to a dos mode. +****************************************************************************/ +static uint32_t dos_mode_from_stat(struct pvfs_state *pvfs, struct stat *st) { - char *full_name = NULL; - struct stat st; - - asprintf(&full_name, "%s/%s", dir_path, name); - if (full_name == NULL) { - return NT_STATUS_NO_MEMORY; + int result = 0; + + if ((st->st_mode & S_IWUSR) == 0) + result |= FILE_ATTRIBUTE_READONLY; + + if ((pvfs->flags & PVFS_FLAG_MAP_ARCHIVE) && ((st->st_mode & S_IXUSR) != 0)) + result |= FILE_ATTRIBUTE_ARCHIVE; + + if ((pvfs->flags & PVFS_FLAG_MAP_SYSTEM) && ((st->st_mode & S_IXGRP) != 0)) + result |= FILE_ATTRIBUTE_SYSTEM; + + if ((pvfs->flags & PVFS_FLAG_MAP_HIDDEN) && ((st->st_mode & S_IXOTH) != 0)) + result |= FILE_ATTRIBUTE_HIDDEN; + + if (S_ISDIR(st->st_mode)) + result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY); + +#if defined (HAVE_STAT_ST_BLOCKS) && defined (HAVE_STAT_ST_BLKSIZE) + if (st->st_size > st->st_blocks * (off_t)st->st_blksize) { + result |= FILE_ATTRIBUTE_SPARSE; } +#endif + + return result; +} + - if (stat(full_name, &st) == -1) { - free(full_name); - return pvfs_map_errno(pvfs, errno); - } - unix_to_nt_time(&finfo->create_time, st.st_ctime); - unix_to_nt_time(&finfo->access_time, st.st_atime); - unix_to_nt_time(&finfo->write_time, st.st_mtime); - unix_to_nt_time(&finfo->change_time, st.st_mtime); - finfo->attrib = 0; - finfo->alloc_size = st.st_size; - finfo->size = st.st_size; - finfo->nlink = st.st_nlink; - finfo->ea_size = 0; - finfo->file_id = st.st_ino; - finfo->unix_uid = st.st_uid; - finfo->unix_gid = st.st_gid; - finfo->unix_file_type = unix_filetype(st.st_mode); - finfo->unix_dev_major = unix_dev_major(st.st_rdev); - finfo->unix_dev_minor = unix_dev_minor(st.st_rdev); - finfo->unix_permissions = unix_perms_to_wire(st.st_mode); +/* + fill in the dos file attributes for a file +*/ +NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name) +{ + /* for now just use the simple samba mapping */ + unix_to_nt_time(&name->dos.create_time, name->st.st_ctime); + unix_to_nt_time(&name->dos.access_time, name->st.st_atime); + unix_to_nt_time(&name->dos.write_time, name->st.st_mtime); + unix_to_nt_time(&name->dos.change_time, name->st.st_mtime); + name->dos.attrib = dos_mode_from_stat(pvfs, &name->st); + name->dos.alloc_size = name->st.st_size; + name->dos.nlink = name->st.st_nlink; + name->dos.ea_size = 0; + name->dos.file_id = (((uint64_t)name->st.st_dev)<<32) | name->st.st_ino; return NT_STATUS_OK; } diff --git a/source4/ntvfs/posix/pvfs_fsinfo.c b/source4/ntvfs/posix/pvfs_fsinfo.c new file mode 100644 index 0000000000..826e331b84 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_fsinfo.c @@ -0,0 +1,65 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - fsinfo + + 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" + + +/* + return filesystem space info +*/ +NTSTATUS pvfs_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs) +{ + struct pvfs_state *pvfs = req->tcon->ntvfs_private; + struct stat st; + + if (fs->generic.level != RAW_QFS_GENERIC) { + return ntvfs_map_fsinfo(req, fs); + } + + if (sys_fsusage(pvfs->base_directory, + &fs->generic.out.blocks_free, + &fs->generic.out.blocks_total) == -1) { + return pvfs_map_errno(pvfs, errno); + } + + fs->generic.out.block_size = 512; + + if (stat(pvfs->base_directory, &st) != 0) { + return NT_STATUS_DISK_CORRUPT_ERROR; + } + + fs->generic.out.fs_id = st.st_ino; + unix_to_nt_time(&fs->generic.out.create_time, st.st_ctime); + fs->generic.out.serial_number = st.st_ino; + fs->generic.out.fs_attr = 0; + fs->generic.out.max_file_component_length = 255; + fs->generic.out.device_type = 0; + fs->generic.out.device_characteristics = 0; + fs->generic.out.quota_soft = 0; + fs->generic.out.quota_hard = 0; + fs->generic.out.quota_flags = 0; + fs->generic.out.volume_name = talloc_strdup(req, pvfs->share_name); + fs->generic.out.fs_type = req->tcon->fs_type; + + return NT_STATUS_OK; +} diff --git a/source4/ntvfs/posix/pvfs_mkdir.c b/source4/ntvfs/posix/pvfs_mkdir.c new file mode 100644 index 0000000000..4881326ecb --- /dev/null +++ b/source4/ntvfs/posix/pvfs_mkdir.c @@ -0,0 +1,85 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - mkdir and rmdir + + 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" + +/* + create a directory +*/ +NTSTATUS pvfs_mkdir(struct smbsrv_request *req, union smb_mkdir *md) +{ + struct pvfs_state *pvfs = req->tcon->ntvfs_private; + NTSTATUS status; + struct pvfs_filename *name; + + if (md->generic.level != RAW_MKDIR_MKDIR) { + return NT_STATUS_INVALID_LEVEL; + } + + /* resolve the cifs name to a posix name */ + status = pvfs_resolve_name(pvfs, req, md->mkdir.in.path, + PVFS_RESOLVE_NO_WILDCARD, &name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (name->exists) { + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + /* TODO: this is a temporary implementation to allow other + tests to run */ + + if (mkdir(name->full_name, 0777) == -1) { + return pvfs_map_errno(pvfs, errno); + } + + return NT_STATUS_OK; +} + +/* + remove a directory +*/ +NTSTATUS pvfs_rmdir(struct smbsrv_request *req, struct smb_rmdir *rd) +{ + struct pvfs_state *pvfs = req->tcon->ntvfs_private; + NTSTATUS status; + struct pvfs_filename *name; + + /* resolve the cifs name to a posix name */ + status = pvfs_resolve_name(pvfs, req, rd->in.path, + PVFS_RESOLVE_NO_WILDCARD, &name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!name->exists) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (rmdir(name->full_name) == -1) { + return pvfs_map_errno(pvfs, errno); + } + + return NT_STATUS_OK; +} 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; +} + diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c new file mode 100644 index 0000000000..691ba91532 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -0,0 +1,129 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - read + + 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" + + +/* + approximately map a struct pvfs_filename to a generic fileinfo struct +*/ +static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, + struct pvfs_filename *name, union smb_fileinfo *info) +{ + info->generic.out.create_time = name->dos.create_time; + info->generic.out.access_time = name->dos.access_time; + info->generic.out.write_time = name->dos.write_time; + info->generic.out.change_time = name->dos.change_time; + + info->generic.out.alloc_size = name->dos.alloc_size; + info->generic.out.size = name->st.st_size; + info->generic.out.attrib = name->dos.attrib; + info->generic.out.nlink = name->dos.nlink; + info->generic.out.directory = (name->dos.attrib&FILE_ATTRIBUTE_DIRECTORY)?1:0; + info->generic.out.file_id = name->dos.file_id; + + /* REWRITE: TODO stuff in here */ + info->generic.out.delete_pending = 0; + info->generic.out.ea_size = 0; + info->generic.out.num_eas = 0; + info->generic.out.fname.s = name->original_name; + info->generic.out.alt_fname.s = pvfs_short_name(pvfs, name); + info->generic.out.compressed_size = name->st.st_size; + info->generic.out.format = 0; + info->generic.out.unit_shift = 0; + info->generic.out.chunk_shift = 0; + info->generic.out.cluster_shift = 0; + + info->generic.out.access_flags = 0; + info->generic.out.position = 0; + info->generic.out.mode = 0; + info->generic.out.alignment_requirement = 0; + info->generic.out.reparse_tag = 0; + + /* setup a single data stream */ + info->generic.out.num_streams = 1; + info->generic.out.streams = talloc_array_p(mem_ctx, + struct stream_struct, + info->generic.out.num_streams); + if (!info->generic.out.streams) { + return NT_STATUS_NO_MEMORY; + } + info->generic.out.streams[0].size = name->st.st_size; + info->generic.out.streams[0].alloc_size = name->st.st_size; + info->generic.out.streams[0].stream_name.s = talloc_strdup(mem_ctx, "::$DATA"); + + return NT_STATUS_OK; +} + +/* + return info on a pathname +*/ +NTSTATUS pvfs_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info) +{ + struct pvfs_state *pvfs = req->tcon->ntvfs_private; + struct pvfs_filename *name; + NTSTATUS status; + + if (info->generic.level != RAW_FILEINFO_GENERIC) { + return ntvfs_map_qpathinfo(req, info); + } + + /* resolve the cifs name to a posix name */ + status = pvfs_resolve_name(pvfs, req, info->generic.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; + } + + return pvfs_map_fileinfo(pvfs, req, name, info); +} + +/* + query info on a open file +*/ +NTSTATUS pvfs_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info) +{ + struct pvfs_state *pvfs = req->tcon->ntvfs_private; + struct pvfs_file *f; + NTSTATUS status; + + if (info->generic.level != RAW_FILEINFO_GENERIC) { + return ntvfs_map_qfileinfo(req, info); + } + + f = pvfs_find_fd(pvfs, info->generic.in.fnum); + if (!f) { + return NT_STATUS_INVALID_HANDLE; + } + + /* update the file information */ + status = pvfs_resolve_name_fd(pvfs, f->fd, f->name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return pvfs_map_fileinfo(pvfs, req, f->name, info); +} diff --git a/source4/ntvfs/posix/pvfs_read.c b/source4/ntvfs/posix/pvfs_read.c new file mode 100644 index 0000000000..d30645e76d --- /dev/null +++ b/source4/ntvfs/posix/pvfs_read.c @@ -0,0 +1,57 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - read + + 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" + +/* + read from a file +*/ +NTSTATUS pvfs_read(struct smbsrv_request *req, union smb_read *rd) +{ + struct pvfs_private *pvfs = req->tcon->ntvfs_private; + ssize_t ret; + struct pvfs_file *f; + + if (rd->generic.level != RAW_READ_READX) { + return NT_STATUS_NOT_SUPPORTED; + } + + f = pvfs_find_fd(pvfs, rd->readx.in.fnum); + if (!f) { + return NT_STATUS_INVALID_HANDLE; + } + + ret = pread(f->fd, + rd->readx.out.data, + rd->readx.in.maxcnt, + rd->readx.in.offset); + if (ret == -1) { + return pvfs_map_errno(pvfs, errno); + } + + rd->readx.out.nread = ret; + rd->readx.out.remaining = 0; /* should fill this in? */ + rd->readx.out.compaction_mode = 0; + + return NT_STATUS_OK; +} diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c index 66e7a5d103..5c535c9880 100644 --- a/source4/ntvfs/posix/pvfs_resolve.c +++ b/source4/ntvfs/posix/pvfs_resolve.c @@ -116,11 +116,13 @@ static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename * } if (!de) { - closedir(dir); - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + if (i < num_components-1) { + closedir(dir); + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + } else { + components[i] = talloc_strdup(name, de->d_name); } - - components[i] = talloc_strdup(name, de->d_name); test_name = talloc_asprintf(name, "%s/%s", partial_name, components[i]); talloc_free(partial_name); partial_name = test_name; @@ -137,6 +139,10 @@ static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename * talloc_free(name->full_name); name->full_name = partial_name; + if (name->exists) { + return pvfs_fill_dos_info(pvfs, name); + } + return NT_STATUS_OK; } @@ -154,7 +160,7 @@ static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name, { char *ret, *p; - name->original_name = cifs_name; + name->original_name = talloc_strdup(name, cifs_name); name->stream_name = NULL; name->has_wildcard = False; @@ -252,7 +258,7 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, /* if we can stat() the full name now then we are done */ if (stat((*name)->full_name, &(*name)->st) == 0) { (*name)->exists = True; - return NT_STATUS_OK; + return pvfs_fill_dos_info(pvfs, *name); } /* the filesystem might be case insensitive, in which @@ -280,12 +286,14 @@ NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, const char *unix_dir, const char *fname, struct pvfs_filename **name) { + NTSTATUS status; + *name = talloc_p(mem_ctx, struct pvfs_filename); if (*name == NULL) { return NT_STATUS_NO_MEMORY; } - (*name)->full_name = talloc_asprintf(mem_ctx, "%s/%s", unix_dir, fname); + (*name)->full_name = talloc_asprintf(*name, "%s/%s", unix_dir, fname); if ((*name)->full_name == NULL) { return NT_STATUS_NO_MEMORY; } @@ -296,8 +304,28 @@ NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, (*name)->exists = True; (*name)->has_wildcard = False; - (*name)->original_name = fname; + (*name)->original_name = talloc_strdup(*name, fname); (*name)->stream_name = NULL; - return NT_STATUS_OK; + status = pvfs_fill_dos_info(pvfs, *name); + + return status; +} + + +/* + fill in the pvfs_filename info for an open file, given the current + info for a (possibly) non-open file. This is used by places that need + to update the pvfs_filename stat information, and by pvfs_open() +*/ +NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd, + struct pvfs_filename *name) +{ + if (fstat(fd, &name->st) == -1) { + return NT_STATUS_INVALID_HANDLE; + } + + name->exists = True; + + return pvfs_fill_dos_info(pvfs, name); } diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c index da47bba75a..548d7ad77e 100644 --- a/source4/ntvfs/posix/pvfs_search.c +++ b/source4/ntvfs/posix/pvfs_search.c @@ -29,45 +29,36 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs, enum smb_search_level level, const char *unix_path, - const char *name, + const char *fname, uint16_t search_attrib, uint32_t dir_index, union smb_search_data *file) { - struct pvfs_file_info *finfo; + struct pvfs_filename *name; NTSTATUS status; - finfo = talloc_p((TALLOC_CTX *)file, struct pvfs_file_info); - if (!finfo) { - return NT_STATUS_NO_MEMORY; - } - - status = pvfs_relative_file_info_cs(pvfs, unix_path, name, finfo); + status = pvfs_resolve_partial(pvfs, file, unix_path, fname, &name); if (!NT_STATUS_IS_OK(status)) { - talloc_free(finfo); return status; } - + switch (level) { case RAW_SEARCH_BOTH_DIRECTORY_INFO: file->both_directory_info.file_index = dir_index; - file->both_directory_info.create_time = finfo->create_time; - file->both_directory_info.access_time = finfo->access_time; - file->both_directory_info.write_time = finfo->write_time; - file->both_directory_info.change_time = finfo->change_time; - file->both_directory_info.size = finfo->size; - file->both_directory_info.alloc_size = finfo->alloc_size; - file->both_directory_info.attrib = finfo->attrib; - file->both_directory_info.ea_size = finfo->ea_size; - file->both_directory_info.short_name.s = pvfs_short_name(pvfs, (TALLOC_CTX *)file, - unix_path, name); - file->both_directory_info.name.s = name; + file->both_directory_info.create_time = name->dos.create_time; + file->both_directory_info.access_time = name->dos.access_time; + file->both_directory_info.write_time = name->dos.write_time; + file->both_directory_info.change_time = name->dos.change_time; + file->both_directory_info.size = name->st.st_size; + file->both_directory_info.alloc_size = name->dos.alloc_size; + file->both_directory_info.attrib = name->dos.attrib; + file->both_directory_info.ea_size = name->dos.ea_size; + file->both_directory_info.short_name.s = pvfs_short_name(pvfs, name); + file->both_directory_info.name.s = fname; break; } - talloc_free(finfo); - return NT_STATUS_OK; } @@ -104,7 +95,6 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i struct pvfs_dir *dir; struct pvfs_state *pvfs = req->tcon->ntvfs_private; struct pvfs_search_state *search; - union smb_search_data *file; uint16_t max_count, reply_count; uint16_t search_attrib; const char *pattern; @@ -183,17 +173,19 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i max_count = dir->count; } - file = talloc_p(req, union smb_search_data); - if (!file) { - return NT_STATUS_NO_MEMORY; - } - /* note that fill_search_info() can fail, if for example a file disappears during a search or we don't have sufficient permissions to stat() it, or the search_attrib does not match the files attribute. In that case the name is ignored and the search continues. */ for (i=reply_count=0; i < dir->count && reply_count < max_count;i++) { + union smb_search_data *file; + + file = talloc_p(req, union smb_search_data); + if (!file) { + return NT_STATUS_NO_MEMORY; + } + status = fill_search_info(pvfs, io->generic.level, dir->unix_path, dir->names[i], search_attrib, i, file); if (NT_STATUS_IS_OK(status)) { @@ -202,6 +194,7 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i } reply_count++; } + talloc_free(file); } /* not matching any entries is an error */ diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c new file mode 100644 index 0000000000..a271b43d38 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -0,0 +1,69 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - setfileinfo + + 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" + +/* + set info on a open file +*/ +NTSTATUS pvfs_setfileinfo(struct smbsrv_request *req, + union smb_setfileinfo *info) +{ + struct pvfs_private *pvfs = req->tcon->ntvfs_private; + struct utimbuf unix_times; + struct pvfs_file *f; + + f = pvfs_find_fd(pvfs, info->generic.file.fnum); + if (!f) { + return NT_STATUS_INVALID_HANDLE; + } + + switch (info->generic.level) { + case RAW_SFILEINFO_END_OF_FILE_INFO: + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + if (ftruncate(f->fd, + info->end_of_file_info.in.size) != 0) { + return pvfs_map_errno(pvfs, errno); + } + break; + case RAW_SFILEINFO_SETATTRE: + unix_times.actime = info->setattre.in.access_time; + unix_times.modtime = info->setattre.in.write_time; + + if (unix_times.actime == 0 && unix_times.modtime == 0) { + break; + } + + /* set modify time = to access time if modify time was 0 */ + if (unix_times.actime != 0 && unix_times.modtime == 0) { + unix_times.modtime = unix_times.actime; + } + + /* Set the date on this file */ + if (utime(f->name->full_name, &unix_times) == -1) { + return NT_STATUS_ACCESS_DENIED; + } + break; + } + return NT_STATUS_OK; +} diff --git a/source4/ntvfs/posix/pvfs_shortname.c b/source4/ntvfs/posix/pvfs_shortname.c index b68f60d5e7..fe6fd8e030 100644 --- a/source4/ntvfs/posix/pvfs_shortname.c +++ b/source4/ntvfs/posix/pvfs_shortname.c @@ -26,9 +26,10 @@ /* return the short name for a given entry in a directory + TODO: this is obviously not very useful in its current form ! */ -char *pvfs_short_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, - const char *unix_path, const char *name) +char *pvfs_short_name(struct pvfs_state *pvfs, struct pvfs_filename *name) { - return talloc_strndup(mem_ctx, name, 12); + char *p = strrchr(name->full_name, '/'); + return talloc_strndup(name, p+1, 12); } diff --git a/source4/ntvfs/posix/pvfs_unlink.c b/source4/ntvfs/posix/pvfs_unlink.c index d93c15f19e..98151d4e75 100644 --- a/source4/ntvfs/posix/pvfs_unlink.c +++ b/source4/ntvfs/posix/pvfs_unlink.c @@ -63,8 +63,8 @@ static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, */ NTSTATUS pvfs_unlink(struct smbsrv_request *req, struct smb_unlink *unl) { - struct pvfs_dir *dir; struct pvfs_state *pvfs = req->tcon->ntvfs_private; + struct pvfs_dir *dir; NTSTATUS status; uint32_t i, total_deleted=0; struct pvfs_filename *name; diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c new file mode 100644 index 0000000000..4194ced431 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_write.c @@ -0,0 +1,79 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - write + + 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" + + +/* + write to a file +*/ +NTSTATUS pvfs_write(struct smbsrv_request *req, union smb_write *wr) +{ + struct pvfs_private *pvfs = req->tcon->ntvfs_private; + ssize_t ret; + struct pvfs_file *f; + + switch (wr->generic.level) { + case RAW_WRITE_WRITEX: + f = pvfs_find_fd(pvfs, wr->writex.in.fnum); + if (!f) { + return NT_STATUS_INVALID_HANDLE; + } + 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, 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 { + 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; + + return NT_STATUS_OK; + } + + return NT_STATUS_NOT_SUPPORTED; +} diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index 86179debc5..b2c9d81086 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -29,6 +29,22 @@ /* + setup config options for a posix share +*/ +static void pvfs_setup_options(struct pvfs_state *pvfs) +{ + int snum = pvfs->tcon->service; + + if (lp_map_hidden(snum)) pvfs->flags |= PVFS_FLAG_MAP_HIDDEN; + if (lp_map_archive(snum)) pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE; + if (lp_map_system(snum)) pvfs->flags |= PVFS_FLAG_MAP_SYSTEM; + if (lp_readonly(snum)) pvfs->flags |= PVFS_FLAG_READONLY; + + pvfs->share_name = talloc_strdup(pvfs, lp_servicename(snum)); +} + + +/* connect to a share - used when a tree_connect operation comes in. For a disk based backend we needs to ensure that the base directory exists (tho it doesn't need to be accessible by the user, @@ -53,6 +69,7 @@ static NTSTATUS pvfs_connect(struct smbsrv_request *req, const char *sharename) base_directory = talloc_strdup(pvfs, lp_pathname(tcon->service)); trim_string(base_directory, NULL, "/"); + pvfs->tcon = tcon; pvfs->base_directory = base_directory; /* the directory must exist. Note that we deliberately don't @@ -67,6 +84,8 @@ static NTSTATUS pvfs_connect(struct smbsrv_request *req, const char *sharename) tcon->dev_type = talloc_strdup(tcon, "A:"); tcon->ntvfs_private = pvfs; + pvfs_setup_options(pvfs); + return NT_STATUS_OK; } @@ -114,52 +133,6 @@ static NTSTATUS pvfs_chkpath(struct smbsrv_request *req, struct smb_chkpath *cp) } /* - return info on a pathname -*/ -static NTSTATUS pvfs_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info) -{ - DEBUG(0,("pvfs_qpathinfo not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* - query info on a open file -*/ -static NTSTATUS pvfs_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info) -{ - DEBUG(0,("pvfs_qfileinfo not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - - -/* - open a file -*/ -static NTSTATUS pvfs_open(struct smbsrv_request *req, union smb_open *io) -{ - DEBUG(0,("pvfs_open not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* - create a directory -*/ -static NTSTATUS pvfs_mkdir(struct smbsrv_request *req, union smb_mkdir *md) -{ - DEBUG(0,("pvfs_mkdir not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* - remove a directory -*/ -static NTSTATUS pvfs_rmdir(struct smbsrv_request *req, struct smb_rmdir *rd) -{ - DEBUG(0,("pvfs_rmdir not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* rename a set of files */ static NTSTATUS pvfs_rename(struct smbsrv_request *req, union smb_rename *ren) @@ -178,24 +151,6 @@ static NTSTATUS pvfs_copy(struct smbsrv_request *req, struct smb_copy *cp) } /* - read from a file -*/ -static NTSTATUS pvfs_read(struct smbsrv_request *req, union smb_read *rd) -{ - DEBUG(0,("pvfs_read not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* - write to a file -*/ -static NTSTATUS pvfs_write(struct smbsrv_request *req, union smb_write *wr) -{ - DEBUG(0,("pvfs_write not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* seek in a file */ static NTSTATUS pvfs_seek(struct smbsrv_request *req, struct smb_seek *io) @@ -214,15 +169,6 @@ static NTSTATUS pvfs_flush(struct smbsrv_request *req, struct smb_flush *io) } /* - close a file -*/ -static NTSTATUS pvfs_close(struct smbsrv_request *req, union smb_close *io) -{ - DEBUG(0,("pvfs_close not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* exit - closing files? */ static NTSTATUS pvfs_exit(struct smbsrv_request *req) @@ -250,26 +196,6 @@ static NTSTATUS pvfs_setpathinfo(struct smbsrv_request *req, union smb_setfilein } /* - set info on a open file -*/ -static NTSTATUS pvfs_setfileinfo(struct smbsrv_request *req, - union smb_setfileinfo *info) -{ - DEBUG(0,("pvfs_setfileinfo not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - - -/* - return filesystem space info -*/ -static NTSTATUS pvfs_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs) -{ - DEBUG(0,("pvfs_fsinfo not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* return print queue info */ static NTSTATUS pvfs_lpq(struct smbsrv_request *req, union smb_lpq *lpq) diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index 1e6d763fc1..12955ced5c 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -26,8 +26,10 @@ /* this is the private structure for the posix vfs backend. It is used to hold per-connection (per tree connect) state information */ struct pvfs_state { + struct smbsrv_tcon *tcon; const char *base_directory; + const char *share_name; uint_t flags; struct { @@ -45,6 +47,22 @@ struct pvfs_state { the initial search attributes */ uint16_t search_attrib; } search; + + struct pvfs_file *open_files; +}; + + +/* this is the basic information needed about a file from the filesystem */ +struct pvfs_dos_fileinfo { + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint32_t attrib; + uint64_t alloc_size; + uint32_t nlink; + uint32_t ea_size; + uint64_t file_id; }; /* @@ -58,6 +76,7 @@ struct pvfs_filename { BOOL has_wildcard; BOOL exists; struct stat st; + struct pvfs_dos_fileinfo dos; }; @@ -79,32 +98,25 @@ struct pvfs_search_state { struct pvfs_dir *dir; }; - -/* this is the basic information needed about a file from the filesystem */ -struct pvfs_file_info { - NTTIME create_time; - NTTIME access_time; - NTTIME write_time; - NTTIME change_time; - uint32_t attrib; - uint64_t alloc_size; - uint64_t size; - uint32_t nlink; - uint32_t ea_size; - uint64_t file_id; - uint64_t unix_uid; - uint64_t unix_gid; - uint32_t unix_file_type; - uint64_t unix_dev_major; - uint64_t unix_dev_minor; - uint64_t unix_permissions; +/* open file state - this is a temporary implementation + to allow some tests to work */ +struct pvfs_file { + struct pvfs_file *next, *prev; + int fd; + uint16_t fnum; + struct pvfs_filename *name; }; + /* flags to pvfs_resolve_name() */ #define PVFS_RESOLVE_NO_WILDCARD (1<<0) #define PVFS_RESOLVE_STREAMS (1<<1) /* flags in pvfs->flags */ #define PVFS_FLAG_CI_FILESYSTEM (1<<0) /* the filesystem is case insensitive */ +#define PVFS_FLAG_MAP_ARCHIVE (1<<1) +#define PVFS_FLAG_MAP_SYSTEM (1<<2) +#define PVFS_FLAG_MAP_HIDDEN (1<<3) +#define PVFS_FLAG_READONLY (1<<4) #endif /* _VFS_POSIX_H_ */ |