s3/smbd: remove unneeded flags argument from SMB_VFS_OFFLOAD_WRITE_SEND
[kai/samba-autobuild/.git] / source3 / smbd / vfs.c
index 40c41ed27fc29787573444414917586ccc776f44..67b79ef621b031f9dacd5cfd6d9b2a76f130f779 100644 (file)
@@ -881,9 +881,14 @@ int vfs_ChDir(connection_struct *conn, const struct smb_filename *smb_fname)
                LastDir = SMB_STRDUP(smb_fname->base_name);
 
                /* conn cache. */
-               TALLOC_FREE(conn->cwd);
-               conn->cwd = vfs_GetWd(conn, conn);
-               DEBUG(4,("vfs_ChDir got %s\n",conn->cwd));
+               TALLOC_FREE(conn->cwd_fname);
+               conn->cwd_fname = vfs_GetWd(conn, conn);
+               if (conn->cwd_fname == NULL) {
+                       smb_panic("con->cwd getwd failed\n");
+                       /* NOTREACHED */
+                       return -1;
+               }
+               DEBUG(4,("vfs_ChDir got %s\n",conn->cwd_fname->base_name));
        }
        return ret;
 }
@@ -894,14 +899,13 @@ int vfs_ChDir(connection_struct *conn, const struct smb_filename *smb_fname)
  format. Note this can be called with conn == NULL.
 ********************************************************************/
 
-char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
+struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 {
-        char *current_dir = NULL;
-       char *result = NULL;
-       DATA_BLOB cache_value;
+        struct smb_filename *current_dir_fname = NULL;
        struct file_id key;
        struct smb_filename *smb_fname_dot = NULL;
        struct smb_filename *smb_fname_full = NULL;
+       struct smb_filename *result = NULL;
 
        if (!lp_getwd_cache()) {
                goto nocache;
@@ -925,20 +929,13 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 
        key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
 
-       if (!memcache_lookup(smbd_memcache(), GETWD_CACHE,
-                            data_blob_const(&key, sizeof(key)),
-                            &cache_value)) {
-               goto nocache;
-       }
+       smb_fname_full = (struct smb_filename *)memcache_lookup_talloc(
+                                       smbd_memcache(),
+                                       GETWD_CACHE,
+                                       data_blob_const(&key, sizeof(key)));
 
-       SMB_ASSERT((cache_value.length > 0)
-                  && (cache_value.data[cache_value.length-1] == '\0'));
-
-       smb_fname_full = synthetic_smb_fname(ctx, (char *)cache_value.data,
-                                            NULL, NULL, 0);
        if (smb_fname_full == NULL) {
-               errno = ENOMEM;
-               goto out;
+               goto nocache;
        }
 
        if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) &&
@@ -947,8 +944,10 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
            (S_ISDIR(smb_fname_dot->st.st_ex_mode))) {
                /*
                 * Ok, we're done
+                * Note: smb_fname_full is owned by smbd_memcache()
+                * so we must make a copy to return.
                 */
-               result = talloc_strdup(ctx, smb_fname_full->base_name);
+               result = cp_smb_filename(ctx, smb_fname_full);
                if (result == NULL) {
                        errno = ENOMEM;
                }
@@ -963,8 +962,8 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
         * systems, or the not quite so bad getwd.
         */
 
-       current_dir = SMB_VFS_GETWD(conn);
-       if (current_dir == NULL) {
+       current_dir_fname = SMB_VFS_GETWD(conn, ctx);
+       if (current_dir_fname == NULL) {
                DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
                          strerror(errno)));
                goto out;
@@ -973,21 +972,39 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
        if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) {
                key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
 
-               memcache_add(smbd_memcache(), GETWD_CACHE,
-                            data_blob_const(&key, sizeof(key)),
-                            data_blob_const(current_dir,
-                                               strlen(current_dir)+1));
-       }
+               /*
+                * smbd_memcache() will own current_dir_fname after the
+                * memcache_add_talloc call, so we must make
+                * a copy on ctx to return.
+                */
+               result = cp_smb_filename(ctx, current_dir_fname);
+               if (result == NULL) {
+                       errno = ENOMEM;
+               }
 
