1*69d94f4cSDag-Erling Smørgrav /*- 2*69d94f4cSDag-Erling Smørgrav * SPDX-License-Identifier: BSD-2-Clause 3*69d94f4cSDag-Erling Smørgrav * 4*69d94f4cSDag-Erling Smørgrav * Copyright (c) 2013 Juniper Networks, Inc. 5*69d94f4cSDag-Erling Smørgrav * Copyright (c) 2022-2023 Klara, Inc. 6*69d94f4cSDag-Erling Smørgrav * 7*69d94f4cSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 8*69d94f4cSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 9*69d94f4cSDag-Erling Smørgrav * are met: 10*69d94f4cSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 11*69d94f4cSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 12*69d94f4cSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 13*69d94f4cSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 14*69d94f4cSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 15*69d94f4cSDag-Erling Smørgrav * 16*69d94f4cSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*69d94f4cSDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*69d94f4cSDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*69d94f4cSDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*69d94f4cSDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*69d94f4cSDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*69d94f4cSDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*69d94f4cSDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*69d94f4cSDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*69d94f4cSDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*69d94f4cSDag-Erling Smørgrav * SUCH DAMAGE. 27*69d94f4cSDag-Erling Smørgrav */ 28*69d94f4cSDag-Erling Smørgrav 29*69d94f4cSDag-Erling Smørgrav #include "opt_tarfs.h" 30*69d94f4cSDag-Erling Smørgrav 31*69d94f4cSDag-Erling Smørgrav #include <sys/param.h> 32*69d94f4cSDag-Erling Smørgrav #include <sys/stat.h> 33*69d94f4cSDag-Erling Smørgrav #include <sys/systm.h> 34*69d94f4cSDag-Erling Smørgrav #include <sys/buf.h> 35*69d94f4cSDag-Erling Smørgrav #include <sys/fcntl.h> 36*69d94f4cSDag-Erling Smørgrav #include <sys/libkern.h> 37*69d94f4cSDag-Erling Smørgrav #include <sys/lock.h> 38*69d94f4cSDag-Erling Smørgrav #include <sys/malloc.h> 39*69d94f4cSDag-Erling Smørgrav #include <sys/mount.h> 40*69d94f4cSDag-Erling Smørgrav #include <sys/namei.h> 41*69d94f4cSDag-Erling Smørgrav #include <sys/proc.h> 42*69d94f4cSDag-Erling Smørgrav #include <sys/queue.h> 43*69d94f4cSDag-Erling Smørgrav #include <sys/sysctl.h> 44*69d94f4cSDag-Erling Smørgrav #include <sys/vnode.h> 45*69d94f4cSDag-Erling Smørgrav 46*69d94f4cSDag-Erling Smørgrav #include <vm/vm_param.h> 47*69d94f4cSDag-Erling Smørgrav 48*69d94f4cSDag-Erling Smørgrav #include <fs/tarfs/tarfs.h> 49*69d94f4cSDag-Erling Smørgrav #include <fs/tarfs/tarfs_dbg.h> 50*69d94f4cSDag-Erling Smørgrav 51*69d94f4cSDag-Erling Smørgrav MALLOC_DEFINE(M_TARFSNAME, "tarfs name", "tarfs file names"); 52*69d94f4cSDag-Erling Smørgrav MALLOC_DEFINE(M_TARFSBLK, "tarfs blk", "tarfs block maps"); 53*69d94f4cSDag-Erling Smørgrav 54*69d94f4cSDag-Erling Smørgrav SYSCTL_NODE(_vfs, OID_AUTO, tarfs, CTLFLAG_RW, 0, "Tar filesystem"); 55*69d94f4cSDag-Erling Smørgrav 56*69d94f4cSDag-Erling Smørgrav unsigned int tarfs_ioshift = TARFS_IOSHIFT_DEFAULT; 57*69d94f4cSDag-Erling Smørgrav 58*69d94f4cSDag-Erling Smørgrav static int 59*69d94f4cSDag-Erling Smørgrav tarfs_sysctl_handle_ioshift(SYSCTL_HANDLER_ARGS) 60*69d94f4cSDag-Erling Smørgrav { 61*69d94f4cSDag-Erling Smørgrav unsigned int tmp; 62*69d94f4cSDag-Erling Smørgrav int error; 63*69d94f4cSDag-Erling Smørgrav 64*69d94f4cSDag-Erling Smørgrav tmp = *(unsigned int *)arg1; 65*69d94f4cSDag-Erling Smørgrav if ((error = SYSCTL_OUT(req, &tmp, sizeof(tmp))) != 0) 66*69d94f4cSDag-Erling Smørgrav return (error); 67*69d94f4cSDag-Erling Smørgrav if (req->newptr != NULL) { 68*69d94f4cSDag-Erling Smørgrav if ((error = SYSCTL_IN(req, &tmp, sizeof(tmp))) != 0) 69*69d94f4cSDag-Erling Smørgrav return (error); 70*69d94f4cSDag-Erling Smørgrav if (tmp == 0) 71*69d94f4cSDag-Erling Smørgrav tmp = TARFS_IOSHIFT_DEFAULT; 72*69d94f4cSDag-Erling Smørgrav if (tmp < TARFS_IOSHIFT_MIN) 73*69d94f4cSDag-Erling Smørgrav tmp = TARFS_IOSHIFT_MIN; 74*69d94f4cSDag-Erling Smørgrav if (tmp > TARFS_IOSHIFT_MAX) 75*69d94f4cSDag-Erling Smørgrav tmp = TARFS_IOSHIFT_MAX; 76*69d94f4cSDag-Erling Smørgrav *(unsigned int *)arg1 = tmp; 77*69d94f4cSDag-Erling Smørgrav } 78*69d94f4cSDag-Erling Smørgrav return (0); 79*69d94f4cSDag-Erling Smørgrav } 80*69d94f4cSDag-Erling Smørgrav 81*69d94f4cSDag-Erling Smørgrav SYSCTL_PROC(_vfs_tarfs, OID_AUTO, ioshift, 82*69d94f4cSDag-Erling Smørgrav CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RW | CTLFLAG_TUN, 83*69d94f4cSDag-Erling Smørgrav &tarfs_ioshift, 0, tarfs_sysctl_handle_ioshift, "IU", 84*69d94f4cSDag-Erling Smørgrav "Tar filesystem preferred I/O size (log 2)"); 85*69d94f4cSDag-Erling Smørgrav 86*69d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG 87*69d94f4cSDag-Erling Smørgrav int tarfs_debug; 88*69d94f4cSDag-Erling Smørgrav SYSCTL_INT(_vfs_tarfs, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, 89*69d94f4cSDag-Erling Smørgrav &tarfs_debug, 0, "Tar filesystem debug mask"); 90*69d94f4cSDag-Erling Smørgrav #endif /* TARFS_DEBUG */ 91*69d94f4cSDag-Erling Smørgrav 92*69d94f4cSDag-Erling Smørgrav static void 93*69d94f4cSDag-Erling Smørgrav tarfs_dump_tree_internal(struct tarfs_node *tnp, int indent) 94*69d94f4cSDag-Erling Smørgrav { 95*69d94f4cSDag-Erling Smørgrav struct tarfs_node *current; 96*69d94f4cSDag-Erling Smørgrav const char *name; 97*69d94f4cSDag-Erling Smørgrav 98*69d94f4cSDag-Erling Smørgrav if (tnp->type != VDIR) 99*69d94f4cSDag-Erling Smørgrav return; 100*69d94f4cSDag-Erling Smørgrav 101*69d94f4cSDag-Erling Smørgrav TAILQ_FOREACH(current, &tnp->dir.dirhead, dirents) { 102*69d94f4cSDag-Erling Smørgrav if (current->name == NULL) 103*69d94f4cSDag-Erling Smørgrav name = "<<root>>"; 104*69d94f4cSDag-Erling Smørgrav else 105*69d94f4cSDag-Erling Smørgrav name = current->name; 106*69d94f4cSDag-Erling Smørgrav printf("%*s%s\n", indent * 4, "", name); 107*69d94f4cSDag-Erling Smørgrav if (current->type == VDIR) 108*69d94f4cSDag-Erling Smørgrav tarfs_dump_tree_internal(current, indent + 1); 109*69d94f4cSDag-Erling Smørgrav } 110*69d94f4cSDag-Erling Smørgrav } 111*69d94f4cSDag-Erling Smørgrav 112*69d94f4cSDag-Erling Smørgrav void 113*69d94f4cSDag-Erling Smørgrav tarfs_dump_tree(struct tarfs_node *tnp) 114*69d94f4cSDag-Erling Smørgrav { 115*69d94f4cSDag-Erling Smørgrav const char *name; 116*69d94f4cSDag-Erling Smørgrav 117*69d94f4cSDag-Erling Smørgrav if (tnp == NULL) 118*69d94f4cSDag-Erling Smørgrav return; 119*69d94f4cSDag-Erling Smørgrav 120*69d94f4cSDag-Erling Smørgrav if (tnp->name == NULL) 121*69d94f4cSDag-Erling Smørgrav name = "<<root>>"; 122*69d94f4cSDag-Erling Smørgrav else 123*69d94f4cSDag-Erling Smørgrav name = tnp->name; 124*69d94f4cSDag-Erling Smørgrav printf("%s\n", name); 125*69d94f4cSDag-Erling Smørgrav 126*69d94f4cSDag-Erling Smørgrav tarfs_dump_tree_internal(tnp, 1); 127*69d94f4cSDag-Erling Smørgrav } 128*69d94f4cSDag-Erling Smørgrav 129*69d94f4cSDag-Erling Smørgrav void 130*69d94f4cSDag-Erling Smørgrav tarfs_print_node(struct tarfs_node *tnp) 131*69d94f4cSDag-Erling Smørgrav { 132*69d94f4cSDag-Erling Smørgrav 133*69d94f4cSDag-Erling Smørgrav if (tnp == NULL) 134*69d94f4cSDag-Erling Smørgrav return; 135*69d94f4cSDag-Erling Smørgrav 136*69d94f4cSDag-Erling Smørgrav printf("%s: node %p\n", __func__, tnp); 137*69d94f4cSDag-Erling Smørgrav printf("\tvnode %p\n", tnp->vnode); 138*69d94f4cSDag-Erling Smørgrav printf("\ttmp %p\n", tnp->tmp); 139*69d94f4cSDag-Erling Smørgrav printf("\ttype %d\n", tnp->type); 140*69d94f4cSDag-Erling Smørgrav printf("\tino %lu\n", tnp->ino); 141*69d94f4cSDag-Erling Smørgrav printf("\tsize %zu\n", tnp->size); 142*69d94f4cSDag-Erling Smørgrav printf("\tname %s\n", 143*69d94f4cSDag-Erling Smørgrav (tnp->name == NULL) ? "<<root>>" : tnp->name); 144*69d94f4cSDag-Erling Smørgrav printf("\tnamelen %zu\n", tnp->namelen); 145*69d94f4cSDag-Erling Smørgrav printf("\tuid %d\n", tnp->uid); 146*69d94f4cSDag-Erling Smørgrav printf("\tgid %d\n", tnp->gid); 147*69d94f4cSDag-Erling Smørgrav printf("\tmode o%o\n", tnp->mode); 148*69d94f4cSDag-Erling Smørgrav printf("\tflags %u\n", tnp->flags); 149*69d94f4cSDag-Erling Smørgrav printf("\tnlink %lu\n", tnp->nlink); 150*69d94f4cSDag-Erling Smørgrav printf("\tatime %d\n", (int)tnp->atime.tv_sec); 151*69d94f4cSDag-Erling Smørgrav printf("\tmtime %d\n", (int)tnp->mtime.tv_sec); 152*69d94f4cSDag-Erling Smørgrav printf("\tctime %d\n", (int)tnp->ctime.tv_sec); 153*69d94f4cSDag-Erling Smørgrav printf("\tbirthtime %d\n", (int)tnp->birthtime.tv_sec); 154*69d94f4cSDag-Erling Smørgrav printf("\tgen %lu\n", tnp->gen); 155*69d94f4cSDag-Erling Smørgrav printf("\tparent %p\n", tnp->parent); 156*69d94f4cSDag-Erling Smørgrav 157*69d94f4cSDag-Erling Smørgrav switch (tnp->type) { 158*69d94f4cSDag-Erling Smørgrav case VDIR: 159*69d94f4cSDag-Erling Smørgrav printf("\tdir.lastcookie %jd\n", 160*69d94f4cSDag-Erling Smørgrav tnp->dir.lastcookie); 161*69d94f4cSDag-Erling Smørgrav printf("\tdir.lastnode %p\n", tnp->dir.lastnode); 162*69d94f4cSDag-Erling Smørgrav break; 163*69d94f4cSDag-Erling Smørgrav case VBLK: 164*69d94f4cSDag-Erling Smørgrav case VCHR: 165*69d94f4cSDag-Erling Smørgrav printf("\trdev %lu\n", tnp->rdev); 166*69d94f4cSDag-Erling Smørgrav break; 167*69d94f4cSDag-Erling Smørgrav default: 168*69d94f4cSDag-Erling Smørgrav break; 169*69d94f4cSDag-Erling Smørgrav } 170*69d94f4cSDag-Erling Smørgrav } 171*69d94f4cSDag-Erling Smørgrav 172*69d94f4cSDag-Erling Smørgrav struct tarfs_node * 173*69d94f4cSDag-Erling Smørgrav tarfs_lookup_node(struct tarfs_node *tnp, struct tarfs_node *f, 174*69d94f4cSDag-Erling Smørgrav struct componentname *cnp) 175*69d94f4cSDag-Erling Smørgrav { 176*69d94f4cSDag-Erling Smørgrav boolean_t found; 177*69d94f4cSDag-Erling Smørgrav struct tarfs_node *entry; 178*69d94f4cSDag-Erling Smørgrav 179*69d94f4cSDag-Erling Smørgrav TARFS_DPF(LOOKUP, "%s: name: %.*s\n", __func__, (int)cnp->cn_namelen, 180*69d94f4cSDag-Erling Smørgrav cnp->cn_nameptr); 181*69d94f4cSDag-Erling Smørgrav 182*69d94f4cSDag-Erling Smørgrav found = false; 183*69d94f4cSDag-Erling Smørgrav TAILQ_FOREACH(entry, &tnp->dir.dirhead, dirents) { 184*69d94f4cSDag-Erling Smørgrav if (f != NULL && entry != f) 185*69d94f4cSDag-Erling Smørgrav continue; 186*69d94f4cSDag-Erling Smørgrav 187*69d94f4cSDag-Erling Smørgrav if (entry->namelen == cnp->cn_namelen && 188*69d94f4cSDag-Erling Smørgrav bcmp(entry->name, cnp->cn_nameptr, 189*69d94f4cSDag-Erling Smørgrav entry->namelen) == 0) { 190*69d94f4cSDag-Erling Smørgrav found = 1; 191*69d94f4cSDag-Erling Smørgrav break; 192*69d94f4cSDag-Erling Smørgrav } 193*69d94f4cSDag-Erling Smørgrav } 194*69d94f4cSDag-Erling Smørgrav 195*69d94f4cSDag-Erling Smørgrav if (found) { 196*69d94f4cSDag-Erling Smørgrav if (entry->type == VREG && entry->other != NULL) { 197*69d94f4cSDag-Erling Smørgrav TARFS_DPF_IFF(LOOKUP, "%s: following hard link %p\n", 198*69d94f4cSDag-Erling Smørgrav __func__, entry); 199*69d94f4cSDag-Erling Smørgrav entry = entry->other; 200*69d94f4cSDag-Erling Smørgrav } 201*69d94f4cSDag-Erling Smørgrav TARFS_DPF(LOOKUP, "%s: found tarfs_node %p\n", __func__, 202*69d94f4cSDag-Erling Smørgrav entry); 203*69d94f4cSDag-Erling Smørgrav return (entry); 204*69d94f4cSDag-Erling Smørgrav } 205*69d94f4cSDag-Erling Smørgrav 206*69d94f4cSDag-Erling Smørgrav TARFS_DPF(LOOKUP, "%s: no match found\n", __func__); 207*69d94f4cSDag-Erling Smørgrav return (NULL); 208*69d94f4cSDag-Erling Smørgrav } 209*69d94f4cSDag-Erling Smørgrav 210*69d94f4cSDag-Erling Smørgrav struct tarfs_node * 211*69d94f4cSDag-Erling Smørgrav tarfs_lookup_dir(struct tarfs_node *tnp, off_t cookie) 212*69d94f4cSDag-Erling Smørgrav { 213*69d94f4cSDag-Erling Smørgrav struct tarfs_node *current; 214*69d94f4cSDag-Erling Smørgrav 215*69d94f4cSDag-Erling Smørgrav TARFS_DPF(LOOKUP, "%s: tarfs_node %p, cookie %jd\n", __func__, tnp, 216*69d94f4cSDag-Erling Smørgrav cookie); 217*69d94f4cSDag-Erling Smørgrav TARFS_DPF(LOOKUP, "%s: name: %s\n", __func__, 218*69d94f4cSDag-Erling Smørgrav (tnp->name == NULL) ? "<<root>>" : tnp->name); 219*69d94f4cSDag-Erling Smørgrav 220*69d94f4cSDag-Erling Smørgrav if (cookie == tnp->dir.lastcookie && 221*69d94f4cSDag-Erling Smørgrav tnp->dir.lastnode != NULL) { 222*69d94f4cSDag-Erling Smørgrav TARFS_DPF(LOOKUP, "%s: Using cached entry: tarfs_node %p, " 223*69d94f4cSDag-Erling Smørgrav "cookie %jd\n", __func__, tnp->dir.lastnode, 224*69d94f4cSDag-Erling Smørgrav tnp->dir.lastcookie); 225*69d94f4cSDag-Erling Smørgrav return (tnp->dir.lastnode); 226*69d94f4cSDag-Erling Smørgrav } 227*69d94f4cSDag-Erling Smørgrav 228*69d94f4cSDag-Erling Smørgrav TAILQ_FOREACH(current, &tnp->dir.dirhead, dirents) { 229*69d94f4cSDag-Erling Smørgrav TARFS_DPF(LOOKUP, "%s: tarfs_node %p, current %p, ino %lu\n", 230*69d94f4cSDag-Erling Smørgrav __func__, tnp, current, current->ino); 231*69d94f4cSDag-Erling Smørgrav TARFS_DPF_IFF(LOOKUP, current->name != NULL, 232*69d94f4cSDag-Erling Smørgrav "%s: name: %s\n", __func__, current->name); 233*69d94f4cSDag-Erling Smørgrav if (current->ino == cookie) { 234*69d94f4cSDag-Erling Smørgrav TARFS_DPF(LOOKUP, "%s: Found entry: tarfs_node %p, " 235*69d94f4cSDag-Erling Smørgrav "cookie %lu\n", __func__, current, 236*69d94f4cSDag-Erling Smørgrav current->ino); 237*69d94f4cSDag-Erling Smørgrav break; 238*69d94f4cSDag-Erling Smørgrav } 239*69d94f4cSDag-Erling Smørgrav } 240*69d94f4cSDag-Erling Smørgrav 241*69d94f4cSDag-Erling Smørgrav return (current); 242*69d94f4cSDag-Erling Smørgrav } 243*69d94f4cSDag-Erling Smørgrav 244*69d94f4cSDag-Erling Smørgrav int 245*69d94f4cSDag-Erling Smørgrav tarfs_alloc_node(struct tarfs_mount *tmp, const char *name, size_t namelen, 246*69d94f4cSDag-Erling Smørgrav enum vtype type, off_t off, size_t sz, time_t mtime, uid_t uid, gid_t gid, 247*69d94f4cSDag-Erling Smørgrav mode_t mode, unsigned int flags, const char *linkname, dev_t rdev, 248*69d94f4cSDag-Erling Smørgrav struct tarfs_node *parent, struct tarfs_node **retnode) 249*69d94f4cSDag-Erling Smørgrav { 250*69d94f4cSDag-Erling Smørgrav struct tarfs_node *tnp; 251*69d94f4cSDag-Erling Smørgrav 252*69d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s(%.*s)\n", __func__, (int)namelen, name); 253*69d94f4cSDag-Erling Smørgrav 254*69d94f4cSDag-Erling Smørgrav tnp = malloc(sizeof(struct tarfs_node), M_TARFSNODE, M_WAITOK | M_ZERO); 255*69d94f4cSDag-Erling Smørgrav mtx_init(&tnp->lock, "tarfs node lock", NULL, MTX_DEF); 256*69d94f4cSDag-Erling Smørgrav tnp->gen = arc4random(); 257*69d94f4cSDag-Erling Smørgrav tnp->tmp = tmp; 258*69d94f4cSDag-Erling Smørgrav if (namelen > 0) { 259*69d94f4cSDag-Erling Smørgrav tnp->name = malloc(namelen + 1, M_TARFSNAME, M_WAITOK); 260*69d94f4cSDag-Erling Smørgrav tnp->namelen = namelen; 261*69d94f4cSDag-Erling Smørgrav memcpy(tnp->name, name, namelen); 262*69d94f4cSDag-Erling Smørgrav tnp->name[namelen] = '\0'; 263*69d94f4cSDag-Erling Smørgrav } 264*69d94f4cSDag-Erling Smørgrav tnp->type = type; 265*69d94f4cSDag-Erling Smørgrav tnp->uid = uid; 266*69d94f4cSDag-Erling Smørgrav tnp->gid = gid; 267*69d94f4cSDag-Erling Smørgrav tnp->mode = mode; 268*69d94f4cSDag-Erling Smørgrav tnp->nlink = 1; 269*69d94f4cSDag-Erling Smørgrav vfs_timestamp(&tnp->atime); 270*69d94f4cSDag-Erling Smørgrav tnp->mtime.tv_sec = mtime; 271*69d94f4cSDag-Erling Smørgrav tnp->birthtime = tnp->atime; 272*69d94f4cSDag-Erling Smørgrav tnp->ctime = tnp->mtime; 273*69d94f4cSDag-Erling Smørgrav if (parent != NULL) { 274*69d94f4cSDag-Erling Smørgrav tnp->ino = alloc_unr(tmp->ino_unr); 275*69d94f4cSDag-Erling Smørgrav } 276*69d94f4cSDag-Erling Smørgrav tnp->offset = off; 277*69d94f4cSDag-Erling Smørgrav tnp->size = tnp->physize = sz; 278*69d94f4cSDag-Erling Smørgrav switch (type) { 279*69d94f4cSDag-Erling Smørgrav case VDIR: 280*69d94f4cSDag-Erling Smørgrav MPASS(parent != tnp); 281*69d94f4cSDag-Erling Smørgrav MPASS(parent != NULL || tmp->root == NULL); 282*69d94f4cSDag-Erling Smørgrav TAILQ_INIT(&tnp->dir.dirhead); 283*69d94f4cSDag-Erling Smørgrav tnp->nlink++; 284*69d94f4cSDag-Erling Smørgrav if (parent == NULL) { 285*69d94f4cSDag-Erling Smørgrav tnp->ino = TARFS_ROOTINO; 286*69d94f4cSDag-Erling Smørgrav } 287*69d94f4cSDag-Erling Smørgrav tnp->physize = 0; 288*69d94f4cSDag-Erling Smørgrav break; 289*69d94f4cSDag-Erling Smørgrav case VLNK: 290*69d94f4cSDag-Erling Smørgrav tnp->link.name = malloc(sz + 1, M_TARFSNAME, 291*69d94f4cSDag-Erling Smørgrav M_WAITOK); 292*69d94f4cSDag-Erling Smørgrav tnp->link.namelen = sz; 293*69d94f4cSDag-Erling Smørgrav memcpy(tnp->link.name, linkname, sz); 294*69d94f4cSDag-Erling Smørgrav tnp->link.name[sz] = '\0'; 295*69d94f4cSDag-Erling Smørgrav break; 296*69d94f4cSDag-Erling Smørgrav case VREG: 297*69d94f4cSDag-Erling Smørgrav /* create dummy block map */ 298*69d94f4cSDag-Erling Smørgrav tnp->nblk = 1; 299*69d94f4cSDag-Erling Smørgrav tnp->blk = malloc(sizeof(*tnp->blk), M_TARFSBLK, M_WAITOK); 300*69d94f4cSDag-Erling Smørgrav tnp->blk[0].i = 0; 301*69d94f4cSDag-Erling Smørgrav tnp->blk[0].o = 0; 302*69d94f4cSDag-Erling Smørgrav tnp->blk[0].l = tnp->physize; 303*69d94f4cSDag-Erling Smørgrav break; 304*69d94f4cSDag-Erling Smørgrav case VFIFO: 305*69d94f4cSDag-Erling Smørgrav /* Nothing extra to do */ 306*69d94f4cSDag-Erling Smørgrav break; 307*69d94f4cSDag-Erling Smørgrav case VBLK: 308*69d94f4cSDag-Erling Smørgrav case VCHR: 309*69d94f4cSDag-Erling Smørgrav tnp->rdev = rdev; 310*69d94f4cSDag-Erling Smørgrav tnp->physize = 0; 311*69d94f4cSDag-Erling Smørgrav break; 312*69d94f4cSDag-Erling Smørgrav default: 313*69d94f4cSDag-Erling Smørgrav panic("%s: type %d not allowed", __func__, type); 314*69d94f4cSDag-Erling Smørgrav } 315*69d94f4cSDag-Erling Smørgrav if (parent != NULL) { 316*69d94f4cSDag-Erling Smørgrav MPASS(parent->type == VDIR); 317*69d94f4cSDag-Erling Smørgrav TARFS_NODE_LOCK(parent); 318*69d94f4cSDag-Erling Smørgrav TAILQ_INSERT_TAIL(&parent->dir.dirhead, tnp, dirents); 319*69d94f4cSDag-Erling Smørgrav parent->size += sizeof(struct tarfs_node); 320*69d94f4cSDag-Erling Smørgrav tnp->parent = parent; 321*69d94f4cSDag-Erling Smørgrav if (type == VDIR) { 322*69d94f4cSDag-Erling Smørgrav parent->nlink++; 323*69d94f4cSDag-Erling Smørgrav } 324*69d94f4cSDag-Erling Smørgrav TARFS_NODE_UNLOCK(parent); 325*69d94f4cSDag-Erling Smørgrav } else { 326*69d94f4cSDag-Erling Smørgrav tnp->parent = tnp; 327*69d94f4cSDag-Erling Smørgrav } 328*69d94f4cSDag-Erling Smørgrav MPASS(tnp->ino != 0); 329*69d94f4cSDag-Erling Smørgrav 330*69d94f4cSDag-Erling Smørgrav TARFS_ALLNODES_LOCK(tmp); 331*69d94f4cSDag-Erling Smørgrav TAILQ_INSERT_TAIL(&tmp->allnodes, tnp, entries); 332*69d94f4cSDag-Erling Smørgrav TARFS_ALLNODES_UNLOCK(tmp); 333*69d94f4cSDag-Erling Smørgrav 334*69d94f4cSDag-Erling Smørgrav *retnode = tnp; 335*69d94f4cSDag-Erling Smørgrav tmp->nfiles++; 336*69d94f4cSDag-Erling Smørgrav return (0); 337*69d94f4cSDag-Erling Smørgrav } 338*69d94f4cSDag-Erling Smørgrav 339*69d94f4cSDag-Erling Smørgrav #define is09(ch) ((ch) >= '0' && (ch) <= '9') 340*69d94f4cSDag-Erling Smørgrav 341*69d94f4cSDag-Erling Smørgrav int 342*69d94f4cSDag-Erling Smørgrav tarfs_load_blockmap(struct tarfs_node *tnp, size_t realsize) 343*69d94f4cSDag-Erling Smørgrav { 344*69d94f4cSDag-Erling Smørgrav struct tarfs_blk *blk = NULL; 345*69d94f4cSDag-Erling Smørgrav char *map = NULL; 346*69d94f4cSDag-Erling Smørgrav size_t nmap = 0, nblk = 0; 347*69d94f4cSDag-Erling Smørgrav char *p, *q; 348*69d94f4cSDag-Erling Smørgrav ssize_t res; 349*69d94f4cSDag-Erling Smørgrav unsigned int i; 350*69d94f4cSDag-Erling Smørgrav long n; 351*69d94f4cSDag-Erling Smørgrav 352*69d94f4cSDag-Erling Smørgrav /* 353*69d94f4cSDag-Erling Smørgrav * Load the entire map into memory. We don't know how big it is, 354*69d94f4cSDag-Erling Smørgrav * but as soon as we start reading it we will know how many 355*69d94f4cSDag-Erling Smørgrav * entries it contains, and then we can count newlines. 356*69d94f4cSDag-Erling Smørgrav */ 357*69d94f4cSDag-Erling Smørgrav do { 358*69d94f4cSDag-Erling Smørgrav nmap++; 359*69d94f4cSDag-Erling Smørgrav if (tnp->size < nmap * TARFS_BLOCKSIZE) { 360*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: map too large\n", __func__); 361*69d94f4cSDag-Erling Smørgrav goto bad; 362*69d94f4cSDag-Erling Smørgrav } 363*69d94f4cSDag-Erling Smørgrav /* grow the map */ 364*69d94f4cSDag-Erling Smørgrav map = realloc(map, nmap * TARFS_BLOCKSIZE + 1, M_TARFSBLK, 365*69d94f4cSDag-Erling Smørgrav M_ZERO | M_WAITOK); 366*69d94f4cSDag-Erling Smørgrav /* read an additional block */ 367*69d94f4cSDag-Erling Smørgrav res = tarfs_io_read_buf(tnp->tmp, false, 368*69d94f4cSDag-Erling Smørgrav map + (nmap - 1) * TARFS_BLOCKSIZE, 369*69d94f4cSDag-Erling Smørgrav tnp->offset + (nmap - 1) * TARFS_BLOCKSIZE, 370*69d94f4cSDag-Erling Smørgrav TARFS_BLOCKSIZE); 371*69d94f4cSDag-Erling Smørgrav if (res < 0) 372*69d94f4cSDag-Erling Smørgrav return (-res); 373*69d94f4cSDag-Erling Smørgrav else if (res < TARFS_BLOCKSIZE) 374*69d94f4cSDag-Erling Smørgrav return (EIO); 375*69d94f4cSDag-Erling Smørgrav map[nmap * TARFS_BLOCKSIZE] = '\0'; /* sentinel */ 376*69d94f4cSDag-Erling Smørgrav if (nblk == 0) { 377*69d94f4cSDag-Erling Smørgrav n = strtol(p = map, &q, 10); 378*69d94f4cSDag-Erling Smørgrav if (q == p || *q != '\n' || n < 1) 379*69d94f4cSDag-Erling Smørgrav goto syntax; 380*69d94f4cSDag-Erling Smørgrav nblk = n; 381*69d94f4cSDag-Erling Smørgrav } 382*69d94f4cSDag-Erling Smørgrav for (n = 0, p = map; *p != '\0'; ++p) { 383*69d94f4cSDag-Erling Smørgrav if (*p == '\n') { 384*69d94f4cSDag-Erling Smørgrav ++n; 385*69d94f4cSDag-Erling Smørgrav } 386*69d94f4cSDag-Erling Smørgrav } 387*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: %ld newlines in map\n", __func__, n); 388*69d94f4cSDag-Erling Smørgrav } while (n < nblk * 2 + 1); 389*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: block map length %zu\n", __func__, nblk); 390*69d94f4cSDag-Erling Smørgrav blk = malloc(sizeof(*blk) * nblk, M_TARFSBLK, M_WAITOK | M_ZERO); 391*69d94f4cSDag-Erling Smørgrav p = strchr(map, '\n') + 1; 392*69d94f4cSDag-Erling Smørgrav for (i = 0; i < nblk; i++) { 393*69d94f4cSDag-Erling Smørgrav if (i == 0) 394*69d94f4cSDag-Erling Smørgrav blk[i].i = nmap * TARFS_BLOCKSIZE; 395*69d94f4cSDag-Erling Smørgrav else 396*69d94f4cSDag-Erling Smørgrav blk[i].i = blk[i - 1].i + blk[i - 1].l; 397*69d94f4cSDag-Erling Smørgrav n = strtol(p, &q, 10); 398*69d94f4cSDag-Erling Smørgrav if (q == p || *q != '\n' || n < 0) 399*69d94f4cSDag-Erling Smørgrav goto syntax; 400*69d94f4cSDag-Erling Smørgrav p = q + 1; 401*69d94f4cSDag-Erling Smørgrav blk[i].o = n; 402*69d94f4cSDag-Erling Smørgrav n = strtol(p, &q, 10); 403*69d94f4cSDag-Erling Smørgrav if (q == p || *q != '\n' || n < 0) 404*69d94f4cSDag-Erling Smørgrav goto syntax; 405*69d94f4cSDag-Erling Smørgrav p = q + 1; 406*69d94f4cSDag-Erling Smørgrav blk[i].l = n; 407*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: %3d %12zu %12zu %12zu\n", __func__, 408*69d94f4cSDag-Erling Smørgrav i, blk[i].i, blk[i].o, blk[i].l); 409*69d94f4cSDag-Erling Smørgrav /* 410*69d94f4cSDag-Erling Smørgrav * Check block alignment if the block is of non-zero 411*69d94f4cSDag-Erling Smørgrav * length (a zero-length block indicates the end of a 412*69d94f4cSDag-Erling Smørgrav * trailing hole). Checking i indirectly checks the 413*69d94f4cSDag-Erling Smørgrav * previous block's l. It's ok for the final block to 414*69d94f4cSDag-Erling Smørgrav * have an uneven length. 415*69d94f4cSDag-Erling Smørgrav */ 416*69d94f4cSDag-Erling Smørgrav if (blk[i].l == 0) { 417*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: zero-length block\n", __func__); 418*69d94f4cSDag-Erling Smørgrav } else if (blk[i].i % TARFS_BLOCKSIZE != 0 || 419*69d94f4cSDag-Erling Smørgrav blk[i].o % TARFS_BLOCKSIZE != 0) { 420*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: misaligned map entry\n", __func__); 421*69d94f4cSDag-Erling Smørgrav goto bad; 422*69d94f4cSDag-Erling Smørgrav } 423*69d94f4cSDag-Erling Smørgrav /* 424*69d94f4cSDag-Erling Smørgrav * Check that this block starts after the end of the 425*69d94f4cSDag-Erling Smørgrav * previous one. 426*69d94f4cSDag-Erling Smørgrav */ 427*69d94f4cSDag-Erling Smørgrav if (i > 0 && blk[i].o < blk[i - 1].o + blk[i - 1].l) { 428*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: overlapping map entries\n", __func__); 429*69d94f4cSDag-Erling Smørgrav goto bad; 430*69d94f4cSDag-Erling Smørgrav } 431*69d94f4cSDag-Erling Smørgrav /* 432*69d94f4cSDag-Erling Smørgrav * Check that the block is within the file, both 433*69d94f4cSDag-Erling Smørgrav * physically and logically. 434*69d94f4cSDag-Erling Smørgrav */ 435*69d94f4cSDag-Erling Smørgrav if (blk[i].i + blk[i].l > tnp->physize || 436*69d94f4cSDag-Erling Smørgrav blk[i].o + blk[i].l > realsize) { 437*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: map overflow\n", __func__); 438*69d94f4cSDag-Erling Smørgrav goto bad; 439*69d94f4cSDag-Erling Smørgrav } 440*69d94f4cSDag-Erling Smørgrav } 441*69d94f4cSDag-Erling Smørgrav free(map, M_TARFSBLK); 442*69d94f4cSDag-Erling Smørgrav 443*69d94f4cSDag-Erling Smørgrav /* store in node */ 444*69d94f4cSDag-Erling Smørgrav free(tnp->blk, M_TARFSBLK); 445*69d94f4cSDag-Erling Smørgrav tnp->nblk = nblk; 446*69d94f4cSDag-Erling Smørgrav tnp->blk = blk; 447*69d94f4cSDag-Erling Smørgrav tnp->size = realsize; 448*69d94f4cSDag-Erling Smørgrav return (0); 449*69d94f4cSDag-Erling Smørgrav syntax: 450*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s: syntax error in block map\n", __func__); 451*69d94f4cSDag-Erling Smørgrav bad: 452*69d94f4cSDag-Erling Smørgrav free(map, M_TARFSBLK); 453*69d94f4cSDag-Erling Smørgrav free(blk, M_TARFSBLK); 454*69d94f4cSDag-Erling Smørgrav return (EINVAL); 455*69d94f4cSDag-Erling Smørgrav } 456*69d94f4cSDag-Erling Smørgrav 457*69d94f4cSDag-Erling Smørgrav void 458*69d94f4cSDag-Erling Smørgrav tarfs_free_node(struct tarfs_node *tnp) 459*69d94f4cSDag-Erling Smørgrav { 460*69d94f4cSDag-Erling Smørgrav struct tarfs_mount *tmp; 461*69d94f4cSDag-Erling Smørgrav 462*69d94f4cSDag-Erling Smørgrav MPASS(tnp != NULL); 463*69d94f4cSDag-Erling Smørgrav tmp = tnp->tmp; 464*69d94f4cSDag-Erling Smørgrav 465*69d94f4cSDag-Erling Smørgrav switch (tnp->type) { 466*69d94f4cSDag-Erling Smørgrav case VLNK: 467*69d94f4cSDag-Erling Smørgrav if (tnp->link.name) 468*69d94f4cSDag-Erling Smørgrav free(tnp->link.name, M_TARFSNAME); 469*69d94f4cSDag-Erling Smørgrav break; 470*69d94f4cSDag-Erling Smørgrav default: 471*69d94f4cSDag-Erling Smørgrav break; 472*69d94f4cSDag-Erling Smørgrav } 473*69d94f4cSDag-Erling Smørgrav if (tnp->name != NULL) 474*69d94f4cSDag-Erling Smørgrav free(tnp->name, M_TARFSNAME); 475*69d94f4cSDag-Erling Smørgrav if (tnp->blk != NULL) 476*69d94f4cSDag-Erling Smørgrav free(tnp->blk, M_TARFSBLK); 477*69d94f4cSDag-Erling Smørgrav if (tnp->ino >= TARFS_MININO) 478*69d94f4cSDag-Erling Smørgrav free_unr(tmp->ino_unr, tnp->ino); 479*69d94f4cSDag-Erling Smørgrav free(tnp, M_TARFSNODE); 480*69d94f4cSDag-Erling Smørgrav tmp->nfiles--; 481*69d94f4cSDag-Erling Smørgrav } 482*69d94f4cSDag-Erling Smørgrav 483*69d94f4cSDag-Erling Smørgrav int 484*69d94f4cSDag-Erling Smørgrav tarfs_read_file(struct tarfs_node *tnp, size_t len, struct uio *uiop) 485*69d94f4cSDag-Erling Smørgrav { 486*69d94f4cSDag-Erling Smørgrav struct uio auio; 487*69d94f4cSDag-Erling Smørgrav size_t resid = len; 488*69d94f4cSDag-Erling Smørgrav size_t copylen; 489*69d94f4cSDag-Erling Smørgrav unsigned int i; 490*69d94f4cSDag-Erling Smørgrav int error; 491*69d94f4cSDag-Erling Smørgrav 492*69d94f4cSDag-Erling Smørgrav TARFS_DPF(VNODE, "%s(%s, %zu, %zu)\n", __func__, 493*69d94f4cSDag-Erling Smørgrav tnp->name, uiop->uio_offset, resid); 494*69d94f4cSDag-Erling Smørgrav for (i = 0; i < tnp->nblk && resid > 0; ++i) { 495*69d94f4cSDag-Erling Smørgrav if (uiop->uio_offset > tnp->blk[i].o + tnp->blk[i].l) { 496*69d94f4cSDag-Erling Smørgrav /* skip this block */ 497*69d94f4cSDag-Erling Smørgrav continue; 498*69d94f4cSDag-Erling Smørgrav } 499*69d94f4cSDag-Erling Smørgrav while (resid > 0 && 500*69d94f4cSDag-Erling Smørgrav uiop->uio_offset < tnp->blk[i].o) { 501*69d94f4cSDag-Erling Smørgrav /* move out some zeroes... */ 502*69d94f4cSDag-Erling Smørgrav copylen = tnp->blk[i].o - uiop->uio_offset; 503*69d94f4cSDag-Erling Smørgrav if (copylen > resid) 504*69d94f4cSDag-Erling Smørgrav copylen = resid; 505*69d94f4cSDag-Erling Smørgrav if (copylen > ZERO_REGION_SIZE) 506*69d94f4cSDag-Erling Smørgrav copylen = ZERO_REGION_SIZE; 507*69d94f4cSDag-Erling Smørgrav auio = *uiop; 508*69d94f4cSDag-Erling Smørgrav auio.uio_offset = 0; 509*69d94f4cSDag-Erling Smørgrav auio.uio_resid = copylen; 510*69d94f4cSDag-Erling Smørgrav error = uiomove(__DECONST(void *, zero_region), 511*69d94f4cSDag-Erling Smørgrav copylen, &auio); 512*69d94f4cSDag-Erling Smørgrav if (error != 0) 513*69d94f4cSDag-Erling Smørgrav return (error); 514*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s(%s) = zero %zu\n", __func__, 515*69d94f4cSDag-Erling Smørgrav tnp->name, copylen - auio.uio_resid); 516*69d94f4cSDag-Erling Smørgrav uiop->uio_offset += copylen - auio.uio_resid; 517*69d94f4cSDag-Erling Smørgrav uiop->uio_resid -= copylen - auio.uio_resid; 518*69d94f4cSDag-Erling Smørgrav resid -= copylen - auio.uio_resid; 519*69d94f4cSDag-Erling Smørgrav } 520*69d94f4cSDag-Erling Smørgrav while (resid > 0 && 521*69d94f4cSDag-Erling Smørgrav uiop->uio_offset < tnp->blk[i].o + tnp->blk[i].l) { 522*69d94f4cSDag-Erling Smørgrav /* now actual data */ 523*69d94f4cSDag-Erling Smørgrav copylen = tnp->blk[i].l; 524*69d94f4cSDag-Erling Smørgrav if (copylen > resid) 525*69d94f4cSDag-Erling Smørgrav copylen = resid; 526*69d94f4cSDag-Erling Smørgrav auio = *uiop; 527*69d94f4cSDag-Erling Smørgrav auio.uio_offset = tnp->offset + tnp->blk[i].i + 528*69d94f4cSDag-Erling Smørgrav uiop->uio_offset - tnp->blk[i].o; 529*69d94f4cSDag-Erling Smørgrav auio.uio_resid = copylen; 530*69d94f4cSDag-Erling Smørgrav error = tarfs_io_read(tnp->tmp, false, &auio); 531*69d94f4cSDag-Erling Smørgrav if (error != 0) 532*69d94f4cSDag-Erling Smørgrav return (error); 533*69d94f4cSDag-Erling Smørgrav TARFS_DPF(MAP, "%s(%s) = data %zu\n", __func__, 534*69d94f4cSDag-Erling Smørgrav tnp->name, copylen - auio.uio_resid); 535*69d94f4cSDag-Erling Smørgrav uiop->uio_offset += copylen - auio.uio_resid; 536*69d94f4cSDag-Erling Smørgrav uiop->uio_resid -= copylen - auio.uio_resid; 537*69d94f4cSDag-Erling Smørgrav resid -= copylen - auio.uio_resid; 538*69d94f4cSDag-Erling Smørgrav } 539*69d94f4cSDag-Erling Smørgrav } 540*69d94f4cSDag-Erling Smørgrav TARFS_DPF(VNODE, "%s(%s) = %zu\n", __func__, 541*69d94f4cSDag-Erling Smørgrav tnp->name, len - resid); 542*69d94f4cSDag-Erling Smørgrav return (0); 543*69d94f4cSDag-Erling Smørgrav } 544*69d94f4cSDag-Erling Smørgrav 545*69d94f4cSDag-Erling Smørgrav /* 546*69d94f4cSDag-Erling Smørgrav * XXX ugly file flag parser which could easily be a finite state machine 547*69d94f4cSDag-Erling Smørgrav * driven by a small precomputed table. 548*69d94f4cSDag-Erling Smørgrav * 549*69d94f4cSDag-Erling Smørgrav * Note that unlike strtofflags(3), we make no attempt to handle negated 550*69d94f4cSDag-Erling Smørgrav * flags, since they shouldn't appear in tar files. 551*69d94f4cSDag-Erling Smørgrav */ 552*69d94f4cSDag-Erling Smørgrav static const struct tarfs_flag { 553*69d94f4cSDag-Erling Smørgrav const char *name; 554*69d94f4cSDag-Erling Smørgrav unsigned int flag; 555*69d94f4cSDag-Erling Smørgrav } tarfs_flags[] = { 556*69d94f4cSDag-Erling Smørgrav { "nodump", UF_NODUMP }, 557*69d94f4cSDag-Erling Smørgrav { "uchg", UF_IMMUTABLE }, 558*69d94f4cSDag-Erling Smørgrav { "uappnd", UF_APPEND }, 559*69d94f4cSDag-Erling Smørgrav { "opaque", UF_OPAQUE }, 560*69d94f4cSDag-Erling Smørgrav { "uunlnk", UF_NOUNLINK }, 561*69d94f4cSDag-Erling Smørgrav { "arch", SF_ARCHIVED }, 562*69d94f4cSDag-Erling Smørgrav { "schg", SF_IMMUTABLE }, 563*69d94f4cSDag-Erling Smørgrav { "sappnd", SF_APPEND }, 564*69d94f4cSDag-Erling Smørgrav { "sunlnk", SF_NOUNLINK }, 565*69d94f4cSDag-Erling Smørgrav { NULL, 0 }, 566*69d94f4cSDag-Erling Smørgrav }; 567*69d94f4cSDag-Erling Smørgrav 568*69d94f4cSDag-Erling Smørgrav unsigned int 569*69d94f4cSDag-Erling Smørgrav tarfs_strtofflags(const char *str, char **end) 570*69d94f4cSDag-Erling Smørgrav { 571*69d94f4cSDag-Erling Smørgrav const struct tarfs_flag *tf; 572*69d94f4cSDag-Erling Smørgrav const char *p, *q; 573*69d94f4cSDag-Erling Smørgrav unsigned int ret; 574*69d94f4cSDag-Erling Smørgrav 575*69d94f4cSDag-Erling Smørgrav ret = 0; 576*69d94f4cSDag-Erling Smørgrav for (p = q = str; *q != '\0'; p = q + 1) { 577*69d94f4cSDag-Erling Smørgrav for (q = p; *q != '\0' && *q != ','; ++q) { 578*69d94f4cSDag-Erling Smørgrav if (*q < 'a' || *q > 'z') { 579*69d94f4cSDag-Erling Smørgrav goto end; 580*69d94f4cSDag-Erling Smørgrav } 581*69d94f4cSDag-Erling Smørgrav /* nothing */ 582*69d94f4cSDag-Erling Smørgrav } 583*69d94f4cSDag-Erling Smørgrav for (tf = tarfs_flags; tf->name != NULL; tf++) { 584*69d94f4cSDag-Erling Smørgrav if (strncmp(tf->name, p, q - p) == 0 && 585*69d94f4cSDag-Erling Smørgrav tf->name[q - p] == '\0') { 586*69d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: %.*s = 0x%06x\n", __func__, 587*69d94f4cSDag-Erling Smørgrav (int)(q - p), p, tf->flag); 588*69d94f4cSDag-Erling Smørgrav ret |= tf->flag; 589*69d94f4cSDag-Erling Smørgrav break; 590*69d94f4cSDag-Erling Smørgrav } 591*69d94f4cSDag-Erling Smørgrav } 592*69d94f4cSDag-Erling Smørgrav if (tf->name == NULL) { 593*69d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: %.*s = 0x??????\n", 594*69d94f4cSDag-Erling Smørgrav __func__, (int)(q - p), p); 595*69d94f4cSDag-Erling Smørgrav goto end; 596*69d94f4cSDag-Erling Smørgrav } 597*69d94f4cSDag-Erling Smørgrav } 598*69d94f4cSDag-Erling Smørgrav end: 599*69d94f4cSDag-Erling Smørgrav if (*end != NULL) { 600*69d94f4cSDag-Erling Smørgrav *end = __DECONST(char *, q); 601*69d94f4cSDag-Erling Smørgrav } 602*69d94f4cSDag-Erling Smørgrav return (ret); 603*69d94f4cSDag-Erling Smørgrav } 604