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. 2738451Smsmith * 4. 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$"); 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); 8787631Sjhbstatic int ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 8838451Smsmithstatic int ufs_close(struct open_file *f); 8938451Smsmithstatic int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 9038451Smsmithstatic off_t ufs_seek(struct open_file *f, off_t offset, int where); 9138451Smsmithstatic int ufs_stat(struct open_file *f, struct stat *sb); 9259766Sjlemonstatic int ufs_readdir(struct open_file *f, struct dirent *d); 9338451Smsmith 9438451Smsmithstruct fs_ops ufs_fsops = { 9559766Sjlemon "ufs", 9659766Sjlemon ufs_open, 9759766Sjlemon ufs_close, 9859766Sjlemon ufs_read, 9987631Sjhb ufs_write, 10059766Sjlemon ufs_seek, 10159766Sjlemon ufs_stat, 10259766Sjlemon ufs_readdir 10338451Smsmith}; 10438451Smsmith 10538451Smsmith/* 10638451Smsmith * In-core open file. 10738451Smsmith */ 10838451Smsmithstruct file { 10938451Smsmith off_t f_seekp; /* seek pointer */ 11038451Smsmith struct fs *f_fs; /* pointer to super-block */ 11198542Smckusick union dinode { 11298542Smckusick struct ufs1_dinode di1; 11398542Smckusick struct ufs2_dinode di2; 11498542Smckusick } f_di; /* copy of on-disk inode */ 11538451Smsmith int f_nindir[NIADDR]; 11638451Smsmith /* number of blocks mapped by 11738451Smsmith indirect block at level i */ 11838451Smsmith char *f_blk[NIADDR]; /* buffer for indirect block at 11938451Smsmith level i */ 12038451Smsmith size_t f_blksize[NIADDR]; 12138451Smsmith /* size of buffer */ 12298542Smckusick ufs2_daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ 12398542Smckusick ufs2_daddr_t f_buf_blkno; /* block number of data block */ 12438451Smsmith char *f_buf; /* buffer for data block */ 12538451Smsmith size_t f_buf_size; /* size of data block */ 12638451Smsmith}; 12798542Smckusick#define DIP(fp, field) \ 12898542Smckusick ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ 12998542Smckusick (fp)->f_di.di1.field : (fp)->f_di.di2.field) 13038451Smsmith 13138451Smsmithstatic int read_inode(ino_t, struct open_file *); 13298542Smckusickstatic int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); 13338451Smsmithstatic int buf_read_file(struct open_file *, char **, size_t *); 13487631Sjhbstatic int buf_write_file(struct open_file *, char *, size_t *); 13538451Smsmithstatic int search_directory(char *, struct open_file *, ino_t *); 13638451Smsmith 13738451Smsmith/* 13838451Smsmith * Read a new inode into a file structure. 13938451Smsmith */ 14038451Smsmithstatic int 14138451Smsmithread_inode(inumber, f) 14238451Smsmith ino_t inumber; 14338451Smsmith struct open_file *f; 14438451Smsmith{ 14592913Sobrien struct file *fp = (struct file *)f->f_fsdata; 14692913Sobrien struct fs *fs = fp->f_fs; 14738451Smsmith char *buf; 14838451Smsmith size_t rsize; 14938451Smsmith int rc; 15038451Smsmith 15139665Smsmith if (fs == NULL) 15239665Smsmith panic("fs == NULL"); 15339665Smsmith 15438451Smsmith /* 15538451Smsmith * Read inode and save it. 15638451Smsmith */ 15739665Smsmith buf = malloc(fs->fs_bsize); 15838451Smsmith twiddle(); 15938451Smsmith rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 16038451Smsmith fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, 16138451Smsmith buf, &rsize); 16238451Smsmith if (rc) 16338451Smsmith goto out; 16438451Smsmith if (rsize != fs->fs_bsize) { 16538451Smsmith rc = EIO; 16638451Smsmith goto out; 16738451Smsmith } 16838451Smsmith 16998542Smckusick if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 17098542Smckusick fp->f_di.di1 = ((struct ufs1_dinode *)buf) 17198542Smckusick [ino_to_fsbo(fs, inumber)]; 17298542Smckusick else 17398542Smckusick fp->f_di.di2 = ((struct ufs2_dinode *)buf) 17498542Smckusick [ino_to_fsbo(fs, inumber)]; 17538451Smsmith 17638451Smsmith /* 17738451Smsmith * Clear out the old buffers 17838451Smsmith */ 17938451Smsmith { 18092913Sobrien int level; 18138451Smsmith 18238451Smsmith for (level = 0; level < NIADDR; level++) 18338451Smsmith fp->f_blkno[level] = -1; 18438451Smsmith fp->f_buf_blkno = -1; 18538451Smsmith } 186134760Siedowse fp->f_seekp = 0; 18738451Smsmithout: 18839665Smsmith free(buf); 18938451Smsmith return (rc); 19038451Smsmith} 19138451Smsmith 19238451Smsmith/* 19338451Smsmith * Given an offset in a file, find the disk block number that 19438451Smsmith * contains that block. 19538451Smsmith */ 19638451Smsmithstatic int 19738451Smsmithblock_map(f, file_block, disk_block_p) 19838451Smsmith struct open_file *f; 19998542Smckusick ufs2_daddr_t file_block; 20098542Smckusick ufs2_daddr_t *disk_block_p; /* out */ 20138451Smsmith{ 20292913Sobrien struct file *fp = (struct file *)f->f_fsdata; 20392913Sobrien struct fs *fs = fp->f_fs; 20438451Smsmith int level; 20538451Smsmith int idx; 20698542Smckusick ufs2_daddr_t ind_block_num; 20738451Smsmith int rc; 20838451Smsmith 20938451Smsmith /* 21038451Smsmith * Index structure of an inode: 21138451Smsmith * 21238451Smsmith * di_db[0..NDADDR-1] hold block numbers for blocks 21338451Smsmith * 0..NDADDR-1 21438451Smsmith * 21538451Smsmith * di_ib[0] index block 0 is the single indirect block 21638451Smsmith * holds block numbers for blocks 21738451Smsmith * NDADDR .. NDADDR + NINDIR(fs)-1 21838451Smsmith * 21938451Smsmith * di_ib[1] index block 1 is the double indirect block 22038451Smsmith * holds block numbers for INDEX blocks for blocks 22138451Smsmith * NDADDR + NINDIR(fs) .. 22238451Smsmith * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 22338451Smsmith * 22438451Smsmith * di_ib[2] index block 2 is the triple indirect block 22538451Smsmith * holds block numbers for double-indirect 22638451Smsmith * blocks for blocks 22738451Smsmith * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 22838451Smsmith * NDADDR + NINDIR(fs) + NINDIR(fs)**2 22938451Smsmith * + NINDIR(fs)**3 - 1 23038451Smsmith */ 23138451Smsmith 23238451Smsmith if (file_block < NDADDR) { 23338451Smsmith /* Direct block. */ 23498542Smckusick *disk_block_p = DIP(fp, di_db[file_block]); 23538451Smsmith return (0); 23638451Smsmith } 23738451Smsmith 23838451Smsmith file_block -= NDADDR; 23938451Smsmith 24038451Smsmith /* 24138451Smsmith * nindir[0] = NINDIR 24238451Smsmith * nindir[1] = NINDIR**2 24338451Smsmith * nindir[2] = NINDIR**3 24438451Smsmith * etc 24538451Smsmith */ 24638451Smsmith for (level = 0; level < NIADDR; level++) { 24738451Smsmith if (file_block < fp->f_nindir[level]) 24838451Smsmith break; 24938451Smsmith file_block -= fp->f_nindir[level]; 25038451Smsmith } 25138451Smsmith if (level == NIADDR) { 25238451Smsmith /* Block number too high */ 25338451Smsmith return (EFBIG); 25438451Smsmith } 25538451Smsmith 25698542Smckusick ind_block_num = DIP(fp, di_ib[level]); 25738451Smsmith 25838451Smsmith for (; level >= 0; level--) { 25938451Smsmith if (ind_block_num == 0) { 26038451Smsmith *disk_block_p = 0; /* missing */ 26138451Smsmith return (0); 26238451Smsmith } 26338451Smsmith 26438451Smsmith if (fp->f_blkno[level] != ind_block_num) { 26538451Smsmith if (fp->f_blk[level] == (char *)0) 26638451Smsmith fp->f_blk[level] = 26739665Smsmith malloc(fs->fs_bsize); 26838451Smsmith twiddle(); 26938451Smsmith rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 27038451Smsmith fsbtodb(fp->f_fs, ind_block_num), 27138451Smsmith fs->fs_bsize, 27238451Smsmith fp->f_blk[level], 27338451Smsmith &fp->f_blksize[level]); 27438451Smsmith if (rc) 27538451Smsmith return (rc); 27638451Smsmith if (fp->f_blksize[level] != fs->fs_bsize) 27738451Smsmith return (EIO); 27838451Smsmith fp->f_blkno[level] = ind_block_num; 27938451Smsmith } 28038451Smsmith 28138451Smsmith if (level > 0) { 28238451Smsmith idx = file_block / fp->f_nindir[level - 1]; 28338451Smsmith file_block %= fp->f_nindir[level - 1]; 28438451Smsmith } else 28538451Smsmith idx = file_block; 28638451Smsmith 28798542Smckusick if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 28898542Smckusick ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx]; 28998542Smckusick else 29098542Smckusick ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx]; 29138451Smsmith } 29238451Smsmith 29338451Smsmith *disk_block_p = ind_block_num; 29438451Smsmith 29538451Smsmith return (0); 29638451Smsmith} 29738451Smsmith 29838451Smsmith/* 29987631Sjhb * Write a portion of a file from an internal buffer. 30087631Sjhb */ 30187631Sjhbstatic int 30287631Sjhbbuf_write_file(f, buf_p, size_p) 30387631Sjhb struct open_file *f; 30487631Sjhb char *buf_p; 30587631Sjhb size_t *size_p; /* out */ 30687631Sjhb{ 30792913Sobrien struct file *fp = (struct file *)f->f_fsdata; 30892913Sobrien struct fs *fs = fp->f_fs; 30987631Sjhb long off; 31098542Smckusick ufs_lbn_t file_block; 31198542Smckusick ufs2_daddr_t disk_block; 31287631Sjhb size_t block_size; 31387631Sjhb int rc; 31487631Sjhb 31587631Sjhb /* 31687631Sjhb * Calculate the starting block address and offset. 31787631Sjhb */ 31887631Sjhb off = blkoff(fs, fp->f_seekp); 31987631Sjhb file_block = lblkno(fs, fp->f_seekp); 32098542Smckusick block_size = sblksize(fs, DIP(fp, di_size), file_block); 32187631Sjhb 32287631Sjhb rc = block_map(f, file_block, &disk_block); 32387631Sjhb if (rc) 32487631Sjhb return (rc); 32587631Sjhb 32687631Sjhb if (disk_block == 0) 32798542Smckusick /* Because we can't allocate space on the drive */ 32898542Smckusick return (EFBIG); 32987631Sjhb 33087631Sjhb /* 33187631Sjhb * Truncate buffer at end of file, and at the end of 33287631Sjhb * this block. 33387631Sjhb */ 33498542Smckusick if (*size_p > DIP(fp, di_size) - fp->f_seekp) 33598542Smckusick *size_p = DIP(fp, di_size) - fp->f_seekp; 33687631Sjhb if (*size_p > block_size - off) 33787631Sjhb *size_p = block_size - off; 33887631Sjhb 33987631Sjhb /* 34087631Sjhb * If we don't entirely occlude the block and it's not 34187631Sjhb * in memory already, read it in first. 34287631Sjhb */ 34387631Sjhb if (((off > 0) || (*size_p + off < block_size)) && 34487631Sjhb (file_block != fp->f_buf_blkno)) { 34587631Sjhb 34687631Sjhb if (fp->f_buf == (char *)0) 34787631Sjhb fp->f_buf = malloc(fs->fs_bsize); 34887631Sjhb 34987631Sjhb twiddle(); 35087631Sjhb rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 35187631Sjhb fsbtodb(fs, disk_block), 35287631Sjhb block_size, fp->f_buf, &fp->f_buf_size); 35387631Sjhb if (rc) 35487631Sjhb return (rc); 35587631Sjhb 35687631Sjhb fp->f_buf_blkno = file_block; 35787631Sjhb } 35887631Sjhb 35987631Sjhb /* 36087631Sjhb * Copy the user data into the cached block. 36187631Sjhb */ 36298542Smckusick bcopy(buf_p, fp->f_buf + off, *size_p); 36387631Sjhb 36487631Sjhb /* 36587631Sjhb * Write the block out to storage. 36687631Sjhb */ 36787631Sjhb 36887631Sjhb twiddle(); 36987631Sjhb rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, 37087631Sjhb fsbtodb(fs, disk_block), 37187631Sjhb block_size, fp->f_buf, &fp->f_buf_size); 37287631Sjhb return (rc); 37387631Sjhb} 37487631Sjhb 37587631Sjhb/* 37638451Smsmith * Read a portion of a file into an internal buffer. Return 37738451Smsmith * the location in the buffer and the amount in the buffer. 37838451Smsmith */ 37938451Smsmithstatic int 38038451Smsmithbuf_read_file(f, buf_p, size_p) 38138451Smsmith struct open_file *f; 38238451Smsmith char **buf_p; /* out */ 38338451Smsmith size_t *size_p; /* out */ 38438451Smsmith{ 38592913Sobrien struct file *fp = (struct file *)f->f_fsdata; 38692913Sobrien struct fs *fs = fp->f_fs; 38738451Smsmith long off; 38898542Smckusick ufs_lbn_t file_block; 38998542Smckusick ufs2_daddr_t disk_block; 39038451Smsmith size_t block_size; 39138451Smsmith int rc; 39238451Smsmith 39338451Smsmith off = blkoff(fs, fp->f_seekp); 39438451Smsmith file_block = lblkno(fs, fp->f_seekp); 39598542Smckusick block_size = sblksize(fs, DIP(fp, di_size), file_block); 39638451Smsmith 39738451Smsmith if (file_block != fp->f_buf_blkno) { 39887631Sjhb if (fp->f_buf == (char *)0) 39987631Sjhb fp->f_buf = malloc(fs->fs_bsize); 40087631Sjhb 40138451Smsmith rc = block_map(f, file_block, &disk_block); 40238451Smsmith if (rc) 40338451Smsmith return (rc); 40438451Smsmith 40538451Smsmith if (disk_block == 0) { 40638451Smsmith bzero(fp->f_buf, block_size); 40738451Smsmith fp->f_buf_size = block_size; 40838451Smsmith } else { 40938451Smsmith twiddle(); 41038451Smsmith rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 41138451Smsmith fsbtodb(fs, disk_block), 41238451Smsmith block_size, fp->f_buf, &fp->f_buf_size); 41338451Smsmith if (rc) 41438451Smsmith return (rc); 41538451Smsmith } 41638451Smsmith 41738451Smsmith fp->f_buf_blkno = file_block; 41838451Smsmith } 41938451Smsmith 42038451Smsmith /* 42138451Smsmith * Return address of byte in buffer corresponding to 42238451Smsmith * offset, and size of remainder of buffer after that 42338451Smsmith * byte. 42438451Smsmith */ 42538451Smsmith *buf_p = fp->f_buf + off; 42638451Smsmith *size_p = block_size - off; 42738451Smsmith 42838451Smsmith /* 42938451Smsmith * But truncate buffer at end of file. 43038451Smsmith */ 43198542Smckusick if (*size_p > DIP(fp, di_size) - fp->f_seekp) 43298542Smckusick *size_p = DIP(fp, di_size) - fp->f_seekp; 43338451Smsmith 43438451Smsmith return (0); 43538451Smsmith} 43638451Smsmith 43738451Smsmith/* 43838451Smsmith * Search a directory for a name and return its 43938451Smsmith * i_number. 44038451Smsmith */ 44138451Smsmithstatic int 44238451Smsmithsearch_directory(name, f, inumber_p) 44338451Smsmith char *name; 44438451Smsmith struct open_file *f; 44538451Smsmith ino_t *inumber_p; /* out */ 44638451Smsmith{ 44792913Sobrien struct file *fp = (struct file *)f->f_fsdata; 44892913Sobrien struct direct *dp; 44938451Smsmith struct direct *edp; 45038451Smsmith char *buf; 45138451Smsmith size_t buf_size; 45238451Smsmith int namlen, length; 45338451Smsmith int rc; 45438451Smsmith 45538451Smsmith length = strlen(name); 45638451Smsmith 45738451Smsmith fp->f_seekp = 0; 45898542Smckusick while (fp->f_seekp < DIP(fp, di_size)) { 45938451Smsmith rc = buf_read_file(f, &buf, &buf_size); 46038451Smsmith if (rc) 46138451Smsmith return (rc); 46238451Smsmith 46338451Smsmith dp = (struct direct *)buf; 46438451Smsmith edp = (struct direct *)(buf + buf_size); 46538451Smsmith while (dp < edp) { 46638451Smsmith if (dp->d_ino == (ino_t)0) 46738451Smsmith goto next; 46838451Smsmith#if BYTE_ORDER == LITTLE_ENDIAN 46938451Smsmith if (fp->f_fs->fs_maxsymlinklen <= 0) 47038451Smsmith namlen = dp->d_type; 47138451Smsmith else 47238451Smsmith#endif 47338451Smsmith namlen = dp->d_namlen; 47438451Smsmith if (namlen == length && 47538451Smsmith !strcmp(name, dp->d_name)) { 47638451Smsmith /* found entry */ 47738451Smsmith *inumber_p = dp->d_ino; 47838451Smsmith return (0); 47938451Smsmith } 48038451Smsmith next: 48138451Smsmith dp = (struct direct *)((char *)dp + dp->d_reclen); 48238451Smsmith } 48338451Smsmith fp->f_seekp += buf_size; 48438451Smsmith } 48538451Smsmith return (ENOENT); 48638451Smsmith} 48738451Smsmith 48898542Smckusickstatic int sblock_try[] = SBLOCKSEARCH; 48998542Smckusick 49038451Smsmith/* 49138451Smsmith * Open a file. 49238451Smsmith */ 49338451Smsmithstatic int 49439468Smsmithufs_open(upath, f) 49539468Smsmith const char *upath; 49638451Smsmith struct open_file *f; 49738451Smsmith{ 49892913Sobrien char *cp, *ncp; 49992913Sobrien int c; 50038451Smsmith ino_t inumber, parent_inumber; 50138451Smsmith struct file *fp; 50238451Smsmith struct fs *fs; 50398542Smckusick int i, rc; 50438451Smsmith size_t buf_size; 50538451Smsmith int nlinks = 0; 50638451Smsmith char namebuf[MAXPATHLEN+1]; 50738451Smsmith char *buf = NULL; 50839468Smsmith char *path = NULL; 50938451Smsmith 51038451Smsmith /* allocate file system specific data structure */ 51138451Smsmith fp = malloc(sizeof(struct file)); 51238451Smsmith bzero(fp, sizeof(struct file)); 51338451Smsmith f->f_fsdata = (void *)fp; 51438451Smsmith 51538451Smsmith /* allocate space and read super block */ 51698542Smckusick fs = malloc(SBLOCKSIZE); 51738451Smsmith fp->f_fs = fs; 51838451Smsmith twiddle(); 51998542Smckusick /* 52098542Smckusick * Try reading the superblock in each of its possible locations. 52198542Smckusick */ 52298542Smckusick for (i = 0; sblock_try[i] != -1; i++) { 52398542Smckusick rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 52498542Smckusick sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, 52598542Smckusick (char *)fs, &buf_size); 52698542Smckusick if (rc) 52798542Smckusick goto out; 52898542Smckusick if ((fs->fs_magic == FS_UFS1_MAGIC || 52998542Smckusick (fs->fs_magic == FS_UFS2_MAGIC && 530107555Sjake fs->fs_sblockloc == sblock_try[i])) && 53198542Smckusick buf_size == SBLOCKSIZE && 53298542Smckusick fs->fs_bsize <= MAXBSIZE && 53398542Smckusick fs->fs_bsize >= sizeof(struct fs)) 53498542Smckusick break; 53598542Smckusick } 53698542Smckusick if (sblock_try[i] == -1) { 53738451Smsmith rc = EINVAL; 53838451Smsmith goto out; 53938451Smsmith } 54038451Smsmith /* 54138451Smsmith * Calculate indirect block levels. 54238451Smsmith */ 54338451Smsmith { 54498542Smckusick ufs2_daddr_t mult; 54592913Sobrien int level; 54638451Smsmith 54738451Smsmith mult = 1; 54838451Smsmith for (level = 0; level < NIADDR; level++) { 54938451Smsmith mult *= NINDIR(fs); 55038451Smsmith fp->f_nindir[level] = mult; 55138451Smsmith } 55238451Smsmith } 55338451Smsmith 55438451Smsmith inumber = ROOTINO; 55538451Smsmith if ((rc = read_inode(inumber, f)) != 0) 55638451Smsmith goto out; 55738451Smsmith 55839468Smsmith cp = path = strdup(upath); 55939468Smsmith if (path == NULL) { 56039468Smsmith rc = ENOMEM; 56139468Smsmith goto out; 56239468Smsmith } 56338451Smsmith while (*cp) { 56438451Smsmith 56538451Smsmith /* 56638451Smsmith * Remove extra separators 56738451Smsmith */ 56838451Smsmith while (*cp == '/') 56938451Smsmith cp++; 57038451Smsmith if (*cp == '\0') 57138451Smsmith break; 57238451Smsmith 57338451Smsmith /* 57438451Smsmith * Check that current node is a directory. 57538451Smsmith */ 57698542Smckusick if ((DIP(fp, di_mode) & IFMT) != IFDIR) { 57738451Smsmith rc = ENOTDIR; 57838451Smsmith goto out; 57938451Smsmith } 58038451Smsmith 58138451Smsmith /* 58238451Smsmith * Get next component of path name. 58338451Smsmith */ 58438451Smsmith { 58592913Sobrien int len = 0; 58638451Smsmith 58738451Smsmith ncp = cp; 58838451Smsmith while ((c = *cp) != '\0' && c != '/') { 58938451Smsmith if (++len > MAXNAMLEN) { 59038451Smsmith rc = ENOENT; 59138451Smsmith goto out; 59238451Smsmith } 59338451Smsmith cp++; 59438451Smsmith } 59538451Smsmith *cp = '\0'; 59638451Smsmith } 59738451Smsmith 59838451Smsmith /* 59938451Smsmith * Look up component in current directory. 60038451Smsmith * Save directory inumber in case we find a 60138451Smsmith * symbolic link. 60238451Smsmith */ 60338451Smsmith parent_inumber = inumber; 60438451Smsmith rc = search_directory(ncp, f, &inumber); 60538451Smsmith *cp = c; 60638451Smsmith if (rc) 60738451Smsmith goto out; 60838451Smsmith 60938451Smsmith /* 61038451Smsmith * Open next component. 61138451Smsmith */ 61238451Smsmith if ((rc = read_inode(inumber, f)) != 0) 61338451Smsmith goto out; 61438451Smsmith 61538451Smsmith /* 61638451Smsmith * Check for symbolic link. 61738451Smsmith */ 61898542Smckusick if ((DIP(fp, di_mode) & IFMT) == IFLNK) { 61998542Smckusick int link_len = DIP(fp, di_size); 62038451Smsmith int len; 62138451Smsmith 62238451Smsmith len = strlen(cp); 62338451Smsmith 62438451Smsmith if (link_len + len > MAXPATHLEN || 62538451Smsmith ++nlinks > MAXSYMLINKS) { 62638451Smsmith rc = ENOENT; 62738451Smsmith goto out; 62838451Smsmith } 62938451Smsmith 63038451Smsmith bcopy(cp, &namebuf[link_len], len + 1); 63138451Smsmith 63238451Smsmith if (link_len < fs->fs_maxsymlinklen) { 63398542Smckusick if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 63498542Smckusick cp = (caddr_t)(fp->f_di.di1.di_db); 63598542Smckusick else 63698542Smckusick cp = (caddr_t)(fp->f_di.di2.di_db); 63798542Smckusick bcopy(cp, namebuf, (unsigned) link_len); 63838451Smsmith } else { 63938451Smsmith /* 64038451Smsmith * Read file for symbolic link 64138451Smsmith */ 64238451Smsmith size_t buf_size; 64398542Smckusick ufs2_daddr_t disk_block; 64492913Sobrien struct fs *fs = fp->f_fs; 64538451Smsmith 64638451Smsmith if (!buf) 64739665Smsmith buf = malloc(fs->fs_bsize); 64898542Smckusick rc = block_map(f, (ufs2_daddr_t)0, &disk_block); 64938451Smsmith if (rc) 65038451Smsmith goto out; 65138451Smsmith 65238451Smsmith twiddle(); 65338451Smsmith rc = (f->f_dev->dv_strategy)(f->f_devdata, 65438451Smsmith F_READ, fsbtodb(fs, disk_block), 65538451Smsmith fs->fs_bsize, buf, &buf_size); 65638451Smsmith if (rc) 65738451Smsmith goto out; 65838451Smsmith 65938451Smsmith bcopy((char *)buf, namebuf, (unsigned)link_len); 66038451Smsmith } 66138451Smsmith 66238451Smsmith /* 66338451Smsmith * If relative pathname, restart at parent directory. 66438451Smsmith * If absolute pathname, restart at root. 66538451Smsmith */ 66638451Smsmith cp = namebuf; 66738451Smsmith if (*cp != '/') 66838451Smsmith inumber = parent_inumber; 66938451Smsmith else 67038451Smsmith inumber = (ino_t)ROOTINO; 67138451Smsmith 67238451Smsmith if ((rc = read_inode(inumber, f)) != 0) 67338451Smsmith goto out; 67438451Smsmith } 67538451Smsmith } 67638451Smsmith 67738451Smsmith /* 67838451Smsmith * Found terminal component. 67938451Smsmith */ 68038451Smsmith rc = 0; 681134760Siedowse fp->f_seekp = 0; 68238451Smsmithout: 68338451Smsmith if (buf) 68439665Smsmith free(buf); 68539468Smsmith if (path) 68639468Smsmith free(path); 68738451Smsmith if (rc) { 68838451Smsmith if (fp->f_buf) 68939665Smsmith free(fp->f_buf); 69038451Smsmith free(fp->f_fs); 69138451Smsmith free(fp); 69238451Smsmith } 69338451Smsmith return (rc); 69438451Smsmith} 69538451Smsmith 69638451Smsmithstatic int 69738451Smsmithufs_close(f) 69838451Smsmith struct open_file *f; 69938451Smsmith{ 70092913Sobrien struct file *fp = (struct file *)f->f_fsdata; 70138451Smsmith int level; 70238451Smsmith 70338451Smsmith f->f_fsdata = (void *)0; 70438451Smsmith if (fp == (struct file *)0) 70538451Smsmith return (0); 70638451Smsmith 70738451Smsmith for (level = 0; level < NIADDR; level++) { 70838451Smsmith if (fp->f_blk[level]) 70939665Smsmith free(fp->f_blk[level]); 71038451Smsmith } 71138451Smsmith if (fp->f_buf) 71239665Smsmith free(fp->f_buf); 71339665Smsmith free(fp->f_fs); 71438451Smsmith free(fp); 71538451Smsmith return (0); 71638451Smsmith} 71738451Smsmith 71838451Smsmith/* 71938451Smsmith * Copy a portion of a file into kernel memory. 72038451Smsmith * Cross block boundaries when necessary. 72138451Smsmith */ 72238451Smsmithstatic int 72338451Smsmithufs_read(f, start, size, resid) 72438451Smsmith struct open_file *f; 72538451Smsmith void *start; 72638451Smsmith size_t size; 72738451Smsmith size_t *resid; /* out */ 72838451Smsmith{ 72992913Sobrien struct file *fp = (struct file *)f->f_fsdata; 73092913Sobrien size_t csize; 73138451Smsmith char *buf; 73238451Smsmith size_t buf_size; 73338451Smsmith int rc = 0; 73492913Sobrien char *addr = start; 73538451Smsmith 73638451Smsmith while (size != 0) { 73798542Smckusick if (fp->f_seekp >= DIP(fp, di_size)) 73838451Smsmith break; 73938451Smsmith 74038451Smsmith rc = buf_read_file(f, &buf, &buf_size); 74138451Smsmith if (rc) 74238451Smsmith break; 74338451Smsmith 74438451Smsmith csize = size; 74538451Smsmith if (csize > buf_size) 74638451Smsmith csize = buf_size; 74738451Smsmith 74838451Smsmith bcopy(buf, addr, csize); 74938451Smsmith 75038451Smsmith fp->f_seekp += csize; 75138451Smsmith addr += csize; 75238451Smsmith size -= csize; 75338451Smsmith } 75438451Smsmith if (resid) 75538451Smsmith *resid = size; 75638451Smsmith return (rc); 75738451Smsmith} 75838451Smsmith 75987631Sjhb/* 76087631Sjhb * Write to a portion of an already allocated file. 76187631Sjhb * Cross block boundaries when necessary. Can not 76287631Sjhb * extend the file. 76387631Sjhb */ 76487631Sjhbstatic int 76587631Sjhbufs_write(f, start, size, resid) 76687631Sjhb struct open_file *f; 76787631Sjhb void *start; 76887631Sjhb size_t size; 76987631Sjhb size_t *resid; /* out */ 77087631Sjhb{ 77192913Sobrien struct file *fp = (struct file *)f->f_fsdata; 77287631Sjhb size_t csize; 77387631Sjhb int rc = 0; 77492913Sobrien char *addr = start; 77587631Sjhb 77687631Sjhb csize = size; 77787631Sjhb while ((size != 0) && (csize != 0)) { 77898542Smckusick if (fp->f_seekp >= DIP(fp, di_size)) 77987631Sjhb break; 78087631Sjhb 78187631Sjhb if (csize >= 512) csize = 512; /* XXX */ 78287631Sjhb 78387631Sjhb rc = buf_write_file(f, addr, &csize); 78487631Sjhb if (rc) 78587631Sjhb break; 78687631Sjhb 78787631Sjhb fp->f_seekp += csize; 78887631Sjhb addr += csize; 78987631Sjhb size -= csize; 79087631Sjhb } 79187631Sjhb if (resid) 79287631Sjhb *resid = size; 79387631Sjhb return (rc); 79487631Sjhb} 79587631Sjhb 79638451Smsmithstatic off_t 79738451Smsmithufs_seek(f, offset, where) 79838451Smsmith struct open_file *f; 79938451Smsmith off_t offset; 80038451Smsmith int where; 80138451Smsmith{ 80292913Sobrien struct file *fp = (struct file *)f->f_fsdata; 80338451Smsmith 80438451Smsmith switch (where) { 80538451Smsmith case SEEK_SET: 80638451Smsmith fp->f_seekp = offset; 80738451Smsmith break; 80838451Smsmith case SEEK_CUR: 80938451Smsmith fp->f_seekp += offset; 81038451Smsmith break; 81138451Smsmith case SEEK_END: 81298542Smckusick fp->f_seekp = DIP(fp, di_size) - offset; 81338451Smsmith break; 81438451Smsmith default: 815124811Sjhb errno = EINVAL; 81638451Smsmith return (-1); 81738451Smsmith } 81838451Smsmith return (fp->f_seekp); 81938451Smsmith} 82038451Smsmith 82138451Smsmithstatic int 82238451Smsmithufs_stat(f, sb) 82338451Smsmith struct open_file *f; 82438451Smsmith struct stat *sb; 82538451Smsmith{ 82692913Sobrien struct file *fp = (struct file *)f->f_fsdata; 82738451Smsmith 82838451Smsmith /* only important stuff */ 82998542Smckusick sb->st_mode = DIP(fp, di_mode); 83098542Smckusick sb->st_uid = DIP(fp, di_uid); 83198542Smckusick sb->st_gid = DIP(fp, di_gid); 83298542Smckusick sb->st_size = DIP(fp, di_size); 83338451Smsmith return (0); 83438451Smsmith} 83538451Smsmith 83659766Sjlemonstatic int 83759766Sjlemonufs_readdir(struct open_file *f, struct dirent *d) 83859766Sjlemon{ 83959766Sjlemon struct file *fp = (struct file *)f->f_fsdata; 84059766Sjlemon struct direct *dp; 84159766Sjlemon char *buf; 84259766Sjlemon size_t buf_size; 84359766Sjlemon int error; 84459766Sjlemon 84559766Sjlemon /* 84659766Sjlemon * assume that a directory entry will not be split across blocks 84759766Sjlemon */ 84859766Sjlemonagain: 84998542Smckusick if (fp->f_seekp >= DIP(fp, di_size)) 85059766Sjlemon return (ENOENT); 85159766Sjlemon error = buf_read_file(f, &buf, &buf_size); 85259766Sjlemon if (error) 85359766Sjlemon return (error); 85459766Sjlemon dp = (struct direct *)buf; 85559766Sjlemon fp->f_seekp += dp->d_reclen; 85659766Sjlemon if (dp->d_ino == (ino_t)0) 85759766Sjlemon goto again; 85859766Sjlemon d->d_type = dp->d_type; 85959766Sjlemon strcpy(d->d_name, dp->d_name); 86059766Sjlemon return (0); 86159766Sjlemon} 862