link.c 16.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/link.c
 *
S
Steve French 已提交
4
 *   Copyright (C) International Business Machines  Corp., 2002,2008
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <linux/fs.h>
#include <linux/stat.h>
23
#include <linux/slab.h>
L
Linus Torvalds 已提交
24 25 26 27 28 29 30
#include <linux/namei.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
31
#include "smb2proto.h"
32

S
Sachin Prabhu 已提交
33 34 35 36
/*
 * M-F Symlink Functions - Begin
 */

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
#define CIFS_MF_SYMLINK_FILE_SIZE \
	(CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)

#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
#define CIFS_MF_SYMLINK_MD5_FORMAT \
	"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n"
#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \
	md5_hash[0],  md5_hash[1],  md5_hash[2],  md5_hash[3], \
	md5_hash[4],  md5_hash[5],  md5_hash[6],  md5_hash[7], \
	md5_hash[8],  md5_hash[9],  md5_hash[10], md5_hash[11],\
	md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]

53 54 55 56 57 58 59 60 61
static int
symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
{
	int rc;
	unsigned int size;
	struct crypto_shash *md5;
	struct sdesc *sdescmd5;

	md5 = crypto_alloc_shash("md5", 0, 0);
62
	if (IS_ERR(md5)) {
63
		rc = PTR_ERR(md5);
64 65
		cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n",
			 __func__, rc);
66
		return rc;
67 68 69 70 71 72 73 74 75 76 77 78
	}
	size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
	sdescmd5 = kmalloc(size, GFP_KERNEL);
	if (!sdescmd5) {
		rc = -ENOMEM;
		goto symlink_hash_err;
	}
	sdescmd5->shash.tfm = md5;
	sdescmd5->shash.flags = 0x0;

	rc = crypto_shash_init(&sdescmd5->shash);
	if (rc) {
79
		cifs_dbg(VFS, "%s: Could not init md5 shash\n", __func__);
80 81
		goto symlink_hash_err;
	}
82 83
	rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len);
	if (rc) {
84
		cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__);
85 86
		goto symlink_hash_err;
	}
87
	rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
88
	if (rc)
89
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
90 91 92 93 94 95 96 97

symlink_hash_err:
	crypto_free_shash(md5);
	kfree(sdescmd5);

	return rc;
}

98
static int
99 100
parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
		 char **_link_str)
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
{
	int rc;
	unsigned int link_len;
	const char *md5_str1;
	const char *link_str;
	u8 md5_hash[16];
	char md5_str2[34];

	if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
		return -EINVAL;

	md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET];
	link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET];

	rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len);
	if (rc != 1)
		return -EINVAL;

119 120
	rc = symlink_hash(link_len, link_str, md5_hash);
	if (rc) {
121
		cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
122 123
		return rc;
	}
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140

	snprintf(md5_str2, sizeof(md5_str2),
		 CIFS_MF_SYMLINK_MD5_FORMAT,
		 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));

	if (strncmp(md5_str1, md5_str2, 17) != 0)
		return -EINVAL;

	if (_link_str) {
		*_link_str = kstrndup(link_str, link_len, GFP_KERNEL);
		if (!*_link_str)
			return -ENOMEM;
	}

	*_link_len = link_len;
	return 0;
}
L
Linus Torvalds 已提交
141

142
static int
143
format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
144
{
145
	int rc;
146 147 148 149 150 151 152 153 154 155 156 157
	unsigned int link_len;
	unsigned int ofs;
	u8 md5_hash[16];

	if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
		return -EINVAL;

	link_len = strlen(link_str);

	if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
		return -ENAMETOOLONG;

158 159
	rc = symlink_hash(link_len, link_str, md5_hash);
	if (rc) {
160
		cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
161 162
		return rc;
	}
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

	snprintf(buf, buf_len,
		 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
		 link_len,
		 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));

	ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
	memcpy(buf + ofs, link_str, link_len);

	ofs += link_len;
	if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
		buf[ofs] = '\n';
		ofs++;
	}

	while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
		buf[ofs] = ' ';
		ofs++;
	}

	return 0;
}

S
Sachin Prabhu 已提交
186 187 188
bool
couldbe_mf_symlink(const struct cifs_fattr *fattr)
{
189
	if (!S_ISREG(fattr->cf_mode))
S
Sachin Prabhu 已提交
190 191 192 193 194 195 196 197 198 199
		/* it's not a symlink */
		return false;

	if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
		/* it's not a symlink */
		return false;

	return true;
}

200
static int
201
create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
202 203
		  struct cifs_sb_info *cifs_sb, const char *fromName,
		  const char *toName)
