Skip to content

Commit cf2ce67

Browse files
palismfrench
authored andcommitted
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 <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 89c601a commit cf2ce67

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

fs/smb/client/inode.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
529529
struct cifs_fid fid;
530530
struct cifs_open_parms oparms;
531531
struct cifs_io_parms io_parms = {0};
532+
char *symlink_buf_utf16;
533+
unsigned int symlink_len_utf16;
532534
char buf[24];
533535
unsigned int bytes_read;
534536
char *pbuf;
@@ -616,6 +618,33 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
616618
cifs_dbg(FYI, "Symlink\n");
617619
fattr->cf_mode |= S_IFLNK;
618620
fattr->cf_dtype = DT_LNK;
621+
if ((fattr->cf_eof > 8) && (fattr->cf_eof % 2 == 0)) {
622+
symlink_buf_utf16 = kmalloc(fattr->cf_eof-8 + 1, GFP_KERNEL);
623+
if (symlink_buf_utf16) {
624+
io_parms.offset = 8;
625+
io_parms.length = fattr->cf_eof-8 + 1;
626+
buf_type = CIFS_NO_BUFFER;
627+
rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms,
628+
&symlink_len_utf16,
629+
&symlink_buf_utf16,
630+
&buf_type);
631+
if ((rc == 0) &&
632+
(symlink_len_utf16 > 0) &&
633+
(symlink_len_utf16 < fattr->cf_eof-8 + 1) &&
634+
(symlink_len_utf16 % 2 == 0)) {
635+
fattr->cf_symlink_target =
636+
cifs_strndup_from_utf16(symlink_buf_utf16,
637+
symlink_len_utf16,
638+
true,
639+
cifs_sb->local_nls);
640+
if (!fattr->cf_symlink_target)
641+
rc = -ENOMEM;
642+
}
643+
kfree(symlink_buf_utf16);
644+
} else {
645+
rc = -ENOMEM;
646+
}
647+
}
619648
} else if (memcmp("LnxFIFO", pbuf, 8) == 0) {
620649
cifs_dbg(FYI, "FIFO\n");
621650
fattr->cf_mode |= S_IFIFO;

0 commit comments

Comments
 (0)