0835ad8e77b0fe37024a718b6ed1130df11266e0
[lufs.git] / kernel / Linux / 2.5 / dir.c
1 /*
2  * dir.c
3  * Copyright (C) 2002 Florin Malita <mali@go.ro>
4  *
5  * This file is part of LUFS, a free userspace filesystem implementation.
6  * See http://lufs.sourceforge.net/ for updates.
7  *
8  * LUFS is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * LUFS is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <linux/version.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/fs.h>
27 #include <linux/slab.h>
28 #include <linux/ctype.h>
29 #include <linux/socket.h>
30
31 #include <asm/uaccess.h>
32 #include <asm/system.h>
33
34 #include <linux/smp_lock.h>
35
36 #include "lufs.h"
37 #include "proc.h"
38
39
40 extern struct inode* lu_iget(struct super_block*, struct lufs_fattr*);
41 extern int lufs_notify_change(struct dentry*, struct iattr*);
42
43 static int lu_readdir(struct file*, void*, filldir_t);
44
45 static struct dentry *lu_lookup(struct inode*, struct dentry*);
46 static int lu_mkdir(struct inode*, struct dentry*, int);
47 static int lu_create(struct inode*, struct dentry*, int);
48 static int lu_rmdir(struct inode*, struct dentry*);
49 static int lu_rename(struct inode*, struct dentry*, struct inode*, struct dentry*);
50 static int lu_unlink(struct inode*, struct dentry*);
51 static int lu_link(struct dentry*, struct inode*, struct dentry*);
52 static int lu_symlink(struct inode*, struct dentry*, const char*);
53
54 struct file_operations lu_dir_operations = {
55     .read       = generic_read_dir,
56     .readdir    = lu_readdir,
57 };
58
59 struct inode_operations lu_dir_inode_operations = {
60     .create     = lu_create,
61     .lookup     = lu_lookup,
62     .link       = lu_link,
63     .unlink     = lu_unlink,
64     .symlink    = lu_symlink,
65     .mkdir      = lu_mkdir,
66     .rmdir      = lu_rmdir,
67     .rename     = lu_rename,
68     .setattr    = lufs_notify_change,
69 };
70
71 static int lu_lookup_validate(struct dentry *dentry, int flags)
72 {
73     struct inode *inode = dentry->d_inode;
74     unsigned long age = jiffies - dentry->d_time;
75     int res;
76     
77     TRACE("in\n");
78     
79     res = (age <= LU_MAXAGE);
80     TRACE("age: %lu, valid: %d\n", age, res);
81
82     if(!res)
83         res = (lu_revalidate_inode(dentry) == 0);
84
85     
86     if(inode){
87         lock_kernel();
88
89         if(is_bad_inode(inode))
90             res = 0;
91         unlock_kernel();
92     }else
93         TRACE("no inode?!\n");
94
95     TRACE("out(res=%d)\n", res);
96
97     return res;
98 }
99
100 static int lu_delete_dentry(struct dentry *dentry)
101 {
102     
103     TRACE("in\n");
104     if(dentry->d_inode && is_bad_inode(dentry->d_inode)){
105         WARN("bad inode, unhashing \n");
106         return 1;
107     }
108
109     TRACE("out\n");
110     return 0;
111 }
112
113 struct dentry_operations lufs_dentry_operations = {
114     .d_revalidate       = lu_lookup_validate,
115     .d_delete           = lu_delete_dentry,
116 };
117
118 static int lu_readdir(struct file *f, void *dirent, filldir_t filldir)
119 {
120     int res = -1;
121     char *c;
122     struct qstr qname;
123     unsigned long ino;
124     struct iovec siov[2], riov;
125     struct server_slot *slot;
126     unsigned short offset;
127     
128     TRACE("in\n");
129     
130     if((slot = lu_getslot(GET_INFO(f->f_dentry->d_sb))) == NULL)
131         return -ERESTARTSYS;
132
133     if(lu_getname(f->f_dentry, slot->s_buf, LU_MAXDATA) < 0){
134         WARN("lu_getname failed!\n");
135         goto out;
136     }
137
138     TRACE("reading %s, offset %u...\n", slot->s_buf, (unsigned)f->f_pos);
139     res = 0;
140     
141     switch((unsigned int)f->f_pos){
142
143     case 0:
144         if(filldir(dirent, ".", 1, 0, f->f_dentry->d_inode->i_ino, DT_DIR) < 0)
145             goto out;
146         f->f_pos++;
147
148     case 1:
149         if(filldir(dirent, "..", 2, 1, f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
150             goto out;
151         f->f_pos++;
152
153     default:
154         offset = f->f_pos;
155         siov[0].iov_base = &offset;
156         siov[0].iov_len = sizeof(unsigned short);
157         siov[1].iov_base = slot->s_buf;
158         siov[1].iov_len = strlen(slot->s_buf) + 1;
159         riov.iov_base = slot->s_buf;
160         riov.iov_len = LU_MAXDATA;
161
162         if((res = lu_execute(GET_INFO(f->f_dentry->d_inode->i_sb), slot, PTYPE_READDIR, siov, 2, &riov, 1)) < 0){
163             WARN("could not read directory content!\n");
164             if(res == -ERESTARTSYS)
165                 res = -EINTR;
166             goto out;
167         }
168         if(PIS_ERROR(res)){
169             WARN("server failure!\n");
170             res = PERROR(res);
171             goto out;
172         }
173         for(qname.name = slot->s_buf, c = strchr(slot->s_buf, '\n'); c != NULL; qname.name = c+1, c = strchr(c+1, '\n')){
174             *c = 0;
175             TRACE("direntry: %s.\n", qname.name);
176             qname.len = strlen(qname.name);
177             if((ino = find_inode_number(f->f_dentry, &qname)) == 0)
178                 ino = iunique(f->f_dentry->d_sb, 2);
179             if(filldir(dirent, qname.name, qname.len, f->f_pos, ino, DT_UNKNOWN) < 0)
180                 break;
181             f->f_pos++;     
182         }
183     }
184
185     TRACE("out\n");
186  out:
187     lu_putslot(slot);
188     return res;
189 }
190
191 static struct dentry* lu_lookup(struct inode *dir, struct dentry *dentry)
192 {
193     int res;
194     struct lufs_fattr fattr;
195     struct iovec siov, riov;
196     struct inode *inode;
197     struct server_slot *slot;
198
199     TRACE("in\n");
200
201     if((slot = lu_getslot(GET_INFO(dir->i_sb))) == NULL)
202         return ERR_PTR(-ERESTARTSYS);
203     
204     if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
205         WARN("lu_getname failed!\n");
206         goto out;
207     }
208
209     TRACE("looking up %s\n", slot->s_buf);
210     
211     siov.iov_base = slot->s_buf;
212     siov.iov_len = strlen(slot->s_buf) + 1;
213     riov.iov_base = &fattr;
214     riov.iov_len = sizeof(struct lufs_fattr);
215
216     if((res = lu_execute(GET_INFO(dir->i_sb), slot, PTYPE_STAT, &siov, 1, &riov, 1)) < 0)
217         goto out;
218
219     if(PIS_ERROR(res)){
220         TRACE("File not found...\n");
221         dentry->d_op = &lufs_dentry_operations;
222         dentry->d_time = jiffies;
223         d_add(dentry, NULL);
224         lu_putslot(slot);
225         return NULL;
226     }
227
228     lu_fixattrs(GET_INFO(dir->i_sb), &fattr);
229
230     if(dentry == dentry->d_parent)
231         fattr.f_ino = 2;
232     else 
233         fattr.f_ino = iunique(dentry->d_sb, 2);
234
235     if((inode = lu_iget(dir->i_sb, &fattr))){
236         dentry->d_op = &lufs_dentry_operations;
237         dentry->d_time = jiffies;
238         d_add(dentry, inode);
239     }
240     res = 0;
241
242  out:
243     lu_putslot(slot);
244
245     TRACE("out\n");
246     return ERR_PTR(res);
247 }
248
249 static int lu_instantiate(struct dentry *dentry, char *name, struct server_slot *slot)
250 {
251     int res;
252     struct lufs_fattr fattr;
253     struct iovec siov, riov;
254     struct inode *inode;
255
256     TRACE("in\n");
257
258     TRACE("instantiating %s\n", name);
259     
260     siov.iov_base = name;
261     siov.iov_len = strlen(name) + 1;
262     riov.iov_base = &fattr;
263     riov.iov_len = sizeof(struct lufs_fattr);
264
265     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_STAT, &siov, 1, &riov, 1)) < 0)
266         goto out;
267
268     if(PIS_ERROR(res)){
269         TRACE("File not found...\n");
270         res = PERROR(res);
271         goto out;
272     }
273
274     lu_fixattrs(GET_INFO(dentry->d_sb), &fattr);
275
276     fattr.f_ino = iunique(dentry->d_sb, 2);
277     inode = lu_iget(dentry->d_sb, &fattr);
278
279     if(!inode){
280         res = -EACCES;
281         goto out;
282     }
283
284     d_instantiate(dentry, inode);
285     res = 0;
286
287   out:
288     TRACE("out\n");
289     return res;
290 }
291
292 static int lu_mkdir(struct inode *dir, struct dentry *dentry, int mode)
293 {
294     int res;
295     struct server_slot *slot;
296     struct iovec iov[2];
297
298     TRACE("in\n");
299
300     if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
301         return -ERESTARTSYS;
302
303     if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
304         WARN("lu_getname failed!\n");
305         goto out;
306     }
307     
308     iov[0].iov_base = &mode;
309     iov[0].iov_len = sizeof(mode);
310     iov[1].iov_base = slot->s_buf;
311     iov[1].iov_len = strlen(slot->s_buf) + 1;
312
313     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_MKDIR, iov, 2, NULL, 0)) < 0)
314         goto out;
315
316     if(PIS_ERROR(res)){
317         TRACE("Could not create directory.\n");
318         res = PERROR(res);
319         goto out;
320     }
321
322     res = lu_instantiate(dentry, slot->s_buf, slot);
323
324   out:
325     lu_putslot(slot);
326     
327     TRACE("out\n");
328     return res;
329 }
330
331 static int lu_create(struct inode *dir, struct dentry *dentry, int mode)
332 {
333     int res;
334     struct server_slot *slot;
335     struct iovec iov[2];
336
337     TRACE("in\n");
338
339     if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
340         return -ERESTARTSYS;
341
342     if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
343         WARN("lu_getname failed!\n");
344         goto out;
345     }
346     
347     iov[0].iov_base = &mode;
348     iov[0].iov_len = sizeof(mode);
349     iov[1].iov_base = slot->s_buf;
350     iov[1].iov_len = strlen(slot->s_buf) + 1;
351
352     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_CREATE, iov, 2, NULL, 0)) < 0)
353         goto out;
354
355     if(PIS_ERROR(res)){
356         TRACE("Could not create file.\n");
357         res = PERROR(res);
358         goto out;
359     }
360
361     res = lu_instantiate(dentry, slot->s_buf, slot);
362     
363   out:
364     lu_putslot(slot);
365
366     TRACE("out\n");
367     return res;
368 }
369
370 static int lu_rmdir(struct inode *dir, struct dentry *dentry)
371 {
372     int res;
373     struct server_slot *slot;
374     struct iovec iov;
375
376     if(!d_unhashed(dentry))
377         return -EBUSY;    
378
379     TRACE("in\n");
380     
381     if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
382         return -ERESTARTSYS;
383
384     if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
385         WARN("lu_getname failed!");
386         goto out;
387     }
388     
389     iov.iov_base = slot->s_buf;
390     iov.iov_len = strlen(slot->s_buf) + 1;
391
392     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_RMDIR, &iov, 1, NULL, 0)) < 0)
393         goto out;
394
395     if(PIS_ERROR(res)){
396         TRACE("rmdir failed!\n");
397         res = PERROR(res);
398         goto out;
399     }
400     res = 0;
401
402   out:
403     lu_putslot(slot);
404
405     TRACE("out\n");
406     return res;
407 }
408
409 static int lu_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
410 {
411     struct server_slot *slot;
412     int res;
413     struct iovec iov[2];
414
415     TRACE("in\n");
416
417     if((slot = lu_getslot(GET_INFO(old_dentry->d_sb))) == NULL)
418         return -ERESTARTSYS;
419
420     if((res = lu_getname(old_dentry, slot->s_buf, LU_MAXPATHLEN)) < 0 ||
421        (res = lu_getname(new_dentry, &(slot->s_buf[LU_MAXPATHLEN]), LU_MAXPATHLEN)) < 0){
422         WARN("lu_getname failed!\n");
423         goto out;
424     }
425
426     iov[0].iov_base = slot->s_buf;
427     iov[0].iov_len = strlen(slot->s_buf) + 1;
428     iov[1].iov_base = &(slot->s_buf[LU_MAXPATHLEN]);
429     iov[1].iov_len = strlen(&(slot->s_buf[LU_MAXPATHLEN])) + 1;
430
431     if((res = lu_execute(GET_INFO(old_dentry->d_sb), slot, PTYPE_RENAME, iov, 2, NULL, 0)) < 0)
432         goto out;
433
434     if(PIS_ERROR(res)){
435         TRACE("rename failed!\n");
436         res = PERROR(res);
437         goto out;
438     }
439     res = 0;
440
441   out:
442     lu_putslot(slot);
443
444     TRACE("out\n");
445     return res;
446 }
447
448 static int lu_unlink(struct inode *dir, struct dentry *dentry)
449 {
450     int res;
451     struct server_slot *slot;
452     struct iovec iov;
453
454     TRACE("in\n");
455
456     if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
457         return -ERESTARTSYS;
458
459     if((res = lu_getname(dentry, slot->s_buf, LU_MAXPATHLEN)) < 0){
460         WARN("lu_getname failed!");
461         goto out;
462     }
463     
464     iov.iov_base = slot->s_buf;
465     iov.iov_len = strlen(slot->s_buf) + 1;
466
467     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_UNLINK, &iov, 1, NULL, 0)) < 0)
468         goto out;
469
470     if(PIS_ERROR(res)){
471         TRACE("unlink failed!\n");
472         res = PERROR(res);
473         goto out;
474     }
475     res = 0;
476
477   out:
478     lu_putslot(slot);
479
480     TRACE("out\n");
481     return res;
482 }
483
484
485 static int lu_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
486 {
487     int res;
488     struct server_slot *slot;
489     struct iovec iov[2];
490
491     TRACE("in\n");
492
493     if(S_ISDIR(old_dentry->d_inode->i_mode))
494         return -EPERM;
495
496     if(!(slot = lu_getslot(GET_INFO(old_dentry->d_sb))))
497         return -ERESTARTSYS;
498
499     if((res = lu_getname(old_dentry, slot->s_buf, LU_MAXPATHLEN)) < 0){
500         WARN("lu_getname failed!\n");
501         goto out;
502     }
503
504     if((res = lu_getname(dentry, &slot->s_buf[LU_MAXPATHLEN], LU_MAXPATHLEN)) < 0){
505         WARN("lu_getname failed!\n");
506         goto out;
507     }
508
509     iov[0].iov_base = slot->s_buf;
510     iov[0].iov_len = strlen(slot->s_buf) + 1;
511     iov[1].iov_base = &slot->s_buf[LU_MAXPATHLEN];
512     iov[1].iov_len = strlen(&slot->s_buf[LU_MAXPATHLEN]) + 1;
513
514     d_drop(dentry);
515
516     if((res = lu_execute(GET_INFO(old_dentry->d_sb), slot, PTYPE_LINK, iov, 2, NULL, 0)) < 0)
517         goto out;
518
519     if(PIS_ERROR(res)){
520         TRACE("link failed!\n");
521         res = PERROR(res);
522         goto out;
523     }
524
525     res = 0;
526
527   out:
528     lu_putslot(slot);
529     TRACE("out\n");
530     return res;
531 }
532
533 static int lu_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
534 {
535     int res;
536     struct server_slot *slot;
537     struct iovec iov[2];
538
539     TRACE("in\n");
540     TRACE("symlink: %s\n", symname);
541     
542     if(strlen(symname) > LU_MAXPATHLEN - 1)
543         return -ENAMETOOLONG;
544
545     if(!(slot = lu_getslot(GET_INFO(dentry->d_sb))))
546         return -ERESTARTSYS;
547
548     if((res = lu_getname(dentry, slot->s_buf, LU_MAXPATHLEN)) < 0){
549         WARN("lu_getname failed!\n");
550         goto out;
551     }
552
553     TRACE("fname: %s\n", slot->s_buf);
554
555     strcpy(&slot->s_buf[LU_MAXPATHLEN], symname);
556
557     iov[0].iov_base = slot->s_buf;
558     iov[0].iov_len = strlen(slot->s_buf) + 1;
559     iov[1].iov_base = &slot->s_buf[LU_MAXPATHLEN];
560     iov[1].iov_len = strlen(&slot->s_buf[LU_MAXPATHLEN]) + 1;
561
562     d_drop(dentry);
563
564     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_SYMLINK, iov, 2, NULL, 0)) < 0)
565         goto out;
566
567     if(PIS_ERROR(res)){
568         TRACE("symlink failed!\n");
569         res = PERROR(res);
570         goto out;
571     }
572
573     res = 0;
574
575   out:
576     lu_putslot(slot);
577     TRACE("out\n");
578     return res;
579 }
580
581
582