]> git.saurik.com Git - apple/hfs.git/commitdiff
hfs-285.tar.gz os-x-1010 os-x-10101 os-x-10102 os-x-10103 os-x-10104 os-x-10105 v285
authorApple <opensource@apple.com>
Fri, 24 Oct 2014 18:05:37 +0000 (18:05 +0000)
committerApple <opensource@apple.com>
Fri, 24 Oct 2014 18:05:37 +0000 (18:05 +0000)
28 files changed:
CopyHFSMeta/CopyHFSMeta.entitlements [new file with mode: 0644]
CopyHFSMeta/Data.h
CopyHFSMeta/ScanExtents.c
CopyHFSMeta/SparseBundle.c
CopyHFSMeta/hfsmeta.h
CopyHFSMeta/main.c
CopyHFSMeta/misc.c
CopyHFSMeta/util.c [new file with mode: 0644]
fsck_hfs/cache.c
fsck_hfs/dfalib/SControl.c
fsck_hfs/dfalib/SUtils.c
fsck_hfs/dfalib/fsck_journal.c
fsck_hfs/fsck_hfs.entitlements [new file with mode: 0644]
fsck_hfs/fsck_hfs.h
fsck_hfs/utilities.c
fstyp_hfs/fstyp_hfs.entitlements [new file with mode: 0644]
hfs.xcodeproj/project.pbxproj
hfs_util/hfs_util.entitlements [new file with mode: 0644]
hfs_util/hfsutil_jnl.c
hfs_util/hfsutil_main.c
libhfs_metadata/iterate_hfs_metadata.c [new file with mode: 0644]
libhfs_metadata/iterate_hfs_metadata.h [new file with mode: 0644]
mount_hfs/mount_hfs.c
mount_hfs/mount_hfs.entitlements [new file with mode: 0644]
newfs_hfs/makehfs.c
newfs_hfs/newfs_hfs.c
newfs_hfs/newfs_hfs.entitlements [new file with mode: 0644]
newfs_hfs/newfs_hfs.h

diff --git a/CopyHFSMeta/CopyHFSMeta.entitlements b/CopyHFSMeta/CopyHFSMeta.entitlements
new file mode 100644 (file)
index 0000000..1f58459
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.private.security.disk-device-access</key>
+       <true/>
+</dict>
+</plist>
index 6f183bfab35c7c2c0ac16fe8869e5da8edae0816..a6dc8c67232784972b56109bb92af5cad8f87570 100644 (file)
@@ -1,6 +1,27 @@
 #ifndef _DATA_H
 # define _DATA_H
 
+# include <errno.h>
+/*
+ * Exit status values.  We use some errno values because
+ * they are convenient.
+ * kGoodExit:  we finished copying, and no problems.
+ * kNoSpaceExit:  Not enough space for the skeleton copy.
+ * kCopyIOExit:  An I/O error occurred.  This may not be fatal,
+ *     as it may just mean the source device went away.  We
+ *     can continue later, perhaps.
+ * kIntrExit:  The copying was interrupted.  As above, this may
+ *     not be fatal.
+ * kBadExit:  Any other problem.
+ */
+enum {
+       kGoodExit = 0,
+       kNoSpaceExit = ENOSPC,
+       kCopyIOExit = EIO,
+       kIntrExit = EINTR,
+       kBadExit = 1,
+};
+
 /*
  * Data-manipulating functions and structures, used to
  * create the skeleton copy.
@@ -16,6 +37,7 @@ struct IOWrapper;
 struct Extents {
        off_t base;
        off_t length;
+       unsigned int fid;       // Optional, may not be set
 };
 typedef struct Extents Extents_t;
 
@@ -31,7 +53,6 @@ struct ExtentList {
        struct ExtentList *next;
 };
 typedef struct ExtentList ExtentList_t;
-
 /*
  * The in-core description of the volume:  an input source,
  * a description of the volume, the linked list of extents,
@@ -47,11 +68,25 @@ struct VolumeObjects {
 };
 typedef struct VolumeObjects VolumeObjects_t;
 
+typedef int (^extent_handler_t)(int fid, off_t start, off_t len);
+
 extern VolumeObjects_t *InitVolumeObject(struct DeviceInfo *devp, struct VolumeDescriptor *vdp);
 extern int AddExtent(VolumeObjects_t *vop, off_t start, off_t length);
+extern int AddExtentForFile(VolumeObjects_t *vop, off_t start, off_t length, unsigned int fid);
 extern void PrintVolumeObject(VolumeObjects_t*);
 extern int CopyObjectsToDest(VolumeObjects_t*, struct IOWrapper *wrapper, off_t skip);
 
 extern void WriteGatheredData(const char *, VolumeObjects_t*);
 
+extern struct DeviceInfo *OpenDevice(const char *, int);
+extern struct VolumeDescriptor *VolumeInfo(struct DeviceInfo *);
+extern int AddHeaders(VolumeObjects_t *, int);
+extern void AddJournal(VolumeObjects_t *);
+extern void AddFileExtents(VolumeObjects_t *);
+extern int FindOtherMetadata(VolumeObjects_t *, extent_handler_t);
+extern int CompareVolumeHeaders(struct VolumeDescriptor*);
+
+void ReleaseDeviceInfo(struct DeviceInfo *);
+void ReleaseVolumeDescriptor(struct VolumeDescriptor*);
+void ReleaseVolumeObjects(VolumeObjects_t *);
 #endif /* _DATA_H */
index 5910e4a3898f0032f23100945b0d3f3d68e4f38f..470a699dbadabd5e1d2567e6d2ff550394ad5f52 100644 (file)
@@ -166,7 +166,7 @@ ScanNode(VolumeObjects_t *vop, uint8_t *nodePtr, size_t nodeSize, off_t blockSiz
                                off_t start = S32((*datap)[i].startBlock) * (off_t)blockSize;
                                off_t len = S32((*datap)[i].blockCount) * (off_t)blockSize;
                                if (start && len)
-                                       AddExtent(vop, start, len);
+                                       AddExtentForFile(vop, start, len, S32(keyp->fileID));
                        }
                }
        }
@@ -179,6 +179,7 @@ ScanNode(VolumeObjects_t *vop, uint8_t *nodePtr, size_t nodeSize, off_t blockSiz
  * looking for system-file extents (those with a CNID < 16).  If useAltHdr
  * is set, it'll use the extents overflow descriptor in the alternate header.
  */
+__private_extern__
 int
 ScanExtents(VolumeObjects_t *vop, int useAltHdr)
 {
index a7c5668ecf1f3b8d872158e6495c5583df20e359..455903eebec2fbf7b7c2e7003a393de4145f0e59 100644 (file)
  * no encryption.
  */
 
-#define MIN(a, b) \
+#ifndef MIN
+# define MIN(a, b) \
        ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \
                __a < __b ? __a : __b; })
+#endif
 
 /*
  * Context for the sparse bundle routines.  The path name,
@@ -61,45 +63,6 @@ static const char *bundlePrototype =
 "</dict>\n"
        "</plist>\n";
 
-/*
- * Perform a (potentially) unaligned read from a given input device.
- */
-static ssize_t
-UnalignedRead(DeviceInfo_t *devp, void *buffer, size_t size, off_t offset)
-{
-       ssize_t nread = -1;
-       size_t readSize = ((size + devp->blockSize - 1) / devp->blockSize) * devp->blockSize;
-       off_t baseOffset = (offset / devp->blockSize) * devp->blockSize;
-       size_t off = offset - baseOffset;
-       char *tmpbuf = NULL;
-       
-       if ((baseOffset == offset) && (readSize == size)) {
-               /*
-                * The read is already properly aligned, so call pread.
-                */
-               return pread(devp->fd, buffer, size, offset);
-       }
-       
-       tmpbuf = malloc(readSize);
-       if (!tmpbuf) {
-               goto done;
-       }
-       
-       nread = pread(devp->fd, tmpbuf, readSize, baseOffset);
-       if (nread == -1) {
-               goto done;
-       }
-       
-       nread -= off;
-       if (nread > (ssize_t)size) {
-               nread = size;
-       }
-       memcpy(buffer, tmpbuf + off, nread);
-       
-done:
-       free(tmpbuf);
-       return nread;
-}
 
 /*
  * Read from a sparse bundle.  If the band file doesn't exist, or is shorter than
index 52d954045cfd56356f49e48fc5bbb993ee606ec4..7485c498f96afe83eec90316da2d2c798494eb4f 100644 (file)
@@ -63,6 +63,8 @@ struct IOWrapper {
 };
 typedef struct IOWrapper IOWrapper_t;
 
+extern ssize_t UnalignedRead(DeviceInfo_t *, void *, size_t, off_t);
+
 extern int debug, verbose, printProgress;
 
 #endif /* _HFS_META_H */
index 2c5b69b30a7ce48f736ec59afc5b68e6270dc24e..d562d7f44737abcf51a6fd02bc954ebfe626ce93 100644 (file)
@@ -9,6 +9,7 @@
 #include <sys/disk.h>
 #include <sys/sysctl.h>
 #include <hfs/hfs_mount.h>
+#include <Block.h>
 #include "hfsmeta.h"
 #include "Data.h"
 #include "Sparse.h"
@@ -27,166 +28,16 @@ int verbose;
 int debug;
 int printProgress;
 
