1ca987d46SWarner Losh /* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */ 2ca987d46SWarner Losh 3ca987d46SWarner Losh /*- 4ca987d46SWarner Losh * Copyright (c) 2002 Networks Associates Technology, Inc. 5ca987d46SWarner Losh * All rights reserved. 6ca987d46SWarner Losh * 7ca987d46SWarner Losh * This software was developed for the FreeBSD Project by Marshall 8ca987d46SWarner Losh * Kirk McKusick and Network Associates Laboratories, the Security 9ca987d46SWarner Losh * Research Division of Network Associates, Inc. under DARPA/SPAWAR 10ca987d46SWarner Losh * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 11ca987d46SWarner Losh * research program 12ca987d46SWarner Losh * 13ca987d46SWarner Losh * Copyright (c) 1982, 1989, 1993 14ca987d46SWarner Losh * The Regents of the University of California. All rights reserved. 15ca987d46SWarner Losh * 16ca987d46SWarner Losh * This code is derived from software contributed to Berkeley by 17ca987d46SWarner Losh * The Mach Operating System project at Carnegie-Mellon University. 18ca987d46SWarner Losh * 19ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 20ca987d46SWarner Losh * modification, are permitted provided that the following conditions 21ca987d46SWarner Losh * are met: 22ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 23ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 24ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 25ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 26ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 27ca987d46SWarner Losh * 3. Neither the name of the University nor the names of its contributors 28ca987d46SWarner Losh * may be used to endorse or promote products derived from this software 29ca987d46SWarner Losh * without specific prior written permission. 30ca987d46SWarner Losh * 31ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 32ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 35ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41ca987d46SWarner Losh * SUCH DAMAGE. 42ca987d46SWarner Losh * 43ca987d46SWarner Losh * 44ca987d46SWarner Losh * Copyright (c) 1990, 1991 Carnegie Mellon University 45ca987d46SWarner Losh * All Rights Reserved. 46ca987d46SWarner Losh * 47ca987d46SWarner Losh * Author: David Golub 48ca987d46SWarner Losh * 49ca987d46SWarner Losh * Permission to use, copy, modify and distribute this software and its 50ca987d46SWarner Losh * documentation is hereby granted, provided that both the copyright 51ca987d46SWarner Losh * notice and this permission notice appear in all copies of the 52ca987d46SWarner Losh * software, derivative works or modified versions, and any portions 53ca987d46SWarner Losh * thereof, and that both notices appear in supporting documentation. 54ca987d46SWarner Losh * 55ca987d46SWarner Losh * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 56ca987d46SWarner Losh * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 57ca987d46SWarner Losh * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 58ca987d46SWarner Losh * 59ca987d46SWarner Losh * Carnegie Mellon requests users of this software to return to 60ca987d46SWarner Losh * 61ca987d46SWarner Losh * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 62ca987d46SWarner Losh * School of Computer Science 63ca987d46SWarner Losh * Carnegie Mellon University 64ca987d46SWarner Losh * Pittsburgh PA 15213-3890 65ca987d46SWarner Losh * 66ca987d46SWarner Losh * any improvements or extensions that they make and grant Carnegie the 67ca987d46SWarner Losh * rights to redistribute these changes. 68ca987d46SWarner Losh */ 69ca987d46SWarner Losh 70ca987d46SWarner Losh #include <sys/cdefs.h> 71ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 72ca987d46SWarner Losh 73ca987d46SWarner Losh /* 74ca987d46SWarner Losh * Stand-alone file reading package. 75ca987d46SWarner Losh */ 76ca987d46SWarner Losh 77ca987d46SWarner Losh #include <sys/param.h> 78ca987d46SWarner Losh #include <sys/disklabel.h> 79ca987d46SWarner Losh #include <sys/time.h> 80ca987d46SWarner Losh #include <ufs/ufs/dinode.h> 81ca987d46SWarner Losh #include <ufs/ufs/dir.h> 82ca987d46SWarner Losh #include <ufs/ffs/fs.h> 83ca987d46SWarner Losh #include "stand.h" 84ca987d46SWarner Losh #include "string.h" 85ca987d46SWarner Losh 86ca987d46SWarner Losh static int ufs_open(const char *path, struct open_file *f); 872e7e6fbcSConrad Meyer static int ufs_write(struct open_file *f, const void *buf, size_t size, 882e7e6fbcSConrad Meyer size_t *resid); 89ca987d46SWarner Losh static int ufs_close(struct open_file *f); 90ca987d46SWarner Losh static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 91ca987d46SWarner Losh static off_t ufs_seek(struct open_file *f, off_t offset, int where); 92ca987d46SWarner Losh static int ufs_stat(struct open_file *f, struct stat *sb); 93ca987d46SWarner Losh static int ufs_readdir(struct open_file *f, struct dirent *d); 94ca987d46SWarner Losh 95ca987d46SWarner Losh struct fs_ops ufs_fsops = { 96ca987d46SWarner Losh "ufs", 97ca987d46SWarner Losh ufs_open, 98ca987d46SWarner Losh ufs_close, 99ca987d46SWarner Losh ufs_read, 100ca987d46SWarner Losh ufs_write, 101ca987d46SWarner Losh ufs_seek, 102ca987d46SWarner Losh ufs_stat, 103ca987d46SWarner Losh ufs_readdir 104ca987d46SWarner Losh }; 105ca987d46SWarner Losh 106ca987d46SWarner Losh /* 107ca987d46SWarner Losh * In-core open file. 108ca987d46SWarner Losh */ 109ca987d46SWarner Losh struct file { 110ca987d46SWarner Losh off_t f_seekp; /* seek pointer */ 111ca987d46SWarner Losh struct fs *f_fs; /* pointer to super-block */ 112ca987d46SWarner Losh union dinode { 113ca987d46SWarner Losh struct ufs1_dinode di1; 114ca987d46SWarner Losh struct ufs2_dinode di2; 115ca987d46SWarner Losh } f_di; /* copy of on-disk inode */ 116ca987d46SWarner Losh int f_nindir[UFS_NIADDR]; 117ca987d46SWarner Losh /* number of blocks mapped by 118ca987d46SWarner Losh indirect block at level i */ 119ca987d46SWarner Losh char *f_blk[UFS_NIADDR]; /* buffer for indirect block at 120ca987d46SWarner Losh level i */ 121ca987d46SWarner Losh size_t f_blksize[UFS_NIADDR]; 122ca987d46SWarner Losh /* size of buffer */ 123ca987d46SWarner Losh ufs2_daddr_t f_blkno[UFS_NIADDR];/* disk address of block in buffer */ 124ca987d46SWarner Losh ufs2_daddr_t f_buf_blkno; /* block number of data block */ 125ca987d46SWarner Losh char *f_buf; /* buffer for data block */ 126ca987d46SWarner Losh size_t f_buf_size; /* size of data block */ 1275ad42d0fSSimon J. Gerraty int f_inumber; /* inumber */ 128ca987d46SWarner Losh }; 129ca987d46SWarner Losh #define DIP(fp, field) \ 130ca987d46SWarner Losh ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ 131ca987d46SWarner Losh (fp)->f_di.di1.field : (fp)->f_di.di2.field) 132ca987d46SWarner Losh 133ca987d46SWarner Losh static int read_inode(ino_t, struct open_file *); 134ca987d46SWarner Losh static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); 135ca987d46SWarner Losh static int buf_read_file(struct open_file *, char **, size_t *); 1362e7e6fbcSConrad Meyer static int buf_write_file(struct open_file *, const char *, size_t *); 137ca987d46SWarner Losh static int search_directory(char *, struct open_file *, ino_t *); 138dffce215SKirk McKusick static int ufs_use_sa_read(void *, off_t, void **, int); 139dffce215SKirk McKusick 140dffce215SKirk McKusick /* from ffs_subr.c */ 141dffce215SKirk McKusick int ffs_sbget(void *, struct fs **, off_t, char *, 142dffce215SKirk McKusick int (*)(void *, off_t, void **, int)); 143ca987d46SWarner Losh 144ca987d46SWarner Losh /* 145ca987d46SWarner Losh * Read a new inode into a file structure. 146ca987d46SWarner Losh */ 147ca987d46SWarner Losh static int 148ca987d46SWarner Losh read_inode(inumber, f) 149ca987d46SWarner Losh ino_t inumber; 150ca987d46SWarner Losh struct open_file *f; 151ca987d46SWarner Losh { 152ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 153ca987d46SWarner Losh struct fs *fs = fp->f_fs; 154ca987d46SWarner Losh char *buf; 155ca987d46SWarner Losh size_t rsize; 156ca987d46SWarner Losh int rc; 157ca987d46SWarner Losh 158ca987d46SWarner Losh if (fs == NULL) 159ca987d46SWarner Losh panic("fs == NULL"); 160ca987d46SWarner Losh 161ca987d46SWarner Losh /* 162ca987d46SWarner Losh * Read inode and save it. 163ca987d46SWarner Losh */ 164ca987d46SWarner Losh buf = malloc(fs->fs_bsize); 165ca987d46SWarner Losh twiddle(1); 166ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 167ca987d46SWarner Losh fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, 168ca987d46SWarner Losh buf, &rsize); 169ca987d46SWarner Losh if (rc) 170ca987d46SWarner Losh goto out; 171ca987d46SWarner Losh if (rsize != fs->fs_bsize) { 172ca987d46SWarner Losh rc = EIO; 173ca987d46SWarner Losh goto out; 174ca987d46SWarner Losh } 175ca987d46SWarner Losh 176ca987d46SWarner Losh if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 177ca987d46SWarner Losh fp->f_di.di1 = ((struct ufs1_dinode *)buf) 178ca987d46SWarner Losh [ino_to_fsbo(fs, inumber)]; 179ca987d46SWarner Losh else 180ca987d46SWarner Losh fp->f_di.di2 = ((struct ufs2_dinode *)buf) 181ca987d46SWarner Losh [ino_to_fsbo(fs, inumber)]; 182ca987d46SWarner Losh 183ca987d46SWarner Losh /* 184ca987d46SWarner Losh * Clear out the old buffers 185ca987d46SWarner Losh */ 186ca987d46SWarner Losh { 187ca987d46SWarner Losh int level; 188ca987d46SWarner Losh 189ca987d46SWarner Losh for (level = 0; level < UFS_NIADDR; level++) 190ca987d46SWarner Losh fp->f_blkno[level] = -1; 191ca987d46SWarner Losh fp->f_buf_blkno = -1; 192ca987d46SWarner Losh } 193ca987d46SWarner Losh fp->f_seekp = 0; 1945ad42d0fSSimon J. Gerraty fp->f_inumber = inumber; 195ca987d46SWarner Losh out: 196ca987d46SWarner Losh free(buf); 197ca987d46SWarner Losh return (rc); 198ca987d46SWarner Losh } 199ca987d46SWarner Losh 200ca987d46SWarner Losh /* 201ca987d46SWarner Losh * Given an offset in a file, find the disk block number that 202ca987d46SWarner Losh * contains that block. 203ca987d46SWarner Losh */ 204ca987d46SWarner Losh static int 205ca987d46SWarner Losh block_map(f, file_block, disk_block_p) 206ca987d46SWarner Losh struct open_file *f; 207ca987d46SWarner Losh ufs2_daddr_t file_block; 208ca987d46SWarner Losh ufs2_daddr_t *disk_block_p; /* out */ 209ca987d46SWarner Losh { 210ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 211ca987d46SWarner Losh struct fs *fs = fp->f_fs; 212ca987d46SWarner Losh int level; 213ca987d46SWarner Losh int idx; 214ca987d46SWarner Losh ufs2_daddr_t ind_block_num; 215ca987d46SWarner Losh int rc; 216ca987d46SWarner Losh 217ca987d46SWarner Losh /* 218ca987d46SWarner Losh * Index structure of an inode: 219ca987d46SWarner Losh * 220ca987d46SWarner Losh * di_db[0..UFS_NDADDR-1] hold block numbers for blocks 221ca987d46SWarner Losh * 0..UFS_NDADDR-1 222ca987d46SWarner Losh * 223ca987d46SWarner Losh * di_ib[0] index block 0 is the single indirect block 224ca987d46SWarner Losh * holds block numbers for blocks 225ca987d46SWarner Losh * UFS_NDADDR .. UFS_NDADDR + NINDIR(fs)-1 226ca987d46SWarner Losh * 227ca987d46SWarner Losh * di_ib[1] index block 1 is the double indirect block 228ca987d46SWarner Losh * holds block numbers for INDEX blocks for blocks 229ca987d46SWarner Losh * UFS_NDADDR + NINDIR(fs) .. 230ca987d46SWarner Losh * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 231ca987d46SWarner Losh * 232ca987d46SWarner Losh * di_ib[2] index block 2 is the triple indirect block 233ca987d46SWarner Losh * holds block numbers for double-indirect 234ca987d46SWarner Losh * blocks for blocks 235ca987d46SWarner Losh * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 236ca987d46SWarner Losh * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 237ca987d46SWarner Losh * + NINDIR(fs)**3 - 1 238ca987d46SWarner Losh */ 239ca987d46SWarner Losh 240ca987d46SWarner Losh if (file_block < UFS_NDADDR) { 241ca987d46SWarner Losh /* Direct block. */ 242ca987d46SWarner Losh *disk_block_p = DIP(fp, di_db[file_block]); 243ca987d46SWarner Losh return (0); 244ca987d46SWarner Losh } 245ca987d46SWarner Losh 246ca987d46SWarner Losh file_block -= UFS_NDADDR; 247ca987d46SWarner Losh 248ca987d46SWarner Losh /* 249ca987d46SWarner Losh * nindir[0] = NINDIR 250ca987d46SWarner Losh * nindir[1] = NINDIR**2 251ca987d46SWarner Losh * nindir[2] = NINDIR**3 252ca987d46SWarner Losh * etc 253ca987d46SWarner Losh */ 254ca987d46SWarner Losh for (level = 0; level < UFS_NIADDR; level++) { 255ca987d46SWarner Losh if (file_block < fp->f_nindir[level]) 256ca987d46SWarner Losh break; 257ca987d46SWarner Losh file_block -= fp->f_nindir[level]; 258ca987d46SWarner Losh } 259ca987d46SWarner Losh if (level == UFS_NIADDR) { 260ca987d46SWarner Losh /* Block number too high */ 261ca987d46SWarner Losh return (EFBIG); 262ca987d46SWarner Losh } 263ca987d46SWarner Losh 264ca987d46SWarner Losh ind_block_num = DIP(fp, di_ib[level]); 265ca987d46SWarner Losh 266ca987d46SWarner Losh for (; level >= 0; level--) { 267ca987d46SWarner Losh if (ind_block_num == 0) { 268ca987d46SWarner Losh *disk_block_p = 0; /* missing */ 269ca987d46SWarner Losh return (0); 270ca987d46SWarner Losh } 271ca987d46SWarner Losh 272ca987d46SWarner Losh if (fp->f_blkno[level] != ind_block_num) { 273ca987d46SWarner Losh if (fp->f_blk[level] == (char *)0) 274ca987d46SWarner Losh fp->f_blk[level] = 275ca987d46SWarner Losh malloc(fs->fs_bsize); 276ca987d46SWarner Losh twiddle(1); 277ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 278ca987d46SWarner Losh fsbtodb(fp->f_fs, ind_block_num), 279ca987d46SWarner Losh fs->fs_bsize, 280ca987d46SWarner Losh fp->f_blk[level], 281ca987d46SWarner Losh &fp->f_blksize[level]); 282ca987d46SWarner Losh if (rc) 283ca987d46SWarner Losh return (rc); 284ca987d46SWarner Losh if (fp->f_blksize[level] != fs->fs_bsize) 285ca987d46SWarner Losh return (EIO); 286ca987d46SWarner Losh fp->f_blkno[level] = ind_block_num; 287ca987d46SWarner Losh } 288ca987d46SWarner Losh 289ca987d46SWarner Losh if (level > 0) { 290ca987d46SWarner Losh idx = file_block / fp->f_nindir[level - 1]; 291ca987d46SWarner Losh file_block %= fp->f_nindir[level - 1]; 292ca987d46SWarner Losh } else 293ca987d46SWarner Losh idx = file_block; 294ca987d46SWarner Losh 295ca987d46SWarner Losh if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 296ca987d46SWarner Losh ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx]; 297ca987d46SWarner Losh else 298ca987d46SWarner Losh ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx]; 299ca987d46SWarner Losh } 300ca987d46SWarner Losh 301ca987d46SWarner Losh *disk_block_p = ind_block_num; 302ca987d46SWarner Losh 303ca987d46SWarner Losh return (0); 304ca987d46SWarner Losh } 305ca987d46SWarner Losh 306ca987d46SWarner Losh /* 307ca987d46SWarner Losh * Write a portion of a file from an internal buffer. 308ca987d46SWarner Losh */ 309ca987d46SWarner Losh static int 310ca987d46SWarner Losh buf_write_file(f, buf_p, size_p) 311ca987d46SWarner Losh struct open_file *f; 3122e7e6fbcSConrad Meyer const char *buf_p; 313ca987d46SWarner Losh size_t *size_p; /* out */ 314ca987d46SWarner Losh { 315ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 316ca987d46SWarner Losh struct fs *fs = fp->f_fs; 317ca987d46SWarner Losh long off; 318ca987d46SWarner Losh ufs_lbn_t file_block; 319ca987d46SWarner Losh ufs2_daddr_t disk_block; 320ca987d46SWarner Losh size_t block_size; 321ca987d46SWarner Losh int rc; 322ca987d46SWarner Losh 323ca987d46SWarner Losh /* 324ca987d46SWarner Losh * Calculate the starting block address and offset. 325ca987d46SWarner Losh */ 326ca987d46SWarner Losh off = blkoff(fs, fp->f_seekp); 327ca987d46SWarner Losh file_block = lblkno(fs, fp->f_seekp); 328ca987d46SWarner Losh block_size = sblksize(fs, DIP(fp, di_size), file_block); 329ca987d46SWarner Losh 330ca987d46SWarner Losh rc = block_map(f, file_block, &disk_block); 331ca987d46SWarner Losh if (rc) 332ca987d46SWarner Losh return (rc); 333ca987d46SWarner Losh 334ca987d46SWarner Losh if (disk_block == 0) 335ca987d46SWarner Losh /* Because we can't allocate space on the drive */ 336ca987d46SWarner Losh return (EFBIG); 337ca987d46SWarner Losh 338ca987d46SWarner Losh /* 339ca987d46SWarner Losh * Truncate buffer at end of file, and at the end of 340ca987d46SWarner Losh * this block. 341ca987d46SWarner Losh */ 342ca987d46SWarner Losh if (*size_p > DIP(fp, di_size) - fp->f_seekp) 343ca987d46SWarner Losh *size_p = DIP(fp, di_size) - fp->f_seekp; 344ca987d46SWarner Losh if (*size_p > block_size - off) 345ca987d46SWarner Losh *size_p = block_size - off; 346ca987d46SWarner Losh 347ca987d46SWarner Losh /* 348ca987d46SWarner Losh * If we don't entirely occlude the block and it's not 349ca987d46SWarner Losh * in memory already, read it in first. 350ca987d46SWarner Losh */ 351ca987d46SWarner Losh if (((off > 0) || (*size_p + off < block_size)) && 352ca987d46SWarner Losh (file_block != fp->f_buf_blkno)) { 353ca987d46SWarner Losh 354ca987d46SWarner Losh if (fp->f_buf == (char *)0) 355ca987d46SWarner Losh fp->f_buf = malloc(fs->fs_bsize); 356ca987d46SWarner Losh 357ca987d46SWarner Losh twiddle(4); 358ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 359ca987d46SWarner Losh fsbtodb(fs, disk_block), 360ca987d46SWarner Losh block_size, fp->f_buf, &fp->f_buf_size); 361ca987d46SWarner Losh if (rc) 362ca987d46SWarner Losh return (rc); 363ca987d46SWarner Losh 364ca987d46SWarner Losh fp->f_buf_blkno = file_block; 365ca987d46SWarner Losh } 366ca987d46SWarner Losh 367ca987d46SWarner Losh /* 368ca987d46SWarner Losh * Copy the user data into the cached block. 369ca987d46SWarner Losh */ 370ca987d46SWarner Losh bcopy(buf_p, fp->f_buf + off, *size_p); 371ca987d46SWarner Losh 372ca987d46SWarner Losh /* 373ca987d46SWarner Losh * Write the block out to storage. 374ca987d46SWarner Losh */ 375ca987d46SWarner Losh 376ca987d46SWarner Losh twiddle(4); 377ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, 378ca987d46SWarner Losh fsbtodb(fs, disk_block), 379ca987d46SWarner Losh block_size, fp->f_buf, &fp->f_buf_size); 380ca987d46SWarner Losh return (rc); 381ca987d46SWarner Losh } 382ca987d46SWarner Losh 383ca987d46SWarner Losh /* 384ca987d46SWarner Losh * Read a portion of a file into an internal buffer. Return 385ca987d46SWarner Losh * the location in the buffer and the amount in the buffer. 386ca987d46SWarner Losh */ 387ca987d46SWarner Losh static int 388ca987d46SWarner Losh buf_read_file(f, buf_p, size_p) 389ca987d46SWarner Losh struct open_file *f; 390ca987d46SWarner Losh char **buf_p; /* out */ 391ca987d46SWarner Losh size_t *size_p; /* out */ 392ca987d46SWarner Losh { 393ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 394ca987d46SWarner Losh struct fs *fs = fp->f_fs; 395ca987d46SWarner Losh long off; 396ca987d46SWarner Losh ufs_lbn_t file_block; 397ca987d46SWarner Losh ufs2_daddr_t disk_block; 398ca987d46SWarner Losh size_t block_size; 399ca987d46SWarner Losh int rc; 400ca987d46SWarner Losh 401ca987d46SWarner Losh off = blkoff(fs, fp->f_seekp); 402ca987d46SWarner Losh file_block = lblkno(fs, fp->f_seekp); 403ca987d46SWarner Losh block_size = sblksize(fs, DIP(fp, di_size), file_block); 404ca987d46SWarner Losh 405ca987d46SWarner Losh if (file_block != fp->f_buf_blkno) { 406ca987d46SWarner Losh if (fp->f_buf == (char *)0) 407ca987d46SWarner Losh fp->f_buf = malloc(fs->fs_bsize); 408ca987d46SWarner Losh 409ca987d46SWarner Losh rc = block_map(f, file_block, &disk_block); 410ca987d46SWarner Losh if (rc) 411ca987d46SWarner Losh return (rc); 412ca987d46SWarner Losh 413ca987d46SWarner Losh if (disk_block == 0) { 414ca987d46SWarner Losh bzero(fp->f_buf, block_size); 415ca987d46SWarner Losh fp->f_buf_size = block_size; 416ca987d46SWarner Losh } else { 417ca987d46SWarner Losh twiddle(4); 418ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 419ca987d46SWarner Losh fsbtodb(fs, disk_block), 420ca987d46SWarner Losh block_size, fp->f_buf, &fp->f_buf_size); 421ca987d46SWarner Losh if (rc) 422ca987d46SWarner Losh return (rc); 423ca987d46SWarner Losh } 424ca987d46SWarner Losh 425ca987d46SWarner Losh fp->f_buf_blkno = file_block; 426ca987d46SWarner Losh } 427ca987d46SWarner Losh 428ca987d46SWarner Losh /* 429ca987d46SWarner Losh * Return address of byte in buffer corresponding to 430ca987d46SWarner Losh * offset, and size of remainder of buffer after that 431ca987d46SWarner Losh * byte. 432ca987d46SWarner Losh */ 433ca987d46SWarner Losh *buf_p = fp->f_buf + off; 434ca987d46SWarner Losh *size_p = block_size - off; 435ca987d46SWarner Losh 436ca987d46SWarner Losh /* 437ca987d46SWarner Losh * But truncate buffer at end of file. 438ca987d46SWarner Losh */ 439ca987d46SWarner Losh if (*size_p > DIP(fp, di_size) - fp->f_seekp) 440ca987d46SWarner Losh *size_p = DIP(fp, di_size) - fp->f_seekp; 441ca987d46SWarner Losh 442ca987d46SWarner Losh return (0); 443ca987d46SWarner Losh } 444ca987d46SWarner Losh 445ca987d46SWarner Losh /* 446ca987d46SWarner Losh * Search a directory for a name and return its 447ca987d46SWarner Losh * i_number. 448ca987d46SWarner Losh */ 449ca987d46SWarner Losh static int 450ca987d46SWarner Losh search_directory(name, f, inumber_p) 451ca987d46SWarner Losh char *name; 452ca987d46SWarner Losh struct open_file *f; 453ca987d46SWarner Losh ino_t *inumber_p; /* out */ 454ca987d46SWarner Losh { 455ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 456ca987d46SWarner Losh struct direct *dp; 457ca987d46SWarner Losh struct direct *edp; 458ca987d46SWarner Losh char *buf; 459ca987d46SWarner Losh size_t buf_size; 460ca987d46SWarner Losh int namlen, length; 461ca987d46SWarner Losh int rc; 462ca987d46SWarner Losh 463ca987d46SWarner Losh length = strlen(name); 464ca987d46SWarner Losh 465ca987d46SWarner Losh fp->f_seekp = 0; 466ca987d46SWarner Losh while (fp->f_seekp < DIP(fp, di_size)) { 467ca987d46SWarner Losh rc = buf_read_file(f, &buf, &buf_size); 468ca987d46SWarner Losh if (rc) 469ca987d46SWarner Losh return (rc); 470ca987d46SWarner Losh 471ca987d46SWarner Losh dp = (struct direct *)buf; 472ca987d46SWarner Losh edp = (struct direct *)(buf + buf_size); 473ca987d46SWarner Losh while (dp < edp) { 474ca987d46SWarner Losh if (dp->d_ino == (ino_t)0) 475ca987d46SWarner Losh goto next; 476ca987d46SWarner Losh #if BYTE_ORDER == LITTLE_ENDIAN 477ca987d46SWarner Losh if (fp->f_fs->fs_maxsymlinklen <= 0) 478ca987d46SWarner Losh namlen = dp->d_type; 479ca987d46SWarner Losh else 480ca987d46SWarner Losh #endif 481ca987d46SWarner Losh namlen = dp->d_namlen; 482ca987d46SWarner Losh if (namlen == length && 483ca987d46SWarner Losh !strcmp(name, dp->d_name)) { 484ca987d46SWarner Losh /* found entry */ 485ca987d46SWarner Losh *inumber_p = dp->d_ino; 486ca987d46SWarner Losh return (0); 487ca987d46SWarner Losh } 488ca987d46SWarner Losh next: 489ca987d46SWarner Losh dp = (struct direct *)((char *)dp + dp->d_reclen); 490ca987d46SWarner Losh } 491ca987d46SWarner Losh fp->f_seekp += buf_size; 492ca987d46SWarner Losh } 493ca987d46SWarner Losh return (ENOENT); 494ca987d46SWarner Losh } 495ca987d46SWarner Losh 496ca987d46SWarner Losh /* 497ca987d46SWarner Losh * Open a file. 498ca987d46SWarner Losh */ 499ca987d46SWarner Losh static int 500ca987d46SWarner Losh ufs_open(upath, f) 501ca987d46SWarner Losh const char *upath; 502ca987d46SWarner Losh struct open_file *f; 503ca987d46SWarner Losh { 504ca987d46SWarner Losh char *cp, *ncp; 505ca987d46SWarner Losh int c; 506ca987d46SWarner Losh ino_t inumber, parent_inumber; 507ca987d46SWarner Losh struct file *fp; 508ca987d46SWarner Losh struct fs *fs; 509ca987d46SWarner Losh int i, rc; 510ca987d46SWarner Losh size_t buf_size; 511ca987d46SWarner Losh int nlinks = 0; 512ca987d46SWarner Losh char namebuf[MAXPATHLEN+1]; 513ca987d46SWarner Losh char *buf = NULL; 514ca987d46SWarner Losh char *path = NULL; 515ca987d46SWarner Losh 516ca987d46SWarner Losh /* allocate file system specific data structure */ 517ca987d46SWarner Losh fp = malloc(sizeof(struct file)); 518ca987d46SWarner Losh bzero(fp, sizeof(struct file)); 519ca987d46SWarner Losh f->f_fsdata = (void *)fp; 520ca987d46SWarner Losh 521dffce215SKirk McKusick /* read super block */ 522ca987d46SWarner Losh twiddle(1); 523efbf3964SKirk McKusick if ((rc = ffs_sbget(f, &fs, -1, "stand", ufs_use_sa_read)) != 0) 524ca987d46SWarner Losh goto out; 525dffce215SKirk McKusick fp->f_fs = fs; 526ca987d46SWarner Losh /* 527ca987d46SWarner Losh * Calculate indirect block levels. 528ca987d46SWarner Losh */ 529ca987d46SWarner Losh { 530ca987d46SWarner Losh ufs2_daddr_t mult; 531ca987d46SWarner Losh int level; 532ca987d46SWarner Losh 533ca987d46SWarner Losh mult = 1; 534ca987d46SWarner Losh for (level = 0; level < UFS_NIADDR; level++) { 535ca987d46SWarner Losh mult *= NINDIR(fs); 536ca987d46SWarner Losh fp->f_nindir[level] = mult; 537ca987d46SWarner Losh } 538ca987d46SWarner Losh } 539ca987d46SWarner Losh 540ca987d46SWarner Losh inumber = UFS_ROOTINO; 541ca987d46SWarner Losh if ((rc = read_inode(inumber, f)) != 0) 542ca987d46SWarner Losh goto out; 543ca987d46SWarner Losh 544ca987d46SWarner Losh cp = path = strdup(upath); 545ca987d46SWarner Losh if (path == NULL) { 546ca987d46SWarner Losh rc = ENOMEM; 547ca987d46SWarner Losh goto out; 548ca987d46SWarner Losh } 549ca987d46SWarner Losh while (*cp) { 550ca987d46SWarner Losh 551ca987d46SWarner Losh /* 552ca987d46SWarner Losh * Remove extra separators 553ca987d46SWarner Losh */ 554ca987d46SWarner Losh while (*cp == '/') 555ca987d46SWarner Losh cp++; 556ca987d46SWarner Losh if (*cp == '\0') 557ca987d46SWarner Losh break; 558ca987d46SWarner Losh 559ca987d46SWarner Losh /* 560ca987d46SWarner Losh * Check that current node is a directory. 561ca987d46SWarner Losh */ 562d8ba45e2SEd Maste if ((DIP(fp, di_mode) & IFMT) != IFDIR) { 563ca987d46SWarner Losh rc = ENOTDIR; 564ca987d46SWarner Losh goto out; 565ca987d46SWarner Losh } 566ca987d46SWarner Losh 567ca987d46SWarner Losh /* 568ca987d46SWarner Losh * Get next component of path name. 569ca987d46SWarner Losh */ 570ca987d46SWarner Losh { 571ca987d46SWarner Losh int len = 0; 572ca987d46SWarner Losh 573ca987d46SWarner Losh ncp = cp; 574ca987d46SWarner Losh while ((c = *cp) != '\0' && c != '/') { 575ca987d46SWarner Losh if (++len > UFS_MAXNAMLEN) { 576ca987d46SWarner Losh rc = ENOENT; 577ca987d46SWarner Losh goto out; 578ca987d46SWarner Losh } 579ca987d46SWarner Losh cp++; 580ca987d46SWarner Losh } 581ca987d46SWarner Losh *cp = '\0'; 582ca987d46SWarner Losh } 583ca987d46SWarner Losh 584ca987d46SWarner Losh /* 585ca987d46SWarner Losh * Look up component in current directory. 586ca987d46SWarner Losh * Save directory inumber in case we find a 587ca987d46SWarner Losh * symbolic link. 588ca987d46SWarner Losh */ 589ca987d46SWarner Losh parent_inumber = inumber; 590ca987d46SWarner Losh rc = search_directory(ncp, f, &inumber); 591ca987d46SWarner Losh *cp = c; 592ca987d46SWarner Losh if (rc) 593ca987d46SWarner Losh goto out; 594ca987d46SWarner Losh 595ca987d46SWarner Losh /* 596ca987d46SWarner Losh * Open next component. 597ca987d46SWarner Losh */ 598ca987d46SWarner Losh if ((rc = read_inode(inumber, f)) != 0) 599ca987d46SWarner Losh goto out; 600ca987d46SWarner Losh 601ca987d46SWarner Losh /* 602ca987d46SWarner Losh * Check for symbolic link. 603ca987d46SWarner Losh */ 604d8ba45e2SEd Maste if ((DIP(fp, di_mode) & IFMT) == IFLNK) { 605ca987d46SWarner Losh int link_len = DIP(fp, di_size); 606ca987d46SWarner Losh int len; 607ca987d46SWarner Losh 608ca987d46SWarner Losh len = strlen(cp); 609ca987d46SWarner Losh 610ca987d46SWarner Losh if (link_len + len > MAXPATHLEN || 611ca987d46SWarner Losh ++nlinks > MAXSYMLINKS) { 612ca987d46SWarner Losh rc = ENOENT; 613ca987d46SWarner Losh goto out; 614ca987d46SWarner Losh } 615ca987d46SWarner Losh 616ca987d46SWarner Losh bcopy(cp, &namebuf[link_len], len + 1); 617ca987d46SWarner Losh 618ca987d46SWarner Losh if (link_len < fs->fs_maxsymlinklen) { 619ca987d46SWarner Losh if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 620ca987d46SWarner Losh cp = (caddr_t)(fp->f_di.di1.di_db); 621ca987d46SWarner Losh else 622ca987d46SWarner Losh cp = (caddr_t)(fp->f_di.di2.di_db); 623ca987d46SWarner Losh bcopy(cp, namebuf, (unsigned) link_len); 624ca987d46SWarner Losh } else { 625ca987d46SWarner Losh /* 626ca987d46SWarner Losh * Read file for symbolic link 627ca987d46SWarner Losh */ 628ca987d46SWarner Losh size_t buf_size; 629ca987d46SWarner Losh ufs2_daddr_t disk_block; 630ca987d46SWarner Losh struct fs *fs = fp->f_fs; 631ca987d46SWarner Losh 632ca987d46SWarner Losh if (!buf) 633ca987d46SWarner Losh buf = malloc(fs->fs_bsize); 634ca987d46SWarner Losh rc = block_map(f, (ufs2_daddr_t)0, &disk_block); 635ca987d46SWarner Losh if (rc) 636ca987d46SWarner Losh goto out; 637ca987d46SWarner Losh 638ca987d46SWarner Losh twiddle(1); 639ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, 640ca987d46SWarner Losh F_READ, fsbtodb(fs, disk_block), 641ca987d46SWarner Losh fs->fs_bsize, buf, &buf_size); 642ca987d46SWarner Losh if (rc) 643ca987d46SWarner Losh goto out; 644ca987d46SWarner Losh 645ca987d46SWarner Losh bcopy((char *)buf, namebuf, (unsigned)link_len); 646ca987d46SWarner Losh } 647ca987d46SWarner Losh 648ca987d46SWarner Losh /* 649ca987d46SWarner Losh * If relative pathname, restart at parent directory. 650ca987d46SWarner Losh * If absolute pathname, restart at root. 651ca987d46SWarner Losh */ 652ca987d46SWarner Losh cp = namebuf; 653ca987d46SWarner Losh if (*cp != '/') 654ca987d46SWarner Losh inumber = parent_inumber; 655ca987d46SWarner Losh else 656ca987d46SWarner Losh inumber = (ino_t)UFS_ROOTINO; 657ca987d46SWarner Losh 658ca987d46SWarner Losh if ((rc = read_inode(inumber, f)) != 0) 659ca987d46SWarner Losh goto out; 660ca987d46SWarner Losh } 661ca987d46SWarner Losh } 662ca987d46SWarner Losh 663ca987d46SWarner Losh /* 664ca987d46SWarner Losh * Found terminal component. 665ca987d46SWarner Losh */ 666ca987d46SWarner Losh rc = 0; 667ca987d46SWarner Losh fp->f_seekp = 0; 668ca987d46SWarner Losh out: 669ca987d46SWarner Losh if (buf) 670ca987d46SWarner Losh free(buf); 671ca987d46SWarner Losh if (path) 672ca987d46SWarner Losh free(path); 673ca987d46SWarner Losh if (rc) { 674ca987d46SWarner Losh if (fp->f_buf) 675ca987d46SWarner Losh free(fp->f_buf); 676ca987d46SWarner Losh free(fp->f_fs); 677ca987d46SWarner Losh free(fp); 678ca987d46SWarner Losh } 679ca987d46SWarner Losh return (rc); 680ca987d46SWarner Losh } 681ca987d46SWarner Losh 682dffce215SKirk McKusick /* 683dffce215SKirk McKusick * A read function for use by standalone-layer routines. 684dffce215SKirk McKusick */ 685dffce215SKirk McKusick static int 686dffce215SKirk McKusick ufs_use_sa_read(void *devfd, off_t loc, void **bufp, int size) 687dffce215SKirk McKusick { 688dffce215SKirk McKusick struct open_file *f; 689dffce215SKirk McKusick size_t buf_size; 690dffce215SKirk McKusick int error; 691dffce215SKirk McKusick 692dffce215SKirk McKusick f = (struct open_file *)devfd; 693dffce215SKirk McKusick if ((*bufp = malloc(size)) == NULL) 694dffce215SKirk McKusick return (ENOSPC); 695dffce215SKirk McKusick error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, loc / DEV_BSIZE, 696dffce215SKirk McKusick size, *bufp, &buf_size); 697dffce215SKirk McKusick if (error != 0) 698dffce215SKirk McKusick return (error); 699dffce215SKirk McKusick if (buf_size != size) 700dffce215SKirk McKusick return (EIO); 701dffce215SKirk McKusick return (0); 702dffce215SKirk McKusick } 703dffce215SKirk McKusick 704ca987d46SWarner Losh static int 705ca987d46SWarner Losh ufs_close(f) 706ca987d46SWarner Losh struct open_file *f; 707ca987d46SWarner Losh { 708ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 709ca987d46SWarner Losh int level; 710ca987d46SWarner Losh 711ca987d46SWarner Losh f->f_fsdata = (void *)0; 712ca987d46SWarner Losh if (fp == (struct file *)0) 713ca987d46SWarner Losh return (0); 714ca987d46SWarner Losh 715ca987d46SWarner Losh for (level = 0; level < UFS_NIADDR; level++) { 716ca987d46SWarner Losh if (fp->f_blk[level]) 717ca987d46SWarner Losh free(fp->f_blk[level]); 718ca987d46SWarner Losh } 719ca987d46SWarner Losh if (fp->f_buf) 720ca987d46SWarner Losh free(fp->f_buf); 721ca987d46SWarner Losh free(fp->f_fs); 722ca987d46SWarner Losh free(fp); 723ca987d46SWarner Losh return (0); 724ca987d46SWarner Losh } 725ca987d46SWarner Losh 726ca987d46SWarner Losh /* 727ca987d46SWarner Losh * Copy a portion of a file into kernel memory. 728ca987d46SWarner Losh * Cross block boundaries when necessary. 729ca987d46SWarner Losh */ 730ca987d46SWarner Losh static int 731ca987d46SWarner Losh ufs_read(f, start, size, resid) 732ca987d46SWarner Losh struct open_file *f; 733ca987d46SWarner Losh void *start; 734ca987d46SWarner Losh size_t size; 735ca987d46SWarner Losh size_t *resid; /* out */ 736ca987d46SWarner Losh { 737ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 738ca987d46SWarner Losh size_t csize; 739ca987d46SWarner Losh char *buf; 740ca987d46SWarner Losh size_t buf_size; 741ca987d46SWarner Losh int rc = 0; 742ca987d46SWarner Losh char *addr = start; 743ca987d46SWarner Losh 744ca987d46SWarner Losh while (size != 0) { 745ca987d46SWarner Losh if (fp->f_seekp >= DIP(fp, di_size)) 746ca987d46SWarner Losh break; 747ca987d46SWarner Losh 748ca987d46SWarner Losh rc = buf_read_file(f, &buf, &buf_size); 749ca987d46SWarner Losh if (rc) 750ca987d46SWarner Losh break; 751ca987d46SWarner Losh 752ca987d46SWarner Losh csize = size; 753ca987d46SWarner Losh if (csize > buf_size) 754ca987d46SWarner Losh csize = buf_size; 755ca987d46SWarner Losh 756ca987d46SWarner Losh bcopy(buf, addr, csize); 757ca987d46SWarner Losh 758ca987d46SWarner Losh fp->f_seekp += csize; 759ca987d46SWarner Losh addr += csize; 760ca987d46SWarner Losh size -= csize; 761ca987d46SWarner Losh } 762ca987d46SWarner Losh if (resid) 763ca987d46SWarner Losh *resid = size; 764ca987d46SWarner Losh return (rc); 765ca987d46SWarner Losh } 766ca987d46SWarner Losh 767ca987d46SWarner Losh /* 768ca987d46SWarner Losh * Write to a portion of an already allocated file. 769ca987d46SWarner Losh * Cross block boundaries when necessary. Can not 770ca987d46SWarner Losh * extend the file. 771ca987d46SWarner Losh */ 772ca987d46SWarner Losh static int 773ca987d46SWarner Losh ufs_write(f, start, size, resid) 774ca987d46SWarner Losh struct open_file *f; 7752e7e6fbcSConrad Meyer const void *start; 776ca987d46SWarner Losh size_t size; 777ca987d46SWarner Losh size_t *resid; /* out */ 778ca987d46SWarner Losh { 779ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 780ca987d46SWarner Losh size_t csize; 781ca987d46SWarner Losh int rc = 0; 7822e7e6fbcSConrad Meyer const char *addr = start; 783ca987d46SWarner Losh 784ca987d46SWarner Losh csize = size; 785ca987d46SWarner Losh while ((size != 0) && (csize != 0)) { 786ca987d46SWarner Losh if (fp->f_seekp >= DIP(fp, di_size)) 787ca987d46SWarner Losh break; 788ca987d46SWarner Losh 789ca987d46SWarner Losh if (csize >= 512) csize = 512; /* XXX */ 790ca987d46SWarner Losh 791ca987d46SWarner Losh rc = buf_write_file(f, addr, &csize); 792ca987d46SWarner Losh if (rc) 793ca987d46SWarner Losh break; 794ca987d46SWarner Losh 795ca987d46SWarner Losh fp->f_seekp += csize; 796ca987d46SWarner Losh addr += csize; 797ca987d46SWarner Losh size -= csize; 798ca987d46SWarner Losh } 799ca987d46SWarner Losh if (resid) 800ca987d46SWarner Losh *resid = size; 801ca987d46SWarner Losh return (rc); 802ca987d46SWarner Losh } 803ca987d46SWarner Losh 804ca987d46SWarner Losh static off_t 805ca987d46SWarner Losh ufs_seek(f, offset, where) 806ca987d46SWarner Losh struct open_file *f; 807ca987d46SWarner Losh off_t offset; 808ca987d46SWarner Losh int where; 809ca987d46SWarner Losh { 810ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 811ca987d46SWarner Losh 812ca987d46SWarner Losh switch (where) { 813ca987d46SWarner Losh case SEEK_SET: 814ca987d46SWarner Losh fp->f_seekp = offset; 815ca987d46SWarner Losh break; 816ca987d46SWarner Losh case SEEK_CUR: 817ca987d46SWarner Losh fp->f_seekp += offset; 818ca987d46SWarner Losh break; 819ca987d46SWarner Losh case SEEK_END: 820ca987d46SWarner Losh fp->f_seekp = DIP(fp, di_size) - offset; 821ca987d46SWarner Losh break; 822ca987d46SWarner Losh default: 823ca987d46SWarner Losh errno = EINVAL; 824ca987d46SWarner Losh return (-1); 825ca987d46SWarner Losh } 826ca987d46SWarner Losh return (fp->f_seekp); 827ca987d46SWarner Losh } 828ca987d46SWarner Losh 829ca987d46SWarner Losh static int 830ca987d46SWarner Losh ufs_stat(f, sb) 831ca987d46SWarner Losh struct open_file *f; 832ca987d46SWarner Losh struct stat *sb; 833ca987d46SWarner Losh { 834ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 835ca987d46SWarner Losh 836ca987d46SWarner Losh /* only important stuff */ 837ca987d46SWarner Losh sb->st_mode = DIP(fp, di_mode); 838ca987d46SWarner Losh sb->st_uid = DIP(fp, di_uid); 839ca987d46SWarner Losh sb->st_gid = DIP(fp, di_gid); 840ca987d46SWarner Losh sb->st_size = DIP(fp, di_size); 8415ad42d0fSSimon J. Gerraty sb->st_mtime = DIP(fp, di_mtime); 8425ad42d0fSSimon J. Gerraty /* 8435ad42d0fSSimon J. Gerraty * The items below are ufs specific! 8445ad42d0fSSimon J. Gerraty * Other fs types will need their own solution 8455ad42d0fSSimon J. Gerraty * if these fields are needed. 8465ad42d0fSSimon J. Gerraty */ 8475ad42d0fSSimon J. Gerraty sb->st_ino = fp->f_inumber; 8485ad42d0fSSimon J. Gerraty /* 8495ad42d0fSSimon J. Gerraty * We need something to differentiate devs. 8505ad42d0fSSimon J. Gerraty * fs_id is unique but 64bit, we xor the two 8515ad42d0fSSimon J. Gerraty * halves to squeeze it into 32bits. 8525ad42d0fSSimon J. Gerraty */ 8535ad42d0fSSimon J. Gerraty sb->st_dev = (dev_t)(fp->f_fs->fs_id[0] ^ fp->f_fs->fs_id[1]); 8545ad42d0fSSimon J. Gerraty 855ca987d46SWarner Losh return (0); 856ca987d46SWarner Losh } 857ca987d46SWarner Losh 858ca987d46SWarner Losh static int 859ca987d46SWarner Losh ufs_readdir(struct open_file *f, struct dirent *d) 860ca987d46SWarner Losh { 861ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 862ca987d46SWarner Losh struct direct *dp; 863ca987d46SWarner Losh char *buf; 864ca987d46SWarner Losh size_t buf_size; 865ca987d46SWarner Losh int error; 866ca987d46SWarner Losh 867ca987d46SWarner Losh /* 868ca987d46SWarner Losh * assume that a directory entry will not be split across blocks 869ca987d46SWarner Losh */ 870ca987d46SWarner Losh again: 871ca987d46SWarner Losh if (fp->f_seekp >= DIP(fp, di_size)) 872ca987d46SWarner Losh return (ENOENT); 873ca987d46SWarner Losh error = buf_read_file(f, &buf, &buf_size); 874ca987d46SWarner Losh if (error) 875ca987d46SWarner Losh return (error); 876ca987d46SWarner Losh dp = (struct direct *)buf; 877ca987d46SWarner Losh fp->f_seekp += dp->d_reclen; 878ca987d46SWarner Losh if (dp->d_ino == (ino_t)0) 879ca987d46SWarner Losh goto again; 880ca987d46SWarner Losh d->d_type = dp->d_type; 881ca987d46SWarner Losh strcpy(d->d_name, dp->d_name); 882ca987d46SWarner Losh return (0); 883ca987d46SWarner Losh } 884