204 205 206 207 208 209 210 211 212
{
	int rc;
	u8 *buf;
	unsigned int bytes_written = 0;

	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

213
	rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
214 215
	if (rc)
		goto out;
216

217 218 219 220 221 222
	if (tcon->ses->server->ops->create_mf_symlink)
		rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon,
					cifs_sb, fromName, buf, &bytes_written);
	else
		rc = -EOPNOTSUPP;

223 224
	if (rc)
		goto out;
225 226

	if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
227 228 229 230
		rc = -EIO;
out:
	kfree(buf);
	return rc;
231 232 233
}

static int
234
query_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
235 236
		 struct cifs_sb_info *cifs_sb, const unsigned char *path,
		 char **symlinkinfo)
237 238
{
	int rc;
239
	u8 *buf = NULL;
240
	unsigned int link_len = 0;
241
	unsigned int bytes_read = 0;
242 243 244 245 246

	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

247 248 249 250 251 252 253 254 255 256 257 258
	if (tcon->ses->server->ops->query_mf_symlink)
		rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
					      cifs_sb, path, buf, &bytes_read);
	else
		rc = -ENOSYS;

	if (rc)
		goto out;

	if (bytes_read == 0) { /* not a symlink */
		rc = -EINVAL;
		goto out;
259 260
	}

261
	rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo);
262
out:
263
	kfree(buf);
264
	return rc;
265 266
}

S
Sachin Prabhu 已提交
267 268 269 270
int
check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
		 struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
		 const unsigned char *path)
271
{
S
Sachin Prabhu 已提交
272 273 274 275 276 277
	int rc;
	u8 *buf = NULL;
	unsigned int link_len = 0;
	unsigned int bytes_read = 0;

	if (!couldbe_mf_symlink(fattr))
278
		/* it's not a symlink */
S
Sachin Prabhu 已提交
279
		return 0;
280

S
Sachin Prabhu 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	if (tcon->ses->server->ops->query_mf_symlink)
		rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
					      cifs_sb, path, buf, &bytes_read);
	else
		rc = -ENOSYS;

	if (rc)
		goto out;

	if (bytes_read == 0) /* not a symlink */
		goto out;

	rc = parse_mf_symlink(buf, bytes_read, &link_len, NULL);
	if (rc == -EINVAL) {
299
		/* it's not a symlink */
S
Sachin Prabhu 已提交
300 301 302
		rc = 0;
		goto out;
	}
303

S
Sachin Prabhu 已提交
304 305 306 307 308 309 310 311 312 313 314
	if (rc != 0)
		goto out;

	/* it is a symlink */
	fattr->cf_eof = link_len;
	fattr->cf_mode &= ~S_IFMT;
	fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
	fattr->cf_dtype = DT_LNK;
out:
	kfree(buf);
	return rc;
315 316
}

S
Sachin Prabhu 已提交
317 318 319 320
/*
 * SMB 1.0 Protocol specific functions
 */

321
int
322 323 324
cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
		      char *pbuf, unsigned int *pbytes_read)
325 326 327
{
	int rc;
	int oplock = 0;
328 329
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
330
	struct cifs_io_parms io_parms;
331 332 333
	int buf_type = CIFS_NO_BUFFER;
	FILE_ALL_INFO file_info;

334 335 336 337 338 339 340 341 342 343
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = GENERIC_READ;
	oparms.create_options = CREATE_NOT_DIR;
	oparms.disposition = FILE_OPEN;
	oparms.path = path;
	oparms.fid = &fid;
	oparms.reconnect = false;

	rc = CIFS_open(xid, &oparms, &oplock, &file_info);
344
	if (rc)
345
		return rc;
346

S
Steve French 已提交
347 348
	if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
		rc = -ENOENT;
349
		/* it's not a symlink */
350
		goto out;
S
Steve French 已提交
351
	}
352

353
	io_parms.netfid = fid.netfid;
354
	io_parms.pid = current->tgid;
355
	io_parms.tcon = tcon;
356 357
	io_parms.offset = 0;
	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
358

359
	rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
360
out:
361
	CIFSSMBClose(xid, tcon, fid.netfid);
362 363 364
	return rc;
}

365 366 367 368 369 370 371
int
cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
		       char *pbuf, unsigned int *pbytes_written)
{
	int rc;
	int oplock = 0;
372 373
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
374 375 376 377 378 379
	struct cifs_io_parms io_parms;
	int create_options = CREATE_NOT_DIR;

	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

380 381 382 383
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = GENERIC_WRITE;
	oparms.create_options = create_options;
384
	oparms.disposition = FILE_CREATE;
385 386 387 388 389
	oparms.path = path;
	oparms.fid = &fid;
	oparms.reconnect = false;

	rc = CIFS_open(xid, &oparms, &oplock, NULL);
390 391 392
	if (rc)
		return rc;

393
	io_parms.netfid = fid.netfid;
394 395 396 397 398 399
	io_parms.pid = current->tgid;
	io_parms.tcon = tcon;
	io_parms.offset = 0;
	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;

	rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf, NULL, 0);
