link.c 17.3 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 "cifs_unicode.h"
32
#include "smb2proto.h"
33

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

38 39 40 41 42 43 44 45
#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"
46 47
#define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
48

49 50 51 52
static int
symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
{
	int rc;
53 54
	struct crypto_shash *md5 = NULL;
	struct sdesc *sdescmd5 = NULL;
55

56 57
	rc = cifs_alloc_hash("md5", &md5, &sdescmd5);
	if (rc)
58 59 60 61
		goto symlink_hash_err;

	rc = crypto_shash_init(&sdescmd5->shash);
	if (rc) {
62
		cifs_dbg(VFS, "%s: Could not init md5 shash\n", __func__);
63 64
		goto symlink_hash_err;
	}
65 66
	rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len);
	if (rc) {
67
		cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__);
68 69
		goto symlink_hash_err;
	}
70
	rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
71
	if (rc)
72
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
73 74

symlink_hash_err:
75
	cifs_free_hash(&md5, &sdescmd5);
76 77 78
	return rc;
}

79
static int
80 81
parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
		 char **_link_str)
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
{
	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;

100 101
	rc = symlink_hash(link_len, link_str, md5_hash);
	if (rc) {
102
		cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
103 104
		return rc;
	}
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

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

123
static int
124
format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
125
{
126
	int rc;
127 128 129 130 131 132 133 134 135 136 137 138
	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;

139 140
	rc = symlink_hash(link_len, link_str, md5_hash);
	if (rc) {
141
		cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
142 143
		return rc;
	}
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

	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 已提交
167 168 169
bool
couldbe_mf_symlink(const struct cifs_fattr *fattr)
{
170
	if (!S_ISREG(fattr->cf_mode))
S
Sachin Prabhu 已提交
171 172 173 174 175 176 177 178 179 180
		/* 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;
}

181
static int
182
create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
183 184
		  struct cifs_sb_info *cifs_sb, const char *fromName,
		  const char *toName)
185 186 187 188 189 190 191 192 193
{
	int rc;
	u8 *buf;
	unsigned int bytes_written = 0;

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

194
	rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
195 196
	if (rc)
		goto out;
197

198 199 200 201 202 203
	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;

204 205
	if (rc)
		goto out;
206 207

	if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
208 209 210 211
		rc = -EIO;
out:
	kfree(buf);
	return rc;
212 213 214
}

static int
215
query_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
216 217
		 struct cifs_sb_info *cifs_sb, const unsigned char *path,
		 char **symlinkinfo)
218 219
{
	int rc;
220
	u8 *buf = NULL;
221
	unsigned int link_len = 0;
222
	unsigned int bytes_read = 0;
223 224 225 226 227

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

228 229 230 231 232 233 234 235 236 237 238 239
	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;
240 241
	}

242
	rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo);
243
out:
244
	kfree(buf);
245
	return rc;
246 247
}

S
Sachin Prabhu 已提交
248 249 250 251
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)
252
{
S
Sachin Prabhu 已提交
253 254 255 256 257 258
	int rc;
	u8 *buf = NULL;
	unsigned int link_len = 0;
	unsigned int bytes_read = 0;

	if (!couldbe_mf_symlink(fattr))
259
		/* it's not a symlink */
S
Sachin Prabhu 已提交
260
		return 0;
261

S
Sachin Prabhu 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
	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) {
280
		/* it's not a symlink */
S
Sachin Prabhu 已提交
281 282 283
		rc = 0;
		goto out;
	}
284

S
Sachin Prabhu 已提交
285 286 287 288 289 290 291 292 293 294 295
	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;
296 297
}

S
Sachin Prabhu 已提交
298 299 300 301
/*
 * SMB 1.0 Protocol specific functions
 */

302
int
303 304 305
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)
306 307 308
{
	int rc;
	int oplock = 0;
309 310
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
311
	struct cifs_io_parms io_parms;
312 313 314
	int buf_type = CIFS_NO_BUFFER;
	FILE_ALL_INFO file_info;

315 316 317 318 319 320 321 322 323 324
	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);
325
	if (rc)
326
		return rc;
327

S
Steve French 已提交
328 329
	if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
		rc = -ENOENT;
330
		/* it's not a symlink */
331
		goto out;
S
Steve French 已提交
332
	}
333

334
	io_parms.netfid = fid.netfid;
335
	io_parms.pid = current->tgid;
336
	io_parms.tcon = tcon;
337 338
	io_parms.offset = 0;
	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
339

340
	rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
341
out:
342
	CIFSSMBClose(xid, tcon, fid.netfid);
343 344 345
	return rc;
}

346 347 348 349 350 351 352
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;
353 354
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
355 356 357 358 359 360
	struct cifs_io_parms io_parms;
	int create_options = CREATE_NOT_DIR;

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