-/*
- * Exit status values.  We use some errno values because
- * they are convenient.
- * kGoodExit:  we finished copying, and no problems.
- * kNoSpaceExit:  Not enough space for the skeleton copy.
- * kCopyIOExit:  An I/O error occurred.  This may not be fatal,
- *     as it may just mean the source device went away.  We
- *     can continue later, perhaps.
- * kIntrExit:  The copying was interrupted.  As above, this may
- *     not be fatal.
- * kBadExit:  Any other problem.
- */
-enum {
-       kGoodExit = 0,
-       kNoSpaceExit = ENOSPC,
-       kCopyIOExit = EIO,
-       kIntrExit = EINTR,
-       kBadExit = 1,
-};
-
-/*
- * Open the source device.  In addition to opening the device,
- * this also attempts to flush the journal, and then sets up a
- * DeviceInfo_t object that will be used when doing the actual
- * reading.
- */
-static DeviceInfo_t *
-OpenDevice(const char *devname)
-{
-       char *rawname;
-       DeviceInfo_t *retval = NULL;
-       int fd;
-       DeviceInfo_t dev = { 0 };
-       struct stat sb;
-       struct vfsconf vfc;
-
-       if (stat(devname, &sb) == -1) {
-               err(kBadExit, "cannot open device %s", devname);
-       }
-       /*
-        * Attempt to flush the journal.  If it fails, we just warn, but don't abort.
-        */
-       if (getvfsbyname("hfs", &vfc) == 0) {
-               int rv;
-               int mib[4];
-               char block_device[MAXPATHLEN+1];
-               int jfd;
-
-               /*
-                * The journal replay code, sadly, requires a block device.
-                * So we need to go from the raw device to block device, if
-                * necessary.
-                */
-               if (strncmp(devname, "/dev/rdisk", 10) == 0) {
-                       snprintf(block_device, sizeof(block_device), "/dev/%s", devname+6);
-               } else {
-                       snprintf(block_device, sizeof(block_device), "%s", devname);
-               }
-               jfd = open(block_device, O_RDWR);
-               if (jfd == -1) {
-                       warn("Cannot open block device %s for read-write", block_device);
-               } else {
-                       mib[0] = CTL_VFS;
-                       mib[1] = vfc.vfc_typenum;
-                       mib[2] = HFS_REPLAY_JOURNAL;
-                       mib[3] = jfd;
-                       if (debug)
-                               fprintf(stderr, "about to replay journal\n");
-                       rv = sysctl(mib, 4, NULL, NULL, NULL, 0);
-                       if (rv == -1) {
-                               warn("cannot replay journal");
-                       }
-                       /* This is probably not necessary, but we couldn't prove it. */
-                       (void)fcntl(jfd, F_FULLFSYNC, 0);
-                       close(jfd);
-               }
-       }
-       /*
-        * We only allow a character device (e.g., /dev/rdisk1s2)
-        * If we're given a non-character device, we'll try to turn
-        * into a character device assuming a name pattern of /dev/rdisk*
-        */
-       if ((sb.st_mode & S_IFMT) == S_IFCHR) {
-               dev.devname = strdup(devname);
-       } else if (strncmp(devname, "/dev/disk", 9) == 0) {
-               // Turn "/dev/diskFoo" into "/dev/rdiskFoo"
-               char tmpname[strlen(devname) + 2];
-               (void)snprintf(tmpname, sizeof(tmpname), "/dev/rdisk%s", devname + sizeof("/dev/disk") - 1);
-               if (stat(tmpname, &sb) == -1) {
-                       err(kBadExit, "cannot open raw device %s", tmpname);
-               }
-               if ((sb.st_mode & S_IFMT) != S_IFCHR) {
-                       errx(kBadExit, "raw device %s is not a raw device", tmpname);
-               }
-               dev.devname = strdup(tmpname);
-       } else {
-               errx(kBadExit, "device name `%s' does not fit pattern", devname);
-       }
-       // Only use an exclusive open if we're not debugging.
-       fd = open(dev.devname, O_RDONLY | (debug ? 0 : O_EXLOCK));
-       if (fd == -1) {
-               err(kBadExit, "cannot open raw device %s", dev.devname);
-       }
-       // Get the block size and counts for the device.
-       if (ioctl(fd, DKIOCGETBLOCKSIZE, &dev.blockSize) == -1) {
-               dev.blockSize = 512;    // Sane default, I hope
-       }
-       if (ioctl(fd, DKIOCGETBLOCKCOUNT, &dev.blockCount) == -1) {
-               err(kBadExit, "cannot get size of device %s", dev.devname);
-       }
-
-       dev.size = dev.blockCount * dev.blockSize;
-       dev.fd = fd;
-
-       retval = malloc(sizeof(*retval));
-       if (retval == NULL) {
-               err(kBadExit, "cannot allocate device info structure");
-       }
-       *retval = dev;
-       return retval;
-}
-
-/*
- * Get the header and alternate header for a device.
- */
-VolumeDescriptor_t *
-VolumeInfo(DeviceInfo_t *devp)
-{
-       uint8_t buffer[devp->blockSize];
-       VolumeDescriptor_t *vdp = NULL, vd = { 0 };
-       ssize_t rv;
-
-       vd.priOffset = 1024;    // primary volume header is at 1024 bytes
-       vd.altOffset = devp->size - 1024;       // alternate header is 1024 bytes from the end
-
-       rv = GetBlock(devp, vd.priOffset, buffer);
-       if (rv == -1) {
-               err(kBadExit, "cannot get primary volume header for device %s", devp->devname);
-       }
-       vd.priHeader = *(HFSPlusVolumeHeader*)buffer;
-
-       rv = GetBlock(devp, vd.altOffset, buffer);
-       if (rv == -1) {
-               err(kBadExit, "cannot get alternate volume header for device %s", devp->devname);
-       }
-       vd.altHeader = *(HFSPlusVolumeHeader*)buffer;
-
-       vdp = malloc(sizeof(*vdp));
-       *vdp = vd;
-
-       return vdp;
-}
 
 /*
  * Compare two volume headers to see if they're the same.  Some fields
  * we may not care about, so we only compare specific fields.  Note that
  * since we're looking for equality, we don't need to byte swap.
+ * (The function CompareVolumeHeaders() will compare the two volume
+ * headers to see if the extents they describe are the same.)
  */
