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