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