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.
28 #include <sys/types.h>
35 #include <linux/kdev_t.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
39 #include <arpa/inet.h>
42 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
44 typedef struct Fid Fid
;
59 char *Estatfailed
= "stat failed";
60 char *Ebadfid
= "fid unknown or out of range";
61 char *Enoextension
= "empty extension while creating special file";
62 char *Eformat
= "incorrect extension format";
63 char *Ecreatesocket
= "cannot create socket";
66 static int fidstat(Fid
*fid
);
67 static void ustat2qid(struct stat
*st
, Npqid
*qid
);
68 static u8
ustat2qidtype(struct stat
*st
);
69 static u32
umode2npmode(mode_t umode
, int dotu
);
70 static mode_t
npstat2umode(Npstat
*st
, int dotu
);
71 static void ustat2npwstat(char *path
, struct stat
*st
, Npwstat
*wstat
, int dotu
);
73 static void npfs_connclose(Npconn
*conn
);
74 static Npfcall
* npfs_attach(Npfid
*fid
, Npfid
*afid
, Npstr
*uname
, Npstr
*aname
);
75 static int npfs_clone(Npfid
*fid
, Npfid
*newfid
);
76 static int npfs_walk(Npfid
*fid
, Npstr
* wname
, Npqid
*wqid
);
77 static Npfcall
* npfs_open(Npfid
*fid
, u8 mode
);
78 static Npfcall
* npfs_create(Npfid
*fid
, Npstr
* name
, u32 perm
, u8 mode
);
79 static Npfcall
* npfs_read(Npfid
*fid
, u64 offset
, u32 count
, Npreq
*req
);
80 static Npfcall
* npfs_write(Npfid
*fid
, u64 offset
, u32 count
, u8
*data
, Npreq
*req
);
81 static Npfcall
* npfs_clunk(Npfid
*fid
);
82 static Npfcall
* npfs_remove(Npfid
*fid
);
83 static Npfcall
* npfs_stat(Npfid
*fid
);
84 static Npfcall
* npfs_wstat(Npfid
*fid
, Npstat
*stat
);
85 static void npfs_fiddestroy(Npfid
*fid
);
88 get_local_addr(char *hostname
, char *addr
, int addrlen
)
92 struct sockaddr_in saddr
;
93 struct hostent
*hostinfo
;
95 sock
= socket(PF_INET
, SOCK_STREAM
, 0);
97 saddr
.sin_family
= AF_INET
;
98 saddr
.sin_port
= htons (22);
99 hostinfo
= gethostbyname (hostname
);
100 if (hostinfo
== NULL
) {
101 fprintf (stderr
, "Unknown host %s.\n", hostname
);
105 saddr
.sin_addr
= *(struct in_addr
*) hostinfo
->h_addr
;
106 if (0 > connect (sock
, (struct sockaddr
*) &saddr
, sizeof (saddr
))) {
112 getsockname(sock
, (struct sockaddr
*) &saddr
, &n
);
113 snprintf(addr
, addrlen
, "%s", inet_ntoa(saddr
.sin_addr
));
114 shutdown(sock
, SHUT_RDWR
);
119 main(int argc
, char **argv
)
124 char sport
[20], hostname
[20];
128 user
= np_uid2user(getuid());
131 srv
= np_socksrv_create_tcp(nwthreads
, &port
);
135 srv
->connclose
= npfs_connclose
;
136 srv
->attach
= npfs_attach
;
137 srv
->clone
= npfs_clone
;
138 srv
->walk
= npfs_walk
;
139 srv
->open
= npfs_open
;
140 srv
->create
= npfs_create
;
141 srv
->read
= npfs_read
;
142 srv
->write
= npfs_write
;
143 srv
->clunk
= npfs_clunk
;
144 srv
->remove
= npfs_remove
;
145 srv
->stat
= npfs_stat
;
146 srv
->wstat
= npfs_wstat
;
147 srv
->fiddestroy
= npfs_fiddestroy
;
148 srv
->debuglevel
= debuglevel
;
159 if (get_local_addr(argv
[1], hostname
, sizeof(hostname
)))
162 sprintf(sport
, "%d", port
);
163 sargv
= calloc(argc
+ 6, sizeof(char *));
167 sargv
[3] = "/usr/sbin/cpuhelper";
168 sargv
[4] = user
->uname
;
172 for(i
= 2; i
< argc
; i
++)
173 sargv
[i
+5] = argv
[i
];
175 execvp("ssh", sargv
);
181 npfs_connclose(Npconn
*conn
)
189 if (stat(fid
->path
, &fid
->stat
) < 0)
192 if (S_ISDIR(fid
->stat
.st_mode
))
193 fid
->stat
.st_size
= 0;
202 f
= malloc(sizeof(*f
));
209 f
->direntname
= NULL
;
215 npfs_fiddestroy(Npfid
*fid
)
234 create_rerror(int ecode
)
238 if (strerror_r(ecode
, buf
, sizeof(buf
)))
239 strcpy(buf
, "unknown error");
241 np_werror(buf
, ecode
);
245 omode2uflags(u8 mode
)
278 ustat2qid(struct stat
*st
, Npqid
*qid
)
283 n
= sizeof(qid
->path
);
284 if (n
> sizeof(st
->st_ino
))
285 n
= sizeof(st
->st_ino
);
286 memmove(&qid
->path
, &st
->st_ino
, n
);
287 qid
->version
= st
->st_mtime
^ (st
->st_size
<< 8);
288 qid
->type
= ustat2qidtype(st
);
292 ustat2qidtype(struct stat
*st
)
297 if (S_ISDIR(st
->st_mode
))
300 if (S_ISLNK(st
->st_mode
))
307 umode2npmode(mode_t umode
, int dotu
)
336 npstat2umode(Npstat
*st
, int dotu
)
347 if (npmode
& Dmsymlink
)
349 if (npmode
& Dmsocket
)
351 if (npmode
& Dmnamedpipe
)
353 if (npmode
& Dmdevice
) {
354 if (st
->extension
.str
[0] == 'c')
364 if (npmode
& Dmsetuid
)
366 if (npmode
& Dmsetgid
)
373 ustat2npwstat(char *path
, struct stat
*st
, Npwstat
*wstat
, int dotu
)
380 memset(wstat
, 0, sizeof(*wstat
));
381 ustat2qid(st
, &wstat
->qid
);
382 wstat
->mode
= umode2npmode(st
->st_mode
, dotu
);
383 wstat
->atime
= st
->st_atime
;
384 wstat
->mtime
= st
->st_mtime
;
385 wstat
->length
= st
->st_size
;
387 u
= np_uid2user(st
->st_uid
);
388 g
= np_gid2group(st
->st_gid
);
390 wstat
->uid
= u
?u
->uname
:"???";
391 wstat
->gid
= g
?g
->gname
:"???";
394 wstat
->extension
= NULL
;
396 wstat
->n_uid
= st
->st_uid
;
397 wstat
->n_gid
= st
->st_gid
;
399 if (wstat
->mode
& Dmsymlink
) {
400 err
= readlink(path
, ext
, sizeof(ext
) - 1);
405 } else if (wstat
->mode
& Dmdevice
) {
406 snprintf(ext
, sizeof(ext
), "%c %llu %llu",
407 S_ISCHR(st
->st_mode
)?'c':'b',
408 MAJOR(st
->st_rdev
), MINOR(st
->st_rdev
));
413 wstat
->extension
= strdup(ext
);
416 s
= strrchr(path
, '/');
424 npfs_attach(Npfid
*nfid
, Npfid
*nafid
, Npstr
*uname
, Npstr
*aname
)
436 np_werror(Enoauth
, EIO
);
440 fid
= npfs_fidalloc();
442 user
= np_strdup(uname
);
443 nfid
->user
= np_uname2user(user
);
447 np_werror(Eunknownuser
, EIO
);
450 // np_change_user(nfid->user);
453 if (aname
->len
==0 || *aname
->str
!='/')
454 fid
->path
= strdup("/");
456 fid
->path
= np_strdup(aname
);
465 ustat2qid(&fid
->stat
, &qid
);
466 ret
= np_create_rattach(&qid
);
474 npfs_clone(Npfid
*fid
, Npfid
*newfid
)
479 nf
= npfs_fidalloc();
480 nf
->path
= strdup(f
->path
);
488 npfs_walk(Npfid
*fid
, Npstr
* wname
, Npqid
*wqid
)
496 // np_change_user(fid->user);
502 path
= malloc(n
+ wname
->len
+ 2);
503 memcpy(path
, f
->path
, n
);
505 memcpy(path
+ n
+ 1, wname
->str
, wname
->len
);
506 path
[n
+ wname
->len
+ 1] = '\0';
508 if (stat(path
, &st
) < 0) {
510 create_rerror(errno
);
516 ustat2qid(&st
, wqid
);
522 npfs_open(Npfid
*fid
, u8 mode
)
529 // np_change_user(fid->user);
530 if ((err
= fidstat(f
)) < 0)
533 if (S_ISDIR(f
->stat
.st_mode
)) {
534 f
->dir
= opendir(f
->path
);
536 create_rerror(errno
);
538 f
->fd
= open(f
->path
, omode2uflags(mode
));
540 create_rerror(errno
);
548 ustat2qid(&f
->stat
, &qid
);
549 return np_create_ropen(&qid
, 0);
553 npfs_create(Npfid
*fid
, Npstr
* name
, u32 perm
, u8 mode
)
565 if ((err
= fidstat(f
)) < 0)
569 npath
= malloc(n
+ name
->len
+ 2);
570 memmove(npath
, f
->path
, n
);
572 memmove(npath
+ n
+ 1, name
->str
, name
->len
);
573 npath
[n
+ name
->len
+ 1] = '\0';
575 if (stat(npath
, &st
)==0 || errno
!=ENOENT
) {
576 np_werror(Eexist
, EEXIST
);
581 && perm
&(Dmnamedpipe
|Dmsymlink
|Dmlink
|Dmdevice
|Dmsocket
)) {
582 np_werror(Eperm
, EPERM
);
587 if (mkdir(npath
, perm
& 0777) < 0) {
588 create_rerror(errno
);
592 if (stat(npath
, &f
->stat
) < 0) {
593 create_rerror(errno
);
598 f
->dir
= opendir(npath
);
600 create_rerror(errno
);
604 } else if (perm
& Dmnamedpipe
) {
605 if (mknod(npath
, S_IFIFO
| (perm
&0777), 0) < 0) {
606 create_rerror(errno
);
610 if (stat(npath
, &f
->stat
) < 0) {
611 create_rerror(errno
);
615 } else if (perm
& (Dmsymlink
|Dmlink
|Dmdevice
)) {
616 // do nothing, the files are created by wstat
618 if (perm
& Dmsymlink
)
619 qid
.type
= Qtsymlink
;
620 else if (perm
& Dmlink
)
627 } else if (perm
& Dmsocket
) {
628 np_werror(Ecreatesocket
, EIO
);
631 f
->fd
= open(npath
, O_CREAT
|O_EXCL
|omode2uflags(mode
),
634 create_rerror(errno
);
638 if (stat(npath
, &f
->stat
) < 0) {
639 create_rerror(errno
);
650 if ((perm
& (Dmsymlink
|Dmlink
|Dmdevice
)) == 0)
651 ustat2qid(&f
->stat
, &qid
);
653 ret
= np_create_rcreate(&qid
, 0);
661 npfs_read_dir(Fid
*f
, u8
* buf
, u64 offset
, u32 count
, int dotu
)
665 struct dirent
*dirent
;
674 plen
= strlen(f
->path
);
677 dname
= f
->direntname
;
680 dirent
= readdir(f
->dir
);
684 if (strcmp(dirent
->d_name
, ".") == 0
685 || strcmp(dirent
->d_name
, "..") == 0)
688 dname
= dirent
->d_name
;
691 path
= malloc(plen
+ strlen(dname
) + 2);
692 sprintf(path
, "%s/%s", f
->path
, dname
);
694 if (stat(path
, &st
) < 0) {
696 create_rerror(errno
);
700 ustat2npwstat(path
, &st
, &wstat
, dotu
);
701 i
= np_serialize_stat(&wstat
, buf
+ n
, count
- n
- 1, dotu
);
702 free(wstat
.extension
);
714 f
->direntname
= NULL
;
718 f
->direntname
= strdup(dirent
->d_name
);
725 npfs_read(Npfid
*fid
, u64 offset
, u32 count
, Npreq
*req
)
732 ret
= np_alloc_rread(count
);
733 // np_change_user(fid->user);
735 n
= npfs_read_dir(f
, ret
->data
, offset
, count
, fid
->conn
->dotu
);
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 // np_change_user(fid->user);
759 n
= pwrite(f
->fd
, data
, count
, offset
);
761 create_rerror(errno
);
763 return np_create_rwrite(n
);
767 npfs_clunk(Npfid
*fid
)
773 ret
= np_create_rclunk();
779 npfs_remove(Npfid
*fid
)
785 // np_change_user(fid->user);
786 if (remove(f
->path
) < 0) {
787 create_rerror(errno
);
791 ret
= np_create_rremove();
800 npfs_stat(Npfid
*fid
)
808 // np_change_user(fid->user);
813 ustat2npwstat(f
->path
, &f
->stat
, &wstat
, fid
->conn
->dotu
);
815 ret
= np_create_rstat(&wstat
, fid
->conn
->dotu
);
816 free(wstat
.extension
);
822 npfs_create_special(Npfid
*fid
, Npstat
*stat
)
825 int mode
, major
, minor
;
835 if (!stat
->extension
.len
) {
836 np_werror(Enoextension
, EIO
);
840 umode
= npstat2umode(stat
, fid
->conn
->dotu
);
842 ext
= np_strdup(&stat
->extension
);
843 if (stat
->mode
& Dmsymlink
) {
844 if (symlink(ext
, f
->path
) < 0) {
845 create_rerror(errno
);
848 } else if (stat
->mode
& Dmlink
) {
849 if (sscanf(ext
, "%d", &nfid
) == 0) {
850 np_werror(Eformat
, EIO
);
854 ofid
= np_fid_find(fid
->conn
, nfid
);
856 np_werror(Eunknownfid
, EIO
);
861 if (link(of
->path
, f
->path
) < 0) {
862 create_rerror(errno
);
865 } else if (stat
->mode
& Dmdevice
) {
866 if (sscanf(ext
, "%c %u %u", &ctype
, &major
, &minor
) != 3) {
867 np_werror(Eformat
, EIO
);
882 np_werror(Eformat
, EIO
);
886 mode
|= stat
->mode
& 0777;
887 if (mknod(f
->path
, mode
, MKDEV(major
, minor
)) < 0) {
888 create_rerror(errno
);
894 if (chmod(f
->path
, umode
) < 0) {
895 create_rerror(errno
);
905 ret
= np_create_rwstat();
913 npfs_wstat(Npfid
*fid
, Npstat
*stat
)
927 // np_change_user(fid->user);
928 if (f
->omode
!=-1 && f
->omode
&Ouspecial
&& fid
->conn
->dotu
) {
929 ret
= npfs_create_special(fid
, stat
);
939 if (fid
->conn
->dotu
) {
947 if (uid
== -1 && stat
->uid
.len
) {
948 s
= np_strdup(&stat
->uid
);
949 user
= np_uname2user(s
);
952 np_werror(Eunknownuser
, EIO
);
959 if (gid
== -1 && stat
->gid
.len
) {
960 s
= np_strdup(&stat
->gid
);
961 group
= np_gname2group(s
);
964 np_werror(Eunknownuser
, EIO
);
971 if (stat
->mode
!= (u32
)~0) {
972 if (stat
->mode
&Dmdir
&& !S_ISDIR(f
->stat
.st_mode
)) {
973 np_werror(Edirchange
, EIO
);
977 if (chmod(f
->path
, npstat2umode(stat
, fid
->conn
->dotu
)) < 0) {
978 create_rerror(errno
);
983 if (stat
->mtime
!= (u32
)~0) {
985 tb
.modtime
= stat
->mtime
;
986 if (utime(f
->path
, &tb
) < 0) {
987 create_rerror(errno
);
993 if (chown(f
->path
, uid
, gid
) < 0) {
994 create_rerror(errno
);
999 if (stat
->name
.len
!= 0) {
1000 p
= strrchr(f
->path
, '/');
1002 p
= f
->path
+ strlen(f
->path
);
1004 npath
= malloc(stat
->name
.len
+ (p
- f
->path
) + 2);
1005 memcpy(npath
, f
->path
, p
- f
->path
);
1006 npath
[p
- f
->path
] = '/';
1007 memcpy(npath
+ (p
- f
->path
) + 1, stat
->name
.str
, stat
->name
.len
);
1008 npath
[(p
- f
->path
) + 1 + stat
->name
.len
] = 0;
1009 if (strcmp(npath
, f
->path
) != 0) {
1010 if (rename(f
->path
, npath
) < 0) {
1011 create_rerror(errno
);
1020 if (stat
->length
!= ~0) {
1021 if (truncate(f
->path
, stat
->length
) < 0) {
1022 create_rerror(errno
);
1026 ret
= np_create_rwstat();