400
	CIFSSMBClose(xid, tcon, fid.netfid);
401 402 403
	return rc;
}

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
int
smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
		       char *pbuf, unsigned int *pbytes_written)
{
	int rc;
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
	struct cifs_io_parms io_parms;
	int create_options = CREATE_NOT_DIR;
	__le16 *utf16_path;
	__u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
	struct kvec iov[2];

	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

	cifs_dbg(FYI, "%s: path: %s\n", __func__, path);

	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
	if (!utf16_path)
		return -ENOMEM;

	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = GENERIC_WRITE;
	oparms.create_options = create_options;
	oparms.disposition = FILE_CREATE;
	oparms.fid = &fid;
	oparms.reconnect = false;

	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
	if (rc) {
		kfree(utf16_path);
		return rc;
	}

	io_parms.netfid = fid.netfid;
	io_parms.pid = current->tgid;
	io_parms.tcon = tcon;
	io_parms.offset = 0;
	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
	io_parms.persistent_fid = fid.persistent_fid;
	io_parms.volatile_fid = fid.volatile_fid;

	/* iov[0] is reserved for smb header */
	iov[1].iov_base = pbuf;
	iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;

	rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);

	/* Make sure we wrote all of the symlink data */
	if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
		rc = -EIO;

	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);

	kfree(utf16_path);
	return rc;
}


S
Sachin Prabhu 已提交
466 467 468
/*
 * M-F Symlink Functions - End
 */
469

L
Linus Torvalds 已提交
470 471 472 473 474
int
cifs_hardlink(struct dentry *old_file, struct inode *inode,
	      struct dentry *direntry)
{
	int rc = -EACCES;
475
	unsigned int xid;
S
Steve French 已提交
476 477
	char *from_name = NULL;
	char *to_name = NULL;
478 479
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink;
S
Steve French 已提交
480 481
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
L
Linus Torvalds 已提交
482 483
	struct cifsInodeInfo *cifsInode;

484 485 486
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
S
Steve French 已提交
487
	tcon = tlink_tcon(tlink);
L
Linus Torvalds 已提交
488

489
	xid = get_xid();
L
Linus Torvalds 已提交
490

S
Steve French 已提交
491 492 493
	from_name = build_path_from_dentry(old_file);
	to_name = build_path_from_dentry(direntry);
	if ((from_name == NULL) || (to_name == NULL)) {
L
Linus Torvalds 已提交
494 495 496 497
		rc = -ENOMEM;
		goto cifs_hl_exit;
	}

S
Steve French 已提交
498 499
	if (tcon->unix_ext)
		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
500 501
					    cifs_sb->local_nls,
					    cifs_sb->mnt_cifs_flags &
502
						CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
503
	else {
S
Steve French 已提交
504
		server = tcon->ses->server;
505 506 507 508
		if (!server->ops->create_hardlink) {
			rc = -ENOSYS;
			goto cifs_hl_exit;
		}
S
Steve French 已提交
509 510
		rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
						  cifs_sb);
S
Steve French 已提交
511 512
		if ((rc == -EIO) || (rc == -EINVAL))
			rc = -EOPNOTSUPP;
L
Linus Torvalds 已提交
513 514
	}

515 516
	d_drop(direntry);	/* force new lookup from server of target */

S
Steve French 已提交
517 518 519 520
	/*
	 * if source file is cached (oplocked) revalidate will not go to server
	 * until the file is closed or oplock broken so update nlinks locally
	 */
S
Steve French 已提交
521
	if (old_file->d_inode) {
522
		cifsInode = CIFS_I(old_file->d_inode);
S
Steve French 已提交
523
		if (rc == 0) {
524
			spin_lock(&old_file->d_inode->i_lock);
525
			inc_nlink(old_file->d_inode);
526
			spin_unlock(&old_file->d_inode->i_lock);
S
Steve French 已提交
527 528 529 530 531 532 533 534 535 536 537
			/*
			 * BB should we make this contingent on superblock flag
			 * NOATIME?
			 */
			/* old_file->d_inode->i_ctime = CURRENT_TIME; */
			/*
			 * parent dir timestamps will update from srv within a
			 * second, would it really be worth it to set the parent
			 * dir cifs inode time to zero to force revalidate
			 * (faster) for it too?
			 */
538
		}
S
Steve French 已提交
539 540 541 542
		/*
		 * if not oplocked will force revalidate to get info on source
		 * file from srv
		 */
543 544
		cifsInode->time = 0;

S
Steve French 已提交
545 546 547 548 549 550 551 552
		/*
		 * Will update parent dir timestamps from srv within a second.
		 * Would it really be worth it to set the parent dir (cifs
		 * inode) time field to zero to force revalidate on parent
		 * directory faster ie
		 *
		 * CIFS_I(inode)->time = 0;
		 */
L
Linus Torvalds 已提交
553 554 555
	}

