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