]>
git.saurik.com Git - apple/hfs.git/blob - fsck_hfs/fsck_hfs.c
2 * Copyright (c) 1999-2000, 2002-2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 #include <sys/types.h>
25 #include <sys/param.h>
26 #include <sys/ucred.h>
27 #include <sys/mount.h>
28 #include <sys/ioctl.h>
30 #include <sys/sysctl.h>
34 #include <hfs/hfs_mount.h>
45 #include <TargetConditionals.h>
48 #include "fsck_msgnums.h"
49 #include "fsck_hfs_msgnums.h"
51 #include "fsck_debug.h"
52 #include "dfalib/CheckHFS.h"
55 * These definitions are duplicated from xnu's hfs_readwrite.c, and could live
56 * in a shared header file if desired. On the other hand, the freeze and thaw
57 * commands are not really supposed to be public.
60 #define F_FREEZE_FS 53 /* "freeze" all fs operations */
61 #define F_THAW_FS 54 /* "thaw" all fs operations */
64 /* Global Variables for front end */
65 const char *cdevname
; /* name of device being checked */
67 char lflag
; /* live fsck */
68 char nflag
; /* assume a no response */
69 char yflag
; /* assume a yes response */
70 char preen
; /* just fix normal inconsistencies */
71 char force
; /* force fsck even if clean (preen only) */
72 char quick
; /* quick check returns clean, dirty, or failure */
73 char debug
; /* output debugging info */
74 char disable_journal
; /* If debug, and set, do not simulate journal replay */
75 char scanflag
; /* Scan entire disk for bad blocks */
82 char hotroot
; /* checking root device */
83 char hotmount
; /* checking read-only mounted device */
84 char guiControl
; /* this app should output info for gui control */
85 char xmlControl
; /* Output XML (plist) messages -- implies guiControl as well */
86 char rebuildBTree
; /* Rebuild requested btree files */
87 int rebuildOptions
; /* Options to indicate which btree should be rebuilt */
88 char modeSetting
; /* set the mode when creating "lost+found" directory */
89 char errorOnExit
= 0; /* Exit on first error */
90 int upgrading
; /* upgrading format */
91 int lostAndFoundMode
= 0; /* octal mode used when creating "lost+found" directory */
92 uint64_t reqCacheSize
; /* Cache size requested by the caller (may be specified by the user via -c) */
93 int detonator_run
= 0;
95 int fsmodified
; /* 1 => write done to file system */
96 int fsreadfd
; /* file descriptor for reading file system */
97 int fswritefd
; /* file descriptor for writing file system */
101 * Variables used to map physical block numbers to file paths
103 enum { BLOCK_LIST_INCREMENT
= 512 };
104 int gBlkListEntries
= 0;
105 u_int64_t
*gBlockList
= NULL
;
106 int gFoundBlockEntries
= 0;
107 struct found_blocks
*gFoundBlocksList
= NULL
;
108 long gBlockSize
= 512;
109 static void ScanDisk(int);
110 static int getblocklist(const char *filepath
);
113 static int checkfilesys
__P((char * filesys
));
114 static int setup
__P(( char *dev
, int *canWritePtr
));
115 static void usage
__P((void));
116 static void getWriteAccess
__P(( char *dev
, int *canWritePtr
));
117 extern char *unrawname
__P((char *name
));
131 if ((progname
= strrchr(*argv
, '/')))
136 while ((ch
= getopt(argc
, argv
, "b:B:c:D:e:Edfglm:npqrR:SuyxJ")) != EOF
) {
139 gBlockSize
= atoi(optarg
);
140 if ((gBlockSize
< 512) || (gBlockSize
& (gBlockSize
-1))) {
141 (void) fprintf(stderr
, "%s invalid block size %d\n",
142 progname
, gBlockSize
);
150 getblocklist(optarg
);
153 /* Cache size to use in fsck_hfs */
154 reqCacheSize
= strtoull(optarg
, &lastChar
, 0);
156 switch (tolower(*lastChar
)) {
158 reqCacheSize
*= 1024ULL;
161 reqCacheSize
*= 1024ULL;
164 reqCacheSize
*= 1024ULL;
181 /* Input value should be in hex example: -D 0x5 */
182 cur_debug_level
= strtoul(optarg
, NULL
, 0);
183 if (cur_debug_level
== 0) {
184 (void) fplog (stderr
, "%s: invalid debug development argument. Assuming zero\n", progname
);
190 if (strcasecmp(optarg
, "embedded") == 0)
192 else if (strcasecmp(optarg
, "desktop") == 0)
198 /* Exit on first error, after logging it */
223 mode
= strtol( optarg
, NULL
, 8 );
224 lostAndFoundMode
= (int)mode
;
225 if ( lostAndFoundMode
== 0 || mode
< INT_MIN
|| mode
> INT_MAX
)
227 (void) fplog(stderr
, "%s: %ld is invalid mode argument\n", progname
, mode
);
246 // rebuild catalog btree
248 rebuildOptions
|= REBUILD_CATALOG
;
257 // rebuild attribute btree
259 rebuildOptions
|= REBUILD_ATTRIBUTE
;
263 // rebuild catalog btree
265 rebuildOptions
|= REBUILD_CATALOG
;
269 // rebuild extents overflow btree
271 rebuildOptions
|= REBUILD_EXTENTS
;
275 fprintf(stderr
, "%s: unknown btree rebuild code `%c' (%#x)\n", progname
, *cp
, *cp
);
298 if (debug
== 0 && disable_journal
!= 0)
301 if (gBlkListEntries
!= 0 && gBlockSize
== 0)
305 debug
= 0; /* debugging is for command line only */
307 if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
308 (void)signal(SIGINT
, catch);
311 (void) fplog(stderr
, "%s: missing special-device\n", progname
);
317 char *pcBlkChk
= blockcheck(*argv
++);
318 ret
|= checkfilesys(pcBlkChk
);
324 int fs_fd
=-1; // fd to the root-dir of the fs we're checking (only w/lfag == 1)
330 fcntl(fs_fd
, F_THAW_FS
, NULL
);
337 mountpoint(const char *cdev
)
340 struct statfs
*fsinfo
;
348 unraw
= strdup(cdev
);
354 result
= getmntinfo(&fsinfo
, MNT_NOWAIT
);
356 for (i
= 0; i
< result
; i
++) {
357 if (strcmp(unraw
, fsinfo
[i
].f_mntfromname
) == 0) {
358 retval
= strdup(fsinfo
[i
].f_mntonname
);
371 checkfilesys(char * filesys
)
375 int chkLev
, repLev
, logLev
;
377 char *mntonname
= NULL
;
378 fsck_ctx_t context
= NULL
;
382 hotmount
= hotroot
; // hotroot will be 1 or 0 by this time
385 // initialize the printing/logging without actually printing anything
386 // DO NOT DELETE THIS or else you can deadlock during a live fsck
387 // when something is printed and we try to create the log file.
391 context
= fsckCreate();
393 mntonname
= mountpoint(cdevname
);
397 mntonname
= strdup("/");
400 if (lflag
&& !detonator_run
) {
404 * Ensure that, if we're doing a live verify, that we're not trying
405 * to do input or output to the same device. This would cause a deadlock.
408 if (stat(cdevname
, &fs_stat
) != -1 &&
409 (((fs_stat
.st_mode
& S_IFMT
) == S_IFCHR
) ||
410 ((fs_stat
.st_mode
& S_IFMT
) == S_IFBLK
))) {
413 if (fstat(fileno(stdin
), &io_stat
) != -1 &&
414 (fs_stat
.st_rdev
== io_stat
.st_dev
)) {
415 plog("ERROR: input redirected from target volume for live verify.\n");
418 if (fstat(fileno(stdout
), &io_stat
) != -1 &&
419 (fs_stat
.st_rdev
== io_stat
.st_dev
)) {
420 plog("ERROR: output redirected to target volume for live verify.\n");
423 if (fstat(fileno(stderr
), &io_stat
) != -1 &&
424 (fs_stat
.st_rdev
== io_stat
.st_dev
)) {
425 plog("ERROR: error output redirected to target volume for live verify.\n");
433 * If the device is mounted somewhere, then we need to make sure that it's
434 * a read-only device, or that a live-verify has been requested.
436 if (mntonname
!= NULL
) {
437 struct statfs stfs_buf
;
439 if (statfs(mntonname
, &stfs_buf
) == 0) {
441 // Need to try to freeze it
442 fs_fd
= open(mntonname
, O_RDONLY
);
444 plog("ERROR: could not open %s to freeze the volume.\n", mntonname
);
449 if (fcntl(fs_fd
, F_FREEZE_FS
, NULL
) != 0) {
451 plog("ERROR: could not freeze volume (%s)\n", strerror(errno
));
454 } else if (stfs_buf
.f_flags
& MNT_RDONLY
) {
457 /* MNT_RDONLY is not set and this is not a live verification */
458 plog("ERROR: volume %s is mounted with write access. Re-run with (-l) to freeze volume.\n", mntonname
);
467 if (setup( filesys
, &canWrite
) == 0) {
469 pfatal("CAN'T CHECK FILE SYSTEM.");
471 goto ExitThisRoutine
;
475 if (hotroot
&& !guiControl
)
476 plog("** Root file system\n");
479 /* start with defaults for dfa back-end */
480 chkLev
= kAlwaysCheck
;
481 repLev
= kMajorRepairs
;
482 logLev
= kVerboseLog
;
485 repLev
= kMajorRepairs
;
488 chkLev
= kNeverCheck
;
489 repLev
= kNeverRepair
;
492 chkLev
= kForceCheck
;
495 repLev
= kMinorRepairs
;
496 chkLev
= force
? kAlwaysCheck
: kDirtyCheck
;
503 repLev
= kNeverRepair
;
505 if ( rebuildBTree
) {
506 chkLev
= kPartialCheck
;
507 repLev
= kForceRepairs
; // this will force rebuild of B-Tree file
510 fsckSetVerbosity(context
, logLev
);
511 /* All of fsck_hfs' output should go thorugh logstring */
512 fsckSetOutput(context
, NULL
);
513 /* Setup writer that will output to standard out */
514 fsckSetWriter(context
, &outstring
);
516 /* Setup logger that will write to log file */
517 fsckSetLogger(context
, &logstring
);
520 fsckSetOutputStyle(context
, fsckOutputXML
);
522 fsckSetOutputStyle(context
, fsckOutputGUI
);
524 fsckSetOutputStyle(context
, fsckOutputTraditional
);
527 if (errorOnExit
&& nflag
) {
528 chkLev
= kMajorCheck
;
532 * go check HFS volume...
535 if (rebuildOptions
&& canWrite
== 0) {
536 plog("BTree rebuild requested but writing disabled\n");
538 goto ExitThisRoutine
;
541 if (gBlockList
!= NULL
&& scanflag
!= 0) {
542 plog("Cannot scan for bad blocks and ask for listed blocks to file mapping\n");
544 goto ExitThisRoutine
;
547 plog("Scanning entire disk for bad blocks\n");
551 result
= CheckHFS( filesys
, fsreadfd
, fswritefd
, chkLev
, repLev
, context
,
552 lostAndFoundMode
, canWrite
, &fsmodified
,
553 lflag
, rebuildOptions
);
555 plog("\tCheckHFS returned %d, fsmodified = %d\n", result
, fsmodified
);
561 pwarn("QUICKCHECK ONLY; FILESYSTEM CLEAN\n");
563 goto ExitThisRoutine
;
564 } else if (result
== R_Dirty
) {
565 pwarn("QUICKCHECK ONLY; FILESYSTEM DIRTY\n");
567 goto ExitThisRoutine
;
568 } else if (result
== R_BadSig
) {
569 pwarn("QUICKCHECK ONLY; NO HFS SIGNATURE FOUND\n");
571 goto ExitThisRoutine
;
574 goto ExitThisRoutine
;
578 struct statfs stfs_buf
;
581 * Check to see if root is mounted read-write.
583 if (statfs(mntonname
, &stfs_buf
) == 0)
584 flags
= stfs_buf
.f_flags
;
587 ckfini(flags
& MNT_RDONLY
);
590 /* XXX free any allocated memory here */
592 if (hotmount
&& fsmodified
) {
593 struct hfs_mount_args args
;
595 * We modified the root. Do a mount update on
596 * it, unless it is read-write, so we can continue.
599 fsckPrint(context
, fsckVolumeModified
);
600 if (flags
& MNT_RDONLY
) {
601 bzero(&args
, sizeof(args
));
602 flags
|= MNT_UPDATE
| MNT_RELOAD
;
604 fprintf(stderr
, "doing update / reload mount for %s now\n", mntonname
);
605 if (mount("hfs", mntonname
, flags
, &args
) == 0) {
608 goto ExitThisRoutine
;
611 fprintf(stderr
, "update/reload mount for %s failed: %s\n", mntonname
, strerror(errno
));
615 plog("\n***** REBOOT NOW *****\n");
617 result
= FIXEDROOTEXIT
;
618 goto ExitThisRoutine
;
621 if (result
!= 0 && result
!= MAJOREXIT
)
627 fcntl(fs_fd
, F_THAW_FS
, NULL
);
636 fsckDestroy(context
);
643 * Setup for I/O to device
644 * Return 1 if successful, 0 if unsuccessful.
645 * canWrite - 1 if we can safely write to the raw device or 0 if not.
648 setup( char *dev
, int *canWritePtr
)
652 uint32_t cacheBlockSize
;
653 uint32_t cacheTotalBlocks
;
661 if (stat(dev
, &statb
) < 0) {
662 plog("Can't stat %s: %s\n", dev
, strerror(errno
));
665 if ((statb
.st_mode
& S_IFMT
) != S_IFCHR
) {
666 pfatal("%s is not a character device", dev
);
667 if (reply("CONTINUE") == 0)
670 /* Always attempt to replay the journal */
671 if (!nflag
&& !quick
) {
672 // We know we have a character device by now.
673 if (strncmp(dev
, "/dev/rdisk", 10) == 0) {
674 char block_device
[MAXPATHLEN
+1];
676 snprintf(block_device
, sizeof(block_device
), "/dev/%s", dev
+ 6);
677 rv
= journal_replay(block_device
);
679 plog("journal_replay(%s) returned %d\n", block_device
, rv
);
682 /* attempt to get write access to the block device and if not check if volume is */
683 /* mounted read-only. */
684 if (nflag
== 0 && quick
== 0) {
685 getWriteAccess( dev
, canWritePtr
);
688 if (nflag
|| quick
|| (fswritefd
= open(dev
, O_RDWR
| (hotmount
? 0 : O_EXLOCK
))) < 0) {
691 pfatal("** %s (NO WRITE ACCESS)\n", dev
);
694 } else { // detonator run
695 plog("fsck_hfs: detonator_run (%s).\n", dev
);
697 fswritefd
= (int)strtol(dev
+8, &end_ptr
, 10);
700 err(1, "fsck_hfs: Invalid file descriptor path: %s", dev
);
704 int error
= fstat(fswritefd
, &info
);
707 err(1, "fsck_hfs: fstat %s", dev
);
710 error
= (int)lseek(fswritefd
, 0, SEEK_SET
);
713 err(1, "fsck_hfs: Could not seek %d for dev: %s, errorno %d", fswritefd
, dev
, errno
);
719 if (preen
== 0 && !guiControl
) {
720 if (nflag
|| quick
|| fswritefd
== -1) {
721 plog("** %s (NO WRITE)\n", dev
);
723 plog("** %s\n", dev
);
727 if (fswritefd
== -1) {
728 if ((fsreadfd
= open(dev
, O_RDONLY
)) < 0) {
729 plog("Can't open %s: %s\n", dev
, strerror(errno
));
733 fsreadfd
= dup(fswritefd
);
735 plog("Can't dup fd for reading on %s: %s\n", dev
, strerror(errno
));
741 /* Get device block size to initialize cache */
742 if (ioctl(fsreadfd
, DKIOCGETBLOCKSIZE
, &devBlockSize
) < 0) {
743 pfatal ("Can't get device block size\n");
748 * Calculate the cache block size and total blocks.
750 * If a quick check was requested, we'll only be checking to see if
751 * the volume was cleanly unmounted or journalled, so we won't need
752 * a lot of cache. Since lots of quick checks can be run in parallel
753 * when a new disk with several partitions comes on line, let's avoid
754 * the memory usage when we don't need it.
756 if (reqCacheSize
== 0 && quick
== 0) {
758 * Auto-pick the cache size. The cache code will deal with minimum
759 * maximum values, so we just need to find out the size of memory, and
760 * how much of it we'll use.
762 * If we're looking at the root device, and it's not a live verify (lflag),
763 * then we will use half of physical memory; otherwise, we'll use an eigth.
767 size_t dsize
= sizeof(memSize
);
770 rv
= sysctlbyname("hw.memsize", &memSize
, &dsize
, NULL
, 0);
772 (void)fplog(stderr
, "sysctlbyname failed, not auto-setting cache size\n");
774 int d
= (hotroot
&& !lflag
) ? 2 : 8;
775 if (!detonator_run
) {
777 dsize
= sizeof(safeMode
);
778 rv
= sysctlbyname("kern.safeboot", &safeMode
, &dsize
, NULL
, 0);
779 if (rv
!= -1 && safeMode
!= 0 && hotroot
&& !lflag
) {
780 #define kMaxSafeModeMem ((size_t)2 * 1024 * 1024 * 1024) /* 2Gbytes, means cache will max out at 1gbyte */
782 (void)fplog(stderr
, "Safe mode and single-user, setting memsize to a maximum of 2gbytes\n");
784 memSize
= (memSize
< kMaxSafeModeMem
) ? memSize
: kMaxSafeModeMem
;
787 reqCacheSize
= memSize
/ d
;
791 CalculateCacheSizes(reqCacheSize
, &cacheBlockSize
, &cacheTotalBlocks
, debug
);
793 preTouchMem
= (hotroot
!= 0) && (lflag
!= 0);
794 /* Initialize the cache */
795 if (CacheInit (&fscache
, fsreadfd
, fswritefd
, devBlockSize
,
796 cacheBlockSize
, cacheTotalBlocks
, CacheHashSize
, preTouchMem
) != EOK
) {
797 pfatal("Can't initialize disk cache\n");
806 // This routine will attempt to open the block device with write access for the target
807 // volume in order to block others from mounting the volume with write access while we
808 // check / repair it. If we cannot get write access then we check to see if the volume
809 // has been mounted read-only. If it is read-only then we should be OK to write to
810 // the raw device. Note that this does not protect use from someone upgrading the mount
811 // from read-only to read-write.
813 static void getWriteAccess( char *dev
, int *canWritePtr
)
819 struct statfs
* myBufPtr
;
821 int blockDevice_fd
= -1;
824 myNamePtr
= malloc( strlen(dev
) + 2 );
825 if ( myNamePtr
== NULL
)
828 strcpy( (char *)myNamePtr
, dev
);
829 if ( (myCharPtr
= strrchr( (char *)myNamePtr
, '/' )) != 0 ) {
830 if ( myCharPtr
[1] == 'r' ) {
831 memmove(&myCharPtr
[1], &myCharPtr
[2], strlen(&myCharPtr
[2]) + 1);
832 blockDevice_fd
= open( (char *)myNamePtr
, O_WRONLY
| (hotmount
? 0 : O_EXLOCK
) );
836 if ( blockDevice_fd
> 0 ) {
837 // we got write access to the block device so we can safely write to raw device
839 goto ExitThisRoutine
;
842 // get count of mounts then get the info for each
843 myMountsCount
= getfsstat( NULL
, 0, MNT_NOWAIT
);
844 if ( myMountsCount
< 0 )
845 goto ExitThisRoutine
;
847 myPtr
= (void *) malloc( sizeof(struct statfs
) * myMountsCount
);
849 goto ExitThisRoutine
;
850 myMountsCount
= getfsstat( myPtr
,
851 (int)(sizeof(struct statfs
) * myMountsCount
),
853 if ( myMountsCount
< 0 )
854 goto ExitThisRoutine
;
856 myBufPtr
= (struct statfs
*) myPtr
;
857 for ( i
= 0; i
< myMountsCount
; i
++ )
859 if ( strcmp( myBufPtr
->f_mntfromname
, myNamePtr
) == 0 ) {
860 if ( myBufPtr
->f_flags
& MNT_RDONLY
)
862 goto ExitThisRoutine
;
866 *canWritePtr
= 1; // single user will get us here, f_mntfromname is not /dev/diskXXXX
872 if ( myNamePtr
!= NULL
)
875 if (blockDevice_fd
!= -1) {
876 close(blockDevice_fd
);
881 } /* getWriteAccess */
887 (void) fplog(stderr
, "usage: %s [-b [size] B [path] c [size] e [mode] ESdfglx m [mode] npqruy] special-device\n", progname
);
888 (void) fplog(stderr
, " b size = size of physical blocks (in bytes) for -B option\n");
889 (void) fplog(stderr
, " B path = file containing physical block numbers to map to paths\n");
890 (void) fplog(stderr
, " c size = cache size (ex. 512m, 1g)\n");
891 (void) fplog(stderr
, " e mode = emulate 'embedded' or 'desktop'\n");
892 (void) fplog(stderr
, " E = exit on first major error\n");
893 (void) fplog(stderr
, " d = output debugging info\n");
894 (void) fplog(stderr
, " f = force fsck even if clean (preen only) \n");
895 (void) fplog(stderr
, " g = GUI output mode\n");
896 (void) fplog(stderr
, " x = XML output mode\n");
897 (void) fplog(stderr
, " l = live fsck (lock down and test-only)\n");
898 (void) fplog(stderr
, " m arg = octal mode used when creating lost+found directory \n");
899 (void) fplog(stderr
, " n = assume a no response \n");
900 (void) fplog(stderr
, " p = just fix normal inconsistencies \n");
901 (void) fplog(stderr
, " q = quick check returns clean, dirty, or failure \n");
902 (void) fplog(stderr
, " r = rebuild catalog btree \n");
903 (void) fplog(stderr
, " S = Scan disk for bad blocks\n");
904 (void) fplog(stderr
, " u = usage \n");
905 (void) fplog(stderr
, " y = assume a yes response \n");
912 AddBlockToList(long long block
)
915 if ((gBlkListEntries
% BLOCK_LIST_INCREMENT
) == 0) {
918 // gBlkListEntries += BLOCK_LIST_INCREMENT;
919 tmp
= realloc(gBlockList
, (gBlkListEntries
+ BLOCK_LIST_INCREMENT
) * sizeof(u_int64_t
));
921 pfatal("Can't allocate memory for block list (%llu entries).\n", gBlkListEntries
);
923 gBlockList
= (u_int64_t
*)tmp
;
925 gBlockList
[gBlkListEntries
++] = block
;
929 static int printStatus
;
939 uint32_t devBlockSize
= 512;
940 uint64_t devBlockTotal
;
942 uint8_t *buffer
= NULL
;
943 size_t bufSize
= 1024 * 1024;
946 void (*oldhandler
)(int);
947 uint32_t numErrors
= 0;
948 uint32_t maxErrors
= 40; // Something more variable?
950 oldhandler
= signal(SIGINFO
, &siginfo
);
955 fprintf(stderr, "Scanning offset %lld of %lld (%d%%)\n", \
956 curPos, diskSize, (int)((curPos * 100) / diskSize)); \
958 fprintf(stderr, "Scanning offset %lld\n", curPos); \
963 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, &devBlockSize
) == -1) {
967 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, &devBlockTotal
) == -1) {
970 diskSize
= devBlockTotal
* devBlockSize
;
972 while (buffer
== NULL
&& bufSize
>= devBlockSize
) {
973 buffer
= malloc(bufSize
);
974 if (buffer
== NULL
) {
978 if (buffer
== NULL
) {
979 pfatal("Cannot allocate buffer for disk scan.\n");
987 while ((nread
= pread(fd
, buffer
, bufSize
, curPos
)) == bufSize
) {
995 /* We're done with the disk */
1000 /* Try reading devBlockSize blocks */
1002 for (total
= 0; total
< bufSize
; total
+= devBlockSize
) {
1003 nread
= pread(fd
, buffer
, devBlockSize
, curPos
+ total
);
1007 fprintf(stderr
, "Bad block at offset %lld\n", curPos
+ total
);
1008 AddBlockToList((curPos
+ total
) / gBlockSize
);
1009 if (++numErrors
> maxErrors
) {
1011 fprintf(stderr
, "Got %u errors, maxing out so stopping scan\n", numErrors
);
1016 pfatal("Got a non I/O error reading disk at offset %llu: %s\n",
1017 curPos
+ total
, strerror(errno
));
1018 // Hey, pfatal wasn't fatal!
1019 // But that seems to work out for us for some reason.
1023 /* End of disk, somehow. */
1026 if (nread
!= devBlockSize
) {
1027 pwarn("During disk scan, did not get block size (%zd) read, got %zd instead. Skipping rest of this block.\n", (size_t)devBlockSize
, nread
);
1033 } else if (errno
== EINTR
) {
1036 pfatal("Got a non I/O error reading disk at offset %llu: %s\n", curPos
, strerror(errno
));
1040 if (nread
< bufSize
) {
1041 if ((nread
% devBlockSize
) == 0) {
1044 curPos
= curPos
+ (((nread
% devBlockSize
) + 1) * devBlockSize
);
1052 signal(SIGINFO
, oldhandler
);
1058 getblocklist(const char *filepath
)
1062 size_t blockListCount
; /* Number of elements allocated to gBlockList array */
1064 blockListCount
= BLOCK_LIST_INCREMENT
;
1065 gBlockList
= (u_int64_t
*) malloc(blockListCount
* sizeof(u_int64_t
));
1066 if (gBlockList
== NULL
)
1067 pfatal("Can't allocate memory for block list.\n");
1069 // printf("getblocklist: processing blocklist %s...\n", filepath);
1071 if ((file
= fopen(filepath
, "r")) == NULL
)
1072 pfatal("Can't open %s\n", filepath
);
1074 while (fscanf(file
, "%lli", &block
) > 0) {
1075 AddBlockToList(block
);
1078 (void) fclose(file
);
1080 printf("%d blocks to match:\n", gBlkListEntries
);