diff options
-rw-r--r-- | source/lib/doscalls.c | 16 | ||||
-rw-r--r-- | source/lib/util.c | 4 | ||||
-rw-r--r-- | source/smbd/vfs-wrap.c | 295 | ||||
-rw-r--r-- | source/smbd/vfs.c | 450 |
4 files changed, 761 insertions, 4 deletions
diff --git a/source/lib/doscalls.c b/source/lib/doscalls.c index 4ce84cbca24..2bd68d30974 100644 --- a/source/lib/doscalls.c +++ b/source/lib/doscalls.c @@ -52,18 +52,23 @@ int dos_open(char *fname,int flags,mode_t mode) } /******************************************************************* - Opendir() wrapper that calls dos_to_unix. + Opendir() wrapper that calls dos_to_unix. Should use the + vfs_ops->opendir() function instead. ********************************************************************/ +#if 0 DIR *dos_opendir(char *dname) { return(opendir(dos_to_unix(dname,False))); } +#endif /******************************************************************* - Readdirname() wrapper that calls unix_to_dos. + Readdirname() wrapper that calls unix_to_dos. Should use the + vfs_readdirname() function instead. ********************************************************************/ +#if 0 char *dos_readdirname(DIR *p) { char *dname = readdirname(p); @@ -74,6 +79,7 @@ char *dos_readdirname(DIR *p) unix_to_dos(dname, True); return(dname); } +#endif /******************************************************************* A chown() wrapper that calls dos_to_unix. @@ -106,6 +112,8 @@ int dos_lstat(char *fname,SMB_STRUCT_STAT *sbuf) Mkdir() that calls dos_to_unix. Cope with UNIXes that don't allow high order mode bits on mkdir. Patch from gcarter@lanier.com. + Don't use this call unless you really want to access a file on + disk. Use the vfs_ops.mkdir() function instead. ********************************************************************/ int dos_mkdir(char *dname,mode_t mode) @@ -289,13 +297,15 @@ char *dos_getwd(char *unix_path) } /******************************************************************* - Check if a DOS file exists. + Check if a DOS file exists. Use vfs_file_exist function instead. ********************************************************************/ +#if 0 BOOL dos_file_exist(char *fname,SMB_STRUCT_STAT *sbuf) { return file_exist(dos_to_unix(fname, False), sbuf); } +#endif /******************************************************************* Check if a DOS directory exists. diff --git a/source/lib/util.c b/source/lib/util.c index 0db12e92c6c..71f440eae52 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -334,7 +334,7 @@ int name_mangle( char *In, char *Out, char name_type ) } /* name_mangle */ /******************************************************************* - check if a file exists + check if a file exists - call vfs_file_exist for samba files ********************************************************************/ BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf) { @@ -1562,6 +1562,8 @@ set the length of a file from a filedescriptor. Returns 0 on success, -1 on failure. ****************************************************************************/ +/* tpot vfs need to recode this function */ + int set_filelen(int fd, SMB_OFF_T len) { /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c new file mode 100644 index 00000000000..24e45a6d24a --- /dev/null +++ b/source/smbd/vfs-wrap.c @@ -0,0 +1,295 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. +s Wrap disk only vfs functions to sidestep dodgy compilers. + Copyright (C) Tim Potter 1998 + + 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 "includes.h" + +/* Check for NULL pointer parameters in vfswrap_* functions */ + +#define VFS_CHECK_NULL + +/* We don't want to have NULL function pointers lying around. Someone + is sure to try and execute them. These stubs are used to prevent + this possibility. */ + +int vfswrap_dummy_connect(struct vfs_connection_struct *conn, char *service, + char *user) +{ + return 0; /* Return >= 0 for success */ +} + +void vfswrap_dummy_disconnect(void) +{ +} + +/* Disk operations */ + +SMB_BIG_UINT vfswrap_disk_free(char *path, BOOL small_query, SMB_BIG_UINT *bsize, + SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +{ + SMB_BIG_UINT result; + +#ifdef VFS_CHECK_NULL + if ((path == NULL) || (bsize == NULL) || (dfree == NULL) || + (dsize == NULL)) { + + smb_panic("NULL pointer passed to vfswrap_disk_free() function\n"); + } +#endif + + result = sys_disk_free(path, small_query, bsize, dfree, dsize); + return result; +} + +/* Directory operations */ + +DIR *vfswrap_opendir(char *fname) +{ + DIR *result; + +#ifdef VFS_CHECK_NULL + if (fname == NULL) { + smb_panic("NULL pointer passed to vfswrap_opendir()\n"); + } +#endif + + result = opendir(fname); + return result; +} + +struct dirent *vfswrap_readdir(DIR *dirp) +{ + struct dirent *result; + +#ifdef VFS_CHECK_NULL + if (dirp == NULL) { + smb_panic("NULL pointer passed to vfswrap_readdir()\n"); + } +#endif + + result = readdir(dirp); + return result; +} + +int vfswrap_mkdir(char *path, mode_t mode) +{ + int result; + +#ifdef VFS_CHECK_NULL + if (path == NULL) { + smb_panic("NULL pointer passed to vfswrap_mkdir()\n"); + } +#endif + + result = mkdir(path, mode); + return result; +} + +int vfswrap_rmdir(char *path) +{ + int result; + +#ifdef VFS_CHECK_NULL + if (path == NULL) { + smb_panic("NULL pointer passed to vfswrap_rmdir()\n"); + } +#endif + + result = rmdir(path); + return result; +} + +int vfswrap_closedir(DIR *dirp) +{ + int result; + +#ifdef VFS_CHECK_NULL + if (dirp == NULL) { + smb_panic("NULL pointer passed to vfswrap_closedir()\n"); + } +#endif + + result = closedir(dirp); + return result; +} + +/* File operations */ + +int vfswrap_open(char *fname, int flags, mode_t mode) +{ + int result; + +#ifdef VFS_CHECK_NULL + if (fname == NULL) { + smb_panic("NULL pointer passed to vfswrap_open()\n"); + } +#endif + + result = sys_open(fname, flags, mode); + return result; +} + +int vfswrap_close(int fd) +{ + int result; + + result = close(fd); + return result; +} + +ssize_t vfswrap_read(int fd, char *data, size_t n) +{ + ssize_t result; + +#ifdef VFS_CHECK_NULL + if (data == NULL) { + smb_panic("NULL pointer passed to vfswrap_read()\n"); + } +#endif + + result = read(fd, data, n); + return result; +} + +ssize_t vfswrap_write(int fd, char *data, size_t n) +{ + ssize_t result; + +#ifdef VFS_CHECK_NULL + if (data == NULL) { + smb_panic("NULL pointer passed to vfswrap_write()\n"); + } +#endif + + result = write(fd, data, n); + return result; +} + +SMB_OFF_T vfswrap_lseek(int filedes, SMB_OFF_T offset, int whence) +{ + SMB_OFF_T result; + + result = sys_lseek(filedes, offset, whence); + return result; +} + +int vfswrap_rename(char *old, char *new) +{ + int result; + +#ifdef VFS_CHECK_NULL + if ((old == NULL) || (new == NULL)) { + smb_panic("NULL pointer passed to vfswrap_rename()\n"); + } +#endif + + result = rename(old, new); + return result; +} + +void vfswrap_fsync(int fd) +{ + fsync(fd); +} + +int vfswrap_stat(char *fname, SMB_STRUCT_STAT *sbuf) +{ + int result; + +#ifdef VFS_CHECK_NULL + if ((fname == NULL) || (sbuf == NULL)) { + smb_panic("NULL pointer passed to vfswrap_stat()\n"); + } +#endif + + result = sys_stat(fname, sbuf); + return result; +} + +int vfswrap_fstat(int fd, SMB_STRUCT_STAT *sbuf) +{ + int result; + +#ifdef VFS_CHECK_NULL + if (sbuf == NULL) { + smb_panic("NULL pointer passed to vfswrap_fstat()\n"); + } +#endif + + result = sys_fstat(fd, sbuf); + return result; +} + +int vfswrap_lstat(char *path, + SMB_STRUCT_STAT *sbuf) +{ + int result; + +#ifdef VFS_CHECK_NULL + if ((path == NULL) || (sbuf == NULL)) { + smb_panic("NULL pointer passed to vfswrap_lstat()\n"); + } +#endif + + result = sys_lstat(path, sbuf); + return result; +} + +int vfswrap_unlink(char *path) +{ + int result; + +#ifdef VFS_CHECK_NULL + if (path == NULL) { + smb_panic("NULL pointer passed to vfswrap_unlink()\n"); + } +#endif + + result = unlink(path); + return result; +} + +int vfswrap_chmod(char *path, mode_t mode) +{ + int result; + +#ifdef VFS_CHECK_NULL + if (path == NULL) { + smb_panic("NULL pointer passed to vfswrap_chmod()\n"); + } +#endif + + result = chmod(path, mode); + return result; +} + +int vfswrap_utime(char *path, struct utimbuf *times) +{ + int result; + +#ifdef VFS_CHECK_NULL + if ((path == NULL) || (times == NULL)) { + smb_panic("NULL pointer passed to vfswrap_utime()\n"); + } +#endif + + result = utime(path, times); + return result; +} diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c new file mode 100644 index 00000000000..2f9f847188a --- /dev/null +++ b/source/smbd/vfs.c @@ -0,0 +1,450 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + VFS initialisation and support functions + Copyright (C) Tim Potter 1999 + + 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 "includes.h" + +extern int DEBUGLEVEL; + +/* Some structures to help us initialise the vfs operations table */ + +struct vfs_syminfo { + char *name; + void *fptr; +}; + +/* Default vfs hooks. WARNING: The order of these initialisers is + very important. They must be in the same order as defined in + vfs.h. Change at your own peril. */ + +struct vfs_ops default_vfs_ops = { + + /* Disk operations */ + + vfswrap_dummy_connect, + vfswrap_dummy_disconnect, + vfswrap_disk_free, + + /* Directory operations */ + + vfswrap_opendir, + vfswrap_readdir, + vfswrap_mkdir, + vfswrap_rmdir, + vfswrap_closedir, + + /* File operations */ + + vfswrap_open, + vfswrap_close, + vfswrap_read, + vfswrap_write, + vfswrap_lseek, + vfswrap_rename, + vfswrap_fsync, + vfswrap_stat, + vfswrap_fstat, + vfswrap_lstat, + vfswrap_unlink, + vfswrap_chmod, + vfswrap_utime +}; + +/**************************************************************************** + initialise default vfs hooks +****************************************************************************/ +int vfs_init_default(connection_struct *conn) +{ + DEBUG(3, ("Initialising default vfs hooks\n")); + + memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(conn->vfs_ops)); + return True; +} + +/**************************************************************************** + initialise custom vfs hooks +****************************************************************************/ +#ifdef HAVE_LIBDL +BOOL vfs_init_custom(connection_struct *conn) +{ + void *handle; + struct vfs_ops *ops, *(*fptr)(struct vfs_options *options); + + DEBUG(3, ("Initialising custom vfs hooks from %s\n", + lp_vfsobj(SNUM(conn)))); + + /* Open object file */ + + handle = dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW | RTLD_GLOBAL); + conn->vfs_conn->dl_handle = handle; + + if (!handle) { + DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), + dlerror())); + return False; + } + + /* Get handle on vfs_init() symbol */ + + fptr = dlsym(handle, "vfs_init"); + + if (fptr == NULL) { + DEBUG(0, ("No vfs_init() symbol found in %s\n", + lp_vfsobj(SNUM(conn)))); + return False; + } + + /* Initialise vfs_ops structure */ + + if ((ops = fptr(NULL)) == NULL) { + DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn)))); + return False; + } + + /* Fill in unused operations with default (disk based) ones. + There's probably a neater way to do this then a whole bunch of + if statements. */ + + memcpy(&conn->vfs_ops, ops, sizeof(conn->vfs_ops)); + + if (conn->vfs_ops.connect == NULL) { + conn->vfs_ops.connect = default_vfs_ops.connect; + } + + if (conn->vfs_ops.disconnect == NULL) { + conn->vfs_ops.disconnect = default_vfs_ops.disconnect; + } + + if (conn->vfs_ops.disk_free == NULL) { + conn->vfs_ops.disk_free = default_vfs_ops.disk_free; + } + + if (conn->vfs_ops.opendir == NULL) { + conn->vfs_ops.opendir = default_vfs_ops.opendir; + } + + if (conn->vfs_ops.readdir == NULL) { + conn->vfs_ops.readdir = default_vfs_ops.readdir; + } + + if (conn->vfs_ops.mkdir == NULL) { + conn->vfs_ops.mkdir = default_vfs_ops.mkdir; + } + + if (conn->vfs_ops.rmdir == NULL) { + conn->vfs_ops.rmdir = default_vfs_ops.rmdir; + } + + if (conn->vfs_ops.closedir == NULL) { + conn->vfs_ops.closedir = default_vfs_ops.closedir; + } + + if (conn->vfs_ops.open == NULL) { + conn->vfs_ops.open = default_vfs_ops.open; + } + + if (conn->vfs_ops.close == NULL) { + conn->vfs_ops.close = default_vfs_ops.close; + } + + if (conn->vfs_ops.read == NULL) { + conn->vfs_ops.read = default_vfs_ops.read; + } + + if (conn->vfs_ops.write == NULL) { + conn->vfs_ops.write = default_vfs_ops.write; + } + + if (conn->vfs_ops.lseek == NULL) { + conn->vfs_ops.lseek = default_vfs_ops.lseek; + } + + if (conn->vfs_ops.rename == NULL) { + conn->vfs_ops.rename = default_vfs_ops.rename; + } + + if (conn->vfs_ops.fsync == NULL) { + conn->vfs_ops.fsync = default_vfs_ops.fsync; + } + + if (conn->vfs_ops.stat == NULL) { + conn->vfs_ops.stat = default_vfs_ops.stat; + } + + if (conn->vfs_ops.fstat == NULL) { + conn->vfs_ops.fstat = default_vfs_ops.fstat; + } + + if (conn->vfs_ops.lstat == NULL) { + conn->vfs_ops.lstat = default_vfs_ops.lstat; + } + + if (conn->vfs_ops.unlink == NULL) { + conn->vfs_ops.unlink = default_vfs_ops.unlink; + } + + if (conn->vfs_ops.chmod == NULL) { + conn->vfs_ops.chmod = default_vfs_ops.chmod; + } + + if (conn->vfs_ops.utime == NULL) { + conn->vfs_ops.utime = default_vfs_ops.utime; + } + + return True; +} +#endif + +BOOL vfs_directory_exist(connection_struct *conn, char *dname, + SMB_STRUCT_STAT *st) +{ + SMB_STRUCT_STAT st2; + BOOL ret; + + if (!st) st = &st2; + + if (conn->vfs_ops.stat(dname,st) != 0) + return(False); + + ret = S_ISDIR(st->st_mode); + if(!ret) + errno = ENOTDIR; + + return ret; +} + +/******************************************************************* + check if a vfs file exists +********************************************************************/ +BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf) +{ + SMB_STRUCT_STAT st; + if (!sbuf) sbuf = &st; + + if (conn->vfs_ops.stat(fname,sbuf) != 0) + return(False); + + return(S_ISREG(sbuf->st_mode)); +} + +/**************************************************************************** + write data to a fd on the vfs +****************************************************************************/ +ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N) +{ + size_t total=0; + ssize_t ret; + int fd = fsp->fd_ptr->fd; + + while (total < N) + { + ret = fsp->conn->vfs_ops.write(fd,buffer + total,N - total); + + if (ret == -1) return -1; + if (ret == 0) return total; + + total += ret; + } + return (ssize_t)total; +} + +/**************************************************************************** +transfer some data between two file_struct's +****************************************************************************/ +SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp, + int out_fd, files_struct *out_fsp, + SMB_OFF_T n, char *header, int headlen, int align) +{ + static char *buf=NULL; + static int size=0; + char *buf1,*abuf; + SMB_OFF_T total = 0; + + DEBUG(4,("vfs_transfer_file n=%.0f (head=%d) called\n",(double)n,headlen)); + + /* Check we have at least somewhere to read from */ + + SMB_ASSERT((in_fd != -1) || (in_fsp != NULL)); + + if (size == 0) { + size = lp_readsize(); + size = MAX(size,1024); + } + + while (!buf && size>0) { + buf = (char *)Realloc(buf,size+8); + if (!buf) size /= 2; + } + + if (!buf) { + DEBUG(0,("Can't allocate transfer buffer!\n")); + exit(1); + } + + abuf = buf + (align%8); + + if (header) + n += headlen; + + while (n > 0) + { + int s = (int)MIN(n,(SMB_OFF_T)size); + int ret,ret2=0; + + ret = 0; + + if (header && (headlen >= MIN(s,1024))) { + buf1 = header; + s = headlen; + ret = headlen; + headlen = 0; + header = NULL; + } else { + buf1 = abuf; + } + + if (header && headlen > 0) + { + ret = MIN(headlen,size); + memcpy(buf1,header,ret); + headlen -= ret; + header += ret; + if (headlen <= 0) header = NULL; + } + + if (s > ret) { + ret += in_fsp ? + in_fsp->conn->vfs_ops.read(in_fsp->fd_ptr->fd,buf1+ret,s-ret) : read(in_fd,buf1+ret,s-ret); + } + + if (ret > 0) + { + if (out_fsp) { + ret2 = out_fsp->conn->vfs_ops.write(out_fsp->fd_ptr->fd,buf1,ret); + } else { + ret2= (out_fd != -1) ? write_data(out_fd,buf1,ret) : ret; + } + } + + if (ret2 > 0) total += ret2; + /* if we can't write then dump excess data */ + if (ret2 != ret) + vfs_transfer_file(in_fd, in_fsp, -1,NULL,n-(ret+headlen),NULL,0,0); + + if (ret <= 0 || ret2 != ret) + return(total); + n -= ret; + } + return(total); +} + +/******************************************************************* +a vfs_readdir wrapper which just returns the file name +********************************************************************/ +char *vfs_readdirname(connection_struct *conn, void *p) +{ + struct dirent *ptr; + char *dname; + + if (!p) return(NULL); + + ptr = (struct dirent *)conn->vfs_ops.readdir(p); + if (!ptr) return(NULL); + + dname = ptr->d_name; + +#ifdef NEXT2 + if (telldir(p) < 0) return(NULL); +#endif + +#ifdef HAVE_BROKEN_READDIR + /* using /usr/ucb/cc is BAD */ + dname = dname - 2; +#endif + + { + static pstring buf; + memcpy(buf, dname, NAMLEN(ptr)+1); + unix_to_dos(buf, True); + dname = buf; + } + + unix_to_dos(dname, True); + return(dname); +} + +/*************************************************************************** + handle the interpretation of the vfs option parameter + *************************************************************************/ +static BOOL handle_vfs_option(char *pszParmValue, char **ptr) +{ + struct vfs_options *new_option, **options = (struct vfs_options **)ptr; + int i; + + /* Create new vfs option */ + + new_option = (struct vfs_options *)malloc(sizeof(*new_option)); + if (new_option == NULL) { + return False; + } + + ZERO_STRUCTP(new_option); + + /* Get name and value */ + + new_option->name = strtok(pszParmValue, "="); + + if (new_option->name == NULL) { + return False; + } + + while(isspace(*new_option->name)) { + new_option->name++; + } + + for (i = strlen(new_option->name); i > 0; i--) { + if (!isspace(new_option->name[i - 1])) break; + } + + new_option->name[i] = '\0'; + new_option->name = strdup(new_option->name); + + new_option->value = strtok(NULL, "="); + + if (new_option->value != NULL) { + + while(isspace(*new_option->value)) { + new_option->value++; + } + + for (i = strlen(new_option->value); i > 0; i--) { + if (!isspace(new_option->value[i - 1])) break; + } + + new_option->value[i] = '\0'; + new_option->value = strdup(new_option->value); + } + + /* Add to list */ + + DLIST_ADD(*options, new_option); + + return True; +} |