From: Andrew Tridgell Date: Mon, 20 Sep 2004 07:28:43 +0000 (+0000) Subject: r2436: the second big lump of posix vfs code. X-Git-Url: http://git.samba.org/samba.git/?p=jelmer%2Fsamba4-debian.git;a=commitdiff_plain;h=f2fa7fe565e89360dba3bb5434d3a6a36f398348 r2436: the second big lump of posix vfs code. this is still just a skeleton, and many of the functions are just based on the simple vfs backend, they are there to allow me to run smbtorture tests against the real parts of the posix backend. --- diff --git a/source/ntvfs/config.mk b/source/ntvfs/config.mk index 2298fcd55..416b14a3b 100644 --- a/source/ntvfs/config.mk +++ b/source/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/source/ntvfs/posix/pvfs_fileinfo.c b/source/ntvfs/posix/pvfs_fileinfo.c index 83a577d09..c5a3a1c66 100644 --- a/source/ntvfs/posix/pvfs_fileinfo.c +++ b/source/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/source/ntvfs/posix/pvfs_fsinfo.c b/source/ntvfs/posix/pvfs_fsinfo.c new file mode 100644 index 000000000..826e331b8 --- /dev/null +++ b/source/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/source/ntvfs/posix/pvfs_mkdir.c b/source/ntvfs/posix/pvfs_mkdir.c new file mode 100644 index 000000000..4881326ec --- /dev/null +++ b/source/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/source/ntvfs/posix/pvfs_open.c b/source/ntvfs/posix/pvfs_open.c new file mode 100644 index 000000000..74badb244 --- /dev/null +++ b/source/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/source/ntvfs/posix/pvfs_qfileinfo.c b/source/ntvfs/posix/pvfs_qfileinfo.c new file mode 100644 index 000000000..691ba9153 --- /dev/null +++ b/source/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/source/ntvfs/posix/pvfs_read.c b/source/ntvfs/posix/pvfs_read.c new file mode 100644 index 000000000..d30645e76 --- /dev/null +++ b/source/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/source/ntvfs/posix/pvfs_resolve.c b/source/ntvfs/posix/pvfs_resolve.c index 66e7a5d10..5c535c988 100644 --- a/source/ntvfs/posix/pvfs_resolve.c +++ b/source/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/source/ntvfs/posix/pvfs_search.c b/source/ntvfs/posix/pvfs_search.c index da47bba75..548d7ad77 100644 --- a/source/ntvfs/posix/pvfs_search.c +++ b/source/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/source/ntvfs/posix/pvfs_setfileinfo.c b/source/ntvfs/posix/pvfs_setfileinfo.c new file mode 100644 index 000000000..a271b43d3 --- /dev/null +++ b/source/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/source/ntvfs/posix/pvfs_shortname.c b/source/ntvfs/posix/pvfs_shortname.c index b68f60d5e..fe6fd8e03 100644 --- a/source/ntvfs/posix/pvfs_shortname.c +++ b/source/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/source/ntvfs/posix/pvfs_unlink.c b/source/ntvfs/posix/pvfs_unlink.c index d93c15f19..98151d4e7 100644 --- a/source/ntvfs/posix/pvfs_unlink.c +++ b/source/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/source/ntvfs/posix/pvfs_write.c b/source/ntvfs/posix/pvfs_write.c new file mode 100644 index 000000000..4194ced43 --- /dev/null +++ b/source/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/source/ntvfs/posix/vfs_posix.c b/source/ntvfs/posix/vfs_posix.c index 86179debc..b2c9d8108 100644 --- a/source/ntvfs/posix/vfs_posix.c +++ b/source/ntvfs/posix/vfs_posix.c @@ -28,6 +28,22 @@ #include "vfs_posix.h" +/* + 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 @@ -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; } @@ -113,52 +132,6 @@ static NTSTATUS pvfs_chkpath(struct smbsrv_request *req, struct smb_chkpath *cp) return NT_STATUS_OK; } -/* - 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 */ @@ -177,24 +150,6 @@ static NTSTATUS pvfs_copy(struct smbsrv_request *req, struct smb_copy *cp) return NT_STATUS_NOT_SUPPORTED; } -/* - 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 */ @@ -213,15 +168,6 @@ static NTSTATUS pvfs_flush(struct smbsrv_request *req, struct smb_flush *io) return NT_STATUS_NOT_IMPLEMENTED; } -/* - 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? */ @@ -249,26 +195,6 @@ static NTSTATUS pvfs_setpathinfo(struct smbsrv_request *req, union smb_setfilein return NT_STATUS_NOT_SUPPORTED; } -/* - 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 */ diff --git a/source/ntvfs/posix/vfs_posix.h b/source/ntvfs/posix/vfs_posix.h index 1e6d763fc..12955ced5 100644 --- a/source/ntvfs/posix/vfs_posix.h +++ b/source/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_ */