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