Home | History | Annotate | Line # | Download | only in h_dtfs
      1  1.10  christos /*	$NetBSD: dtfs_vnops.c,v 1.10 2013/10/19 17:45:00 christos Exp $	*/
      2   1.1     pooka 
      3   1.1     pooka /*
      4   1.1     pooka  * Copyright (c) 2006  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/types.h>
     29   1.1     pooka #include <sys/poll.h>
     30   1.1     pooka 
     31   1.1     pooka #include <assert.h>
     32   1.1     pooka #include <errno.h>
     33   1.1     pooka #include <puffs.h>
     34   1.1     pooka #include <stdio.h>
     35   1.1     pooka #include <stdlib.h>
     36   1.1     pooka #include <string.h>
     37   1.1     pooka #include <unistd.h>
     38   1.1     pooka #include <util.h>
     39   1.1     pooka 
     40   1.1     pooka #include "dtfs.h"
     41   1.1     pooka 
     42   1.1     pooka int
     43   1.1     pooka dtfs_node_lookup(struct puffs_usermount *pu, void *opc,
     44   1.1     pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn)
     45   1.1     pooka {
     46   1.1     pooka 	struct puffs_node *pn_dir = opc;
     47   1.1     pooka 	struct dtfs_file *df = DTFS_CTOF(opc);
     48   1.1     pooka 	struct dtfs_dirent *dfd;
     49   1.1     pooka 	extern int straightflush;
     50   1.1     pooka 	int rv;
     51   1.1     pooka 
     52   1.1     pooka 	/* parent dir? */
     53   1.1     pooka 	if (PCNISDOTDOT(pcn)) {
     54   1.8     pooka 		if (df->df_dotdot == NULL)
     55   1.8     pooka 			return ENOENT;
     56   1.8     pooka 
     57   1.1     pooka 		assert(df->df_dotdot->pn_va.va_type == VDIR);
     58   1.1     pooka 		puffs_newinfo_setcookie(pni, df->df_dotdot);
     59   1.1     pooka 		puffs_newinfo_setvtype(pni, df->df_dotdot->pn_va.va_type);
     60   1.1     pooka 
     61   1.1     pooka 		return 0;
     62   1.1     pooka 	}
     63   1.1     pooka 
     64   1.1     pooka 	dfd = dtfs_dirgetbyname(df, pcn->pcn_name, pcn->pcn_namelen);
     65   1.1     pooka 	if (dfd) {
     66   1.9     njoly 		if ((pcn->pcn_flags & NAMEI_ISLASTCN) &&
     67   1.9     njoly 		    (pcn->pcn_nameiop == NAMEI_DELETE)) {
     68   1.9     njoly 			rv = puffs_access(VDIR, pn_dir->pn_va.va_mode,
     69   1.9     njoly 			    pn_dir->pn_va.va_uid, pn_dir->pn_va.va_gid,
     70   1.9     njoly 			    PUFFS_VWRITE, pcn->pcn_cred);
     71   1.9     njoly 			if (rv)
     72   1.9     njoly 				return rv;
     73   1.9     njoly 		}
     74   1.1     pooka 		puffs_newinfo_setcookie(pni, dfd->dfd_node);
     75   1.1     pooka 		puffs_newinfo_setvtype(pni, dfd->dfd_node->pn_va.va_type);
     76   1.1     pooka 		puffs_newinfo_setsize(pni, dfd->dfd_node->pn_va.va_size);
     77   1.1     pooka 		puffs_newinfo_setrdev(pni, dfd->dfd_node->pn_va.va_rdev);
     78   1.1     pooka 
     79   1.1     pooka 		if (straightflush)
     80   1.1     pooka 			puffs_flush_pagecache_node(pu, dfd->dfd_node);
     81   1.1     pooka 
     82   1.1     pooka 		return 0;
     83   1.1     pooka 	}
     84   1.1     pooka 
     85   1.1     pooka 	if ((pcn->pcn_flags & NAMEI_ISLASTCN)
     86   1.1     pooka 	    && (pcn->pcn_nameiop == NAMEI_CREATE ||
     87   1.9     njoly 	        pcn->pcn_nameiop == NAMEI_RENAME)) {
     88   1.1     pooka 		rv = puffs_access(VDIR, pn_dir->pn_va.va_mode,
     89   1.1     pooka 		    pn_dir->pn_va.va_uid, pn_dir->pn_va.va_gid,
     90   1.1     pooka 		    PUFFS_VWRITE, pcn->pcn_cred);
     91   1.1     pooka 		if (rv)
     92   1.1     pooka 			return rv;
     93   1.1     pooka 	}
     94   1.1     pooka 
     95   1.1     pooka 	return ENOENT;
     96   1.1     pooka }
     97   1.1     pooka 
     98   1.1     pooka int
     99   1.1     pooka dtfs_node_access(struct puffs_usermount *pu, void *opc, int acc_mode,
    100   1.1     pooka 	const struct puffs_cred *pcr)
    101   1.1     pooka {
    102   1.1     pooka 	struct puffs_node *pn = opc;
    103   1.1     pooka 
    104   1.1     pooka 	return puffs_access(pn->pn_va.va_type, pn->pn_va.va_mode,
    105   1.1     pooka 	    pn->pn_va.va_uid, pn->pn_va.va_gid, acc_mode, pcr);
    106   1.1     pooka }
    107   1.1     pooka 
    108   1.1     pooka int
    109   1.1     pooka dtfs_node_setattr(struct puffs_usermount *pu, void *opc,
    110   1.1     pooka 	const struct vattr *va, const struct puffs_cred *pcr)
    111   1.1     pooka {
    112   1.1     pooka 	struct puffs_node *pn = opc;
    113   1.1     pooka 	int rv;
    114   1.1     pooka 
    115   1.1     pooka 	/* check permissions */
    116   1.1     pooka 	if (va->va_flags != PUFFS_VNOVAL)
    117   1.1     pooka 		return EOPNOTSUPP;
    118   1.1     pooka 
    119   1.1     pooka 	if (va->va_uid != PUFFS_VNOVAL || va->va_gid != PUFFS_VNOVAL) {
    120   1.1     pooka 		rv = puffs_access_chown(pn->pn_va.va_uid, pn->pn_va.va_gid,
    121   1.1     pooka 		    va->va_uid, va->va_gid, pcr);
    122   1.1     pooka 		if (rv)
    123   1.1     pooka 			return rv;
    124   1.1     pooka 	}
    125   1.1     pooka 
    126   1.1     pooka 	if (va->va_mode != PUFFS_VNOVAL) {
    127   1.1     pooka 		rv = puffs_access_chmod(pn->pn_va.va_uid, pn->pn_va.va_gid,
    128   1.1     pooka 		    pn->pn_va.va_type, va->va_mode, pcr);
    129   1.1     pooka 		if (rv)
    130   1.1     pooka 			return rv;
    131   1.1     pooka 	}
    132   1.1     pooka 
    133   1.1     pooka 	if ((va->va_atime.tv_sec != PUFFS_VNOVAL
    134   1.1     pooka 	      && va->va_atime.tv_nsec != PUFFS_VNOVAL)
    135   1.1     pooka 	    || (va->va_mtime.tv_sec != PUFFS_VNOVAL
    136   1.1     pooka 	      && va->va_mtime.tv_nsec != PUFFS_VNOVAL)) {
    137   1.1     pooka 		rv = puffs_access_times(pn->pn_va.va_uid, pn->pn_va.va_gid,
    138   1.1     pooka 		    pn->pn_va.va_mode, va->va_vaflags & VA_UTIMES_NULL, pcr);
    139   1.1     pooka 		if (rv)
    140   1.1     pooka 			return rv;
    141   1.1     pooka 	}
    142   1.1     pooka 
    143   1.1     pooka 	if (va->va_size != PUFFS_VNOVAL) {
    144   1.1     pooka 		switch (pn->pn_va.va_type) {
    145   1.1     pooka 		case VREG:
    146   1.1     pooka 			dtfs_setsize(pn, va->va_size);
    147   1.1     pooka 			pn->pn_va.va_bytes = va->va_size;
    148   1.1     pooka 			break;
    149   1.1     pooka 		case VBLK:
    150   1.1     pooka 		case VCHR:
    151   1.1     pooka 		case VFIFO:
    152   1.1     pooka 			break;
    153   1.1     pooka 		case VDIR:
    154   1.1     pooka 			return EISDIR;
    155   1.1     pooka 		default:
    156   1.1     pooka 			return EOPNOTSUPP;
    157   1.1     pooka 		}
    158   1.1     pooka 	}
    159   1.1     pooka 
    160   1.1     pooka 	puffs_setvattr(&pn->pn_va, va);
    161   1.1     pooka 
    162   1.1     pooka 	return 0;
    163   1.1     pooka }
    164   1.1     pooka 
    165   1.1     pooka /* create a new node in the parent directory specified by opc */
    166   1.1     pooka int
    167   1.1     pooka dtfs_node_create(struct puffs_usermount *pu, void *opc,
    168   1.1     pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    169   1.1     pooka 	const struct vattr *va)
    170   1.1     pooka {
    171   1.1     pooka 	struct puffs_node *pn_parent = opc;
    172   1.1     pooka 	struct puffs_node *pn_new;
    173   1.1     pooka 
    174   1.1     pooka 	if (!(va->va_type == VREG || va->va_type == VSOCK))
    175   1.1     pooka 		return ENODEV;
    176   1.1     pooka 
    177   1.1     pooka 	pn_new = dtfs_genfile(pn_parent, pcn, va->va_type);
    178   1.1     pooka 	puffs_setvattr(&pn_new->pn_va, va);
    179   1.1     pooka 
    180   1.1     pooka 	puffs_newinfo_setcookie(pni, pn_new);
    181   1.1     pooka 
    182   1.1     pooka 	return 0;
    183   1.1     pooka }
    184   1.1     pooka 
    185   1.1     pooka int
    186   1.1     pooka dtfs_node_remove(struct puffs_usermount *pu, void *opc, void *targ,
    187   1.1     pooka 	const struct puffs_cn *pcn)
    188   1.1     pooka {
    189   1.1     pooka 	struct puffs_node *pn_parent = opc;
    190   1.1     pooka 	struct puffs_node *pn = targ;
    191   1.1     pooka 
    192   1.1     pooka 	if (pn->pn_va.va_type == VDIR)
    193   1.1     pooka 		return EPERM;
    194   1.1     pooka 
    195   1.1     pooka 	dtfs_nukenode(targ, pn_parent, pcn->pcn_name, pcn->pcn_namelen);
    196   1.1     pooka 
    197   1.1     pooka 	if (pn->pn_va.va_nlink == 0)
    198   1.1     pooka 		puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
    199   1.1     pooka 
    200   1.1     pooka 	return 0;
    201   1.1     pooka }
    202   1.1     pooka 
    203   1.1     pooka int
    204   1.1     pooka dtfs_node_mkdir(struct puffs_usermount *pu, void *opc,
    205   1.1     pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    206   1.1     pooka 	const struct vattr *va)
    207   1.1     pooka {
    208   1.1     pooka 	struct puffs_node *pn_parent = opc;
    209   1.1     pooka 	struct puffs_node *pn_new;
    210   1.1     pooka 
    211   1.1     pooka 	pn_new = dtfs_genfile(pn_parent, pcn, VDIR);
    212   1.1     pooka 	puffs_setvattr(&pn_new->pn_va, va);
    213   1.1     pooka 
    214   1.1     pooka 	puffs_newinfo_setcookie(pni, pn_new);
    215   1.1     pooka 
    216   1.1     pooka 	return 0;
    217   1.1     pooka }
    218   1.1     pooka 
    219   1.1     pooka int
    220   1.1     pooka dtfs_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ,
    221   1.1     pooka 	const struct puffs_cn *pcn)
    222   1.1     pooka {
    223   1.1     pooka 	struct puffs_node *pn_parent = opc;
    224   1.1     pooka 	struct dtfs_file *df = DTFS_CTOF(targ);
    225   1.1     pooka 
    226   1.1     pooka 	if (!LIST_EMPTY(&df->df_dirents))
    227   1.1     pooka 		return ENOTEMPTY;
    228   1.1     pooka 
    229   1.1     pooka 	dtfs_nukenode(targ, pn_parent, pcn->pcn_name, pcn->pcn_namelen);
    230   1.1     pooka 	puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
    231   1.1     pooka 
    232   1.1     pooka 	return 0;
    233   1.1     pooka }
    234   1.1     pooka 
    235   1.1     pooka int
    236   1.1     pooka dtfs_node_readdir(struct puffs_usermount *pu, void *opc,
    237   1.1     pooka 	struct dirent *dent, off_t *readoff, size_t *reslen,
    238   1.1     pooka 	const struct puffs_cred *pcr,
    239   1.1     pooka 	int *eofflag, off_t *cookies, size_t *ncookies)
    240   1.1     pooka {
    241   1.1     pooka 	struct puffs_node *pn = opc;
    242   1.1     pooka 	struct puffs_node *pn_nth;
    243   1.1     pooka 	struct dtfs_dirent *dfd_nth;
    244   1.1     pooka 
    245   1.1     pooka 	if (pn->pn_va.va_type != VDIR)
    246   1.1     pooka 		return ENOTDIR;
    247   1.1     pooka 
    248   1.1     pooka 	dtfs_updatetimes(pn, 1, 0, 0);
    249   1.1     pooka 
    250   1.1     pooka 	*ncookies = 0;
    251   1.1     pooka  again:
    252   1.1     pooka 	if (*readoff == DENT_DOT || *readoff == DENT_DOTDOT) {
    253   1.1     pooka 		puffs_gendotdent(&dent, pn->pn_va.va_fileid, *readoff, reslen);
    254   1.1     pooka 		(*readoff)++;
    255   1.1     pooka 		PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff);
    256   1.1     pooka 		goto again;
    257   1.1     pooka 	}
    258   1.1     pooka 
    259   1.1     pooka 	for (;;) {
    260   1.1     pooka 		dfd_nth = dtfs_dirgetnth(pn->pn_data, DENT_ADJ(*readoff));
    261   1.1     pooka 		if (!dfd_nth) {
    262   1.1     pooka 			*eofflag = 1;
    263   1.1     pooka 			break;
    264   1.1     pooka 		}
    265   1.1     pooka 		pn_nth = dfd_nth->dfd_node;
    266   1.1     pooka 
    267   1.1     pooka 		if (!puffs_nextdent(&dent, dfd_nth->dfd_name,
    268   1.1     pooka 		    pn_nth->pn_va.va_fileid,
    269   1.1     pooka 		    puffs_vtype2dt(pn_nth->pn_va.va_type),
    270   1.1     pooka 		    reslen))
    271   1.1     pooka 			break;
    272   1.1     pooka 
    273   1.1     pooka 		(*readoff)++;
    274   1.1     pooka 		PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff);
    275   1.1     pooka 	}
    276   1.1     pooka 
    277   1.1     pooka 	return 0;
    278   1.1     pooka }
    279   1.1     pooka 
    280   1.1     pooka int
    281   1.1     pooka dtfs_node_poll(struct puffs_usermount *pu, void *opc, int *events)
    282   1.1     pooka {
    283   1.1     pooka 	struct dtfs_mount *dtm = puffs_getspecific(pu);
    284   1.1     pooka 	struct dtfs_poll dp;
    285   1.1     pooka 	struct itimerval it;
    286   1.1     pooka 
    287   1.1     pooka 	memset(&it, 0, sizeof(struct itimerval));
    288   1.1     pooka 	it.it_value.tv_sec = 4;
    289   1.1     pooka 	if (setitimer(ITIMER_REAL, &it, NULL) == -1)
    290   1.1     pooka 		return errno;
    291   1.1     pooka 
    292   1.1     pooka 	dp.dp_pcc = puffs_cc_getcc(pu);
    293   1.1     pooka 	LIST_INSERT_HEAD(&dtm->dtm_pollent, &dp, dp_entries);
    294   1.1     pooka 	puffs_cc_yield(dp.dp_pcc);
    295   1.1     pooka 
    296   1.1     pooka 	*events = *events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
    297   1.1     pooka 	return 0;
    298   1.1     pooka }
    299   1.1     pooka 
    300   1.1     pooka int
    301   1.1     pooka dtfs_node_mmap(struct puffs_usermount *pu, void *opc, vm_prot_t prot,
    302   1.1     pooka 	const struct puffs_cred *pcr)
    303   1.1     pooka {
    304   1.1     pooka 	struct dtfs_mount *dtm = puffs_getspecific(pu);
    305   1.1     pooka 
    306   1.1     pooka 	if ((dtm->dtm_allowprot & prot) != prot)
    307   1.1     pooka 		return EACCES;
    308   1.1     pooka 
    309   1.1     pooka 	return 0;
    310   1.1     pooka }
    311   1.1     pooka 
    312   1.1     pooka int
    313   1.1     pooka dtfs_node_rename(struct puffs_usermount *pu, void *opc, void *src,
    314   1.1     pooka 	const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
    315   1.1     pooka 	const struct puffs_cn *pcn_targ)
    316   1.1     pooka {
    317   1.1     pooka 	struct dtfs_dirent *dfd_src;
    318   1.3     pooka 	struct dtfs_file *df_targ;
    319   1.1     pooka 	struct puffs_node *pn_sdir = opc;
    320   1.2     pooka 	struct puffs_node *pn_sfile = src;
    321   1.1     pooka 	struct puffs_node *pn_tdir = targ_dir;
    322   1.1     pooka 	struct puffs_node *pn_tfile = targ;
    323   1.1     pooka 
    324   1.2     pooka 	/* check that we don't do the old amigados trick */
    325   1.2     pooka 	if (pn_sfile->pn_va.va_type == VDIR) {
    326   1.2     pooka 		if (dtfs_isunder(pn_tdir, pn_sfile))
    327   1.2     pooka 			return EINVAL;
    328   1.5     pooka 
    329   1.5     pooka 		if ((pcn_src->pcn_namelen == 1 && pcn_src->pcn_name[0]=='.') ||
    330   1.5     pooka 		    opc == src ||
    331   1.5     pooka 		    PCNISDOTDOT(pcn_src) ||
    332   1.5     pooka 		    PCNISDOTDOT(pcn_targ)) {
    333   1.5     pooka 			return EINVAL;
    334   1.5     pooka 		}
    335   1.2     pooka 	}
    336   1.2     pooka 
    337   1.1     pooka 	dfd_src = dtfs_dirgetbyname(DTFS_PTOF(pn_sdir),
    338   1.1     pooka 	    pcn_src->pcn_name, pcn_src->pcn_namelen);
    339   1.1     pooka 
    340   1.6     pooka 	/* does it still exist, or did someone race us here? */
    341   1.6     pooka 	if (dfd_src == NULL) {
    342   1.6     pooka 		return ENOENT;
    343   1.6     pooka 	}
    344   1.6     pooka 
    345   1.1     pooka 	/* if there's a target file, nuke it for atomic replacement */
    346   1.1     pooka 	if (pn_tfile) {
    347   1.1     pooka 		if (pn_tfile->pn_va.va_type == VDIR) {
    348   1.3     pooka 			df_targ = DTFS_CTOF(pn_tfile);
    349   1.3     pooka 			if (!LIST_EMPTY(&df_targ->df_dirents))
    350   1.3     pooka 				return ENOTEMPTY;
    351   1.1     pooka 		}
    352   1.4     pooka 		dtfs_nukenode(pn_tfile, pn_tdir,
    353   1.1     pooka 		    pcn_targ->pcn_name, pcn_targ->pcn_namelen);
    354   1.1     pooka 	}
    355   1.1     pooka 
    356   1.1     pooka 	/* out with the old */
    357   1.1     pooka 	dtfs_removedent(pn_sdir, dfd_src);
    358   1.1     pooka 	/* and in with the new */
    359   1.1     pooka 	dtfs_adddent(pn_tdir, dfd_src);
    360   1.1     pooka 
    361   1.1     pooka 	/* update name */
    362   1.1     pooka 	free(dfd_src->dfd_name);
    363   1.1     pooka 	dfd_src->dfd_name = estrndup(pcn_targ->pcn_name,pcn_targ->pcn_namelen);
    364   1.1     pooka 	dfd_src->dfd_namelen = strlen(dfd_src->dfd_name);
    365   1.1     pooka 
    366   1.1     pooka 	dtfs_updatetimes(src, 0, 1, 0);
    367   1.1     pooka 
    368   1.1     pooka 	return 0;
    369   1.1     pooka }
    370   1.1     pooka 
    371   1.1     pooka int
    372   1.1     pooka dtfs_node_link(struct puffs_usermount *pu, void *opc, void *targ,
    373   1.1     pooka 	const struct puffs_cn *pcn)
    374   1.1     pooka {
    375   1.1     pooka 	struct puffs_node *pn_dir = opc;
    376   1.1     pooka 	struct dtfs_dirent *dfd;
    377   1.1     pooka 
    378   1.1     pooka 	dfd = emalloc(sizeof(struct dtfs_dirent));
    379   1.1     pooka 	dfd->dfd_node = targ;
    380   1.1     pooka 	dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen);
    381   1.1     pooka 	dfd->dfd_namelen = strlen(dfd->dfd_name);
    382   1.1     pooka 	dtfs_adddent(pn_dir, dfd);
    383   1.1     pooka 
    384   1.1     pooka 	dtfs_updatetimes(targ, 0, 1, 0);
    385   1.1     pooka 
    386   1.1     pooka 	return 0;
    387   1.1     pooka }
    388   1.1     pooka 
    389   1.1     pooka int
    390   1.1     pooka dtfs_node_symlink(struct puffs_usermount *pu, void *opc,
    391   1.1     pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn_src,
    392   1.1     pooka 	const struct vattr *va, const char *link_target)
    393   1.1     pooka {
    394   1.1     pooka 	struct puffs_node *pn_parent = opc;
    395   1.1     pooka 	struct puffs_node *pn_new;
    396   1.1     pooka 	struct dtfs_file *df_new;
    397   1.1     pooka 
    398   1.1     pooka 	if (va->va_type != VLNK)
    399   1.1     pooka 		return ENODEV;
    400   1.1     pooka 
    401   1.1     pooka 	pn_new = dtfs_genfile(pn_parent, pcn_src, VLNK);
    402   1.1     pooka 	puffs_setvattr(&pn_new->pn_va, va);
    403   1.1     pooka 	df_new = DTFS_PTOF(pn_new);
    404   1.1     pooka 	df_new->df_linktarget = estrdup(link_target);
    405   1.1     pooka 	pn_new->pn_va.va_size = strlen(df_new->df_linktarget);
    406   1.1     pooka 
    407   1.1     pooka 	puffs_newinfo_setcookie(pni, pn_new);
    408   1.1     pooka 
    409   1.1     pooka 	return 0;
    410   1.1     pooka }
    411   1.1     pooka 
    412   1.1     pooka int
    413   1.1     pooka dtfs_node_readlink(struct puffs_usermount *pu, void *opc,
    414   1.1     pooka 	const struct puffs_cred *cred, char *linkname, size_t *linklen)
    415   1.1     pooka {
    416   1.1     pooka 	struct dtfs_file *df = DTFS_CTOF(opc);
    417   1.1     pooka 	struct puffs_node *pn = opc;
    418   1.1     pooka 
    419   1.1     pooka 	assert(pn->pn_va.va_type == VLNK);
    420   1.1     pooka 	strlcpy(linkname, df->df_linktarget, *linklen);
    421   1.1     pooka 	*linklen = strlen(linkname);
    422   1.1     pooka 
    423   1.1     pooka 	return 0;
    424   1.1     pooka }
    425   1.1     pooka 
    426   1.1     pooka int
    427   1.1     pooka dtfs_node_mknod(struct puffs_usermount *pu, void *opc,
    428   1.1     pooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
    429   1.1     pooka 	const struct vattr *va)
    430   1.1     pooka {
    431   1.1     pooka 	struct puffs_node *pn_parent = opc;
    432   1.1     pooka 	struct puffs_node *pn_new;
    433   1.1     pooka 
    434   1.1     pooka 	if (!(va->va_type == VBLK || va->va_type == VCHR
    435   1.1     pooka 	    || va->va_type == VFIFO))
    436   1.1     pooka 		return EINVAL;
    437   1.1     pooka 
    438   1.1     pooka 	pn_new = dtfs_genfile(pn_parent, pcn, va->va_type);
    439   1.1     pooka 	puffs_setvattr(&pn_new->pn_va, va);
    440   1.1     pooka 
    441   1.1     pooka 	puffs_newinfo_setcookie(pni, pn_new);
    442   1.1     pooka 
    443   1.1     pooka 	return 0;
    444   1.1     pooka }
    445   1.1     pooka 
    446   1.1     pooka #define BLOCKOFF(a,b) ((a) & ((b)-1))
    447   1.1     pooka #define BLOCKLEFT(a,b) ((b) - BLOCKOFF(a,b))
    448   1.1     pooka 
    449   1.1     pooka /*
    450   1.1     pooka  * Read operation, used both for VOP_READ and VOP_GETPAGES
    451   1.1     pooka  */
    452   1.1     pooka int
    453   1.1     pooka dtfs_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf,
    454   1.1     pooka 	off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
    455   1.1     pooka {
    456   1.1     pooka 	struct puffs_node *pn = opc;
    457   1.1     pooka 	struct dtfs_file *df = DTFS_CTOF(opc);
    458   1.1     pooka 	quad_t xfer, origxfer;
    459   1.1     pooka 	uint8_t *src, *dest;
    460   1.1     pooka 	size_t copylen;
    461   1.1     pooka 
    462   1.1     pooka 	if (pn->pn_va.va_type != VREG)
    463   1.1     pooka 		return EISDIR;
    464   1.1     pooka 
    465   1.1     pooka 	xfer = MIN(*resid, df->df_datalen - offset);
    466   1.1     pooka 	if (xfer < 0)
    467   1.1     pooka 		return EINVAL;
    468   1.1     pooka 
    469   1.1     pooka 	dest = buf;
    470   1.1     pooka 	origxfer = xfer;
    471   1.1     pooka 	while (xfer > 0) {
    472   1.1     pooka 		copylen = MIN(xfer, BLOCKLEFT(offset, DTFS_BLOCKSIZE));
    473   1.1     pooka 		src = df->df_blocks[BLOCKNUM(offset, DTFS_BLOCKSHIFT)]
    474   1.1     pooka 		    + BLOCKOFF(offset, DTFS_BLOCKSIZE);
    475   1.1     pooka 		memcpy(dest, src, copylen);
    476   1.1     pooka 		offset += copylen;
    477   1.1     pooka 		dest += copylen;
    478   1.1     pooka 		xfer -= copylen;
    479   1.1     pooka 	}
    480   1.1     pooka 	*resid -= origxfer;
    481   1.1     pooka 
    482   1.1     pooka 	dtfs_updatetimes(pn, 1, 0, 0);
    483   1.1     pooka 
    484   1.1     pooka 	return 0;
    485   1.1     pooka }
    486   1.1     pooka 
    487   1.1     pooka /*
    488   1.1     pooka  * write operation on the wing
    489   1.1     pooka  */
    490   1.1     pooka int
    491   1.1     pooka dtfs_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf,
    492   1.1     pooka 	off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
    493   1.1     pooka {
    494   1.1     pooka 	struct puffs_node *pn = opc;
    495   1.1     pooka 	struct dtfs_file *df = DTFS_CTOF(opc);
    496   1.1     pooka 	uint8_t *src, *dest;
    497   1.1     pooka 	size_t copylen;
    498   1.1     pooka 
    499   1.1     pooka 	if (pn->pn_va.va_type != VREG)
    500   1.1     pooka 		return EISDIR;
    501   1.1     pooka 
    502   1.1     pooka 	if (ioflag & PUFFS_IO_APPEND)
    503   1.1     pooka 		offset = pn->pn_va.va_size;
    504   1.1     pooka 
    505   1.1     pooka 	if (*resid + offset > pn->pn_va.va_size)
    506   1.1     pooka 		dtfs_setsize(pn, *resid + offset);
    507   1.1     pooka 
    508   1.1     pooka 	src = buf;
    509   1.1     pooka 	while (*resid > 0) {
    510   1.1     pooka 		int i;
    511   1.1     pooka 		copylen = MIN(*resid, BLOCKLEFT(offset, DTFS_BLOCKSIZE));
    512   1.1     pooka 		i = BLOCKNUM(offset, DTFS_BLOCKSHIFT);
    513   1.1     pooka 		dest = df->df_blocks[i]
    514   1.1     pooka 		    + BLOCKOFF(offset, DTFS_BLOCKSIZE);
    515   1.1     pooka 		memcpy(dest, src, copylen);
    516   1.1     pooka 		offset += copylen;
    517   1.1     pooka 		dest += copylen;
    518   1.1     pooka 		*resid -= copylen;
    519   1.1     pooka 	}
    520   1.1     pooka 
    521   1.1     pooka 	dtfs_updatetimes(pn, 0, 1, 1);
    522   1.1     pooka 
    523   1.1     pooka 	return 0;
    524   1.1     pooka }
    525   1.1     pooka 
    526   1.1     pooka int
    527   1.7     pooka dtfs_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc,
    528   1.7     pooka 	int name, register_t *retval)
    529   1.7     pooka {
    530   1.7     pooka 
    531   1.7     pooka 	switch (name) {
    532   1.7     pooka 	case _PC_LINK_MAX:
    533   1.7     pooka 		*retval = LINK_MAX;
    534   1.7     pooka 		return 0;
    535   1.7     pooka 	case _PC_NAME_MAX:
    536   1.7     pooka 		*retval = NAME_MAX;
    537   1.7     pooka 		return 0;
    538   1.7     pooka 	case _PC_PATH_MAX:
    539   1.7     pooka 		*retval = PATH_MAX;
    540   1.7     pooka 		return 0;
    541   1.7     pooka 	case _PC_PIPE_BUF:
    542   1.7     pooka 		*retval = PIPE_BUF;
    543   1.7     pooka 		return 0;
    544   1.7     pooka 	case _PC_CHOWN_RESTRICTED:
    545   1.7     pooka 		*retval = 1;
    546   1.7     pooka 		return 0;
    547   1.7     pooka 	case _PC_NO_TRUNC:
    548   1.7     pooka 		*retval = 1;
    549   1.7     pooka 		return 0;
    550   1.7     pooka 	case _PC_SYNC_IO:
    551   1.7     pooka 		*retval = 1;
    552   1.7     pooka 		return 0;
    553   1.7     pooka 	case _PC_FILESIZEBITS:
    554   1.7     pooka 		*retval = 43; /* this one goes to 11 */
    555   1.7     pooka 		return 0;
    556   1.7     pooka 	case _PC_SYMLINK_MAX:
    557   1.7     pooka 		*retval = MAXPATHLEN;
    558   1.7     pooka 		return 0;
    559   1.7     pooka 	case _PC_2_SYMLINKS:
    560   1.7     pooka 		*retval = 1;
    561   1.7     pooka 		return 0;
    562   1.7     pooka 	default:
    563   1.7     pooka 		return EINVAL;
    564   1.7     pooka 	}
    565   1.7     pooka }
    566   1.7     pooka 
    567   1.7     pooka int
    568   1.1     pooka dtfs_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc)
    569   1.1     pooka {
    570   1.1     pooka 	struct puffs_node *pn = opc;
    571   1.1     pooka 
    572   1.1     pooka 	if (pn->pn_va.va_nlink == 0)
    573   1.1     pooka 		puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1);
    574   1.1     pooka 	return 0;
    575   1.1     pooka }
    576   1.1     pooka 
    577   1.1     pooka int
    578   1.1     pooka dtfs_node_reclaim(struct puffs_usermount *pu, void *opc)
    579   1.1     pooka {
    580   1.1     pooka 	struct puffs_node *pn = opc;
    581   1.1     pooka 
    582   1.1     pooka 	if (pn->pn_va.va_nlink == 0)
    583   1.1     pooka 		dtfs_freenode(pn);
    584   1.1     pooka 
    585   1.1     pooka 	return 0;
    586   1.1     pooka }
    587