1 /* $NetBSD: null.c,v 1.24 2007/11/30 19:02:28 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.24 2007/11/30 19:02:28 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>
50 PUFFSOP_PROTOS(puffs_null
)
53 * set attributes to what is specified. XXX: no rollback in case of failure
56 processvattr(const char *path
, const struct vattr
*va
, int regular
)
60 /* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */
61 if (va
->va_uid
!= (unsigned)-1 || va
->va_gid
!= (unsigned)-1)
62 if (lchown(path
, va
->va_uid
, va
->va_gid
) == -1)
65 if (va
->va_mode
!= (unsigned)PUFFS_VNOVAL
)
66 if (lchmod(path
, va
->va_mode
) == -1)
70 if (va
->va_atime
.tv_sec
!= (unsigned)PUFFS_VNOVAL
71 || va
->va_mtime
.tv_sec
!= (unsigned)PUFFS_VNOVAL
) {
72 TIMESPEC_TO_TIMEVAL(&tv
[0], &va
->va_atime
);
73 TIMESPEC_TO_TIMEVAL(&tv
[1], &va
->va_mtime
);
75 if (lutimes(path
, tv
) == -1)
79 if (regular
&& va
->va_size
!= (u_quad_t
)PUFFS_VNOVAL
)
80 if (truncate(path
, (off_t
)va
->va_size
) == -1)
87 * Kludge to open files which aren't writable *any longer*. This kinda
88 * works because the vfs layer does validation checks based on the file's
89 * permissions to allow writable opening before opening them. However,
90 * the problem arises if we want to create a file, write to it (cache),
91 * adjust permissions and then flush the file.
94 writeableopen(const char *path
)
101 fd
= open(path
, O_WRONLY
);
103 if (errno
== EACCES
) {
104 if (stat(path
, &sb
) == -1)
106 origmode
= sb
.st_mode
& ALLPERMS
;
108 if (chmod(path
, 0200) == -1)
111 fd
= open(path
, O_WRONLY
);
115 chmod(path
, origmode
);
127 inodecmp(struct puffs_usermount
*pu
, struct puffs_node
*pn
, void *arg
)
131 if (pn
->pn_va
.va_fileid
== *cmpino
)
137 makenode(struct puffs_usermount
*pu
, struct puffs_newinfo
*pni
,
138 const struct puffs_cn
*pcn
, const struct vattr
*va
, int regular
)
140 struct puffs_node
*pn
;
144 if ((rv
= processvattr(PCNPATH(pcn
), va
, regular
)) != 0)
147 pn
= puffs_pn_new(pu
, NULL
);
150 puffs_setvattr(&pn
->pn_va
, va
);
152 if (lstat(PCNPATH(pcn
), &sb
) == -1)
154 puffs_stat2vattr(&pn
->pn_va
, &sb
);
156 puffs_newinfo_setcookie(pni
, pn
);
160 /* This should be called first and overriden from the file system */
162 puffs_null_setops(struct puffs_ops
*pops
)
165 PUFFSOP_SET(pops
, puffs_null
, fs
, statvfs
);
166 PUFFSOP_SETFSNOP(pops
, unmount
);
167 PUFFSOP_SETFSNOP(pops
, sync
);
169 PUFFSOP_SET(pops
, puffs_null
, node
, lookup
);
170 PUFFSOP_SET(pops
, puffs_null
, node
, create
);
171 PUFFSOP_SET(pops
, puffs_null
, node
, mknod
);
172 PUFFSOP_SET(pops
, puffs_null
, node
, getattr
);
173 PUFFSOP_SET(pops
, puffs_null
, node
, setattr
);
174 PUFFSOP_SET(pops
, puffs_null
, node
, fsync
);
175 PUFFSOP_SET(pops
, puffs_null
, node
, remove
);
176 PUFFSOP_SET(pops
, puffs_null
, node
, link
);
177 PUFFSOP_SET(pops
, puffs_null
, node
, rename
);
178 PUFFSOP_SET(pops
, puffs_null
, node
, mkdir
);
179 PUFFSOP_SET(pops
, puffs_null
, node
, rmdir
);
180 PUFFSOP_SET(pops
, puffs_null
, node
, symlink
);
181 PUFFSOP_SET(pops
, puffs_null
, node
, readlink
);
182 PUFFSOP_SET(pops
, puffs_null
, node
, readdir
);
183 PUFFSOP_SET(pops
, puffs_null
, node
, read
);
184 PUFFSOP_SET(pops
, puffs_null
, node
, write
);
185 PUFFSOP_SET(pops
, puffs_genfs
, node
, reclaim
);
190 puffs_null_fs_statvfs(struct puffs_usermount
*pu
, struct statvfs
*svfsb
)
193 if (statvfs(PNPATH(puffs_getroot(pu
)), svfsb
) == -1)
200 puffs_null_node_lookup(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
201 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
)
203 struct puffs_node
*pn
= opc
, *pn_res
;
207 assert(pn
->pn_va
.va_type
== VDIR
);
210 * Note to whoever is copypasting this: you must first check
211 * if the node is there and only then do nodewalk. Alternatively
212 * you could make sure that you don't return unlinked/rmdir'd
213 * nodes in some other fashion
215 rv
= lstat(PCNPATH(pcn
), &sb
);
219 /* XXX2: nodewalk is a bit too slow here */
220 pn_res
= puffs_pn_nodewalk(pu
, inodecmp
, &sb
.st_ino
);
222 if (pn_res
== NULL
) {
223 pn_res
= puffs_pn_new(pu
, NULL
);
226 puffs_stat2vattr(&pn_res
->pn_va
, &sb
);
229 puffs_newinfo_setcookie(pni
, pn_res
);
230 puffs_newinfo_setvtype(pni
, pn_res
->pn_va
.va_type
);
231 puffs_newinfo_setsize(pni
, (voff_t
)pn_res
->pn_va
.va_size
);
232 puffs_newinfo_setrdev(pni
, pn_res
->pn_va
.va_rdev
);
239 puffs_null_node_create(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
240 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
241 const struct vattr
*va
)
245 fd
= open(PCNPATH(pcn
), O_RDWR
| O_CREAT
| O_TRUNC
);
250 rv
= makenode(pu
, pni
, pcn
, va
, 1);
252 unlink(PCNPATH(pcn
));
258 puffs_null_node_mknod(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
259 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
260 const struct vattr
*va
)
265 mode
= puffs_addvtype2mode(va
->va_mode
, va
->va_type
);
266 if (mknod(PCNPATH(pcn
), mode
, va
->va_rdev
) == -1)
269 rv
= makenode(pu
, pni
, pcn
, va
, 0);
271 unlink(PCNPATH(pcn
));
277 puffs_null_node_getattr(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
278 struct vattr
*va
, const struct puffs_cred
*pcred
)
280 struct puffs_node
*pn
= opc
;
283 if (lstat(PNPATH(pn
), &sb
) == -1)
285 puffs_stat2vattr(va
, &sb
);
292 puffs_null_node_setattr(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
293 const struct vattr
*va
, const struct puffs_cred
*pcred
)
295 struct puffs_node
*pn
= opc
;
298 rv
= processvattr(PNPATH(pn
), va
, pn
->pn_va
.va_type
== VREG
);
302 puffs_setvattr(&pn
->pn_va
, va
);
309 puffs_null_node_fsync(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
310 const struct puffs_cred
*pcred
, int how
,
311 off_t offlo
, off_t offhi
)
313 struct puffs_node
*pn
= opc
;
318 fd
= writeableopen(PNPATH(pn
));
322 if (how
& PUFFS_FSYNC_DATAONLY
)
326 if (how
& PUFFS_FSYNC_CACHE
)
329 if (fsync_range(fd
, fflags
, offlo
, offhi
- offlo
) == -1)
339 puffs_null_node_remove(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
340 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
342 struct puffs_node
*pn_targ
= targ
;
344 if (unlink(PNPATH(pn_targ
)) == -1)
346 puffs_pn_remove(pn_targ
);
353 puffs_null_node_link(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
354 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
356 struct puffs_node
*pn_targ
= targ
;
358 if (link(PNPATH(pn_targ
), PCNPATH(pcn
)) == -1)
366 puffs_null_node_rename(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
367 puffs_cookie_t src
, const struct puffs_cn
*pcn_src
,
368 puffs_cookie_t targ_dir
, puffs_cookie_t targ
,
369 const struct puffs_cn
*pcn_targ
)
372 if (rename(PCNPATH(pcn_src
), PCNPATH(pcn_targ
)) == -1)
380 puffs_null_node_mkdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
381 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
382 const struct vattr
*va
)
386 if (mkdir(PCNPATH(pcn
), va
->va_mode
) == -1)
389 rv
= makenode(pu
, pni
, pcn
, va
, 0);
397 puffs_null_node_rmdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
398 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
400 struct puffs_node
*pn_targ
= targ
;
402 if (rmdir(PNPATH(pn_targ
)) == -1)
404 puffs_pn_remove(pn_targ
);
411 puffs_null_node_symlink(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
412 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
413 const struct vattr
*va
, const char *linkname
)
417 if (symlink(linkname
, PCNPATH(pcn
)) == -1)
420 rv
= makenode(pu
, pni
, pcn
, va
, 0);
422 unlink(PCNPATH(pcn
));
428 puffs_null_node_readlink(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
429 const struct puffs_cred
*pcred
, char *linkname
, size_t *linklen
)
431 struct puffs_node
*pn
= opc
;
434 rv
= readlink(PNPATH(pn
), linkname
, *linklen
);
444 puffs_null_node_readdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
445 struct dirent
*de
, off_t
*off
, size_t *reslen
,
446 const struct puffs_cred
*pcred
, int *eofflag
, off_t
*cookies
,
449 struct puffs_node
*pn
= opc
;
450 struct dirent entry
, *result
;
455 dp
= opendir(PNPATH(pn
));
463 * XXX: need to do trickery here, telldir/seekdir would be nice, but
464 * then we'd need to keep state, which I'm too lazy to keep
467 rv
= readdir_r(dp
, &entry
, &result
);
473 rv
= readdir_r(dp
, &entry
, &result
);
480 if (_DIRENT_SIZE(result
) > *reslen
)
484 *reslen
-= _DIRENT_SIZE(result
);
485 de
= _DIRENT_NEXT(de
);
497 puffs_null_node_read(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
498 uint8_t *buf
, off_t offset
, size_t *buflen
,
499 const struct puffs_cred
*pcred
, int ioflag
)
501 struct puffs_node
*pn
= opc
;
507 fd
= open(PNPATH(pn
), O_RDONLY
);
510 off
= lseek(fd
, offset
, SEEK_SET
);
516 n
= read(fd
, buf
, *buflen
);
529 puffs_null_node_write(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
530 uint8_t *buf
, off_t offset
, size_t *buflen
,
531 const struct puffs_cred
*pcred
, int ioflag
)
533 struct puffs_node
*pn
= opc
;
539 fd
= writeableopen(PNPATH(pn
));
543 off
= lseek(fd
, offset
, SEEK_SET
);
549 n
= write(fd
, buf
, *buflen
);