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 * PRECISION INSIGHT 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
30 #include <sys/types.h>
41 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
43 typedef struct Fid Fid
;
52 void* aux
; /* for mmapread */
61 char *Estatfailed
= "stat failed";
62 char *Ebadfid
= "fid unknown or out of range";
63 char *Enoextension
= "empty extension while creating special file";
64 char *Eformat
= "incorrect extension format";
65 char *Ecreatesocket
= "cannot create socket";
68 static int fidstat(Fid
*fid
);
69 static void ustat2qid(struct stat
*st
, Spqid
*qid
);
70 static u8
ustat2qidtype(struct stat
*st
);
71 static u32
umode2npmode(mode_t umode
, int dotu
);
72 static mode_t
npstat2umode(Spstat
*st
, int dotu
);
73 static void ustat2npwstat(char *path
, struct stat
*st
, Spwstat
*wstat
, int dotu
, Spuserpool
*);
75 static Spfcall
* npfs_attach(Spfid
*fid
, Spfid
*afid
, Spstr
*uname
, Spstr
*aname
, u32 n_uname
);
76 static int npfs_clone(Spfid
*fid
, Spfid
*newfid
);
77 static int npfs_walk(Spfid
*fid
, Spstr
*wname
, Spqid
*wqid
);
78 static Spfcall
* npfs_open(Spfid
*fid
, u8 mode
);
79 static Spfcall
* npfs_create(Spfid
*fid
, Spstr
*name
, u32 perm
, u8 mode
,
81 static Spfcall
* npfs_read(Spfid
*fid
, u64 offset
, u32 count
, Spreq
*);
82 static Spfcall
* npfs_write(Spfid
*fid
, u64 offset
, u32 count
, u8
*data
, Spreq
*);
83 static Spfcall
* npfs_clunk(Spfid
*fid
);
84 static Spfcall
* npfs_remove(Spfid
*fid
);
85 static Spfcall
* npfs_stat(Spfid
*fid
);
86 static Spfcall
* npfs_wstat(Spfid
*fid
, Spstat
*stat
);
88 static void npfs_fiddestroy(Spfid
*fid
);
93 fprintf(stderr
, "npfs: -d -s -p port -w nthreads\n");
98 main(int argc
, char **argv
)
106 while ((c
= getopt(argc
, argv
, "dsmp:w:")) != -1) {
113 port
= strtol(optarg
, &s
, 10);
119 nwthreads
= strtol(optarg
, &s
, 10);
137 srv
= sp_socksrv_create_tcp(&port
);
143 srv
->attach
= npfs_attach
;
144 srv
->clone
= npfs_clone
;
145 srv
->walk
= npfs_walk
;
146 srv
->open
= npfs_open
;
147 srv
->create
= npfs_create
;
148 srv
->read
= npfs_read
;
149 srv
->write
= npfs_write
;
150 srv
->clunk
= npfs_clunk
;
151 srv
->remove
= npfs_remove
;
152 srv
->stat
= npfs_stat
;
153 srv
->wstat
= npfs_wstat
;
154 srv
->fiddestroy
= npfs_fiddestroy
;
155 srv
->debuglevel
= debuglevel
;
165 if (lstat(fid
->path
, &fid
->stat
) < 0)
168 if (S_ISDIR(fid
->stat
.st_mode
))
169 fid
->stat
.st_size
= 0;
178 f
= malloc(sizeof(*f
));
185 f
->direntname
= NULL
;
191 npfs_fiddestroy(Spfid
*fid
)
210 create_rerror(int ecode
)
214 strerror_r(ecode
, buf
, sizeof(buf
));
215 sp_werror(buf
, ecode
);
219 omode2uflags(u8 mode
)
255 ustat2qid(struct stat
*st
, Spqid
*qid
)
260 n
= sizeof(qid
->path
);
261 if (n
> sizeof(st
->st_ino
))
262 n
= sizeof(st
->st_ino
);
263 memmove(&qid
->path
, &st
->st_ino
, n
);
264 qid
->version
= st
->st_mtime
^ (st
->st_size
<< 8);
265 qid
->type
= ustat2qidtype(st
);
269 ustat2qidtype(struct stat
*st
)
274 if (S_ISDIR(st
->st_mode
))
277 if (S_ISLNK(st
->st_mode
))
284 umode2npmode(mode_t umode
, int dotu
)
313 np2umode(u32 mode
, Spstr
*extension
, int dotu
)
322 if (mode
& Dmsymlink
)
326 if (mode
& Dmnamedpipe
)
328 if (mode
& Dmdevice
) {
329 if (extension
&& extension
->str
[0] == 'c')
348 npstat2umode(Spstat
*st
, int dotu
)
350 return np2umode(st
->mode
, &st
->extension
, dotu
);
354 ustat2npwstat(char *path
, struct stat
*st
, Spwstat
*wstat
, int dotu
, Spuserpool
*up
)
361 memset(wstat
, 0, sizeof(*wstat
));
362 ustat2qid(st
, &wstat
->qid
);
363 wstat
->mode
= umode2npmode(st
->st_mode
, dotu
);
364 wstat
->atime
= st
->st_atime
;
365 wstat
->mtime
= st
->st_mtime
;
366 wstat
->length
= st
->st_size
;
368 u
= up
->uid2user(up
, st
->st_uid
);
369 g
= up
->gid2group(up
, st
->st_gid
);
371 wstat
->uid
= u
?u
->uname
:"???";
372 wstat
->gid
= g
?g
->gname
:"???";
375 wstat
->extension
= NULL
;
377 wstat
->n_uid
= st
->st_uid
;
378 wstat
->n_gid
= st
->st_gid
;
380 if (wstat
->mode
& Dmsymlink
) {
381 err
= readlink(path
, ext
, sizeof(ext
) - 1);
386 } else if (wstat
->mode
& Dmdevice
) {
387 snprintf(ext
, sizeof(ext
), "%c %u %u",
388 S_ISCHR(st
->st_mode
)?'c':'b',
389 major(st
->st_rdev
), minor(st
->st_rdev
));
394 wstat
->extension
= strdup(ext
);
397 s
= strrchr(path
, '/');
405 npfs_change_user(Spuser
*user
)
408 sp_change_user(user
);
412 npfs_attach(Spfid
*nfid
, Spfid
*nafid
, Spstr
*uname
, Spstr
*aname
, u32 n_uname
)
424 sp_werror(Enoauth
, EIO
);
428 fid
= npfs_fidalloc();
430 npfs_change_user(nfid
->user
);
433 if (aname
->len
==0 || *aname
->str
!='/')
434 fid
->path
= strdup("/");
436 fid
->path
= sp_strdup(aname
);
445 ustat2qid(&fid
->stat
, &qid
);
446 ret
= sp_create_rattach(&qid
);
454 npfs_clone(Spfid
*fid
, Spfid
*newfid
)
459 nf
= npfs_fidalloc();
460 nf
->path
= strdup(f
->path
);
468 npfs_walk(Spfid
*fid
, Spstr
* wname
, Spqid
*wqid
)
476 npfs_change_user(fid
->user
);
482 path
= malloc(n
+ wname
->len
+ 2);
483 memcpy(path
, f
->path
, n
);
485 memcpy(path
+ n
+ 1, wname
->str
, wname
->len
);
486 path
[n
+ wname
->len
+ 1] = '\0';
488 if (lstat(path
, &st
) < 0) {
490 create_rerror(errno
);
496 ustat2qid(&st
, wqid
);
502 npfs_open(Spfid
*fid
, u8 mode
)
509 npfs_change_user(fid
->user
);
510 if ((err
= fidstat(f
)) < 0)
513 if (S_ISDIR(f
->stat
.st_mode
)) {
514 f
->dir
= opendir(f
->path
);
516 create_rerror(errno
);
518 f
->fd
= open(f
->path
, omode2uflags(mode
));
520 create_rerror(errno
);
528 ustat2qid(&f
->stat
, &qid
);
529 return sp_create_ropen(&qid
, 0);
533 npfs_create_special(Spfid
*fid
, char *path
, u32 perm
, Spstr
*extension
)
536 int nmode
, major
, minor
;
544 if (!perm
&Dmnamedpipe
&& !extension
->len
) {
545 sp_werror(Enoextension
, EIO
);
549 umode
= np2umode(perm
, extension
, fid
->conn
->dotu
);
550 ext
= sp_strdup(extension
);
551 if (perm
& Dmsymlink
) {
552 if (symlink(ext
, path
) < 0) {
554 fprintf(stderr
, "symlink %s %s %d\n", ext
, path
, err
);
558 } else if (perm
& Dmlink
) {
559 if (sscanf(ext
, "%d", &nfid
) == 0) {
560 sp_werror(Eformat
, EIO
);
564 ofid
= sp_fid_find(fid
->conn
, nfid
);
566 sp_werror(Eunknownfid
, EIO
);
571 if (link(of
->path
, path
) < 0) {
572 create_rerror(errno
);
575 } else if (perm
& Dmdevice
) {
576 if (sscanf(ext
, "%c %u %u", &ctype
, &major
, &minor
) != 3) {
577 sp_werror(Eformat
, EIO
);
592 sp_werror(Eformat
, EIO
);
596 nmode
|= perm
& 0777;
597 if (mknod(path
, nmode
, makedev(major
, minor
)) < 0) {
598 create_rerror(errno
);
601 } else if (perm
& Dmnamedpipe
) {
602 if (mknod(path
, S_IFIFO
| (umode
&0777), 0) < 0) {
603 create_rerror(errno
);
609 if (!perm
&Dmsymlink
&& chmod(path
, umode
)<0) {
610 create_rerror(errno
);
624 npfs_create(Spfid
*fid
, Spstr
*name
, u32 perm
, u8 mode
, Spstr
*extension
)
636 if ((err
= fidstat(f
)) < 0)
640 npath
= malloc(n
+ name
->len
+ 2);
641 memmove(npath
, f
->path
, n
);
643 memmove(npath
+ n
+ 1, name
->str
, name
->len
);
644 npath
[n
+ name
->len
+ 1] = '\0';
646 if (lstat(npath
, &st
)==0 || errno
!=ENOENT
) {
647 sp_werror(Eexist
, EEXIST
);
652 if (mkdir(npath
, perm
& 0777) < 0) {
653 create_rerror(errno
);
657 if (lstat(npath
, &f
->stat
) < 0) {
658 create_rerror(errno
);
663 f
->dir
= opendir(npath
);
665 create_rerror(errno
);
669 } else if (perm
& (Dmnamedpipe
|Dmsymlink
|Dmlink
|Dmdevice
)) {
670 if (npfs_create_special(fid
, npath
, perm
, extension
) < 0)
673 if (lstat(npath
, &f
->stat
) < 0) {
674 create_rerror(errno
);
679 f
->fd
= open(npath
, O_CREAT
|omode2uflags(mode
),
682 create_rerror(errno
);
686 if (lstat(npath
, &f
->stat
) < 0) {
687 create_rerror(errno
);
697 ustat2qid(&f
->stat
, &qid
);
698 ret
= sp_create_rcreate(&qid
, 0);
706 npfs_read_dir(Spfid
*fid
, u8
* buf
, u64 offset
, u32 count
, int dotu
)
710 struct dirent
*dirent
;
721 plen
= strlen(f
->path
);
724 dname
= f
->direntname
;
727 dirent
= readdir(f
->dir
);
731 if (strcmp(dirent
->d_name
, ".") == 0
732 || strcmp(dirent
->d_name
, "..") == 0)
735 dname
= dirent
->d_name
;
738 path
= malloc(plen
+ strlen(dname
) + 2);
739 sprintf(path
, "%s/%s", f
->path
, dname
);
741 if (lstat(path
, &st
) < 0) {
743 create_rerror(errno
);
747 ustat2npwstat(path
, &st
, &wstat
, dotu
, fid
->conn
->srv
->upool
);
748 i
= sp_serialize_stat(&wstat
, buf
+ n
, count
- n
- 1, dotu
);
749 free(wstat
.extension
);
761 f
->direntname
= NULL
;
765 f
->direntname
= strdup(dirent
->d_name
);
772 npfs_read(Spfid
*fid
, u64 offset
, u32 count
, Spreq
*req
)
779 ret
= sp_alloc_rread(count
);
780 npfs_change_user(fid
->user
);
782 n
= npfs_read_dir(fid
, ret
->data
, offset
, count
, fid
->conn
->dotu
);
789 f
->aux
=mmap(0, s
.st_size
, PROT_READ
,
790 MAP_SHARED
, f
->fd
, 0);
792 create_rerror(errno
);
796 if(offset
+count
> s
.st_size
)
797 n
= s
.st_size
-offset
;
799 memcpy(ret
->data
, f
->aux
+offset
, n
);
803 n
= pread(f
->fd
, ret
->data
, count
, offset
);
805 create_rerror(errno
);
814 sp_set_rread_count(ret
, n
);
820 npfs_write(Spfid
*fid
, u64 offset
, u32 count
, u8
*data
, Spreq
*req
)
826 npfs_change_user(fid
->user
);
828 n
= pwrite(f
->fd
, data
, count
, offset
);
830 create_rerror(errno
);
832 return sp_create_rwrite(n
);
836 npfs_clunk(Spfid
*fid
)
842 ret
= sp_create_rclunk();
843 // sp_fid_decref(fid);
848 npfs_remove(Spfid
*fid
)
855 npfs_change_user(fid
->user
);
856 if (remove(f
->path
) < 0) {
857 create_rerror(errno
);
861 ret
= sp_create_rremove();
864 // sp_fid_decref(fid);
870 npfs_stat(Spfid
*fid
)
878 npfs_change_user(fid
->user
);
883 ustat2npwstat(f
->path
, &f
->stat
, &wstat
, fid
->conn
->dotu
, fid
->conn
->srv
->upool
);
885 ret
= sp_create_rstat(&wstat
, fid
->conn
->dotu
);
886 free(wstat
.extension
);
892 npfs_wstat(Spfid
*fid
, Spstat
*stat
)
907 up
= fid
->conn
->srv
->upool
;
908 npfs_change_user(fid
->user
);
915 if (fid
->conn
->dotu
) {
923 if (uid
== -1 && stat
->uid
.len
) {
924 s
= sp_strdup(&stat
->uid
);
925 user
= up
->uname2user(up
, s
);
928 sp_werror(Eunknownuser
, EIO
);
935 if (gid
== -1 && stat
->gid
.len
) {
936 s
= sp_strdup(&stat
->gid
);
937 group
= up
->gname2group(up
, s
);
940 sp_werror(Eunknownuser
, EIO
);
947 if (stat
->mode
!= (u32
)~0) {
948 if (stat
->mode
&Dmdir
&& !S_ISDIR(f
->stat
.st_mode
)) {
949 sp_werror(Edirchange
, EIO
);
953 if (chmod(f
->path
, npstat2umode(stat
, fid
->conn
->dotu
)) < 0) {
954 create_rerror(errno
);
959 if (stat
->mtime
!= (u32
)~0) {
961 tb
.modtime
= stat
->mtime
;
962 if (utime(f
->path
, &tb
) < 0) {
963 create_rerror(errno
);
969 if (chown(f
->path
, uid
, gid
) < 0) {
970 create_rerror(errno
);
975 if (stat
->name
.len
!= 0) {
976 p
= strrchr(f
->path
, '/');
978 p
= f
->path
+ strlen(f
->path
);
980 npath
= malloc(stat
->name
.len
+ (p
- f
->path
) + 2);
981 memcpy(npath
, f
->path
, p
- f
->path
);
982 npath
[p
- f
->path
] = '/';
983 memcpy(npath
+ (p
- f
->path
) + 1, stat
->name
.str
, stat
->name
.len
);
984 npath
[(p
- f
->path
) + 1 + stat
->name
.len
] = 0;
985 if (strcmp(npath
, f
->path
) != 0) {
986 if (rename(f
->path
, npath
) < 0) {
987 create_rerror(errno
);
996 if (stat
->length
!= ~0) {
997 if (truncate(f
->path
, stat
->length
) < 0) {
998 create_rerror(errno
);
1002 ret
= sp_create_rwstat();