1 /* $NetBSD: dtfs_vnops.c,v 1.41 2007/11/30 19:02:37 pooka Exp $ */
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
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/types.h>
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
;
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
);
61 dfd
= dtfs_dirgetbyname(df
, pcn
->pcn_name
, pcn
->pcn_namelen
);
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
);
69 puffs_flush_pagecache_node(pu
, dfd
->dfd_node
);
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
);
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
);
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
;
104 /* check permissions */
105 if (va
->va_flags
!= PUFFS_VNOVAL
)
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
);
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
);
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
);
132 if (va
->va_size
!= PUFFS_VNOVAL
) {
133 switch (pn
->pn_va
.va_type
) {
135 dtfs_setsize(pn
, va
->va_size
);
136 pn
->pn_va
.va_bytes
= va
->va_size
;
149 puffs_setvattr(&pn
->pn_va
, va
);
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
))
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
);
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
)
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
);
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
);
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
))
218 dtfs_nukenode(targ
, pn_parent
, pcn
->pcn_name
, pcn
->pcn_namelen
);
219 puffs_setback(puffs_cc_getcc(pu
), PUFFS_SETBACK_NOREF_N2
);
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
)
237 dtfs_updatetimes(pn
, 1, 0, 0);
241 if (*readoff
== DENT_DOT
|| *readoff
== DENT_DOTDOT
) {
242 puffs_gendotdent(&dent
, pn
->pn_va
.va_fileid
, *readoff
, reslen
);
244 PUFFS_STORE_DCOOKIE(cookies
, ncookies
, *readoff
);
249 dfd_nth
= dtfs_dirgetnth(pn
->pn_data
, DENT_ADJ(*readoff
));
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
),
263 PUFFS_STORE_DCOOKIE(cookies
, ncookies
, *readoff
);
270 dtfs_node_poll(struct puffs_usermount
*pu
, void *opc
, int *events
)
272 struct dtfs_mount
*dtm
= puffs_getspecific(pu
);
276 memset(&it
, 0, sizeof(struct itimerval
));
277 it
.it_value
.tv_sec
= 4;
278 if (setitimer(ITIMER_REAL
, &it
, NULL
) == -1)
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
);
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
)
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? */
318 /* if there's a target file, nuke it for atomic replacement */
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
);
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);
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);
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
)
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
);
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
);
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
))
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
);
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
;
435 if (pn
->pn_va
.va_type
!= VREG
)
438 xfer
= MIN(*resid
, df
->df_datalen
- offset
);
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
);
455 dtfs_updatetimes(pn
, 1, 0, 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
);
472 if (pn
->pn_va
.va_type
!= VREG
)
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
);
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
);
494 dtfs_updatetimes(pn
, 0, 1, 1);
500 dtfs_node_reclaim(struct puffs_usermount
*pu
, void *opc
)
502 struct puffs_node
*pn
= opc
;
504 if (pn
->pn_va
.va_nlink
== 0)