[CIFS] Rename three structures to avoid camel case
[pandora-kernel.git] / fs / cifs / link.c
1 /*
2  *   fs/cifs/link.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2008
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>
23 #include <linux/slab.h>
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"
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
48 static int
49 symlink_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);
57         if (IS_ERR(md5)) {
58                 rc = PTR_ERR(md5);
59                 cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc);
60                 return rc;
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
80 symlink_hash_err:
81         crypto_free_shash(md5);
82         kfree(sdescmd5);
83
84         return rc;
85 }
86
87 static int
88 CIFSParseMFSymlink(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;
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
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         }
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 }
132
133 static int
134 CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
135 {
136         int rc;
137         unsigned int link_len;
138         unsigned int ofs;
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
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         }
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
177 static int
178 CIFSCreateMFSymLink(const int xid, struct cifs_tcon *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         struct cifs_io_parms io_parms;
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
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);
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
225 static int
226 CIFSQueryMFSymLink(const int xid, struct cifs_tcon *tcon,
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;
238         struct cifs_io_parms io_parms;
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
247         if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
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;
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;
262
263         rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
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
278 bool
279 CIFSCouldBeMFSymlink(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
292 int
293 CIFSCheckMFSymlink(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;
300         struct tcon_link *tlink;
301         struct cifs_tcon *pTcon;
302         struct cifs_io_parms io_parms;
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
314         tlink = cifs_sb_tlink(cifs_sb);
315         if (IS_ERR(tlink))
316                 return PTR_ERR(tlink);
317         pTcon = tlink_tcon(tlink);
318
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)
325                 goto out;
326
327         if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
328                 CIFSSMBClose(xid, pTcon, netfid);
329                 /* it's not a symlink */
330                 goto out;
331         }
332
333         buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
334         if (!buf) {
335                 rc = -ENOMEM;
336                 goto out;
337         }
338         pbuf = buf;
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;
344
345         rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
346         CIFSSMBClose(xid, pTcon, netfid);
347         if (rc != 0) {
348                 kfree(buf);
349                 goto out;
350         }
351
352         rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
353         kfree(buf);
354         if (rc == -EINVAL) {
355                 /* it's not a symlink */
356                 rc = 0;
357                 goto out;
358         }
359
360         if (rc != 0)
361                 goto out;
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;
368 out:
369         cifs_put_tlink(tlink);
370         return rc;
371 }
372
373 int
374 cifs_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;
381         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
382         struct tcon_link *tlink;
383         struct cifs_tcon *pTcon;
384         struct cifsInodeInfo *cifsInode;
385
386         tlink = cifs_sb_tlink(cifs_sb);
387         if (IS_ERR(tlink))
388                 return PTR_ERR(tlink);
389         pTcon = tlink_tcon(tlink);
390
391         xid = GetXid();
392
393         fromName = build_path_from_dentry(old_file);
394         toName = build_path_from_dentry(direntry);
395         if ((fromName == NULL) || (toName == NULL)) {
396                 rc = -ENOMEM;
397                 goto cifs_hl_exit;
398         }
399
400         if (pTcon->unix_ext)
401                 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
402                                             cifs_sb->local_nls,
403                                             cifs_sb->mnt_cifs_flags &
404                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
405         else {
406                 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
407                                         cifs_sb->local_nls,
408                                         cifs_sb->mnt_cifs_flags &
409                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
410                 if ((rc == -EIO) || (rc == -EINVAL))
411                         rc = -EOPNOTSUPP;
412         }
413
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 */
418         if (old_file->d_inode) {
419                 cifsInode = CIFS_I(old_file->d_inode);
420                 if (rc == 0) {
421                         old_file->d_inode->i_nlink++;
422 /* BB should we make this contingent on superblock flag NOATIME? */
423 /*                      old_file->d_inode->i_ctime = CURRENT_TIME;*/
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                 }
429                 /* if not oplocked will force revalidate to get info
430                    on source file from srv */
431                 cifsInode->time = 0;
432
433                 /* Will update parent dir timestamps from srv within a second.
434                    Would it really be worth it to set the parent dir (cifs
435                    inode) time field to zero to force revalidate on parent
436                    directory faster ie
437                         CIFS_I(inode)->time = 0;  */
438         }
439
440 cifs_hl_exit:
441         kfree(fromName);
442         kfree(toName);
443         FreeXid(xid);
444         cifs_put_tlink(tlink);
445         return rc;
446 }
447
448 void *
449 cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
450 {
451         struct inode *inode = direntry->d_inode;
452         int rc = -ENOMEM;
453         int xid;
454         char *full_path = NULL;
455         char *target_path = NULL;
456         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
457         struct tcon_link *tlink = NULL;
458         struct cifs_tcon *tcon;
459
460         xid = GetXid();
461
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
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          */
483         if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
484             && !(tcon->ses->capabilities & CAP_UNIX)) {
485                 rc = -EACCES;
486                 goto out;
487         }
488
489         full_path = build_path_from_dentry(direntry);
490         if (!full_path)
491                 goto out;
492
493         cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
494
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
510         kfree(full_path);
511 out:
512         if (rc != 0) {
513                 kfree(target_path);
514                 target_path = ERR_PTR(rc);
515         }
516
517         FreeXid(xid);
518         if (tlink)
519                 cifs_put_tlink(tlink);
520         nd_set_link(nd, target_path);
521         return NULL;
522 }
523
524 int
525 cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
526 {
527         int rc = -EOPNOTSUPP;
528         int xid;
529         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
530         struct tcon_link *tlink;
531         struct cifs_tcon *pTcon;
532         char *full_path = NULL;
533         struct inode *newinode = NULL;
534
535         xid = GetXid();
536
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);
543
544         full_path = build_path_from_dentry(direntry);
545         if (full_path == NULL) {
546                 rc = -ENOMEM;
547                 goto symlink_exit;
548         }
549
550         cFYI(1, "Full path: %s", full_path);
551         cFYI(1, "symname is %s", symname);
552
553         /* BB what if DFS and this volume is on different share? BB */
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)
560                 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
561                                            cifs_sb->local_nls);
562         /* else
563            rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
564                                         cifs_sb_target->local_nls); */
565
566         if (rc == 0) {
567                 if (pTcon->unix_ext)
568                         rc = cifs_get_inode_info_unix(&newinode, full_path,
569                                                       inode->i_sb, xid);
570                 else
571                         rc = cifs_get_inode_info(&newinode, full_path, NULL,
572                                                  inode->i_sb, xid, NULL);
573
574                 if (rc != 0) {
575                         cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d",
576                               rc);
577                 } else {
578                         d_instantiate(direntry, newinode);
579                 }
580         }
581 symlink_exit:
582         kfree(full_path);
583         cifs_put_tlink(tlink);
584         FreeXid(xid);
585         return rc;
586 }
587
588 void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
589 {
590         char *p = nd_get_link(nd);
591         if (!IS_ERR(p))
592                 kfree(p);
593 }