-       result = talloc_strdup(ctx, current_dir);
-       if (result == NULL) {
-               errno = ENOMEM;
+               /*
+                * Ensure the memory going into the cache
+                * doesn't have a destructor so it can be
+                * cleanly freed.
+                */
+               talloc_set_destructor(current_dir_fname, NULL);
+
+               memcache_add_talloc(smbd_memcache(),
+                               GETWD_CACHE,
+                               data_blob_const(&key, sizeof(key)),
+                               &current_dir_fname);
+               /* current_dir_fname is now == NULL here. */
+       } else {
+               /* current_dir_fname is already allocated on ctx. */
+               result = current_dir_fname;
        }
 
  out:
        TALLOC_FREE(smb_fname_dot);
-       TALLOC_FREE(smb_fname_full);
-       SAFE_FREE(current_dir);
+       /*
+        * Don't free current_dir_fname here. It's either been moved
+        * to the memcache or is being returned in result.
+        */
        return result;
 }
 
@@ -999,7 +1016,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 ********************************************************************/
 
 NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
-                       const char *fname,
+                       const struct smb_filename *smb_fname,
                        struct smb_request *smbreq)
 {
        NTSTATUS status;
@@ -1007,16 +1024,16 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
        const char *conn_rootdir;
        size_t rootdir_len;
        char *dir_name = NULL;
-       const char *last_component = NULL;
        char *resolved_name = NULL;
-       char *saved_dir = NULL;
+       const char *last_component = NULL;
+       struct smb_filename *resolved_fname = NULL;
        struct smb_filename *saved_dir_fname = NULL;
        struct smb_filename *smb_fname_cwd = NULL;
        struct privilege_paths *priv_paths = NULL;
        int ret;
 
        DEBUG(3,("check_reduced_name_with_privilege [%s] [%s]\n",
-                       fname,
+                       smb_fname->base_name,
                        conn->connectpath));
 
 
@@ -1026,7 +1043,8 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
                goto err;
        }
 
-       if (!parent_dirname(ctx, fname, &dir_name, &last_component)) {
+       if (!parent_dirname(ctx, smb_fname->base_name,
+                       &dir_name, &last_component)) {
                status = NT_STATUS_NO_MEMORY;
                goto err;
        }
@@ -1045,34 +1063,30 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
                goto err;
        }
        /* Remember where we were. */
