Home | History | Annotate | Line # | Download | only in libpuffs
null.c revision 1.33.40.1
      1  1.33.40.1  martin /*	$NetBSD: null.c,v 1.33.40.1 2020/04/13 08:03:15 martin Exp $	*/
      2        1.1   pooka 
      3        1.1   pooka /*
      4        1.1   pooka  * Copyright (c) 2007  Antti Kantee.  All Rights Reserved.
      5        1.1   pooka  *
      6        1.1   pooka  * Redistribution and use in source and binary forms, with or without
      7        1.1   pooka  * modification, are permitted provided that the following conditions
      8        1.1   pooka  * are met:
      9        1.1   pooka  * 1. Redistributions of source code must retain the above copyright
     10        1.1   pooka  *    notice, this list of conditions and the following disclaimer.
     11        1.1   pooka  * 2. Redistributions in binary form must reproduce the above copyright
     12        1.1   pooka  *    notice, this list of conditions and the following disclaimer in the
     13        1.1   pooka  *    documentation and/or other materials provided with the distribution.
     14        1.1   pooka  *
     15        1.1   pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16        1.1   pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17        1.1   pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18        1.1   pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19        1.1   pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20        1.1   pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21        1.1   pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22        1.1   pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23        1.1   pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24        1.1   pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25        1.1   pooka  * SUCH DAMAGE.
     26        1.1   pooka  */
     27        1.1   pooka 
     28        1.1   pooka #include <sys/cdefs.h>
     29        1.1   pooka #if !defined(lint)
     30  1.33.40.1  martin __RCSID("$NetBSD: null.c,v 1.33.40.1 2020/04/13 08:03:15 martin Exp $");
     31        1.1   pooka #endif /* !lint */
     32        1.1   pooka 
     33        1.1   pooka /*
     34        1.1   pooka  * A "nullfs" using puffs, i.e. maps one location in the hierarchy
     35        1.1   pooka  * to another using standard system calls.
     36        1.1   pooka  */
     37        1.1   pooka 
     38        1.1   pooka #include <sys/types.h>
     39       1.28   pooka #include <sys/stat.h>
     40        1.1   pooka #include <sys/time.h>
     41        1.1   pooka 
     42        1.1   pooka #include <assert.h>
     43        1.1   pooka #include <dirent.h>
     44        1.1   pooka #include <errno.h>
     45        1.1   pooka #include <fcntl.h>
     46        1.1   pooka #include <puffs.h>
     47        1.1   pooka #include <stdio.h>
     48        1.9   pooka #include <stdlib.h>
     49       1.28   pooka #include <time.h>
     50        1.1   pooka #include <unistd.h>
     51        1.1   pooka 
     52        1.1   pooka PUFFSOP_PROTOS(puffs_null)
     53        1.1   pooka 
     54        1.1   pooka /*
     55        1.1   pooka  * set attributes to what is specified.  XXX: no rollback in case of failure
     56        1.1   pooka  */
     57        1.1   pooka static int
     58        1.2   pooka processvattr(const char *path, const struct vattr *va, int regular)
     59        1.1   pooka {
     60        1.1   pooka 	struct timeval tv[2];
     61        1.1   pooka 
     62        1.1   pooka 	/* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */
     63        1.1   pooka 	if (va->va_uid != (unsigned)-1 || va->va_gid != (unsigned)-1)
     64        1.2   pooka 		if (lchown(path, va->va_uid, va->va_gid) == -1)
     65        1.1   pooka 			return errno;
     66        1.1   pooka 
     67        1.1   pooka 	if (va->va_mode != (unsigned)PUFFS_VNOVAL)
     68        1.2   pooka 		if (lchmod(path, va->va_mode) == -1)
     69        1.1   pooka 			return errno;
     70        1.1   pooka 
     71        1.1   pooka 	/* sloppy */
     72       1.27   lukem 	if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL
     73       1.27   lukem 	    || va->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
     74        1.1   pooka 		TIMESPEC_TO_TIMEVAL(&tv[0], &va->va_atime);
     75        1.1   pooka 		TIMESPEC_TO_TIMEVAL(&tv[1], &va->va_mtime);
     76        1.1   pooka 
     77        1.1   pooka 		if (lutimes(path, tv) == -1)
     78        1.1   pooka 			return errno;
     79        1.1   pooka 	}
     80        1.1   pooka 
     81        1.2   pooka 	if (regular && va->va_size != (u_quad_t)PUFFS_VNOVAL)
     82        1.1   pooka 		if (truncate(path, (off_t)va->va_size) == -1)
     83        1.1   pooka 			return errno;
     84        1.1   pooka 
     85        1.1   pooka 	return 0;
     86        1.1   pooka }
     87        1.1   pooka 
     88        1.3   pooka /*
     89        1.3   pooka  * Kludge to open files which aren't writable *any longer*.  This kinda
     90        1.3   pooka  * works because the vfs layer does validation checks based on the file's
     91        1.3   pooka  * permissions to allow writable opening before opening them.  However,
     92        1.3   pooka  * the problem arises if we want to create a file, write to it (cache),
     93        1.3   pooka  * adjust permissions and then flush the file.
     94        1.3   pooka  */
     95        1.3   pooka static int
     96        1.3   pooka writeableopen(const char *path)
     97        1.3   pooka {
     98        1.3   pooka 	struct stat sb;
     99        1.3   pooka 	mode_t origmode;
    100        1.3   pooka 	int sverr = 0;
    101        1.3   pooka 	int fd;
    102        1.3   pooka 
    103        1.3   pooka 	fd = open(path, O_WRONLY);
    104        1.3   pooka 	if (fd == -1) {
    105        1.3   pooka 		if (errno == EACCES) {
    106        1.3   pooka 			if (stat(path, &sb) == -1)
    107       1.15   pooka 				return -1;
    108        1.3   pooka 			origmode = sb.st_mode & ALLPERMS;
    109        1.3   pooka 
    110        1.3   pooka 			if (chmod(path, 0200) == -1)
    111       1.15   pooka 				return -1;
    112        1.3   pooka 
    113        1.3   pooka 			fd = open(path, O_WRONLY);
    114        1.3   pooka 			if (fd == -1)
    115        1.3   pooka 				sverr = errno;
    116        1.3   pooka 
    117        1.3   pooka 			chmod(path, origmode);
    118        1.3   pooka 			if (sverr)
    119        1.3   pooka 				errno = sverr;
    120        1.3   pooka 		} else
    121       1.15   pooka 			return -1;
    122        1.3   pooka 	}
    123        1.3   pooka 
    124        1.3   pooka 	return fd;
    125        1.3   pooka }
    126        1.3   pooka 
    127        1.1   pooka /*ARGSUSED*/
    128        1.9   pooka static void *
    129        1.9   pooka inodecmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
    130        1.9   pooka {
    131        1.9   pooka 	ino_t *cmpino = arg;
    132        1.9   pooka 
    133        1.9   pooka 	if (pn->pn_va.va_fileid == *cmpino)
    134        1.9   pooka 		return pn;
    135        1.9   pooka 	return NULL;
    136        1.9   pooka }
    137        1.9   pooka 
    138       1.19   pooka static int
    139       1.21   pooka makenode(struct puffs_usermount *pu, struct puffs_newinfo *pni,
    140       1.19   pooka 	const struct puffs_cn *pcn, const struct vattr *va, int regular)
    141       1.19   pooka {
    142       1.19   pooka 	struct puffs_node *pn;
    143       1.19   pooka 	struct stat sb;
    144       1.19   pooka 	int rv;
    145       1.19   pooka 
    146       1.19   pooka 	if ((rv = processvattr(PCNPATH(pcn), va, regular)) != 0)
    147       1.19   pooka 		return rv;
    148       1.19   pooka 
    149       1.19   pooka 	pn = puffs_pn_new(pu, NULL);
    150       1.19   pooka 	if (!pn)
    151       1.19   pooka 		return ENOMEM;
    152       1.19   pooka 	puffs_setvattr(&pn->pn_va, va);
    153       1.19   pooka 
    154       1.19   pooka 	if (lstat(PCNPATH(pcn), &sb) == -1)
    155       1.19   pooka 		return errno;
    156       1.19   pooka 	puffs_stat2vattr(&pn->pn_va, &sb);
    157       1.19   pooka 
    158       1.21   pooka 	puffs_newinfo_setcookie(pni, pn);
    159       1.19   pooka 	return 0;
    160       1.19   pooka }
    161       1.19   pooka 
    162       1.17   pooka /* This should be called first and overriden from the file system */
    163       1.17   pooka void
    164       1.17   pooka puffs_null_setops(struct puffs_ops *pops)
    165       1.17   pooka {
    166       1.17   pooka 
    167       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, fs, statvfs);
    168       1.17   pooka 	PUFFSOP_SETFSNOP(pops, unmount);
    169       1.17   pooka 	PUFFSOP_SETFSNOP(pops, sync);
    170       1.26   pooka 	PUFFSOP_SET(pops, puffs_null, fs, fhtonode);
    171       1.26   pooka 	PUFFSOP_SET(pops, puffs_null, fs, nodetofh);
    172       1.17   pooka 
    173       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, lookup);
    174       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, create);
    175       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, mknod);
    176       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, getattr);
    177       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, setattr);
    178       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, fsync);
    179       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, remove);
    180       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, link);
    181       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, rename);
    182       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, mkdir);
    183       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, rmdir);
    184       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, symlink);
    185       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, readlink);
    186       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, readdir);
    187       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, read);
    188       1.17   pooka 	PUFFSOP_SET(pops, puffs_null, node, write);
    189       1.22   pooka 	PUFFSOP_SET(pops, puffs_genfs, node, reclaim);
    190       1.17   pooka }
    191       1.17   pooka 
    192        1.9   pooka /*ARGSUSED*/
    193        1.1   pooka int
    194  1.33.40.1  martin puffs_null_fs_statvfs(struct puffs_usermount *pu, struct puffs_statvfs *svfsb)
    195        1.1   pooka {
    196  1.33.40.1  martin 	struct statvfs sb;
    197  1.33.40.1  martin 	if (statvfs(PNPATH(puffs_getroot(pu)), &sb) == -1)
    198        1.1   pooka 		return errno;
    199  1.33.40.1  martin 	statvfs_to_puffs_statvfs(&sb, svfsb);
    200        1.1   pooka 
    201        1.1   pooka 	return 0;
    202        1.1   pooka }
    203        1.1   pooka 
    204       1.26   pooka /*
    205       1.26   pooka  * XXX: this is the stupidest crap ever, but:
    206       1.26   pooka  * getfh() returns the fhandle type, when we are expected to deliver
    207       1.26   pooka  * the fid type.  Just adjust it a bit and stop whining.
    208       1.26   pooka  *
    209       1.26   pooka  * Yes, this really really needs fixing.  Yes, *REALLY*.
    210       1.26   pooka  */
    211       1.26   pooka #define FHANDLE_HEADERLEN 8
    212       1.26   pooka struct kernfid {
    213       1.26   pooka 	unsigned short	fid_len;		/* length of data in bytes */
    214       1.26   pooka 	unsigned short	fid_reserved;		/* compat: historic align */
    215       1.26   pooka 	char		fid_data[0];		/* data (variable length) */
    216       1.26   pooka };
    217       1.26   pooka 
    218       1.26   pooka /*ARGSUSED*/
    219       1.26   pooka static void *
    220       1.26   pooka fhcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
    221       1.26   pooka {
    222       1.26   pooka 	struct kernfid *kf1, *kf2;
    223       1.26   pooka 
    224       1.26   pooka 	if ((kf1 = pn->pn_data) == NULL)
    225       1.26   pooka 		return NULL;
    226       1.26   pooka 	kf2 = arg;
    227       1.26   pooka 
    228       1.26   pooka 	if (kf1->fid_len != kf2->fid_len)
    229       1.26   pooka 		return NULL;
    230       1.26   pooka 
    231       1.26   pooka 	/*LINTED*/
    232       1.26   pooka 	if (memcmp(kf1, kf2, kf1->fid_len) == 0)
    233       1.26   pooka 		return pn;
    234       1.26   pooka 	return NULL;
    235       1.26   pooka }
    236       1.26   pooka 
    237       1.26   pooka /*
    238       1.26   pooka  * This routine only supports file handles which have been issued while
    239       1.26   pooka  * the server was alive.  Not really stable ones, that is.
    240       1.26   pooka  */
    241       1.26   pooka /*ARGSUSED*/
    242       1.26   pooka int
    243       1.26   pooka puffs_null_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
    244       1.26   pooka 	struct puffs_newinfo *pni)
    245       1.26   pooka {
    246       1.26   pooka 	struct puffs_node *pn_res;
    247       1.26   pooka 
    248       1.26   pooka 	pn_res = puffs_pn_nodewalk(pu, fhcmp, fid);
    249       1.26   pooka 	if (pn_res == NULL)
    250       1.26   pooka 		return ENOENT;
    251       1.26   pooka 
    252       1.26   pooka 	puffs_newinfo_setcookie(pni, pn_res);
    253       1.26   pooka 	puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
    254       1.26   pooka 	puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
    255       1.26   pooka 	puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
    256       1.26   pooka 	return 0;
    257       1.26   pooka }
    258       1.26   pooka 
    259       1.26   pooka /*ARGSUSED*/
    260       1.26   pooka int
    261       1.26   pooka puffs_null_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t opc,
    262       1.26   pooka 	void *fid, size_t *fidsize)
    263       1.26   pooka {
    264       1.26   pooka 	struct puffs_node *pn = opc;
    265       1.26   pooka 	struct kernfid *kfid;
    266       1.26   pooka 	void *bounce;
    267       1.26   pooka 	int rv;
    268       1.26   pooka 
    269       1.26   pooka 	rv = 0;
    270       1.26   pooka 	bounce = NULL;
    271       1.26   pooka 	if (*fidsize) {
    272       1.26   pooka 		bounce = malloc(*fidsize + FHANDLE_HEADERLEN);
    273       1.26   pooka 		if (!bounce)
    274       1.26   pooka 			return ENOMEM;
    275       1.26   pooka 		*fidsize += FHANDLE_HEADERLEN;
    276       1.26   pooka 	}
    277       1.26   pooka 	if (getfh(PNPATH(pn), bounce, fidsize) == -1)
    278       1.26   pooka 		rv = errno;
    279       1.26   pooka 	else
    280       1.26   pooka 		memcpy(fid, (uint8_t *)bounce + FHANDLE_HEADERLEN,
    281       1.26   pooka 		    *fidsize - FHANDLE_HEADERLEN);
    282       1.26   pooka 	kfid = fid;
    283       1.26   pooka 	if (rv == 0) {
    284       1.26   pooka 		*fidsize = kfid->fid_len;
    285       1.26   pooka 		pn->pn_data = malloc(*fidsize);
    286       1.26   pooka 		if (pn->pn_data == NULL)
    287       1.26   pooka 			abort(); /* lazy */
    288       1.26   pooka 		memcpy(pn->pn_data, fid, *fidsize);
    289       1.26   pooka 	} else {
    290       1.26   pooka 		*fidsize -= FHANDLE_HEADERLEN;
    291       1.26   pooka 	}
    292       1.26   pooka 	free(bounce);
    293       1.26   pooka 
    294       1.26   pooka 	return rv;
    295       1.26   pooka }
    296       1.26   pooka 
    297        1.1   pooka int
    298       1.25   pooka puffs_null_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
    299       1.21   pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn)
    300        1.1   pooka {
    301        1.1   pooka 	struct puffs_node *pn = opc, *pn_res;
    302        1.1   pooka 	struct stat sb;
    303        1.1   pooka 	int rv;
    304        1.1   pooka 
    305        1.1   pooka 	assert(pn->pn_va.va_type == VDIR);
    306        1.1   pooka 
    307        1.6   pooka 	/*
    308        1.6   pooka 	 * Note to whoever is copypasting this: you must first check
    309        1.6   pooka 	 * if the node is there and only then do nodewalk.  Alternatively
    310        1.6   pooka 	 * you could make sure that you don't return unlinked/rmdir'd
    311        1.6   pooka 	 * nodes in some other fashion
    312        1.6   pooka 	 */
    313        1.6   pooka 	rv = lstat(PCNPATH(pcn), &sb);
    314        1.1   pooka 	if (rv)
    315       1.10   pooka 		return errno;
    316        1.1   pooka 
    317        1.6   pooka 	/* XXX2: nodewalk is a bit too slow here */
    318        1.9   pooka 	pn_res = puffs_pn_nodewalk(pu, inodecmp, &sb.st_ino);
    319        1.1   pooka 
    320        1.6   pooka 	if (pn_res == NULL) {
    321        1.6   pooka 		pn_res = puffs_pn_new(pu, NULL);
    322        1.6   pooka 		if (pn_res == NULL)
    323        1.6   pooka 			return ENOMEM;
    324        1.6   pooka 		puffs_stat2vattr(&pn_res->pn_va, &sb);
    325        1.6   pooka 	}
    326        1.1   pooka 
    327       1.21   pooka 	puffs_newinfo_setcookie(pni, pn_res);
    328       1.21   pooka 	puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
    329       1.21   pooka 	puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
    330       1.21   pooka 	puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
    331        1.1   pooka 
    332        1.1   pooka 	return 0;
    333        1.1   pooka }
    334        1.1   pooka 
    335        1.1   pooka /*ARGSUSED*/
    336        1.1   pooka int
    337       1.25   pooka puffs_null_node_create(struct puffs_usermount *pu, puffs_cookie_t opc,
    338       1.21   pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    339       1.21   pooka 	const struct vattr *va)
    340        1.1   pooka {
    341        1.1   pooka 	int fd, rv;
    342        1.1   pooka 
    343        1.4   pooka 	fd = open(PCNPATH(pcn), O_RDWR | O_CREAT | O_TRUNC);
    344        1.1   pooka 	if (fd == -1)
    345        1.1   pooka 		return errno;
    346        1.1   pooka 	close(fd);
    347        1.1   pooka 
    348       1.21   pooka 	rv = makenode(pu, pni, pcn, va, 1);
    349       1.19   pooka 	if (rv)
    350        1.4   pooka 		unlink(PCNPATH(pcn));
    351       1.19   pooka 	return rv;
    352        1.1   pooka }
    353        1.1   pooka 
    354        1.1   pooka /*ARGSUSED*/
    355        1.1   pooka int
    356       1.25   pooka puffs_null_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc,
    357       1.21   pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    358       1.21   pooka 	const struct vattr *va)
    359        1.1   pooka {
    360       1.11   pooka 	mode_t mode;
    361        1.1   pooka 	int rv;
    362        1.1   pooka 
    363       1.11   pooka 	mode = puffs_addvtype2mode(va->va_mode, va->va_type);
    364       1.11   pooka 	if (mknod(PCNPATH(pcn), mode, va->va_rdev) == -1)
    365        1.1   pooka 		return errno;
    366        1.1   pooka 
    367       1.21   pooka 	rv = makenode(pu, pni, pcn, va, 0);
    368       1.19   pooka 	if (rv)
    369        1.4   pooka 		unlink(PCNPATH(pcn));
    370       1.19   pooka 	return rv;
    371        1.1   pooka }
    372        1.1   pooka 
    373        1.1   pooka /*ARGSUSED*/
    374        1.1   pooka int
    375       1.25   pooka puffs_null_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc,
    376       1.25   pooka 	struct vattr *va, const struct puffs_cred *pcred)
    377        1.1   pooka {
    378        1.1   pooka 	struct puffs_node *pn = opc;
    379        1.1   pooka 	struct stat sb;
    380        1.1   pooka 
    381        1.4   pooka 	if (lstat(PNPATH(pn), &sb) == -1)
    382        1.1   pooka 		return errno;
    383        1.1   pooka 	puffs_stat2vattr(va, &sb);
    384        1.1   pooka 
    385        1.1   pooka 	return 0;
    386        1.1   pooka }
    387        1.1   pooka 
    388        1.1   pooka /*ARGSUSED*/
    389        1.1   pooka int
    390       1.25   pooka puffs_null_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc,
    391       1.23   pooka 	const struct vattr *va, const struct puffs_cred *pcred)
    392        1.1   pooka {
    393        1.1   pooka 	struct puffs_node *pn = opc;
    394        1.1   pooka 	int rv;
    395        1.1   pooka 
    396        1.4   pooka 	rv = processvattr(PNPATH(pn), va, pn->pn_va.va_type == VREG);
    397        1.1   pooka 	if (rv)
    398        1.1   pooka 		return rv;
    399        1.1   pooka 
    400        1.1   pooka 	puffs_setvattr(&pn->pn_va, va);
    401        1.1   pooka 
    402        1.1   pooka 	return 0;
    403        1.1   pooka }
    404        1.1   pooka 
    405        1.1   pooka /*ARGSUSED*/
    406        1.1   pooka int
    407       1.25   pooka puffs_null_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc,
    408        1.3   pooka 	const struct puffs_cred *pcred, int how,
    409       1.23   pooka 	off_t offlo, off_t offhi)
    410        1.3   pooka {
    411        1.3   pooka 	struct puffs_node *pn = opc;
    412        1.3   pooka 	int fd, rv;
    413        1.3   pooka 	int fflags;
    414       1.29    manu 	struct stat sb;
    415  1.33.40.1  martin 	DIR *dirp;
    416        1.3   pooka 
    417        1.3   pooka 	rv = 0;
    418       1.29    manu 	if (stat(PNPATH(pn), &sb) == -1)
    419        1.3   pooka 		return errno;
    420       1.29    manu 	if (S_ISDIR(sb.st_mode)) {
    421  1.33.40.1  martin 		if ((dirp = opendir(PNPATH(pn))) == NULL)
    422       1.29    manu 			return errno;
    423       1.29    manu 		fd = dirfd(dirp);
    424  1.33.40.1  martin 		if (fd == -1) {
    425  1.33.40.1  martin 			rv = errno;
    426  1.33.40.1  martin 			closedir(dirp);
    427  1.33.40.1  martin 			return rv;
    428  1.33.40.1  martin 		}
    429        1.3   pooka 
    430       1.29    manu 		if (fsync(fd) == -1)
    431       1.29    manu 			rv = errno;
    432  1.33.40.1  martin 
    433  1.33.40.1  martin 		closedir(dirp);
    434       1.29    manu 	} else {
    435       1.29    manu 		fd = writeableopen(PNPATH(pn));
    436       1.29    manu 		if (fd == -1)
    437       1.29    manu 			return errno;
    438       1.29    manu 
    439       1.29    manu 		if (how & PUFFS_FSYNC_DATAONLY)
    440       1.29    manu 			fflags = FDATASYNC;
    441       1.29    manu 		else
    442       1.29    manu 			fflags = FFILESYNC;
    443       1.29    manu 		if (how & PUFFS_FSYNC_CACHE)
    444       1.29    manu 			fflags |= FDISKSYNC;
    445        1.3   pooka 
    446       1.29    manu 		if (fsync_range(fd, fflags, offlo, offhi - offlo) == -1)
    447       1.29    manu 			rv = errno;
    448        1.3   pooka 
    449  1.33.40.1  martin 		close(fd);
    450  1.33.40.1  martin 	}
    451        1.3   pooka 
    452        1.3   pooka 	return rv;
    453        1.3   pooka }
    454        1.3   pooka 
    455        1.3   pooka /*ARGSUSED*/
    456        1.3   pooka int
    457       1.25   pooka puffs_null_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc,
    458       1.25   pooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
    459        1.1   pooka {
    460        1.1   pooka 	struct puffs_node *pn_targ = targ;
    461        1.1   pooka 
    462       1.33    manu 	if (unlink(PNPATH(pn_targ)) == -1)
    463        1.1   pooka 		return errno;
    464       1.16   pooka 	puffs_pn_remove(pn_targ);
    465        1.1   pooka 
    466        1.1   pooka 	return 0;
    467        1.1   pooka }
    468        1.1   pooka 
    469        1.1   pooka /*ARGSUSED*/
    470        1.1   pooka int
    471       1.25   pooka puffs_null_node_link(struct puffs_usermount *pu, puffs_cookie_t opc,
    472       1.25   pooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
    473        1.1   pooka {
    474        1.1   pooka 	struct puffs_node *pn_targ = targ;
    475        1.1   pooka 
    476        1.4   pooka 	if (link(PNPATH(pn_targ), PCNPATH(pcn)) == -1)
    477        1.1   pooka 		return errno;
    478        1.1   pooka 
    479        1.1   pooka 	return 0;
    480        1.1   pooka }
    481        1.1   pooka 
    482        1.1   pooka /*ARGSUSED*/
    483        1.1   pooka int
    484       1.25   pooka puffs_null_node_rename(struct puffs_usermount *pu, puffs_cookie_t opc,
    485       1.25   pooka 	puffs_cookie_t src, const struct puffs_cn *pcn_src,
    486       1.25   pooka 	puffs_cookie_t targ_dir, puffs_cookie_t targ,
    487        1.1   pooka 	const struct puffs_cn *pcn_targ)
    488        1.1   pooka {
    489       1.31    manu 	struct puffs_node *pn_targ = targ;
    490        1.1   pooka 
    491        1.4   pooka 	if (rename(PCNPATH(pcn_src), PCNPATH(pcn_targ)) == -1)
    492        1.1   pooka 		return errno;
    493        1.1   pooka 
    494       1.31    manu         if (pn_targ)
    495       1.31    manu 		puffs_pn_remove(pn_targ);
    496       1.31    manu 
    497        1.1   pooka 	return 0;
    498        1.1   pooka }
    499        1.1   pooka 
    500        1.1   pooka /*ARGSUSED*/
    501        1.1   pooka int
    502       1.25   pooka puffs_null_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    503       1.21   pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    504       1.21   pooka 	const struct vattr *va)
    505        1.1   pooka {
    506        1.1   pooka 	int rv;
    507        1.1   pooka 
    508        1.4   pooka 	if (mkdir(PCNPATH(pcn), va->va_mode) == -1)
    509        1.1   pooka 		return errno;
    510        1.1   pooka 
    511       1.21   pooka 	rv = makenode(pu, pni, pcn, va, 0);
    512       1.19   pooka 	if (rv)
    513        1.5     agc 		rmdir(PCNPATH(pcn));
    514       1.19   pooka 	return rv;
    515        1.1   pooka }
    516        1.1   pooka 
    517        1.1   pooka /*ARGSUSED*/
    518        1.1   pooka int
    519       1.25   pooka puffs_null_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    520       1.25   pooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
    521        1.1   pooka {
    522        1.1   pooka 	struct puffs_node *pn_targ = targ;
    523        1.1   pooka 
    524       1.33    manu 	if (rmdir(PNPATH(pn_targ)) == -1)
    525        1.1   pooka 		return errno;
    526       1.16   pooka 	puffs_pn_remove(pn_targ);
    527        1.1   pooka 
    528        1.1   pooka 	return 0;
    529        1.1   pooka }
    530        1.1   pooka 
    531        1.1   pooka /*ARGSUSED*/
    532        1.1   pooka int
    533       1.25   pooka puffs_null_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
    534       1.21   pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    535       1.21   pooka 	const struct vattr *va, const char *linkname)
    536        1.1   pooka {
    537        1.1   pooka 	int rv;
    538        1.1   pooka 
    539        1.4   pooka 	if (symlink(linkname, PCNPATH(pcn)) == -1)
    540        1.1   pooka 		return errno;
    541        1.1   pooka 
    542       1.21   pooka 	rv = makenode(pu, pni, pcn, va, 0);
    543       1.19   pooka 	if (rv)
    544        1.4   pooka 		unlink(PCNPATH(pcn));
    545       1.19   pooka 	return rv;
    546        1.1   pooka }
    547        1.1   pooka 
    548        1.1   pooka /*ARGSUSED*/
    549        1.1   pooka int
    550       1.25   pooka puffs_null_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
    551        1.1   pooka 	const struct puffs_cred *pcred, char *linkname, size_t *linklen)
    552        1.1   pooka {
    553        1.1   pooka 	struct puffs_node *pn = opc;
    554        1.1   pooka 	ssize_t rv;
    555        1.1   pooka 
    556        1.4   pooka 	rv = readlink(PNPATH(pn), linkname, *linklen);
    557        1.1   pooka 	if (rv == -1)
    558        1.1   pooka 		return errno;
    559        1.1   pooka 
    560        1.8   pooka 	*linklen = rv;
    561        1.1   pooka 	return 0;
    562        1.1   pooka }
    563        1.1   pooka 
    564        1.1   pooka /*ARGSUSED*/
    565        1.1   pooka int
    566       1.25   pooka puffs_null_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    567       1.24   pooka 	struct dirent *de, off_t *off, size_t *reslen,
    568       1.24   pooka 	const struct puffs_cred *pcred, int *eofflag, off_t *cookies,
    569       1.24   pooka 	size_t *ncookies)
    570        1.1   pooka {
    571        1.1   pooka 	struct puffs_node *pn = opc;
    572        1.1   pooka 	struct dirent entry, *result;
    573        1.1   pooka 	DIR *dp;
    574        1.1   pooka 	off_t i;
    575        1.1   pooka 	int rv;
    576        1.1   pooka 
    577       1.26   pooka 	*ncookies = 0;
    578        1.4   pooka 	dp = opendir(PNPATH(pn));
    579        1.1   pooka 	if (dp == NULL)
    580        1.1   pooka 		return errno;
    581        1.1   pooka 
    582        1.1   pooka 	rv = 0;
    583        1.1   pooka 	i = *off;
    584        1.1   pooka 
    585        1.1   pooka 	/*
    586        1.1   pooka 	 * XXX: need to do trickery here, telldir/seekdir would be nice, but
    587        1.1   pooka 	 * then we'd need to keep state, which I'm too lazy to keep
    588        1.1   pooka 	 */
    589        1.1   pooka 	while (i--) {
    590        1.1   pooka 		rv = readdir_r(dp, &entry, &result);
    591       1.30    manu 		if (rv != 0)
    592       1.30    manu 			goto out;
    593       1.30    manu 
    594       1.30    manu 		if (!result) {
    595       1.30    manu 			*eofflag = 1;
    596        1.1   pooka 			goto out;
    597       1.30    manu 		}
    598        1.1   pooka 	}
    599        1.1   pooka 
    600        1.1   pooka 	for (;;) {
    601        1.1   pooka 		rv = readdir_r(dp, &entry, &result);
    602        1.1   pooka 		if (rv != 0)
    603        1.1   pooka 			goto out;
    604        1.1   pooka 
    605       1.26   pooka 		if (!result) {
    606       1.26   pooka 			*eofflag = 1;
    607        1.1   pooka 			goto out;
    608       1.26   pooka 		}
    609        1.1   pooka 
    610        1.1   pooka 		if (_DIRENT_SIZE(result) > *reslen)
    611        1.1   pooka 			goto out;
    612        1.1   pooka 
    613        1.1   pooka 		*de = *result;
    614        1.1   pooka 		*reslen -= _DIRENT_SIZE(result);
    615        1.1   pooka 		de = _DIRENT_NEXT(de);
    616        1.1   pooka 
    617        1.1   pooka 		(*off)++;
    618       1.26   pooka 		PUFFS_STORE_DCOOKIE(cookies, ncookies, *off);
    619        1.1   pooka 	}
    620        1.1   pooka 
    621        1.1   pooka  out:
    622        1.1   pooka 	closedir(dp);
    623        1.1   pooka 	return 0;
    624        1.1   pooka }
    625        1.1   pooka 
    626        1.1   pooka /*ARGSUSED*/
    627        1.1   pooka int
    628       1.25   pooka puffs_null_node_read(struct puffs_usermount *pu, puffs_cookie_t opc,
    629       1.25   pooka 	uint8_t *buf, off_t offset, size_t *buflen,
    630       1.25   pooka 	const struct puffs_cred *pcred, int ioflag)
    631        1.1   pooka {
    632        1.1   pooka 	struct puffs_node *pn = opc;
    633        1.1   pooka 	ssize_t n;
    634        1.1   pooka 	off_t off;
    635        1.1   pooka 	int fd, rv;
    636        1.1   pooka 
    637        1.1   pooka 	rv = 0;
    638        1.4   pooka 	fd = open(PNPATH(pn), O_RDONLY);
    639        1.1   pooka 	if (fd == -1)
    640        1.1   pooka 		return errno;
    641        1.1   pooka 	off = lseek(fd, offset, SEEK_SET);
    642        1.1   pooka 	if (off == -1) {
    643        1.1   pooka 		rv = errno;
    644        1.1   pooka 		goto out;
    645        1.1   pooka 	}
    646        1.1   pooka 
    647        1.1   pooka 	n = read(fd, buf, *buflen);
    648        1.1   pooka 	if (n == -1)
    649        1.1   pooka 		rv = errno;
    650        1.1   pooka 	else
    651        1.1   pooka 		*buflen -= n;
    652        1.1   pooka 
    653        1.1   pooka  out:
    654        1.1   pooka 	close(fd);
    655        1.1   pooka 	return rv;
    656        1.1   pooka }
    657        1.1   pooka 
    658        1.1   pooka /*ARGSUSED*/
    659        1.1   pooka int
    660       1.25   pooka puffs_null_node_write(struct puffs_usermount *pu, puffs_cookie_t opc,
    661       1.25   pooka 	uint8_t *buf, off_t offset, size_t *buflen,
    662       1.25   pooka 	const struct puffs_cred *pcred, int ioflag)
    663        1.1   pooka {
    664        1.1   pooka 	struct puffs_node *pn = opc;
    665        1.1   pooka 	ssize_t n;
    666        1.1   pooka 	off_t off;
    667        1.1   pooka 	int fd, rv;
    668        1.1   pooka 
    669        1.1   pooka 	rv = 0;
    670        1.4   pooka 	fd = writeableopen(PNPATH(pn));
    671        1.3   pooka 	if (fd == -1)
    672        1.3   pooka 		return errno;
    673        1.2   pooka 
    674        1.1   pooka 	off = lseek(fd, offset, SEEK_SET);
    675        1.1   pooka 	if (off == -1) {
    676        1.1   pooka 		rv = errno;
    677        1.1   pooka 		goto out;
    678        1.1   pooka 	}
    679        1.1   pooka 
    680        1.1   pooka 	n = write(fd, buf, *buflen);
    681        1.1   pooka 	if (n == -1)
    682        1.1   pooka 		rv = errno;
    683        1.1   pooka 	else
    684        1.1   pooka 		*buflen -= n;
    685        1.1   pooka 
    686        1.1   pooka  out:
    687        1.1   pooka 	close(fd);
    688        1.1   pooka 	return rv;
    689        1.1   pooka }
    690