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