1 /* $NetBSD: dtfs_vnops.c,v 1.10 2013/10/19 17:45:00 christos 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 if (df
->df_dotdot
== NULL
)
57 assert(df
->df_dotdot
->pn_va
.va_type
== VDIR
);
58 puffs_newinfo_setcookie(pni
, df
->df_dotdot
);
59 puffs_newinfo_setvtype(pni
, df
->df_dotdot
->pn_va
.va_type
);
64 dfd
= dtfs_dirgetbyname(df
, pcn
->pcn_name
, pcn
->pcn_namelen
);
66 if ((pcn
->pcn_flags
& NAMEI_ISLASTCN
) &&
67 (pcn
->pcn_nameiop
== NAMEI_DELETE
)) {
68 rv
= puffs_access(VDIR
, pn_dir
->pn_va
.va_mode
,
69 pn_dir
->pn_va
.va_uid
, pn_dir
->pn_va
.va_gid
,
70 PUFFS_VWRITE
, pcn
->pcn_cred
);
74 puffs_newinfo_setcookie(pni
, dfd
->dfd_node
);
75 puffs_newinfo_setvtype(pni
, dfd
->dfd_node
->pn_va
.va_type
);
76 puffs_newinfo_setsize(pni
, dfd
->dfd_node
->pn_va
.va_size
);
77 puffs_newinfo_setrdev(pni
, dfd
->dfd_node
->pn_va
.va_rdev
);
80 puffs_flush_pagecache_node(pu
, dfd
->dfd_node
);
85 if ((pcn
->pcn_flags
& NAMEI_ISLASTCN
)
86 && (pcn
->pcn_nameiop
== NAMEI_CREATE
||
87 pcn
->pcn_nameiop
== NAMEI_RENAME
)) {
88 rv
= puffs_access(VDIR
, pn_dir
->pn_va
.va_mode
,
89 pn_dir
->pn_va
.va_uid
, pn_dir
->pn_va
.va_gid
,
90 PUFFS_VWRITE
, pcn
->pcn_cred
);
99 dtfs_node_access(struct puffs_usermount
*pu
, void *opc
, int acc_mode
,
100 const struct puffs_cred
*pcr
)
102 struct puffs_node
*pn
= opc
;
104 return puffs_access(pn
->pn_va
.va_type
, pn
->pn_va
.va_mode
,
105 pn
->pn_va
.va_uid
, pn
->pn_va
.va_gid
, acc_mode
, pcr
);
109 dtfs_node_setattr(struct puffs_usermount
*pu
, void *opc
,
110 const struct vattr
*va
, const struct puffs_cred
*pcr
)
112 struct puffs_node
*pn
= opc
;
115 /* check permissions */
116 if (va
->va_flags
!= PUFFS_VNOVAL
)
119 if (va
->va_uid
!= PUFFS_VNOVAL
|| va
->va_gid
!= PUFFS_VNOVAL
) {
120 rv
= puffs_access_chown(pn
->pn_va
.va_uid
, pn
->pn_va
.va_gid
,
121 va
->va_uid
, va
->va_gid
, pcr
);
126 if (va
->va_mode
!= PUFFS_VNOVAL
) {
127 rv
= puffs_access_chmod(pn
->pn_va
.va_uid
, pn
->pn_va
.va_gid
,
128 pn
->pn_va
.va_type
, va
->va_mode
, pcr
);
133 if ((va
->va_atime
.tv_sec
!= PUFFS_VNOVAL
134 && va
->va_atime
.tv_nsec
!= PUFFS_VNOVAL
)
135 || (va
->va_mtime
.tv_sec
!= PUFFS_VNOVAL
136 && va
->va_mtime
.tv_nsec
!= PUFFS_VNOVAL
)) {
137 rv
= puffs_access_times(pn
->pn_va
.va_uid
, pn
->pn_va
.va_gid
,
138 pn
->pn_va
.va_mode
, va
->va_vaflags
& VA_UTIMES_NULL
, pcr
);
143 if (va
->va_size
!= PUFFS_VNOVAL
) {
144 switch (pn
->pn_va
.va_type
) {
146 dtfs_setsize(pn
, va
->va_size
);
147 pn
->pn_va
.va_bytes
= va
->va_size
;
160 puffs_setvattr(&pn
->pn_va
, va
);
165 /* create a new node in the parent directory specified by opc */
167 dtfs_node_create(struct puffs_usermount
*pu
, void *opc
,
168 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
169 const struct vattr
*va
)
171 struct puffs_node
*pn_parent
= opc
;
172 struct puffs_node
*pn_new
;
174 if (!(va
->va_type
== VREG
|| va
->va_type
== VSOCK
))
177 pn_new
= dtfs_genfile(pn_parent
, pcn
, va
->va_type
);
178 puffs_setvattr(&pn_new
->pn_va
, va
);
180 puffs_newinfo_setcookie(pni
, pn_new
);
186 dtfs_node_remove(struct puffs_usermount
*pu
, void *opc
, void *targ
,
187 const struct puffs_cn
*pcn
)
189 struct puffs_node
*pn_parent
= opc
;
190 struct puffs_node
*pn
= targ
;
192 if (pn
->pn_va
.va_type
== VDIR
)
195 dtfs_nukenode(targ
, pn_parent
, pcn
->pcn_name
, pcn
->pcn_namelen
);
197 if (pn
->pn_va
.va_nlink
== 0)
198 puffs_setback(puffs_cc_getcc(pu
), PUFFS_SETBACK_NOREF_N2
);
204 dtfs_node_mkdir(struct puffs_usermount
*pu
, void *opc
,
205 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
206 const struct vattr
*va
)
208 struct puffs_node
*pn_parent
= opc
;
209 struct puffs_node
*pn_new
;
211 pn_new
= dtfs_genfile(pn_parent
, pcn
, VDIR
);
212 puffs_setvattr(&pn_new
->pn_va
, va
);
214 puffs_newinfo_setcookie(pni
, pn_new
);
220 dtfs_node_rmdir(struct puffs_usermount
*pu
, void *opc
, void *targ
,
221 const struct puffs_cn
*pcn
)
223 struct puffs_node
*pn_parent
= opc
;
224 struct dtfs_file
*df
= DTFS_CTOF(targ
);
226 if (!LIST_EMPTY(&df
->df_dirents
))
229 dtfs_nukenode(targ
, pn_parent
, pcn
->pcn_name
, pcn
->pcn_namelen
);
230 puffs_setback(puffs_cc_getcc(pu
), PUFFS_SETBACK_NOREF_N2
);
236 dtfs_node_readdir(struct puffs_usermount
*pu
, void *opc
,
237 struct dirent
*dent
, off_t
*readoff
, size_t *reslen
,
238 const struct puffs_cred
*pcr
,
239 int *eofflag
, off_t
*cookies
, size_t *ncookies
)
241 struct puffs_node
*pn
= opc
;
242 struct puffs_node
*pn_nth
;
243 struct dtfs_dirent
*dfd_nth
;
245 if (pn
->pn_va
.va_type
!= VDIR
)
248 dtfs_updatetimes(pn
, 1, 0, 0);
252 if (*readoff
== DENT_DOT
|| *readoff
== DENT_DOTDOT
) {
253 puffs_gendotdent(&dent
, pn
->pn_va
.va_fileid
, *readoff
, reslen
);
255 PUFFS_STORE_DCOOKIE(cookies
, ncookies
, *readoff
);
260 dfd_nth
= dtfs_dirgetnth(pn
->pn_data
, DENT_ADJ(*readoff
));
265 pn_nth
= dfd_nth
->dfd_node
;
267 if (!puffs_nextdent(&dent
, dfd_nth
->dfd_name
,
268 pn_nth
->pn_va
.va_fileid
,
269 puffs_vtype2dt(pn_nth
->pn_va
.va_type
),
274 PUFFS_STORE_DCOOKIE(cookies
, ncookies
, *readoff
);
281 dtfs_node_poll(struct puffs_usermount
*pu
, void *opc
, int *events
)
283 struct dtfs_mount
*dtm
= puffs_getspecific(pu
);
287 memset(&it
, 0, sizeof(struct itimerval
));
288 it
.it_value
.tv_sec
= 4;
289 if (setitimer(ITIMER_REAL
, &it
, NULL
) == -1)
292 dp
.dp_pcc
= puffs_cc_getcc(pu
);
293 LIST_INSERT_HEAD(&dtm
->dtm_pollent
, &dp
, dp_entries
);
294 puffs_cc_yield(dp
.dp_pcc
);
296 *events
= *events
& (POLLIN
| POLLOUT
| POLLRDNORM
| POLLWRNORM
);
301 dtfs_node_mmap(struct puffs_usermount
*pu
, void *opc
, vm_prot_t prot
,
302 const struct puffs_cred
*pcr
)
304 struct dtfs_mount
*dtm
= puffs_getspecific(pu
);
306 if ((dtm
->dtm_allowprot
& prot
) != prot
)
313 dtfs_node_rename(struct puffs_usermount
*pu
, void *opc
, void *src
,
314 const struct puffs_cn
*pcn_src
, void *targ_dir
, void *targ
,
315 const struct puffs_cn
*pcn_targ
)
317 struct dtfs_dirent
*dfd_src
;
318 struct dtfs_file
*df_targ
;
319 struct puffs_node
*pn_sdir
= opc
;
320 struct puffs_node
*pn_sfile
= src
;
321 struct puffs_node
*pn_tdir
= targ_dir
;
322 struct puffs_node
*pn_tfile
= targ
;
324 /* check that we don't do the old amigados trick */
325 if (pn_sfile
->pn_va
.va_type
== VDIR
) {
326 if (dtfs_isunder(pn_tdir
, pn_sfile
))
329 if ((pcn_src
->pcn_namelen
== 1 && pcn_src
->pcn_name
[0]=='.') ||
331 PCNISDOTDOT(pcn_src
) ||
332 PCNISDOTDOT(pcn_targ
)) {
337 dfd_src
= dtfs_dirgetbyname(DTFS_PTOF(pn_sdir
),
338 pcn_src
->pcn_name
, pcn_src
->pcn_namelen
);
340 /* does it still exist, or did someone race us here? */
341 if (dfd_src
== NULL
) {
345 /* if there's a target file, nuke it for atomic replacement */
347 if (pn_tfile
->pn_va
.va_type
== VDIR
) {
348 df_targ
= DTFS_CTOF(pn_tfile
);
349 if (!LIST_EMPTY(&df_targ
->df_dirents
))
352 dtfs_nukenode(pn_tfile
, pn_tdir
,
353 pcn_targ
->pcn_name
, pcn_targ
->pcn_namelen
);
356 /* out with the old */
357 dtfs_removedent(pn_sdir
, dfd_src
);
358 /* and in with the new */
359 dtfs_adddent(pn_tdir
, dfd_src
);
362 free(dfd_src
->dfd_name
);
363 dfd_src
->dfd_name
= estrndup(pcn_targ
->pcn_name
,pcn_targ
->pcn_namelen
);
364 dfd_src
->dfd_namelen
= strlen(dfd_src
->dfd_name
);
366 dtfs_updatetimes(src
, 0, 1, 0);
372 dtfs_node_link(struct puffs_usermount
*pu
, void *opc
, void *targ
,
373 const struct puffs_cn
*pcn
)
375 struct puffs_node
*pn_dir
= opc
;
376 struct dtfs_dirent
*dfd
;
378 dfd
= emalloc(sizeof(struct dtfs_dirent
));
379 dfd
->dfd_node
= targ
;
380 dfd
->dfd_name
= estrndup(pcn
->pcn_name
, pcn
->pcn_namelen
);
381 dfd
->dfd_namelen
= strlen(dfd
->dfd_name
);
382 dtfs_adddent(pn_dir
, dfd
);
384 dtfs_updatetimes(targ
, 0, 1, 0);
390 dtfs_node_symlink(struct puffs_usermount
*pu
, void *opc
,
391 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn_src
,
392 const struct vattr
*va
, const char *link_target
)
394 struct puffs_node
*pn_parent
= opc
;
395 struct puffs_node
*pn_new
;
396 struct dtfs_file
*df_new
;
398 if (va
->va_type
!= VLNK
)
401 pn_new
= dtfs_genfile(pn_parent
, pcn_src
, VLNK
);
402 puffs_setvattr(&pn_new
->pn_va
, va
);
403 df_new
= DTFS_PTOF(pn_new
);
404 df_new
->df_linktarget
= estrdup(link_target
);
405 pn_new
->pn_va
.va_size
= strlen(df_new
->df_linktarget
);
407 puffs_newinfo_setcookie(pni
, pn_new
);
413 dtfs_node_readlink(struct puffs_usermount
*pu
, void *opc
,
414 const struct puffs_cred
*cred
, char *linkname
, size_t *linklen
)
416 struct dtfs_file
*df
= DTFS_CTOF(opc
);
417 struct puffs_node
*pn
= opc
;
419 assert(pn
->pn_va
.va_type
== VLNK
);
420 strlcpy(linkname
, df
->df_linktarget
, *linklen
);
421 *linklen
= strlen(linkname
);
427 dtfs_node_mknod(struct puffs_usermount
*pu
, void *opc
,
428 struct puffs_newinfo
*pni
, const struct puffs_cn
*pcn
,
429 const struct vattr
*va
)
431 struct puffs_node
*pn_parent
= opc
;
432 struct puffs_node
*pn_new
;
434 if (!(va
->va_type
== VBLK
|| va
->va_type
== VCHR
435 || va
->va_type
== VFIFO
))
438 pn_new
= dtfs_genfile(pn_parent
, pcn
, va
->va_type
);
439 puffs_setvattr(&pn_new
->pn_va
, va
);
441 puffs_newinfo_setcookie(pni
, pn_new
);
446 #define BLOCKOFF(a,b) ((a) & ((b)-1))
447 #define BLOCKLEFT(a,b) ((b) - BLOCKOFF(a,b))
450 * Read operation, used both for VOP_READ and VOP_GETPAGES
453 dtfs_node_read(struct puffs_usermount
*pu
, void *opc
, uint8_t *buf
,
454 off_t offset
, size_t *resid
, const struct puffs_cred
*pcr
, int ioflag
)
456 struct puffs_node
*pn
= opc
;
457 struct dtfs_file
*df
= DTFS_CTOF(opc
);
458 quad_t xfer
, origxfer
;
462 if (pn
->pn_va
.va_type
!= VREG
)
465 xfer
= MIN(*resid
, df
->df_datalen
- offset
);
472 copylen
= MIN(xfer
, BLOCKLEFT(offset
, DTFS_BLOCKSIZE
));
473 src
= df
->df_blocks
[BLOCKNUM(offset
, DTFS_BLOCKSHIFT
)]
474 + BLOCKOFF(offset
, DTFS_BLOCKSIZE
);
475 memcpy(dest
, src
, copylen
);
482 dtfs_updatetimes(pn
, 1, 0, 0);
488 * write operation on the wing
491 dtfs_node_write(struct puffs_usermount
*pu
, void *opc
, uint8_t *buf
,
492 off_t offset
, size_t *resid
, const struct puffs_cred
*pcr
, int ioflag
)
494 struct puffs_node
*pn
= opc
;
495 struct dtfs_file
*df
= DTFS_CTOF(opc
);
499 if (pn
->pn_va
.va_type
!= VREG
)
502 if (ioflag
& PUFFS_IO_APPEND
)
503 offset
= pn
->pn_va
.va_size
;
505 if (*resid
+ offset
> pn
->pn_va
.va_size
)
506 dtfs_setsize(pn
, *resid
+ offset
);
511 copylen
= MIN(*resid
, BLOCKLEFT(offset
, DTFS_BLOCKSIZE
));
512 i
= BLOCKNUM(offset
, DTFS_BLOCKSHIFT
);
513 dest
= df
->df_blocks
[i
]
514 + BLOCKOFF(offset
, DTFS_BLOCKSIZE
);
515 memcpy(dest
, src
, copylen
);
521 dtfs_updatetimes(pn
, 0, 1, 1);
527 dtfs_node_pathconf(struct puffs_usermount
*pu
, puffs_cookie_t opc
,
528 int name
, register_t
*retval
)
544 case _PC_CHOWN_RESTRICTED
:
553 case _PC_FILESIZEBITS
:
554 *retval
= 43; /* this one goes to 11 */
556 case _PC_SYMLINK_MAX
:
557 *retval
= MAXPATHLEN
;
568 dtfs_node_inactive(struct puffs_usermount
*pu
, puffs_cookie_t opc
)
570 struct puffs_node
*pn
= opc
;
572 if (pn
->pn_va
.va_nlink
== 0)
573 puffs_setback(puffs_cc_getcc(pu
), PUFFS_SETBACK_NOREF_N1
);
578 dtfs_node_reclaim(struct puffs_usermount
*pu
, void *opc
)
580 struct puffs_node
*pn
= opc
;
582 if (pn
->pn_va
.va_nlink
== 0)