1 1.5 andvar /* $NetBSD: dtfs_subr.c,v 1.5 2021/09/16 22:19:12 andvar Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.1 pooka * Copyright (c) 2006 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Redistribution and use in source and binary forms, with or without 7 1.1 pooka * modification, are permitted provided that the following conditions 8 1.1 pooka * are met: 9 1.1 pooka * 1. Redistributions of source code must retain the above copyright 10 1.1 pooka * notice, this list of conditions and the following disclaimer. 11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 pooka * notice, this list of conditions and the following disclaimer in the 13 1.1 pooka * documentation and/or other materials provided with the distribution. 14 1.1 pooka * 15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 pooka * SUCH DAMAGE. 26 1.1 pooka */ 27 1.1 pooka 28 1.1 pooka #include <sys/types.h> 29 1.1 pooka #include <sys/time.h> 30 1.1 pooka 31 1.1 pooka #include <assert.h> 32 1.1 pooka #include <err.h> 33 1.1 pooka #include <errno.h> 34 1.1 pooka #include <puffs.h> 35 1.1 pooka #include <stdlib.h> 36 1.1 pooka #include <string.h> 37 1.1 pooka #include <unistd.h> 38 1.1 pooka #include <util.h> 39 1.1 pooka 40 1.1 pooka #include "dtfs.h" 41 1.1 pooka 42 1.1 pooka void 43 1.1 pooka dtfs_baseattrs(struct vattr *vap, enum vtype type, ino_t id) 44 1.1 pooka { 45 1.1 pooka struct timeval tv; 46 1.1 pooka struct timespec ts; 47 1.1 pooka 48 1.1 pooka gettimeofday(&tv, NULL); 49 1.1 pooka TIMEVAL_TO_TIMESPEC(&tv, &ts); 50 1.1 pooka 51 1.1 pooka vap->va_type = type; 52 1.1 pooka if (type == VDIR) { 53 1.1 pooka vap->va_mode = 0777; 54 1.1 pooka vap->va_nlink = 1; /* n + 1 after adding dent */ 55 1.1 pooka } else { 56 1.1 pooka vap->va_mode = 0666; 57 1.1 pooka vap->va_nlink = 0; /* n + 1 */ 58 1.1 pooka } 59 1.1 pooka vap->va_uid = 0; 60 1.1 pooka vap->va_gid = 0; 61 1.1 pooka vap->va_fileid = id; 62 1.1 pooka vap->va_size = 0; 63 1.1 pooka vap->va_blocksize = getpagesize(); 64 1.1 pooka vap->va_gen = random(); 65 1.1 pooka vap->va_flags = 0; 66 1.1 pooka vap->va_rdev = PUFFS_VNOVAL; 67 1.1 pooka vap->va_bytes = 0; 68 1.1 pooka vap->va_filerev = 1; 69 1.1 pooka vap->va_vaflags = 0; 70 1.1 pooka 71 1.1 pooka vap->va_atime = vap->va_mtime = vap->va_ctime = vap->va_birthtime = ts; 72 1.1 pooka } 73 1.1 pooka 74 1.1 pooka /* 75 1.1 pooka * Well, as you can probably see, this interface has the slight problem 76 1.5 andvar * of assuming file creation will always be successful, or at least not 77 1.1 pooka * giving a reason for the failure. Be sure to do better when you 78 1.1 pooka * implement your own fs. 79 1.1 pooka */ 80 1.1 pooka struct puffs_node * 81 1.1 pooka dtfs_genfile(struct puffs_node *dir, const struct puffs_cn *pcn, 82 1.1 pooka enum vtype type) 83 1.1 pooka { 84 1.4 christos struct dtfs_file *dff; 85 1.1 pooka struct dtfs_dirent *dfd; 86 1.1 pooka struct dtfs_mount *dtm; 87 1.1 pooka struct puffs_node *newpn; 88 1.1 pooka uid_t uid; 89 1.1 pooka int rv; 90 1.1 pooka 91 1.1 pooka assert(dir->pn_va.va_type == VDIR); 92 1.1 pooka assert(dir->pn_mnt != NULL); 93 1.1 pooka 94 1.1 pooka uid = 0; 95 1.1 pooka rv = puffs_cred_getuid(pcn->pcn_cred, &uid); 96 1.1 pooka assert(rv == 0); 97 1.1 pooka 98 1.1 pooka if (type == VDIR) { 99 1.1 pooka dff = dtfs_newdir(); 100 1.1 pooka dff->df_dotdot = dir; 101 1.1 pooka } else 102 1.1 pooka dff = dtfs_newfile(); 103 1.1 pooka 104 1.1 pooka dtm = puffs_pn_getmntspecific(dir); 105 1.1 pooka newpn = puffs_pn_new(dir->pn_mnt, dff); 106 1.1 pooka if (newpn == NULL) 107 1.1 pooka errx(1, "getnewpnode"); 108 1.1 pooka dtfs_baseattrs(&newpn->pn_va, type, dtm->dtm_nextfileid++); 109 1.1 pooka 110 1.1 pooka dfd = emalloc(sizeof(struct dtfs_dirent)); 111 1.1 pooka dfd->dfd_node = newpn; 112 1.1 pooka dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen); 113 1.1 pooka dfd->dfd_namelen = strlen(dfd->dfd_name); 114 1.1 pooka dfd->dfd_parent = dir; 115 1.1 pooka dtfs_adddent(dir, dfd); 116 1.1 pooka 117 1.1 pooka newpn->pn_va.va_uid = uid; 118 1.1 pooka newpn->pn_va.va_gid = dir->pn_va.va_gid; 119 1.1 pooka 120 1.1 pooka return newpn; 121 1.1 pooka } 122 1.1 pooka 123 1.1 pooka struct dtfs_file * 124 1.1 pooka dtfs_newdir() 125 1.1 pooka { 126 1.1 pooka struct dtfs_file *dff; 127 1.1 pooka 128 1.1 pooka dff = emalloc(sizeof(struct dtfs_file)); 129 1.1 pooka memset(dff, 0, sizeof(struct dtfs_file)); 130 1.1 pooka LIST_INIT(&dff->df_dirents); 131 1.1 pooka 132 1.1 pooka return dff; 133 1.1 pooka } 134 1.1 pooka 135 1.1 pooka struct dtfs_file * 136 1.1 pooka dtfs_newfile() 137 1.1 pooka { 138 1.1 pooka struct dtfs_file *dff; 139 1.1 pooka 140 1.1 pooka dff = emalloc(sizeof(struct dtfs_file)); 141 1.1 pooka memset(dff, 0, sizeof(struct dtfs_file)); 142 1.1 pooka 143 1.1 pooka return dff; 144 1.1 pooka } 145 1.1 pooka 146 1.1 pooka struct dtfs_dirent * 147 1.1 pooka dtfs_dirgetnth(struct dtfs_file *searchdir, int n) 148 1.1 pooka { 149 1.1 pooka struct dtfs_dirent *dirent; 150 1.1 pooka int i; 151 1.1 pooka 152 1.1 pooka i = 0; 153 1.1 pooka LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) { 154 1.1 pooka if (i == n) 155 1.1 pooka return dirent; 156 1.1 pooka i++; 157 1.1 pooka } 158 1.1 pooka 159 1.1 pooka return NULL; 160 1.1 pooka } 161 1.1 pooka 162 1.1 pooka struct dtfs_dirent * 163 1.1 pooka dtfs_dirgetbyname(struct dtfs_file *searchdir, const char *fname, size_t fnlen) 164 1.1 pooka { 165 1.1 pooka struct dtfs_dirent *dirent; 166 1.1 pooka 167 1.1 pooka LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) 168 1.1 pooka if (dirent->dfd_namelen == fnlen 169 1.1 pooka && strncmp(dirent->dfd_name, fname, fnlen) == 0) 170 1.1 pooka return dirent; 171 1.1 pooka 172 1.1 pooka return NULL; 173 1.1 pooka } 174 1.1 pooka 175 1.1 pooka /* 176 1.1 pooka * common nuke, kill dirent from parent node 177 1.1 pooka */ 178 1.1 pooka void 179 1.1 pooka dtfs_nukenode(struct puffs_node *nukeme, struct puffs_node *pn_parent, 180 1.1 pooka const char *fname, size_t fnlen) 181 1.1 pooka { 182 1.1 pooka struct dtfs_dirent *dfd; 183 1.1 pooka struct dtfs_mount *dtm; 184 1.1 pooka 185 1.1 pooka assert(pn_parent->pn_va.va_type == VDIR); 186 1.1 pooka 187 1.1 pooka dfd = dtfs_dirgetbyname(DTFS_PTOF(pn_parent), fname, fnlen); 188 1.1 pooka assert(dfd); 189 1.1 pooka 190 1.1 pooka dtm = puffs_pn_getmntspecific(nukeme); 191 1.1 pooka dtm->dtm_nfiles--; 192 1.1 pooka assert(dtm->dtm_nfiles >= 1); 193 1.1 pooka 194 1.1 pooka dtfs_removedent(pn_parent, dfd); 195 1.1 pooka free(dfd); 196 1.1 pooka } 197 1.1 pooka 198 1.1 pooka /* free lingering information */ 199 1.1 pooka void 200 1.1 pooka dtfs_freenode(struct puffs_node *pn) 201 1.1 pooka { 202 1.1 pooka struct dtfs_file *df = DTFS_PTOF(pn); 203 1.1 pooka struct dtfs_mount *dtm; 204 1.1 pooka int i; 205 1.1 pooka 206 1.1 pooka assert(pn->pn_va.va_nlink == 0); 207 1.1 pooka dtm = puffs_pn_getmntspecific(pn); 208 1.1 pooka 209 1.1 pooka switch (pn->pn_va.va_type) { 210 1.1 pooka case VREG: 211 1.1 pooka assert(dtm->dtm_fsizes >= pn->pn_va.va_size); 212 1.1 pooka dtm->dtm_fsizes -= pn->pn_va.va_size; 213 1.1 pooka for (i = 0; i < BLOCKNUM(df->df_datalen, DTFS_BLOCKSHIFT); i++) 214 1.1 pooka free(df->df_blocks[i]); 215 1.1 pooka if (df->df_datalen > i << DTFS_BLOCKSHIFT) 216 1.1 pooka free(df->df_blocks[i]); 217 1.1 pooka break; 218 1.1 pooka case VLNK: 219 1.1 pooka free(df->df_linktarget); 220 1.1 pooka break; 221 1.1 pooka case VCHR: 222 1.1 pooka case VBLK: 223 1.1 pooka case VDIR: 224 1.1 pooka case VSOCK: 225 1.1 pooka case VFIFO: 226 1.1 pooka break; 227 1.1 pooka default: 228 1.1 pooka assert(0); 229 1.1 pooka break; 230 1.1 pooka } 231 1.1 pooka 232 1.1 pooka free(df); 233 1.1 pooka puffs_pn_put(pn); 234 1.1 pooka } 235 1.1 pooka 236 1.1 pooka void 237 1.1 pooka dtfs_setsize(struct puffs_node *pn, off_t newsize) 238 1.1 pooka { 239 1.1 pooka struct dtfs_file *df = DTFS_PTOF(pn); 240 1.1 pooka struct dtfs_mount *dtm; 241 1.1 pooka size_t newblocks; 242 1.1 pooka int needalloc, shrinks; 243 1.1 pooka int i; 244 1.1 pooka 245 1.1 pooka needalloc = newsize > ROUNDUP(df->df_datalen, DTFS_BLOCKSIZE); 246 1.1 pooka shrinks = newsize < pn->pn_va.va_size; 247 1.1 pooka 248 1.1 pooka if (needalloc || shrinks) { 249 1.1 pooka newblocks = BLOCKNUM(newsize, DTFS_BLOCKSHIFT) + 1; 250 1.1 pooka 251 1.1 pooka if (shrinks) 252 1.1 pooka for (i = newblocks; i < df->df_numblocks; i++) 253 1.1 pooka free(df->df_blocks[i]); 254 1.1 pooka 255 1.1 pooka df->df_blocks = erealloc(df->df_blocks, 256 1.1 pooka newblocks * sizeof(uint8_t *)); 257 1.1 pooka /* 258 1.1 pooka * if extended, set storage to zero 259 1.1 pooka * to match correct behaviour 260 1.1 pooka */ 261 1.1 pooka if (!shrinks) { 262 1.1 pooka for (i = df->df_numblocks; i < newblocks; i++) { 263 1.1 pooka df->df_blocks[i] = emalloc(DTFS_BLOCKSIZE); 264 1.1 pooka memset(df->df_blocks[i], 0, DTFS_BLOCKSIZE); 265 1.1 pooka } 266 1.1 pooka } 267 1.1 pooka 268 1.1 pooka df->df_datalen = newsize; 269 1.1 pooka df->df_numblocks = newblocks; 270 1.1 pooka } 271 1.1 pooka 272 1.1 pooka dtm = puffs_pn_getmntspecific(pn); 273 1.1 pooka if (!shrinks) { 274 1.1 pooka dtm->dtm_fsizes += newsize - pn->pn_va.va_size; 275 1.1 pooka } else { 276 1.1 pooka dtm->dtm_fsizes -= pn->pn_va.va_size - newsize; 277 1.1 pooka } 278 1.1 pooka 279 1.1 pooka pn->pn_va.va_size = newsize; 280 1.1 pooka pn->pn_va.va_bytes = BLOCKNUM(newsize,DTFS_BLOCKSHIFT)>>DTFS_BLOCKSHIFT; 281 1.1 pooka } 282 1.1 pooka 283 1.1 pooka /* add & bump link count */ 284 1.1 pooka void 285 1.1 pooka dtfs_adddent(struct puffs_node *pn_dir, struct dtfs_dirent *dent) 286 1.1 pooka { 287 1.1 pooka struct dtfs_file *dir = DTFS_PTOF(pn_dir); 288 1.1 pooka struct puffs_node *pn_file = dent->dfd_node; 289 1.1 pooka struct dtfs_file *file = DTFS_PTOF(pn_file); 290 1.1 pooka struct dtfs_mount *dtm; 291 1.1 pooka 292 1.1 pooka assert(pn_dir->pn_va.va_type == VDIR); 293 1.1 pooka LIST_INSERT_HEAD(&dir->df_dirents, dent, dfd_entries); 294 1.1 pooka pn_file->pn_va.va_nlink++; 295 1.1 pooka 296 1.1 pooka dtm = puffs_pn_getmntspecific(pn_file); 297 1.1 pooka dtm->dtm_nfiles++; 298 1.1 pooka 299 1.1 pooka dent->dfd_parent = pn_dir; 300 1.1 pooka if (dent->dfd_node->pn_va.va_type == VDIR) { 301 1.1 pooka file->df_dotdot = pn_dir; 302 1.1 pooka pn_dir->pn_va.va_nlink++; 303 1.1 pooka } 304 1.1 pooka 305 1.1 pooka dtfs_updatetimes(pn_dir, 0, 1, 1); 306 1.1 pooka } 307 1.1 pooka 308 1.1 pooka /* remove & lower link count */ 309 1.1 pooka void 310 1.1 pooka dtfs_removedent(struct puffs_node *pn_dir, struct dtfs_dirent *dent) 311 1.1 pooka { 312 1.1 pooka struct puffs_node *pn_file = dent->dfd_node; 313 1.1 pooka 314 1.1 pooka assert(pn_dir->pn_va.va_type == VDIR); 315 1.1 pooka LIST_REMOVE(dent, dfd_entries); 316 1.3 pooka if (pn_file->pn_va.va_type == VDIR) { 317 1.3 pooka struct dtfs_file *df = DTFS_PTOF(pn_file); 318 1.3 pooka 319 1.1 pooka pn_dir->pn_va.va_nlink--; 320 1.3 pooka df->df_dotdot = NULL; 321 1.3 pooka } 322 1.1 pooka pn_file->pn_va.va_nlink--; 323 1.1 pooka assert(pn_dir->pn_va.va_nlink >= 2); 324 1.1 pooka 325 1.1 pooka dtfs_updatetimes(pn_dir, 0, 1, 1); 326 1.1 pooka } 327 1.1 pooka 328 1.1 pooka void 329 1.1 pooka dtfs_updatetimes(struct puffs_node *pn, int doatime, int doctime, int domtime) 330 1.1 pooka { 331 1.1 pooka struct timeval tv; 332 1.1 pooka struct timespec ts; 333 1.1 pooka 334 1.1 pooka gettimeofday(&tv, NULL); 335 1.1 pooka TIMEVAL_TO_TIMESPEC(&tv, &ts); 336 1.1 pooka 337 1.1 pooka if (doatime) 338 1.1 pooka pn->pn_va.va_atime = ts; 339 1.1 pooka if (doctime) 340 1.1 pooka pn->pn_va.va_ctime = ts; 341 1.1 pooka if (domtime) 342 1.1 pooka pn->pn_va.va_mtime = ts; 343 1.1 pooka } 344 1.2 pooka 345 1.2 pooka bool 346 1.2 pooka dtfs_isunder(struct puffs_node *pn, struct puffs_node *pn_parent) 347 1.2 pooka { 348 1.2 pooka struct dtfs_file *df; 349 1.2 pooka 350 1.2 pooka while (pn) { 351 1.2 pooka if (pn == pn_parent) 352 1.2 pooka return true; 353 1.2 pooka df = DTFS_CTOF(pn); 354 1.2 pooka pn = df->df_dotdot; 355 1.2 pooka } 356 1.2 pooka 357 1.2 pooka return false; 358 1.2 pooka } 359