1/* 2 * fs/cifs/link.c 3 * 4 * Copyright (C) International Business Machines Corp., 2002,2008 5 * Author(s): Steve French (sfrench@us.ibm.com) 6 * 7 * This library is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU Lesser General Public License as published 9 * by the Free Software Foundation; either version 2.1 of the License, or 10 * (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 15 * the GNU Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21#include <linux/fs.h> 22#include <linux/stat.h> 23#include <linux/slab.h> 24#include <linux/namei.h> 25#include "cifsfs.h" 26#include "cifspdu.h" 27#include "cifsglob.h" 28#include "cifsproto.h" 29#include "cifs_debug.h" 30#include "cifs_fs_sb.h" 31#include "cifs_unicode.h" 32#ifdef CONFIG_CIFS_SMB2 33#include "smb2proto.h" 34#endif 35 36/* 37 * M-F Symlink Functions - Begin 38 */ 39 40#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) 41#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) 42#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) 43#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024) 44#define CIFS_MF_SYMLINK_FILE_SIZE \ 45 (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN) 46 47#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n" 48#define CIFS_MF_SYMLINK_MD5_FORMAT \ 49 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" 50#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \ 51 md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \ 52 md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \ 53 md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\ 54 md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15] 55 56static int 57symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) 58{ 59 int rc; 60 unsigned int size; 61 struct crypto_shash *md5; 62 struct sdesc *sdescmd5; 63 64 md5 = crypto_alloc_shash("md5", 0, 0); 65 if (IS_ERR(md5)) { 66 rc = PTR_ERR(md5); 67 cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n", 68 __func__, rc); 69 return rc; 70 } 71 size = sizeof(struct shash_desc) + crypto_shash_descsize(md5); 72 sdescmd5 = kmalloc(size, GFP_KERNEL); 73 if (!sdescmd5) { 74 rc = -ENOMEM; 75 goto symlink_hash_err; 76 } 77 sdescmd5->shash.tfm = md5; 78 sdescmd5->shash.flags = 0x0; 79 80 rc = crypto_shash_init(&sdescmd5->shash); 81 if (rc) { 82 cifs_dbg(VFS, "%s: Could not init md5 shash\n", __func__); 83 goto symlink_hash_err; 84 } 85 rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len); 86 if (rc) { 87 cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__); 88 goto symlink_hash_err; 89 } 90 rc = crypto_shash_final(&sdescmd5->shash, md5_hash); 91 if (rc) 92 cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); 93 94symlink_hash_err: 95 crypto_free_shash(md5); 96 kfree(sdescmd5); 97 98 return rc; 99} 100 101static int 102parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, 103 char **_link_str) 104{ 105 int rc; 106 unsigned int link_len; 107 const char *md5_str1; 108 const char *link_str; 109 u8 md5_hash[16]; 110 char md5_str2[34]; 111 112 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) 113 return -EINVAL; 114 115 md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET]; 116 link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET]; 117 118 rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len); 119 if (rc != 1) 120 return -EINVAL; 121 122 rc = symlink_hash(link_len, link_str, md5_hash); 123 if (rc) { 124 cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); 125 return rc; 126 } 127 128 snprintf(md5_str2, sizeof(md5_str2), 129 CIFS_MF_SYMLINK_MD5_FORMAT, 130 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); 131 132 if (strncmp(md5_str1, md5_str2, 17) != 0) 133 return -EINVAL; 134 135 if (_link_str) { 136 *_link_str = kstrndup(link_str, link_len, GFP_KERNEL); 137 if (!*_link_str) 138 return -ENOMEM; 139 } 140 141 *_link_len = link_len; 142 return 0; 143} 144 145static int 146format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) 147{ 148 int rc; 149 unsigned int link_len; 150 unsigned int ofs; 151 u8 md5_hash[16]; 152 153 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) 154 return -EINVAL; 155 156 link_len = strlen(link_str); 157 158 if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) 159 return -ENAMETOOLONG; 160 161 rc = symlink_hash(link_len, link_str, md5_hash); 162 if (rc) { 163 cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); 164 return rc; 165 } 166 167 snprintf(buf, buf_len, 168 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, 169 link_len, 170 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); 171 172 ofs = CIFS_MF_SYMLINK_LINK_OFFSET; 173 memcpy(buf + ofs, link_str, link_len); 174 175 ofs += link_len; 176 if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { 177 buf[ofs] = '\n'; 178 ofs++; 179 } 180 181 while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { 182 buf[ofs] = ' '; 183 ofs++; 184 } 185 186 return 0; 187} 188 189bool 190couldbe_mf_symlink(const struct cifs_fattr *fattr) 191{ 192 if (!S_ISREG(fattr->cf_mode)) 193 /* it's not a symlink */ 194 return false; 195 196 if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) 197 /* it's not a symlink */ 198 return false; 199 200 return true; 201} 202 203static int 204create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, 205 struct cifs_sb_info *cifs_sb, const char *fromName, 206 const char *toName) 207{ 208 int rc; 209 u8 *buf; 210 unsigned int bytes_written = 0; 211 212 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 213 if (!buf) 214 return -ENOMEM; 215 216 rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName); 217 if (rc) 218 goto out; 219 220 if (tcon->ses->server->ops->create_mf_symlink) 221 rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon, 222 cifs_sb, fromName, buf, &bytes_written); 223 else 224 rc = -EOPNOTSUPP; 225 226 if (rc) 227 goto out; 228 229 if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE) 230 rc = -EIO; 231out: 232 kfree(buf); 233 return rc; 234} 235 236static int 237query_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, 238 struct cifs_sb_info *cifs_sb, const unsigned char *path, 239 char **symlinkinfo) 240{ 241 int rc; 242 u8 *buf = NULL; 243 unsigned int link_len = 0; 244 unsigned int bytes_read = 0; 245 246 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 247 if (!buf) 248 return -ENOMEM; 249 250 if (tcon->ses->server->ops->query_mf_symlink) 251 rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, 252 cifs_sb, path, buf, &bytes_read); 253 else 254 rc = -ENOSYS; 255 256 if (rc) 257 goto out; 258 259 if (bytes_read == 0) { /* not a symlink */ 260 rc = -EINVAL; 261 goto out; 262 } 263 264 rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo); 265out: 266 kfree(buf); 267 return rc; 268} 269 270int 271check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 272 struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, 273 const unsigned char *path) 274{ 275 int rc; 276 u8 *buf = NULL; 277 unsigned int link_len = 0; 278 unsigned int bytes_read = 0; 279 280 if (!couldbe_mf_symlink(fattr)) 281 /* it's not a symlink */ 282 return 0; 283 284 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); 285 if (!buf) 286 return -ENOMEM; 287 288 if (tcon->ses->server->ops->query_mf_symlink) 289 rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, 290 cifs_sb, path, buf, &bytes_read); 291 else 292 rc = -ENOSYS; 293 294 if (rc) 295 goto out; 296 297 if (bytes_read == 0) /* not a symlink */ 298 goto out; 299 300 rc = parse_mf_symlink(buf, bytes_read, &link_len, NULL); 301 if (rc == -EINVAL) { 302 /* it's not a symlink */ 303 rc = 0; 304 goto out; 305 } 306 307 if (rc != 0) 308 goto out; 309 310 /* it is a symlink */ 311 fattr->cf_eof = link_len; 312 fattr->cf_mode &= ~S_IFMT; 313 fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; 314 fattr->cf_dtype = DT_LNK; 315out: 316 kfree(buf); 317 return rc; 318} 319 320/* 321 * SMB 1.0 Protocol specific functions 322 */ 323 324int 325cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 326 struct cifs_sb_info *cifs_sb, const unsigned char *path, 327 char *pbuf, unsigned int *pbytes_read) 328{ 329 int rc; 330 int oplock = 0; 331 struct cifs_fid fid; 332 struct cifs_open_parms oparms; 333 struct cifs_io_parms io_parms; 334 int buf_type = CIFS_NO_BUFFER; 335 FILE_ALL_INFO file_info; 336 337 oparms.tcon = tcon; 338 oparms.cifs_sb = cifs_sb; 339 oparms.desired_access = GENERIC_READ; 340 oparms.create_options = CREATE_NOT_DIR; 341 oparms.disposition = FILE_OPEN; 342 oparms.path = path; 343 oparms.fid = &fid; 344 oparms.reconnect = false; 345 346 rc = CIFS_open(xid, &oparms, &oplock, &file_info); 347 if (rc) 348 return rc; 349 350 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { 351 rc = -ENOENT; 352 /* it's not a symlink */ 353 goto out; 354 } 355 356 io_parms.netfid = fid.netfid; 357 io_parms.pid = current->tgid; 358 io_parms.tcon = tcon; 359 io_parms.offset = 0; 360 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 361 362 rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type); 363out: 364 CIFSSMBClose(xid, tcon, fid.netfid); 365 return rc; 366} 367 368int 369cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 370 struct cifs_sb_info *cifs_sb, const unsigned char *path, 371 char *pbuf, unsigned int *pbytes_written) 372{ 373 int rc; 374 int oplock = 0; 375 struct cifs_fid fid; 376 struct cifs_open_parms oparms; 377 struct cifs_io_parms io_parms; 378 int create_options = CREATE_NOT_DIR; 379 380 if (backup_cred(cifs_sb)) 381 create_options |= CREATE_OPEN_BACKUP_INTENT; 382 383 oparms.tcon = tcon; 384 oparms.cifs_sb = cifs_sb; 385 oparms.desired_access = GENERIC_WRITE; 386 oparms.create_options = create_options; 387 oparms.disposition = FILE_CREATE; 388 oparms.path = path; 389 oparms.fid = &fid; 390 oparms.reconnect = false; 391 392 rc = CIFS_open(xid, &oparms, &oplock, NULL); 393 if (rc) 394 return rc; 395 396 io_parms.netfid = fid.netfid; 397 io_parms.pid = current->tgid; 398 io_parms.tcon = tcon; 399 io_parms.offset = 0; 400 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 401 402 rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf, NULL, 0); 403 CIFSSMBClose(xid, tcon, fid.netfid); 404 return rc; 405} 406 407/* 408 * SMB 2.1/SMB3 Protocol specific functions 409 */ 410#ifdef CONFIG_CIFS_SMB2 411int 412smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 413 struct cifs_sb_info *cifs_sb, const unsigned char *path, 414 char *pbuf, unsigned int *pbytes_read) 415{ 416 int rc; 417 struct cifs_fid fid; 418 struct cifs_open_parms oparms; 419 struct cifs_io_parms io_parms; 420 int buf_type = CIFS_NO_BUFFER; 421 __le16 *utf16_path; 422 __u8 oplock = SMB2_OPLOCK_LEVEL_II; 423 struct smb2_file_all_info *pfile_info = NULL; 424 425 oparms.tcon = tcon; 426 oparms.cifs_sb = cifs_sb; 427 oparms.desired_access = GENERIC_READ; 428 oparms.create_options = CREATE_NOT_DIR; 429 if (backup_cred(cifs_sb)) 430 oparms.create_options |= CREATE_OPEN_BACKUP_INTENT; 431 oparms.disposition = FILE_OPEN; 432 oparms.fid = &fid; 433 oparms.reconnect = false; 434 435 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); 436 if (utf16_path == NULL) 437 return -ENOMEM; 438 439 pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, 440 GFP_KERNEL); 441 442 if (pfile_info == NULL) { 443 kfree(utf16_path); 444 return -ENOMEM; 445 } 446 447 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL); 448 if (rc) 449 goto qmf_out_open_fail; 450 451 if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { 452 /* it's not a symlink */ 453 rc = -ENOENT; /* Is there a better rc to return? */ 454 goto qmf_out; 455 } 456 457 io_parms.netfid = fid.netfid; 458 io_parms.pid = current->tgid; 459 io_parms.tcon = tcon; 460 io_parms.offset = 0; 461 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 462 io_parms.persistent_fid = fid.persistent_fid; 463 io_parms.volatile_fid = fid.volatile_fid; 464 rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type); 465qmf_out: 466 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); 467qmf_out_open_fail: 468 kfree(utf16_path); 469 kfree(pfile_info); 470 return rc; 471} 472 473int 474smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, 475 struct cifs_sb_info *cifs_sb, const unsigned char *path, 476 char *pbuf, unsigned int *pbytes_written) 477{ 478 int rc; 479 struct cifs_fid fid; 480 struct cifs_open_parms oparms; 481 struct cifs_io_parms io_parms; 482 int create_options = CREATE_NOT_DIR; 483 __le16 *utf16_path; 484 __u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 485 struct kvec iov[2]; 486 487 if (backup_cred(cifs_sb)) 488 create_options |= CREATE_OPEN_BACKUP_INTENT; 489 490 cifs_dbg(FYI, "%s: path: %s\n", __func__, path); 491 492 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); 493 if (!utf16_path) 494 return -ENOMEM; 495 496 oparms.tcon = tcon; 497 oparms.cifs_sb = cifs_sb; 498 oparms.desired_access = GENERIC_WRITE; 499 oparms.create_options = create_options; 500 oparms.disposition = FILE_CREATE; 501 oparms.fid = &fid; 502 oparms.reconnect = false; 503 504 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); 505 if (rc) { 506 kfree(utf16_path); 507 return rc; 508 } 509 510 io_parms.netfid = fid.netfid; 511 io_parms.pid = current->tgid; 512 io_parms.tcon = tcon; 513 io_parms.offset = 0; 514 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; 515 io_parms.persistent_fid = fid.persistent_fid; 516 io_parms.volatile_fid = fid.volatile_fid; 517 518 /* iov[0] is reserved for smb header */ 519 iov[1].iov_base = pbuf; 520 iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE; 521 522 rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1); 523 524 /* Make sure we wrote all of the symlink data */ 525 if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE)) 526 rc = -EIO; 527 528 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); 529 530 kfree(utf16_path); 531 return rc; 532} 533#endif /* CONFIG_CIFS_SMB2 */ 534 535/* 536 * M-F Symlink Functions - End 537 */ 538 539int 540cifs_hardlink(struct dentry *old_file, struct inode *inode, 541 struct dentry *direntry) 542{ 543 int rc = -EACCES; 544 unsigned int xid; 545 char *from_name = NULL; 546 char *to_name = NULL; 547 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 548 struct tcon_link *tlink; 549 struct cifs_tcon *tcon; 550 struct TCP_Server_Info *server; 551 struct cifsInodeInfo *cifsInode; 552 553 tlink = cifs_sb_tlink(cifs_sb); 554 if (IS_ERR(tlink)) 555 return PTR_ERR(tlink); 556 tcon = tlink_tcon(tlink); 557 558 xid = get_xid(); 559 560 from_name = build_path_from_dentry(old_file); 561 to_name = build_path_from_dentry(direntry); 562 if ((from_name == NULL) || (to_name == NULL)) { 563 rc = -ENOMEM; 564 goto cifs_hl_exit; 565 } 566 567 if (tcon->unix_ext) 568 rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name, 569 cifs_sb->local_nls, 570 cifs_remap(cifs_sb)); 571 else { 572 server = tcon->ses->server; 573 if (!server->ops->create_hardlink) { 574 rc = -ENOSYS; 575 goto cifs_hl_exit; 576 } 577 rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, 578 cifs_sb); 579 if ((rc == -EIO) || (rc == -EINVAL)) 580 rc = -EOPNOTSUPP; 581 } 582 583 d_drop(direntry); /* force new lookup from server of target */ 584 585 /* 586 * if source file is cached (oplocked) revalidate will not go to server 587 * until the file is closed or oplock broken so update nlinks locally 588 */ 589 if (d_really_is_positive(old_file)) { 590 cifsInode = CIFS_I(d_inode(old_file)); 591 if (rc == 0) { 592 spin_lock(&d_inode(old_file)->i_lock); 593 inc_nlink(d_inode(old_file)); 594 spin_unlock(&d_inode(old_file)->i_lock); 595 596 /* 597 * parent dir timestamps will update from srv within a 598 * second, would it really be worth it to set the parent 599 * dir cifs inode time to zero to force revalidate 600 * (faster) for it too? 601 */ 602 } 603 /* 604 * if not oplocked will force revalidate to get info on source 605 * file from srv. Note Samba server prior to 4.2 has bug - 606 * not updating src file ctime on hardlinks but Windows servers 607 * handle it properly 608 */ 609 cifsInode->time = 0; 610 611 /* 612 * Will update parent dir timestamps from srv within a second. 613 * Would it really be worth it to set the parent dir (cifs 614 * inode) time field to zero to force revalidate on parent 615 * directory faster ie 616 * 617 * CIFS_I(inode)->time = 0; 618 */ 619 } 620 621cifs_hl_exit: 622 kfree(from_name); 623 kfree(to_name); 624 free_xid(xid); 625 cifs_put_tlink(tlink); 626 return rc; 627} 628 629void * 630cifs_follow_link(struct dentry *direntry, struct nameidata *nd) 631{ 632 struct inode *inode = d_inode(direntry); 633 int rc = -ENOMEM; 634 unsigned int xid; 635 char *full_path = NULL; 636 char *target_path = NULL; 637 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 638 struct tcon_link *tlink = NULL; 639 struct cifs_tcon *tcon; 640 struct TCP_Server_Info *server; 641 642 xid = get_xid(); 643 644 tlink = cifs_sb_tlink(cifs_sb); 645 if (IS_ERR(tlink)) { 646 rc = PTR_ERR(tlink); 647 tlink = NULL; 648 goto out; 649 } 650 tcon = tlink_tcon(tlink); 651 server = tcon->ses->server; 652 653 full_path = build_path_from_dentry(direntry); 654 if (!full_path) 655 goto out; 656 657 cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode); 658 659 rc = -EACCES; 660 /* 661 * First try Minshall+French Symlinks, if configured 662 * and fallback to UNIX Extensions Symlinks. 663 */ 664 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) 665 rc = query_mf_symlink(xid, tcon, cifs_sb, full_path, 666 &target_path); 667 668 if (rc != 0 && server->ops->query_symlink) 669 rc = server->ops->query_symlink(xid, tcon, full_path, 670 &target_path, cifs_sb); 671 672 kfree(full_path); 673out: 674 if (rc != 0) { 675 kfree(target_path); 676 target_path = ERR_PTR(rc); 677 } 678 679 free_xid(xid); 680 if (tlink) 681 cifs_put_tlink(tlink); 682 nd_set_link(nd, target_path); 683 return NULL; 684} 685 686int 687cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) 688{ 689 int rc = -EOPNOTSUPP; 690 unsigned int xid; 691 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 692 struct tcon_link *tlink; 693 struct cifs_tcon *pTcon; 694 char *full_path = NULL; 695 struct inode *newinode = NULL; 696 697 xid = get_xid(); 698 699 tlink = cifs_sb_tlink(cifs_sb); 700 if (IS_ERR(tlink)) { 701 rc = PTR_ERR(tlink); 702 goto symlink_exit; 703 } 704 pTcon = tlink_tcon(tlink); 705 706 full_path = build_path_from_dentry(direntry); 707 if (full_path == NULL) { 708 rc = -ENOMEM; 709 goto symlink_exit; 710 } 711 712 cifs_dbg(FYI, "Full path: %s\n", full_path); 713 cifs_dbg(FYI, "symname is %s\n", symname); 714 715 /* BB what if DFS and this volume is on different share? BB */ 716 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) 717 rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); 718 else if (pTcon->unix_ext) 719 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, 720 cifs_sb->local_nls, 721 cifs_remap(cifs_sb)); 722 /* else 723 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, 724 cifs_sb_target->local_nls); */ 725 726 if (rc == 0) { 727 if (pTcon->unix_ext) 728 rc = cifs_get_inode_info_unix(&newinode, full_path, 729 inode->i_sb, xid); 730 else 731 rc = cifs_get_inode_info(&newinode, full_path, NULL, 732 inode->i_sb, xid, NULL); 733 734 if (rc != 0) { 735 cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n", 736 rc); 737 } else { 738 d_instantiate(direntry, newinode); 739 } 740 } 741symlink_exit: 742 kfree(full_path); 743 cifs_put_tlink(tlink); 744 free_xid(xid); 745 return rc; 746} 747