733 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2024 Paulo Alcantara <pc@manguebit.com>4 */5 6#include <linux/fs.h>7#include <linux/stat.h>8#include <linux/slab.h>9#include "cifsglob.h"10#include "smb2proto.h"11#include "cifsproto.h"12#include "cifs_unicode.h"13#include "cifs_debug.h"14#include "fs_context.h"15#include "reparse.h"16 17static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,18 const unsigned int xid,19 const char *full_path,20 const char *symname,21 bool *directory);22 23int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,24 struct dentry *dentry, struct cifs_tcon *tcon,25 const char *full_path, const char *symname)26{27 struct reparse_symlink_data_buffer *buf = NULL;28 struct cifs_open_info_data data;29 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);30 struct inode *new;31 struct kvec iov;32 __le16 *path;33 bool directory;34 char *sym, sep = CIFS_DIR_SEP(cifs_sb);35 u16 len, plen;36 int rc = 0;37 38 sym = kstrdup(symname, GFP_KERNEL);39 if (!sym)40 return -ENOMEM;41 42 data = (struct cifs_open_info_data) {43 .reparse_point = true,44 .reparse = { .tag = IO_REPARSE_TAG_SYMLINK, },45 .symlink_target = sym,46 };47 48 convert_delimiter(sym, sep);49 path = cifs_convert_path_to_utf16(sym, cifs_sb);50 if (!path) {51 rc = -ENOMEM;52 goto out;53 }54 55 /*56 * SMB distinguish between symlink to directory and symlink to file.57 * They cannot be exchanged (symlink of file type which points to58 * directory cannot be resolved and vice-versa). Try to detect if59 * the symlink target could be a directory or not. When detection60 * fails then treat symlink as a file (non-directory) symlink.61 */62 directory = false;63 rc = detect_directory_symlink_target(cifs_sb, xid, full_path, symname, &directory);64 if (rc < 0)65 goto out;66 67 plen = 2 * UniStrnlen((wchar_t *)path, PATH_MAX);68 len = sizeof(*buf) + plen * 2;69 buf = kzalloc(len, GFP_KERNEL);70 if (!buf) {71 rc = -ENOMEM;72 goto out;73 }74 75 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_SYMLINK);76 buf->ReparseDataLength = cpu_to_le16(len - sizeof(struct reparse_data_buffer));77 buf->SubstituteNameOffset = cpu_to_le16(plen);78 buf->SubstituteNameLength = cpu_to_le16(plen);79 memcpy(&buf->PathBuffer[plen], path, plen);80 buf->PrintNameOffset = 0;81 buf->PrintNameLength = cpu_to_le16(plen);82 memcpy(buf->PathBuffer, path, plen);83 buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0);84 if (*sym != sep)85 buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE);86 87 convert_delimiter(sym, '/');88 iov.iov_base = buf;89 iov.iov_len = len;90 new = smb2_get_reparse_inode(&data, inode->i_sb, xid,91 tcon, full_path, directory,92 &iov, NULL);93 if (!IS_ERR(new))94 d_instantiate(dentry, new);95 else96 rc = PTR_ERR(new);97out:98 kfree(path);99 cifs_free_open_info(&data);100 kfree(buf);101 return rc;102}103 104static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,105 const unsigned int xid,106 const char *full_path,107 const char *symname,108 bool *directory)109{110 char sep = CIFS_DIR_SEP(cifs_sb);111 struct cifs_open_parms oparms;112 struct tcon_link *tlink;113 struct cifs_tcon *tcon;114 const char *basename;115 struct cifs_fid fid;116 char *resolved_path;117 int full_path_len;118 int basename_len;119 int symname_len;120 char *path_sep;121 __u32 oplock;122 int open_rc;123 124 /*125 * First do some simple check. If the original Linux symlink target ends126 * with slash, or last path component is dot or dot-dot then it is for127 * sure symlink to the directory.128 */129 basename = kbasename(symname);130 basename_len = strlen(basename);131 if (basename_len == 0 || /* symname ends with slash */132 (basename_len == 1 && basename[0] == '.') || /* last component is "." */133 (basename_len == 2 && basename[0] == '.' && basename[1] == '.')) { /* or ".." */134 *directory = true;135 return 0;136 }137 138 /*139 * For absolute symlinks it is not possible to determinate140 * if it should point to directory or file.141 */142 if (symname[0] == '/') {143 cifs_dbg(FYI,144 "%s: cannot determinate if the symlink target path '%s' "145 "is directory or not, creating '%s' as file symlink\n",146 __func__, symname, full_path);147 return 0;148 }149 150 /*151 * If it was not detected as directory yet and the symlink is relative152 * then try to resolve the path on the SMB server, check if the path153 * exists and determinate if it is a directory or not.154 */155 156 full_path_len = strlen(full_path);157 symname_len = strlen(symname);158 159 tlink = cifs_sb_tlink(cifs_sb);160 if (IS_ERR(tlink))161 return PTR_ERR(tlink);162 163 resolved_path = kzalloc(full_path_len + symname_len + 1, GFP_KERNEL);164 if (!resolved_path) {165 cifs_put_tlink(tlink);166 return -ENOMEM;167 }168 169 /*170 * Compose the resolved SMB symlink path from the SMB full path171 * and Linux target symlink path.172 */173 memcpy(resolved_path, full_path, full_path_len+1);174 path_sep = strrchr(resolved_path, sep);175 if (path_sep)176 path_sep++;177 else178 path_sep = resolved_path;179 memcpy(path_sep, symname, symname_len+1);180 if (sep == '\\')181 convert_delimiter(path_sep, sep);182 183 tcon = tlink_tcon(tlink);184 oparms = CIFS_OPARMS(cifs_sb, tcon, resolved_path,185 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, ACL_NO_MODE);186 oparms.fid = &fid;187 188 /* Try to open as a directory (NOT_FILE) */189 oplock = 0;190 oparms.create_options = cifs_create_options(cifs_sb,191 CREATE_NOT_FILE | OPEN_REPARSE_POINT);192 open_rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);193 if (open_rc == 0) {194 /* Successful open means that the target path is definitely a directory. */195 *directory = true;196 tcon->ses->server->ops->close(xid, tcon, &fid);197 } else if (open_rc == -ENOTDIR) {198 /* -ENOTDIR means that the target path is definitely a file. */199 *directory = false;200 } else if (open_rc == -ENOENT) {201 /* -ENOENT means that the target path does not exist. */202 cifs_dbg(FYI,203 "%s: symlink target path '%s' does not exist, "204 "creating '%s' as file symlink\n",205 __func__, symname, full_path);206 } else {207 /* Try to open as a file (NOT_DIR) */208 oplock = 0;209 oparms.create_options = cifs_create_options(cifs_sb,210 CREATE_NOT_DIR | OPEN_REPARSE_POINT);211 open_rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);212 if (open_rc == 0) {213 /* Successful open means that the target path is definitely a file. */214 *directory = false;215 tcon->ses->server->ops->close(xid, tcon, &fid);216 } else if (open_rc == -EISDIR) {217 /* -EISDIR means that the target path is definitely a directory. */218 *directory = true;219 } else {220 /*221 * This code branch is called when we do not have a permission to222 * open the resolved_path or some other client/process denied223 * opening the resolved_path.224 *225 * TODO: Try to use ops->query_dir_first on the parent directory226 * of resolved_path, search for basename of resolved_path and227 * check if the ATTR_DIRECTORY is set in fi.Attributes. In some228 * case this could work also when opening of the path is denied.229 */230 cifs_dbg(FYI,231 "%s: cannot determinate if the symlink target path '%s' "232 "is directory or not, creating '%s' as file symlink\n",233 __func__, symname, full_path);234 }235 }236 237 kfree(resolved_path);238 cifs_put_tlink(tlink);239 return 0;240}241 242static int nfs_set_reparse_buf(struct reparse_posix_data *buf,243 mode_t mode, dev_t dev,244 struct kvec *iov)245{246 u64 type;247 u16 len, dlen;248 249 len = sizeof(*buf);250 251 switch ((type = reparse_mode_nfs_type(mode))) {252 case NFS_SPECFILE_BLK:253 case NFS_SPECFILE_CHR:254 dlen = sizeof(__le64);255 break;256 case NFS_SPECFILE_FIFO:257 case NFS_SPECFILE_SOCK:258 dlen = 0;259 break;260 default:261 return -EOPNOTSUPP;262 }263 264 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_NFS);265 buf->Reserved = 0;266 buf->InodeType = cpu_to_le64(type);267 buf->ReparseDataLength = cpu_to_le16(len + dlen -268 sizeof(struct reparse_data_buffer));269 *(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MINOR(dev) << 32) |270 MAJOR(dev));271 iov->iov_base = buf;272 iov->iov_len = len + dlen;273 return 0;274}275 276static int mknod_nfs(unsigned int xid, struct inode *inode,277 struct dentry *dentry, struct cifs_tcon *tcon,278 const char *full_path, umode_t mode, dev_t dev)279{280 struct cifs_open_info_data data;281 struct reparse_posix_data *p;282 struct inode *new;283 struct kvec iov;284 __u8 buf[sizeof(*p) + sizeof(__le64)];285 int rc;286 287 p = (struct reparse_posix_data *)buf;288 rc = nfs_set_reparse_buf(p, mode, dev, &iov);289 if (rc)290 return rc;291 292 data = (struct cifs_open_info_data) {293 .reparse_point = true,294 .reparse = { .tag = IO_REPARSE_TAG_NFS, .posix = p, },295 };296 297 new = smb2_get_reparse_inode(&data, inode->i_sb, xid,298 tcon, full_path, false, &iov, NULL);299 if (!IS_ERR(new))300 d_instantiate(dentry, new);301 else302 rc = PTR_ERR(new);303 cifs_free_open_info(&data);304 return rc;305}306 307static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,308 mode_t mode, struct kvec *iov)309{310 u32 tag;311 312 switch ((tag = reparse_mode_wsl_tag(mode))) {313 case IO_REPARSE_TAG_LX_BLK:314 case IO_REPARSE_TAG_LX_CHR:315 case IO_REPARSE_TAG_LX_FIFO:316 case IO_REPARSE_TAG_AF_UNIX:317 break;318 default:319 return -EOPNOTSUPP;320 }321 322 buf->ReparseTag = cpu_to_le32(tag);323 buf->Reserved = 0;324 buf->ReparseDataLength = 0;325 iov->iov_base = buf;326 iov->iov_len = sizeof(*buf);327 return 0;328}329 330static struct smb2_create_ea_ctx *ea_create_context(u32 dlen, size_t *cc_len)331{332 struct smb2_create_ea_ctx *cc;333 334 *cc_len = round_up(sizeof(*cc) + dlen, 8);335 cc = kzalloc(*cc_len, GFP_KERNEL);336 if (!cc)337 return ERR_PTR(-ENOMEM);338 339 cc->ctx.NameOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx,340 name));341 cc->ctx.NameLength = cpu_to_le16(4);342 memcpy(cc->name, SMB2_CREATE_EA_BUFFER, strlen(SMB2_CREATE_EA_BUFFER));343 cc->ctx.DataOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx, ea));344 cc->ctx.DataLength = cpu_to_le32(dlen);345 return cc;346}347 348struct wsl_xattr {349 const char *name;350 __le64 value;351 u16 size;352 u32 next;353};354 355static int wsl_set_xattrs(struct inode *inode, umode_t _mode,356 dev_t _dev, struct kvec *iov)357{358 struct smb2_file_full_ea_info *ea;359 struct smb2_create_ea_ctx *cc;360 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;361 __le64 uid = cpu_to_le64(from_kuid(current_user_ns(), ctx->linux_uid));362 __le64 gid = cpu_to_le64(from_kgid(current_user_ns(), ctx->linux_gid));363 __le64 dev = cpu_to_le64(((u64)MINOR(_dev) << 32) | MAJOR(_dev));364 __le64 mode = cpu_to_le64(_mode);365 struct wsl_xattr xattrs[] = {366 { .name = SMB2_WSL_XATTR_UID, .value = uid, .size = SMB2_WSL_XATTR_UID_SIZE, },367 { .name = SMB2_WSL_XATTR_GID, .value = gid, .size = SMB2_WSL_XATTR_GID_SIZE, },368 { .name = SMB2_WSL_XATTR_MODE, .value = mode, .size = SMB2_WSL_XATTR_MODE_SIZE, },369 { .name = SMB2_WSL_XATTR_DEV, .value = dev, .size = SMB2_WSL_XATTR_DEV_SIZE, },370 };371 size_t cc_len;372 u32 dlen = 0, next = 0;373 int i, num_xattrs;374 u8 name_size = SMB2_WSL_XATTR_NAME_LEN + 1;375 376 memset(iov, 0, sizeof(*iov));377 378 /* Exclude $LXDEV xattr for sockets and fifos */379 if (S_ISSOCK(_mode) || S_ISFIFO(_mode))380 num_xattrs = ARRAY_SIZE(xattrs) - 1;381 else382 num_xattrs = ARRAY_SIZE(xattrs);383 384 for (i = 0; i < num_xattrs; i++) {385 xattrs[i].next = ALIGN(sizeof(*ea) + name_size +386 xattrs[i].size, 4);387 dlen += xattrs[i].next;388 }389 390 cc = ea_create_context(dlen, &cc_len);391 if (IS_ERR(cc))392 return PTR_ERR(cc);393 394 ea = &cc->ea;395 for (i = 0; i < num_xattrs; i++) {396 ea = (void *)((u8 *)ea + next);397 next = xattrs[i].next;398 ea->next_entry_offset = cpu_to_le32(next);399 400 ea->ea_name_length = name_size - 1;401 ea->ea_value_length = cpu_to_le16(xattrs[i].size);402 memcpy(ea->ea_data, xattrs[i].name, name_size);403 memcpy(&ea->ea_data[name_size],404 &xattrs[i].value, xattrs[i].size);405 }406 ea->next_entry_offset = 0;407 408 iov->iov_base = cc;409 iov->iov_len = cc_len;410 return 0;411}412 413static int mknod_wsl(unsigned int xid, struct inode *inode,414 struct dentry *dentry, struct cifs_tcon *tcon,415 const char *full_path, umode_t mode, dev_t dev)416{417 struct cifs_open_info_data data;418 struct reparse_data_buffer buf;419 struct smb2_create_ea_ctx *cc;420 struct inode *new;421 unsigned int len;422 struct kvec reparse_iov, xattr_iov;423 int rc;424 425 rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov);426 if (rc)427 return rc;428 429 rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov);430 if (rc)431 return rc;432 433 data = (struct cifs_open_info_data) {434 .reparse_point = true,435 .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, },436 };437 438 cc = xattr_iov.iov_base;439 len = le32_to_cpu(cc->ctx.DataLength);440 memcpy(data.wsl.eas, &cc->ea, len);441 data.wsl.eas_len = len;442 443 new = smb2_get_reparse_inode(&data, inode->i_sb,444 xid, tcon, full_path, false,445 &reparse_iov, &xattr_iov);446 if (!IS_ERR(new))447 d_instantiate(dentry, new);448 else449 rc = PTR_ERR(new);450 cifs_free_open_info(&data);451 kfree(xattr_iov.iov_base);452 return rc;453}454 455int smb2_mknod_reparse(unsigned int xid, struct inode *inode,456 struct dentry *dentry, struct cifs_tcon *tcon,457 const char *full_path, umode_t mode, dev_t dev)458{459 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;460 int rc = -EOPNOTSUPP;461 462 switch (ctx->reparse_type) {463 case CIFS_REPARSE_TYPE_NFS:464 rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev);465 break;466 case CIFS_REPARSE_TYPE_WSL:467 rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev);468 break;469 }470 return rc;471}472 473/* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */474static int parse_reparse_posix(struct reparse_posix_data *buf,475 struct cifs_sb_info *cifs_sb,476 struct cifs_open_info_data *data)477{478 unsigned int len;479 u64 type;480 481 len = le16_to_cpu(buf->ReparseDataLength);482 if (len < sizeof(buf->InodeType)) {483 cifs_dbg(VFS, "srv returned malformed nfs buffer\n");484 return -EIO;485 }486 487 len -= sizeof(buf->InodeType);488 489 switch ((type = le64_to_cpu(buf->InodeType))) {490 case NFS_SPECFILE_LNK:491 if (len == 0 || (len % 2)) {492 cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n");493 return -EIO;494 }495 /*496 * Check that buffer does not contain UTF-16 null codepoint497 * because Linux cannot process symlink with null byte.498 */499 if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) {500 cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n");501 return -EIO;502 }503 data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,504 len, true,505 cifs_sb->local_nls);506 if (!data->symlink_target)507 return -ENOMEM;508 cifs_dbg(FYI, "%s: target path: %s\n",509 __func__, data->symlink_target);510 break;511 case NFS_SPECFILE_CHR:512 case NFS_SPECFILE_BLK:513 /* DataBuffer for block and char devices contains two 32-bit numbers */514 if (len != 8) {515 cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);516 return -EIO;517 }518 break;519 case NFS_SPECFILE_FIFO:520 case NFS_SPECFILE_SOCK:521 /* DataBuffer for fifos and sockets is empty */522 if (len != 0) {523 cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);524 return -EIO;525 }526 break;527 default:528 cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n",529 __func__, type);530 return -EOPNOTSUPP;531 }532 return 0;533}534 535static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,536 u32 plen, bool unicode,537 struct cifs_sb_info *cifs_sb,538 struct cifs_open_info_data *data)539{540 unsigned int len;541 unsigned int offs;542 543 /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */544 545 offs = le16_to_cpu(sym->SubstituteNameOffset);546 len = le16_to_cpu(sym->SubstituteNameLength);547 if (offs + 20 > plen || offs + len + 20 > plen) {548 cifs_dbg(VFS, "srv returned malformed symlink buffer\n");549 return -EIO;550 }551 552 data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs,553 len, unicode,554 cifs_sb->local_nls);555 if (!data->symlink_target)556 return -ENOMEM;557 558 convert_delimiter(data->symlink_target, '/');559 cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target);560 561 return 0;562}563 564int parse_reparse_point(struct reparse_data_buffer *buf,565 u32 plen, struct cifs_sb_info *cifs_sb,566 bool unicode, struct cifs_open_info_data *data)567{568 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);569 570 data->reparse.buf = buf;571 572 /* See MS-FSCC 2.1.2 */573 switch (le32_to_cpu(buf->ReparseTag)) {574 case IO_REPARSE_TAG_NFS:575 return parse_reparse_posix((struct reparse_posix_data *)buf,576 cifs_sb, data);577 case IO_REPARSE_TAG_SYMLINK:578 return parse_reparse_symlink(579 (struct reparse_symlink_data_buffer *)buf,580 plen, unicode, cifs_sb, data);581 case IO_REPARSE_TAG_LX_SYMLINK:582 case IO_REPARSE_TAG_AF_UNIX:583 case IO_REPARSE_TAG_LX_FIFO:584 case IO_REPARSE_TAG_LX_CHR:585 case IO_REPARSE_TAG_LX_BLK:586 break;587 default:588 cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",589 le32_to_cpu(buf->ReparseTag));590 break;591 }592 return 0;593}594 595int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,596 struct kvec *rsp_iov,597 struct cifs_open_info_data *data)598{599 struct reparse_data_buffer *buf;600 struct smb2_ioctl_rsp *io = rsp_iov->iov_base;601 u32 plen = le32_to_cpu(io->OutputCount);602 603 buf = (struct reparse_data_buffer *)((u8 *)io +604 le32_to_cpu(io->OutputOffset));605 return parse_reparse_point(buf, plen, cifs_sb, true, data);606}607 608static void wsl_to_fattr(struct cifs_open_info_data *data,609 struct cifs_sb_info *cifs_sb,610 u32 tag, struct cifs_fattr *fattr)611{612 struct smb2_file_full_ea_info *ea;613 u32 next = 0;614 615 switch (tag) {616 case IO_REPARSE_TAG_LX_SYMLINK:617 fattr->cf_mode |= S_IFLNK;618 break;619 case IO_REPARSE_TAG_LX_FIFO:620 fattr->cf_mode |= S_IFIFO;621 break;622 case IO_REPARSE_TAG_AF_UNIX:623 fattr->cf_mode |= S_IFSOCK;624 break;625 case IO_REPARSE_TAG_LX_CHR:626 fattr->cf_mode |= S_IFCHR;627 break;628 case IO_REPARSE_TAG_LX_BLK:629 fattr->cf_mode |= S_IFBLK;630 break;631 }632 633 if (!data->wsl.eas_len)634 goto out;635 636 ea = (struct smb2_file_full_ea_info *)data->wsl.eas;637 do {638 const char *name;639 void *v;640 u8 nlen;641 642 ea = (void *)((u8 *)ea + next);643 next = le32_to_cpu(ea->next_entry_offset);644 if (!le16_to_cpu(ea->ea_value_length))645 continue;646 647 name = ea->ea_data;648 nlen = ea->ea_name_length;649 v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1);650 651 if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen))652 fattr->cf_uid = wsl_make_kuid(cifs_sb, v);653 else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen))654 fattr->cf_gid = wsl_make_kgid(cifs_sb, v);655 else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen))656 fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v);657 else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen))658 fattr->cf_rdev = reparse_mkdev(v);659 } while (next);660out:661 fattr->cf_dtype = S_DT(fattr->cf_mode);662}663 664bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,665 struct cifs_fattr *fattr,666 struct cifs_open_info_data *data)667{668 struct reparse_posix_data *buf = data->reparse.posix;669 u32 tag = data->reparse.tag;670 671 if (tag == IO_REPARSE_TAG_NFS && buf) {672 if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType))673 return false;674 switch (le64_to_cpu(buf->InodeType)) {675 case NFS_SPECFILE_CHR:676 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8)677 return false;678 fattr->cf_mode |= S_IFCHR;679 fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);680 break;681 case NFS_SPECFILE_BLK:682 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8)683 return false;684 fattr->cf_mode |= S_IFBLK;685 fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);686 break;687 case NFS_SPECFILE_FIFO:688 fattr->cf_mode |= S_IFIFO;689 break;690 case NFS_SPECFILE_SOCK:691 fattr->cf_mode |= S_IFSOCK;692 break;693 case NFS_SPECFILE_LNK:694 fattr->cf_mode |= S_IFLNK;695 break;696 default:697 WARN_ON_ONCE(1);698 return false;699 }700 goto out;701 }702 703 switch (tag) {704 case IO_REPARSE_TAG_INTERNAL:705 if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY))706 return false;707 fallthrough;708 case IO_REPARSE_TAG_DFS:709 case IO_REPARSE_TAG_DFSR:710 case IO_REPARSE_TAG_MOUNT_POINT:711 /* See cifs_create_junction_fattr() */712 fattr->cf_mode = S_IFDIR | 0711;713 break;714 case IO_REPARSE_TAG_LX_SYMLINK:715 case IO_REPARSE_TAG_LX_FIFO:716 case IO_REPARSE_TAG_AF_UNIX:717 case IO_REPARSE_TAG_LX_CHR:718 case IO_REPARSE_TAG_LX_BLK:719 wsl_to_fattr(data, cifs_sb, tag, fattr);720 break;721 case 0: /* SMB1 symlink */722 case IO_REPARSE_TAG_SYMLINK:723 case IO_REPARSE_TAG_NFS:724 fattr->cf_mode |= S_IFLNK;725 break;726 default:727 return false;728 }729out:730 fattr->cf_dtype = S_DT(fattr->cf_mode);731 return true;732}733