centralized some higher level utility functions of hfs
This commit is contained in:
Родитель
8efb3727dd
Коммит
4aa9b90d5c
|
@ -326,14 +326,6 @@ extern "C" {
|
|||
void writeATAPI(AbstractFile* file, ChecksumFunc dataForkChecksum, void* dataForkToken, ResourceKey **resources, NSizResource** nsizIn);
|
||||
void writeFreePartition(AbstractFile* outFile, uint32_t numSectors, ResourceKey** resources);
|
||||
|
||||
AbstractFile* createAbstractFileFromFile(FILE* file);
|
||||
AbstractFile* createAbstractFileFromDummy();
|
||||
AbstractFile* createAbstractFileFromMemory(void** buffer, size_t size);
|
||||
AbstractFile* createAbstractFileFromMemoryFile(void** buffer, size_t* size);
|
||||
AbstractFile* createAbstractFileFromMemoryFileBuffer(void** buffer, size_t* size, size_t actualBufferSize);
|
||||
void abstractFilePrint(AbstractFile* file, const char* format, ...);
|
||||
io_func* IOFuncFromAbstractFile(AbstractFile* file);
|
||||
|
||||
void extractBLKX(AbstractFile* in, AbstractFile* out, BLKXTable* blkx);
|
||||
BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorNumber, uint32_t numSectors, uint32_t blocksDescriptor,
|
||||
uint32_t checksumType, ChecksumFunc uncompressedChk, void* uncompressedChkToken, ChecksumFunc compressedChk,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
UTILOBJS=hdutil.o
|
||||
DMGOBJS=../dmg/base64.o ../dmg/resources.o ../dmg/checksum.o ../dmg/udif.o ../dmg/partition.o ../dmg/io.o ../dmg/filevault.o ../dmg/dmgfile.o ../dmg/zlib-1.2.3/libz.a ../dmg/openssl-0.9.8g/libcrypto.a
|
||||
HFSOBJS=../hfs/volume.o ../hfs/btree.o ../hfs/extents.o ../hfs/rawfile.o ../hfs/catalog.o ../hfs/flatfile.o ../hfs/utility.o ../hfs/fastunicodecompare.o ../hfs/abstractfile.o
|
||||
HFSOBJS=../hfs/volume.o ../hfs/btree.o ../hfs/extents.o ../hfs/rawfile.o ../hfs/catalog.o ../hfs/flatfile.o ../hfs/utility.o ../hfs/fastunicodecompare.o ../hfs/abstractfile.o ../hfs/hfslib.o
|
||||
CFLAGS=-D_FILE_OFFSET_BITS=64 -DHAVE_CRYPT
|
||||
LIBRARIES=`if $(CC) win32test.c -o /dev/null 2>/dev/null ; then echo ""; else echo "-lgdi32"; fi`
|
||||
|
||||
|
@ -18,7 +18,8 @@ util: $(DMGOBJS) $(HFSOBJS) $(UTILOBJS)
|
|||
../dmg/zlib-1.2.3/libz.a: ../dmg/zlib-1.2.3/Makefile
|
||||
cd ../dmg/zlib-1.2.3; make
|
||||
|
||||
../dmg/openssl-0.9.8g/libcrypto.a:
|
||||
../dmg/openssl-0.9.8g/libcrypto.a:
|
||||
touch ../dmg/openssl-0.9.8g/Makefile
|
||||
cd ../dmg/openssl-0.9.8g/crypto; make
|
||||
|
||||
|
||||
|
|
526
hdutil/hdutil.c
526
hdutil/hdutil.c
|
@ -13,204 +13,46 @@
|
|||
|
||||
char endianness;
|
||||
|
||||
void displayFolder(HFSCatalogNodeID folderID, Volume* volume) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
HFSPlusCatalogFolder* folder;
|
||||
HFSPlusCatalogFile* file;
|
||||
time_t fileTime;
|
||||
struct tm *date;
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
while(list != NULL) {
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
printf("%06o ", folder->permissions.fileMode);
|
||||
printf("%3d ", folder->permissions.ownerID);
|
||||
printf("%3d ", folder->permissions.groupID);
|
||||
printf("%12d ", folder->valence);
|
||||
fileTime = APPLE_TO_UNIX_TIME(folder->contentModDate);
|
||||
} else if(list->record->recordType == kHFSPlusFileRecord) {
|
||||
file = (HFSPlusCatalogFile*)list->record;
|
||||
printf("%06o ", file->permissions.fileMode);
|
||||
printf("%3d ", file->permissions.ownerID);
|
||||
printf("%3d ", file->permissions.groupID);
|
||||
printf("%12lld ", file->dataFork.logicalSize);
|
||||
fileTime = APPLE_TO_UNIX_TIME(file->contentModDate);
|
||||
}
|
||||
|
||||
date = localtime(&fileTime);
|
||||
if(date != NULL) {
|
||||
printf("%2d/%2d/%4d %02d:%02d ", date->tm_mon, date->tm_mday, date->tm_year + 1900, date->tm_hour, date->tm_min);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printUnicode(&list->name);
|
||||
printf("\n");
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
void displayFileLSLine(HFSPlusCatalogFile* file, const char* name) {
|
||||
time_t fileTime;
|
||||
struct tm *date;
|
||||
|
||||
printf("%06o ", file->permissions.fileMode);
|
||||
printf("%3d ", file->permissions.ownerID);
|
||||
printf("%3d ", file->permissions.groupID);
|
||||
printf("%12d ", file->dataFork.logicalSize);
|
||||
fileTime = APPLE_TO_UNIX_TIME(file->contentModDate);
|
||||
date = localtime(&fileTime);
|
||||
if(date != NULL) {
|
||||
printf("%2d/%2d/%4d %2d:%02d ", date->tm_mon, date->tm_mday, date->tm_year + 1900, date->tm_hour, date->tm_min);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%s\n", name);
|
||||
}
|
||||
|
||||
void cmd_ls(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
char* name;
|
||||
|
||||
if(argc > 1)
|
||||
record = getRecordFromPath(argv[1], volume, &name, NULL);
|
||||
hfs_ls(volume, argv[1]);
|
||||
else
|
||||
record = getRecordFromPath("/", volume, &name, NULL);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFolderRecord)
|
||||
displayFolder(((HFSPlusCatalogFolder*)record)->folderID, volume);
|
||||
else
|
||||
displayFileLSLine((HFSPlusCatalogFile*)record, name);
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
printf("Total filesystem size: %d, free: %d\n", (volume->volumeHeader->totalBlocks - volume->volumeHeader->freeBlocks) * volume->volumeHeader->blockSize, volume->volumeHeader->freeBlocks * volume->volumeHeader->blockSize);
|
||||
|
||||
free(record);
|
||||
}
|
||||
|
||||
|
||||
#define BUFSIZE 1024*1024
|
||||
|
||||
void writeToFile(HFSPlusCatalogFile* file, FILE* output, Volume* volume) {
|
||||
unsigned char buffer[BUFSIZE];
|
||||
io_func* io;
|
||||
off_t curPosition;
|
||||
size_t bytesLeft;
|
||||
|
||||
io = openRawFile(file->fileID, &file->dataFork, (HFSPlusCatalogRecord*)file, volume);
|
||||
if(io == NULL) {
|
||||
panic("error opening file");
|
||||
return;
|
||||
}
|
||||
|
||||
curPosition = 0;
|
||||
bytesLeft = file->dataFork.logicalSize;
|
||||
|
||||
while(bytesLeft > 0) {
|
||||
if(bytesLeft > BUFSIZE) {
|
||||
if(!READ(io, curPosition, BUFSIZE, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(fwrite(buffer, BUFSIZE, 1, output) != 1) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += BUFSIZE;
|
||||
bytesLeft -= BUFSIZE;
|
||||
} else {
|
||||
if(!READ(io, curPosition, bytesLeft, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(fwrite(buffer, bytesLeft, 1, output) != 1) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += bytesLeft;
|
||||
bytesLeft -= bytesLeft;
|
||||
}
|
||||
}
|
||||
CLOSE(io);
|
||||
}
|
||||
|
||||
void writeToHFSFile(HFSPlusCatalogFile* file, FILE* input, Volume* volume) {
|
||||
unsigned char buffer[BUFSIZE];
|
||||
io_func* io;
|
||||
off_t curPosition;
|
||||
off_t bytesLeft;
|
||||
|
||||
fseeko(input, 0, SEEK_END);
|
||||
bytesLeft = ftello(input);
|
||||
fseeko(input, 0, SEEK_SET);
|
||||
|
||||
io = openRawFile(file->fileID, &file->dataFork, (HFSPlusCatalogRecord*)file, volume);
|
||||
if(io == NULL) {
|
||||
panic("error opening file");
|
||||
return;
|
||||
}
|
||||
|
||||
curPosition = 0;
|
||||
|
||||
allocate((RawFile*)io->data, bytesLeft);
|
||||
|
||||
while(bytesLeft > 0) {
|
||||
if(bytesLeft > BUFSIZE) {
|
||||
if(fread(buffer, BUFSIZE, 1, input) != 1) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(!WRITE(io, curPosition, BUFSIZE, buffer)) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += BUFSIZE;
|
||||
bytesLeft -= BUFSIZE;
|
||||
} else {
|
||||
if(fread(buffer, (size_t)bytesLeft, 1, input) != 1) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(!WRITE(io, curPosition, (size_t)bytesLeft, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
curPosition += bytesLeft;
|
||||
bytesLeft -= bytesLeft;
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE(io);
|
||||
}
|
||||
hfs_ls(volume, "/");
}
|
||||
|
||||
void cmd_cat(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
|
||||
AbstractFile* stdoutFile;
|
||||
|
||||
record = getRecordFromPath(argv[1], volume, NULL, NULL);
|
||||
|
||||
stdoutFile = createAbstractFileFromFile(stdout);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFileRecord)
|
||||
writeToFile((HFSPlusCatalogFile*)record, stdout, volume);
|
||||
writeToFile((HFSPlusCatalogFile*)record, stdoutFile, volume);
|
||||
else
|
||||
printf("Not a file\n");
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
free(record);
|
||||
free(record);
|
||||
free(stdoutFile);
|
||||
}
|
||||
|
||||
void cmd_extract(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
FILE *outFile;
|
||||
AbstractFile *outFile;
|
||||
|
||||
if(argc < 3) {
|
||||
printf("Not enough arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
outFile = fopen(argv[2], "wb");
|
||||
outFile = createAbstractFileFromFile(fopen(argv[2], "wb"));
|
||||
|
||||
if(outFile == NULL) {
|
||||
printf("cannot create file");
|
||||
|
@ -227,7 +69,7 @@ void cmd_extract(Volume* volume, int argc, const char *argv[]) {
|
|||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
fclose(outFile);
|
||||
outFile->close(outFile);
|
||||
free(record);
|
||||
}
|
||||
|
||||
|
@ -237,6 +79,14 @@ void cmd_mv(Volume* volume, int argc, const char *argv[]) {
|
|||
} else {
|
||||
printf("Not enough arguments");
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_symlink(Volume* volume, int argc, const char *argv[]) {
|
||||
if(argc > 2) {
|
||||
makeSymlink(argv[1], argv[2], volume);
|
||||
} else {
|
||||
printf("Not enough arguments");
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_mkdir(Volume* volume, int argc, const char *argv[]) {
|
||||
|
@ -248,35 +98,20 @@ void cmd_mkdir(Volume* volume, int argc, const char *argv[]) {
|
|||
}
|
||||
|
||||
void cmd_add(Volume* volume, int argc, const char *argv[]) {
|
||||
FILE *inFile;
|
||||
HFSPlusCatalogRecord* record;
|
||||
AbstractFile *inFile;
|
||||
|
||||
if(argc < 3) {
|
||||
printf("Not enough arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
inFile = fopen(argv[1], "rb");
|
||||
inFile = createAbstractFileFromFile(fopen(argv[1], "rb"));
|
||||
|
||||
if(inFile == NULL) {
|
||||
printf("file to add not found");
|
||||
}
|
||||
|
||||
record = getRecordFromPath(argv[2], volume, NULL, NULL);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFileRecord)
|
||||
writeToHFSFile((HFSPlusCatalogFile*)record, inFile, volume);
|
||||
else
|
||||
printf("Not a file\n");
|
||||
} else {
|
||||
newFile(argv[2], volume);
|
||||
record = getRecordFromPath(argv[2], volume, NULL, NULL);
|
||||
writeToHFSFile((HFSPlusCatalogFile*)record, inFile, volume);
|
||||
}
|
||||
|
||||
fclose(inFile);
|
||||
free(record);
|
||||
}
|
||||
|
||||
add_hfs(volume, inFile, argv[2]);
|
||||
}
|
||||
|
||||
void cmd_rm(Volume* volume, int argc, const char *argv[]) {
|
||||
|
@ -298,62 +133,6 @@ void cmd_chmod(Volume* volume, int argc, const char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
void TestByteOrder()
|
||||
{
|
||||
short int word = 0x0001;
|
||||
char *byte = (char *) &word;
|
||||
endianness = byte[0] ? IS_LITTLE_ENDIAN : IS_BIG_ENDIAN;
|
||||
}
|
||||
|
||||
void extractAllInFolder(HFSCatalogNodeID folderID, Volume* volume) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char cwd[1024];
|
||||
char* name;
|
||||
HFSPlusCatalogFolder* folder;
|
||||
HFSPlusCatalogFile* file;
|
||||
FILE* outFile;
|
||||
struct stat status;
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(strncmp(name, ".HFS+ Private Directory Data", sizeof(".HFS+ Private Directory Data") - 1) == 0 || name[0] == '\0') {
|
||||
free(name);
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
printf("folder: %s\n", name);
|
||||
if(stat(name, &status) != 0) {
|
||||
ASSERT(mkdir(name, 0755) == 0, "mkdir");
|
||||
}
|
||||
ASSERT(chdir(name) == 0, "chdir");
|
||||
extractAllInFolder(folder->folderID, volume);
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
} else if(list->record->recordType == kHFSPlusFileRecord) {
|
||||
printf("file: %s\n", name);
|
||||
file = (HFSPlusCatalogFile*)list->record;
|
||||
outFile = fopen(name, "wb");
|
||||
if(outFile != NULL) {
|
||||
writeToFile(file, outFile, volume);
|
||||
fclose(outFile);
|
||||
} else {
|
||||
printf("WARNING: cannot fopen %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
void cmd_extractall(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
char cwd[1024];
|
||||
|
@ -368,7 +147,7 @@ void cmd_extractall(Volume* volume, int argc, const char *argv[]) {
|
|||
|
||||
if(argc > 2) {
|
||||
ASSERT(chdir(argv[2]) == 0, "chdir");
|
||||
}
|
||||
}
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFolderRecord)
|
||||
|
@ -383,59 +162,6 @@ void cmd_extractall(Volume* volume, int argc, const char *argv[]) {
|
|||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
}
|
||||
|
||||
void removeAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char fullName[1024];
|
||||
char* name;
|
||||
char* pathComponent;
|
||||
int pathLen;
|
||||
char isRoot;
|
||||
|
||||
HFSPlusCatalogFolder* folder;
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
strcpy(fullName, parentName);
|
||||
pathComponent = fullName + strlen(fullName);
|
||||
|
||||
isRoot = FALSE;
|
||||
if(strcmp(fullName, "/") == 0) {
|
||||
isRoot = TRUE;
|
||||
}
|
||||
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(isRoot && (name[0] == '\0' || strncmp(name, ".HFS+ Private Directory Data", sizeof(".HFS+ Private Directory Data") - 1) == 0)) {
|
||||
free(name);
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(pathComponent, name);
|
||||
pathLen = strlen(fullName);
|
||||
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
fullName[pathLen] = '/';
|
||||
fullName[pathLen + 1] = '\0';
|
||||
removeAllInFolder(folder->folderID, volume, fullName);
|
||||
} else {
|
||||
printf("%s\n", fullName);
|
||||
removeFile(fullName, volume);
|
||||
}
|
||||
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
|
||||
if(!isRoot) {
|
||||
*(pathComponent - 1) = '\0';
|
||||
printf("%s\n", fullName);
|
||||
removeFile(fullName, volume);
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_rmall(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
|
@ -469,206 +195,40 @@ void cmd_rmall(Volume* volume, int argc, const char *argv[]) {
|
|||
free(record);
|
||||
}
|
||||
|
||||
void addAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char cwd[1024];
|
||||
char fullName[1024];
|
||||
char* pathComponent;
|
||||
int pathLen;
|
||||
|
||||
char* name;
|
||||
|
||||
DIR* dir;
|
||||
DIR* tmp;
|
||||
|
||||
HFSCatalogNodeID cnid;
|
||||
|
||||
struct dirent* ent;
|
||||
|
||||
FILE* file;
|
||||
HFSPlusCatalogFile* outFile;
|
||||
|
||||
strcpy(fullName, parentName);
|
||||
pathComponent = fullName + strlen(fullName);
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
ASSERT((dir = opendir(cwd)) != NULL, "opendir");
|
||||
|
||||
while((ent = readdir(dir)) != NULL) {
|
||||
if(ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(pathComponent, ent->d_name);
|
||||
pathLen = strlen(fullName);
|
||||
|
||||
cnid = 0;
|
||||
list = theList;
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(strcmp(name, ent->d_name) == 0) {
|
||||
list->record = getLinkTarget(list->record, folderID, NULL, volume);
|
||||
cnid = (list->record->recordType == kHFSPlusFolderRecord) ? (((HFSPlusCatalogFolder*)list->record)->folderID)
|
||||
: (((HFSPlusCatalogFile*)list->record)->fileID);
|
||||
free(name);
|
||||
break;
|
||||
}
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if((tmp = opendir(ent->d_name)) != NULL) {
|
||||
closedir(tmp);
|
||||
|
||||
printf("folder: %s\n", fullName);
|
||||
|
||||
if(cnid == 0) {
|
||||
cnid = newFolder(fullName, volume);
|
||||
}
|
||||
|
||||
fullName[pathLen] = '/';
|
||||
fullName[pathLen + 1] = '\0';
|
||||
ASSERT(chdir(ent->d_name) == 0, "chdir");
|
||||
addAllInFolder(cnid, volume, fullName);
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
} else {
|
||||
printf("file: %s\n", fullName);
|
||||
|
||||
if(cnid == 0) {
|
||||
cnid = newFile(fullName, volume);
|
||||
}
|
||||
file = fopen(ent->d_name, "rb");
|
||||
ASSERT(file != NULL, "fopen");
|
||||
outFile = (HFSPlusCatalogFile*)getRecordByCNID(cnid, volume);
|
||||
writeToHFSFile(outFile, file, volume);
|
||||
fclose(file);
|
||||
free(outFile);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
void cmd_addall(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
char* name;
|
||||
char cwd[1024];
|
||||
char initPath[1024];
|
||||
int lastCharOfPath;
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
void cmd_addall(Volume* volume, int argc, const char *argv[]) {
|
||||
if(argc < 2) {
|
||||
printf("Not enough arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
if(chdir(argv[1]) != 0) {
|
||||
printf("Cannot open that directory: %s\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(argc > 2) {
|
||||
record = getRecordFromPath(argv[2], volume, &name, NULL);
|
||||
strcpy(initPath, argv[2]);
|
||||
lastCharOfPath = strlen(argv[2]) - 1;
|
||||
if(argv[2][lastCharOfPath] != '/') {
|
||||
initPath[lastCharOfPath + 1] = '/';
|
||||
initPath[lastCharOfPath + 2] = '\0';
|
||||
}
|
||||
addall_hfs(volume, argv[1], argv[2]);
|
||||
} else {
|
||||
record = getRecordFromPath("/", volume, &name, NULL);
|
||||
record = getRecordFromPath("/", volume, &name, NULL);
|
||||
initPath[0] = '/';
|
||||
initPath[1] = '\0';
|
||||
addall_hfs(volume, argv[1], "/");
|
||||
}
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFolderRecord)
|
||||
addAllInFolder(((HFSPlusCatalogFolder*)record)->folderID, volume, initPath);
|
||||
else
|
||||
printf("Not a folder\n");
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
free(record);
|
||||
|
||||
}
|
||||
|
||||
void cmd_grow(Volume* volume, int argc, const char *argv[]) {
|
||||
uint64_t newSize;
|
||||
uint32_t newBlocks;
|
||||
uint32_t blocksToGrow;
|
||||
uint64_t newMapSize;
|
||||
uint64_t i;
|
||||
unsigned char zero;
|
||||
|
||||
zero = 0;
|
||||
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Not enough arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
newSize = 0;
|
||||
sscanf(argv[1], "%lld", &newSize);
|
||||
newBlocks = newSize / volume->volumeHeader->blockSize;
|
||||
|
||||
if(newBlocks <= volume->volumeHeader->totalBlocks) {
|
||||
printf("Cannot shrink volume\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blocksToGrow = newBlocks - volume->volumeHeader->totalBlocks;
|
||||
newMapSize = newBlocks / 8;
|
||||
|
||||
if(volume->volumeHeader->allocationFile.logicalSize < newMapSize) {
|
||||
if(volume->volumeHeader->freeBlocks
|
||||
< ((newMapSize - volume->volumeHeader->allocationFile.logicalSize) / volume->volumeHeader->blockSize)) {
|
||||
printf("Not enough room to allocate new allocation map blocks\n");
|
||||
}
|
||||
|
||||
allocate((RawFile*) (volume->allocationFile->data), newMapSize);
|
||||
}
|
||||
|
||||
/* unreserve last block */
|
||||
setBlockUsed(volume, volume->volumeHeader->totalBlocks - 1, 0);
|
||||
/* don't need to increment freeBlocks because we will allocate another alternate volume header later on */
|
||||
|
||||
/* "unallocate" the new blocks */
|
||||
for(i = ((volume->volumeHeader->totalBlocks / 8) + 1); i < newMapSize; i++) {
|
||||
ASSERT(WRITE(volume->allocationFile, i, 1, &zero), "WRITE");
|
||||
}
|
||||
|
||||
/* grow backing store size */
|
||||
ASSERT(WRITE(volume->image, newSize - 1, 1, &zero), "WRITE");
|
||||
|
||||
/* write new volume information */
|
||||
volume->volumeHeader->totalBlocks = newBlocks;
|
||||
volume->volumeHeader->freeBlocks += blocksToGrow;
|
||||
|
||||
/* reserve last block */
|
||||
setBlockUsed(volume, volume->volumeHeader->totalBlocks - 1, 1);
|
||||
|
||||
updateVolume(volume);
|
||||
|
||||
printf("grew volume: %lld -> %lld (%d)\n", newSize - (blocksToGrow * volume->volumeHeader->blockSize), newSize, blocksToGrow);
|
||||
}
|
||||
sscanf(argv[1], "%lld", &newSize);
|
||||
|
||||
void cmd_symlink(Volume* volume, int argc, const char *argv[]) {
|
||||
if(argc > 2) {
|
||||
makeSymlink(argv[1], argv[2], volume);
|
||||
} else {
|
||||
printf("Not enough arguments");
|
||||
}
|
||||
grow_hfs(volume, newSize);
|
||||
|
||||
printf("grew volume: %lld\n", newSize);
|
||||
}
|
||||
|
||||
void TestByteOrder()
|
||||
{
|
||||
short int word = 0x0001;
|
||||
char *byte = (char *) &word;
|
||||
endianness = byte[0] ? IS_LITTLE_ENDIAN : IS_BIG_ENDIAN;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
HFSPLUSOBJS=btree.o catalog.o extents.o flatfile.o rawfile.o volume.o utility.o hfs.o fastunicodecompare.o abstractfile.o
|
||||
HFSPLUSOBJS=btree.o catalog.o extents.o flatfile.o rawfile.o volume.o utility.o hfs.o fastunicodecompare.o abstractfile.o hfslib.o
|
||||
CFLAGS=-D_FILE_OFFSET_BITS=64 -O3
|
||||
|
||||
all: hfsplus
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
#ifndef ABSTRACTFILE_H
|
||||
#define ABSTRACTFILE_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct AbstractFile AbstractFile;
|
||||
|
||||
typedef size_t (*WriteFunc)(AbstractFile* file, const void* data, size_t len);
|
||||
|
@ -30,3 +35,19 @@ typedef struct {
|
|||
size_t actualBufferSize;
|
||||
} MemFileWrapperInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
AbstractFile* createAbstractFileFromFile(FILE* file);
|
||||
AbstractFile* createAbstractFileFromDummy();
|
||||
AbstractFile* createAbstractFileFromMemory(void** buffer, size_t size);
|
||||
AbstractFile* createAbstractFileFromMemoryFile(void** buffer, size_t* size);
|
||||
AbstractFile* createAbstractFileFromMemoryFileBuffer(void** buffer, size_t* size, size_t actualBufferSize);
|
||||
void abstractFilePrint(AbstractFile* file, const char* format, ...);
|
||||
io_func* IOFuncFromAbstractFile(AbstractFile* file);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
522
hfs/hfs.c
522
hfs/hfs.c
|
@ -1,214 +1,57 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "hfsplus.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "hfslib.h"
|
||||
#include "abstractfile.h"
|
||||
|
||||
char endianness;
|
||||
|
||||
void displayFolder(HFSCatalogNodeID folderID, Volume* volume) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
HFSPlusCatalogFolder* folder;
|
||||
HFSPlusCatalogFile* file;
|
||||
time_t fileTime;
|
||||
struct tm *date;
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
while(list != NULL) {
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
printf("%06o ", folder->permissions.fileMode);
|
||||
printf("%3d ", folder->permissions.ownerID);
|
||||
printf("%3d ", folder->permissions.groupID);
|
||||
printf("%12d ", folder->valence);
|
||||
fileTime = APPLE_TO_UNIX_TIME(folder->contentModDate);
|
||||
} else if(list->record->recordType == kHFSPlusFileRecord) {
|
||||
file = (HFSPlusCatalogFile*)list->record;
|
||||
printf("%06o ", file->permissions.fileMode);
|
||||
printf("%3d ", file->permissions.ownerID);
|
||||
printf("%3d ", file->permissions.groupID);
|
||||
printf("%12lld ", file->dataFork.logicalSize);
|
||||
fileTime = APPLE_TO_UNIX_TIME(file->contentModDate);
|
||||
}
|
||||
|
||||
date = localtime(&fileTime);
|
||||
if(date != NULL) {
|
||||
printf("%2d/%2d/%4d %02d:%02d ", date->tm_mon, date->tm_mday, date->tm_year + 1900, date->tm_hour, date->tm_min);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printUnicode(&list->name);
|
||||
printf("\n");
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
void displayFileLSLine(HFSPlusCatalogFile* file, const char* name) {
|
||||
time_t fileTime;
|
||||
struct tm *date;
|
||||
|
||||
printf("%06o ", file->permissions.fileMode);
|
||||
printf("%3d ", file->permissions.ownerID);
|
||||
printf("%3d ", file->permissions.groupID);
|
||||
printf("%12d ", file->dataFork.logicalSize);
|
||||
fileTime = APPLE_TO_UNIX_TIME(file->contentModDate);
|
||||
date = localtime(&fileTime);
|
||||
if(date != NULL) {
|
||||
printf("%2d/%2d/%4d %2d:%02d ", date->tm_mon, date->tm_mday, date->tm_year + 1900, date->tm_hour, date->tm_min);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%s\n", name);
|
||||
}
|
||||
|
||||
void cmd_ls(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
char* name;
|
||||
|
||||
if(argc > 1)
|
||||
record = getRecordFromPath(argv[1], volume, &name, NULL);
|
||||
hfs_ls(volume, argv[1]);
|
||||
else
|
||||
record = getRecordFromPath("/", volume, &name, NULL);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFolderRecord)
|
||||
displayFolder(((HFSPlusCatalogFolder*)record)->folderID, volume);
|
||||
else
|
||||
displayFileLSLine((HFSPlusCatalogFile*)record, name);
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
printf("Total filesystem size: %d, free: %d\n", (volume->volumeHeader->totalBlocks - volume->volumeHeader->freeBlocks) * volume->volumeHeader->blockSize, volume->volumeHeader->freeBlocks * volume->volumeHeader->blockSize);
|
||||
|
||||
free(record);
|
||||
}
|
||||
|
||||
|
||||
#define BUFSIZE 1024*1024
|
||||
|
||||
void writeToFile(HFSPlusCatalogFile* file, FILE* output, Volume* volume) {
|
||||
unsigned char buffer[BUFSIZE];
|
||||
io_func* io;
|
||||
off_t curPosition;
|
||||
size_t bytesLeft;
|
||||
|
||||
io = openRawFile(file->fileID, &file->dataFork, (HFSPlusCatalogRecord*)file, volume);
|
||||
if(io == NULL) {
|
||||
panic("error opening file");
|
||||
return;
|
||||
}
|
||||
|
||||
curPosition = 0;
|
||||
bytesLeft = file->dataFork.logicalSize;
|
||||
|
||||
while(bytesLeft > 0) {
|
||||
if(bytesLeft > BUFSIZE) {
|
||||
if(!READ(io, curPosition, BUFSIZE, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(fwrite(buffer, BUFSIZE, 1, output) != 1) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += BUFSIZE;
|
||||
bytesLeft -= BUFSIZE;
|
||||
} else {
|
||||
if(!READ(io, curPosition, bytesLeft, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(fwrite(buffer, bytesLeft, 1, output) != 1) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += bytesLeft;
|
||||
bytesLeft -= bytesLeft;
|
||||
}
|
||||
}
|
||||
CLOSE(io);
|
||||
}
|
||||
|
||||
void writeToHFSFile(HFSPlusCatalogFile* file, FILE* input, Volume* volume) {
|
||||
unsigned char buffer[BUFSIZE];
|
||||
io_func* io;
|
||||
off_t curPosition;
|
||||
off_t bytesLeft;
|
||||
|
||||
fseeko(input, 0, SEEK_END);
|
||||
bytesLeft = ftello(input);
|
||||
fseeko(input, 0, SEEK_SET);
|
||||
|
||||
io = openRawFile(file->fileID, &file->dataFork, (HFSPlusCatalogRecord*)file, volume);
|
||||
if(io == NULL) {
|
||||
panic("error opening file");
|
||||
return;
|
||||
}
|
||||
|
||||
curPosition = 0;
|
||||
|
||||
allocate((RawFile*)io->data, bytesLeft);
|
||||
|
||||
while(bytesLeft > 0) {
|
||||
if(bytesLeft > BUFSIZE) {
|
||||
if(fread(buffer, BUFSIZE, 1, input) != 1) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(!WRITE(io, curPosition, BUFSIZE, buffer)) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += BUFSIZE;
|
||||
bytesLeft -= BUFSIZE;
|
||||
} else {
|
||||
if(fread(buffer, (size_t)bytesLeft, 1, input) != 1) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(!WRITE(io, curPosition, (size_t)bytesLeft, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
curPosition += bytesLeft;
|
||||
bytesLeft -= bytesLeft;
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE(io);
|
||||
}
|
||||
hfs_ls(volume, "/");
}
|
||||
|
||||
void cmd_cat(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
|
||||
AbstractFile* stdoutFile;
|
||||
|
||||
record = getRecordFromPath(argv[1], volume, NULL, NULL);
|
||||
|
||||
stdoutFile = createAbstractFileFromFile(stdout);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFileRecord)
|
||||
writeToFile((HFSPlusCatalogFile*)record, stdout, volume);
|
||||
writeToFile((HFSPlusCatalogFile*)record, stdoutFile, volume);
|
||||
else
|
||||
printf("Not a file\n");
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
free(record);
|
||||
free(record);
|
||||
free(stdoutFile);
|
||||
}
|
||||
|
||||
void cmd_extract(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
FILE *outFile;
|
||||
AbstractFile *outFile;
|
||||
|
||||
if(argc < 3) {
|
||||
printf("Not enough arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
outFile = fopen(argv[2], "wb");
|
||||
outFile = createAbstractFileFromFile(fopen(argv[2], "wb"));
|
||||
|
||||
if(outFile == NULL) {
|
||||
printf("cannot create file");
|
||||
|
@ -225,7 +68,7 @@ void cmd_extract(Volume* volume, int argc, const char *argv[]) {
|
|||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
fclose(outFile);
|
||||
outFile->close(outFile);
|
||||
free(record);
|
||||
}
|
||||
|
||||
|
@ -254,35 +97,20 @@ void cmd_mkdir(Volume* volume, int argc, const char *argv[]) {
|
|||
}
|
||||
|
||||
void cmd_add(Volume* volume, int argc, const char *argv[]) {
|
||||
FILE *inFile;
|
||||
HFSPlusCatalogRecord* record;
|
||||
AbstractFile *inFile;
|
||||
|
||||
if(argc < 3) {
|
||||
printf("Not enough arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
inFile = fopen(argv[1], "rb");
|
||||
inFile = createAbstractFileFromFile(fopen(argv[1], "rb"));
|
||||
|
||||
if(inFile == NULL) {
|
||||
printf("file to add not found");
|
||||
}
|
||||
|
||||
record = getRecordFromPath(argv[2], volume, NULL, NULL);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFileRecord)
|
||||
writeToHFSFile((HFSPlusCatalogFile*)record, inFile, volume);
|
||||
else
|
||||
printf("Not a file\n");
|
||||
} else {
|
||||
newFile(argv[2], volume);
|
||||
record = getRecordFromPath(argv[2], volume, NULL, NULL);
|
||||
writeToHFSFile((HFSPlusCatalogFile*)record, inFile, volume);
|
||||
}
|
||||
|
||||
fclose(inFile);
|
||||
free(record);
|
||||
}
|
||||
|
||||
add_hfs(volume, inFile, argv[2]);
|
||||
}
|
||||
|
||||
void cmd_rm(Volume* volume, int argc, const char *argv[]) {
|
||||
|
@ -304,62 +132,6 @@ void cmd_chmod(Volume* volume, int argc, const char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
void TestByteOrder()
|
||||
{
|
||||
short int word = 0x0001;
|
||||
char *byte = (char *) &word;
|
||||
endianness = byte[0] ? IS_LITTLE_ENDIAN : IS_BIG_ENDIAN;
|
||||
}
|
||||
|
||||
void extractAllInFolder(HFSCatalogNodeID folderID, Volume* volume) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char cwd[1024];
|
||||
char* name;
|
||||
HFSPlusCatalogFolder* folder;
|
||||
HFSPlusCatalogFile* file;
|
||||
FILE* outFile;
|
||||
struct stat status;
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(strncmp(name, ".HFS+ Private Directory Data", sizeof(".HFS+ Private Directory Data") - 1) == 0 || name[0] == '\0') {
|
||||
free(name);
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
printf("folder: %s\n", name);
|
||||
if(stat(name, &status) != 0) {
|
||||
ASSERT(mkdir(name, 0755) == 0, "mkdir");
|
||||
}
|
||||
ASSERT(chdir(name) == 0, "chdir");
|
||||
extractAllInFolder(folder->folderID, volume);
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
} else if(list->record->recordType == kHFSPlusFileRecord) {
|
||||
printf("file: %s\n", name);
|
||||
file = (HFSPlusCatalogFile*)list->record;
|
||||
outFile = fopen(name, "wb");
|
||||
if(outFile != NULL) {
|
||||
writeToFile(file, outFile, volume);
|
||||
fclose(outFile);
|
||||
} else {
|
||||
printf("WARNING: cannot fopen %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
void cmd_extractall(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
char cwd[1024];
|
||||
|
@ -374,7 +146,7 @@ void cmd_extractall(Volume* volume, int argc, const char *argv[]) {
|
|||
|
||||
if(argc > 2) {
|
||||
ASSERT(chdir(argv[2]) == 0, "chdir");
|
||||
}
|
||||
}
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFolderRecord)
|
||||
|
@ -389,59 +161,6 @@ void cmd_extractall(Volume* volume, int argc, const char *argv[]) {
|
|||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
}
|
||||
|
||||
void removeAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char fullName[1024];
|
||||
char* name;
|
||||
char* pathComponent;
|
||||
int pathLen;
|
||||
char isRoot;
|
||||
|
||||
HFSPlusCatalogFolder* folder;
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
strcpy(fullName, parentName);
|
||||
pathComponent = fullName + strlen(fullName);
|
||||
|
||||
isRoot = FALSE;
|
||||
if(strcmp(fullName, "/") == 0) {
|
||||
isRoot = TRUE;
|
||||
}
|
||||
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(isRoot && (name[0] == '\0' || strncmp(name, ".HFS+ Private Directory Data", sizeof(".HFS+ Private Directory Data") - 1) == 0)) {
|
||||
free(name);
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(pathComponent, name);
|
||||
pathLen = strlen(fullName);
|
||||
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
fullName[pathLen] = '/';
|
||||
fullName[pathLen + 1] = '\0';
|
||||
removeAllInFolder(folder->folderID, volume, fullName);
|
||||
} else {
|
||||
printf("%s\n", fullName);
|
||||
removeFile(fullName, volume);
|
||||
}
|
||||
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
|
||||
if(!isRoot) {
|
||||
*(pathComponent - 1) = '\0';
|
||||
printf("%s\n", fullName);
|
||||
removeFile(fullName, volume);
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_rmall(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
|
@ -475,200 +194,43 @@ void cmd_rmall(Volume* volume, int argc, const char *argv[]) {
|
|||
free(record);
|
||||
}
|
||||
|
||||
void addAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char cwd[1024];
|
||||
char fullName[1024];
|
||||
char* pathComponent;
|
||||
int pathLen;
|
||||
|
||||
char* name;
|
||||
|
||||
DIR* dir;
|
||||
DIR* tmp;
|
||||
|
||||
HFSCatalogNodeID cnid;
|
||||
|
||||
struct dirent* ent;
|
||||
|
||||
FILE* file;
|
||||
HFSPlusCatalogFile* outFile;
|
||||
|
||||
strcpy(fullName, parentName);
|
||||
pathComponent = fullName + strlen(fullName);
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
ASSERT((dir = opendir(cwd)) != NULL, "opendir");
|
||||
|
||||
while((ent = readdir(dir)) != NULL) {
|
||||
if(ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(pathComponent, ent->d_name);
|
||||
pathLen = strlen(fullName);
|
||||
|
||||
cnid = 0;
|
||||
list = theList;
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(strcmp(name, ent->d_name) == 0) {
|
||||
list->record = getLinkTarget(list->record, folderID, NULL, volume);
|
||||
cnid = (list->record->recordType == kHFSPlusFolderRecord) ? (((HFSPlusCatalogFolder*)list->record)->folderID)
|
||||
: (((HFSPlusCatalogFile*)list->record)->fileID);
|
||||
free(name);
|
||||
break;
|
||||
}
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if((tmp = opendir(ent->d_name)) != NULL) {
|
||||
closedir(tmp);
|
||||
|
||||
printf("folder: %s\n", fullName);
|
||||
|
||||
if(cnid == 0) {
|
||||
cnid = newFolder(fullName, volume);
|
||||
}
|
||||
|
||||
fullName[pathLen] = '/';
|
||||
fullName[pathLen + 1] = '\0';
|
||||
ASSERT(chdir(ent->d_name) == 0, "chdir");
|
||||
addAllInFolder(cnid, volume, fullName);
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
} else {
|
||||
printf("file: %s\n", fullName);
|
||||
|
||||
if(cnid == 0) {
|
||||
cnid = newFile(fullName, volume);
|
||||
}
|
||||
file = fopen(ent->d_name, "rb");
|
||||
ASSERT(file != NULL, "fopen");
|
||||
outFile = (HFSPlusCatalogFile*)getRecordByCNID(cnid, volume);
|
||||
writeToHFSFile(outFile, file, volume);
|
||||
fclose(file);
|
||||
free(outFile);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
void cmd_addall(Volume* volume, int argc, const char *argv[]) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
char* name;
|
||||
char cwd[1024];
|
||||
char initPath[1024];
|
||||
int lastCharOfPath;
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
void cmd_addall(Volume* volume, int argc, const char *argv[]) {
|
||||
if(argc < 2) {
|
||||
printf("Not enough arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
if(chdir(argv[1]) != 0) {
|
||||
printf("Cannot open that directory: %s\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(argc > 2) {
|
||||
record = getRecordFromPath(argv[2], volume, &name, NULL);
|
||||
strcpy(initPath, argv[2]);
|
||||
lastCharOfPath = strlen(argv[2]) - 1;
|
||||
if(argv[2][lastCharOfPath] != '/') {
|
||||
initPath[lastCharOfPath + 1] = '/';
|
||||
initPath[lastCharOfPath + 2] = '\0';
|
||||
}
|
||||
addall_hfs(volume, argv[1], argv[2]);
|
||||
} else {
|
||||
record = getRecordFromPath("/", volume, &name, NULL);
|
||||
record = getRecordFromPath("/", volume, &name, NULL);
|
||||
initPath[0] = '/';
|
||||
initPath[1] = '\0';
|
||||
addall_hfs(volume, argv[1], "/");
|
||||
}
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFolderRecord)
|
||||
addAllInFolder(((HFSPlusCatalogFolder*)record)->folderID, volume, initPath);
|
||||
else
|
||||
printf("Not a folder\n");
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
free(record);
|
||||
|
||||
}
|
||||
|
||||
void cmd_grow(Volume* volume, int argc, const char *argv[]) {
|
||||
uint64_t newSize;
|
||||
uint32_t newBlocks;
|
||||
uint32_t blocksToGrow;
|
||||
uint64_t newMapSize;
|
||||
uint64_t i;
|
||||
unsigned char zero;
|
||||
|
||||
zero = 0;
|
||||
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Not enough arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
newSize = 0;
|
||||
sscanf(argv[1], "%lld", &newSize);
|
||||
newBlocks = newSize / volume->volumeHeader->blockSize;
|
||||
|
||||
if(newBlocks <= volume->volumeHeader->totalBlocks) {
|
||||
printf("Cannot shrink volume\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blocksToGrow = newBlocks - volume->volumeHeader->totalBlocks;
|
||||
newMapSize = newBlocks / 8;
|
||||
|
||||
if(volume->volumeHeader->allocationFile.logicalSize < newMapSize) {
|
||||
if(volume->volumeHeader->freeBlocks
|
||||
< ((newMapSize - volume->volumeHeader->allocationFile.logicalSize) / volume->volumeHeader->blockSize)) {
|
||||
printf("Not enough room to allocate new allocation map blocks\n");
|
||||
}
|
||||
|
||||
allocate((RawFile*) (volume->allocationFile->data), newMapSize);
|
||||
}
|
||||
|
||||
/* unreserve last block */
|
||||
setBlockUsed(volume, volume->volumeHeader->totalBlocks - 1, 0);
|
||||
/* don't need to increment freeBlocks because we will allocate another alternate volume header later on */
|
||||
|
||||
/* "unallocate" the new blocks */
|
||||
for(i = ((volume->volumeHeader->totalBlocks / 8) + 1); i < newMapSize; i++) {
|
||||
ASSERT(WRITE(volume->allocationFile, i, 1, &zero), "WRITE");
|
||||
}
|
||||
|
||||
/* grow backing store size */
|
||||
ASSERT(WRITE(volume->image, newSize - 1, 1, &zero), "WRITE");
|
||||
|
||||
/* write new volume information */
|
||||
volume->volumeHeader->totalBlocks = newBlocks;
|
||||
volume->volumeHeader->freeBlocks += blocksToGrow;
|
||||
|
||||
/* reserve last block */
|
||||
setBlockUsed(volume, volume->volumeHeader->totalBlocks - 1, 1);
|
||||
|
||||
updateVolume(volume);
|
||||
|
||||
printf("grew volume: %lld -> %lld (%d)\n", newSize - (blocksToGrow * volume->volumeHeader->blockSize), newSize, blocksToGrow);
|
||||
sscanf(argv[1], "%lld", &newSize);
|
||||
|
||||
grow_hfs(volume, newSize);
|
||||
|
||||
printf("grew volume: %lld\n", newSize);
|
||||
}
|
||||
|
||||
void TestByteOrder()
|
||||
{
|
||||
short int word = 0x0001;
|
||||
char *byte = (char *) &word;
|
||||
endianness = byte[0] ? IS_LITTLE_ENDIAN : IS_BIG_ENDIAN;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
io_func* io;
|
||||
Volume* volume;
|
||||
|
|
|
@ -0,0 +1,558 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include "common.h"
|
||||
#include "hfsplus.h"
|
||||
#include "abstractfile.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define BUFSIZE 1024*1024
|
||||
|
||||
void writeToFile(HFSPlusCatalogFile* file, AbstractFile* output, Volume* volume) {
|
||||
unsigned char buffer[BUFSIZE];
|
||||
io_func* io;
|
||||
off_t curPosition;
|
||||
size_t bytesLeft;
|
||||
|
||||
io = openRawFile(file->fileID, &file->dataFork, (HFSPlusCatalogRecord*)file, volume);
|
||||
if(io == NULL) {
|
||||
panic("error opening file");
|
||||
return;
|
||||
}
|
||||
|
||||
curPosition = 0;
|
||||
bytesLeft = file->dataFork.logicalSize;
|
||||
|
||||
while(bytesLeft > 0) {
|
||||
if(bytesLeft > BUFSIZE) {
|
||||
if(!READ(io, curPosition, BUFSIZE, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(output->write(output, buffer, BUFSIZE) != BUFSIZE) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += BUFSIZE;
|
||||
bytesLeft -= BUFSIZE;
|
||||
} else {
|
||||
if(!READ(io, curPosition, bytesLeft, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(output->write(output, buffer, bytesLeft) != bytesLeft) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += bytesLeft;
|
||||
bytesLeft -= bytesLeft;
|
||||
}
|
||||
}
|
||||
CLOSE(io);
|
||||
}
|
||||
|
||||
void writeToHFSFile(HFSPlusCatalogFile* file, AbstractFile* input, Volume* volume) {
|
||||
unsigned char buffer[BUFSIZE];
|
||||
io_func* io;
|
||||
off_t curPosition;
|
||||
off_t bytesLeft;
|
||||
|
||||
bytesLeft = input->getLength(input);
|
||||
|
||||
io = openRawFile(file->fileID, &file->dataFork, (HFSPlusCatalogRecord*)file, volume);
|
||||
if(io == NULL) {
|
||||
panic("error opening file");
|
||||
return;
|
||||
}
|
||||
|
||||
curPosition = 0;
|
||||
|
||||
allocate((RawFile*)io->data, bytesLeft);
|
||||
|
||||
while(bytesLeft > 0) {
|
||||
if(bytesLeft > BUFSIZE) {
|
||||
if(input->read(input, buffer, BUFSIZE) != BUFSIZE) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(!WRITE(io, curPosition, BUFSIZE, buffer)) {
|
||||
panic("error writing");
|
||||
}
|
||||
curPosition += BUFSIZE;
|
||||
bytesLeft -= BUFSIZE;
|
||||
} else {
|
||||
if(input->read(input, buffer, (size_t)bytesLeft) != (size_t)bytesLeft) {
|
||||
panic("error reading");
|
||||
}
|
||||
if(!WRITE(io, curPosition, (size_t)bytesLeft, buffer)) {
|
||||
panic("error reading");
|
||||
}
|
||||
curPosition += bytesLeft;
|
||||
bytesLeft -= bytesLeft;
|
||||
}
|
||||
}
|
||||
|
||||
CLOSE(io);
|
||||
}
|
||||
|
||||
void get_hfs(Volume* volume, const char* inFileName, AbstractFile* output) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
|
||||
record = getRecordFromPath(inFileName, volume, NULL, NULL);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFileRecord)
|
||||
writeToFile((HFSPlusCatalogFile*)record, output, volume);
|
||||
else {
|
||||
printf("Not a file\n");
|
||||
exit(0);
|
||||
}
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
free(record);
|
||||
}
|
||||
|
||||
int add_hfs(Volume* volume, AbstractFile* inFile, const char* outFileName) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
int ret;
|
||||
|
||||
record = getRecordFromPath(outFileName, volume, NULL, NULL);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFileRecord) {
|
||||
writeToHFSFile((HFSPlusCatalogFile*)record, inFile, volume);
|
||||
ret = TRUE;
|
||||
} else {
|
||||
printf("Not a file\n");
|
||||
exit(0);
|
||||
}
|
||||
} else {
|
||||
if(newFile(outFileName, volume)) {
|
||||
record = getRecordFromPath(outFileName, volume, NULL, NULL);
|
||||
writeToHFSFile((HFSPlusCatalogFile*)record, inFile, volume);
|
||||
ret = TRUE;
|
||||
} else {
|
||||
inFile->close(inFile);
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
inFile->close(inFile);
|
||||
if(record != NULL) {
|
||||
free(record);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void grow_hfs(Volume* volume, uint64_t newSize) {
|
||||
uint32_t newBlocks;
|
||||
uint32_t blocksToGrow;
|
||||
uint64_t newMapSize;
|
||||
uint64_t i;
|
||||
unsigned char zero;
|
||||
|
||||
zero = 0;
|
||||
|
||||
newBlocks = newSize / volume->volumeHeader->blockSize;
|
||||
|
||||
if(newBlocks <= volume->volumeHeader->totalBlocks) {
|
||||
printf("Cannot shrink volume\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blocksToGrow = newBlocks - volume->volumeHeader->totalBlocks;
|
||||
newMapSize = newBlocks / 8;
|
||||
|
||||
if(volume->volumeHeader->allocationFile.logicalSize < newMapSize) {
|
||||
if(volume->volumeHeader->freeBlocks
|
||||
< ((newMapSize - volume->volumeHeader->allocationFile.logicalSize) / volume->volumeHeader->blockSize)) {
|
||||
printf("Not enough room to allocate new allocation map blocks\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
allocate((RawFile*) (volume->allocationFile->data), newMapSize);
|
||||
}
|
||||
|
||||
/* unreserve last block */
|
||||
setBlockUsed(volume, volume->volumeHeader->totalBlocks - 1, 0);
|
||||
/* don't need to increment freeBlocks because we will allocate another alternate volume header later on */
|
||||
|
||||
/* "unallocate" the new blocks */
|
||||
for(i = ((volume->volumeHeader->totalBlocks / 8) + 1); i < newMapSize; i++) {
|
||||
ASSERT(WRITE(volume->allocationFile, i, 1, &zero), "WRITE");
|
||||
}
|
||||
|
||||
/* grow backing store size */
|
||||
ASSERT(WRITE(volume->image, newSize - 1, 1, &zero), "WRITE");
|
||||
|
||||
/* write new volume information */
|
||||
volume->volumeHeader->totalBlocks = newBlocks;
|
||||
volume->volumeHeader->freeBlocks += blocksToGrow;
|
||||
|
||||
/* reserve last block */
|
||||
setBlockUsed(volume, volume->volumeHeader->totalBlocks - 1, 1);
|
||||
|
||||
updateVolume(volume);
|
||||
}
|
||||
|
||||
void removeAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char fullName[1024];
|
||||
char* name;
|
||||
char* pathComponent;
|
||||
int pathLen;
|
||||
char isRoot;
|
||||
|
||||
HFSPlusCatalogFolder* folder;
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
strcpy(fullName, parentName);
|
||||
pathComponent = fullName + strlen(fullName);
|
||||
|
||||
isRoot = FALSE;
|
||||
if(strcmp(fullName, "/") == 0) {
|
||||
isRoot = TRUE;
|
||||
}
|
||||
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(isRoot && (name[0] == '\0' || strncmp(name, ".HFS+ Private Directory Data", sizeof(".HFS+ Private Directory Data") - 1) == 0)) {
|
||||
free(name);
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(pathComponent, name);
|
||||
pathLen = strlen(fullName);
|
||||
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
fullName[pathLen] = '/';
|
||||
fullName[pathLen + 1] = '\0';
|
||||
removeAllInFolder(folder->folderID, volume, fullName);
|
||||
} else {
|
||||
printf("%s\n", fullName);
|
||||
removeFile(fullName, volume);
|
||||
}
|
||||
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
|
||||
if(!isRoot) {
|
||||
*(pathComponent - 1) = '\0';
|
||||
printf("%s\n", fullName);
|
||||
removeFile(fullName, volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void addAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char cwd[1024];
|
||||
char fullName[1024];
|
||||
char testBuffer[1024];
|
||||
char* pathComponent;
|
||||
int pathLen;
|
||||
|
||||
char* name;
|
||||
|
||||
DIR* dir;
|
||||
DIR* tmp;
|
||||
|
||||
HFSCatalogNodeID cnid;
|
||||
|
||||
struct dirent* ent;
|
||||
|
||||
AbstractFile* file;
|
||||
HFSPlusCatalogFile* outFile;
|
||||
|
||||
strcpy(fullName, parentName);
|
||||
pathComponent = fullName + strlen(fullName);
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
ASSERT((dir = opendir(cwd)) != NULL, "opendir");
|
||||
|
||||
while((ent = readdir(dir)) != NULL) {
|
||||
if(ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(pathComponent, ent->d_name);
|
||||
pathLen = strlen(fullName);
|
||||
|
||||
cnid = 0;
|
||||
list = theList;
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(strcmp(name, ent->d_name) == 0) {
|
||||
cnid = (list->record->recordType == kHFSPlusFolderRecord) ? (((HFSPlusCatalogFolder*)list->record)->folderID)
|
||||
: (((HFSPlusCatalogFile*)list->record)->fileID);
|
||||
free(name);
|
||||
break;
|
||||
}
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if((tmp = opendir(ent->d_name)) != NULL) {
|
||||
closedir(tmp);
|
||||
printf("folder: %s\n", fullName); fflush(stdout);
|
||||
|
||||
if(cnid == 0) {
|
||||
cnid = newFolder(fullName, volume);
|
||||
}
|
||||
|
||||
fullName[pathLen] = '/';
|
||||
fullName[pathLen + 1] = '\0';
|
||||
ASSERT(chdir(ent->d_name) == 0, "chdir");
|
||||
addAllInFolder(cnid, volume, fullName);
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
} else {
|
||||
printf("file: %s\n", fullName); fflush(stdout);
|
||||
if(cnid == 0) {
|
||||
cnid = newFile(fullName, volume);
|
||||
}
|
||||
file = createAbstractFileFromFile(fopen(ent->d_name, "rb"));
|
||||
ASSERT(file != NULL, "fopen");
|
||||
outFile = (HFSPlusCatalogFile*)getRecordByCNID(cnid, volume);
|
||||
writeToHFSFile(outFile, file, volume);
|
||||
file->close(file);
|
||||
free(outFile);
|
||||
|
||||
if(strncmp(fullName, "/Applications/", sizeof("/Applications/") - 1) == 0) {
|
||||
testBuffer[0] = '\0';
|
||||
strcpy(testBuffer, "/Applications/");
|
||||
strcat(testBuffer, ent->d_name);
|
||||
strcat(testBuffer, ".app/");
|
||||
strcat(testBuffer, ent->d_name);
|
||||
if(strcmp(testBuffer, fullName) == 0) {
|
||||
if(strcmp(ent->d_name, "Installer") == 0
|
||||
|| strcmp(ent->d_name, "BootNeuter") == 0
|
||||
) {
|
||||
printf("Giving setuid permissions to %s...\n", fullName); fflush(stdout);
|
||||
chmodFile(fullName, 04755, volume);
|
||||
} else {
|
||||
printf("Giving permissions to %s\n", fullName); fflush(stdout);
|
||||
chmodFile(fullName, 0755, volume);
|
||||
}
|
||||
}
|
||||
} else if(strncmp(fullName, "/bin/", sizeof("/bin/") - 1) == 0
|
||||
|| strncmp(fullName, "/Applications/BootNeuter.app/bin/", sizeof("/Applications/BootNeuter.app/bin/") - 1) == 0
|
||||
|| strncmp(fullName, "/sbin/", sizeof("/sbin/") - 1) == 0
|
||||
|| strncmp(fullName, "/usr/sbin/", sizeof("/usr/sbin/") - 1) == 0
|
||||
|| strncmp(fullName, "/usr/bin/", sizeof("/usr/bin/") - 1) == 0
|
||||
|| strncmp(fullName, "/usr/libexec/", sizeof("/usr/libexec/") - 1) == 0
|
||||
|| strncmp(fullName, "/usr/local/bin/", sizeof("/usr/local/bin/") - 1) == 0
|
||||
|| strncmp(fullName, "/usr/local/sbin/", sizeof("/usr/local/sbin/") - 1) == 0
|
||||
|| strncmp(fullName, "/usr/local/libexec/", sizeof("/usr/local/libexec/") - 1) == 0
|
||||
) {
|
||||
chmodFile(fullName, 0755, volume);
|
||||
printf("Giving permissions to %s\n", fullName); fflush(stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
void extractAllInFolder(HFSCatalogNodeID folderID, Volume* volume) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
char cwd[1024];
|
||||
char* name;
|
||||
HFSPlusCatalogFolder* folder;
|
||||
HFSPlusCatalogFile* file;
|
||||
AbstractFile* outFile;
|
||||
struct stat status;
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
while(list != NULL) {
|
||||
name = unicodeToAscii(&list->name);
|
||||
if(strncmp(name, ".HFS+ Private Directory Data", sizeof(".HFS+ Private Directory Data") - 1) == 0 || name[0] == '\0') {
|
||||
free(name);
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
printf("folder: %s\n", name);
|
||||
if(stat(name, &status) != 0) {
|
||||
ASSERT(mkdir(name, 0755) == 0, "mkdir");
|
||||
}
|
||||
ASSERT(chdir(name) == 0, "chdir");
|
||||
extractAllInFolder(folder->folderID, volume);
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
} else if(list->record->recordType == kHFSPlusFileRecord) {
|
||||
printf("file: %s\n", name);
|
||||
file = (HFSPlusCatalogFile*)list->record;
|
||||
outFile = createAbstractFileFromFile(fopen(name, "wb"));
|
||||
if(outFile != NULL) {
|
||||
writeToFile(file, outFile, volume);
|
||||
outFile->close(outFile);
|
||||
} else {
|
||||
printf("WARNING: cannot fopen %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
free(name);
|
||||
list = list->next;
|
||||
}
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
|
||||
void addall_hfs(Volume* volume, const char* dirToMerge, const char* dest) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
char* name;
|
||||
char cwd[1024];
|
||||
char initPath[1024];
|
||||
int lastCharOfPath;
|
||||
|
||||
ASSERT(getcwd(cwd, 1024) != NULL, "cannot get current working directory");
|
||||
|
||||
if(chdir(dirToMerge) != 0) {
|
||||
printf("Cannot open that directory: %s\n", dirToMerge);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
record = getRecordFromPath(dest, volume, &name, NULL);
|
||||
strcpy(initPath, dest);
|
||||
lastCharOfPath = strlen(dest) - 1;
|
||||
if(dest[lastCharOfPath] != '/') {
|
||||
initPath[lastCharOfPath + 1] = '/';
|
||||
initPath[lastCharOfPath + 2] = '\0';
|
||||
}
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFolderRecord)
|
||||
addAllInFolder(((HFSPlusCatalogFolder*)record)->folderID, volume, initPath);
|
||||
else {
|
||||
printf("Not a folder\n");
|
||||
exit(0);
|
||||
}
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ASSERT(chdir(cwd) == 0, "chdir");
|
||||
free(record);
|
||||
|
||||
}
|
||||
int copyAcrossVolumes(Volume* volume1, Volume* volume2, char* path1, char* path2) {
|
||||
void* buffer;
|
||||
size_t bufferSize;
|
||||
AbstractFile* tmpFile;
|
||||
int ret;
|
||||
|
||||
buffer = malloc(1);
|
||||
bufferSize = 0;
|
||||
tmpFile = createAbstractFileFromMemoryFile((void**)&buffer, &bufferSize);
|
||||
|
||||
printf("retrieving... "); fflush(stdout);
|
||||
get_hfs(volume1, path1, tmpFile);
|
||||
tmpFile->seek(tmpFile, 0);
|
||||
printf("writing (%lld)... ", tmpFile->getLength(tmpFile)); fflush(stdout);
|
||||
ret = add_hfs(volume2, tmpFile, path2);
|
||||
printf("done\n");
|
||||
|
||||
free(buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void displayFolder(HFSCatalogNodeID folderID, Volume* volume) {
|
||||
CatalogRecordList* list;
|
||||
CatalogRecordList* theList;
|
||||
HFSPlusCatalogFolder* folder;
|
||||
HFSPlusCatalogFile* file;
|
||||
time_t fileTime;
|
||||
struct tm *date;
|
||||
|
||||
theList = list = getFolderContents(folderID, volume);
|
||||
|
||||
while(list != NULL) {
|
||||
if(list->record->recordType == kHFSPlusFolderRecord) {
|
||||
folder = (HFSPlusCatalogFolder*)list->record;
|
||||
printf("%06o ", folder->permissions.fileMode);
|
||||
printf("%3d ", folder->permissions.ownerID);
|
||||
printf("%3d ", folder->permissions.groupID);
|
||||
printf("%12d ", folder->valence);
|
||||
fileTime = APPLE_TO_UNIX_TIME(folder->contentModDate);
|
||||
} else if(list->record->recordType == kHFSPlusFileRecord) {
|
||||
file = (HFSPlusCatalogFile*)list->record;
|
||||
printf("%06o ", file->permissions.fileMode);
|
||||
printf("%3d ", file->permissions.ownerID);
|
||||
printf("%3d ", file->permissions.groupID);
|
||||
printf("%12lld ", file->dataFork.logicalSize);
|
||||
fileTime = APPLE_TO_UNIX_TIME(file->contentModDate);
|
||||
}
|
||||
|
||||
date = localtime(&fileTime);
|
||||
if(date != NULL) {
|
||||
printf("%2d/%2d/%4d %02d:%02d ", date->tm_mon, date->tm_mday, date->tm_year + 1900, date->tm_hour, date->tm_min);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printUnicode(&list->name);
|
||||
printf("\n");
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
releaseCatalogRecordList(theList);
|
||||
}
|
||||
|
||||
void displayFileLSLine(HFSPlusCatalogFile* file, const char* name) {
|
||||
time_t fileTime;
|
||||
struct tm *date;
|
||||
|
||||
printf("%06o ", file->permissions.fileMode);
|
||||
printf("%3d ", file->permissions.ownerID);
|
||||
printf("%3d ", file->permissions.groupID);
|
||||
printf("%12d ", file->dataFork.logicalSize);
|
||||
fileTime = APPLE_TO_UNIX_TIME(file->contentModDate);
|
||||
date = localtime(&fileTime);
|
||||
if(date != NULL) {
|
||||
printf("%2d/%2d/%4d %2d:%02d ", date->tm_mon, date->tm_mday, date->tm_year + 1900, date->tm_hour, date->tm_min);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%s\n", name);
|
||||
}
|
||||
|
||||
void hfs_ls(Volume* volume, const char* path) {
|
||||
HFSPlusCatalogRecord* record;
|
||||
char* name;
|
||||
|
||||
record = getRecordFromPath(path, volume, &name, NULL);
|
||||
|
||||
if(record != NULL) {
|
||||
if(record->recordType == kHFSPlusFolderRecord)
|
||||
displayFolder(((HFSPlusCatalogFolder*)record)->folderID, volume);
|
||||
else
|
||||
displayFileLSLine((HFSPlusCatalogFile*)record, name);
|
||||
} else {
|
||||
printf("No such file or directory\n");
|
||||
}
|
||||
|
||||
printf("Total filesystem size: %d, free: %d\n", (volume->volumeHeader->totalBlocks - volume->volumeHeader->freeBlocks) * volume->volumeHeader->blockSize, volume->volumeHeader->freeBlocks * volume->volumeHeader->blockSize);
|
||||
|
||||
free(record);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#include "common.h"
|
||||
#include "hfsplus.h"
|
||||
#include "abstractfile.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void writeToFile(HFSPlusCatalogFile* file, AbstractFile* output, Volume* volume);
|
||||
void writeToHFSFile(HFSPlusCatalogFile* file, AbstractFile* input, Volume* volume);
|
||||
void get_hfs(Volume* volume, const char* inFileName, AbstractFile* output);
|
||||
int add_hfs(Volume* volume, AbstractFile* inFile, const char* outFileName);
|
||||
void grow_hfs(Volume* volume, uint64_t newSize);
|
||||
void removeAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName);
|
||||
void addAllInFolder(HFSCatalogNodeID folderID, Volume* volume, const char* parentName);
|
||||
void addall_hfs(Volume* volume, const char* dirToMerge, const char* dest);
|
||||
void extractAllInFolder(HFSCatalogNodeID folderID, Volume* volume);
|
||||
int copyAcrossVolumes(Volume* volume1, Volume* volume2, char* path1, char* path2);
|
||||
|
||||
void hfs_ls(Volume* volume, const char* path);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Загрузка…
Ссылка в новой задаче