http://prdownloads.sourceforge.net/lufs/lufs-0.9.7.tar.gz?download
[lufs.git] / lufsd / filesystem.c
1 /*
2  * filesystem.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 <unistd.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include <sys/wait.h>
35 #include <sys/ipc.h>
36 #include <sys/msg.h>
37
38 #include <lufs/proto.h>
39 #include <lufs/fs.h>
40
41 #include "list.h"
42 #include "message.h"
43 #include "dircache.h"
44 #include "filesystem.h"
45
46
47
48 static struct message*
49 generic_umount(struct file_system *fs, struct message *msg){
50     TRACE("unmounting this filesystem");
51
52     if(!fs->fs_ops->umount)
53         return NULL;
54
55     fs->fs_ops->umount(fs->fs_context);
56     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
57 }
58
59 static struct message*
60 generic_readdir(struct file_system *fs, struct message *msg){
61     struct lufs_req_readdir *req;
62     struct directory *dir;
63     struct message *res;
64     
65     if(!fs->fs_ops->readdir)
66         return NULL;
67
68     req = (struct lufs_req_readdir*)msg->m_data;
69
70     TRACE("readdir %s, offset %d",req->dirname, req->offset);
71     
72     if(lu_cache_readdir(fs->fs_cache, req->dirname, req->offset, fs->fs_buf, LU_MAXDATA) < 0){
73         if(!(dir = lu_cache_mkdir(req->dirname)))
74             return NULL;
75
76         if(fs->fs_ops->readdir(fs->fs_context, req->dirname, dir) < 0){
77             lu_cache_killdir(dir);
78             return NULL;
79         }
80
81         lu_cache_add_dir(fs->fs_cache, dir);
82         
83         if(lu_cache_readdir(fs->fs_cache, req->dirname, req->offset, fs->fs_buf, LU_MAXDATA) < 0){
84             WARN("could not read directory!");
85             return NULL;
86         }
87
88     }
89
90     res = lu_makemsg(&fs->fs_msg, PTYPE_OK, fs->fs_buf, strlen(fs->fs_buf) + 1);
91     return res;
92 }
93
94 static struct message*
95 generic_illegal(struct file_system *fs, struct message *msg){
96     WARN("Illegal message type: %d", msg->m_hdr.msg_type);
97     return NULL;
98 }
99
100 static struct message*
101 generic_read(struct file_system *fs, struct message *msg){
102     struct lufs_req_rw *req;
103     struct message *res;
104     int r;
105     
106     if(!fs->fs_ops->read)
107         return NULL;
108
109     req = (struct lufs_req_rw*)msg->m_data;
110     TRACE("read");
111     TRACE("read %s, offset= %Ld, count= %d", req->name, req->offset, (int)req->count);
112     
113     if((r = fs->fs_ops->read(fs->fs_context, req->name, req->offset, req->count, fs->fs_buf)) < 0){
114         TRACE("read failed\n");
115         res = NULL;
116     }else{
117         if((unsigned)r < req->count)
118             memset(fs->fs_buf + r, 0, req->count - r);
119         res = lu_makemsg(&fs->fs_msg, PTYPE_OK, fs->fs_buf, req->count);
120     }
121     return res;
122 }
123
124 static struct message*
125 generic_write(struct file_system *fs, struct message *msg){
126     struct lufs_req_rw *req;
127     char *buf;
128     struct message *res;
129
130     if(!fs->fs_ops->write)
131         return NULL;
132
133     req = (struct lufs_req_rw*)msg->m_data;
134     buf = req->name + strlen(req->name) + 1;
135
136     TRACE("write %s, offset=%Ld, count=%d", req->name, req->offset, (int)req->count);
137
138     if(fs->fs_ops->write(fs->fs_context, req->name, req->offset, req->count, buf) < 0){
139         TRACE("write failed\n");
140         res = NULL;
141     }else
142         res = lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
143
144     return res;
145 }
146
147 static struct message*
148 generic_stat(struct file_system *fs, struct message *msg){
149     struct lufs_fattr *fattr = (struct lufs_fattr*)fs->fs_buf;
150
151     if(!fs->fs_ops->stat)
152         return NULL;
153
154     TRACE("stat %s", msg->m_data);
155
156     memset(fattr, 0, sizeof(struct lufs_fattr));
157
158     if(lu_cache_lookup_file(fs->fs_cache, msg->m_data, fattr, NULL, 0) < 0){
159         TRACE("lookup failed on master");
160
161         if(strlen(msg->m_data) <= 1)
162             sprintf(msg->m_data, "/.");
163
164         if(fs->fs_ops->stat(fs->fs_context, msg->m_data , fattr) < 0){
165             TRACE("do_stat failed too");
166             return NULL;
167         }
168     }
169
170     return lu_makemsg(&fs->fs_msg, PTYPE_OK, (char*)fattr, sizeof(struct lufs_fattr));
171 }
172
173 static struct message*
174 generic_mkdir(struct file_system *fs, struct message *msg){
175     struct lufs_req_mkdir *req;
176
177
178     if(!fs->fs_ops->mkdir)
179         return NULL;
180
181     TRACE("mkdir");
182
183     req = (struct lufs_req_mkdir*)msg->m_data;
184     
185     if(fs->fs_ops->mkdir(fs->fs_context, req->dirname, req->mode) < 0){
186         TRACE("mkdir failed!");
187         return NULL;
188     }
189
190     lu_cache_invalidate(fs->fs_cache, req->dirname);
191
192     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
193 }
194
195 static struct message*
196 generic_rmdir(struct file_system *fs, struct message *msg){
197     
198     if(!fs->fs_ops->rmdir)
199         return NULL;
200
201     TRACE("rmdir");
202
203     if(fs->fs_ops->rmdir(fs->fs_context, msg->m_data) < 0){
204         TRACE("rmdir failed!");
205         return NULL;
206     }
207
208     lu_cache_invalidate(fs->fs_cache, msg->m_data);
209
210     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
211 }
212
213 static struct message*
214 generic_create(struct file_system *fs, struct message *msg){
215     struct lufs_req_mkdir *req;
216
217     if(!fs->fs_ops->create)
218         return NULL;
219
220     TRACE("create");
221
222     req = (struct lufs_req_mkdir*)msg->m_data;
223     
224     if(fs->fs_ops->create(fs->fs_context, req->dirname, req->mode) < 0){
225         TRACE("create failed!");
226         return NULL;
227     }
228     
229     lu_cache_invalidate(fs->fs_cache, req->dirname);
230
231     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
232 }
233
234 static struct message*
235 generic_unlink(struct file_system *fs, struct message *msg){
236
237     if(!fs->fs_ops->unlink)
238         return NULL;
239
240     TRACE("unlink");
241
242     if(fs->fs_ops->unlink(fs->fs_context, msg->m_data) < 0){
243         TRACE("unlink failed!");
244         return NULL;
245     }
246
247     lu_cache_invalidate(fs->fs_cache, msg->m_data);
248
249     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
250 }
251
252 static struct message*
253 generic_rename(struct file_system *fs, struct message *msg){
254
255     if(!fs->fs_ops->rename)
256         return NULL;
257
258     TRACE("old: %s, new: %s", msg->m_data, msg->m_data + strlen(msg->m_data) + 1);
259
260     if(fs->fs_ops->rename(fs->fs_context, msg->m_data, msg->m_data + strlen(msg->m_data) + 1) < 0){
261         TRACE("rename failed!");
262         return NULL;
263     }
264
265     lu_cache_invalidate(fs->fs_cache, msg->m_data);
266     lu_cache_invalidate(fs->fs_cache, msg->m_data + strlen(msg->m_data) + 1);
267
268     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
269 }
270
271 static struct message*
272 generic_open(struct file_system *fs, struct message *msg){
273     struct lufs_req_open *req;
274
275     if(!fs->fs_ops->open)
276         return NULL;
277
278     TRACE("open");
279     
280     req = (struct lufs_req_open*)msg->m_data;
281
282     if(fs->fs_ops->open(fs->fs_context, req->name, req->mode) < 0){
283         TRACE("open failed!");
284         return NULL;
285     }
286
287     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
288 }
289
290 static struct message*
291 generic_release(struct file_system *fs, struct message *msg){
292
293     if(!fs->fs_ops->release)
294         return NULL;
295
296     TRACE("release");
297
298     if(fs->fs_ops->release(fs->fs_context, msg->m_data) < 0){
299         TRACE("release failed!");
300         return NULL;
301     }
302
303     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
304 }
305
306
307 static struct message*
308 generic_readlink(struct file_system *fs, struct message *msg){
309     struct lufs_fattr fattr;
310     int len;
311
312     if(!fs->fs_ops->readlink)
313         return NULL;
314
315     TRACE("readlink %s", msg->m_data);
316     
317     /* try to get the link target from dircache first */
318     if(lu_cache_lookup_file(fs->fs_cache, msg->m_data, &fattr, fs->fs_buf, LU_MAXDATA) < 0)
319         goto def;
320
321     if(strcmp(fs->fs_buf, "")){
322         TRACE("link target found in dircache.");
323         return lu_makemsg(&fs->fs_msg, PTYPE_OK, fs->fs_buf, strlen(fs->fs_buf) + 1);
324     }
325         
326
327 def:
328
329     if((len = fs->fs_ops->readlink(fs->fs_context, msg->m_data, fs->fs_buf, LU_MAXDATA)) < 0){
330         TRACE("readlink failed!");
331         return NULL;
332     }
333     
334     fs->fs_buf[len++] = 0;
335     
336     return lu_makemsg(&fs->fs_msg, PTYPE_OK, fs->fs_buf, len);
337 }
338
339 static struct message*
340 generic_link(struct file_system *fs, struct message *msg){
341
342     if(!fs->fs_ops->link)
343         return NULL;
344
345     TRACE("link %s %s", msg->m_data, &msg->m_data[strlen(msg->m_data)+1]);
346
347     if(fs->fs_ops->link(fs->fs_context, msg->m_data, &msg->m_data[strlen(msg->m_data) + 1]) < 0){
348         TRACE("link failed!");
349         return NULL;
350     }
351     
352     lu_cache_invalidate(fs->fs_cache, msg->m_data);
353     lu_cache_invalidate(fs->fs_cache, &msg->m_data[strlen(msg->m_data) + 1]);
354     
355     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
356 }
357
358 static struct message*
359 generic_symlink(struct file_system *fs, struct message *msg){
360
361     if(!fs->fs_ops->symlink)
362         return NULL;
363
364     TRACE("symlink %s %s", msg->m_data, &msg->m_data[strlen(msg->m_data)+1]);
365
366     if(fs->fs_ops->symlink(fs->fs_context, &msg->m_data[strlen(msg->m_data) + 1], msg->m_data) < 0){
367         TRACE("symlink failed!");
368         return NULL;
369     }
370
371     lu_cache_invalidate(fs->fs_cache, msg->m_data);
372
373     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
374 }
375
376 static struct message*
377 generic_setattr(struct file_system *fs, struct message *msg){
378     struct lufs_req_setattr *req = (struct lufs_req_setattr*)msg->m_data;
379
380     if(!fs->fs_ops->setattr)
381         return NULL;
382
383     TRACE("setattr %s", req->name);
384
385     if(fs->fs_ops->setattr(fs->fs_context, req->name, &req->fattr) < 0){
386         TRACE("setattr failed!");
387         return NULL;
388     }
389     
390     lu_cache_invalidate(fs->fs_cache, req->name);
391     
392     return lu_makemsg(&fs->fs_msg, PTYPE_OK, NULL, 0);
393 }
394
395
396 void
397 handle_fs(struct file_system *fs, int sock, pid_t pid){
398     struct message *msg, *rep;
399     struct message* (*handlers[PTYPE_MAX + 1])(struct file_system*, struct message*);
400
401     handlers[0] = generic_illegal;      // PTYPE_OK
402     handlers[1] = generic_illegal;      // PTYPE_MOUNT
403     handlers[2] = generic_read;         // PTYPE_READ
404     handlers[3] = generic_write;        // PTYPE_WRITE
405     handlers[4] = generic_readdir;      // PTYPE_READDIR
406     handlers[5] = generic_stat;         // PTYPE_STAT
407     handlers[6] = generic_umount;       // PTYPE_UMOUNT
408     handlers[7] = generic_setattr;      // PTYPE_SETATTR
409     handlers[8] = generic_mkdir;        // PTYPE_MKDIR
410     handlers[9] = generic_rmdir;        // PTYPE_RMDIR
411     handlers[10] = generic_create;      // PTYPE_CREATE
412     handlers[11] = generic_unlink;      // PTYPE_UNLINK
413     handlers[12] = generic_rename;      // PTYPE_RENAME
414     handlers[13] = generic_open;        // PTYPE_OPEN
415     handlers[14] = generic_release;     // PTYPE_RELEASE
416     handlers[15] = generic_readlink;    // PTYPE_READLINK
417     handlers[16] = generic_link;        // PTYPE_LINK
418     handlers[17] = generic_symlink;     // PTYPE_SYMLINK
419
420     if(!fs->fs_mounted){
421         TRACE("connecting the slot...");
422
423         if(!fs->fs_ops->mount(fs->fs_context)){
424             WARN("couldn't connect!");
425             return;
426         }
427     }
428
429     signal(SIGPIPE, SIG_IGN);
430
431     TRACE("entering I/O loop...");
432     
433     for(;;){
434         msg = lu_recvmsg(&fs->fs_msg, sock);
435
436         if(!msg){
437             TRACE("oops, my kernel pair disconnected");
438             return;
439         }
440
441         rep = NULL;
442         if(msg->m_hdr.msg_type <= PTYPE_MAX){
443             rep = (handlers[msg->m_hdr.msg_type])(fs, msg);
444         }
445
446         if(!rep){
447             TRACE("operation failed, sending error reply...");
448             rep = lu_makemsg(&fs->fs_msg, PTYPE_ERROR, NULL, 0);
449         }
450
451         lu_sendmsg(rep, sock);
452     }
453
454 }
455
456
457