Home | History | Annotate | Line # | Download | only in libpuffs
null.c revision 1.35
      1  1.35       tnn /*	$NetBSD: null.c,v 1.35 2019/11/02 18:14:36 tnn 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.35       tnn __RCSID("$NetBSD: null.c,v 1.35 2019/11/02 18:14:36 tnn 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.34  christos puffs_null_fs_statvfs(struct puffs_usermount *pu, struct puffs_statvfs *svfsb)
    195   1.1     pooka {
    196  1.34  christos 	struct statvfs sb;
    197  1.34  christos 	if (statvfs(PNPATH(puffs_getroot(pu)), &sb) == -1)
    198   1.1     pooka 		return errno;
    199  1.34  christos 	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.35       tnn 	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.35       tnn 		if ((dirp = opendir(PNPATH(pn))) == NULL)
    422  1.29      manu 			return errno;
    423  1.29      manu 		fd = dirfd(dirp);
    424  1.35       tnn 		if (fd == -1) {
    425  1.35       tnn 			rv = errno;
    426  1.35       tnn 			closedir(dirp);
    427  1.35       tnn 			return rv;
    428  1.35       tnn 		}
    429   1.3     pooka 
    430  1.29      manu 		if (fsync(fd) == -1)
    431  1.29      manu 			rv = errno;
    432  1.35       tnn 
    433  1.35       tnn 		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.35       tnn 
    449  1.35       tnn 		close(fd);
    450  1.29      manu 	}
    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