s3: smbd: Duplicate smb_file_link_information() hardlink handling as smb2_file_link_i...
authorJeremy Allison <jra@samba.org>
Mon, 27 Mar 2023 18:07:07 +0000 (11:07 -0700)
committerRalph Boehme <slow@samba.org>
Fri, 31 Mar 2023 05:12:32 +0000 (05:12 +0000)
We're going to change the SMB2 path handling for DFS and I
really don't want to try and mix these changes into the
existing smb_file_link_information() code.

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/smbd/smb2_trans2.c

index 089a8f08853d40b09720aaecb50aed94e3d01c93..24c21bc16f92a58130ec3a98e47c3a5a612ad23b 100644 (file)
@@ -4504,6 +4504,99 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
        return status;
 }
 
+static NTSTATUS smb2_file_link_information(connection_struct *conn,
+                                           struct smb_request *req,
+                                           const char *pdata,
+                                           int total_data,
+                                           files_struct *fsp,
+                                           struct smb_filename *smb_fname_src)
+{
+       bool overwrite;
+       uint32_t len;
+       char *newname = NULL;
+       struct files_struct *dst_dirfsp = NULL;
+       struct smb_filename *smb_fname_dst = NULL;
+       NTSTATUS status = NT_STATUS_OK;
+       uint32_t ucf_flags = ucf_flags_from_smb_request(req);
+       NTTIME dst_twrp = 0;
+       TALLOC_CTX *ctx = talloc_tos();
+
+       if (!fsp) {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       if (total_data < 20) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       overwrite = (CVAL(pdata,0) ? true : false);
+       len = IVAL(pdata,16);
+
+       if (len > (total_data - 20) || (len == 0)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
+               srvstr_get_path_posix(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
+                               &status);
+               ucf_flags |= UCF_POSIX_PATHNAMES;
+       } else {
+               srvstr_get_path(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
+                               &status);
+       }
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       DBG_DEBUG("got name |%s|\n", newname);
+
+       if (ucf_flags & UCF_GMT_PATHNAME) {
+               extract_snapshot_token(newname, &dst_twrp);
+       }
+       status = filename_convert_dirfsp(ctx,
+                                        conn,
+                                        newname,
+                                        ucf_flags,
+                                        dst_twrp,
+                                        &dst_dirfsp,
+                                        &smb_fname_dst);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (fsp->base_fsp) {
+               /* No stream names. */
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       DBG_DEBUG("SMB_FILE_LINK_INFORMATION (%s) %s -> %s\n",
+                 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
+                 smb_fname_str_dbg(smb_fname_dst));
+       status = hardlink_internals(ctx,
+                               conn,
+                               req,
+                               overwrite,
+                               NULL, /* src_dirfsp */
+                               fsp->fsp_name,
+                               dst_dirfsp, /* dst_dirfsp */
+                               smb_fname_dst);
+
+       TALLOC_FREE(smb_fname_dst);
+       return status;
+}
+
 static NTSTATUS smb_file_link_information(connection_struct *conn,
                                            struct smb_request *req,
                                            const char *pdata,
@@ -4599,6 +4692,7 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
        return status;
 }
 
+
 /****************************************************************************
  Deal with SMB_FILE_RENAME_INFORMATION.
 ****************************************************************************/
@@ -5206,9 +5300,21 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
 
                case SMB_FILE_LINK_INFORMATION:
                {
-                       status = smb_file_link_information(conn, req,
-                                                       pdata, total_data,
-                                                       fsp, smb_fname);
+                       if (conn->sconn->using_smb2) {
+                               status = smb2_file_link_information(conn,
+                                                       req,
+                                                       pdata,
+                                                       total_data,
+                                                       fsp,
+                                                       smb_fname);
+                       } else {
+                               status = smb_file_link_information(conn,
+                                                       req,
+                                                       pdata,
+                                                       total_data,
+                                                       fsp,
+                                                       smb_fname);
+                       }
                        break;
                }