summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/smbd/vfs.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
new file mode 100644
index 0000000000..937bc1606e
--- /dev/null
+++ b/source3/smbd/vfs.c
@@ -0,0 +1,407 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ vfs initialisation and support functions
+ Copyright (C) Tim Potter 1992-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"
+#include <dlfcn.h>
+
+extern int DEBUGLEVEL;
+
+/* Some structures to help us initialise the vfs operations table */
+
+struct vfs_syminfo {
+ char *name;
+ void *fptr;
+};
+
+struct vfs_ops dl_ops;
+
+struct vfs_syminfo vfs_syminfo[] = {
+
+ /* Global operations */
+
+ {"vfs_init", &dl_ops.init},
+
+ /* Disk operations */
+
+ {"vfs_connect", &dl_ops.connect},
+ {"vfs_disconnect", &dl_ops.disconnect},
+ {"vfs_disk_free", &dl_ops.disk_free},
+
+ /* Directory operations */
+
+ {"vfs_opendir", &dl_ops.opendir},
+ {"vfs_readdir", &dl_ops.readdir},
+ {"vfs_mkdir", &dl_ops.mkdir},
+ {"vfs_rmdir", &dl_ops.rmdir},
+
+ /* File operations */
+
+ {"vfs_open", &dl_ops.open},
+ {"vfs_close", &dl_ops.close},
+ {"vfs_read", &dl_ops.read},
+ {"vfs_write", &dl_ops.write},
+ {"vfs_lseek", &dl_ops.lseek},
+ {"vfs_rename", &dl_ops.rename},
+ {"vfs_sync", &dl_ops.sync},
+ {"vfs_stat", &dl_ops.stat},
+ {"vfs_fstat", &dl_ops.fstat},
+ {"vfs_lstat", &dl_ops.lstat},
+ {"vfs_lock", &dl_ops.lock},
+ {"vfs_unlink", &dl_ops.unlink},
+ {"vfs_chmod", &dl_ops.chmod},
+ {"vfs_utime", &dl_ops.utime},
+
+ {NULL, 0}
+};
+
+/* Default vfs hooks. WARNING: The order of these initialisers is
+ very important. Change at your own peril. */
+
+struct vfs_ops default_vfs_ops = {
+
+ /* Global operations */
+
+ NULL, /* init */
+
+ /* Disk operations */
+
+ NULL, /* connect */
+ NULL, /* disconnect */
+ vfswrap_disk_free,
+
+ /* Directory operations */
+
+ vfswrap_opendir,
+ vfswrap_readdir,
+ vfswrap_mkdir,
+ vfswrap_rmdir,
+
+ /* File operations */
+
+ vfswrap_open,
+ vfswrap_close,
+ vfswrap_read,
+ vfswrap_write,
+ vfswrap_lseek,
+ vfswrap_rename,
+ vfswrap_sync_file,
+ vfswrap_stat,
+ vfswrap_fstat,
+ vfswrap_lstat,
+ vfswrap_fcntl_lock,
+ vfswrap_unlink,
+ vfswrap_chmod,
+ vfswrap_utime
+};
+
+/****************************************************************************
+ call vfs_init function of loadable module
+****************************************************************************/
+BOOL do_vfs_init(char *vfs_object)
+{
+ void *handle, (*fptr)(void);
+
+ DEBUG(3, ("Calling vfs_init for module %s\n", vfs_object));
+
+ handle = dlopen(vfs_object, RTLD_NOW);
+ if (!handle) {
+ DEBUG(0, ("Error opening %s: %s\n", vfs_object, dlerror()));
+ return False;
+ }
+
+ fptr = dlsym(handle, "vfs_init");
+
+ /* Call initialisation function */
+
+ if (fptr != NULL) {
+ fptr();
+ }
+
+ dlclose(handle);
+
+ return True;
+}
+
+/****************************************************************************
+ initialise default vfs hooks
+****************************************************************************/
+int vfs_init_default(connection_struct *conn)
+{
+ DEBUG(3, ("Initialising default vfs hooks\n"));
+
+ bcopy(&default_vfs_ops, &conn->vfs_ops, sizeof(conn->vfs_ops));
+ return 0;
+}
+
+/****************************************************************************
+ initialise custom vfs hooks
+****************************************************************************/
+int vfs_init_custom(connection_struct *conn)
+{
+ void *handle, *fptr;
+ int index;
+
+ DEBUG(3, ("Initialising custom vfs hooks from %s\n",
+ lp_vfsobj(SNUM(conn))));
+
+ /* Open object file */
+
+ handle = dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW);
+ if (!handle) {
+ DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)),
+ dlerror()));
+ return -1;
+ }
+
+ /* Read list of symbols */
+
+ for(index = 0; vfs_syminfo[index].name; index++) {
+ fptr = dlsym(handle, vfs_syminfo[index].name);
+ if (fptr == NULL) {
+ DEBUG(0, ("Symbol %s not found in %s\n", vfs_syminfo[index].name,
+ lp_vfsobj(SNUM(conn))));
+ return -1;
+ }
+
+ *((void **)vfs_syminfo[index].fptr) = fptr;
+ }
+
+ /* Copy loaded symbols into connection struct */
+
+ bcopy(&dl_ops, &conn->vfs_ops, sizeof(dl_ops));
+ dlclose(handle);
+
+#if 0
+ do_vfs_init(lp_vfsobj(SNUM(conn)));
+#endif
+
+ return 0;
+}
+
+/*******************************************************************
+ 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));
+}
+
+/****************************************************************************
+ read data from the client vfs, reading exactly N bytes.
+****************************************************************************/
+ssize_t vfs_read_data(files_struct *fsp,char *buffer,size_t N)
+{
+ ssize_t ret;
+ size_t total=0;
+ int fd = fsp->fd_ptr->fd;
+ extern int smb_read_error;
+
+ smb_read_error = 0;
+
+ while (total < N)
+ {
+#ifdef WITH_SSL
+ DEBUG(0, ("WARNING: read_data() called with SSL enabled\n"));
+ if(fd == sslFd){
+ ret = SSL_read(ssl, buffer + total, N - total);
+ }else{
+ ret = read(fd,buffer + total,N - total);
+ }
+#else /* WITH_SSL */
+ ret = fsp->conn->vfs_ops.read(fd,buffer + total,N - total);
+ DEBUG(0, ("VFS_READ -> read %d/%d bytes\n", ret, N));
+#endif /* WITH_SSL */
+
+ if (ret == 0)
+ {
+ smb_read_error = READ_EOF;
+ return 0;
+ }
+ if (ret == -1)
+ {
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ total += ret;
+ }
+ return (ssize_t)total;
+}
+
+/****************************************************************************
+ 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)
+ {
+#ifdef WITH_SSL
+ DEBUG(0, ("WARNING: write_data called with SSL enabled\n"));
+ if(fd == sslFd){
+ ret = SSL_write(ssl,buffer + total,N - total);
+ }else{
+ ret = write(fd,buffer + total,N - total);
+ }
+#else /* WITH_SSL */
+ ret = fsp->conn->vfs_ops.write(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+ 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);
+}