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