- filled in group field, previously missing.
[npfs.git] / fs / cpu.c
blob9dbdc615e41f931e2afd484f657b05d285959316
1 /*
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
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 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <pthread.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <dirent.h>
33 #include <fcntl.h>
34 #include <utime.h>
35 #include <linux/kdev_t.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netdb.h>
39 #include <arpa/inet.h>
40 #include "npfs.h"
42 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
44 typedef struct Fid Fid;
46 struct Fid {
47 char* path;
48 int omode;
49 int fd;
50 DIR* dir;
51 int diroffset;
52 char* direntname;
53 struct stat stat;
56 Npsrv *srv;
57 int debuglevel;
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";
64 //char *E = "";
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);
87 static int
88 get_local_addr(char *hostname, char *addr, int addrlen)
90 int sock;
91 socklen_t n;
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);
102 return -1;
105 saddr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
106 if (0 > connect (sock, (struct sockaddr *) &saddr, sizeof (saddr))) {
107 perror ("connect");
108 return -1;
111 n = sizeof(saddr);
112 getsockname(sock, (struct sockaddr *) &saddr, &n);
113 snprintf(addr, addrlen, "%s", inet_ntoa(saddr.sin_addr));
114 shutdown(sock, SHUT_RDWR);
115 return 0;
119 main(int argc, char **argv)
121 int i;
122 int port, nwthreads;
123 pid_t pid;
124 char sport[20], hostname[20];
125 char **sargv;
126 Npuser *user;
128 user = np_uid2user(getuid());
129 port = 0;
130 nwthreads = 16;
131 srv = np_socksrv_create_tcp(nwthreads, &port);
132 if (!srv)
133 return -1;
134 srv->dotu = 1;
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;
149 np_srv_start(srv);
151 pid = fork();
152 if (pid < 0)
153 return -1;
154 else if (pid != 0)
155 while (1)
156 sleep(100);
158 /* child */
159 if (get_local_addr(argv[1], hostname, sizeof(hostname)))
160 return -1;
162 sprintf(sport, "%d", port);
163 sargv = calloc(argc + 6, sizeof(char *));
164 sargv[0] = "ssh";
165 sargv[1] = "-t";
166 sargv[2] = argv[1];
167 sargv[3] = "/usr/sbin/cpuhelper";
168 sargv[4] = user->uname;
169 sargv[5] = hostname;
170 sargv[6] = sport;
172 for(i = 2; i < argc; i++)
173 sargv[i+5] = argv[i];
175 execvp("ssh", sargv);
177 return 0;
180 static void
181 npfs_connclose(Npconn *conn)
183 exit(0);
186 static int
187 fidstat(Fid *fid)
189 if (stat(fid->path, &fid->stat) < 0)
190 return errno;
192 if (S_ISDIR(fid->stat.st_mode))
193 fid->stat.st_size = 0;
195 return 0;
198 static Fid*
199 npfs_fidalloc() {
200 Fid *f;
202 f = malloc(sizeof(*f));
204 f->path = NULL;
205 f->omode = -1;
206 f->fd = -1;
207 f->dir = NULL;
208 f->diroffset = 0;
209 f->direntname = NULL;
211 return f;
214 static void
215 npfs_fiddestroy(Npfid *fid)
217 Fid *f;
219 f = fid->aux;
220 if (!f)
221 return;
223 if (f->fd != -1)
224 close(f->fd);
226 if (f->dir)
227 closedir(f->dir);
229 free(f->path);
230 free(f);
233 static void
234 create_rerror(int ecode)
236 char buf[256];
238 if (strerror_r(ecode, buf, sizeof(buf)))
239 strcpy(buf, "unknown error");
241 np_werror(buf, ecode);
244 static int
245 omode2uflags(u8 mode)
247 int ret;
249 ret = 0;
250 switch (mode & 3) {
251 case Oread:
252 ret = O_RDONLY;
253 break;
255 case Ordwr:
256 ret = O_RDWR;
257 break;
259 case Owrite:
260 ret = O_WRONLY;
261 break;
263 case Oexec:
264 ret = O_RDONLY;
265 break;
268 if (mode & Otrunc)
269 ret |= O_TRUNC;
271 if (mode & Oappend)
272 ret |= O_APPEND;
274 return ret;
277 static void
278 ustat2qid(struct stat *st, Npqid *qid)
280 int n;
282 qid->path = 0;
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);
291 static u8
292 ustat2qidtype(struct stat *st)
294 u8 ret;
296 ret = 0;
297 if (S_ISDIR(st->st_mode))
298 ret |= Qtdir;
300 if (S_ISLNK(st->st_mode))
301 ret |= Qtsymlink;
303 return ret;
306 static u32
307 umode2npmode(mode_t umode, int dotu)
309 u32 ret;
311 ret = umode & 0777;
312 if (S_ISDIR(umode))
313 ret |= Dmdir;
315 if (dotu) {
316 if (S_ISLNK(umode))
317 ret |= Dmsymlink;
318 if (S_ISSOCK(umode))
319 ret |= Dmsocket;
320 if (S_ISFIFO(umode))
321 ret |= Dmnamedpipe;
322 if (S_ISBLK(umode))
323 ret |= Dmdevice;
324 if (S_ISCHR(umode))
325 ret |= Dmdevice;
326 if (umode & S_ISUID)
327 ret |= Dmsetuid;
328 if (umode & S_ISGID)
329 ret |= Dmsetgid;
332 return ret;
335 static mode_t
336 npstat2umode(Npstat *st, int dotu)
338 u32 npmode;
339 mode_t ret;
341 npmode = st->mode;
342 ret = npmode & 0777;
343 if (npmode & Dmdir)
344 ret |= S_IFDIR;
346 if (dotu) {
347 if (npmode & Dmsymlink)
348 ret |= S_IFLNK;
349 if (npmode & Dmsocket)
350 ret |= S_IFSOCK;
351 if (npmode & Dmnamedpipe)
352 ret |= S_IFIFO;
353 if (npmode & Dmdevice) {
354 if (st->extension.str[0] == 'c')
355 ret |= S_IFCHR;
356 else
357 ret |= S_IFBLK;
361 if (!(ret&~0777))
362 ret |= S_IFREG;
364 if (npmode & Dmsetuid)
365 ret |= S_ISUID;
366 if (npmode & Dmsetgid)
367 ret |= S_ISGID;
369 return ret;
372 static void
373 ustat2npwstat(char *path, struct stat *st, Npwstat *wstat, int dotu)
375 int err;
376 Npuser *u;
377 Npgroup *g;
378 char *s, ext[256];
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:"???";
392 wstat->muid = "";
394 wstat->extension = NULL;
395 if (dotu) {
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);
401 if (err < 0)
402 err = 0;
404 ext[err] = '\0';
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));
409 } else {
410 ext[0] = '\0';
413 wstat->extension = strdup(ext);
416 s = strrchr(path, '/');
417 if (s)
418 wstat->name = s + 1;
419 else
420 wstat->name = path;
423 static Npfcall*
424 npfs_attach(Npfid *nfid, Npfid *nafid, Npstr *uname, Npstr *aname)
426 int err;
427 Npfcall* ret;
428 Fid *fid;
429 Npqid qid;
430 char *user;
432 user = NULL;
433 ret = NULL;
435 if (nafid != NULL) {
436 np_werror(Enoauth, EIO);
437 goto done;
440 fid = npfs_fidalloc();
441 fid->omode = -1;
442 user = np_strdup(uname);
443 nfid->user = np_uname2user(user);
444 free(user);
445 if (!nfid->user) {
446 free(fid);
447 np_werror(Eunknownuser, EIO);
448 goto done;
450 // np_change_user(nfid->user);
452 fid->omode = -1;
453 if (aname->len==0 || *aname->str!='/')
454 fid->path = strdup("/");
455 else
456 fid->path = np_strdup(aname);
458 nfid->aux = fid;
459 err = fidstat(fid);
460 if (err < 0) {
461 create_rerror(err);
462 goto done;
465 ustat2qid(&fid->stat, &qid);
466 ret = np_create_rattach(&qid);
467 np_fid_incref(nfid);
469 done:
470 return ret;
473 static int
474 npfs_clone(Npfid *fid, Npfid *newfid)
476 Fid *f, *nf;
478 f = fid->aux;
479 nf = npfs_fidalloc();
480 nf->path = strdup(f->path);
481 newfid->aux = nf;
483 return 1;
487 static int
488 npfs_walk(Npfid *fid, Npstr* wname, Npqid *wqid)
490 int n;
491 Fid *f;
492 struct stat st;
493 char *path;
495 f = fid->aux;
496 // np_change_user(fid->user);
497 n = fidstat(f);
498 if (n < 0)
499 create_rerror(n);
501 n = strlen(f->path);
502 path = malloc(n + wname->len + 2);
503 memcpy(path, f->path, n);
504 path[n] = '/';
505 memcpy(path + n + 1, wname->str, wname->len);
506 path[n + wname->len + 1] = '\0';
508 if (stat(path, &st) < 0) {
509 free(path);
510 create_rerror(errno);
511 return 0;
514 free(f->path);
515 f->path = path;
516 ustat2qid(&st, wqid);
518 return 1;
521 static Npfcall*
522 npfs_open(Npfid *fid, u8 mode)
524 int err;
525 Fid *f;
526 Npqid qid;
528 f = fid->aux;
529 // np_change_user(fid->user);
530 if ((err = fidstat(f)) < 0)
531 create_rerror(err);
533 if (S_ISDIR(f->stat.st_mode)) {
534 f->dir = opendir(f->path);
535 if (!f->dir)
536 create_rerror(errno);
537 } else {
538 f->fd = open(f->path, omode2uflags(mode));
539 if (f->fd < 0)
540 create_rerror(errno);
543 err = fidstat(f);
544 if (err < 0)
545 create_rerror(err);
547 f->omode = mode;
548 ustat2qid(&f->stat, &qid);
549 return np_create_ropen(&qid, 0);
552 static Npfcall*
553 npfs_create(Npfid *fid, Npstr* name, u32 perm, u8 mode)
555 int n, err, omode;
556 Fid *f;
557 Npfcall *ret;
558 Npqid qid;
559 char *npath;
560 struct stat st;
562 ret = NULL;
563 omode = mode;
564 f = fid->aux;
565 if ((err = fidstat(f)) < 0)
566 create_rerror(err);
568 n = strlen(f->path);
569 npath = malloc(n + name->len + 2);
570 memmove(npath, f->path, n);
571 npath[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);
577 goto out;
580 if (!fid->conn->dotu
581 && perm&(Dmnamedpipe|Dmsymlink|Dmlink|Dmdevice|Dmsocket)) {
582 np_werror(Eperm, EPERM);
583 goto out;
586 if (perm & Dmdir) {
587 if (mkdir(npath, perm & 0777) < 0) {
588 create_rerror(errno);
589 goto out;
592 if (stat(npath, &f->stat) < 0) {
593 create_rerror(errno);
594 rmdir(npath);
595 goto out;
598 f->dir = opendir(npath);
599 if (!f->dir) {
600 create_rerror(errno);
601 remove(npath);
602 goto out;
604 } else if (perm & Dmnamedpipe) {
605 if (mknod(npath, S_IFIFO | (perm&0777), 0) < 0) {
606 create_rerror(errno);
607 goto out;
610 if (stat(npath, &f->stat) < 0) {
611 create_rerror(errno);
612 remove(npath);
613 goto out;
615 } else if (perm & (Dmsymlink|Dmlink|Dmdevice)) {
616 // do nothing, the files are created by wstat
617 omode = Ouspecial;
618 if (perm & Dmsymlink)
619 qid.type = Qtsymlink;
620 else if (perm & Dmlink)
621 qid.type = Qtlink;
622 else
623 qid.type = Qttmp;
625 qid.version = ~0;
626 qid.path = ~0;
627 } else if (perm & Dmsocket) {
628 np_werror(Ecreatesocket, EIO);
629 goto out;
630 } else {
631 f->fd = open(npath, O_CREAT|O_EXCL|omode2uflags(mode),
632 perm & 0777);
633 if (f->fd < 0) {
634 create_rerror(errno);
635 goto out;
638 if (stat(npath, &f->stat) < 0) {
639 create_rerror(errno);
640 remove(npath);
641 goto out;
645 free(f->path);
646 f->path = npath;
647 f->omode = omode;
648 npath = NULL;
650 if ((perm & (Dmsymlink|Dmlink|Dmdevice)) == 0)
651 ustat2qid(&f->stat, &qid);
653 ret = np_create_rcreate(&qid, 0);
655 out:
656 free(npath);
657 return ret;
660 static u32
661 npfs_read_dir(Fid *f, u8* buf, u64 offset, u32 count, int dotu)
663 int i, n, plen;
664 char *dname, *path;
665 struct dirent *dirent;
666 struct stat st;
667 Npwstat wstat;
669 if (offset == 0) {
670 rewinddir(f->dir);
671 f->diroffset = 0;
674 plen = strlen(f->path);
675 n = 0;
676 dirent = NULL;
677 dname = f->direntname;
678 while (n < count) {
679 if (!dname) {
680 dirent = readdir(f->dir);
681 if (!dirent)
682 break;
684 if (strcmp(dirent->d_name, ".") == 0
685 || strcmp(dirent->d_name, "..") == 0)
686 continue;
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) {
695 free(path);
696 create_rerror(errno);
697 return 0;
700 ustat2npwstat(path, &st, &wstat, dotu);
701 i = np_serialize_stat(&wstat, buf + n, count - n - 1, dotu);
702 free(wstat.extension);
703 free(path);
704 path = NULL;
705 if (i==0)
706 break;
708 dname = NULL;
709 n += i;
712 if (f->direntname) {
713 free(f->direntname);
714 f->direntname = NULL;
717 if (dirent)
718 f->direntname = strdup(dirent->d_name);
720 f->diroffset += n;
721 return n;
724 static Npfcall*
725 npfs_read(Npfid *fid, u64 offset, u32 count, Npreq *req)
727 int n;
728 Fid *f;
729 Npfcall *ret;
731 f = fid->aux;
732 ret = np_alloc_rread(count);
733 // np_change_user(fid->user);
734 if (f->dir)
735 n = npfs_read_dir(f, ret->data, offset, count, fid->conn->dotu);
736 else {
737 n = pread(f->fd, ret->data, count, offset);
738 if (n < 0)
739 create_rerror(errno);
742 if (np_haserror()) {
743 free(ret);
744 ret = NULL;
745 } else
746 np_set_rread_count(ret, n);
748 return ret;
751 static Npfcall*
752 npfs_write(Npfid *fid, u64 offset, u32 count, u8 *data, Npreq *req)
754 int n;
755 Fid *f;
757 f = fid->aux;
758 // np_change_user(fid->user);
759 n = pwrite(f->fd, data, count, offset);
760 if (n < 0)
761 create_rerror(errno);
763 return np_create_rwrite(n);
766 static Npfcall*
767 npfs_clunk(Npfid *fid)
769 Fid *f;
770 Npfcall *ret;
772 f = fid->aux;
773 ret = np_create_rclunk();
774 np_fid_decref(fid);
775 return ret;
778 static Npfcall*
779 npfs_remove(Npfid *fid)
781 Fid *f;
782 Npfcall *ret;
784 f = fid->aux;
785 // np_change_user(fid->user);
786 if (remove(f->path) < 0) {
787 create_rerror(errno);
788 goto out;
791 ret = np_create_rremove();
793 out:
794 np_fid_decref(fid);
795 return ret;
799 static Npfcall*
800 npfs_stat(Npfid *fid)
802 int err;
803 Fid *f;
804 Npfcall *ret;
805 Npwstat wstat;
807 f = fid->aux;
808 // np_change_user(fid->user);
809 err = fidstat(f);
810 if (err < 0)
811 create_rerror(err);
813 ustat2npwstat(f->path, &f->stat, &wstat, fid->conn->dotu);
815 ret = np_create_rstat(&wstat, fid->conn->dotu);
816 free(wstat.extension);
818 return ret;
821 static Npfcall*
822 npfs_create_special(Npfid *fid, Npstat *stat)
824 int nfid, err;
825 int mode, major, minor;
826 char ctype;
827 mode_t umode;
828 Npfid *ofid;
829 Fid *f, *of;
830 Npfcall *ret;
831 char *ext;
833 ret = NULL;
834 f = fid->aux;
835 if (!stat->extension.len) {
836 np_werror(Enoextension, EIO);
837 return NULL;
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);
846 goto out;
848 } else if (stat->mode & Dmlink) {
849 if (sscanf(ext, "%d", &nfid) == 0) {
850 np_werror(Eformat, EIO);
851 goto out;
854 ofid = np_fid_find(fid->conn, nfid);
855 if (!ofid) {
856 np_werror(Eunknownfid, EIO);
857 goto out;
860 of = ofid->aux;
861 if (link(of->path, f->path) < 0) {
862 create_rerror(errno);
863 goto out;
865 } else if (stat->mode & Dmdevice) {
866 if (sscanf(ext, "%c %u %u", &ctype, &major, &minor) != 3) {
867 np_werror(Eformat, EIO);
868 goto out;
871 mode = 0;
872 switch (ctype) {
873 case 'c':
874 mode = S_IFCHR;
875 break;
877 case 'b':
878 mode = S_IFBLK;
879 break;
881 default:
882 np_werror(Eformat, EIO);
883 goto out;
886 mode |= stat->mode & 0777;
887 if (mknod(f->path, mode, MKDEV(major, minor)) < 0) {
888 create_rerror(errno);
889 goto out;
893 f->omode = 0;
894 if (chmod(f->path, umode) < 0) {
895 create_rerror(errno);
896 goto out;
899 err = fidstat(f);
900 if (err < 0) {
901 create_rerror(err);
902 goto out;
905 ret = np_create_rwstat();
906 out:
907 free(ext);
908 return ret;
912 static Npfcall*
913 npfs_wstat(Npfid *fid, Npstat *stat)
915 int err;
916 Fid *f;
917 Npfcall *ret;
918 uid_t uid;
919 gid_t gid;
920 char *npath, *p, *s;
921 Npuser *user;
922 Npgroup *group;
923 struct utimbuf tb;
925 ret = NULL;
926 f = fid->aux;
927 // np_change_user(fid->user);
928 if (f->omode!=-1 && f->omode&Ouspecial && fid->conn->dotu) {
929 ret = npfs_create_special(fid, stat);
930 goto out;
933 err = fidstat(f);
934 if (err < 0) {
935 create_rerror(err);
936 goto out;
939 if (fid->conn->dotu) {
940 uid = stat->n_uid;
941 gid = stat->n_gid;
942 } else {
943 uid = (uid_t) -1;
944 gid = (gid_t) -1;
947 if (uid == -1 && stat->uid.len) {
948 s = np_strdup(&stat->uid);
949 user = np_uname2user(s);
950 free(s);
951 if (!user) {
952 np_werror(Eunknownuser, EIO);
953 goto out;
956 uid = user->uid;
959 if (gid == -1 && stat->gid.len) {
960 s = np_strdup(&stat->gid);
961 group = np_gname2group(s);
962 free(s);
963 if (!group) {
964 np_werror(Eunknownuser, EIO);
965 goto out;
968 gid = group->gid;
971 if (stat->mode != (u32)~0) {
972 if (stat->mode&Dmdir && !S_ISDIR(f->stat.st_mode)) {
973 np_werror(Edirchange, EIO);
974 goto out;
977 if (chmod(f->path, npstat2umode(stat, fid->conn->dotu)) < 0) {
978 create_rerror(errno);
979 goto out;
983 if (stat->mtime != (u32)~0) {
984 tb.actime = 0;
985 tb.modtime = stat->mtime;
986 if (utime(f->path, &tb) < 0) {
987 create_rerror(errno);
988 goto out;
992 if (gid != -1) {
993 if (chown(f->path, uid, gid) < 0) {
994 create_rerror(errno);
995 goto out;
999 if (stat->name.len != 0) {
1000 p = strrchr(f->path, '/');
1001 if (!p)
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);
1012 goto out;
1015 free(f->path);
1016 f->path = npath;
1020 if (stat->length != ~0) {
1021 if (truncate(f->path, stat->length) < 0) {
1022 create_rerror(errno);
1023 goto out;
1026 ret = np_create_rwstat();
1028 out:
1029 return ret;