1272343Sngie/* $NetBSD: dtfs_subr.c,v 1.4 2013/10/19 17:45:00 christos Exp $ */ 2272343Sngie 3272343Sngie/* 4272343Sngie * Copyright (c) 2006 Antti Kantee. All Rights Reserved. 5272343Sngie * 6272343Sngie * Redistribution and use in source and binary forms, with or without 7272343Sngie * modification, are permitted provided that the following conditions 8272343Sngie * are met: 9272343Sngie * 1. Redistributions of source code must retain the above copyright 10272343Sngie * notice, this list of conditions and the following disclaimer. 11272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 12272343Sngie * notice, this list of conditions and the following disclaimer in the 13272343Sngie * documentation and/or other materials provided with the distribution. 14272343Sngie * 15272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16272343Sngie * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17272343Sngie * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18272343Sngie * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21272343Sngie * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25272343Sngie * SUCH DAMAGE. 26272343Sngie */ 27272343Sngie 28272343Sngie#include <sys/types.h> 29272343Sngie#include <sys/time.h> 30272343Sngie 31272343Sngie#include <assert.h> 32272343Sngie#include <err.h> 33272343Sngie#include <errno.h> 34272343Sngie#include <puffs.h> 35272343Sngie#include <stdlib.h> 36272343Sngie#include <string.h> 37272343Sngie#include <unistd.h> 38272343Sngie#include <util.h> 39272343Sngie 40272343Sngie#include "dtfs.h" 41272343Sngie 42272343Sngievoid 43272343Sngiedtfs_baseattrs(struct vattr *vap, enum vtype type, ino_t id) 44272343Sngie{ 45272343Sngie struct timeval tv; 46272343Sngie struct timespec ts; 47272343Sngie 48272343Sngie gettimeofday(&tv, NULL); 49272343Sngie TIMEVAL_TO_TIMESPEC(&tv, &ts); 50272343Sngie 51272343Sngie vap->va_type = type; 52272343Sngie if (type == VDIR) { 53272343Sngie vap->va_mode = 0777; 54272343Sngie vap->va_nlink = 1; /* n + 1 after adding dent */ 55272343Sngie } else { 56272343Sngie vap->va_mode = 0666; 57272343Sngie vap->va_nlink = 0; /* n + 1 */ 58272343Sngie } 59272343Sngie vap->va_uid = 0; 60272343Sngie vap->va_gid = 0; 61272343Sngie vap->va_fileid = id; 62272343Sngie vap->va_size = 0; 63272343Sngie vap->va_blocksize = getpagesize(); 64272343Sngie vap->va_gen = random(); 65272343Sngie vap->va_flags = 0; 66272343Sngie vap->va_rdev = PUFFS_VNOVAL; 67272343Sngie vap->va_bytes = 0; 68272343Sngie vap->va_filerev = 1; 69272343Sngie vap->va_vaflags = 0; 70272343Sngie 71272343Sngie vap->va_atime = vap->va_mtime = vap->va_ctime = vap->va_birthtime = ts; 72272343Sngie} 73272343Sngie 74272343Sngie/* 75272343Sngie * Well, as you can probably see, this interface has the slight problem 76272343Sngie * of assuming file creation will always be succesful, or at least not 77272343Sngie * giving a reason for the failure. Be sure to do better when you 78272343Sngie * implement your own fs. 79272343Sngie */ 80272343Sngiestruct puffs_node * 81272343Sngiedtfs_genfile(struct puffs_node *dir, const struct puffs_cn *pcn, 82272343Sngie enum vtype type) 83272343Sngie{ 84272343Sngie struct dtfs_file *dff; 85272343Sngie struct dtfs_dirent *dfd; 86272343Sngie struct dtfs_mount *dtm; 87272343Sngie struct puffs_node *newpn; 88272343Sngie uid_t uid; 89272343Sngie int rv; 90272343Sngie 91272343Sngie assert(dir->pn_va.va_type == VDIR); 92272343Sngie assert(dir->pn_mnt != NULL); 93272343Sngie 94272343Sngie uid = 0; 95272343Sngie rv = puffs_cred_getuid(pcn->pcn_cred, &uid); 96272343Sngie assert(rv == 0); 97272343Sngie 98272343Sngie if (type == VDIR) { 99272343Sngie dff = dtfs_newdir(); 100272343Sngie dff->df_dotdot = dir; 101272343Sngie } else 102272343Sngie dff = dtfs_newfile(); 103272343Sngie 104272343Sngie dtm = puffs_pn_getmntspecific(dir); 105272343Sngie newpn = puffs_pn_new(dir->pn_mnt, dff); 106272343Sngie if (newpn == NULL) 107272343Sngie errx(1, "getnewpnode"); 108272343Sngie dtfs_baseattrs(&newpn->pn_va, type, dtm->dtm_nextfileid++); 109272343Sngie 110272343Sngie dfd = emalloc(sizeof(struct dtfs_dirent)); 111272343Sngie dfd->dfd_node = newpn; 112272343Sngie dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen); 113272343Sngie dfd->dfd_namelen = strlen(dfd->dfd_name); 114272343Sngie dfd->dfd_parent = dir; 115272343Sngie dtfs_adddent(dir, dfd); 116272343Sngie 117272343Sngie newpn->pn_va.va_uid = uid; 118272343Sngie newpn->pn_va.va_gid = dir->pn_va.va_gid; 119272343Sngie 120272343Sngie return newpn; 121272343Sngie} 122272343Sngie 123272343Sngiestruct dtfs_file * 124272343Sngiedtfs_newdir() 125272343Sngie{ 126272343Sngie struct dtfs_file *dff; 127272343Sngie 128272343Sngie dff = emalloc(sizeof(struct dtfs_file)); 129272343Sngie memset(dff, 0, sizeof(struct dtfs_file)); 130272343Sngie LIST_INIT(&dff->df_dirents); 131272343Sngie 132272343Sngie return dff; 133272343Sngie} 134272343Sngie 135272343Sngiestruct dtfs_file * 136272343Sngiedtfs_newfile() 137272343Sngie{ 138272343Sngie struct dtfs_file *dff; 139272343Sngie 140272343Sngie dff = emalloc(sizeof(struct dtfs_file)); 141272343Sngie memset(dff, 0, sizeof(struct dtfs_file)); 142272343Sngie 143272343Sngie return dff; 144272343Sngie} 145272343Sngie 146272343Sngiestruct dtfs_dirent * 147272343Sngiedtfs_dirgetnth(struct dtfs_file *searchdir, int n) 148272343Sngie{ 149272343Sngie struct dtfs_dirent *dirent; 150272343Sngie int i; 151272343Sngie 152272343Sngie i = 0; 153272343Sngie LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) { 154272343Sngie if (i == n) 155272343Sngie return dirent; 156272343Sngie i++; 157272343Sngie } 158272343Sngie 159272343Sngie return NULL; 160272343Sngie} 161272343Sngie 162272343Sngiestruct dtfs_dirent * 163272343Sngiedtfs_dirgetbyname(struct dtfs_file *searchdir, const char *fname, size_t fnlen) 164272343Sngie{ 165272343Sngie struct dtfs_dirent *dirent; 166272343Sngie 167272343Sngie LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) 168272343Sngie if (dirent->dfd_namelen == fnlen 169272343Sngie && strncmp(dirent->dfd_name, fname, fnlen) == 0) 170272343Sngie return dirent; 171272343Sngie 172272343Sngie return NULL; 173272343Sngie} 174272343Sngie 175272343Sngie/* 176272343Sngie * common nuke, kill dirent from parent node 177272343Sngie */ 178272343Sngievoid 179272343Sngiedtfs_nukenode(struct puffs_node *nukeme, struct puffs_node *pn_parent, 180272343Sngie const char *fname, size_t fnlen) 181272343Sngie{ 182272343Sngie struct dtfs_dirent *dfd; 183272343Sngie struct dtfs_mount *dtm; 184272343Sngie 185272343Sngie assert(pn_parent->pn_va.va_type == VDIR); 186272343Sngie 187272343Sngie dfd = dtfs_dirgetbyname(DTFS_PTOF(pn_parent), fname, fnlen); 188272343Sngie assert(dfd); 189272343Sngie 190272343Sngie dtm = puffs_pn_getmntspecific(nukeme); 191272343Sngie dtm->dtm_nfiles--; 192272343Sngie assert(dtm->dtm_nfiles >= 1); 193272343Sngie 194272343Sngie dtfs_removedent(pn_parent, dfd); 195272343Sngie free(dfd); 196272343Sngie} 197272343Sngie 198272343Sngie/* free lingering information */ 199272343Sngievoid 200272343Sngiedtfs_freenode(struct puffs_node *pn) 201272343Sngie{ 202272343Sngie struct dtfs_file *df = DTFS_PTOF(pn); 203272343Sngie struct dtfs_mount *dtm; 204272343Sngie int i; 205272343Sngie 206272343Sngie assert(pn->pn_va.va_nlink == 0); 207272343Sngie dtm = puffs_pn_getmntspecific(pn); 208272343Sngie 209272343Sngie switch (pn->pn_va.va_type) { 210272343Sngie case VREG: 211272343Sngie assert(dtm->dtm_fsizes >= pn->pn_va.va_size); 212272343Sngie dtm->dtm_fsizes -= pn->pn_va.va_size; 213272343Sngie for (i = 0; i < BLOCKNUM(df->df_datalen, DTFS_BLOCKSHIFT); i++) 214272343Sngie free(df->df_blocks[i]); 215272343Sngie if (df->df_datalen > i << DTFS_BLOCKSHIFT) 216272343Sngie free(df->df_blocks[i]); 217272343Sngie break; 218272343Sngie case VLNK: 219272343Sngie free(df->df_linktarget); 220272343Sngie break; 221272343Sngie case VCHR: 222272343Sngie case VBLK: 223272343Sngie case VDIR: 224272343Sngie case VSOCK: 225272343Sngie case VFIFO: 226272343Sngie break; 227272343Sngie default: 228272343Sngie assert(0); 229272343Sngie break; 230272343Sngie } 231272343Sngie 232272343Sngie free(df); 233272343Sngie puffs_pn_put(pn); 234272343Sngie} 235272343Sngie 236272343Sngievoid 237272343Sngiedtfs_setsize(struct puffs_node *pn, off_t newsize) 238272343Sngie{ 239272343Sngie struct dtfs_file *df = DTFS_PTOF(pn); 240272343Sngie struct dtfs_mount *dtm; 241272343Sngie size_t newblocks; 242272343Sngie int needalloc, shrinks; 243272343Sngie int i; 244272343Sngie 245272343Sngie needalloc = newsize > ROUNDUP(df->df_datalen, DTFS_BLOCKSIZE); 246272343Sngie shrinks = newsize < pn->pn_va.va_size; 247272343Sngie 248272343Sngie if (needalloc || shrinks) { 249272343Sngie newblocks = BLOCKNUM(newsize, DTFS_BLOCKSHIFT) + 1; 250272343Sngie 251272343Sngie if (shrinks) 252272343Sngie for (i = newblocks; i < df->df_numblocks; i++) 253272343Sngie free(df->df_blocks[i]); 254272343Sngie 255272343Sngie df->df_blocks = erealloc(df->df_blocks, 256272343Sngie newblocks * sizeof(uint8_t *)); 257272343Sngie /* 258272343Sngie * if extended, set storage to zero 259272343Sngie * to match correct behaviour 260272343Sngie */ 261272343Sngie if (!shrinks) { 262272343Sngie for (i = df->df_numblocks; i < newblocks; i++) { 263272343Sngie df->df_blocks[i] = emalloc(DTFS_BLOCKSIZE); 264272343Sngie memset(df->df_blocks[i], 0, DTFS_BLOCKSIZE); 265272343Sngie } 266272343Sngie } 267272343Sngie 268272343Sngie df->df_datalen = newsize; 269272343Sngie df->df_numblocks = newblocks; 270272343Sngie } 271272343Sngie 272272343Sngie dtm = puffs_pn_getmntspecific(pn); 273272343Sngie if (!shrinks) { 274272343Sngie dtm->dtm_fsizes += newsize - pn->pn_va.va_size; 275272343Sngie } else { 276272343Sngie dtm->dtm_fsizes -= pn->pn_va.va_size - newsize; 277272343Sngie } 278272343Sngie 279272343Sngie pn->pn_va.va_size = newsize; 280272343Sngie pn->pn_va.va_bytes = BLOCKNUM(newsize,DTFS_BLOCKSHIFT)>>DTFS_BLOCKSHIFT; 281272343Sngie} 282272343Sngie 283272343Sngie/* add & bump link count */ 284272343Sngievoid 285272343Sngiedtfs_adddent(struct puffs_node *pn_dir, struct dtfs_dirent *dent) 286272343Sngie{ 287272343Sngie struct dtfs_file *dir = DTFS_PTOF(pn_dir); 288272343Sngie struct puffs_node *pn_file = dent->dfd_node; 289272343Sngie struct dtfs_file *file = DTFS_PTOF(pn_file); 290272343Sngie struct dtfs_mount *dtm; 291272343Sngie 292272343Sngie assert(pn_dir->pn_va.va_type == VDIR); 293272343Sngie LIST_INSERT_HEAD(&dir->df_dirents, dent, dfd_entries); 294272343Sngie pn_file->pn_va.va_nlink++; 295272343Sngie 296272343Sngie dtm = puffs_pn_getmntspecific(pn_file); 297272343Sngie dtm->dtm_nfiles++; 298272343Sngie 299272343Sngie dent->dfd_parent = pn_dir; 300272343Sngie if (dent->dfd_node->pn_va.va_type == VDIR) { 301272343Sngie file->df_dotdot = pn_dir; 302272343Sngie pn_dir->pn_va.va_nlink++; 303272343Sngie } 304272343Sngie 305272343Sngie dtfs_updatetimes(pn_dir, 0, 1, 1); 306272343Sngie} 307272343Sngie 308272343Sngie/* remove & lower link count */ 309272343Sngievoid 310272343Sngiedtfs_removedent(struct puffs_node *pn_dir, struct dtfs_dirent *dent) 311272343Sngie{ 312272343Sngie struct puffs_node *pn_file = dent->dfd_node; 313272343Sngie 314272343Sngie assert(pn_dir->pn_va.va_type == VDIR); 315272343Sngie LIST_REMOVE(dent, dfd_entries); 316272343Sngie if (pn_file->pn_va.va_type == VDIR) { 317272343Sngie struct dtfs_file *df = DTFS_PTOF(pn_file); 318272343Sngie 319272343Sngie pn_dir->pn_va.va_nlink--; 320272343Sngie df->df_dotdot = NULL; 321272343Sngie } 322272343Sngie pn_file->pn_va.va_nlink--; 323272343Sngie assert(pn_dir->pn_va.va_nlink >= 2); 324272343Sngie 325272343Sngie dtfs_updatetimes(pn_dir, 0, 1, 1); 326272343Sngie} 327272343Sngie 328272343Sngievoid 329272343Sngiedtfs_updatetimes(struct puffs_node *pn, int doatime, int doctime, int domtime) 330272343Sngie{ 331272343Sngie struct timeval tv; 332272343Sngie struct timespec ts; 333272343Sngie 334272343Sngie gettimeofday(&tv, NULL); 335272343Sngie TIMEVAL_TO_TIMESPEC(&tv, &ts); 336272343Sngie 337272343Sngie if (doatime) 338272343Sngie pn->pn_va.va_atime = ts; 339272343Sngie if (doctime) 340272343Sngie pn->pn_va.va_ctime = ts; 341272343Sngie if (domtime) 342272343Sngie pn->pn_va.va_mtime = ts; 343272343Sngie} 344272343Sngie 345272343Sngiebool 346272343Sngiedtfs_isunder(struct puffs_node *pn, struct puffs_node *pn_parent) 347272343Sngie{ 348272343Sngie struct dtfs_file *df; 349272343Sngie 350272343Sngie while (pn) { 351272343Sngie if (pn == pn_parent) 352272343Sngie return true; 353272343Sngie df = DTFS_CTOF(pn); 354272343Sngie pn = df->df_dotdot; 355272343Sngie } 356272343Sngie 357272343Sngie return false; 358272343Sngie} 359