2 * Copyright (C) 2005 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
31 #include <sys/types.h>
48 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
50 typedef struct Fid Fid
;
66 char *Estatfailed
= "stat failed";
67 char *Ebadfid
= "fid unknown or out of range";
68 char *Enoextension
= "empty extension while creating special file";
69 char *Eformat
= "incorrect extension format";
70 char *Ecreatesocket
= "cannot create socket";
73 static int fidstat(Fid
*fid
);
74 static void ustat2qid(struct stat
*st
, Npqid
*qid
);
75 static u8
ustat2qidtype(struct stat
*st
);
76 static u32
umode2npmode(mode_t umode
, int dotu
);
77 static mode_t
npstat2umode(Npstat
*st
, int dotu
);
78 static void ustat2npwstat(char *path
, struct stat
*st
, Npwstat
*wstat
, int dotu
, Npuserpool
*up
);
80 static int npfs_aio_read(Npfid
*fid
, Npfcall
*rread
, u64 offset
, u32 count
, Npreq
*);
81 static int npfs_aio_write(Npfid
*fid
, u8
*data
, u64 offset
, u32 count
, Npreq
*);
85 typedef struct Aioreq Aioreq
;
98 pthread_mutex_t aio_lock
= PTHREAD_MUTEX_INITIALIZER
;
104 pthread_t aio_thread
;
109 if (lstat(fid
->path
, &fid
->stat
) < 0)
112 if (S_ISDIR(fid
->stat
.st_mode
))
113 fid
->stat
.st_size
= 0;
122 f
= malloc(sizeof(*f
));
129 f
->direntname
= NULL
;
135 npfs_fiddestroy(Npfid
*fid
)
154 create_rerror(int ecode
)
158 strerror_r(ecode
, buf
, sizeof(buf
));
159 np_werror(buf
, ecode
);
163 omode2uflags(u8 mode
)
199 ustat2qid(struct stat
*st
, Npqid
*qid
)
204 n
= sizeof(qid
->path
);
205 if (n
> sizeof(st
->st_ino
))
206 n
= sizeof(st
->st_ino
);
207 memmove(&qid
->path
, &st
->st_ino
, n
);
208 qid
->version
= st
->st_mtime
^ (st
->st_size
<< 8);
209 qid
->type
= ustat2qidtype(st
);
213 ustat2qidtype(struct stat
*st
)
218 if (S_ISDIR(st
->st_mode
))
221 if (S_ISLNK(st
->st_mode
))
228 umode2npmode(mode_t umode
, int dotu
)
257 np2umode(u32 mode
, Npstr
*extension
, int dotu
)
266 if (mode
& Dmsymlink
)
270 if (mode
& Dmnamedpipe
)
272 if (mode
& Dmdevice
) {
273 if (extension
&& extension
->str
[0] == 'c')
292 npstat2umode(Npstat
*st
, int dotu
)
294 return np2umode(st
->mode
, &st
->extension
, dotu
);
298 ustat2npwstat(char *path
, struct stat
*st
, Npwstat
*wstat
, int dotu
, Npuserpool
*up
)
305 memset(wstat
, 0, sizeof(*wstat
));
306 ustat2qid(st
, &wstat
->qid
);
307 wstat
->mode
= umode2npmode(st
->st_mode
, dotu
);
308 wstat
->atime
= st
->st_atime
;
309 wstat
->mtime
= st
->st_mtime
;
310 wstat
->length
= st
->st_size
;
312 u
= up
->uid2user(up
, st
->st_uid
);
313 g
= up
->gid2group(up
, st
->st_gid
);
315 wstat
->uid
= u
?u
->uname
:"???";
316 wstat
->gid
= g
?g
->gname
:"???";
319 wstat
->extension
= NULL
;
321 wstat
->n_uid
= st
->st_uid
;
322 wstat
->n_gid
= st
->st_gid
;
324 if (wstat
->mode
& Dmsymlink
) {
325 err
= readlink(path
, ext
, sizeof(ext
) - 1);
330 } else if (wstat
->mode
& Dmdevice
) {
331 snprintf(ext
, sizeof(ext
), "%c %u %u",
332 S_ISCHR(st
->st_mode
)?'c':'b',
333 major(st
->st_rdev
), minor(st
->st_rdev
));
338 wstat
->extension
= strdup(ext
);
341 s
= strrchr(path
, '/');
349 npfs_set_user(Npuser
*user
)
354 if (geteuid() == user
->uid
)
357 np_change_user(user
);
361 npfs_attach(Npfid
*nfid
, Npfid
*nafid
, Npstr
*uname
, Npstr
*aname
)
372 npfs_set_user(nfid
->user
);
374 np_werror(Enoauth
, EIO
);
378 fid
= npfs_fidalloc();
380 if (aname
->len
==0 || *aname
->str
!='/')
381 fid
->path
= strdup("/");
383 fid
->path
= np_strdup(aname
);
392 ustat2qid(&fid
->stat
, &qid
);
393 ret
= np_create_rattach(&qid
);
401 npfs_clone(Npfid
*fid
, Npfid
*newfid
)
406 nf
= npfs_fidalloc();
407 nf
->path
= strdup(f
->path
);
415 npfs_walk(Npfid
*fid
, Npstr
* wname
, Npqid
*wqid
)
423 npfs_set_user(fid
->user
);
429 path
= malloc(n
+ wname
->len
+ 2);
430 memcpy(path
, f
->path
, n
);
432 memcpy(path
+ n
+ 1, wname
->str
, wname
->len
);
433 path
[n
+ wname
->len
+ 1] = '\0';
435 if (lstat(path
, &st
) < 0) {
437 create_rerror(errno
);
443 ustat2qid(&st
, wqid
);
449 npfs_open(Npfid
*fid
, u8 mode
)
456 npfs_set_user(fid
->user
);
457 if ((err
= fidstat(f
)) < 0)
460 if (S_ISDIR(f
->stat
.st_mode
)) {
461 f
->dir
= opendir(f
->path
);
463 create_rerror(errno
);
465 f
->fd
= open(f
->path
, omode2uflags(mode
));
467 create_rerror(errno
);
475 ustat2qid(&f
->stat
, &qid
);
476 return np_create_ropen(&qid
, 0);
480 npfs_create_special(Npfid
*fid
, char *path
, u32 perm
, Npstr
*extension
)
483 int nmode
, major
, minor
;
491 if (!perm
&Dmnamedpipe
&& !extension
->len
) {
492 np_werror(Enoextension
, EIO
);
496 umode
= np2umode(perm
, extension
, fid
->conn
->dotu
);
497 ext
= np_strdup(extension
);
498 if (perm
& Dmsymlink
) {
499 if (symlink(ext
, path
) < 0) {
501 fprintf(stderr
, "symlink %s %s %d\n", ext
, path
, err
);
505 } else if (perm
& Dmlink
) {
506 if (sscanf(ext
, "%d", &nfid
) == 0) {
507 np_werror(Eformat
, EIO
);
511 ofid
= np_fid_find(fid
->conn
, nfid
);
513 np_werror(Eunknownfid
, EIO
);
518 if (link(of
->path
, path
) < 0) {
519 create_rerror(errno
);
522 } else if (perm
& Dmdevice
) {
523 if (sscanf(ext
, "%c %u %u", &ctype
, &major
, &minor
) != 3) {
524 np_werror(Eformat
, EIO
);
539 np_werror(Eformat
, EIO
);
543 nmode
|= perm
& 0777;
544 if (mknod(path
, nmode
, makedev(major
, minor
)) < 0) {
545 create_rerror(errno
);
548 } else if (perm
& Dmnamedpipe
) {
549 if (mknod(path
, S_IFIFO
| (umode
&0777), 0) < 0) {
550 create_rerror(errno
);
556 if (!perm
&Dmsymlink
&& chmod(path
, umode
)<0) {
557 create_rerror(errno
);
571 npfs_create(Npfid
*fid
, Npstr
*name
, u32 perm
, u8 mode
, Npstr
*extension
)
583 if ((err
= fidstat(f
)) < 0)
587 npath
= malloc(n
+ name
->len
+ 2);
588 memmove(npath
, f
->path
, n
);
590 memmove(npath
+ n
+ 1, name
->str
, name
->len
);
591 npath
[n
+ name
->len
+ 1] = '\0';
593 if (lstat(npath
, &st
)==0 || errno
!=ENOENT
) {
594 np_werror(Eexist
, EEXIST
);
599 if (mkdir(npath
, perm
& 0777) < 0) {
600 create_rerror(errno
);
604 if (lstat(npath
, &f
->stat
) < 0) {
605 create_rerror(errno
);
610 f
->dir
= opendir(npath
);
612 create_rerror(errno
);
616 } else if (perm
& (Dmnamedpipe
|Dmsymlink
|Dmlink
|Dmdevice
)) {
617 if (npfs_create_special(fid
, npath
, perm
, extension
) < 0)
620 if (lstat(npath
, &f
->stat
) < 0) {
621 create_rerror(errno
);
626 f
->fd
= open(npath
, O_CREAT
|omode2uflags(mode
),
629 create_rerror(errno
);
633 if (lstat(npath
, &f
->stat
) < 0) {
634 create_rerror(errno
);
644 ustat2qid(&f
->stat
, &qid
);
645 ret
= np_create_rcreate(&qid
, 0);
653 npfs_read_dir(Npfid
*fid
, u8
* buf
, u64 offset
, u32 count
, int dotu
)
657 struct dirent
*dirent
;
668 plen
= strlen(f
->path
);
671 dname
= f
->direntname
;
674 dirent
= readdir(f
->dir
);
678 if (strcmp(dirent
->d_name
, ".") == 0
679 || strcmp(dirent
->d_name
, "..") == 0)
682 dname
= dirent
->d_name
;
685 path
= malloc(plen
+ strlen(dname
) + 2);
686 sprintf(path
, "%s/%s", f
->path
, dname
);
688 if (lstat(path
, &st
) < 0) {
690 create_rerror(errno
);
694 ustat2npwstat(path
, &st
, &wstat
, dotu
, fid
->conn
->srv
->upool
);
695 i
= np_serialize_stat(&wstat
, buf
+ n
, count
- n
- 1, dotu
);
696 free(wstat
.extension
);
708 f
->direntname
= NULL
;
712 f
->direntname
= strdup(dirent
->d_name
);
719 npfs_read(Npfid
*fid
, u64 offset
, u32 count
, Npreq
*req
)
726 ret
= np_alloc_rread(count
);
727 npfs_set_user(fid
->user
);
729 n
= npfs_read_dir(fid
, ret
->data
, offset
, count
, fid
->conn
->dotu
);
732 n
= npfs_aio_read(fid
, ret
, offset
, count
, req
);
737 n
= pread(f
->fd
, ret
->data
, count
, offset
);
739 create_rerror(errno
);
746 np_set_rread_count(ret
, n
);
752 npfs_write(Npfid
*fid
, u64 offset
, u32 count
, u8
*data
, Npreq
*req
)
758 npfs_set_user(fid
->user
);
761 n
= npfs_aio_write(fid
, data
, offset
, count
, req
);
762 // fprintf(stderr, "$$ %d\n", n);
767 n
= pwrite(f
->fd
, data
, count
, offset
);
769 create_rerror(errno
);
771 return np_create_rwrite(n
);
775 npfs_clunk(Npfid
*fid
)
781 ret
= np_create_rclunk();
782 // np_fid_decref(fid);
787 npfs_remove(Npfid
*fid
)
794 npfs_set_user(fid
->user
);
795 if (remove(f
->path
) < 0) {
796 create_rerror(errno
);
800 ret
= np_create_rremove();
803 // np_fid_decref(fid);
809 npfs_stat(Npfid
*fid
)
817 npfs_set_user(fid
->user
);
822 ustat2npwstat(f
->path
, &f
->stat
, &wstat
, fid
->conn
->dotu
, fid
->conn
->srv
->upool
);
824 ret
= np_create_rstat(&wstat
, fid
->conn
->dotu
);
825 free(wstat
.extension
);
831 npfs_wstat(Npfid
*fid
, Npstat
*stat
)
846 up
= fid
->conn
->srv
->upool
;
847 npfs_set_user(fid
->user
);
854 if (fid
->conn
->dotu
) {
862 if (uid
== -1 && stat
->uid
.len
) {
863 s
= np_strdup(&stat
->uid
);
864 user
= up
->uname2user(up
, s
);
867 np_werror(Eunknownuser
, EIO
);
874 if (gid
== -1 && stat
->gid
.len
) {
875 s
= np_strdup(&stat
->gid
);
876 group
= up
->gname2group(up
, s
);
879 np_werror(Eunknownuser
, EIO
);
886 if (stat
->mode
!= (u32
)~0) {
887 if (stat
->mode
&Dmdir
&& !S_ISDIR(f
->stat
.st_mode
)) {
888 np_werror(Edirchange
, EIO
);
892 if (chmod(f
->path
, npstat2umode(stat
, fid
->conn
->dotu
)) < 0) {
893 create_rerror(errno
);
898 if (stat
->mtime
!= (u32
)~0) {
900 tb
.modtime
= stat
->mtime
;
901 if (utime(f
->path
, &tb
) < 0) {
902 create_rerror(errno
);
908 if (chown(f
->path
, uid
, gid
) < 0) {
909 create_rerror(errno
);
914 if (stat
->name
.len
!= 0) {
915 p
= strrchr(f
->path
, '/');
917 p
= f
->path
+ strlen(f
->path
);
919 npath
= malloc(stat
->name
.len
+ (p
- f
->path
) + 2);
920 memcpy(npath
, f
->path
, p
- f
->path
);
921 npath
[p
- f
->path
] = '/';
922 memcpy(npath
+ (p
- f
->path
) + 1, stat
->name
.str
, stat
->name
.len
);
923 npath
[(p
- f
->path
) + 1 + stat
->name
.len
] = 0;
924 if (strcmp(npath
, f
->path
) != 0) {
925 if (rename(f
->path
, npath
) < 0) {
926 create_rerror(errno
);
935 if (stat
->length
!= ~0) {
936 if (truncate(f
->path
, stat
->length
) < 0) {
937 create_rerror(errno
);
941 ret
= np_create_rwstat();
949 npfs_aio_respond(Aioreq
*areq
, struct io_event
*event
, int flush
)
958 if (count
<0 && !flush
) {
959 if (areq
->req
->tcall
->type
== Tread
)
962 if (strerror_r(count
, buf
, sizeof(buf
)))
963 strcpy(buf
, "unknown error");
965 rc
= np_create_rerror(buf
, count
, areq
->req
->conn
->dotu
);
967 if (areq
->req
->tcall
->type
== Tread
) {
969 np_set_rread_count(rc
, count
);
971 rc
= np_create_rwrite(count
);
975 // np_fid_decref(areq->fid);
976 np_respond(areq
->req
, rc
);
982 npfs_flush(Npreq
*req
)
984 if (req
->tcall
->type
!=Tread
&& req
->tcall
->type
!=Twrite
)
989 struct io_event event
;
992 pthread_mutex_lock(&aio_lock
);
993 for(areq
= aio_reqs
; areq
!= NULL
; areq
= areq
->next
) {
994 if (areq
->req
== req
) {
995 io_cancel(aio_ctx
, &areq
->iocb
, &event
);
996 npfs_aio_respond(areq
, &event
, 1);
999 areq
->prev
->next
= areq
->next
;
1001 aio_reqs
= areq
->next
;
1003 areq
->next
->prev
= areq
->prev
;
1009 pthread_mutex_unlock(&aio_lock
);
1017 npfs_aio_init(int n
)
1022 ret
= io_queue_init(n
, &aio_ctx
);
1030 npfs_aio_read(Npfid
*fid
, Npfcall
*rread
, u64 offset
, u32 count
, Npreq
*req
)
1037 struct iocb
*iocbs
[1];
1040 areq
= malloc(sizeof(*areq
));
1043 areq
->rread
= rread
;
1044 pthread_mutex_lock(&aio_lock
);
1045 areq
->next
= aio_reqs
;
1048 pthread_mutex_unlock(&aio_lock
);
1049 io_prep_pread(&areq
->iocb
, f
->fd
, rread
->data
, count
, offset
);
1050 iocbs
[0] = &areq
->iocb
;
1051 ret
= io_submit(aio_ctx
, 1, iocbs
);
1058 npfs_aio_write(Npfid
*fid
, u8
*data
, u64 offset
, u32 count
, Npreq
*req
)
1065 struct iocb
*iocbs
[1];
1068 areq
= malloc(sizeof(*areq
));
1071 pthread_mutex_lock(&aio_lock
);
1072 areq
->next
= aio_reqs
;
1075 pthread_mutex_unlock(&aio_lock
);
1076 io_prep_pwrite(&areq
->iocb
, f
->fd
, data
, count
, offset
);
1077 iocbs
[0] = &areq
->iocb
;
1078 ret
= io_submit(aio_ctx
, 1, iocbs
);
1085 npfs_aio_proc(void *a
)
1091 struct io_event events
[8];
1097 n
= io_getevents(aio_ctx
, 1, 1 /* sizeof(events) / sizeof(events[0]) */,
1100 // fprintf(stderr,"++ %d\n", n);
1101 for(i
= 0; i
< n
; i
++) {
1102 count
= events
[i
].res
;
1103 areq
= (Aioreq
*) ((char *) events
[i
].obj
-
1104 (int) (&((Aioreq
*)0)->iocb
));
1106 npfs_aio_respond(areq
, &events
[i
], 0);