Sync usage with man page.
[netbsd-mini2440.git] / share / examples / puffs / dtfs / dtfs_vnops.c
blob254fa9c9b05ae8f9961c8c2cf0f38070fcb8422c
1 /* $NetBSD: dtfs_vnops.c,v 1.41 2007/11/30 19:02:37 pooka Exp $ */
3 /*
4 * Copyright (c) 2006 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
28 #include <sys/types.h>
29 #include <sys/poll.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <puffs.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <util.h>
40 #include "dtfs.h"
42 int
43 dtfs_node_lookup(struct puffs_usermount *pu, void *opc,
44 struct puffs_newinfo *pni, const struct puffs_cn *pcn)
46 struct puffs_node *pn_dir = opc;
47 struct dtfs_file *df = DTFS_CTOF(opc);
48 struct dtfs_dirent *dfd;
49 extern int straightflush;
50 int rv;
52 /* parent dir? */
53 if (PCNISDOTDOT(pcn)) {
54 assert(df->df_dotdot->pn_va.va_type == VDIR);
55 puffs_newinfo_setcookie(pni, df->df_dotdot);
56 puffs_newinfo_setvtype(pni, df->df_dotdot->pn_va.va_type);
58 return 0;
61 dfd = dtfs_dirgetbyname(df, pcn->pcn_name, pcn->pcn_namelen);
62 if (dfd) {
63 puffs_newinfo_setcookie(pni, dfd->dfd_node);
64 puffs_newinfo_setvtype(pni, dfd->dfd_node->pn_va.va_type);
65 puffs_newinfo_setsize(pni, dfd->dfd_node->pn_va.va_size);
66 puffs_newinfo_setrdev(pni, dfd->dfd_node->pn_va.va_rdev);
68 if (straightflush)
69 puffs_flush_pagecache_node(pu, dfd->dfd_node);
71 return 0;
74 if ((pcn->pcn_flags & NAMEI_ISLASTCN)
75 && (pcn->pcn_nameiop == NAMEI_CREATE ||
76 pcn->pcn_nameiop == NAMEI_RENAME)) {
77 rv = puffs_access(VDIR, pn_dir->pn_va.va_mode,
78 pn_dir->pn_va.va_uid, pn_dir->pn_va.va_gid,
79 PUFFS_VWRITE, pcn->pcn_cred);
80 if (rv)
81 return rv;
84 return ENOENT;
87 int
88 dtfs_node_access(struct puffs_usermount *pu, void *opc, int acc_mode,
89 const struct puffs_cred *pcr)
91 struct puffs_node *pn = opc;
93 return puffs_access(pn->pn_va.va_type, pn->pn_va.va_mode,
94 pn->pn_va.va_uid, pn->pn_va.va_gid, acc_mode, pcr);
97 int
98 dtfs_node_setattr(struct puffs_usermount *pu, void *opc,
99 const struct vattr *va, const struct puffs_cred *pcr)
101 struct puffs_node *pn = opc;
102 int rv;
104 /* check permissions */
105 if (va->va_flags != PUFFS_VNOVAL)
106 return EOPNOTSUPP;
108 if (va->va_uid != PUFFS_VNOVAL || va->va_gid != PUFFS_VNOVAL) {
109 rv = puffs_access_chown(pn->pn_va.va_uid, pn->pn_va.va_gid,
110 va->va_uid, va->va_gid, pcr);
111 if (rv)
112 return rv;
115 if (va->va_mode != PUFFS_VNOVAL) {
116 rv = puffs_access_chmod(pn->pn_va.va_uid, pn->pn_va.va_gid,
117 pn->pn_va.va_type, va->va_mode, pcr);
118 if (rv)
119 return rv;
122 if ((va->va_atime.tv_sec != PUFFS_VNOVAL
123 && va->va_atime.tv_nsec != PUFFS_VNOVAL)
124 || (va->va_mtime.tv_sec != PUFFS_VNOVAL
125 && va->va_mtime.tv_nsec != PUFFS_VNOVAL)) {
126 rv = puffs_access_times(pn->pn_va.va_uid, pn->pn_va.va_gid,
127 pn->pn_va.va_mode, va->va_vaflags & VA_UTIMES_NULL, pcr);
128 if (rv)
129 return rv;
132 if (va->va_size != PUFFS_VNOVAL) {
133 switch (pn->pn_va.va_type) {
134 case VREG:
135 dtfs_setsize(pn, va->va_size);
136 pn->pn_va.va_bytes = va->va_size;
137 break;
138 case VBLK:
139 case VCHR:
140 case VFIFO:
141 break;
142 case VDIR:
143 return EISDIR;
144 default:
145 return EOPNOTSUPP;
149 puffs_setvattr(&pn->pn_va, va);
151 return 0;
154 /* create a new node in the parent directory specified by opc */
156 dtfs_node_create(struct puffs_usermount *pu, void *opc,
157 struct puffs_newinfo *pni, const struct puffs_cn *pcn,
158 const struct vattr *va)
160 struct puffs_node *pn_parent = opc;
161 struct puffs_node *pn_new;
163 if (!(va->va_type == VREG || va->va_type == VSOCK))
164 return ENODEV;
166 pn_new = dtfs_genfile(pn_parent, pcn, va->va_type);
167 puffs_setvattr(&pn_new->pn_va, va);
169 puffs_newinfo_setcookie(pni, pn_new);
171 return 0;
175 dtfs_node_remove(struct puffs_usermount *pu, void *opc, void *targ,
176 const struct puffs_cn *pcn)
178 struct puffs_node *pn_parent = opc;
179 struct puffs_node *pn = targ;
181 if (pn->pn_va.va_type == VDIR)
182 return EPERM;
184 dtfs_nukenode(targ, pn_parent, pcn->pcn_name, pcn->pcn_namelen);
186 if (pn->pn_va.va_nlink == 0)
187 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
189 return 0;
193 dtfs_node_mkdir(struct puffs_usermount *pu, void *opc,
194 struct puffs_newinfo *pni, const struct puffs_cn *pcn,
195 const struct vattr *va)
197 struct puffs_node *pn_parent = opc;
198 struct puffs_node *pn_new;
200 pn_new = dtfs_genfile(pn_parent, pcn, VDIR);
201 puffs_setvattr(&pn_new->pn_va, va);
203 puffs_newinfo_setcookie(pni, pn_new);
205 return 0;
209 dtfs_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ,
210 const struct puffs_cn *pcn)
212 struct puffs_node *pn_parent = opc;
213 struct dtfs_file *df = DTFS_CTOF(targ);
215 if (!LIST_EMPTY(&df->df_dirents))
216 return ENOTEMPTY;
218 dtfs_nukenode(targ, pn_parent, pcn->pcn_name, pcn->pcn_namelen);
219 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
221 return 0;
225 dtfs_node_readdir(struct puffs_usermount *pu, void *opc,
226 struct dirent *dent, off_t *readoff, size_t *reslen,
227 const struct puffs_cred *pcr,
228 int *eofflag, off_t *cookies, size_t *ncookies)
230 struct puffs_node *pn = opc;
231 struct puffs_node *pn_nth;
232 struct dtfs_dirent *dfd_nth;
234 if (pn->pn_va.va_type != VDIR)
235 return ENOTDIR;
237 dtfs_updatetimes(pn, 1, 0, 0);
239 *ncookies = 0;
240 again:
241 if (*readoff == DENT_DOT || *readoff == DENT_DOTDOT) {
242 puffs_gendotdent(&dent, pn->pn_va.va_fileid, *readoff, reslen);
243 (*readoff)++;
244 PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff);
245 goto again;
248 for (;;) {
249 dfd_nth = dtfs_dirgetnth(pn->pn_data, DENT_ADJ(*readoff));
250 if (!dfd_nth) {
251 *eofflag = 1;
252 break;
254 pn_nth = dfd_nth->dfd_node;
256 if (!puffs_nextdent(&dent, dfd_nth->dfd_name,
257 pn_nth->pn_va.va_fileid,
258 puffs_vtype2dt(pn_nth->pn_va.va_type),
259 reslen))
260 break;
262 (*readoff)++;
263 PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff);
266 return 0;
270 dtfs_node_poll(struct puffs_usermount *pu, void *opc, int *events)
272 struct dtfs_mount *dtm = puffs_getspecific(pu);
273 struct dtfs_poll dp;
274 struct itimerval it;
276 memset(&it, 0, sizeof(struct itimerval));
277 it.it_value.tv_sec = 4;
278 if (setitimer(ITIMER_REAL, &it, NULL) == -1)
279 return errno;
281 dp.dp_pcc = puffs_cc_getcc(pu);
282 LIST_INSERT_HEAD(&dtm->dtm_pollent, &dp, dp_entries);
283 puffs_cc_yield(dp.dp_pcc);
285 *events = *events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
286 return 0;
290 dtfs_node_mmap(struct puffs_usermount *pu, void *opc, vm_prot_t prot,
291 const struct puffs_cred *pcr)
293 struct dtfs_mount *dtm = puffs_getspecific(pu);
295 if ((dtm->dtm_allowprot & prot) != prot)
296 return EACCES;
298 return 0;
302 dtfs_node_rename(struct puffs_usermount *pu, void *opc, void *src,
303 const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
304 const struct puffs_cn *pcn_targ)
306 struct dtfs_dirent *dfd_src;
307 struct puffs_node *pn_sdir = opc;
308 struct puffs_node *pn_tdir = targ_dir;
309 struct puffs_node *pn_tfile = targ;
311 dfd_src = dtfs_dirgetbyname(DTFS_PTOF(pn_sdir),
312 pcn_src->pcn_name, pcn_src->pcn_namelen);
314 /* asked for "." or ".." XXX: make sure? */
315 if (!dfd_src)
316 return EINVAL;
318 /* if there's a target file, nuke it for atomic replacement */
319 if (pn_tfile) {
320 if (pn_tfile->pn_va.va_type == VDIR) {
321 assert(/*CONSTCOND*/0); /* XXX FIXME */
323 dtfs_nukenode(pn_tfile, pn_sdir,
324 pcn_targ->pcn_name, pcn_targ->pcn_namelen);
327 /* out with the old */
328 dtfs_removedent(pn_sdir, dfd_src);
329 /* and in with the new */
330 dtfs_adddent(pn_tdir, dfd_src);
332 /* update name */
333 free(dfd_src->dfd_name);
334 dfd_src->dfd_name = estrndup(pcn_targ->pcn_name,pcn_targ->pcn_namelen);
335 dfd_src->dfd_namelen = strlen(dfd_src->dfd_name);
337 dtfs_updatetimes(src, 0, 1, 0);
339 return 0;
343 dtfs_node_link(struct puffs_usermount *pu, void *opc, void *targ,
344 const struct puffs_cn *pcn)
346 struct puffs_node *pn_dir = opc;
347 struct dtfs_dirent *dfd;
349 dfd = emalloc(sizeof(struct dtfs_dirent));
350 dfd->dfd_node = targ;
351 dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen);
352 dfd->dfd_namelen = strlen(dfd->dfd_name);
353 dtfs_adddent(pn_dir, dfd);
355 dtfs_updatetimes(targ, 0, 1, 0);
357 return 0;
361 dtfs_node_symlink(struct puffs_usermount *pu, void *opc,
362 struct puffs_newinfo *pni, const struct puffs_cn *pcn_src,
363 const struct vattr *va, const char *link_target)
365 struct puffs_node *pn_parent = opc;
366 struct puffs_node *pn_new;
367 struct dtfs_file *df_new;
369 if (va->va_type != VLNK)
370 return ENODEV;
372 pn_new = dtfs_genfile(pn_parent, pcn_src, VLNK);
373 puffs_setvattr(&pn_new->pn_va, va);
374 df_new = DTFS_PTOF(pn_new);
375 df_new->df_linktarget = estrdup(link_target);
376 pn_new->pn_va.va_size = strlen(df_new->df_linktarget);
378 puffs_newinfo_setcookie(pni, pn_new);
380 return 0;
384 dtfs_node_readlink(struct puffs_usermount *pu, void *opc,
385 const struct puffs_cred *cred, char *linkname, size_t *linklen)
387 struct dtfs_file *df = DTFS_CTOF(opc);
388 struct puffs_node *pn = opc;
390 assert(pn->pn_va.va_type == VLNK);
391 strlcpy(linkname, df->df_linktarget, *linklen);
392 *linklen = strlen(linkname);
394 return 0;
398 dtfs_node_mknod(struct puffs_usermount *pu, void *opc,
399 struct puffs_newinfo *pni, const struct puffs_cn *pcn,
400 const struct vattr *va)
402 struct puffs_node *pn_parent = opc;
403 struct puffs_node *pn_new;
404 struct dtfs_file *df;
406 if (!(va->va_type == VBLK || va->va_type == VCHR
407 || va->va_type == VFIFO))
408 return EINVAL;
410 pn_new = dtfs_genfile(pn_parent, pcn, va->va_type);
411 puffs_setvattr(&pn_new->pn_va, va);
413 df = DTFS_PTOF(pn_new);
414 puffs_newinfo_setcookie(pni, pn_new);
416 return 0;
419 #define BLOCKOFF(a,b) ((a) & ((b)-1))
420 #define BLOCKLEFT(a,b) ((b) - BLOCKOFF(a,b))
423 * Read operation, used both for VOP_READ and VOP_GETPAGES
426 dtfs_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf,
427 off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
429 struct puffs_node *pn = opc;
430 struct dtfs_file *df = DTFS_CTOF(opc);
431 quad_t xfer, origxfer;
432 uint8_t *src, *dest;
433 size_t copylen;
435 if (pn->pn_va.va_type != VREG)
436 return EISDIR;
438 xfer = MIN(*resid, df->df_datalen - offset);
439 if (xfer < 0)
440 return EINVAL;
442 dest = buf;
443 origxfer = xfer;
444 while (xfer > 0) {
445 copylen = MIN(xfer, BLOCKLEFT(offset, DTFS_BLOCKSIZE));
446 src = df->df_blocks[BLOCKNUM(offset, DTFS_BLOCKSHIFT)]
447 + BLOCKOFF(offset, DTFS_BLOCKSIZE);
448 memcpy(dest, src, copylen);
449 offset += copylen;
450 dest += copylen;
451 xfer -= copylen;
453 *resid -= origxfer;
455 dtfs_updatetimes(pn, 1, 0, 0);
457 return 0;
461 * write operation on the wing
464 dtfs_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf,
465 off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
467 struct puffs_node *pn = opc;
468 struct dtfs_file *df = DTFS_CTOF(opc);
469 uint8_t *src, *dest;
470 size_t copylen;
472 if (pn->pn_va.va_type != VREG)
473 return EISDIR;
475 if (ioflag & PUFFS_IO_APPEND)
476 offset = pn->pn_va.va_size;
478 if (*resid + offset > pn->pn_va.va_size)
479 dtfs_setsize(pn, *resid + offset);
481 src = buf;
482 while (*resid > 0) {
483 int i;
484 copylen = MIN(*resid, BLOCKLEFT(offset, DTFS_BLOCKSIZE));
485 i = BLOCKNUM(offset, DTFS_BLOCKSHIFT);
486 dest = df->df_blocks[i]
487 + BLOCKOFF(offset, DTFS_BLOCKSIZE);
488 memcpy(dest, src, copylen);
489 offset += copylen;
490 dest += copylen;
491 *resid -= copylen;
494 dtfs_updatetimes(pn, 0, 1, 1);
496 return 0;
500 dtfs_node_reclaim(struct puffs_usermount *pu, void *opc)
502 struct puffs_node *pn = opc;
504 if (pn->pn_va.va_nlink == 0)
505 dtfs_freenode(pn);
507 return 0;