link.c 14.2 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

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

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
#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]

52 53 54 55 56 57 58 59 60
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);
61
	if (IS_ERR(md5)) {
62
		rc = PTR_ERR(md5);
63 64
		cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n",
			 __func__, rc);
65
		return rc;
66 67 68 69 70 71 72 73 74 75 76 77
	}
	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) {
78
		cifs_dbg(VFS, "%s: Could not init md5 shash\n", __func__);
79 80
		goto symlink_hash_err;
	}
81 82
	rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len);
	if (rc) {
83
		cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__);
84 85
		goto symlink_hash_err;
	}
86
	rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
87
	if (rc)
88
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
89 90 91 92 93 94 95 96

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

	return rc;
}

97
static int
98 99
parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
		 char **_link_str)
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
{
	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;

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

	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 已提交
140

141
static int
142
format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
143
{
144
	int rc;
145 146 147 148 149 150 151 152 153 154 155 156
	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;

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

	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 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198
bool
couldbe_mf_symlink(const struct cifs_fattr *fattr)
{
	if (!(fattr->cf_mode & S_IFREG))
		/* 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;
}

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

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

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

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

	if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
222 223 224 225
		rc = -EIO;
out:
	kfree(buf);
	return rc;
226 227 228
}

static int
229
query_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
230 231
		 struct cifs_sb_info *cifs_sb, const unsigned char *path,
		 char **symlinkinfo)
232 233
{
	int rc;
234
	u8 *buf = NULL;
235
	unsigned int link_len = 0;
236
	unsigned int bytes_read = 0;
237 238 239 240 241

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

242 243 244 245 246 247 248 249 250 251 252 253
	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;
254 255
	}

256
	rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo);
257
out:
258
	kfree(buf);
259
	return rc;
260 261
}

S
Sachin Prabhu 已提交
262 263 264 265
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)
266
{
S
Sachin Prabhu 已提交
267 268 269 270 271 272
	int rc;
	u8 *buf = NULL;
	unsigned int link_len = 0;
	unsigned int bytes_read = 0;

	if (!couldbe_mf_symlink(fattr))
273
		/* it's not a symlink */
S
Sachin Prabhu 已提交
274
		return 0;
275

S
Sachin Prabhu 已提交
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
	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) {
294
		/* it's not a symlink */
S
Sachin Prabhu 已提交
295 296 297
		rc = 0;
		goto out;
	}
298

S
Sachin Prabhu 已提交
299 300 301 302 303 304 305 306 307 308 309
	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;
310 311
}

S
Sachin Prabhu 已提交
312 313 314 315
/*
 * SMB 1.0 Protocol specific functions
 */

316
int
317 318 319
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)
320 321 322 323
{
	int rc;
	int oplock = 0;
	__u16 netfid = 0;
324
	struct cifs_io_parms io_parms;
325 326 327
	int buf_type = CIFS_NO_BUFFER;
	FILE_ALL_INFO file_info;

328
	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ,
329 330 331 332
			 CREATE_NOT_DIR, &netfid, &oplock, &file_info,
			 cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags &
				CIFS_MOUNT_MAP_SPECIAL_CHR);
333
	if (rc)
334
		return rc;
335

336
	if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE))
337
		/* it's not a symlink */
338
		goto out;
339

340 341
	io_parms.netfid = netfid;
	io_parms.pid = current->tgid;
342
	io_parms.tcon = tcon;
343 344
	io_parms.offset = 0;
	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
345

346
	rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
347 348
out:
	CIFSSMBClose(xid, tcon, netfid);
349 350 351
	return rc;
}

352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
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;
	__u16 netfid = 0;
	struct cifs_io_parms io_parms;
	int create_options = CREATE_NOT_DIR;

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

	rc = CIFSSMBOpen(xid, tcon, path, FILE_CREATE, GENERIC_WRITE,
			 create_options, &netfid, &oplock, NULL,
			 cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags &
				CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc)
		return rc;

	io_parms.netfid = netfid;
	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);
	CIFSSMBClose(xid, tcon, netfid);
	return rc;
}

S
Sachin Prabhu 已提交
385 386 387
/*
 * M-F Symlink Functions - End
 */
388

L
Linus Torvalds 已提交
389 390 391 392 393
int
cifs_hardlink(struct dentry *old_file, struct inode *inode,
	      struct dentry *direntry)
{
	int rc = -EACCES;
394
	unsigned int xid;
S
Steve French 已提交
395 396
	char *from_name = NULL;
	char *to_name = NULL;
397 398
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink;
S
Steve French 已提交
399 400
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
L
Linus Torvalds 已提交
401 402
	struct cifsInodeInfo *cifsInode;

403 404 405
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
S
Steve French 已提交
406
	tcon = tlink_tcon(tlink);
L
Linus Torvalds 已提交
407

408
	xid = get_xid();
L
Linus Torvalds 已提交
409

S
Steve French 已提交
410 411 412
	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 已提交
413 414 415 416
		rc = -ENOMEM;
		goto cifs_hl_exit;
	}

S
Steve French 已提交
417 418
	if (tcon->unix_ext)
		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
419 420
					    cifs_sb->local_nls,
					    cifs_sb->mnt_cifs_flags &
421
						CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
422
	else {
S
Steve French 已提交
423
		server = tcon->ses->server;
424 425 426 427
		if (!server->ops->create_hardlink) {
			rc = -ENOSYS;
			goto cifs_hl_exit;
		}
S
Steve French 已提交
428 429
		rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
						  cifs_sb);
