Merge 2.6.38-rc5 into staging-next
[deliverable/linux.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
SM
177static int
178CIFSCreateMFSymLink(const int xid, struct cifsTconInfo *tcon,
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;
187
188 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
189 if (!buf)
190 return -ENOMEM;
191
192 rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
193 if (rc != 0) {
194 kfree(buf);
195 return rc;
196 }
197
198 rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE,
199 CREATE_NOT_DIR, &netfid, &oplock, NULL,
200 nls_codepage, remap);
201 if (rc != 0) {
202 kfree(buf);
203 return rc;
204 }
205
206 rc = CIFSSMBWrite(xid, tcon, netfid,
207 CIFS_MF_SYMLINK_FILE_SIZE /* length */,
208 0 /* offset */,
209 &bytes_written, buf, NULL, 0);
210 CIFSSMBClose(xid, tcon, netfid);
211 kfree(buf);
212 if (rc != 0)
213 return rc;
214
215 if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
216 return -EIO;
217
218 return 0;
219}
220
221static int
0fd43ae4
SM
222CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon,
223 const unsigned char *searchName, char **symlinkinfo,
224 const struct nls_table *nls_codepage, int remap)
225{
226 int rc;
227 int oplock = 0;
228 __u16 netfid = 0;
229 u8 *buf;
230 char *pbuf;
231 unsigned int bytes_read = 0;
232 int buf_type = CIFS_NO_BUFFER;
233 unsigned int link_len = 0;
234 FILE_ALL_INFO file_info;
235
236 rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ,
237 CREATE_NOT_DIR, &netfid, &oplock, &file_info,
238 nls_codepage, remap);
239 if (rc != 0)
240 return rc;
241
242 if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) {
243 CIFSSMBClose(xid, tcon, netfid);
244 /* it's not a symlink */
245 return -EINVAL;
246 }
247
248 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
249 if (!buf)
250 return -ENOMEM;
251 pbuf = buf;
252
253 rc = CIFSSMBRead(xid, tcon, netfid,
254 CIFS_MF_SYMLINK_FILE_SIZE /* length */,
255 0 /* offset */,
256 &bytes_read, &pbuf, &buf_type);
257 CIFSSMBClose(xid, tcon, netfid);
258 if (rc != 0) {
259 kfree(buf);
260 return rc;
261 }
262
263 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo);
264 kfree(buf);
265 if (rc != 0)
266 return rc;
267
268 return 0;
269}
270
8bfb50a8
SM
271bool
272CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
273{
274 if (!(fattr->cf_mode & S_IFREG))
275 /* it's not a symlink */
276 return false;
277
278 if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
279 /* it's not a symlink */
280 return false;
281
282 return true;
283}
284
285int
286CIFSCheckMFSymlink(struct cifs_fattr *fattr,
287 const unsigned char *path,
288 struct cifs_sb_info *cifs_sb, int xid)
289{
290 int rc;
291 int oplock = 0;
292 __u16 netfid = 0;
7ffec372
JL
293 struct tcon_link *tlink;
294 struct cifsTconInfo *pTcon;
8bfb50a8
SM
295 u8 *buf;
296 char *pbuf;
297 unsigned int bytes_read = 0;
298 int buf_type = CIFS_NO_BUFFER;
299 unsigned int link_len = 0;
300 FILE_ALL_INFO file_info;
301
302 if (!CIFSCouldBeMFSymlink(fattr))
303 /* it's not a symlink */
304 return 0;
305
7ffec372
JL
306 tlink = cifs_sb_tlink(cifs_sb);
307 if (IS_ERR(tlink))
308 return PTR_ERR(tlink);
309 pTcon = tlink_tcon(tlink);
310
8bfb50a8
SM
311 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
312 CREATE_NOT_DIR, &netfid, &oplock, &file_info,
313 cifs_sb->local_nls,
314 cifs_sb->mnt_cifs_flags &
315 CIFS_MOUNT_MAP_SPECIAL_CHR);
316 if (rc != 0)
7ffec372 317 goto out;
8bfb50a8
SM
318
319 if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) {
320 CIFSSMBClose(xid, pTcon, netfid);
321 /* it's not a symlink */
7ffec372 322 goto out;
8bfb50a8
SM
323 }
324
325 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
7ffec372
JL
326 if (!buf) {
327 rc = -ENOMEM;
328 goto out;
329 }
8bfb50a8
SM
330 pbuf = buf;
331
332 rc = CIFSSMBRead(xid, pTcon, netfid,
333 CIFS_MF_SYMLINK_FILE_SIZE /* length */,
334 0 /* offset */,
335 &bytes_read, &pbuf, &buf_type);
336 CIFSSMBClose(xid, pTcon, netfid);
337 if (rc != 0) {
338 kfree(buf);
7ffec372 339 goto out;
8bfb50a8
SM
340 }
341
342 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
343 kfree(buf);
7ffec372 344 if (rc == -EINVAL) {
8bfb50a8 345 /* it's not a symlink */
7ffec372
JL
346 rc = 0;
347 goto out;
348 }
349
8bfb50a8 350 if (rc != 0)
7ffec372 351 goto out;
8bfb50a8
SM
352
353 /* it is a symlink */
354 fattr->cf_eof = link_len;
355 fattr->cf_mode &= ~S_IFMT;
356 fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
357 fattr->cf_dtype = DT_LNK;
7ffec372
JL
358out:
359 cifs_put_tlink(tlink);
360 return rc;
8bfb50a8
SM
361}
362
1da177e4
LT
363int
364cifs_hardlink(struct dentry *old_file, struct inode *inode,
365 struct dentry *direntry)
366{
367 int rc = -EACCES;
368 int xid;
369 char *fromName = NULL;
370 char *toName = NULL;
7ffec372
JL
371 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
372 struct tcon_link *tlink;
1da177e4
LT
373 struct cifsTconInfo *pTcon;
374 struct cifsInodeInfo *cifsInode;
375
7ffec372
JL
376 tlink = cifs_sb_tlink(cifs_sb);
377 if (IS_ERR(tlink))
378 return PTR_ERR(tlink);
379 pTcon = tlink_tcon(tlink);
1da177e4 380
7ffec372 381 xid = GetXid();
1da177e4 382
7f57356b
SF
383 fromName = build_path_from_dentry(old_file);
384 toName = build_path_from_dentry(direntry);
fb8c4b14 385 if ((fromName == NULL) || (toName == NULL)) {
1da177e4
LT
386 rc = -ENOMEM;
387 goto cifs_hl_exit;
388 }
389
c18c842b 390 if (pTcon->unix_ext)
1da177e4 391 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
7ffec372
JL
392 cifs_sb->local_nls,
393 cifs_sb->mnt_cifs_flags &
737b758c 394 CIFS_MOUNT_MAP_SPECIAL_CHR);
1da177e4
LT
395 else {
396 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
7ffec372
JL
397 cifs_sb->local_nls,
398 cifs_sb->mnt_cifs_flags &
737b758c 399 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14
SF
400 if ((rc == -EIO) || (rc == -EINVAL))
401 rc = -EOPNOTSUPP;
1da177e4
LT
402 }
403
31ec35d6
SF
404 d_drop(direntry); /* force new lookup from server of target */
405
406 /* if source file is cached (oplocked) revalidate will not go to server
407 until the file is closed or oplock broken so update nlinks locally */
fb8c4b14 408 if (old_file->d_inode) {
31ec35d6 409 cifsInode = CIFS_I(old_file->d_inode);
fb8c4b14 410 if (rc == 0) {
31ec35d6 411 old_file->d_inode->i_nlink++;
1b2b2126
SF
412/* BB should we make this contingent on superblock flag NOATIME? */
413/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
31ec35d6
SF
414 /* parent dir timestamps will update from srv
415 within a second, would it really be worth it
416 to set the parent dir cifs inode time to zero
417 to force revalidate (faster) for it too? */
418 }
fb8c4b14 419 /* if not oplocked will force revalidate to get info
31ec35d6
SF
420 on source file from srv */
421 cifsInode->time = 0;
422
fb8c4b14 423 /* Will update parent dir timestamps from srv within a second.
31ec35d6
SF
424 Would it really be worth it to set the parent dir (cifs
425 inode) time field to zero to force revalidate on parent
fb8c4b14 426 directory faster ie
31ec35d6 427 CIFS_I(inode)->time = 0; */
1da177e4 428 }
1da177e4
LT
429
430cifs_hl_exit:
f99d49ad
JJ
431 kfree(fromName);
432 kfree(toName);
1da177e4 433 FreeXid(xid);
7ffec372 434 cifs_put_tlink(tlink);
1da177e4
LT
435 return rc;
436}
437
cc314eef 438void *
1da177e4
LT
439cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
440{
441 struct inode *inode = direntry->d_inode;
8b6427a2 442 int rc = -ENOMEM;
1da177e4
LT
443 int xid;
444 char *full_path = NULL;
8b6427a2
JL
445 char *target_path = NULL;
446 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
7ffec372
JL
447 struct tcon_link *tlink = NULL;
448 struct cifsTconInfo *tcon;
1da177e4
LT
449
450 xid = GetXid();
451
7ffec372
JL
452 tlink = cifs_sb_tlink(cifs_sb);
453 if (IS_ERR(tlink)) {
454 rc = PTR_ERR(tlink);
455 tlink = NULL;
456 goto out;
457 }
458 tcon = tlink_tcon(tlink);
459
8b6427a2
JL
460 /*
461 * For now, we just handle symlinks with unix extensions enabled.
462 * Eventually we should handle NTFS reparse points, and MacOS
463 * symlink support. For instance...
464 *
465 * rc = CIFSSMBQueryReparseLinkInfo(...)
466 *
467 * For now, just return -EACCES when the server doesn't support posix
468 * extensions. Note that we still allow querying symlinks when posix
469 * extensions are manually disabled. We could disable these as well
470 * but there doesn't seem to be any harm in allowing the client to
471 * read them.
472 */
1b12b9c1
SM
473 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
474 && !(tcon->ses->capabilities & CAP_UNIX)) {
8b6427a2
JL
475 rc = -EACCES;
476 goto out;
477 }
1da177e4 478
8b6427a2 479 full_path = build_path_from_dentry(direntry);
1da177e4 480 if (!full_path)
460b9696 481 goto out;
1da177e4 482
b6b38f70 483 cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
1da177e4 484
1b12b9c1
SM
485 rc = -EACCES;
486 /*
487 * First try Minshall+French Symlinks, if configured
488 * and fallback to UNIX Extensions Symlinks.
489 */
490 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
491 rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path,
492 cifs_sb->local_nls,
493 cifs_sb->mnt_cifs_flags &
494 CIFS_MOUNT_MAP_SPECIAL_CHR);
495
496 if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
497 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
498 cifs_sb->local_nls);
499
8b6427a2
JL
500 kfree(full_path);
501out:
460b9696 502 if (rc != 0) {
1da177e4
LT
503 kfree(target_path);
504 target_path = ERR_PTR(rc);
505 }
506
1da177e4 507 FreeXid(xid);
7ffec372
JL
508 if (tlink)
509 cifs_put_tlink(tlink);
1da177e4 510 nd_set_link(nd, target_path);
460b9696 511 return NULL;
1da177e4
LT
512}
513
514int
515cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
516{
517 int rc = -EOPNOTSUPP;
518 int xid;
7ffec372
JL
519 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
520 struct tcon_link *tlink;
1da177e4
LT
521 struct cifsTconInfo *pTcon;
522 char *full_path = NULL;
523 struct inode *newinode = NULL;
524
525 xid = GetXid();
526
7ffec372
JL
527 tlink = cifs_sb_tlink(cifs_sb);
528 if (IS_ERR(tlink)) {
529 rc = PTR_ERR(tlink);
530 goto symlink_exit;
531 }
532 pTcon = tlink_tcon(tlink);
1da177e4 533
7f57356b 534 full_path = build_path_from_dentry(direntry);
fb8c4b14 535 if (full_path == NULL) {
0f3bc09e 536 rc = -ENOMEM;
7ffec372 537 goto symlink_exit;
1da177e4
LT
538 }
539
b6b38f70
JP
540 cFYI(1, "Full path: %s", full_path);
541 cFYI(1, "symname is %s", symname);
1da177e4
LT
542
543 /* BB what if DFS and this volume is on different share? BB */
1b12b9c1
SM
544 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
545 rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
546 cifs_sb->local_nls,
547 cifs_sb->mnt_cifs_flags &
548 CIFS_MOUNT_MAP_SPECIAL_CHR);
549 else if (pTcon->unix_ext)
1da177e4
LT
550 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
551 cifs_sb->local_nls);
552 /* else
fb8c4b14
SF
553 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
554 cifs_sb_target->local_nls); */
1da177e4
LT
555
556 if (rc == 0) {
c18c842b 557 if (pTcon->unix_ext)
1da177e4 558 rc = cifs_get_inode_info_unix(&newinode, full_path,
fb8c4b14 559 inode->i_sb, xid);
1da177e4
LT
560 else
561 rc = cifs_get_inode_info(&newinode, full_path, NULL,
8b1327f6 562 inode->i_sb, xid, NULL);
1da177e4
LT
563
564 if (rc != 0) {
b6b38f70
JP
565 cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d",
566 rc);
1da177e4 567 } else {
1da177e4
LT
568 d_instantiate(direntry, newinode);
569 }
570 }
7ffec372 571symlink_exit:
f99d49ad 572 kfree(full_path);
7ffec372 573 cifs_put_tlink(tlink);
1da177e4
LT
574 FreeXid(xid);
575 return rc;
576}
577
cc314eef 578void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
1da177e4
LT
579{
580 char *p = nd_get_link(nd);
581 if (!IS_ERR(p))
582 kfree(p);
583}
This page took 0.452876 seconds and 5 git commands to generate.