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
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
33 #include <sys/types.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>
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
;
115 Dmappend
= 0x40000000,
117 Dmmount
= 0x10000000,
120 Dmsymlink
= 0x02000000,
123 /* 9P2000.u extensions */
124 Dmdevice
= 0x00800000,
125 Dmnamedpipe
= 0x00200000,
126 Dmsocket
= 0x00100000,
127 Dmsetuid
= 0x00080000,
128 Dmsetgid
= 0x00040000,
160 pthread_mutex_t rlock
;
165 /* data for the next message (if size not ~0) */
172 /* used to write to file */
178 Fid fidtbl
[Fidtblsz
];
179 Fid
*fidhtbl
[Fidhtblsz
];
180 pthread_mutex_t wlock
;
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;
225 static int sameuser
= 0;
227 static int (*fhndlrs
[])(Conn
*, u8
, u16
, u32
, u8
*) = {
248 cmpxchg(int *ptr
, int old
, int new)
252 asm volatile("lock cmpxchgl %k1,%2"
254 : "r"(new), "m"(*ptr
), "0"(old
)
261 xchg(int *ptr
, int x
)
263 asm volatile("lock xchgl %k0,%1"
265 : "m" (*ptr
), "0" (x
)
277 asm volatile("lock xaddl %0, %1"
278 : "+r" (i
), "+m" (*ptr
)
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
);
295 if ((n
= cmpxchg(val
, 0, 1)) == 0)
298 while (xchg(val
, 2) != 0)
299 futex(val
, FUTEX_WAIT
, 2, NULL
, NULL
, 0);
307 if ((n
= dec(val
)) != 1) {
309 futex(val
, FUTEX_WAKE
, 1, NULL
, NULL
, 0);
314 debug(char *fmt
, ...)
320 vfprintf(stderr
, fmt
, ap
);
327 flock(&conn
->rfutex
);
328 // pthread_mutex_lock(&conn->rlock);
334 fulock(&conn
->rfutex
);
335 // pthread_mutex_unlock(&conn->rlock);
341 flock(&conn
->wfutex
);
342 // pthread_mutex_lock(&conn->wlock);
348 fulock(&conn
->wfutex
);
349 // pthread_mutex_unlock(&conn->wlock);
353 pint8(u8
*data
, u8 val
)
360 pint16(u8
*data
, u16 val
)
368 pint32(u8
*data
, u32 val
)
378 pint64(u8
*data
, u64 val
)
392 pstr(u8
*data
, u16 sz
, char *val
)
396 memmove(data
+2, val
, sz
);
402 pstat(char *path
, u8
*data
, int dotu
, int maxsz
)
404 int n
, sz
, nsz
, usz
, gsz
, msz
, esz
;
408 char ext
[256], ubuf
[256], gbuf
[256], *name
;
409 struct passwd pw
, *pwp
;
410 struct group grp
, *pgrp
;
413 if (lstat(path
, &st
) < 0)
416 name
= strrchr(path
, '/');
423 if (S_ISDIR(st
.st_mode
))
428 if (S_ISLNK(st
.st_mode
)) {
430 n
= readlink(path
, ext
, sizeof(ext
) - 1);
435 if (S_ISSOCK(st
.st_mode
))
437 if (S_ISFIFO(st
.st_mode
))
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
));
446 if (st
.st_mode
& S_ISUID
)
448 if (st
.st_mode
& S_ISGID
)
452 mode
|= st
.st_mode
& 0777;
462 if (getpwuid_r(st
.st_uid
, &pw
, ubuf
, sizeof(ubuf
), &pwp
))
465 usz
= strlen(pw
.pw_name
);
466 if (getgrgid_r(st
.st_gid
, &grp
, gbuf
, sizeof(gbuf
), &pgrp
))
469 gsz
= strlen(grp
.gr_name
);
473 sz
= 2+4+13+4+4+4+8+2+2+2+2+nsz
+usz
+gsz
+msz
+esz
;
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);
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
);
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
);
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);
521 return data
[0] | (data
[1]<<8);
527 return data
[0] | (data
[1]<<8) | (data
[2]<<16) | (data
[3]<<24);
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);
539 gstr(u8
*data
, char **s
, int maxsize
)
548 memmove(data
, data
+ 2, n
);
558 fidget(Conn
*conn
, u32 fid
)
563 if (fid
< Fidtblsz
) {
564 f
= &conn
->fidtbl
[fid
];
571 hash
= fid
% Fidhtblsz
;
572 for(f
= conn
->fidhtbl
[hash
]; f
!= NULL
; f
= f
->next
)
580 fidcreate(Conn
*conn
, u32 fid
)
585 if (fid
< Fidtblsz
) {
586 f
= &conn
->fidtbl
[fid
];
594 f
= calloc(1, sizeof(Fid
));
595 hash
= fid
% Fidhtblsz
;
596 if (!conn
->fidhtbl
[hash
])
597 conn
->fidhtbl
[hash
] = f
;
599 for(p
= conn
->fidhtbl
[hash
]; p
->next
!= NULL
; p
= p
->next
)
609 fiddestroy(Conn
*conn
, Fid
*f
)
614 if (f
->fid
< Fidtblsz
) {
615 memset(f
, 0, sizeof(*f
));
620 hash
= f
->fid
% Fidhtblsz
;
621 if (f
== conn
->fidhtbl
[hash
])
622 conn
->fidhtbl
[hash
] = f
->next
;
624 for(p
= conn
->fidhtbl
[hash
]; p
->next
!= NULL
; p
= p
->next
)
635 conncreate(int sock
, int nwthreads
)
640 conn
= calloc(1, sizeof(*conn
) + nwthreads
*sizeof(Wthread
));
642 // pthread_mutex_init(&conn->rlock, NULL);
643 // pthread_mutex_init(&conn->wlock, NULL);
649 for(i
= 0; i
< Fidtblsz
; i
++)
650 conn
->fidtbl
[i
].fid
= ~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) {
666 if (pthread_create(&conn
->wthreads
[i
].tid
, NULL
, connproc
, &conn
->wthreads
[i
]) < 0) {
678 conndestroy(Conn
*conn
)
688 for(i
= 0; i
< conn
->nwthreads
; i
++)
689 pthread_join(conn
->wthreads
[i
].tid
, &v
);
695 conndisconnect(Conn
*conn
)
715 buf
= malloc(conn
->msize
+ sizeof(conn
->buf
));
718 if (conn
->sock
< 0) {
723 if (conn
->size
== ~0) {
725 n
= read(conn
->sock
, conn
->buf
+ conn
->bpos
,
726 sizeof(conn
->buf
) - conn
->bpos
);
729 if (n
<0 && (errno
==EAGAIN
|| errno
==EINTR
))
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);
749 assert(size
<= conn
->msize
);
751 if (type
&1 || type
<Tfirst
|| type
>Tlast
|| !fhndlrs
[(type
-Tfirst
)/2])
754 assert(wt
->tag
==(u16
)~0 && wt
->freqs
==NULL
);
757 n
= (*fhndlrs
[(type
-Tfirst
)/2])(conn
, type
, tag
, size
, buf
);
760 writen(conn
, buf
, n
);
763 while (freq
!= NULL
) {
764 n
= rflush(conn
, tag
, buf
);
765 writen(conn
, buf
, n
);
777 conndisconnect(conn
);
784 writen(Conn
*conn
, u8
*buf
, int buflen
)
791 n
= write(conn
->sock
, buf
+ pos
, buflen
- pos
);
793 if (n
<0 && (errno
==EAGAIN
|| errno
==EINTR
))
796 conndisconnect(conn
);
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 */
810 readrest(Conn
*conn
, u32 size
, u8
*buf
, int unlock
)
818 /* first get data from conn->buf, if there is any */
821 // debug("%%%% move sz %d bpos %d\n", sz, conn->bpos);
825 memmove(p
, conn
->buf
+ 7, n
);
828 if (n
< conn
->bpos
-7)
829 memmove(conn
->buf
, conn
->buf
+ 7 + n
, conn
->bpos
- 7 - n
);
835 // debug("%%%% read sz %d\n", sz);
836 n
= read(conn
->sock
, p
, sz
+ (unlock
?sizeof(conn
->buf
):0));
838 if (n
<0 && (errno
==EAGAIN
|| errno
==EINTR
))
848 /* now we have the whole message in buf, may be some data for the next */
850 // debug("%%%% move2 sz %d bpos %d\n", sz, conn->bpos);
851 memmove(conn
->buf
+ conn
->bpos
, buf
+ size
, -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);
867 fprintf(stderr
, "readrest error %d\n", errno
);
868 conndisconnect(conn
);
875 rerror(Conn
*conn
, u16 tag
, u8
*buf
, char *ename
, int ecode
)
879 slen
= strlen(ename
);
885 pint8(buf
+ 4, Rerror
);
886 pint16(buf
+ 5, tag
);
887 pint16(buf
+ 7, slen
);
888 memmove(buf
+9, ename
, slen
);
890 pint32(buf
+ 9 + slen
, ecode
);
896 ruerror(Conn
*conn
, u16 tag
, u8
*buf
, int ecode
)
900 strerror_r(ecode
, ename
, sizeof(ename
));
901 return rerror(conn
, tag
, buf
, ename
, ecode
);
905 badmsg(Conn
*conn
, u16 tag
, u8
*buf
)
907 fprintf(stderr
, "bad message\n");
908 return rerror(conn
, tag
, buf
, "invalid message", EINVAL
);
912 badfid(Conn
*conn
, u16 tag
, u8
*buf
)
914 return rerror(conn
, tag
, buf
, "invalid fid", EINVAL
);
918 rversion(Conn
*conn
, u16 tag
, u8
*buf
, char *version
, int msize
)
922 slen
= strlen(version
);
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
);
934 rflush(Conn
*conn
, u16 tag
, u8
*buf
)
937 pint8(buf
+ 4, Rflush
);
938 pint16(buf
+ 5, tag
);
943 rattach(Conn
*conn
, u16 tag
, u8
*buf
, Qid
*qid
)
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
);
955 rwalk(Conn
*conn
, u16 tag
, u8
*buf
, u16 nwqid
, Qid
*wqid
)
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
);
973 ropen(Conn
*conn
, u16 tag
, u8
*buf
, Qid
*qid
, u32 iounit
)
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
);
986 rcreate(Conn
*conn
, u16 tag
, u8
*buf
, Qid
*qid
, u32 iounit
)
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
);
999 rwrite(Conn
*conn
, u16 tag
, u8
*buf
, u32 count
)
1002 pint8(buf
+ 4, Rwrite
);
1003 pint16(buf
+ 5, tag
);
1004 pint32(buf
+ 7, count
);
1009 rclunk(Conn
*conn
, u16 tag
, u8
*buf
)
1012 pint8(buf
+ 4, Rclunk
);
1013 pint16(buf
+ 5, tag
);
1018 rremove(Conn
*conn
, u16 tag
, u8
*buf
)
1021 pint8(buf
+ 4, Rremove
);
1022 pint16(buf
+ 5, tag
);
1027 rstat(Conn
*conn
, u16 tag
, u8
*buf
, char *path
)
1031 pint8(buf
+ 4, Rstat
);
1032 pint16(buf
+ 5, tag
);
1033 sz
= pstat(path
, buf
+ 9, conn
->dotu
, conn
->msize
- 9);
1035 return rerror(conn
, tag
, buf
, "insufficient msize", EIO
);
1038 pint16(buf
+ 7, sz
);
1039 pint32(buf
, 7 + sz
+ 2);
1044 rwstat(Conn
*conn
, u16 tag
, u8
*buf
)
1047 pint8(buf
+ 4, Rwstat
);
1048 pint16(buf
+ 5, tag
);
1053 setuser(uid_t uid
, gid_t gid
)
1058 syscall(SYS_setreuid
, -1, uid
);
1059 syscall(SYS_setregid
, -1, gid
);
1063 p9version(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1068 debug("version tag %d\n", tag
);
1070 if (readrest(conn
, size
, buf
, 1) < 0)
1074 return badmsg(conn
, tag
, buf
);
1076 msize
= gint32(buf
);
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);
1088 if (dotu
&& strcmp(version
, "9P2000.u")==0)
1089 version
= "9P2000.u";
1095 return rversion(conn
, tag
, buf
, version
, conn
->msize
);
1100 p9auth(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1102 debug("auth tag %d\n", tag
);
1104 if (readrest(conn
, size
, buf
, 1) < 0)
1107 return rerror(conn
, tag
, buf
, "authentication not required", EIO
);
1111 stat2qid(struct stat
*st
, Qid
*qid
)
1116 if (S_ISDIR(st
->st_mode
))
1119 if (S_ISLNK(st
->st_mode
))
1120 qid
->type
|= Qtsymlink
;
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);
1133 statqid(char *path
, Qid
*qid
)
1137 if (lstat(path
, &st
) < 0)
1140 return stat2qid(&st
, qid
);
1144 p9attach(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1147 char *uname
, *aname
;
1152 struct passwd pw
, *pwp
;
1154 debug("attach tag %d\n", tag
);
1156 if (readrest(conn
, size
, buf
, 1) < 0)
1160 return badmsg(conn
, tag
, buf
);
1162 fid
= fidcreate(conn
, gint32(buf
));
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
);
1170 if ((m
= gstr(buf
+n
, &uname
, size
-n
)) < 0)
1171 return badmsg(conn
, tag
, buf
);
1174 if ((m
= gstr(buf
+n
, &aname
, size
-n
)) < 0)
1175 return rerror(conn
, tag
, buf
, "invalid aname", EIO
);
1179 nuname
= gint32(buf
+n
);
1187 n
= getpwuid_r(nuname
, &pw
, ubuf
, sizeof(ubuf
), &pwp
);
1189 return ruerror(conn
, tag
, buf
, n
);
1191 fid
->gid
= pw
.pw_gid
;
1193 n
= getpwnam_r(uname
, &pw
, ubuf
, sizeof(ubuf
), &pwp
);
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
);
1203 n
= strlen(aname
) + 1;
1207 if (n
< sizeof(fid
->cpath
)) {
1208 fid
->path
= fid
->cpath
;
1210 memmove(fid
->path
, aname
, n
);
1212 fid
->path
= strdup("/");
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
);
1227 p9flush(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1234 debug("flush tag %d\n", tag
);
1236 if (readrest(conn
, size
, buf
, 1) < 0)
1239 oldtag
= gint16(buf
);
1244 for(i
= 0; i
< conn
->nwthreads
; i
++) {
1245 wt
= &conn
->wthreads
[i
];
1246 if (wt
->tag
== oldtag
) {
1247 freq
= malloc(sizeof(*freq
));
1249 freq
->next
= wt
->freqs
;
1258 return rflush(conn
, tag
, buf
);
1262 p9walk(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1264 int i
, n
, m
, nwname
, slen
, olen
;
1267 char *wnames
[Maxwelem
];
1269 Qid wqids
[Maxwelem
];
1271 debug("walk tag %d\n", tag
);
1273 if (readrest(conn
, size
, buf
, 1) < 0)
1277 return badmsg(conn
, tag
, buf
);
1279 fid
= fidget(conn
, gint32(buf
));
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
);
1288 return rerror(conn
, tag
, buf
, "fid already exists", EIO
);
1292 nwname
= gint16(buf
+ 8);
1294 for(i
= 0, n
= 10, m
= 0; i
< nwname
; i
++) {
1295 wlen
[i
] = gstr(buf
+n
, &wnames
[i
], size
-n
);
1297 return badmsg(conn
, tag
, buf
);
1300 slen
+= wlen
[i
] + 1;
1303 olen
= strlen(fid
->path
);
1305 if (slen
>= sizeof(newfid
->cpath
))
1306 path
= malloc(slen
);
1308 path
= newfid
->cpath
;
1311 memmove(path
, fid
->path
, n
+1);
1312 for(i
= 0; i
< nwname
; i
++) {
1314 memmove(&path
[n
], wnames
[i
], wlen
[i
]);
1317 if (statqid(path
, &wqids
[i
]) < 0)
1321 if (nwname
&& i
<=0) {
1323 fiddestroy(conn
, newfid
);
1327 if (path
!= newfid
->cpath
)
1330 return ruerror(conn
, tag
, buf
, ENOENT
);
1333 if (newfid
->path
&& newfid
->path
!= newfid
->cpath
)
1336 newfid
->path
= path
;
1338 newfid
->type
= fid
->type
;
1340 newfid
->type
= wqids
[i
-1].type
;
1342 return rwalk(conn
, tag
, buf
, i
, wqids
);
1375 p9open(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1380 debug("open tag %d\n", tag
);
1382 if (readrest(conn
, size
, buf
, 1) < 0)
1386 return badmsg(conn
, tag
, buf
);
1388 fid
= fidget(conn
, gint32(buf
));
1390 return badfid(conn
, tag
, buf
);
1392 setuser(fid
->uid
, fid
->gid
);
1393 if (fid
->type
& Qtdir
) {
1394 fid
->dir
= opendir(fid
->path
);
1396 return ruerror(conn
, tag
, buf
, errno
);
1398 fid
->fd
= open(fid
->path
, uflags(gint8(buf
+ 4)));
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);
1411 p9create(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1418 char *path
, *name
, *extension
, *s
;
1422 debug("create tag %d\n", tag
);
1424 if (readrest(conn
, size
, buf
, 1) < 0)
1428 return badmsg(conn
, tag
, buf
);
1430 fid
= fidget(conn
, gint32(buf
));
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);
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
))
1451 path
= malloc(olen
+nlen
+2);
1453 memmove(path
, fid
->path
, olen
);
1455 memmove(path
+ olen
+ 1, name
, nlen
+ 1);
1458 if (mkdir(path
, perm
& 0777) < 0)
1460 } else if (perm
& Dmnamedpipe
) {
1461 if (mknod(path
, S_IFIFO
| (perm
&0777), 0) < 0)
1463 } else if (perm
& Dmsymlink
) {
1464 if (symlink(extension
, path
) < 0)
1467 if (chmod(path
, perm
&0777) < 0)
1469 } else if (perm
& Dmlink
) {
1470 n
= strtol(extension
, &s
, 10);
1472 n
= rerror(conn
, tag
, buf
, "invalid link", EINVAL
);
1476 ofid
= fidget(conn
, n
);
1478 n
= rerror(conn
, tag
, buf
, "invalid fid", EINVAL
);
1482 if (link(ofid
->path
, path
) < 0)
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
);
1500 n
= rerror(conn
, tag
, buf
, "invalid device type", EINVAL
);
1504 if (mknod(path
, n
& (perm
&0777), 0) < 0)
1507 fid
->fd
= open(path
, O_CREAT
| uflags(omode
), perm
&0777);
1512 if (fid
->path
!= fid
->cpath
)
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);
1523 n
= ruerror(conn
, tag
, buf
, errno
);
1526 if (path
!= fid
->cpath
)
1535 p9readdir(Conn
*conn
, u16 tag
, u8
*buf
, Fid
*fid
, u64 offset
, u32 count
)
1539 struct dirent
*dirent
;
1542 rewinddir(fid
->dir
);
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
);
1553 dname
= fid
->direntname
;
1556 dirent
= readdir(fid
->dir
);
1560 if (strcmp(dirent
->d_name
, ".") == 0 ||
1561 strcmp(dirent
->d_name
, "..") == 0)
1564 dname
= dirent
->d_name
;
1567 strcpy(&path
[plen
+ 1], dname
);
1568 m
= pstat(path
, buf
+ n
+ 11, conn
->dotu
, count
+ 11 - n
);
1574 return ruerror(conn
, tag
, buf
, m
);
1584 free(fid
->direntname
);
1586 fid
->direntname
= strdup(dname
);
1588 pint32(buf
, 11 + n
);
1589 pint8(buf
+4, Rread
);
1597 p9read(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1607 debug("read tag %d\n", tag
);
1609 if (readrest(conn
, size
, buf
, 1) < 0)
1613 return badmsg(conn
, tag
, buf
);
1615 fid
= fidget(conn
, gint32(buf
));
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;
1636 while (iov.iov_len > 0) {
1637 n = sendmsg(conn->sock, &mhdr, MSG_MORE);
1639 fprintf(stderr, "ERROR %d\n", errno);
1652 m
= pread(fid
->fd
, buf
+11+n
, count
-n
, offset
+n
);
1654 return ruerror(conn
, tag
, buf
, errno
);
1662 pint8(buf
+4, Rread
);
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
);
1676 pint32(buf
+7, count
);
1677 n
= writen(conn
, buf
, 11);
1685 n
= sendfile(conn
->sock
, fid
->fd
, &eoff
, count
);
1687 if (errno
==EAGAIN
|| errno
==EINTR
)
1690 // TODO: that's not right
1691 return ruerror(conn
, tag
, buf
, errno
);
1705 p9write(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1712 debug("write tag %d\n", tag
);
1715 return badmsg(conn
, tag
, buf
);
1718 if (readrest(conn
, 16, buf
, 0) < 0) {
1720 if (readrest(conn
, size
, buf
, 1) < 0) {
1726 fid
= fidget(conn
, gint32(buf
));
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
);
1750 m
= pwrite(fid
->fd
, conn
->buf
+ i
, n
- i
, offset
+ i
);
1752 return ruerror(conn
, tag
, buf
, errno
);
1757 if (conn
->bpos
> count
) {
1758 memmove(conn
->buf
, conn
->buf
+ count
, conn
->bpos
- count
);
1759 conn
->bpos
-= count
;
1767 n
= splice(conn
->sock
, NULL
, conn
->pip
[1], NULL
, count
, 0);
1771 m
= splice(conn
->pip
[0], NULL
, fid
->fd
, (off_t
*) &offset
, n
, 0);
1786 m
= pwrite(fid
->fd
, buf
+4+n
, count
-n
, offset
+n
);
1788 return ruerror(conn
, tag
, buf
, errno
);
1795 return rwrite(conn
, tag
, buf
, c
);
1799 fprintf(stderr
, "*** splice error\n");
1800 conndisconnect(conn
);
1806 p9clunk(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1810 debug("clunk tag %d\n", tag
);
1813 return badmsg(conn
, tag
, buf
);
1815 if (readrest(conn
, size
, buf
, 1) < 0)
1818 fid
= fidget(conn
, gint32(buf
));
1821 return badfid(conn
, tag
, buf
);
1824 setuser(fid
->uid
, fid
->gid
);
1832 if (fid
->path
!= fid
->cpath
)
1835 free(fid
->direntname
);
1836 fiddestroy(conn
, fid
);
1838 return rclunk(conn
, tag
, buf
);
1843 p9remove(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1847 debug("remove tag %d\n", tag
);
1850 return badmsg(conn
, tag
, buf
);
1852 if (readrest(conn
, size
, buf
, 1) < 0)
1855 fid
= fidget(conn
, gint32(buf
));
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
);
1866 if (unlink(fid
->path
) < 0)
1867 return ruerror(conn
, tag
, buf
, errno
);
1873 if (fid
->path
!= fid
->cpath
)
1876 free(fid
->direntname
);
1877 fiddestroy(conn
, fid
);
1878 return rremove(conn
, tag
, buf
);
1883 p9stat(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1887 debug("stat tag %d\n", tag
);
1890 return badmsg(conn
, tag
, buf
);
1892 if (readrest(conn
, size
, buf
, 1) < 0)
1895 fid
= fidget(conn
, gint32(buf
));
1898 return badfid(conn
, tag
, buf
);
1901 setuser(fid
->uid
, fid
->gid
);
1902 return rstat(conn
, tag
, buf
, fid
->path
);
1907 p9wstat(Conn
*conn
, u8 type
, u16 tag
, u32 size
, u8
*buf
)
1909 int n
, nlen
, pos
, glen
;
1910 u32 mode
, mtime
, ngid
;
1912 char *name
, *gid
, *p
, *npath
, ubuf
[512];
1914 struct group grp
, *pgrp
;
1917 debug("wstat tag %d\n", tag
);
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)
1928 fid
= fidget(conn
, gint32(buf
));
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);
1940 return badmsg(conn
, tag
, buf
);
1943 pos
+= gint16(buf
+pos
) + 2;
1945 return badmsg(conn
, tag
, buf
);
1947 glen
= gstr(buf
+pos
, &gid
, size
-pos
);
1949 return badmsg(conn
, tag
, buf
);
1952 pos
+= gint16(buf
+pos
) + 2;
1954 return badmsg(conn
, tag
, buf
);
1958 pos
+= gint16(buf
+pos
) + 2;
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
);
1968 return ruerror(conn
, tag
, buf
, n
);
1974 if (chmod(fid
->path
, mode
&0777) < 0)
1975 return ruerror(conn
, tag
, buf
, errno
);
1980 if (utime(fid
->path
, &tb
) < 0)
1981 return ruerror(conn
, tag
, buf
, errno
);
1984 if (chown(fid
->path
, -1, ngid
) < 0)
1985 return ruerror(conn
, tag
, buf
, errno
);
1988 p
= strrchr(fid
->path
, '/');
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) {
2001 return ruerror(conn
, tag
, buf
, errno
);
2004 if (fid
->path
!= fid
->cpath
)
2012 if (truncate(fid
->path
, length
) < 0)
2013 return ruerror(conn
, tag
, buf
, errno
);
2016 return rwstat(conn
, tag
, buf
);
2022 fprintf(stderr
, "npfs: -d -s -p port -w nthreads\n");
2027 main(int argc
, char *argv
[])
2031 int port
, nwthreads
;
2033 struct sockaddr_in saddr
;
2039 while ((c
= getopt(argc
, argv
, "dsp:w:m:")) != -1) {
2046 port
= strtol(optarg
, &s
, 10);
2052 nwthreads
= strtol(optarg
, &s
, 10);
2062 msize
= strtol(optarg
, &s
, 10);
2072 sock
= socket(PF_INET
, SOCK_STREAM
, 0);
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) {
2086 if (listen(sock
, 1) < 0) {
2092 while ((csock
= accept(sock
, &saddr
, &n
)) >= 0) {
2093 conn
= conncreate(csock
, nwthreads
);