-int
-CompareVolumeHeaders(HFSPlusVolumeHeader *left, HFSPlusVolumeHeader *right)
+static int
+CheckVolumeHeaders(HFSPlusVolumeHeader *left, HFSPlusVolumeHeader *right)
 {
        if (left->signature != right->signature ||
            left->version != right->version ||
@@ -200,144 +51,11 @@ CompareVolumeHeaders(HFSPlusVolumeHeader *left, HFSPlusVolumeHeader *right)
        return 1;
 }
 
-/*
- * Only two (currently) types of signatures are valid: H+ and HX.
- */
-static int
-IsValidSigWord(uint16_t word) {
-       if (word == kHFSPlusSigWord ||
-           word == kHFSXSigWord)
-               return 1;
-       return 0;
-}
-
-/*
- * Add the volume headers to the in-core volume information list.
- */
-int
-AddHeaders(VolumeObjects_t *vop)
-{
-       int retval = 1;
-       HFSPlusVolumeHeader *hp;
-       uint8_t buffer[vop->devp->blockSize];
-       ssize_t rv;
-
-       hp = &vop->vdp->priHeader;
-
-       if (IsValidSigWord(S16(hp->signature)) == 0) {
-               warnx("primary volume header signature = %x, invalid", S16(hp->signature));
-               retval = 0;
-       }
-       AddExtent(vop, 1024, 512);
-
-       hp = &vop->vdp->altHeader;
-
-       if (IsValidSigWord(S16(hp->signature)) == 0) {
-               warnx("alternate volume header signature = %x, invalid", S16(hp->signature));
-               retval = 0;
-       }
-       AddExtent(vop, vop->vdp->altOffset, 512);
-
-done:
-       return retval;
-}
-
-/*
- * Add the journal information to the in-core volume list.
- * This means the journal info block, the journal itself, and
- * the contents of the same as described by the alternate volume
- * header (if it's different from the primary volume header).
- */
-void
-AddJournal(VolumeObjects_t *vop)
-{
-       DeviceInfo_t *devp = vop->devp;
-       uint8_t buffer[devp->blockSize];
-       ssize_t rv;
-       HFSPlusVolumeHeader *php, *ahp;
-       JournalInfoBlock *jib;
-
-       php = &vop->vdp->priHeader;
-       ahp = &vop->vdp->altHeader;
-
-       if (php->journalInfoBlock) {
-               off_t jOffset = (off_t)S32(php->journalInfoBlock) * S32(php->blockSize);
-               rv = GetBlock(devp, jOffset, buffer);
-               if (rv == -1) {
-                       err(kBadExit, "cannot get primary header's copy of journal info block");
-               }
-               AddExtent(vop, jOffset, sizeof(buffer));
-               jib = (JournalInfoBlock*)buffer;
-               if (S32(jib->flags) & kJIJournalInFSMask) {
-                       AddExtent(vop, S64(jib->offset), S64(jib->size));
-               }
-       }
-
-       if (ahp->journalInfoBlock &&
-           ahp->journalInfoBlock != php->journalInfoBlock) {
-               off_t jOffset = (off_t)S32(ahp->journalInfoBlock) * S32(ahp->blockSize);
-               rv = GetBlock(devp, jOffset, buffer);
-               if (rv == -1) {
-                       err(kBadExit, "cannot get alternate header's copy of journal info block");
-               }
-               AddExtent(vop, jOffset, sizeof(buffer));
-               jib = (JournalInfoBlock*)buffer;
-               if (S32(jib->flags) & kJIJournalInFSMask) {
-                       AddExtent(vop, S64(jib->offset), S64(jib->size));
-               }
-       }
-
-}
-
-/*
- * Add the extents for the special files in the volume header.  Compare
- * them with the alternate volume header's versions, and if they're different,
- * add that as well.
- */
-void
-AddFileExtents(VolumeObjects_t *vop)
-{
-       int useAlt = 0;
-#define ADDEXTS(vop, file) \
-       do { \
-               off_t pSize = S32(vop->vdp->priHeader.blockSize);       \
-               off_t aSize = S32(vop->vdp->altHeader.blockSize);       \
-               int i;                                                  \
-               if (debug) printf("Adding " #file " extents\n");                \
-               for (i = 0; i < kHFSPlusExtentDensity; i++) {           \
-                       HFSPlusExtentDescriptor *ep = &vop->vdp->priHeader. file .extents[i]; \
-                       HFSPlusExtentDescriptor *ap = &vop->vdp->altHeader. file .extents[i]; \
-                       if (debug) printf("\tExtent <%u, %u>\n", S32(ep->startBlock), S32(ep->blockCount)); \
-                       if (ep->startBlock && ep->blockCount) {         \
-                               AddExtent(vop, S32(ep->startBlock) * pSize, S32(ep->blockCount) * pSize); \
-                               if (memcmp(ep, ap, sizeof(*ep)) != 0) { \
-                                       AddExtent(vop, S32(ap->startBlock) * aSize, S32(ap->blockCount) * aSize); \
-                                       useAlt = 1;                     \
-                               }                                       \
-                       }                                               \
-               }                                                       \
-       } while (0)
-
-       ADDEXTS(vop, allocationFile);
-       ADDEXTS(vop, extentsFile);
-       ADDEXTS(vop, catalogFile);
-       ADDEXTS(vop, attributesFile);
-       ADDEXTS(vop, startupFile);
-
-#undef ADDEXTS
-
-       ScanExtents(vop, 0);
-       if (useAlt)
-               ScanExtents(vop, useAlt);
-
-       return;
-}
-
 static void
 usage(const char *progname)
 {
 
-       errx(kBadExit, "usage: %s [-vdpS] [-g gatherFile] [-r <bytes>] <src device> <destination>", progname);
+       errx(kBadExit, "usage: %s [-vdpS] [-g gatherFile] [-C] [-r <bytes>] <src device> <destination>", progname);
 }
 
 
@@ -356,9 +74,11 @@ main(int ac, char **av)
        char *gather = NULL;
        int force = 0;
        int retval = kGoodExit;
+       int find_all_metadata = 0;
 
-       while ((ch = getopt(ac, av, "fvdg:Spr:")) != -1) {
+       while ((ch = getopt(ac, av, "fvdg:Spr:CA")) != -1) {
                switch (ch) {
+               case 'A':       find_all_metadata = 1; break;
                case 'v':       verbose++; break;
                case 'd':       debug++; verbose++; break;
                case 'S':       printEstimate = 1; break;
@@ -381,7 +101,7 @@ main(int ac, char **av)
                dst = av[1];
 
        // Start by opening the input device
-       devp = OpenDevice(src);
+       devp = OpenDevice(src, 1);
        if (devp == NULL) {
                errx(kBadExit, "cannot get device information for %s", src);
        }
@@ -393,13 +113,25 @@ main(int ac, char **av)
        vop = InitVolumeObject(devp, vdp);
 
        // Add the volume headers
-       if (AddHeaders(vop) == 0) {
+       if (AddHeaders(vop, 0) == 0) {
                errx(kBadExit, "Invalid volume header(s) for %s", src);
        }
        // Add the journal and file extents
        AddJournal(vop);
        AddFileExtents(vop);
 
+       /*
+        * find_all_metadata requires scanning through
+        * the catalog and attributes files, looking for
+        * other bits treated as metadata.
+        */
+       if (find_all_metadata)
+               FindOtherMetadata(vop, ^(int fid, off_t start, off_t len) {
+                               AddExtentForFile(vop, start, len, fid);
+//                             fprintf(stderr, "AddExtentForFile(%p, %llu, %llu, %u)\n", vop, start, len, fid);
+                               return 0;
+                       });
+
        if (debug)
                PrintVolumeObject(vop);
 
@@ -446,11 +178,11 @@ main(int ac, char **av)
                        HFSPlusVolumeHeader priHeader, altHeader;
 
                        if (wrapper->reader(wrapper, 1024, &priHeader, sizeof(priHeader)) != -1) {
-                               if (CompareVolumeHeaders(&priHeader, &vop->vdp->priHeader) == 0) {
+                               if (CheckVolumeHeaders(&priHeader, &vop->vdp->priHeader) == 0) {
                                        restart = 0;
                                } else {
                                        if (wrapper->reader(wrapper, vop->vdp->altOffset, &altHeader, sizeof(altHeader)) != -1) {
-                                               if (CompareVolumeHeaders(&altHeader, &vop->vdp->altHeader) == 0) {
+                                               if (CheckVolumeHeaders(&altHeader, &vop->vdp->altHeader) == 0) {
                                                        restart = 0;
                                                }
                                        }
index c0c870f4be0a1cbb0b24e2f56f1dc77fee709d07..f79b8d2ad3a704fb2f8605532d1baeda49931974 100644 (file)
@@ -18,6 +18,7 @@
 /*
  * Get a block from a given input device.
  */
+__private_extern__
 ssize_t
 GetBlock(DeviceInfo_t *devp, off_t offset, uint8_t *buffer)
 {
@@ -40,6 +41,7 @@ done:
 /*
  * Initialize a VolumeObject.  Simple function.
  */
+__private_extern__
 VolumeObjects_t *
 InitVolumeObject(struct DeviceInfo *devp, struct VolumeDescriptor *vdp)
 {
@@ -67,19 +69,28 @@ done:
  * number of objects we allocate, while still trying to keep
  * the waste memory allocation low.
  */
+__private_extern__
 int
 AddExtent(VolumeObjects_t *vdp, off_t start, off_t length)
+{
+       return AddExtentForFile(vdp, start, length, 0);
+}
+
+__private_extern__
+int
+AddExtentForFile(VolumeObjects_t *vdp, off_t start, off_t length, unsigned int fid)
 {
        int retval = 0;
        size_t indx;
        ExtentList_t **ep = &vdp->list;
 
-       if (debug) printf("AddExtent(%p, %lld, %lld)\n", vdp, start, length);
+       if (debug) printf("AddExtent(%p, %lld, %lld) (file id %u)\n", vdp, start, length, fid);
        while (*ep) {
                if ((*ep)->count < kExtentCount) {
                        indx = (*ep)->count;
                        (*ep)->extents[indx].base = start;
                        (*ep)->extents[indx].length = length;
+                       (*ep)->extents[indx].fid = fid;
                        (*ep)->count++;
                        break;
                } else {
@@ -94,6 +105,7 @@ AddExtent(VolumeObjects_t *vdp, off_t start, off_t length)
                (*ep)->count = 1;
                (*ep)->extents[0].base = start;
                (*ep)->extents[0].length = length;
+               (*ep)->extents[0].fid = fid;
                (*ep)->next = NULL;
        }
        vdp->count++;
@@ -104,6 +116,7 @@ done:
 }
 
 // Debugging function
+__private_extern__
 void
 PrintVolumeObject(VolumeObjects_t *vop)
 {
@@ -124,7 +137,7 @@ PrintVolumeObject(VolumeObjects_t *vop)
             exts = exts->next) {
                int indx;
                for (indx = 0; indx < exts->count; indx++) {
-                       printf("\t\t<%lld, %lld>\n", exts->extents[indx].base, exts->extents[indx].length);
+                       printf("\t\t<%lld, %lld> (file %u)\n", exts->extents[indx].base, exts->extents[indx].length, exts->extents[indx].fid);
                }
        }
        return;
@@ -136,6 +149,7 @@ PrintVolumeObject(VolumeObjects_t *vop)
  * track of progress, and also takes an amount to skip (which happens if it's
  * resuming an earlier, interrupted copy).
  */
+__private_extern__
 int
 CopyObjectsToDest(VolumeObjects_t *vop, struct IOWrapper *wrapper, off_t skip)
 {
diff --git a/CopyHFSMeta/util.c b/CopyHFSMeta/util.c
new file mode 100644 (file)
index 0000000..d90f7de
--- /dev/null
@@ -0,0 +1,648 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <err.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/disk.h>
+#include <sys/sysctl.h>
+#include <hfs/hfs_mount.h>
+#include <Block.h>
+#include "hfsmeta.h"
+#include "Data.h"
+
+/*
+ * Open the source device.  In addition to opening the device,
+ * this also attempts to flush the journal, and then sets up a
+ * DeviceInfo_t object that will be used when doing the actual
+ * reading.
+ */
+__private_extern__
+DeviceInfo_t *
+OpenDevice(const char *devname, int flushJournal)
+{
+       DeviceInfo_t *retval = NULL;
+       int fd;
+       DeviceInfo_t dev = { 0 };
+       struct stat sb;
+       struct vfsconf vfc;
+
+       if (stat(devname, &sb) == -1) {
+               err(kBadExit, "cannot open device %s", devname);
+       }
+       /*
+        * Attempt to flush the journal if requested.  If it fails, we just warn, but don't abort.
+        */
+       if (flushJournal && getvfsbyname("hfs", &vfc) == 0) {
+               int rv;
+               int mib[4];
+               char block_device[MAXPATHLEN+1];
+               int jfd;
+
+               /*
+                * The journal replay code, sadly, requires a block device.
+                * So we need to go from the raw device to block device, if
+                * necessary.
+                */
+               if (strncmp(devname, "/dev/rdisk", 10) == 0) {
+                       snprintf(block_device, sizeof(block_device), "/dev/%s", devname+6);
+               } else {
+                       snprintf(block_device, sizeof(block_device), "%s", devname);
+               }
+               jfd = open(block_device, O_RDWR);
+               if (jfd == -1) {
+                       warn("Cannot open block device %s for read-write", block_device);
+               } else {
+                       mib[0] = CTL_VFS;
+                       mib[1] = vfc.vfc_typenum;
+                       mib[2] = HFS_REPLAY_JOURNAL;
+                       mib[3] = jfd;
+                       if (debug)
+                               fprintf(stderr, "about to replay journal\n");
+                       rv = sysctl(mib, 4, NULL, NULL, NULL, 0);
+                       if (rv == -1) {
+                               warn("cannot replay journal");
+                       }
+                       /* This is probably not necessary, but we couldn't prove it. */
+                       (void)fcntl(jfd, F_FULLFSYNC, 0);
+                       close(jfd);
+               }
+       }
+       /*
+        * We only allow a character device (e.g., /dev/rdisk1s2)
+        * If we're given a non-character device, we'll try to turn
+        * into a character device assuming a name pattern of /dev/rdisk*
+        */
+       if ((sb.st_mode & S_IFMT) == S_IFCHR) {
+               dev.devname = strdup(devname);
+       } else if (strncmp(devname, "/dev/disk", 9) == 0) {
+               // Turn "/dev/diskFoo" into "/dev/rdiskFoo"
+               char tmpname[strlen(devname) + 2];
+               (void)snprintf(tmpname, sizeof(tmpname), "/dev/rdisk%s", devname + sizeof("/dev/disk") - 1);
+               if (stat(tmpname, &sb) == -1) {
+                       err(kBadExit, "cannot open raw device %s", tmpname);
+               }
+               if ((sb.st_mode & S_IFMT) != S_IFCHR) {
+                       errx(kBadExit, "raw device %s is not a raw device", tmpname);
+               }
+               dev.devname = strdup(tmpname);
+       } else {
+               errx(kBadExit, "device name `%s' does not fit pattern", devname);
+       }
+       // Only use an exclusive open if we're not debugging.
+       fd = open(dev.devname, O_RDONLY | (debug ? 0 : O_EXLOCK));
+       if (fd == -1) {
+               err(kBadExit, "cannot open raw device %s", dev.devname);
+       }
+       // Get the block size and counts for the device.
+       if (ioctl(fd, DKIOCGETBLOCKSIZE, &dev.blockSize) == -1) {
+               dev.blockSize = 512;    // Sane default, I hope
+       }
+       if (ioctl(fd, DKIOCGETBLOCKCOUNT, &dev.blockCount) == -1) {
+               err(kBadExit, "cannot get size of device %s", dev.devname);
+       }
+
+       dev.size = dev.blockCount * dev.blockSize;
+       dev.fd = fd;
+
+       retval = malloc(sizeof(*retval));
+       if (retval == NULL) {
+               err(kBadExit, "cannot allocate device info structure");
+       }
+       *retval = dev;
+       return retval;
+}
+
+/*
+ * Get the header and alternate header for a device.
+ */
+__private_extern__
+VolumeDescriptor_t *
+VolumeInfo(DeviceInfo_t *devp)
+{
+       uint8_t buffer[devp->blockSize];
+       VolumeDescriptor_t *vdp = NULL, vd = { 0 };
+       ssize_t rv;
+
+       vd.priOffset = 1024;    // primary volume header is at 1024 bytes
+       vd.altOffset = devp->size - 1024;       // alternate header is 1024 bytes from the end
+
+       rv = GetBlock(devp, vd.priOffset, buffer);
+       if (rv == -1) {
+               err(kBadExit, "cannot get primary volume header for device %s", devp->devname);
+       }
+       vd.priHeader = *(HFSPlusVolumeHeader*)buffer;
+
+       rv = GetBlock(devp, vd.altOffset, buffer);
+       if (rv == -1) {
+               err(kBadExit, "cannot get alternate volume header for device %s", devp->devname);
+       }
+       vd.altHeader = *(HFSPlusVolumeHeader*)buffer;
+
+       vdp = malloc(sizeof(*vdp));
+       *vdp = vd;
+
+       return vdp;
+}
+
+/*
+ * Compare the primary and alternate volume headers.
+ * We only care about the "important" bits (namely, the
+ * portions related to extents).
+ */
+__private_extern__
+int
+CompareVolumeHeaders(VolumeDescriptor_t *vdp)
+{
+       int retval = -1;
+
+#define CMP_FILE(v, f) memcmp(&(v)->priHeader.f, &(v)->altHeader.f, sizeof(v->priHeader.f))
+
+       if (vdp &&
+           vdp->priHeader.journalInfoBlock == vdp->altHeader.journalInfoBlock &&
+           CMP_FILE(vdp, allocationFile) == 0 &&
+           CMP_FILE(vdp, extentsFile) == 0 &&
+           CMP_FILE(vdp, catalogFile) == 0 &&
+           CMP_FILE(vdp, attributesFile) == 0 &&
+           CMP_FILE(vdp, startupFile) == 0)
+               retval = 0;
+#undef CMP_FILE
+       return retval;
+}
+
+/*
+ * Only two (currently) types of signatures are valid: H+ and HX.
+ */
+static int
+IsValidSigWord(uint16_t word) {
+       if (word == kHFSPlusSigWord ||
+           word == kHFSXSigWord)
+               return 1;
+       return 0;
+}
+
+/*
+ * Add the volume headers to the in-core volume information list.
+ */
+__private_extern__
+int
+AddHeaders(VolumeObjects_t *vop, int roundBlock)
+{
+       int retval = 1;
+       HFSPlusVolumeHeader *hp;
+       uint8_t buffer[vop->devp->blockSize];
+       ssize_t rv;
+
+       hp = &vop->vdp->priHeader;
+
+       if (IsValidSigWord(S16(hp->signature)) == 0) {
+               warnx("primary volume header signature = %x, invalid", S16(hp->signature));
+               retval = 0;
+       }
+       if (roundBlock) {
+               AddExtent(vop, 1024 / vop->devp->blockSize, vop->devp->blockSize);
+       } else {
+               AddExtent(vop, 1024, 512);
+       }
+
+       hp = &vop->vdp->altHeader;
+
+       if (IsValidSigWord(S16(hp->signature)) == 0) {
+               warnx("alternate volume header signature = %x, invalid", S16(hp->signature));
+               retval = 0;
+       }
+       if (roundBlock) {
+               AddExtent(vop, (vop->vdp->altOffset / vop->devp->blockSize) * vop->devp->blockSize, vop->devp->blockSize);
+       } else {
+               AddExtent(vop, vop->vdp->altOffset, 512);
+       }
+
+done:
+       return retval;
+}
+
+/*
+ * Add the journal information to the in-core volume list.
+ * This means the journal info block, the journal itself, and
+ * the contents of the same as described by the alternate volume
+ * header (if it's different from the primary volume header).
+ */
+__private_extern__
+void
+AddJournal(VolumeObjects_t *vop)
+{
+       DeviceInfo_t *devp = vop->devp;
+       uint8_t buffer[devp->blockSize];
+       ssize_t rv;
+       HFSPlusVolumeHeader *php, *ahp;
+       JournalInfoBlock *jib;
+
+       php = &vop->vdp->priHeader;
+       ahp = &vop->vdp->altHeader;
+
+       if (php->journalInfoBlock) {
+               off_t jOffset = (off_t)S32(php->journalInfoBlock) * S32(php->blockSize);
+               rv = GetBlock(devp, jOffset, buffer);
+               if (rv == -1) {
+                       err(kBadExit, "cannot get primary header's copy of journal info block");
+               }
+               AddExtent(vop, jOffset, sizeof(buffer));
+               jib = (JournalInfoBlock*)buffer;
+               if (S32(jib->flags) & kJIJournalInFSMask) {
+                       AddExtent(vop, S64(jib->offset), S64(jib->size));
+               }
+       }
+
+       if (ahp->journalInfoBlock &&
+           ahp->journalInfoBlock != php->journalInfoBlock) {
+               off_t jOffset = (off_t)S32(ahp->journalInfoBlock) * S32(ahp->blockSize);
+               rv = GetBlock(devp, jOffset, buffer);
+               if (rv == -1) {
+                       err(kBadExit, "cannot get alternate header's copy of journal info block");
+               }
+               AddExtent(vop, jOffset, sizeof(buffer));
+               jib = (JournalInfoBlock*)buffer;
+               if (S32(jib->flags) & kJIJournalInFSMask) {
+                       AddExtent(vop, S64(jib->offset), S64(jib->size));
+               }
+       }
+
+}
+
+/*
+ * Add the extents for the special files in the volume header.  Compare
+ * them with the alternate volume header's versions, and if they're different,
+ * add that as well.
+ */
+__private_extern__
+void
+AddFileExtents(VolumeObjects_t *vop)
+{
+       int useAlt = 0;
+#define ADDEXTS(vop, file, fid)                        \
+       do { \
+               off_t pSize = S32(vop->vdp->priHeader.blockSize);       \
+               off_t aSize = S32(vop->vdp->altHeader.blockSize);       \
+               int i;                                                  \
+               if (debug) printf("Adding " #file " extents\n");                \
+               for (i = 0; i < kHFSPlusExtentDensity; i++) {           \
+                       HFSPlusExtentDescriptor *ep = &vop->vdp->priHeader. file .extents[i]; \
+                       HFSPlusExtentDescriptor *ap = &vop->vdp->altHeader. file .extents[i]; \
+                       if (debug) printf("\tExtent <%u, %u>\n", S32(ep->startBlock), S32(ep->blockCount)); \
+                       if (ep->startBlock && ep->blockCount) {         \
+                               AddExtentForFile(vop, S32(ep->startBlock) * pSize, S32(ep->blockCount) * pSize, fid); \
+                               if (memcmp(ep, ap, sizeof(*ep)) != 0) { \
+                                       AddExtentForFile(vop, S32(ap->startBlock) * aSize, S32(ap->blockCount) * aSize, fid); \
+                                       useAlt = 1;                     \
+                               }                                       \
+                       }                                               \
+               }                                                       \
+       } while (0)
+
+       ADDEXTS(vop, allocationFile, kHFSAllocationFileID);
+       ADDEXTS(vop, extentsFile, kHFSExtentsFileID);
+       ADDEXTS(vop, catalogFile, kHFSCatalogFileID);
+       ADDEXTS(vop, attributesFile, kHFSAttributesFileID);
+       ADDEXTS(vop, startupFile, kHFSStartupFileID);
+
+#undef ADDEXTS
+
+       ScanExtents(vop, 0);
+       if (useAlt)
+               ScanExtents(vop, useAlt);
+
+       return;
+}
+
+static int
+ScanCatalogNode(VolumeObjects_t *vop, uint8_t *buffer, size_t nodeSize, extent_handler_t handler)
+{
+       BTNodeDescriptor *ndp = (BTNodeDescriptor *)buffer;
+       uint16_t *indices = (uint16_t*)(buffer + nodeSize);
+       size_t counter;
+       off_t blockSize = S32(vop->vdp->priHeader.blockSize);
+       int retval = 0;
+
+       if (ndp->kind != kBTLeafNode)   // Skip if it's not a leaf node
+               return 0;
+
+       if (debug)
+               fprintf(stderr, "%s:  scanning catalog node\n", __FUNCTION__);
+
+       for (counter = 1; counter <= S16(ndp->numRecords); counter++) {
+               // Need to get past the end of the key
+               uint16_t recOffset = S16(indices[-counter]);
+               HFSPlusCatalogKey *keyp = (HFSPlusCatalogKey*)(buffer + recOffset);
+               size_t keyLength = S16(keyp->keyLength);
+               // Add two because the keyLength field is not included.
+               HFSPlusCatalogFile *fp = (HFSPlusCatalogFile*)(((uint8_t*)keyp) +  2 + keyLength + (keyLength & 1));
+
+               if (S16(fp->recordType) != kHFSPlusFileRecord) {
+                       if (debug)
+                               fprintf(stderr, "%s:  skipping node record %zu because it is type %#x, at offset %u keyLength %zu\n", __FUNCTION__, counter, S16(fp->recordType), recOffset, keyLength);
+                       continue;
+               }
+
+               if (debug)
+                       fprintf(stderr, "%s:  node record %zu, file id = %u\n", __FUNCTION__, counter, S32(fp->fileID));
+               if (S32(fp->userInfo.fdType) == kSymLinkFileType &&
+                   S32(fp->userInfo.fdCreator) == kSymLinkCreator) {
+                       unsigned int fid = S32(fp->fileID);
+                       HFSPlusExtentDescriptor *extPtr = fp->dataFork.extents;
+                       int i;
+
+                       for (i = 0; i < 8; i++) {
+                               if (extPtr[i].startBlock &&
+                                   extPtr[i].blockCount) {
+                                       off_t start = blockSize * S32(extPtr[i].startBlock);
+                                       off_t length = blockSize * S32(extPtr[i].blockCount);
+                                       retval = handler(fid, start, length);
+                                       if (retval != 0)
+                                               return retval;
+                               } else {
+                                       break;
+                               }
+                       }
+               }
+       }
+       return retval;
+}
+
+static int
+ScanAttrNode(VolumeObjects_t *vop, uint8_t *buffer, size_t nodeSize, extent_handler_t handler)
+{
+       BTNodeDescriptor *ndp = (BTNodeDescriptor *)buffer;
+       uint16_t *indices = (uint16_t*)(buffer + nodeSize);
+       size_t counter;
+       off_t blockSize = S32(vop->vdp->priHeader.blockSize);
+       int retval = 0;
+
+       if (ndp->kind != kBTLeafNode)
+               return 0;       // Skip if it's not a leaf node
+
+       /*
+        * Look for records of type kHFSPlusForkData and kHFSPlusAttrExtents
+        */
+       for (counter = 1; counter <= S16(ndp->numRecords); counter++) {
+               // Need to get past the end of the key
+               unsigned int fid;
+               HFSPlusAttrKey *keyp = (HFSPlusAttrKey*)(buffer + S16(indices[-counter]));
+               size_t keyLength = S16(keyp->keyLength);
+               // Add two because the keyLength field is not included.
+               HFSPlusAttrRecord *ap = (HFSPlusAttrRecord*)(((uint8_t*)keyp) + 2 + keyLength + (keyLength & 1));
+               HFSPlusExtentDescriptor *theExtents = NULL;
+               switch (S32(ap->recordType)) {
+               case kHFSPlusAttrForkData:
+                       theExtents = ap->forkData.theFork.extents;
+                       break;
+               case kHFSPlusAttrExtents:
+                       theExtents = ap->overflowExtents.extents;
+                       break;
+               default:
+                       break;
+               }
+               if (theExtents != NULL) {
+                       HFSPlusExtentDescriptor *extPtr = theExtents;
+                       int i;
+                       fid = S32(keyp->fileID);
+
+                       for (i = 0; i < 8; i++) {
+                               if (extPtr[i].startBlock &&
+                                   extPtr[i].blockCount) {
+                                       off_t start = blockSize * S32(extPtr[i].startBlock);
+                                       off_t length = blockSize * S32(extPtr[i].blockCount);
+                                       retval = handler(fid, start, length);
+                                       if (retval != 0)
+                                               return retval;
+                               } else {
+                                       break;
+                               }
+                       }
+               }
+       }
+       return retval;
+}
+
+
+/*
+ * Given a VolumeObject_t, search for the other metadata that
+ * aren't described by the system files, but rather in the
+ * system files.  This includes symbolic links, and large EA
+ * extents.  We can do this at one of two times -- while copying
+ * the data, or while setting up the list of extents.  The
+ * former is going to be more efficient, but the latter will
+ * mean the estimates and continuation will be less likely to
+ * be wrong as we add extents to the list.
+ */
+__private_extern__
+int
+FindOtherMetadata(VolumeObjects_t *vop, extent_handler_t handler)
+{
+       size_t catNodeSize = 0, attrNodeSize = 0;
+       off_t node0_location = 0;
+       uint8_t *tBuffer;
+       BTHeaderRec *hdp;
+       BTNodeDescriptor *ndp;
+       int retval = 0;
+
+       tBuffer = calloc(1, vop->devp->blockSize);
+       if (tBuffer == NULL) {
+               warn("Could not allocate memory to collect extra metadata");
+               goto done;
+       }
+       /*
+        * First, do the catalog file
+        */
+       if (vop->vdp->priHeader.catalogFile.logicalSize) {
+
+               node0_location = S32(vop->vdp->priHeader.catalogFile.extents[0].startBlock);
+               node0_location = node0_location * S32(vop->vdp->priHeader.blockSize);
+               if (GetBlock(vop->devp, node0_location, tBuffer) == -1) {
+                       warn("Could not read catalog header node");
+               } else {
+                       ndp = (BTNodeDescriptor*)tBuffer;
+                       hdp = (BTHeaderRec*)(tBuffer + sizeof(BTNodeDescriptor));
+                       
+                       if (ndp->kind != kBTHeaderNode) {
+                               warnx("Did not read header node for catalog as expected");
+                       } else {
+                               catNodeSize = S16(hdp->nodeSize);
+                       }
+               }
+       }
+       /*
+        * Now, the attributes file.
+        */
+       if (vop->vdp->priHeader.attributesFile.logicalSize) {
+
+               node0_location = S32(vop->vdp->priHeader.attributesFile.extents[0].startBlock);
+               node0_location = node0_location * S32(vop->vdp->priHeader.blockSize);
+               if (GetBlock(vop->devp, node0_location, tBuffer) == -1) {
+                       warn("Could not read attributes file header node");
+               } else {
+                       ndp = (BTNodeDescriptor*)tBuffer;
+                       hdp = (BTHeaderRec*)(tBuffer + sizeof(BTNodeDescriptor));
+                       
+                       if (ndp->kind != kBTHeaderNode) {
+                               warnx("Did not read header node for attributes file as expected");
+                       } else {
+                               attrNodeSize = S16(hdp->nodeSize);
+                       }
+               }
+       }
+       if (debug)
+               fprintf(stderr, "Catalog node size = %zu, attributes node size = %zu\n", catNodeSize, attrNodeSize);
+
+       /*
+        * We start reading the extents now.
+        *
+        * This is a lot of duplicated code, unfortunately.
+        */
+       ExtentList_t *exts;
+       for (exts = vop->list;
+            exts;
+            exts = exts->next) {
+               size_t indx;
+               
+               for (indx = 0; indx < exts->count; indx++) {
+                       off_t start = exts->extents[indx].base;
+                       off_t len = exts->extents[indx].length;
+                       off_t nread = 0;
+                       if (exts->extents[indx].fid == 0) {
+                               continue;       // Unknown file, skip
+                       } else {
+                               if (debug) fprintf(stderr, "%s:  fid = %u, start = %llu, len = %llu\n", __FUNCTION__, exts->extents[indx].fid, start, len);
+                               while (nread < len) {
+                                       size_t bufSize;
+                                       uint8_t *buffer;
+                                       bufSize = MIN(len - nread, 1024 * 1024);        // Read 1mbyte max
+                                       buffer = calloc(1, bufSize);
+                                       if (buffer == NULL) {
+                                               warn("Cannot allocate %zu bytes for buffer, skipping node scan", bufSize);
+                                       } else {
+                                               ssize_t t = UnalignedRead(vop->devp, buffer, bufSize, start + nread);
+                                               if (t != bufSize) {
+                                                       warn("Attempted to read %zu bytes, only read %zd, skipping node scan", bufSize, t);
+                                               } else {
+                                                       uint8_t *curPtr = buffer, *endPtr = (buffer + bufSize);
+                                                       size_t nodeSize = 0;
+                                                       int (*func)(VolumeObjects_t *, uint8_t *, size_t, extent_handler_t) = NULL;
+                                                       if (exts->extents[indx].fid == kHFSCatalogFileID) {
+                                                               func = ScanCatalogNode;
+                                                               nodeSize = catNodeSize;
+                                                       } else if (exts->extents[indx].fid == kHFSAttributesFileID) {
+                                                               func = ScanAttrNode;
+                                                               nodeSize = attrNodeSize;
+                                                       }
+                                                       if (func) {
+                                                               while (curPtr < endPtr && retval == 0) {
+                                                                       retval = (*func)(vop, curPtr, nodeSize, handler);
+                                                                       curPtr += nodeSize;
+                                                               }
+                                                       }
+                                               }
+                                               free(buffer);
+                                       }
+                                       if (retval != 0)
+                                               goto done;
+                                       nread += bufSize;
+                               }
+                       }
+               }
+       }
+
+done:
+       if (tBuffer)
+               free(tBuffer);
+       return retval;
+}
+
+/*
+ * Perform a (potentially) unaligned read from a given input device.
+ */
+__private_extern__
+ssize_t
+UnalignedRead(DeviceInfo_t *devp, void *buffer, size_t size, off_t offset)
+{
+       ssize_t nread = -1;
+       size_t readSize = ((size + devp->blockSize - 1) / devp->blockSize) * devp->blockSize;
+       off_t baseOffset = (offset / devp->blockSize) * devp->blockSize;
+       size_t off = offset - baseOffset;
+       char *tmpbuf = NULL;
+       
+       if ((baseOffset == offset) && (readSize == size)) {
+               /*
+                * The read is already properly aligned, so call pread.
+                */
+               return pread(devp->fd, buffer, size, offset);
+       }
+       
+       tmpbuf = malloc(readSize);
+       if (!tmpbuf) {
+               goto done;
+       }
+       
+       nread = pread(devp->fd, tmpbuf, readSize, baseOffset);
+       if (nread == -1) {
+               goto done;
+       }
+       
+       nread -= off;
+       if (nread > (ssize_t)size) {
+               nread = size;
+       }
+       memcpy(buffer, tmpbuf + off, nread);
+       
+done:
+       free(tmpbuf);
+       return nread;
+}
+
+__private_extern__
+void
+ReleaseDeviceInfo(DeviceInfo_t *devp)
+{
+       if (devp) {
+               if (devp->fd != -1) {
+                       close(devp->fd);
+               }
+               if (devp->devname)
+                       free(devp->devname);
+               free(devp);
+       }
+       return;
+}
+
+__private_extern__
+void
+ReleaseVolumeDescriptor(VolumeDescriptor_t *vdp)
+{
+       if (vdp)
+               free(vdp);      // No contained pointers!
+       return;
+}
+
+__private_extern__
+void
+ReleaseVolumeObjects(VolumeObjects_t *vop)
+{
+       if (vop) {
+               if (vop->devp) {
+                       ReleaseDeviceInfo(vop->devp);
+               }
+               if (vop->vdp) {
+                       ReleaseVolumeDescriptor(vop->vdp);
+               }
+               ExtentList_t *extList;
+               for (extList = vop->list;
+                    extList;
+                       ) {
+                       ExtentList_t *next = extList->next;
+                       free(extList);
+                       extList = next;
+               }
+               free(vop);
+       }
+}
index fdd5649ca8afdf63c3e289d2e9613b7ca47325d8..a5ce2b6aafd4c6bde10dbe44cee8b3b53d18e020 100644 (file)
@@ -341,7 +341,7 @@ int CacheRead (Cache_t *cache, uint64_t off, uint32_t len, Buf_t **bufp)
        while (searchBuf != NULL) {
                if ((searchBuf->Offset >= off) && (searchBuf->Offset < off + len)) {
 #if CACHE_DEBUG
-                       printf ("ERROR: CacheRead: Deadlock\n");
+                       printf ("ERROR: CacheRead: Deadlock (searchBuff = <%llu, %u>, off = %llu, off+len = %llu)\n", searchBuf->Offset, searchBuf->Length, off, off+len);
 #endif
                        return (EDEADLK);
                }
@@ -372,6 +372,9 @@ int CacheRead (Cache_t *cache, uint64_t off, uint32_t len, Buf_t **bufp)
                buf->Flags |= BUF_SPAN;
        }
        /* Fetch the first cache block */
+#if CACHE_DEBUG
+       printf("%s(%d):  Looking up cache block %llu for offset %llu, cache blockSize %u\n", __FUNCTION__, __LINE__, cblk, off, cache->BlockSize);
+#endif
        error = CacheLookup (cache, cblk, &tag);
        if (error != EOK) {
 #if CACHE_DEBUG
index 5c654b93315b1258d5a305f99c3ada850a65e7ab..5ee6c40d6cfe54bd32d48211965b025b0983eeb2 100644 (file)
@@ -494,7 +494,21 @@ termScav:
        if ( fsckGetVerbosity(dataArea.context) >= kDebugLog && 
                 (err != noErr || dataArea.RepLevel != repairLevelNoProblemsFound) )
                PrintVolumeObject();
-       
+       if (err != 0 && embedded == 1) {
+               Buf_t *buf = NULL;
+               off_t offset = 1024;
+               uint32_t len = 512;     // the size of an HFS+ volume header
+               int rv = CacheRead(&fscache, offset, len, &buf);
+               if (rv == 0) {
+                       fprintf(stderr, "Offset %llu length %u:\n", offset, len);
+                       DumpData(buf->Buffer, len);
+                       CacheRelease(&fscache, buf, 0);
+               } else {
+                       fprintf(stderr, "%s(%d):  rv = %d\n", __FUNCTION__, __LINE__, rv);
+               }
+               fflush(stderr);
+       }
+
        // If we have write access on volume and we are allowed to write, 
        // mark the volume clean/dirty
        if ((fsWriteRef != -1) && (dataArea.canWrite != 0)) {
index 6404891c092b4f61d5f8dbfb9c05253836cbf536..44b98472119d3e20f2d2f070b393e3a34eb47198 100644 (file)
@@ -1596,7 +1596,7 @@ static void CompareVolHeaderBTreeSizes(   SGlobPtr GPtr,
 
 enum { WIDTH = 16, };
 
-static void
+void
 DumpData(const void *data, size_t len)
 {
        unsigned char *base = (unsigned char*)data;
@@ -1707,6 +1707,7 @@ done:
                } else {
                        uint8_t *ptr = (uint8_t*)theBlockDesc.buffer;
                        DumpData(ptr, theBlockDesc.blockSize);
+                       ReleaseVolumeBlock(myVOPtr->vcbPtr, &theBlockDesc, kReleaseBlock);
                }
        }
        return retval;
index fa93f99bde86a772886bc85b8e2a242bd335c50a..6c5b0e41cda7854984579186d575cb00f65fa2ba 100644 (file)
@@ -46,6 +46,8 @@
 #include "../fsck_hfs.h"
 #include "fsck_journal.h"
 
+#define DEBUG_JOURNAL 0
+
 extern char debug;
 
 #include <hfs/hfs_format.h>
@@ -191,8 +193,10 @@ getJournalTransaction(JournalIOInfo_t *jinfo, swapper_t *swap)
                 * Either there really are no blocks, or this is not a valid
                 * transaction.  Either way, there's nothing for us to do here.
                 */
+#if DEBUG_JOURNAL
                if (debug)
                        fplog(stderr, "%s(%d):  hdr->num_blocks == 0\n", __FUNCTION__, __LINE__);
+#endif
                return NULL;
        }
        /*
@@ -214,10 +218,12 @@ getJournalTransaction(JournalIOInfo_t *jinfo, swapper_t *swap)
        }
 
        if (swap->swap32(hdr->bytes_used) < sizeof(block)) {
+#if DEBUG_JOURNAL
                if (debug) {
                        fplog(stderr, "%s(%d):  hdr has bytes_used (%u) less than sizeof block (%zd)\n",
                              __FUNCTION__, __LINE__, swap->swap32(hdr->bytes_used), sizeof(block));
                }
+#endif
                return NULL;
        }
 
@@ -267,8 +273,10 @@ replayTransaction(block_list_header *txn, size_t blSize, size_t blkSize, swapper
        uint8_t *dataPtr = ((uint8_t*)txn) + blSize;
        int retval = -1;
        for (i = 1; i < swap->swap32(txn->num_blocks); i++) {
+#if DEBUG_JOURNAL
                if (debug)
                        plog("\tBlock %d:  blkNum %llu, size %u, data offset = %zd\n", i, swap->swap64(txn->binfo[i].bnum), swap->swap32(txn->binfo[i].bsize), dataPtr - (uint8_t*)txn);
+#endif
                /*
                 * XXX
                 * Check with security types on these checks.  Need to ensure
@@ -290,6 +298,7 @@ replayTransaction(block_list_header *txn, size_t blSize, size_t blkSize, swapper
                                plog("\tData end out of range for block_list_header\n");
                        return retval;
                }
+#if DEBUG_JOURNAL
                // Just for debugging
                if (debug) {
                        if (swap->swap64(txn->binfo[i].bnum) == 2) {
@@ -297,10 +306,13 @@ replayTransaction(block_list_header *txn, size_t blSize, size_t blkSize, swapper
                                plog("vp->signature = %#x, version = %#x\n", vp->signature, vp->version);
                        }
                }
+#endif
                // It's in the spec, and I saw it come up once on a live volume.
                if (swap->swap64(txn->binfo[i].bnum) == ~(uint64_t)0) {
+#if DEBUG_JOURNAL
                        if (debug)
                                plog("\tSkipping this block due to magic skip number\n");
+#endif
                } else {
                        // Should we set retval to -2 here?
                        if (writer) {
@@ -451,8 +463,10 @@ journal_open(int jfd,
 
        JournalIOInfo_t jinfo = { 0 };
 
+#if DEBUG_JOURNAL
        if (debug)
                plog("Journal start sequence number = %u\n", jnlSwap->swap32(jhdr.sequence_num));
+#endif
 
        /*
         * Now set up the JournalIOInfo object with the file descriptor,
@@ -496,34 +510,44 @@ journal_open(int jfd,
                                plog("Journal sequence number is 0, is going into the end okay?\n");
                        }
                        into_the_weeds = 1;
+#if DEBUG_JOURNAL
                        if (debug)
                                plog("Attempting to read past stated end of journal\n");
+#endif
                        state = "tentative ";
                        jinfo.end = (jinfo.base + startOffset - jinfo.bSize);
                        continue;
                }
+#if DEBUG_JOURNAL
                if (debug)
                        plog("Before getting %stransaction:  jinfo.current = %llu\n", state, jinfo.current);
+#endif
                /*
                 * Note that getJournalTransaction verifies the checksum on the block_list_header, so
                 * if it's bad, it'll return NULL.
                 */
                txn = getJournalTransaction(&jinfo, jnlSwap);
                if (txn == NULL) {
+#if DEBUG_JOURNAL
                        if (debug)
                                plog("txn is NULL, jinfo.current = %llu\n", jinfo.current);
+#endif
                        if (into_the_weeds) {
+#if DEBUG_JOURNAL
                                if (debug)
                                        plog("\tBut we do not care, since it is past the end of the journal\n");
+#endif
                        } else {
                                bad_journal = 1;
                        }
                        break;
                }
+#if DEBUG_JOURNAL
                if (debug) {
                        plog("After getting %stransaction:  jinfo.current = %llu\n", state, jinfo.current);
                        plog("%stxn = { %u max_blocks, %u num_blocks, %u bytes_used, binfo[0].next = %u }\n", state, jnlSwap->swap32(txn->max_blocks), jnlSwap->swap32(txn->num_blocks), jnlSwap->swap32(txn->bytes_used), jnlSwap->swap32(txn->binfo[0].next));
                }
+#endif
                if (into_the_weeds) {
                        /*
                         * This seems to be what the kernel was checking:  if the
@@ -538,8 +562,10 @@ journal_open(int jfd,
                            jnlSwap->swap32(txn->binfo[0].next) != last_sequence_number &&
                            jnlSwap->swap32(txn->binfo[0].next) != (last_sequence_number + 1)) {
                                // Probably not a valid transaction
+#if DEBUG_JOURNAL
                                if (debug)
                                        plog("\tTentative txn sequence %u is not expected %u, stopping journal replay\n", jnlSwap->swap32(txn->binfo[0].next), last_sequence_number + 1);
+#endif
                                break;
                        }
                }
diff --git a/fsck_hfs/fsck_hfs.entitlements b/fsck_hfs/fsck_hfs.entitlements
new file mode 100644 (file)
index 0000000..1f58459
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.private.security.disk-device-access</key>
+       <true/>
+</dict>
+</plist>
index cdac5db8c4402037c52b0988830865844099e1da..c3ccea1d0204c745dcfc118d94b532315fd0bf14 100644 (file)
@@ -71,3 +71,5 @@ int           reply __P((char *question));
 void           start_progress(void);
 void           draw_progress(int);
 void           end_progress(void);
+void           DumpData(const void *, size_t);
+
index 683a506254241756603cebf8b0378aa6c92f6f75..e42777c0f075a39f40d5885499271ad95575de07 100644 (file)
@@ -445,7 +445,8 @@ shutdown_logging(void)
     /* Log fsck_hfs check completion time */
     t = time(NULL);
     if (in_mem_log) {
-       print_to_mem(DO_STR, IN_MEM_LOG, "fsck_hfs completed at %s\n", ctime(&t), NULL);
+       va_list empty_list = {0};
+       print_to_mem(DO_STR, IN_MEM_LOG, "fsck_hfs completed at %s\n", ctime(&t), empty_list);
     } else {
        fprintf(log_file, "%s: fsck_hfs completed at %s\n", cdevname ? cdevname : "UNKNOWN-DEV", ctime(&t));
     }
@@ -630,7 +631,8 @@ setup_logging(void)
                cur_in_mem_out = in_mem_out;
 
                t = time(NULL);
-               print_to_mem(DO_STR, IN_MEM_LOG, "\nfsck_hfs started at %s", ctime(&t), NULL);
+               va_list empty_list = {0};
+               print_to_mem(DO_STR, IN_MEM_LOG, "\nfsck_hfs started at %s", ctime(&t), empty_list);
 
                if (live_fsck && log_file) {
                    pthread_cond_init(&mem_buf_cond, NULL);
@@ -794,7 +796,8 @@ static int need_prefix=1;
        LOG_PREFIX;                             \
        fprintf(log_file, fmt, str);            \
     } else { \
-       print_to_mem(DO_STR, IN_MEM_LOG, fmt, str, NULL);       \
+       va_list empty_list = {0}; \
+       print_to_mem(DO_STR, IN_MEM_LOG, fmt, str, empty_list); \
     }
 
 
diff --git a/fstyp_hfs/fstyp_hfs.entitlements b/fstyp_hfs/fstyp_hfs.entitlements
new file mode 100644 (file)
index 0000000..1f58459
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.private.security.disk-device-access</key>
+       <true/>
+</dict>
+</plist>
index 18a12b39257bd2a8f0ae41e661898cefced783a0..17c67020d4a4babc0a05d5593d6be044a7ee1a5e 100644 (file)
@@ -13,6 +13,7 @@
                        buildPhases = (
                        );
                        dependencies = (
+                               8657285C18319A93007F580F /* PBXTargetDependency */,
                                4DBD523F1548A499007AA736 /* PBXTargetDependency */,
                                4DBD52411548A49A007AA736 /* PBXTargetDependency */,
                                4DBD52431548A49D007AA736 /* PBXTargetDependency */,
                4DFD9538153746210039B6BA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4DFD9536153746210039B6BA /* InfoPlist.strings */; };
                4DFD953C15377BD80039B6BA /* fsck_keys.h in Copy fsck_keys.h */ = {isa = PBXBuildFile; fileRef = 4DFD9449153600060039B6BA /* fsck_keys.h */; };
                7279A68D1593AA5C00192947 /* fsck_journal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7279A68B1593AA5C00192947 /* fsck_journal.c */; };
+               862C904C1834311200BAD882 /* iterate_hfs_metadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 862C904B1834311200BAD882 /* iterate_hfs_metadata.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               863D03971820761900A4F0C4 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 863D03961820761900A4F0C4 /* util.c */; };
+               8654E4C01832A68400808937 /* ScanExtents.c in Sources */ = {isa = PBXBuildFile; fileRef = FDD9FA4F14A1343D0043D4A9 /* ScanExtents.c */; };
+               86CBF382183186FB00A64A93 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 863D03961820761900A4F0C4 /* util.c */; };
+               86CBF3831831876200A64A93 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = FDD9FA4E14A1343D0043D4A9 /* misc.c */; };
+               86CBF3861831880F00A64A93 /* iterate_hfs_metadata.c in Sources */ = {isa = PBXBuildFile; fileRef = 86CBF3851831880F00A64A93 /* iterate_hfs_metadata.c */; };
+               86CBF3871831884600A64A93 /* Data.h in Headers */ = {isa = PBXBuildFile; fileRef = FDD9FA4714A1343D0043D4A9 /* Data.h */; };
                C1B6FA0810CC0A0A00778D48 /* hfsutil_jnl.c in Sources */ = {isa = PBXBuildFile; fileRef = C1B6FA0610CC0A0A00778D48 /* hfsutil_jnl.c */; };
                C1B6FA0910CC0A0A00778D48 /* hfsutil_main.c in Sources */ = {isa = PBXBuildFile; fileRef = C1B6FA0710CC0A0A00778D48 /* hfsutil_main.c */; };
                C1B6FA3010CC0B9500778D48 /* hfs.util.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = C1B6FA2F10CC0B8A00778D48 /* hfs.util.8 */; };
                        remoteGlobalIDString = 4DFD94BC15373C2C0039B6BA;
                        remoteInfo = fsck_makestrings;
                };
+               8657285B18319A93007F580F /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 86CBF37E183186C300A64A93;
+                       remoteInfo = hfs_metadata;
+               };
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
                4D0E89A71534FF48004CD678 /* mount_hfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mount_hfs.c; sourceTree = "<group>"; };
                4D0E89A81534FF48004CD678 /* optical.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = optical.c; sourceTree = "<group>"; };
                4D0E89A91534FF48004CD678 /* optical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = optical.h; sourceTree = "<group>"; };
+               4D6E7827191D3E7E004E3F93 /* fsck_hfs.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = fsck_hfs.entitlements; sourceTree = "<group>"; };
+               4D6E7828191D3F26004E3F93 /* newfs_hfs.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = newfs_hfs.entitlements; path = newfs_hfs/newfs_hfs.entitlements; sourceTree = SOURCE_ROOT; };
+               4D6E7829191D3F41004E3F93 /* mount_hfs.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = mount_hfs.entitlements; sourceTree = "<group>"; };
+               4D7C8964192141CA002013C9 /* hfs_util.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = hfs_util.entitlements; sourceTree = "<group>"; };
+               4D7C8965192141DB002013C9 /* CopyHFSMeta.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = CopyHFSMeta.entitlements; sourceTree = "<group>"; };
+               4D7C8966192141ED002013C9 /* fstyp_hfs.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = fstyp_hfs.entitlements; sourceTree = "<group>"; };
                4DE6C7461535012200C11066 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
                4DE6C74A1535018100C11066 /* libutil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libutil.dylib; path = /usr/lib/libutil.dylib; sourceTree = "<absolute>"; };
                4DE6C75B153504C100C11066 /* newfs_hfs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = newfs_hfs; sourceTree = BUILT_PRODUCTS_DIR; };
                4DFD953D15377C7D0039B6BA /* hfs.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = hfs.xcconfig; sourceTree = "<group>"; };
                7279A68B1593AA5C00192947 /* fsck_journal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fsck_journal.c; path = dfalib/fsck_journal.c; sourceTree = "<group>"; };
                7279A68C1593AA5C00192947 /* fsck_journal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fsck_journal.h; path = dfalib/fsck_journal.h; sourceTree = "<group>"; };
+               862C904B1834311200BAD882 /* iterate_hfs_metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iterate_hfs_metadata.h; path = libhfs_metadata/iterate_hfs_metadata.h; sourceTree = SOURCE_ROOT; };
+               863D03961820761900A4F0C4 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+               86CBF37F183186C300A64A93 /* libhfs_metadata.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libhfs_metadata.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               86CBF3851831880F00A64A93 /* iterate_hfs_metadata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iterate_hfs_metadata.c; path = libhfs_metadata/iterate_hfs_metadata.c; sourceTree = SOURCE_ROOT; };
                C1B6FA0610CC0A0A00778D48 /* hfsutil_jnl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hfsutil_jnl.c; sourceTree = "<group>"; };
                C1B6FA0710CC0A0A00778D48 /* hfsutil_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hfsutil_main.c; sourceTree = "<group>"; };
                C1B6FA2210CC0AF400778D48 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               86CBF37C183186C300A64A93 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                8DD76FAD0486AB0100D96B5E /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        children = (
                                4DFD953D15377C7D0039B6BA /* hfs.xcconfig */,
                                FDD9FA4614A1343D0043D4A9 /* CopyHFSMeta */,
+                               86CBF384183187D500A64A93 /* libhfs_metadata */,
                                FDD9FA3F14A1335D0043D4A9 /* hfs_util */,
                                4D0E899E1534FE65004CD678 /* mount_hfs */,
                                4DE6C75D153504C100C11066 /* newfs_hfs */,
                        children = (
                                4D07DCC31538EF92002B57CB /* fstyp_hfs.c */,
                                4D07DCC21538EF92002B57CB /* fstyp_hfs.8 */,
+                               4D7C8966192141ED002013C9 /* fstyp_hfs.entitlements */,
                        );
                        path = fstyp_hfs;
                        sourceTree = "<group>";
                                4D0E89A71534FF48004CD678 /* mount_hfs.c */,
                                4D0E89A81534FF48004CD678 /* optical.c */,
                                4D0E89A61534FF48004CD678 /* mount_hfs.8 */,
+                               4D6E7829191D3F41004E3F93 /* mount_hfs.entitlements */,
                        );
                        path = mount_hfs;
                        sourceTree = "<group>";
                                4DE6C7661535050700C11066 /* makehfs.c */,
                                4DE6C7641535050700C11066 /* hfs_endian.c */,
                                4DE6C7671535050700C11066 /* newfs_hfs.8 */,
+                               4D6E7828191D3F26004E3F93 /* newfs_hfs.entitlements */,
                        );
                        path = newfs_hfs;
                        sourceTree = "<group>";
                                4DFD9418153600060039B6BA /* dfalib */,
                                4DFD9440153600060039B6BA /* docs */,
                                4DFD9446153600060039B6BA /* fsck_hfs.8 */,
+                               4D6E7827191D3E7E004E3F93 /* fsck_hfs.entitlements */,
                        );
                        path = fsck_hfs;
                        sourceTree = "<group>";
                        path = fs;
                        sourceTree = "<group>";
                };
+               86CBF384183187D500A64A93 /* libhfs_metadata */ = {
+                       isa = PBXGroup;
+                       children = (
+                               86CBF3851831880F00A64A93 /* iterate_hfs_metadata.c */,
+                               862C904B1834311200BAD882 /* iterate_hfs_metadata.h */,
+                       );
+                       name = libhfs_metadata;
+                       path = CopyHFSMeta;
+                       sourceTree = "<group>";
+               };
                C1B6FD2C10CC0DB200778D48 /* Products */ = {
                        isa = PBXGroup;
                        children = (
                                4DFD94E615373C2C0039B6BA /* fsck_makestrings */,
                                4DFD95121537402A0039B6BA /* hfs.fs */,
                                4D07DCB81538EF3A002B57CB /* fstyp_hfs */,
+                               86CBF37F183186C300A64A93 /* libhfs_metadata.a */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                                C1B6FA2F10CC0B8A00778D48 /* hfs.util.8 */,
                                C1B6FA0610CC0A0A00778D48 /* hfsutil_jnl.c */,
                                C1B6FA0710CC0A0A00778D48 /* hfsutil_main.c */,
+                               4D7C8964192141CA002013C9 /* hfs_util.entitlements */,
                        );
                        path = hfs_util;
                        sourceTree = "<group>";
                FDD9FA4614A1343D0043D4A9 /* CopyHFSMeta */ = {
                        isa = PBXGroup;
                        children = (
+                               863D03961820761900A4F0C4 /* util.c */,
                                FDD9FA4714A1343D0043D4A9 /* Data.h */,
                                FDD9FA4814A1343D0043D4A9 /* DeviceWrapper.c */,
                                FDD9FA4914A1343D0043D4A9 /* dump.c */,
                                FDD9FA4F14A1343D0043D4A9 /* ScanExtents.c */,
                                FDD9FA5014A1343D0043D4A9 /* Sparse.h */,
                                FDD9FA5114A1343D0043D4A9 /* SparseBundle.c */,
+                               4D7C8965192141DB002013C9 /* CopyHFSMeta.entitlements */,
                        );
                        path = CopyHFSMeta;
                        sourceTree = "<group>";
                };
 /* End PBXGroup section */
 
+/* Begin PBXHeadersBuildPhase section */
+               86CBF37D183186C300A64A93 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               862C904C1834311200BAD882 /* iterate_hfs_metadata.h in Headers */,
+                               86CBF3871831884600A64A93 /* Data.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
 /* Begin PBXNativeTarget section */
                4D07DCB71538EF3A002B57CB /* fstyp_hfs */ = {
                        isa = PBXNativeTarget;
                        productReference = 4DFD95121537402A0039B6BA /* hfs.fs */;
                        productType = "com.apple.product-type.bundle";
                };
+               86CBF37E183186C300A64A93 /* hfs_metadata */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 86CBF381183186C300A64A93 /* Build configuration list for PBXNativeTarget "hfs_metadata" */;
+                       buildPhases = (
+                               86CBF37B183186C300A64A93 /* Sources */,
+                               86CBF37C183186C300A64A93 /* Frameworks */,
+                               86CBF37D183186C300A64A93 /* Headers */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = hfs_metadata;
+                       productName = hfs_metadata;
+                       productReference = 86CBF37F183186C300A64A93 /* libhfs_metadata.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
                8DD76FA90486AB0100D96B5E /* hfs.util */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "hfs.util" */;
                                4DFD93F31535FF510039B6BA /* fsck_hfs */,
                                4D07DCB71538EF3A002B57CB /* fstyp_hfs */,
                                4DFD94BC15373C2C0039B6BA /* fsck_makestrings */,
+                               86CBF37E183186C300A64A93 /* hfs_metadata */,
                        );
                };
 /* End PBXProject section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               86CBF37B183186C300A64A93 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               86CBF382183186FB00A64A93 /* util.c in Sources */,
+                               86CBF3831831876200A64A93 /* misc.c in Sources */,
+                               8654E4C01832A68400808937 /* ScanExtents.c in Sources */,
+                               86CBF3861831880F00A64A93 /* iterate_hfs_metadata.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                8DD76FAB0486AB0100D96B5E /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                                FDD9FA5814A1343D0043D4A9 /* ScanExtents.c in Sources */,
                                FDD9FA5314A1343D0043D4A9 /* dump.c in Sources */,
                                FDD9FA5914A1343D0043D4A9 /* SparseBundle.c in Sources */,
+                               863D03971820761900A4F0C4 /* util.c in Sources */,
                                FDD9FA5214A1343D0043D4A9 /* DeviceWrapper.c in Sources */,
                                FDD9FA5414A1343D0043D4A9 /* Gather.c in Sources */,
                        );
                        target = 4DFD94BC15373C2C0039B6BA /* fsck_makestrings */;
                        targetProxy = 4DBD52521548A4D4007AA736 /* PBXContainerItemProxy */;
                };
+               8657285C18319A93007F580F /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 86CBF37E183186C300A64A93 /* hfs_metadata */;
+                       targetProxy = 8657285B18319A93007F580F /* PBXContainerItemProxy */;
+               };
 /* End PBXTargetDependency section */
 
 /* Begin PBXVariantGroup section */
                1DEB928708733DD80010E9CD /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = hfs_util/hfs_util.entitlements;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
                                INSTALL_PATH = $FS_BUNDLE_BIN_PATH;
                                PRODUCT_NAME = hfs.util;
                        };
                4D07DCBF1538EF3A002B57CB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = fstyp_hfs/fstyp_hfs.entitlements;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
                                INSTALL_PATH = /sbin;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                        };
                4D0E89A41534FE65004CD678 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = mount_hfs/mount_hfs.entitlements;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
                                EXCLUDED_SOURCE_FILE_NAMES = "";
                                "EXCLUDED_SOURCE_FILE_NAMES[sdk=iphoneos*]" = optical.c;
                                "EXCLUDED_SOURCE_FILE_NAMES[sdk=iphonesimulator*]" = optical.c;
                4DE6C763153504C100C11066 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = newfs_hfs/newfs_hfs.entitlements;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
                                INSTALL_PATH = $FS_BUNDLE_BIN_PATH;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                        };
                4DFD93FB1535FF510039B6BA /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = fsck_hfs/fsck_hfs.entitlements;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "BSD=1",
                                        "CONFIG_HFS_TRIM=1",
                4DFD94AE153649070039B6BA /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = newfs_hfs/newfs_hfs.entitlements;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
                                GCC_PREPROCESSOR_DEFINITIONS = "DEBUG_BUILD=1";
                                PRODUCT_NAME = newfs_hfs_debug;
                        };
                        };
                        name = Release;
                };
