1 /* $NetBSD: null.c,v 1.30 2011/06/27 12:06:19 manu 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
29 * A "nullfs" using puffs, i.e. maps one location in the hierarchy
30 * to another using standard system calls.
33 #include <sys/types.h>
48 PUFFSOP_PROTOS(puffs_null
)
51 * set attributes to what is specified. XXX: no rollback in case of failure
54 processvattr(const char *path
, const struct vattr
*va
, int regular
)
58 /* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */
59 if (va
->va_uid
!= (unsigned)-1 || va
->va_gid
!= (unsigned)-1)
60 if (lchown(path
, va
->va_uid
, va
->va_gid
) == -1)
63 if (va
->va_mode
!= (unsigned)PUFFS_VNOVAL
)
64 if (lchmod(path
, va
->va_mode
) == -1)
68 if (va
->va_atime
.tv_sec
!= (time_t)PUFFS_VNOVAL
69 || va
->va_mtime
.tv_sec
!= (time_t)PUFFS_VNOVAL
) {
70 TIMESPEC_TO_TIMEVAL(&tv
[0], &va
->va_atime
);
71 TIMESPEC_TO_TIMEVAL(&tv
[1], &va
->va_mtime
);
73 if (lutimes(path
, tv
) == -1)
77 if (regular
&& va
->va_size
!= (u_quad_t
)PUFFS_VNOVAL
)
78 if (truncate(path
, (off_t
)va
->va_size
) == -1)
85 * Kludge to open files which aren't writable *any longer*. This kinda
86 * works because the vfs layer does validation checks based on the file's
87 * permissions to allow writable opening before opening them. However,
88 * the problem arises if we want to create a file, write to it (cache),
89 * adjust permissions and then flush the file.
92 writeableopen(const char *path
)
99 fd
= open(path
, O_WRONLY
);
101 if (errno
== EACCES
) {
102 if (stat(path
, &sb
) == -1)
104 origmode
= sb
.st_mode
& ALLPERMS
;
106 if (chmod(path
, 0200) == -1)
109 fd
= open(path
, O_WRONLY
);
113 chmod(path
, origmode
);
125 inodecmp(struct puffs_usermount
*pu
, struct puffs_node
*pn
, void *arg
)
129 if (pn
->pn_va
.va_fileid
== *cmpino
)
135 makenode(struct puffs_usermount
*pu
, struct puffs_newinfo
*pni
,
136 const struct puffs_cn
*pcn
, const struct vattr
*va
, int regular
)
138 struct puffs_node
*pn
;
142 if ((rv
= processvattr(PCNPATH(pcn
), va
, regular
)) != 0)
145 pn
= puffs_pn_new(pu
, NULL
);
148 puffs_setvattr(&pn
->pn_va
, va
);
150 if (lstat(PCNPATH(pcn
), &sb
) == -1)
152 puffs_stat2vattr(&pn
->pn_va
, &sb
);
154 puffs_newinfo_setcookie(pni
, pn
);
158 /* This should be called first and overriden from the file system */
160 puffs_null_setops(struct puffs_ops
*pops
)
163 PUFFSOP_SET(pops
, puffs_null
, fs
, statvfs
);
164 PUFFSOP_SETFSNOP(pops
, unmount
);
165 PUFFSOP_SETFSNOP(pops
, sync
);
166 PUFFSOP_SET(pops
, puffs_null
, fs
, fhtonode
);
167 PUFFSOP_SET(pops
, puffs_null
, fs
, nodetofh
);
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)
201 fhcmp(struct puffs_usermount
*pu
, struct puffs_node
*pn
, void *arg
)
203 struct fid
*kf1
, *kf2
;
205 if ((kf1
= pn
->pn_data
) == NULL
)
209 if (kf1
->fid_len
!= kf2
->fid_len
)
213 if (memcmp(kf1
, kf2
, kf1
->fid_len
) == 0)
219 * This routine only supports file handles which have been issued while
220 * the server was alive. Not really stable ones, that is.
224 puffs_null_fs_fhtonode(struct puffs_usermount
*pu
, void *fid
, size_t fidsize
,
225 struct puffs_newinfo
*pni
)
227 struct puffs_node
*pn_res
;
229 if (fidsize
!= sizeof(struct fid
))
232 pn_res
= puffs_pn_nodewalk(pu
, fhcmp
, fid
);
236 puffs_newinfo_setcookie(pni
, pn_res
);
237 puffs_newinfo_setvtype(pni
, pn_res
->pn_va
.va_type
);
238 puffs_newinfo_setsize(pni
, (voff_t
)pn_res
->pn_va
.va_size
);
244 puffs_null_fs_nodetofh(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
245 void *fid
, size_t *fidsize
)
247 struct puffs_node
*pn
= opc
;
251 if (*fidsize
!= sizeof(struct fid
))
255 if (getfh(PNPATH(pn
), &fh
) == -1)
258 *(struct fid
*)fid
= fh
.fh_fid
;
259 pn
->pn_data
= malloc(*fidsize
);
260 if (pn
->pn_data
== NULL
)
262 memcpy(pn
->pn_data
, fid
, *fidsize
);
269 puffs_null_node_lookup(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
270 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
)
272 struct puffs_node
*pn
= opc
, *pn_res
;
276 assert(pn
->pn_va
.va_type
== VDIR
);
279 * Note to whoever is copypasting this: you must first check
280 * if the node is there and only then do nodewalk. Alternatively
281 * you could make sure that you don't return unlinked/rmdir'd
282 * nodes in some other fashion
284 rv
= lstat(PCNPATH(pcn
), &sb
);
288 /* XXX2: nodewalk is a bit too slow here */
289 pn_res
= puffs_pn_nodewalk(pu
, inodecmp
, &sb
.st_ino
);
291 if (pn_res
== NULL
) {
292 pn_res
= puffs_pn_new(pu
, NULL
);
295 puffs_stat2vattr(&pn_res
->pn_va
, &sb
);
298 puffs_newinfo_setcookie(pni
, pn_res
);
299 puffs_newinfo_setvtype(pni
, pn_res
->pn_va
.va_type
);
300 puffs_newinfo_setsize(pni
, (voff_t
)pn_res
->pn_va
.va_size
);
306 puffs_null_node_lookupdotdot(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
307 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
)
309 return puffs_null_node_lookup(pu
, opc
, pni
, pcn
);
314 puffs_null_node_create(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
315 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
316 const struct vattr
*va
)
320 fd
= open(PCNPATH(pcn
), O_RDWR
| O_CREAT
| O_TRUNC
);
325 rv
= makenode(pu
, pni
, pcn
, va
, 1);
327 unlink(PCNPATH(pcn
));
333 puffs_null_node_mknod(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
334 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
335 const struct vattr
*va
)
340 mode
= puffs_addvtype2mode(va
->va_mode
, va
->va_type
);
341 switch (va
->va_type
) {
343 if (mkfifo(PCNPATH(pcn
), mode
) == -1)
353 rv
= makenode(pu
, pni
, pcn
, va
, 0);
355 unlink(PCNPATH(pcn
));
361 puffs_null_node_getattr(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
362 struct vattr
*va
, const struct puffs_cred
*pcred
)
364 struct puffs_node
*pn
= opc
;
367 if (lstat(PNPATH(pn
), &sb
) == -1)
369 puffs_stat2vattr(va
, &sb
);
376 puffs_null_node_setattr(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
377 const struct vattr
*va
, const struct puffs_cred
*pcred
)
379 struct puffs_node
*pn
= opc
;
382 rv
= processvattr(PNPATH(pn
), va
, pn
->pn_va
.va_type
== VREG
);
386 puffs_setvattr(&pn
->pn_va
, va
);
393 puffs_null_node_fsync(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
396 struct puffs_node
*pn
= opc
;
401 if (stat(PNPATH(pn
), &sb
) == -1)
403 if (S_ISDIR(sb
.st_mode
)) {
405 if ((dirp
= opendir(PNPATH(pn
))) == NULL
)
411 fd
= writeableopen(PNPATH(pn
));
426 puffs_null_node_remove(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
427 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
429 struct puffs_node
*pn_targ
= targ
;
431 if (unlink(PNPATH(pn_targ
)) == -1)
433 puffs_pn_remove(pn_targ
);
440 puffs_null_node_link(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
441 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
443 struct puffs_node
*pn_targ
= targ
;
445 if (link(PNPATH(pn_targ
), PCNPATH(pcn
)) == -1)
453 puffs_null_node_rename(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
454 puffs_cookie_t src
, const struct puffs_cn
*pcn_src
,
455 puffs_cookie_t targ_dir
, puffs_cookie_t targ
,
456 const struct puffs_cn
*pcn_targ
)
459 if (rename(PCNPATH(pcn_src
), PCNPATH(pcn_targ
)) == -1)
467 puffs_null_node_mkdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
468 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
469 const struct vattr
*va
)
473 if (mkdir(PCNPATH(pcn
), va
->va_mode
) == -1)
476 rv
= makenode(pu
, pni
, pcn
, va
, 0);
484 puffs_null_node_rmdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
485 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
487 struct puffs_node
*pn_targ
= targ
;
489 if (rmdir(PNPATH(pn_targ
)) == -1)
491 puffs_pn_remove(pn_targ
);
498 puffs_null_node_symlink(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
499 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
500 const struct vattr
*va
, const char *linkname
)
504 if (symlink(linkname
, PCNPATH(pcn
)) == -1)
507 rv
= makenode(pu
, pni
, pcn
, va
, 0);
509 unlink(PCNPATH(pcn
));
515 puffs_null_node_readlink(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
516 const struct puffs_cred
*pcred
, char *linkname
, size_t *linklen
)
518 struct puffs_node
*pn
= opc
;
521 rv
= readlink(PNPATH(pn
), linkname
, *linklen
);
531 puffs_null_node_readdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
532 struct dirent
*de
, off_t
*off
, size_t *reslen
,
533 const struct puffs_cred
*pcred
, int *eofflag
, off_t
*cookies
,
536 struct puffs_node
*pn
= opc
;
537 struct dirent entry
, *result
;
543 dp
= opendir(PNPATH(pn
));
551 * XXX: need to do trickery here, telldir/seekdir would be nice, but
552 * then we'd need to keep state, which I'm too lazy to keep
555 rv
= readdir_r(dp
, &entry
, &result
);
566 rv
= readdir_r(dp
, &entry
, &result
);
575 if (_DIRENT_DIRSIZ(result
) > *reslen
)
579 *reslen
-= _DIRENT_DIRSIZ(result
);
580 de
= _DIRENT_NEXT(de
);
583 PUFFS_STORE_DCOOKIE(cookies
, ncookies
, *off
);
593 puffs_null_node_read(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
594 uint8_t *buf
, off_t offset
, size_t *buflen
,
595 const struct puffs_cred
*pcred
, int ioflag
)
597 struct puffs_node
*pn
= opc
;
603 fd
= open(PNPATH(pn
), O_RDONLY
);
606 off
= lseek(fd
, offset
, SEEK_SET
);
612 n
= read(fd
, buf
, *buflen
);
625 puffs_null_node_write(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
626 uint8_t *buf
, off_t offset
, size_t *buflen
,
627 const struct puffs_cred
*pcred
, int ioflag
)
629 struct puffs_node
*pn
= opc
;
635 fd
= writeableopen(PNPATH(pn
));
639 off
= lseek(fd
, offset
, SEEK_SET
);
645 n
= write(fd
, buf
, *buflen
);