1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Processing of reparse points 4 * 5 * Part of this file is based on code from the NTFS-3G. 6 * 7 * Copyright (c) 2008-2021 Jean-Pierre Andre 8 * Copyright (c) 2025 LG Electronics Co., Ltd. 9 */ 10 11 #include "ntfs.h" 12 #include "layout.h" 13 #include "attrib.h" 14 #include "inode.h" 15 #include "dir.h" 16 #include "volume.h" 17 #include "mft.h" 18 #include "index.h" 19 #include "lcnalloc.h" 20 #include "reparse.h" 21 22 struct wsl_link_reparse_data { 23 __le32 type; 24 char link[]; 25 }; 26 27 static bool reparse_name_is_valid(size_t size, size_t name_off, u16 len) 28 { 29 if ((name_off | len) & 1) 30 return false; 31 32 return name_off + len <= size; 33 } 34 35 /* 36 * Windows-native reparse payloads store pathnames as UTF-16 strings with '\\' 37 * separators. Convert the on-disk UTF-16 target into the mount's NLS and 38 * normalize path separators. 39 */ 40 static int ntfs_reparse_target_to_nls(struct ntfs_volume *vol, 41 const __le16 *uname, u16 ulen, 42 char **target) 43 { 44 int err, i; 45 46 *target = NULL; 47 ulen >>= 1; 48 if (!ulen) 49 return -EINVAL; 50 51 if (!uname[ulen - 1]) 52 ulen--; 53 54 err = ntfs_ucstonls(vol, uname, ulen, (unsigned char **)target, 0); 55 if (err < 0) { 56 ntfs_attr_name_free((unsigned char **)target); 57 return err; 58 } 59 60 for (i = 0; i < err; i++) { 61 if ((*target)[i] == '\\') 62 (*target)[i] = '/'; 63 } 64 65 return 0; 66 } 67 68 /* Index entry in $Extend/$Reparse */ 69 struct reparse_index { 70 struct index_entry_header header; 71 struct reparse_index_key key; 72 __le32 filling; 73 }; 74 75 __le16 reparse_index_name[] = {cpu_to_le16('$'), cpu_to_le16('R'), 0}; 76 77 78 /* 79 * Check if the reparse point attribute buffer is valid. 80 * Returns true if valid, false otherwise. 81 */ 82 static bool valid_reparse_buffer(struct ntfs_inode *ni, 83 const struct reparse_point *reparse_attr, 84 size_t size, 85 size_t payload_min_len) 86 { 87 size_t expected; 88 89 if (!ni || !reparse_attr) 90 return false; 91 92 /* Minimum size must cover reparse_point header */ 93 if (size < sizeof(struct reparse_point)) 94 return false; 95 96 /* The payload must contain the fixed fields for the current tag. */ 97 if (payload_min_len && 98 le16_to_cpu(reparse_attr->reparse_data_length) < payload_min_len) 99 return false; 100 101 /* Reserved zero tag is invalid */ 102 if (reparse_attr->reparse_tag == IO_REPARSE_TAG_RESERVED_ZERO) 103 return false; 104 105 /* Calculate expected total size */ 106 expected = sizeof(struct reparse_point) + 107 le16_to_cpu(reparse_attr->reparse_data_length); 108 109 /* Add GUID size for non-Microsoft tags */ 110 if (!(reparse_attr->reparse_tag & IO_REPARSE_TAG_IS_MICROSOFT)) 111 expected += sizeof(struct guid); 112 113 /* Buffer must exactly match the expected size */ 114 return expected == size; 115 } 116 117 /* 118 * Do some sanity checks on reparse data 119 * 120 * Microsoft reparse points have an 8-byte header whereas 121 * non-Microsoft reparse points have a 24-byte header. In each case, 122 * 'reparse_data_length' must equal the number of non-header bytes. 123 * 124 * If the reparse data looks like a junction point or symbolic 125 * link, more checks can be done. 126 */ 127 static bool valid_reparse_data(struct ntfs_inode *ni, 128 const struct reparse_point *reparse_attr, size_t size) 129 { 130 if (size < sizeof(*reparse_attr)) 131 return false; 132 133 switch (reparse_attr->reparse_tag) { 134 case IO_REPARSE_TAG_MOUNT_POINT: 135 { 136 struct mount_point_reparse_data *data; 137 size_t data_offs; 138 139 if (!valid_reparse_buffer(ni, reparse_attr, size, sizeof(*data))) 140 return false; 141 142 data = (struct mount_point_reparse_data *)reparse_attr->reparse_data; 143 data_offs = offsetof(struct reparse_point, reparse_data) + 144 offsetof(struct mount_point_reparse_data, path_buffer); 145 146 if (!reparse_name_is_valid(size, 147 data_offs + 148 le16_to_cpu(data->substitute_name_offset), 149 le16_to_cpu(data->substitute_name_length)) || 150 !reparse_name_is_valid(size, 151 data_offs + 152 le16_to_cpu(data->print_name_offset), 153 le16_to_cpu(data->print_name_length))) 154 return false; 155 break; 156 } 157 case IO_REPARSE_TAG_SYMLINK: 158 { 159 struct symlink_reparse_data *data; 160 size_t data_offs; 161 162 if (!valid_reparse_buffer(ni, reparse_attr, size, 163 sizeof(*data))) 164 return false; 165 166 data = (struct symlink_reparse_data *)reparse_attr->reparse_data; 167 data_offs = offsetof(struct reparse_point, reparse_data) + 168 offsetof(struct symlink_reparse_data, path_buffer); 169 170 if (!reparse_name_is_valid(size, 171 data_offs + 172 le16_to_cpu(data->substitute_name_offset), 173 le16_to_cpu(data->substitute_name_length)) || 174 !reparse_name_is_valid(size, 175 data_offs + 176 le16_to_cpu(data->print_name_offset), 177 le16_to_cpu(data->print_name_length))) 178 return false; 179 break; 180 } 181 case IO_REPARSE_TAG_LX_SYMLINK: 182 { 183 struct wsl_link_reparse_data *data; 184 185 if (!valid_reparse_buffer(ni, reparse_attr, size, 186 sizeof(*data))) 187 return false; 188 189 data = (struct wsl_link_reparse_data *)reparse_attr->reparse_data; 190 191 if (le16_to_cpu(reparse_attr->reparse_data_length) <= sizeof(data->type) || 192 data->type != cpu_to_le32(2)) 193 return false; 194 break; 195 } 196 case IO_REPARSE_TAG_AF_UNIX: 197 case IO_REPARSE_TAG_LX_FIFO: 198 case IO_REPARSE_TAG_LX_CHR: 199 case IO_REPARSE_TAG_LX_BLK: 200 if (!valid_reparse_buffer(ni, reparse_attr, size, 0)) 201 return false; 202 if (le16_to_cpu(reparse_attr->reparse_data_length) || 203 !(ni->flags & FILE_ATTRIBUTE_RECALL_ON_OPEN)) 204 return false; 205 break; 206 default: 207 if (!valid_reparse_buffer(ni, reparse_attr, size, 0)) 208 return false; 209 break; 210 } 211 212 return true; 213 } 214 215 static unsigned int ntfs_reparse_tag_mode(__le32 reparse_tag) 216 { 217 unsigned int mode = 0; 218 219 switch (reparse_tag) { 220 case IO_REPARSE_TAG_MOUNT_POINT: 221 case IO_REPARSE_TAG_SYMLINK: 222 case IO_REPARSE_TAG_LX_SYMLINK: 223 mode = S_IFLNK; 224 break; 225 case IO_REPARSE_TAG_AF_UNIX: 226 mode = S_IFSOCK; 227 break; 228 case IO_REPARSE_TAG_LX_FIFO: 229 mode = S_IFIFO; 230 break; 231 case IO_REPARSE_TAG_LX_CHR: 232 mode = S_IFCHR; 233 break; 234 case IO_REPARSE_TAG_LX_BLK: 235 mode = S_IFBLK; 236 } 237 238 return mode; 239 } 240 241 /* 242 * Get the target for symbolic link 243 */ 244 unsigned int ntfs_make_symlink(struct ntfs_inode *ni) 245 { 246 s64 attr_size = 0; 247 int err; 248 unsigned int lth; 249 struct reparse_point *reparse_attr; 250 unsigned int mode = 0; 251 252 kvfree(ni->target); 253 ni->target = NULL; 254 ni->reparse_tag = 0; 255 ni->reparse_flags = 0; 256 257 reparse_attr = ntfs_attr_readall(ni, AT_REPARSE_POINT, NULL, 0, 258 &attr_size); 259 if (reparse_attr && 260 valid_reparse_data(ni, reparse_attr, attr_size)) { 261 err = -EINVAL; 262 263 switch (reparse_attr->reparse_tag) { 264 case IO_REPARSE_TAG_MOUNT_POINT: 265 { 266 struct mount_point_reparse_data *data = 267 (struct mount_point_reparse_data *)reparse_attr->reparse_data; 268 const __le16 *name = (const __le16 *)((u8 *)data->path_buffer + 269 le16_to_cpu(data->substitute_name_offset)); 270 271 err = ntfs_reparse_target_to_nls(ni->vol, 272 name, 273 le16_to_cpu(data->substitute_name_length), 274 &ni->target); 275 break; 276 } 277 case IO_REPARSE_TAG_SYMLINK: 278 { 279 struct symlink_reparse_data *data = 280 (struct symlink_reparse_data *)reparse_attr->reparse_data; 281 const __le16 *name = (const __le16 *)((u8 *)data->path_buffer + 282 le16_to_cpu(data->substitute_name_offset)); 283 284 err = ntfs_reparse_target_to_nls(ni->vol, 285 name, 286 le16_to_cpu(data->substitute_name_length), 287 &ni->target); 288 if (!err) 289 ni->reparse_flags = data->flags; 290 break; 291 } 292 case IO_REPARSE_TAG_LX_SYMLINK: 293 { 294 struct wsl_link_reparse_data *wsl_link_data = 295 (struct wsl_link_reparse_data *)reparse_attr->reparse_data; 296 297 if (wsl_link_data->type == cpu_to_le32(2)) { 298 lth = le16_to_cpu(reparse_attr->reparse_data_length) - 299 sizeof(wsl_link_data->type); 300 ni->target = kvzalloc(lth + 1, GFP_NOFS); 301 if (ni->target) { 302 memcpy(ni->target, wsl_link_data->link, lth); 303 ni->target[lth] = 0; 304 err = 0; 305 } 306 } 307 break; 308 } 309 default: 310 err = 0; 311 } 312 313 if (!err) { 314 mode = ntfs_reparse_tag_mode(reparse_attr->reparse_tag); 315 ni->reparse_tag = reparse_attr->reparse_tag; 316 } 317 } else 318 ni->flags &= ~FILE_ATTR_REPARSE_POINT; 319 320 if (reparse_attr) 321 kvfree(reparse_attr); 322 323 return mode; 324 } 325 326 unsigned int ntfs_reparse_tag_dt_types(struct ntfs_volume *vol, unsigned long mref) 327 { 328 s64 attr_size = 0; 329 struct reparse_point *reparse_attr; 330 unsigned int dt_type = DT_UNKNOWN; 331 struct inode *vi; 332 333 vi = ntfs_iget(vol->sb, mref); 334 if (IS_ERR(vi)) 335 return PTR_ERR(vi); 336 337 reparse_attr = (struct reparse_point *)ntfs_attr_readall(NTFS_I(vi), 338 AT_REPARSE_POINT, NULL, 0, &attr_size); 339 340 if (reparse_attr && attr_size >= sizeof(*reparse_attr)) { 341 switch (reparse_attr->reparse_tag) { 342 case IO_REPARSE_TAG_MOUNT_POINT: 343 case IO_REPARSE_TAG_SYMLINK: 344 case IO_REPARSE_TAG_LX_SYMLINK: 345 dt_type = DT_LNK; 346 break; 347 case IO_REPARSE_TAG_AF_UNIX: 348 dt_type = DT_SOCK; 349 break; 350 case IO_REPARSE_TAG_LX_FIFO: 351 dt_type = DT_FIFO; 352 break; 353 case IO_REPARSE_TAG_LX_CHR: 354 dt_type = DT_CHR; 355 break; 356 case IO_REPARSE_TAG_LX_BLK: 357 dt_type = DT_BLK; 358 } 359 } 360 361 if (reparse_attr) 362 kvfree(reparse_attr); 363 364 iput(vi); 365 return dt_type; 366 } 367 368 static bool ntfs_is_drive_letter(const char *target) 369 { 370 return ((target[0] >= 'A' && target[0] <= 'Z') || 371 (target[0] >= 'a' && target[0] <= 'z')) && 372 target[1] == ':'; 373 } 374 375 /* 376 * ntfs_translate_symlink_path 377 * 378 * @dentry: dentry of the symlink/junction being resolved 379 * @target: NUL-terminated NLS target string with '\\' already normalized to '/' 380 * @translated: out parameter, set to a newly kmalloc'd relative path on success 381 * 382 * Windows junctions (IO_REPARSE_TAG_MOUNT_POINT) and non-relative symlinks 383 * (IO_REPARSE_TAG_SYMLINK without SYMLINK_FLAG_RELATIVE) store substitute 384 * names such as "/??/C:/foo", "//?/C:/foo", "/foo", or "C:/foo". Linux 385 * cannot continue pathname lookup from those syntaxes, so rewrite them as a 386 * path relative to the symlink's containing directory on this NTFS volume, 387 * anchored at the volume root via "../". 388 * 389 * Note: bind-mounted subtrees of the volume may resolve to unexpected 390 * locations because the computed "../" depth is relative to the NTFS volume 391 * root, not the bind-mounted subtree root. 392 * 393 * Return: 0 on success with *translated set to a newly allocated string the 394 * caller must kfree(); negative errno on failure. 395 */ 396 int ntfs_translate_symlink_path(struct dentry *dentry, const char *target, 397 char **translated) 398 { 399 char *buf, *link_path, *out, *p; 400 const char *path, *tail; 401 unsigned int up_levels = 0; 402 size_t tail_len, out_len; 403 int err; 404 405 if (!dentry || !target || !translated) 406 return -EINVAL; 407 408 path = target; 409 /* reject UNC path. */ 410 if (path[0] == '/' && path[1] == '/' && 411 !(path[2] == '?' && path[3] == '/')) 412 return -EOPNOTSUPP; 413 414 /* target starts with "/??/" or "//?/"? */ 415 if ((path[0] == '/' && path[1] == '?' && path[2] == '?' && path[3] == '/') || 416 (path[0] == '/' && path[1] == '/' && path[2] == '?' && path[3] == '/')) 417 path += 4; 418 419 /* target must start with a drive character or '/'. */ 420 if (ntfs_is_drive_letter(path)) { 421 if (path[2] && path[2] != '/') 422 return -EOPNOTSUPP; 423 tail = path + 2; 424 if (*tail == '/') 425 tail++; 426 } else if (*path == '/') { 427 tail = path + 1; 428 } else { 429 return -EOPNOTSUPP; 430 } 431 432 tail_len = strlen(tail); 433 434 buf = kmalloc(PATH_MAX, GFP_NOFS); 435 if (!buf) 436 return -ENOMEM; 437 438 link_path = dentry_path_raw(dentry, buf, PATH_MAX); 439 if (IS_ERR(link_path)) { 440 err = PTR_ERR(link_path); 441 goto out; 442 } 443 444 /* count '/' after the leading slash. */ 445 for (p = link_path + 1; *p; p++) 446 if (*p == '/') 447 up_levels++; 448 449 /* build "./" + ("../" * up_levels) + tail. */ 450 out_len = 2 + up_levels * 3 + tail_len; 451 if (out_len >= PATH_MAX) { 452 err = -ENAMETOOLONG; 453 goto out; 454 } 455 456 out = kmalloc(out_len + 1, GFP_NOFS); 457 if (!out) { 458 err = -ENOMEM; 459 goto out; 460 } 461 462 memcpy(out, "./", 2); 463 p = out + 2; 464 while (up_levels--) { 465 memcpy(p, "../", 3); 466 p += 3; 467 } 468 memcpy(p, tail, tail_len + 1); 469 470 *translated = out; 471 err = 0; 472 out: 473 kfree(buf); 474 return err; 475 } 476 477 /* 478 * Set the index for new reparse data 479 */ 480 static int set_reparse_index(struct ntfs_inode *ni, struct ntfs_index_context *xr, 481 __le32 reparse_tag) 482 { 483 struct reparse_index indx; 484 u64 file_id_cpu; 485 __le64 file_id; 486 487 file_id_cpu = MK_MREF(ni->mft_no, ni->seq_no); 488 file_id = cpu_to_le64(file_id_cpu); 489 indx.header.data.vi.data_offset = 490 cpu_to_le16(sizeof(struct index_entry_header) + sizeof(struct reparse_index_key)); 491 indx.header.data.vi.data_length = 0; 492 indx.header.data.vi.reservedV = 0; 493 indx.header.length = cpu_to_le16(sizeof(struct reparse_index)); 494 indx.header.key_length = cpu_to_le16(sizeof(struct reparse_index_key)); 495 indx.header.flags = 0; 496 indx.header.reserved = 0; 497 indx.key.reparse_tag = reparse_tag; 498 /* danger on processors which require proper alignment! */ 499 memcpy(&indx.key.file_id, &file_id, 8); 500 indx.filling = 0; 501 ntfs_index_ctx_reinit(xr); 502 503 return ntfs_ie_add(xr, (struct index_entry *)&indx); 504 } 505 506 /* 507 * Remove a reparse data index entry if attribute present 508 */ 509 static int remove_reparse_index(struct inode *rp, struct ntfs_index_context *xr, 510 __le32 *preparse_tag) 511 { 512 struct reparse_index_key key; 513 u64 file_id_cpu; 514 __le64 file_id; 515 s64 size; 516 struct ntfs_inode *ni = NTFS_I(rp); 517 int err = 0, ret = ni->data_size; 518 519 if (ni->data_size == 0) 520 return 0; 521 522 /* read the existing reparse_tag */ 523 size = ntfs_inode_attr_pread(rp, 0, 4, (char *)preparse_tag); 524 if (size != 4) 525 return -ENODATA; 526 527 file_id_cpu = MK_MREF(ni->mft_no, ni->seq_no); 528 file_id = cpu_to_le64(file_id_cpu); 529 key.reparse_tag = *preparse_tag; 530 /* danger on processors which require proper alignment! */ 531 memcpy(&key.file_id, &file_id, 8); 532 if (!ntfs_index_lookup(&key, sizeof(struct reparse_index_key), xr)) { 533 err = ntfs_index_rm(xr); 534 if (err) 535 ret = err; 536 } 537 return ret; 538 } 539 540 /* 541 * Open the $Extend/$Reparse file and its index 542 */ 543 static struct ntfs_index_context *open_reparse_index(struct ntfs_volume *vol) 544 { 545 struct ntfs_index_context *xr = NULL; 546 u64 mref; 547 __le16 *uname; 548 struct ntfs_name *name = NULL; 549 int uname_len; 550 struct inode *vi, *dir_vi; 551 552 /* do not use path_name_to inode - could reopen root */ 553 dir_vi = ntfs_iget(vol->sb, FILE_Extend); 554 if (IS_ERR(dir_vi)) 555 return NULL; 556 557 uname_len = ntfs_nlstoucs(vol, "$Reparse", 8, &uname, 558 NTFS_MAX_NAME_LEN); 559 if (uname_len < 0) { 560 iput(dir_vi); 561 return NULL; 562 } 563 564 mutex_lock_nested(&NTFS_I(dir_vi)->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 565 mref = ntfs_lookup_inode_by_name(NTFS_I(dir_vi), uname, uname_len, 566 &name); 567 mutex_unlock(&NTFS_I(dir_vi)->mrec_lock); 568 kfree(name); 569 kmem_cache_free(ntfs_name_cache, uname); 570 if (IS_ERR_MREF(mref)) 571 goto put_dir_vi; 572 573 vi = ntfs_iget(vol->sb, MREF(mref)); 574 if (IS_ERR(vi)) 575 goto put_dir_vi; 576 577 xr = ntfs_index_ctx_get(NTFS_I(vi), reparse_index_name, 2); 578 if (!xr) 579 iput(vi); 580 put_dir_vi: 581 iput(dir_vi); 582 return xr; 583 } 584 585 586 /* 587 * Update the reparse data and index 588 * 589 * The reparse data attribute should have been created, and 590 * an existing index is expected if there is an existing value. 591 * 592 */ 593 static int update_reparse_data(struct ntfs_inode *ni, struct ntfs_index_context *xr, 594 char *value, size_t size) 595 { 596 struct inode *rp_inode; 597 int err = 0; 598 s64 written; 599 int oldsize; 600 __le32 reparse_tag; 601 struct ntfs_inode *rp_ni; 602 603 rp_inode = ntfs_attr_iget(VFS_I(ni), AT_REPARSE_POINT, AT_UNNAMED, 0); 604 if (IS_ERR(rp_inode)) 605 return -EINVAL; 606 rp_ni = NTFS_I(rp_inode); 607 608 /* remove the existing reparse data */ 609 oldsize = remove_reparse_index(rp_inode, xr, &reparse_tag); 610 if (oldsize < 0) { 611 err = oldsize; 612 goto put_rp_inode; 613 } 614 615 /* overwrite value if any */ 616 written = ntfs_inode_attr_pwrite(rp_inode, 0, size, value, false); 617 if (written != size) { 618 ntfs_error(ni->vol->sb, "Failed to update reparse data\n"); 619 err = -EIO; 620 goto put_rp_inode; 621 } 622 623 if (set_reparse_index(ni, xr, ((const struct reparse_point *)value)->reparse_tag) && 624 oldsize > 0) { 625 /* 626 * If cannot index, try to remove the reparse 627 * data and log the error. There will be an 628 * inconsistency if removal fails. 629 */ 630 ntfs_attr_rm(rp_ni); 631 ntfs_error(ni->vol->sb, 632 "Failed to index reparse data. Possible corruption.\n"); 633 } 634 635 mark_mft_record_dirty(ni); 636 put_rp_inode: 637 iput(rp_inode); 638 639 return err; 640 } 641 642 /* 643 * Delete a reparse index entry 644 */ 645 int ntfs_delete_reparse_index(struct ntfs_inode *ni) 646 { 647 struct inode *vi; 648 struct ntfs_index_context *xr; 649 struct ntfs_inode *xrni; 650 __le32 reparse_tag; 651 int err = 0; 652 653 if (!(ni->flags & FILE_ATTR_REPARSE_POINT)) 654 return 0; 655 656 vi = ntfs_attr_iget(VFS_I(ni), AT_REPARSE_POINT, AT_UNNAMED, 0); 657 if (IS_ERR(vi)) 658 return PTR_ERR(vi); 659 660 /* 661 * read the existing reparse data (the tag is enough) 662 * and un-index it 663 */ 664 xr = open_reparse_index(ni->vol); 665 if (xr) { 666 xrni = xr->idx_ni; 667 mutex_lock_nested(&xrni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 668 err = remove_reparse_index(vi, xr, &reparse_tag); 669 if (err < 0) { 670 ntfs_index_ctx_put(xr); 671 mutex_unlock(&xrni->mrec_lock); 672 iput(VFS_I(xrni)); 673 goto out; 674 } 675 mark_mft_record_dirty(xrni); 676 ntfs_index_ctx_put(xr); 677 mutex_unlock(&xrni->mrec_lock); 678 iput(VFS_I(xrni)); 679 } 680 681 ni->flags &= ~FILE_ATTR_REPARSE_POINT; 682 NInoSetFileNameDirty(ni); 683 mark_mft_record_dirty(ni); 684 685 out: 686 iput(vi); 687 return err; 688 } 689 690 /* 691 * Set the reparse data from an extended attribute 692 */ 693 static int ntfs_set_ntfs_reparse_data(struct ntfs_inode *ni, char *value, size_t size) 694 { 695 int err = 0; 696 struct ntfs_inode *xrni; 697 struct ntfs_index_context *xr; 698 699 if (!ni) 700 return -EINVAL; 701 702 /* 703 * reparse data compatibily with EA is not checked 704 * any more, it is required by Windows 10, but may 705 * lead to problems with earlier versions. 706 */ 707 if (valid_reparse_data(ni, (const struct reparse_point *)value, size) == false) 708 return -EINVAL; 709 710 xr = open_reparse_index(ni->vol); 711 if (!xr) 712 return -EINVAL; 713 xrni = xr->idx_ni; 714 715 if (!ntfs_attr_exist(ni, AT_REPARSE_POINT, AT_UNNAMED, 0)) { 716 struct reparse_point rp = {0, }; 717 718 /* 719 * no reparse data attribute : add one, 720 * apparently, this does not feed the new value in 721 * Note : NTFS version must be >= 3 722 */ 723 if (ni->vol->major_ver < 3) { 724 err = -EOPNOTSUPP; 725 ntfs_index_ctx_put(xr); 726 goto out; 727 } 728 729 err = ntfs_attr_add(ni, AT_REPARSE_POINT, AT_UNNAMED, 0, (u8 *)&rp, sizeof(rp)); 730 if (err) { 731 ntfs_index_ctx_put(xr); 732 goto out; 733 } 734 ni->flags |= FILE_ATTR_REPARSE_POINT; 735 NInoSetFileNameDirty(ni); 736 mark_mft_record_dirty(ni); 737 } 738 739 /* update value and index */ 740 mutex_lock_nested(&xrni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 741 err = update_reparse_data(ni, xr, value, size); 742 if (err) { 743 ni->flags &= ~FILE_ATTR_REPARSE_POINT; 744 NInoSetFileNameDirty(ni); 745 mark_mft_record_dirty(ni); 746 } 747 ntfs_index_ctx_put(xr); 748 mutex_unlock(&xrni->mrec_lock); 749 750 out: 751 if (!err) 752 mark_mft_record_dirty(xrni); 753 iput(VFS_I(xrni)); 754 755 return err; 756 } 757 758 /* 759 * Set reparse data for a WSL type symlink 760 */ 761 int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni, 762 const char *target, int target_len) 763 { 764 int err = 0; 765 int reparse_len; 766 struct reparse_point *reparse; 767 struct wsl_link_reparse_data *data; 768 769 reparse_len = sizeof(struct reparse_point) + sizeof(data->type) + 770 target_len; 771 reparse = kvzalloc(reparse_len, GFP_NOFS); 772 if (!reparse) 773 return -ENOMEM; 774 775 ni->target = kstrdup(target, GFP_NOFS); 776 if (!ni->target) { 777 kvfree(reparse); 778 return -ENOMEM; 779 } 780 781 data = (struct wsl_link_reparse_data *)reparse->reparse_data; 782 reparse->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; 783 reparse->reparse_data_length = 784 cpu_to_le16(sizeof(data->type) + target_len); 785 reparse->reserved = 0; 786 data->type = cpu_to_le32(2); 787 memcpy(data->link, target, target_len); 788 err = ntfs_set_ntfs_reparse_data(ni, 789 (char *)reparse, reparse_len); 790 kvfree(reparse); 791 if (err) { 792 kfree(ni->target); 793 ni->target = NULL; 794 } else { 795 ni->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; 796 ni->reparse_flags = 0; 797 } 798 return err; 799 } 800 801 int ntfs_reparse_set_native_symlink(struct ntfs_inode *ni, 802 const char *target, int target_len) 803 { 804 int err = 0; 805 bool is_absolute, prt_sub_shared = true; 806 char *sub_name = NULL; 807 char *prt_name = NULL; 808 __le16 *sub_name_utf16 = NULL; 809 __le16 *prt_name_utf16 = NULL; 810 int sub_len, prt_len; 811 int total_data_len, total_reparse_len; 812 struct reparse_point *reparse = NULL; 813 struct symlink_reparse_data *data; 814 int i; 815 816 /* Determine if target is absolute (starts with drive letter like C:/ or C:\) */ 817 is_absolute = target_len > 2 && 818 ntfs_is_drive_letter(target) && 819 (target[2] == '/' || target[2] == '\\'); 820 821 822 /* Normalize and prepare NLS paths */ 823 prt_name = kstrdup(target, GFP_NOFS); 824 if (!prt_name) 825 return -ENOMEM; 826 827 /* Replace '/' with '\' */ 828 for (i = 0; i < target_len; i++) { 829 if (prt_name[i] == '/') 830 prt_name[i] = '\\'; 831 } 832 833 if (is_absolute) { 834 /* Prepend '\??\' to Substitutename */ 835 sub_name = kmalloc(target_len + 5, GFP_NOFS); 836 if (!sub_name) { 837 err = -ENOMEM; 838 goto out; 839 } 840 snprintf(sub_name, target_len + 5, "\\??\\%s", prt_name); 841 prt_sub_shared = false; 842 } else { 843 /* For relative symlinks (including absolute paths without drive letters), 844 * SubstituteName and PrintName are identical. 845 */ 846 sub_name = prt_name; 847 } 848 849 /* Convert NLS paths to UTF-16 */ 850 sub_len = ntfs_nlstoucs(ni->vol, sub_name, strlen(sub_name), 851 &sub_name_utf16, PATH_MAX); 852 if (sub_len < 0) { 853 err = sub_len; 854 goto out; 855 } 856 857 prt_len = ntfs_nlstoucs(ni->vol, prt_name, strlen(prt_name), 858 &prt_name_utf16, PATH_MAX); 859 if (prt_len < 0) { 860 err = prt_len; 861 goto out; 862 } 863 864 /* Check for buffer size limits */ 865 total_data_len = sizeof(struct symlink_reparse_data) + 866 (sub_len + prt_len) * sizeof(__le16); 867 if (total_data_len > 16384) { /* 16KB max reparse tag size */ 868 err = -EFBIG; 869 goto out; 870 } 871 872 total_reparse_len = sizeof(struct reparse_point) + total_data_len; 873 reparse = kvzalloc(total_reparse_len, GFP_NOFS); 874 if (!reparse) { 875 err = -ENOMEM; 876 goto out; 877 } 878 879 /* Pack fields in reparse buffer */ 880 reparse->reparse_tag = IO_REPARSE_TAG_SYMLINK; 881 reparse->reparse_data_length = cpu_to_le16(total_data_len); 882 reparse->reserved = 0; 883 884 data = (struct symlink_reparse_data *)reparse->reparse_data; 885 data->substitute_name_offset = 0; 886 data->substitute_name_length = cpu_to_le16(sub_len * sizeof(__le16)); 887 data->print_name_offset = data->substitute_name_length; 888 data->print_name_length = cpu_to_le16(prt_len * sizeof(__le16)); 889 data->flags = is_absolute ? 0 : cpu_to_le32(SYMLINK_FLAG_RELATIVE); 890 891 /* Copy names to path_buffer */ 892 memcpy(data->path_buffer, sub_name_utf16, sub_len * sizeof(__le16)); 893 memcpy(data->path_buffer + sub_len, prt_name_utf16, prt_len * sizeof(__le16)); 894 895 err = ntfs_set_ntfs_reparse_data(ni, (char *)reparse, total_reparse_len); 896 if (!err) { 897 int len = strlen(sub_name); 898 899 for (i = 0; i < len; i++) { 900 if (sub_name[i] == '\\') 901 sub_name[i] = '/'; 902 } 903 ni->target = sub_name; 904 sub_name = NULL; 905 if (prt_sub_shared) 906 prt_name = NULL; 907 ni->reparse_tag = IO_REPARSE_TAG_SYMLINK; 908 ni->reparse_flags = is_absolute ? 0 : 909 cpu_to_le32(SYMLINK_FLAG_RELATIVE); 910 } 911 912 out: 913 kfree(prt_name); 914 if (!prt_sub_shared) 915 kfree(sub_name); 916 kvfree(sub_name_utf16); 917 kvfree(prt_name_utf16); 918 kvfree(reparse); 919 return err; 920 } 921 922 /* 923 * Set reparse data for a WSL special file other than a symlink 924 * (socket, fifo, character or block device) 925 */ 926 int ntfs_reparse_set_wsl_not_symlink(struct ntfs_inode *ni, mode_t mode) 927 { 928 int err; 929 int len; 930 int reparse_len; 931 __le32 reparse_tag; 932 struct reparse_point *reparse; 933 934 len = 0; 935 if (S_ISSOCK(mode)) 936 reparse_tag = IO_REPARSE_TAG_AF_UNIX; 937 else if (S_ISFIFO(mode)) 938 reparse_tag = IO_REPARSE_TAG_LX_FIFO; 939 else if (S_ISCHR(mode)) 940 reparse_tag = IO_REPARSE_TAG_LX_CHR; 941 else if (S_ISBLK(mode)) 942 reparse_tag = IO_REPARSE_TAG_LX_BLK; 943 else 944 return -EOPNOTSUPP; 945 946 reparse_len = sizeof(struct reparse_point) + len; 947 reparse = kvzalloc(reparse_len, GFP_NOFS); 948 if (!reparse) 949 err = -ENOMEM; 950 else { 951 reparse->reparse_tag = reparse_tag; 952 reparse->reparse_data_length = cpu_to_le16(len); 953 reparse->reserved = cpu_to_le16(0); 954 err = ntfs_set_ntfs_reparse_data(ni, (char *)reparse, 955 reparse_len); 956 kvfree(reparse); 957 if (!err) { 958 ni->reparse_tag = reparse_tag; 959 ni->reparse_flags = 0; 960 } 961 } 962 963 return err; 964 } 965