+               86CBF380183186C300A64A93 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               DEPLOYMENT_POSTPROCESSING = YES;
+                               ENABLE_NS_ASSERTIONS = NO;
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               GENERATE_MASTER_OBJECT_FILE = YES;
+                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx;
+                               STRIPFLAGS = "";
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               STRIP_STYLE = "non-global";
+                       };
+                       name = Release;
+               };
                FDD9FA3414A132BF0043D4A9 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = CopyHFSMeta/CopyHFSMeta.entitlements;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
                                INSTALL_PATH = $FS_BUNDLE_BIN_PATH;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                        };
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               86CBF381183186C300A64A93 /* Build configuration list for PBXNativeTarget "hfs_metadata" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               86CBF380183186C300A64A93 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                FDD9FA3514A132BF0043D4A9 /* Build configuration list for PBXNativeTarget "CopyHFSMeta" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
diff --git a/hfs_util/hfs_util.entitlements b/hfs_util/hfs_util.entitlements
new file mode 100644 (file)
index 0000000..1f58459
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.private.security.disk-device-access</key>
+       <true/>
+</dict>
+</plist>
index aab17dea36a00e833539dac73b42086bde5022ab..663a43f060cbaec28122b66ff4d42c6f48a552c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2012 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2014 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -46,6 +46,9 @@
 
 #include <System/hfs/hfs_fsctl.h>
 
+#include <System/sys/content_protection.h>
+#include <TargetConditionals.h>
+
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
@@ -411,7 +414,15 @@ DoMakeJournaled(char *volname, int jsize) {
        }
        // printf("Embedded offset == 0x%llx\n", embedded_offset);
 
-       fd = open(journal_fname, O_CREAT|O_TRUNC|O_RDWR, 000);
+#if TARGET_OS_EMBEDDED
+       /* 
+        * Must use open_dprotected_np to create a class D file.  This will
+        * be the same as standard open(2) on systems that do not support content protection
+        */
+       fd = open_dprotected_np (journal_fname, O_CREAT|O_TRUNC|O_RDWR, PROTECTION_CLASS_D, 0, 000);
+#else
+       fd = open (journal_fname, O_CREAT|O_TRUNC|O_RDWR, 000);
+#endif
        if (fd < 0) {
                fprintf(stderr, "Can't create journal file on volume %s (%s)\n",
                                volname, strerror(errno));
@@ -500,7 +511,16 @@ retry:
        jib.offset = (off_t)((unsigned int)jstart_block) * (off_t)((unsigned int)block_size);
        jib.size   = (off_t)((unsigned int)journal_size);
 
+#if TARGET_OS_EMBEDDED
+       /* 
+        * Use open_dprotected_np to create JIB as a class D file.  This will
+        * behave the same as a standard open(2) on systems that do not support content protection
+        */
+       fd = open_dprotected_np(jib_fname, O_CREAT|O_TRUNC|O_RDWR, PROTECTION_CLASS_D, 0, 000);
+#else
        fd = open(jib_fname, O_CREAT|O_TRUNC|O_RDWR, 000);
+#endif
+
        if (fd < 0) {
                fprintf(stderr, "Could not create journal info block file on volume %s (%s)\n",
                                volname, strerror(errno));
index 8bb4e84cf17cd5808c98e631c6279376b70d928d..bb843459e6a9340d25e2cd32e57a7085e2019bba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2014 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 /* **************************************** L O C A L S ******************************************* */
 
+#define kHFSPlusMaxFileNameBytes       (3 * 255 + 1)   /* 255 unicode characters, plus 1 NUL byte */
+
 #define        HFS_BLOCK_SIZE                  512
 
 char gHFS_FS_NAME[] = "hfs";
@@ -741,7 +743,7 @@ DoProbe(char *rawDeviceNamePtr, char *blockDeviceNamePtr)
        char * bufPtr;
        HFSMasterDirectoryBlock * mdbPtr;
        HFSPlusVolumeHeader * volHdrPtr;
-       u_char volnameUTF8[NAME_MAX+1];
+       u_char volnameUTF8[kHFSPlusMaxFileNameBytes];
 
        /*
         * Determine if there is a volume already mounted from this device.  If
@@ -1949,7 +1951,7 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, unsigned c
            }
            swapped->unicode[i] = 0;
            cfstr = CFStringCreateWithCharacters(kCFAllocatorDefault, swapped->unicode, swapped->length);
-           (void) CFStringGetCString(cfstr, (char *)name_o, NAME_MAX, kCFStringEncodingUTF8);
+           (void) CFStringGetCString(cfstr, (char *)name_o, NAME_MAX * 3 + 1, kCFStringEncodingUTF8);
            CFRelease(cfstr);
            free(swapped);
        }
diff --git a/libhfs_metadata/iterate_hfs_metadata.c b/libhfs_metadata/iterate_hfs_metadata.c
new file mode 100644 (file)
index 0000000..b2aa4ae
--- /dev/null
@@ -0,0 +1,113 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "iterate_hfs_metadata.h"
+#include "../CopyHFSMeta/Data.h"
+#include "../CopyHFSMeta/hfsmeta.h"
+
+/*
+ * These variables are used by the CopyHFSMeta routines, so we have to define them
+ */
+
+__private_extern__ int debug = 0;
+__private_extern__ int verbose = 0;
+__private_extern__ int printProgress = 0;
+
+/*
+ * This is essentially the guts of CopyHFSMeta, only without
+ * the ability to write out to a sparse bundle.  It also always
+ * wants to get the "other" metadata (symlinks and large EA extents).
+ *
+ * For each extent it finds, it calls the passed-in function pointer,
+ * with the start and length.
+ *
+ * It will go through and get the symlink and EA extents first, and
+ * then go through the rest of the extents.  It does not attempt any
+ * sorting past that.
+ */
+int
+iterate_hfs_metadata(char *device, int (*handle_extent)(int fd, off_t start, off_t length, void *ctx), void *context_ptr)
+{
+       struct DeviceInfo *devp = NULL;
+       struct VolumeDescriptor *vdp = NULL;
+       VolumeObjects_t *vop = NULL;
+       int retval = 0;
+
+       devp = OpenDevice(device, 0);
+       if (devp == NULL) {
+               retval = errno;
+               goto done;
+       }
+
+       vdp = VolumeInfo(devp);
+       if (vdp == NULL) {
+               retval = errno;
+               goto done;
+       }
+
+       if (CompareVolumeHeaders(vdp) == -1) {
+               retval = EINVAL;
+               goto done;
+       }
+
+       vop = InitVolumeObject(devp, vdp);
+       if (vop == NULL) {
+               retval = errno;
+               goto done;
+       }
+
+       /*
+        * These guys don't have an error.  Probably
+        * a mistake.
+        */
+       AddHeaders(vop, 1);
+       AddJournal(vop);
+       AddFileExtents(vop);
+
+       /*
+        * By this point, vop has all of the system metadata.
+        * The only metadata we don't have would be symlinks (from
+        * the catalog file), and extended attribute fork extents
+        * (from the attributes file).  We get those with
+        * FindOtherMetadata().
+        */
+       retval = FindOtherMetadata(vop, ^(int fid __unused, off_t start, off_t len) {
+                       return (*handle_extent)(devp->fd, start, len, context_ptr);
+               });
+
+       if (retval != 0)
+               goto done;
+
+       /*
+        * Now, we've handled all of the other metadata, so we need
+        * to go through the rest of our metadata, which is in vop.
+        */
+       ExtentList_t *extList;
+       for (extList = vop->list;
+            extList;
+            extList = extList->next) {
+               size_t index;
+
+               for (index = 0; index < extList->count; index++) {
+                       retval = (*handle_extent)(devp->fd, extList->extents[index].base, extList->extents[index].length, context_ptr);
+                       if (retval != 0)
+                               goto done;
+               }
+       }
+       
+done:
+       if (vop) {
+               ReleaseVolumeObjects(vop);
+       } else {
+               if (vdp) {
+                       ReleaseVolumeDescriptor(vdp);
+               }
+               if (devp) {
+                       ReleaseDeviceInfo(devp);
+               }
+       }
+
+       return retval;
+
+}
diff --git a/libhfs_metadata/iterate_hfs_metadata.h b/libhfs_metadata/iterate_hfs_metadata.h
new file mode 100644 (file)
index 0000000..86e9bb8
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _hfs_iterate_hfs_metadata_h
+#define _hfs_iterate_hfs_metadata_h
+
+/*
+ * Given a device name, a function pointer, and
+ * a context pointer, call the function pointer for
+ * each metadata extent in the HFS+ filesystem.
+ */
+extern int iterate_hfs_metadata(char *, int (*)(int, off_t, off_t, void*), void *);
+
+#endif
index 8f086e82c61af670ae8bbf697584438efde7f37c..a737aaf3413d5f46d7481a907ede2cd3458792d5 100644 (file)
 #include <mntopts.h>
 
 
+/*
+ * Replay the journal.  We don't care if there are problems.
+ */
+static void
+replay_journal(const char *device)
+{
+       struct vfsconf vfc;
+       int mib[4];
+       int fd = -1;
+
+       fd = open(device, O_RDWR);
+       if (fd == -1) {
+               warn("Could not open block device %s for writing", device);
+               goto done;
+       }
+       if (getvfsbyname("hfs", &vfc) != 0) {
+               warn("Could not get hfs vfs information");
+               goto done;
+       }
+       mib[0] = CTL_VFS;
+       mib[1] = vfc.vfc_typenum;
+       mib[2] = HFS_REPLAY_JOURNAL;
+       mib[3] = fd;
+       (void)sysctl(mib, 4, NULL, NULL, NULL, 0);
+
+done:
+       if (fd != -1)
+               close(fd);
+       return;
+}
+
 struct mntopt mopts[] = {
        MOPT_STDOPTS,
        MOPT_IGNORE_OWNERSHIP,
@@ -423,6 +454,8 @@ main(argc, argv)
        u_int32_t localCreateTime;
        struct hfs_mnt_encoding *encp;
 
+       int do_rekey = 0;
+       int tmp_mntflags = 0;
 #if TARGET_OS_EMBEDDED
        mntflags = MNT_NOATIME;
 #else
@@ -615,45 +648,46 @@ main(argc, argv)
 #endif
 
 #if !TARGET_OS_EMBEDDED
-       /*
-       * We shouldn't really be calling up to other layers, but
-       * an exception was made in this case to fix the situation
-       * where HFS was writable on optical media.
-       */
-
-       if ((_optical_is_writable(dev) & _OPTICAL_WRITABLE_PACKET)) {
-               mntflags |= MNT_RDONLY;
-       }
+    /*
+     * We shouldn't really be calling up to other layers, but
+     * an exception was made in this case to fix the situation
+     * where HFS was writable on optical media.
+     */
+    
+    if ((_optical_is_writable(dev) & _OPTICAL_WRITABLE_PACKET)) {
+           mntflags |= MNT_RDONLY;
+    }
 #endif
        
-       if (is_hfs_std)
-               mntflags |= MNT_RDONLY;
-
-       if ((mntflags & MNT_RDONLY) == 0) {
-               /*
-                * get the volume's create date so we can synchronize
-                * it with the root directory create date
-                */
-               localCreateTime = getVolumeCreateDate(dev);
-       }
-       else {
-               localCreateTime = 0;
-       }
-
+    if (is_hfs_std)
+           mntflags |= MNT_RDONLY;
+    
+    if ((mntflags & MNT_RDONLY) == 0) {
+           /*
+            * get the volume's create date so we can synchronize
+            * it with the root directory create date
+            */
+           localCreateTime = getVolumeCreateDate(dev);
+    }
+    else {
+           localCreateTime = 0;
+    }
+    
     if ((mountStatus = mount(HFS_MOUNT_TYPE, dir, mntflags, &args)) < 0) {
 #if DEBUG
-        printf("mount_hfs: error on mount(): error = %d.\n", mountStatus);
+           printf("mount_hfs: error on mount(): error = %d.\n", mountStatus);
 #endif
-        err(1, NULL);
-        };
-   
-       /*
-        * synchronize the root directory's create date
-        * with the volume's create date
-        */
-       if (localCreateTime)
-               syncCreateDate(dir, localCreateTime);
-
+           err(1, NULL);
+    };
+    
+    /*
+     * synchronize the root directory's create date
+     * with the volume's create date
+     */
+    if (localCreateTime)
+           syncCreateDate(dir, localCreateTime);
+    
+    
     exit(0);
 }
 
diff --git a/mount_hfs/mount_hfs.entitlements b/mount_hfs/mount_hfs.entitlements
new file mode 100644 (file)
index 0000000..1f58459
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.private.security.disk-device-access</key>
+       <true/>
+</dict>
+</plist>
index 27b922ab87a09bdefacbc228a1be34a7986c0811..0fdaba911f42cdb4341482adba7d06a5a483bb12 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2014 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -1436,6 +1436,24 @@ WriteJournalInfo(const DriveInfo *driveInfo, UInt64 startingSector,
     jibp->offset = SWAP_BE64(jibp->offset);
     jibp->size   = SWAP_BE64(jibp->size);
 
+       if (jibp->flags & kJIJournalInFSMask) {
+               /* 
+                * Zero out the on-disk content of the journal file.
+                *
+                * This is a really ugly hack.  Right now, all of the logic in the code
+                * that calls us (make_hfsplus), uses the value 'sectorsPerBlock' but it
+                * is really hardcoded to assume the sector size is 512 bytes.  The code
+                * in WriteBuffer will massage the I/O to use the actual physical sector
+                * size.   Since WriteBuffer takes a sector # relative to 512 byte sectors,
+                * We need to convert the journal offset in bytes to value that represents
+                * its start LBA in 512 byte sectors.
+                * 
+                * Note further that we swapped to big endian prior to the WriteBuffer call,
+                * but we have swapped back to native after the call.
+                */
+               WriteBuffer(driveInfo, jibp->offset / kBytesPerSector, jibp->size, NULL);
+       }
+
     return 0;
 }
 
@@ -1560,7 +1578,7 @@ InitCatalogRoot_HFSPlus(const hfsparams_t *dp, const HFSPlusVolumeHeader *header
        UInt16                                  nodeSize;
        SInt16                                  offset;
        size_t                                  unicodeBytes;
-       UInt8 canonicalName[256];
+       UInt8 canonicalName[kHFSPlusMaxFileNameBytes];  // UTF8 character may convert to three bytes, plus a NUL
        CFStringRef cfstr;
        Boolean cfOK;
        int index = 0;
index 682ed8d07c401919c3981a4033b50a2fa03c1922..bd7b076c431567742b34443f3ed8455a55076bb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2014 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -93,7 +93,7 @@ static int bad_disk_size (u_int64_t numsectors, u_int64_t sectorsize);
 
 
 char   *progname;
-char   gVolumeName[kHFSPlusMaxFileNameChars + 1] = {kDefaultVolumeNameStr};
+char   *gVolumeName = kDefaultVolumeNameStr;
 char   rawdevice[MAXPATHLEN];
 char   blkdevice[MAXPATHLEN];
 uint32_t gBlockSize = 0;
@@ -316,13 +316,9 @@ main(argc, argv)
                        break;
 
                case 'v':
-                       n = strlen(optarg);
-                       if ((size_t)n > (sizeof(gVolumeName) - 1))
-                               fatal("\"%s\" is too long (%d byte maximum)",
-                                     optarg, sizeof(gVolumeName) - 1);
-                       if (n == 0)
-                               fatal("name required with -v option");
-                       strlcpy(gVolumeName, optarg, sizeof(gVolumeName));
+                       if ((gVolumeName = strdup(optarg)) == NULL) {
+                               fatal("Could not copy volume name %s", optarg);
+                       }
                        break;
 
                case '?':
@@ -1086,8 +1082,7 @@ static void hfsplus_params (const DriveInfo* dip, hfsparams_t *defaults)
                }
        }
        
