etc/services - sync with NetBSD-8
[minix.git] / tests / fs / puffs / h_dtfs / dtfs_subr.c
blobfcb817680b912ed6dee1548429d1873ab6eb51dd
1 /* $NetBSD: dtfs_subr.c,v 1.4 2013/10/19 17:45:00 christos Exp $ */
3 /*
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
8 * are met:
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
25 * SUCH DAMAGE.
28 #include <sys/types.h>
29 #include <sys/time.h>
31 #include <assert.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <puffs.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <util.h>
40 #include "dtfs.h"
42 void
43 dtfs_baseattrs(struct vattr *vap, enum vtype type, ino_t id)
45 struct timeval tv;
46 struct timespec ts;
48 gettimeofday(&tv, NULL);
49 TIMEVAL_TO_TIMESPEC(&tv, &ts);
51 vap->va_type = type;
52 if (type == VDIR) {
53 vap->va_mode = 0777;
54 vap->va_nlink = 1; /* n + 1 after adding dent */
55 } else {
56 vap->va_mode = 0666;
57 vap->va_nlink = 0; /* n + 1 */
59 vap->va_uid = 0;
60 vap->va_gid = 0;
61 vap->va_fileid = id;
62 vap->va_size = 0;
63 vap->va_blocksize = getpagesize();
64 vap->va_gen = random();
65 vap->va_flags = 0;
66 vap->va_rdev = PUFFS_VNOVAL;
67 vap->va_bytes = 0;
68 vap->va_filerev = 1;
69 vap->va_vaflags = 0;
71 vap->va_atime = vap->va_mtime = vap->va_ctime = vap->va_birthtime = ts;
75 * Well, as you can probably see, this interface has the slight problem
76 * of assuming file creation will always be succesful, or at least not
77 * giving a reason for the failure. Be sure to do better when you
78 * implement your own fs.
80 struct puffs_node *
81 dtfs_genfile(struct puffs_node *dir, const struct puffs_cn *pcn,
82 enum vtype type)
84 struct dtfs_file *dff;
85 struct dtfs_dirent *dfd;
86 struct dtfs_mount *dtm;
87 struct puffs_node *newpn;
88 uid_t uid;
89 int rv;
91 assert(dir->pn_va.va_type == VDIR);
92 assert(dir->pn_mnt != NULL);
94 uid = 0;
95 rv = puffs_cred_getuid(pcn->pcn_cred, &uid);
96 assert(rv == 0);
98 if (type == VDIR) {
99 dff = dtfs_newdir();
100 dff->df_dotdot = dir;
101 } else
102 dff = dtfs_newfile();
104 dtm = puffs_pn_getmntspecific(dir);
105 newpn = puffs_pn_new(dir->pn_mnt, dff);
106 if (newpn == NULL)
107 errx(1, "getnewpnode");
108 dtfs_baseattrs(&newpn->pn_va, type, dtm->dtm_nextfileid++);
110 dfd = emalloc(sizeof(struct dtfs_dirent));
111 dfd->dfd_node = newpn;
112 dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen);
113 dfd->dfd_namelen = strlen(dfd->dfd_name);
114 dfd->dfd_parent = dir;
115 dtfs_adddent(dir, dfd);
117 newpn->pn_va.va_uid = uid;
118 newpn->pn_va.va_gid = dir->pn_va.va_gid;
120 return newpn;
123 struct dtfs_file *
124 dtfs_newdir()
126 struct dtfs_file *dff;
128 dff = emalloc(sizeof(struct dtfs_file));
129 memset(dff, 0, sizeof(struct dtfs_file));
130 LIST_INIT(&dff->df_dirents);
132 return dff;
135 struct dtfs_file *
136 dtfs_newfile()
138 struct dtfs_file *dff;
140 dff = emalloc(sizeof(struct dtfs_file));
141 memset(dff, 0, sizeof(struct dtfs_file));
143 return dff;
146 struct dtfs_dirent *
147 dtfs_dirgetnth(struct dtfs_file *searchdir, int n)
149 struct dtfs_dirent *dirent;
150 int i;
152 i = 0;
153 LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) {
154 if (i == n)
155 return dirent;
156 i++;
159 return NULL;
162 struct dtfs_dirent *
163 dtfs_dirgetbyname(struct dtfs_file *searchdir, const char *fname, size_t fnlen)
165 struct dtfs_dirent *dirent;
167 LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries)
168 if (dirent->dfd_namelen == fnlen
169 && strncmp(dirent->dfd_name, fname, fnlen) == 0)
170 return dirent;
172 return NULL;
176 * common nuke, kill dirent from parent node
178 void
179 dtfs_nukenode(struct puffs_node *nukeme, struct puffs_node *pn_parent,
180 const char *fname, size_t fnlen)
182 struct dtfs_dirent *dfd;
183 struct dtfs_mount *dtm;
185 assert(pn_parent->pn_va.va_type == VDIR);
187 dfd = dtfs_dirgetbyname(DTFS_PTOF(pn_parent), fname, fnlen);
188 assert(dfd);
190 dtm = puffs_pn_getmntspecific(nukeme);
191 dtm->dtm_nfiles--;
192 assert(dtm->dtm_nfiles >= 1);
194 dtfs_removedent(pn_parent, dfd);
195 free(dfd);
198 /* free lingering information */
199 void
200 dtfs_freenode(struct puffs_node *pn)
202 struct dtfs_file *df = DTFS_PTOF(pn);
203 struct dtfs_mount *dtm;
204 int i;
206 assert(pn->pn_va.va_nlink == 0);
207 dtm = puffs_pn_getmntspecific(pn);
209 switch (pn->pn_va.va_type) {
210 case VREG:
211 assert(dtm->dtm_fsizes >= pn->pn_va.va_size);
212 dtm->dtm_fsizes -= pn->pn_va.va_size;
213 for (i = 0; i < BLOCKNUM(df->df_datalen, DTFS_BLOCKSHIFT); i++)
214 free(df->df_blocks[i]);
215 if (df->df_datalen > i << DTFS_BLOCKSHIFT)
216 free(df->df_blocks[i]);
217 break;
218 case VLNK:
219 free(df->df_linktarget);
220 break;
221 case VCHR:
222 case VBLK:
223 case VDIR:
224 case VSOCK:
225 case VFIFO:
226 break;
227 default:
228 assert(0);
229 break;
232 free(df);
233 puffs_pn_put(pn);
236 void
237 dtfs_setsize(struct puffs_node *pn, off_t newsize)
239 struct dtfs_file *df = DTFS_PTOF(pn);
240 struct dtfs_mount *dtm;
241 size_t newblocks;
242 int needalloc, shrinks;
243 int i;
245 needalloc = newsize > ROUNDUP(df->df_datalen, DTFS_BLOCKSIZE);
246 shrinks = newsize < pn->pn_va.va_size;
248 if (needalloc || shrinks) {
249 newblocks = BLOCKNUM(newsize, DTFS_BLOCKSHIFT) + 1;
251 if (shrinks)
252 for (i = newblocks; i < df->df_numblocks; i++)
253 free(df->df_blocks[i]);
255 df->df_blocks = erealloc(df->df_blocks,
256 newblocks * sizeof(uint8_t *));
258 * if extended, set storage to zero
259 * to match correct behaviour
261 if (!shrinks) {
262 for (i = df->df_numblocks; i < newblocks; i++) {
263 df->df_blocks[i] = emalloc(DTFS_BLOCKSIZE);
264 memset(df->df_blocks[i], 0, DTFS_BLOCKSIZE);
268 df->df_datalen = newsize;
269 df->df_numblocks = newblocks;
272 dtm = puffs_pn_getmntspecific(pn);
273 if (!shrinks) {
274 dtm->dtm_fsizes += newsize - pn->pn_va.va_size;
275 } else {
276 dtm->dtm_fsizes -= pn->pn_va.va_size - newsize;
279 pn->pn_va.va_size = newsize;
280 pn->pn_va.va_bytes = BLOCKNUM(newsize,DTFS_BLOCKSHIFT)>>DTFS_BLOCKSHIFT;
283 /* add & bump link count */
284 void
285 dtfs_adddent(struct puffs_node *pn_dir, struct dtfs_dirent *dent)
287 struct dtfs_file *dir = DTFS_PTOF(pn_dir);
288 struct puffs_node *pn_file = dent->dfd_node;
289 struct dtfs_file *file = DTFS_PTOF(pn_file);
290 struct dtfs_mount *dtm;
292 assert(pn_dir->pn_va.va_type == VDIR);
293 LIST_INSERT_HEAD(&dir->df_dirents, dent, dfd_entries);
294 pn_file->pn_va.va_nlink++;
296 dtm = puffs_pn_getmntspecific(pn_file);
297 dtm->dtm_nfiles++;
299 dent->dfd_parent = pn_dir;
300 if (dent->dfd_node->pn_va.va_type == VDIR) {
301 file->df_dotdot = pn_dir;
302 pn_dir->pn_va.va_nlink++;
305 dtfs_updatetimes(pn_dir, 0, 1, 1);
308 /* remove & lower link count */
309 void
310 dtfs_removedent(struct puffs_node *pn_dir, struct dtfs_dirent *dent)
312 struct puffs_node *pn_file = dent->dfd_node;
314 assert(pn_dir->pn_va.va_type == VDIR);
315 LIST_REMOVE(dent, dfd_entries);
316 if (pn_file->pn_va.va_type == VDIR) {
317 struct dtfs_file *df = DTFS_PTOF(pn_file);
319 pn_dir->pn_va.va_nlink--;
320 df->df_dotdot = NULL;
322 pn_file->pn_va.va_nlink--;
323 assert(pn_dir->pn_va.va_nlink >= 2);
325 dtfs_updatetimes(pn_dir, 0, 1, 1);
328 void
329 dtfs_updatetimes(struct puffs_node *pn, int doatime, int doctime, int domtime)
331 struct timeval tv;
332 struct timespec ts;
334 gettimeofday(&tv, NULL);
335 TIMEVAL_TO_TIMESPEC(&tv, &ts);
337 if (doatime)
338 pn->pn_va.va_atime = ts;
339 if (doctime)
340 pn->pn_va.va_ctime = ts;
341 if (domtime)
342 pn->pn_va.va_mtime = ts;
345 bool
346 dtfs_isunder(struct puffs_node *pn, struct puffs_node *pn_parent)
348 struct dtfs_file *df;
350 while (pn) {
351 if (pn == pn_parent)
352 return true;
353 df = DTFS_CTOF(pn);
354 pn = df->df_dotdot;
357 return false;