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