Introduce "struct stat_ex" as a replacement for SMB_STRUCT_STAT
[abartlet/samba.git/.git] / source3 / smbd / vfs.c
index 53a0001515dc36e3bf9d4413a2956751a82f4f07..0f706697726ad71d615ebc69c770b97639c30312 100644 (file)
@@ -23,6 +23,7 @@
 */
 
 #include "includes.h"
+#include "smbd/globals.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -35,8 +36,6 @@ struct vfs_init_function_entry {
        struct vfs_init_function_entry *prev, *next;
 };
 
-static struct vfs_init_function_entry *backends = NULL;
-
 /****************************************************************************
     maintain the list of available backends
 ****************************************************************************/
@@ -162,22 +161,34 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
        }
 
        /* First, try to load the module with the new module system */
-       if((entry = vfs_find_backend_entry(module_name)) || 
-          (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
-               (entry = vfs_find_backend_entry(module_name)))) {
-
-               DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
-               
-               if ((ops = entry->vfs_op_tuples) == NULL) {
-                       DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
+       entry = vfs_find_backend_entry(module_name);
+       if (!entry) {
+               NTSTATUS status;
+
+               DEBUG(5, ("vfs module [%s] not loaded - trying to load...\n",
+                         vfs_object));
+
+               status = smb_probe_module("vfs", module_path);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("error probing vfs module '%s': %s\n",
+                                 module_path, nt_errstr(status)));
                        goto fail;
-               }
-       } else {
-               DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
+               }
+
+               entry = vfs_find_backend_entry(module_name);
+               if (!entry) {
+                       DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
+                       goto fail;
+               }
+       }
+
+       DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
+       if ((ops = entry->vfs_op_tuples) == NULL) {
+               DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
                goto fail;
        }
 
-       handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
+       handle = TALLOC_ZERO_P(connvfs_handle_struct);
        if (!handle) {
                DEBUG(0,("TALLOC_ZERO() failed!\n"));
                goto fail;
@@ -185,7 +196,7 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
        memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
        handle->conn = conn;
        if (module_param) {
-               handle->param = talloc_strdup(conn->mem_ctx, module_param);
+               handle->param = talloc_strdup(conn, module_param);
        }
        DLIST_ADD(conn->vfs_handles, handle);
 
@@ -221,7 +232,9 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
 
 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
 
-void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
+void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle,
+                                  files_struct *fsp, size_t ext_size,
+                                  void (*destroy_fn)(void *p_data))
 {
        struct vfs_fsp_data *ext;
        void * ext_data;
@@ -232,13 +245,14 @@ void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp,
        }
 
        ext = (struct vfs_fsp_data *)TALLOC_ZERO(
-               handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
+               handle->conn, sizeof(struct vfs_fsp_data) + ext_size);
        if (ext == NULL) {
                return NULL;
        }
 
        ext->owner = handle;
        ext->next = fsp->vfs_extension;
+       ext->destroy = destroy_fn;
        fsp->vfs_extension = ext;
        return EXT_DATA_AREA(ext);
 }
@@ -257,6 +271,9 @@ void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
                    } else {
                            fsp->vfs_extension = curr->next;
                    }
+                   if (curr->destroy) {
+                           curr->destroy(EXT_DATA_AREA(curr));
+                   }
                    TALLOC_FREE(curr);
                    return;
                }
@@ -336,7 +353,7 @@ bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_
        if (SMB_VFS_STAT(conn,dname,st) != 0)
                return(False);
 
-       ret = S_ISDIR(st->st_mode);
+       ret = S_ISDIR(st->st_ex_mode);
        if(!ret)
                errno = ENOTDIR;
 
@@ -376,7 +393,7 @@ bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *
 
        if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
                return False;
