- filled in group field, previously missing.
[npfs.git] / fs / fus.c
blobb1d6256405752a5a80e9bb67353faaf64f5d7b7e
1 /*
2 * Copyright (C) 2008 by Latchesar Ionkov <lucho@ionkov.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * LATCHESAR IONKOV AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
23 //#define _XOPEN_SOURCE 500
24 #define _BSD_SOURCE
25 #define _GNU_SOURCE
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <pthread.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <dirent.h>
37 #include <fcntl.h>
38 #include <utime.h>
39 #include <pwd.h>
40 #include <grp.h>
41 #include <assert.h>
42 #include <sys/syscall.h>
43 #include <sys/sendfile.h>
44 #include <sys/socket.h>
45 #include <sys/types.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <stdarg.h>
49 #include <sched.h>
51 typedef uint8_t u8;
52 typedef uint16_t u16;
53 typedef uint32_t u32;
54 typedef uint64_t u64;
56 typedef struct Conn Conn;
57 typedef struct Fid Fid;
58 typedef struct Wthread Wthread;
59 typedef struct Freq Freq;
60 typedef struct Qid Qid;
62 enum {
63 Tfirst = 100,
64 Tversion = 100,
65 Rversion,
66 Tauth = 102,
67 Rauth,
68 Tattach = 104,
69 Rattach,
70 Terror = 106,
71 Rerror,
72 Tflush = 108,
73 Rflush,
74 Twalk = 110,
75 Rwalk,
76 Topen = 112,
77 Ropen,
78 Tcreate = 114,
79 Rcreate,
80 Tread = 116,
81 Rread,
82 Twrite = 118,
83 Rwrite,
84 Tclunk = 120,
85 Rclunk,
86 Tremove = 122,
87 Rremove,
88 Tstat = 124,
89 Rstat,
90 Twstat = 126,
91 Rwstat,
92 Tlast = 126,
94 Fidtblsz = 8192,
95 Fidhtblsz = 32,
96 Maxwelem = 16,
99 /* modes */
100 enum {
101 Oread = 0x00,
102 Owrite = 0x01,
103 Ordwr = 0x02,
104 Oexec = 0x03,
105 Oexcl = 0x04,
106 Otrunc = 0x10,
107 Orexec = 0x20,
108 Orclose = 0x40,
109 Oappend = 0x80,
112 /* permissions */
113 enum {
114 Dmdir = 0x80000000,
115 Dmappend = 0x40000000,
116 Dmexcl = 0x20000000,
117 Dmmount = 0x10000000,
118 Dmauth = 0x08000000,
119 Dmtmp = 0x04000000,
120 Dmsymlink = 0x02000000,
121 Dmlink = 0x01000000,
123 /* 9P2000.u extensions */
124 Dmdevice = 0x00800000,
125 Dmnamedpipe = 0x00200000,
126 Dmsocket = 0x00100000,
127 Dmsetuid = 0x00080000,
128 Dmsetgid = 0x00040000,
131 /* qid.types */
132 enum {
133 Qtdir = 0x80,
134 Qtappend = 0x40,
135 Qtexcl = 0x20,
136 Qtmount = 0x10,
137 Qtauth = 0x08,
138 Qttmp = 0x04,
139 Qtsymlink = 0x02,
140 Qtlink = 0x01,
141 Qtfile = 0x00,
144 struct Fid {
145 u32 fid;
146 char* path;
147 int fd;
148 DIR* dir;
149 int diroffset;
150 char* direntname;
151 char cpath[256];
152 u8 type;
153 uid_t uid;
154 gid_t gid;
155 Fid* next;
158 struct Conn {
159 int sock;
160 pthread_mutex_t rlock;
161 int rfutex;
162 int dotu;
163 u32 msize;
165 /* data for the next message (if size not ~0) */
166 u32 size;
167 u8 type;
168 u16 tag;
169 u8 buf[23];
170 int bpos;
172 /* used to write to file */
173 int pip[2];
174 int nwthreads;
175 Wthread* wthreads;
177 /* Fid stuff */
178 Fid fidtbl[Fidtblsz];
179 Fid *fidhtbl[Fidhtblsz];
180 pthread_mutex_t wlock;
181 int wfutex;
184 struct Wthread {
185 pthread_t tid;
186 Conn* conn;
187 u16 tag;
188 Freq* freqs;
189 u8 stk[32768];
192 struct Freq {
193 u16 tag;
194 Freq* next;
197 struct Qid {
198 u8 type;
199 u32 version;
200 u64 path;
203 static int p9version(Conn *, u8, u16, u32, u8 *);
204 static int p9auth(Conn *, u8, u16, u32, u8 *);
205 static int p9attach(Conn *, u8, u16, u32, u8 *);
206 static int p9flush(Conn *, u8, u16, u32, u8 *);
207 static int p9walk(Conn *, u8, u16, u32, u8 *);
208 static int p9open(Conn *, u8, u16, u32, u8 *);
209 static int p9create(Conn *, u8, u16, u32, u8 *);
210 static int p9read(Conn *, u8, u16, u32, u8 *);
211 static int p9write(Conn *, u8, u16, u32, u8 *);
212 static int p9clunk(Conn *, u8, u16, u32, u8 *);
213 static int p9remove(Conn *, u8, u16, u32, u8 *);
214 static int p9stat(Conn *, u8, u16, u32, u8 *);
215 static int p9wstat(Conn *, u8, u16, u32, u8 *);
217 static int connproc(void *a);
218 void conndestroy(Conn *conn);
219 static int writen(Conn *conn, u8 *buf, int buflen);
220 static int rflush(Conn *conn, u16 tag, u8 *buf);
222 static int debuglevel;
223 static int msize = 8192;
224 static int dotu = 1;
225 static int sameuser = 0;
227 static int (*fhndlrs[])(Conn *, u8, u16, u32, u8 *) = {
228 p9version,
229 p9auth,
230 p9attach,
231 NULL,
232 p9flush,
233 p9walk,
234 p9open,
235 p9create,
236 p9read,
237 p9write,
238 p9clunk,
239 p9remove,
240 p9stat,
241 p9wstat,
244 #define FUTEX_WAIT 0
245 #define FUTEX_WAKE 1
247 static inline int
248 cmpxchg(int *ptr, int old, int new)
250 int prev;
252 asm volatile("lock cmpxchgl %k1,%2"
253 : "=a"(prev)
254 : "r"(new), "m"(*ptr), "0"(old)
255 : "memory");
257 return prev;
260 static inline int
261 xchg(int *ptr, int x)
263 asm volatile("lock xchgl %k0,%1"
264 : "=r" (x)
265 : "m" (*ptr), "0" (x)
266 : "memory");
268 return x;
271 static inline int
272 dec(int *ptr)
274 int i;
276 i = -1;
277 asm volatile("lock xaddl %0, %1"
278 : "+r" (i), "+m" (*ptr)
279 : : "memory");
281 return i;
284 static int
285 futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3)
287 return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
290 static inline void
291 flock(int *val)
293 int n;
295 if ((n = cmpxchg(val, 0, 1)) == 0)
296 return;
298 while (xchg(val, 2) != 0)
299 futex(val, FUTEX_WAIT, 2, NULL, NULL, 0);
302 static inline void
303 fulock(int *val)
305 unsigned long n;
307 if ((n = dec(val)) != 1) {
308 *val = 0;
309 futex(val, FUTEX_WAKE, 1, NULL, NULL, 0);
313 static void
314 debug(char *fmt, ...)
316 va_list ap;
318 va_start(ap, fmt);
319 if (debuglevel)
320 vfprintf(stderr, fmt, ap);
321 va_end(ap);
324 static inline void
325 rlock(Conn *conn)
327 flock(&conn->rfutex);
328 // pthread_mutex_lock(&conn->rlock);
331 static inline void
332 runlock(Conn *conn)
334 fulock(&conn->rfutex);
335 // pthread_mutex_unlock(&conn->rlock);
338 static inline void
339 wlock(Conn *conn)
341 flock(&conn->wfutex);
342 // pthread_mutex_lock(&conn->wlock);
345 static inline void
346 wunlock(Conn *conn)
348 fulock(&conn->wfutex);
349 // pthread_mutex_unlock(&conn->wlock);
352 static inline u8 *
353 pint8(u8 *data, u8 val)
355 data[0] = val;
356 return data + 1;
359 static inline u8 *
360 pint16(u8 *data, u16 val)
362 data[0] = val;
363 data[1] = val >> 8;
364 return data + 2;
367 static inline u8 *
368 pint32(u8 *data, u32 val)
370 data[0] = val;
371 data[1] = val >> 8;
372 data[2] = val >> 16;
373 data[3] = val >> 24;
374 return data + 4;
377 static inline u8 *
378 pint64(u8 *data, u64 val)
380 data[0] = val;
381 data[1] = val >> 8;
382 data[2] = val >> 16;
383 data[3] = val >> 24;
384 data[4] = val >> 32;
385 data[5] = val >> 40;
386 data[6] = val >> 48;
387 data[7] = val >> 56;
388 return data + 8;
391 static inline int
392 pstr(u8 *data, u16 sz, char *val)
394 pint16(data, sz);
395 if (sz)
396 memmove(data+2, val, sz);
398 return sz + 2;
401 static inline int
402 pstat(char *path, u8 *data, int dotu, int maxsz)
404 int n, sz, nsz, usz, gsz, msz, esz;
405 int mode;
406 u32 version;
407 u64 qpath;
408 char ext[256], ubuf[256], gbuf[256], *name;
409 struct passwd pw, *pwp;
410 struct group grp, *pgrp;
411 struct stat st;
413 if (lstat(path, &st) < 0)
414 return -1;
416 name = strrchr(path, '/');
417 if (name)
418 name++;
419 else
420 name = path;
422 mode = 0;
423 if (S_ISDIR(st.st_mode))
424 mode |= Dmdir;
426 ext[0] = '\0';
427 if (dotu) {
428 if (S_ISLNK(st.st_mode)) {
429 mode |= Dmsymlink;
430 n = readlink(path, ext, sizeof(ext) - 1);
431 if (n < 0)
432 return -1;
435 if (S_ISSOCK(st.st_mode))
436 mode |= Dmsocket;
437 if (S_ISFIFO(st.st_mode))
438 mode |= Dmnamedpipe;
439 if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) {
440 snprintf(ext, sizeof(ext), "%c %u %u", S_ISCHR(st.st_mode)?'c':'b',
441 major(st.st_rdev), minor(st.st_rdev));
443 mode |= Dmdevice;
446 if (st.st_mode & S_ISUID)
447 mode |= Dmsetuid;
448 if (st.st_mode & S_ISGID)
449 mode |= Dmsetgid;
452 mode |= st.st_mode & 0777;
453 nsz = 0;
454 usz = 0;
455 gsz = 0;
456 msz = 0;
457 esz = 0;
458 if (name)
459 nsz = strlen(name);
461 if (!dotu) {
462 if (getpwuid_r(st.st_uid, &pw, ubuf, sizeof(ubuf), &pwp))
463 return -1;
465 usz = strlen(pw.pw_name);
466 if (getgrgid_r(st.st_gid, &grp, gbuf, sizeof(gbuf), &pgrp))
467 return -1;
469 gsz = strlen(grp.gr_name);
472 esz = strlen(ext);
473 sz = 2+4+13+4+4+4+8+2+2+2+2+nsz+usz+gsz+msz+esz;
474 if (dotu)
475 sz += 4+4+4+2;
477 if (sz >= maxsz)
478 return -1;
480 qpath = 0;
481 n = sizeof(qpath);
482 if (n > sizeof(st.st_ino))
483 n = sizeof(st.st_ino);
484 memmove(&qpath, &st.st_ino, n);
485 version = st.st_mtime ^ (st.st_size << 8);
487 pint16(data, sz);
488 pint16(data+2, 0);
489 pint32(data+4, 0);
490 pint8(data+8, mode>>24);
491 pint32(data+9, version);
492 pint64(data+13, qpath);
493 pint32(data+21, mode);
494 pint32(data+25, st.st_atime);
495 pint32(data+29, st.st_mtime);
496 pint64(data+33, st.st_size);
497 n = 41;
498 n += pstr(data+n, nsz, name);
499 n += pstr(data+n, usz, pw.pw_name);
500 n += pstr(data+n, gsz, grp.gr_name);
501 n += pstr(data+n, 0, NULL);
502 if (dotu) {
503 n += pstr(data+n, esz, ext);
504 pint32(data+n, st.st_uid);
505 pint32(data+n+4, st.st_gid);
506 pint32(data+n+8, ~0);
509 return sz + 2;
512 static inline u8
513 gint8(u8 *data)
515 return data[0];
518 static inline u16
519 gint16(u8 *data)
521 return data[0] | (data[1]<<8);
524 static inline u32
525 gint32(u8 *data)
527 return data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
530 static inline u64
531 gint64(u8 *data)
533 return (u64)data[0] | ((u64)data[1]<<8) | ((u64)data[2]<<16) |
534 ((u64)data[3]<<24) | ((u64)data[4]<<32) | ((u64)data[5]<<40) |
535 ((u64)data[6]<<48) | ((u64)data[7]<<56);
538 static inline int
539 gstr(u8 *data, char **s, int maxsize)
541 u16 n;
543 n = gint16(data);
544 if (n >= maxsize)
545 return -1;
547 if (n) {
548 memmove(data, data + 2, n);
549 data[n] = '\0';
550 *s = (char *) data;
551 } else
552 *s = NULL;
554 return n;
557 Fid *
558 fidget(Conn *conn, u32 fid)
560 int hash;
561 Fid *f;
563 if (fid < Fidtblsz) {
564 f = &conn->fidtbl[fid];
565 if (f->fid == ~0)
566 f = NULL;
568 return f;
571 hash = fid % Fidhtblsz;
572 for(f = conn->fidhtbl[hash]; f != NULL; f = f->next)
573 if (f->fid == fid)
574 break;
576 return f;
579 Fid *
580 fidcreate(Conn *conn, u32 fid)
582 int hash;
583 Fid *f, *p;
585 if (fid < Fidtblsz) {
586 f = &conn->fidtbl[fid];
587 if (f->fid != ~0)
588 return NULL;
590 f->fid = fid;
591 return f;
594 f = calloc(1, sizeof(Fid));
595 hash = fid % Fidhtblsz;
596 if (!conn->fidhtbl[hash])
597 conn->fidhtbl[hash] = f;
598 else {
599 for(p = conn->fidhtbl[hash]; p->next != NULL; p = p->next)
602 p->next = f;
605 return f;
608 void
609 fiddestroy(Conn *conn, Fid *f)
611 int hash;
612 Fid *p;
614 if (f->fid < Fidtblsz) {
615 memset(f, 0, sizeof(*f));
616 f->fid = ~0;
617 return;
620 hash = f->fid % Fidhtblsz;
621 if (f == conn->fidhtbl[hash])
622 conn->fidhtbl[hash] = f->next;
623 else {
624 for(p = conn->fidhtbl[hash]; p->next != NULL; p = p->next)
625 if (p->next == f) {
626 p->next = f->next;
627 break;
631 free(f);
634 Conn *
635 conncreate(int sock, int nwthreads)
637 int i;
638 Conn *conn;
640 conn = calloc(1, sizeof(*conn) + nwthreads*sizeof(Wthread));
641 conn->sock = sock;
642 // pthread_mutex_init(&conn->rlock, NULL);
643 // pthread_mutex_init(&conn->wlock, NULL);
644 conn->msize = msize;
645 conn->dotu = dotu;
646 conn->size = ~0;
647 conn->bpos = 0;
648 pipe(conn->pip);
649 for(i = 0; i < Fidtblsz; i++)
650 conn->fidtbl[i].fid = ~0;
652 conn->nwthreads = 0;
653 conn->wthreads = (Wthread *) &conn[1];
654 for(i = 0; i < nwthreads; i++) {
655 conn->wthreads[i].conn = conn;
656 conn->wthreads[i].tag = ~0;
659 if (clone(connproc, conn->wthreads[i].stk + sizeof(conn->wthreads[i].stk),
660 CLONE_FS | CLONE_FILES | CLONE_VM, &conn->wthreads[i]) < 0) {
661 conndestroy(conn);
662 return NULL;
666 if (pthread_create(&conn->wthreads[i].tid, NULL, connproc, &conn->wthreads[i]) < 0) {
667 conndestroy(conn);
668 return NULL;
671 conn->nwthreads++;
674 return conn;
677 void
678 conndestroy(Conn *conn)
680 int i;
681 void *v;
683 close(conn->sock);
684 rlock(conn);
685 conn->sock = -1;
686 runlock(conn);
688 for(i = 0; i < conn->nwthreads; i++)
689 pthread_join(conn->wthreads[i].tid, &v);
691 free(conn);
694 void
695 conndisconnect(Conn *conn)
697 close(conn->sock);
698 conn->sock = -1;
701 static int
702 connproc(void *a)
704 int n;
705 u8 type;
706 u32 size;
707 u16 tag;
708 u8 *buf;
709 Wthread *wt;
710 Conn *conn;
711 Freq *freq, *freq1;
713 wt = a;
714 conn = wt->conn;
715 buf = malloc(conn->msize + sizeof(conn->buf));
716 while (1) {
717 rlock(conn);
718 if (conn->sock < 0) {
719 runlock(conn);
720 return -1;
723 if (conn->size == ~0) {
724 ragain:
725 n = read(conn->sock, conn->buf + conn->bpos,
726 sizeof(conn->buf) - conn->bpos);
728 if (n <= 0) {
729 if (n<0 && (errno==EAGAIN || errno==EINTR))
730 goto ragain;
732 goto disconn;
735 conn->bpos += n;
736 if (conn->bpos < 7)
737 goto ragain;
739 size = gint32(conn->buf);
740 type = gint8(conn->buf + 4);
741 tag = gint16(conn->buf + 5);
742 assert(size>0&&size<conn->msize && type>=100);
743 } else {
744 size = conn->size;
745 type = conn->type;
746 tag = conn->tag;
749 assert(size <= conn->msize);
750 conn->size = ~0;
751 if (type&1 || type<Tfirst || type>Tlast || !fhndlrs[(type-Tfirst)/2])
752 goto disconn;
754 assert(wt->tag==(u16)~0 && wt->freqs==NULL);
755 wt->tag = tag;
756 assert(size>0);
757 n = (*fhndlrs[(type-Tfirst)/2])(conn, type, tag, size, buf);
758 wlock(conn);
759 if (n)
760 writen(conn, buf, n);
762 freq = wt->freqs;
763 while (freq != NULL) {
764 n = rflush(conn, tag, buf);
765 writen(conn, buf, n);
766 freq1 = freq->next;
767 free(freq);
768 freq = freq1;
771 wt->tag = ~0;
772 wt->freqs = NULL;
773 wunlock(conn);
776 disconn:
777 conndisconnect(conn);
778 runlock(conn);
780 return -1;
783 static int
784 writen(Conn *conn, u8 *buf, int buflen)
786 int n, pos;
788 pos = 0;
790 again:
791 n = write(conn->sock, buf + pos, buflen - pos);
792 if (n <= 0) {
793 if (n<0 && (errno==EAGAIN || errno==EINTR))
794 goto again;
796 conndisconnect(conn);
797 return -1;
800 pos += n;
801 if (pos < n)
802 goto again;
804 return buflen;
807 /* reads the rest of the message into buf, sets up the size, type, tag values
808 for the next message, and unlocks the read lock */
809 static int
810 readrest(Conn *conn, u32 size, u8 *buf, int unlock)
812 int n, sz;
813 u8 *p;
815 sz = size;
816 p = buf;
817 assert(sz >= 0);
818 /* first get data from conn->buf, if there is any */
819 n = conn->bpos - 7;
820 if (n > 0) {
821 // debug("%%%% move sz %d bpos %d\n", sz, conn->bpos);
822 if (n > sz)
823 n = sz;
825 memmove(p, conn->buf + 7, n);
826 sz -= n;
827 p += n;
828 if (n < conn->bpos-7)
829 memmove(conn->buf, conn->buf + 7 + n, conn->bpos - 7 - n);
831 conn->bpos -= 7 + n;
834 while (sz > 0) {
835 // debug("%%%% read sz %d\n", sz);
836 n = read(conn->sock, p, sz + (unlock?sizeof(conn->buf):0));
837 if (n <= 0) {
838 if (n<0 && (errno==EAGAIN || errno==EINTR))
839 continue;
841 goto error;
844 p += n;
845 sz -= n;
848 /* now we have the whole message in buf, may be some data for the next */
849 if (sz <= 0) {
850 // debug("%%%% move2 sz %d bpos %d\n", sz, conn->bpos);
851 memmove(conn->buf + conn->bpos, buf + size, -sz);
852 conn->bpos += -sz;
855 if (conn->bpos > 7) {
856 conn->size = gint32(conn->buf);
857 conn->type = gint8(conn->buf + 4);
858 conn->tag = gint16(conn->buf + 5);
859 assert(conn->size>0 && conn->size<=conn->msize && conn->type>=100);
862 if (unlock)
863 runlock(conn);
864 return size;
866 error:
867 fprintf(stderr, "readrest error %d\n", errno);
868 conndisconnect(conn);
869 if (unlock)
870 runlock(conn);
871 return -1;
874 static int
875 rerror(Conn *conn, u16 tag, u8 *buf, char *ename, int ecode)
877 int sz, slen;
879 slen = strlen(ename);
880 sz = 9 + slen;
881 if (conn->dotu)
882 sz += 4;
884 pint32(buf, sz);
885 pint8(buf + 4, Rerror);
886 pint16(buf + 5, tag);
887 pint16(buf + 7, slen);
888 memmove(buf+9, ename, slen);
889 if (conn->dotu)
890 pint32(buf + 9 + slen, ecode);
892 return sz;
895 static int
896 ruerror(Conn *conn, u16 tag, u8 *buf, int ecode)
898 char ename[256];
900 strerror_r(ecode, ename, sizeof(ename));
901 return rerror(conn, tag, buf, ename, ecode);
904 static int
905 badmsg(Conn *conn, u16 tag, u8 *buf)
907 fprintf(stderr, "bad message\n");
908 return rerror(conn, tag, buf, "invalid message", EINVAL);
911 static int
912 badfid(Conn *conn, u16 tag, u8 *buf)
914 return rerror(conn, tag, buf, "invalid fid", EINVAL);
917 static int
918 rversion(Conn *conn, u16 tag, u8 *buf, char *version, int msize)
920 int sz, slen;
922 slen = strlen(version);
923 sz = 13 + slen;
924 pint32(buf, sz);
925 pint8(buf + 4, Rversion);
926 pint16(buf + 5, tag);
927 pint32(buf + 7, msize);
928 pint16(buf + 11, slen);
929 memmove(buf+13, version, slen);
930 return sz;
933 static int
934 rflush(Conn *conn, u16 tag, u8 *buf)
936 pint32(buf, 7);
937 pint8(buf + 4, Rflush);
938 pint16(buf + 5, tag);
939 return 7;
942 static int
943 rattach(Conn *conn, u16 tag, u8 *buf, Qid *qid)
945 pint32(buf, 20);
946 pint8(buf + 4, Rattach);
947 pint16(buf + 5, tag);
948 pint8(buf + 7, qid->type);
949 pint32(buf + 8, qid->version);
950 pint64(buf + 12, qid->path);
951 return 20;
954 static int
955 rwalk(Conn *conn, u16 tag, u8 *buf, u16 nwqid, Qid *wqid)
957 int i;
959 pint32(buf, 9 + nwqid*13);
960 pint8(buf + 4, Rwalk);
961 pint16(buf + 5, tag);
962 pint16(buf + 7, nwqid);
963 for(i = 0; i < nwqid; i++) {
964 pint8(buf + 9 + i*13, wqid[i].type);
965 pint32(buf + 10 + i*13, wqid[i].version);
966 pint64(buf + 14 + i*13, wqid[i].path);
969 return 9 + nwqid*13;
972 static int
973 ropen(Conn *conn, u16 tag, u8 *buf, Qid *qid, u32 iounit)
975 pint32(buf, 24);
976 pint8(buf + 4, Ropen);
977 pint16(buf + 5, tag);
978 pint8(buf + 7, qid->type);
979 pint32(buf + 8, qid->version);
980 pint64(buf + 12, qid->path);
981 pint32(buf + 20, iounit);
982 return 24;
985 static int
986 rcreate(Conn *conn, u16 tag, u8 *buf, Qid *qid, u32 iounit)
988 pint32(buf, 24);
989 pint8(buf + 4, Rcreate);
990 pint16(buf + 5, tag);
991 pint8(buf + 7, qid->type);
992 pint32(buf + 8, qid->version);
993 pint64(buf + 12, qid->path);
994 pint32(buf + 20, iounit);
995 return 24;
998 static int
999 rwrite(Conn *conn, u16 tag, u8 *buf, u32 count)
1001 pint32(buf, 11);
1002 pint8(buf + 4, Rwrite);
1003 pint16(buf + 5, tag);
1004 pint32(buf + 7, count);
1005 return 11;
1008 static int
1009 rclunk(Conn *conn, u16 tag, u8 *buf)
1011 pint32(buf, 7);
1012 pint8(buf + 4, Rclunk);
1013 pint16(buf + 5, tag);
1014 return 7;
1017 static int
1018 rremove(Conn *conn, u16 tag, u8 *buf)
1020 pint32(buf, 7);
1021 pint8(buf + 4, Rremove);
1022 pint16(buf + 5, tag);
1023 return 7;
1026 static int
1027 rstat(Conn *conn, u16 tag, u8 *buf, char *path)
1029 int sz;
1031 pint8(buf + 4, Rstat);
1032 pint16(buf + 5, tag);
1033 sz = pstat(path, buf + 9, conn->dotu, conn->msize - 9);
1034 if (sz < 0) {
1035 return rerror(conn, tag, buf, "insufficient msize", EIO);
1038 pint16(buf + 7, sz);
1039 pint32(buf, 7 + sz + 2);
1040 return 9 + sz;
1043 static int
1044 rwstat(Conn *conn, u16 tag, u8 *buf)
1046 pint32(buf, 7);
1047 pint8(buf + 4, Rwstat);
1048 pint16(buf + 5, tag);
1049 return 7;
1052 static inline void
1053 setuser(uid_t uid, gid_t gid)
1055 if (sameuser)
1056 return;
1058 syscall(SYS_setreuid, -1, uid);
1059 syscall(SYS_setregid, -1, gid);
1062 static int
1063 p9version(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1065 int msize;
1066 char *version;
1068 debug("version tag %d\n", tag);
1069 size -= 7;
1070 if (readrest(conn, size, buf, 1) < 0)
1071 return 0;
1073 if (size < 6)
1074 return badmsg(conn, tag, buf);
1076 msize = gint32(buf);
1077 conn->dotu = 0;
1078 if (gstr(buf + 4, &version, size - 4) < 0)
1079 return badmsg(conn, tag, buf);
1081 if (msize < conn->msize)
1082 conn->msize = msize;
1084 if (strncmp(version, "9P2000", 6) != 0)
1085 return rerror(conn, tag, buf, "unsupported version", 0);
1087 conn->dotu = dotu;
1088 if (dotu && strcmp(version, "9P2000.u")==0)
1089 version = "9P2000.u";
1090 else {
1091 conn->dotu = 0;
1092 version = "9P2000";
1095 return rversion(conn, tag, buf, version, conn->msize);
1099 static int
1100 p9auth(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1102 debug("auth tag %d\n", tag);
1103 size -= 7;
1104 if (readrest(conn, size, buf, 1) < 0)
1105 return 0;
1107 return rerror(conn, tag, buf, "authentication not required", EIO);
1110 static int
1111 stat2qid(struct stat *st, Qid *qid)
1113 int n;
1115 qid->type = 0;
1116 if (S_ISDIR(st->st_mode))
1117 qid->type |= Qtdir;
1119 if (S_ISLNK(st->st_mode))
1120 qid->type |= Qtsymlink;
1122 qid->path = 0;
1123 n = sizeof(qid->path);
1124 if (n > sizeof(st->st_ino))
1125 n = sizeof(st->st_ino);
1126 memmove(&qid->path, &st->st_ino, n);
1127 qid->version = st->st_mtime ^ (st->st_size << 8);
1129 return 0;
1132 static int
1133 statqid(char *path, Qid *qid)
1135 struct stat st;
1137 if (lstat(path, &st) < 0)
1138 return -errno;
1140 return stat2qid(&st, qid);
1143 static int
1144 p9attach(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1146 int n, m;
1147 char *uname, *aname;
1148 u32 nuname;
1149 Fid *fid;
1150 Qid qid;
1151 char ubuf[512];
1152 struct passwd pw, *pwp;
1154 debug("attach tag %d\n", tag);
1155 size -= 7;
1156 if (readrest(conn, size, buf, 1) < 0)
1157 return 0;
1159 if (size < 12)
1160 return badmsg(conn, tag, buf);
1162 fid = fidcreate(conn, gint32(buf));
1163 if (!fid)
1164 return rerror(conn, tag, buf, "cannot allocate fid", EIO);
1166 if (gint32(buf+4) != ~0)
1167 return rerror(conn, tag, buf, "invalid afid", EIO);
1169 n = 8;
1170 if ((m = gstr(buf+n, &uname, size-n)) < 0)
1171 return badmsg(conn, tag, buf);
1173 n += m + 2;
1174 if ((m = gstr(buf+n, &aname, size-n)) < 0)
1175 return rerror(conn, tag, buf, "invalid aname", EIO);
1177 n += m + 2;
1178 if (conn->dotu)
1179 nuname = gint32(buf+n);
1180 else
1181 nuname = ~0;
1183 fid->uid = ~0;
1184 fid->gid = ~0;
1185 if (nuname != ~0) {
1186 fid->uid = nuname;
1187 n = getpwuid_r(nuname, &pw, ubuf, sizeof(ubuf), &pwp);
1188 if (n)
1189 return ruerror(conn, tag, buf, n);
1191 fid->gid = pw.pw_gid;
1192 } else if (uname) {
1193 n = getpwnam_r(uname, &pw, ubuf, sizeof(ubuf), &pwp);
1194 if (n)
1195 return ruerror(conn, tag, buf, n);
1197 fid->uid = pw.pw_uid;
1198 fid->gid = pw.pw_gid;
1201 setuser(fid->uid, fid->gid);
1202 if (aname)
1203 n = strlen(aname) + 1;
1204 else
1205 n = 2;
1207 if (n < sizeof(fid->cpath)) {
1208 fid->path = fid->cpath;
1209 if (aname)
1210 memmove(fid->path, aname, n);
1211 else
1212 fid->path = strdup("/");
1213 } else
1214 fid->path = strdup(aname);
1217 if ((n = statqid(fid->path, &qid)) < 0) {
1218 fiddestroy(conn, fid);
1219 return ruerror(conn, tag, buf, -n);
1222 fid->type = qid.type;
1223 return rattach(conn, tag, buf, &qid);
1226 static int
1227 p9flush(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1229 int i;
1230 u16 oldtag;
1231 Wthread *wt;
1232 Freq *freq;
1234 debug("flush tag %d\n", tag);
1235 size -= 7;
1236 if (readrest(conn, size, buf, 1) < 0)
1237 return 0;
1239 oldtag = gint16(buf);
1240 if (oldtag == tag)
1241 goto respond;
1243 wlock(conn);
1244 for(i = 0; i < conn->nwthreads; i++) {
1245 wt = &conn->wthreads[i];
1246 if (wt->tag == oldtag) {
1247 freq = malloc(sizeof(*freq));
1248 freq->tag = oldtag;
1249 freq->next = wt->freqs;
1250 wt->freqs = freq;
1251 wunlock(conn);
1252 return 0;
1255 wunlock(conn);
1257 respond:
1258 return rflush(conn, tag, buf);
1261 static int
1262 p9walk(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1264 int i, n, m, nwname, slen, olen;
1265 char *path;
1266 Fid *fid, *newfid;
1267 char *wnames[Maxwelem];
1268 u16 wlen[Maxwelem];
1269 Qid wqids[Maxwelem];
1271 debug("walk tag %d\n", tag);
1272 size -= 7;
1273 if (readrest(conn, size, buf, 1) < 0)
1274 return 0;
1276 if (size < 10)
1277 return badmsg(conn, tag, buf);
1279 fid = fidget(conn, gint32(buf));
1280 if (!fid)
1281 return badfid(conn, tag, buf);
1283 setuser(fid->uid, fid->gid);
1284 n = gint32(buf + 4);
1285 if (n != fid->fid) {
1286 newfid = fidcreate(conn, n);
1287 if (!newfid)
1288 return rerror(conn, tag, buf, "fid already exists", EIO);
1289 } else
1290 newfid = fid;
1292 nwname = gint16(buf + 8);
1293 slen = 0;
1294 for(i = 0, n = 10, m = 0; i < nwname; i++) {
1295 wlen[i] = gstr(buf+n, &wnames[i], size-n);
1296 if (wlen[i] < 0)
1297 return badmsg(conn, tag, buf);
1299 n += wlen[i] + 2;
1300 slen += wlen[i] + 1;
1303 olen = strlen(fid->path);
1304 slen += olen + 1;
1305 if (slen >= sizeof(newfid->cpath))
1306 path = malloc(slen);
1307 else
1308 path = newfid->cpath;
1310 n = olen;
1311 memmove(path, fid->path, n+1);
1312 for(i = 0; i < nwname; i++) {
1313 path[n++] = '/';
1314 memmove(&path[n], wnames[i], wlen[i]);
1315 n += wlen[i];
1316 path[n] = '\0';
1317 if (statqid(path, &wqids[i]) < 0)
1318 break;
1321 if (nwname && i<=0) {
1322 if (newfid != fid)
1323 fiddestroy(conn, newfid);
1324 else
1325 path[olen] = '\0';
1327 if (path != newfid->cpath)
1328 free(path);
1330 return ruerror(conn, tag, buf, ENOENT);
1333 if (newfid->path && newfid->path != newfid->cpath)
1334 free(newfid->path);
1336 newfid->path = path;
1337 if (i==0)
1338 newfid->type = fid->type;
1339 else
1340 newfid->type = wqids[i-1].type;
1342 return rwalk(conn, tag, buf, i, wqids);
1346 uflags(u8 mode)
1348 int flags;
1350 flags = 0;
1351 switch (mode & 3) {
1352 case Oexec:
1353 case Oread:
1354 flags = O_RDONLY;
1355 break;
1356 case Owrite:
1357 flags = O_WRONLY;
1358 break;
1359 case Ordwr:
1360 flags = O_RDWR;
1361 break;
1364 if (mode & Otrunc)
1365 flags |= O_TRUNC;
1366 if (mode & Oappend)
1367 flags |= O_APPEND;
1368 if (mode & Oexcl)
1369 flags |= O_EXCL;
1371 return flags;
1374 static int
1375 p9open(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1377 Fid *fid;
1378 Qid qid;
1380 debug("open tag %d\n", tag);
1381 size -= 7;
1382 if (readrest(conn, size, buf, 1) < 0)
1383 return 0;
1385 if (size < 5)
1386 return badmsg(conn, tag, buf);
1388 fid = fidget(conn, gint32(buf));
1389 if (!fid)
1390 return badfid(conn, tag, buf);
1392 setuser(fid->uid, fid->gid);
1393 if (fid->type & Qtdir) {
1394 fid->dir = opendir(fid->path);
1395 if (!fid->dir)
1396 return ruerror(conn, tag, buf, errno);
1397 } else {
1398 fid->fd = open(fid->path, uflags(gint8(buf + 4)));
1399 if (fid->fd < 0)
1400 return ruerror(conn, tag, buf, errno);
1403 if (statqid(fid->path, &qid) < 0)
1404 return ruerror(conn, tag, buf, errno);
1406 return ropen(conn, tag, buf, &qid, 0);
1410 static int
1411 p9create(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1413 u8 omode;
1414 char ctype;
1415 int olen, nlen, n;
1416 int major, minor;
1417 u32 perm;
1418 char *path, *name, *extension, *s;
1419 Fid *fid, *ofid;
1420 Qid qid;
1422 debug("create tag %d\n", tag);
1423 size -= 7;
1424 if (readrest(conn, size, buf, 1) < 0)
1425 return 0;
1427 if (size < 11)
1428 return badmsg(conn, tag, buf);
1430 fid = fidget(conn, gint32(buf));
1431 if (!fid)
1432 return badfid(conn, tag, buf);
1434 setuser(fid->uid, fid->gid);
1435 if (!(fid->type & Qtdir))
1436 return rerror(conn, tag, buf, "not a directory", ENOTDIR);
1438 nlen = gstr(buf+4, &name, size-4);
1439 if (nlen < 0)
1440 return badmsg(conn, tag, buf);
1442 perm = gint32(buf+6+nlen);
1443 omode = gint8(buf+10+nlen);
1444 if (conn->dotu && gstr(buf+11+nlen, &extension, size-8-nlen) < 0)
1445 return badmsg(conn, tag, buf);
1447 olen = strlen(fid->path);
1448 if (olen+nlen+2 < sizeof(fid->cpath))
1449 path = fid->cpath;
1450 else
1451 path = malloc(olen+nlen+2);
1453 memmove(path, fid->path, olen);
1454 path[olen] = '/';
1455 memmove(path + olen + 1, name, nlen + 1);
1457 if (perm & Dmdir) {
1458 if (mkdir(path, perm & 0777) < 0)
1459 goto uerror;
1460 } else if (perm & Dmnamedpipe) {
1461 if (mknod(path, S_IFIFO | (perm&0777), 0) < 0)
1462 goto uerror;
1463 } else if (perm & Dmsymlink) {
1464 if (symlink(extension, path) < 0)
1465 goto uerror;
1467 if (chmod(path, perm&0777) < 0)
1468 goto uerror;
1469 } else if (perm & Dmlink) {
1470 n = strtol(extension, &s, 10);
1471 if (*s != '\0') {
1472 n = rerror(conn, tag, buf, "invalid link", EINVAL);
1473 goto error;
1476 ofid = fidget(conn, n);
1477 if (!ofid) {
1478 n = rerror(conn, tag, buf, "invalid fid", EINVAL);
1479 goto error;
1482 if (link(ofid->path, path) < 0)
1483 goto uerror;
1484 } else if (perm & Dmdevice) {
1485 if (sscanf(extension, "%c %u %u", &ctype, &major, &minor) != 3) {
1486 n = rerror(conn, tag, buf, "invalid format", EINVAL);
1487 goto error;
1490 switch (ctype) {
1491 case 'c':
1492 n = S_IFCHR;
1493 break;
1495 case 'b':
1496 n = S_IFBLK;
1497 break;
1499 default:
1500 n = rerror(conn, tag, buf, "invalid device type", EINVAL);
1501 goto error;
1504 if (mknod(path, n & (perm&0777), 0) < 0)
1505 goto uerror;
1506 } else {
1507 fid->fd = open(path, O_CREAT | uflags(omode), perm&0777);
1508 if (fid->fd < 0)
1509 goto uerror;
1512 if (fid->path != fid->cpath)
1513 free(fid->path);
1515 fid->path = path;
1516 if (statqid(fid->path, &qid) < 0)
1517 return ruerror(conn, tag, buf, errno);
1519 fid->type = qid.type;
1520 return rcreate(conn, tag, buf, &qid, 0);
1522 uerror:
1523 n = ruerror(conn, tag, buf, errno);
1525 error:
1526 if (path != fid->cpath)
1527 free(path);
1528 else
1529 path[olen] = '\0';
1531 return n;
1534 static int
1535 p9readdir(Conn *conn, u16 tag, u8 *buf, Fid *fid, u64 offset, u32 count)
1537 int n, m, plen;
1538 char *path, *dname;
1539 struct dirent *dirent;
1541 if (offset==0) {
1542 rewinddir(fid->dir);
1543 fid->diroffset = 0;
1544 free(fid->direntname);
1545 fid->direntname = NULL;
1548 plen = strlen(fid->path);
1549 path = malloc(plen + NAME_MAX + 3);
1550 memmove(path, fid->path, plen);
1551 path[plen] = '/';
1552 n = 0;
1553 dname = fid->direntname;
1554 while (n < count) {
1555 if (!dname) {
1556 dirent = readdir(fid->dir);
1557 if (!dirent)
1558 break;
1560 if (strcmp(dirent->d_name, ".") == 0 ||
1561 strcmp(dirent->d_name, "..") == 0)
1562 continue;
1564 dname = dirent->d_name;
1567 strcpy(&path[plen + 1], dname);
1568 m = pstat(path, buf + n + 11, conn->dotu, count + 11 - n);
1569 if (m < 0) {
1570 if (n==0) {
1571 m = errno;
1572 if (m==0)
1573 m = EIO;
1574 return ruerror(conn, tag, buf, m);
1577 break;
1580 n += m;
1581 dname = NULL;
1584 free(fid->direntname);
1585 if (dname)
1586 fid->direntname = strdup(dname);
1588 pint32(buf, 11 + n);
1589 pint8(buf+4, Rread);
1590 pint16(buf+5, tag);
1591 pint32(buf+7, n);
1593 return 11 + n;
1596 static int
1597 p9read(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1599 int n, m;
1600 u32 count;
1601 u64 offset;
1602 off_t eoff;
1603 Fid *fid;
1604 struct msghdr mhdr;
1605 struct iovec iov;
1607 debug("read tag %d\n", tag);
1608 size -= 7;
1609 if (readrest(conn, size, buf, 1) < 0)
1610 return 0;
1612 if (size < 16)
1613 return badmsg(conn, tag, buf);
1615 fid = fidget(conn, gint32(buf));
1616 if (!fid)
1617 return badfid(conn, tag, buf);
1619 setuser(fid->uid, fid->gid);
1620 offset = gint64(buf+4);
1621 count = gint32(buf+12);
1623 if (fid->type & Qtdir)
1624 return p9readdir(conn, tag, buf, fid, offset, count);
1627 mhdr.msg_name = NULL;
1628 mhdr.msg_namelen = 0;
1629 mhdr.msg_iov = &iov;
1630 mhdr.msg_iovlen = 0;
1631 mhdr.msg_control = NULL;
1632 mhdr.msg_controllen = 0;
1633 mhdr.msg_flags = MSG_MORE;
1634 iov.iov_base = buf;
1635 iov.iov_len = 11;
1636 while (iov.iov_len > 0) {
1637 n = sendmsg(conn->sock, &mhdr, MSG_MORE);
1638 if (n < 0) {
1639 fprintf(stderr, "ERROR %d\n", errno);
1640 wunlock(conn);
1641 return 0;
1644 iov.iov_base += n;
1645 iov.iov_len -= n;
1649 #ifndef X
1650 n = 0;
1651 while (n < count) {
1652 m = pread(fid->fd, buf+11+n, count-n, offset+n);
1653 if (m < 0)
1654 return ruerror(conn, tag, buf, errno);
1655 else if (m == 0)
1656 break;
1658 n += m;
1661 pint32(buf, 11+n);
1662 pint8(buf+4, Rread);
1663 pint16(buf+5, tag);
1664 pint32(buf+7, n);
1666 return 11+n;
1667 #else
1668 wlock(conn);
1669 eoff = lseek(fid->fd, 0, SEEK_END);
1670 if (eoff-offset < count)
1671 count = eoff - offset;
1673 pint32(buf, 11 + count);
1674 pint8(buf+4, Rread);
1675 pint16(buf+5, tag);
1676 pint32(buf+7, count);
1677 n = writen(conn, buf, 11);
1678 if (n < 0) {
1679 wunlock(conn);
1680 return 0;
1683 eoff = offset;
1684 while (count) {
1685 n = sendfile(conn->sock, fid->fd, &eoff, count);
1686 if (n < 0) {
1687 if (errno==EAGAIN || errno==EINTR)
1688 continue;
1690 // TODO: that's not right
1691 return ruerror(conn, tag, buf, errno);
1692 } else if (n == 0)
1693 break;
1695 count -= n;
1697 wunlock(conn);
1700 return 0;
1701 #endif
1704 static int
1705 p9write(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1707 int i, n, m, c;
1708 u32 count;
1709 u64 offset;
1710 Fid *fid;
1712 debug("write tag %d\n", tag);
1713 size -= 7;
1714 if (size < 16)
1715 return badmsg(conn, tag, buf);
1717 #ifdef XY
1718 if (readrest(conn, 16, buf, 0) < 0) {
1719 #else
1720 if (readrest(conn, size, buf, 1) < 0) {
1721 #endif
1722 runlock(conn);
1723 return 0;
1726 fid = fidget(conn, gint32(buf));
1727 if (!fid) {
1728 runlock(conn);
1729 return badfid(conn, tag, buf);
1732 setuser(fid->uid, fid->gid);
1733 offset = gint64(buf+4);
1734 count = gint32(buf+12);
1736 if (fid->type & Qtdir) {
1737 readrest(conn, size - 16, buf, 1);
1738 return rerror(conn, tag, buf, "permission denied", EPERM);
1741 #ifdef XY
1742 c = count;
1743 if (conn->bpos) {
1744 n = conn->bpos;
1745 if (count < n)
1746 n = count;
1748 i = 0;
1749 while (i < n) {
1750 m = pwrite(fid->fd, conn->buf + i, n - i, offset + i);
1751 if (m < 0)
1752 return ruerror(conn, tag, buf, errno);
1753 else if (m == 0)
1754 goto error;
1757 if (conn->bpos > count) {
1758 memmove(conn->buf, conn->buf + count, conn->bpos - count);
1759 conn->bpos -= count;
1762 offset += n;
1763 count -= n;
1766 while (count > 0) {
1767 n = splice(conn->sock, NULL, conn->pip[1], NULL, count, 0);
1768 if (n < 0)
1769 goto error;
1771 m = splice(conn->pip[0], NULL, fid->fd, (off_t *) &offset, n, 0);
1772 if (m < 0)
1773 goto error;
1775 if (m != n)
1776 goto error;
1778 count -= n;
1781 runlock(conn);
1782 #else
1783 c = count;
1784 n = 0;
1785 while (n < count) {
1786 m = pwrite(fid->fd, buf+4+n, count-n, offset+n);
1787 if (m < 0)
1788 return ruerror(conn, tag, buf, errno);
1789 else if (m == 0)
1790 goto error;
1792 n += m;
1795 return rwrite(conn, tag, buf, c);
1796 #endif
1798 error:
1799 fprintf(stderr, "*** splice error\n");
1800 conndisconnect(conn);
1801 return 0;
1805 static int
1806 p9clunk(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1808 Fid *fid;
1810 debug("clunk tag %d\n", tag);
1811 size -= 7;
1812 if (size < 4)
1813 return badmsg(conn, tag, buf);
1815 if (readrest(conn, size, buf, 1) < 0)
1816 return 0;
1818 fid = fidget(conn, gint32(buf));
1819 if (!fid) {
1820 runlock(conn);
1821 return badfid(conn, tag, buf);
1824 setuser(fid->uid, fid->gid);
1825 if (fid->fd)
1826 close(fid->fd);
1828 if (fid->dir) {
1829 closedir(fid->dir);
1832 if (fid->path != fid->cpath)
1833 free(fid->path);
1835 free(fid->direntname);
1836 fiddestroy(conn, fid);
1838 return rclunk(conn, tag, buf);
1842 static int
1843 p9remove(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1845 Fid *fid;
1847 debug("remove tag %d\n", tag);
1848 size -= 7;
1849 if (size < 4)
1850 return badmsg(conn, tag, buf);
1852 if (readrest(conn, size, buf, 1) < 0)
1853 return 0;
1855 fid = fidget(conn, gint32(buf));
1856 if (!fid) {
1857 runlock(conn);
1858 return badfid(conn, tag, buf);
1861 setuser(fid->uid, fid->gid);
1862 if (fid->type&Qtdir) {
1863 if (rmdir(fid->path) < 0)
1864 return ruerror(conn, tag, buf, errno);
1865 } else {
1866 if (unlink(fid->path) < 0)
1867 return ruerror(conn, tag, buf, errno);
1870 if (fid->fd)
1871 close(fid->fd);
1873 if (fid->path != fid->cpath)
1874 free(fid->path);
1876 free(fid->direntname);
1877 fiddestroy(conn, fid);
1878 return rremove(conn, tag, buf);
1882 static int
1883 p9stat(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1885 Fid *fid;
1887 debug("stat tag %d\n", tag);
1888 size -= 7;
1889 if (size < 4)
1890 return badmsg(conn, tag, buf);
1892 if (readrest(conn, size, buf, 1) < 0)
1893 return 0;
1895 fid = fidget(conn, gint32(buf));
1896 if (!fid) {
1897 runlock(conn);
1898 return badfid(conn, tag, buf);
1901 setuser(fid->uid, fid->gid);
1902 return rstat(conn, tag, buf, fid->path);
1906 static int
1907 p9wstat(Conn *conn, u8 type, u16 tag, u32 size, u8 *buf)
1909 int n, nlen, pos, glen;
1910 u32 mode, mtime, ngid;
1911 u64 length;
1912 char *name, *gid, *p, *npath, ubuf[512];
1913 Fid *fid;
1914 struct group grp, *pgrp;
1915 struct utimbuf tb;
1917 debug("wstat tag %d\n", tag);
1918 size -= 7;
1919 if (size < 53)
1920 return badmsg(conn, tag, buf);
1922 if (conn->dotu && size<67)
1923 return badmsg(conn, tag, buf);
1925 if (readrest(conn, size, buf, 1) < 0)
1926 return 0;
1928 fid = fidget(conn, gint32(buf));
1929 if (!fid) {
1930 runlock(conn);
1931 return badfid(conn, tag, buf);
1934 setuser(fid->uid, fid->gid);
1935 mode = gint32(buf+27);
1936 mtime = gint32(buf+35);
1937 length = gint64(buf+39);
1938 nlen = gstr(buf+47, &name, size-47);
1939 if (nlen<0)
1940 return badmsg(conn, tag, buf);
1942 pos = 49 + nlen;
1943 pos += gint16(buf+pos) + 2;
1944 if (pos >= size)
1945 return badmsg(conn, tag, buf);
1947 glen = gstr(buf+pos, &gid, size-pos);
1948 if (glen<0)
1949 return badmsg(conn, tag, buf);
1951 pos += glen + 2;
1952 pos += gint16(buf+pos) + 2;
1953 if (pos >= size)
1954 return badmsg(conn, tag, buf);
1956 ngid = ~0;
1957 if (conn->dotu) {
1958 pos += gint16(buf+pos) + 2;
1959 if (pos >= size)
1960 return badmsg(conn, tag, buf);
1962 ngid = gint32(buf+pos+4);
1965 if (ngid==~0 && gid) {
1966 n = getgrnam_r(gid, &grp, ubuf, sizeof(ubuf), &pgrp);
1967 if (n)
1968 return ruerror(conn, tag, buf, n);
1970 ngid = grp.gr_gid;
1973 if (mode != ~0) {
1974 if (chmod(fid->path, mode&0777) < 0)
1975 return ruerror(conn, tag, buf, errno);
1977 if (mtime != ~0) {
1978 tb.actime = 0;
1979 tb.modtime = mtime;
1980 if (utime(fid->path, &tb) < 0)
1981 return ruerror(conn, tag, buf, errno);
1983 if (ngid != ~0) {
1984 if (chown(fid->path, -1, ngid) < 0)
1985 return ruerror(conn, tag, buf, errno);
1987 if (name) {
1988 p = strrchr(fid->path, '/');
1989 if (!p)
1990 p = fid->path + strlen(fid->path);
1992 nlen = strlen(name);
1993 npath = malloc(nlen + (p - fid->path) + 2);
1994 memmove(npath, fid->path, p - fid->path);
1995 npath[p - fid->path] = '/';
1996 memmove(npath + (p - fid->path) + 1, name, nlen);
1997 npath[(p - fid->path) + 1 + nlen] = 0;
1998 if (strcmp(npath, fid->path) != 0) {
1999 if (rename(fid->path, npath) < 0) {
2000 free(npath);
2001 return ruerror(conn, tag, buf, errno);
2004 if (fid->path != fid->cpath)
2005 free(fid->path);
2007 fid->path = npath;
2008 } else
2009 free(npath);
2011 if (length != ~0) {
2012 if (truncate(fid->path, length) < 0)
2013 return ruerror(conn, tag, buf, errno);
2016 return rwstat(conn, tag, buf);
2019 void
2020 usage()
2022 fprintf(stderr, "npfs: -d -s -p port -w nthreads\n");
2023 exit(-1);
2027 main(int argc, char *argv[])
2029 int c, csock, sock;
2030 socklen_t n;
2031 int port, nwthreads;
2032 char *s;
2033 struct sockaddr_in saddr;
2034 Conn *conn;
2036 port = 564;
2037 nwthreads = 16;
2038 msize = 8216;
2039 while ((c = getopt(argc, argv, "dsp:w:m:")) != -1) {
2040 switch (c) {
2041 case 'd':
2042 debuglevel = 1;
2043 break;
2045 case 'p':
2046 port = strtol(optarg, &s, 10);
2047 if (*s != '\0')
2048 usage();
2049 break;
2051 case 'w':
2052 nwthreads = strtol(optarg, &s, 10);
2053 if (*s != '\0')
2054 usage();
2055 break;
2057 case 's':
2058 sameuser = 1;
2059 break;
2061 case 'm':
2062 msize = strtol(optarg, &s, 10);
2063 if (*s != '\0')
2064 usage();
2065 break;
2067 default:
2068 usage();
2072 sock = socket(PF_INET, SOCK_STREAM, 0);
2073 if (sock < 0) {
2074 perror("socket");
2075 return -1;
2078 saddr.sin_family = AF_INET;
2079 saddr.sin_port = htons(port);
2080 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
2081 if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
2082 perror("bind");
2083 return -1;
2086 if (listen(sock, 1) < 0) {
2087 perror("listen");
2088 return -1;
2091 n = sizeof(saddr);
2092 while ((csock = accept(sock, &saddr, &n)) >= 0) {
2093 conn = conncreate(csock, nwthreads);
2096 return 0;