151149Sbostic /*- 251149Sbostic * Copyright (c) 1991 The Regents of the University of California. 351149Sbostic * All rights reserved. 451149Sbostic * 551149Sbostic * %sccs.include.redist.c% 651149Sbostic */ 751149Sbostic 851149Sbostic #ifndef lint 9*51864Sbostic static char sccsid[] = "@(#)lfs.c 5.2 (Berkeley) 12/06/91"; 1051149Sbostic #endif /* not lint */ 1151149Sbostic 1251149Sbostic #include <sys/param.h> 13*51864Sbostic #include <sys/uio.h> 1451149Sbostic #include <sys/disklabel.h> 15*51864Sbostic #include <sys/time.h> 16*51864Sbostic #include <sys/resource.h> 17*51864Sbostic #include <sys/proc.h> 18*51864Sbostic #include <sys/vnode.h> 1951149Sbostic #include <ufs/dinode.h> 20*51864Sbostic #include <ufs/dir.h> 2151149Sbostic #include <unistd.h> 2251149Sbostic #include <errno.h> 2351149Sbostic #include <stdlib.h> 2451149Sbostic #include <string.h> 2551149Sbostic #include "lfs.h" /* XXX move to <sys/lfs.h> */ 2651149Sbostic #include "config.h" 2751149Sbostic #include "extern.h" 2851149Sbostic 29*51864Sbostic static LFS lfs_default = { 3051149Sbostic /* lfs_magic */ LFS_MAGIC, 3151149Sbostic /* lfs_version */ LFS_VERSION, 3251149Sbostic /* lfs_size */ 0, 3351149Sbostic /* lfs_ssize */ 0, 3451149Sbostic /* lfs_dsize */ 0, 3551149Sbostic /* lfs_bsize */ DFL_LFSBLOCK, 36*51864Sbostic /* lfs_fsize */ DFL_LFSBLOCK, 37*51864Sbostic /* lfs_frag */ 1, 3851149Sbostic /* lfs_free */ LFS_FIRST_INUM, 39*51864Sbostic /* lfs_bfree */ 0, 40*51864Sbostic /* lfs_nfiles */ 0, 4151149Sbostic /* lfs_idaddr */ 0, 4251149Sbostic /* lfs_ifile */ LFS_IFILE_INUM, 4351149Sbostic /* lfs_lastseg */ 0, 44*51864Sbostic /* lfs_nextseg */ 0, 4551149Sbostic /* lfs_tstamp */ 0, 4651149Sbostic /* lfs_minfree */ MINFREE, 4751149Sbostic /* lfs_inopb */ DFL_LFSBLOCK/sizeof(struct dinode), 4851149Sbostic /* lfs_ifpb */ DFL_LFSBLOCK/sizeof(IFILE), 4951149Sbostic /* lfs_nindir */ DFL_LFSBLOCK/sizeof(daddr_t), 5051149Sbostic /* lfs_nseg */ 0, 5151149Sbostic /* lfs_nspf */ 0, 5251149Sbostic /* lfs_segtabsz */ 0, 5351149Sbostic /* lfs_segmask */ DFL_LFSSEG_MASK, 5451149Sbostic /* lfs_segshift */ DFL_LFSSEG_SHIFT, 5551149Sbostic /* lfs_bmask */ DFL_LFSBLOCK_MASK, 5651149Sbostic /* lfs_bshift */ DFL_LFSBLOCK_SHIFT, 5751149Sbostic /* lfs_ffmask */ 0, 5851149Sbostic /* lfs_ffshift */ 0, 5951149Sbostic /* lfs_fbmask */ 0, 6051149Sbostic /* lfs_fbshift */ 0, 6151149Sbostic /* lfs_fsbtodb */ 0, 6251149Sbostic /* lfs_sboffs */ { 0 }, 63*51864Sbostic /* lfs_ivnode */ NULL, 64*51864Sbostic /* lfs_segtab */ NULL, 65*51864Sbostic /* lfs_seglist */ NULL, 66*51864Sbostic /* lfs_iocount */ 0, 6751149Sbostic /* lfs_fmod */ 0, 6851149Sbostic /* lfs_clean */ 0, 6951149Sbostic /* lfs_ronly */ 0, 7051149Sbostic /* lfs_flags */ 0, 7151149Sbostic /* lfs_fsmnt */ { 0 }, 72*51864Sbostic /* lfs_pad */ { 0 }, 7351149Sbostic /* lfs_cksum */ 0 7451149Sbostic }; 7551149Sbostic 76*51864Sbostic 77*51864Sbostic struct direct lfs_root_dir[] = { 78*51864Sbostic { ROOTINO, sizeof(struct direct), 1, "."}, 79*51864Sbostic { ROOTINO, sizeof(struct direct), 2, ".."}, 80*51864Sbostic { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found"}, 81*51864Sbostic }; 82*51864Sbostic 83*51864Sbostic struct direct lfs_lf_dir[] = { 84*51864Sbostic { LOSTFOUNDINO, sizeof(struct direct), 1, "." }, 85*51864Sbostic { ROOTINO, sizeof(struct direct), 2, ".." }, 86*51864Sbostic }; 87*51864Sbostic 88*51864Sbostic static daddr_t make_dinode 89*51864Sbostic __P((ino_t, struct dinode *, int, daddr_t, LFS *)); 90*51864Sbostic static void make_dir __P(( void *, struct direct *, int)); 9151149Sbostic static void put __P((int, off_t, void *, size_t)); 9251149Sbostic 9351149Sbostic int 9451149Sbostic make_lfs(fd, lp, partp, minfree, block_size, seg_size) 9551149Sbostic int fd; 9651149Sbostic struct disklabel *lp; 9751149Sbostic struct partition *partp; 9851149Sbostic int minfree; 9951149Sbostic int block_size; 10051149Sbostic int seg_size; 10151149Sbostic { 10251149Sbostic struct dinode *dip; /* Pointer to a disk inode */ 103*51864Sbostic struct dinode *dpagep; /* Pointer to page of disk inodes */ 10451149Sbostic FINFO file_info; /* File info structure in summary blocks */ 10551149Sbostic IFILE *ifile; /* Pointer to array of ifile structures */ 10651149Sbostic IFILE *ip; /* Pointer to array of ifile structures */ 107*51864Sbostic LFS *lfsp; /* Superblock */ 108*51864Sbostic SEGUSE *segp; /* Segment usage table */ 109*51864Sbostic SEGUSE *segtable; /* Segment usage table */ 11051149Sbostic SEGSUM summary; /* Segment summary structure */ 111*51864Sbostic SEGSUM *sp, *sp1, *sp2; /* Segment summary pointer */ 11251149Sbostic daddr_t last_sb_addr; /* Address of superblocks */ 113*51864Sbostic daddr_t last_addr; /* Previous segment address */ 11451149Sbostic daddr_t sb_addr; /* Address of superblocks */ 115*51864Sbostic daddr_t seg_addr; /* Address of current segment */ 11651149Sbostic void *pagep; /* Pointer to the page we use to write stuff */ 11751149Sbostic void *sump; /* Used to copy stuff into segment buffer */ 11851149Sbostic u_long *block_array; /* Array of logical block nos to put in sum */ 11951149Sbostic int block_array_size; /* How many entries in block array */ 12051149Sbostic int bsize; /* Block size */ 12151149Sbostic int db_per_fb; /* Disk blocks per file block */ 122*51864Sbostic int i, j; 12351149Sbostic int sb_to_sum; /* offset between superblock and summary */ 12451149Sbostic int sb_interval; /* number of segs between super blocks */ 12551149Sbostic int seg_seek; /* Seek offset for a segment */ 12651149Sbostic int ssize; /* Segment size */ 12751149Sbostic int sum_size; /* Size of the summary block */ 12851149Sbostic int wbytes; /* Number of bytes returned by write */ 12951149Sbostic 13051149Sbostic lfsp = &lfs_default; 13151149Sbostic 13251149Sbostic if (!(bsize = block_size)) 13351149Sbostic bsize = DFL_LFSBLOCK; 13451149Sbostic if (!(ssize = seg_size)) 13551149Sbostic ssize = DFL_LFSSEG; 13651149Sbostic 13751149Sbostic /* Modify parts of superblock overridden by command line arguments */ 13851149Sbostic if (bsize != DFL_LFSBLOCK) { 13951149Sbostic lfsp->lfs_bshift = log2(bsize); 14051149Sbostic if (1 << lfsp->lfs_bshift != bsize) 14151149Sbostic fatal("%d: block size not a power of 2", bsize); 14251149Sbostic lfsp->lfs_bsize = bsize; 143*51864Sbostic lfsp->lfs_fsize = bsize; 14451149Sbostic lfsp->lfs_bmask = bsize - 1; 14551149Sbostic lfsp->lfs_inopb = bsize / sizeof(struct dinode); 14651149Sbostic /* MIS -- should I round to power of 2 */ 14751149Sbostic lfsp->lfs_ifpb = bsize / sizeof(IFILE); 14851149Sbostic lfsp->lfs_nindir = bsize / sizeof(daddr_t); 14951149Sbostic } 15051149Sbostic 15151149Sbostic if (ssize != DFL_LFSSEG) { 15251149Sbostic lfsp->lfs_segshift = log2(ssize); 15351149Sbostic if (1 << lfsp->lfs_segshift != ssize) 15451149Sbostic fatal("%d: segment size not power of 2", ssize); 15551149Sbostic lfsp->lfs_ssize = ssize; 15651149Sbostic lfsp->lfs_segmask = ssize - 1; 15751149Sbostic } 15851149Sbostic lfsp->lfs_ssize = ssize >> lfsp->lfs_bshift; 15951149Sbostic 16051149Sbostic if (minfree) 16151149Sbostic lfsp->lfs_minfree = minfree; 16251149Sbostic 16351149Sbostic /* 16451149Sbostic * Fill in parts of superblock that can be computed from file system 16551149Sbostic * size, disk geometry and current time. 16651149Sbostic */ 16751149Sbostic db_per_fb = bsize/lp->d_secsize; 16851149Sbostic lfsp->lfs_fsbtodb = log2(db_per_fb); 16951149Sbostic lfsp->lfs_size = partp->p_size >> lfsp->lfs_fsbtodb; 17051149Sbostic lfsp->lfs_dsize = lfsp->lfs_size - (LFS_LABELPAD >> lfsp->lfs_bshift); 17151149Sbostic lfsp->lfs_nseg = lfsp->lfs_dsize / lfsp->lfs_ssize; 172*51864Sbostic 173*51864Sbostic /* 174*51864Sbostic * The number of free blocks is set from the total data size (lfs_dsize) 175*51864Sbostic * minus one block for each segment (for the segment summary). Then 176*51864Sbostic * we'll dubstract off the room for the superblocks, ifile entries and 177*51864Sbostic * segment usage table 178*51864Sbostic */ 179*51864Sbostic lfsp->lfs_bfree = lfsp->lfs_dsize - lfsp->lfs_nseg; 18051149Sbostic lfsp->lfs_segtabsz = SEGTABSIZE_SU(lfsp); 18151149Sbostic if ((lfsp->lfs_tstamp = time(NULL)) == -1) 18251149Sbostic fatal("time: %s", strerror(errno)); 18351149Sbostic if ((sb_interval = lfsp->lfs_nseg / LFS_MAXNUMSB) < LFS_MIN_SBINTERVAL) 18451149Sbostic sb_interval = LFS_MIN_SBINTERVAL; 18551149Sbostic 18651149Sbostic /* 18751149Sbostic * Now, lay out the file system. We need to figure out where 18851149Sbostic * the superblocks go, initialize the checkpoint information 18951149Sbostic * for the first two superblocks, initialize the segment usage 19051149Sbostic * information, put the segusage information in the ifile, create 19151149Sbostic * the first block of IFILE structures, and link all the IFILE 19251149Sbostic * structures into a free list. 19351149Sbostic */ 19451149Sbostic 19551149Sbostic /* Figure out where the superblocks are going to live */ 19651149Sbostic lfsp->lfs_sboffs[0] = LFS_LABELPAD/lp->d_secsize; 19751149Sbostic for (i = 1; i < LFS_MAXNUMSB; i++) { 19851149Sbostic sb_addr = ((i * sb_interval) << 19951149Sbostic (lfsp->lfs_segshift - lfsp->lfs_bshift + lfsp->lfs_fsbtodb)) 20051149Sbostic + lfsp->lfs_sboffs[0]; 20151149Sbostic if (sb_addr > partp->p_size) 20251149Sbostic break; 20351149Sbostic lfsp->lfs_sboffs[i] = sb_addr; 20451149Sbostic } 20551149Sbostic last_sb_addr = lfsp->lfs_sboffs[i - 1]; 20651149Sbostic lfsp->lfs_lastseg = lfsp->lfs_sboffs[0]; 207*51864Sbostic lfsp->lfs_nextseg = 208*51864Sbostic lfsp->lfs_sboffs[1] ? lfsp->lfs_sboffs[1] : lfsp->lfs_sboffs[0]; 20951149Sbostic 21051149Sbostic /* 21151149Sbostic * Initialize the segment usage table. The first segment will 21251149Sbostic * contain the superblock, the segusage table (segtabsz), 1 213*51864Sbostic * block's worth of IFILE entries, the root directory, the lost+found 214*51864Sbostic * directory and one block's worth of inodes (containing the ifile, 215*51864Sbostic * root, and l+f inodes). 21651149Sbostic */ 21751149Sbostic if (!(segtable = malloc(lfsp->lfs_segtabsz << lfsp->lfs_bshift))) 21851149Sbostic fatal("%s", strerror(errno)); 21951149Sbostic segp = segtable; 220*51864Sbostic segp->su_nbytes = LFS_SBPAD + 221*51864Sbostic ((lfsp->lfs_segtabsz + 4) << lfsp->lfs_bshift); 22251149Sbostic segp->su_lastmod = lfsp->lfs_tstamp; 223*51864Sbostic segp->su_flags = SEGUSE_DIRTY; 224*51864Sbostic lfsp->lfs_bfree -= (lfsp->lfs_segtabsz + 4); 22551149Sbostic 22651149Sbostic /* Now use su_nbytes to figure out the daddr of the ifile inode */ 22751149Sbostic lfsp->lfs_idaddr = (((segp->su_nbytes >> lfsp->lfs_bshift) - 1) << 22851149Sbostic lfsp->lfs_fsbtodb) + lfsp->lfs_sboffs[0]; 22951149Sbostic 23051149Sbostic for (segp = segtable + 1, i = 1; i < lfsp->lfs_nseg; i++, segp++) { 231*51864Sbostic if ((i % sb_interval) == 0) { 23251149Sbostic segp->su_nbytes = LFS_SBPAD; 233*51864Sbostic lfsp->lfs_bfree -= (LFS_SBPAD >> lfsp->lfs_bshift); 234*51864Sbostic } else 23551149Sbostic segp->su_nbytes = 0; 23651149Sbostic segp->su_lastmod = 0; 23751149Sbostic segp->su_flags = 0; 23851149Sbostic } 23951149Sbostic 24051149Sbostic /* 24151149Sbostic * Ready to start writing segments. The first segment is different 24251149Sbostic * because it contains the segment usage table and the ifile inode 243*51864Sbostic * as well as a superblock. For the rest of the segments, set the 244*51864Sbostic * time stamp to be 0 so that the first segment is the most recent. 245*51864Sbostic * For each segment that is supposed to contain a copy of the super 246*51864Sbostic * block, initialize its first few blocks and its segment summary 247*51864Sbostic * to indicate this. 24851149Sbostic */ 249*51864Sbostic lfsp->lfs_nfiles = LFS_FIRST_INUM - 1; 25051149Sbostic lfsp->lfs_cksum = 251*51864Sbostic cksum(lfsp, sizeof(LFS) - sizeof(lfsp->lfs_cksum)); 252*51864Sbostic put(fd, LFS_LABELPAD, lfsp, sizeof(LFS)); 25351149Sbostic put(fd, LFS_LABELPAD + LFS_SBPAD, segtable, 25451149Sbostic lfsp->lfs_segtabsz << lfsp->lfs_bshift); 25551149Sbostic (void)free(segtable); 25651149Sbostic 257*51864Sbostic /* Now create a block of disk inodes */ 258*51864Sbostic if (!(dpagep = malloc(lfsp->lfs_bsize))) 259*51864Sbostic fatal("%s", strerror(errno)); 260*51864Sbostic dip = (struct dinode *)dpagep; 261*51864Sbostic bzero(dip, lfsp->lfs_bsize); 262*51864Sbostic 263*51864Sbostic /* Create a block of the IFILES. */ 26451149Sbostic if (!(pagep = malloc(lfsp->lfs_bsize))) 26551149Sbostic fatal("%s", strerror(errno)); 26651149Sbostic ifile = (IFILE *)pagep; 267*51864Sbostic 268*51864Sbostic /* Initialize IFILE */ 269*51864Sbostic sb_addr = (LFS_LABELPAD + LFS_SBPAD) / lp->d_secsize; 270*51864Sbostic sb_addr = make_dinode(LFS_IFILE_INUM, dip, lfsp->lfs_segtabsz+1, 271*51864Sbostic sb_addr, lfsp); 272*51864Sbostic dip->di_mode = IFREG|IREAD|IWRITE; 273*51864Sbostic ip = &ifile[LFS_IFILE_INUM]; 274*51864Sbostic ip->if_version = 1; 275*51864Sbostic ip->if_daddr = lfsp->lfs_idaddr; 276*51864Sbostic ip->if_st_atime = lfsp->lfs_tstamp; 277*51864Sbostic 278*51864Sbostic /* Initialize the ROOT Directory */ 279*51864Sbostic sb_addr = make_dinode(ROOTINO, ++dip, 1, sb_addr, lfsp); 280*51864Sbostic dip->di_mode = IFDIR|IREAD|IWRITE|IEXEC; 281*51864Sbostic dip->di_size = DIRBLKSIZ; 282*51864Sbostic dip->di_nlink = 3; 283*51864Sbostic ip = &ifile[ROOTINO]; 284*51864Sbostic ip->if_version = 1; 285*51864Sbostic ip->if_daddr = lfsp->lfs_idaddr; 286*51864Sbostic ip->if_st_atime = lfsp->lfs_tstamp; 287*51864Sbostic 288*51864Sbostic /* Initialize the lost+found Directory */ 289*51864Sbostic sb_addr = make_dinode(LOSTFOUNDINO, ++dip, 1, sb_addr, lfsp); 290*51864Sbostic dip->di_mode = IFDIR|IREAD|IWRITE|IEXEC; 291*51864Sbostic dip->di_size = DIRBLKSIZ; 292*51864Sbostic dip->di_nlink = 2; 293*51864Sbostic ip = &ifile[LOSTFOUNDINO]; 294*51864Sbostic ip->if_version = 1; 295*51864Sbostic ip->if_daddr = lfsp->lfs_idaddr; 296*51864Sbostic ip->if_st_atime = lfsp->lfs_tstamp; 297*51864Sbostic 298*51864Sbostic /* Make all the other dinodes invalid */ 299*51864Sbostic for (i = INOPB(lfsp)-3, dip++; i; i--, dip++) 300*51864Sbostic dip->di_inum = LFS_UNUSED_INUM; 301*51864Sbostic 302*51864Sbostic 303*51864Sbostic /* Link remaining IFILE entries in free list */ 304*51864Sbostic for (ip = &ifile[LFS_FIRST_INUM], i = LFS_FIRST_INUM; 305*51864Sbostic i < lfsp->lfs_ifpb; ++ip) { 30651149Sbostic ip->if_version = 1; 30751149Sbostic ip->if_daddr = LFS_UNUSED_DADDR; 30851149Sbostic ip->if_nextfree = ++i; 30951149Sbostic } 31051149Sbostic ifile[lfsp->lfs_ifpb - 1].if_nextfree = LFS_UNUSED_INUM; 31151149Sbostic 312*51864Sbostic /* Now, write the ifile */ 31351149Sbostic if ((wbytes = write(fd, ifile, lfsp->lfs_bsize)) < 0) 31451149Sbostic fatal("%s: %s", special, strerror(errno)); 31551149Sbostic if (wbytes != lfsp->lfs_bsize) 31651149Sbostic fatal("%s: short write (%d, not %d)", 31751149Sbostic special, wbytes, lfsp->lfs_bsize); 31851149Sbostic 319*51864Sbostic /* Write out the root and lost and found directories */ 320*51864Sbostic bzero(pagep, lfsp->lfs_bsize); 321*51864Sbostic make_dir(pagep, lfs_root_dir, 322*51864Sbostic sizeof(lfs_root_dir) / sizeof(struct direct)); 323*51864Sbostic if ((wbytes = write(fd, pagep, lfsp->lfs_bsize)) < 0) 324*51864Sbostic fatal("%s: %s", special, strerror(errno)); 325*51864Sbostic if (wbytes != lfsp->lfs_bsize) 326*51864Sbostic fatal("%s: short write (%d, not %d)", 327*51864Sbostic special, wbytes, lfsp->lfs_bsize); 32851149Sbostic 329*51864Sbostic bzero(pagep, lfsp->lfs_bsize); 330*51864Sbostic make_dir(pagep, lfs_lf_dir, 331*51864Sbostic sizeof(lfs_lf_dir) / sizeof(struct direct)); 332*51864Sbostic if ((wbytes = write(fd, pagep, lfsp->lfs_bsize)) < 0) 333*51864Sbostic fatal("%s: %s", special, strerror(errno)); 334*51864Sbostic if (wbytes != lfsp->lfs_bsize) 335*51864Sbostic fatal("%s: short write (%d, not %d)", 336*51864Sbostic special, wbytes, lfsp->lfs_bsize); 33751149Sbostic 33851149Sbostic /* Finally, write out the inode block */ 339*51864Sbostic if ((wbytes = write(fd, dpagep, lfsp->lfs_bsize)) < 0) 34051149Sbostic fatal("%s: %s", special, strerror(errno)); 34151149Sbostic if (wbytes != lfsp->lfs_bsize) 34251149Sbostic fatal("%s: short write (%d, not %d)", 34351149Sbostic special, wbytes, lfsp->lfs_bsize); 34451149Sbostic 34551149Sbostic /* MIS -- probably want to replace with "write block code" */ 34651149Sbostic /* Now it's time to write the summary for the first segment. */ 347*51864Sbostic summary.ss_next = lfsp->lfs_nextseg; 34851149Sbostic summary.ss_prev = last_sb_addr; 34951149Sbostic summary.ss_nextsum = -1; 35051149Sbostic summary.ss_create = lfsp->lfs_tstamp; 351*51864Sbostic summary.ss_nfinfo = 4; 35251149Sbostic summary.ss_ninos = 1; 35351149Sbostic 354*51864Sbostic /* Superblock */ 35551149Sbostic file_info.fi_nblocks = LFS_SBPAD >> lfsp->lfs_bshift; 35651149Sbostic file_info.fi_version = 1; 35751149Sbostic file_info.fi_ino = LFS_UNUSED_INUM; 35851149Sbostic 359*51864Sbostic /* 360*51864Sbostic * Make sure that we don't overflow a summary block. We have to 361*51864Sbostic * record: FINFO structures for superblock, ifile, root, l+f. 362*51864Sbostic */ 363*51864Sbostic sum_size = 4*sizeof(FINFO) + sizeof(SEGSUM) + 364*51864Sbostic file_info.fi_nblocks * sizeof(u_long) + /* sb blocks */ 365*51864Sbostic (lfsp->lfs_segtabsz + 1) * sizeof(u_long) + /* ifile blocks */ 366*51864Sbostic 2 * sizeof(u_long); /* root and l+f block */ 36751149Sbostic #define SUMERR \ 36851149Sbostic "Multiple summary blocks in segment 1 not yet implemented\nsummary is %d bytes." 36951149Sbostic if (sum_size > LFS_SUMMARY_SIZE) 37051149Sbostic fatal(SUMERR, sum_size); 37151149Sbostic 37251149Sbostic block_array_size = file_info.fi_nblocks; 37351149Sbostic if ((lfsp->lfs_segtabsz + 1) > block_array_size) 37451149Sbostic block_array_size = lfsp->lfs_segtabsz + 1; 37551149Sbostic 37651149Sbostic if (!(block_array = malloc(block_array_size *sizeof(int)))) 37751149Sbostic fatal("%s: %s", special, strerror(errno)); 37851149Sbostic 37951149Sbostic /* fill in the array */ 38051149Sbostic for (i = 0; i < file_info.fi_nblocks; i++) 38151149Sbostic block_array[i] = i; 38251149Sbostic 38351149Sbostic /* copy into segment */ 38451149Sbostic sump = pagep; 38551149Sbostic bcopy(&summary, sump, sizeof(SEGSUM)); 38651149Sbostic sump += sizeof(SEGSUM); 38751149Sbostic bcopy(&file_info, sump, sizeof(FINFO) - sizeof(u_long)); 38851149Sbostic sump += sizeof(FINFO) - sizeof(u_long); 38951149Sbostic bcopy(block_array, sump, sizeof(u_long) * file_info.fi_nblocks); 39051149Sbostic sump += sizeof(u_long) * file_info.fi_nblocks; 39151149Sbostic 39251149Sbostic /* Now, add the ifile */ 39351149Sbostic file_info.fi_nblocks = lfsp->lfs_segtabsz + 1; 39451149Sbostic file_info.fi_version = 1; 39551149Sbostic file_info.fi_ino = LFS_IFILE_INUM; 39651149Sbostic 39751149Sbostic for (i = 0; i < file_info.fi_nblocks; i++) 39851149Sbostic block_array[i] = i; 39951149Sbostic 40051149Sbostic bcopy(&file_info, sump, sizeof(FINFO) - sizeof(u_long)); 40151149Sbostic sump += sizeof(FINFO) - sizeof(u_long); 40251149Sbostic bcopy(block_array, sump, sizeof(u_long) * file_info.fi_nblocks); 403*51864Sbostic sump += sizeof(u_long) * file_info.fi_nblocks; 40451149Sbostic 405*51864Sbostic /* Now, add the root directory */ 406*51864Sbostic file_info.fi_nblocks = 1; 407*51864Sbostic file_info.fi_version = 1; 408*51864Sbostic file_info.fi_ino = ROOTINO; 409*51864Sbostic file_info.fi_blocks[0] = 0; 410*51864Sbostic bcopy(&file_info, sump, sizeof(FINFO)); 411*51864Sbostic sump += sizeof(FINFO); 412*51864Sbostic 413*51864Sbostic /* Now, add the lost and found */ 414*51864Sbostic file_info.fi_ino = LOSTFOUNDINO; 415*51864Sbostic bcopy(&file_info, sump, sizeof(FINFO)); 416*51864Sbostic 417*51864Sbostic 41851149Sbostic sb_to_sum = (lfsp->lfs_ssize << lfsp->lfs_bshift) - LFS_SUMMARY_SIZE; 41951149Sbostic ((SEGSUM *)pagep)->ss_cksum = cksum(pagep+sizeof(summary.ss_cksum), 42051149Sbostic LFS_SUMMARY_SIZE - sizeof(summary.ss_cksum)); 42151149Sbostic put(fd, LFS_LABELPAD + sb_to_sum, pagep, LFS_SUMMARY_SIZE); 42251149Sbostic 423*51864Sbostic /* 424*51864Sbostic * The first FINFO structure from above is good, just need to change 425*51864Sbostic * the pointers 426*51864Sbostic */ 427*51864Sbostic sp1 = (SEGSUM *)pagep; 428*51864Sbostic sp1->ss_nextsum = -1; 429*51864Sbostic sp1->ss_create = 0; 430*51864Sbostic sp1->ss_nfinfo = 1; 431*51864Sbostic sp1->ss_ninos = 0; 43251149Sbostic 433*51864Sbostic sp2 = (SEGSUM *)dpagep; 434*51864Sbostic sp2->ss_nextsum = -1; 435*51864Sbostic sp2->ss_create = 0; 436*51864Sbostic sp2->ss_nfinfo = 0; 437*51864Sbostic sp2->ss_ninos = 0; 43851149Sbostic 43951149Sbostic /* Now, write rest of segments containing superblocks */ 44051149Sbostic lfsp->lfs_tstamp = 0; 441*51864Sbostic lfsp->lfs_cksum = 442*51864Sbostic cksum(lfsp, sizeof(LFS) - sizeof(lfsp->lfs_cksum)); 443*51864Sbostic for (seg_addr = last_addr = lfsp->lfs_sboffs[0], j = 1, i = 1; 444*51864Sbostic i < lfsp->lfs_nseg; i++) { 44551149Sbostic 446*51864Sbostic seg_addr += lfsp->lfs_ssize << lfsp->lfs_fsbtodb; 447*51864Sbostic if (seg_addr == lfsp->lfs_sboffs[j]) { 448*51864Sbostic sp = sp1; /* It's a superblock */ 449*51864Sbostic if (j < (LFS_MAXNUMSB - 2)) 450*51864Sbostic j++; 451*51864Sbostic } else 452*51864Sbostic sp = sp2; 45351149Sbostic 454*51864Sbostic sp->ss_next = last_addr; 455*51864Sbostic last_addr = seg_addr; 456*51864Sbostic 457*51864Sbostic seg_seek = seg_addr * lp->d_secsize; 458*51864Sbostic if (sp == sp1) 459*51864Sbostic put(fd, seg_seek, lfsp, sizeof(LFS)); 460*51864Sbostic 46151149Sbostic /* Summary */ 462*51864Sbostic sp->ss_cksum = cksum(&sp->ss_next, 46351149Sbostic LFS_SUMMARY_SIZE - sizeof(sp->ss_cksum)); 464*51864Sbostic put(fd, sb_to_sum + seg_seek, sp, LFS_SUMMARY_SIZE); 46551149Sbostic } 466*51864Sbostic free(dpagep); 467*51864Sbostic free(pagep); 468*51864Sbostic close(fd); 46951149Sbostic return (0); 47051149Sbostic } 47151149Sbostic 47251149Sbostic static void 47351149Sbostic put(fd, off, p, len) 47451149Sbostic int fd; 47551149Sbostic off_t off; 47651149Sbostic void *p; 47751149Sbostic size_t len; 47851149Sbostic { 47951149Sbostic int wbytes; 48051149Sbostic 48151149Sbostic if (lseek(fd, off, SEEK_SET) < 0) 48251149Sbostic fatal("%s: %s", special, strerror(errno)); 48351149Sbostic if ((wbytes = write(fd, p, len)) < 0) 48451149Sbostic fatal("%s: %s", special, strerror(errno)); 48551149Sbostic if (wbytes != len) 48651149Sbostic fatal("%s: short write (%d, not %d)", special, wbytes, len); 48751149Sbostic } 488*51864Sbostic 489*51864Sbostic /* 490*51864Sbostic * Create the root directory for this file system and the lost+found 491*51864Sbostic * directory. 492*51864Sbostic */ 493*51864Sbostic 494*51864Sbostic u_long d_ino; /* inode number of entry */ 495*51864Sbostic u_short d_reclen; /* length of this record */ 496*51864Sbostic u_short d_namlen; /* length of string in d_name */ 497*51864Sbostic char d_name[MAXNAMLEN + 1]; /* name with length <= MAXNAMLEN */ 498*51864Sbostic lfsinit() 499*51864Sbostic { 500*51864Sbostic } 501*51864Sbostic 502*51864Sbostic static daddr_t 503*51864Sbostic make_dinode(ino, dip, nblocks, saddr, lfsp) 504*51864Sbostic ino_t ino; /* inode we're creating */ 505*51864Sbostic struct dinode *dip; /* disk inode */ 506*51864Sbostic int nblocks; /* number of blocks in file */ 507*51864Sbostic daddr_t saddr; /* starting block address */ 508*51864Sbostic LFS *lfsp; /* superblock */ 509*51864Sbostic { 510*51864Sbostic int db_per_fb, i; 511*51864Sbostic 512*51864Sbostic dip->di_nlink = 1; 513*51864Sbostic dip->di_blocks = nblocks; 514*51864Sbostic 515*51864Sbostic /* If we ever need something longer than 32 bits, this changes */ 516*51864Sbostic dip->di_size = (dip->di_blocks << lfsp->lfs_bshift); 517*51864Sbostic dip->di_atime = dip->di_mtime = dip->di_ctime = lfsp->lfs_tstamp; 518*51864Sbostic dip->di_inum = ino; 519*51864Sbostic 520*51864Sbostic #define SEGERR \ 521*51864Sbostic "File requires more than the number of direct blocks; increase block or segment size." 522*51864Sbostic if (NDADDR < nblocks) 523*51864Sbostic fatal("%s", SEGERR); 524*51864Sbostic 525*51864Sbostic /* Assign the block addresses for the ifile */ 526*51864Sbostic db_per_fb = 1 << lfsp->lfs_fsbtodb; 527*51864Sbostic for (i = 0; i < dip->di_blocks; i++, saddr += db_per_fb) 528*51864Sbostic dip->di_db[i] = saddr; 529*51864Sbostic 530*51864Sbostic return (saddr); 531*51864Sbostic } 532*51864Sbostic 533*51864Sbostic 534*51864Sbostic /* 535*51864Sbostic * Construct a set of directory entries in "bufp". We assume that all the 536*51864Sbostic * entries in protodir fir in the first DIRBLKSIZ. 537*51864Sbostic */ 538*51864Sbostic static void 539*51864Sbostic make_dir(bufp, protodir, entries) 540*51864Sbostic void *bufp; 541*51864Sbostic register struct direct *protodir; 542*51864Sbostic int entries; 543*51864Sbostic { 544*51864Sbostic char *cp; 545*51864Sbostic int i, spcleft; 546*51864Sbostic 547*51864Sbostic spcleft = DIRBLKSIZ; 548*51864Sbostic for (cp = bufp, i = 0; i < entries - 1; i++) { 549*51864Sbostic protodir[i].d_reclen = DIRSIZ(&protodir[i]); 550*51864Sbostic bcopy(&protodir[i], cp, protodir[i].d_reclen); 551*51864Sbostic cp += protodir[i].d_reclen; 552*51864Sbostic if ((spcleft -= protodir[i].d_reclen) < 0) 553*51864Sbostic fatal("%s: %s", special, "directory too big"); 554*51864Sbostic } 555*51864Sbostic protodir[i].d_reclen = spcleft; 556*51864Sbostic bcopy(&protodir[i], cp, DIRSIZ(&protodir[i])); 557*51864Sbostic } 558