361 362 363 364
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = GENERIC_WRITE;
	oparms.create_options = create_options;
365
	oparms.disposition = FILE_CREATE;
366 367 368 369 370
	oparms.path = path;
	oparms.fid = &fid;
	oparms.reconnect = false;

	rc = CIFS_open(xid, &oparms, &oplock, NULL);
371 372 373
	if (rc)
		return rc;

374
	io_parms.netfid = fid.netfid;
375 376 377 378 379
	io_parms.pid = current->tgid;
	io_parms.tcon = tcon;
	io_parms.offset = 0;
	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;

380
	rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf);
381
	CIFSSMBClose(xid, tcon, fid.netfid);
382 383 384
	return rc;
}

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
/*
 * SMB 2.1/SMB3 Protocol specific functions
 */
int
smb3_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)
{
	int rc;
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
	struct cifs_io_parms io_parms;
	int buf_type = CIFS_NO_BUFFER;
	__le16 *utf16_path;
	__u8 oplock = SMB2_OPLOCK_LEVEL_II;
	struct smb2_file_all_info *pfile_info = NULL;

	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = GENERIC_READ;
	oparms.create_options = CREATE_NOT_DIR;
	if (backup_cred(cifs_sb))
		oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
	oparms.disposition = FILE_OPEN;
	oparms.fid = &fid;
	oparms.reconnect = false;

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

	pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
			     GFP_KERNEL);

	if (pfile_info == NULL) {
		kfree(utf16_path);
		return  -ENOMEM;
	}

424 425
	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL,
		       NULL);
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
	if (rc)
		goto qmf_out_open_fail;

	if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
		/* it's not a symlink */
		rc = -ENOENT; /* Is there a better rc to return? */
		goto qmf_out;
	}

	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;
	rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
qmf_out:
	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
qmf_out_open_fail:
	kfree(utf16_path);
	kfree(pfile_info);
	return rc;
}

451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
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;

482 483
	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
		       NULL);
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
	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 已提交
513 514 515
/*
 * M-F Symlink Functions - End
 */
516

L
Linus Torvalds 已提交
517 518 519 520 521
int
cifs_hardlink(struct dentry *old_file, struct inode *inode,
	      struct dentry *direntry)
{
	int rc = -EACCES;
522
	unsigned int xid;
S
Steve French 已提交
523 524
	char *from_name = NULL;
	char *to_name = NULL;
525 526
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink;
S
Steve French 已提交
527 528
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
L
Linus Torvalds 已提交
529 530
	struct cifsInodeInfo *cifsInode;

531 532 533
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
S
Steve French 已提交
534
	tcon = tlink_tcon(tlink);
L
Linus Torvalds 已提交
535

536
	xid = get_xid();
L
Linus Torvalds 已提交
537

S
Steve French 已提交
538 539 540
	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 已提交
541 542 543 544
		rc = -ENOMEM;
		goto cifs_hl_exit;
	}

S
Steve French 已提交
545 546
	if (tcon->unix_ext)
		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
547
					    cifs_sb->local_nls,
548
					    cifs_remap(cifs_sb));
L
Linus Torvalds 已提交
549
	else {
S
Steve French 已提交
550
		server = tcon->ses->server;
551 552 553 554
		if (!server->ops->create_hardlink) {
			rc = -ENOSYS;
			goto cifs_hl_exit;
		}
S
Steve French 已提交
555 556
		rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
						  cifs_sb);
S
Steve French 已提交
557 558
		if ((rc == -EIO) || (rc == -EINVAL))
			rc = -EOPNOTSUPP;
L
Linus Torvalds 已提交
559 560
	}

561 562
	d_drop(direntry);	/* force new lookup from server of target */

S
Steve French 已提交
563 564 565 566
	/*
	 * if source file is cached (oplocked) revalidate will not go to server
	 * until the file is closed or oplock broken so update nlinks locally
	 */
