xref: /linux/fs/smb/client/link.c (revision 3d99347a2e1ae60d9368b1d734290bab1acde0ce)
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 = smb_EIO2(smb_eio_trace_symlink_file_size,
164 			      bytes_written, CIFS_MF_SYMLINK_FILE_SIZE);
165 out:
166 	kfree(buf);
167 	return rc;
168 }
169 
170 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)171 check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
172 		 struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
173 		 const unsigned char *path)
174 {
175 	int rc;
176 	u8 *buf = NULL;
177 	unsigned int link_len = 0;
178 	unsigned int bytes_read = 0;
179 	char *symlink = NULL;
180 
181 	if (!couldbe_mf_symlink(fattr))
182 		/* it's not a symlink */
183 		return 0;
184 
185 	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
186 	if (!buf)
187 		return -ENOMEM;
188 
189 	if (tcon->ses->server->ops->query_mf_symlink)
190 		rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
191 					      cifs_sb, path, buf, &bytes_read);
192 	else
193 		rc = -ENOSYS;
194 
195 	if (rc)
196 		goto out;
197 
198 	if (bytes_read == 0) /* not a symlink */
199 		goto out;
200 
201 	rc = parse_mf_symlink(buf, bytes_read, &link_len, &symlink);
202 	if (rc == -EINVAL) {
203 		/* it's not a symlink */
204 		rc = 0;
205 		goto out;
206 	}
207 
208 	if (rc != 0)
209 		goto out;
210 
211 	/* it is a symlink */
212 	fattr->cf_eof = link_len;
213 	fattr->cf_mode &= ~S_IFMT;
214 	fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
215 	fattr->cf_dtype = DT_LNK;
216 	fattr->cf_symlink_target = symlink;
217 out:
218 	kfree(buf);
219 	return rc;
220 }
221 
222 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
223 /*
224  * SMB 1.0 Protocol specific functions
225  */
226 
227 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)228 cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
229 		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
230 		      char *pbuf, unsigned int *pbytes_read)
231 {
232 	int rc;
233 	int oplock = 0;
234 	struct cifs_fid fid;
235 	struct cifs_open_parms oparms;
236 	struct cifs_io_parms io_parms = {0};
237 	int buf_type = CIFS_NO_BUFFER;
238 	struct cifs_open_info_data query_data;
239 
240 	oparms = (struct cifs_open_parms) {
241 		.tcon = tcon,
242 		.cifs_sb = cifs_sb,
243 		.desired_access = GENERIC_READ,
244 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
245 		.disposition = FILE_OPEN,
246 		.path = path,
247 		.fid = &fid,
248 	};
249 
250 	rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &query_data);
251 	if (rc)
252 		return rc;
253 
254 	if (query_data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
255 		rc = -ENOENT;
256 		/* it's not a symlink */
257 		goto out;
258 	}
259 
260 	io_parms.netfid = fid.netfid;
261 	io_parms.pid = current->tgid;
262 	io_parms.tcon = tcon;
263 	io_parms.offset = 0;
264 	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
265 
266 	rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
267 out:
268 	CIFSSMBClose(xid, tcon, fid.netfid);
269 	return rc;
270 }
271 
272 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)273 cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
274 		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
275 		       char *pbuf, unsigned int *pbytes_written)
276 {
277 	int rc;
278 	int oplock = 0;
279 	struct cifs_fid fid;
280 	struct cifs_open_parms oparms;
281 	struct cifs_io_parms io_parms = {0};
282 
283 	oparms = (struct cifs_open_parms) {
284 		.tcon = tcon,
285 		.cifs_sb = cifs_sb,
286 		.desired_access = GENERIC_WRITE,
287 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
288 		.disposition = FILE_CREATE,
289 		.path = path,
290 		.fid = &fid,
291 	};
292 
293 	rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
294 	if (rc)
295 		return rc;
296 
297 	io_parms.netfid = fid.netfid;
298 	io_parms.pid = current->tgid;
299 	io_parms.tcon = tcon;
300 	io_parms.offset = 0;
301 	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
302 
303 	rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf);
304 	CIFSSMBClose(xid, tcon, fid.netfid);
305 	return rc;
306 }
307 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
308 
309 /*
310  * SMB 2.1/SMB3 Protocol specific functions
311  */
312 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)313 smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
314 		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
315 		      char *pbuf, unsigned int *pbytes_read)
316 {
317 	int rc;
318 	struct cifs_fid fid;
319 	struct cifs_open_parms oparms;
320 	struct cifs_io_parms io_parms = {0};
321 	int buf_type = CIFS_NO_BUFFER;
322 	__le16 *utf16_path;
323 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
324 	struct smb2_file_all_info *pfile_info = NULL;
325 
326 	oparms = (struct cifs_open_parms) {
327 		.tcon = tcon,
328 		.cifs_sb = cifs_sb,
329 		.path = path,
330 		.desired_access = GENERIC_READ,
331 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
332 		.disposition = FILE_OPEN,
333 		.fid = &fid,
334 	};
335 
336 	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
337 	if (utf16_path == NULL)
338 		return -ENOMEM;
339 
340 	pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
341 			     GFP_KERNEL);
342 
343 	if (pfile_info == NULL) {
344 		kfree(utf16_path);
345 		return  -ENOMEM;
346 	}
347 
348 	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL,
349 		       NULL, NULL);
350 	if (rc)
351 		goto qmf_out_open_fail;
352 
353 	if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
354 		/* it's not a symlink */
355 		rc = -ENOENT; /* Is there a better rc to return? */
356 		goto qmf_out;
357 	}
358 
359 	io_parms.netfid = fid.netfid;
360 	io_parms.pid = current->tgid;
361 	io_parms.tcon = tcon;
362 	io_parms.offset = 0;
363 	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
364 	io_parms.persistent_fid = fid.persistent_fid;
365 	io_parms.volatile_fid = fid.volatile_fid;
366 	rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
367 qmf_out:
368 	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
369 qmf_out_open_fail:
370 	kfree(utf16_path);
371 	kfree(pfile_info);
372 	return rc;
373 }
374 
375 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)376 smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
377 		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
378 		       char *pbuf, unsigned int *pbytes_written)
379 {
380 	int rc;
381 	struct cifs_fid fid;
382 	struct cifs_open_parms oparms;
383 	struct cifs_io_parms io_parms = {0};
384 	__le16 *utf16_path;
385 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
386 	struct kvec iov[2];
387 
388 	cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
389 
390 	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
391 	if (!utf16_path)
392 		return -ENOMEM;
393 
394 	oparms = (struct cifs_open_parms) {
395 		.tcon = tcon,
396 		.cifs_sb = cifs_sb,
397 		.path = path,
398 		.desired_access = GENERIC_WRITE,
399 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
400 		.disposition = FILE_CREATE,
401 		.fid = &fid,
402 		.mode = 0644,
403 	};
404 
405 	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
406 		       NULL, NULL);
407 	if (rc) {
408 		kfree(utf16_path);
409 		return rc;
410 	}
411 
412 	io_parms.netfid = fid.netfid;
413 	io_parms.pid = current->tgid;
414 	io_parms.tcon = tcon;
415 	io_parms.offset = 0;
416 	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
417 	io_parms.persistent_fid = fid.persistent_fid;
418 	io_parms.volatile_fid = fid.volatile_fid;
419 
420 	/* iov[0] is reserved for smb header */
421 	iov[1].iov_base = pbuf;
422 	iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
423 
424 	rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
425 
426 	/* Make sure we wrote all of the symlink data */
427 	if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
428 		rc = smb_EIO2(smb_eio_trace_short_symlink_write,
429 			      *pbytes_written, CIFS_MF_SYMLINK_FILE_SIZE);
430 
431 	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
432 
433 	kfree(utf16_path);
434 	return rc;
435 }
436 
437 /*
438  * M-F Symlink Functions - End
439  */
440 
441 int
cifs_hardlink(struct dentry * old_file,struct inode * inode,struct dentry * direntry)442 cifs_hardlink(struct dentry *old_file, struct inode *inode,
443 	      struct dentry *direntry)
444 {
445 	int rc = -EACCES;
446 	unsigned int xid;
447 	const char *from_name, *to_name;
448 	void *page1, *page2;
449 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
450 	struct tcon_link *tlink;
451 	struct cifs_tcon *tcon;
452 	struct TCP_Server_Info *server;
453 	struct cifsInodeInfo *cifsInode;
454 
455 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
456 		return smb_EIO(smb_eio_trace_forced_shutdown);
457 
458 	tlink = cifs_sb_tlink(cifs_sb);
459 	if (IS_ERR(tlink))
460 		return PTR_ERR(tlink);
461 	tcon = tlink_tcon(tlink);
462 
463 	xid = get_xid();
464 	page1 = alloc_dentry_path();
465 	page2 = alloc_dentry_path();
466 
467 	from_name = build_path_from_dentry(old_file, page1);
468 	if (IS_ERR(from_name)) {
469 		rc = PTR_ERR(from_name);
470 		goto cifs_hl_exit;
471 	}
472 	to_name = build_path_from_dentry(direntry, page2);
473 	if (IS_ERR(to_name)) {
474 		rc = PTR_ERR(to_name);
475 		goto cifs_hl_exit;
476 	}
477 
478 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
479 	if (tcon->unix_ext)
480 		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
481 					    cifs_sb->local_nls,
482 					    cifs_remap(cifs_sb));
483 	else {
484 #else
485 	{
486 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
487 		server = tcon->ses->server;
488 		if (!server->ops->create_hardlink) {
489 			rc = -ENOSYS;
490 			goto cifs_hl_exit;
491 		}
492 		rc = server->ops->create_hardlink(xid, tcon, old_file,
493 						  from_name, to_name, cifs_sb);
494 		if ((rc == -EIO) || (rc == -EINVAL))
495 			rc = -EOPNOTSUPP;
496 	}
497 
498 	d_drop(direntry);	/* force new lookup from server of target */
499 
500 	/*
501 	 * if source file is cached (oplocked) revalidate will not go to server
502 	 * until the file is closed or oplock broken so update nlinks locally
503 	 */
504 	if (d_really_is_positive(old_file)) {
505 		cifsInode = CIFS_I(d_inode(old_file));
506 		if (rc == 0) {
507 			spin_lock(&d_inode(old_file)->i_lock);
508 			inc_nlink(d_inode(old_file));
509 			spin_unlock(&d_inode(old_file)->i_lock);
510 
511 			/*
512 			 * parent dir timestamps will update from srv within a
513 			 * second, would it really be worth it to set the parent
514 			 * dir cifs inode time to zero to force revalidate
515 			 * (faster) for it too?
516 			 */
517 		}
518 		/*
519 		 * if not oplocked will force revalidate to get info on source
520 		 * file from srv.  Note Samba server prior to 4.2 has bug -
521 		 * not updating src file ctime on hardlinks but Windows servers
522 		 * handle it properly
523 		 */
524 		cifsInode->time = 0;
525 
526 		/*
527 		 * Will update parent dir timestamps from srv within a second.
528 		 * Would it really be worth it to set the parent dir (cifs
529 		 * inode) time field to zero to force revalidate on parent
530 		 * directory faster ie
531 		 *
532 		 * CIFS_I(inode)->time = 0;
533 		 */
534 	}
535 
536 cifs_hl_exit:
537 	free_dentry_path(page1);
538 	free_dentry_path(page2);
539 	free_xid(xid);
540 	cifs_put_tlink(tlink);
541 	return rc;
542 }
543 
544 int
545 cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
546 	     struct dentry *direntry, const char *symname)
547 {
548 	int rc = -EOPNOTSUPP;
549 	unsigned int xid;
550 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
551 	struct tcon_link *tlink;
552 	struct cifs_tcon *pTcon;
553 	const char *full_path;
554 	void *page;
555 	struct inode *newinode = NULL;
556 
557 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
558 		return smb_EIO(smb_eio_trace_forced_shutdown);
559 
560 	page = alloc_dentry_path();
561 	if (!page)
562 		return -ENOMEM;
563 
564 	xid = get_xid();
565 
566 	tlink = cifs_sb_tlink(cifs_sb);
567 	if (IS_ERR(tlink)) {
568 		rc = PTR_ERR(tlink);
569 		/* BB could be clearer if skipped put_tlink on error here, but harmless */
570 		goto symlink_exit;
571 	}
572 	pTcon = tlink_tcon(tlink);
573 
574 	full_path = build_path_from_dentry(direntry, page);
575 	if (IS_ERR(full_path)) {
576 		rc = PTR_ERR(full_path);
577 		goto symlink_exit;
578 	}
579 
580 	cifs_dbg(FYI, "Full path: %s\n", full_path);
581 	cifs_dbg(FYI, "symname is %s\n", symname);
582 
583 	/* BB what if DFS and this volume is on different share? BB */
584 	rc = -EOPNOTSUPP;
585 	switch (cifs_symlink_type(cifs_sb)) {
586 	case CIFS_SYMLINK_TYPE_UNIX:
587 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
588 		if (pTcon->unix_ext) {
589 			rc = CIFSUnixCreateSymLink(xid, pTcon, full_path,
590 						   symname,
591 						   cifs_sb->local_nls,
592 						   cifs_remap(cifs_sb));
593 		}
594 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
595 		break;
596 
597 	case CIFS_SYMLINK_TYPE_MFSYMLINKS:
598 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
599 			rc = create_mf_symlink(xid, pTcon, cifs_sb,
600 					       full_path, symname);
601 		}
602 		break;
603 
604 	case CIFS_SYMLINK_TYPE_SFU:
605 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
606 			rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon,
607 						  full_path, S_IFLNK,
608 						  0, symname);
609 		}
610 		break;
611 
612 	case CIFS_SYMLINK_TYPE_NATIVE:
613 	case CIFS_SYMLINK_TYPE_NFS:
614 	case CIFS_SYMLINK_TYPE_WSL:
615 		if (CIFS_REPARSE_SUPPORT(pTcon)) {
616 			rc = create_reparse_symlink(xid, inode, direntry, pTcon,
617 						    full_path, symname);
618 			goto symlink_exit;
619 		}
620 		break;
621 	default:
622 		break;
623 	}
624 
625 	if (rc == 0) {
626 		if (pTcon->posix_extensions) {
627 			rc = smb311_posix_get_inode_info(&newinode, full_path,
628 							 NULL, inode->i_sb, xid);
629 		} else if (pTcon->unix_ext) {
630 			rc = cifs_get_inode_info_unix(&newinode, full_path,
631 						      inode->i_sb, xid);
632 		} else {
633 			rc = cifs_get_inode_info(&newinode, full_path, NULL,
634 						 inode->i_sb, xid, NULL);
635 		}
636 
637 		if (rc != 0) {
638 			cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
639 				 rc);
640 		} else {
641 			d_instantiate(direntry, newinode);
642 		}
643 	}
644 symlink_exit:
645 	free_dentry_path(page);
646 	cifs_put_tlink(tlink);
647 	free_xid(xid);
648 	return rc;
649 }
650