home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / 3b1 / volume02 / packdisk / part01 < prev    next >
Encoding:
Internet Message Format  |  1993-06-28  |  23.6 KB

  1. Path: comp-sources-3b1
  2. From: andy@scp.caltech.edu (Andy Fyfe)
  3. Subject:  v02i041:  packdisk - a program for defragmenting your disk, Part01/01
  4. Newsgroups: comp.sources.3b1
  5. Approved: dave@galaxia.network23.com
  6. X-Checksum-Snefru: 6715c3ee f38bc91d b522d7eb b9679373
  7.  
  8. Submitted-by: andy@scp.caltech.edu (Andy Fyfe)
  9. Posting-number: Volume 2, Issue 41
  10. Archive-name: packdisk/part01
  11.  
  12. Enclosed is a copy of my packdisk program.  It rearranges completely
  13. a disk containing a unix file system so that each file is composed
  14. of a contiguous allocation of disk blocks.  The program "fsanalyze"
  15. (att7300/misc/fsanaly.cpio.Z, in the uunet/OSU 3b1 archives) can be
  16. used to check the amount of fragmentation within a file system.
  17.  
  18. This version of packdisk is virtually identical to the version already
  19. in the 3b1 archives (att7300/misc/packdsk.cpio.Z), except for one
  20. important change.  The code now attempts, via a call to ustat(), to
  21. verify that the disk is not mounted, and the README file is a bit
  22. clearer on the importance of this.
  23.  
  24. Andy Fyfe                    andy@cs.caltech.edu
  25.  
  26. #! /bin/sh
  27. # This is a shell archive.  Remove anything before this line, then unpack
  28. # it by saving it into a file and typing "sh file".  To overwrite existing
  29. # files, type "sh file -c".  You can also feed this as standard input via
  30. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  31. # will see the following message at the end:
  32. #        "End of shell archive."
  33. # Contents:  README COPYRIGHT Makefile packdisk.c
  34. # Wrapped by andy@marmot on Thu May  6 10:26:02 1993
  35. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  36. if test -f 'README' -a "${1}" != "-c" ; then 
  37.   echo shar: Will not clobber existing file \"'README'\"
  38. else
  39. echo shar: Extracting \"'README'\" \(3690 characters\)
  40. sed "s/^X//" >'README' <<'END_OF_FILE'
  41. XThis program rearranges the files and directories on a disk
  42. Xso that they appear contiguously.  This is to counteract the
  43. Xfragmentation that occurs after a time under System V.  After
  44. Xthe program finishes all the free space will be collected at
  45. Xthe end of the disk.
  46. X
  47. XThis program is rather drastic, in the sense that it does a
  48. Xwholesale rearrangement of the disk -- every single file may be
  49. Xmoved to a different part of the disk.  It does this based on
  50. Xits view of the disk.  Similarly, the kernel, if it had the
  51. Xdisk mounted, would update the disk, from time to time, based
  52. Xon its view of the disk.  For both to happen simultaneously,
  53. Xboth would have to be made aware of any changes made by the
  54. Xother, since if not, then either may update the disk based on
  55. Xno longer current information, resulting in a scrambed mess.
  56. XI'm not sure such awareness is even possible, but in any event,
  57. X*the program doesn't even try*(*).  Thus both *can not* happen
  58. Xsimultaneously, that is, this program can only be used on
  59. Xa disk that is *not* *mounted*(+).  This may very well mean that
  60. Xyou have to run the program from a floppy file system, after
  61. Xbooting from floppies.
  62. X
  63. XThis program was written on an AT&T 3b1 (running unix version 3.5).
  64. XWhile the program was written with portability in mind, it is *not*
  65. Xguaranteed to run on *any* machine, not even the 3b1.  It has,
  66. Xhowever, worked for me.
  67. X
  68. XYou should run fsck before running this program, and again after
  69. Xit's done, just to be sure!
  70. X
  71. XThe program is *slow*.  However, the disk is updated after *every*
  72. Xblock is moved, so the file system should be in a consistent state
  73. Xif the program is halted for any reason (except for the free list,
  74. Xwhich is not rebuilt until the very end, but fsck will easily
  75. Xrebuild the free list).
  76. X
  77. XI don't guarantee that this program won't destroy your disk.
  78. XMake sure you have a backup just in case!!!
  79. X
  80. XTo run the program, simply give the disk device as its only
  81. Xargument.  The program will normally ensure that the given name
  82. Xis a character special device, and will try to verify that the
  83. Xdisk is not mounted.  If compiled with '-DDEBUG', these checks are
  84. Xeliminated.  This allows, for example, you to "dd" a floppy to
  85. Xa disk file (say /tmp/disk) and then run the program with
  86. X'/tmp/disk' as its argument.  Again, when running on a real disk,
  87. Xthe disk in question *must* *not* be mounted (the internal attempt
  88. Xto verify this is not guaranteed to save you)!!!
  89. X
  90. XRemember:  THIS PROGRAM IS POTENTIALLY VERY DANGEROUS.  Use it
  91. Xat your own risk.
  92. X
  93. X                Andy Fyfe
  94. X                andy@cs.caltech.edu
  95. X
  96. X(*) There are at least 2 problems.  First, is cache consistency.  For
  97. Xefficiency, both the kernel and packdisk keep in memory various parts
  98. Xof the disk.  Things aren't likely as simple as having packdisk use
  99. Xthe block device (which goes through the buffer cache).  For example,
  100. Xthe head of the free list (which changes constantly as packdisk runs)
  101. Xis kept in the superblock.  Second, is mutual exclusion.  Packdisk makes
  102. Xa long series of read-modify-write operations, each of which must be
  103. Xatomic.  The kernel can enforce mutual exclusion by blocking interrupts
  104. Xor suspending processes.  A user process has no such control -- indeed,
  105. Xa read or write system call leaves the process open to suspension.
  106. X
  107. X(+) Typing "/etc/mount" will list the devices that are currently
  108. Xmounted.  For example, I get
  109. X    $ /etc/mount
  110. X    / on /dev/fp002 read/write on Mon Apr 19 23:08:57 1993
  111. XIn this state I should not run packdisk on /dev/rfp002.  Attempting
  112. Xto run packdisk anyway should give the following error:
  113. X    $ packdisk /dev/rfp002
  114. X    packdisk: /dev/fp002 appears to be mounted, packdisk cannot be run
  115. Xbut you shouldn't rely on the internal check alone!
  116. END_OF_FILE
  117. if test 3690 -ne `wc -c <'README'`; then
  118.     echo shar: \"'README'\" unpacked with wrong size!
  119. fi
  120. # end of 'README'
  121. fi
  122. if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then 
  123.   echo shar: Will not clobber existing file \"'COPYRIGHT'\"
  124. else
  125. echo shar: Extracting \"'COPYRIGHT'\" \(1026 characters\)
  126. sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE'
  127. X/*
  128. X * Copyright (c) Andrew Fyfe, 1989
  129. X * All rights reserved.
  130. X * Written by Andrew Fyfe.
  131. X *
  132. X * Permission is granted to anyone to use this software for any purpose on
  133. X * any computer system, and to alter it and redistribute it freely, subject
  134. X * to the following restrictions:
  135. X *
  136. X * 1. The author is not responsible for the consequences of use of this
  137. X *    software, no matter how awful, even if they arise from flaws in it.
  138. X *
  139. X * 2. The origin of this software must not be misrepresented, either by
  140. X *    explicit claim or by omission.  Since few users ever read sources,
  141. X *    credits must appear in the documentation.
  142. X *
  143. X * 3. Altered versions must be plainly marked as such, and must not be
  144. X *    misrepresented as being the original software.  Since few users
  145. X *    ever read sources, credits must appear in the documentation.
  146. X *
  147. X * 4. This notice may not be removed or altered.
  148. X */
  149. X
  150. X /*
  151. X  * This notice is copied from that included with cnews, which was
  152. X  * written (mostly) by Geoffrey Collyer and Henry Spencer.
  153. X  */
  154. END_OF_FILE
  155. if test 1026 -ne `wc -c <'COPYRIGHT'`; then
  156.     echo shar: \"'COPYRIGHT'\" unpacked with wrong size!
  157. fi
  158. # end of 'COPYRIGHT'
  159. fi
  160. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  161.   echo shar: Will not clobber existing file \"'Makefile'\"
  162. else
  163. echo shar: Extracting \"'Makefile'\" \(130 characters\)
  164. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  165. XCC = gcc -Wall
  166. XCFLAGS = -O # -DDEBUG
  167. XLDFLAGS = -s -shlib
  168. X
  169. Xpackdisk: packdisk.o
  170. X    $(CC) $(CFLAGS) $(LDFLAGS) -o packdisk packdisk.o
  171. END_OF_FILE
  172. if test 130 -ne `wc -c <'Makefile'`; then
  173.     echo shar: \"'Makefile'\" unpacked with wrong size!
  174. fi
  175. # end of 'Makefile'
  176. fi
  177. if test -f 'packdisk.c' -a "${1}" != "-c" ; then 
  178.   echo shar: Will not clobber existing file \"'packdisk.c'\"
  179. else
  180. echo shar: Extracting \"'packdisk.c'\" \(15433 characters\)
  181. sed "s/^X//" >'packdisk.c' <<'END_OF_FILE'
  182. X/*
  183. X *
  184. X * This program takes a disk and makes all the files and directories,
  185. X * and the free list, contiguous.
  186. X *
  187. X * The idea to add the reference count to the "map" array comes from
  188. X * Rick Richardson, pcrat!rick@uunet.uu.net
  189. X *
  190. X * Patches from George Sipe, rebel!george@gatech.edu were helpful
  191. X * in converting this back to "OLDC".
  192. X *
  193. X * Other modifications include a minor fix to speed up the search for
  194. X * free blocks.  I now get about 15 Mbytes / hour on the 3b1.
  195. X *
  196. X * Added a call to ustat() to see if the disk is mounted.  April 1993
  197. X *
  198. X *                         Andrew Fyfe
  199. X *                         7 October 1989
  200. X *                        16 October 1989
  201. X *
  202. X *                        andy@csvax.caltech.edu
  203. X */
  204. X
  205. X#include <sys/types.h>
  206. X#include <sys/param.h>
  207. X#include <sys/filsys.h>
  208. X#include <sys/ino.h>
  209. X#include <sys/stat.h>
  210. X#include <ustat.h>
  211. X#include <stdio.h>
  212. X#include <memory.h>
  213. X#include <malloc.h>
  214. X
  215. X#define NUM_ADDR    13
  216. X#define FIRST_INDIR    10   /* 0-9 direct, 10 single, 11 double, 12 triple */
  217. X#define NUM_INDIR    (NUM_ADDR - FIRST_INDIR)
  218. X
  219. X#ifdef __GNUC__
  220. X#define FsBSIZE_dev_    FsBSIZE(dev)
  221. X#else
  222. X#define FsBSIZE_dev_    1024    /* must be as big as your disk block size */
  223. X#endif
  224. X
  225. Xchar *cmd_name;
  226. Xint disk, dev;
  227. Xdaddr_t used;
  228. X
  229. Xstruct filsys filsys;
  230. X
  231. Xstruct dinode ino;    /* current working inode, and its number */
  232. Xino_t w_ino;
  233. X
  234. Xchar *inode_block;    /* block containing last read/written inode */
  235. Xdaddr_t w_ino_blk;    /* and its number */
  236. X
  237. Xchar *indir[NUM_INDIR];        /* current working indirect blocks */
  238. Xdaddr_t w_indir[NUM_INDIR];    /* and their numbers */
  239. X
  240. Xdaddr_t next_fill;    /* next (sequential) block to fill */
  241. Xdaddr_t last_free;    /* last free block on the disk */
  242. X
  243. Xchar *inode_table;    /* a cache of the entire inode section of the disk */
  244. X
  245. Xlong *map;    /* a map from block numbers to referencing inode/indir block */
  246. Xlong *ref;    /* a reference count */
  247. X
  248. X#ifdef __STDC__
  249. Xstatic void read_superblk(void);
  250. Xstatic void write_superblk(void);
  251. Xstatic void map_inode(ino_t inode);
  252. Xstatic void update_map(long map_entry, daddr_t block, int level);
  253. Xstatic void read_block(daddr_t block, void *buf);
  254. Xstatic void write_block(daddr_t block, void *buf);
  255. Xstatic void read_inode(ino_t inode, struct dinode *buf);
  256. Xstatic void write_inode(ino_t inode, struct dinode *buf);
  257. Xstatic void move_block(daddr_t from, daddr_t to);
  258. Xstatic void move_inode(ino_t inode);
  259. Xstatic void mov_indirect(daddr_t block, int level);
  260. Xstatic void make_hole(void);
  261. Xstatic void rebuild_free_list(void);
  262. X
  263. Xextern void l3tol(long *, char *, int length);
  264. Xextern void ltol3(char *, long *, int length);
  265. Xextern int  stat(const char *, struct stat *);
  266. Xextern long lseek(int fildes, long offset, int whence);
  267. Xextern char *ctime(long *);
  268. X#else
  269. Xstatic void read_superblk();
  270. Xstatic void write_superblk();
  271. Xstatic void map_inode();
  272. Xstatic void update_map();
  273. Xstatic void read_block();
  274. Xstatic void write_block();
  275. Xstatic void read_inode();
  276. Xstatic void write_inode();
  277. Xstatic void move_block();
  278. Xstatic void move_inode();
  279. Xstatic void mov_indirect();
  280. Xstatic void make_hole();
  281. Xstatic void rebuild_free_list();
  282. X
  283. Xextern void l3tol();
  284. Xextern void ltol3();
  285. Xextern long lseek();
  286. Xextern char *ctime();
  287. X#endif
  288. X
  289. X#ifdef __STDC__
  290. Xvoid
  291. Xmain(int argc, char *argv[])
  292. X#else
  293. Xvoid
  294. Xmain(argc, argv)
  295. Xint argc;
  296. Xchar *argv[];
  297. X#endif
  298. X{
  299. X    ino_t inode, total_inodes;
  300. X    daddr_t block;
  301. X    int i;
  302. X#ifndef DEBUG
  303. X    struct stat statb;
  304. X    struct ustat ustatb;
  305. X    char blkdev[80];
  306. X#endif
  307. X
  308. X    cmd_name = argv[0];
  309. X
  310. X    if (argc != 2) {
  311. X    fprintf(stderr, "%s: Usage: %s <file system>\n",
  312. X        cmd_name, cmd_name);
  313. X    exit(1);
  314. X    }
  315. X
  316. X#ifndef DEBUG
  317. X    if (stat(argv[1], &statb) < 0) {
  318. X    fprintf(stderr, "%s: can't stat %s: ", cmd_name, argv[1]);
  319. X    perror("");
  320. X    exit(1);
  321. X    }
  322. X    if ((statb.st_mode & S_IFMT) != S_IFCHR) {
  323. X    fprintf(stderr, "%s: %s is not a character device\n",
  324. X        cmd_name, argv[1]);
  325. X    exit(1);
  326. X    }
  327. X    strcpy(blkdev, "/dev/");
  328. X    strcat(blkdev, &argv[1][6]);
  329. X    if (strncmp(argv[1], "/dev/r", 6) == 0 && stat(blkdev, &statb) == 0
  330. X    && (statb.st_mode & S_IFMT) == S_IFBLK) {
  331. X    if (ustat(statb.st_rdev, &ustatb) == 0) {
  332. X        fprintf(stderr,
  333. X        "%s: %s appears to be mounted, packdisk cannot be run\n",
  334. X        cmd_name, blkdev);
  335. X        exit(1);
  336. X    }
  337. X    else {
  338. X        fprintf(stderr,
  339. X        "%s: the block device %s appears not to be mounted\n",
  340. X        cmd_name, blkdev);
  341. X    }
  342. X    }
  343. X    else {
  344. X    fprintf(stderr,
  345. X        "%s: Warning: can't find the block device corresponding to %s\n",
  346. X        cmd_name, argv[1]);
  347. X    fprintf(stderr,
  348. X        "%s: Warning: no check that the disk is not mounted\n",
  349. X        cmd_name);
  350. X    }
  351. X#endif
  352. X
  353. X    disk = open(argv[1], 2, 0);
  354. X    if (disk < 0) {
  355. X    fprintf(stderr, "%s: can't open %s: ", cmd_name, argv[1]);
  356. X    perror("");
  357. X    exit(1);
  358. X    }
  359. X
  360. X    read_superblk();
  361. X
  362. X    total_inodes = (filsys.s_isize - FsITOD(dev, ROOTINO)) * FsINOPB(dev);
  363. X    used = filsys.s_fsize - filsys.s_isize - filsys.s_tfree;
  364. X    fprintf(stderr, "File system: name: \"%.6s\", pack: \"%.6s\"\n",
  365. X    filsys.s_fname, filsys.s_fpack);
  366. X    fprintf(stderr, "\tlast modified on %s", ctime(&filsys.s_time));
  367. X    fprintf(stderr,
  368. X    "\ttotal inodes = %d, data blocks = %ld, total = %ld blocks\n",
  369. X    total_inodes, (long)(filsys.s_fsize - filsys.s_isize),
  370. X    (long)filsys.s_fsize);
  371. X    fprintf(stderr, "\tfree blocks = %ld, free inodes = %d\n",
  372. X    (long)filsys.s_tfree, filsys.s_tinode);
  373. X
  374. X    for (i = 0; i < NUM_INDIR; ++i) {
  375. X    w_indir[i] = 0;
  376. X    indir[i] = (char *)malloc((size_t)FsBSIZE(dev));
  377. X    if (indir[i] == 0) {
  378. X        fprintf(stderr, "%s: can't malloc indir buffer space: ", cmd_name);
  379. X        perror("");
  380. X        exit(1);
  381. X    }
  382. X    }
  383. X    w_ino = 0;
  384. X
  385. X    map = (long *)calloc((size_t)filsys.s_fsize, sizeof(*map));
  386. X    if (map == 0) {
  387. X    fprintf(stderr, "%s: can't calloc map: ", cmd_name);
  388. X    perror("");
  389. X    exit(1);
  390. X    }
  391. X    ref = (long *)calloc((size_t)filsys.s_fsize, sizeof(*ref));
  392. X    if (ref == 0) {
  393. X    fprintf(stderr, "%s: can't calloc ref: ", cmd_name);
  394. X    perror("");
  395. X    exit(1);
  396. X    }
  397. X
  398. X    inode_table = (char *)malloc((size_t)filsys.s_isize * FsBSIZE(dev));
  399. X    if (inode_table == 0) {
  400. X    fprintf(stderr, "%s: can't malloc space for inode table\n", cmd_name);
  401. X    w_ino_blk = 0;
  402. X    inode_block = (char *)malloc((size_t)FsBSIZE(dev));
  403. X    if (inode_block == 0) {
  404. X        fprintf(stderr, "%s: can't malloc inode buffer space: ", cmd_name);
  405. X        perror("");
  406. X        exit(1);
  407. X    }
  408. X    }
  409. X    else
  410. X    for (block = FsITOD(dev, ROOTINO); block < filsys.s_isize; ++block)
  411. X        read_block(block, &inode_table[block * FsBSIZE(dev)]);
  412. X
  413. X    fprintf(stderr, "mapping...");
  414. X    for (inode = ROOTINO; inode <= total_inodes; ++inode)
  415. X    map_inode(inode);
  416. X    fprintf(stderr, "done\n");
  417. X
  418. X    next_fill = filsys.s_isize;
  419. X    last_free = filsys.s_fsize - 1;
  420. X    for (inode = ROOTINO; inode <= total_inodes; ++inode)
  421. X    move_inode(inode);
  422. X
  423. X    fprintf(stderr, "\nrebuilding the free list\n");
  424. X    rebuild_free_list();
  425. X
  426. X    fprintf(stderr, "*** Run fsck to check out the disk!!!\n");
  427. X
  428. X    close(disk);
  429. X    exit(0);
  430. X}
  431. X
  432. Xstatic void
  433. Xread_superblk()
  434. X{
  435. X    if (lseek(disk, (long)SUPERBOFF, 0) != SUPERBOFF) {
  436. X    fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);
  437. X    perror("");
  438. X    exit(1);
  439. X    }
  440. X    if (read(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {
  441. X    fprintf(stderr, "%s: can't read superblock: ", cmd_name);
  442. X    perror("");
  443. X    exit(1);
  444. X    }
  445. X    if (filsys.s_magic != FsMAGIC) {
  446. X    fprintf(stderr, "%s: invalid superblock magic number\n", cmd_name);
  447. X    exit(1);
  448. X    }
  449. X    dev = (filsys.s_type == Fs2b) ? Fs2BLK : 0;
  450. X}
  451. X
  452. Xstatic void
  453. Xwrite_superblk()
  454. X{
  455. X    if (lseek(disk, (long)SUPERBOFF, 0) != SUPERBOFF) {
  456. X    fprintf(stderr, "%s: can't seek to superblock: ", cmd_name);
  457. X    perror("");
  458. X    exit(1);
  459. X    }
  460. X    if (write(disk, &filsys, sizeof(filsys)) != sizeof(filsys)) {
  461. X    fprintf(stderr, "%s: can't write superblock: ", cmd_name);
  462. X    perror("");
  463. X    exit(1);
  464. X    }
  465. X}
  466. X
  467. X#ifdef __STDC__
  468. Xstatic void
  469. Xmap_inode(ino_t inode)
  470. X#else
  471. Xstatic void
  472. Xmap_inode(inode)
  473. Xino_t inode;
  474. X#endif
  475. X{
  476. X    int type, i;
  477. X    long block[NUM_ADDR];
  478. X
  479. X    read_inode(inode, &ino);
  480. X    if (ino.di_mode == 0)
  481. X    return;
  482. X    type = ino.di_mode & S_IFMT;
  483. X    if (type == S_IFCHR || type == S_IFBLK)
  484. X    return;
  485. X
  486. X    l3tol(block, ino.di_addr, NUM_ADDR);
  487. X    for (i = 0; i < NUM_ADDR; ++i)
  488. X    if (block[i] != 0)
  489. X        update_map((long)inode, block[i],
  490. X        (i < FIRST_INDIR) ? 0 : (i - FIRST_INDIR + 1));
  491. X}
  492. X
  493. X#ifdef __STDC__
  494. Xstatic void
  495. Xupdate_map(long map_entry, daddr_t block, int level)
  496. X#else
  497. Xstatic void
  498. Xupdate_map(map_entry, block, level)
  499. Xlong map_entry;
  500. Xdaddr_t block;
  501. Xint level;
  502. X#endif
  503. X{
  504. X    int i;
  505. X
  506. X    if (map[block] != 0) {
  507. X    fprintf(stderr, "%s: duplicate block %ld in %ld and %ld\n",
  508. X        cmd_name, (long)block, map[block], map_entry);
  509. X    exit(1);
  510. X    }
  511. X    map[block] = map_entry;
  512. X
  513. X    if (map_entry < 0)
  514. X    ++ref[-map_entry];
  515. X
  516. X    if (level == 0)
  517. X    return;
  518. X
  519. X    --level;
  520. X    read_block(block, indir[level]);
  521. X    for (i = 0; i < FsNINDIR(dev); ++i)
  522. X    if (((daddr_t *)indir[level])[i] != 0)
  523. X        update_map(-block, ((daddr_t *)indir[level])[i], level);
  524. X}
  525. X
  526. X#ifdef __STDC__
  527. Xstatic void
  528. Xread_block(daddr_t block, void *buf)
  529. X#else
  530. Xstatic void
  531. Xread_block(block, buf)
  532. Xdaddr_t block;
  533. Xchar *buf;
  534. X#endif
  535. X{
  536. X    if (lseek(disk, (long)block * FsBSIZE(dev), 0) != block * FsBSIZE(dev)) {
  537. X    fprintf(stderr, "%s: can't seek to block %ld: ", cmd_name, (long)block);
  538. X    perror("");
  539. X    exit(1);
  540. X    }
  541. X    if (read(disk, buf, FsBSIZE(dev)) != FsBSIZE(dev)) {
  542. X    fprintf(stderr, "%s: can't read block %ld: ", cmd_name, (long)block);
  543. X    perror("");
  544. X    exit(1);
  545. X    }
  546. X}
  547. X
  548. X#ifdef __STDC__
  549. Xstatic void
  550. Xwrite_block(daddr_t block, void *buf)
  551. X#else
  552. Xstatic void
  553. Xwrite_block(block, buf)
  554. Xdaddr_t block;
  555. Xchar *buf;
  556. X#endif
  557. X{
  558. X    if (lseek(disk, (long)block * FsBSIZE(dev), 0) != block * FsBSIZE(dev)) {
  559. X    fprintf(stderr, "%s: can't seek to block %ld: ", cmd_name, (long)block);
  560. X    perror("");
  561. X    exit(1);
  562. X    }
  563. X    if (write(disk, buf, FsBSIZE(dev)) != FsBSIZE(dev)) {
  564. X    fprintf(stderr, "%s: can't write block %ld: ", cmd_name, (long)block);
  565. X    perror("");
  566. X    exit(1);
  567. X    }
  568. X}
  569. X
  570. X#ifdef __STDC__
  571. Xstatic void
  572. Xread_inode(ino_t inode, struct dinode *ino_p)
  573. X#else
  574. Xstatic void
  575. Xread_inode(inode, ino_p)
  576. Xino_t inode;
  577. Xstruct dinode *ino_p;
  578. X#endif
  579. X{
  580. X    daddr_t block;
  581. X
  582. X    block = FsITOD(dev, inode);
  583. X    if (inode_table == 0) {
  584. X    if (w_ino_blk != block) {
  585. X        w_ino_blk = block;
  586. X        read_block(block, inode_block);
  587. X    }
  588. X    *ino_p = ((struct dinode *)inode_block)[FsITOO(dev, inode)];
  589. X    }
  590. X    else {
  591. X    *ino_p = ((struct dinode *)&inode_table[block * FsBSIZE(dev)])
  592. X        [FsITOO(dev, inode)];
  593. X    }
  594. X}
  595. X
  596. X#ifdef __STDC__
  597. Xstatic void
  598. Xwrite_inode(ino_t inode, struct dinode *ino_p)
  599. X#else
  600. Xstatic void
  601. Xwrite_inode(inode, ino_p)
  602. Xino_t inode;
  603. Xstruct dinode *ino_p;
  604. X#endif
  605. X{
  606. X    daddr_t block;
  607. X
  608. X    block = FsITOD(dev, inode);
  609. X    if (inode_table == 0) {
  610. X    if (w_ino_blk != block) {
  611. X        w_ino_blk = block;
  612. X        read_block(block, inode_block);
  613. X    }
  614. X    ((struct dinode *)inode_block)[FsITOO(dev, inode)] = *ino_p;
  615. X    write_block(block, inode_block);
  616. X    }
  617. X    else {
  618. X    ((struct dinode *)&inode_table[block * FsBSIZE(dev)])
  619. X        [FsITOO(dev, inode)] = *ino_p;
  620. X    write_block(block, &inode_table[block * FsBSIZE(dev)]);
  621. X    }
  622. X}
  623. X
  624. X#ifdef __STDC__
  625. Xstatic void
  626. Xmove_block(daddr_t from, daddr_t to)
  627. X#else
  628. Xstatic void
  629. Xmove_block(from, to)
  630. Xdaddr_t from;
  631. Xdaddr_t to;
  632. X#endif
  633. X{
  634. X    char buffer[FsBSIZE_dev_];
  635. X    daddr_t block;
  636. X
  637. X    if (map[to] != 0)
  638. X    make_hole();
  639. X
  640. X    read_block(from, buffer);
  641. X    write_block(to, buffer);
  642. X
  643. X    map[to] = map[from];
  644. X    ref[to] = ref[from];
  645. X    map[from] = 0;
  646. X    ref[from] = 0;
  647. X
  648. X    if (from > last_free)
  649. X    last_free = from;
  650. X
  651. X    if (ref[to] > 0)
  652. X    for (block = filsys.s_isize; block < filsys.s_fsize; ++block)
  653. X        if (map[block] == -from)
  654. X        map[block] = -to;
  655. X}
  656. X
  657. X#ifdef __STDC__
  658. Xstatic void
  659. Xmove_inode(ino_t inode)
  660. X#else
  661. Xstatic void
  662. Xmove_inode(inode)
  663. Xino_t inode;
  664. X#endif
  665. X{
  666. X    int type, i;
  667. X    long block[NUM_ADDR];
  668. X
  669. X    read_inode(inode, &ino);
  670. X    w_ino = inode;
  671. X    if (ino.di_mode == 0)
  672. X    return;
  673. X    type = ino.di_mode & S_IFMT;
  674. X    if (type == S_IFCHR || type == S_IFBLK)
  675. X    return;
  676. X    
  677. X    fprintf(stderr, "moving inode %5d (size %8ld) -- %2d%% done\r",
  678. X    inode, ino.di_size, (next_fill - filsys.s_isize) * 100 / used);
  679. X
  680. X    l3tol(block, ino.di_addr, NUM_ADDR);
  681. X    for (i = 0; i < NUM_ADDR; ++i) {
  682. X    if (block[i] == 0)
  683. X        continue;
  684. X    if (block[i] != next_fill) {
  685. X        move_block(block[i], next_fill);
  686. X        l3tol(block, ino.di_addr, NUM_ADDR);
  687. X        block[i] = next_fill;
  688. X        ltol3(ino.di_addr, block, NUM_ADDR);
  689. X        write_inode(inode, &ino);
  690. X    }
  691. X    ++next_fill;
  692. X    }
  693. X    
  694. X    for (i = FIRST_INDIR; i < NUM_ADDR; ++i)
  695. X    mov_indirect(block[i], i-FIRST_INDIR);
  696. X}
  697. X
  698. X#ifdef __STDC__
  699. Xstatic void
  700. Xmov_indirect(daddr_t block, int level)
  701. X#else
  702. Xstatic void
  703. Xmov_indirect(block, level)
  704. Xdaddr_t block;
  705. Xint level;
  706. X#endif
  707. X{
  708. X    int i;
  709. X
  710. X    if (block == 0)
  711. X    return;
  712. X
  713. X    read_block(block, indir[level]);
  714. X    w_indir[level] = block;
  715. X
  716. X    for (i = 0; i < FsNINDIR(dev); ++i) {
  717. X    if (((daddr_t *)indir[level])[i] == 0)
  718. X        continue;
  719. X    if (((daddr_t *)indir[level])[i] != next_fill) {
  720. X        move_block(((daddr_t *)indir[level])[i], next_fill);
  721. X        ((daddr_t *)indir[level])[i] = next_fill;
  722. X        write_block(block, indir[level]);
  723. X    }
  724. X    ++next_fill;
  725. X    }
  726. X
  727. X    if (level == 0)
  728. X    return;
  729. X
  730. X    for (i = 0; i < FsNINDIR(dev); ++i)
  731. X    mov_indirect(((daddr_t *)indir[level])[i], level-1);
  732. X}
  733. X
  734. Xstatic void
  735. Xmake_hole()
  736. X{
  737. X    char t_indir[FsBSIZE_dev_];
  738. X    daddr_t *p_indir;
  739. X    struct dinode t_ino, *p_ino;
  740. X    long block[NUM_ADDR];
  741. X    daddr_t back;
  742. X    int i;
  743. X
  744. X    for(back = last_free; next_fill < back && map[back] != 0; --back)
  745. X    ;
  746. X
  747. X    if (next_fill >= back) {
  748. X    fprintf(stderr, "%s: can't find a free block for %ld\n",
  749. X        cmd_name, (long)next_fill);
  750. X    exit(1);
  751. X    }
  752. X    last_free = back - 1;
  753. X
  754. X    move_block(next_fill, back);
  755. X
  756. X    if (map[back] < 0) {
  757. X    block[0] = -map[back];
  758. X    for (i = 0; i < NUM_INDIR; ++i)
  759. X        if (block[0] == w_indir[i])
  760. X        break;
  761. X    if (i < NUM_INDIR) {
  762. X        p_indir = (daddr_t *)indir[i];
  763. X    }
  764. X    else {
  765. X        p_indir = (daddr_t *)t_indir;
  766. X        read_block(block[0], t_indir);
  767. X    }
  768. X    for (i = 0; i < FsNINDIR(dev); ++i) {
  769. X        if (p_indir[i] == next_fill) {
  770. X        p_indir[i] = back;
  771. X        break;
  772. X        }
  773. X    }
  774. X    if (i == FsNINDIR(dev)) {
  775. X        fprintf(stderr,
  776. X        "%s: panic: can't find %ld in indirect block %ld\n",
  777. X        cmd_name, (long)next_fill, -map[back]);
  778. X        exit(1);
  779. X    }
  780. X    write_block(block[0], (char *)p_indir);
  781. X    }
  782. X    else {
  783. X    if (map[back] == w_ino) {
  784. X        p_ino = &ino;
  785. X    }
  786. X    else {
  787. X        p_ino = &t_ino;
  788. X        read_inode((ino_t)map[back], &t_ino);
  789. X    }
  790. X    l3tol(block, p_ino->di_addr, NUM_ADDR);
  791. X    for (i = 0; i < NUM_ADDR; ++i) {
  792. X        if (block[i] == next_fill) {
  793. X        block[i] = back;
  794. X        ltol3(p_ino->di_addr, block, NUM_ADDR);
  795. X        break;
  796. X        }
  797. X    }
  798. X    if (i == NUM_ADDR) {
  799. X        fprintf(stderr, "%s: panic: can't find %ld in inode %ld\n",
  800. X        cmd_name, (long)next_fill, map[back]);
  801. X        exit(1);
  802. X    }
  803. X    write_inode((ino_t)map[back], p_ino);
  804. X    }
  805. X}
  806. X
  807. Xstatic void
  808. Xrebuild_free_list()
  809. X{
  810. X    long free_size;
  811. X    int nfree;
  812. X    daddr_t free[NICFREE], block;
  813. X    char buf[FsBSIZE_dev_];
  814. X
  815. X    free_size = filsys.s_fsize - next_fill;
  816. X    if (free_size != filsys.s_tfree) {
  817. X    fprintf(stderr, "%s: free list changed size from %ld to %ld\n",
  818. X        cmd_name, (long)filsys.s_tfree, free_size);
  819. X    exit(1);
  820. X    }
  821. X
  822. X    nfree = 1;
  823. X    memset((char *)free, 0, sizeof(free));
  824. X    memset((char *)buf, 0, sizeof(buf));
  825. X
  826. X    for (block = filsys.s_fsize - 1; block >= next_fill; --block) {
  827. X    if (nfree == NICFREE) {
  828. X        ((int *)buf)[0] = nfree;
  829. X        memcpy((char *)&((int *)buf)[1], (char *)free, sizeof(free));
  830. X        write_block(block, buf);
  831. X        nfree = 0;
  832. X        memset((char *)free, 0, sizeof(free));
  833. X    }
  834. X    free[nfree++] = block;
  835. X    }
  836. X
  837. X    filsys.s_nfree = nfree;
  838. X    memcpy((char *)filsys.s_free, (char *)free, sizeof(free));
  839. X    filsys.s_dinfo[0] = 1;
  840. X    write_superblk();
  841. X}
  842. END_OF_FILE
  843. if test 15433 -ne `wc -c <'packdisk.c'`; then
  844.     echo shar: \"'packdisk.c'\" unpacked with wrong size!
  845. fi
  846. # end of 'packdisk.c'
  847. fi
  848. echo shar: End of shell archive.
  849. exit 0
  850.  
  851. -- 
  852. David H. Brierley                            Work: dhb@ssd.ray.com
  853. 3B1 Hacker Extraordinaire                    Home: dave@galaxia.network23.com
  854.