Wrote VFS initialisation routines.
authorTim Potter <tpot@samba.org>
Sun, 4 Apr 1999 06:39:45 +0000 (06:39 +0000)
committerTim Potter <tpot@samba.org>
Sun, 4 Apr 1999 06:39:45 +0000 (06:39 +0000)
Converted some useful routines from doscalls.c and changed them to use
VFS I/O functions:

dos_file_exist
dos_read_data
dos_write_data
dos_transfer_file
dos_readdirname

Some of these functions have been #ifdef'ed out of doscalls.c as they
are not used anywhere else.  Not sure whether they should be deleted
or not.  The remaining dos_* calls seem to be used by clients and for
locking stuff.  This should be cleaned up sometime.
(This used to be commit ddde0ab9a1e1b90c2a96103721056eb035dcd49d)

source3/smbd/vfs.c [new file with mode: 0644]

diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
new file mode 100644 (file)
index 0000000..937bc16
--- /dev/null
@@ -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);
+}