Line 0
Link Here
|
|
|
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 |
|