-       saved_dir = vfs_GetWd(ctx, conn);
-       if (!saved_dir) {
+       saved_dir_fname = vfs_GetWd(ctx, conn);
+       if (!saved_dir_fname) {
                status = map_nt_error_from_unix(errno);
                goto err;
        }
 
-       saved_dir_fname = synthetic_smb_fname(ctx,
-                                       saved_dir,
-                                       NULL,
-                                       NULL,
-                                       0);
-       if (saved_dir_fname == NULL) {
-               status = NT_STATUS_NO_MEMORY;
+       if (vfs_ChDir(conn, &priv_paths->parent_name) == -1) {
+               status = map_nt_error_from_unix(errno);
                goto err;
        }
 
-       /* Go to the parent directory to lock in memory. */
-       if (vfs_ChDir(conn, &priv_paths->parent_name) == -1) {
-               status = map_nt_error_from_unix(errno);
+       smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL, 0);
+       if (smb_fname_cwd == NULL) {
+               status = NT_STATUS_NO_MEMORY;
                goto err;
        }
 
        /* Get the absolute path of the parent directory. */
-       resolved_name = SMB_VFS_REALPATH(conn,".");
-       if (!resolved_name) {
+       resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname_cwd);
+       if (resolved_fname == NULL) {
                status = map_nt_error_from_unix(errno);
                goto err;
        }
+       resolved_name = resolved_fname->base_name;
 
        if (*resolved_name != '/') {
                DEBUG(0,("check_reduced_name_with_privilege: realpath "
@@ -1086,12 +1100,6 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
                resolved_name));
 
        /* Now check the stat value is the same. */
-       smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL, 0);
-       if (smb_fname_cwd == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto err;
-       }
-
        if (SMB_VFS_LSTAT(conn, smb_fname_cwd) != 0) {
                status = map_nt_error_from_unix(errno);
                goto err;
@@ -1109,7 +1117,7 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
 
        /* Ensure we're below the connect path. */
 
-       conn_rootdir = SMB_VFS_CONNECTPATH(conn, fname);
+       conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
        if (conn_rootdir == NULL) {
                DEBUG(2, ("check_reduced_name_with_privilege: Could not get "
                        "conn_rootdir\n"));
@@ -1177,12 +1185,11 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
 
   err:
 
-       if (saved_dir_fname) {
+       if (saved_dir_fname != NULL) {
                vfs_ChDir(conn, saved_dir_fname);
-               TALLOC_FREE(saved_dir);
                TALLOC_FREE(saved_dir_fname);
        }
-       SAFE_FREE(resolved_name);
+       TALLOC_FREE(resolved_fname);
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(priv_paths);
        }
@@ -1202,9 +1209,13 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
 ********************************************************************/
 
 NTSTATUS check_reduced_name(connection_struct *conn,
-                               const char *cwd_name,
-                               const char *fname)
+                               const struct smb_filename *cwd_fname,
+                               const struct smb_filename *smb_fname)
 {
+       TALLOC_CTX *ctx = talloc_tos();
+       const char *cwd_name = cwd_fname ? cwd_fname->base_name : NULL;
+       const char *fname = smb_fname->base_name;
+       struct smb_filename *resolved_fname;
        char *resolved_name = NULL;
        char *new_fname = NULL;
        bool allow_symlinks = true;
@@ -1212,9 +1223,9 @@ NTSTATUS check_reduced_name(connection_struct *conn,
 
        DBG_DEBUG("check_reduced_name [%s] [%s]\n", fname, conn->connectpath);
 
-       resolved_name = SMB_VFS_REALPATH(conn,fname);
+       resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname);
 
-       if (!resolved_name) {
+       if (resolved_fname == NULL) {
                switch (errno) {
                        case ENOTDIR:
                                DEBUG(3,("check_reduced_name: Component not a "
@@ -1223,11 +1234,9 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
                        case ENOENT:
                        {
-                               TALLOC_CTX *ctx = talloc_tos();
                                char *dir_name = NULL;
+                               struct smb_filename dir_fname = {0};
                                const char *last_component = NULL;
-                               char *new_name = NULL;
-                               int ret;
 
                                /* Last component didn't exist.
                                   Remove it and try and canonicalise
@@ -1238,8 +1247,12 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                                        return NT_STATUS_NO_MEMORY;
                                }
 
-                               resolved_name = SMB_VFS_REALPATH(conn,dir_name);
-                               if (!resolved_name) {
+                               dir_fname = (struct smb_filename)
+                                       { .base_name = dir_name };
+                               resolved_fname = SMB_VFS_REALPATH(conn,
+                                                       ctx,
+                                                       &dir_fname);
+                               if (resolved_fname == NULL) {
                                        NTSTATUS status = map_nt_error_from_unix(errno);
 
                                        if (errno == ENOENT || errno == ENOTDIR) {
@@ -1253,13 +1266,13 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                                                nt_errstr(status)));
                                        return status;
                                }
-                               ret = asprintf(&new_name, "%s/%s",
-                                              resolved_name, last_component);
-                               SAFE_FREE(resolved_name);
-                               if (ret == -1) {
+                               resolved_name = talloc_asprintf(ctx,
+                                               "%s/%s",
+                                               resolved_fname->base_name,
+                                               last_component);
+                               if (resolved_name == NULL) {
                                        return NT_STATUS_NO_MEMORY;
                                }
-                               resolved_name = new_name;
                                break;
                        }
                        default:
@@ -1267,6 +1280,8 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                                         "realpath for %s\n", fname));
                                return map_nt_error_from_unix(errno);
                }
+       } else {
+               resolved_name = resolved_fname->base_name;
        }
 
        DEBUG(10,("check_reduced_name realpath [%s] -> [%s]\n", fname,
@@ -1275,7 +1290,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
        if (*resolved_name != '/') {
                DEBUG(0,("check_reduced_name: realpath doesn't return "
                         "absolute paths !\n"));
-               SAFE_FREE(resolved_name);
+               TALLOC_FREE(resolved_fname);
                return NT_STATUS_OBJECT_NAME_INVALID;
        }
 
@@ -1287,11 +1302,11 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                const char *conn_rootdir;
                size_t rootdir_len;
 
-               conn_rootdir = SMB_VFS_CONNECTPATH(conn, fname);
+               conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
                if (conn_rootdir == NULL) {
                        DEBUG(2, ("check_reduced_name: Could not get "
                                "conn_rootdir\n"));
-                       SAFE_FREE(resolved_name);
+                       TALLOC_FREE(resolved_fname);
                        return NT_STATUS_ACCESS_DENIED;
                }
 
@@ -1320,7 +1335,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                                             conn_rootdir));
                                DEBUGADD(2, ("resolved_name=%s\n",
                                             resolved_name));
-                               SAFE_FREE(resolved_name);
+                               TALLOC_FREE(resolved_fname);
                                return NT_STATUS_ACCESS_DENIED;
                        }
                }
@@ -1343,7 +1358,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                                        "in resolved_name: %s\n",
                                        *p,
                                        fname));
-                               SAFE_FREE(resolved_name);
+                               TALLOC_FREE(resolved_fname);
                                return NT_STATUS_ACCESS_DENIED;
                        }
 
@@ -1357,12 +1372,12 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                         * sent (cwd_name+fname).
                         */
                        if (cwd_name != NULL && !ISDOT(cwd_name)) {
-                               new_fname = talloc_asprintf(talloc_tos(),
+                               new_fname = talloc_asprintf(ctx,
                                                        "%s/%s",
                                                        cwd_name,
                                                        fname);
                                if (new_fname == NULL) {
-                                       SAFE_FREE(resolved_name);
+                                       TALLOC_FREE(resolved_fname);
                                        return NT_STATUS_NO_MEMORY;
                                }
                                fname = new_fname;
@@ -1372,7 +1387,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
                                DEBUG(2, ("check_reduced_name: Bad access "
                                        "attempt: %s is a symlink to %s\n",
                                          fname, p));
-                               SAFE_FREE(resolved_name);
+                               TALLOC_FREE(resolved_fname);
                                TALLOC_FREE(new_fname);
                                return NT_STATUS_ACCESS_DENIED;
                        }
@@ -1382,7 +1397,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
   out:
 
        DBG_INFO("%s reduced to %s\n", fname, resolved_name);
-       SAFE_FREE(resolved_name);
+       TALLOC_FREE(resolved_fname);
        TALLOC_FREE(new_fname);
        return NT_STATUS_OK;
 }
@@ -2024,15 +2039,14 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
                 * and always act using lchown to ensure we
                 * don't deref any symbolic links.
                 */
-               char *saved_dir = NULL;
                char *parent_dir = NULL;
                const char *final_component = NULL;
                struct smb_filename *local_smb_fname = NULL;
                struct smb_filename parent_dir_fname = {0};
-               struct smb_filename saved_dir_fname = {0};
+               struct smb_filename *saved_dir_fname = NULL;
 
-               saved_dir = vfs_GetWd(talloc_tos(),fsp->conn);
-               if (!saved_dir) {
+               saved_dir_fname = vfs_GetWd(talloc_tos(),fsp->conn);
+               if (!saved_dir_fname) {
                        status = map_nt_error_from_unix(errno);
                        DEBUG(0,("vfs_chown_fsp: failed to get "
                                "current working directory. Error was %s\n",
@@ -2040,10 +2054,6 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
                        return status;
                }
 
-               saved_dir_fname = (struct smb_filename) {
-                       .base_name = saved_dir
-               };
-
                if (!parent_dirname(talloc_tos(),
                                fsp->fsp_name->base_name,
                                &parent_dir,
@@ -2098,9 +2108,9 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
 
   out:
 
-               vfs_ChDir(fsp->conn, &saved_dir_fname);
+               vfs_ChDir(fsp->conn, saved_dir_fname);
                TALLOC_FREE(local_smb_fname);
-               TALLOC_FREE(saved_dir);
+               TALLOC_FREE(saved_dir_fname);
                TALLOC_FREE(parent_dir);
 
                return status;
@@ -2131,10 +2141,11 @@ int smb_vfs_call_chdir(struct vfs_handle_struct *handle,
        return handle->fns->chdir_fn(handle, smb_fname);
 }
 
-char *smb_vfs_call_getwd(struct vfs_handle_struct *handle)
+struct smb_filename *smb_vfs_call_getwd(struct vfs_handle_struct *handle,
+                               TALLOC_CTX *ctx)
 {
        VFS_FIND(getwd);
-       return handle->fns->getwd_fn(handle);
+       return handle->fns->getwd_fn(handle, ctx);
 }
 
 int smb_vfs_call_ntimes(struct vfs_handle_struct *handle,
@@ -2212,10 +2223,12 @@ int smb_vfs_call_mknod(struct vfs_handle_struct *handle,
        return handle->fns->mknod_fn(handle, smb_fname, mode, dev);
 }
 
-char *smb_vfs_call_realpath(struct vfs_handle_struct *handle, const char *path)
+struct smb_filename *smb_vfs_call_realpath(struct vfs_handle_struct *handle,
+                       TALLOC_CTX *ctx,
+                       const struct smb_filename *smb_fname)
 {
        VFS_FIND(realpath);
-       return handle->fns->realpath_fn(handle, path);
+       return handle->fns->realpath_fn(handle, ctx, smb_fname);
 }
 
 int smb_vfs_call_chflags(struct vfs_handle_struct *handle,
@@ -2255,10 +2268,10 @@ int smb_vfs_call_get_real_filename(struct vfs_handle_struct *handle,
 }
 
 const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle,
-                                    const char *filename)
+                                const struct smb_filename *smb_fname)
 {
        VFS_FIND(connectpath);
-       return handle->fns->connectpath_fn(handle, filename);
+       return handle->fns->connectpath_fn(handle, smb_fname);
 }
 
 bool smb_vfs_call_strict_lock(struct vfs_handle_struct *handle,
@@ -2337,28 +2350,52 @@ NTSTATUS smb_vfs_call_fset_dos_attributes(struct vfs_handle_struct *handle,
        return handle->fns->fset_dos_attributes_fn(handle, fsp, dosmode);
 }
 
-struct tevent_req *smb_vfs_call_copy_chunk_send(struct vfs_handle_struct *handle,
-                                               TALLOC_CTX *mem_ctx,
-                                               struct tevent_context *ev,
-                                               struct files_struct *src_fsp,
-                                               off_t src_off,
-                                               struct files_struct *dest_fsp,
-                                               off_t dest_off,
-                                               off_t num,
-                                               uint32_t flags)
+struct tevent_req *smb_vfs_call_offload_read_send(TALLOC_CTX *mem_ctx,
+                                                 struct tevent_context *ev,
+                                                 struct vfs_handle_struct *handle,
+                                                 struct files_struct *fsp,
+                                                 uint32_t fsctl,
+                                                 uint32_t ttl,
+                                                 off_t offset,
+                                                 size_t to_copy)
+{
+       VFS_FIND(offload_read_send);
+       return handle->fns->offload_read_send_fn(mem_ctx, ev, handle,
+                                                fsp, fsctl,
+                                                ttl, offset, to_copy);
+}
+
+NTSTATUS smb_vfs_call_offload_read_recv(struct tevent_req *req,
+                                       struct vfs_handle_struct *handle,
+                                       TALLOC_CTX *mem_ctx,
+                                       DATA_BLOB *token_blob)
+{
+       VFS_FIND(offload_read_recv);
+       return handle->fns->offload_read_recv_fn(req, handle, mem_ctx, token_blob);
+}
+
+struct tevent_req *smb_vfs_call_offload_write_send(struct vfs_handle_struct *handle,
+                                                  TALLOC_CTX *mem_ctx,
+                                                  struct tevent_context *ev,
+                                                  uint32_t fsctl,
+                                                  DATA_BLOB *token,
+                                                  off_t transfer_offset,
+                                                  struct files_struct *dest_fsp,
+                                                  off_t dest_off,
+                                                  off_t num)
 {
-       VFS_FIND(copy_chunk_send);
-       return handle->fns->copy_chunk_send_fn(handle, mem_ctx, ev, src_fsp,
-                                              src_off, dest_fsp, dest_off, num,
-                                              flags);
+       VFS_FIND(offload_write_send);
+       return handle->fns->offload_write_send_fn(handle, mem_ctx, ev, fsctl,
+                                              token, transfer_offset,
+                                              dest_fsp, dest_off, num);
 }
 
-NTSTATUS smb_vfs_call_copy_chunk_recv(struct vfs_handle_struct *handle,
-                                     struct tevent_req *req,
-                                     off_t *copied)
+NTSTATUS smb_vfs_call_offload_write_recv(struct vfs_handle_struct *handle,
+                                        struct tevent_req *req,
+                                        off_t *copied)
 {
-       VFS_FIND(copy_chunk_recv);
-       return handle->fns->copy_chunk_recv_fn(handle, req, copied);
+       VFS_FIND(offload_write_recv);
+       return handle->fns->offload_write_recv_fn(handle, req, copied);
 }
 
 NTSTATUS smb_vfs_call_get_compression(vfs_handle_struct *handle,