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