Fix a type-punned warning
[ira/wip.git] / source3 / smbd / vfs.c
index bc272914c75b7f55984a644a8ce14cd313b6aebc..f219e5554c4602d560a03735799a7a8a1b33ecad 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;
+               }
+
+               entry = vfs_find_backend_entry(module_name);
+               if (!entry) {
+                       DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
                        goto fail;
-               }
-       } else {
-               DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
+               }
+       }
+
+       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;
                }
@@ -389,8 +406,8 @@ ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
 
        while (total < byte_count)
        {
-               ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
-                                       byte_count - total);
+               ssize_t ret = SMB_VFS_READ(fsp, buf + total,
+                                          byte_count - total);
 
                if (ret == 0) return total;
                if (ret == -1) {
@@ -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,14 +495,13 @@ 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);
        }
 
        while (total < N) {
-               ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
-                                N - total, offset + total);
+               ret = SMB_VFS_PWRITE(fsp, buffer + total, N - total,
+                                    offset + total);
 
                if (ret == -1)
                        return -1;
@@ -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....
@@ -525,35 +538,43 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
                return -1;
        }
 
-       ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
+       ret = SMB_VFS_FSTAT(fsp, &st);
        if (ret == -1)
                return ret;
 
-       if (len == (SMB_BIG_UINT)st.st_size)
+       if (len == (uint64_t)st.st_size)
                return 0;
 
-       if (len < (SMB_BIG_UINT)st.st_size) {
+       if (len < (uint64_t)st.st_size) {
                /* Shrink - use ftruncate. */
 
                DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
                                fsp->fsp_name, (double)st.st_size ));
 
+               contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
+
                flush_write_cache(fsp, SIZECHANGE_FLUSH);
-               if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
+               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 /= 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;
        }
 
@@ -578,10 +599,11 @@ 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, fsp->fh->fd, len)) != -1) {
+       if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
                set_filelen_write_cache(fsp, len);
                notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
                             FILE_NOTIFY_CHANGE_SIZE
@@ -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,8 +634,7 @@ 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,fsp->fh->fd,&st);
+       ret = SMB_VFS_FSTAT(fsp, &st);
        if (ret == -1) {
                return ret;
        }
@@ -624,13 +646,16 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
        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)));
 
+       contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
+
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
 
        if (!sparse_buf) {
                sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
                if (!sparse_buf) {
                        errno = ENOMEM;
-                       return -1;
+                       ret = -1;
+                       goto out;
                }
        }
 
@@ -641,53 +666,58 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
        while (total < num_to_write) {
                size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
 
-               pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
+               pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total);
                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;
 }
 
 /****************************************************************************
  Transfer some data (n bytes) between two file_struct's.
 ****************************************************************************/
 
-static files_struct *in_fsp;
-static files_struct *out_fsp;
-
-static ssize_t read_fn(int fd, void *buf, size_t len)
+static ssize_t vfs_read_fn(void *file, void *buf, size_t len)
 {
-       return SMB_VFS_READ(in_fsp, fd, buf, len);
+       struct files_struct *fsp = (struct files_struct *)file;
+
+       return SMB_VFS_READ(fsp, buf, len);
 }
 
-static ssize_t write_fn(int fd, const void *buf, size_t len)
+static ssize_t vfs_write_fn(void *file, const void *buf, size_t len)
 {
-       return SMB_VFS_WRITE(out_fsp, fd, buf, len);
+       struct files_struct *fsp = (struct files_struct *)file;
+
+       return SMB_VFS_WRITE(fsp, buf, len);
 }
 
 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
 {
-       in_fsp = in;
-       out_fsp = out;
-
-       return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
+       return transfer_file_internal((void *)in, (void *)out, n,
+                                     vfs_read_fn, vfs_write_fn);
 }
 
 /*******************************************************************
  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;
@@ -695,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);
 
@@ -721,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("");
@@ -749,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;
 
@@ -780,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)),
@@ -821,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)),
@@ -869,14 +889,13 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
                                return map_nt_error_from_unix(errno);
                        case ENOENT:
                        {
-                               TALLOC_CTX *tmp_ctx = talloc_stackframe();
+                               TALLOC_CTX *ctx = talloc_tos();
                                char *tmp_fname = NULL;
                                char *last_component = NULL;
                                /* Last component didn't exist. Remove it and try and canonicalise the directory. */
 
-                               tmp_fname = talloc_strdup(tmp_ctx, fname);
+                               tmp_fname = talloc_strdup(ctx, fname);
                                if (!tmp_fname) {
-                                       TALLOC_FREE(tmp_ctx);
                                        return NT_STATUS_NO_MEMORY;
                                }
                                p = strrchr_m(tmp_fname, '/');
@@ -885,10 +904,9 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
                                        last_component = p;
                                } else {
                                        last_component = tmp_fname;
-                                       tmp_fname = talloc_strdup(tmp_ctx,
+                                       tmp_fname = talloc_strdup(ctx,
                                                        ".");
                                        if (!tmp_fname) {
-                                               TALLOC_FREE(tmp_ctx);
                                                return NT_STATUS_NO_MEMORY;
                                        }
                                }
@@ -900,15 +918,13 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
 #endif
                                if (!resolved_name) {
                                        DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
-                                       TALLOC_FREE(tmp_ctx);
                                        return map_nt_error_from_unix(errno);
                                }
-                               tmp_fname = talloc_asprintf(tmp_ctx,
+                               tmp_fname = talloc_asprintf(ctx,
                                                "%s/%s",
                                                resolved_name,
                                                last_component);
                                if (!tmp_fname) {
-                                       TALLOC_FREE(tmp_ctx);
                                        return NT_STATUS_NO_MEMORY;
                                }
 #ifdef REALPATH_TAKES_NULL
@@ -922,7 +938,6 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
                                safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
                                resolved_name = resolved_name_buf;
 #endif
-                               TALLOC_FREE(tmp_ctx);
                                break;
                        }
                        default: