1 1.34 rin /* $NetBSD: ext2fs.c,v 1.34 2022/04/29 07:42:07 rin Exp $ */ 2 1.1 tsutsui 3 1.1 tsutsui /* 4 1.1 tsutsui * Copyright (c) 1997 Manuel Bouyer. 5 1.1 tsutsui * 6 1.1 tsutsui * Redistribution and use in source and binary forms, with or without 7 1.1 tsutsui * modification, are permitted provided that the following conditions 8 1.1 tsutsui * are met: 9 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright 10 1.1 tsutsui * notice, this list of conditions and the following disclaimer. 11 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the 13 1.1 tsutsui * documentation and/or other materials provided with the distribution. 14 1.1 tsutsui * 15 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 tsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 tsutsui * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 tsutsui * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 tsutsui * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.1 tsutsui * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.1 tsutsui * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.1 tsutsui * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.1 tsutsui * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.1 tsutsui * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 tsutsui */ 26 1.1 tsutsui 27 1.1 tsutsui /*- 28 1.1 tsutsui * Copyright (c) 1993 29 1.1 tsutsui * The Regents of the University of California. All rights reserved. 30 1.1 tsutsui * 31 1.1 tsutsui * This code is derived from software contributed to Berkeley by 32 1.1 tsutsui * The Mach Operating System project at Carnegie-Mellon University. 33 1.1 tsutsui * 34 1.1 tsutsui * Redistribution and use in source and binary forms, with or without 35 1.1 tsutsui * modification, are permitted provided that the following conditions 36 1.1 tsutsui * are met: 37 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright 38 1.1 tsutsui * notice, this list of conditions and the following disclaimer. 39 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright 40 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the 41 1.1 tsutsui * documentation and/or other materials provided with the distribution. 42 1.1 tsutsui * 3. Neither the name of the University nor the names of its contributors 43 1.1 tsutsui * may be used to endorse or promote products derived from this software 44 1.1 tsutsui * without specific prior written permission. 45 1.1 tsutsui * 46 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 47 1.1 tsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 1.1 tsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 1.1 tsutsui * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 50 1.1 tsutsui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 1.1 tsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 1.1 tsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 1.1 tsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 1.1 tsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 1.1 tsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 1.1 tsutsui * SUCH DAMAGE. 57 1.1 tsutsui * 58 1.1 tsutsui * 59 1.1 tsutsui * Copyright (c) 1990, 1991 Carnegie Mellon University 60 1.1 tsutsui * All Rights Reserved. 61 1.1 tsutsui * 62 1.1 tsutsui * Author: David Golub 63 1.1 tsutsui * 64 1.1 tsutsui * Permission to use, copy, modify and distribute this software and its 65 1.1 tsutsui * documentation is hereby granted, provided that both the copyright 66 1.1 tsutsui * notice and this permission notice appear in all copies of the 67 1.1 tsutsui * software, derivative works or modified versions, and any portions 68 1.1 tsutsui * thereof, and that both notices appear in supporting documentation. 69 1.1 tsutsui * 70 1.1 tsutsui * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 71 1.1 tsutsui * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 72 1.1 tsutsui * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 73 1.1 tsutsui * 74 1.1 tsutsui * Carnegie Mellon requests users of this software to return to 75 1.1 tsutsui * 76 1.1 tsutsui * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 77 1.1 tsutsui * School of Computer Science 78 1.1 tsutsui * Carnegie Mellon University 79 1.1 tsutsui * Pittsburgh PA 15213-3890 80 1.1 tsutsui * 81 1.1 tsutsui * any improvements or extensions that they make and grant Carnegie the 82 1.1 tsutsui * rights to redistribute these changes. 83 1.1 tsutsui */ 84 1.1 tsutsui 85 1.1 tsutsui /* 86 1.1 tsutsui * Stand-alone file reading package for Ext2 file system. 87 1.1 tsutsui */ 88 1.1 tsutsui 89 1.1 tsutsui /* #define EXT2FS_DEBUG */ 90 1.1 tsutsui 91 1.1 tsutsui #include <sys/param.h> 92 1.1 tsutsui #include <sys/time.h> 93 1.1 tsutsui #include <ufs/ext2fs/ext2fs_dinode.h> 94 1.1 tsutsui #include <ufs/ext2fs/ext2fs_dir.h> 95 1.1 tsutsui #include <ufs/ext2fs/ext2fs.h> 96 1.1 tsutsui #ifdef _STANDALONE 97 1.1 tsutsui #include <lib/libkern/libkern.h> 98 1.1 tsutsui #else 99 1.1 tsutsui #include <string.h> 100 1.1 tsutsui #endif 101 1.1 tsutsui 102 1.1 tsutsui #include "stand.h" 103 1.1 tsutsui #include "ext2fs.h" 104 1.1 tsutsui 105 1.1 tsutsui #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK) 106 1.1 tsutsui #define LIBSA_NO_FS_SYMLINK 107 1.1 tsutsui #endif 108 1.1 tsutsui 109 1.1 tsutsui #if defined(LIBSA_NO_TWIDDLE) 110 1.1 tsutsui #define twiddle() 111 1.1 tsutsui #endif 112 1.1 tsutsui 113 1.1 tsutsui #ifndef indp_t 114 1.1 tsutsui #define indp_t int32_t 115 1.1 tsutsui #endif 116 1.1 tsutsui typedef uint32_t ino32_t; 117 1.1 tsutsui #ifndef FSBTODB 118 1.17 dholland #define FSBTODB(fs, indp) EXT2_FSBTODB(fs, indp) 119 1.1 tsutsui #endif 120 1.1 tsutsui 121 1.1 tsutsui /* 122 1.1 tsutsui * To avoid having a lot of filesystem-block sized buffers lurking (which 123 1.1 tsutsui * could be 32k) we only keep a few entries of the indirect block map. 124 1.1 tsutsui * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block 125 1.1 tsutsui * ~13 times pulling in a 6M kernel. 126 1.1 tsutsui * The cache size must be smaller than the smallest filesystem block, 127 1.1 tsutsui * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks). 128 1.1 tsutsui */ 129 1.1 tsutsui #define LN2_IND_CACHE_SZ 6 130 1.1 tsutsui #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ) 131 1.1 tsutsui #define IND_CACHE_MASK (IND_CACHE_SZ - 1) 132 1.1 tsutsui 133 1.1 tsutsui /* 134 1.1 tsutsui * In-core open file. 135 1.1 tsutsui */ 136 1.1 tsutsui struct file { 137 1.1 tsutsui off_t f_seekp; /* seek pointer */ 138 1.1 tsutsui struct m_ext2fs *f_fs; /* pointer to super-block */ 139 1.1 tsutsui struct ext2fs_dinode f_di; /* copy of on-disk inode */ 140 1.1 tsutsui uint f_nishift; /* for blocks in indirect block */ 141 1.1 tsutsui indp_t f_ind_cache_block; 142 1.1 tsutsui indp_t f_ind_cache[IND_CACHE_SZ]; 143 1.1 tsutsui 144 1.1 tsutsui char *f_buf; /* buffer for data block */ 145 1.1 tsutsui size_t f_buf_size; /* size of data block */ 146 1.1 tsutsui daddr_t f_buf_blkno; /* block number of data block */ 147 1.1 tsutsui }; 148 1.1 tsutsui 149 1.11 tsutsui 150 1.1 tsutsui static int read_inode(ino32_t, struct open_file *); 151 1.1 tsutsui static int block_map(struct open_file *, indp_t, indp_t *); 152 1.1 tsutsui static int buf_read_file(struct open_file *, char **, size_t *); 153 1.1 tsutsui static int search_directory(const char *, int, struct open_file *, ino32_t *); 154 1.1 tsutsui static int read_sblock(struct open_file *, struct m_ext2fs *); 155 1.1 tsutsui static int read_gdblock(struct open_file *, struct m_ext2fs *); 156 1.1 tsutsui #ifdef EXT2FS_DEBUG 157 1.1 tsutsui static void dump_sblock(struct m_ext2fs *); 158 1.1 tsutsui #endif 159 1.1 tsutsui 160 1.1 tsutsui /* 161 1.1 tsutsui * Read a new inode into a file structure. 162 1.1 tsutsui */ 163 1.1 tsutsui static int 164 1.1 tsutsui read_inode(ino32_t inumber, struct open_file *f) 165 1.1 tsutsui { 166 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 167 1.1 tsutsui struct m_ext2fs *fs = fp->f_fs; 168 1.1 tsutsui char *buf; 169 1.1 tsutsui size_t rsize; 170 1.1 tsutsui int rc; 171 1.1 tsutsui daddr_t inode_sector; 172 1.1 tsutsui struct ext2fs_dinode *dip; 173 1.1 tsutsui 174 1.1 tsutsui inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); 175 1.1 tsutsui 176 1.1 tsutsui /* 177 1.1 tsutsui * Read inode and save it. 178 1.1 tsutsui */ 179 1.1 tsutsui buf = fp->f_buf; 180 1.1 tsutsui twiddle(); 181 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 182 1.1 tsutsui inode_sector, fs->e2fs_bsize, buf, &rsize); 183 1.1 tsutsui if (rc) 184 1.1 tsutsui return rc; 185 1.26 christos if (rsize != (size_t)fs->e2fs_bsize) 186 1.1 tsutsui return EIO; 187 1.1 tsutsui 188 1.7 tsutsui dip = (struct ext2fs_dinode *)(buf + 189 1.7 tsutsui EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, inumber)); 190 1.22 nonaka e2fs_iload(dip, &fp->f_di, EXT2_DINODE_SIZE(fs)); 191 1.1 tsutsui 192 1.1 tsutsui /* 193 1.1 tsutsui * Clear out the old buffers 194 1.1 tsutsui */ 195 1.1 tsutsui fp->f_ind_cache_block = ~0; 196 1.1 tsutsui fp->f_buf_blkno = -1; 197 1.1 tsutsui return rc; 198 1.1 tsutsui } 199 1.1 tsutsui 200 1.1 tsutsui /* 201 1.1 tsutsui * Given an offset in a file, find the disk block number that 202 1.1 tsutsui * contains that block. 203 1.1 tsutsui */ 204 1.1 tsutsui static int 205 1.1 tsutsui block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p) 206 1.1 tsutsui { 207 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 208 1.1 tsutsui struct m_ext2fs *fs = fp->f_fs; 209 1.1 tsutsui uint level; 210 1.1 tsutsui indp_t ind_cache; 211 1.1 tsutsui indp_t ind_block_num; 212 1.1 tsutsui size_t rsize; 213 1.1 tsutsui int rc; 214 1.1 tsutsui indp_t *buf = (void *)fp->f_buf; 215 1.1 tsutsui 216 1.1 tsutsui /* 217 1.1 tsutsui * Index structure of an inode: 218 1.1 tsutsui * 219 1.14 dholland * e2di_blocks[0..EXT2FS_NDADDR-1] 220 1.15 tsutsui * hold block numbers for blocks 221 1.15 tsutsui * 0..EXT2FS_NDADDR-1 222 1.1 tsutsui * 223 1.14 dholland * e2di_blocks[EXT2FS_NDADDR+0] 224 1.15 tsutsui * block EXT2FS_NDADDR+0 is the single indirect block 225 1.15 tsutsui * holds block numbers for blocks 226 1.16 dholland * EXT2FS_NDADDR .. EXT2FS_NDADDR + EXT2_NINDIR(fs)-1 227 1.1 tsutsui * 228 1.14 dholland * e2di_blocks[EXT2FS_NDADDR+1] 229 1.15 tsutsui * block EXT2FS_NDADDR+1 is the double indirect block 230 1.15 tsutsui * holds block numbers for INDEX blocks for blocks 231 1.16 dholland * EXT2FS_NDADDR + EXT2_NINDIR(fs) .. 232 1.16 dholland * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 - 1 233 1.1 tsutsui * 234 1.14 dholland * e2di_blocks[EXT2FS_NDADDR+2] 235 1.15 tsutsui * block EXT2FS_NDADDR+2 is the triple indirect block 236 1.15 tsutsui * holds block numbers for double-indirect 237 1.15 tsutsui * blocks for blocks 238 1.16 dholland * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 .. 239 1.16 dholland * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 240 1.16 dholland * + EXT2_NINDIR(fs)**3 - 1 241 1.1 tsutsui */ 242 1.1 tsutsui 243 1.14 dholland if (file_block < EXT2FS_NDADDR) { 244 1.1 tsutsui /* Direct block. */ 245 1.1 tsutsui *disk_block_p = fs2h32(fp->f_di.e2di_blocks[file_block]); 246 1.1 tsutsui return 0; 247 1.1 tsutsui } 248 1.1 tsutsui 249 1.14 dholland file_block -= EXT2FS_NDADDR; 250 1.1 tsutsui 251 1.1 tsutsui ind_cache = file_block >> LN2_IND_CACHE_SZ; 252 1.1 tsutsui if (ind_cache == fp->f_ind_cache_block) { 253 1.2 tsutsui *disk_block_p = 254 1.2 tsutsui fs2h32(fp->f_ind_cache[file_block & IND_CACHE_MASK]); 255 1.1 tsutsui return 0; 256 1.1 tsutsui } 257 1.1 tsutsui 258 1.1 tsutsui for (level = 0;;) { 259 1.1 tsutsui level += fp->f_nishift; 260 1.1 tsutsui if (file_block < (indp_t)1 << level) 261 1.1 tsutsui break; 262 1.14 dholland if (level > EXT2FS_NIADDR * fp->f_nishift) 263 1.1 tsutsui /* Block number too high */ 264 1.1 tsutsui return EFBIG; 265 1.1 tsutsui file_block -= (indp_t)1 << level; 266 1.1 tsutsui } 267 1.1 tsutsui 268 1.1 tsutsui ind_block_num = 269 1.15 tsutsui fs2h32(fp->f_di.e2di_blocks[EXT2FS_NDADDR + 270 1.15 tsutsui (level / fp->f_nishift - 1)]); 271 1.1 tsutsui 272 1.1 tsutsui for (;;) { 273 1.1 tsutsui level -= fp->f_nishift; 274 1.1 tsutsui if (ind_block_num == 0) { 275 1.1 tsutsui *disk_block_p = 0; /* missing */ 276 1.1 tsutsui return 0; 277 1.1 tsutsui } 278 1.1 tsutsui 279 1.1 tsutsui twiddle(); 280 1.1 tsutsui /* 281 1.1 tsutsui * If we were feeling brave, we could work out the number 282 1.1 tsutsui * of the disk sector and read a single disk sector instead 283 1.1 tsutsui * of a filesystem block. 284 1.1 tsutsui * However we don't do this very often anyway... 285 1.1 tsutsui */ 286 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 287 1.1 tsutsui FSBTODB(fp->f_fs, ind_block_num), fs->e2fs_bsize, 288 1.1 tsutsui buf, &rsize); 289 1.1 tsutsui if (rc) 290 1.1 tsutsui return rc; 291 1.26 christos if (rsize != (size_t)fs->e2fs_bsize) 292 1.1 tsutsui return EIO; 293 1.2 tsutsui ind_block_num = fs2h32(buf[file_block >> level]); 294 1.1 tsutsui if (level == 0) 295 1.1 tsutsui break; 296 1.1 tsutsui file_block &= (1 << level) - 1; 297 1.1 tsutsui } 298 1.1 tsutsui 299 1.1 tsutsui /* Save the part of the block that contains this sector */ 300 1.1 tsutsui memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK], 301 1.1 tsutsui IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); 302 1.1 tsutsui fp->f_ind_cache_block = ind_cache; 303 1.1 tsutsui 304 1.1 tsutsui *disk_block_p = ind_block_num; 305 1.1 tsutsui 306 1.1 tsutsui return 0; 307 1.1 tsutsui } 308 1.1 tsutsui 309 1.1 tsutsui /* 310 1.1 tsutsui * Read a portion of a file into an internal buffer. 311 1.1 tsutsui * Return the location in the buffer and the amount in the buffer. 312 1.1 tsutsui */ 313 1.1 tsutsui static int 314 1.1 tsutsui buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 315 1.1 tsutsui { 316 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 317 1.1 tsutsui struct m_ext2fs *fs = fp->f_fs; 318 1.1 tsutsui long off; 319 1.1 tsutsui indp_t file_block; 320 1.19 christos indp_t disk_block = 0; /* XXX: gcc */ 321 1.26 christos size_t block_size, tsz; 322 1.1 tsutsui int rc; 323 1.1 tsutsui 324 1.16 dholland off = ext2_blkoff(fs, fp->f_seekp); 325 1.18 dholland file_block = ext2_lblkno(fs, fp->f_seekp); 326 1.1 tsutsui block_size = fs->e2fs_bsize; /* no fragment */ 327 1.1 tsutsui 328 1.1 tsutsui if (file_block != fp->f_buf_blkno) { 329 1.1 tsutsui rc = block_map(f, file_block, &disk_block); 330 1.1 tsutsui if (rc) 331 1.1 tsutsui return rc; 332 1.1 tsutsui 333 1.1 tsutsui if (disk_block == 0) { 334 1.1 tsutsui memset(fp->f_buf, 0, block_size); 335 1.1 tsutsui fp->f_buf_size = block_size; 336 1.1 tsutsui } else { 337 1.1 tsutsui twiddle(); 338 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 339 1.1 tsutsui FSBTODB(fs, disk_block), 340 1.1 tsutsui block_size, fp->f_buf, &fp->f_buf_size); 341 1.1 tsutsui if (rc) 342 1.1 tsutsui return rc; 343 1.1 tsutsui } 344 1.1 tsutsui 345 1.1 tsutsui fp->f_buf_blkno = file_block; 346 1.1 tsutsui } 347 1.1 tsutsui 348 1.1 tsutsui /* 349 1.1 tsutsui * Return address of byte in buffer corresponding to 350 1.1 tsutsui * offset, and size of remainder of buffer after that 351 1.1 tsutsui * byte. 352 1.1 tsutsui */ 353 1.1 tsutsui *buf_p = fp->f_buf + off; 354 1.1 tsutsui *size_p = block_size - off; 355 1.1 tsutsui 356 1.1 tsutsui /* 357 1.1 tsutsui * But truncate buffer at end of file. 358 1.1 tsutsui */ 359 1.1 tsutsui /* XXX should handle LARGEFILE */ 360 1.26 christos tsz = (size_t)(fp->f_di.e2di_size - fp->f_seekp); 361 1.26 christos if (*size_p > tsz) 362 1.26 christos *size_p = tsz; 363 1.1 tsutsui 364 1.1 tsutsui return 0; 365 1.1 tsutsui } 366 1.1 tsutsui 367 1.1 tsutsui /* 368 1.1 tsutsui * Search a directory for a name and return its 369 1.1 tsutsui * inode number. 370 1.1 tsutsui */ 371 1.1 tsutsui static int 372 1.1 tsutsui search_directory(const char *name, int length, struct open_file *f, 373 1.1 tsutsui ino32_t *inumber_p) 374 1.1 tsutsui { 375 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 376 1.1 tsutsui struct ext2fs_direct *dp; 377 1.1 tsutsui struct ext2fs_direct *edp; 378 1.1 tsutsui char *buf; 379 1.1 tsutsui size_t buf_size; 380 1.1 tsutsui int namlen; 381 1.1 tsutsui int rc; 382 1.1 tsutsui 383 1.1 tsutsui fp->f_seekp = 0; 384 1.1 tsutsui /* XXX should handle LARGEFILE */ 385 1.1 tsutsui while (fp->f_seekp < (off_t)fp->f_di.e2di_size) { 386 1.1 tsutsui rc = buf_read_file(f, &buf, &buf_size); 387 1.1 tsutsui if (rc) 388 1.1 tsutsui return rc; 389 1.1 tsutsui 390 1.1 tsutsui dp = (struct ext2fs_direct *)buf; 391 1.1 tsutsui edp = (struct ext2fs_direct *)(buf + buf_size); 392 1.1 tsutsui for (; dp < edp; 393 1.1 tsutsui dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) { 394 1.1 tsutsui if (fs2h16(dp->e2d_reclen) <= 0) 395 1.1 tsutsui break; 396 1.1 tsutsui if (fs2h32(dp->e2d_ino) == (ino32_t)0) 397 1.1 tsutsui continue; 398 1.1 tsutsui namlen = dp->e2d_namlen; 399 1.1 tsutsui if (namlen == length && 400 1.1 tsutsui !memcmp(name, dp->e2d_name, length)) { 401 1.1 tsutsui /* found entry */ 402 1.1 tsutsui *inumber_p = fs2h32(dp->e2d_ino); 403 1.1 tsutsui return 0; 404 1.1 tsutsui } 405 1.1 tsutsui } 406 1.1 tsutsui fp->f_seekp += buf_size; 407 1.1 tsutsui } 408 1.1 tsutsui return ENOENT; 409 1.1 tsutsui } 410 1.1 tsutsui 411 1.1 tsutsui int 412 1.1 tsutsui read_sblock(struct open_file *f, struct m_ext2fs *fs) 413 1.1 tsutsui { 414 1.1 tsutsui static uint8_t sbbuf[SBSIZE]; 415 1.1 tsutsui struct ext2fs ext2fs; 416 1.1 tsutsui size_t buf_size; 417 1.1 tsutsui int rc; 418 1.1 tsutsui 419 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 420 1.34 rin SBOFF / GETSECSIZE(f), SBSIZE, sbbuf, &buf_size); 421 1.1 tsutsui if (rc) 422 1.1 tsutsui return rc; 423 1.1 tsutsui 424 1.1 tsutsui if (buf_size != SBSIZE) 425 1.1 tsutsui return EIO; 426 1.1 tsutsui 427 1.1 tsutsui e2fs_sbload((void *)sbbuf, &ext2fs); 428 1.1 tsutsui if (ext2fs.e2fs_magic != E2FS_MAGIC) 429 1.1 tsutsui return EINVAL; 430 1.1 tsutsui if (ext2fs.e2fs_rev > E2FS_REV1 || 431 1.1 tsutsui (ext2fs.e2fs_rev == E2FS_REV1 && 432 1.1 tsutsui (ext2fs.e2fs_first_ino != EXT2_FIRSTINO || 433 1.6 christos (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) || 434 1.1 tsutsui ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) { 435 1.1 tsutsui return ENODEV; 436 1.1 tsutsui } 437 1.1 tsutsui 438 1.1 tsutsui e2fs_sbload((void *)sbbuf, &fs->e2fs); 439 1.1 tsutsui /* compute in-memory m_ext2fs values */ 440 1.1 tsutsui fs->e2fs_ncg = 441 1.1 tsutsui howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, 442 1.1 tsutsui fs->e2fs.e2fs_bpg); 443 1.1 tsutsui /* XXX assume hw bsize = 512 */ 444 1.1 tsutsui fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; 445 1.1 tsutsui fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize; 446 1.1 tsutsui fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; 447 1.1 tsutsui fs->e2fs_qbmask = fs->e2fs_bsize - 1; 448 1.1 tsutsui fs->e2fs_bmask = ~fs->e2fs_qbmask; 449 1.1 tsutsui fs->e2fs_ngdb = 450 1.1 tsutsui howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); 451 1.6 christos fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size; 452 1.1 tsutsui fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb; 453 1.1 tsutsui 454 1.1 tsutsui return 0; 455 1.1 tsutsui } 456 1.1 tsutsui 457 1.1 tsutsui int 458 1.1 tsutsui read_gdblock(struct open_file *f, struct m_ext2fs *fs) 459 1.1 tsutsui { 460 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 461 1.1 tsutsui size_t rsize; 462 1.1 tsutsui uint gdpb; 463 1.1 tsutsui int i, rc; 464 1.1 tsutsui 465 1.1 tsutsui gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd); 466 1.1 tsutsui 467 1.1 tsutsui for (i = 0; i < fs->e2fs_ngdb; i++) { 468 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 469 1.1 tsutsui FSBTODB(fs, fs->e2fs.e2fs_first_dblock + 470 1.1 tsutsui 1 /* superblock */ + i), 471 1.1 tsutsui fs->e2fs_bsize, fp->f_buf, &rsize); 472 1.1 tsutsui if (rc) 473 1.1 tsutsui return rc; 474 1.26 christos if (rsize != (size_t)fs->e2fs_bsize) 475 1.1 tsutsui return EIO; 476 1.1 tsutsui 477 1.1 tsutsui e2fs_cgload((struct ext2_gd *)fp->f_buf, 478 1.1 tsutsui &fs->e2fs_gd[i * gdpb], 479 1.1 tsutsui (i == (fs->e2fs_ngdb - 1)) ? 480 1.1 tsutsui (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd): 481 1.26 christos (size_t)fs->e2fs_bsize); 482 1.1 tsutsui } 483 1.1 tsutsui 484 1.1 tsutsui return 0; 485 1.1 tsutsui } 486 1.1 tsutsui 487 1.1 tsutsui 488 1.1 tsutsui /* 489 1.1 tsutsui * Open a file. 490 1.1 tsutsui */ 491 1.10 joerg __compactcall int 492 1.1 tsutsui ext2fs_open(const char *path, struct open_file *f) 493 1.1 tsutsui { 494 1.1 tsutsui #ifndef LIBSA_FS_SINGLECOMPONENT 495 1.1 tsutsui const char *cp, *ncp; 496 1.1 tsutsui int c; 497 1.1 tsutsui #endif 498 1.1 tsutsui ino32_t inumber; 499 1.1 tsutsui struct file *fp; 500 1.1 tsutsui struct m_ext2fs *fs; 501 1.1 tsutsui int rc; 502 1.1 tsutsui #ifndef LIBSA_NO_FS_SYMLINK 503 1.1 tsutsui ino32_t parent_inumber; 504 1.1 tsutsui int nlinks = 0; 505 1.1 tsutsui char namebuf[MAXPATHLEN+1]; 506 1.1 tsutsui char *buf; 507 1.1 tsutsui #endif 508 1.1 tsutsui 509 1.1 tsutsui /* allocate file system specific data structure */ 510 1.1 tsutsui fp = alloc(sizeof(struct file)); 511 1.1 tsutsui memset(fp, 0, sizeof(struct file)); 512 1.1 tsutsui f->f_fsdata = (void *)fp; 513 1.1 tsutsui 514 1.1 tsutsui /* allocate space and read super block */ 515 1.3 tsutsui fs = alloc(sizeof(*fs)); 516 1.9 jakllsch memset(fs, 0, sizeof(*fs)); 517 1.1 tsutsui fp->f_fs = fs; 518 1.1 tsutsui twiddle(); 519 1.1 tsutsui 520 1.1 tsutsui rc = read_sblock(f, fs); 521 1.1 tsutsui if (rc) 522 1.1 tsutsui goto out; 523 1.1 tsutsui 524 1.1 tsutsui #ifdef EXT2FS_DEBUG 525 1.1 tsutsui dump_sblock(fs); 526 1.1 tsutsui #endif 527 1.1 tsutsui 528 1.1 tsutsui /* alloc a block sized buffer used for all fs transfers */ 529 1.1 tsutsui fp->f_buf = alloc(fs->e2fs_bsize); 530 1.1 tsutsui 531 1.1 tsutsui /* read group descriptor blocks */ 532 1.1 tsutsui fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg); 533 1.1 tsutsui rc = read_gdblock(f, fs); 534 1.1 tsutsui if (rc) 535 1.1 tsutsui goto out; 536 1.1 tsutsui 537 1.1 tsutsui /* 538 1.1 tsutsui * Calculate indirect block levels. 539 1.1 tsutsui */ 540 1.1 tsutsui { 541 1.1 tsutsui indp_t mult; 542 1.1 tsutsui int ln2; 543 1.1 tsutsui 544 1.1 tsutsui /* 545 1.1 tsutsui * We note that the number of indirect blocks is always 546 1.1 tsutsui * a power of 2. This lets us use shifts and masks instead 547 1.30 skrll * of divide and remainder and avoids pulling in the 548 1.1 tsutsui * 64bit division routine into the boot code. 549 1.1 tsutsui */ 550 1.16 dholland mult = EXT2_NINDIR(fs); 551 1.1 tsutsui #ifdef DEBUG 552 1.1 tsutsui if (!powerof2(mult)) { 553 1.1 tsutsui /* Hummm was't a power of 2 */ 554 1.1 tsutsui rc = EINVAL; 555 1.1 tsutsui goto out; 556 1.1 tsutsui } 557 1.1 tsutsui #endif 558 1.1 tsutsui for (ln2 = 0; mult != 1; ln2++) 559 1.1 tsutsui mult >>= 1; 560 1.1 tsutsui 561 1.1 tsutsui fp->f_nishift = ln2; 562 1.1 tsutsui } 563 1.1 tsutsui 564 1.1 tsutsui inumber = EXT2_ROOTINO; 565 1.1 tsutsui if ((rc = read_inode(inumber, f)) != 0) 566 1.1 tsutsui goto out; 567 1.1 tsutsui 568 1.1 tsutsui #ifndef LIBSA_FS_SINGLECOMPONENT 569 1.1 tsutsui cp = path; 570 1.1 tsutsui while (*cp) { 571 1.1 tsutsui 572 1.1 tsutsui /* 573 1.1 tsutsui * Remove extra separators 574 1.1 tsutsui */ 575 1.1 tsutsui while (*cp == '/') 576 1.1 tsutsui cp++; 577 1.1 tsutsui if (*cp == '\0') 578 1.1 tsutsui break; 579 1.1 tsutsui 580 1.1 tsutsui /* 581 1.1 tsutsui * Check that current node is a directory. 582 1.1 tsutsui */ 583 1.1 tsutsui if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) { 584 1.1 tsutsui rc = ENOTDIR; 585 1.1 tsutsui goto out; 586 1.1 tsutsui } 587 1.1 tsutsui 588 1.1 tsutsui /* 589 1.1 tsutsui * Get next component of path name. 590 1.1 tsutsui */ 591 1.1 tsutsui ncp = cp; 592 1.1 tsutsui while ((c = *cp) != '\0' && c != '/') 593 1.1 tsutsui cp++; 594 1.1 tsutsui 595 1.1 tsutsui /* 596 1.1 tsutsui * Look up component in current directory. 597 1.1 tsutsui * Save directory inumber in case we find a 598 1.1 tsutsui * symbolic link. 599 1.1 tsutsui */ 600 1.1 tsutsui #ifndef LIBSA_NO_FS_SYMLINK 601 1.1 tsutsui parent_inumber = inumber; 602 1.1 tsutsui #endif 603 1.1 tsutsui rc = search_directory(ncp, cp - ncp, f, &inumber); 604 1.1 tsutsui if (rc) 605 1.1 tsutsui goto out; 606 1.1 tsutsui 607 1.1 tsutsui /* 608 1.1 tsutsui * Open next component. 609 1.1 tsutsui */ 610 1.1 tsutsui if ((rc = read_inode(inumber, f)) != 0) 611 1.1 tsutsui goto out; 612 1.1 tsutsui 613 1.1 tsutsui #ifndef LIBSA_NO_FS_SYMLINK 614 1.1 tsutsui /* 615 1.1 tsutsui * Check for symbolic link. 616 1.1 tsutsui */ 617 1.1 tsutsui if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) { 618 1.1 tsutsui /* XXX should handle LARGEFILE */ 619 1.26 christos size_t link_len = fp->f_di.e2di_size; 620 1.26 christos size_t len; 621 1.1 tsutsui 622 1.1 tsutsui len = strlen(cp); 623 1.1 tsutsui 624 1.1 tsutsui if (link_len + len > MAXPATHLEN || 625 1.1 tsutsui ++nlinks > MAXSYMLINKS) { 626 1.1 tsutsui rc = ENOENT; 627 1.1 tsutsui goto out; 628 1.1 tsutsui } 629 1.1 tsutsui 630 1.1 tsutsui memmove(&namebuf[link_len], cp, len + 1); 631 1.1 tsutsui 632 1.1 tsutsui if (link_len < EXT2_MAXSYMLINKLEN) { 633 1.1 tsutsui memcpy(namebuf, fp->f_di.e2di_blocks, link_len); 634 1.1 tsutsui } else { 635 1.1 tsutsui /* 636 1.1 tsutsui * Read file for symbolic link 637 1.1 tsutsui */ 638 1.1 tsutsui size_t buf_size; 639 1.1 tsutsui indp_t disk_block; 640 1.1 tsutsui 641 1.1 tsutsui buf = fp->f_buf; 642 1.1 tsutsui rc = block_map(f, (indp_t)0, &disk_block); 643 1.1 tsutsui if (rc) 644 1.1 tsutsui goto out; 645 1.1 tsutsui 646 1.1 tsutsui twiddle(); 647 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, 648 1.1 tsutsui F_READ, FSBTODB(fs, disk_block), 649 1.1 tsutsui fs->e2fs_bsize, buf, &buf_size); 650 1.1 tsutsui if (rc) 651 1.1 tsutsui goto out; 652 1.1 tsutsui 653 1.1 tsutsui memcpy(namebuf, buf, link_len); 654 1.1 tsutsui } 655 1.1 tsutsui 656 1.1 tsutsui /* 657 1.1 tsutsui * If relative pathname, restart at parent directory. 658 1.1 tsutsui * If absolute pathname, restart at root. 659 1.1 tsutsui */ 660 1.1 tsutsui cp = namebuf; 661 1.1 tsutsui if (*cp != '/') 662 1.1 tsutsui inumber = parent_inumber; 663 1.1 tsutsui else 664 1.1 tsutsui inumber = (ino32_t)EXT2_ROOTINO; 665 1.1 tsutsui 666 1.1 tsutsui if ((rc = read_inode(inumber, f)) != 0) 667 1.1 tsutsui goto out; 668 1.1 tsutsui } 669 1.1 tsutsui #endif /* !LIBSA_NO_FS_SYMLINK */ 670 1.1 tsutsui } 671 1.1 tsutsui 672 1.1 tsutsui /* 673 1.1 tsutsui * Found terminal component. 674 1.1 tsutsui */ 675 1.1 tsutsui rc = 0; 676 1.1 tsutsui 677 1.1 tsutsui #else /* !LIBSA_FS_SINGLECOMPONENT */ 678 1.1 tsutsui 679 1.1 tsutsui /* look up component in the current (root) directory */ 680 1.1 tsutsui rc = search_directory(path, strlen(path), f, &inumber); 681 1.1 tsutsui if (rc) 682 1.1 tsutsui goto out; 683 1.1 tsutsui 684 1.1 tsutsui /* open it */ 685 1.1 tsutsui rc = read_inode(inumber, f); 686 1.1 tsutsui 687 1.1 tsutsui #endif /* !LIBSA_FS_SINGLECOMPONENT */ 688 1.1 tsutsui 689 1.1 tsutsui fp->f_seekp = 0; /* reset seek pointer */ 690 1.1 tsutsui 691 1.1 tsutsui out: 692 1.1 tsutsui if (rc) 693 1.1 tsutsui ext2fs_close(f); 694 1.13 dsl else 695 1.28 pgoyette fsmod = "ufs/ext2fs"; 696 1.1 tsutsui return rc; 697 1.1 tsutsui } 698 1.1 tsutsui 699 1.10 joerg __compactcall int 700 1.1 tsutsui ext2fs_close(struct open_file *f) 701 1.1 tsutsui { 702 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 703 1.1 tsutsui 704 1.1 tsutsui f->f_fsdata = NULL; 705 1.1 tsutsui if (fp == NULL) 706 1.1 tsutsui return 0; 707 1.1 tsutsui 708 1.4 tsutsui if (fp->f_fs->e2fs_gd) 709 1.4 tsutsui dealloc(fp->f_fs->e2fs_gd, 710 1.4 tsutsui sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg); 711 1.1 tsutsui if (fp->f_buf) 712 1.1 tsutsui dealloc(fp->f_buf, fp->f_fs->e2fs_bsize); 713 1.4 tsutsui dealloc(fp->f_fs, sizeof(*fp->f_fs)); 714 1.1 tsutsui dealloc(fp, sizeof(struct file)); 715 1.1 tsutsui return 0; 716 1.1 tsutsui } 717 1.1 tsutsui 718 1.1 tsutsui /* 719 1.1 tsutsui * Copy a portion of a file into kernel memory. 720 1.1 tsutsui * Cross block boundaries when necessary. 721 1.1 tsutsui */ 722 1.10 joerg __compactcall int 723 1.1 tsutsui ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid) 724 1.1 tsutsui { 725 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 726 1.1 tsutsui size_t csize; 727 1.1 tsutsui char *buf; 728 1.1 tsutsui size_t buf_size; 729 1.1 tsutsui int rc = 0; 730 1.1 tsutsui char *addr = start; 731 1.1 tsutsui 732 1.1 tsutsui while (size != 0) { 733 1.1 tsutsui /* XXX should handle LARGEFILE */ 734 1.1 tsutsui if (fp->f_seekp >= (off_t)fp->f_di.e2di_size) 735 1.1 tsutsui break; 736 1.1 tsutsui 737 1.1 tsutsui rc = buf_read_file(f, &buf, &buf_size); 738 1.1 tsutsui if (rc) 739 1.1 tsutsui break; 740 1.1 tsutsui 741 1.1 tsutsui csize = size; 742 1.1 tsutsui if (csize > buf_size) 743 1.1 tsutsui csize = buf_size; 744 1.1 tsutsui 745 1.1 tsutsui memcpy(addr, buf, csize); 746 1.1 tsutsui 747 1.1 tsutsui fp->f_seekp += csize; 748 1.1 tsutsui addr += csize; 749 1.1 tsutsui size -= csize; 750 1.1 tsutsui } 751 1.1 tsutsui if (resid) 752 1.1 tsutsui *resid = size; 753 1.1 tsutsui return rc; 754 1.1 tsutsui } 755 1.1 tsutsui 756 1.1 tsutsui /* 757 1.1 tsutsui * Not implemented. 758 1.1 tsutsui */ 759 1.1 tsutsui #ifndef LIBSA_NO_FS_WRITE 760 1.10 joerg __compactcall int 761 1.1 tsutsui ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid) 762 1.1 tsutsui { 763 1.1 tsutsui 764 1.1 tsutsui return EROFS; 765 1.1 tsutsui } 766 1.1 tsutsui #endif /* !LIBSA_NO_FS_WRITE */ 767 1.1 tsutsui 768 1.1 tsutsui #ifndef LIBSA_NO_FS_SEEK 769 1.10 joerg __compactcall off_t 770 1.1 tsutsui ext2fs_seek(struct open_file *f, off_t offset, int where) 771 1.1 tsutsui { 772 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 773 1.1 tsutsui 774 1.1 tsutsui switch (where) { 775 1.1 tsutsui case SEEK_SET: 776 1.1 tsutsui fp->f_seekp = offset; 777 1.1 tsutsui break; 778 1.1 tsutsui case SEEK_CUR: 779 1.1 tsutsui fp->f_seekp += offset; 780 1.1 tsutsui break; 781 1.1 tsutsui case SEEK_END: 782 1.1 tsutsui /* XXX should handle LARGEFILE */ 783 1.1 tsutsui fp->f_seekp = fp->f_di.e2di_size - offset; 784 1.1 tsutsui break; 785 1.1 tsutsui default: 786 1.1 tsutsui return -1; 787 1.1 tsutsui } 788 1.1 tsutsui return fp->f_seekp; 789 1.1 tsutsui } 790 1.1 tsutsui #endif /* !LIBSA_NO_FS_SEEK */ 791 1.1 tsutsui 792 1.10 joerg __compactcall int 793 1.1 tsutsui ext2fs_stat(struct open_file *f, struct stat *sb) 794 1.1 tsutsui { 795 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata; 796 1.1 tsutsui 797 1.1 tsutsui /* only important stuff */ 798 1.1 tsutsui memset(sb, 0, sizeof *sb); 799 1.1 tsutsui sb->st_mode = fp->f_di.e2di_mode; 800 1.1 tsutsui sb->st_uid = fp->f_di.e2di_uid; 801 1.1 tsutsui sb->st_gid = fp->f_di.e2di_gid; 802 1.1 tsutsui /* XXX should handle LARGEFILE */ 803 1.1 tsutsui sb->st_size = fp->f_di.e2di_size; 804 1.1 tsutsui return 0; 805 1.1 tsutsui } 806 1.1 tsutsui 807 1.11 tsutsui #if defined(LIBSA_ENABLE_LS_OP) 808 1.20 christos 809 1.20 christos #include "ls.h" 810 1.20 christos 811 1.20 christos static const char *const typestr[] = { 812 1.20 christos "unknown", 813 1.20 christos "REG", 814 1.20 christos "DIR", 815 1.20 christos "CHR", 816 1.20 christos "BLK", 817 1.20 christos "FIFO", 818 1.20 christos "SOCK", 819 1.20 christos "LNK" 820 1.20 christos }; 821 1.20 christos 822 1.11 tsutsui __compactcall void 823 1.11 tsutsui ext2fs_ls(struct open_file *f, const char *pattern) 824 1.11 tsutsui { 825 1.11 tsutsui struct file *fp = (struct file *)f->f_fsdata; 826 1.11 tsutsui size_t block_size = fp->f_fs->e2fs_bsize; 827 1.11 tsutsui char *buf; 828 1.11 tsutsui size_t buf_size; 829 1.20 christos lsentry_t *names = NULL; 830 1.11 tsutsui 831 1.11 tsutsui fp->f_seekp = 0; 832 1.11 tsutsui while (fp->f_seekp < (off_t)fp->f_di.e2di_size) { 833 1.11 tsutsui struct ext2fs_direct *dp, *edp; 834 1.11 tsutsui int rc = buf_read_file(f, &buf, &buf_size); 835 1.11 tsutsui if (rc) 836 1.11 tsutsui goto out; 837 1.11 tsutsui if (buf_size != block_size || buf_size == 0) 838 1.11 tsutsui goto out; 839 1.11 tsutsui 840 1.11 tsutsui dp = (struct ext2fs_direct *)buf; 841 1.11 tsutsui edp = (struct ext2fs_direct *)(buf + buf_size); 842 1.11 tsutsui 843 1.11 tsutsui for (; dp < edp; 844 1.11 tsutsui dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) { 845 1.11 tsutsui const char *t; 846 1.11 tsutsui 847 1.11 tsutsui if (fs2h16(dp->e2d_reclen) <= 0) 848 1.11 tsutsui goto out; 849 1.11 tsutsui 850 1.11 tsutsui if (fs2h32(dp->e2d_ino) == 0) 851 1.11 tsutsui continue; 852 1.11 tsutsui 853 1.11 tsutsui if (dp->e2d_type >= NELEM(typestr) || 854 1.11 tsutsui !(t = typestr[dp->e2d_type])) { 855 1.11 tsutsui /* 856 1.11 tsutsui * This does not handle "old" 857 1.11 tsutsui * filesystems properly. On little 858 1.11 tsutsui * endian machines, we get a bogus 859 1.11 tsutsui * type name if the namlen matches a 860 1.11 tsutsui * valid type identifier. We could 861 1.11 tsutsui * check if we read namlen "0" and 862 1.11 tsutsui * handle this case specially, if 863 1.11 tsutsui * there were a pressing need... 864 1.11 tsutsui */ 865 1.11 tsutsui printf("bad dir entry\n"); 866 1.11 tsutsui goto out; 867 1.11 tsutsui } 868 1.20 christos lsadd(&names, pattern, dp->e2d_name, 869 1.29 jakllsch dp->e2d_namlen, fs2h32(dp->e2d_ino), t); 870 1.11 tsutsui } 871 1.11 tsutsui fp->f_seekp += buf_size; 872 1.11 tsutsui } 873 1.11 tsutsui 874 1.20 christos lsprint(names); 875 1.20 christos out: lsfree(names); 876 1.11 tsutsui } 877 1.11 tsutsui #endif 878 1.11 tsutsui 879 1.1 tsutsui /* 880 1.1 tsutsui * byte swap functions for big endian machines 881 1.1 tsutsui * (ext2fs is always little endian) 882 1.1 tsutsui * 883 1.1 tsutsui * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c 884 1.1 tsutsui */ 885 1.1 tsutsui 886 1.1 tsutsui /* These functions are only needed if native byte order is not big endian */ 887 1.1 tsutsui #if BYTE_ORDER == BIG_ENDIAN 888 1.1 tsutsui void 889 1.1 tsutsui e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new) 890 1.1 tsutsui { 891 1.1 tsutsui 892 1.1 tsutsui /* preserve unused fields */ 893 1.1 tsutsui memcpy(new, old, sizeof(struct ext2fs)); 894 1.1 tsutsui new->e2fs_icount = bswap32(old->e2fs_icount); 895 1.1 tsutsui new->e2fs_bcount = bswap32(old->e2fs_bcount); 896 1.1 tsutsui new->e2fs_rbcount = bswap32(old->e2fs_rbcount); 897 1.1 tsutsui new->e2fs_fbcount = bswap32(old->e2fs_fbcount); 898 1.1 tsutsui new->e2fs_ficount = bswap32(old->e2fs_ficount); 899 1.1 tsutsui new->e2fs_first_dblock = bswap32(old->e2fs_first_dblock); 900 1.1 tsutsui new->e2fs_log_bsize = bswap32(old->e2fs_log_bsize); 901 1.1 tsutsui new->e2fs_fsize = bswap32(old->e2fs_fsize); 902 1.1 tsutsui new->e2fs_bpg = bswap32(old->e2fs_bpg); 903 1.1 tsutsui new->e2fs_fpg = bswap32(old->e2fs_fpg); 904 1.1 tsutsui new->e2fs_ipg = bswap32(old->e2fs_ipg); 905 1.1 tsutsui new->e2fs_mtime = bswap32(old->e2fs_mtime); 906 1.1 tsutsui new->e2fs_wtime = bswap32(old->e2fs_wtime); 907 1.1 tsutsui new->e2fs_mnt_count = bswap16(old->e2fs_mnt_count); 908 1.1 tsutsui new->e2fs_max_mnt_count = bswap16(old->e2fs_max_mnt_count); 909 1.1 tsutsui new->e2fs_magic = bswap16(old->e2fs_magic); 910 1.1 tsutsui new->e2fs_state = bswap16(old->e2fs_state); 911 1.1 tsutsui new->e2fs_beh = bswap16(old->e2fs_beh); 912 1.1 tsutsui new->e2fs_minrev = bswap16(old->e2fs_minrev); 913 1.1 tsutsui new->e2fs_lastfsck = bswap32(old->e2fs_lastfsck); 914 1.1 tsutsui new->e2fs_fsckintv = bswap32(old->e2fs_fsckintv); 915 1.1 tsutsui new->e2fs_creator = bswap32(old->e2fs_creator); 916 1.1 tsutsui new->e2fs_rev = bswap32(old->e2fs_rev); 917 1.1 tsutsui new->e2fs_ruid = bswap16(old->e2fs_ruid); 918 1.1 tsutsui new->e2fs_rgid = bswap16(old->e2fs_rgid); 919 1.1 tsutsui new->e2fs_first_ino = bswap32(old->e2fs_first_ino); 920 1.1 tsutsui new->e2fs_inode_size = bswap16(old->e2fs_inode_size); 921 1.1 tsutsui new->e2fs_block_group_nr = bswap16(old->e2fs_block_group_nr); 922 1.1 tsutsui new->e2fs_features_compat = bswap32(old->e2fs_features_compat); 923 1.1 tsutsui new->e2fs_features_incompat = bswap32(old->e2fs_features_incompat); 924 1.1 tsutsui new->e2fs_features_rocompat = bswap32(old->e2fs_features_rocompat); 925 1.1 tsutsui new->e2fs_algo = bswap32(old->e2fs_algo); 926 1.1 tsutsui new->e2fs_reserved_ngdb = bswap16(old->e2fs_reserved_ngdb); 927 1.1 tsutsui } 928 1.1 tsutsui 929 1.23 nonaka void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new, 930 1.23 nonaka size_t isize) 931 1.1 tsutsui { 932 1.23 nonaka /* preserve non-swapped and unused fields */ 933 1.23 nonaka memcpy(new, old, isize); 934 1.1 tsutsui 935 1.23 nonaka /* swap what needs to be swapped */ 936 1.1 tsutsui new->e2di_mode = bswap16(old->e2di_mode); 937 1.1 tsutsui new->e2di_uid = bswap16(old->e2di_uid); 938 1.1 tsutsui new->e2di_gid = bswap16(old->e2di_gid); 939 1.1 tsutsui new->e2di_nlink = bswap16(old->e2di_nlink); 940 1.1 tsutsui new->e2di_size = bswap32(old->e2di_size); 941 1.1 tsutsui new->e2di_atime = bswap32(old->e2di_atime); 942 1.1 tsutsui new->e2di_ctime = bswap32(old->e2di_ctime); 943 1.1 tsutsui new->e2di_mtime = bswap32(old->e2di_mtime); 944 1.1 tsutsui new->e2di_dtime = bswap32(old->e2di_dtime); 945 1.1 tsutsui new->e2di_nblock = bswap32(old->e2di_nblock); 946 1.1 tsutsui new->e2di_flags = bswap32(old->e2di_flags); 947 1.23 nonaka new->e2di_version = bswap32(old->e2di_version); 948 1.1 tsutsui new->e2di_gen = bswap32(old->e2di_gen); 949 1.1 tsutsui new->e2di_facl = bswap32(old->e2di_facl); 950 1.24 rjs new->e2di_size_high = bswap32(old->e2di_size_high); 951 1.23 nonaka new->e2di_nblock_high = bswap16(old->e2di_nblock_high); 952 1.23 nonaka new->e2di_facl_high = bswap16(old->e2di_facl_high); 953 1.23 nonaka new->e2di_uid_high = bswap16(old->e2di_uid_high); 954 1.23 nonaka new->e2di_gid_high = bswap16(old->e2di_gid_high); 955 1.23 nonaka new->e2di_checksum_low = bswap16(old->e2di_checksum_low); 956 1.23 nonaka 957 1.23 nonaka /* 958 1.23 nonaka * Following fields are only supported for inode sizes bigger 959 1.23 nonaka * than the old ext2 one 960 1.23 nonaka */ 961 1.23 nonaka if (isize == EXT2_REV0_DINODE_SIZE) 962 1.23 nonaka return; 963 1.23 nonaka 964 1.23 nonaka new->e2di_extra_isize = bswap16(old->e2di_extra_isize); 965 1.23 nonaka new->e2di_checksum_high = bswap16(old->e2di_checksum_high); 966 1.23 nonaka 967 1.23 nonaka /* Following fields are ext4, might not be actually present */ 968 1.23 nonaka if (EXT2_DINODE_FITS(new, e2di_ctime_extra, isize)) 969 1.23 nonaka new->e2di_ctime_extra = bswap32(old->e2di_ctime_extra); 970 1.23 nonaka if (EXT2_DINODE_FITS(new, e2di_mtime_extra, isize)) 971 1.23 nonaka new->e2di_mtime_extra = bswap32(old->e2di_mtime_extra); 972 1.23 nonaka if (EXT2_DINODE_FITS(new, e2di_atime_extra, isize)) 973 1.23 nonaka new->e2di_atime_extra = bswap32(old->e2di_atime_extra); 974 1.23 nonaka if (EXT2_DINODE_FITS(new, e2di_crtime, isize)) 975 1.23 nonaka new->e2di_crtime = bswap32(old->e2di_crtime); 976 1.23 nonaka if (EXT2_DINODE_FITS(new, e2di_crtime_extra, isize)) 977 1.23 nonaka new->e2di_crtime_extra = bswap32(old->e2di_crtime_extra); 978 1.23 nonaka if (EXT2_DINODE_FITS(new, e2di_version_high, isize)) 979 1.23 nonaka new->e2di_version_high = bswap32(old->e2di_version_high); 980 1.23 nonaka if (EXT2_DINODE_FITS(new, e2di_projid, isize)) 981 1.23 nonaka new->e2di_projid = bswap32(old->e2di_projid); 982 1.1 tsutsui } 983 1.1 tsutsui #endif 984 1.1 tsutsui 985 1.1 tsutsui #ifdef EXT2FS_DEBUG 986 1.1 tsutsui void 987 1.1 tsutsui dump_sblock(struct m_ext2fs *fs) 988 1.1 tsutsui { 989 1.1 tsutsui 990 1.1 tsutsui printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount); 991 1.1 tsutsui printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock); 992 1.1 tsutsui printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize); 993 1.1 tsutsui printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg); 994 1.1 tsutsui printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg); 995 1.27 christos printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic); 996 1.1 tsutsui printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev); 997 1.1 tsutsui 998 1.1 tsutsui if (fs->e2fs.e2fs_rev == E2FS_REV1) { 999 1.1 tsutsui printf("fs->e2fs.e2fs_first_ino = %u\n", 1000 1.1 tsutsui fs->e2fs.e2fs_first_ino); 1001 1.1 tsutsui printf("fs->e2fs.e2fs_inode_size = %u\n", 1002 1.1 tsutsui fs->e2fs.e2fs_inode_size); 1003 1.1 tsutsui printf("fs->e2fs.e2fs_features_compat = %u\n", 1004 1.1 tsutsui fs->e2fs.e2fs_features_compat); 1005 1.1 tsutsui printf("fs->e2fs.e2fs_features_incompat = %u\n", 1006 1.1 tsutsui fs->e2fs.e2fs_features_incompat); 1007 1.1 tsutsui printf("fs->e2fs.e2fs_features_rocompat = %u\n", 1008 1.1 tsutsui fs->e2fs.e2fs_features_rocompat); 1009 1.1 tsutsui printf("fs->e2fs.e2fs_reserved_ngdb = %u\n", 1010 1.1 tsutsui fs->e2fs.e2fs_reserved_ngdb); 1011 1.1 tsutsui } 1012 1.1 tsutsui 1013 1.1 tsutsui printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize); 1014 1.1 tsutsui printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb); 1015 1.1 tsutsui printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg); 1016 1.1 tsutsui printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb); 1017 1.1 tsutsui printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb); 1018 1.1 tsutsui printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg); 1019 1.1 tsutsui } 1020 1.1 tsutsui #endif 1021