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); 94b4cb3fe0SToomas Soome static int ufs_mount(const char *dev, const char *path, void **data); 95b4cb3fe0SToomas Soome static int ufs_unmount(const char *dev, void *data); 96ca987d46SWarner Losh 97ca987d46SWarner Losh struct fs_ops ufs_fsops = { 98b4cb3fe0SToomas Soome .fs_name = "ufs", 99b4cb3fe0SToomas Soome .fo_open = ufs_open, 100b4cb3fe0SToomas Soome .fo_close = ufs_close, 101b4cb3fe0SToomas Soome .fo_read = ufs_read, 102b4cb3fe0SToomas Soome .fo_write = ufs_write, 103b4cb3fe0SToomas Soome .fo_seek = ufs_seek, 104b4cb3fe0SToomas Soome .fo_stat = ufs_stat, 105b4cb3fe0SToomas Soome .fo_readdir = ufs_readdir, 106b4cb3fe0SToomas Soome .fo_mount = ufs_mount, 107b4cb3fe0SToomas Soome .fo_unmount = ufs_unmount 108ca987d46SWarner Losh }; 109ca987d46SWarner Losh 110ca987d46SWarner Losh /* 111ca987d46SWarner Losh * In-core open file. 112ca987d46SWarner Losh */ 113ca987d46SWarner Losh struct file { 114ca987d46SWarner Losh off_t f_seekp; /* seek pointer */ 115ca987d46SWarner Losh struct fs *f_fs; /* pointer to super-block */ 116ca987d46SWarner Losh union dinode { 117ca987d46SWarner Losh struct ufs1_dinode di1; 118ca987d46SWarner Losh struct ufs2_dinode di2; 119ca987d46SWarner Losh } f_di; /* copy of on-disk inode */ 120ca987d46SWarner Losh int f_nindir[UFS_NIADDR]; 121ca987d46SWarner Losh /* number of blocks mapped by 122ca987d46SWarner Losh indirect block at level i */ 123ca987d46SWarner Losh char *f_blk[UFS_NIADDR]; /* buffer for indirect block at 124ca987d46SWarner Losh level i */ 125ca987d46SWarner Losh size_t f_blksize[UFS_NIADDR]; 126ca987d46SWarner Losh /* size of buffer */ 127ca987d46SWarner Losh ufs2_daddr_t f_blkno[UFS_NIADDR];/* disk address of block in buffer */ 128ca987d46SWarner Losh ufs2_daddr_t f_buf_blkno; /* block number of data block */ 129ca987d46SWarner Losh char *f_buf; /* buffer for data block */ 130ca987d46SWarner Losh size_t f_buf_size; /* size of data block */ 1315ad42d0fSSimon J. Gerraty int f_inumber; /* inumber */ 132ca987d46SWarner Losh }; 133ca987d46SWarner Losh #define DIP(fp, field) \ 134ca987d46SWarner Losh ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ 135ca987d46SWarner Losh (fp)->f_di.di1.field : (fp)->f_di.di2.field) 136ca987d46SWarner Losh 137b4cb3fe0SToomas Soome typedef struct ufs_mnt { 138b4cb3fe0SToomas Soome char *um_dev; 139b4cb3fe0SToomas Soome int um_fd; 140b4cb3fe0SToomas Soome STAILQ_ENTRY(ufs_mnt) um_link; 141b4cb3fe0SToomas Soome } ufs_mnt_t; 142b4cb3fe0SToomas Soome 143b4cb3fe0SToomas Soome typedef STAILQ_HEAD(ufs_mnt_list, ufs_mnt) ufs_mnt_list_t; 144b4cb3fe0SToomas Soome static ufs_mnt_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list); 145b4cb3fe0SToomas Soome 146ca987d46SWarner Losh static int read_inode(ino_t, struct open_file *); 147ca987d46SWarner Losh static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); 148ca987d46SWarner Losh static int buf_read_file(struct open_file *, char **, size_t *); 1492e7e6fbcSConrad Meyer static int buf_write_file(struct open_file *, const char *, size_t *); 150ca987d46SWarner Losh static int search_directory(char *, struct open_file *, ino_t *); 151dffce215SKirk McKusick static int ufs_use_sa_read(void *, off_t, void **, int); 152dffce215SKirk McKusick 153dffce215SKirk McKusick /* from ffs_subr.c */ 1546d645da0SWarner Losh int ffs_sbget(void *devfd, struct fs **fsp, off_t sblock, int flags, 1556d645da0SWarner Losh char *filltype, 1566d645da0SWarner Losh int (*readfunc)(void *devfd, off_t loc, void **bufp, int size)); 157e6886616SKirk McKusick int ffs_sbsearch(void *, struct fs **, int, char *, 158dffce215SKirk McKusick int (*)(void *, off_t, void **, int)); 159ca987d46SWarner Losh 160ca987d46SWarner Losh /* 161ca987d46SWarner Losh * Read a new inode into a file structure. 162ca987d46SWarner Losh */ 163ca987d46SWarner Losh static int 164b4cb3fe0SToomas Soome read_inode(ino_t inumber, struct open_file *f) 165ca987d46SWarner Losh { 166ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 167ca987d46SWarner Losh struct fs *fs = fp->f_fs; 168ca987d46SWarner Losh char *buf; 169ca987d46SWarner Losh size_t rsize; 170ca987d46SWarner Losh int rc; 171ca987d46SWarner Losh 172ca987d46SWarner Losh if (fs == NULL) 173ca987d46SWarner Losh panic("fs == NULL"); 174ca987d46SWarner Losh 175ca987d46SWarner Losh /* 176ca987d46SWarner Losh * Read inode and save it. 177ca987d46SWarner Losh */ 178ca987d46SWarner Losh buf = malloc(fs->fs_bsize); 179ca987d46SWarner Losh twiddle(1); 180ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 181ca987d46SWarner Losh fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, 182ca987d46SWarner Losh buf, &rsize); 183ca987d46SWarner Losh if (rc) 184ca987d46SWarner Losh goto out; 185ca987d46SWarner Losh if (rsize != fs->fs_bsize) { 186ca987d46SWarner Losh rc = EIO; 187ca987d46SWarner Losh goto out; 188ca987d46SWarner Losh } 189ca987d46SWarner Losh 190ca987d46SWarner Losh if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 191ca987d46SWarner Losh fp->f_di.di1 = ((struct ufs1_dinode *)buf) 192ca987d46SWarner Losh [ino_to_fsbo(fs, inumber)]; 193ca987d46SWarner Losh else 194ca987d46SWarner Losh fp->f_di.di2 = ((struct ufs2_dinode *)buf) 195ca987d46SWarner Losh [ino_to_fsbo(fs, inumber)]; 196ca987d46SWarner Losh 197ca987d46SWarner Losh /* 198ca987d46SWarner Losh * Clear out the old buffers 199ca987d46SWarner Losh */ 200ca987d46SWarner Losh { 201ca987d46SWarner Losh int level; 202ca987d46SWarner Losh 203ca987d46SWarner Losh for (level = 0; level < UFS_NIADDR; level++) 204ca987d46SWarner Losh fp->f_blkno[level] = -1; 205ca987d46SWarner Losh fp->f_buf_blkno = -1; 206ca987d46SWarner Losh } 207ca987d46SWarner Losh fp->f_seekp = 0; 2085ad42d0fSSimon J. Gerraty fp->f_inumber = inumber; 209ca987d46SWarner Losh out: 210ca987d46SWarner Losh free(buf); 211ca987d46SWarner Losh return (rc); 212ca987d46SWarner Losh } 213ca987d46SWarner Losh 214ca987d46SWarner Losh /* 215ca987d46SWarner Losh * Given an offset in a file, find the disk block number that 216ca987d46SWarner Losh * contains that block. 217ca987d46SWarner Losh */ 218ca987d46SWarner Losh static int 219b4cb3fe0SToomas Soome block_map(struct open_file *f, ufs2_daddr_t file_block, 220b4cb3fe0SToomas Soome ufs2_daddr_t *disk_block_p) 221ca987d46SWarner Losh { 222ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 223ca987d46SWarner Losh struct fs *fs = fp->f_fs; 224ca987d46SWarner Losh int level; 225ca987d46SWarner Losh int idx; 226ca987d46SWarner Losh ufs2_daddr_t ind_block_num; 227ca987d46SWarner Losh int rc; 228ca987d46SWarner Losh 229ca987d46SWarner Losh /* 230ca987d46SWarner Losh * Index structure of an inode: 231ca987d46SWarner Losh * 232ca987d46SWarner Losh * di_db[0..UFS_NDADDR-1] hold block numbers for blocks 233ca987d46SWarner Losh * 0..UFS_NDADDR-1 234ca987d46SWarner Losh * 235ca987d46SWarner Losh * di_ib[0] index block 0 is the single indirect block 236ca987d46SWarner Losh * holds block numbers for blocks 237ca987d46SWarner Losh * UFS_NDADDR .. UFS_NDADDR + NINDIR(fs)-1 238ca987d46SWarner Losh * 239ca987d46SWarner Losh * di_ib[1] index block 1 is the double indirect block 240ca987d46SWarner Losh * holds block numbers for INDEX blocks for blocks 241ca987d46SWarner Losh * UFS_NDADDR + NINDIR(fs) .. 242ca987d46SWarner Losh * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 243ca987d46SWarner Losh * 244ca987d46SWarner Losh * di_ib[2] index block 2 is the triple indirect block 245ca987d46SWarner Losh * holds block numbers for double-indirect 246ca987d46SWarner Losh * blocks for blocks 247ca987d46SWarner Losh * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 248ca987d46SWarner Losh * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 249ca987d46SWarner Losh * + NINDIR(fs)**3 - 1 250ca987d46SWarner Losh */ 251ca987d46SWarner Losh 252ca987d46SWarner Losh if (file_block < UFS_NDADDR) { 253ca987d46SWarner Losh /* Direct block. */ 254ca987d46SWarner Losh *disk_block_p = DIP(fp, di_db[file_block]); 255ca987d46SWarner Losh return (0); 256ca987d46SWarner Losh } 257ca987d46SWarner Losh 258ca987d46SWarner Losh file_block -= UFS_NDADDR; 259ca987d46SWarner Losh 260ca987d46SWarner Losh /* 261ca987d46SWarner Losh * nindir[0] = NINDIR 262ca987d46SWarner Losh * nindir[1] = NINDIR**2 263ca987d46SWarner Losh * nindir[2] = NINDIR**3 264ca987d46SWarner Losh * etc 265ca987d46SWarner Losh */ 266ca987d46SWarner Losh for (level = 0; level < UFS_NIADDR; level++) { 267ca987d46SWarner Losh if (file_block < fp->f_nindir[level]) 268ca987d46SWarner Losh break; 269ca987d46SWarner Losh file_block -= fp->f_nindir[level]; 270ca987d46SWarner Losh } 271ca987d46SWarner Losh if (level == UFS_NIADDR) { 272ca987d46SWarner Losh /* Block number too high */ 273ca987d46SWarner Losh return (EFBIG); 274ca987d46SWarner Losh } 275ca987d46SWarner Losh 276ca987d46SWarner Losh ind_block_num = DIP(fp, di_ib[level]); 277ca987d46SWarner Losh 278ca987d46SWarner Losh for (; level >= 0; level--) { 279ca987d46SWarner Losh if (ind_block_num == 0) { 280ca987d46SWarner Losh *disk_block_p = 0; /* missing */ 281ca987d46SWarner Losh return (0); 282ca987d46SWarner Losh } 283ca987d46SWarner Losh 284ca987d46SWarner Losh if (fp->f_blkno[level] != ind_block_num) { 285ca987d46SWarner Losh if (fp->f_blk[level] == (char *)0) 286ca987d46SWarner Losh fp->f_blk[level] = 287ca987d46SWarner Losh malloc(fs->fs_bsize); 288ca987d46SWarner Losh twiddle(1); 289ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 290ca987d46SWarner Losh fsbtodb(fp->f_fs, ind_block_num), 291ca987d46SWarner Losh fs->fs_bsize, 292ca987d46SWarner Losh fp->f_blk[level], 293ca987d46SWarner Losh &fp->f_blksize[level]); 294ca987d46SWarner Losh if (rc) 295ca987d46SWarner Losh return (rc); 296ca987d46SWarner Losh if (fp->f_blksize[level] != fs->fs_bsize) 297ca987d46SWarner Losh return (EIO); 298ca987d46SWarner Losh fp->f_blkno[level] = ind_block_num; 299ca987d46SWarner Losh } 300ca987d46SWarner Losh 301ca987d46SWarner Losh if (level > 0) { 302ca987d46SWarner Losh idx = file_block / fp->f_nindir[level - 1]; 303ca987d46SWarner Losh file_block %= fp->f_nindir[level - 1]; 304ca987d46SWarner Losh } else 305ca987d46SWarner Losh idx = file_block; 306ca987d46SWarner Losh 307ca987d46SWarner Losh if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 308ca987d46SWarner Losh ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx]; 309ca987d46SWarner Losh else 310ca987d46SWarner Losh ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx]; 311ca987d46SWarner Losh } 312ca987d46SWarner Losh 313ca987d46SWarner Losh *disk_block_p = ind_block_num; 314ca987d46SWarner Losh 315ca987d46SWarner Losh return (0); 316ca987d46SWarner Losh } 317ca987d46SWarner Losh 318ca987d46SWarner Losh /* 319ca987d46SWarner Losh * Write a portion of a file from an internal buffer. 320ca987d46SWarner Losh */ 321ca987d46SWarner Losh static int 322b4cb3fe0SToomas Soome buf_write_file(struct open_file *f, const char *buf_p, size_t *size_p) 323ca987d46SWarner Losh { 324ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 325ca987d46SWarner Losh struct fs *fs = fp->f_fs; 326ca987d46SWarner Losh long off; 327ca987d46SWarner Losh ufs_lbn_t file_block; 328ca987d46SWarner Losh ufs2_daddr_t disk_block; 329ca987d46SWarner Losh size_t block_size; 330ca987d46SWarner Losh int rc; 331ca987d46SWarner Losh 332ca987d46SWarner Losh /* 333ca987d46SWarner Losh * Calculate the starting block address and offset. 334ca987d46SWarner Losh */ 335ca987d46SWarner Losh off = blkoff(fs, fp->f_seekp); 336ca987d46SWarner Losh file_block = lblkno(fs, fp->f_seekp); 337ca987d46SWarner Losh block_size = sblksize(fs, DIP(fp, di_size), file_block); 338ca987d46SWarner Losh 339ca987d46SWarner Losh rc = block_map(f, file_block, &disk_block); 340ca987d46SWarner Losh if (rc) 341ca987d46SWarner Losh return (rc); 342ca987d46SWarner Losh 343ca987d46SWarner Losh if (disk_block == 0) 344ca987d46SWarner Losh /* Because we can't allocate space on the drive */ 345ca987d46SWarner Losh return (EFBIG); 346ca987d46SWarner Losh 347ca987d46SWarner Losh /* 348ca987d46SWarner Losh * Truncate buffer at end of file, and at the end of 349ca987d46SWarner Losh * this block. 350ca987d46SWarner Losh */ 351ca987d46SWarner Losh if (*size_p > DIP(fp, di_size) - fp->f_seekp) 352ca987d46SWarner Losh *size_p = DIP(fp, di_size) - fp->f_seekp; 353ca987d46SWarner Losh if (*size_p > block_size - off) 354ca987d46SWarner Losh *size_p = block_size - off; 355ca987d46SWarner Losh 356ca987d46SWarner Losh /* 357ca987d46SWarner Losh * If we don't entirely occlude the block and it's not 358ca987d46SWarner Losh * in memory already, read it in first. 359ca987d46SWarner Losh */ 360ca987d46SWarner Losh if (((off > 0) || (*size_p + off < block_size)) && 361ca987d46SWarner Losh (file_block != fp->f_buf_blkno)) { 362ca987d46SWarner Losh 363ca987d46SWarner Losh if (fp->f_buf == (char *)0) 364ca987d46SWarner Losh fp->f_buf = malloc(fs->fs_bsize); 365ca987d46SWarner Losh 366ca987d46SWarner Losh twiddle(4); 367ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 368ca987d46SWarner Losh fsbtodb(fs, disk_block), 369ca987d46SWarner Losh block_size, fp->f_buf, &fp->f_buf_size); 370ca987d46SWarner Losh if (rc) 371ca987d46SWarner Losh return (rc); 372ca987d46SWarner Losh 373ca987d46SWarner Losh fp->f_buf_blkno = file_block; 374ca987d46SWarner Losh } 375ca987d46SWarner Losh 376ca987d46SWarner Losh /* 377ca987d46SWarner Losh * Copy the user data into the cached block. 378ca987d46SWarner Losh */ 379ca987d46SWarner Losh bcopy(buf_p, fp->f_buf + off, *size_p); 380ca987d46SWarner Losh 381ca987d46SWarner Losh /* 382ca987d46SWarner Losh * Write the block out to storage. 383ca987d46SWarner Losh */ 384ca987d46SWarner Losh 385ca987d46SWarner Losh twiddle(4); 386ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, 387ca987d46SWarner Losh fsbtodb(fs, disk_block), 388ca987d46SWarner Losh block_size, fp->f_buf, &fp->f_buf_size); 389ca987d46SWarner Losh return (rc); 390ca987d46SWarner Losh } 391ca987d46SWarner Losh 392ca987d46SWarner Losh /* 393ca987d46SWarner Losh * Read a portion of a file into an internal buffer. Return 394ca987d46SWarner Losh * the location in the buffer and the amount in the buffer. 395ca987d46SWarner Losh */ 396ca987d46SWarner Losh static int 397b4cb3fe0SToomas Soome buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 398ca987d46SWarner Losh { 399ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 400ca987d46SWarner Losh struct fs *fs = fp->f_fs; 401ca987d46SWarner Losh long off; 402ca987d46SWarner Losh ufs_lbn_t file_block; 403ca987d46SWarner Losh ufs2_daddr_t disk_block; 404ca987d46SWarner Losh size_t block_size; 405ca987d46SWarner Losh int rc; 406ca987d46SWarner Losh 407ca987d46SWarner Losh off = blkoff(fs, fp->f_seekp); 408ca987d46SWarner Losh file_block = lblkno(fs, fp->f_seekp); 409ca987d46SWarner Losh block_size = sblksize(fs, DIP(fp, di_size), file_block); 410ca987d46SWarner Losh 411ca987d46SWarner Losh if (file_block != fp->f_buf_blkno) { 41268160fbdSAlfonso if (fp->f_buf == NULL) 413ca987d46SWarner Losh fp->f_buf = malloc(fs->fs_bsize); 414ca987d46SWarner Losh 415ca987d46SWarner Losh rc = block_map(f, file_block, &disk_block); 416ca987d46SWarner Losh if (rc) 417ca987d46SWarner Losh return (rc); 418ca987d46SWarner Losh 419ca987d46SWarner Losh if (disk_block == 0) { 420ca987d46SWarner Losh bzero(fp->f_buf, block_size); 421ca987d46SWarner Losh fp->f_buf_size = block_size; 422ca987d46SWarner Losh } else { 423ca987d46SWarner Losh twiddle(4); 424ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 425ca987d46SWarner Losh fsbtodb(fs, disk_block), 426ca987d46SWarner Losh block_size, fp->f_buf, &fp->f_buf_size); 427ca987d46SWarner Losh if (rc) 428ca987d46SWarner Losh return (rc); 429ca987d46SWarner Losh } 430ca987d46SWarner Losh 431ca987d46SWarner Losh fp->f_buf_blkno = file_block; 432ca987d46SWarner Losh } 433ca987d46SWarner Losh 434ca987d46SWarner Losh /* 435ca987d46SWarner Losh * Return address of byte in buffer corresponding to 436ca987d46SWarner Losh * offset, and size of remainder of buffer after that 437ca987d46SWarner Losh * byte. 438ca987d46SWarner Losh */ 439ca987d46SWarner Losh *buf_p = fp->f_buf + off; 440ca987d46SWarner Losh *size_p = block_size - off; 441ca987d46SWarner Losh 442ca987d46SWarner Losh /* 443ca987d46SWarner Losh * But truncate buffer at end of file. 444ca987d46SWarner Losh */ 445ca987d46SWarner Losh if (*size_p > DIP(fp, di_size) - fp->f_seekp) 446ca987d46SWarner Losh *size_p = DIP(fp, di_size) - fp->f_seekp; 447ca987d46SWarner Losh 448ca987d46SWarner Losh return (0); 449ca987d46SWarner Losh } 450ca987d46SWarner Losh 451ca987d46SWarner Losh /* 452ca987d46SWarner Losh * Search a directory for a name and return its 453ca987d46SWarner Losh * i_number. 454ca987d46SWarner Losh */ 455ca987d46SWarner Losh static int 456b4cb3fe0SToomas Soome search_directory(char *name, struct open_file *f, ino_t *inumber_p) 457ca987d46SWarner Losh { 458ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 459ca987d46SWarner Losh struct direct *dp; 460ca987d46SWarner Losh struct direct *edp; 461ca987d46SWarner Losh char *buf; 462ca987d46SWarner Losh size_t buf_size; 463ca987d46SWarner Losh int namlen, length; 464ca987d46SWarner Losh int rc; 465ca987d46SWarner Losh 466ca987d46SWarner Losh length = strlen(name); 467ca987d46SWarner Losh 468ca987d46SWarner Losh fp->f_seekp = 0; 469ca987d46SWarner Losh while (fp->f_seekp < DIP(fp, di_size)) { 470ca987d46SWarner Losh rc = buf_read_file(f, &buf, &buf_size); 471ca987d46SWarner Losh if (rc) 472ca987d46SWarner Losh return (rc); 473ca987d46SWarner Losh 474ca987d46SWarner Losh dp = (struct direct *)buf; 475ca987d46SWarner Losh edp = (struct direct *)(buf + buf_size); 476ca987d46SWarner Losh while (dp < edp) { 477ca987d46SWarner Losh if (dp->d_ino == (ino_t)0) 478ca987d46SWarner Losh goto next; 479ca987d46SWarner Losh #if BYTE_ORDER == LITTLE_ENDIAN 480ca987d46SWarner Losh if (fp->f_fs->fs_maxsymlinklen <= 0) 481ca987d46SWarner Losh namlen = dp->d_type; 482ca987d46SWarner Losh else 483ca987d46SWarner Losh #endif 484ca987d46SWarner Losh namlen = dp->d_namlen; 485ca987d46SWarner Losh if (namlen == length && 486ca987d46SWarner Losh !strcmp(name, dp->d_name)) { 487ca987d46SWarner Losh /* found entry */ 488ca987d46SWarner Losh *inumber_p = dp->d_ino; 489ca987d46SWarner Losh return (0); 490ca987d46SWarner Losh } 491ca987d46SWarner Losh next: 492ca987d46SWarner Losh dp = (struct direct *)((char *)dp + dp->d_reclen); 493ca987d46SWarner Losh } 494ca987d46SWarner Losh fp->f_seekp += buf_size; 495ca987d46SWarner Losh } 496ca987d46SWarner Losh return (ENOENT); 497ca987d46SWarner Losh } 498ca987d46SWarner Losh 499ca987d46SWarner Losh /* 500ca987d46SWarner Losh * Open a file. 501ca987d46SWarner Losh */ 502ca987d46SWarner Losh static int 503b4cb3fe0SToomas Soome ufs_open(const char *upath, struct open_file *f) 504ca987d46SWarner Losh { 505ca987d46SWarner Losh char *cp, *ncp; 506ca987d46SWarner Losh int c; 507ca987d46SWarner Losh ino_t inumber, parent_inumber; 508ca987d46SWarner Losh struct file *fp; 509ca987d46SWarner Losh struct fs *fs; 5106d423eb2SWarner Losh int rc; 511ca987d46SWarner Losh int nlinks = 0; 512ca987d46SWarner Losh char namebuf[MAXPATHLEN+1]; 513ca987d46SWarner Losh char *buf = NULL; 514ca987d46SWarner Losh char *path = NULL; 515b4cb3fe0SToomas Soome const char *dev; 516b4cb3fe0SToomas Soome ufs_mnt_t *mnt; 517ca987d46SWarner Losh 518ca987d46SWarner Losh /* allocate file system specific data structure */ 519b4cb3fe0SToomas Soome errno = 0; 520b4cb3fe0SToomas Soome fp = calloc(1, sizeof(struct file)); 521b4cb3fe0SToomas Soome if (fp == NULL) 522b4cb3fe0SToomas Soome return (errno); 523ca987d46SWarner Losh f->f_fsdata = (void *)fp; 524ca987d46SWarner Losh 5250b3a4a58SWarner Losh dev = devformat((struct devdesc *)f->f_devdata); 526b4cb3fe0SToomas Soome /* Is this device mounted? */ 527b4cb3fe0SToomas Soome STAILQ_FOREACH(mnt, &mnt_list, um_link) { 528b4cb3fe0SToomas Soome if (strcmp(dev, mnt->um_dev) == 0) 529b4cb3fe0SToomas Soome break; 530b4cb3fe0SToomas Soome } 531b4cb3fe0SToomas Soome 532b4cb3fe0SToomas Soome if (mnt == NULL) { 533dffce215SKirk McKusick /* read super block */ 534ca987d46SWarner Losh twiddle(1); 5356d645da0SWarner Losh if ((rc = ffs_sbget(f, &fs, UFS_STDSB, UFS_NOHASHFAIL, "stand", 5366d645da0SWarner Losh ufs_use_sa_read)) != 0) { 537ca987d46SWarner Losh goto out; 538b4cb3fe0SToomas Soome } 539b4cb3fe0SToomas Soome } else { 540b4cb3fe0SToomas Soome struct open_file *sbf; 541b4cb3fe0SToomas Soome struct file *sfp; 542b4cb3fe0SToomas Soome 543b4cb3fe0SToomas Soome /* get superblock from mounted file system */ 544b4cb3fe0SToomas Soome sbf = fd2open_file(mnt->um_fd); 545b4cb3fe0SToomas Soome sfp = sbf->f_fsdata; 546b4cb3fe0SToomas Soome fs = sfp->f_fs; 547b4cb3fe0SToomas Soome } 548dffce215SKirk McKusick fp->f_fs = fs; 549b4cb3fe0SToomas Soome 550ca987d46SWarner Losh /* 551ca987d46SWarner Losh * Calculate indirect block levels. 552ca987d46SWarner Losh */ 553ca987d46SWarner Losh { 554ca987d46SWarner Losh ufs2_daddr_t mult; 555ca987d46SWarner Losh int level; 556ca987d46SWarner Losh 557ca987d46SWarner Losh mult = 1; 558ca987d46SWarner Losh for (level = 0; level < UFS_NIADDR; level++) { 559ca987d46SWarner Losh mult *= NINDIR(fs); 560ca987d46SWarner Losh fp->f_nindir[level] = mult; 561ca987d46SWarner Losh } 562ca987d46SWarner Losh } 563ca987d46SWarner Losh 564ca987d46SWarner Losh inumber = UFS_ROOTINO; 565ca987d46SWarner Losh if ((rc = read_inode(inumber, f)) != 0) 566ca987d46SWarner Losh goto out; 567ca987d46SWarner Losh 568ca987d46SWarner Losh cp = path = strdup(upath); 569ca987d46SWarner Losh if (path == NULL) { 570ca987d46SWarner Losh rc = ENOMEM; 571ca987d46SWarner Losh goto out; 572ca987d46SWarner Losh } 573ca987d46SWarner Losh while (*cp) { 574ca987d46SWarner Losh 575ca987d46SWarner Losh /* 576ca987d46SWarner Losh * Remove extra separators 577ca987d46SWarner Losh */ 578ca987d46SWarner Losh while (*cp == '/') 579ca987d46SWarner Losh cp++; 580ca987d46SWarner Losh if (*cp == '\0') 581ca987d46SWarner Losh break; 582ca987d46SWarner Losh 583ca987d46SWarner Losh /* 584ca987d46SWarner Losh * Check that current node is a directory. 585ca987d46SWarner Losh */ 586d8ba45e2SEd Maste if ((DIP(fp, di_mode) & IFMT) != IFDIR) { 587ca987d46SWarner Losh rc = ENOTDIR; 588ca987d46SWarner Losh goto out; 589ca987d46SWarner Losh } 590ca987d46SWarner Losh 591ca987d46SWarner Losh /* 592ca987d46SWarner Losh * Get next component of path name. 593ca987d46SWarner Losh */ 594ca987d46SWarner Losh { 595ca987d46SWarner Losh int len = 0; 596ca987d46SWarner Losh 597ca987d46SWarner Losh ncp = cp; 598ca987d46SWarner Losh while ((c = *cp) != '\0' && c != '/') { 599ca987d46SWarner Losh if (++len > UFS_MAXNAMLEN) { 600ca987d46SWarner Losh rc = ENOENT; 601ca987d46SWarner Losh goto out; 602ca987d46SWarner Losh } 603ca987d46SWarner Losh cp++; 604ca987d46SWarner Losh } 605ca987d46SWarner Losh *cp = '\0'; 606ca987d46SWarner Losh } 607ca987d46SWarner Losh 608ca987d46SWarner Losh /* 609ca987d46SWarner Losh * Look up component in current directory. 610ca987d46SWarner Losh * Save directory inumber in case we find a 611ca987d46SWarner Losh * symbolic link. 612ca987d46SWarner Losh */ 613ca987d46SWarner Losh parent_inumber = inumber; 614ca987d46SWarner Losh rc = search_directory(ncp, f, &inumber); 615ca987d46SWarner Losh *cp = c; 616ca987d46SWarner Losh if (rc) 617ca987d46SWarner Losh goto out; 618ca987d46SWarner Losh 619ca987d46SWarner Losh /* 620ca987d46SWarner Losh * Open next component. 621ca987d46SWarner Losh */ 622ca987d46SWarner Losh if ((rc = read_inode(inumber, f)) != 0) 623ca987d46SWarner Losh goto out; 624ca987d46SWarner Losh 625ca987d46SWarner Losh /* 626ca987d46SWarner Losh * Check for symbolic link. 627ca987d46SWarner Losh */ 628d8ba45e2SEd Maste if ((DIP(fp, di_mode) & IFMT) == IFLNK) { 629ca987d46SWarner Losh int link_len = DIP(fp, di_size); 630ca987d46SWarner Losh int len; 631ca987d46SWarner Losh 632ca987d46SWarner Losh len = strlen(cp); 633ca987d46SWarner Losh 634ca987d46SWarner Losh if (link_len + len > MAXPATHLEN || 635ca987d46SWarner Losh ++nlinks > MAXSYMLINKS) { 636ca987d46SWarner Losh rc = ENOENT; 637ca987d46SWarner Losh goto out; 638ca987d46SWarner Losh } 639ca987d46SWarner Losh 640ca987d46SWarner Losh bcopy(cp, &namebuf[link_len], len + 1); 641ca987d46SWarner Losh 642ca987d46SWarner Losh if (link_len < fs->fs_maxsymlinklen) { 6435b13fa79SJessica Clarke bcopy(DIP(fp, di_shortlink), namebuf, 6445b13fa79SJessica Clarke (unsigned) link_len); 645ca987d46SWarner Losh } else { 646ca987d46SWarner Losh /* 647ca987d46SWarner Losh * Read file for symbolic link 648ca987d46SWarner Losh */ 649ca987d46SWarner Losh size_t buf_size; 650ca987d46SWarner Losh ufs2_daddr_t disk_block; 651ca987d46SWarner Losh struct fs *fs = fp->f_fs; 652ca987d46SWarner Losh 653ca987d46SWarner Losh if (!buf) 654ca987d46SWarner Losh buf = malloc(fs->fs_bsize); 655ca987d46SWarner Losh rc = block_map(f, (ufs2_daddr_t)0, &disk_block); 656ca987d46SWarner Losh if (rc) 657ca987d46SWarner Losh goto out; 658ca987d46SWarner Losh 659ca987d46SWarner Losh twiddle(1); 660ca987d46SWarner Losh rc = (f->f_dev->dv_strategy)(f->f_devdata, 661ca987d46SWarner Losh F_READ, fsbtodb(fs, disk_block), 662ca987d46SWarner Losh fs->fs_bsize, buf, &buf_size); 663ca987d46SWarner Losh if (rc) 664ca987d46SWarner Losh goto out; 665ca987d46SWarner Losh 666ca987d46SWarner Losh bcopy((char *)buf, namebuf, (unsigned)link_len); 667ca987d46SWarner Losh } 668ca987d46SWarner Losh 669ca987d46SWarner Losh /* 670ca987d46SWarner Losh * If relative pathname, restart at parent directory. 671ca987d46SWarner Losh * If absolute pathname, restart at root. 672ca987d46SWarner Losh */ 673ca987d46SWarner Losh cp = namebuf; 674ca987d46SWarner Losh if (*cp != '/') 675ca987d46SWarner Losh inumber = parent_inumber; 676ca987d46SWarner Losh else 677ca987d46SWarner Losh inumber = (ino_t)UFS_ROOTINO; 678ca987d46SWarner Losh 679ca987d46SWarner Losh if ((rc = read_inode(inumber, f)) != 0) 680ca987d46SWarner Losh goto out; 681ca987d46SWarner Losh } 682ca987d46SWarner Losh } 683ca987d46SWarner Losh 684ca987d46SWarner Losh /* 685ca987d46SWarner Losh * Found terminal component. 686ca987d46SWarner Losh */ 687ca987d46SWarner Losh rc = 0; 688ca987d46SWarner Losh fp->f_seekp = 0; 689ca987d46SWarner Losh out: 690ca987d46SWarner Losh free(buf); 691ca987d46SWarner Losh free(path); 692ca987d46SWarner Losh if (rc) { 693ca987d46SWarner Losh free(fp->f_buf); 694b4cb3fe0SToomas Soome 695b4cb3fe0SToomas Soome if (mnt == NULL && fp->f_fs != NULL) { 69634816cb9SKirk McKusick free(fp->f_fs->fs_csp); 69734816cb9SKirk McKusick free(fp->f_fs->fs_si); 698ca987d46SWarner Losh free(fp->f_fs); 69934816cb9SKirk McKusick } 700ca987d46SWarner Losh free(fp); 701ca987d46SWarner Losh } 702ca987d46SWarner Losh return (rc); 703ca987d46SWarner Losh } 704ca987d46SWarner Losh 705dffce215SKirk McKusick /* 706dffce215SKirk McKusick * A read function for use by standalone-layer routines. 707dffce215SKirk McKusick */ 708dffce215SKirk McKusick static int 709dffce215SKirk McKusick ufs_use_sa_read(void *devfd, off_t loc, void **bufp, int size) 710dffce215SKirk McKusick { 711dffce215SKirk McKusick struct open_file *f; 712dffce215SKirk McKusick size_t buf_size; 713dffce215SKirk McKusick int error; 714dffce215SKirk McKusick 715dffce215SKirk McKusick f = (struct open_file *)devfd; 716dffce215SKirk McKusick if ((*bufp = malloc(size)) == NULL) 717dffce215SKirk McKusick return (ENOSPC); 718dffce215SKirk McKusick error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, loc / DEV_BSIZE, 719dffce215SKirk McKusick size, *bufp, &buf_size); 720dffce215SKirk McKusick if (error != 0) 721dffce215SKirk McKusick return (error); 722dffce215SKirk McKusick if (buf_size != size) 723dffce215SKirk McKusick return (EIO); 724dffce215SKirk McKusick return (0); 725dffce215SKirk McKusick } 726dffce215SKirk McKusick 727ca987d46SWarner Losh static int 728b4cb3fe0SToomas Soome ufs_close(struct open_file *f) 729ca987d46SWarner Losh { 730b4cb3fe0SToomas Soome ufs_mnt_t *mnt; 731ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 732ca987d46SWarner Losh int level; 733b4cb3fe0SToomas Soome char *dev; 734ca987d46SWarner Losh 735b4cb3fe0SToomas Soome f->f_fsdata = NULL; 736b4cb3fe0SToomas Soome if (fp == NULL) 737ca987d46SWarner Losh return (0); 738ca987d46SWarner Losh 739ca987d46SWarner Losh for (level = 0; level < UFS_NIADDR; level++) { 740ca987d46SWarner Losh free(fp->f_blk[level]); 741ca987d46SWarner Losh } 742ca987d46SWarner Losh free(fp->f_buf); 743b4cb3fe0SToomas Soome 7440b3a4a58SWarner Losh dev = devformat((struct devdesc *)f->f_devdata); 745b4cb3fe0SToomas Soome STAILQ_FOREACH(mnt, &mnt_list, um_link) { 746b4cb3fe0SToomas Soome if (strcmp(dev, mnt->um_dev) == 0) 747b4cb3fe0SToomas Soome break; 748b4cb3fe0SToomas Soome } 749b4cb3fe0SToomas Soome 750b4cb3fe0SToomas Soome if (mnt == NULL && fp->f_fs != NULL) { 75134816cb9SKirk McKusick free(fp->f_fs->fs_csp); 75234816cb9SKirk McKusick free(fp->f_fs->fs_si); 753ca987d46SWarner Losh free(fp->f_fs); 75434816cb9SKirk McKusick } 755b4cb3fe0SToomas Soome 756ca987d46SWarner Losh free(fp); 757ca987d46SWarner Losh return (0); 758ca987d46SWarner Losh } 759ca987d46SWarner Losh 760ca987d46SWarner Losh /* 761ca987d46SWarner Losh * Copy a portion of a file into kernel memory. 762ca987d46SWarner Losh * Cross block boundaries when necessary. 763ca987d46SWarner Losh */ 764ca987d46SWarner Losh static int 765b4cb3fe0SToomas Soome ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) 766ca987d46SWarner Losh { 767ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 768ca987d46SWarner Losh size_t csize; 769ca987d46SWarner Losh char *buf; 770ca987d46SWarner Losh size_t buf_size; 771ca987d46SWarner Losh int rc = 0; 772ca987d46SWarner Losh char *addr = start; 773ca987d46SWarner Losh 774ca987d46SWarner Losh while (size != 0) { 775ca987d46SWarner Losh if (fp->f_seekp >= DIP(fp, di_size)) 776ca987d46SWarner Losh break; 777ca987d46SWarner Losh 778ca987d46SWarner Losh rc = buf_read_file(f, &buf, &buf_size); 779ca987d46SWarner Losh if (rc) 780ca987d46SWarner Losh break; 781ca987d46SWarner Losh 782ca987d46SWarner Losh csize = size; 783ca987d46SWarner Losh if (csize > buf_size) 784ca987d46SWarner Losh csize = buf_size; 785ca987d46SWarner Losh 786ca987d46SWarner Losh bcopy(buf, addr, csize); 787ca987d46SWarner Losh 788ca987d46SWarner Losh fp->f_seekp += csize; 789ca987d46SWarner Losh addr += csize; 790ca987d46SWarner Losh size -= csize; 791ca987d46SWarner Losh } 792ca987d46SWarner Losh if (resid) 793ca987d46SWarner Losh *resid = size; 794ca987d46SWarner Losh return (rc); 795ca987d46SWarner Losh } 796ca987d46SWarner Losh 797ca987d46SWarner Losh /* 798ca987d46SWarner Losh * Write to a portion of an already allocated file. 799ca987d46SWarner Losh * Cross block boundaries when necessary. Can not 800ca987d46SWarner Losh * extend the file. 801ca987d46SWarner Losh */ 802ca987d46SWarner Losh static int 803b4cb3fe0SToomas Soome ufs_write(struct open_file *f, const void *start, size_t size, size_t *resid) 804ca987d46SWarner Losh { 805ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 806ca987d46SWarner Losh size_t csize; 807ca987d46SWarner Losh int rc = 0; 8082e7e6fbcSConrad Meyer const char *addr = start; 809ca987d46SWarner Losh 810ca987d46SWarner Losh csize = size; 811ca987d46SWarner Losh while ((size != 0) && (csize != 0)) { 812ca987d46SWarner Losh if (fp->f_seekp >= DIP(fp, di_size)) 813ca987d46SWarner Losh break; 814ca987d46SWarner Losh 815ca987d46SWarner Losh if (csize >= 512) csize = 512; /* XXX */ 816ca987d46SWarner Losh 817ca987d46SWarner Losh rc = buf_write_file(f, addr, &csize); 818ca987d46SWarner Losh if (rc) 819ca987d46SWarner Losh break; 820ca987d46SWarner Losh 821ca987d46SWarner Losh fp->f_seekp += csize; 822ca987d46SWarner Losh addr += csize; 823ca987d46SWarner Losh size -= csize; 824ca987d46SWarner Losh } 825ca987d46SWarner Losh if (resid) 826ca987d46SWarner Losh *resid = size; 827ca987d46SWarner Losh return (rc); 828ca987d46SWarner Losh } 829ca987d46SWarner Losh 830ca987d46SWarner Losh static off_t 831b4cb3fe0SToomas Soome ufs_seek(struct open_file *f, off_t offset, int where) 832ca987d46SWarner Losh { 833ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 834ca987d46SWarner Losh 835ca987d46SWarner Losh switch (where) { 836ca987d46SWarner Losh case SEEK_SET: 837ca987d46SWarner Losh fp->f_seekp = offset; 838ca987d46SWarner Losh break; 839ca987d46SWarner Losh case SEEK_CUR: 840ca987d46SWarner Losh fp->f_seekp += offset; 841ca987d46SWarner Losh break; 842ca987d46SWarner Losh case SEEK_END: 843ca987d46SWarner Losh fp->f_seekp = DIP(fp, di_size) - offset; 844ca987d46SWarner Losh break; 845ca987d46SWarner Losh default: 846ca987d46SWarner Losh errno = EINVAL; 847ca987d46SWarner Losh return (-1); 848ca987d46SWarner Losh } 849ca987d46SWarner Losh return (fp->f_seekp); 850ca987d46SWarner Losh } 851ca987d46SWarner Losh 852ca987d46SWarner Losh static int 853b4cb3fe0SToomas Soome ufs_stat(struct open_file *f, struct stat *sb) 854ca987d46SWarner Losh { 855ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 856ca987d46SWarner Losh 857ca987d46SWarner Losh /* only important stuff */ 858ca987d46SWarner Losh sb->st_mode = DIP(fp, di_mode); 859ca987d46SWarner Losh sb->st_uid = DIP(fp, di_uid); 860ca987d46SWarner Losh sb->st_gid = DIP(fp, di_gid); 861ca987d46SWarner Losh sb->st_size = DIP(fp, di_size); 8625ad42d0fSSimon J. Gerraty sb->st_mtime = DIP(fp, di_mtime); 8635ad42d0fSSimon J. Gerraty /* 8645ad42d0fSSimon J. Gerraty * The items below are ufs specific! 8655ad42d0fSSimon J. Gerraty * Other fs types will need their own solution 8665ad42d0fSSimon J. Gerraty * if these fields are needed. 8675ad42d0fSSimon J. Gerraty */ 8685ad42d0fSSimon J. Gerraty sb->st_ino = fp->f_inumber; 8695ad42d0fSSimon J. Gerraty /* 8705ad42d0fSSimon J. Gerraty * We need something to differentiate devs. 8715ad42d0fSSimon J. Gerraty * fs_id is unique but 64bit, we xor the two 8725ad42d0fSSimon J. Gerraty * halves to squeeze it into 32bits. 8735ad42d0fSSimon J. Gerraty */ 8745ad42d0fSSimon J. Gerraty sb->st_dev = (dev_t)(fp->f_fs->fs_id[0] ^ fp->f_fs->fs_id[1]); 8755ad42d0fSSimon J. Gerraty 876ca987d46SWarner Losh return (0); 877ca987d46SWarner Losh } 878ca987d46SWarner Losh 879ca987d46SWarner Losh static int 880ca987d46SWarner Losh ufs_readdir(struct open_file *f, struct dirent *d) 881ca987d46SWarner Losh { 882ca987d46SWarner Losh struct file *fp = (struct file *)f->f_fsdata; 883ca987d46SWarner Losh struct direct *dp; 884ca987d46SWarner Losh char *buf; 885ca987d46SWarner Losh size_t buf_size; 886ca987d46SWarner Losh int error; 887ca987d46SWarner Losh 888ca987d46SWarner Losh /* 889ca987d46SWarner Losh * assume that a directory entry will not be split across blocks 890ca987d46SWarner Losh */ 89168160fbdSAlfonso 89268160fbdSAlfonso do { 893ca987d46SWarner Losh if (fp->f_seekp >= DIP(fp, di_size)) 894ca987d46SWarner Losh return (ENOENT); 895ca987d46SWarner Losh error = buf_read_file(f, &buf, &buf_size); 896ca987d46SWarner Losh if (error) 897ca987d46SWarner Losh return (error); 898ca987d46SWarner Losh dp = (struct direct *)buf; 899ca987d46SWarner Losh fp->f_seekp += dp->d_reclen; 90068160fbdSAlfonso } while (dp->d_ino == (ino_t)0); 90168160fbdSAlfonso 902ca987d46SWarner Losh d->d_type = dp->d_type; 903ca987d46SWarner Losh strcpy(d->d_name, dp->d_name); 904ca987d46SWarner Losh return (0); 905ca987d46SWarner Losh } 906b4cb3fe0SToomas Soome 907b4cb3fe0SToomas Soome static int 908b4cb3fe0SToomas Soome ufs_mount(const char *dev, const char *path, void **data) 909b4cb3fe0SToomas Soome { 910b4cb3fe0SToomas Soome char *fs; 911b4cb3fe0SToomas Soome ufs_mnt_t *mnt; 912b4cb3fe0SToomas Soome struct open_file *f; 913b4cb3fe0SToomas Soome 914b4cb3fe0SToomas Soome errno = 0; 915b4cb3fe0SToomas Soome mnt = calloc(1, sizeof(*mnt)); 916b4cb3fe0SToomas Soome if (mnt == NULL) 917b4cb3fe0SToomas Soome return (errno); 918b4cb3fe0SToomas Soome mnt->um_fd = -1; 919b4cb3fe0SToomas Soome mnt->um_dev = strdup(dev); 920b4cb3fe0SToomas Soome if (mnt->um_dev == NULL) 921b4cb3fe0SToomas Soome goto done; 922b4cb3fe0SToomas Soome 923b4cb3fe0SToomas Soome if (asprintf(&fs, "%s%s", dev, path) < 0) 924b4cb3fe0SToomas Soome goto done; 925b4cb3fe0SToomas Soome 926b4cb3fe0SToomas Soome mnt->um_fd = open(fs, O_RDONLY); 927b4cb3fe0SToomas Soome free(fs); 928b4cb3fe0SToomas Soome if (mnt->um_fd == -1) 929b4cb3fe0SToomas Soome goto done; 930b4cb3fe0SToomas Soome 931b4cb3fe0SToomas Soome /* Is it ufs file system? */ 932b4cb3fe0SToomas Soome f = fd2open_file(mnt->um_fd); 933b4cb3fe0SToomas Soome if (strcmp(f->f_ops->fs_name, "ufs") == 0) 934b4cb3fe0SToomas Soome STAILQ_INSERT_TAIL(&mnt_list, mnt, um_link); 935b4cb3fe0SToomas Soome else 936b4cb3fe0SToomas Soome errno = ENXIO; 937b4cb3fe0SToomas Soome 938b4cb3fe0SToomas Soome done: 939b4cb3fe0SToomas Soome if (errno != 0) { 940b4cb3fe0SToomas Soome free(mnt->um_dev); 941b4cb3fe0SToomas Soome if (mnt->um_fd >= 0) 942b4cb3fe0SToomas Soome close(mnt->um_fd); 943b4cb3fe0SToomas Soome free(mnt); 944b4cb3fe0SToomas Soome } else { 945b4cb3fe0SToomas Soome *data = mnt; 946b4cb3fe0SToomas Soome } 947b4cb3fe0SToomas Soome 948b4cb3fe0SToomas Soome return (errno); 949b4cb3fe0SToomas Soome } 950b4cb3fe0SToomas Soome 951b4cb3fe0SToomas Soome static int 952b4cb3fe0SToomas Soome ufs_unmount(const char *dev __unused, void *data) 953b4cb3fe0SToomas Soome { 954b4cb3fe0SToomas Soome ufs_mnt_t *mnt = data; 955b4cb3fe0SToomas Soome 956b4cb3fe0SToomas Soome STAILQ_REMOVE(&mnt_list, mnt, ufs_mnt, um_link); 957b4cb3fe0SToomas Soome free(mnt->um_dev); 958b4cb3fe0SToomas Soome close(mnt->um_fd); 959b4cb3fe0SToomas Soome free(mnt); 960b4cb3fe0SToomas Soome return (0); 961b4cb3fe0SToomas Soome } 962