Home | History | Annotate | Line # | Download | only in h_dtfs
      1 /*	$NetBSD: dtfs_subr.c,v 1.5 2021/09/16 22:19:12 andvar 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 successful, 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 }
    359