Merged revisions 10129-10142 via svnmerge from
[wvapps.git] / funfs / funfsd.cc
blob80c4854dc231a73452d49d1ab9caa6574062391e
1 #include "funfsd.h"
2 #include "funfscodecs.h"
3 #include "wvfshelpers.h"
5 #include <wvfork.h>
6 #include <wvistreamlist.h>
8 #include <sys/stat.h>
9 #include <dirent.h>
10 #include <utime.h>
11 #include <stdio.h>
12 #include <fcntl.h>
14 #define GETPATH() \
15 WvString path = getline(-1); \
16 assert(!!path)
19 FunFSd::FunFSd(int port, bool _forkok)
20 : forkok(_forkok), listener(WvIPPortAddr("0.0.0.0", port)),
21 log("FunFSd", WvLog::Info)
23 log("Listening on port %s.\n", port);
25 listener.setcallback(WvStreamCallback(this, &FunFSd::callback_incoming), 0);
27 append(&listener, false);
31 bool FunFSd::isok() const
33 if (!listener.isok())
35 log(WvLog::Error, "%s.", listener.errstr());
36 return false;
38 return true;
42 void FunFSd::callback_incoming(WvStream &, void *)
44 WvFDStream *s = listener.accept();
46 int pid = forkok ? wvfork(s->getfd()) : 0;
48 if (pid > 0)
50 delete s;
52 else if (pid == 0)
54 WvIStreamList::globallist.append(new FunFSdCon(s, forkok), true);
56 else
58 log(WvLog::Error, "Fork failed!\n");
63 FunFSdCon::FunFSdCon(WvStream *s, bool _quit_on_disconnect)
64 : WvStreamClone(s), quit_on_disconnect(_quit_on_disconnect),
65 log(WvString("Client<%s>", *s->src()), WvLog::Debug2)
67 log(WvLog::Info, "Incoming connection.\n");
68 uses_continue_select = true;
70 s->write("FunFS Server 0.0 ready\n");
72 setcallback(WvStreamCallback(this, &FunFSdCon::line_mode_execute), NULL);
76 FunFSdCon::~FunFSdCon()
78 close();
80 log(WvLog::Info, "Connection terminated.\n");
82 terminate_continue_select();
84 if (quit_on_disconnect)
85 _exit(0);
89 void FunFSdCon::line_mode_execute(WvStream &, void *)
91 WvStream *&mycloned = (WvStream*)cloned;
93 // Switch to data mode
94 mycloned->delay_output(true);
95 setcallback(WvStreamCallback(this, &FunFSdCon::data_mode_execute), NULL);
99 void FunFSdCon::data_mode_execute(WvStream &, void *)
101 uint16 jobid = 0;
102 uint8 jobtype = 0;
104 READ(jobid);
105 READ(jobtype);
107 log(WvLog::Debug4, "jobid = %s, jobtype = %s\n", (int)jobid, (int)jobtype);
109 if (!isok())
110 return;
112 assert(jobid);
114 // FIXME: parallelize replys
115 cloned->write(SWAP16(&jobid), sizeof(jobid));
117 switch (jobtype)
119 case JT_GETATTR:
120 handle_getattr();
121 break;
122 case JT_GETDIR:
123 handle_getdir();
124 break;
125 case JT_READLINK:
126 handle_readlink();
127 break;
128 case JT_READ:
129 handle_read();
130 break;
131 case JT_STATFS:
132 handle_statfs();
133 break;
134 case JT_OPEN:
135 handle_open();
136 break;
137 case JT_RELEASE:
138 handle_release();
139 break;
141 case JT_UTIME:
142 handle_utime();
143 break;
144 case JT_LINK:
145 handle_link();
146 break;
148 default:
149 break;
152 flush_queued();
156 void FunFSdCon::flush_queued()
158 if (int c = queue.count())
159 log("<BOB> Flushing %s queued message(s).\n", c);
161 WvList<WvDynBuf>::Iter i(queue);
162 uint16 jobid = 0;
163 for (i.rewind(); i.next(); )
165 cloned->write(&jobid, sizeof(jobid));
166 write(*i);
168 queue.zap();
172 size_t FunFSdCon::write(WvBuf &inbuf, size_t count)
174 //fprintf(stderr, "wrote count %d\n", inbuf.used());
175 uint32 clength = inbuf.used();
177 cloned->write(SWAP32(&clength), sizeof(clength));
178 size_t r = cloned->write(inbuf);
180 cloned->flush(0);
182 inbuf.zap();
184 return r;
187 void FunFSdCon::handle_getdir()
189 GETPATH();
190 log("<GetDir> Read path: %s\n", path);
192 struct dirent *de;
193 struct stat stbuf;
195 DIR *dp = opendir(path);
197 if (!dp)
199 uint16 err = errno;
200 xoutbuf.put(SWAP16(&err), sizeof(err));
202 else
204 cim_mark_uptodate(path, JT_GETDIR);
207 while (dp && (de = readdir(dp)) != NULL)
209 if (strcmp(de->d_name, ".") && strcmp(de->d_name, ".."))
211 WvString fullpath("%s/%s", path, de->d_name);
213 // Make sure we fill in the type field if libc didn't
214 if (de->d_type == DT_UNKNOWN)
216 if (!lstat(fullpath, &stbuf))
218 de->d_type = IFTODT(stbuf.st_mode);
220 else
221 fprintf(stderr, "Error stat'ing '%s': %s.\n",
222 WvString("%s/%s", path, de->d_name).cstr(),
223 strerror(errno));
226 // Presend the information the client might be interested in
227 switch (de->d_type)
229 case DT_LNK:
230 enqueue(JT_READLINK, fullpath);
231 case DT_REG:
232 enqueue(JT_GETATTR, fullpath);
233 break;
234 case DT_UNKNOWN:
235 fprintf(stderr, "Still no type in getdir!\n");
236 default:
237 break;
239 encode_fuse_dirent(xoutbuf, de);
243 closedir(dp);
244 write(xoutbuf);
247 void FunFSdCon::enqueue(JobType type, WvStringParm path)
249 WvDynBuf *mybuf = new WvDynBuf();
251 mybuf->putch(type);
252 mybuf->putstr(path);
253 mybuf->putch('\0');
255 bool success = false;
257 switch (type)
259 case JT_READLINK:
260 success = do_readlink(path, *mybuf);
261 break;
262 case JT_GETATTR:
263 success = do_getattr(path, *mybuf);
264 break;
265 default:
266 break;
269 if (success)
271 queue.append(mybuf, true);
273 else
274 delete mybuf;
277 void FunFSdCon::handle_getattr()
279 GETPATH();
280 log("<GetAttr> Read path: %s\n", path);
282 do_getattr(path, xoutbuf);
284 write(xoutbuf);
288 bool FunFSdCon::do_getattr(WvStringParm path, WvDynBuf &myoutbuf)
290 struct stat stbuf;
292 int res = lstat(path, &stbuf);
294 if (res < 0)
296 uint16 err = errno;
297 myoutbuf.put(SWAP16(&err), sizeof(err));
299 else
301 fuse_attr attr;
302 convert_stat(&stbuf, &attr);
303 encode_fuse_attr(myoutbuf, &attr);
304 cim_mark_uptodate(path, JT_GETATTR);
307 return !res;
311 void FunFSdCon::handle_readlink()
313 GETPATH();
314 log("<ReadLink> Read path: %s\n", path);
316 do_readlink(path, xoutbuf);
318 write(xoutbuf);
321 bool FunFSdCon::do_readlink(WvStringParm path, WvDynBuf &myoutbuf)
323 char link[PATH_MAX];
325 int size = readlink(path, link, PATH_MAX);
327 uint16 err = (size >= 0 ? 0 : errno);
328 myoutbuf.put(SWAP16(&err), sizeof(err));
330 if (size >= 0)
332 cim_mark_uptodate(path, JT_READLINK);
333 myoutbuf.put(link, size);
334 myoutbuf.putch('\0');
335 return true;
337 return false;
340 void FunFSdCon::handle_read()
342 int fd = 0;
343 uint32 size = 0;
344 uint32 offset = 0;
346 READ(fd);
347 READ(size);
348 READ(offset);
350 //fprintf(stderr, "fd = %d, size = %lu, offset = %lu\n", fd, size, offset);
352 int err = 0;
353 int remaining = size;
355 int res = 0;
356 char *tmpbuf = new char[size];
358 for (char *where = tmpbuf; remaining > 0; where += res,
359 remaining -= res, offset += res)
361 res = ::pread(fd, where, remaining, offset);
363 if (res == -1)
364 err = errno;
366 // Zero indicates end of file
367 if (res <= 0)
368 break;
371 if (err)
372 fprintf(stderr, "Error on read: %s\n", strerror(errno));
374 if (size - remaining)
375 xoutbuf.put(tmpbuf, size - remaining);
377 //fprintf(stderr, "buf.used(): %d\n", buf.used());
379 delete[] tmpbuf;
381 write(xoutbuf);
384 void FunFSdCon::handle_statfs()
386 struct statfs st;
388 // FIXME: this should use filesystem root
389 int res = statfs("/",&st);
391 if (res < 0)
393 uint16 err = errno;
394 xoutbuf.put(SWAP16(&err), sizeof(err));
396 else
398 fuse_kstatfs fst;
399 convert_statfs(&st, &fst);
400 encode_fuse_kstatfs(xoutbuf, &fst);
403 write(xoutbuf);
406 void FunFSdCon::handle_open()
408 GETPATH();
410 int flags;
411 READ(flags);
413 int fd = ::open(path, flags);
415 if (fd >= 0)
417 cim_do_open(path, fd);
418 xoutbuf.put(SWAP32(&fd), sizeof(fd));
420 else
422 uint16 err = errno;
423 xoutbuf.put(SWAP16(&err), sizeof(err));
426 write(xoutbuf);
429 void FunFSdCon::handle_release()
431 int fd;
432 READ(fd);
434 cim_do_close(fd);
436 ::close(fd);
437 write(xoutbuf);
441 void FunFSdCon::handle_link()
443 WvString from = getline(-1, '\0');
444 assert(!!from);
445 WvString to = getline(-1, '\0');
446 assert(!!to);
448 int res = link(from, to);
450 PUTERRNO(res < 0);
452 write(xoutbuf);
457 void FunFSdCon::handle_utime()
459 WvString path = getline(-1, '\0');
461 if (!path)
462 return;
464 log("<Utime>Read path: %s\n", path);
466 struct utimbuf utbuf;
468 int res = utime(path, &utbuf);
470 PUTERRNO(res < 0);
472 if (res == 0)
474 xoutbuf.put(SWAP32(&utbuf.actime), 32);
475 xoutbuf.put(SWAP32(&utbuf.modtime), 32);
478 write(xoutbuf);
483 void FunFSdCon::file_changed(WvStringParm path)
485 log(WvLog::Debug4, "%s changed!\n");
489 void FunFSdCon::file_deleted(WvStringParm path)
491 log(WvLog::Debug4, "%s deleted!\n");
495 void FunFSdCon::file_created(WvStringParm path)
497 log(WvLog::Debug4, "%s created!\n");