CIFS: Add SMB2 support for hardlink operation
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
parent
d6e906f1b5
commit
568798cc62
|
@ -40,6 +40,7 @@
|
||||||
#define SMB2_OP_MKDIR 5
|
#define SMB2_OP_MKDIR 5
|
||||||
#define SMB2_OP_RENAME 6
|
#define SMB2_OP_RENAME 6
|
||||||
#define SMB2_OP_DELETE 7
|
#define SMB2_OP_DELETE 7
|
||||||
|
#define SMB2_OP_HARDLINK 8
|
||||||
|
|
||||||
/* Used when constructing chained read requests. */
|
/* Used when constructing chained read requests. */
|
||||||
#define CHAINED_REQUEST 1
|
#define CHAINED_REQUEST 1
|
||||||
|
|
|
@ -78,6 +78,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
|
tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
|
||||||
(__le16 *)data);
|
(__le16 *)data);
|
||||||
break;
|
break;
|
||||||
|
case SMB2_OP_HARDLINK:
|
||||||
|
tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid,
|
||||||
|
volatile_fid, (__le16 *)data);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
cERROR(1, "Invalid command");
|
cERROR(1, "Invalid command");
|
||||||
break;
|
break;
|
||||||
|
@ -175,10 +179,10 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
||||||
SMB2_OP_DELETE);
|
SMB2_OP_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
const char *from_name, const char *to_name,
|
const char *from_name, const char *to_name,
|
||||||
struct cifs_sb_info *cifs_sb)
|
struct cifs_sb_info *cifs_sb, __u32 access, int command)
|
||||||
{
|
{
|
||||||
__le16 *smb2_to_name = NULL;
|
__le16 *smb2_to_name = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -189,9 +193,27 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
goto smb2_rename_path;
|
goto smb2_rename_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, DELETE,
|
rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access,
|
||||||
FILE_OPEN, 0, 0, smb2_to_name, SMB2_OP_RENAME);
|
FILE_OPEN, 0, 0, smb2_to_name, command);
|
||||||
smb2_rename_path:
|
smb2_rename_path:
|
||||||
kfree(smb2_to_name);
|
kfree(smb2_to_name);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
const char *from_name, const char *to_name,
|
||||||
|
struct cifs_sb_info *cifs_sb)
|
||||||
|
{
|
||||||
|
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
|
||||||
|
DELETE, SMB2_OP_RENAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
const char *from_name, const char *to_name,
|
||||||
|
struct cifs_sb_info *cifs_sb)
|
||||||
|
{
|
||||||
|
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
|
||||||
|
FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
|
||||||
|
}
|
||||||
|
|
|
@ -452,6 +452,7 @@ struct smb_version_operations smb21_operations = {
|
||||||
.rmdir = smb2_rmdir,
|
.rmdir = smb2_rmdir,
|
||||||
.unlink = smb2_unlink,
|
.unlink = smb2_unlink,
|
||||||
.rename = smb2_rename_path,
|
.rename = smb2_rename_path,
|
||||||
|
.create_hardlink = smb2_create_hardlink,
|
||||||
.open = smb2_open_file,
|
.open = smb2_open_file,
|
||||||
.set_fid = smb2_set_fid,
|
.set_fid = smb2_set_fid,
|
||||||
.close = smb2_close_file,
|
.close = smb2_close_file,
|
||||||
|
|
|
@ -1709,3 +1709,34 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
|
||||||
|
{
|
||||||
|
struct smb2_file_link_info info;
|
||||||
|
void **data;
|
||||||
|
unsigned int size[2];
|
||||||
|
int rc;
|
||||||
|
int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
|
||||||
|
|
||||||
|
data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
info.ReplaceIfExists = 0; /* 1 = replace existing link with new */
|
||||||
|
/* 0 = fail if link already exists */
|
||||||
|
info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */
|
||||||
|
info.FileNameLength = cpu_to_le32(len);
|
||||||
|
|
||||||
|
data[0] = &info;
|
||||||
|
size[0] = sizeof(struct smb2_file_link_info);
|
||||||
|
|
||||||
|
data[1] = target_file;
|
||||||
|
size[1] = len + 2 /* null */;
|
||||||
|
|
||||||
|
rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||||
|
FILE_LINK_INFORMATION, 2, data, size);
|
||||||
|
kfree(data);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
|
@ -653,6 +653,15 @@ struct smb2_file_rename_info { /* encoding of request for level 10 */
|
||||||
char FileName[0]; /* New name to be assigned */
|
char FileName[0]; /* New name to be assigned */
|
||||||
} __packed; /* level 10 Set */
|
} __packed; /* level 10 Set */
|
||||||
|
|
||||||
|
struct smb2_file_link_info { /* encoding of request for level 11 */
|
||||||
|
__u8 ReplaceIfExists; /* 1 = replace existing link with new */
|
||||||
|
/* 0 = fail if link already exists */
|
||||||
|
__u8 Reserved[7];
|
||||||
|
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
|
||||||
|
__le32 FileNameLength;
|
||||||
|
char FileName[0]; /* Name to be assigned to new link */
|
||||||
|
} __packed; /* level 11 Set */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This level 18, although with struct with same name is different from cifs
|
* This level 18, although with struct with same name is different from cifs
|
||||||
* level 0x107. Level 0x107 has an extra u64 between AccessFlags and
|
* level 0x107. Level 0x107 has an extra u64 between AccessFlags and
|
||||||
|
|
|
@ -68,6 +68,9 @@ extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
const char *from_name, const char *to_name,
|
const char *from_name, const char *to_name,
|
||||||
struct cifs_sb_info *cifs_sb);
|
struct cifs_sb_info *cifs_sb);
|
||||||
|
extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
const char *from_name, const char *to_name,
|
||||||
|
struct cifs_sb_info *cifs_sb);
|
||||||
|
|
||||||
extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
const char *full_path, int disposition,
|
const char *full_path, int disposition,
|
||||||
|
@ -112,5 +115,8 @@ extern int SMB2_echo(struct TCP_Server_Info *server);
|
||||||
extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
u64 persistent_fid, u64 volatile_fid,
|
u64 persistent_fid, u64 volatile_fid,
|
||||||
__le16 *target_file);
|
__le16 *target_file);
|
||||||
|
extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
u64 persistent_fid, u64 volatile_fid,
|
||||||
|
__le16 *target_file);
|
||||||
|
|
||||||
#endif /* _SMB2PROTO_H */
|
#endif /* _SMB2PROTO_H */
|
||||||
|
|
Loading…
Reference in New Issue