1 /* $NetBSD: null.c,v 1.27 2009/01/08 02:19:48 lukem 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.27 2009/01/08 02:19:48 lukem 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>
52 PUFFSOP_PROTOS(puffs_null
)
55 * set attributes to what is specified. XXX: no rollback in case of failure
58 processvattr(const char *path
, const struct vattr
*va
, int regular
)
62 /* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */
63 if (va
->va_uid
!= (unsigned)-1 || va
->va_gid
!= (unsigned)-1)
64 if (lchown(path
, va
->va_uid
, va
->va_gid
) == -1)
67 if (va
->va_mode
!= (unsigned)PUFFS_VNOVAL
)
68 if (lchmod(path
, va
->va_mode
) == -1)
72 if (va
->va_atime
.tv_sec
!= (time_t)PUFFS_VNOVAL
73 || va
->va_mtime
.tv_sec
!= (time_t)PUFFS_VNOVAL
) {
74 TIMESPEC_TO_TIMEVAL(&tv
[0], &va
->va_atime
);
75 TIMESPEC_TO_TIMEVAL(&tv
[1], &va
->va_mtime
);
77 if (lutimes(path
, tv
) == -1)
81 if (regular
&& va
->va_size
!= (u_quad_t
)PUFFS_VNOVAL
)
82 if (truncate(path
, (off_t
)va
->va_size
) == -1)
89 * Kludge to open files which aren't writable *any longer*. This kinda
90 * works because the vfs layer does validation checks based on the file's
91 * permissions to allow writable opening before opening them. However,
92 * the problem arises if we want to create a file, write to it (cache),
93 * adjust permissions and then flush the file.
96 writeableopen(const char *path
)
103 fd
= open(path
, O_WRONLY
);
105 if (errno
== EACCES
) {
106 if (stat(path
, &sb
) == -1)
108 origmode
= sb
.st_mode
& ALLPERMS
;
110 if (chmod(path
, 0200) == -1)
113 fd
= open(path
, O_WRONLY
);
117 chmod(path
, origmode
);
129 inodecmp(struct puffs_usermount
*pu
, struct puffs_node
*pn
, void *arg
)
133 if (pn
->pn_va
.va_fileid
== *cmpino
)
139 makenode(struct puffs_usermount
*pu
, struct puffs_newinfo
*pni
,
140 const struct puffs_cn
*pcn
, const struct vattr
*va
, int regular
)
142 struct puffs_node
*pn
;
146 if ((rv
= processvattr(PCNPATH(pcn
), va
, regular
)) != 0)
149 pn
= puffs_pn_new(pu
, NULL
);
152 puffs_setvattr(&pn
->pn_va
, va
);
154 if (lstat(PCNPATH(pcn
), &sb
) == -1)
156 puffs_stat2vattr(&pn
->pn_va
, &sb
);
158 puffs_newinfo_setcookie(pni
, pn
);
162 /* This should be called first and overriden from the file system */
164 puffs_null_setops(struct puffs_ops
*pops
)
167 PUFFSOP_SET(pops
, puffs_null
, fs
, statvfs
);
168 PUFFSOP_SETFSNOP(pops
, unmount
);
169 PUFFSOP_SETFSNOP(pops
, sync
);
170 PUFFSOP_SET(pops
, puffs_null
, fs
, fhtonode
);
171 PUFFSOP_SET(pops
, puffs_null
, fs
, nodetofh
);
173 PUFFSOP_SET(pops
, puffs_null
, node
, lookup
);
174 PUFFSOP_SET(pops
, puffs_null
, node
, create
);
175 PUFFSOP_SET(pops
, puffs_null
, node
, mknod
);
176 PUFFSOP_SET(pops
, puffs_null
, node
, getattr
);
177 PUFFSOP_SET(pops
, puffs_null
, node
, setattr
);
178 PUFFSOP_SET(pops
, puffs_null
, node
, fsync
);
179 PUFFSOP_SET(pops
, puffs_null
, node
, remove
);
180 PUFFSOP_SET(pops
, puffs_null
, node
, link
);
181 PUFFSOP_SET(pops
, puffs_null
, node
, rename
);
182 PUFFSOP_SET(pops
, puffs_null
, node
, mkdir
);
183 PUFFSOP_SET(pops
, puffs_null
, node
, rmdir
);
184 PUFFSOP_SET(pops
, puffs_null
, node
, symlink
);
185 PUFFSOP_SET(pops
, puffs_null
, node
, readlink
);
186 PUFFSOP_SET(pops
, puffs_null
, node
, readdir
);
187 PUFFSOP_SET(pops
, puffs_null
, node
, read
);
188 PUFFSOP_SET(pops
, puffs_null
, node
, write
);
189 PUFFSOP_SET(pops
, puffs_genfs
, node
, reclaim
);
194 puffs_null_fs_statvfs(struct puffs_usermount
*pu
, struct statvfs
*svfsb
)
197 if (statvfs(PNPATH(puffs_getroot(pu
)), svfsb
) == -1)
204 * XXX: this is the stupidest crap ever, but:
205 * getfh() returns the fhandle type, when we are expected to deliver
206 * the fid type. Just adjust it a bit and stop whining.
208 * Yes, this really really needs fixing. Yes, *REALLY*.
210 #define FHANDLE_HEADERLEN 8
212 unsigned short fid_len
; /* length of data in bytes */
213 unsigned short fid_reserved
; /* compat: historic align */
214 char fid_data
[0]; /* data (variable length) */
219 fhcmp(struct puffs_usermount
*pu
, struct puffs_node
*pn
, void *arg
)
221 struct kernfid
*kf1
, *kf2
;
223 if ((kf1
= pn
->pn_data
) == NULL
)
227 if (kf1
->fid_len
!= kf2
->fid_len
)
231 if (memcmp(kf1
, kf2
, kf1
->fid_len
) == 0)
237 * This routine only supports file handles which have been issued while
238 * the server was alive. Not really stable ones, that is.
242 puffs_null_fs_fhtonode(struct puffs_usermount
*pu
, void *fid
, size_t fidsize
,
243 struct puffs_newinfo
*pni
)
245 struct puffs_node
*pn_res
;
247 pn_res
= puffs_pn_nodewalk(pu
, fhcmp
, fid
);
251 puffs_newinfo_setcookie(pni
, pn_res
);
252 puffs_newinfo_setvtype(pni
, pn_res
->pn_va
.va_type
);
253 puffs_newinfo_setsize(pni
, (voff_t
)pn_res
->pn_va
.va_size
);
254 puffs_newinfo_setrdev(pni
, pn_res
->pn_va
.va_rdev
);
260 puffs_null_fs_nodetofh(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
261 void *fid
, size_t *fidsize
)
263 struct puffs_node
*pn
= opc
;
264 struct kernfid
*kfid
;
271 bounce
= malloc(*fidsize
+ FHANDLE_HEADERLEN
);
274 *fidsize
+= FHANDLE_HEADERLEN
;
276 if (getfh(PNPATH(pn
), bounce
, fidsize
) == -1)
279 memcpy(fid
, (uint8_t *)bounce
+ FHANDLE_HEADERLEN
,
280 *fidsize
- FHANDLE_HEADERLEN
);
283 *fidsize
= kfid
->fid_len
;
284 pn
->pn_data
= malloc(*fidsize
);
285 if (pn
->pn_data
== NULL
)
287 memcpy(pn
->pn_data
, fid
, *fidsize
);
289 *fidsize
-= FHANDLE_HEADERLEN
;
297 puffs_null_node_lookup(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
298 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
)
300 struct puffs_node
*pn
= opc
, *pn_res
;
304 assert(pn
->pn_va
.va_type
== VDIR
);
307 * Note to whoever is copypasting this: you must first check
308 * if the node is there and only then do nodewalk. Alternatively
309 * you could make sure that you don't return unlinked/rmdir'd
310 * nodes in some other fashion
312 rv
= lstat(PCNPATH(pcn
), &sb
);
316 /* XXX2: nodewalk is a bit too slow here */
317 pn_res
= puffs_pn_nodewalk(pu
, inodecmp
, &sb
.st_ino
);
319 if (pn_res
== NULL
) {
320 pn_res
= puffs_pn_new(pu
, NULL
);
323 puffs_stat2vattr(&pn_res
->pn_va
, &sb
);
326 puffs_newinfo_setcookie(pni
, pn_res
);
327 puffs_newinfo_setvtype(pni
, pn_res
->pn_va
.va_type
);
328 puffs_newinfo_setsize(pni
, (voff_t
)pn_res
->pn_va
.va_size
);
329 puffs_newinfo_setrdev(pni
, pn_res
->pn_va
.va_rdev
);
336 puffs_null_node_create(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
337 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
338 const struct vattr
*va
)
342 fd
= open(PCNPATH(pcn
), O_RDWR
| O_CREAT
| O_TRUNC
);
347 rv
= makenode(pu
, pni
, pcn
, va
, 1);
349 unlink(PCNPATH(pcn
));
355 puffs_null_node_mknod(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
356 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
357 const struct vattr
*va
)
362 mode
= puffs_addvtype2mode(va
->va_mode
, va
->va_type
);
363 if (mknod(PCNPATH(pcn
), mode
, va
->va_rdev
) == -1)
366 rv
= makenode(pu
, pni
, pcn
, va
, 0);
368 unlink(PCNPATH(pcn
));
374 puffs_null_node_getattr(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
375 struct vattr
*va
, const struct puffs_cred
*pcred
)
377 struct puffs_node
*pn
= opc
;
380 if (lstat(PNPATH(pn
), &sb
) == -1)
382 puffs_stat2vattr(va
, &sb
);
389 puffs_null_node_setattr(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
390 const struct vattr
*va
, const struct puffs_cred
*pcred
)
392 struct puffs_node
*pn
= opc
;
395 rv
= processvattr(PNPATH(pn
), va
, pn
->pn_va
.va_type
== VREG
);
399 puffs_setvattr(&pn
->pn_va
, va
);
406 puffs_null_node_fsync(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
407 const struct puffs_cred
*pcred
, int how
,
408 off_t offlo
, off_t offhi
)
410 struct puffs_node
*pn
= opc
;
415 fd
= writeableopen(PNPATH(pn
));
419 if (how
& PUFFS_FSYNC_DATAONLY
)
423 if (how
& PUFFS_FSYNC_CACHE
)
426 if (fsync_range(fd
, fflags
, offlo
, offhi
- offlo
) == -1)
436 puffs_null_node_remove(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
437 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
439 struct puffs_node
*pn_targ
= targ
;
441 if (unlink(PNPATH(pn_targ
)) == -1)
443 puffs_pn_remove(pn_targ
);
450 puffs_null_node_link(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
451 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
453 struct puffs_node
*pn_targ
= targ
;
455 if (link(PNPATH(pn_targ
), PCNPATH(pcn
)) == -1)
463 puffs_null_node_rename(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
464 puffs_cookie_t src
, const struct puffs_cn
*pcn_src
,
465 puffs_cookie_t targ_dir
, puffs_cookie_t targ
,
466 const struct puffs_cn
*pcn_targ
)
469 if (rename(PCNPATH(pcn_src
), PCNPATH(pcn_targ
)) == -1)
477 puffs_null_node_mkdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
478 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
479 const struct vattr
*va
)
483 if (mkdir(PCNPATH(pcn
), va
->va_mode
) == -1)
486 rv
= makenode(pu
, pni
, pcn
, va
, 0);
494 puffs_null_node_rmdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
495 puffs_cookie_t targ
, const struct puffs_cn
*pcn
)
497 struct puffs_node
*pn_targ
= targ
;
499 if (rmdir(PNPATH(pn_targ
)) == -1)
501 puffs_pn_remove(pn_targ
);
508 puffs_null_node_symlink(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
509 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
510 const struct vattr
*va
, const char *linkname
)
514 if (symlink(linkname
, PCNPATH(pcn
)) == -1)
517 rv
= makenode(pu
, pni
, pcn
, va
, 0);
519 unlink(PCNPATH(pcn
));
525 puffs_null_node_readlink(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
526 const struct puffs_cred
*pcred
, char *linkname
, size_t *linklen
)
528 struct puffs_node
*pn
= opc
;
531 rv
= readlink(PNPATH(pn
), linkname
, *linklen
);
541 puffs_null_node_readdir(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
542 struct dirent
*de
, off_t
*off
, size_t *reslen
,
543 const struct puffs_cred
*pcred
, int *eofflag
, off_t
*cookies
,
546 struct puffs_node
*pn
= opc
;
547 struct dirent entry
, *result
;
553 dp
= opendir(PNPATH(pn
));
561 * XXX: need to do trickery here, telldir/seekdir would be nice, but
562 * then we'd need to keep state, which I'm too lazy to keep
565 rv
= readdir_r(dp
, &entry
, &result
);
571 rv
= readdir_r(dp
, &entry
, &result
);
580 if (_DIRENT_SIZE(result
) > *reslen
)
584 *reslen
-= _DIRENT_SIZE(result
);
585 de
= _DIRENT_NEXT(de
);
588 PUFFS_STORE_DCOOKIE(cookies
, ncookies
, *off
);
598 puffs_null_node_read(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
599 uint8_t *buf
, off_t offset
, size_t *buflen
,
600 const struct puffs_cred
*pcred
, int ioflag
)
602 struct puffs_node
*pn
= opc
;
608 fd
= open(PNPATH(pn
), O_RDONLY
);
611 off
= lseek(fd
, offset
, SEEK_SET
);
617 n
= read(fd
, buf
, *buflen
);
630 puffs_null_node_write(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
631 uint8_t *buf
, off_t offset
, size_t *buflen
,
632 const struct puffs_cred
*pcred
, int ioflag
)
634 struct puffs_node
*pn
= opc
;
640 fd
= writeableopen(PNPATH(pn
));
644 off
= lseek(fd
, offset
, SEEK_SET
);
650 n
= write(fd
, buf
, *buflen
);