Fix typecast format warnings when printing the 9p debug information
[spfs.git] / fs / ufs.c
blobd891c8fc581b1fea90799d234f7fd297f3dffecf
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 * 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
24 #define _BSD_SOURCE
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <string.h>
33 #include <dirent.h>
34 #include <fcntl.h>
35 #include <utime.h>
36 #include <sys/mman.h>
37 #include "spfs.h"
39 #undef NPFS_USE_AIO
41 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
43 typedef struct Fid Fid;
45 struct Fid {
46 char* path;
47 int omode;
48 int fd;
49 DIR* dir;
50 int diroffset;
51 char* direntname;
52 void* aux; /* for mmapread */
53 struct stat stat;
56 Spsrv *srv;
57 int debuglevel;
58 int sameuser;
59 int mmapreads;
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";
66 //char *E = "";
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,
80 Spstr *extension);
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);
90 void
91 usage()
93 fprintf(stderr, "npfs: -d -s -p port -w nthreads\n");
94 exit(-1);
97 int
98 main(int argc, char **argv)
100 int c;
101 int port, nwthreads;
102 char *s;
104 port = 564;
105 nwthreads = 16;
106 while ((c = getopt(argc, argv, "dsmp:w:")) != -1) {
107 switch (c) {
108 case 'd':
109 debuglevel = 1;
110 break;
112 case 'p':
113 port = strtol(optarg, &s, 10);
114 if (*s != '\0')
115 usage();
116 break;
118 case 'w':
119 nwthreads = strtol(optarg, &s, 10);
120 if (*s != '\0')
121 usage();
122 break;
124 case 's':
125 sameuser = 1;
126 break;
128 case 'm':
129 mmapreads = 1;
130 break;
132 default:
133 usage();
137 srv = sp_socksrv_create_tcp(&port);
139 if (!srv)
140 return -1;
142 srv->dotu = 1;
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;
157 sp_srv_start(srv);
158 sp_poll_loop();
159 return 0;
162 static int
163 fidstat(Fid *fid)
165 if (lstat(fid->path, &fid->stat) < 0)
166 return errno;
168 if (S_ISDIR(fid->stat.st_mode))
169 fid->stat.st_size = 0;
171 return 0;
174 static Fid*
175 npfs_fidalloc() {
176 Fid *f;
178 f = malloc(sizeof(*f));
180 f->path = NULL;
181 f->omode = -1;
182 f->fd = -1;
183 f->dir = NULL;
184 f->diroffset = 0;
185 f->direntname = NULL;
187 return f;
190 static void
191 npfs_fiddestroy(Spfid *fid)
193 Fid *f;
195 f = fid->aux;
196 if (!f)
197 return;
199 if (f->fd != -1)
200 close(f->fd);
202 if (f->dir)
203 closedir(f->dir);
205 free(f->path);
206 free(f);
209 static void
210 create_rerror(int ecode)
212 char buf[256];
214 strerror_r(ecode, buf, sizeof(buf));
215 sp_werror(buf, ecode);
218 static int
219 omode2uflags(u8 mode)
221 int ret;
223 ret = 0;
224 switch (mode & 3) {
225 case Oread:
226 ret = O_RDONLY;
227 break;
229 case Ordwr:
230 ret = O_RDWR;
231 break;
233 case Owrite:
234 ret = O_WRONLY;
235 break;
237 case Oexec:
238 ret = O_RDONLY;
239 break;
242 if (mode & Otrunc)
243 ret |= O_TRUNC;
245 if (mode & Oappend)
246 ret |= O_APPEND;
248 if (mode & Oexcl)
249 ret |= O_EXCL;
251 return ret;
254 static void
255 ustat2qid(struct stat *st, Spqid *qid)
257 int n;
259 qid->path = 0;
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);
268 static u8
269 ustat2qidtype(struct stat *st)
271 u8 ret;
273 ret = 0;
274 if (S_ISDIR(st->st_mode))
275 ret |= Qtdir;
277 if (S_ISLNK(st->st_mode))
278 ret |= Qtsymlink;
280 return ret;
283 static u32
284 umode2npmode(mode_t umode, int dotu)
286 u32 ret;
288 ret = umode & 0777;
289 if (S_ISDIR(umode))
290 ret |= Dmdir;
292 if (dotu) {
293 if (S_ISLNK(umode))
294 ret |= Dmsymlink;
295 if (S_ISSOCK(umode))
296 ret |= Dmsocket;
297 if (S_ISFIFO(umode))
298 ret |= Dmnamedpipe;
299 if (S_ISBLK(umode))
300 ret |= Dmdevice;
301 if (S_ISCHR(umode))
302 ret |= Dmdevice;
303 if (umode & S_ISUID)
304 ret |= Dmsetuid;
305 if (umode & S_ISGID)
306 ret |= Dmsetgid;
309 return ret;
312 static mode_t
313 np2umode(u32 mode, Spstr *extension, int dotu)
315 mode_t ret;
317 ret = mode & 0777;
318 if (mode & Dmdir)
319 ret |= S_IFDIR;
321 if (dotu) {
322 if (mode & Dmsymlink)
323 ret |= S_IFLNK;
324 if (mode & Dmsocket)
325 ret |= S_IFSOCK;
326 if (mode & Dmnamedpipe)
327 ret |= S_IFIFO;
328 if (mode & Dmdevice) {
329 if (extension && extension->str[0] == 'c')
330 ret |= S_IFCHR;
331 else
332 ret |= S_IFBLK;
336 if (!(ret&~0777))
337 ret |= S_IFREG;
339 if (mode & Dmsetuid)
340 ret |= S_ISUID;
341 if (mode & Dmsetgid)
342 ret |= S_ISGID;
344 return ret;
347 static mode_t
348 npstat2umode(Spstat *st, int dotu)
350 return np2umode(st->mode, &st->extension, dotu);
353 static void
354 ustat2npwstat(char *path, struct stat *st, Spwstat *wstat, int dotu, Spuserpool *up)
356 int err;
357 Spuser *u;
358 Spgroup *g;
359 char *s, ext[256];
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:"???";
373 wstat->muid = "";
375 wstat->extension = NULL;
376 if (dotu) {
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);
382 if (err < 0)
383 err = 0;
385 ext[err] = '\0';
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));
390 } else {
391 ext[0] = '\0';
394 wstat->extension = strdup(ext);
397 s = strrchr(path, '/');
398 if (s)
399 wstat->name = s + 1;
400 else
401 wstat->name = path;
404 static inline void
405 npfs_change_user(Spuser *user)
407 if (!sameuser)
408 sp_change_user(user);
411 static Spfcall*
412 npfs_attach(Spfid *nfid, Spfid *nafid, Spstr *uname, Spstr *aname, u32 n_uname)
414 int err;
415 Spfcall* ret;
416 Fid *fid;
417 Spqid qid;
418 char *user;
420 user = NULL;
421 ret = NULL;
423 if (nafid != NULL) {
424 sp_werror(Enoauth, EIO);
425 goto done;
428 fid = npfs_fidalloc();
429 fid->omode = -1;
430 npfs_change_user(nfid->user);
432 fid->omode = -1;
433 if (aname->len==0 || *aname->str!='/')
434 fid->path = strdup("/");
435 else
436 fid->path = sp_strdup(aname);
438 nfid->aux = fid;
439 err = fidstat(fid);
440 if (err < 0) {
441 create_rerror(err);
442 goto done;
445 ustat2qid(&fid->stat, &qid);
446 ret = sp_create_rattach(&qid);
447 sp_fid_incref(nfid);
449 done:
450 return ret;
453 static int
454 npfs_clone(Spfid *fid, Spfid *newfid)
456 Fid *f, *nf;
458 f = fid->aux;
459 nf = npfs_fidalloc();
460 nf->path = strdup(f->path);
461 newfid->aux = nf;
463 return 1;
467 static int
468 npfs_walk(Spfid *fid, Spstr* wname, Spqid *wqid)
470 int n;
471 Fid *f;
472 struct stat st;
473 char *path;
475 f = fid->aux;
476 npfs_change_user(fid->user);
477 n = fidstat(f);
478 if (n < 0)
479 create_rerror(n);
481 n = strlen(f->path);
482 path = malloc(n + wname->len + 2);
483 memcpy(path, f->path, n);
484 path[n] = '/';
485 memcpy(path + n + 1, wname->str, wname->len);
486 path[n + wname->len + 1] = '\0';
488 if (lstat(path, &st) < 0) {
489 free(path);
490 create_rerror(errno);
491 return 0;
494 free(f->path);
495 f->path = path;
496 ustat2qid(&st, wqid);
498 return 1;
501 static Spfcall*
502 npfs_open(Spfid *fid, u8 mode)
504 int err;
505 Fid *f;
506 Spqid qid;
508 f = fid->aux;
509 npfs_change_user(fid->user);
510 if ((err = fidstat(f)) < 0)
511 create_rerror(err);
513 if (S_ISDIR(f->stat.st_mode)) {
514 f->dir = opendir(f->path);
515 if (!f->dir)
516 create_rerror(errno);
517 } else {
518 f->fd = open(f->path, omode2uflags(mode));
519 if (f->fd < 0)
520 create_rerror(errno);
523 err = fidstat(f);
524 if (err < 0)
525 create_rerror(err);
527 f->omode = mode;
528 ustat2qid(&f->stat, &qid);
529 return sp_create_ropen(&qid, 0);
532 static int
533 npfs_create_special(Spfid *fid, char *path, u32 perm, Spstr *extension)
535 int nfid, err;
536 int nmode, major, minor;
537 char ctype;
538 mode_t umode;
539 Spfid *ofid;
540 Fid *f, *of;
541 char *ext;
543 f = fid->aux;
544 if (!perm&Dmnamedpipe && !extension->len) {
545 sp_werror(Enoextension, EIO);
546 return -1;
549 umode = np2umode(perm, extension, fid->conn->dotu);
550 ext = sp_strdup(extension);
551 if (perm & Dmsymlink) {
552 if (symlink(ext, path) < 0) {
553 err = errno;
554 fprintf(stderr, "symlink %s %s %d\n", ext, path, err);
555 create_rerror(err);
556 goto error;
558 } else if (perm & Dmlink) {
559 if (sscanf(ext, "%d", &nfid) == 0) {
560 sp_werror(Eformat, EIO);
561 goto error;
564 ofid = sp_fid_find(fid->conn, nfid);
565 if (!ofid) {
566 sp_werror(Eunknownfid, EIO);
567 goto error;
570 of = ofid->aux;
571 if (link(of->path, path) < 0) {
572 create_rerror(errno);
573 goto error;
575 } else if (perm & Dmdevice) {
576 if (sscanf(ext, "%c %u %u", &ctype, &major, &minor) != 3) {
577 sp_werror(Eformat, EIO);
578 goto error;
581 nmode = 0;
582 switch (ctype) {
583 case 'c':
584 nmode = S_IFCHR;
585 break;
587 case 'b':
588 nmode = S_IFBLK;
589 break;
591 default:
592 sp_werror(Eformat, EIO);
593 goto error;
596 nmode |= perm & 0777;
597 if (mknod(path, nmode, makedev(major, minor)) < 0) {
598 create_rerror(errno);
599 goto error;
601 } else if (perm & Dmnamedpipe) {
602 if (mknod(path, S_IFIFO | (umode&0777), 0) < 0) {
603 create_rerror(errno);
604 goto error;
608 f->omode = 0;
609 if (!perm&Dmsymlink && chmod(path, umode)<0) {
610 create_rerror(errno);
611 goto error;
614 free(ext);
615 return 0;
617 error:
618 free(ext);
619 return -1;
623 static Spfcall*
624 npfs_create(Spfid *fid, Spstr *name, u32 perm, u8 mode, Spstr *extension)
626 int n, err, omode;
627 Fid *f;
628 Spfcall *ret;
629 Spqid qid;
630 char *npath;
631 struct stat st;
633 ret = NULL;
634 omode = mode;
635 f = fid->aux;
636 if ((err = fidstat(f)) < 0)
637 create_rerror(err);
639 n = strlen(f->path);
640 npath = malloc(n + name->len + 2);
641 memmove(npath, f->path, n);
642 npath[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);
648 goto out;
651 if (perm & Dmdir) {
652 if (mkdir(npath, perm & 0777) < 0) {
653 create_rerror(errno);
654 goto out;
657 if (lstat(npath, &f->stat) < 0) {
658 create_rerror(errno);
659 rmdir(npath);
660 goto out;
663 f->dir = opendir(npath);
664 if (!f->dir) {
665 create_rerror(errno);
666 remove(npath);
667 goto out;
669 } else if (perm & (Dmnamedpipe|Dmsymlink|Dmlink|Dmdevice)) {
670 if (npfs_create_special(fid, npath, perm, extension) < 0)
671 goto out;
673 if (lstat(npath, &f->stat) < 0) {
674 create_rerror(errno);
675 remove(npath);
676 goto out;
678 } else {
679 f->fd = open(npath, O_CREAT|omode2uflags(mode),
680 perm & 0777);
681 if (f->fd < 0) {
682 create_rerror(errno);
683 goto out;
686 if (lstat(npath, &f->stat) < 0) {
687 create_rerror(errno);
688 remove(npath);
689 goto out;
693 free(f->path);
694 f->path = npath;
695 f->omode = omode;
696 npath = NULL;
697 ustat2qid(&f->stat, &qid);
698 ret = sp_create_rcreate(&qid, 0);
700 out:
701 free(npath);
702 return ret;
705 static u32
706 npfs_read_dir(Spfid *fid, u8* buf, u64 offset, u32 count, int dotu)
708 int i, n, plen;
709 char *dname, *path;
710 struct dirent *dirent;
711 struct stat st;
712 Fid *f;
713 Spwstat wstat;
715 f = fid->aux;
716 if (offset == 0) {
717 rewinddir(f->dir);
718 f->diroffset = 0;
721 plen = strlen(f->path);
722 n = 0;
723 dirent = NULL;
724 dname = f->direntname;
725 while (n < count) {
726 if (!dname) {
727 dirent = readdir(f->dir);
728 if (!dirent)
729 break;
731 if (strcmp(dirent->d_name, ".") == 0
732 || strcmp(dirent->d_name, "..") == 0)
733 continue;
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) {
742 free(path);
743 create_rerror(errno);
744 return 0;
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);
750 free(path);
751 path = NULL;
752 if (i==0)
753 break;
755 dname = NULL;
756 n += i;
759 if (f->direntname) {
760 free(f->direntname);
761 f->direntname = NULL;
764 if (dirent)
765 f->direntname = strdup(dirent->d_name);
767 f->diroffset += n;
768 return n;
771 static Spfcall*
772 npfs_read(Spfid *fid, u64 offset, u32 count, Spreq *req)
774 int n;
775 Fid *f;
776 Spfcall *ret;
778 f = fid->aux;
779 ret = sp_alloc_rread(count);
780 npfs_change_user(fid->user);
781 if (f->dir)
782 n = npfs_read_dir(fid, ret->data, offset, count, fid->conn->dotu);
783 else {
784 if(mmapreads) {
785 struct stat s;
786 n = count;
787 if(!f->aux) {
788 fstat(f->fd, &s);
789 f->aux=mmap(0, s.st_size, PROT_READ,
790 MAP_SHARED, f->fd, 0);
791 if(f->aux < 0) {
792 create_rerror(errno);
793 goto error;
796 if(offset+count > s.st_size)
797 n = s.st_size-offset;
798 if(n>0)
799 memcpy(ret->data, f->aux+offset, n);
800 else
801 n = 0;
802 } else {
803 n = pread(f->fd, ret->data, count, offset);
804 if (n < 0)
805 create_rerror(errno);
809 error:
810 if (sp_haserror()) {
811 free(ret);
812 ret = NULL;
813 } else
814 sp_set_rread_count(ret, n);
816 return ret;
819 static Spfcall*
820 npfs_write(Spfid *fid, u64 offset, u32 count, u8 *data, Spreq *req)
822 int n;
823 Fid *f;
825 f = fid->aux;
826 npfs_change_user(fid->user);
828 n = pwrite(f->fd, data, count, offset);
829 if (n < 0)
830 create_rerror(errno);
832 return sp_create_rwrite(n);
835 static Spfcall*
836 npfs_clunk(Spfid *fid)
838 Fid *f;
839 Spfcall *ret;
841 f = fid->aux;
842 ret = sp_create_rclunk();
843 // sp_fid_decref(fid);
844 return ret;
847 static Spfcall*
848 npfs_remove(Spfid *fid)
850 Fid *f;
851 Spfcall *ret;
853 ret = NULL;
854 f = fid->aux;
855 npfs_change_user(fid->user);
856 if (remove(f->path) < 0) {
857 create_rerror(errno);
858 goto out;
861 ret = sp_create_rremove();
863 out:
864 // sp_fid_decref(fid);
865 return ret;
869 static Spfcall*
870 npfs_stat(Spfid *fid)
872 int err;
873 Fid *f;
874 Spfcall *ret;
875 Spwstat wstat;
877 f = fid->aux;
878 npfs_change_user(fid->user);
879 err = fidstat(f);
880 if (err < 0)
881 create_rerror(err);
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);
888 return ret;
891 static Spfcall*
892 npfs_wstat(Spfid *fid, Spstat *stat)
894 int err;
895 Fid *f;
896 Spfcall *ret;
897 uid_t uid;
898 gid_t gid;
899 char *npath, *p, *s;
900 Spuser *user;
901 Spgroup *group;
902 struct utimbuf tb;
903 Spuserpool *up;
905 ret = NULL;
906 f = fid->aux;
907 up = fid->conn->srv->upool;
908 npfs_change_user(fid->user);
909 err = fidstat(f);
910 if (err < 0) {
911 create_rerror(err);
912 goto out;
915 if (fid->conn->dotu) {
916 uid = stat->n_uid;
917 gid = stat->n_gid;
918 } else {
919 uid = (uid_t) -1;
920 gid = (gid_t) -1;
923 if (uid == -1 && stat->uid.len) {
924 s = sp_strdup(&stat->uid);
925 user = up->uname2user(up, s);
926 free(s);
927 if (!user) {
928 sp_werror(Eunknownuser, EIO);
929 goto out;
932 uid = user->uid;
935 if (gid == -1 && stat->gid.len) {
936 s = sp_strdup(&stat->gid);
937 group = up->gname2group(up, s);
938 free(s);
939 if (!group) {
940 sp_werror(Eunknownuser, EIO);
941 goto out;
944 gid = group->gid;
947 if (stat->mode != (u32)~0) {
948 if (stat->mode&Dmdir && !S_ISDIR(f->stat.st_mode)) {
949 sp_werror(Edirchange, EIO);
950 goto out;
953 if (chmod(f->path, npstat2umode(stat, fid->conn->dotu)) < 0) {
954 create_rerror(errno);
955 goto out;
959 if (stat->mtime != (u32)~0) {
960 tb.actime = 0;
961 tb.modtime = stat->mtime;
962 if (utime(f->path, &tb) < 0) {
963 create_rerror(errno);
964 goto out;
968 if (gid != -1) {
969 if (chown(f->path, uid, gid) < 0) {
970 create_rerror(errno);
971 goto out;
975 if (stat->name.len != 0) {
976 p = strrchr(f->path, '/');
977 if (!p)
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);
988 goto out;
991 free(f->path);
992 f->path = npath;
996 if (stat->length != ~0) {
997 if (truncate(f->path, stat->length) < 0) {
998 create_rerror(errno);
999 goto out;
1002 ret = sp_create_rwstat();
1004 out:
1005 return ret;