| File: | src/sbin/newfs_ext2fs/mke2fs.c |
| Warning: | line 325, column 30 Division by zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: mke2fs.c,v 1.18 2019/07/01 07:17:26 kevlo Exp $ */ | |||
| 2 | /* $NetBSD: mke2fs.c,v 1.13 2009/10/19 18:41:08 bouyer Exp $ */ | |||
| 3 | ||||
| 4 | /*- | |||
| 5 | * Copyright (c) 2007 Izumi Tsutsui. All rights reserved. | |||
| 6 | * | |||
| 7 | * Redistribution and use in source and binary forms, with or without | |||
| 8 | * modification, are permitted provided that the following conditions | |||
| 9 | * are met: | |||
| 10 | * 1. Redistributions of source code must retain the above copyright | |||
| 11 | * notice, this list of conditions and the following disclaimer. | |||
| 12 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 13 | * notice, this list of conditions and the following disclaimer in the | |||
| 14 | * documentation and/or other materials provided with the distribution. | |||
| 15 | * | |||
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
| 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
| 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
| 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
| 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 26 | */ | |||
| 27 | ||||
| 28 | /* | |||
| 29 | * Copyright (c) 1980, 1989, 1993 | |||
| 30 | * The Regents of the University of California. All rights reserved. | |||
| 31 | * | |||
| 32 | * Redistribution and use in source and binary forms, with or without | |||
| 33 | * modification, are permitted provided that the following conditions | |||
| 34 | * are met: | |||
| 35 | * 1. Redistributions of source code must retain the above copyright | |||
| 36 | * notice, this list of conditions and the following disclaimer. | |||
| 37 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 38 | * notice, this list of conditions and the following disclaimer in the | |||
| 39 | * documentation and/or other materials provided with the distribution. | |||
| 40 | * 3. Neither the name of the University nor the names of its contributors | |||
| 41 | * may be used to endorse or promote products derived from this software | |||
| 42 | * without specific prior written permission. | |||
| 43 | * | |||
| 44 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 45 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 47 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 48 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 49 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 50 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 52 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 53 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 54 | * SUCH DAMAGE. | |||
| 55 | */ | |||
| 56 | ||||
| 57 | /* | |||
| 58 | * Copyright (c) 1997 Manuel Bouyer. | |||
| 59 | * | |||
| 60 | * Redistribution and use in source and binary forms, with or without | |||
| 61 | * modification, are permitted provided that the following conditions | |||
| 62 | * are met: | |||
| 63 | * 1. Redistributions of source code must retain the above copyright | |||
| 64 | * notice, this list of conditions and the following disclaimer. | |||
| 65 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 66 | * notice, this list of conditions and the following disclaimer in the | |||
| 67 | * documentation and/or other materials provided with the distribution. | |||
| 68 | * | |||
| 69 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
| 70 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| 71 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
| 72 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
| 73 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
| 74 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| 75 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| 76 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| 77 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
| 78 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 79 | */ | |||
| 80 | ||||
| 81 | /* | |||
| 82 | * mke2fs.c: "re-invent (dumb but non-GPLed) wheel as a fun project" | |||
| 83 | * | |||
| 84 | * In spite of this name, there is no piece of code | |||
| 85 | * derived from GPLed e2fsprogs written for Linux. | |||
| 86 | * I referred them only to see how each structure | |||
| 87 | * member should be initialized. | |||
| 88 | * | |||
| 89 | * Reference: | |||
| 90 | * - All NetBSD sources under src/sys/ufs/ext2fs and src/sbin/fsck_ext2fs | |||
| 91 | * - Ext2fs Home Page | |||
| 92 | * http://e2fsprogs.sourceforge.net/ext2.html | |||
| 93 | * - Design and Implementation of the Second Extended Filesystem | |||
| 94 | * http://e2fsprogs.sourceforge.net/ext2intro.html | |||
| 95 | * - Linux Documentation "The Second Extended Filesystem" | |||
| 96 | * src/linux/Documentation/filesystems/ext2.txt | |||
| 97 | * in the Linux kernel distribution | |||
| 98 | */ | |||
| 99 | ||||
| 100 | #include <sys/param.h> /* MAXBSIZE powerof2 roundup setbit isset MIN */ | |||
| 101 | #include <sys/types.h> | |||
| 102 | #include <sys/mman.h> | |||
| 103 | #include <sys/time.h> | |||
| 104 | #include <ufs/ext2fs/ext2fs_dinode.h> | |||
| 105 | #include <ufs/ext2fs/ext2fs_dir.h> | |||
| 106 | #include <ufs/ext2fs/ext2fs.h> | |||
| 107 | #include <sys/ioctl.h> | |||
| 108 | ||||
| 109 | #include <err.h> | |||
| 110 | #include <errno(*__errno()).h> | |||
| 111 | #include <inttypes.h> | |||
| 112 | #include <string.h> | |||
| 113 | #include <unistd.h> | |||
| 114 | #include <stdint.h> | |||
| 115 | #include <stdlib.h> | |||
| 116 | #include <stddef.h> | |||
| 117 | #include <stdio.h> | |||
| 118 | ||||
| 119 | #include "extern.h" | |||
| 120 | ||||
| 121 | static void initcg(uint); | |||
| 122 | static void zap_old_sblock(daddr32_t); | |||
| 123 | static uint cgoverhead(uint); | |||
| 124 | static int fsinit(const struct timeval *); | |||
| 125 | static int makedir(struct ext2fs_direct *, int); | |||
| 126 | static void copy_dir(struct ext2fs_direct *, struct ext2fs_direct *); | |||
| 127 | static void init_resizeino(const struct timeval *); | |||
| 128 | static uint32_t alloc(uint32_t, uint16_t); | |||
| 129 | static void iput(struct ext2fs_dinode *, ino_t); | |||
| 130 | static void rdfs(daddr32_t, int, void *); | |||
| 131 | static void wtfs(daddr32_t, int, void *); | |||
| 132 | static int ilog2(uint); | |||
| 133 | static int skpc(int, size_t, uint8_t *); | |||
| 134 | static void uuid_get(struct m_ext2fs *); | |||
| 135 | ||||
| 136 | /* XXX: some of these macro should be into <ufs/ext2fs/ext2fs.h>? */ | |||
| 137 | #define EXT2_DEF_MAX_MNT_COUNT20 20 | |||
| 138 | #define EXT2_DEF_FSCKINTV(180 * 24 * 60 * 60) (180 * 24 * 60 * 60) /* 180 days */ | |||
| 139 | #define EXT2_RESERVED_INODES(((ufsino_t)11) - 1) (EXT2_FIRSTINO((ufsino_t)11) - 1) | |||
| 140 | #define EXT2_UMASK0755 0755 | |||
| 141 | ||||
| 142 | #define EXT2_INO_INDEX(ino)((ino) - 1) ((ino) - 1) /* no inode zero */ | |||
| 143 | ||||
| 144 | #define EXT2_LOSTFOUNDSIZE16384 16384 | |||
| 145 | #define EXT2_LOSTFOUNDINO((ufsino_t)11) EXT2_FIRSTINO((ufsino_t)11) /* XXX: not quite */ | |||
| 146 | #define EXT2_LOSTFOUNDUMASK0700 0700 | |||
| 147 | ||||
| 148 | #define EXT2_RESIZEINOUMASK0600 0600 | |||
| 149 | ||||
| 150 | #define NBLOCK_SUPERBLOCK1 1 | |||
| 151 | #define NBLOCK_BLOCK_BITMAP1 1 | |||
| 152 | #define NBLOCK_INODE_BITMAP1 1 | |||
| 153 | ||||
| 154 | #define cgbase(fs, c)((fs)->e2fs.e2fs_first_dblock + (fs)->e2fs.e2fs_bpg * ( c)) \ | |||
| 155 | ((fs)->e2fs.e2fs_first_dblock + (fs)->e2fs.e2fs_bpg * (c)) | |||
| 156 | ||||
| 157 | #define rounddown(x,y)(((x)/(y))*(y)) (((x)/(y))*(y)) | |||
| 158 | ||||
| 159 | /* | |||
| 160 | * ext2fs super block and group descriptor structures | |||
| 161 | * | |||
| 162 | * We don't have to use or setup whole in-memory m_ext2fs structure, | |||
| 163 | * but prepare it to use several macro defined in kernel headers. | |||
| 164 | */ | |||
| 165 | union { | |||
| 166 | struct m_ext2fs m_ext2fs; | |||
| 167 | char pad[SBSIZE1024]; | |||
| 168 | } ext2fsun; | |||
| 169 | #define sblockext2fsun.m_ext2fs ext2fsun.m_ext2fs | |||
| 170 | #define gdext2fsun.m_ext2fs.e2fs_gd ext2fsun.m_ext2fs.e2fs_gd | |||
| 171 | ||||
| 172 | static uint8_t *iobuf; /* for superblock and group descriptors */ | |||
| 173 | static int iobufsize; | |||
| 174 | ||||
| 175 | static uint8_t buf[MAXBSIZE(64 * 1024)]; /* for initcg() and makedir() ops */ | |||
| 176 | ||||
| 177 | static int fd; | |||
| 178 | ||||
| 179 | extern int max_cols; | |||
| 180 | ||||
| 181 | void | |||
| 182 | mke2fs(const char *fsys, int f) | |||
| 183 | { | |||
| 184 | struct timeval tv; | |||
| 185 | int64_t minfssize; | |||
| 186 | uint bcount, fbcount, ficount; | |||
| 187 | uint blocks_gd, blocks_per_cg, inodes_per_cg, iblocks_per_cg; | |||
| 188 | uint minblocks_per_cg, blocks_lastcg; | |||
| 189 | uint ncg, cylno, sboff; | |||
| 190 | int i, len, col, delta, fld_width; | |||
| 191 | ||||
| 192 | gettimeofday(&tv, NULL((void*)0)); | |||
| 193 | fd = f; | |||
| 194 | ||||
| 195 | /* | |||
| 196 | * collect and verify the block and fragment sizes | |||
| 197 | */ | |||
| 198 | if (!powerof2(bsize)((((bsize)-1)&(bsize))==0)) { | |||
| ||||
| 199 | errx(EXIT_FAILURE1, | |||
| 200 | "block size must be a power of 2, not %u\n", | |||
| 201 | bsize); | |||
| 202 | } | |||
| 203 | if (!powerof2(fsize)((((fsize)-1)&(fsize))==0)) { | |||
| 204 | errx(EXIT_FAILURE1, | |||
| 205 | "fragment size must be a power of 2, not %u\n", | |||
| 206 | fsize); | |||
| 207 | } | |||
| 208 | if (fsize < sectorsize) { | |||
| 209 | errx(EXIT_FAILURE1, | |||
| 210 | "fragment size %u is too small, minimum is %u\n", | |||
| 211 | fsize, sectorsize); | |||
| 212 | } | |||
| 213 | if (bsize < MINBSIZE(1 << 10)) { | |||
| 214 | errx(EXIT_FAILURE1, | |||
| 215 | "block size %u is too small, minimum is %u\n", | |||
| 216 | bsize, MINBSIZE(1 << 10)); | |||
| 217 | } | |||
| 218 | if (bsize > EXT2_MAXBSIZE(1 << 12)) { | |||
| 219 | errx(EXIT_FAILURE1, | |||
| 220 | "block size %u is too large, maximum is %u\n", | |||
| 221 | bsize, MAXBSIZE(64 * 1024)); | |||
| 222 | } | |||
| 223 | if (bsize != fsize) { | |||
| 224 | /* | |||
| 225 | * There is no fragment support on current ext2fs (yet?), | |||
| 226 | * but some kernel code refers fsize or fpg as bsize or bpg | |||
| 227 | * and Linux seems to set the same values to them. | |||
| 228 | */ | |||
| 229 | errx(EXIT_FAILURE1, | |||
| 230 | "block size (%u) can't be different from " | |||
| 231 | "fragment size (%u)\n", | |||
| 232 | bsize, fsize); | |||
| 233 | } | |||
| 234 | ||||
| 235 | /* variable inodesize is REV1 feature */ | |||
| 236 | if (Oflag == 0 && inodesize != EXT2_REV0_DINODE_SIZE128) { | |||
| 237 | errx(EXIT_FAILURE1, "GOOD_OLD_REV file system format" | |||
| 238 | " doesn't support %d byte inode\n", inodesize); | |||
| 239 | } | |||
| 240 | ||||
| 241 | sblockext2fsun.m_ext2fs.e2fs.e2fs_log_bsize = ilog2(bsize) - LOG_MINBSIZE10; | |||
| 242 | sblockext2fsun.m_ext2fs.e2fs.e2fs_log_fsize = ilog2(fsize) - LOG_MINFSIZE10; | |||
| 243 | ||||
| 244 | sblockext2fsun.m_ext2fs.e2fs_bsize = bsize; | |||
| 245 | sblockext2fsun.m_ext2fs.e2fs_fsize = fsize; | |||
| 246 | sblockext2fsun.m_ext2fs.e2fs_bshift = sblockext2fsun.m_ext2fs.e2fs.e2fs_log_bsize + LOG_MINBSIZE10; | |||
| 247 | sblockext2fsun.m_ext2fs.e2fs_qbmask = sblockext2fsun.m_ext2fs.e2fs_bsize - 1; | |||
| 248 | sblockext2fsun.m_ext2fs.e2fs_bmask = ~sblockext2fsun.m_ext2fs.e2fs_qbmask; | |||
| 249 | sblockext2fsun.m_ext2fs.e2fs_fsbtodb = ilog2(sblockext2fsun.m_ext2fs.e2fs_bsize) - ilog2(sectorsize); | |||
| 250 | sblockext2fsun.m_ext2fs.e2fs_ipb = sblockext2fsun.m_ext2fs.e2fs_bsize / inodesize; | |||
| 251 | ||||
| 252 | /* | |||
| 253 | * Ext2fs preserves BBSIZE (1024 bytes) space at the top for | |||
| 254 | * bootloader (though it is not enough at all for our bootloader). | |||
| 255 | * If bsize == BBSIZE we have to preserve one block. | |||
| 256 | * If bsize > BBSIZE, the first block already contains BBSIZE space | |||
| 257 | * before superblock because superblock is allocated at SBOFF and | |||
| 258 | * bsize is a power of two (i.e. 2048 bytes or more). | |||
| 259 | */ | |||
| 260 | sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock = (sblockext2fsun.m_ext2fs.e2fs_bsize > BBSIZE1024) ? 0 : 1; | |||
| 261 | minfssize = fsbtodb(&sblock,((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 262 | sblock.e2fs.e2fs_first_dblock +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 263 | NBLOCK_SUPERBLOCK +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 264 | 1 /* at least one group descriptor */ +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 265 | NBLOCK_BLOCK_BITMAP +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 266 | NBLOCK_INODE_BITMAP +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 267 | 1 /* at least one inode table block */ +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 268 | 1 /* at least one data block for rootdir */ +((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 269 | 1 /* at least one data block for data */((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb) | |||
| 270 | )((ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + 1 + 1 + 1 + 1 + 1 + 1 + 1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); /* XXX and more? */ | |||
| 271 | ||||
| 272 | if (fssize < minfssize) | |||
| 273 | errx(EXIT_FAILURE1, "Filesystem size %" PRId64"lld" | |||
| 274 | " < minimum size of %" PRId64"lld" "\n", fssize, minfssize); | |||
| 275 | ||||
| 276 | bcount = dbtofsb(&sblock, fssize)((fssize) >> (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
| 277 | ||||
| 278 | /* | |||
| 279 | * While many people claim that ext2fs is a (bad) clone of ufs/ffs, | |||
| 280 | * it isn't actual ffs so maybe we should call it "block group" | |||
| 281 | * as their native name rather than ffs derived "cylinder group." | |||
| 282 | * But we'll use the latter here since other kernel sources use it. | |||
| 283 | * (I also agree "cylinder" based allocation is obsolete though) | |||
| 284 | */ | |||
| 285 | ||||
| 286 | /* maybe "simple is the best" */ | |||
| 287 | blocks_per_cg = sblockext2fsun.m_ext2fs.e2fs_bsize * NBBY8; | |||
| 288 | ||||
| 289 | ncg = howmany(bcount - sblock.e2fs.e2fs_first_dblock, blocks_per_cg)(((bcount - ext2fsun.m_ext2fs.e2fs.e2fs_first_dblock) + ((blocks_per_cg ) - 1)) / (blocks_per_cg)); | |||
| 290 | blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize)(((sizeof(struct ext2_gd) * ncg) + ((bsize) - 1)) / (bsize)); | |||
| 291 | ||||
| 292 | /* check range of inode number */ | |||
| 293 | if (num_inodes < EXT2_FIRSTINO((ufsino_t)11)) | |||
| 294 | num_inodes = EXT2_FIRSTINO((ufsino_t)11); /* needs reserved inodes + 1 */ | |||
| 295 | if (num_inodes > UINT16_MAX0xffff * ncg) | |||
| 296 | num_inodes = UINT16_MAX0xffff * ncg; /* ext2bgd_nifree is uint16_t */ | |||
| 297 | ||||
| 298 | inodes_per_cg = num_inodes / ncg; | |||
| 299 | iblocks_per_cg = howmany(inodesize * inodes_per_cg, bsize)(((inodesize * inodes_per_cg) + ((bsize) - 1)) / (bsize)); | |||
| 300 | ||||
| 301 | /* Check that the last cylinder group has enough space for inodes */ | |||
| 302 | minblocks_per_cg = | |||
| 303 | NBLOCK_BLOCK_BITMAP1 + | |||
| 304 | NBLOCK_INODE_BITMAP1 + | |||
| 305 | iblocks_per_cg + | |||
| 306 | 1; /* at least one data block */ | |||
| 307 | if (Oflag
| |||
| 308 | minblocks_per_cg += NBLOCK_SUPERBLOCK1 + blocks_gd; | |||
| 309 | ||||
| 310 | blocks_lastcg = bcount - sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock - | |||
| 311 | blocks_per_cg * (ncg - 1); | |||
| 312 | if (blocks_lastcg < minblocks_per_cg) { | |||
| 313 | /* | |||
| 314 | * Since we make all the cylinder groups the same size, the | |||
| 315 | * last will only be small if there are more than one | |||
| 316 | * cylinder groups. If the last one is too small to store | |||
| 317 | * filesystem data, just kill it. | |||
| 318 | * | |||
| 319 | * XXX: Does fsck_ext2fs(8) properly handle this case? | |||
| 320 | */ | |||
| 321 | bcount -= blocks_lastcg; | |||
| 322 | ncg--; | |||
| 323 | blocks_lastcg = blocks_per_cg; | |||
| 324 | blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize)(((sizeof(struct ext2_gd) * ncg) + ((bsize) - 1)) / (bsize)); | |||
| 325 | inodes_per_cg = num_inodes / ncg; | |||
| ||||
| 326 | } | |||
| 327 | /* roundup inodes_per_cg to make it use whole inode table blocks */ | |||
| 328 | inodes_per_cg = roundup(inodes_per_cg, sblock.e2fs_ipb)((((inodes_per_cg)+((ext2fsun.m_ext2fs.e2fs_ipb)-1))/(ext2fsun .m_ext2fs.e2fs_ipb))*(ext2fsun.m_ext2fs.e2fs_ipb)); | |||
| 329 | num_inodes = inodes_per_cg * ncg; | |||
| 330 | iblocks_per_cg = inodes_per_cg / sblockext2fsun.m_ext2fs.e2fs_ipb; | |||
| 331 | ||||
| 332 | /* XXX: probably we should check these adjusted values again */ | |||
| 333 | ||||
| 334 | sblockext2fsun.m_ext2fs.e2fs.e2fs_bcount = bcount; | |||
| 335 | sblockext2fsun.m_ext2fs.e2fs.e2fs_icount = num_inodes; | |||
| 336 | ||||
| 337 | sblockext2fsun.m_ext2fs.e2fs_ncg = ncg; | |||
| 338 | sblockext2fsun.m_ext2fs.e2fs_ngdb = blocks_gd; | |||
| 339 | sblockext2fsun.m_ext2fs.e2fs_itpg = iblocks_per_cg; | |||
| 340 | ||||
| 341 | sblockext2fsun.m_ext2fs.e2fs.e2fs_rbcount = sblockext2fsun.m_ext2fs.e2fs.e2fs_bcount * minfree / 100; | |||
| 342 | /* e2fs_fbcount will be accounted later */ | |||
| 343 | /* e2fs_ficount will be accounted later */ | |||
| 344 | ||||
| 345 | sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg = blocks_per_cg; | |||
| 346 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fpg = blocks_per_cg; | |||
| 347 | ||||
| 348 | sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg = inodes_per_cg; | |||
| 349 | ||||
| 350 | sblockext2fsun.m_ext2fs.e2fs.e2fs_mtime = 0; | |||
| 351 | sblockext2fsun.m_ext2fs.e2fs.e2fs_wtime = (u_int32_t)tv.tv_sec; | |||
| 352 | sblockext2fsun.m_ext2fs.e2fs.e2fs_mnt_count = 0; | |||
| 353 | /* XXX: should add some entropy to avoid checking all fs at once? */ | |||
| 354 | sblockext2fsun.m_ext2fs.e2fs.e2fs_max_mnt_count = EXT2_DEF_MAX_MNT_COUNT20; | |||
| 355 | ||||
| 356 | sblockext2fsun.m_ext2fs.e2fs.e2fs_magic = E2FS_MAGIC0xef53; | |||
| 357 | sblockext2fsun.m_ext2fs.e2fs.e2fs_state = E2FS_ISCLEAN0x01; | |||
| 358 | sblockext2fsun.m_ext2fs.e2fs.e2fs_beh = E2FS_BEH_DEFAULT1; | |||
| 359 | sblockext2fsun.m_ext2fs.e2fs.e2fs_minrev = 0; | |||
| 360 | sblockext2fsun.m_ext2fs.e2fs.e2fs_lastfsck = (u_int32_t)tv.tv_sec; | |||
| 361 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fsckintv = EXT2_DEF_FSCKINTV(180 * 24 * 60 * 60); | |||
| 362 | ||||
| 363 | /* | |||
| 364 | * Maybe we can use E2FS_OS_FREEBSD here and it would be more proper, | |||
| 365 | * but the purpose of this newfs_ext2fs(8) command is to provide | |||
| 366 | * a filesystem which can be recognized by firmware on some | |||
| 367 | * Linux based appliances that can load bootstrap files only from | |||
| 368 | * (their native) ext2fs, and anyway we will (and should) try to | |||
| 369 | * act like them as much as possible. | |||
| 370 | * | |||
| 371 | * Anyway, I hope that all newer such boxes will keep their support | |||
| 372 | * for the "GOOD_OLD_REV" ext2fs. | |||
| 373 | */ | |||
| 374 | sblockext2fsun.m_ext2fs.e2fs.e2fs_creator = E2FS_OS_LINUX0; | |||
| 375 | ||||
| 376 | if (Oflag == 0) { | |||
| 377 | sblockext2fsun.m_ext2fs.e2fs.e2fs_rev = E2FS_REV00; | |||
| 378 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat = 0; | |||
| 379 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_incompat = 0; | |||
| 380 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat = 0; | |||
| 381 | } else { | |||
| 382 | sblockext2fsun.m_ext2fs.e2fs.e2fs_rev = E2FS_REV11; | |||
| 383 | /* | |||
| 384 | * e2fsprogs say "REV1" is "dynamic" so | |||
| 385 | * it isn't quite a version and maybe it means | |||
| 386 | * "extended from REV0 so check compat features." | |||
| 387 | * | |||
| 388 | * XXX: We don't have any native tool to activate | |||
| 389 | * the EXT2F_COMPAT_RESIZE feature and | |||
| 390 | * fsck_ext2fs(8) might not fix structures for it. | |||
| 391 | */ | |||
| 392 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat = EXT2F_COMPAT_RESIZE0x0010; | |||
| 393 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_incompat = EXT2F_INCOMPAT_FTYPE0x0002; | |||
| 394 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat = | |||
| 395 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001 | EXT2F_ROCOMPAT_LARGE_FILE0x0002; | |||
| 396 | } | |||
| 397 | ||||
| 398 | sblockext2fsun.m_ext2fs.e2fs.e2fs_ruid = geteuid(); | |||
| 399 | sblockext2fsun.m_ext2fs.e2fs.e2fs_rgid = getegid(); | |||
| 400 | ||||
| 401 | sblockext2fsun.m_ext2fs.e2fs.e2fs_first_ino = EXT2_FIRSTINO((ufsino_t)11); | |||
| 402 | sblockext2fsun.m_ext2fs.e2fs.e2fs_inode_size = inodesize; | |||
| 403 | ||||
| 404 | /* e2fs_block_group_nr is set on writing superblock to each group */ | |||
| 405 | ||||
| 406 | uuid_get(&sblockext2fsun.m_ext2fs); | |||
| 407 | if (volname != NULL((void*)0)) { | |||
| 408 | if (strlen(volname) > sizeof(sblockext2fsun.m_ext2fs.e2fs.e2fs_vname)) | |||
| 409 | errx(EXIT_FAILURE1, "Volume name is too long"); | |||
| 410 | strlcpy(sblockext2fsun.m_ext2fs.e2fs.e2fs_vname, volname, | |||
| 411 | sizeof(sblockext2fsun.m_ext2fs.e2fs.e2fs_vname)); | |||
| 412 | } | |||
| 413 | ||||
| 414 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fsmnt[0] = '\0'; | |||
| 415 | sblockext2fsun.m_ext2fs.e2fs_fsmnt[0] = '\0'; | |||
| 416 | ||||
| 417 | sblockext2fsun.m_ext2fs.e2fs.e2fs_algo = 0; /* XXX unsupported? */ | |||
| 418 | sblockext2fsun.m_ext2fs.e2fs.e2fs_prealloc = 0; /* XXX unsupported? */ | |||
| 419 | sblockext2fsun.m_ext2fs.e2fs.e2fs_dir_prealloc = 0; /* XXX unsupported? */ | |||
| 420 | ||||
| 421 | /* calculate blocks for reserved group descriptors for resize */ | |||
| 422 | sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb = 0; | |||
| 423 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
| 424 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE0x0010) != 0) { | |||
| 425 | uint64_t target_blocks; | |||
| 426 | uint target_ncg, target_ngdb, reserved_ngdb; | |||
| 427 | ||||
| 428 | /* reserve descriptors for size as 1024 times as current */ | |||
| 429 | target_blocks = | |||
| 430 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_bcount - sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock) | |||
| 431 | * 1024ULL; | |||
| 432 | /* number of blocks must be in uint32_t */ | |||
| 433 | if (target_blocks > UINT32_MAX0xffffffffU) | |||
| 434 | target_blocks = UINT32_MAX0xffffffffU; | |||
| 435 | target_ncg = howmany(target_blocks, sblock.e2fs.e2fs_bpg)(((target_blocks) + ((ext2fsun.m_ext2fs.e2fs.e2fs_bpg) - 1)) / (ext2fsun.m_ext2fs.e2fs.e2fs_bpg)); | |||
| 436 | target_ngdb = howmany(sizeof(struct ext2_gd) * target_ncg,(((sizeof(struct ext2_gd) * target_ncg) + ((ext2fsun.m_ext2fs .e2fs_bsize) - 1)) / (ext2fsun.m_ext2fs.e2fs_bsize)) | |||
| 437 | sblock.e2fs_bsize)(((sizeof(struct ext2_gd) * target_ncg) + ((ext2fsun.m_ext2fs .e2fs_bsize) - 1)) / (ext2fsun.m_ext2fs.e2fs_bsize)); | |||
| 438 | /* | |||
| 439 | * Reserved group descriptor blocks are preserved as | |||
| 440 | * the second level double indirect reference blocks in | |||
| 441 | * the EXT2_RESIZEINO inode, so the maximum number of | |||
| 442 | * the blocks is NINDIR(fs). | |||
| 443 | * (see also descriptions in init_resizeino() function) | |||
| 444 | * | |||
| 445 | * We check a number including current e2fs_ngdb here | |||
| 446 | * because they will be moved into reserved gdb on | |||
| 447 | * possible future size shrink, though e2fsprogs don't | |||
| 448 | * seem to care about it. | |||
| 449 | */ | |||
| 450 | if (target_ngdb > NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t))) | |||
| 451 | target_ngdb = NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)); | |||
| 452 | ||||
| 453 | reserved_ngdb = target_ngdb - sblockext2fsun.m_ext2fs.e2fs_ngdb; | |||
| 454 | ||||
| 455 | /* make sure reserved_ngdb fits in the last cg */ | |||
| 456 | if (reserved_ngdb >= blocks_lastcg - cgoverhead(ncg - 1)) | |||
| 457 | reserved_ngdb = blocks_lastcg - cgoverhead(ncg - 1); | |||
| 458 | if (reserved_ngdb == 0) { | |||
| 459 | /* if no space for reserved gdb, disable the feature */ | |||
| 460 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat &= | |||
| 461 | ~EXT2F_COMPAT_RESIZE0x0010; | |||
| 462 | } | |||
| 463 | sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb = reserved_ngdb; | |||
| 464 | } | |||
| 465 | ||||
| 466 | /* | |||
| 467 | * Initialize group descriptors | |||
| 468 | */ | |||
| 469 | gdext2fsun.m_ext2fs.e2fs_gd = calloc(sblockext2fsun.m_ext2fs.e2fs_ngdb, bsize); | |||
| 470 | if (gdext2fsun.m_ext2fs.e2fs_gd == NULL((void*)0)) | |||
| 471 | errx(EXIT_FAILURE1, "Can't allocate descriptors buffer"); | |||
| 472 | ||||
| 473 | fbcount = 0; | |||
| 474 | ficount = 0; | |||
| 475 | for (cylno = 0; cylno < ncg; cylno++) { | |||
| 476 | uint boffset; | |||
| 477 | ||||
| 478 | boffset = cgbase(&sblock, cylno)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno)); | |||
| 479 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev == E2FS_REV00 || | |||
| 480 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
| 481 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) == 0 || | |||
| 482 | cg_has_sb(cylno)) { | |||
| 483 | boffset += NBLOCK_SUPERBLOCK1 + sblockext2fsun.m_ext2fs.e2fs_ngdb; | |||
| 484 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
| 485 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat & | |||
| 486 | EXT2F_COMPAT_RESIZE0x0010) != 0) | |||
| 487 | boffset += sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb; | |||
| 488 | } | |||
| 489 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_b_bitmap = boffset; | |||
| 490 | boffset += NBLOCK_BLOCK_BITMAP1; | |||
| 491 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_i_bitmap = boffset; | |||
| 492 | boffset += NBLOCK_INODE_BITMAP1; | |||
| 493 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_i_tables = boffset; | |||
| 494 | if (cylno == (ncg - 1)) | |||
| 495 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nbfree = | |||
| 496 | blocks_lastcg - cgoverhead(cylno); | |||
| 497 | else | |||
| 498 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nbfree = | |||
| 499 | sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg - cgoverhead(cylno); | |||
| 500 | fbcount += gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nbfree; | |||
| 501 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nifree = sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg; | |||
| 502 | if (cylno == 0) { | |||
| 503 | /* take reserved inodes off nifree */ | |||
| 504 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nifree -= EXT2_RESERVED_INODES(((ufsino_t)11) - 1); | |||
| 505 | } | |||
| 506 | ficount += gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_nifree; | |||
| 507 | gdext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_ndirs = 0; | |||
| 508 | } | |||
| 509 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fbcount = fbcount; | |||
| 510 | sblockext2fsun.m_ext2fs.e2fs.e2fs_ficount = ficount; | |||
| 511 | ||||
| 512 | /* | |||
| 513 | * Dump out summary information about file system. | |||
| 514 | */ | |||
| 515 | if (verbosity > 0) { | |||
| 516 | printf("%s: %u.%1uMB (%" PRId64"lld" " sectors) " | |||
| 517 | "block size %u, fragment size %u\n", | |||
| 518 | fsys, | |||
| 519 | (uint)(((uint64_t)bcount * bsize) / (1024 * 1024)), | |||
| 520 | (uint)((uint64_t)bcount * bsize - | |||
| 521 | rounddown((uint64_t)bcount * bsize, 1024 * 1024)((((uint64_t)bcount * bsize)/(1024 * 1024))*(1024 * 1024))) | |||
| 522 | / 1024 / 100, | |||
| 523 | fssize, bsize, fsize); | |||
| 524 | printf("\tusing %u block groups of %u.0MB, %u blks, " | |||
| 525 | "%u inodes.\n", | |||
| 526 | ncg, bsize * sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg / (1024 * 1024), | |||
| 527 | sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg, sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg); | |||
| 528 | } | |||
| 529 | ||||
| 530 | /* | |||
| 531 | * allocate space for superblock and group descriptors | |||
| 532 | */ | |||
| 533 | iobufsize = (NBLOCK_SUPERBLOCK1 + sblockext2fsun.m_ext2fs.e2fs_ngdb) * sblockext2fsun.m_ext2fs.e2fs_bsize; | |||
| 534 | iobuf = mmap(0, iobufsize, PROT_READ0x01|PROT_WRITE0x02, | |||
| 535 | MAP_ANON0x1000|MAP_PRIVATE0x0002, -1, 0); | |||
| 536 | if (iobuf == MAP_FAILED((void *)-1)) | |||
| 537 | errx(EXIT_FAILURE1, "Cannot allocate I/O buffer\n"); | |||
| 538 | ||||
| 539 | /* | |||
| 540 | * We now start writing to the filesystem | |||
| 541 | */ | |||
| 542 | ||||
| 543 | if (!Nflag) { | |||
| 544 | static const uint pbsize[] = { 1024, 2048, 4096, 0 }; | |||
| 545 | uint pblock, epblock; | |||
| 546 | /* | |||
| 547 | * Validate the given file system size. | |||
| 548 | * Verify that its last block can actually be accessed. | |||
| 549 | * Convert to file system fragment sized units. | |||
| 550 | */ | |||
| 551 | if (fssize <= 0) | |||
| 552 | errx(EXIT_FAILURE1, "Preposterous size %" PRId64"lld" "\n", | |||
| 553 | fssize); | |||
| 554 | wtfs(fssize - 1, sectorsize, iobuf); | |||
| 555 | ||||
| 556 | /* | |||
| 557 | * Ensure there is nothing that looks like a filesystem | |||
| 558 | * superblock anywhere other than where ours will be. | |||
| 559 | * If fsck_ext2fs finds the wrong one all hell breaks loose! | |||
| 560 | * | |||
| 561 | * XXX: needs to check how fsck_ext2fs programs even | |||
| 562 | * on other OSes determine alternate superblocks | |||
| 563 | */ | |||
| 564 | for (i = 0; pbsize[i] != 0; i++) { | |||
| 565 | epblock = (uint64_t)bcount * bsize / pbsize[i]; | |||
| 566 | for (pblock = ((pbsize[i] == SBSIZE1024) ? 1 : 0); | |||
| 567 | pblock < epblock; | |||
| 568 | pblock += pbsize[i] * NBBY8 /* bpg */) | |||
| 569 | zap_old_sblock((daddr32_t)pblock * | |||
| 570 | pbsize[i] / sectorsize); | |||
| 571 | } | |||
| 572 | } | |||
| 573 | ||||
| 574 | if (verbosity >= 3) | |||
| 575 | printf("super-block backups (for fsck_ext2fs -b #) at:\n"); | |||
| 576 | /* If we are printing more than one line of numbers, line up columns */ | |||
| 577 | fld_width = verbosity < 4 ? 1 : snprintf(NULL((void*)0), 0, "%" PRIu64"llu", | |||
| 578 | (uint64_t)cgbase(&sblock, ncg - 1)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (ncg - 1))); | |||
| 579 | if (Nflag && verbosity == 3) | |||
| 580 | /* Leave space to add " ..." after one row of numbers */ | |||
| 581 | max_cols -= 4; | |||
| 582 | #define BASE 0x10000 /* For some fixed-point maths */ | |||
| 583 | col = 0; | |||
| 584 | delta = verbosity > 2 ? 0 : max_cols * BASE / ncg; | |||
| 585 | for (cylno = 0; cylno < ncg; cylno++) { | |||
| 586 | fflush(stdout(&__sF[1])); | |||
| 587 | initcg(cylno); | |||
| 588 | if (verbosity < 2) | |||
| 589 | continue; | |||
| 590 | /* the first one is a master, not backup */ | |||
| 591 | if (cylno == 0) | |||
| 592 | continue; | |||
| 593 | /* skip if this cylinder doesn't have a backup */ | |||
| 594 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
| 595 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
| 596 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) != 0 && | |||
| 597 | cg_has_sb(cylno) == 0) | |||
| 598 | continue; | |||
| 599 | ||||
| 600 | if (delta > 0) { | |||
| 601 | if (Nflag) | |||
| 602 | /* No point doing dots for -N */ | |||
| 603 | break; | |||
| 604 | /* Print dots scaled to end near RH margin */ | |||
| 605 | for (col += delta; col > BASE; col -= BASE) | |||
| 606 | printf("."); | |||
| 607 | continue; | |||
| 608 | } | |||
| 609 | /* Print superblock numbers */ | |||
| 610 | len = printf("%s%*" PRIu64"llu" ",", (col ? " " : ""), fld_width, | |||
| 611 | (uint64_t)cgbase(&sblock, cylno)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno))); | |||
| 612 | col += len; | |||
| 613 | if (col + len < max_cols) | |||
| 614 | /* Next number fits */ | |||
| 615 | continue; | |||
| 616 | /* Next number won't fit, need a newline */ | |||
| 617 | if (verbosity <= 3) { | |||
| 618 | /* Print dots for subsequent cylinder groups */ | |||
| 619 | delta = sblockext2fsun.m_ext2fs.e2fs_ncg - cylno - 1; | |||
| 620 | if (delta != 0) { | |||
| 621 | if (Nflag) { | |||
| 622 | printf(" ..."); | |||
| 623 | break; | |||
| 624 | } | |||
| 625 | delta = max_cols * BASE / delta; | |||
| 626 | } | |||
| 627 | } | |||
| 628 | col = 0; | |||
| 629 | printf("\n"); | |||
| 630 | } | |||
| 631 | #undef BASE | |||
| 632 | if (col > 0) | |||
| 633 | printf("\n"); | |||
| 634 | if (Nflag) | |||
| 635 | return; | |||
| 636 | ||||
| 637 | /* | |||
| 638 | * Now construct the initial file system, | |||
| 639 | */ | |||
| 640 | if (fsinit(&tv) == 0) | |||
| 641 | errx(EXIT_FAILURE1, "Error making filesystem"); | |||
| 642 | /* | |||
| 643 | * Write out the superblock and group descriptors | |||
| 644 | */ | |||
| 645 | sblockext2fsun.m_ext2fs.e2fs.e2fs_block_group_nr = 0; | |||
| 646 | sboff = 0; | |||
| 647 | if (cgbase(&sblock, 0)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (0)) == 0) { | |||
| 648 | /* | |||
| 649 | * If the first block contains the boot block sectors, | |||
| 650 | * (i.e. in case of sblock.e2fs.e2fs_bsize > BBSIZE) | |||
| 651 | * we have to preserve data in it. | |||
| 652 | */ | |||
| 653 | sboff = SBOFF((off_t)(((off_t)(0)) + 1024)); | |||
| 654 | } | |||
| 655 | e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff))memcpy(((struct ext2fs *)(iobuf + sboff)), (&ext2fsun.m_ext2fs .e2fs), 1024);; | |||
| 656 | e2fs_cgsave(gd, (struct ext2_gd *)(iobuf + sblock.e2fs_bsize),memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize )), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun .m_ext2fs.e2fs_ncg)); | |||
| 657 | sizeof(struct ext2_gd) * sblock.e2fs_ncg)memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize )), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun .m_ext2fs.e2fs_ncg));; | |||
| 658 | wtfs(fsbtodb(&sblock, cgbase(&sblock, 0))((((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (0))) << (&ext2fsun .m_ext2fs)->e2fs_fsbtodb) + sboff / sectorsize, | |||
| 659 | iobufsize - sboff, iobuf + sboff); | |||
| 660 | ||||
| 661 | munmap(iobuf, iobufsize); | |||
| 662 | } | |||
| 663 | ||||
| 664 | /* | |||
| 665 | * Initialize a cylinder (block) group. | |||
| 666 | */ | |||
| 667 | void | |||
| 668 | initcg(uint cylno) | |||
| 669 | { | |||
| 670 | uint nblcg, i, j, sboff; | |||
| 671 | struct ext2fs_dinode *dp; | |||
| 672 | ||||
| 673 | /* | |||
| 674 | * Make a copy of the superblock and group descriptors. | |||
| 675 | */ | |||
| 676 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev == E2FS_REV00 || | |||
| 677 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
| 678 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) == 0 || | |||
| 679 | cg_has_sb(cylno)) { | |||
| 680 | sblockext2fsun.m_ext2fs.e2fs.e2fs_block_group_nr = cylno; | |||
| 681 | sboff = 0; | |||
| 682 | if (cgbase(&sblock, cylno)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno)) == 0) { | |||
| 683 | /* preserve data in bootblock in cg0 */ | |||
| 684 | sboff = SBOFF((off_t)(((off_t)(0)) + 1024)); | |||
| 685 | } | |||
| 686 | e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff))memcpy(((struct ext2fs *)(iobuf + sboff)), (&ext2fsun.m_ext2fs .e2fs), 1024);; | |||
| 687 | e2fs_cgsave(gd, (struct ext2_gd *)(iobuf +memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize * 1)), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun.m_ext2fs.e2fs_ncg)); | |||
| 688 | sblock.e2fs_bsize * NBLOCK_SUPERBLOCK),memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize * 1)), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun.m_ext2fs.e2fs_ncg)); | |||
| 689 | sizeof(struct ext2_gd) * sblock.e2fs_ncg)memcpy(((struct ext2_gd *)(iobuf + ext2fsun.m_ext2fs.e2fs_bsize * 1)), (ext2fsun.m_ext2fs.e2fs_gd), (sizeof(struct ext2_gd) * ext2fsun.m_ext2fs.e2fs_ncg));; | |||
| 690 | /* write superblock and group descriptor backups */ | |||
| 691 | wtfs(fsbtodb(&sblock, cgbase(&sblock, cylno))((((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno))) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb) + | |||
| 692 | sboff / sectorsize, iobufsize - sboff, iobuf + sboff); | |||
| 693 | } | |||
| 694 | ||||
| 695 | /* | |||
| 696 | * Initialize block bitmap. | |||
| 697 | */ | |||
| 698 | memset(buf, 0, sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
| 699 | if (cylno == (sblockext2fsun.m_ext2fs.e2fs_ncg - 1)) { | |||
| 700 | /* The last group could have less blocks than e2fs_bpg. */ | |||
| 701 | nblcg = sblockext2fsun.m_ext2fs.e2fs.e2fs_bcount - | |||
| 702 | cgbase(&sblock, sblock.e2fs_ncg - 1)((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (& ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (ext2fsun.m_ext2fs.e2fs_ncg - 1)); | |||
| 703 | for (i = nblcg; i < roundup(nblcg, NBBY)((((nblcg)+((8)-1))/(8))*(8)); i++) | |||
| 704 | setbit(buf, i)((buf)[(i)>>3] |= 1<<((i)&(8 -1))); | |||
| 705 | memset(&buf[i / NBBY8], ~0U, sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg - i); | |||
| 706 | } | |||
| 707 | /* set overhead (superblock, group descriptor etc.) blocks used */ | |||
| 708 | for (i = 0; i < cgoverhead(cylno) / NBBY8; i++) | |||
| 709 | buf[i] = ~0; | |||
| 710 | i = i * NBBY8; | |||
| 711 | for (; i < cgoverhead(cylno); i++) | |||
| 712 | setbit(buf, i)((buf)[(i)>>3] |= 1<<((i)&(8 -1))); | |||
| 713 | wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_b_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_b_bitmap) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, | |||
| 714 | buf); | |||
| 715 | ||||
| 716 | /* | |||
| 717 | * Initialize inode bitmap. | |||
| 718 | * | |||
| 719 | * Assume e2fs_ipg is a multiple of NBBY since | |||
| 720 | * it's a multiple of e2fs_ipb (as we did above). | |||
| 721 | * Note even (possibly smaller) the last group has the same e2fs_ipg. | |||
| 722 | */ | |||
| 723 | i = sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg / NBBY8; | |||
| 724 | memset(buf, 0, i); | |||
| 725 | memset(buf + i, ~0U, sblockext2fsun.m_ext2fs.e2fs_bsize - i); | |||
| 726 | if (cylno == 0) { | |||
| 727 | /* mark reserved inodes */ | |||
| 728 | for (i = 1; i < EXT2_FIRSTINO((ufsino_t)11); i++) | |||
| 729 | setbit(buf, EXT2_INO_INDEX(i))((buf)[(((i) - 1))>>3] |= 1<<((((i) - 1))&(8 - 1))); | |||
| 730 | } | |||
| 731 | wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_i_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_i_bitmap) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, | |||
| 732 | buf); | |||
| 733 | ||||
| 734 | /* | |||
| 735 | * Initialize inode tables. | |||
| 736 | * | |||
| 737 | * Just initialize generation numbers for NFS security. | |||
| 738 | * XXX: sys/ufs/ext2fs/ext2fs_alloc.c:ext2fs_valloc() seems | |||
| 739 | * to override these generated numbers. | |||
| 740 | */ | |||
| 741 | memset(buf, 0, sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
| 742 | for (i = 0; i < sblockext2fsun.m_ext2fs.e2fs_itpg; i++) { | |||
| 743 | for (j = 0; j < sblockext2fsun.m_ext2fs.e2fs_ipb; j++) { | |||
| 744 | dp = (struct ext2fs_dinode *)(buf + inodesize * j); | |||
| 745 | /* If there is some bias in arc4random(), keep it. */ | |||
| 746 | dp->e2di_gen = htole32(arc4random())((__uint32_t)(arc4random())); | |||
| 747 | } | |||
| 748 | wtfs(fsbtodb(&sblock, gd[cylno].ext2bgd_i_tables + i)((ext2fsun.m_ext2fs.e2fs_gd[cylno].ext2bgd_i_tables + i) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb), | |||
| 749 | sblockext2fsun.m_ext2fs.e2fs_bsize, buf); | |||
| 750 | } | |||
| 751 | } | |||
| 752 | ||||
| 753 | /* | |||
| 754 | * Zap possible lingering old superblock data | |||
| 755 | */ | |||
| 756 | static void | |||
| 757 | zap_old_sblock(daddr32_t sec) | |||
| 758 | { | |||
| 759 | static daddr32_t cg0_data; | |||
| 760 | uint32_t oldfs[SBSIZE1024 / sizeof(uint32_t)]; | |||
| 761 | static const struct fsm { | |||
| 762 | uint32_t offset; | |||
| 763 | uint32_t magic; | |||
| 764 | uint32_t mask; | |||
| 765 | } fs_magics[] = { | |||
| 766 | {offsetof(struct ext2fs, e2fs_magic)__builtin_offsetof(struct ext2fs, e2fs_magic) / 4, E2FS_MAGIC0xef53, 0xffff}, | |||
| 767 | {offsetof(struct ext2fs, e2fs_magic)__builtin_offsetof(struct ext2fs, e2fs_magic) / 4, | |||
| 768 | E2FS_MAGIC0xef53 << 16, 0xffff0000}, | |||
| 769 | {14, 0xef530000, 0xffff0000}, /* EXT2FS (big) */ | |||
| 770 | {0x55c / 4, 0x00011954, ~0U}, /* FS_UFS1_MAGIC */ | |||
| 771 | {0x55c / 4, 0x19540119, ~0U}, /* FS_UFS2_MAGIC */ | |||
| 772 | {0, 0x70162, ~0U}, /* LFS_MAGIC */ | |||
| 773 | {.offset = ~0U}, | |||
| 774 | }; | |||
| 775 | const struct fsm *fsm; | |||
| 776 | ||||
| 777 | if (Nflag) | |||
| 778 | return; | |||
| 779 | ||||
| 780 | /* don't override data before superblock */ | |||
| 781 | if (sec < SBOFF((off_t)(((off_t)(0)) + 1024)) / sectorsize) | |||
| 782 | return; | |||
| 783 | ||||
| 784 | if (cg0_data == 0) { | |||
| 785 | cg0_data = | |||
| 786 | ((daddr32_t)sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + cgoverhead(0)) * | |||
| 787 | sblockext2fsun.m_ext2fs.e2fs_bsize / sectorsize; | |||
| 788 | } | |||
| 789 | ||||
| 790 | /* Ignore anything that is beyond our filesystem */ | |||
| 791 | if (sec >= fssize) | |||
| 792 | return; | |||
| 793 | /* Zero anything inside our filesystem... */ | |||
| 794 | if (sec >= sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock * bsize / sectorsize) { | |||
| 795 | /* ...unless we will write that area anyway */ | |||
| 796 | if (sec >= cg0_data) | |||
| 797 | /* assume iobuf is zero'ed here */ | |||
| 798 | wtfs(sec, roundup(SBSIZE, sectorsize)((((1024)+((sectorsize)-1))/(sectorsize))*(sectorsize)), iobuf); | |||
| 799 | return; | |||
| 800 | } | |||
| 801 | ||||
| 802 | /* | |||
| 803 | * The sector might contain boot code, so we must validate it | |||
| 804 | * | |||
| 805 | * XXX: ext2fs won't preserve data after SBOFF, | |||
| 806 | * but first_dblock could have a different value. | |||
| 807 | */ | |||
| 808 | rdfs(sec, sizeof(oldfs), &oldfs); | |||
| 809 | for (fsm = fs_magics;; fsm++) { | |||
| 810 | uint32_t v; | |||
| 811 | if (fsm->mask == 0) | |||
| 812 | return; | |||
| 813 | v = oldfs[fsm->offset]; | |||
| 814 | if ((v & fsm->mask) == fsm->magic || | |||
| 815 | (swap32(v)(__uint32_t)(__builtin_constant_p(v) ? (__uint32_t)(((__uint32_t )(v) & 0xff) << 24 | ((__uint32_t)(v) & 0xff00) << 8 | ((__uint32_t)(v) & 0xff0000) >> 8 | ( (__uint32_t)(v) & 0xff000000) >> 24) : __swap32md(v )) & fsm->mask) == fsm->magic) | |||
| 816 | break; | |||
| 817 | } | |||
| 818 | ||||
| 819 | /* Just zap the magic number */ | |||
| 820 | oldfs[fsm->offset] = 0; | |||
| 821 | wtfs(sec, sizeof(oldfs), &oldfs); | |||
| 822 | } | |||
| 823 | ||||
| 824 | /* | |||
| 825 | * uint cgoverhead(uint c) | |||
| 826 | * | |||
| 827 | * Return a number of reserved blocks on the specified group. | |||
| 828 | * XXX: should be shared with src/sbin/fsck_ext2fs/setup.c | |||
| 829 | */ | |||
| 830 | uint | |||
| 831 | cgoverhead(uint c) | |||
| 832 | { | |||
| 833 | uint overh; | |||
| 834 | ||||
| 835 | overh = NBLOCK_BLOCK_BITMAP1 + NBLOCK_INODE_BITMAP1 + sblockext2fsun.m_ext2fs.e2fs_itpg; | |||
| 836 | ||||
| 837 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev == E2FS_REV00 || | |||
| 838 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
| 839 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) == 0 || | |||
| 840 | cg_has_sb(c) != 0) { | |||
| 841 | overh += NBLOCK_SUPERBLOCK1 + sblockext2fsun.m_ext2fs.e2fs_ngdb; | |||
| 842 | ||||
| 843 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
| 844 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat & | |||
| 845 | EXT2F_COMPAT_RESIZE0x0010) != 0) | |||
| 846 | overh += sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb; | |||
| 847 | } | |||
| 848 | ||||
| 849 | return overh; | |||
| 850 | } | |||
| 851 | ||||
| 852 | /* | |||
| 853 | * Initialize the file system | |||
| 854 | */ | |||
| 855 | ||||
| 856 | #define LOSTDIR /* e2fsck complains if there is no lost+found */ | |||
| 857 | ||||
| 858 | #define PREDEFDIR2 2 | |||
| 859 | ||||
| 860 | #ifdef LOSTDIR | |||
| 861 | #define PREDEFROOTDIR(2 + 1) (PREDEFDIR2 + 1) | |||
| 862 | #else | |||
| 863 | #define PREDEFROOTDIR(2 + 1) PREDEFDIR2 | |||
| 864 | #endif | |||
| 865 | ||||
| 866 | struct ext2fs_direct root_dir[] = { | |||
| 867 | { EXT2_ROOTINO((ufsino_t)2), 0, 1, 0, "." }, | |||
| 868 | { EXT2_ROOTINO((ufsino_t)2), 0, 2, 0, ".." }, | |||
| 869 | #ifdef LOSTDIR | |||
| 870 | { EXT2_LOSTFOUNDINO((ufsino_t)11), 0, 10, 0, "lost+found" }, | |||
| 871 | #endif | |||
| 872 | }; | |||
| 873 | ||||
| 874 | #ifdef LOSTDIR | |||
| 875 | struct ext2fs_direct lost_found_dir[] = { | |||
| 876 | { EXT2_LOSTFOUNDINO((ufsino_t)11), 0, 1, 0, "." }, | |||
| 877 | { EXT2_ROOTINO((ufsino_t)2), 0, 2, 0, ".." }, | |||
| 878 | }; | |||
| 879 | struct ext2fs_direct pad_dir = { 0, sizeof(struct ext2fs_direct), 0, 0, "" }; | |||
| 880 | #endif | |||
| 881 | ||||
| 882 | int | |||
| 883 | fsinit(const struct timeval *tv) | |||
| 884 | { | |||
| 885 | struct ext2fs_dinode node; | |||
| 886 | #ifdef LOSTDIR | |||
| 887 | uint i, nblks_lostfound, blk; | |||
| 888 | #endif | |||
| 889 | ||||
| 890 | /* | |||
| 891 | * Initialize the inode for the resizefs feature | |||
| 892 | */ | |||
| 893 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
| 894 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE0x0010) != 0) | |||
| 895 | init_resizeino(tv); | |||
| 896 | ||||
| 897 | /* | |||
| 898 | * Initialize the node | |||
| 899 | */ | |||
| 900 | ||||
| 901 | #ifdef LOSTDIR | |||
| 902 | /* | |||
| 903 | * Create the lost+found directory | |||
| 904 | */ | |||
| 905 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
| 906 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002) { | |||
| 907 | lost_found_dir[0].e2d_type = EXT2_FT_DIR2; | |||
| 908 | lost_found_dir[1].e2d_type = EXT2_FT_DIR2; | |||
| 909 | } | |||
| 910 | (void)makedir(lost_found_dir, nitems(lost_found_dir)(sizeof((lost_found_dir)) / sizeof((lost_found_dir)[0]))); | |||
| 911 | ||||
| 912 | /* prepare a bit large directory for preserved files */ | |||
| 913 | nblks_lostfound = EXT2_LOSTFOUNDSIZE16384 / sblockext2fsun.m_ext2fs.e2fs_bsize; | |||
| 914 | /* ...but only with direct blocks */ | |||
| 915 | if (nblks_lostfound > NDADDR12) | |||
| 916 | nblks_lostfound = NDADDR12; | |||
| 917 | ||||
| 918 | memset(&node, 0, sizeof(node)); | |||
| 919 | node.e2di_mode = EXT2_IFDIR0040000 | EXT2_LOSTFOUNDUMASK0700; | |||
| 920 | node.e2di_uid_low = geteuid(); | |||
| 921 | node.e2di_size = sblockext2fsun.m_ext2fs.e2fs_bsize * nblks_lostfound; | |||
| 922 | node.e2di_atime = (u_int32_t)tv->tv_sec; | |||
| 923 | node.e2di_ctime = (u_int32_t)tv->tv_sec; | |||
| 924 | node.e2di_mtime = (u_int32_t)tv->tv_sec; | |||
| 925 | node.e2di_gid_low = getegid(); | |||
| 926 | node.e2di_nlink = PREDEFDIR2; | |||
| 927 | /* e2di_nblock is a number of disk blocks, not ext2fs blocks */ | |||
| 928 | node.e2di_nblock = fsbtodb(&sblock, nblks_lostfound)((nblks_lostfound) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb ); | |||
| 929 | node.e2di_blocks[0] = alloc(sblockext2fsun.m_ext2fs.e2fs_bsize, node.e2di_mode); | |||
| 930 | if (node.e2di_blocks[0] == 0) { | |||
| 931 | printf("%s: can't allocate block for lost+found\n", __func__); | |||
| 932 | return 0; | |||
| 933 | } | |||
| 934 | for (i = 1; i < nblks_lostfound; i++) { | |||
| 935 | blk = alloc(sblockext2fsun.m_ext2fs.e2fs_bsize, 0); | |||
| 936 | if (blk == 0) { | |||
| 937 | printf("%s: can't allocate blocks for lost+found\n", | |||
| 938 | __func__); | |||
| 939 | return 0; | |||
| 940 | } | |||
| 941 | node.e2di_blocks[i] = blk; | |||
| 942 | } | |||
| 943 | wtfs(fsbtodb(&sblock, node.e2di_blocks[0])((node.e2di_blocks[0]) << (&ext2fsun.m_ext2fs)-> e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, buf); | |||
| 944 | pad_dir.e2d_reclen = sblockext2fsun.m_ext2fs.e2fs_bsize; | |||
| 945 | for (i = 1; i < nblks_lostfound; i++) { | |||
| 946 | memset(buf, 0, sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
| 947 | copy_dir(&pad_dir, (struct ext2fs_direct *)buf); | |||
| 948 | wtfs(fsbtodb(&sblock, node.e2di_blocks[i])((node.e2di_blocks[i]) << (&ext2fsun.m_ext2fs)-> e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, | |||
| 949 | buf); | |||
| 950 | } | |||
| 951 | iput(&node, EXT2_LOSTFOUNDINO((ufsino_t)11)); | |||
| 952 | #endif | |||
| 953 | /* | |||
| 954 | * create the root directory | |||
| 955 | */ | |||
| 956 | memset(&node, 0, sizeof(node)); | |||
| 957 | if (sblockext2fsun.m_ext2fs.e2fs.e2fs_rev > E2FS_REV00 && | |||
| 958 | sblockext2fsun.m_ext2fs.e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002) { | |||
| 959 | root_dir[0].e2d_type = EXT2_FT_DIR2; | |||
| 960 | root_dir[1].e2d_type = EXT2_FT_DIR2; | |||
| 961 | #ifdef LOSTDIR | |||
| 962 | root_dir[2].e2d_type = EXT2_FT_DIR2; | |||
| 963 | #endif | |||
| 964 | } | |||
| 965 | node.e2di_mode = EXT2_IFDIR0040000 | EXT2_UMASK0755; | |||
| 966 | node.e2di_uid_low = geteuid(); | |||
| 967 | node.e2di_size = makedir(root_dir, nitems(root_dir)(sizeof((root_dir)) / sizeof((root_dir)[0]))); | |||
| 968 | node.e2di_atime = (u_int32_t)tv->tv_sec; | |||
| 969 | node.e2di_ctime = (u_int32_t)tv->tv_sec; | |||
| 970 | node.e2di_mtime = (u_int32_t)tv->tv_sec; | |||
| 971 | node.e2di_gid_low = getegid(); | |||
| 972 | node.e2di_nlink = PREDEFROOTDIR(2 + 1); | |||
| 973 | /* e2di_nblock is a number of disk block, not ext2fs block */ | |||
| 974 | node.e2di_nblock = fsbtodb(&sblock, 1)((1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
| 975 | node.e2di_blocks[0] = alloc(node.e2di_size, node.e2di_mode); | |||
| 976 | if (node.e2di_blocks[0] == 0) { | |||
| 977 | printf("%s: can't allocate block for root dir\n", __func__); | |||
| 978 | return 0; | |||
| 979 | } | |||
| 980 | wtfs(fsbtodb(&sblock, node.e2di_blocks[0])((node.e2di_blocks[0]) << (&ext2fsun.m_ext2fs)-> e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, buf); | |||
| 981 | iput(&node, EXT2_ROOTINO((ufsino_t)2)); | |||
| 982 | return 1; | |||
| 983 | } | |||
| 984 | ||||
| 985 | /* | |||
| 986 | * Construct a set of directory entries in "buf". | |||
| 987 | * return size of directory. | |||
| 988 | */ | |||
| 989 | int | |||
| 990 | makedir(struct ext2fs_direct *protodir, int entries) | |||
| 991 | { | |||
| 992 | uint8_t *cp; | |||
| 993 | uint i, spcleft; | |||
| 994 | uint dirblksiz; | |||
| 995 | ||||
| 996 | dirblksiz = sblockext2fsun.m_ext2fs.e2fs_bsize; | |||
| 997 | memset(buf, 0, dirblksiz); | |||
| 998 | spcleft = dirblksiz; | |||
| 999 | for (cp = buf, i = 0; i < entries - 1; i++) { | |||
| 1000 | protodir[i].e2d_reclen = EXT2FS_DIRSIZ(protodir[i].e2d_namlen)(( 8 + protodir[i].e2d_namlen + 3) &~ 3); | |||
| 1001 | copy_dir(&protodir[i], (struct ext2fs_direct *)cp); | |||
| 1002 | cp += protodir[i].e2d_reclen; | |||
| 1003 | spcleft -= protodir[i].e2d_reclen; | |||
| 1004 | } | |||
| 1005 | protodir[i].e2d_reclen = spcleft; | |||
| 1006 | copy_dir(&protodir[i], (struct ext2fs_direct *)cp); | |||
| 1007 | return dirblksiz; | |||
| 1008 | } | |||
| 1009 | ||||
| 1010 | /* | |||
| 1011 | * Copy a direntry to a buffer, in fs byte order | |||
| 1012 | */ | |||
| 1013 | static void | |||
| 1014 | copy_dir(struct ext2fs_direct *dir, struct ext2fs_direct *dbuf) | |||
| 1015 | { | |||
| 1016 | ||||
| 1017 | memcpy(dbuf, dir, EXT2FS_DIRSIZ(dir->e2d_namlen)(( 8 + dir->e2d_namlen + 3) &~ 3)); | |||
| 1018 | dbuf->e2d_ino = htole32(dir->e2d_ino)((__uint32_t)(dir->e2d_ino)); | |||
| 1019 | dbuf->e2d_reclen = htole16(dir->e2d_reclen)((__uint16_t)(dir->e2d_reclen)); | |||
| 1020 | } | |||
| 1021 | ||||
| 1022 | /* | |||
| 1023 | * void init_resizeino(const struct timeval *tv); | |||
| 1024 | * | |||
| 1025 | * Initialize the EXT2_RESEIZE_INO inode to preserve | |||
| 1026 | * reserved group descriptor blocks for future growth of this ext2fs. | |||
| 1027 | */ | |||
| 1028 | void | |||
| 1029 | init_resizeino(const struct timeval *tv) | |||
| 1030 | { | |||
| 1031 | struct ext2fs_dinode node; | |||
| 1032 | uint64_t isize; | |||
| 1033 | uint32_t *dindir_block, *reserved_gdb; | |||
| 1034 | uint nblock, i, cylno, n; | |||
| 1035 | ||||
| 1036 | memset(&node, 0, sizeof(node)); | |||
| 1037 | ||||
| 1038 | /* | |||
| 1039 | * Note this function only prepares required structures for | |||
| 1040 | * future resize. It's a quite different work to implement | |||
| 1041 | * a utility like resize_ext2fs(8) which handles actual | |||
| 1042 | * resize ops even on offline. | |||
| 1043 | * | |||
| 1044 | * Anyway, I'm not sure if there is any documentation about | |||
| 1045 | * this resize ext2fs feature and related data structures, | |||
| 1046 | * and I've written this function based on things what I see | |||
| 1047 | * on some existing implementation and real file system data | |||
| 1048 | * created by existing tools. To be honest, they are not | |||
| 1049 | * so easy to read, so I will try to implement it here without | |||
| 1050 | * any dumb optimization for people who would eventually | |||
| 1051 | * work on "yet another wheel" like resize_ext2fs(8). | |||
| 1052 | */ | |||
| 1053 | ||||
| 1054 | /* | |||
| 1055 | * I'm not sure what type is appropriate for this inode. | |||
| 1056 | * The release notes of e2fsprogs says they changed e2fsck to allow | |||
| 1057 | * IFREG for RESIZEINO since a certain resize tool used it. Hmm. | |||
| 1058 | */ | |||
| 1059 | node.e2di_mode = EXT2_IFREG0100000 | EXT2_RESIZEINOUMASK0600; | |||
| 1060 | node.e2di_uid_low = geteuid(); | |||
| 1061 | node.e2di_atime = (u_int32_t)tv->tv_sec; | |||
| 1062 | node.e2di_ctime = (u_int32_t)tv->tv_sec; | |||
| 1063 | node.e2di_mtime = (u_int32_t)tv->tv_sec; | |||
| 1064 | node.e2di_gid_low = getegid(); | |||
| 1065 | node.e2di_nlink = 1; | |||
| 1066 | ||||
| 1067 | /* | |||
| 1068 | * To preserve the reserved group descriptor blocks, | |||
| 1069 | * EXT2_RESIZEINO uses only double indirect reference | |||
| 1070 | * blocks in its inode entries. | |||
| 1071 | * | |||
| 1072 | * All entries for direct, single indirect and triple | |||
| 1073 | * indirect references are left zero'ed. Maybe it's safe | |||
| 1074 | * because no write operation will happen with this inode. | |||
| 1075 | * | |||
| 1076 | * We have to allocate a block for the first level double | |||
| 1077 | * indirect reference block. Indexes of inode entries in | |||
| 1078 | * this first level dindirect block are corresponding to | |||
| 1079 | * indexes of group descriptors including both used (e2fs_ngdb) | |||
| 1080 | * and reserved (e2fs_reserved_ngdb) group descriptor blocks. | |||
| 1081 | * | |||
| 1082 | * Inode entries of indexes for used (e2fs_ngdb) descriptors are | |||
| 1083 | * left zero'ed. Entries for reserved (e2fs_reserved_ngdb) ones | |||
| 1084 | * have block numbers of actual reserved group descriptors | |||
| 1085 | * allocated at block group zero. This means e2fs_reserved_ngdb | |||
| 1086 | * blocks are reserved as the second level dindirect reference | |||
| 1087 | * blocks, and they actually contain block numbers of indirect | |||
| 1088 | * references. It may be safe since they don't have to keep any | |||
| 1089 | * data yet. | |||
| 1090 | * | |||
| 1091 | * Each these second dindirect blocks (i.e. reserved group | |||
| 1092 | * descriptor blocks in the first block group) should have | |||
| 1093 | * block numbers of its backups in all other block groups. | |||
| 1094 | * I.e. reserved_ngdb[0] block in block group 0 contains block | |||
| 1095 | * numbers of resreved_ngdb[0] from group 1 through (e2fs_ncg - 1). | |||
| 1096 | * The number of backups can be determined by the | |||
| 1097 | * EXT2_ROCOMPAT_SPARSESUPER feature and cg_has_sb() macro | |||
| 1098 | * as done in the above initcg() function. | |||
| 1099 | */ | |||
| 1100 | ||||
| 1101 | /* set e2di_size which occupies whole blocks through DINDIR blocks */ | |||
| 1102 | isize = (uint64_t)sblockext2fsun.m_ext2fs.e2fs_bsize * NDADDR12 + | |||
| 1103 | (uint64_t)sblockext2fsun.m_ext2fs.e2fs_bsize * NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)) + | |||
| 1104 | (uint64_t)sblockext2fsun.m_ext2fs.e2fs_bsize * NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)) * NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)); | |||
| 1105 | if (isize > UINT32_MAX0xffffffffU && | |||
| 1106 | (sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
| 1107 | EXT2F_ROCOMPAT_LARGE_FILE0x0002) == 0) { | |||
| 1108 | /* XXX should enable it here and update all backups? */ | |||
| 1109 | errx(EXIT_FAILURE1, "%s: large_file rocompat feature is " | |||
| 1110 | "required to enable resize feature for this filesystem\n", | |||
| 1111 | __func__); | |||
| 1112 | } | |||
| 1113 | /* upper 32bit is stored into e2di_size_hi on REV1 feature */ | |||
| 1114 | node.e2di_size = isize & UINT32_MAX0xffffffffU; | |||
| 1115 | node.e2di_size_hi = isize >> 32; | |||
| 1116 | ||||
| 1117 | #define SINGLE0 0 /* index of single indirect block */ | |||
| 1118 | #define DOUBLE1 1 /* index of double indirect block */ | |||
| 1119 | #define TRIPLE2 2 /* index of triple indirect block */ | |||
| 1120 | ||||
| 1121 | /* zero out entries for direct references */ | |||
| 1122 | for (i = 0; i < NDADDR12; i++) | |||
| 1123 | node.e2di_blocks[i] = 0; | |||
| 1124 | /* also zero out entries for single and triple indirect references */ | |||
| 1125 | node.e2di_blocks[NDADDR12 + SINGLE0] = 0; | |||
| 1126 | node.e2di_blocks[NDADDR12 + TRIPLE2] = 0; | |||
| 1127 | ||||
| 1128 | /* allocate a block for the first level double indirect reference */ | |||
| 1129 | node.e2di_blocks[NDADDR12 + DOUBLE1] = | |||
| 1130 | alloc(sblockext2fsun.m_ext2fs.e2fs_bsize, node.e2di_mode); | |||
| 1131 | if (node.e2di_blocks[NDADDR12 + DOUBLE1] == 0) | |||
| 1132 | errx(EXIT_FAILURE1, "%s: Can't allocate a dindirect block", | |||
| 1133 | __func__); | |||
| 1134 | ||||
| 1135 | /* account this first block */ | |||
| 1136 | nblock = fsbtodb(&sblock, 1)((1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
| 1137 | ||||
| 1138 | /* allocate buffer to set data in the dindirect block */ | |||
| 1139 | dindir_block = malloc(sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
| 1140 | if (dindir_block == NULL((void*)0)) | |||
| 1141 | errx(EXIT_FAILURE1, | |||
| 1142 | "%s: Can't allocate buffer for a dindirect block", | |||
| 1143 | __func__); | |||
| 1144 | ||||
| 1145 | /* allocate buffer to set data in the group descriptor blocks */ | |||
| 1146 | reserved_gdb = malloc(sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
| 1147 | if (reserved_gdb == NULL((void*)0)) | |||
| 1148 | errx(EXIT_FAILURE1, | |||
| 1149 | "%s: Can't allocate buffer for group descriptor blocks", | |||
| 1150 | __func__); | |||
| 1151 | ||||
| 1152 | /* | |||
| 1153 | * Setup block entries in the first level dindirect blocks | |||
| 1154 | */ | |||
| 1155 | for (i = 0; i < sblockext2fsun.m_ext2fs.e2fs_ngdb; i++) { | |||
| 1156 | /* no need to handle used group descriptor blocks */ | |||
| 1157 | dindir_block[i] = 0; | |||
| 1158 | } | |||
| 1159 | for (; i < sblockext2fsun.m_ext2fs.e2fs_ngdb + sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb; i++) { | |||
| 1160 | /* | |||
| 1161 | * point reserved group descriptor block in the first | |||
| 1162 | * (i.e. master) block group | |||
| 1163 | * | |||
| 1164 | * XXX: e2fsprogs seem to use "(i % NINDIR(&sblock))" here | |||
| 1165 | * to store maximum NINDIR(&sblock) reserved gdbs. | |||
| 1166 | * I'm not sure what will be done on future filesystem | |||
| 1167 | * shrink in that case on their way. | |||
| 1168 | */ | |||
| 1169 | if (i >= NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t))) | |||
| 1170 | errx(EXIT_FAILURE1, "%s: too many reserved " | |||
| 1171 | "group descriptors (%u) for resize inode", | |||
| 1172 | __func__, sblockext2fsun.m_ext2fs.e2fs.e2fs_reserved_ngdb); | |||
| 1173 | dindir_block[i] = | |||
| 1174 | htole32(cgbase(&sblock, 0) + NBLOCK_SUPERBLOCK + i)((__uint32_t)(((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (&ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (0)) + 1 + i) ); | |||
| 1175 | ||||
| 1176 | /* | |||
| 1177 | * Setup block entries in the second dindirect blocks | |||
| 1178 | * (which are primary reserved group descriptor blocks) | |||
| 1179 | * to point their backups. | |||
| 1180 | */ | |||
| 1181 | for (n = 0, cylno = 1; cylno < sblockext2fsun.m_ext2fs.e2fs_ncg; cylno++) { | |||
| 1182 | /* skip block groups without backup */ | |||
| 1183 | if ((sblockext2fsun.m_ext2fs.e2fs.e2fs_features_rocompat & | |||
| 1184 | EXT2F_ROCOMPAT_SPARSE_SUPER0x0001) != 0 && | |||
| 1185 | cg_has_sb(cylno) == 0) | |||
| 1186 | continue; | |||
| 1187 | ||||
| 1188 | if (n >= NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t))) | |||
| 1189 | errx(EXIT_FAILURE1, "%s: too many block groups " | |||
| 1190 | "for the resize feature", __func__); | |||
| 1191 | /* | |||
| 1192 | * These blocks are already reserved in | |||
| 1193 | * initcg() so no need to use alloc() here. | |||
| 1194 | */ | |||
| 1195 | reserved_gdb[n++] = htole32(cgbase(&sblock, cylno) +((__uint32_t)(((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (&ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno)) + 1 + i)) | |||
| 1196 | NBLOCK_SUPERBLOCK + i)((__uint32_t)(((&ext2fsun.m_ext2fs)->e2fs.e2fs_first_dblock + (&ext2fsun.m_ext2fs)->e2fs.e2fs_bpg * (cylno)) + 1 + i)); | |||
| 1197 | nblock += fsbtodb(&sblock, 1)((1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
| 1198 | } | |||
| 1199 | for (; n < NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)); n++) | |||
| 1200 | reserved_gdb[n] = 0; | |||
| 1201 | ||||
| 1202 | /* write group descriptor block as the second dindirect refs */ | |||
| 1203 | wtfs(fsbtodb(&sblock, letoh32(dindir_block[i]))((((__uint32_t)(dindir_block[i]))) << (&ext2fsun.m_ext2fs )->e2fs_fsbtodb), | |||
| 1204 | sblockext2fsun.m_ext2fs.e2fs_bsize, reserved_gdb); | |||
| 1205 | nblock += fsbtodb(&sblock, 1)((1) << (&ext2fsun.m_ext2fs)->e2fs_fsbtodb); | |||
| 1206 | } | |||
| 1207 | for (; i < NINDIR(&sblock)((&ext2fsun.m_ext2fs)->e2fs_bsize / sizeof(u_int32_t)); i++) { | |||
| 1208 | /* leave trailing entries unallocated */ | |||
| 1209 | dindir_block[i] = 0; | |||
| 1210 | } | |||
| 1211 | free(reserved_gdb); | |||
| 1212 | ||||
| 1213 | /* finally write the first level dindirect block */ | |||
| 1214 | wtfs(fsbtodb(&sblock, node.e2di_blocks[NDADDR + DOUBLE])((node.e2di_blocks[12 + 1]) << (&ext2fsun.m_ext2fs) ->e2fs_fsbtodb), | |||
| 1215 | sblockext2fsun.m_ext2fs.e2fs_bsize, dindir_block); | |||
| 1216 | free(dindir_block); | |||
| 1217 | ||||
| 1218 | node.e2di_nblock = nblock; | |||
| 1219 | iput(&node, EXT2_RESIZEINO((ufsino_t)7)); | |||
| 1220 | } | |||
| 1221 | ||||
| 1222 | /* | |||
| 1223 | * uint32_t alloc(uint32_t size, uint16_t mode) | |||
| 1224 | * | |||
| 1225 | * Allocate a block (from cylinder group 0) | |||
| 1226 | * Reference: src/sys/ufs/ext2fs/ext2fs_alloc.c:ext2fs_alloccg() | |||
| 1227 | */ | |||
| 1228 | uint32_t | |||
| 1229 | alloc(uint32_t size, uint16_t mode) | |||
| 1230 | { | |||
| 1231 | uint32_t loc, bno; | |||
| 1232 | uint8_t *bbp; | |||
| 1233 | uint len, map, i; | |||
| 1234 | ||||
| 1235 | if (gdext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_nbfree == 0) | |||
| 1236 | return 0; | |||
| 1237 | ||||
| 1238 | if (size > sblockext2fsun.m_ext2fs.e2fs_bsize) | |||
| 1239 | return 0; | |||
| 1240 | ||||
| 1241 | bbp = malloc(sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
| 1242 | if (bbp == NULL((void*)0)) | |||
| 1243 | return 0; | |||
| 1244 | rdfs(fsbtodb(&sblock, gd[0].ext2bgd_b_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_b_bitmap) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, bbp); | |||
| 1245 | ||||
| 1246 | /* XXX: kernel uses e2fs_fpg here */ | |||
| 1247 | len = sblockext2fsun.m_ext2fs.e2fs.e2fs_bpg / NBBY8; | |||
| 1248 | ||||
| 1249 | #if 0 /* no need block allocation for root or lost+found dir */ | |||
| 1250 | for (loc = 0; loc < len; loc++) { | |||
| 1251 | if (bbp[loc] == 0) { | |||
| 1252 | bno = loc * NBBY8; | |||
| 1253 | goto gotit; | |||
| 1254 | } | |||
| 1255 | } | |||
| 1256 | #endif | |||
| 1257 | ||||
| 1258 | loc = skpc(~0U, len, bbp); | |||
| 1259 | if (loc == 0) { | |||
| 1260 | free(bbp); | |||
| 1261 | return 0; | |||
| 1262 | } | |||
| 1263 | loc = len - loc; | |||
| 1264 | map = bbp[loc]; | |||
| 1265 | bno = loc * NBBY8; | |||
| 1266 | for (i = 0; i < NBBY8; i++, bno++) { | |||
| 1267 | if ((map & (1 << i)) == 0) | |||
| 1268 | goto gotit; | |||
| 1269 | } | |||
| 1270 | free(bbp); | |||
| 1271 | return 0; | |||
| 1272 | ||||
| 1273 | gotit: | |||
| 1274 | if (isset(bbp, bno)((bbp)[(bno)>>3] & (1<<((bno)&(8 -1))))) | |||
| 1275 | errx(EXIT_FAILURE1, "%s: inconsistent bitmap\n", __func__); | |||
| 1276 | ||||
| 1277 | setbit(bbp, bno)((bbp)[(bno)>>3] |= 1<<((bno)&(8 -1))); | |||
| 1278 | wtfs(fsbtodb(&sblock, gd[0].ext2bgd_b_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_b_bitmap) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb), sblockext2fsun.m_ext2fs.e2fs_bsize, bbp); | |||
| 1279 | free(bbp); | |||
| 1280 | /* XXX: modified group descriptors won't be written into backups */ | |||
| 1281 | gdext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_nbfree--; | |||
| 1282 | if ((mode & EXT2_IFDIR0040000) != 0) | |||
| 1283 | gdext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_ndirs++; | |||
| 1284 | sblockext2fsun.m_ext2fs.e2fs.e2fs_fbcount--; | |||
| 1285 | ||||
| 1286 | return sblockext2fsun.m_ext2fs.e2fs.e2fs_first_dblock + bno; | |||
| 1287 | } | |||
| 1288 | ||||
| 1289 | /* | |||
| 1290 | * void iput(struct ext2fs_dinode *ip, ino_t ino) | |||
| 1291 | * | |||
| 1292 | * Put an inode entry into the corresponding table. | |||
| 1293 | */ | |||
| 1294 | static void | |||
| 1295 | iput(struct ext2fs_dinode *ip, ino_t ino) | |||
| 1296 | { | |||
| 1297 | daddr32_t d; | |||
| 1298 | uint c, i; | |||
| 1299 | struct ext2fs_dinode *dp; | |||
| 1300 | uint8_t *bp; | |||
| 1301 | ||||
| 1302 | bp = malloc(sblockext2fsun.m_ext2fs.e2fs_bsize); | |||
| 1303 | if (bp == NULL((void*)0)) | |||
| 1304 | errx(EXIT_FAILURE1, "%s: can't allocate buffer for inode\n", | |||
| 1305 | __func__); | |||
| 1306 | ||||
| 1307 | /* | |||
| 1308 | * Reserved inodes are allocated and accounted in initcg() | |||
| 1309 | * so skip checks of the bitmap and allocation for them. | |||
| 1310 | */ | |||
| 1311 | if (ino >= EXT2_FIRSTINO((ufsino_t)11)) { | |||
| 1312 | c = ino_to_cg(&sblock, ino)(((ino) - 1) / (&ext2fsun.m_ext2fs)->e2fs.e2fs_ipg); | |||
| 1313 | ||||
| 1314 | /* sanity check */ | |||
| 1315 | if (gdext2fsun.m_ext2fs.e2fs_gd[c].ext2bgd_nifree == 0) | |||
| 1316 | errx(EXIT_FAILURE1, | |||
| 1317 | "%s: no free inode %" PRIu64"llu" " in block group %u\n", | |||
| 1318 | __func__, (uint64_t)ino, c); | |||
| 1319 | ||||
| 1320 | /* update inode bitmap */ | |||
| 1321 | rdfs(fsbtodb(&sblock, gd[0].ext2bgd_i_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_i_bitmap) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb), | |||
| 1322 | sblockext2fsun.m_ext2fs.e2fs_bsize, bp); | |||
| 1323 | ||||
| 1324 | /* more sanity */ | |||
| 1325 | if (isset(bp, EXT2_INO_INDEX(ino))((bp)[(((ino) - 1))>>3] & (1<<((((ino) - 1))& (8 -1))))) | |||
| 1326 | errx(EXIT_FAILURE1, "%s: inode %" PRIu64"llu" | |||
| 1327 | " already in use\n", __func__, (uint64_t)ino); | |||
| 1328 | setbit(bp, EXT2_INO_INDEX(ino))((bp)[(((ino) - 1))>>3] |= 1<<((((ino) - 1))& (8 -1))); | |||
| 1329 | wtfs(fsbtodb(&sblock, gd[0].ext2bgd_i_bitmap)((ext2fsun.m_ext2fs.e2fs_gd[0].ext2bgd_i_bitmap) << (& ext2fsun.m_ext2fs)->e2fs_fsbtodb), | |||
| 1330 | sblockext2fsun.m_ext2fs.e2fs_bsize, bp); | |||
| 1331 | gdext2fsun.m_ext2fs.e2fs_gd[c].ext2bgd_nifree--; | |||
| 1332 | sblockext2fsun.m_ext2fs.e2fs.e2fs_ficount--; | |||
| 1333 | } | |||
| 1334 | ||||
| 1335 | if (ino >= sblockext2fsun.m_ext2fs.e2fs.e2fs_ipg * sblockext2fsun.m_ext2fs.e2fs_ncg) | |||
| 1336 | errx(EXIT_FAILURE1, "%s: inode value out of range (%" PRIu64"llu" | |||
| 1337 | ").\n", __func__, (uint64_t)ino); | |||
| 1338 | ||||
| 1339 | /* update an inode entry in the table */ | |||
| 1340 | d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino))((((&ext2fsun.m_ext2fs)->e2fs_gd[(((ino) - 1) / (& ext2fsun.m_ext2fs)->e2fs.e2fs_ipg)].ext2bgd_i_tables + ((( ino)-1) % (&ext2fsun.m_ext2fs)->e2fs.e2fs_ipg)/(&ext2fsun .m_ext2fs)->e2fs_ipb)) << (&ext2fsun.m_ext2fs)-> e2fs_fsbtodb); | |||
| 1341 | rdfs(d, sblockext2fsun.m_ext2fs.e2fs_bsize, bp); | |||
| 1342 | ||||
| 1343 | dp = (struct ext2fs_dinode *)(bp + | |||
| 1344 | inodesize * ino_to_fsbo(&sblock, ino)(((ino)-1) % (&ext2fsun.m_ext2fs)->e2fs_ipb)); | |||
| 1345 | e2fs_isave(&sblock, ip, dp)memcpy((dp),(ip), (((((&ext2fsun.m_ext2fs)->e2fs.e2fs_rev > 0 ? (&ext2fsun.m_ext2fs)->e2fs.e2fs_inode_size : 128))<(sizeof(*dp)))?(((&ext2fsun.m_ext2fs)->e2fs. e2fs_rev > 0 ? (&ext2fsun.m_ext2fs)->e2fs.e2fs_inode_size : 128)):(sizeof(*dp)))); | |||
| 1346 | /* e2fs_i_bswap() doesn't swap e2di_blocks addrs */ | |||
| 1347 | if ((ip->e2di_mode & EXT2_IFMT0170000) != EXT2_IFLNK0120000) { | |||
| 1348 | for (i = 0; i < NDADDR12 + NIADDR3; i++) | |||
| 1349 | dp->e2di_blocks[i] = htole32(ip->e2di_blocks[i])((__uint32_t)(ip->e2di_blocks[i])); | |||
| 1350 | } | |||
| 1351 | /* If there is some bias in arc4random(), keep it. */ | |||
| 1352 | dp->e2di_gen = htole32(arc4random())((__uint32_t)(arc4random())); | |||
| 1353 | ||||
| 1354 | wtfs(d, sblockext2fsun.m_ext2fs.e2fs_bsize, bp); | |||
| 1355 | free(bp); | |||
| 1356 | } | |||
| 1357 | ||||
| 1358 | /* | |||
| 1359 | * Read a block from the file system | |||
| 1360 | */ | |||
| 1361 | void | |||
| 1362 | rdfs(daddr32_t bno, int size, void *bf) | |||
| 1363 | { | |||
| 1364 | int n; | |||
| 1365 | off_t offset; | |||
| 1366 | ||||
| 1367 | offset = bno; | |||
| 1368 | n = pread(fd, bf, size, offset * sectorsize); | |||
| 1369 | if (n != size) | |||
| 1370 | err(EXIT_FAILURE1, "%s: read error for sector %" PRId64"lld", | |||
| 1371 | __func__, (int64_t)bno); | |||
| 1372 | } | |||
| 1373 | ||||
| 1374 | /* | |||
| 1375 | * Write a block to the file system | |||
| 1376 | */ | |||
| 1377 | void | |||
| 1378 | wtfs(daddr32_t bno, int size, void *bf) | |||
| 1379 | { | |||
| 1380 | int n; | |||
| 1381 | off_t offset; | |||
| 1382 | ||||
| 1383 | if (Nflag) | |||
| 1384 | return; | |||
| 1385 | offset = bno; | |||
| 1386 | n = pwrite(fd, bf, size, offset * sectorsize); | |||
| 1387 | if (n != size) | |||
| 1388 | err(EXIT_FAILURE1, "%s: write error for sector %" PRId64"lld", | |||
| 1389 | __func__, (int64_t)bno); | |||
| 1390 | } | |||
| 1391 | ||||
| 1392 | int | |||
| 1393 | ilog2(uint val) | |||
| 1394 | { | |||
| 1395 | ||||
| 1396 | if (val == 0 || !powerof2(val)((((val)-1)&(val))==0)) | |||
| 1397 | errx(EXIT_FAILURE1, "%s: %u is not a power of 2\n", | |||
| 1398 | __func__, val); | |||
| 1399 | ||||
| 1400 | return ffs(val) - 1; | |||
| 1401 | } | |||
| 1402 | ||||
| 1403 | /* | |||
| 1404 | * int skpc(int mask, size_t size, uint8_t *cp) | |||
| 1405 | * | |||
| 1406 | * Locate an unsigned character of value mask inside cp[]. | |||
| 1407 | * (from src/sys/lib/libkern/skpc.c) | |||
| 1408 | */ | |||
| 1409 | int | |||
| 1410 | skpc(int mask, size_t size, uint8_t *cp) | |||
| 1411 | { | |||
| 1412 | uint8_t *end; | |||
| 1413 | ||||
| 1414 | end = &cp[size]; | |||
| 1415 | while (cp < end && *cp == (uint8_t)mask) | |||
| 1416 | cp++; | |||
| 1417 | ||||
| 1418 | return end - cp; | |||
| 1419 | } | |||
| 1420 | ||||
| 1421 | static void | |||
| 1422 | uuid_get(struct m_ext2fs *sb) | |||
| 1423 | { | |||
| 1424 | unsigned char buf[sizeof(sb->e2fs.e2fs_uuid)]; | |||
| 1425 | ||||
| 1426 | arc4random_buf(buf, sizeof(buf)); | |||
| 1427 | /* UUID version 4: random */ | |||
| 1428 | buf[6] &= 0x0f; | |||
| 1429 | buf[6] |= 0x40; | |||
| 1430 | /* RFC4122 variant */ | |||
| 1431 | buf[8] &= 0x3f; | |||
| 1432 | buf[8] |= 0x80; | |||
| 1433 | memcpy(sb->e2fs.e2fs_uuid, buf, sizeof(sb->e2fs.e2fs_uuid)); | |||
| 1434 | } |