567 568
	if (d_really_is_positive(old_file)) {
		cifsInode = CIFS_I(d_inode(old_file));
S
Steve French 已提交
569
		if (rc == 0) {
570 571 572
			spin_lock(&d_inode(old_file)->i_lock);
			inc_nlink(d_inode(old_file));
			spin_unlock(&d_inode(old_file)->i_lock);
S
Steve French 已提交
573

S
Steve French 已提交
574 575 576 577 578 579
			/*
			 * 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?
			 */
580
		}
S
Steve French 已提交
581 582
		/*
		 * if not oplocked will force revalidate to get info on source
S
Steve French 已提交
583 584 585
		 * file from srv.  Note Samba server prior to 4.2 has bug -
		 * not updating src file ctime on hardlinks but Windows servers
		 * handle it properly
S
Steve French 已提交
586
		 */
587 588
		cifsInode->time = 0;

S
Steve French 已提交
589 590 591 592 593 594 595 596
		/*
		 * 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 已提交
597 598 599
	}

cifs_hl_exit:
S
Steve French 已提交
600 601
	kfree(from_name);
	kfree(to_name);
602
	free_xid(xid);
603
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
604 605 606
	return rc;
}

607
const char *
608 609
cifs_get_link(struct dentry *direntry, struct inode *inode,
	      struct delayed_call *done)
L
Linus Torvalds 已提交
610
{
611
	int rc = -ENOMEM;
612
	unsigned int xid;
L
Linus Torvalds 已提交
613
	char *full_path = NULL;
614 615
	char *target_path = NULL;
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
616
	struct tcon_link *tlink = NULL;
617
	struct cifs_tcon *tcon;
618
	struct TCP_Server_Info *server;
L
Linus Torvalds 已提交
619

620 621 622
	if (!direntry)
		return ERR_PTR(-ECHILD);

623
	xid = get_xid();
L
Linus Torvalds 已提交
624

625 626
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
627 628
		free_xid(xid);
		return ERR_CAST(tlink);
629 630
	}
	tcon = tlink_tcon(tlink);
631
	server = tcon->ses->server;
L
Linus Torvalds 已提交
632

633
	full_path = build_path_from_dentry(direntry);
634 635 636 637 638
	if (!full_path) {
		free_xid(xid);
		cifs_put_tlink(tlink);
		return ERR_PTR(-ENOMEM);
	}
L
Linus Torvalds 已提交
639

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

642 643 644 645 646 647
	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)
648 649
		rc = query_mf_symlink(xid, tcon, cifs_sb, full_path,
				      &target_path);
650

651
	if (rc != 0 && server->ops->query_symlink)
652 653
		rc = server->ops->query_symlink(xid, tcon, full_path,
						&target_path, cifs_sb);
654

655
	kfree(full_path);
656 657
	free_xid(xid);
	cifs_put_tlink(tlink);
658
	if (rc != 0) {
L
Linus Torvalds 已提交
659
		kfree(target_path);
660
		return ERR_PTR(rc);
L
Linus Torvalds 已提交
661
	}
662 663
	set_delayed_call(done, kfree_link, target_path);
	return target_path;
L
Linus Torvalds 已提交
664 665 666 667 668 669
}

int
cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
{
	int rc = -EOPNOTSUPP;
670
	unsigned int xid;
671 672
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink;
673
	struct cifs_tcon *pTcon;
L
Linus Torvalds 已提交
674 675 676
	char *full_path = NULL;
	struct inode *newinode = NULL;

677
	xid = get_xid();
L
Linus Torvalds 已提交
678

679 680 681 682 683 684
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		goto symlink_exit;
	}
	pTcon = tlink_tcon(tlink);
L
Linus Torvalds 已提交
685

686
	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
687
	if (full_path == NULL) {
688
		rc = -ENOMEM;
689
		goto symlink_exit;
L
Linus Torvalds 已提交
690 691
	}

692 693
	cifs_dbg(FYI, "Full path: %s\n", full_path);
	cifs_dbg(FYI, "symname is %s\n", symname);
L
Linus Torvalds 已提交
694 695

	/* BB what if DFS and this volume is on different share? BB */
696
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
697
		rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
698
	else if (pTcon->unix_ext)
L
Linus Torvalds 已提交
699
		rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
700 701
					   cifs_sb->local_nls,
					   cifs_remap(cifs_sb));
L
Linus Torvalds 已提交
702
	/* else
S
Steve French 已提交
703 704
	   rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
					cifs_sb_target->local_nls); */
L
Linus Torvalds 已提交
705 706

	if (rc == 0) {
707
		if (pTcon->unix_ext)
L
Linus Torvalds 已提交
708
			rc = cifs_get_inode_info_unix(&newinode, full_path,
S
Steve French 已提交
709
						      inode->i_sb, xid);
L
Linus Torvalds 已提交
710 711
		else
			rc = cifs_get_inode_info(&newinode, full_path, NULL,
712
						 inode->i_sb, xid, NULL);
L
Linus Torvalds 已提交
713 714

		if (rc != 0) {
715 716
			cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
				 rc);
L
Linus Torvalds 已提交
717 718 719 720
		} else {
			d_instantiate(direntry, newinode);
		}
	}
721
symlink_exit:
J
Jesper Juhl 已提交
722
	kfree(full_path);
723
	cifs_put_tlink(tlink);
724
	free_xid(xid);
L
Linus Torvalds 已提交
725 726
	return rc;
}