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 "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 #include "fs_context.h"
22 #include "reparse.h"
23
24 /*
25 * M-F Symlink Functions - Begin
26 */
27
28 #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
29 #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
30 #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
31 #define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
32 #define CIFS_MF_SYMLINK_FILE_SIZE \
33 (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
34
35 #define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
36 #define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
37 #define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
38
39 static int
parse_mf_symlink(const u8 * buf,unsigned int buf_len,unsigned int * _link_len,char ** _link_str)40 parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
41 char **_link_str)
42 {
43 int rc;
44 unsigned int link_len;
45 const char *md5_str1;
46 const char *link_str;
47 u8 md5_hash[16];
48 char md5_str2[34];
49
50 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
51 return -EINVAL;
52
53 md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET];
54 link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET];
55
56 rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len);
57 if (rc != 1)
58 return -EINVAL;
59
60 if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
61 return -EINVAL;
62
63 md5(link_str, link_len, md5_hash);
64
65 scnprintf(md5_str2, sizeof(md5_str2),
66 CIFS_MF_SYMLINK_MD5_FORMAT,
67 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
68
69 if (strncmp(md5_str1, md5_str2, 17) != 0)
70 return -EINVAL;
71
72 if (_link_str) {
73 *_link_str = kstrndup(link_str, link_len, GFP_KERNEL);
74 if (!*_link_str)
75 return -ENOMEM;
76 }
77
78 *_link_len = link_len;
79 return 0;
80 }
81
82 static int
format_mf_symlink(u8 * buf,unsigned int buf_len,const char * link_str)83 format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
84 {
85 unsigned int link_len;
86 unsigned int ofs;
87 u8 md5_hash[16];
88
89 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
90 return -EINVAL;
91
92 link_len = strlen(link_str);
93
94 if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
95 return -ENAMETOOLONG;
96
97 md5(link_str, link_len, md5_hash);
98
99 scnprintf(buf, buf_len,
100 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
101 link_len,
102 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
103
104 ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
105 memcpy(buf + ofs, link_str, link_len);
106
107 ofs += link_len;
108 if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
109 buf[ofs] = '\n';
110 ofs++;
111 }
112
113 while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
114 buf[ofs] = ' ';
115 ofs++;
116 }
117
118 return 0;
119 }
120
121 bool
couldbe_mf_symlink(const struct cifs_fattr * fattr)122 couldbe_mf_symlink(const struct cifs_fattr *fattr)
123 {
124 if (!S_ISREG(fattr->cf_mode))
125 /* it's not a symlink */
126 return false;
127
128 if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
129 /* it's not a symlink */
130 return false;
131
132 return true;
133 }
134
135 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)136 create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
137 struct cifs_sb_info *cifs_sb, const char *fromName,
138 const char *toName)
139 {
140 int rc;
141 u8 *buf;
142 unsigned int bytes_written = 0;
143
144 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
145 if (!buf)
146 return -ENOMEM;
147
148 rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
149 if (rc)
150 goto out;
151
152 if (tcon->ses->server->ops->create_mf_symlink)
153 rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon,
154 cifs_sb, fromName, buf, &bytes_written);
155 else
156 rc = -EOPNOTSUPP;
157
158 if (rc)
159 goto out;
160
161 if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
162 rc = smb_EIO2(smb_eio_trace_symlink_file_size,
163 bytes_written, CIFS_MF_SYMLINK_FILE_SIZE);
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 = smb_EIO2(smb_eio_trace_short_symlink_write,
428 *pbytes_written, CIFS_MF_SYMLINK_FILE_SIZE);
429
430 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
431
432 kfree(utf16_path);
433 return rc;
434 }
435
436 /*
437 * M-F Symlink Functions - End
438 */
439
440 int
cifs_hardlink(struct dentry * old_file,struct inode * inode,struct dentry * direntry)441 cifs_hardlink(struct dentry *old_file, struct inode *inode,
442 struct dentry *direntry)
443 {
444 int rc = -EACCES;
445 unsigned int xid;
446 const char *from_name, *to_name;
447 void *page1, *page2;
448 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
449 struct tcon_link *tlink;
450 struct cifs_tcon *tcon;
451 struct TCP_Server_Info *server;
452 struct cifsInodeInfo *cifsInode;
453
454 if (unlikely(cifs_forced_shutdown(cifs_sb)))
455 return smb_EIO(smb_eio_trace_forced_shutdown);
456
457 tlink = cifs_sb_tlink(cifs_sb);
458 if (IS_ERR(tlink))
459 return PTR_ERR(tlink);
460 tcon = tlink_tcon(tlink);
461
462 xid = get_xid();
463 page1 = alloc_dentry_path();
464 page2 = alloc_dentry_path();
465
466 from_name = build_path_from_dentry(old_file, page1);
467 if (IS_ERR(from_name)) {
468 rc = PTR_ERR(from_name);
469 goto cifs_hl_exit;
470 }
471 to_name = build_path_from_dentry(direntry, page2);
472 if (IS_ERR(to_name)) {
473 rc = PTR_ERR(to_name);
474 goto cifs_hl_exit;
475 }
476
477 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
478 if (tcon->unix_ext)
479 rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
480 cifs_sb->local_nls,
481 cifs_remap(cifs_sb));
482 else {
483 #else
484 {
485 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
486 server = tcon->ses->server;
487 if (!server->ops->create_hardlink) {
488 rc = -ENOSYS;
489 goto cifs_hl_exit;
490 }
491 rc = server->ops->create_hardlink(xid, tcon, old_file,
492 from_name, to_name, cifs_sb);
493 if ((rc == -EIO) || (rc == -EINVAL))
494 rc = -EOPNOTSUPP;
495 }
496
497 d_drop(direntry); /* force new lookup from server of target */
498
499 /*
500 * if source file is cached (oplocked) revalidate will not go to server
501 * until the file is closed or oplock broken so update nlinks locally
502 */
503 if (d_really_is_positive(old_file)) {
504 cifsInode = CIFS_I(d_inode(old_file));
505 if (rc == 0) {
506 spin_lock(&d_inode(old_file)->i_lock);
507 inc_nlink(d_inode(old_file));
508 spin_unlock(&d_inode(old_file)->i_lock);
509
510 /*
511 * parent dir timestamps will update from srv within a
512 * second, would it really be worth it to set the parent
513 * dir cifs inode time to zero to force revalidate
514 * (faster) for it too?
515 */
516 }
517 /*
518 * if not oplocked will force revalidate to get info on source
519 * file from srv. Note Samba server prior to 4.2 has bug -
520 * not updating src file ctime on hardlinks but Windows servers
521 * handle it properly
522 */
523 cifsInode->time = 0;
524
525 /*
526 * Will update parent dir timestamps from srv within a second.
527 * Would it really be worth it to set the parent dir (cifs
528 * inode) time field to zero to force revalidate on parent
529 * directory faster ie
530 *
531 * CIFS_I(inode)->time = 0;
532 */
533 }
534
535 cifs_hl_exit:
536 free_dentry_path(page1);
537 free_dentry_path(page2);
538 free_xid(xid);
539 cifs_put_tlink(tlink);
540 return rc;
541 }
542
543 int
544 cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
545 struct dentry *direntry, const char *symname)
546 {
547 struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
548 struct inode *newinode = NULL;
549 struct tcon_link *tlink;
550 struct cifs_tcon *pTcon;
551 const char *full_path;
552 int rc = -EOPNOTSUPP;
553 unsigned int sbflags;
554 unsigned int xid;
555 void *page;
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 sbflags = cifs_sb_flags(cifs_sb);
585 rc = -EOPNOTSUPP;
586 switch (cifs_symlink_type(cifs_sb)) {
587 case CIFS_SYMLINK_TYPE_UNIX:
588 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
589 if (pTcon->unix_ext) {
590 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path,
591 symname,
592 cifs_sb->local_nls,
593 cifs_remap(cifs_sb));
594 }
595 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
596 break;
597
598 case CIFS_SYMLINK_TYPE_MFSYMLINKS:
599 if (sbflags & CIFS_MOUNT_MF_SYMLINKS) {
600 rc = create_mf_symlink(xid, pTcon, cifs_sb,
601 full_path, symname);
602 }
603 break;
604
605 case CIFS_SYMLINK_TYPE_SFU:
606 if (sbflags & CIFS_MOUNT_UNX_EMUL) {
607 rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon,
608 full_path, S_IFLNK,
609 0, symname);
610 }
611 break;
612
613 case CIFS_SYMLINK_TYPE_NATIVE:
614 case CIFS_SYMLINK_TYPE_NFS:
615 case CIFS_SYMLINK_TYPE_WSL:
616 if (CIFS_REPARSE_SUPPORT(pTcon)) {
617 rc = create_reparse_symlink(xid, inode, direntry, pTcon,
618 full_path, symname);
619 goto symlink_exit;
620 }
621 break;
622 default:
623 break;
624 }
625
626 if (rc == 0) {
627 if (pTcon->posix_extensions) {
628 rc = smb311_posix_get_inode_info(&newinode, full_path,
629 NULL, inode->i_sb, xid);
630 } else if (pTcon->unix_ext) {
631 rc = cifs_get_inode_info_unix(&newinode, full_path,
632 inode->i_sb, xid);
633 } else {
634 rc = cifs_get_inode_info(&newinode, full_path, NULL,
635 inode->i_sb, xid, NULL);
636 }
637
638 if (rc != 0) {
639 cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
640 rc);
641 } else {
642 d_instantiate(direntry, newinode);
643 }
644 }
645 symlink_exit:
646 free_dentry_path(page);
647 cifs_put_tlink(tlink);
648 free_xid(xid);
649 return rc;
650 }
651