mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 23:23:03 +00:00
cifs: Add support for reading SFU symlink location
Currently when sfu mount option is specified then CIFS can recognize SFU symlink, but is not able to read symlink target location. readlink() syscall just returns that operation is not supported. Implement this missing functionality in cifs_sfu_type() function. Read target location of SFU-style symlink, parse it and fill into fattr's cf_symlink_target member. SFU-style symlink is file which has system attribute set and file content is buffer "IntxLNK\1" (8th byte is 0x01) followed by the target location encoded in little endian UCS-2/UTF-16. This format was introduced in Interix 3.0 subsystem, as part of the Microsoft SFU 3.0 and is used also by all later versions. Previous versions had no symlink support. Signed-off-by: Pali Rohár <pali@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
89c601ab7c
commit
cf2ce67345
@ -529,6 +529,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_io_parms io_parms = {0};
|
||||
char *symlink_buf_utf16;
|
||||
unsigned int symlink_len_utf16;
|
||||
char buf[24];
|
||||
unsigned int bytes_read;
|
||||
char *pbuf;
|
||||
@ -616,6 +618,33 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
|
||||
cifs_dbg(FYI, "Symlink\n");
|
||||
fattr->cf_mode |= S_IFLNK;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
if ((fattr->cf_eof > 8) && (fattr->cf_eof % 2 == 0)) {
|
||||
symlink_buf_utf16 = kmalloc(fattr->cf_eof-8 + 1, GFP_KERNEL);
|
||||
if (symlink_buf_utf16) {
|
||||
io_parms.offset = 8;
|
||||
io_parms.length = fattr->cf_eof-8 + 1;
|
||||
buf_type = CIFS_NO_BUFFER;
|
||||
rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms,
|
||||
&symlink_len_utf16,
|
||||
&symlink_buf_utf16,
|
||||
&buf_type);
|
||||
if ((rc == 0) &&
|
||||
(symlink_len_utf16 > 0) &&
|
||||
(symlink_len_utf16 < fattr->cf_eof-8 + 1) &&
|
||||
(symlink_len_utf16 % 2 == 0)) {
|
||||
fattr->cf_symlink_target =
|
||||
cifs_strndup_from_utf16(symlink_buf_utf16,
|
||||
symlink_len_utf16,
|
||||
true,
|
||||
cifs_sb->local_nls);
|
||||
if (!fattr->cf_symlink_target)
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
kfree(symlink_buf_utf16);
|
||||
} else {
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
}
|
||||
} else if (memcmp("LnxFIFO", pbuf, 8) == 0) {
|
||||
cifs_dbg(FYI, "FIFO\n");
|
||||
fattr->cf_mode |= S_IFIFO;
|
||||
|
Loading…
Reference in New Issue
Block a user