link.c 17.8 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
#ifdef CONFIG_CIFS_SMB2
33
#include "smb2proto.h"
34
#endif
35

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

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
#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]

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

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

	return rc;
}

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

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

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

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

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

	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 已提交
189 190 191
bool
couldbe_mf_symlink(const struct cifs_fattr *fattr)
{
192
	if (!S_ISREG(fattr->cf_mode))
S
Sachin Prabhu 已提交
193 194 195 196 197 198 199 200 201 202
		/* 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;
}

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

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

216
	rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
217 218
	if (rc)
		goto out;
219

220 221 222 223 224 225
	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;

226 227
	if (rc)
		goto out;
228 229

	if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
230 231 232 233
		rc = -EIO;
out:
	kfree(buf);
	return rc;
234 235 236
}

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

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

250 251 252 253 254 255 256 257 258 259 260 261
	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;
262 263
	}

264
	rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo);
265
out:
266
	kfree(buf);
267
	return rc;
268 269
}

S
Sachin Prabhu 已提交
270 271 272 273
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)
274
{
S
Sachin Prabhu 已提交
275 276 277 278 279 280
	int rc;
	u8 *buf = NULL;
	unsigned int link_len = 0;
	unsigned int bytes_read = 0;

	if (!couldbe_mf_symlink(fattr))
281
		/* it's not a symlink */
S
Sachin Prabhu 已提交
282
		return 0;
283

S
Sachin Prabhu 已提交
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
	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) {
302
		/* it's not a symlink */
S
Sachin Prabhu 已提交
303 304 305
		rc = 0;
		goto out;
	}
306

S
Sachin Prabhu 已提交
307 308 309 310 311 312 313 314 315 316 317
	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;
318 319
}

S
Sachin Prabhu 已提交
320 321 322 323
/*
 * SMB 1.0 Protocol specific functions
 */

324
int
325 326 327
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)
328 329 330
{
	int rc;
	int oplock = 0;
331 332
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
333
	struct cifs_io_parms io_parms;
334 335 336
	int buf_type = CIFS_NO_BUFFER;
	FILE_ALL_INFO file_info;

337 338 339 340 341 342 343 344 345 346
	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);
347
	if (rc)
348
		return rc;
349

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

356
	io_parms.netfid = fid.netfid;
357
	io_parms.pid = current->tgid;
358
	io_parms.tcon = tcon;
359 360
	io_parms.offset = 0;
	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
361

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

368 369 370 371 372 373 374
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;
375 376
	struct cifs_fid fid;
	struct cifs_open_parms oparms;
377 378 379 380 381 382
	struct cifs_io_parms io_parms;
	int create_options = CREATE_NOT_DIR;

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

383 384 385 386
	oparms.tcon = tcon;
	oparms.cifs_sb = cifs_sb;
	oparms.desired_access = GENERIC_WRITE;
	oparms.create_options = create_options;
387
	oparms.disposition = FILE_CREATE;
388 389 390 391 392
	oparms.path = path;
	oparms.fid = &fid;
	oparms.reconnect = false;

	rc = CIFS_open(xid, &oparms, &oplock, NULL);
393 394 395
	if (rc)
		return rc;

396
	io_parms.netfid = fid.netfid;
397 398 399 400 401 402
	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);
403
	CIFSSMBClose(xid, tcon, fid.netfid);
404 405 406
	return rc;
}

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 466 467 468 469 470 471 472
/*
 * SMB 2.1/SMB3 Protocol specific functions
 */
#ifdef CONFIG_CIFS_SMB2
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;
	}

	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
	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;
}

473 474 475 476 477 478 479 480 481 482 483 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 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
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;
}
533
#endif /* CONFIG_CIFS_SMB2 */
534

S
Sachin Prabhu 已提交
535 536 537
/*
 * M-F Symlink Functions - End
 */
538

L
Linus Torvalds 已提交
539 540 541 542 543
int
cifs_hardlink(struct dentry *old_file, struct inode *inode,
	      struct dentry *direntry)
{
	int rc = -EACCES;
544
	unsigned int xid;
S
Steve French 已提交
545 546
	char *from_name = NULL;
	char *to_name = NULL;
547 548
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink;
S
Steve French 已提交
549 550
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
L
Linus Torvalds 已提交
551 552
	struct cifsInodeInfo *cifsInode;

553 554 555
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
S
Steve French 已提交
556
	tcon = tlink_tcon(tlink);
L
Linus Torvalds 已提交
557

558
	xid = get_xid();
L
Linus Torvalds 已提交
559

S
Steve French 已提交
560 561 562
	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 已提交
563 564 565 566
		rc = -ENOMEM;
		goto cifs_hl_exit;
	}

S
Steve French 已提交
567 568
	if (tcon->unix_ext)
		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
569
					    cifs_sb->local_nls,
570
					    cifs_remap(cifs_sb));
L
Linus Torvalds 已提交
571
	else {
S
Steve French 已提交
572
		server = tcon->ses->server;
573 574 575 576
		if (!server->ops->create_hardlink) {
			rc = -ENOSYS;
			goto cifs_hl_exit;
		}
S
Steve French 已提交
577 578
		rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
						  cifs_sb);