-       return(S_ISREG(sbuf->st_mode));
+       return(S_ISREG(sbuf->st_ex_mode));
 }
 
 /****************************************************************************
@@ -445,13 +462,12 @@ ssize_t vfs_write_data(struct smb_request *req,
                req->unread_bytes = 0;
                return SMB_VFS_RECVFILE(smbd_server_fd(),
                                        fsp,
-                                       fsp->fh->fd,
                                        (SMB_OFF_T)-1,
                                        N);
        }
 
        while (total < N) {
-               ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
+               ret = SMB_VFS_WRITE(fsp, buffer + total, N - total);
 
                if (ret == -1)
                        return -1;
@@ -479,7 +495,6 @@ ssize_t vfs_pwrite_data(struct smb_request *req,
                req->unread_bytes = 0;
                return SMB_VFS_RECVFILE(smbd_server_fd(),
                                        fsp,
-                                       fsp->fh->fd,
                                        offset,
                                        N);
        }
@@ -503,15 +518,13 @@ ssize_t vfs_pwrite_data(struct smb_request *req,
  Returns 0 on success, -1 on failure.
 ****************************************************************************/
 
-int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
+int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
 {
        int ret;
        SMB_STRUCT_STAT st;
        connection_struct *conn = fsp->conn;
-       SMB_BIG_UINT space_avail;
-       SMB_BIG_UINT bsize,dfree,dsize;
-
-       release_level_2_oplocks_on_change(fsp);
+       uint64_t space_avail;
+       uint64_t bsize,dfree,dsize;
 
        /*
         * Actually try and commit the space on disk....
@@ -529,36 +542,44 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
        if (ret == -1)
                return ret;
 
-       if (len == (SMB_BIG_UINT)st.st_size)
+       if (len == (uint64_t)st.st_ex_size)
                return 0;
 
-       if (len < (SMB_BIG_UINT)st.st_size) {
+       if (len < (uint64_t)st.st_ex_size) {
                /* Shrink - use ftruncate. */
 
                DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
-                               fsp->fsp_name, (double)st.st_size ));
+                               fsp->fsp_name, (double)st.st_ex_size ));
+
+               contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
 
                flush_write_cache(fsp, SIZECHANGE_FLUSH);
                if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
                        set_filelen_write_cache(fsp, len);
                }
+
+               contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
+
                return ret;
        }
 
        /* Grow - we need to test if we have enough space. */
 
+       contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
+       contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
+
        if (!lp_strict_allocate(SNUM(fsp->conn)))
                return 0;
 
-       len -= st.st_size;
+       len -= st.st_ex_size;
        len /= 1024; /* Len is now number of 1k blocks needed. */
        space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
-       if (space_avail == (SMB_BIG_UINT)-1) {
+       if (space_avail == (uint64_t)-1) {
                return -1;
        }
 
        DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
-                       fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
+                       fsp->fsp_name, (double)st.st_ex_size, (double)len, (double)space_avail ));
 
        if (len > space_avail) {
                errno = ENOSPC;
@@ -578,7 +599,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
 {
        int ret;
 
-       release_level_2_oplocks_on_change(fsp);
+       contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
+
        DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
        if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
@@ -589,6 +611,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
                             fsp->fsp_name);
        }
 
+       contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
+
        return ret;
 }
 
@@ -599,7 +623,6 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
  Returns 0 on success, -1 on failure.
 ****************************************************************************/
 
-static char *sparse_buf;
 #define SPARSE_BUF_WRITE_SIZE (32*1024)
 
 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
@@ -611,18 +634,19 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
        size_t num_to_write;
        ssize_t pwrite_ret;
 
-       release_level_2_oplocks_on_change(fsp);
        ret = SMB_VFS_FSTAT(fsp, &st);
        if (ret == -1) {
                return ret;
        }
 
-       if (len <= st.st_size) {
+       if (len <= st.st_ex_size) {
                return 0;
        }
 
        DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
-               fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
+               fsp->fsp_name, (double)st.st_ex_size, (double)len, (double)(len - st.st_ex_size)));
+
+       contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
 
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
 
@@ -630,12 +654,13 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
                sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
                if (!sparse_buf) {
                        errno = ENOMEM;
-                       return -1;
+                       ret = -1;
+                       goto out;
                }
        }
 
-       offset = st.st_size;
-       num_to_write = len - st.st_size;
+       offset = st.st_ex_size;
+       num_to_write = len - st.st_ex_size;
        total = 0;
 
        while (total < num_to_write) {
@@ -645,17 +670,23 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
                if (pwrite_ret == -1) {
                        DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
                                fsp->fsp_name, strerror(errno) ));
