summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2010-05-18 18:34:54 -0700
committerJeremy Allison <jra@samba.org>2010-05-18 18:34:54 -0700
commit572e5dec1bbd4af3ccc4b8bfe56a72ded4c9aa6e (patch)
treef93d57f9b800584d29befa6583ccb828b96847e9 /source3
parentc7982074a7ea85219411311ebf31444ea4c501a5 (diff)
downloadsamba-572e5dec1bbd4af3ccc4b8bfe56a72ded4c9aa6e.tar.gz
samba-572e5dec1bbd4af3ccc4b8bfe56a72ded4c9aa6e.tar.bz2
samba-572e5dec1bbd4af3ccc4b8bfe56a72ded4c9aa6e.zip
Implement missing info level SMB_FILE_LINK_INFORMATION.
Fix bug #7435 - SMB2 hardlink fails (invalid level). Found at the Microsoft plugsharing plugfest. Jeremy.
Diffstat (limited to 'source3')
-rw-r--r--source3/include/proto.h4
-rw-r--r--source3/smbd/nttrans.c2
-rw-r--r--source3/smbd/trans2.c104
3 files changed, 104 insertions, 6 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 154efeb43b..3deeb9fa2f 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -6368,8 +6368,10 @@ void send_trans2_replies(connection_struct *conn,
unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16]);
NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
connection_struct *conn,
+ struct smb_request *req,
+ bool overwrite_if_exists,
const struct smb_filename *smb_fname_old,
- const struct smb_filename *smb_fname_new);
+ struct smb_filename *smb_fname_new);
NTSTATUS smb_set_file_time(connection_struct *conn,
files_struct *fsp,
const struct smb_filename *smb_fname,
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index b42d665668..9b4d38a904 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1550,6 +1550,8 @@ void reply_ntrename(struct smb_request *req)
status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
} else {
status = hardlink_internals(ctx, conn,
+ req,
+ false,
smb_fname_old,
smb_fname_new);
}
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 56d22b37bb..dec9d7f8f9 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -5348,8 +5348,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
connection_struct *conn,
+ struct smb_request *req,
+ bool overwrite_if_exists,
const struct smb_filename *smb_fname_old,
- const struct smb_filename *smb_fname_new)
+ struct smb_filename *smb_fname_new)
{
NTSTATUS status = NT_STATUS_OK;
@@ -5358,9 +5360,23 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
- /* Disallow if newname already exists. */
if (VALID_STAT(smb_fname_new->st)) {
- return NT_STATUS_OBJECT_NAME_COLLISION;
+ if (overwrite_if_exists) {
+ if (S_ISDIR(smb_fname_new->st.st_ex_mode)) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+ status = unlink_internals(conn,
+ req,
+ FILE_ATTRIBUTE_NORMAL,
+ smb_fname_new,
+ false);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ /* Disallow if newname already exists. */
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
}
/* No links from a directory. */
@@ -5870,7 +5886,7 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
struct smb_request *req,
const char *pdata, int total_data,
- const struct smb_filename *smb_fname_new)
+ struct smb_filename *smb_fname_new)
{
char *oldname = NULL;
struct smb_filename *smb_fname_old = NULL;
@@ -5902,7 +5918,8 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
return status;
}
- return hardlink_internals(ctx, conn, smb_fname_old, smb_fname_new);
+ return hardlink_internals(ctx, conn, req, false,
+ smb_fname_old, smb_fname_new);
}
/****************************************************************************
@@ -6006,6 +6023,75 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
return status;
}
+static NTSTATUS smb_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 smb_filename *smb_fname_dst = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+ 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;
+ }
+
+ srvstr_get_path(ctx, pdata, req->flags2, &newname,
+ &pdata[20], len, STR_TERMINATE,
+ &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10,("smb_file_link_information: got name |%s|\n",
+ newname));
+
+ status = filename_convert(ctx,
+ conn,
+ req->flags2 & FLAGS2_DFS_PATHNAMES,
+ newname,
+ 0,
+ NULL,
+ &smb_fname_dst);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (fsp->base_fsp) {
+ /* No stream names. */
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ DEBUG(10,("smb_file_link_information: "
+ "SMB_FILE_LINK_INFORMATION (fnum %d) %s -> %s\n",
+ fsp->fnum, fsp_str_dbg(fsp),
+ smb_fname_str_dbg(smb_fname_dst)));
+ status = hardlink_internals(ctx,
+ conn,
+ req,
+ overwrite,
+ fsp->fsp_name,
+ smb_fname_dst);
+
+ TALLOC_FREE(smb_fname_dst);
+ return status;
+}
/****************************************************************************
Deal with SMB_FILE_RENAME_INFORMATION.
@@ -7609,6 +7695,14 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
break;
}
+ case SMB_FILE_LINK_INFORMATION:
+ {
+ status = smb_file_link_information(conn, req,
+ pdata, total_data,
+ fsp, smb_fname);
+ break;
+ }
+
#if defined(HAVE_POSIX_ACLS)
case SMB_SET_POSIX_ACL:
{