xref: /linux/fs/smb/client/link.c (revision 4ccb3a800028759b2ba39857cb180589575d7445)
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2008
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  */
8 #include <crypto/md5.h>
9 #include <linux/fs.h>
10 #include <linux/stat.h>
11 #include <linux/slab.h>
12 #include <linux/namei.h>
13 #include "cifsfs.h"
14 #include "cifspdu.h"
15 #include "cifsglob.h"
16 #include "cifsproto.h"
17 #include "cifs_debug.h"
18 #include "cifs_fs_sb.h"
19 #include "cifs_unicode.h"
20 #include "smb2proto.h"
21 #include "cifs_ioctl.h"
22 #include "fs_context.h"
23 #include "reparse.h"
24 
25 /*
26  * M-F Symlink Functions - Begin
27  */
28 
29 #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
30 #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
31 #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
32 #define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
33 #define CIFS_MF_SYMLINK_FILE_SIZE \
34 	(CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
35 
36 #define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
37 #define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
38 #define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
39 
40 static int
parse_mf_symlink(const u8 * buf,unsigned int buf_len,unsigned int * _link_len,char ** _link_str)41 parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
42 		 char **_link_str)
43 {
44 	int rc;
45 	unsigned int link_len;
46 	const char *md5_str1;
47 	const char *link_str;
48 	u8 md5_hash[16];
49 	char md5_str2[34];
50 
51 	if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
52 		return -EINVAL;
53 
54 	md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET];
55 	link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET];
56 
57 	rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len);
58 	if (rc != 1)
59 		return -EINVAL;
60 
61 	if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
62 		return -EINVAL;
63 
64 	md5(link_str, link_len, md5_hash);
65 
66 	scnprintf(md5_str2, sizeof(md5_str2),
67 		  CIFS_MF_SYMLINK_MD5_FORMAT,
68 		  CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
69 
70 	if (strncmp(md5_str1, md5_str2, 17) != 0)
71 		return -EINVAL;
72 
73 	if (_link_str) {
74 		*_link_str = kstrndup(link_str, link_len, GFP_KERNEL);
75 		if (!*_link_str)
76 			return -ENOMEM;
77 	}
78 
79 	*_link_len = link_len;
80 	return 0;
81 }
82 
83 static int
format_mf_symlink(u8 * buf,unsigned int buf_len,const char * link_str)84 format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
85 {
86 	unsigned int link_len;
87 	unsigned int ofs;
88 	u8 md5_hash[16];
89 
90 	if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
91 		return -EINVAL;
92 
93 	link_len = strlen(link_str);
94 
95 	if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
96 		return -ENAMETOOLONG;
97 
98 	md5(link_str, link_len, md5_hash);
99 
100 	scnprintf(buf, buf_len,
101 		  CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
102 		  link_len,
103 		  CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
104 
105 	ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
106 	memcpy(buf + ofs, link_str, link_len);
107 
108 	ofs += link_len;
109 	if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
110 		buf[ofs] = '\n';
111 		ofs++;
112 	}
113 
114 	while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
115 		buf[ofs] = ' ';
116 		ofs++;
117 	}
118 
119 	return 0;
120 }
121 
122 bool
couldbe_mf_symlink(const struct cifs_fattr * fattr)123 couldbe_mf_symlink(const struct cifs_fattr *fattr)
124 {
125 	if (!S_ISREG(fattr->cf_mode))
126 		/* it's not a symlink */
127 		return false;
128 
129 	if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
130 		/* it's not a symlink */
131 		return false;
132 
133 	return true;
134 }
135 
136 static int
create_mf_symlink(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * fromName,const char * toName)137 create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
138 		  struct cifs_sb_info *cifs_sb, const char *fromName,
139 		  const char *toName)
140 {
141 	int rc;
142 	u8 *buf;
143 	unsigned int bytes_written = 0;
144 
145 	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
146 	if (!buf)
147 		return -ENOMEM;
148 
149 	rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
150 	if (rc)
151 		goto out;
152 
153 	if (tcon->ses->server->ops->create_mf_symlink)
154 		rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon,
155 					cifs_sb, fromName, buf, &bytes_written);
156 	else
157 		rc = -EOPNOTSUPP;
158 
159 	if (rc)
160 		goto out;
161 
162 	if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
163 		rc = -EIO;
164 out:
165 	kfree(buf);
166 	return rc;
167 }
168 
169 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)170 check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
171 		 struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
172 		 const unsigned char *path)
173 {
174 	int rc;
175 	u8 *buf = NULL;
176 	unsigned int link_len = 0;
177 	unsigned int bytes_read = 0;
178 	char *symlink = NULL;
179 
180 	if (!couldbe_mf_symlink(fattr))
181 		/* it's not a symlink */
182 		return 0;
183 
184 	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
185 	if (!buf)
186 		return -ENOMEM;
187 
188 	if (tcon->ses->server->ops->query_mf_symlink)
189 		rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
190 					      cifs_sb, path, buf, &bytes_read);
191 	else
192 		rc = -ENOSYS;
193 
194 	if (rc)
195 		goto out;
196 
197 	if (bytes_read == 0) /* not a symlink */
198 		goto out;
199 
200 	rc = parse_mf_symlink(buf, bytes_read, &link_len, &symlink);
201 	if (rc == -EINVAL) {
202 		/* it's not a symlink */
203 		rc = 0;
204 		goto out;
205 	}
206 
207 	if (rc != 0)
208 		goto out;
209 
210 	/* it is a symlink */
211 	fattr->cf_eof = link_len;
212 	fattr->cf_mode &= ~S_IFMT;
213 	fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
214 	fattr->cf_dtype = DT_LNK;
215 	fattr->cf_symlink_target = symlink;
216 out:
217 	kfree(buf);
218 	return rc;
219 }
220 
221 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
222 /*
223  * SMB 1.0 Protocol specific functions
224  */
225 
226 int
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)227 cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
228 		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
229 		      char *pbuf, unsigned int *pbytes_read)
230 {
231 	int rc;
232 	int oplock = 0;
233 	struct cifs_fid fid;
234 	struct cifs_open_parms oparms;
235 	struct cifs_io_parms io_parms = {0};
236 	int buf_type = CIFS_NO_BUFFER;
237 	struct cifs_open_info_data query_data;
238 
239 	oparms = (struct cifs_open_parms) {
240 		.tcon = tcon,
241 		.cifs_sb = cifs_sb,
242 		.desired_access = GENERIC_READ,
243 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
244 		.disposition = FILE_OPEN,
245 		.path = path,
246 		.fid = &fid,
247 	};
248 
249 	rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &query_data);
250 	if (rc)
251 		return rc;
252 
253 	if (query_data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
254 		rc = -ENOENT;
255 		/* it's not a symlink */
256 		goto out;
257 	}
258 
259 	io_parms.netfid = fid.netfid;
260 	io_parms.pid = current->tgid;
261 	io_parms.tcon = tcon;
262 	io_parms.offset = 0;
263 	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
264 
265 	rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
266 out:
267 	CIFSSMBClose(xid, tcon, fid.netfid);
268 	return rc;
269 }
270 
271 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)272 cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
273 		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
274 		       char *pbuf, unsigned int *pbytes_written)
275 {
276 	int rc;
277 	int oplock = 0;
278 	struct cifs_fid fid;
279 	struct cifs_open_parms oparms;
280 	struct cifs_io_parms io_parms = {0};
281 
282 	oparms = (struct cifs_open_parms) {
283 		.tcon = tcon,
284 		.cifs_sb = cifs_sb,
285 		.desired_access = GENERIC_WRITE,
286 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
287 		.disposition = FILE_CREATE,
288 		.path = path,
289 		.fid = &fid,
290 	};
291 
292 	rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
293 	if (rc)
294 		return rc;
295 
296 	io_parms.netfid = fid.netfid;
297 	io_parms.pid = current->tgid;
298 	io_parms.tcon = tcon;
299 	io_parms.offset = 0;
300 	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
301 
302 	rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf);
303 	CIFSSMBClose(xid, tcon, fid.netfid);
304 	return rc;
305 }
306 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
307 
308 /*
309  * SMB 2.1/SMB3 Protocol specific functions
310  */
311 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)312 smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
313 		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
314 		      char *pbuf, unsigned int *pbytes_read)
315 {
316 	int rc;
317 	struct cifs_fid fid;
318 	struct cifs_open_parms oparms;
319 	struct cifs_io_parms io_parms = {0};
320 	int buf_type = CIFS_NO_BUFFER;
321 	__le16 *utf16_path;
322 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
323 	struct smb2_file_all_info *pfile_info = NULL;
324 
325 	oparms = (struct cifs_open_parms) {
326 		.tcon = tcon,
327 		.cifs_sb = cifs_sb,
328 		.path = path,
329 		.desired_access = GENERIC_READ,
330 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
331 		.disposition = FILE_OPEN,
332 		.fid = &fid,
333 	};
334 
335 	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
336 	if (utf16_path == NULL)
337 		return -ENOMEM;
338 
339 	pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
340 			     GFP_KERNEL);
341 
342 	if (pfile_info == NULL) {
343 		kfree(utf16_path);
344 		return  -ENOMEM;
345 	}
346 
347 	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL,
348 		       NULL, NULL);
349 	if (rc)
350 		goto qmf_out_open_fail;
351 
352 	if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
353 		/* it's not a symlink */
354 		rc = -ENOENT; /* Is there a better rc to return? */
355 		goto qmf_out;
356 	}
357 
358 	io_parms.netfid = fid.netfid;
359 	io_parms.pid = current->tgid;
360 	io_parms.tcon = tcon;
361 	io_parms.offset = 0;
362 	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
363 	io_parms.persistent_fid = fid.persistent_fid;
364 	io_parms.volatile_fid = fid.volatile_fid;
365 	rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
366 qmf_out:
367 	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
368 qmf_out_open_fail:
369 	kfree(utf16_path);
370 	kfree(pfile_info);
371 	return rc;
372 }
373 
374 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)375 smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
376 		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
377 		       char *pbuf, unsigned int *pbytes_written)
378 {
379 	int rc;
380 	struct cifs_fid fid;
381 	struct cifs_open_parms oparms;
382 	struct cifs_io_parms io_parms = {0};
383 	__le16 *utf16_path;
384 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
385 	struct kvec iov[2];
386 
387 	cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
388 
389 	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
390 	if (!utf16_path)
391 		return -ENOMEM;
392 
393 	oparms = (struct cifs_open_parms) {
394 		.tcon = tcon,
395 		.cifs_sb = cifs_sb,
396 		.path = path,
397 		.desired_access = GENERIC_WRITE,
398 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
399 		.disposition = FILE_CREATE,
400 		.fid = &fid,
401 		.mode = 0644,
402 	};
403 
404 	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
405 		       NULL, NULL);
406 	if (rc) {
407 		kfree(utf16_path);
408 		return rc;
409 	}
410 
411 	io_parms.netfid = fid.netfid;
412 	io_parms.pid = current->tgid;
413 	io_parms.tcon = tcon;
414 	io_parms.offset = 0;
415 	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
416 	io_parms.persistent_fid = fid.persistent_fid;
417 	io_parms.volatile_fid = fid.volatile_fid;
418 
419 	/* iov[0] is reserved for smb header */
420 	iov[1].iov_base = pbuf;
421 	iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
422 
423 	rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
424 
425 	/* Make sure we wrote all of the symlink data */
426 	if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
427 		rc = -EIO;
428 
429 	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
430 
431 	kfree(utf16_path);
432 	return rc;
433 }
434 
435 /*
436  * M-F Symlink Functions - End
437  */
438 
439 int
cifs_hardlink(struct dentry * old_file,struct inode * inode,struct dentry * direntry)440 cifs_hardlink(struct dentry *old_file, struct inode *inode,
441 	      struct dentry *direntry)
442 {
443 	int rc = -EACCES;
444 	unsigned int xid;
445 	const char *from_name, *to_name;
446 	void *page1, *page2;
447 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
448 	struct tcon_link *tlink;
449 	struct cifs_tcon *tcon;
450 	struct TCP_Server_Info *server;
451 	struct cifsInodeInfo *cifsInode;
452 
453 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
454 		return -EIO;
455 
456 	tlink = cifs_sb_tlink(cifs_sb);
457 	if (IS_ERR(tlink))
458 		return PTR_ERR(tlink);
459 	tcon = tlink_tcon(tlink);
460 
461 	xid = get_xid();
462 	page1 = alloc_dentry_path();
463 	page2 = alloc_dentry_path();
464 
465 	from_name = build_path_from_dentry(old_file, page1);
466 	if (IS_ERR(from_name)) {
467 		rc = PTR_ERR(from_name);
468 		goto cifs_hl_exit;
469 	}
470 	to_name = build_path_from_dentry(direntry, page2);
471 	if (IS_ERR(to_name)) {
472 		rc = PTR_ERR(to_name);
473 		goto cifs_hl_exit;
474 	}
475 
476 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
477 	if (tcon->unix_ext)
478 		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
479 					    cifs_sb->local_nls,
480 					    cifs_remap(cifs_sb));
481 	else {
482 #else
483 	{
484 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
485 		server = tcon->ses->server;
486 		if (!server->ops->create_hardlink) {
487 			rc = -ENOSYS;
488 			goto cifs_hl_exit;
489 		}
490 		rc = server->ops->create_hardlink(xid, tcon, old_file,
491 						  from_name, to_name, cifs_sb);
492 		if ((rc == -EIO) || (rc == -EINVAL))
493 			rc = -EOPNOTSUPP;
494 	}
495 
496 	d_drop(direntry);	/* force new lookup from server of target */
497 
498 	/*
499 	 * if source file is cached (oplocked) revalidate will not go to server
500 	 * until the file is closed or oplock broken so update nlinks locally
501 	 */
502 	if (d_really_is_positive(old_file)) {
503 		cifsInode = CIFS_I(d_inode(old_file));
504 		if (rc == 0) {
505 			spin_lock(&d_inode(old_file)->i_lock);
506 			inc_nlink(d_inode(old_file));
507 			spin_unlock(&d_inode(old_file)->i_lock);
508 
509 			/*
510 			 * parent dir timestamps will update from srv within a
511 			 * second, would it really be worth it to set the parent
512 			 * dir cifs inode time to zero to force revalidate
513 			 * (faster) for it too?
514 			 */
515 		}
516 		/*
517 		 * if not oplocked will force revalidate to get info on source
518 		 * file from srv.  Note Samba server prior to 4.2 has bug -
519 		 * not updating src file ctime on hardlinks but Windows servers
520 		 * handle it properly
521 		 */
522 		cifsInode->time = 0;
523 
524 		/*
525 		 * Will update parent dir timestamps from srv within a second.
526 		 * Would it really be worth it to set the parent dir (cifs
527 		 * inode) time field to zero to force revalidate on parent
528 		 * directory faster ie
529 		 *
530 		 * CIFS_I(inode)->time = 0;
531 		 */
532 	}
533 
534 cifs_hl_exit:
535 	free_dentry_path(page1);
536 	free_dentry_path(page2);
537 	free_xid(xid);
538 	cifs_put_tlink(tlink);
539 	return rc;
540 }
541 
542 int
543 cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
544 	     struct dentry *direntry, const char *symname)
545 {
546 	int rc = -EOPNOTSUPP;
547 	unsigned int xid;
548 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
549 	struct tcon_link *tlink;
550 	struct cifs_tcon *pTcon;
551 	const char *full_path;
552 	void *page;
553 	struct inode *newinode = NULL;
554 
555 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
556 		return -EIO;
557 
558 	page = alloc_dentry_path();
559 	if (!page)
560 		return -ENOMEM;
561 
562 	xid = get_xid();
563 
564 	tlink = cifs_sb_tlink(cifs_sb);
565 	if (IS_ERR(tlink)) {
566 		rc = PTR_ERR(tlink);
567 		/* BB could be clearer if skipped put_tlink on error here, but harmless */
568 		goto symlink_exit;
569 	}
570 	pTcon = tlink_tcon(tlink);
571 
572 	full_path = build_path_from_dentry(direntry, page);
573 	if (IS_ERR(full_path)) {
574 		rc = PTR_ERR(full_path);
575 		goto symlink_exit;
576 	}
577 
578 	cifs_dbg(FYI, "Full path: %s\n", full_path);
579 	cifs_dbg(FYI, "symname is %s\n", symname);
580 
581 	/* BB what if DFS and this volume is on different share? BB */
582 	rc = -EOPNOTSUPP;
583 	switch (cifs_symlink_type(cifs_sb)) {
584 	case CIFS_SYMLINK_TYPE_UNIX:
585 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
586 		if (pTcon->unix_ext) {
587 			rc = CIFSUnixCreateSymLink(xid, pTcon, full_path,
588 						   symname,
589 						   cifs_sb->local_nls,
590 						   cifs_remap(cifs_sb));
591 		}
592 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
593 		break;
594 
595 	case CIFS_SYMLINK_TYPE_MFSYMLINKS:
596 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
597 			rc = create_mf_symlink(xid, pTcon, cifs_sb,
598 					       full_path, symname);
599 		}
600 		break;
601 
602 	case CIFS_SYMLINK_TYPE_SFU:
603 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
604 			rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon,
605 						  full_path, S_IFLNK,
606 						  0, symname);
607 		}
608 		break;
609 
610 	case CIFS_SYMLINK_TYPE_NATIVE:
611 	case CIFS_SYMLINK_TYPE_NFS:
612 	case CIFS_SYMLINK_TYPE_WSL:
613 		if (CIFS_REPARSE_SUPPORT(pTcon)) {
614 			rc = create_reparse_symlink(xid, inode, direntry, pTcon,
615 						    full_path, symname);
616 			goto symlink_exit;
617 		}
618 		break;
619 	default:
620 		break;
621 	}
622 
623 	if (rc == 0) {
624 		if (pTcon->posix_extensions) {
625 			rc = smb311_posix_get_inode_info(&newinode, full_path,
626 							 NULL, inode->i_sb, xid);
627 		} else if (pTcon->unix_ext) {
628 			rc = cifs_get_inode_info_unix(&newinode, full_path,
629 						      inode->i_sb, xid);
630 		} else {
631 			rc = cifs_get_inode_info(&newinode, full_path, NULL,
632 						 inode->i_sb, xid, NULL);
633 		}
634 
635 		if (rc != 0) {
636 			cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
637 				 rc);
638 		} else {
639 			d_instantiate(direntry, newinode);
640 		}
641 	}
642 symlink_exit:
643 	free_dentry_path(page);
644 	cifs_put_tlink(tlink);
645 	free_xid(xid);
646 	return rc;
647 }
648