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