1 /* $NetBSD: null.c,v 1.25 2008/08/12 19:44:39 pooka Exp $ */
4 * Copyright (c) 2007 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
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
28 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: null.c,v 1.25 2008/08/12 19:44:39 pooka Exp $");
34 * A "nullfs" using puffs, i.e. maps one location in the hierarchy
35 * to another using standard system calls.
38 #include <sys/types.h>
53 PUFFSOP_PROTOS(puffs_null
)
56 * set attributes to what is specified. XXX: no rollback in case of failure
59 processvattr(const char *path
, const struct vattr
*va
, int regular
)
63 /* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */
64 if (va
->va_uid
!= (unsigned)-1 || va
->va_gid
!= (unsigned)-1)
66 if (chown(path
, va
->va_uid
, va
->va_gid
) == -1)
70 if (va
->va_mode
!= (unsigned)PUFFS_VNOVAL
)
73 if (chmod(path
, va
->va_mode
) == -1)
77 if (va
->va_atime
.tv_sec
!= (unsigned)PUFFS_VNOVAL
78 || va
->va_mtime
.tv_sec
!= (unsigned)PUFFS_VNOVAL
) {
80 tbuf
.actime
= va
->va_atime
.tv_sec
;
81 tbuf
.modtime
= va
->va_mtime
.tv_sec
;
84 if (utime(path
, &tbuf
) == -1)
88 if (regular
&& va
->va_size
!= (u_quad_t
)PUFFS_VNOVAL
)
89 if (truncate(path
, (off_t
)va
->va_size
) == -1)
96 * Kludge to open files which aren't writable *any longer*. This kinda
97 * works because the vfs layer does validation checks based on the file's
98 * permissions to allow writable opening before opening them. However,
99 * the problem arises if we want to create a file, write to it (cache),
100 * adjust permissions and then flush the file.
103 writeableopen(const char *path
)
110 fd
= open(path
, O_WRONLY
);
112 if (errno
== EACCES
) {
113 if (stat(path
, &sb
) == -1)
115 origmode
= sb
.st_mode
& ALLPERMS
;
117 if (chmod(path
, 0200) == -1)
120 fd
= open(path
, O_WRONLY
);
124 chmod(path
, origmode
);
136 inodecmp(struct puffs_usermount
*pu
, struct puffs_node
*pn
, void *arg
)
140 if (pn
->pn_va
.va_fileid
== *cmpino
)
146 makenode(struct puffs_usermount
*pu
, struct puffs_newinfo
*pni
,
147 const struct puffs_cn
*pcn
, const struct vattr
*va
, int regular
)
149 struct puffs_node
*pn
;
153 if ((rv
= processvattr(PCNPATH(pcn
), va
, regular
)) != 0)
156 pn
= puffs_pn_new(pu
, NULL
);
159 puffs_setvattr(&pn
->pn_va
, va
);
161 if (lstat(PCNPATH(pcn
), &sb
) == -1)
163 puffs_stat2vattr(&pn
->pn_va
, &sb
);
165 puffs_newinfo_setcookie(pni
, pn
);
169 /* This should be called first and overriden from the file system */
171 puffs_null_setops(struct puffs_ops
*pops
)
174 PUFFSOP_SET(pops
, puffs_null
, fs
, statvfs
);
175 PUFFSOP_SETFSNOP(pops
, unmount
);
176 PUFFSOP_SETFSNOP(pops
, sync
);
178 PUFFSOP_SET(pops
, puffs_null
, node
, lookup
);
179 PUFFSOP_SET(pops
, puffs_null
, node
, create
);
180 PUFFSOP_SET(pops
, puffs_null
, node
, mknod
);
181 PUFFSOP_SET(pops
, puffs_null
, node
, getattr
);
182 PUFFSOP_SET(pops
, puffs_null
, node
, setattr
);
183 PUFFSOP_SET(pops
, puffs_null
, node
, fsync
);
184 PUFFSOP_SET(pops
, puffs_null
, node
, remove
);
185 PUFFSOP_SET(pops
, puffs_null
, node
, link
);
186 PUFFSOP_SET(pops
, puffs_null
, node
, rename
);
187 PUFFSOP_SET(pops
, puffs_null
, node
, mkdir
);
188 PUFFSOP_SET(pops
, puffs_null
, node
, rmdir
);
189 PUFFSOP_SET(pops
, puffs_null
, node
, symlink
);
190 PUFFSOP_SET(pops
, puffs_null
, node
, readlink
);
191 PUFFSOP_SET(pops
, puffs_null
, node
, readdir
);
192 PUFFSOP_SET(pops
, puffs_null
, node
, read
);
193 PUFFSOP_SET(pops
, puffs_null
, node
, write
);
194 PUFFSOP_SET(pops
, puffs_genfs
, node
, reclaim
);
199 puffs_null_fs_statvfs(struct puffs_usermount
*pu
, struct statvfs
*svfsb
)
202 if (statvfs(PNPATH(puffs_getroot(pu
)), svfsb
) == -1)
209 puffs_null_node_lookup(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
210 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
)
212 struct puffs_node
*pn
= opc
, *pn_res
;
216 assert(pn
->pn_va
.va_type
== VDIR
);
219 * Note to whoever is copypasting this: you must first check
220 * if the node is there and only then do nodewalk. Alternatively
221 * you could make sure that you don't return unlinked/rmdir'd
222 * nodes in some other fashion
224 rv
= lstat(PCNPATH(pcn
), &sb
);
228 /* XXX2: nodewalk is a bit too slow here */
229 pn_res
= puffs_pn_nodewalk(pu
, inodecmp
, &sb
.st_ino
);
231 if (pn_res
== NULL
) {
232 pn_res
= puffs_pn_new(pu
, NULL
);
235 puffs_stat2vattr(&pn_res
->pn_va
, &sb
);
238 puffs_newinfo_setcookie(pni
, pn_res
);
239 puffs_newinfo_setvtype(pni
, pn_res
->pn_va
.va_type
);
240 puffs_newinfo_setsize(pni
, (voff_t
)pn_res
->pn_va
.va_size
);
241 puffs_newinfo_setrdev(pni
, pn_res
->pn_va
.va_rdev
);
248 puffs_null_node_create(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
249 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
250 const struct vattr
*va
)
254 fd
= open(PCNPATH(pcn
), O_RDWR
| O_CREAT
| O_TRUNC
);
259 rv
= makenode(pu
, pni
, pcn
, va
, 1);
261 unlink(PCNPATH(pcn
));
267 puffs_null_node_mknod(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
268 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
269 const struct vattr
*va
)
274 mode
= puffs_addvtype2mode(va
->va_mode
, va
->va_type
);
275 if (mknod(PCNPATH(pcn
), mode
, va
->va_rdev
) == -1)
278 rv
= makenode(pu
, pni
, pcn
, va
, 0);
280 unlink(PCNPATH(pcn
));
286 puffs_null_node_getattr(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
287 struct vattr
*va
, const struct puffs_cred
*pcred
)
289 struct puffs_node
*pn
= opc
;
292 if (lstat(PNPATH(pn
), &sb
) == -1)
294 puffs_stat2vattr(va
, &sb
);
301 puffs_null_node_setattr(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
302 const struct vattr
*va
, const struct puffs_cred
*pcred
)
304 struct puffs_node
*pn
= opc
;
307 rv
= processvattr(PNPATH(pn
), va
, pn
->pn_va
.va_type
== VREG
);
311 puffs_setvattr(&pn
->pn_va
, va
);
318 puffs_null_node_fsync(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
319 const struct puffs_cred
*pcred
, int how
,
320 off_t offlo
, off_t offhi
)
322 /* FIXME: implement me. */
324 struct puffs_node
*pn
= opc
;
329 fd
= writeableopen(PNPATH(pn
));
333 if (how
& PUFFS_FSYNC_DATAONLY
)
337 if (how
& PUFFS_FSYNC_CACHE
)
340 if (fsync_range(fd
, fflags
, offlo
, offhi
- offlo
) == -1)
352 puffs_null_node_remove(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
353 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
355 struct puffs_node
*pn_targ
= targ
;
357 if (unlink(PCNPATH(pcn
)) == -1)
359 puffs_pn_remove(pn_targ
);
366 puffs_null_node_link(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
367 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
369 struct puffs_node
*pn_targ
= targ
;
371 if (link(PNPATH(pn_targ
), PCNPATH(pcn
)) == -1)
379 puffs_null_node_rename(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
380 puffs_cookie_t src
, const struct puffs_cn
*pcn_src
,
381 puffs_cookie_t targ_dir
, puffs_cookie_t targ
,
382 const struct puffs_cn
*pcn_targ
)
384 struct puffs_node
*pn_targ
= targ
;
386 if (rename(PCNPATH(pcn_src
), PCNPATH(pcn_targ
)) == -1)
390 puffs_pn_remove(pn_targ
);
397 puffs_null_node_mkdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
398 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
399 const struct vattr
*va
)
403 if (mkdir(PCNPATH(pcn
), va
->va_mode
) == -1)
406 rv
= makenode(pu
, pni
, pcn
, va
, 0);
414 puffs_null_node_rmdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
415 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
417 struct puffs_node
*pn_targ
= targ
;
419 if (rmdir(PNPATH(pn_targ
)) == -1)
421 puffs_pn_remove(pn_targ
);
428 puffs_null_node_symlink(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
429 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
430 const struct vattr
*va
, const char *linkname
)
434 if (symlink(linkname
, PCNPATH(pcn
)) == -1)
437 rv
= makenode(pu
, pni
, pcn
, va
, 0);
439 unlink(PCNPATH(pcn
));
445 puffs_null_node_readlink(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
446 const struct puffs_cred
*pcred
, char *linkname
, size_t *linklen
)
448 struct puffs_node
*pn
= opc
;
451 rv
= readlink(PNPATH(pn
), linkname
, *linklen
);
461 puffs_null_node_readdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
462 struct dirent
*de
, off_t
*off
, size_t *reslen
,
463 const struct puffs_cred
*pcred
, int *eofflag
, off_t
*cookies
,
466 /* TODO: use original code since we have libc from NetBSD */
467 struct puffs_node
*pn
= opc
;
468 struct dirent
*entry
;
473 dp
= opendir(PNPATH(pn
));
481 * XXX: need to do trickery here, telldir/seekdir would be nice, but
482 * then we'd need to keep state, which I'm too lazy to keep
493 /* FIXME: DIRENT_SIZE macro? For now do calculations here */
505 cp
= memchr(entry
->d_name
, '\0', NAME_MAX
);
509 namelen
= cp
- (entry
->d_name
);
510 dirent_size
= _DIRENT_RECLEN(entry
, namelen
);
512 if (dirent_size
> *reslen
)
516 strncpy(de
->d_name
, entry
->d_name
, namelen
);
517 *reslen
-= dirent_size
;
519 de
= _DIRENT_NEXT(de
);
530 puffs_null_node_read(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
531 uint8_t *buf
, off_t offset
, size_t *buflen
,
532 const struct puffs_cred
*pcred
, int ioflag
)
534 struct puffs_node
*pn
= opc
;
540 fd
= open(PNPATH(pn
), O_RDONLY
);
543 off
= lseek(fd
, offset
, SEEK_SET
);
549 n
= read(fd
, buf
, *buflen
);
562 puffs_null_node_write(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
563 uint8_t *buf
, off_t offset
, size_t *buflen
,
564 const struct puffs_cred
*pcred
, int ioflag
)
566 struct puffs_node
*pn
= opc
;
572 fd
= writeableopen(PNPATH(pn
));
576 off
= lseek(fd
, offset
, SEEK_SET
);
582 n
= write(fd
, buf
, *buflen
);