]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - fs/cifs/link.c
Merge branch 'rcu/fixes-for-v3.2' into rcu/urgent
[mirror_ubuntu-zesty-kernel.git] / fs / cifs / link.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/link.c
3 *
366781c1 4 * Copyright (C) International Business Machines Corp., 2002,2008
1da177e4
LT
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/fs.h>
22#include <linux/stat.h>
5a0e3ad6 23#include <linux/slab.h>
1da177e4
LT
24#include <linux/namei.h>
25#include "cifsfs.h"
26#include "cifspdu.h"
27#include "cifsglob.h"
28#include "cifsproto.h"
29#include "cifs_debug.h"
30#include "cifs_fs_sb.h"
c69c1b6e
SM
31
32#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
33#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
34#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
35#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
36#define CIFS_MF_SYMLINK_FILE_SIZE \
37 (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
38
39#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
40#define CIFS_MF_SYMLINK_MD5_FORMAT \
41 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n"
42#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \
43 md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \
44 md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \
45 md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\
46 md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
47
93c100c0
SF
48static int
49symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
50{
51 int rc;
52 unsigned int size;
53 struct crypto_shash *md5;
54 struct sdesc *sdescmd5;
55
56 md5 = crypto_alloc_shash("md5", 0, 0);
ee2c9258 57 if (IS_ERR(md5)) {
ffeb414a 58 rc = PTR_ERR(md5);
93c100c0 59 cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc);
ffeb414a 60 return rc;
93c100c0
SF
61 }
62 size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
63 sdescmd5 = kmalloc(size, GFP_KERNEL);
64 if (!sdescmd5) {
65 rc = -ENOMEM;
66 cERROR(1, "%s: Memory allocation failure\n", __func__);
67 goto symlink_hash_err;
68 }
69 sdescmd5->shash.tfm = md5;
70 sdescmd5->shash.flags = 0x0;
71
72 rc = crypto_shash_init(&sdescmd5->shash);
73 if (rc) {
74 cERROR(1, "%s: Could not init md5 shash\n", __func__);
75 goto symlink_hash_err;
76 }
14cae324
SP
77 rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len);
78 if (rc) {
79 cERROR(1, "%s: Could not update iwth link_str\n", __func__);
80 goto symlink_hash_err;
81 }
93c100c0 82 rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
14cae324
SP
83 if (rc)
84 cERROR(1, "%s: Could not generate md5 hash\n", __func__);
93c100c0
SF
85
86symlink_hash_err:
87 crypto_free_shash(md5);
88 kfree(sdescmd5);
89
90 return rc;
91}
92
c69c1b6e
SM
93static int
94CIFSParseMFSymlink(const u8 *buf,
95 unsigned int buf_len,
96 unsigned int *_link_len,
97 char **_link_str)
98{
99 int rc;
100 unsigned int link_len;
101 const char *md5_str1;
102 const char *link_str;
c69c1b6e
SM
103 u8 md5_hash[16];
104 char md5_str2[34];
105
106 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
107 return -EINVAL;
108
109 md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET];
110 link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET];
111
112 rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len);
113 if (rc != 1)
114 return -EINVAL;
115
93c100c0
SF
116 rc = symlink_hash(link_len, link_str, md5_hash);
117 if (rc) {
118 cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
119 return rc;
120 }
c69c1b6e
SM
121
122 snprintf(md5_str2, sizeof(md5_str2),
123 CIFS_MF_SYMLINK_MD5_FORMAT,
124 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
125
126 if (strncmp(md5_str1, md5_str2, 17) != 0)
127 return -EINVAL;
128
129 if (_link_str) {
130 *_link_str = kstrndup(link_str, link_len, GFP_KERNEL);
131 if (!*_link_str)
132 return -ENOMEM;
133 }
134
135 *_link_len = link_len;
136 return 0;
137}
1da177e4 138
0fd43ae4 139static int
18bddd10
SM
140CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
141{
93c100c0 142 int rc;
18bddd10
SM
143 unsigned int link_len;
144 unsigned int ofs;
18bddd10
SM
145 u8 md5_hash[16];
146
147 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
148 return -EINVAL;
149
150 link_len = strlen(link_str);
151
152 if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
153 return -ENAMETOOLONG;
154
93c100c0
SF
155 rc = symlink_hash(link_len, link_str, md5_hash);
156 if (rc) {
157 cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
158 return rc;
159 }
18bddd10
SM
160
161 snprintf(buf, buf_len,
162 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
163 link_len,
164 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
165
166 ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
167 memcpy(buf + ofs, link_str, link_len);
168
169 ofs += link_len;
170 if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
171 buf[ofs] = '\n';
172 ofs++;
173 }
174
175 while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
176 buf[ofs] = ' ';
177 ofs++;
178 }
179
180 return 0;
181}
182
8713d01d 183static int
96daf2b0 184CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon,
8713d01d 185 const char *fromName, const char *toName,
3d3ea8e6 186 struct cifs_sb_info *cifs_sb)
8713d01d
SM
187{
188 int rc;
189 int oplock = 0;
3d3ea8e6
SP
190 int remap;
191 int create_options = CREATE_NOT_DIR;
8713d01d
SM
192 __u16 netfid = 0;
193 u8 *buf;
194 unsigned int bytes_written = 0;
fa2989f4 195 struct cifs_io_parms io_parms;
3d3ea8e6
SP
196 struct nls_table *nls_codepage;
197
198 nls_codepage = cifs_sb->local_nls;
199 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
8713d01d
SM
200
201 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
202 if (!buf)
203 return -ENOMEM;
204
205 rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
206 if (rc != 0) {
207 kfree(buf);
208 return rc;
209 }
210
3d3ea8e6
SP
211 if (backup_cred(cifs_sb))
212 create_options |= CREATE_OPEN_BACKUP_INTENT;
213
8713d01d 214 rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE,
3d3ea8e6 215 create_options, &netfid, &oplock, NULL,
8713d01d
SM
216 nls_codepage, remap);
217 if (rc != 0) {
218 kfree(buf);
219 return rc;
220 }
221
fa2989f4
PS
222 io_parms.netfid = netfid;
223 io_parms.pid = current->tgid;
224 io_parms.tcon = tcon;
225 io_parms.offset = 0;
226 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
227
228 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, buf, NULL, 0);
8713d01d
SM
229 CIFSSMBClose(xid, tcon, netfid);
230 kfree(buf);
231 if (rc != 0)
232 return rc;
233
234 if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
235 return -EIO;
236
237 return 0;
238}
239
240static int
96daf2b0 241CIFSQueryMFSymLink(const int xid, struct cifs_tcon *tcon,
0fd43ae4
SM
242 const unsigned char *searchName, char **symlinkinfo,
243 const struct nls_table *nls_codepage, int remap)
244{
245 int rc;
246 int oplock = 0;
247 __u16 netfid = 0;
248 u8 *buf;
249 char *pbuf;
250 unsigned int bytes_read = 0;
251 int buf_type = CIFS_NO_BUFFER;
252 unsigned int link_len = 0;
d4ffff1f 253 struct cifs_io_parms io_parms;
0fd43ae4
SM
254 FILE_ALL_INFO file_info;
255
256 rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ,
257 CREATE_NOT_DIR, &netfid, &oplock, &file_info,
258 nls_codepage, remap);
259 if (rc != 0)
260 return rc;
261
5443d130 262 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
0fd43ae4
SM
263 CIFSSMBClose(xid, tcon, netfid);
264 /* it's not a symlink */
265 return -EINVAL;
266 }
267
268 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
269 if (!buf)
270 return -ENOMEM;
271 pbuf = buf;
d4ffff1f
PS
272 io_parms.netfid = netfid;
273 io_parms.pid = current->tgid;
274 io_parms.tcon = tcon;
275 io_parms.offset = 0;
276 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
0fd43ae4 277
d4ffff1f 278 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
0fd43ae4
SM
279 CIFSSMBClose(xid, tcon, netfid);
280 if (rc != 0) {
281 kfree(buf);
282 return rc;
283 }
284
285 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo);
286 kfree(buf);
287 if (rc != 0)
288 return rc;
289
290 return 0;
291}
292
8bfb50a8
SM
293bool
294CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
295{
296 if (!(fattr->cf_mode & S_IFREG))
297 /* it's not a symlink */
298 return false;
299
300 if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
301 /* it's not a symlink */
302 return false;
303
304 return true;
305}
306
307int
308CIFSCheckMFSymlink(struct cifs_fattr *fattr,
309 const unsigned char *path,
310 struct cifs_sb_info *cifs_sb, int xid)
311{
312 int rc;
313 int oplock = 0;
314 __u16 netfid = 0;
7ffec372 315 struct tcon_link *tlink;
96daf2b0 316 struct cifs_tcon *pTcon;
d4ffff1f 317 struct cifs_io_parms io_parms;
8bfb50a8
SM
318 u8 *buf;
319 char *pbuf;
320 unsigned int bytes_read = 0;
321 int buf_type = CIFS_NO_BUFFER;
322 unsigned int link_len = 0;
323 FILE_ALL_INFO file_info;
324
325 if (!CIFSCouldBeMFSymlink(fattr))
326 /* it's not a symlink */
327 return 0;
328
7ffec372
JL
329 tlink = cifs_sb_tlink(cifs_sb);
330 if (IS_ERR(tlink))
331 return PTR_ERR(tlink);
332 pTcon = tlink_tcon(tlink);
333
8bfb50a8
SM
334 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
335 CREATE_NOT_DIR, &netfid, &oplock, &file_info,
336 cifs_sb->local_nls,
337 cifs_sb->mnt_cifs_flags &
338 CIFS_MOUNT_MAP_SPECIAL_CHR);
339 if (rc != 0)
7ffec372 340 goto out;
8bfb50a8 341
5443d130 342 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
8bfb50a8
SM
343 CIFSSMBClose(xid, pTcon, netfid);
344 /* it's not a symlink */
7ffec372 345 goto out;
8bfb50a8
SM
346 }
347
348 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
7ffec372
JL
349 if (!buf) {
350 rc = -ENOMEM;
351 goto out;
352 }
8bfb50a8 353 pbuf = buf;
d4ffff1f
PS
354 io_parms.netfid = netfid;
355 io_parms.pid = current->tgid;
356 io_parms.tcon = pTcon;
357 io_parms.offset = 0;
358 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
8bfb50a8 359
d4ffff1f 360 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
8bfb50a8
SM
361 CIFSSMBClose(xid, pTcon, netfid);
362 if (rc != 0) {
363 kfree(buf);
7ffec372 364 goto out;
8bfb50a8
SM
365 }
366
367 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
368 kfree(buf);
7ffec372 369 if (rc == -EINVAL) {
8bfb50a8 370 /* it's not a symlink */
7ffec372
JL
371 rc = 0;
372 goto out;
373 }
374
8bfb50a8 375 if (rc != 0)
7ffec372 376 goto out;
8bfb50a8
SM
377
378 /* it is a symlink */
379 fattr->cf_eof = link_len;
380 fattr->cf_mode &= ~S_IFMT;
381 fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
382 fattr->cf_dtype = DT_LNK;
7ffec372
JL
383out:
384 cifs_put_tlink(tlink);
385 return rc;
8bfb50a8
SM
386}
387
1da177e4
LT
388int
389cifs_hardlink(struct dentry *old_file, struct inode *inode,
390 struct dentry *direntry)
391{
392 int rc = -EACCES;
393 int xid;
394 char *fromName = NULL;
395 char *toName = NULL;
7ffec372
JL
396 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
397 struct tcon_link *tlink;
96daf2b0 398 struct cifs_tcon *pTcon;
1da177e4
LT
399 struct cifsInodeInfo *cifsInode;
400
7ffec372
JL
401 tlink = cifs_sb_tlink(cifs_sb);
402 if (IS_ERR(tlink))
403 return PTR_ERR(tlink);
404 pTcon = tlink_tcon(tlink);
1da177e4 405
7ffec372 406 xid = GetXid();
1da177e4 407
7f57356b
SF
408 fromName = build_path_from_dentry(old_file);
409 toName = build_path_from_dentry(direntry);
fb8c4b14 410 if ((fromName == NULL) || (toName == NULL)) {
1da177e4
LT
411 rc = -ENOMEM;
412 goto cifs_hl_exit;
413 }
414
c18c842b 415 if (pTcon->unix_ext)
1da177e4 416 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
7ffec372
JL
417 cifs_sb->local_nls,
418 cifs_sb->mnt_cifs_flags &
737b758c 419 CIFS_MOUNT_MAP_SPECIAL_CHR);
1da177e4
LT
420 else {
421 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
7ffec372
JL
422 cifs_sb->local_nls,
423 cifs_sb->mnt_cifs_flags &
737b758c 424 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14
SF
425 if ((rc == -EIO) || (rc == -EINVAL))
426 rc = -EOPNOTSUPP;
1da177e4
LT
427 }
428
31ec35d6
SF
429 d_drop(direntry); /* force new lookup from server of target */
430
431 /* if source file is cached (oplocked) revalidate will not go to server
432 until the file is closed or oplock broken so update nlinks locally */
fb8c4b14 433 if (old_file->d_inode) {
31ec35d6 434 cifsInode = CIFS_I(old_file->d_inode);
fb8c4b14 435 if (rc == 0) {
6d6b77f1 436 inc_nlink(old_file->d_inode);
1b2b2126
SF
437/* BB should we make this contingent on superblock flag NOATIME? */
438/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
31ec35d6
SF
439 /* parent dir timestamps will update from srv
440 within a second, would it really be worth it
441 to set the parent dir cifs inode time to zero
442 to force revalidate (faster) for it too? */
443 }
fb8c4b14 444 /* if not oplocked will force revalidate to get info
31ec35d6
SF
445 on source file from srv */
446 cifsInode->time = 0;
447
fb8c4b14 448 /* Will update parent dir timestamps from srv within a second.
31ec35d6
SF
449 Would it really be worth it to set the parent dir (cifs
450 inode) time field to zero to force revalidate on parent
fb8c4b14 451 directory faster ie
31ec35d6 452 CIFS_I(inode)->time = 0; */
1da177e4 453 }
1da177e4
LT
454
455cifs_hl_exit:
f99d49ad
JJ
456 kfree(fromName);
457 kfree(toName);
1da177e4 458 FreeXid(xid);
7ffec372 459 cifs_put_tlink(tlink);
1da177e4
LT
460 return rc;
461}
462
cc314eef 463void *
1da177e4
LT
464cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
465{
466 struct inode *inode = direntry->d_inode;
8b6427a2 467 int rc = -ENOMEM;
1da177e4
LT
468 int xid;
469 char *full_path = NULL;
8b6427a2
JL
470 char *target_path = NULL;
471 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
7ffec372 472 struct tcon_link *tlink = NULL;
96daf2b0 473 struct cifs_tcon *tcon;
1da177e4
LT
474
475 xid = GetXid();
476
7ffec372
JL
477 tlink = cifs_sb_tlink(cifs_sb);
478 if (IS_ERR(tlink)) {
479 rc = PTR_ERR(tlink);
480 tlink = NULL;
481 goto out;
482 }
483 tcon = tlink_tcon(tlink);
484
8b6427a2
JL
485 /*
486 * For now, we just handle symlinks with unix extensions enabled.
487 * Eventually we should handle NTFS reparse points, and MacOS
488 * symlink support. For instance...
489 *
490 * rc = CIFSSMBQueryReparseLinkInfo(...)
491 *
492 * For now, just return -EACCES when the server doesn't support posix
493 * extensions. Note that we still allow querying symlinks when posix
494 * extensions are manually disabled. We could disable these as well
495 * but there doesn't seem to be any harm in allowing the client to
496 * read them.
497 */
1b12b9c1
SM
498 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
499 && !(tcon->ses->capabilities & CAP_UNIX)) {
8b6427a2
JL
500 rc = -EACCES;
501 goto out;
502 }
1da177e4 503
8b6427a2 504 full_path = build_path_from_dentry(direntry);
1da177e4 505 if (!full_path)
460b9696 506 goto out;
1da177e4 507
b6b38f70 508 cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
1da177e4 509
1b12b9c1
SM
510 rc = -EACCES;
511 /*
512 * First try Minshall+French Symlinks, if configured
513 * and fallback to UNIX Extensions Symlinks.
514 */
515 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
516 rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path,
517 cifs_sb->local_nls,
518 cifs_sb->mnt_cifs_flags &
519 CIFS_MOUNT_MAP_SPECIAL_CHR);
520
521 if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
522 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
523 cifs_sb->local_nls);
524
8b6427a2
JL
525 kfree(full_path);
526out:
460b9696 527 if (rc != 0) {
1da177e4
LT
528 kfree(target_path);
529 target_path = ERR_PTR(rc);
530 }
531
1da177e4 532 FreeXid(xid);
7ffec372
JL
533 if (tlink)
534 cifs_put_tlink(tlink);
1da177e4 535 nd_set_link(nd, target_path);
460b9696 536 return NULL;
1da177e4
LT
537}
538
539int
540cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
541{
542 int rc = -EOPNOTSUPP;
543 int xid;
7ffec372
JL
544 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
545 struct tcon_link *tlink;
96daf2b0 546 struct cifs_tcon *pTcon;
1da177e4
LT
547 char *full_path = NULL;
548 struct inode *newinode = NULL;
549
550 xid = GetXid();
551
7ffec372
JL
552 tlink = cifs_sb_tlink(cifs_sb);
553 if (IS_ERR(tlink)) {
554 rc = PTR_ERR(tlink);
555 goto symlink_exit;
556 }
557 pTcon = tlink_tcon(tlink);
1da177e4 558
7f57356b 559 full_path = build_path_from_dentry(direntry);
fb8c4b14 560 if (full_path == NULL) {
0f3bc09e 561 rc = -ENOMEM;
7ffec372 562 goto symlink_exit;
1da177e4
LT
563 }
564
b6b38f70
JP
565 cFYI(1, "Full path: %s", full_path);
566 cFYI(1, "symname is %s", symname);
1da177e4
LT
567
568 /* BB what if DFS and this volume is on different share? BB */
1b12b9c1
SM
569 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
570 rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
3d3ea8e6 571 cifs_sb);
1b12b9c1 572 else if (pTcon->unix_ext)
1da177e4
LT
573 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
574 cifs_sb->local_nls);
575 /* else
fb8c4b14
SF
576 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
577 cifs_sb_target->local_nls); */
1da177e4
LT
578
579 if (rc == 0) {
c18c842b 580 if (pTcon->unix_ext)
1da177e4 581 rc = cifs_get_inode_info_unix(&newinode, full_path,
fb8c4b14 582 inode->i_sb, xid);
1da177e4
LT
583 else
584 rc = cifs_get_inode_info(&newinode, full_path, NULL,
8b1327f6 585 inode->i_sb, xid, NULL);
1da177e4
LT
586
587 if (rc != 0) {
b6b38f70
JP
588 cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d",
589 rc);
1da177e4 590 } else {
1da177e4
LT
591 d_instantiate(direntry, newinode);
592 }
593 }
7ffec372 594symlink_exit:
f99d49ad 595 kfree(full_path);
7ffec372 596 cifs_put_tlink(tlink);
1da177e4
LT
597 FreeXid(xid);
598 return rc;
599}
600
cc314eef 601void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
1da177e4
LT
602{
603 char *p = nd_get_link(nd);
604 if (!IS_ERR(p))
605 kfree(p);
606}