This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / fs / hostfs / meta_fs.c
1 /* 
2  * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3  * Licensed under the GPL
4  */
5
6 #include <linux/slab.h>
7 #include <linux/init.h>
8 #include "hostfs.h"
9 #include "metadata.h"
10 #include "kern_util.h"
11
12 #define METADATA_FILE_PATH(meta) (meta)->root, "file_metadata"
13 #define METADATA_DIR_PATH(meta) (meta)->root, "dir_metadata"
14
15 struct meta_fs {
16         struct humfs humfs;
17         char *root;
18 };
19
20 struct meta_file {
21         struct humfs_file humfs;
22         struct file_handle fh;
23 };
24
25 static int meta_file_path(const char *path, struct meta_fs *meta, 
26                           const char *path_out[])
27 {
28         const char *data_path[] = { meta->root, "data", path, NULL };
29         char data_tmp[HOSTFS_BUFSIZE];
30         char *data_file = get_path(data_path, data_tmp, sizeof(data_tmp));
31
32         if(data_file == NULL)
33                 return(-ENOMEM);
34
35         path_out[0] = meta->root;
36         path_out[2] = path;
37         if(os_file_type(data_file) == OS_TYPE_DIR){
38                 path_out[1] = "dir_metadata";
39                 path_out[3] = "metadata";
40                 path_out[4] = NULL;
41         }
42         else {
43                 path_out[1] = "file_metadata";
44                 path_out[3] = NULL;
45         }
46
47         return(0);
48 }
49
50 static int open_meta_file(const char *path, struct humfs *humfs,
51                           struct file_handle *fh)
52 {
53         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
54         const char *meta_path[5];
55         char meta_tmp[HOSTFS_BUFSIZE];
56         char *meta_file;
57         int err;
58
59         err = meta_file_path(path, meta, meta_path);
60         if(err)
61                 goto out;
62
63         meta_file = get_path(meta_path, meta_tmp, sizeof(meta_tmp));
64         if(meta_file == NULL)
65                 goto out;
66         
67         err = open_filehandle(meta_file, of_rdwr(OPENFLAGS()), 0, fh);
68
69  out:
70         return(err);
71 }
72
73 static char *meta_fs_name(struct inode *inode)
74 {
75         struct humfs *mount = inode_humfs_info(inode);
76         struct meta_fs *meta = container_of(mount, struct meta_fs, humfs);
77         const char *metadata_path[5];
78         char tmp[HOSTFS_BUFSIZE], *name, *file;
79
80         if(meta_file_path("", meta, metadata_path))
81                 return(NULL);
82
83         file = get_path(metadata_path, tmp, sizeof(tmp));
84         if(file == NULL)
85                 return(NULL);
86
87         name = inode_name_prefix(inode, file);
88
89         free_path(file, tmp);
90         return(name);
91 }
92
93 static void metafs_invisible(struct humfs_file *hf)
94 {
95         struct meta_file *mf = container_of(hf, struct meta_file, humfs);
96
97         not_reclaimable(&mf->fh);
98 }
99
100 static struct humfs_file *metafs_init_file(void)
101 {
102         struct meta_file *mf;
103         int err = -ENOMEM;
104
105         mf = kmalloc(sizeof(*mf), GFP_KERNEL);
106         if(mf == NULL)
107                 return(ERR_PTR(err));
108
109         return(&mf->humfs);
110 }
111
112 static int metafs_open_file(struct humfs_file *hf, const char *path, 
113                             struct inode *inode, struct humfs *humfs)
114 {
115         struct meta_file *mf = container_of(hf, struct meta_file, humfs);
116         int err;
117
118         err = open_meta_file(path, humfs, &mf->fh);
119         if(err)
120                 return(err);
121
122         is_reclaimable(&mf->fh, meta_fs_name, inode);
123
124         return(0);
125 }
126
127 static void metafs_close_file(struct humfs_file *hf)
128 {
129         struct meta_file *meta = container_of(hf, struct meta_file, humfs);
130
131         close_file(&meta->fh);
132         kfree(meta);
133 }
134
135 static int metafs_create_file(struct humfs_file *hf, const char *path, 
136                               int mode, int uid, int gid, struct inode *inode, 
137                               struct humfs *humfs)
138 {
139         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
140         struct meta_file *mf = container_of(hf, struct meta_file, humfs);
141         char tmp[HOSTFS_BUFSIZE];
142         const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
143         char *file = get_path(metadata_path, tmp, sizeof(tmp));
144         char buf[sizeof("mmmm uuuuuuuuuu gggggggggg")];
145         int err = -ENOMEM;
146
147         if(file == NULL)
148                 goto out;
149
150         err = open_filehandle(file, of_write(of_create(OPENFLAGS())), 0644, 
151                               &mf->fh);
152         if(err)
153                 goto out_free_path;
154
155         if(inode != NULL)
156                 is_reclaimable(&mf->fh, meta_fs_name, inode);
157
158         sprintf(buf, "%d %d %d\n", mode  & S_IRWXUGO, uid, gid);
159         err = write_file(&mf->fh, 0, buf, strlen(buf));
160         if(err < 0)
161                 goto out_rm;
162
163         free_path(file, tmp);
164         return(0);
165
166  out_rm:
167         close_file(&mf->fh);
168         os_remove_file(file);
169  out_free_path:
170         free_path(file, tmp);
171  out:
172         return(err);
173 }
174
175 static int metafs_create_link(const char *to, const char *from, 
176                               struct humfs *humfs)
177 {
178         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
179         const char *path_to[] = { METADATA_FILE_PATH(meta), to,  NULL };
180         const char *path_from[] = { METADATA_FILE_PATH(meta), from, NULL };
181
182         return(host_link_file(path_to, path_from));
183 }
184
185 static int metafs_remove_file(const char *path, struct humfs *humfs)
186 {
187         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
188         char tmp[HOSTFS_BUFSIZE];
189         const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
190         char *file = get_path(metadata_path, tmp, sizeof(tmp));
191         int err = -ENOMEM;
192
193         if(file == NULL)
194                 goto out;
195
196         err = os_remove_file(file);
197
198  out:
199         free_path(file, tmp);
200         return(err);
201 }
202
203 static int metafs_create_directory(const char *path, int mode, int uid, 
204                                    int gid, struct humfs *humfs)
205 {
206         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
207         char tmp[HOSTFS_BUFSIZE];
208         const char *dir_path[] = { METADATA_DIR_PATH(meta), path, NULL, NULL };
209         const char *file_path[] = { METADATA_FILE_PATH(meta), path, NULL, 
210                                     NULL };
211         char *file, dir_meta[sizeof("mmmm uuuuuuuuuu gggggggggg\n")];
212         int err, fd;
213
214         err = host_make_dir(dir_path, 0755);
215         if(err)
216                 goto out;
217
218         err = host_make_dir(file_path, 0755);
219         if(err)
220                 goto out_rm;
221
222         /* This to make the index independent of the number of elements in
223          * METADATA_DIR_PATH().
224          */
225         dir_path[sizeof(dir_path) / sizeof(dir_path[0]) - 2] = "metadata";
226
227         err = -ENOMEM;
228         file = get_path(dir_path, tmp, sizeof(tmp));
229         if(file == NULL)
230                 goto out;
231
232         fd = os_open_file(file, of_create(of_rdwr(OPENFLAGS())), 0644);
233         if(fd < 0){
234                 err = fd;
235                 goto out_free;
236         }
237
238         sprintf(dir_meta, "%d %d %d\n", mode & S_IRWXUGO, uid, gid);
239         err = os_write_file(fd, dir_meta, strlen(dir_meta));
240         if(err > 0)
241                 err = 0;
242
243         os_close_file(fd);
244
245  out_free:
246         free_path(file, tmp);
247  out_rm:
248         host_remove_dir(dir_path);
249  out:
250         return(err);
251 }
252
253 static int metafs_remove_directory(const char *path, struct humfs *humfs)
254 {
255         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
256         char tmp[HOSTFS_BUFSIZE], *file;
257         const char *dir_path[] = { METADATA_DIR_PATH(meta), path, "metadata", 
258                                    NULL };
259         const char *file_path[] = { METADATA_FILE_PATH(meta), path, NULL };
260         char *slash;
261         int err;
262
263         err = -ENOMEM;
264         file = get_path(dir_path, tmp, sizeof(tmp));
265         if(file == NULL)
266                 goto out;
267
268         err = os_remove_file(file);
269         if(err)
270                 goto out_free;
271
272         slash = strrchr(file, '/');
273         if(slash == NULL){
274                 printk("remove_shadow_directory failed to find last slash\n");
275                 goto out_free;
276         }
277         *slash = '\0';
278         err = os_remove_dir(file);
279         free_path(file, tmp);
280
281         file = get_path(file_path, tmp, sizeof(tmp));
282         if(file == NULL)
283                 goto out;
284
285         err = os_remove_dir(file);
286         if(err)
287                 goto out_free;
288
289  out:
290         return(err);
291  out_free:
292         free_path(file, tmp);
293         goto out;
294 }
295
296 static int metafs_make_node(const char *path, int mode, int uid, int gid, 
297                             int type, int maj, int min, struct humfs *humfs)
298 {
299         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
300         struct file_handle fh;
301         char tmp[HOSTFS_BUFSIZE];
302         const char *metadata_path[] = { METADATA_FILE_PATH(meta), path, NULL };
303         int err;
304         char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")], *file;
305
306         sprintf(buf, "%d %d %d %c %d %d\n", mode & S_IRWXUGO, uid, gid, type, 
307                 maj, min);
308
309         err = -ENOMEM;
310         file = get_path(metadata_path, tmp, sizeof(tmp));
311         if(file == NULL)
312                 goto out;
313
314         err = open_filehandle(file, 
315                               of_create(of_rdwr(OPENFLAGS())), 0644, &fh);
316         if(err)
317                 goto out_free;
318
319         err = write_file(&fh, 0, buf, strlen(buf));
320         if(err > 0)
321                 err = 0;
322
323         close_file(&fh);
324
325  out_free:
326         free_path(file, tmp);
327  out:
328         return(err);
329 }
330
331 static int metafs_ownerships(const char *path, int *mode_out, int *uid_out, 
332                              int *gid_out, char *type_out, int *maj_out, 
333                              int *min_out, struct humfs *humfs)
334 {
335         struct file_handle fh;
336         char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")];
337         int err, n, mode, uid, gid, maj, min;
338         char type;
339
340         err = open_meta_file(path, humfs, &fh);
341         if(err)
342                 goto out;
343
344         err = os_read_file(fh.fd, buf, sizeof(buf) - 1);
345         if(err < 0)
346                 goto out_close;
347
348         buf[err] = '\0';
349         err = 0;
350
351         n = sscanf(buf, "%d %d %d %c %d %d", &mode, &uid, &gid, &type, &maj, 
352                    &min);
353         if(n == 3){
354                 maj = -1;
355                 min = -1;
356                 type = 0;
357                 err = 0;
358         }
359         else if(n != 6)
360                 err = -EINVAL;
361
362         if(mode_out != NULL)
363                 *mode_out = mode;
364         if(uid_out != NULL)
365                 *uid_out = uid;
366         if(gid_out != NULL)
367                 *gid_out = uid;
368         if(type_out != NULL)
369                 *type_out = type;
370         if(maj_out != NULL)
371                 *maj_out = maj;
372         if(min_out != NULL)
373                 *min_out = min;
374
375  out_close:
376         close_file(&fh);
377  out:
378         return(err);
379 }
380
381 static int metafs_change_ownerships(const char *path, int mode, int uid, 
382                                     int gid, struct humfs *humfs)
383 {
384         struct file_handle fh;
385         char type;
386         char buf[sizeof("mmmm uuuuuuuuuu gggggggggg x nnn mmm\n")];
387         int err = -ENOMEM, old_mode, old_uid, old_gid, n, maj, min;
388
389         err = open_meta_file(path, humfs, &fh);
390         if(err)
391                 goto out;
392
393         err = read_file(&fh, 0, buf, sizeof(buf) - 1);
394         if(err < 0)
395                 goto out_close;
396
397         buf[err] = '\0';
398
399         n = sscanf(buf, "%d %d %d %c %d %d\n", &old_mode, &old_uid, &old_gid,
400                    &type, &maj, &min);
401         if((n != 3) && (n != 6)){
402                 err = -EINVAL;
403                 goto out_close;
404         }
405
406         if(mode == -1)
407                 mode = old_mode;
408         if(uid == -1)
409                 uid = old_uid;
410         if(gid == -1)
411                 gid = old_gid;
412
413         if(n == 3)
414                 sprintf(buf, "%d %d %d\n", mode & S_IRWXUGO, uid, gid);
415         else
416                 sprintf(buf, "%d %d %d %c %d %d\n", mode & S_IRWXUGO, uid, gid,
417                         type, maj, min);
418
419         err = write_file(&fh, 0, buf, strlen(buf));
420         if(err > 0)
421                 err = 0;
422
423         err = truncate_file(&fh, strlen(buf));
424
425  out_close:
426         close_file(&fh);
427  out:
428         return(err);
429 }
430
431 static int metafs_rename_file(const char *from, const char *to, 
432                               struct humfs *humfs)
433 {
434         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
435         const char *metadata_path_from[5], *metadata_path_to[5];
436         int err;
437
438         err = meta_file_path(from, meta, metadata_path_from);
439         if(err)
440                 return(err);
441
442         err = meta_file_path(to, meta, metadata_path_to);
443         if(err)
444                 return(err);
445
446         return(host_rename_file(metadata_path_from, metadata_path_to));
447 }
448
449 static struct humfs *metafs_init_mount(char *root)
450 {
451         struct meta_fs *meta;
452         int err = -ENOMEM;
453
454         meta = kmalloc(sizeof(*meta), GFP_KERNEL);
455         if(meta == NULL)
456                 goto out;
457
458         meta->root = uml_strdup(root);
459         if(meta->root == NULL)
460                 goto out_free_meta;
461
462         return(&meta->humfs);
463
464  out_free_meta:
465         kfree(meta);
466  out:
467         return(ERR_PTR(err));
468 }
469
470 static void metafs_free_mount(struct humfs *humfs)
471 {
472         struct meta_fs *meta = container_of(humfs, struct meta_fs, humfs);
473         
474         kfree(meta);
475 }
476
477 struct humfs_meta_ops hum_fs_meta_fs_ops = {
478         .list                   = LIST_HEAD_INIT(hum_fs_meta_fs_ops.list),
479         .name                   = "shadow_fs",
480         .init_file              = metafs_init_file,
481         .open_file              = metafs_open_file,
482         .close_file             = metafs_close_file,
483         .ownerships             = metafs_ownerships,
484         .make_node              = metafs_make_node,
485         .create_file            = metafs_create_file,
486         .create_link            = metafs_create_link,
487         .remove_file            = metafs_remove_file,
488         .create_dir             = metafs_create_directory,
489         .remove_dir             = metafs_remove_directory,
490         .change_ownerships      = metafs_change_ownerships,
491         .rename_file            = metafs_rename_file,
492         .invisible              = metafs_invisible,
493         .init_mount             = metafs_init_mount,
494         .free_mount             = metafs_free_mount,
495 };
496
497 static int __init init_meta_fs(void)
498 {
499         register_meta(&hum_fs_meta_fs_ops);
500         return(0);
501 }
502
503 static void __exit exit_meta_fs(void)
504 {
505         unregister_meta(&hum_fs_meta_fs_ops);
506 }
507
508 __initcall(init_meta_fs);
509 __exitcall(exit_meta_fs);
510
511 /*
512  * Overrides for Emacs so that we follow Linus's tabbing style.
513  * Emacs will notice this stuff at the end of the file and automatically
514  * adjust the settings for this buffer only.  This must remain at the end
515  * of the file.
516  * ---------------------------------------------------------------------------
517  * Local variables:
518  * c-file-style: "linux"
519  * End:
520  */