S
Steve French 已提交
430 431
		if ((rc == -EIO) || (rc == -EINVAL))
			rc = -EOPNOTSUPP;
L
Linus Torvalds 已提交
432 433
	}

434 435
	d_drop(direntry);	/* force new lookup from server of target */

S
Steve French 已提交
436 437 438 439
	/*
	 * 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 已提交
440
	if (old_file->d_inode) {
441
		cifsInode = CIFS_I(old_file->d_inode);
S
Steve French 已提交
442
		if (rc == 0) {
443
			spin_lock(&old_file->d_inode->i_lock);
444
			inc_nlink(old_file->d_inode);
445
			spin_unlock(&old_file->d_inode->i_lock);
S
Steve French 已提交
446 447 448 449 450 451 452 453 454 455 456
			/*
			 * 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?
			 */
457
		}
S
Steve French 已提交
458 459 460 461
		/*
		 * if not oplocked will force revalidate to get info on source
		 * file from srv
		 */
462 463
		cifsInode->time = 0;

S
Steve French 已提交
464 465 466 467 468 469 470 471
		/*
		 * 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 已提交
472 473 474
	}

cifs_hl_exit:
S
Steve French 已提交
475 476
	kfree(from_name);
	kfree(to_name);
477
	free_xid(xid);
478
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
479 480 481
	return rc;
}

482
void *
L
Linus Torvalds 已提交
483 484 485
cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
{
	struct inode *inode = direntry->d_inode;
486
	int rc = -ENOMEM;
487
	unsigned int xid;
L
Linus Torvalds 已提交
488
	char *full_path = NULL;
489 490
	char *target_path = NULL;
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
491
	struct tcon_link *tlink = NULL;
492
	struct cifs_tcon *tcon;
493
	struct TCP_Server_Info *server;
L
Linus Torvalds 已提交
494

495
	xid = get_xid();
L
Linus Torvalds 已提交
496

497 498 499 500 501 502 503
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		tlink = NULL;
		goto out;
	}
	tcon = tlink_tcon(tlink);
504
	server = tcon->ses->server;
L
Linus Torvalds 已提交
505

506
	full_path = build_path_from_dentry(direntry);
L
Linus Torvalds 已提交
507
	if (!full_path)
508
		goto out;
L
Linus Torvalds 已提交
509

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

512 513 514 515 516 517
	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)
518 519
		rc = query_mf_symlink(xid, tcon, cifs_sb, full_path,
				      &target_path);
520

521
	if ((rc != 0) && cap_unix(tcon->ses))
522 523
		rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
					     cifs_sb->local_nls);
524 525 526
	else if (rc != 0 && server->ops->query_symlink)
		rc = server->ops->query_symlink(xid, tcon, full_path,
						&target_path, cifs_sb);
527

528 529
	kfree(full_path);
out:
530
	if (rc != 0) {
L
Linus Torvalds 已提交
531 532 533 534
		kfree(target_path);
		target_path = ERR_PTR(rc);
	}

535
	free_xid(xid);
536 537
	if (tlink)
		cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
538
	nd_set_link(nd, target_path);
539
	return NULL;
L
Linus Torvalds 已提交
540 541 542 543 544 545
}

int
cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
{
	int rc = -EOPNOTSUPP;
546
	unsigned int xid;
547 548
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink;
549
	struct cifs_tcon *pTcon;
L
Linus Torvalds 已提交
550 551 552
	char *full_path = NULL;
	struct inode *newinode = NULL;

553
	xid = get_xid();
L
Linus Torvalds 已提交
554

555 556 557 558 559 560
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		goto symlink_exit;
	}
	pTcon = tlink_tcon(tlink);
L
Linus Torvalds 已提交
561

562
	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
563
	if (full_path == NULL) {
564
		rc = -ENOMEM;
565
		goto symlink_exit;
L
Linus Torvalds 已提交
566 567
	}

568 569
	cifs_dbg(FYI, "Full path: %s\n", full_path);
	cifs_dbg(FYI, "symname is %s\n", symname);
L
Linus Torvalds 已提交
570 571

	/* BB what if DFS and this volume is on different share? BB */
572
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
573
		rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
574
	else if (pTcon->unix_ext)
L
Linus Torvalds 已提交
575 576 577
		rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
					   cifs_sb->local_nls);
	/* else
S
Steve French 已提交
578 579
	   rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
					cifs_sb_target->local_nls); */
L
Linus Torvalds 已提交
580 581

	if (rc == 0) {
582
		if (pTcon->unix_ext)
L
Linus Torvalds 已提交
583
			rc = cifs_get_inode_info_unix(&newinode, full_path,
S
Steve French 已提交
584
						      inode->i_sb, xid);
L
Linus Torvalds 已提交
585 586
		else
			rc = cifs_get_inode_info(&newinode, full_path, NULL,
587
						 inode->i_sb, xid, NULL);
L
Linus Torvalds 已提交
588 589

		if (rc != 0) {
590 591
			cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
				 rc);
L
Linus Torvalds 已提交
592 593 594 595
		} else {
			d_instantiate(direntry, newinode);
		}
	}
596
symlink_exit:
J
Jesper Juhl 已提交
597
	kfree(full_path);
598
	cifs_put_tlink(tlink);
599
	free_xid(xid);
L
Linus Torvalds 已提交
600 601
	return rc;
}