-       strncpy((char *)defaults->volumeName, gVolumeName, sizeof(defaults->volumeName) - 1);
-       defaults->volumeName[sizeof(defaults->volumeName) - 1] = '\0';
+       defaults->volumeName = (unsigned char*)gVolumeName;
 
        if (rsrclumpblks == 0) {
                if (gBlockSize > DFL_BLKSIZE)
diff --git a/newfs_hfs/newfs_hfs.entitlements b/newfs_hfs/newfs_hfs.entitlements
new file mode 100644 (file)
index 0000000..1f58459
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.private.security.disk-device-access</key>
+       <true/>
+</dict>
+</plist>
index 4f0c5211c1f0cf301c556240d6136b11f9698948..79d9624ba3fce07082ab2270de21672e04ef5d8c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2011 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2014 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -174,6 +174,13 @@ enum {
  */
 #define MAC_GMT_FACTOR         2082844800UL
 
+/*
+ * Maximum number of bytes in an HFS+ filename.
+ * It's 255 characters; a UTF16 character may translate
+ * to 3 bytes.  Plus one for NUL.
+ */
+
+#define kHFSPlusMaxFileNameBytes       (3 * 255 + 1)
 
 /* sectorSize = kBytesPerSector = 512
    sectorOffset and totalSectors are in terms of 512-byte sector size.
@@ -231,7 +238,7 @@ struct hfsparams {
 
        uint32_t        createDate;             /* in UTC */
        uint32_t        hfsAlignment;
-       unsigned char volumeName[kHFSPlusMaxFileNameChars + 1];  /* in UTF-8 */
+       unsigned char   *volumeName;            /* In UTF8, but we need to allocate space for it. */
        uint32_t        encodingHint;
        uint32_t        journaledHFS;
        uint32_t        journalSize;