s3:modules: Fix compilation of nfs41acl_xdr.c when building outside src
[samba.git] / source3 / modules / vfs_streams_depot.c
index ae1af24684611498ffd026066b7f00cf530a4e27..31625b347118040a4a73974a81310f39627532da 100644 (file)
@@ -67,13 +67,14 @@ static uint32_t hash_fn(DATA_BLOB key)
  * an option to put in a special ACL entry for a non-existing group.
  */
 
-static bool file_is_valid(vfs_handle_struct *handle, const char *path)
+static bool file_is_valid(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname)
 {
        char buf;
 
-       DEBUG(10, ("file_is_valid (%s) called\n", path));
+       DEBUG(10, ("file_is_valid (%s) called\n", smb_fname->base_name));
 
-       if (SMB_VFS_GETXATTR(handle->conn, path, SAMBA_XATTR_MARKER,
+       if (SMB_VFS_GETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
                                  &buf, sizeof(buf)) != sizeof(buf)) {
                DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
                return false;
@@ -87,14 +88,15 @@ static bool file_is_valid(vfs_handle_struct *handle, const char *path)
        return true;
 }
 
-static bool mark_file_valid(vfs_handle_struct *handle, const char *path)
+static bool mark_file_valid(vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname)
 {
        char buf = '1';
        int ret;
 
-       DEBUG(10, ("marking file %s as valid\n", path));
+       DEBUG(10, ("marking file %s as valid\n", smb_fname->base_name));
 
-       ret = SMB_VFS_SETXATTR(handle->conn, path, SAMBA_XATTR_MARKER,
+       ret = SMB_VFS_SETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
                                    &buf, sizeof(buf), 0);
 
        if (ret == -1) {
@@ -121,30 +123,51 @@ static char *stream_dir(vfs_handle_struct *handle,
        char *tmp;
        char *id_hex;
        struct file_id id;
-       uint8 id_buf[16];
+       uint8_t id_buf[16];
        bool check_valid;
-       const char *rootdir;
+       char *rootdir = NULL;
+       struct smb_filename *rootdir_fname = NULL;
+       struct smb_filename *tmp_fname = NULL;
 
        check_valid = lp_parm_bool(SNUM(handle->conn),
                      "streams_depot", "check_valid", true);
 
-       tmp = talloc_asprintf(talloc_tos(), "%s/.streams", handle->conn->cwd);
+       tmp = talloc_asprintf(talloc_tos(), "%s/.streams",
+               handle->conn->connectpath);
 
        if (tmp == NULL) {
                errno = ENOMEM;
                goto fail;
        }
 
-       rootdir = lp_parm_const_string(
+       rootdir = lp_parm_talloc_string(talloc_tos(),
                SNUM(handle->conn), "streams_depot", "directory",
                tmp);
+       if (rootdir == NULL) {
+               errno = ENOMEM;
+               goto fail;
+       }
+
+       rootdir_fname = synthetic_smb_fname(talloc_tos(),
+                                       rootdir,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (rootdir_fname == NULL) {
+               errno = ENOMEM;
+               goto fail;
+       }
 
        /* Stat the base file if it hasn't already been done. */
        if (base_sbuf == NULL) {
                struct smb_filename *smb_fname_base;
 
                smb_fname_base = synthetic_smb_fname(
-                       talloc_tos(), smb_fname->base_name, NULL, NULL);
+                                       talloc_tos(),
+                                       smb_fname->base_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
                if (smb_fname_base == NULL) {
                        errno = ENOMEM;
                        goto fail;
@@ -185,7 +208,11 @@ static char *stream_dir(vfs_handle_struct *handle,
                return NULL;
        }
 
-       smb_fname_hash = synthetic_smb_fname(talloc_tos(), result, NULL, NULL);
+       smb_fname_hash = synthetic_smb_fname(talloc_tos(),
+                                       result,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
        if (smb_fname_hash == NULL) {
                errno = ENOMEM;
                goto fail;
@@ -202,7 +229,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                }
 
                if (!check_valid ||
-                   file_is_valid(handle, smb_fname->base_name)) {
+                   file_is_valid(handle, smb_fname)) {
                        return result;
                }
 
@@ -222,7 +249,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                              smb_fname_hash->base_name));
                        recursive_rmdir(talloc_tos(), handle->conn,
                                        smb_fname_hash);
-                       SMB_VFS_NEXT_RMDIR(handle, smb_fname_hash->base_name);
+                       SMB_VFS_NEXT_RMDIR(handle, smb_fname_hash);
                } else {
                        newname = talloc_asprintf(talloc_tos(), "lost-%lu",
                                                  random());
@@ -236,7 +263,11 @@ static char *stream_dir(vfs_handle_struct *handle,
                        }
 
                        smb_fname_new = synthetic_smb_fname(
-                               talloc_tos(), newname, NULL, NULL);
+                                               talloc_tos(),
+                                               newname,
+                                               NULL,
+                                               NULL,
+                                               smb_fname->flags);
                        TALLOC_FREE(newname);
                        if (smb_fname_new == NULL) {
                                errno = ENOMEM;
@@ -261,7 +292,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                goto fail;
        }
 
-       if ((SMB_VFS_NEXT_MKDIR(handle, rootdir, 0755) != 0)
+       if ((SMB_VFS_NEXT_MKDIR(handle, rootdir_fname, 0755) != 0)
            && (errno != EEXIST)) {
                goto fail;
        }
@@ -272,12 +303,23 @@ static char *stream_dir(vfs_handle_struct *handle,
                goto fail;
        }
 
-       if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
+       tmp_fname = synthetic_smb_fname(talloc_tos(),
+                                       tmp,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (tmp_fname == NULL) {
+               errno = ENOMEM;
+               goto fail;
+       }
+
+       if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
            && (errno != EEXIST)) {
                goto fail;
        }
 
        TALLOC_FREE(tmp);
+       TALLOC_FREE(tmp_fname);
 
        tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
                              second);
@@ -286,26 +328,44 @@ static char *stream_dir(vfs_handle_struct *handle,
                goto fail;
        }
 
-       if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
+       tmp_fname = synthetic_smb_fname(talloc_tos(),
+                                       tmp,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+       if (tmp_fname == NULL) {
+               errno = ENOMEM;
+               goto fail;
+       }
+
+       if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
            && (errno != EEXIST)) {
                goto fail;
        }
 
        TALLOC_FREE(tmp);
+       TALLOC_FREE(tmp_fname);
 
-       if ((SMB_VFS_NEXT_MKDIR(handle, result, 0755) != 0)
+       /* smb_fname_hash is the struct smb_filename version of 'result' */
+       if ((SMB_VFS_NEXT_MKDIR(handle, smb_fname_hash, 0755) != 0)
            && (errno != EEXIST)) {
                goto fail;
        }
 
-       if (check_valid && !mark_file_valid(handle, smb_fname->base_name)) {
+       if (check_valid && !mark_file_valid(handle, smb_fname)) {
                goto fail;
        }
 
+       TALLOC_FREE(rootdir_fname);
+       TALLOC_FREE(rootdir);
+       TALLOC_FREE(tmp_fname);
        TALLOC_FREE(smb_fname_hash);
        return result;
 
  fail:
+       TALLOC_FREE(rootdir_fname);
+       TALLOC_FREE(rootdir);
+       TALLOC_FREE(tmp_fname);
        TALLOC_FREE(smb_fname_hash);
        TALLOC_FREE(result);
        return NULL;
@@ -367,8 +427,11 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
        DEBUG(10, ("stream filename = %s\n", stream_fname));
 
        /* Create an smb_filename with stream_name == NULL. */
-       *smb_fname_out = synthetic_smb_fname(
-               talloc_tos(), stream_fname, NULL, NULL);
+       *smb_fname_out = synthetic_smb_fname(talloc_tos(),
+                                       stream_fname,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
        if (*smb_fname_out == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -390,6 +453,7 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle,
                             void *private_data)
 {
        char *dirname;
+       struct smb_filename *dir_smb_fname = NULL;
        DIR *dirhandle = NULL;
        const char *dirent = NULL;
        char *talloced = NULL;
@@ -409,7 +473,19 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle,
 
        DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
 
-       dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dirname, NULL, 0);
+       dir_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       dirname,
+                                       NULL,
+                                       NULL,
+                                       smb_fname_base->flags);
+       if (dir_smb_fname == NULL) {
+               TALLOC_FREE(dirname);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dir_smb_fname, NULL, 0);
+
+       TALLOC_FREE(dir_smb_fname);
 
        if (dirhandle == NULL) {
                TALLOC_FREE(dirname);
@@ -567,8 +643,11 @@ static int streams_depot_open(vfs_handle_struct *handle,
        }
 
        /* Ensure the base file still exists. */
-       smb_fname_base = synthetic_smb_fname(
-               talloc_tos(), smb_fname->base_name, NULL, NULL);
+       smb_fname_base = synthetic_smb_fname(talloc_tos(),
+                                       smb_fname->base_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
        if (smb_fname_base == NULL) {
                ret = -1;
                errno = ENOMEM;
@@ -628,14 +707,17 @@ static int streams_depot_unlink(vfs_handle_struct *handle,
         * We potentially need to delete the per-inode streams directory
         */
 
-       smb_fname_base = synthetic_smb_fname(
-               talloc_tos(), smb_fname->base_name, NULL, NULL);
+       smb_fname_base = synthetic_smb_fname(talloc_tos(),
+                                       smb_fname->base_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
        if (smb_fname_base == NULL) {
                errno = ENOMEM;
                return -1;
        }
 
-       if (lp_posix_pathnames()) {
+       if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
                ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
        } else {
                ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
@@ -646,39 +728,63 @@ static int streams_depot_unlink(vfs_handle_struct *handle,
                return -1;
        }
 
-       ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-       if (ret == 0) {
+       /*
+        * We know the unlink should succeed as the ACL
+        * check is already done in the caller. Remove the
+        * file *after* the streams.
+        */
+       {
                char *dirname = stream_dir(handle, smb_fname_base,
                                           &smb_fname_base->st, false);
 
                if (dirname != NULL) {
-                       SMB_VFS_NEXT_RMDIR(handle, dirname);
+                       struct smb_filename *smb_fname_dir =
+                               synthetic_smb_fname(talloc_tos(),
+                                               dirname,
+                                               NULL,
+                                               NULL,
+                                               smb_fname->flags);
+                       if (smb_fname_dir == NULL) {
+                               TALLOC_FREE(smb_fname_base);
+                               TALLOC_FREE(dirname);
+                               errno = ENOMEM;
+                               return -1;
+                       }
+                       SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
+                       TALLOC_FREE(smb_fname_dir);
                }
                TALLOC_FREE(dirname);
        }
 
+       ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
        TALLOC_FREE(smb_fname_base);
        return ret;
 }
 
-static int streams_depot_rmdir(vfs_handle_struct *handle, const char *path)
+static int streams_depot_rmdir(vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname)
 {
        struct smb_filename *smb_fname_base = NULL;
        int ret = -1;
 
-       DEBUG(10, ("streams_depot_rmdir called for %s\n", path));
+       DEBUG(10, ("streams_depot_rmdir called for %s\n",
+               smb_fname->base_name));
 
        /*
         * We potentially need to delete the per-inode streams directory
         */
 
-       smb_fname_base = synthetic_smb_fname(talloc_tos(), path, NULL, NULL);
+       smb_fname_base = synthetic_smb_fname(talloc_tos(),
+                               smb_fname->base_name,
+                               NULL,
+                               NULL,
+                               smb_fname->flags);
        if (smb_fname_base == NULL) {
                errno = ENOMEM;
                return -1;
        }
 
-       if (lp_posix_pathnames()) {
+       if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
                ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
        } else {
                ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
@@ -689,17 +795,35 @@ static int streams_depot_rmdir(vfs_handle_struct *handle, const char *path)
                return -1;
        }
 
-       ret = SMB_VFS_NEXT_RMDIR(handle, path);
-       if (ret == 0) {
+       /*
+        * We know the rmdir should succeed as the ACL
+        * check is already done in the caller. Remove the
+        * directory *after* the streams.
+        */
+       {
                char *dirname = stream_dir(handle, smb_fname_base,
                                           &smb_fname_base->st, false);
 
                if (dirname != NULL) {
-                       SMB_VFS_NEXT_RMDIR(handle, dirname);
+                       struct smb_filename *smb_fname_dir =
+                               synthetic_smb_fname(talloc_tos(),
+                                               dirname,
+                                               NULL,
+                                               NULL,
+                                               smb_fname->flags);
+                       if (smb_fname_dir == NULL) {
+                               TALLOC_FREE(smb_fname_base);
+                               TALLOC_FREE(dirname);
+                               errno = ENOMEM;
+                               return -1;
+                       }
+                       SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
+                       TALLOC_FREE(smb_fname_dir);
                }
                TALLOC_FREE(dirname);
        }
 
+       ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname_base);
        TALLOC_FREE(smb_fname_base);
        return ret;
 }
@@ -807,7 +931,7 @@ static bool collect_one_stream(const char *dirname,
                goto out;
        }
 
-       smb_fname = synthetic_smb_fname(talloc_tos(), sname, NULL, NULL);
+       smb_fname = synthetic_smb_fname(talloc_tos(), sname, NULL, NULL, 0);
        if (smb_fname == NULL) {
                state->status = NT_STATUS_NO_MEMORY;
                ret = false;
@@ -840,17 +964,21 @@ static bool collect_one_stream(const char *dirname,
 
 static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
                                         struct files_struct *fsp,
-                                        const char *fname,
+                                        const struct smb_filename *smb_fname,
                                         TALLOC_CTX *mem_ctx,
                                         unsigned int *pnum_streams,
                                         struct stream_struct **pstreams)
 {
-       struct smb_filename *smb_fname_base;
+       struct smb_filename *smb_fname_base = NULL;
        int ret;
        NTSTATUS status;
        struct streaminfo_state state;
 
-       smb_fname_base = synthetic_smb_fname(talloc_tos(), fname, NULL, NULL);
+       smb_fname_base = synthetic_smb_fname(talloc_tos(),
+                                       smb_fname->base_name,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
        if (smb_fname_base == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -859,7 +987,7 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
                ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
        }
        else {
-               if (lp_posix_pathnames()) {
+               if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
                        ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
                } else {
                        ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
@@ -877,8 +1005,19 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
        state.handle = handle;
        state.status = NT_STATUS_OK;
 
-       status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
+       if (S_ISLNK(smb_fname_base->st.st_ex_mode)) {
+               /*
+                * Currently we do't have SMB_VFS_LLISTXATTR
+                * inside the VFS which means there's no way
+                * to cope with a symlink when lp_posix_pathnames().
+                * returns true. For now ignore links.
+                * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
+                */
+               status = NT_STATUS_OK;
+       } else {
+               status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
                              &state);
+       }
 
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(state.streams);
@@ -893,7 +1032,12 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
 
        *pnum_streams = state.num_streams;
        *pstreams = state.streams;
-       status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, pnum_streams, pstreams);
+       status = SMB_VFS_NEXT_STREAMINFO(handle,
+                               fsp,
+                               smb_fname_base,
+                               mem_ctx,
+                               pnum_streams,
+                               pstreams);
 
  out:
        TALLOC_FREE(smb_fname_base);
@@ -917,8 +1061,8 @@ static struct vfs_fn_pointers vfs_streams_depot_fns = {
        .streaminfo_fn = streams_depot_streaminfo,
 };
 
-NTSTATUS vfs_streams_depot_init(void);
-NTSTATUS vfs_streams_depot_init(void)
+static_decl_vfs;
+NTSTATUS vfs_streams_depot_init(TALLOC_CTX *ctx)
 {
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
                                &vfs_streams_depot_fns);