cifs_hl_exit:
S
Steve French 已提交
556 557
	kfree(from_name);
	kfree(to_name);
558
	free_xid(xid);
559
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
560 561 562
	return rc;
}

563
void *
L
Linus Torvalds 已提交
564 565 566
cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
{
	struct inode *inode = direntry->d_inode;
567
	int rc = -ENOMEM;
568
	unsigned int xid;
L
Linus Torvalds 已提交
569
	char *full_path = NULL;
570 571
	char *target_path = NULL;
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
572
	struct tcon_link *tlink = NULL;
573
	struct cifs_tcon *tcon;
574
	struct TCP_Server_Info *server;
L
Linus Torvalds 已提交
575

576
	xid = get_xid();
L
Linus Torvalds 已提交
577

578 579 580 581 582 583 584
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		tlink = NULL;
		goto out;
	}
	tcon = tlink_tcon(tlink);
585
	server = tcon->ses->server;
L
Linus Torvalds 已提交
586

587
	full_path = build_path_from_dentry(direntry);
L
Linus Torvalds 已提交
588
	if (!full_path)
589
		goto out;
L
Linus Torvalds 已提交
590

591
	cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode);
L
Linus Torvalds 已提交
592

593 594 595 596 597 598
	rc = -EACCES;
	/*
	 * First try Minshall+French Symlinks, if configured
	 * and fallback to UNIX Extensions Symlinks.
	 */
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
599 600
		rc = query_mf_symlink(xid, tcon, cifs_sb, full_path,
				      &target_path);
601

602
	if (rc != 0 && server->ops->query_symlink)
603 604
		rc = server->ops->query_symlink(xid, tcon, full_path,
						&target_path, cifs_sb);
605

606 607
	kfree(full_path);
out:
608
	if (rc != 0) {
L
Linus Torvalds 已提交
609 610 611 612
		kfree(target_path);
		target_path = ERR_PTR(rc);
	}

613
	free_xid(xid);
614 615
	if (tlink)
		cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
616
	nd_set_link(nd, target_path);
617
	return NULL;
L
Linus Torvalds 已提交
618 619 620 621 622 623
}

int
cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
{
	int rc = -EOPNOTSUPP;
624
	unsigned int xid;
625 626
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink;
627
	struct cifs_tcon *pTcon;
L
Linus Torvalds 已提交
628 629 630
	char *full_path = NULL;
	struct inode *newinode = NULL;

631
	xid = get_xid();
L
Linus Torvalds 已提交
632

633 634 635 636 637 638
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		goto symlink_exit;
	}
	pTcon = tlink_tcon(tlink);
L
Linus Torvalds 已提交
639

640
	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
641
	if (full_path == NULL) {
642
		rc = -ENOMEM;
643
		goto symlink_exit;
L
Linus Torvalds 已提交
644 645
	}

646 647
	cifs_dbg(FYI, "Full path: %s\n", full_path);
	cifs_dbg(FYI, "symname is %s\n", symname);
L
Linus Torvalds 已提交
648 649

	/* BB what if DFS and this volume is on different share? BB */
650
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
651
		rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
652
	else if (pTcon->unix_ext)
L
Linus Torvalds 已提交
653 654 655
		rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
					   cifs_sb->local_nls);
	/* else
S
Steve French 已提交
656 657
	   rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
					cifs_sb_target->local_nls); */
L
Linus Torvalds 已提交
658 659

	if (rc == 0) {
660
		if (pTcon->unix_ext)
L
Linus Torvalds 已提交
661
			rc = cifs_get_inode_info_unix(&newinode, full_path,
S
Steve French 已提交
662
						      inode->i_sb, xid);
L
Linus Torvalds 已提交
663 664
		else
			rc = cifs_get_inode_info(&newinode, full_path, NULL,
665
						 inode->i_sb, xid, NULL);
L
Linus Torvalds 已提交
666 667

		if (rc != 0) {
668 669
			cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
				 rc);
L
Linus Torvalds 已提交
670 671 672 673
		} else {
			d_instantiate(direntry, newinode);
		}
	}
674
symlink_exit:
J
Jesper Juhl 已提交
675
	kfree(full_path);
676
	cifs_put_tlink(tlink);
677
	free_xid(xid);
L
Linus Torvalds 已提交
678 679
	return rc;
}