S
Steve French 已提交
579 580
		if ((rc == -EIO) || (rc == -EINVAL))
			rc = -EOPNOTSUPP;
L
Linus Torvalds 已提交
581 582
	}

583 584
	d_drop(direntry);	/* force new lookup from server of target */

S
Steve French 已提交
585 586 587 588
	/*
	 * if source file is cached (oplocked) revalidate will not go to server
	 * until the file is closed or oplock broken so update nlinks locally
	 */
589 590
	if (d_really_is_positive(old_file)) {
		cifsInode = CIFS_I(d_inode(old_file));
S
Steve French 已提交
591
		if (rc == 0) {
592 593 594
			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 已提交
595

S
Steve French 已提交
596 597 598 599 600 601
			/*
			 * 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?
			 */
602
		}
S
Steve French 已提交
603 604
		/*
		 * if not oplocked will force revalidate to get info on source
S
Steve French 已提交
605 606 607
		 * 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 已提交
608
		 */
609 610
		cifsInode->time = 0;

S
Steve French 已提交
611 612 613 614 615 616 617 618
		/*
		 * 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 已提交
619 620 621
	}

cifs_hl_exit:
S
Steve French 已提交
622 623
	kfree(from_name);
	kfree(to_name);
624
	free_xid(xid);
625
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
626 627 628
	return rc;
}

629
void *
L
Linus Torvalds 已提交
630 631
cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
{
632
	struct inode *inode = d_inode(direntry);
633
	int rc = -ENOMEM;
634
	unsigned int xid;
L
Linus Torvalds 已提交
635
	char *full_path = NULL;
636 637
	char *target_path = NULL;
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
638
	struct tcon_link *tlink = NULL;
639
	struct cifs_tcon *tcon;
640
	struct TCP_Server_Info *server;
L
Linus Torvalds 已提交
641

642
	xid = get_xid();
L
Linus Torvalds 已提交
643

644 645 646 647 648 649 650
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		tlink = NULL;
		goto out;
	}
	tcon = tlink_tcon(tlink);
651
	server = tcon->ses->server;
L
Linus Torvalds 已提交
652

653
	full_path = build_path_from_dentry(direntry);
L
Linus Torvalds 已提交
654
	if (!full_path)
655
		goto out;
L
Linus Torvalds 已提交
656

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

659 660 661 662 663 664
	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)
665 666
		rc = query_mf_symlink(xid, tcon, cifs_sb, full_path,
				      &target_path);
667

668
	if (rc != 0 && server->ops->query_symlink)
669 670
		rc = server->ops->query_symlink(xid, tcon, full_path,
						&target_path, cifs_sb);
671

672 673
	kfree(full_path);
out:
674
	if (rc != 0) {
L
Linus Torvalds 已提交
675 676 677 678
		kfree(target_path);
		target_path = ERR_PTR(rc);
	}

679
	free_xid(xid);
680 681
	if (tlink)
		cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
682
	nd_set_link(nd, target_path);
683
	return NULL;
L
Linus Torvalds 已提交
684 685 686 687 688 689
}

int
cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
{
	int rc = -EOPNOTSUPP;
690
	unsigned int xid;
691 692
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink;
693
	struct cifs_tcon *pTcon;
L
Linus Torvalds 已提交
694 695 696
	char *full_path = NULL;
	struct inode *newinode = NULL;

697
	xid = get_xid();
L
Linus Torvalds 已提交
698

699 700 701 702 703 704
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		goto symlink_exit;
	}
	pTcon = tlink_tcon(tlink);
L
Linus Torvalds 已提交
705

706
	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
707
	if (full_path == NULL) {
708
		rc = -ENOMEM;
709
		goto symlink_exit;
L
Linus Torvalds 已提交
710 711
	}

712 713
	cifs_dbg(FYI, "Full path: %s\n", full_path);
	cifs_dbg(FYI, "symname is %s\n", symname);
L
Linus Torvalds 已提交
714 715

	/* BB what if DFS and this volume is on different share? BB */
716
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
717
		rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
718
	else if (pTcon->unix_ext)
L
Linus Torvalds 已提交
719
		rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
720 721
					   cifs_sb->local_nls,
					   cifs_remap(cifs_sb));
L
Linus Torvalds 已提交
722
	/* else
S
Steve French 已提交
723 724
	   rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
					cifs_sb_target->local_nls); */
L
Linus Torvalds 已提交
725 726

	if (rc == 0) {
727
		if (pTcon->unix_ext)
L
Linus Torvalds 已提交
728
			rc = cifs_get_inode_info_unix(&newinode, full_path,
S
Steve French 已提交
729
						      inode->i_sb, xid);
L
Linus Torvalds 已提交
730 731
		else
			rc = cifs_get_inode_info(&newinode, full_path, NULL,
732
						 inode->i_sb, xid, NULL);
L
Linus Torvalds 已提交
733 734

		if (rc != 0) {
735 736
			cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
				 rc);
L
Linus Torvalds 已提交
737 738 739 740
		} else {
			d_instantiate(direntry, newinode);
		}
	}
741
symlink_exit:
J
Jesper Juhl 已提交
742
	kfree(full_path);
743
	cifs_put_tlink(tlink);
744
	free_xid(xid);
L
Linus Torvalds 已提交
745 746
	return rc;
}