]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / netbsd-tests / fs / puffs / h_dtfs / dtfs_subr.c
1 /*      $NetBSD: dtfs_subr.c,v 1.4 2013/10/19 17:45:00 christos Exp $   */
2
3 /*
4  * Copyright (c) 2006  Antti Kantee.  All Rights Reserved.
5  *
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.
14  *
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.
26  */
27
28 #include <sys/types.h>
29 #include <sys/time.h>
30
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>
39
40 #include "dtfs.h"
41
42 void
43 dtfs_baseattrs(struct vattr *vap, enum vtype type, ino_t id)
44 {
45         struct timeval tv;
46         struct timespec ts;
47
48         gettimeofday(&tv, NULL);
49         TIMEVAL_TO_TIMESPEC(&tv, &ts);
50
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 */
58         }
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;
70
71         vap->va_atime = vap->va_mtime = vap->va_ctime = vap->va_birthtime = ts;
72 }
73
74 /*
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.
79  */
80 struct puffs_node *
81 dtfs_genfile(struct puffs_node *dir, const struct puffs_cn *pcn,
82         enum vtype type)
83 {
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;
90
91         assert(dir->pn_va.va_type == VDIR);
92         assert(dir->pn_mnt != NULL);
93
94         uid = 0;
95         rv = puffs_cred_getuid(pcn->pcn_cred, &uid);
96         assert(rv == 0);
97
98         if (type == VDIR) {
99                 dff = dtfs_newdir();
100                 dff->df_dotdot = dir;
101         } else
102                 dff = dtfs_newfile();
103
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++);
109
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);
116
117         newpn->pn_va.va_uid = uid;
118         newpn->pn_va.va_gid = dir->pn_va.va_gid;
119
120         return newpn;
121 }
122
123 struct dtfs_file *
124 dtfs_newdir()
125 {
126         struct dtfs_file *dff;
127
128         dff = emalloc(sizeof(struct dtfs_file));
129         memset(dff, 0, sizeof(struct dtfs_file));
130         LIST_INIT(&dff->df_dirents);
131
132         return dff;
133 }
134
135 struct dtfs_file *
136 dtfs_newfile()
137 {
138         struct dtfs_file *dff;
139
140         dff = emalloc(sizeof(struct dtfs_file));
141         memset(dff, 0, sizeof(struct dtfs_file));
142
143         return dff;
144 }
145
146 struct dtfs_dirent *
147 dtfs_dirgetnth(struct dtfs_file *searchdir, int n)
148 {
149         struct dtfs_dirent *dirent;
150         int i;
151
152         i = 0;
153         LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) {
154                 if (i == n)
155                         return dirent;
156                 i++;
157         }
158
159         return NULL;
160 }
161
162 struct dtfs_dirent *
163 dtfs_dirgetbyname(struct dtfs_file *searchdir, const char *fname, size_t fnlen)
164 {
165         struct dtfs_dirent *dirent;
166
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;
171
172         return NULL;
173 }
174
175 /*
176  * common nuke, kill dirent from parent node
177  */
178 void
179 dtfs_nukenode(struct puffs_node *nukeme, struct puffs_node *pn_parent,
180         const char *fname, size_t fnlen)
181 {
182         struct dtfs_dirent *dfd;
183         struct dtfs_mount *dtm;
184
185         assert(pn_parent->pn_va.va_type == VDIR);
186
187         dfd = dtfs_dirgetbyname(DTFS_PTOF(pn_parent), fname, fnlen);
188         assert(dfd);
189
190         dtm = puffs_pn_getmntspecific(nukeme);
191         dtm->dtm_nfiles--;
192         assert(dtm->dtm_nfiles >= 1);
193
194         dtfs_removedent(pn_parent, dfd);
195         free(dfd);
196 }
197
198 /* free lingering information */
199 void
200 dtfs_freenode(struct puffs_node *pn)
201 {
202         struct dtfs_file *df = DTFS_PTOF(pn);
203         struct dtfs_mount *dtm;
204         int i;
205
206         assert(pn->pn_va.va_nlink == 0);
207         dtm = puffs_pn_getmntspecific(pn);
208
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;
230         }
231
232         free(df);
233         puffs_pn_put(pn);
234 }
235
236 void
237 dtfs_setsize(struct puffs_node *pn, off_t newsize)
238 {
239         struct dtfs_file *df = DTFS_PTOF(pn);
240         struct dtfs_mount *dtm;
241         size_t newblocks;
242         int needalloc, shrinks;
243         int i;
244
245         needalloc = newsize > ROUNDUP(df->df_datalen, DTFS_BLOCKSIZE);
246         shrinks = newsize < pn->pn_va.va_size;
247
248         if (needalloc || shrinks) {
249                 newblocks = BLOCKNUM(newsize, DTFS_BLOCKSHIFT) + 1;
250
251                 if (shrinks)
252                         for (i = newblocks; i < df->df_numblocks; i++)
253                                 free(df->df_blocks[i]);
254
255                 df->df_blocks = erealloc(df->df_blocks,
256                     newblocks * sizeof(uint8_t *));
257                 /*
258                  * if extended, set storage to zero
259                  * to match correct behaviour
260                  */ 
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);
265                         }
266                 }
267
268                 df->df_datalen = newsize;
269                 df->df_numblocks = newblocks;
270         }
271
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;
277         }
278
279         pn->pn_va.va_size = newsize;
280         pn->pn_va.va_bytes = BLOCKNUM(newsize,DTFS_BLOCKSHIFT)>>DTFS_BLOCKSHIFT;
281 }
282
283 /* add & bump link count */
284 void
285 dtfs_adddent(struct puffs_node *pn_dir, struct dtfs_dirent *dent)
286 {
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;
291
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++;
295
296         dtm = puffs_pn_getmntspecific(pn_file);
297         dtm->dtm_nfiles++;
298
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++;
303         }
304
305         dtfs_updatetimes(pn_dir, 0, 1, 1);
306 }
307
308 /* remove & lower link count */
309 void
310 dtfs_removedent(struct puffs_node *pn_dir, struct dtfs_dirent *dent)
311 {
312         struct puffs_node *pn_file = dent->dfd_node;
313
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);
318
319                 pn_dir->pn_va.va_nlink--;
320                 df->df_dotdot = NULL;
321         }
322         pn_file->pn_va.va_nlink--;
323         assert(pn_dir->pn_va.va_nlink >= 2);
324
325         dtfs_updatetimes(pn_dir, 0, 1, 1);
326 }
327
328 void
329 dtfs_updatetimes(struct puffs_node *pn, int doatime, int doctime, int domtime)
330 {
331         struct timeval tv;
332         struct timespec ts;
333
334         gettimeofday(&tv, NULL);
335         TIMEVAL_TO_TIMESPEC(&tv, &ts);
336
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;
343 }
344
345 bool
346 dtfs_isunder(struct puffs_node *pn, struct puffs_node *pn_parent)
347 {
348         struct dtfs_file *df;
349
350         while (pn) {
351                 if (pn == pn_parent)
352                         return true;
353                 df = DTFS_CTOF(pn);
354                 pn = df->df_dotdot;
355         }
356
357         return false;
358 }