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