cifs: Add support for creating WSL-style symlinks

This change implements support for creating new symlink in WSL-style by
Linux cifs client when -o reparse=wsl mount option is specified. WSL-style
symlink uses reparse point with tag IO_REPARSE_TAG_LX_SYMLINK and symlink
target location is stored in reparse buffer in UTF-8 encoding prefixed by
32-bit flags. Flags bits are unknown, but it was observed that WSL always
sets flags to value 0x02000000. Do same in Linux cifs client.

New symlinks would be created in WSL-style only in case the mount option
-o reparse=wsl is specified, which is not by default. So default CIFS
mounts are not affected by this change.

Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by Pali Rohár and committed by Steve French 4e2043be eea5119f

+53 -12
+53 -12
fs/smb/client/reparse.c
··· 505 505 return rc; 506 506 } 507 507 508 - static int wsl_set_reparse_buf(struct reparse_data_buffer *buf, 509 - mode_t mode, struct kvec *iov) 508 + static int wsl_set_reparse_buf(struct reparse_data_buffer **buf, 509 + mode_t mode, const char *symname, 510 + struct cifs_sb_info *cifs_sb, 511 + struct kvec *iov) 510 512 { 513 + struct reparse_wsl_symlink_data_buffer *symlink_buf; 514 + __le16 *symname_utf16; 515 + int symname_utf16_len; 516 + int symname_utf8_maxlen; 517 + int symname_utf8_len; 518 + size_t buf_len; 511 519 u32 tag; 512 520 513 521 switch ((tag = reparse_mode_wsl_tag(mode))) { ··· 523 515 case IO_REPARSE_TAG_LX_CHR: 524 516 case IO_REPARSE_TAG_LX_FIFO: 525 517 case IO_REPARSE_TAG_AF_UNIX: 518 + buf_len = sizeof(struct reparse_data_buffer); 519 + *buf = kzalloc(buf_len, GFP_KERNEL); 520 + if (!*buf) 521 + return -ENOMEM; 526 522 break; 527 - case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */ 523 + case IO_REPARSE_TAG_LX_SYMLINK: 524 + symname_utf16 = cifs_strndup_to_utf16(symname, strlen(symname), 525 + &symname_utf16_len, 526 + cifs_sb->local_nls, 527 + NO_MAP_UNI_RSVD); 528 + if (!symname_utf16) 529 + return -ENOMEM; 530 + symname_utf8_maxlen = symname_utf16_len/2*3; 531 + symlink_buf = kzalloc(sizeof(struct reparse_wsl_symlink_data_buffer) + 532 + symname_utf8_maxlen, GFP_KERNEL); 533 + if (!symlink_buf) { 534 + kfree(symname_utf16); 535 + return -ENOMEM; 536 + } 537 + /* Flag 0x02000000 is unknown, but all wsl symlinks have this value */ 538 + symlink_buf->Flags = cpu_to_le32(0x02000000); 539 + /* PathBuffer is in UTF-8 but without trailing null-term byte */ 540 + symname_utf8_len = utf16s_to_utf8s((wchar_t *)symname_utf16, symname_utf16_len/2, 541 + UTF16_LITTLE_ENDIAN, 542 + symlink_buf->PathBuffer, 543 + symname_utf8_maxlen); 544 + *buf = (struct reparse_data_buffer *)symlink_buf; 545 + buf_len = sizeof(struct reparse_wsl_symlink_data_buffer) + symname_utf8_len; 546 + kfree(symname_utf16); 547 + break; 528 548 default: 529 549 return -EOPNOTSUPP; 530 550 } 531 551 532 - buf->ReparseTag = cpu_to_le32(tag); 533 - buf->Reserved = 0; 534 - buf->ReparseDataLength = 0; 535 - iov->iov_base = buf; 536 - iov->iov_len = sizeof(*buf); 552 + (*buf)->ReparseTag = cpu_to_le32(tag); 553 + (*buf)->Reserved = 0; 554 + (*buf)->ReparseDataLength = cpu_to_le16(buf_len - sizeof(struct reparse_data_buffer)); 555 + iov->iov_base = *buf; 556 + iov->iov_len = buf_len; 537 557 return 0; 538 558 } 539 559 ··· 653 617 const char *full_path, umode_t mode, dev_t dev, 654 618 const char *symname) 655 619 { 620 + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 656 621 struct cifs_open_info_data data; 657 - struct reparse_data_buffer buf; 622 + struct reparse_data_buffer *buf; 658 623 struct smb2_create_ea_ctx *cc; 659 624 struct inode *new; 660 625 unsigned int len; 661 626 struct kvec reparse_iov, xattr_iov; 662 627 int rc; 663 628 664 - rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov); 629 + rc = wsl_set_reparse_buf(&buf, mode, symname, cifs_sb, &reparse_iov); 665 630 if (rc) 666 631 return rc; 667 632 668 633 rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov); 669 - if (rc) 634 + if (rc) { 635 + kfree(buf); 670 636 return rc; 637 + } 671 638 672 639 data = (struct cifs_open_info_data) { 673 640 .reparse_point = true, 674 - .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, }, 641 + .reparse = { .tag = le32_to_cpu(buf->ReparseTag), .buf = buf, }, 642 + .symlink_target = kstrdup(symname, GFP_KERNEL), 675 643 }; 676 644 677 645 cc = xattr_iov.iov_base; ··· 692 652 rc = PTR_ERR(new); 693 653 cifs_free_open_info(&data); 694 654 kfree(xattr_iov.iov_base); 655 + kfree(buf); 695 656 return rc; 696 657 } 697 658