Home | History | Annotate | Line # | Download | only in libpuffs
null.c revision 1.29
      1  1.29   manu /*	$NetBSD: null.c,v 1.29 2011/06/24 16:59:29 manu 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.29   manu __RCSID("$NetBSD: null.c,v 1.29 2011/06/24 16:59:29 manu 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.24  pooka puffs_null_fs_statvfs(struct puffs_usermount *pu, struct statvfs *svfsb)
    195   1.1  pooka {
    196   1.1  pooka 
    197  1.13  pooka 	if (statvfs(PNPATH(puffs_getroot(pu)), svfsb) == -1)
    198   1.1  pooka 		return errno;
    199   1.1  pooka 
    200   1.1  pooka 	return 0;
    201   1.1  pooka }
    202   1.1  pooka 
    203  1.26  pooka /*
    204  1.26  pooka  * XXX: this is the stupidest crap ever, but:
    205  1.26  pooka  * getfh() returns the fhandle type, when we are expected to deliver
    206  1.26  pooka  * the fid type.  Just adjust it a bit and stop whining.
    207  1.26  pooka  *
    208  1.26  pooka  * Yes, this really really needs fixing.  Yes, *REALLY*.
    209  1.26  pooka  */
    210  1.26  pooka #define FHANDLE_HEADERLEN 8
    211  1.26  pooka struct kernfid {
    212  1.26  pooka 	unsigned short	fid_len;		/* length of data in bytes */
    213  1.26  pooka 	unsigned short	fid_reserved;		/* compat: historic align */
    214  1.26  pooka 	char		fid_data[0];		/* data (variable length) */
    215  1.26  pooka };
    216  1.26  pooka 
    217  1.26  pooka /*ARGSUSED*/
    218  1.26  pooka static void *
    219  1.26  pooka fhcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
    220  1.26  pooka {
    221  1.26  pooka 	struct kernfid *kf1, *kf2;
    222  1.26  pooka 
    223  1.26  pooka 	if ((kf1 = pn->pn_data) == NULL)
    224  1.26  pooka 		return NULL;
    225  1.26  pooka 	kf2 = arg;
    226  1.26  pooka 
    227  1.26  pooka 	if (kf1->fid_len != kf2->fid_len)
    228  1.26  pooka 		return NULL;
    229  1.26  pooka 
    230  1.26  pooka 	/*LINTED*/
    231  1.26  pooka 	if (memcmp(kf1, kf2, kf1->fid_len) == 0)
    232  1.26  pooka 		return pn;
    233  1.26  pooka 	return NULL;
    234  1.26  pooka }
    235  1.26  pooka 
    236  1.26  pooka /*
    237  1.26  pooka  * This routine only supports file handles which have been issued while
    238  1.26  pooka  * the server was alive.  Not really stable ones, that is.
    239  1.26  pooka  */
    240  1.26  pooka /*ARGSUSED*/
    241  1.26  pooka int
    242  1.26  pooka puffs_null_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
    243  1.26  pooka 	struct puffs_newinfo *pni)
    244  1.26  pooka {
    245  1.26  pooka 	struct puffs_node *pn_res;
    246  1.26  pooka 
    247  1.26  pooka 	pn_res = puffs_pn_nodewalk(pu, fhcmp, fid);
    248  1.26  pooka 	if (pn_res == NULL)
    249  1.26  pooka 		return ENOENT;
    250  1.26  pooka 
    251  1.26  pooka 	puffs_newinfo_setcookie(pni, pn_res);
    252  1.26  pooka 	puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
    253  1.26  pooka 	puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
    254  1.26  pooka 	puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
    255  1.26  pooka 	return 0;
    256  1.26  pooka }
    257  1.26  pooka 
    258  1.26  pooka /*ARGSUSED*/
    259  1.26  pooka int
    260  1.26  pooka puffs_null_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t opc,
    261  1.26  pooka 	void *fid, size_t *fidsize)
    262  1.26  pooka {
    263  1.26  pooka 	struct puffs_node *pn = opc;
    264  1.26  pooka 	struct kernfid *kfid;
    265  1.26  pooka 	void *bounce;
    266  1.26  pooka 	int rv;
    267  1.26  pooka 
    268  1.26  pooka 	rv = 0;
    269  1.26  pooka 	bounce = NULL;
    270  1.26  pooka 	if (*fidsize) {
    271  1.26  pooka 		bounce = malloc(*fidsize + FHANDLE_HEADERLEN);
    272  1.26  pooka 		if (!bounce)
    273  1.26  pooka 			return ENOMEM;
    274  1.26  pooka 		*fidsize += FHANDLE_HEADERLEN;
    275  1.26  pooka 	}
    276  1.26  pooka 	if (getfh(PNPATH(pn), bounce, fidsize) == -1)
    277  1.26  pooka 		rv = errno;
    278  1.26  pooka 	else
    279  1.26  pooka 		memcpy(fid, (uint8_t *)bounce + FHANDLE_HEADERLEN,
    280  1.26  pooka 		    *fidsize - FHANDLE_HEADERLEN);
    281  1.26  pooka 	kfid = fid;
    282  1.26  pooka 	if (rv == 0) {
    283  1.26  pooka 		*fidsize = kfid->fid_len;
    284  1.26  pooka 		pn->pn_data = malloc(*fidsize);
    285  1.26  pooka 		if (pn->pn_data == NULL)
    286  1.26  pooka 			abort(); /* lazy */
    287  1.26  pooka 		memcpy(pn->pn_data, fid, *fidsize);
    288  1.26  pooka 	} else {
    289  1.26  pooka 		*fidsize -= FHANDLE_HEADERLEN;
    290  1.26  pooka 	}
    291  1.26  pooka 	free(bounce);
    292  1.26  pooka 
    293  1.26  pooka 	return rv;
    294  1.26  pooka }
    295  1.26  pooka 
    296   1.1  pooka int
    297  1.25  pooka puffs_null_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
    298  1.21  pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn)
    299   1.1  pooka {
    300   1.1  pooka 	struct puffs_node *pn = opc, *pn_res;
    301   1.1  pooka 	struct stat sb;
    302   1.1  pooka 	int rv;
    303   1.1  pooka 
    304   1.1  pooka 	assert(pn->pn_va.va_type == VDIR);
    305   1.1  pooka 
    306   1.6  pooka 	/*
    307   1.6  pooka 	 * Note to whoever is copypasting this: you must first check
    308   1.6  pooka 	 * if the node is there and only then do nodewalk.  Alternatively
    309   1.6  pooka 	 * you could make sure that you don't return unlinked/rmdir'd
    310   1.6  pooka 	 * nodes in some other fashion
    311   1.6  pooka 	 */
    312   1.6  pooka 	rv = lstat(PCNPATH(pcn), &sb);
    313   1.1  pooka 	if (rv)
    314  1.10  pooka 		return errno;
    315   1.1  pooka 
    316   1.6  pooka 	/* XXX2: nodewalk is a bit too slow here */
    317   1.9  pooka 	pn_res = puffs_pn_nodewalk(pu, inodecmp, &sb.st_ino);
    318   1.1  pooka 
    319   1.6  pooka 	if (pn_res == NULL) {
    320   1.6  pooka 		pn_res = puffs_pn_new(pu, NULL);
    321   1.6  pooka 		if (pn_res == NULL)
    322   1.6  pooka 			return ENOMEM;
    323   1.6  pooka 		puffs_stat2vattr(&pn_res->pn_va, &sb);
    324   1.6  pooka 	}
    325   1.1  pooka 
    326  1.21  pooka 	puffs_newinfo_setcookie(pni, pn_res);
    327  1.21  pooka 	puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
    328  1.21  pooka 	puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
    329  1.21  pooka 	puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
    330   1.1  pooka 
    331   1.1  pooka 	return 0;
    332   1.1  pooka }
    333   1.1  pooka 
    334   1.1  pooka /*ARGSUSED*/
    335   1.1  pooka int
    336  1.25  pooka puffs_null_node_create(struct puffs_usermount *pu, puffs_cookie_t opc,
    337  1.21  pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    338  1.21  pooka 	const struct vattr *va)
    339   1.1  pooka {
    340   1.1  pooka 	int fd, rv;
    341   1.1  pooka 
    342   1.4  pooka 	fd = open(PCNPATH(pcn), O_RDWR | O_CREAT | O_TRUNC);
    343   1.1  pooka 	if (fd == -1)
    344   1.1  pooka 		return errno;
    345   1.1  pooka 	close(fd);
    346   1.1  pooka 
    347  1.21  pooka 	rv = makenode(pu, pni, pcn, va, 1);
    348  1.19  pooka 	if (rv)
    349   1.4  pooka 		unlink(PCNPATH(pcn));
    350  1.19  pooka 	return rv;
    351   1.1  pooka }
    352   1.1  pooka 
    353   1.1  pooka /*ARGSUSED*/
    354   1.1  pooka int
    355  1.25  pooka puffs_null_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc,
    356  1.21  pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    357  1.21  pooka 	const struct vattr *va)
    358   1.1  pooka {
    359  1.11  pooka 	mode_t mode;
    360   1.1  pooka 	int rv;
    361   1.1  pooka 
    362  1.11  pooka 	mode = puffs_addvtype2mode(va->va_mode, va->va_type);
    363  1.11  pooka 	if (mknod(PCNPATH(pcn), mode, va->va_rdev) == -1)
    364   1.1  pooka 		return errno;
    365   1.1  pooka 
    366  1.21  pooka 	rv = makenode(pu, pni, pcn, va, 0);
    367  1.19  pooka 	if (rv)
    368   1.4  pooka 		unlink(PCNPATH(pcn));
    369  1.19  pooka 	return rv;
    370   1.1  pooka }
    371   1.1  pooka 
    372   1.1  pooka /*ARGSUSED*/
    373   1.1  pooka int
    374  1.25  pooka puffs_null_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc,
    375  1.25  pooka 	struct vattr *va, const struct puffs_cred *pcred)
    376   1.1  pooka {
    377   1.1  pooka 	struct puffs_node *pn = opc;
    378   1.1  pooka 	struct stat sb;
    379   1.1  pooka 
    380   1.4  pooka 	if (lstat(PNPATH(pn), &sb) == -1)
    381   1.1  pooka 		return errno;
    382   1.1  pooka 	puffs_stat2vattr(va, &sb);
    383   1.1  pooka 
    384   1.1  pooka 	return 0;
    385   1.1  pooka }
    386   1.1  pooka 
    387   1.1  pooka /*ARGSUSED*/
    388   1.1  pooka int
    389  1.25  pooka puffs_null_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc,
    390  1.23  pooka 	const struct vattr *va, const struct puffs_cred *pcred)
    391   1.1  pooka {
    392   1.1  pooka 	struct puffs_node *pn = opc;
    393   1.1  pooka 	int rv;
    394   1.1  pooka 
    395   1.4  pooka 	rv = processvattr(PNPATH(pn), va, pn->pn_va.va_type == VREG);
    396   1.1  pooka 	if (rv)
    397   1.1  pooka 		return rv;
    398   1.1  pooka 
    399   1.1  pooka 	puffs_setvattr(&pn->pn_va, va);
    400   1.1  pooka 
    401   1.1  pooka 	return 0;
    402   1.1  pooka }
    403   1.1  pooka 
    404   1.1  pooka /*ARGSUSED*/
    405   1.1  pooka int
    406  1.25  pooka puffs_null_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc,
    407   1.3  pooka 	const struct puffs_cred *pcred, int how,
    408  1.23  pooka 	off_t offlo, off_t offhi)
    409   1.3  pooka {
    410   1.3  pooka 	struct puffs_node *pn = opc;
    411   1.3  pooka 	int fd, rv;
    412   1.3  pooka 	int fflags;
    413  1.29   manu 	struct stat sb;
    414   1.3  pooka 
    415   1.3  pooka 	rv = 0;
    416  1.29   manu 	if (stat(PNPATH(pn), &sb) == -1)
    417   1.3  pooka 		return errno;
    418  1.29   manu 	if (S_ISDIR(sb.st_mode)) {
    419  1.29   manu 		DIR *dirp;
    420  1.29   manu 		if ((dirp = opendir(PNPATH(pn))) == 0)
    421  1.29   manu 			return errno;
    422  1.29   manu 		fd = dirfd(dirp);
    423  1.29   manu 		if (fd == -1)
    424  1.29   manu 			return errno;
    425   1.3  pooka 
    426  1.29   manu 		if (fsync(fd) == -1)
    427  1.29   manu 			rv = errno;
    428  1.29   manu 	} else {
    429  1.29   manu 		fd = writeableopen(PNPATH(pn));
    430  1.29   manu 		if (fd == -1)
    431  1.29   manu 			return errno;
    432  1.29   manu 
    433  1.29   manu 		if (how & PUFFS_FSYNC_DATAONLY)
    434  1.29   manu 			fflags = FDATASYNC;
    435  1.29   manu 		else
    436  1.29   manu 			fflags = FFILESYNC;
    437  1.29   manu 		if (how & PUFFS_FSYNC_CACHE)
    438  1.29   manu 			fflags |= FDISKSYNC;
    439   1.3  pooka 
    440  1.29   manu 		if (fsync_range(fd, fflags, offlo, offhi - offlo) == -1)
    441  1.29   manu 			rv = errno;
    442  1.29   manu 	}
    443   1.3  pooka 
    444   1.3  pooka 	close(fd);
    445   1.3  pooka 
    446   1.3  pooka 	return rv;
    447   1.3  pooka }
    448   1.3  pooka 
    449   1.3  pooka /*ARGSUSED*/
    450   1.3  pooka int
    451  1.25  pooka puffs_null_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc,
    452  1.25  pooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
    453   1.1  pooka {
    454   1.1  pooka 	struct puffs_node *pn_targ = targ;
    455   1.1  pooka 
    456   1.4  pooka 	if (unlink(PNPATH(pn_targ)) == -1)
    457   1.1  pooka 		return errno;
    458  1.16  pooka 	puffs_pn_remove(pn_targ);
    459   1.1  pooka 
    460   1.1  pooka 	return 0;
    461   1.1  pooka }
    462   1.1  pooka 
    463   1.1  pooka /*ARGSUSED*/
    464   1.1  pooka int
    465  1.25  pooka puffs_null_node_link(struct puffs_usermount *pu, puffs_cookie_t opc,
    466  1.25  pooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
    467   1.1  pooka {
    468   1.1  pooka 	struct puffs_node *pn_targ = targ;
    469   1.1  pooka 
    470   1.4  pooka 	if (link(PNPATH(pn_targ), PCNPATH(pcn)) == -1)
    471   1.1  pooka 		return errno;
    472   1.1  pooka 
    473   1.1  pooka 	return 0;
    474   1.1  pooka }
    475   1.1  pooka 
    476   1.1  pooka /*ARGSUSED*/
    477   1.1  pooka int
    478  1.25  pooka puffs_null_node_rename(struct puffs_usermount *pu, puffs_cookie_t opc,
    479  1.25  pooka 	puffs_cookie_t src, const struct puffs_cn *pcn_src,
    480  1.25  pooka 	puffs_cookie_t targ_dir, puffs_cookie_t targ,
    481   1.1  pooka 	const struct puffs_cn *pcn_targ)
    482   1.1  pooka {
    483   1.1  pooka 
    484   1.4  pooka 	if (rename(PCNPATH(pcn_src), PCNPATH(pcn_targ)) == -1)
    485   1.1  pooka 		return errno;
    486   1.1  pooka 
    487   1.1  pooka 	return 0;
    488   1.1  pooka }
    489   1.1  pooka 
    490   1.1  pooka /*ARGSUSED*/
    491   1.1  pooka int
    492  1.25  pooka puffs_null_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    493  1.21  pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    494  1.21  pooka 	const struct vattr *va)
    495   1.1  pooka {
    496   1.1  pooka 	int rv;
    497   1.1  pooka 
    498   1.4  pooka 	if (mkdir(PCNPATH(pcn), va->va_mode) == -1)
    499   1.1  pooka 		return errno;
    500   1.1  pooka 
    501  1.21  pooka 	rv = makenode(pu, pni, pcn, va, 0);
    502  1.19  pooka 	if (rv)
    503   1.5    agc 		rmdir(PCNPATH(pcn));
    504  1.19  pooka 	return rv;
    505   1.1  pooka }
    506   1.1  pooka 
    507   1.1  pooka /*ARGSUSED*/
    508   1.1  pooka int
    509  1.25  pooka puffs_null_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    510  1.25  pooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
    511   1.1  pooka {
    512   1.1  pooka 	struct puffs_node *pn_targ = targ;
    513   1.1  pooka 
    514   1.4  pooka 	if (rmdir(PNPATH(pn_targ)) == -1)
    515   1.1  pooka 		return errno;
    516  1.16  pooka 	puffs_pn_remove(pn_targ);
    517   1.1  pooka 
    518   1.1  pooka 	return 0;
    519   1.1  pooka }
    520   1.1  pooka 
    521   1.1  pooka /*ARGSUSED*/
    522   1.1  pooka int
    523  1.25  pooka puffs_null_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
    524  1.21  pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    525  1.21  pooka 	const struct vattr *va, const char *linkname)
    526   1.1  pooka {
    527   1.1  pooka 	int rv;
    528   1.1  pooka 
    529   1.4  pooka 	if (symlink(linkname, PCNPATH(pcn)) == -1)
    530   1.1  pooka 		return errno;
    531   1.1  pooka 
    532  1.21  pooka 	rv = makenode(pu, pni, pcn, va, 0);
    533  1.19  pooka 	if (rv)
    534   1.4  pooka 		unlink(PCNPATH(pcn));
    535  1.19  pooka 	return rv;
    536   1.1  pooka }
    537   1.1  pooka 
    538   1.1  pooka /*ARGSUSED*/
    539   1.1  pooka int
    540  1.25  pooka puffs_null_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
    541   1.1  pooka 	const struct puffs_cred *pcred, char *linkname, size_t *linklen)
    542   1.1  pooka {
    543   1.1  pooka 	struct puffs_node *pn = opc;
    544   1.1  pooka 	ssize_t rv;
    545   1.1  pooka 
    546   1.4  pooka 	rv = readlink(PNPATH(pn), linkname, *linklen);
    547   1.1  pooka 	if (rv == -1)
    548   1.1  pooka 		return errno;
    549   1.1  pooka 
    550   1.8  pooka 	*linklen = rv;
    551   1.1  pooka 	return 0;
    552   1.1  pooka }
    553   1.1  pooka 
    554   1.1  pooka /*ARGSUSED*/
    555   1.1  pooka int
    556  1.25  pooka puffs_null_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    557  1.24  pooka 	struct dirent *de, off_t *off, size_t *reslen,
    558  1.24  pooka 	const struct puffs_cred *pcred, int *eofflag, off_t *cookies,
    559  1.24  pooka 	size_t *ncookies)
    560   1.1  pooka {
    561   1.1  pooka 	struct puffs_node *pn = opc;
    562   1.1  pooka 	struct dirent entry, *result;
    563   1.1  pooka 	DIR *dp;
    564   1.1  pooka 	off_t i;
    565   1.1  pooka 	int rv;
    566   1.1  pooka 
    567  1.26  pooka 	*ncookies = 0;
    568   1.4  pooka 	dp = opendir(PNPATH(pn));
    569   1.1  pooka 	if (dp == NULL)
    570   1.1  pooka 		return errno;
    571   1.1  pooka 
    572   1.1  pooka 	rv = 0;
    573   1.1  pooka 	i = *off;
    574   1.1  pooka 
    575   1.1  pooka 	/*
    576   1.1  pooka 	 * XXX: need to do trickery here, telldir/seekdir would be nice, but
    577   1.1  pooka 	 * then we'd need to keep state, which I'm too lazy to keep
    578   1.1  pooka 	 */
    579   1.1  pooka 	while (i--) {
    580   1.1  pooka 		rv = readdir_r(dp, &entry, &result);
    581   1.1  pooka 		if (rv || !result)
    582   1.1  pooka 			goto out;
    583   1.1  pooka 	}
    584   1.1  pooka 
    585   1.1  pooka 	for (;;) {
    586   1.1  pooka 		rv = readdir_r(dp, &entry, &result);
    587   1.1  pooka 		if (rv != 0)
    588   1.1  pooka 			goto out;
    589   1.1  pooka 
    590  1.26  pooka 		if (!result) {
    591  1.26  pooka 			*eofflag = 1;
    592   1.1  pooka 			goto out;
    593  1.26  pooka 		}
    594   1.1  pooka 
    595   1.1  pooka 		if (_DIRENT_SIZE(result) > *reslen)
    596   1.1  pooka 			goto out;
    597   1.1  pooka 
    598   1.1  pooka 		*de = *result;
    599   1.1  pooka 		*reslen -= _DIRENT_SIZE(result);
    600   1.1  pooka 		de = _DIRENT_NEXT(de);
    601   1.1  pooka 
    602   1.1  pooka 		(*off)++;
    603  1.26  pooka 		PUFFS_STORE_DCOOKIE(cookies, ncookies, *off);
    604   1.1  pooka 	}
    605   1.1  pooka 
    606   1.1  pooka  out:
    607   1.1  pooka 	closedir(dp);
    608   1.1  pooka 	return 0;
    609   1.1  pooka }
    610   1.1  pooka 
    611   1.1  pooka /*ARGSUSED*/
    612   1.1  pooka int
    613  1.25  pooka puffs_null_node_read(struct puffs_usermount *pu, puffs_cookie_t opc,
    614  1.25  pooka 	uint8_t *buf, off_t offset, size_t *buflen,
    615  1.25  pooka 	const struct puffs_cred *pcred, int ioflag)
    616   1.1  pooka {
    617   1.1  pooka 	struct puffs_node *pn = opc;
    618   1.1  pooka 	ssize_t n;
    619   1.1  pooka 	off_t off;
    620   1.1  pooka 	int fd, rv;
    621   1.1  pooka 
    622   1.1  pooka 	rv = 0;
    623   1.4  pooka 	fd = open(PNPATH(pn), O_RDONLY);
    624   1.1  pooka 	if (fd == -1)
    625   1.1  pooka 		return errno;
    626   1.1  pooka 	off = lseek(fd, offset, SEEK_SET);
    627   1.1  pooka 	if (off == -1) {
    628   1.1  pooka 		rv = errno;
    629   1.1  pooka 		goto out;
    630   1.1  pooka 	}
    631   1.1  pooka 
    632   1.1  pooka 	n = read(fd, buf, *buflen);
    633   1.1  pooka 	if (n == -1)
    634   1.1  pooka 		rv = errno;
    635   1.1  pooka 	else
    636   1.1  pooka 		*buflen -= n;
    637   1.1  pooka 
    638   1.1  pooka  out:
    639   1.1  pooka 	close(fd);
    640   1.1  pooka 	return rv;
    641   1.1  pooka }
    642   1.1  pooka 
    643   1.1  pooka /*ARGSUSED*/
    644   1.1  pooka int
    645  1.25  pooka puffs_null_node_write(struct puffs_usermount *pu, puffs_cookie_t opc,
    646  1.25  pooka 	uint8_t *buf, off_t offset, size_t *buflen,
    647  1.25  pooka 	const struct puffs_cred *pcred, int ioflag)
    648   1.1  pooka {
    649   1.1  pooka 	struct puffs_node *pn = opc;
    650   1.1  pooka 	ssize_t n;
    651   1.1  pooka 	off_t off;
    652   1.1  pooka 	int fd, rv;
    653   1.1  pooka 
    654   1.1  pooka 	rv = 0;
    655   1.4  pooka 	fd = writeableopen(PNPATH(pn));
    656   1.3  pooka 	if (fd == -1)
    657   1.3  pooka 		return errno;
    658   1.2  pooka 
    659   1.1  pooka 	off = lseek(fd, offset, SEEK_SET);
    660   1.1  pooka 	if (off == -1) {
    661   1.1  pooka 		rv = errno;
    662   1.1  pooka 		goto out;
    663   1.1  pooka 	}
    664   1.1  pooka 
    665   1.1  pooka 	n = write(fd, buf, *buflen);
    666   1.1  pooka 	if (n == -1)
    667   1.1  pooka 		rv = errno;
    668   1.1  pooka 	else
    669   1.1  pooka 		*buflen -= n;
    670   1.1  pooka 
    671   1.1  pooka  out:
    672   1.1  pooka 	close(fd);
    673   1.1  pooka 	return rv;
    674   1.1  pooka }
    675