-                       return -1;
+                       ret = -1;
+                       goto out;
                }
                if (pwrite_ret == 0) {
-                       return 0;
+                       ret = 0;
+                       goto out;
                }
 
                total += pwrite_ret;
        }
 
        set_filelen_write_cache(fsp, len);
-       return 0;
+
+       ret = 0;
+ out:
+       contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
+       return ret;
 }
 
 /****************************************************************************
@@ -673,7 +704,7 @@ static ssize_t vfs_write_fn(void *file, const void *buf, size_t len)
 {
        struct files_struct *fsp = (struct files_struct *)file;
 
-       return SMB_VFS_WRITE(fsp, fsp->fh->fd, buf, len);
+       return SMB_VFS_WRITE(fsp, buf, len);
 }
 
 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
@@ -686,7 +717,7 @@ SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
  A vfs_readdir wrapper which just returns the file name.
 ********************************************************************/
 
-char *vfs_readdirname(connection_struct *conn, void *p)
+char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf)
 {
        SMB_STRUCT_DIRENT *ptr= NULL;
        char *dname;
@@ -694,7 +725,7 @@ char *vfs_readdirname(connection_struct *conn, void *p)
        if (!p)
                return(NULL);
 
-       ptr = SMB_VFS_READDIR(conn, (DIR *)p);
+       ptr = SMB_VFS_READDIR(conn, (DIR *)p, sbuf);
        if (!ptr)
                return(NULL);
 
@@ -720,7 +751,6 @@ char *vfs_readdirname(connection_struct *conn, void *p)
 int vfs_ChDir(connection_struct *conn, const char *path)
 {
        int res;
-       static char *LastDir = NULL;
 
        if (!LastDir) {
                LastDir = SMB_STRDUP("");
@@ -748,18 +778,13 @@ int vfs_ChDir(connection_struct *conn, const char *path)
  format. Note this can be called with conn == NULL.
 ********************************************************************/
 
-struct getwd_cache_key {
-       SMB_DEV_T dev;
-       SMB_INO_T ino;
-};
-
 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 {
         char s[PATH_MAX+1];
        SMB_STRUCT_STAT st, st2;
        char *result;
        DATA_BLOB cache_value;
-       struct getwd_cache_key key;
+       struct file_id key;
 
        *s = 0;
 
@@ -779,9 +804,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
                goto nocache;
        }
 
-       ZERO_STRUCT(key); /* unlikely, but possible padding */
-       key.dev = st.st_dev;
-       key.ino = st.st_ino;
+       key = vfs_file_id_from_sbuf(conn, &st);
 
        if (!memcache_lookup(smbd_memcache(), GETWD_CACHE,
                             data_blob_const(&key, sizeof(key)),
@@ -793,8 +816,8 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
                   && (cache_value.data[cache_value.length-1] == '\0'));
 
        if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0)
-           && (st.st_dev == st2.st_dev) && (st.st_ino == st2.st_ino)
-           && (S_ISDIR(st.st_mode))) {
+           && (st.st_ex_dev == st2.st_ex_dev) && (st.st_ex_ino == st2.st_ex_ino)
+           && (S_ISDIR(st.st_ex_mode))) {
                /*
                 * Ok, we're done
                 */
@@ -820,9 +843,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
        }
 
        if (lp_getwd_cache() && VALID_STAT(st)) {
-               ZERO_STRUCT(key); /* unlikely, but possible padding */
-               key.dev = st.st_dev;
-               key.ino = st.st_ino;
+               key = vfs_file_id_from_sbuf(conn, &st);
 
                memcache_add(smbd_memcache(), GETWD_CACHE,
                             data_blob_const(&key, sizeof(key)),
@@ -952,7 +973,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
         if (!lp_symlinks(SNUM(conn))) {
                 SMB_STRUCT_STAT statbuf;
                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
-                                (S_ISLNK(statbuf.st_mode)) ) {
+                                (S_ISLNK(statbuf.st_ex_mode)) ) {
                        if (free_resolved_name) {
                                SAFE_FREE(resolved_name);
                        }