138451Smsmith/* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */ 238451Smsmith 338451Smsmith/*- 498542Smckusick * Copyright (c) 2002 Networks Associates Technology, Inc. 598542Smckusick * All rights reserved. 698542Smckusick * 798542Smckusick * This software was developed for the FreeBSD Project by Marshall 898542Smckusick * Kirk McKusick and Network Associates Laboratories, the Security 998542Smckusick * Research Division of Network Associates, Inc. under DARPA/SPAWAR 1098542Smckusick * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 1198542Smckusick * research program 1298542Smckusick * 1398542Smckusick * Copyright (c) 1982, 1989, 1993 1438451Smsmith * The Regents of the University of California. All rights reserved. 1538451Smsmith * 1638451Smsmith * This code is derived from software contributed to Berkeley by 1738451Smsmith * The Mach Operating System project at Carnegie-Mellon University. 1838451Smsmith * 1938451Smsmith * Redistribution and use in source and binary forms, with or without 2038451Smsmith * modification, are permitted provided that the following conditions 2138451Smsmith * are met: 2238451Smsmith * 1. Redistributions of source code must retain the above copyright 2338451Smsmith * notice, this list of conditions and the following disclaimer. 2438451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 2538451Smsmith * notice, this list of conditions and the following disclaimer in the 2638451Smsmith * documentation and/or other materials provided with the distribution. 27344376Skevans * 3. Neither the name of the University nor the names of its contributors 2838451Smsmith * may be used to endorse or promote products derived from this software 2938451Smsmith * without specific prior written permission. 3038451Smsmith * 3138451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 3238451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3338451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3438451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3538451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3638451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3738451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3838451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3938451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4038451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4138451Smsmith * SUCH DAMAGE. 4238451Smsmith * 4338451Smsmith * 4438451Smsmith * Copyright (c) 1990, 1991 Carnegie Mellon University 4538451Smsmith * All Rights Reserved. 4638451Smsmith * 4738451Smsmith * Author: David Golub 4838451Smsmith * 4938451Smsmith * Permission to use, copy, modify and distribute this software and its 5038451Smsmith * documentation is hereby granted, provided that both the copyright 5138451Smsmith * notice and this permission notice appear in all copies of the 5238451Smsmith * software, derivative works or modified versions, and any portions 5338451Smsmith * thereof, and that both notices appear in supporting documentation. 5438451Smsmith * 5538451Smsmith * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 5638451Smsmith * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 5738451Smsmith * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 5838451Smsmith * 5938451Smsmith * Carnegie Mellon requests users of this software to return to 6038451Smsmith * 6138451Smsmith * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 6238451Smsmith * School of Computer Science 6338451Smsmith * Carnegie Mellon University 6438451Smsmith * Pittsburgh PA 15213-3890 6538451Smsmith * 6638451Smsmith * any improvements or extensions that they make and grant Carnegie the 6738451Smsmith * rights to redistribute these changes. 6838451Smsmith */ 6938451Smsmith 7084221Sdillon#include <sys/cdefs.h> 7184221Sdillon__FBSDID("$FreeBSD: stable/11/stand/libsa/ufs.c 344376 2019-02-20 19:05:58Z kevans $"); 7284221Sdillon 7338451Smsmith/* 7438451Smsmith * Stand-alone file reading package. 7538451Smsmith */ 7638451Smsmith 7738451Smsmith#include <sys/param.h> 7896477Sphk#include <sys/disklabel.h> 7938451Smsmith#include <sys/time.h> 8038451Smsmith#include <ufs/ufs/dinode.h> 8138451Smsmith#include <ufs/ufs/dir.h> 8238451Smsmith#include <ufs/ffs/fs.h> 8338451Smsmith#include "stand.h" 8438451Smsmith#include "string.h" 8538451Smsmith 8639468Smsmithstatic int ufs_open(const char *path, struct open_file *f); 87332138Skevansstatic int ufs_write(struct open_file *f, const void *buf, size_t size, 88332138Skevans size_t *resid); 8938451Smsmithstatic int ufs_close(struct open_file *f); 9038451Smsmithstatic int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 9138451Smsmithstatic off_t ufs_seek(struct open_file *f, off_t offset, int where); 9238451Smsmithstatic int ufs_stat(struct open_file *f, struct stat *sb); 9359766Sjlemonstatic int ufs_readdir(struct open_file *f, struct dirent *d); 9438451Smsmith 9538451Smsmithstruct fs_ops ufs_fsops = { 9659766Sjlemon "ufs", 9759766Sjlemon ufs_open, 9859766Sjlemon ufs_close, 9959766Sjlemon ufs_read, 10087631Sjhb ufs_write, 10159766Sjlemon ufs_seek, 10259766Sjlemon ufs_stat, 10359766Sjlemon ufs_readdir 10438451Smsmith}; 10538451Smsmith 10638451Smsmith/* 10738451Smsmith * In-core open file. 10838451Smsmith */ 10938451Smsmithstruct file { 11038451Smsmith off_t f_seekp; /* seek pointer */ 11138451Smsmith struct fs *f_fs; /* pointer to super-block */ 11298542Smckusick union dinode { 11398542Smckusick struct ufs1_dinode di1; 11498542Smckusick struct ufs2_dinode di2; 11598542Smckusick } f_di; /* copy of on-disk inode */ 11638451Smsmith int f_nindir[NIADDR]; 11738451Smsmith /* number of blocks mapped by 11838451Smsmith indirect block at level i */ 11938451Smsmith char *f_blk[NIADDR]; /* buffer for indirect block at 12038451Smsmith level i */ 12138451Smsmith size_t f_blksize[NIADDR]; 12238451Smsmith /* size of buffer */ 12398542Smckusick ufs2_daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ 12498542Smckusick ufs2_daddr_t f_buf_blkno; /* block number of data block */ 12538451Smsmith char *f_buf; /* buffer for data block */ 12638451Smsmith size_t f_buf_size; /* size of data block */ 127344288Skevans int f_inumber; /* inumber */ 12838451Smsmith}; 12998542Smckusick#define DIP(fp, field) \ 13098542Smckusick ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ 13198542Smckusick (fp)->f_di.di1.field : (fp)->f_di.di2.field) 13238451Smsmith 13338451Smsmithstatic int read_inode(ino_t, struct open_file *); 13498542Smckusickstatic int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); 13538451Smsmithstatic int buf_read_file(struct open_file *, char **, size_t *); 136332138Skevansstatic int buf_write_file(struct open_file *, const char *, size_t *); 13738451Smsmithstatic int search_directory(char *, struct open_file *, ino_t *); 13838451Smsmith 13938451Smsmith/* 14038451Smsmith * Read a new inode into a file structure. 14138451Smsmith */ 14238451Smsmithstatic int 14338451Smsmithread_inode(inumber, f) 14438451Smsmith ino_t inumber; 14538451Smsmith struct open_file *f; 14638451Smsmith{ 14792913Sobrien struct file *fp = (struct file *)f->f_fsdata; 14892913Sobrien struct fs *fs = fp->f_fs; 14938451Smsmith char *buf; 15038451Smsmith size_t rsize; 15138451Smsmith int rc; 15238451Smsmith 15339665Smsmith if (fs == NULL) 15439665Smsmith panic("fs == NULL"); 15539665Smsmith 15638451Smsmith /* 15738451Smsmith * Read inode and save it. 15838451Smsmith */ 15939665Smsmith buf = malloc(fs->fs_bsize); 160276079Sian twiddle(1); 16138451Smsmith rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 162313355Stsoome fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, 16338451Smsmith buf, &rsize); 16438451Smsmith if (rc) 16538451Smsmith goto out; 16638451Smsmith if (rsize != fs->fs_bsize) { 16738451Smsmith rc = EIO; 16838451Smsmith goto out; 16938451Smsmith } 17038451Smsmith 17198542Smckusick if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 17298542Smckusick fp->f_di.di1 = ((struct ufs1_dinode *)buf) 17398542Smckusick [ino_to_fsbo(fs, inumber)]; 17498542Smckusick else 17598542Smckusick fp->f_di.di2 = ((struct ufs2_dinode *)buf) 17698542Smckusick [ino_to_fsbo(fs, inumber)]; 17738451Smsmith 17838451Smsmith /* 17938451Smsmith * Clear out the old buffers 18038451Smsmith */ 18138451Smsmith { 18292913Sobrien int level; 18338451Smsmith 18438451Smsmith for (level = 0; level < NIADDR; level++) 18538451Smsmith fp->f_blkno[level] = -1; 18638451Smsmith fp->f_buf_blkno = -1; 18738451Smsmith } 188134760Siedowse fp->f_seekp = 0; 189344288Skevans fp->f_inumber = inumber; 19038451Smsmithout: 19139665Smsmith free(buf); 19238451Smsmith return (rc); 19338451Smsmith} 19438451Smsmith 19538451Smsmith/* 19638451Smsmith * Given an offset in a file, find the disk block number that 19738451Smsmith * contains that block. 19838451Smsmith */ 19938451Smsmithstatic int 20038451Smsmithblock_map(f, file_block, disk_block_p) 20138451Smsmith struct open_file *f; 20298542Smckusick ufs2_daddr_t file_block; 20398542Smckusick ufs2_daddr_t *disk_block_p; /* out */ 20438451Smsmith{ 20592913Sobrien struct file *fp = (struct file *)f->f_fsdata; 20692913Sobrien struct fs *fs = fp->f_fs; 20738451Smsmith int level; 20838451Smsmith int idx; 20998542Smckusick ufs2_daddr_t ind_block_num; 21038451Smsmith int rc; 21138451Smsmith 21238451Smsmith /* 21338451Smsmith * Index structure of an inode: 21438451Smsmith * 21538451Smsmith * di_db[0..NDADDR-1] hold block numbers for blocks 21638451Smsmith * 0..NDADDR-1 21738451Smsmith * 21838451Smsmith * di_ib[0] index block 0 is the single indirect block 21938451Smsmith * holds block numbers for blocks 22038451Smsmith * NDADDR .. NDADDR + NINDIR(fs)-1 22138451Smsmith * 22238451Smsmith * di_ib[1] index block 1 is the double indirect block 22338451Smsmith * holds block numbers for INDEX blocks for blocks 22438451Smsmith * NDADDR + NINDIR(fs) .. 22538451Smsmith * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 22638451Smsmith * 22738451Smsmith * di_ib[2] index block 2 is the triple indirect block 22838451Smsmith * holds block numbers for double-indirect 22938451Smsmith * blocks for blocks 23038451Smsmith * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 23138451Smsmith * NDADDR + NINDIR(fs) + NINDIR(fs)**2 23238451Smsmith * + NINDIR(fs)**3 - 1 23338451Smsmith */ 23438451Smsmith 23538451Smsmith if (file_block < NDADDR) { 23638451Smsmith /* Direct block. */ 23798542Smckusick *disk_block_p = DIP(fp, di_db[file_block]); 23838451Smsmith return (0); 23938451Smsmith } 24038451Smsmith 24138451Smsmith file_block -= NDADDR; 24238451Smsmith 24338451Smsmith /* 24438451Smsmith * nindir[0] = NINDIR 24538451Smsmith * nindir[1] = NINDIR**2 24638451Smsmith * nindir[2] = NINDIR**3 24738451Smsmith * etc 24838451Smsmith */ 24938451Smsmith for (level = 0; level < NIADDR; level++) { 25038451Smsmith if (file_block < fp->f_nindir[level]) 25138451Smsmith break; 25238451Smsmith file_block -= fp->f_nindir[level]; 25338451Smsmith } 25438451Smsmith if (level == NIADDR) { 25538451Smsmith /* Block number too high */ 25638451Smsmith return (EFBIG); 25738451Smsmith } 25838451Smsmith 25998542Smckusick ind_block_num = DIP(fp, di_ib[level]); 26038451Smsmith 26138451Smsmith for (; level >= 0; level--) { 26238451Smsmith if (ind_block_num == 0) { 26338451Smsmith *disk_block_p = 0; /* missing */ 26438451Smsmith return (0); 26538451Smsmith } 26638451Smsmith 26738451Smsmith if (fp->f_blkno[level] != ind_block_num) { 26838451Smsmith if (fp->f_blk[level] == (char *)0) 26938451Smsmith fp->f_blk[level] = 27039665Smsmith malloc(fs->fs_bsize); 271276079Sian twiddle(1); 27238451Smsmith rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 273313355Stsoome fsbtodb(fp->f_fs, ind_block_num), 27438451Smsmith fs->fs_bsize, 27538451Smsmith fp->f_blk[level], 27638451Smsmith &fp->f_blksize[level]); 27738451Smsmith if (rc) 27838451Smsmith return (rc); 27938451Smsmith if (fp->f_blksize[level] != fs->fs_bsize) 28038451Smsmith return (EIO); 28138451Smsmith fp->f_blkno[level] = ind_block_num; 28238451Smsmith } 28338451Smsmith 28438451Smsmith if (level > 0) { 28538451Smsmith idx = file_block / fp->f_nindir[level - 1]; 28638451Smsmith file_block %= fp->f_nindir[level - 1]; 28738451Smsmith } else 28838451Smsmith idx = file_block; 28938451Smsmith 29098542Smckusick if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 29198542Smckusick ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx]; 29298542Smckusick else 29398542Smckusick ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx]; 29438451Smsmith } 29538451Smsmith 29638451Smsmith *disk_block_p = ind_block_num; 29738451Smsmith 29838451Smsmith return (0); 29938451Smsmith} 30038451Smsmith 30138451Smsmith/* 30287631Sjhb * Write a portion of a file from an internal buffer. 30387631Sjhb */ 30487631Sjhbstatic int 30587631Sjhbbuf_write_file(f, buf_p, size_p) 30687631Sjhb struct open_file *f; 307332138Skevans const char *buf_p; 30887631Sjhb size_t *size_p; /* out */ 30987631Sjhb{ 31092913Sobrien struct file *fp = (struct file *)f->f_fsdata; 31192913Sobrien struct fs *fs = fp->f_fs; 31287631Sjhb long off; 31398542Smckusick ufs_lbn_t file_block; 31498542Smckusick ufs2_daddr_t disk_block; 31587631Sjhb size_t block_size; 31687631Sjhb int rc; 31787631Sjhb 31887631Sjhb /* 31987631Sjhb * Calculate the starting block address and offset. 32087631Sjhb */ 32187631Sjhb off = blkoff(fs, fp->f_seekp); 32287631Sjhb file_block = lblkno(fs, fp->f_seekp); 32398542Smckusick block_size = sblksize(fs, DIP(fp, di_size), file_block); 32487631Sjhb 32587631Sjhb rc = block_map(f, file_block, &disk_block); 32687631Sjhb if (rc) 32787631Sjhb return (rc); 32887631Sjhb 32987631Sjhb if (disk_block == 0) 33098542Smckusick /* Because we can't allocate space on the drive */ 33198542Smckusick return (EFBIG); 33287631Sjhb 33387631Sjhb /* 33487631Sjhb * Truncate buffer at end of file, and at the end of 33587631Sjhb * this block. 33687631Sjhb */ 33798542Smckusick if (*size_p > DIP(fp, di_size) - fp->f_seekp) 33898542Smckusick *size_p = DIP(fp, di_size) - fp->f_seekp; 33987631Sjhb if (*size_p > block_size - off) 34087631Sjhb *size_p = block_size - off; 34187631Sjhb 34287631Sjhb /* 34387631Sjhb * If we don't entirely occlude the block and it's not 34487631Sjhb * in memory already, read it in first. 34587631Sjhb */ 34687631Sjhb if (((off > 0) || (*size_p + off < block_size)) && 34787631Sjhb (file_block != fp->f_buf_blkno)) { 34887631Sjhb 34987631Sjhb if (fp->f_buf == (char *)0) 35087631Sjhb fp->f_buf = malloc(fs->fs_bsize); 35187631Sjhb 352276079Sian twiddle(4); 35387631Sjhb rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 354313355Stsoome fsbtodb(fs, disk_block), 35587631Sjhb block_size, fp->f_buf, &fp->f_buf_size); 35687631Sjhb if (rc) 35787631Sjhb return (rc); 35887631Sjhb 35987631Sjhb fp->f_buf_blkno = file_block; 36087631Sjhb } 36187631Sjhb 36287631Sjhb /* 36387631Sjhb * Copy the user data into the cached block. 36487631Sjhb */ 36598542Smckusick bcopy(buf_p, fp->f_buf + off, *size_p); 36687631Sjhb 36787631Sjhb /* 36887631Sjhb * Write the block out to storage. 36987631Sjhb */ 37087631Sjhb 371276079Sian twiddle(4); 37287631Sjhb rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, 373313355Stsoome fsbtodb(fs, disk_block), 37487631Sjhb block_size, fp->f_buf, &fp->f_buf_size); 37587631Sjhb return (rc); 37687631Sjhb} 37787631Sjhb 37887631Sjhb/* 37938451Smsmith * Read a portion of a file into an internal buffer. Return 38038451Smsmith * the location in the buffer and the amount in the buffer. 38138451Smsmith */ 38238451Smsmithstatic int 38338451Smsmithbuf_read_file(f, buf_p, size_p) 38438451Smsmith struct open_file *f; 38538451Smsmith char **buf_p; /* out */ 38638451Smsmith size_t *size_p; /* out */ 38738451Smsmith{ 38892913Sobrien struct file *fp = (struct file *)f->f_fsdata; 38992913Sobrien struct fs *fs = fp->f_fs; 39038451Smsmith long off; 39198542Smckusick ufs_lbn_t file_block; 39298542Smckusick ufs2_daddr_t disk_block; 39338451Smsmith size_t block_size; 39438451Smsmith int rc; 39538451Smsmith 39638451Smsmith off = blkoff(fs, fp->f_seekp); 39738451Smsmith file_block = lblkno(fs, fp->f_seekp); 39898542Smckusick block_size = sblksize(fs, DIP(fp, di_size), file_block); 39938451Smsmith 40038451Smsmith if (file_block != fp->f_buf_blkno) { 40187631Sjhb if (fp->f_buf == (char *)0) 40287631Sjhb fp->f_buf = malloc(fs->fs_bsize); 40387631Sjhb 40438451Smsmith rc = block_map(f, file_block, &disk_block); 40538451Smsmith if (rc) 40638451Smsmith return (rc); 40738451Smsmith 40838451Smsmith if (disk_block == 0) { 40938451Smsmith bzero(fp->f_buf, block_size); 41038451Smsmith fp->f_buf_size = block_size; 41138451Smsmith } else { 412276079Sian twiddle(4); 41338451Smsmith rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 414313355Stsoome fsbtodb(fs, disk_block), 41538451Smsmith block_size, fp->f_buf, &fp->f_buf_size); 41638451Smsmith if (rc) 41738451Smsmith return (rc); 41838451Smsmith } 41938451Smsmith 42038451Smsmith fp->f_buf_blkno = file_block; 42138451Smsmith } 42238451Smsmith 42338451Smsmith /* 42438451Smsmith * Return address of byte in buffer corresponding to 42538451Smsmith * offset, and size of remainder of buffer after that 42638451Smsmith * byte. 42738451Smsmith */ 42838451Smsmith *buf_p = fp->f_buf + off; 42938451Smsmith *size_p = block_size - off; 43038451Smsmith 43138451Smsmith /* 43238451Smsmith * But truncate buffer at end of file. 43338451Smsmith */ 43498542Smckusick if (*size_p > DIP(fp, di_size) - fp->f_seekp) 43598542Smckusick *size_p = DIP(fp, di_size) - fp->f_seekp; 43638451Smsmith 43738451Smsmith return (0); 43838451Smsmith} 43938451Smsmith 44038451Smsmith/* 44138451Smsmith * Search a directory for a name and return its 44238451Smsmith * i_number. 44338451Smsmith */ 44438451Smsmithstatic int 44538451Smsmithsearch_directory(name, f, inumber_p) 44638451Smsmith char *name; 44738451Smsmith struct open_file *f; 44838451Smsmith ino_t *inumber_p; /* out */ 44938451Smsmith{ 45092913Sobrien struct file *fp = (struct file *)f->f_fsdata; 45192913Sobrien struct direct *dp; 45238451Smsmith struct direct *edp; 45338451Smsmith char *buf; 45438451Smsmith size_t buf_size; 45538451Smsmith int namlen, length; 45638451Smsmith int rc; 45738451Smsmith 45838451Smsmith length = strlen(name); 45938451Smsmith 46038451Smsmith fp->f_seekp = 0; 46198542Smckusick while (fp->f_seekp < DIP(fp, di_size)) { 46238451Smsmith rc = buf_read_file(f, &buf, &buf_size); 46338451Smsmith if (rc) 46438451Smsmith return (rc); 46538451Smsmith 46638451Smsmith dp = (struct direct *)buf; 46738451Smsmith edp = (struct direct *)(buf + buf_size); 46838451Smsmith while (dp < edp) { 46938451Smsmith if (dp->d_ino == (ino_t)0) 47038451Smsmith goto next; 47138451Smsmith#if BYTE_ORDER == LITTLE_ENDIAN 47238451Smsmith if (fp->f_fs->fs_maxsymlinklen <= 0) 47338451Smsmith namlen = dp->d_type; 47438451Smsmith else 47538451Smsmith#endif 47638451Smsmith namlen = dp->d_namlen; 47738451Smsmith if (namlen == length && 47838451Smsmith !strcmp(name, dp->d_name)) { 47938451Smsmith /* found entry */ 48038451Smsmith *inumber_p = dp->d_ino; 48138451Smsmith return (0); 48238451Smsmith } 48338451Smsmith next: 48438451Smsmith dp = (struct direct *)((char *)dp + dp->d_reclen); 48538451Smsmith } 48638451Smsmith fp->f_seekp += buf_size; 48738451Smsmith } 48838451Smsmith return (ENOENT); 48938451Smsmith} 49038451Smsmith 49198542Smckusickstatic int sblock_try[] = SBLOCKSEARCH; 49298542Smckusick 49338451Smsmith/* 49438451Smsmith * Open a file. 49538451Smsmith */ 49638451Smsmithstatic int 49739468Smsmithufs_open(upath, f) 49839468Smsmith const char *upath; 49938451Smsmith struct open_file *f; 50038451Smsmith{ 50192913Sobrien char *cp, *ncp; 50292913Sobrien int c; 50338451Smsmith ino_t inumber, parent_inumber; 50438451Smsmith struct file *fp; 50538451Smsmith struct fs *fs; 50698542Smckusick int i, rc; 50738451Smsmith size_t buf_size; 50838451Smsmith int nlinks = 0; 50938451Smsmith char namebuf[MAXPATHLEN+1]; 51038451Smsmith char *buf = NULL; 51139468Smsmith char *path = NULL; 51238451Smsmith 51338451Smsmith /* allocate file system specific data structure */ 51438451Smsmith fp = malloc(sizeof(struct file)); 51538451Smsmith bzero(fp, sizeof(struct file)); 51638451Smsmith f->f_fsdata = (void *)fp; 51738451Smsmith 51838451Smsmith /* allocate space and read super block */ 51998542Smckusick fs = malloc(SBLOCKSIZE); 52038451Smsmith fp->f_fs = fs; 521276079Sian twiddle(1); 52298542Smckusick /* 52398542Smckusick * Try reading the superblock in each of its possible locations. 52498542Smckusick */ 52598542Smckusick for (i = 0; sblock_try[i] != -1; i++) { 52698542Smckusick rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 527313355Stsoome sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, 52898542Smckusick (char *)fs, &buf_size); 52998542Smckusick if (rc) 53098542Smckusick goto out; 53198542Smckusick if ((fs->fs_magic == FS_UFS1_MAGIC || 53298542Smckusick (fs->fs_magic == FS_UFS2_MAGIC && 533107555Sjake fs->fs_sblockloc == sblock_try[i])) && 53498542Smckusick buf_size == SBLOCKSIZE && 53598542Smckusick fs->fs_bsize <= MAXBSIZE && 53698542Smckusick fs->fs_bsize >= sizeof(struct fs)) 53798542Smckusick break; 53898542Smckusick } 53998542Smckusick if (sblock_try[i] == -1) { 54038451Smsmith rc = EINVAL; 54138451Smsmith goto out; 54238451Smsmith } 54338451Smsmith /* 54438451Smsmith * Calculate indirect block levels. 54538451Smsmith */ 54638451Smsmith { 54798542Smckusick ufs2_daddr_t mult; 54892913Sobrien int level; 54938451Smsmith 55038451Smsmith mult = 1; 55138451Smsmith for (level = 0; level < NIADDR; level++) { 55238451Smsmith mult *= NINDIR(fs); 55338451Smsmith fp->f_nindir[level] = mult; 55438451Smsmith } 55538451Smsmith } 55638451Smsmith 55738451Smsmith inumber = ROOTINO; 55838451Smsmith if ((rc = read_inode(inumber, f)) != 0) 55938451Smsmith goto out; 56038451Smsmith 56139468Smsmith cp = path = strdup(upath); 56239468Smsmith if (path == NULL) { 56339468Smsmith rc = ENOMEM; 56439468Smsmith goto out; 56539468Smsmith } 56638451Smsmith while (*cp) { 56738451Smsmith 56838451Smsmith /* 56938451Smsmith * Remove extra separators 57038451Smsmith */ 57138451Smsmith while (*cp == '/') 57238451Smsmith cp++; 57338451Smsmith if (*cp == '\0') 57438451Smsmith break; 57538451Smsmith 57638451Smsmith /* 57738451Smsmith * Check that current node is a directory. 57838451Smsmith */ 57998542Smckusick if ((DIP(fp, di_mode) & IFMT) != IFDIR) { 58038451Smsmith rc = ENOTDIR; 58138451Smsmith goto out; 58238451Smsmith } 58338451Smsmith 58438451Smsmith /* 58538451Smsmith * Get next component of path name. 58638451Smsmith */ 58738451Smsmith { 58892913Sobrien int len = 0; 58938451Smsmith 59038451Smsmith ncp = cp; 59138451Smsmith while ((c = *cp) != '\0' && c != '/') { 59238451Smsmith if (++len > MAXNAMLEN) { 59338451Smsmith rc = ENOENT; 59438451Smsmith goto out; 59538451Smsmith } 59638451Smsmith cp++; 59738451Smsmith } 59838451Smsmith *cp = '\0'; 59938451Smsmith } 60038451Smsmith 60138451Smsmith /* 60238451Smsmith * Look up component in current directory. 60338451Smsmith * Save directory inumber in case we find a 60438451Smsmith * symbolic link. 60538451Smsmith */ 60638451Smsmith parent_inumber = inumber; 60738451Smsmith rc = search_directory(ncp, f, &inumber); 60838451Smsmith *cp = c; 60938451Smsmith if (rc) 61038451Smsmith goto out; 61138451Smsmith 61238451Smsmith /* 61338451Smsmith * Open next component. 61438451Smsmith */ 61538451Smsmith if ((rc = read_inode(inumber, f)) != 0) 61638451Smsmith goto out; 61738451Smsmith 61838451Smsmith /* 61938451Smsmith * Check for symbolic link. 62038451Smsmith */ 62198542Smckusick if ((DIP(fp, di_mode) & IFMT) == IFLNK) { 62298542Smckusick int link_len = DIP(fp, di_size); 62338451Smsmith int len; 62438451Smsmith 62538451Smsmith len = strlen(cp); 62638451Smsmith 62738451Smsmith if (link_len + len > MAXPATHLEN || 62838451Smsmith ++nlinks > MAXSYMLINKS) { 62938451Smsmith rc = ENOENT; 63038451Smsmith goto out; 63138451Smsmith } 63238451Smsmith 63338451Smsmith bcopy(cp, &namebuf[link_len], len + 1); 63438451Smsmith 63538451Smsmith if (link_len < fs->fs_maxsymlinklen) { 63698542Smckusick if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 63798542Smckusick cp = (caddr_t)(fp->f_di.di1.di_db); 63898542Smckusick else 63998542Smckusick cp = (caddr_t)(fp->f_di.di2.di_db); 64098542Smckusick bcopy(cp, namebuf, (unsigned) link_len); 64138451Smsmith } else { 64238451Smsmith /* 64338451Smsmith * Read file for symbolic link 64438451Smsmith */ 64538451Smsmith size_t buf_size; 64698542Smckusick ufs2_daddr_t disk_block; 64792913Sobrien struct fs *fs = fp->f_fs; 64838451Smsmith 64938451Smsmith if (!buf) 65039665Smsmith buf = malloc(fs->fs_bsize); 65198542Smckusick rc = block_map(f, (ufs2_daddr_t)0, &disk_block); 65238451Smsmith if (rc) 65338451Smsmith goto out; 65438451Smsmith 655276079Sian twiddle(1); 65638451Smsmith rc = (f->f_dev->dv_strategy)(f->f_devdata, 657313355Stsoome F_READ, fsbtodb(fs, disk_block), 65838451Smsmith fs->fs_bsize, buf, &buf_size); 65938451Smsmith if (rc) 66038451Smsmith goto out; 66138451Smsmith 66238451Smsmith bcopy((char *)buf, namebuf, (unsigned)link_len); 66338451Smsmith } 66438451Smsmith 66538451Smsmith /* 66638451Smsmith * If relative pathname, restart at parent directory. 66738451Smsmith * If absolute pathname, restart at root. 66838451Smsmith */ 66938451Smsmith cp = namebuf; 67038451Smsmith if (*cp != '/') 67138451Smsmith inumber = parent_inumber; 67238451Smsmith else 67338451Smsmith inumber = (ino_t)ROOTINO; 67438451Smsmith 67538451Smsmith if ((rc = read_inode(inumber, f)) != 0) 67638451Smsmith goto out; 67738451Smsmith } 67838451Smsmith } 67938451Smsmith 68038451Smsmith /* 68138451Smsmith * Found terminal component. 68238451Smsmith */ 68338451Smsmith rc = 0; 684134760Siedowse fp->f_seekp = 0; 68538451Smsmithout: 68638451Smsmith if (buf) 68739665Smsmith free(buf); 68839468Smsmith if (path) 68939468Smsmith free(path); 69038451Smsmith if (rc) { 69138451Smsmith if (fp->f_buf) 69239665Smsmith free(fp->f_buf); 69338451Smsmith free(fp->f_fs); 69438451Smsmith free(fp); 69538451Smsmith } 69638451Smsmith return (rc); 69738451Smsmith} 69838451Smsmith 69938451Smsmithstatic int 70038451Smsmithufs_close(f) 70138451Smsmith struct open_file *f; 70238451Smsmith{ 70392913Sobrien struct file *fp = (struct file *)f->f_fsdata; 70438451Smsmith int level; 70538451Smsmith 70638451Smsmith f->f_fsdata = (void *)0; 70738451Smsmith if (fp == (struct file *)0) 70838451Smsmith return (0); 70938451Smsmith 71038451Smsmith for (level = 0; level < NIADDR; level++) { 71138451Smsmith if (fp->f_blk[level]) 71239665Smsmith free(fp->f_blk[level]); 71338451Smsmith } 71438451Smsmith if (fp->f_buf) 71539665Smsmith free(fp->f_buf); 71639665Smsmith free(fp->f_fs); 71738451Smsmith free(fp); 71838451Smsmith return (0); 71938451Smsmith} 72038451Smsmith 72138451Smsmith/* 72238451Smsmith * Copy a portion of a file into kernel memory. 72338451Smsmith * Cross block boundaries when necessary. 72438451Smsmith */ 72538451Smsmithstatic int 72638451Smsmithufs_read(f, start, size, resid) 72738451Smsmith struct open_file *f; 72838451Smsmith void *start; 72938451Smsmith size_t size; 73038451Smsmith size_t *resid; /* out */ 73138451Smsmith{ 73292913Sobrien struct file *fp = (struct file *)f->f_fsdata; 73392913Sobrien size_t csize; 73438451Smsmith char *buf; 73538451Smsmith size_t buf_size; 73638451Smsmith int rc = 0; 73792913Sobrien char *addr = start; 73838451Smsmith 73938451Smsmith while (size != 0) { 74098542Smckusick if (fp->f_seekp >= DIP(fp, di_size)) 74138451Smsmith break; 74238451Smsmith 74338451Smsmith rc = buf_read_file(f, &buf, &buf_size); 74438451Smsmith if (rc) 74538451Smsmith break; 74638451Smsmith 74738451Smsmith csize = size; 74838451Smsmith if (csize > buf_size) 74938451Smsmith csize = buf_size; 75038451Smsmith 75138451Smsmith bcopy(buf, addr, csize); 75238451Smsmith 75338451Smsmith fp->f_seekp += csize; 75438451Smsmith addr += csize; 75538451Smsmith size -= csize; 75638451Smsmith } 75738451Smsmith if (resid) 75838451Smsmith *resid = size; 75938451Smsmith return (rc); 76038451Smsmith} 76138451Smsmith 76287631Sjhb/* 76387631Sjhb * Write to a portion of an already allocated file. 76487631Sjhb * Cross block boundaries when necessary. Can not 76587631Sjhb * extend the file. 76687631Sjhb */ 76787631Sjhbstatic int 76887631Sjhbufs_write(f, start, size, resid) 76987631Sjhb struct open_file *f; 770332138Skevans const void *start; 77187631Sjhb size_t size; 77287631Sjhb size_t *resid; /* out */ 77387631Sjhb{ 77492913Sobrien struct file *fp = (struct file *)f->f_fsdata; 77587631Sjhb size_t csize; 77687631Sjhb int rc = 0; 777332138Skevans const char *addr = start; 77887631Sjhb 77987631Sjhb csize = size; 78087631Sjhb while ((size != 0) && (csize != 0)) { 78198542Smckusick if (fp->f_seekp >= DIP(fp, di_size)) 78287631Sjhb break; 78387631Sjhb 78487631Sjhb if (csize >= 512) csize = 512; /* XXX */ 78587631Sjhb 78687631Sjhb rc = buf_write_file(f, addr, &csize); 78787631Sjhb if (rc) 78887631Sjhb break; 78987631Sjhb 79087631Sjhb fp->f_seekp += csize; 79187631Sjhb addr += csize; 79287631Sjhb size -= csize; 79387631Sjhb } 79487631Sjhb if (resid) 79587631Sjhb *resid = size; 79687631Sjhb return (rc); 79787631Sjhb} 79887631Sjhb 79938451Smsmithstatic off_t 80038451Smsmithufs_seek(f, offset, where) 80138451Smsmith struct open_file *f; 80238451Smsmith off_t offset; 80338451Smsmith int where; 80438451Smsmith{ 80592913Sobrien struct file *fp = (struct file *)f->f_fsdata; 80638451Smsmith 80738451Smsmith switch (where) { 80838451Smsmith case SEEK_SET: 80938451Smsmith fp->f_seekp = offset; 81038451Smsmith break; 81138451Smsmith case SEEK_CUR: 81238451Smsmith fp->f_seekp += offset; 81338451Smsmith break; 81438451Smsmith case SEEK_END: 81598542Smckusick fp->f_seekp = DIP(fp, di_size) - offset; 81638451Smsmith break; 81738451Smsmith default: 818124811Sjhb errno = EINVAL; 81938451Smsmith return (-1); 82038451Smsmith } 82138451Smsmith return (fp->f_seekp); 82238451Smsmith} 82338451Smsmith 82438451Smsmithstatic int 82538451Smsmithufs_stat(f, sb) 82638451Smsmith struct open_file *f; 82738451Smsmith struct stat *sb; 82838451Smsmith{ 82992913Sobrien struct file *fp = (struct file *)f->f_fsdata; 83038451Smsmith 83138451Smsmith /* only important stuff */ 83298542Smckusick sb->st_mode = DIP(fp, di_mode); 83398542Smckusick sb->st_uid = DIP(fp, di_uid); 83498542Smckusick sb->st_gid = DIP(fp, di_gid); 83598542Smckusick sb->st_size = DIP(fp, di_size); 836344288Skevans sb->st_mtime = DIP(fp, di_mtime); 837344288Skevans /* 838344288Skevans * The items below are ufs specific! 839344288Skevans * Other fs types will need their own solution 840344288Skevans * if these fields are needed. 841344288Skevans */ 842344288Skevans sb->st_ino = fp->f_inumber; 843344288Skevans /* 844344288Skevans * We need something to differentiate devs. 845344288Skevans * fs_id is unique but 64bit, we xor the two 846344288Skevans * halves to squeeze it into 32bits. 847344288Skevans */ 848344288Skevans sb->st_dev = (dev_t)(fp->f_fs->fs_id[0] ^ fp->f_fs->fs_id[1]); 849344288Skevans 85038451Smsmith return (0); 85138451Smsmith} 85238451Smsmith 85359766Sjlemonstatic int 85459766Sjlemonufs_readdir(struct open_file *f, struct dirent *d) 85559766Sjlemon{ 85659766Sjlemon struct file *fp = (struct file *)f->f_fsdata; 85759766Sjlemon struct direct *dp; 85859766Sjlemon char *buf; 85959766Sjlemon size_t buf_size; 86059766Sjlemon int error; 86159766Sjlemon 86259766Sjlemon /* 86359766Sjlemon * assume that a directory entry will not be split across blocks 86459766Sjlemon */ 86559766Sjlemonagain: 86698542Smckusick if (fp->f_seekp >= DIP(fp, di_size)) 86759766Sjlemon return (ENOENT); 86859766Sjlemon error = buf_read_file(f, &buf, &buf_size); 86959766Sjlemon if (error) 87059766Sjlemon return (error); 87159766Sjlemon dp = (struct direct *)buf; 87259766Sjlemon fp->f_seekp += dp->d_reclen; 87359766Sjlemon if (dp->d_ino == (ino_t)0) 87459766Sjlemon goto again; 87559766Sjlemon d->d_type = dp->d_type; 87659766Sjlemon strcpy(d->d_name, dp->d_name); 87759766Sjlemon return (0); 87859766Sjlemon} 879