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