Home | History | Annotate | Line # | Download | only in libpuffs
null.c revision 1.30.2.1
      1  1.30.2.1   yamt /*	$NetBSD: null.c,v 1.30.2.1 2012/04/17 00:05:31 yamt 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.30.2.1   yamt __RCSID("$NetBSD: null.c,v 1.30.2.1 2012/04/17 00:05:31 yamt 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.30.2.1   yamt 	struct puffs_node *pn_targ = targ;
    484       1.1  pooka 
    485       1.4  pooka 	if (rename(PCNPATH(pcn_src), PCNPATH(pcn_targ)) == -1)
    486       1.1  pooka 		return errno;
    487       1.1  pooka 
    488  1.30.2.1   yamt         if (pn_targ)
    489  1.30.2.1   yamt 		puffs_pn_remove(pn_targ);
    490  1.30.2.1   yamt 
    491       1.1  pooka 	return 0;
    492       1.1  pooka }
    493       1.1  pooka 
    494       1.1  pooka /*ARGSUSED*/
    495       1.1  pooka int
    496      1.25  pooka puffs_null_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    497      1.21  pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    498      1.21  pooka 	const struct vattr *va)
    499       1.1  pooka {
    500       1.1  pooka 	int rv;
    501       1.1  pooka 
    502       1.4  pooka 	if (mkdir(PCNPATH(pcn), va->va_mode) == -1)
    503       1.1  pooka 		return errno;
    504       1.1  pooka 
    505      1.21  pooka 	rv = makenode(pu, pni, pcn, va, 0);
    506      1.19  pooka 	if (rv)
    507       1.5    agc 		rmdir(PCNPATH(pcn));
    508      1.19  pooka 	return rv;
    509       1.1  pooka }
    510       1.1  pooka 
    511       1.1  pooka /*ARGSUSED*/
    512       1.1  pooka int
    513      1.25  pooka puffs_null_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    514      1.25  pooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
    515       1.1  pooka {
    516       1.1  pooka 	struct puffs_node *pn_targ = targ;
    517       1.1  pooka 
    518       1.4  pooka 	if (rmdir(PNPATH(pn_targ)) == -1)
    519       1.1  pooka 		return errno;
    520      1.16  pooka 	puffs_pn_remove(pn_targ);
    521       1.1  pooka 
    522       1.1  pooka 	return 0;
    523       1.1  pooka }
    524       1.1  pooka 
    525       1.1  pooka /*ARGSUSED*/
    526       1.1  pooka int
    527      1.25  pooka puffs_null_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
    528      1.21  pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    529      1.21  pooka 	const struct vattr *va, const char *linkname)
    530       1.1  pooka {
    531       1.1  pooka 	int rv;
    532       1.1  pooka 
    533       1.4  pooka 	if (symlink(linkname, PCNPATH(pcn)) == -1)
    534       1.1  pooka 		return errno;
    535       1.1  pooka 
    536      1.21  pooka 	rv = makenode(pu, pni, pcn, va, 0);
    537      1.19  pooka 	if (rv)
    538       1.4  pooka 		unlink(PCNPATH(pcn));
    539      1.19  pooka 	return rv;
    540       1.1  pooka }
    541       1.1  pooka 
    542       1.1  pooka /*ARGSUSED*/
    543       1.1  pooka int
    544      1.25  pooka puffs_null_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
    545       1.1  pooka 	const struct puffs_cred *pcred, char *linkname, size_t *linklen)
    546       1.1  pooka {
    547       1.1  pooka 	struct puffs_node *pn = opc;
    548       1.1  pooka 	ssize_t rv;
    549       1.1  pooka 
    550       1.4  pooka 	rv = readlink(PNPATH(pn), linkname, *linklen);
    551       1.1  pooka 	if (rv == -1)
    552       1.1  pooka 		return errno;
    553       1.1  pooka 
    554       1.8  pooka 	*linklen = rv;
    555       1.1  pooka 	return 0;
    556       1.1  pooka }
    557       1.1  pooka 
    558       1.1  pooka /*ARGSUSED*/
    559       1.1  pooka int
    560      1.25  pooka puffs_null_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
    561      1.24  pooka 	struct dirent *de, off_t *off, size_t *reslen,
    562      1.24  pooka 	const struct puffs_cred *pcred, int *eofflag, off_t *cookies,
    563      1.24  pooka 	size_t *ncookies)
    564       1.1  pooka {
    565       1.1  pooka 	struct puffs_node *pn = opc;
    566       1.1  pooka 	struct dirent entry, *result;
    567       1.1  pooka 	DIR *dp;
    568       1.1  pooka 	off_t i;
    569       1.1  pooka 	int rv;
    570       1.1  pooka 
    571      1.26  pooka 	*ncookies = 0;
    572       1.4  pooka 	dp = opendir(PNPATH(pn));
    573       1.1  pooka 	if (dp == NULL)
    574       1.1  pooka 		return errno;
    575       1.1  pooka 
    576       1.1  pooka 	rv = 0;
    577       1.1  pooka 	i = *off;
    578       1.1  pooka 
    579       1.1  pooka 	/*
    580       1.1  pooka 	 * XXX: need to do trickery here, telldir/seekdir would be nice, but
    581       1.1  pooka 	 * then we'd need to keep state, which I'm too lazy to keep
    582       1.1  pooka 	 */
    583       1.1  pooka 	while (i--) {
    584       1.1  pooka 		rv = readdir_r(dp, &entry, &result);
    585      1.30   manu 		if (rv != 0)
    586      1.30   manu 			goto out;
    587      1.30   manu 
    588      1.30   manu 		if (!result) {
    589      1.30   manu 			*eofflag = 1;
    590       1.1  pooka 			goto out;
    591      1.30   manu 		}
    592       1.1  pooka 	}
    593       1.1  pooka 
    594       1.1  pooka 	for (;;) {
    595       1.1  pooka 		rv = readdir_r(dp, &entry, &result);
    596       1.1  pooka 		if (rv != 0)
    597       1.1  pooka 			goto out;
    598       1.1  pooka 
    599      1.26  pooka 		if (!result) {
    600      1.26  pooka 			*eofflag = 1;
    601       1.1  pooka 			goto out;
    602      1.26  pooka 		}
    603       1.1  pooka 
    604       1.1  pooka 		if (_DIRENT_SIZE(result) > *reslen)
    605       1.1  pooka 			goto out;
    606       1.1  pooka 
    607       1.1  pooka 		*de = *result;
    608       1.1  pooka 		*reslen -= _DIRENT_SIZE(result);
    609       1.1  pooka 		de = _DIRENT_NEXT(de);
    610       1.1  pooka 
    611       1.1  pooka 		(*off)++;
    612      1.26  pooka 		PUFFS_STORE_DCOOKIE(cookies, ncookies, *off);
    613       1.1  pooka 	}
    614       1.1  pooka 
    615       1.1  pooka  out:
    616       1.1  pooka 	closedir(dp);
    617       1.1  pooka 	return 0;
    618       1.1  pooka }
    619       1.1  pooka 
    620       1.1  pooka /*ARGSUSED*/
    621       1.1  pooka int
    622      1.25  pooka puffs_null_node_read(struct puffs_usermount *pu, puffs_cookie_t opc,
    623      1.25  pooka 	uint8_t *buf, off_t offset, size_t *buflen,
    624      1.25  pooka 	const struct puffs_cred *pcred, int ioflag)
    625       1.1  pooka {
    626       1.1  pooka 	struct puffs_node *pn = opc;
    627       1.1  pooka 	ssize_t n;
    628       1.1  pooka 	off_t off;
    629       1.1  pooka 	int fd, rv;
    630       1.1  pooka 
    631       1.1  pooka 	rv = 0;
    632       1.4  pooka 	fd = open(PNPATH(pn), O_RDONLY);
    633       1.1  pooka 	if (fd == -1)
    634       1.1  pooka 		return errno;
    635       1.1  pooka 	off = lseek(fd, offset, SEEK_SET);
    636       1.1  pooka 	if (off == -1) {
    637       1.1  pooka 		rv = errno;
    638       1.1  pooka 		goto out;
    639       1.1  pooka 	}
    640       1.1  pooka 
    641       1.1  pooka 	n = read(fd, buf, *buflen);
    642       1.1  pooka 	if (n == -1)
    643       1.1  pooka 		rv = errno;
    644       1.1  pooka 	else
    645       1.1  pooka 		*buflen -= n;
    646       1.1  pooka 
    647       1.1  pooka  out:
    648       1.1  pooka 	close(fd);
    649       1.1  pooka 	return rv;
    650       1.1  pooka }
    651       1.1  pooka 
    652       1.1  pooka /*ARGSUSED*/
    653       1.1  pooka int
    654      1.25  pooka puffs_null_node_write(struct puffs_usermount *pu, puffs_cookie_t opc,
    655      1.25  pooka 	uint8_t *buf, off_t offset, size_t *buflen,
    656      1.25  pooka 	const struct puffs_cred *pcred, int ioflag)
    657       1.1  pooka {
    658       1.1  pooka 	struct puffs_node *pn = opc;
    659       1.1  pooka 	ssize_t n;
    660       1.1  pooka 	off_t off;
    661       1.1  pooka 	int fd, rv;
    662       1.1  pooka 
    663       1.1  pooka 	rv = 0;
    664       1.4  pooka 	fd = writeableopen(PNPATH(pn));
    665       1.3  pooka 	if (fd == -1)
    666       1.3  pooka 		return errno;
    667       1.2  pooka 
    668       1.1  pooka 	off = lseek(fd, offset, SEEK_SET);
    669       1.1  pooka 	if (off == -1) {
    670       1.1  pooka 		rv = errno;
    671       1.1  pooka 		goto out;
    672       1.1  pooka 	}
    673       1.1  pooka 
    674       1.1  pooka 	n = write(fd, buf, *buflen);
    675       1.1  pooka 	if (n == -1)
    676       1.1  pooka 		rv = errno;
    677       1.1  pooka 	else
    678       1.1  pooka 		*buflen -= n;
    679       1.1  pooka 
    680       1.1  pooka  out:
    681       1.1  pooka 	close(fd);
    682       1.1  pooka 	return rv;
    683       1.1  pooka }
    684