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