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