finish installer

This commit is contained in:
nakst 2021-09-16 11:34:54 +01:00
parent 975f41808d
commit 348f30df4e
9 changed files with 353 additions and 107 deletions

View File

@ -1,8 +1,3 @@
// TODO Report errors.
// TODO GPT support.
// TODO Handle crashing?
// TODO Write any modified settings during installation.
#define INSTALLER #define INSTALLER
#define ES_CRT_WITHOUT_PREFIX #define ES_CRT_WITHOUT_PREFIX
@ -16,8 +11,7 @@
#include <ports/lzma/LzmaDec.c> #include <ports/lzma/LzmaDec.c>
#define Log(...) #define Log(...)
// TODO Error handling. #define EsFSError() EsAssert(false)
#define exit(x) EsAssert(false)
#include <shared/esfs2.h> #include <shared/esfs2.h>
// Assume an additional 64MB of storage capacity is needed on top of totalUncompressedBytes. // Assume an additional 64MB of storage capacity is needed on top of totalUncompressedBytes.
@ -27,6 +21,7 @@
struct InstallerMetadata { struct InstallerMetadata {
uint64_t totalUncompressedBytes; uint64_t totalUncompressedBytes;
uint64_t crc64;
}; };
const EsStyle styleRoot = { const EsStyle styleRoot = {
@ -76,6 +71,8 @@ EsPanel *panelCustomizeOptions;
EsPanel *panelLicenses; EsPanel *panelLicenses;
EsPanel *panelWait; EsPanel *panelWait;
EsPanel *panelComplete; EsPanel *panelComplete;
EsPanel *panelError;
EsPanel *panelNotSupported;
EsTextbox *userNameTextbox; EsTextbox *userNameTextbox;
EsTextDisplay *progressDisplay; EsTextDisplay *progressDisplay;
const char *cSelectedFont; const char *cSelectedFont;
@ -90,6 +87,8 @@ EsFileOffset partitionBytes;
EsUniqueIdentifier installationIdentifier; EsUniqueIdentifier installationIdentifier;
EsMountPoint newFileSystemMountPoint; EsMountPoint newFileSystemMountPoint;
EsHandle mountNewFileSystemEvent; EsHandle mountNewFileSystemEvent;
EsError installError;
bool archiveCRCError;
///////////////////////////////////////////// /////////////////////////////////////////////
@ -160,7 +159,7 @@ EsError Extract(const char *pathIn, size_t pathInBytes, const char *pathOut, siz
e->inFileOffset = sizeof(header); e->inFileOffset = sizeof(header);
uint64_t crc64 = 0, actualCRC64 = 0; uint64_t crc64 = 0;
uint64_t totalBytesExtracted = 0; uint64_t totalBytesExtracted = 0;
uint8_t lastProgressByte = 0; uint8_t lastProgressByte = 0;
@ -169,7 +168,6 @@ EsError Extract(const char *pathIn, size_t pathInBytes, const char *pathOut, siz
while (true) { while (true) {
uint64_t fileSize; uint64_t fileSize;
if (!Decompress(e, &fileSize, sizeof(fileSize))) break; if (!Decompress(e, &fileSize, sizeof(fileSize))) break;
actualCRC64 = fileSize;
uint16_t nameBytes; uint16_t nameBytes;
if (!Decompress(e, &nameBytes, sizeof(nameBytes))) break; if (!Decompress(e, &nameBytes, sizeof(nameBytes))) break;
if (nameBytes > NAME_MAX - pathOutBytes) break; if (nameBytes > NAME_MAX - pathOutBytes) break;
@ -209,46 +207,56 @@ EsError Extract(const char *pathIn, size_t pathInBytes, const char *pathOut, siz
LzmaDec_Free(&e->state, &decompressAllocator); LzmaDec_Free(&e->state, &decompressAllocator);
EsHandleClose(e->fileIn.handle); EsHandleClose(e->fileIn.handle);
return crc64 == actualCRC64 ? ES_SUCCESS : ES_ERROR_CORRUPT_DATA; return crc64 == metadata->crc64 ? ES_SUCCESS : ES_ERROR_CORRUPT_DATA;
} }
///////////////////////////////////////////// /////////////////////////////////////////////
// TODO Error handling.
uint64_t writeOffset; uint64_t writeOffset;
uint64_t writeBytes; uint64_t writeBytes;
uint8_t writeBuffer[BUFFER_SIZE]; uint8_t writeBuffer[BUFFER_SIZE];
EsError formatError = ES_SUCCESS;
void FlushWriteBuffer() { bool FlushWriteBuffer() {
if (!writeBytes) return; if (!writeBytes) return true;
EsFileOffset parameters[2] = { partitionOffset * blockDeviceInformation.sectorSize + writeOffset, writeBytes }; EsFileOffset parameters[2] = { partitionOffset * blockDeviceInformation.sectorSize + writeOffset, writeBytes };
EsError error = EsDeviceControl(driveHandle, ES_DEVICE_CONTROL_BLOCK_WRITE, writeBuffer, parameters); EsError error = EsDeviceControl(driveHandle, ES_DEVICE_CONTROL_BLOCK_WRITE, writeBuffer, parameters);
EsAssert(error == ES_SUCCESS);
writeBytes = 0; writeBytes = 0;
if (error != ES_SUCCESS) formatError = error;
return error == ES_SUCCESS;
} }
void ReadBlock(uint64_t block, uint64_t count, void *buffer) { bool ReadBlock(uint64_t block, uint64_t count, void *buffer) {
if (!FlushWriteBuffer()) {
return false;
}
EsFileOffset parameters[2] = { partitionOffset * blockDeviceInformation.sectorSize + block * blockSize, count * blockSize }; EsFileOffset parameters[2] = { partitionOffset * blockDeviceInformation.sectorSize + block * blockSize, count * blockSize };
EsError error = EsDeviceControl(driveHandle, ES_DEVICE_CONTROL_BLOCK_READ, buffer, parameters); EsError error = EsDeviceControl(driveHandle, ES_DEVICE_CONTROL_BLOCK_READ, buffer, parameters);
EsAssert(error == ES_SUCCESS); if (error != ES_SUCCESS) formatError = error;
return error == ES_SUCCESS;
} }
void WriteBlock(uint64_t block, uint64_t count, void *buffer) { bool WriteBlock(uint64_t block, uint64_t count, void *buffer) {
uint64_t offset = block * blockSize, bytes = count * blockSize; uint64_t offset = block * blockSize, bytes = count * blockSize;
if (writeBytes && writeOffset + writeBytes == offset && writeBytes + bytes < sizeof(writeBuffer)) { if (writeBytes && writeOffset + writeBytes == offset && writeBytes + bytes < sizeof(writeBuffer)) {
EsMemoryCopy(writeBuffer + writeBytes, buffer, bytes); EsMemoryCopy(writeBuffer + writeBytes, buffer, bytes);
writeBytes += bytes; writeBytes += bytes;
return true;
} else { } else {
FlushWriteBuffer(); if (!FlushWriteBuffer()) {
return false;
}
writeOffset = offset; writeOffset = offset;
writeBytes = bytes; writeBytes = bytes;
EsMemoryCopy(writeBuffer, buffer, bytes); EsMemoryCopy(writeBuffer, buffer, bytes);
return true;
} }
} }
void WriteBytes(uint64_t byteOffset, uint64_t byteCount, void *buffer) { bool WriteBytes(uint64_t byteOffset, uint64_t byteCount, void *buffer) {
uint64_t firstSector = byteOffset / blockDeviceInformation.sectorSize; uint64_t firstSector = byteOffset / blockDeviceInformation.sectorSize;
uint64_t lastSector = (byteOffset + byteCount - 1) / blockDeviceInformation.sectorSize; uint64_t lastSector = (byteOffset + byteCount - 1) / blockDeviceInformation.sectorSize;
uint64_t sectorCount = lastSector - firstSector + 1; uint64_t sectorCount = lastSector - firstSector + 1;
@ -259,16 +267,25 @@ void WriteBytes(uint64_t byteOffset, uint64_t byteCount, void *buffer) {
if (i > 0 && i < sectorCount - 1) continue; if (i > 0 && i < sectorCount - 1) continue;
EsFileOffset parameters[2] = { (partitionOffset + firstSector + i) * blockDeviceInformation.sectorSize, blockDeviceInformation.sectorSize } ; EsFileOffset parameters[2] = { (partitionOffset + firstSector + i) * blockDeviceInformation.sectorSize, blockDeviceInformation.sectorSize } ;
EsError error = EsDeviceControl(driveHandle, ES_DEVICE_CONTROL_BLOCK_READ, (uint8_t *) buffer2 + i * blockDeviceInformation.sectorSize, parameters); EsError error = EsDeviceControl(driveHandle, ES_DEVICE_CONTROL_BLOCK_READ, (uint8_t *) buffer2 + i * blockDeviceInformation.sectorSize, parameters);
EsAssert(error == ES_SUCCESS);
if (error != ES_SUCCESS) {
formatError = error;
return false;
}
} }
EsMemoryCopy((uint8_t *) buffer2 + byteOffset % blockDeviceInformation.sectorSize, buffer, byteCount); EsMemoryCopy((uint8_t *) buffer2 + byteOffset % blockDeviceInformation.sectorSize, buffer, byteCount);
EsFileOffset parameters[2] = { (partitionOffset + firstSector) * blockDeviceInformation.sectorSize, sectorCount * blockDeviceInformation.sectorSize }; EsFileOffset parameters[2] = { (partitionOffset + firstSector) * blockDeviceInformation.sectorSize, sectorCount * blockDeviceInformation.sectorSize };
EsError error = EsDeviceControl(driveHandle, ES_DEVICE_CONTROL_BLOCK_WRITE, buffer, parameters); EsError error = EsDeviceControl(driveHandle, ES_DEVICE_CONTROL_BLOCK_WRITE, buffer, parameters);
EsAssert(error == ES_SUCCESS);
if (error != ES_SUCCESS) {
formatError = error;
return false;
}
EsHeapFree(buffer2); EsHeapFree(buffer2);
return true;
} }
///////////////////////////////////////////// /////////////////////////////////////////////
@ -828,6 +845,10 @@ EsError Install() {
Format(partitionBytes, interfaceString_InstallerVolumeLabel, installationIdentifier, kernel, kernelBytes); Format(partitionBytes, interfaceString_InstallerVolumeLabel, installationIdentifier, kernel, kernelBytes);
FlushWriteBuffer(); FlushWriteBuffer();
if (formatError != ES_SUCCESS) {
return formatError;
}
m.user.context1.u = 8; m.user.context1.u = 8;
EsMessagePost(nullptr, &m); EsMessagePost(nullptr, &m);
@ -843,22 +864,60 @@ EsError Install() {
} }
error = Extract(EsLiteral("0:/installer_archive.dat"), newFileSystemMountPoint.prefix, newFileSystemMountPoint.prefixBytes); error = Extract(EsLiteral("0:/installer_archive.dat"), newFileSystemMountPoint.prefix, newFileSystemMountPoint.prefixBytes);
if (error != ES_SUCCESS) return error;
if (error == ES_ERROR_CORRUPT_DATA) {
archiveCRCError = true;
}
if (error != ES_SUCCESS) {
return error;
}
return ES_SUCCESS; return ES_SUCCESS;
} }
void InstallThread(EsGeneric) { void InstallThread(EsGeneric) {
EsPerformanceTimerPush(); EsPerformanceTimerPush();
EsError error = Install(); installError = Install();
EsAssert(error == ES_SUCCESS); // TODO Reporting errors. EsPrint("Installation finished in %Fs. Extracted %D from the archive. Error code = %d.\n", EsPerformanceTimerPop(), metadata->totalUncompressedBytes, installError);
EsPrint("Installation finished in %Fs. Extracted %D from the archive.\n", EsPerformanceTimerPop(), metadata->totalUncompressedBytes);
EsMessage m = { MSG_SET_PROGRESS }; EsMessage m = { MSG_SET_PROGRESS };
m.user.context1.u = 100; m.user.context1.u = 100;
EsMessagePost(nullptr, &m); EsMessagePost(nullptr, &m);
} }
void WriteNewConfiguration() {
size_t newSystemConfigurationPathBytes, newSystemConfigurationBytes;
char *newSystemConfigurationPath = EsStringAllocateAndFormat(&newSystemConfigurationPathBytes, "%s/Essence/Default.ini",
newFileSystemMountPoint.prefixBytes, newFileSystemMountPoint.prefix);
char *newSystemConfiguration = (char *) EsFileReadAll(newSystemConfigurationPath, newSystemConfigurationPathBytes, &newSystemConfigurationBytes);
size_t lineBufferBytes = 4096;
char *lineBuffer = (char *) EsHeapAllocate(lineBufferBytes, false);
EsINIState s = { .buffer = newSystemConfiguration, .bytes = newSystemConfigurationBytes };
EsBuffer buffer = { .canGrow = true };
while (EsINIParse(&s)) {
if (!s.sectionClassBytes && 0 == EsStringCompareRaw(s.section, s.sectionBytes, EsLiteral("ui"))
&& 0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("font_sans"))) {
EsBufferFormat(&buffer, "font_sans=%z\n", cSelectedFont);
} else if (!s.sectionClassBytes && 0 == EsStringCompareRaw(s.section, s.sectionBytes, EsLiteral("general"))
&& 0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("installation_state"))) {
EsBufferFormat(&buffer, "installation_state=0\n");
} else {
size_t lineBytes = EsINIFormat(&s, lineBuffer, lineBufferBytes);
EsBufferWrite(&buffer, lineBuffer, lineBytes);
EsAssert(lineBytes < lineBufferBytes);
}
}
EsFileWriteAll(newSystemConfigurationPath, newSystemConfigurationPathBytes, buffer.out, buffer.position);
EsHeapFree(newSystemConfigurationPath);
EsHeapFree(buffer.out);
EsHeapFree(lineBuffer);
}
///////////////////////////////////////////// /////////////////////////////////////////////
void ButtonViewLicenses(EsInstance *, EsElement *, EsCommand *) { void ButtonViewLicenses(EsInstance *, EsElement *, EsCommand *) {
@ -894,9 +953,35 @@ void ButtonFont(EsInstance *, EsElement *element, EsCommand *) {
} }
} }
void Complete() {
if (installError == ES_SUCCESS) {
WriteNewConfiguration();
EsPanelSwitchTo(switcher, panelComplete, ES_TRANSITION_FADE_IN);
} else {
EsPanel *row = EsPanelCreate(panelError, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL);
EsIconDisplayCreate(row, ES_FLAGS_DEFAULT, 0, ES_ICON_DIALOG_ERROR);
EsSpacerCreate(row, ES_FLAGS_DEFAULT, 0, 15, 0);
if (installError == ES_ERROR_INSUFFICIENT_RESOURCES) {
EsTextDisplayCreate(row, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(InstallerFailedResources));
} else if (archiveCRCError) {
EsTextDisplayCreate(row, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(InstallerFailedArchiveCRCError));
} else {
EsTextDisplayCreate(row, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(InstallerFailedGeneric));
}
EsSpacerCreate(panelError, ES_CELL_FILL);
EsPanel *buttonsRow = EsPanelCreate(panelError, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleButtonsRow);
EsSpacerCreate(buttonsRow, ES_CELL_H_FILL);
EsButtonOnCommand(EsButtonCreate(buttonsRow, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(DesktopRestartAction)), ButtonRestart);
EsPanelSwitchTo(switcher, panelError, ES_TRANSITION_FADE_IN);
}
}
void ButtonFinish(EsInstance *, EsElement *, EsCommand *) { void ButtonFinish(EsInstance *, EsElement *, EsCommand *) {
if (progress == 100) { if (progress == 100) {
EsPanelSwitchTo(switcher, panelComplete, ES_TRANSITION_FADE_IN); Complete();
} else { } else {
onWaitScreen = true; onWaitScreen = true;
EsPanelSwitchTo(switcher, panelWait, ES_TRANSITION_FADE_IN); EsPanelSwitchTo(switcher, panelWait, ES_TRANSITION_FADE_IN);
@ -960,7 +1045,6 @@ void _start() {
{ {
panelInstallOptions = EsPanelCreate(switcher, ES_CELL_H_FILL, &styleRoot); panelInstallOptions = EsPanelCreate(switcher, ES_CELL_H_FILL, &styleRoot);
EsPanelSwitchTo(switcher, panelInstallOptions, ES_TRANSITION_NONE);
EsTextDisplayCreate(panelInstallOptions, ES_CELL_H_FILL, ES_STYLE_TEXT_HEADING0, INTERFACE_STRING(InstallerTitle)); EsTextDisplayCreate(panelInstallOptions, ES_CELL_H_FILL, ES_STYLE_TEXT_HEADING0, INTERFACE_STRING(InstallerTitle));
EsPanel *drivesPanel = EsPanelCreate(panelInstallOptions, ES_CELL_H_FILL, ES_STYLE_PANEL_INSET); EsPanel *drivesPanel = EsPanelCreate(panelInstallOptions, ES_CELL_H_FILL, ES_STYLE_PANEL_INSET);
@ -1049,14 +1133,45 @@ void _start() {
EsTextDisplayCreate(panelComplete, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(InstallerCompleteFromOther)); EsTextDisplayCreate(panelComplete, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(InstallerCompleteFromOther));
} }
// TODO Failure messages.
EsSpacerCreate(panelComplete, ES_CELL_FILL); EsSpacerCreate(panelComplete, ES_CELL_FILL);
EsPanel *buttonsRow = EsPanelCreate(panelComplete, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleButtonsRow); EsPanel *buttonsRow = EsPanelCreate(panelComplete, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleButtonsRow);
EsSpacerCreate(buttonsRow, ES_CELL_H_FILL); EsSpacerCreate(buttonsRow, ES_CELL_H_FILL);
EsButtonOnCommand(EsButtonCreate(buttonsRow, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(DesktopRestartAction)), ButtonRestart); EsButtonOnCommand(EsButtonCreate(buttonsRow, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(DesktopRestartAction)), ButtonRestart);
} }
{
panelError = EsPanelCreate(switcher, ES_CELL_FILL, &styleRoot);
EsTextDisplayCreate(panelError, ES_CELL_H_FILL, ES_STYLE_TEXT_HEADING0, INTERFACE_STRING(InstallerTitle));
// Contents is created in Complete().
}
{
panelNotSupported = EsPanelCreate(switcher, ES_CELL_FILL, &styleRoot);
EsTextDisplayCreate(panelNotSupported, ES_CELL_H_FILL, ES_STYLE_TEXT_HEADING0, INTERFACE_STRING(InstallerTitle));
EsPanel *row = EsPanelCreate(panelNotSupported, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL);
EsIconDisplayCreate(row, ES_FLAGS_DEFAULT, 0, ES_ICON_DIALOG_ERROR);
EsSpacerCreate(row, ES_FLAGS_DEFAULT, 0, 15, 0);
EsTextDisplayCreate(row, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(InstallerNotSupported));
EsSpacerCreate(panelNotSupported, ES_CELL_FILL);
EsPanel *buttonsRow = EsPanelCreate(panelNotSupported, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleButtonsRow);
EsSpacerCreate(buttonsRow, ES_CELL_H_FILL);
EsButtonOnCommand(EsButtonCreate(buttonsRow, ES_FLAGS_DEFAULT, 0, INTERFACE_STRING(DesktopRestartAction)), ButtonRestart);
}
{
MemoryAvailable available;
EsSyscall(ES_SYSCALL_MEMORY_GET_AVAILABLE, (uintptr_t) &available, 0, 0, 0);
if (available.total < 64 * 1024 * 1024) {
EsPanelSwitchTo(switcher, panelNotSupported, ES_TRANSITION_NONE);
} else {
EsPanelSwitchTo(switcher, panelInstallOptions, ES_TRANSITION_NONE);
}
}
EsDeviceEnumerate([] (EsMessageDevice device, EsGeneric) { EsDeviceEnumerate([] (EsMessageDevice device, EsGeneric) {
ConnectedDriveAdd(device); ConnectedDriveAdd(device);
}, 0); }, 0);
@ -1101,7 +1216,7 @@ void _start() {
if (onWaitScreen && progress == 100) { if (onWaitScreen && progress == 100) {
onWaitScreen = false; onWaitScreen = false;
EsPanelSwitchTo(switcher, panelComplete, ES_TRANSITION_FADE_IN); Complete();
} }
} }
} }

View File

@ -1654,6 +1654,12 @@ void ApplicationInstanceCrashed(EsMessage *message) {
} }
application->singleInstance = nullptr; application->singleInstance = nullptr;
if (desktop.installationState == INSTALLATION_STATE_INSTALLER && desktop.installer == application) {
// Restart the installer.
ApplicationInstanceCreate(desktop.installer->id, nullptr, nullptr, true /* hidden */);
}
ApplicationTemporaryDestroy(application); ApplicationTemporaryDestroy(application);
} }

View File

@ -762,6 +762,7 @@ enum EsSyscallType {
ES_SYSCALL_MEMORY_OPEN ES_SYSCALL_MEMORY_OPEN
ES_SYSCALL_MEMORY_COMMIT ES_SYSCALL_MEMORY_COMMIT
ES_SYSCALL_MEMORY_FAULT_RANGE ES_SYSCALL_MEMORY_FAULT_RANGE
ES_SYSCALL_MEMORY_GET_AVAILABLE
// Processing. // Processing.

View File

@ -274,6 +274,11 @@ struct BundleFile {
uint64_t offset; uint64_t offset;
}; };
struct MemoryAvailable {
size_t available;
size_t total;
};
#ifdef KERNEL #ifdef KERNEL
#define K_BOOT_DRIVE "" #define K_BOOT_DRIVE ""
#else #else

View File

@ -217,6 +217,15 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_FAULT_RANGE) {
SYSCALL_RETURN(success ? ES_SUCCESS : ES_FATAL_ERROR_INVALID_BUFFER, !success); SYSCALL_RETURN(success ? ES_SUCCESS : ES_FATAL_ERROR_INVALID_BUFFER, !success);
} }
SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_GET_AVAILABLE) {
MemoryAvailable available;
EsMemoryZero(&available, sizeof(MemoryAvailable));
available.available = MM_REMAINING_COMMIT() * K_PAGE_SIZE;
available.total = pmm.commitLimit * K_PAGE_SIZE;
SYSCALL_WRITE(argument0, &available, sizeof(MemoryAvailable));
SYSCALL_RETURN(ES_SUCCESS, false);
}
SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_CREATE) { SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_CREATE) {
EsProcessCreationArguments arguments; EsProcessCreationArguments arguments;
SYSCALL_READ(&arguments, argument0, sizeof(EsProcessCreationArguments)); SYSCALL_READ(&arguments, argument0, sizeof(EsProcessCreationArguments));

View File

@ -267,23 +267,32 @@ Superblock superblock;
GroupDescriptor *groupDescriptorTable; GroupDescriptor *groupDescriptorTable;
uint64_t copiedCount; uint64_t copiedCount;
void ReadBlock(uint64_t block, uint64_t count, void *buffer); bool ReadBlock(uint64_t block, uint64_t count, void *buffer);
void WriteBlock(uint64_t block, uint64_t count, void *buffer); bool WriteBlock(uint64_t block, uint64_t count, void *buffer);
void WriteBytes(uint64_t offset, uint64_t count, void *buffer); bool WriteBytes(uint64_t offset, uint64_t count, void *buffer);
void ReadDirectoryEntryReference(DirectoryEntryReference reference, DirectoryEntry *entry) { bool ReadDirectoryEntryReference(DirectoryEntryReference reference, DirectoryEntry *entry) {
uint8_t buffer[superblock.blockSize]; uint8_t buffer[superblock.blockSize];
ReadBlock(reference.block, 1, buffer);
if (!ReadBlock(reference.block, 1, buffer)) {
return false;
}
memcpy(entry, buffer + reference.offsetIntoBlock, sizeof(DirectoryEntry)); memcpy(entry, buffer + reference.offsetIntoBlock, sizeof(DirectoryEntry));
return true;
} }
void WriteDirectoryEntryReference(DirectoryEntryReference reference, DirectoryEntry *entry) { bool WriteDirectoryEntryReference(DirectoryEntryReference reference, DirectoryEntry *entry) {
entry->checksum = 0; entry->checksum = 0;
entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0); entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0);
uint8_t buffer[superblock.blockSize]; uint8_t buffer[superblock.blockSize];
ReadBlock(reference.block, 1, buffer);
memcpy(buffer + reference.offsetIntoBlock, entry, sizeof(DirectoryEntry)); if (ReadBlock(reference.block, 1, buffer)) {
WriteBlock(reference.block, 1, buffer); memcpy(buffer + reference.offsetIntoBlock, entry, sizeof(DirectoryEntry));
return WriteBlock(reference.block, 1, buffer);
} else {
return false;
}
} }
Attribute *FindAttribute(DirectoryEntry *entry, uint16_t type) { Attribute *FindAttribute(DirectoryEntry *entry, uint16_t type) {
@ -295,7 +304,7 @@ Attribute *FindAttribute(DirectoryEntry *entry, uint16_t type) {
if (count++ == entry->attributeCount) { if (count++ == entry->attributeCount) {
Log("Could not find attribute %d.\n", type); Log("Could not find attribute %d.\n", type);
exit(1); EsFSError();
} }
} }
@ -346,7 +355,7 @@ IndexKey *InsertKeyIntoVertex(uint64_t newKey, IndexVertex *vertex) {
return insertionPosition; return insertionPosition;
} }
void AllocateExtent(uint64_t increaseBlocks, uint64_t *extentStart, uint64_t *extentCount) { bool AllocateExtent(uint64_t increaseBlocks, uint64_t *extentStart, uint64_t *extentCount) {
// Log("used %ld/%ld, need %ld more\n", superblock.blocksUsed, superblock.blockCount, increaseBlocks); // Log("used %ld/%ld, need %ld more\n", superblock.blocksUsed, superblock.blockCount, increaseBlocks);
// Find a group to allocate the next extent from. // Find a group to allocate the next extent from.
@ -373,7 +382,7 @@ void AllocateExtent(uint64_t increaseBlocks, uint64_t *extentStart, uint64_t *ex
if (!target) { if (!target) {
Log("Out of space.\n"); Log("Out of space.\n");
exit(1); EsFSError();
} }
// Load the bitmap, find the largest extent, and mark it as in use. // Load the bitmap, find the largest extent, and mark it as in use.
@ -382,7 +391,9 @@ void AllocateExtent(uint64_t increaseBlocks, uint64_t *extentStart, uint64_t *ex
{ {
if (target->blockBitmap) { if (target->blockBitmap) {
ReadBlock(target->blockBitmap, superblock.blocksPerGroupBlockBitmap, bitmap); if (!ReadBlock(target->blockBitmap, superblock.blocksPerGroupBlockBitmap, bitmap)) {
return false;
}
} else { } else {
memset(bitmap, 0, superblock.blocksPerGroupBlockBitmap * superblock.blockSize); memset(bitmap, 0, superblock.blocksPerGroupBlockBitmap * superblock.blockSize);
for (uint64_t i = 0; i < superblock.blocksPerGroupBlockBitmap; i++) bitmap[i / 8] |= 1 << (i % 8); for (uint64_t i = 0; i < superblock.blocksPerGroupBlockBitmap; i++) bitmap[i / 8] |= 1 << (i % 8);
@ -453,25 +464,28 @@ void AllocateExtent(uint64_t increaseBlocks, uint64_t *extentStart, uint64_t *ex
target->checksum = 0; target->checksum = 0;
target->checksum = CalculateCRC32(target, sizeof(GroupDescriptor), 0); target->checksum = CalculateCRC32(target, sizeof(GroupDescriptor), 0);
WriteBlock(target->blockBitmap, superblock.blocksPerGroupBlockBitmap, bitmap); if (!WriteBlock(target->blockBitmap, superblock.blocksPerGroupBlockBitmap, bitmap)) {
return false;
}
} }
*extentStart = *extentStart + (target - groupDescriptorTable) * superblock.blocksPerGroup; *extentStart = *extentStart + (target - groupDescriptorTable) * superblock.blocksPerGroup;
superblock.blocksUsed += *extentCount; superblock.blocksUsed += *extentCount;
// Log("allocate extent: %ld -> %ld (for %ld)\n", extentStart, extentStart + extentCount, increaseBlocks); // Log("allocate extent: %ld -> %ld (for %ld)\n", extentStart, extentStart + extentCount, increaseBlocks);
return true;
} }
void AccessNode(DirectoryEntry *node, void *buffer, uint64_t offsetIntoFile, uint64_t totalCount, DirectoryEntryReference *reference, bool read) { bool AccessNode(DirectoryEntry *node, void *buffer, uint64_t offsetIntoFile, uint64_t totalCount, DirectoryEntryReference *reference, bool read) {
if (!totalCount) return; if (!totalCount) return true;
AttributeData *dataAttribute = (AttributeData *) FindAttribute(node, ESFS_ATTRIBUTE_DATA); AttributeData *dataAttribute = (AttributeData *) FindAttribute(node, ESFS_ATTRIBUTE_DATA);
if (dataAttribute->indirection == ESFS_INDIRECTION_DIRECT && read) { if (dataAttribute->indirection == ESFS_INDIRECTION_DIRECT && read) {
memcpy(buffer, dataAttribute->data + offsetIntoFile, totalCount); memcpy(buffer, dataAttribute->data + offsetIntoFile, totalCount);
return; return true;
} else if (dataAttribute->indirection == ESFS_INDIRECTION_DIRECT && !read) { } else if (dataAttribute->indirection == ESFS_INDIRECTION_DIRECT && !read) {
assert(!reference); assert(!reference);
memcpy(dataAttribute->data + offsetIntoFile, buffer, totalCount); memcpy(dataAttribute->data + offsetIntoFile, buffer, totalCount);
return; return true;
} }
assert(dataAttribute->indirection == ESFS_INDIRECTION_L1); assert(dataAttribute->indirection == ESFS_INDIRECTION_L1);
@ -521,14 +535,19 @@ void AccessNode(DirectoryEntry *node, void *buffer, uint64_t offsetIntoFile, uin
uint8_t blockBuffer[superblock.blockSize]; uint8_t blockBuffer[superblock.blockSize];
if (read || count != superblock.blockSize) { if (read || count != superblock.blockSize) {
ReadBlock(block, 1, blockBuffer); if (!ReadBlock(block, 1, blockBuffer)) {
return false;
}
} }
if (read) { if (read) {
memcpy(buffer, blockBuffer + offset, count); memcpy(buffer, blockBuffer + offset, count);
} else { } else {
memcpy(blockBuffer + offset, buffer, count); memcpy(blockBuffer + offset, buffer, count);
WriteBlock(block, 1, blockBuffer);
if (!WriteBlock(block, 1, blockBuffer)) {
return false;
}
} }
if (reference) { if (reference) {
@ -543,9 +562,11 @@ void AccessNode(DirectoryEntry *node, void *buffer, uint64_t offsetIntoFile, uin
buffer = (uint8_t *) buffer + count; buffer = (uint8_t *) buffer + count;
goto next; goto next;
} }
return true;
} }
void ResizeNode(DirectoryEntry *entry, uint64_t newSize) { bool ResizeNode(DirectoryEntry *entry, uint64_t newSize) {
assert(newSize >= entry->fileSize); assert(newSize >= entry->fileSize);
AttributeData *dataAttribute = (AttributeData *) FindAttribute(entry, ESFS_ATTRIBUTE_DATA); AttributeData *dataAttribute = (AttributeData *) FindAttribute(entry, ESFS_ATTRIBUTE_DATA);
@ -553,7 +574,7 @@ void ResizeNode(DirectoryEntry *entry, uint64_t newSize) {
if (newSize < (uint64_t) (dataAttribute->size - dataAttribute->dataOffset) && entry->nodeType == ESFS_NODE_TYPE_FILE) { if (newSize < (uint64_t) (dataAttribute->size - dataAttribute->dataOffset) && entry->nodeType == ESFS_NODE_TYPE_FILE) {
dataAttribute->indirection = ESFS_INDIRECTION_DIRECT; dataAttribute->indirection = ESFS_INDIRECTION_DIRECT;
dataAttribute->count = entry->fileSize = newSize; dataAttribute->count = entry->fileSize = newSize;
return; return true;
} }
// Log("\tresize to %lu\n", newSize); // Log("\tresize to %lu\n", newSize);
@ -588,7 +609,9 @@ void ResizeNode(DirectoryEntry *entry, uint64_t newSize) {
uint64_t extentStart, extentCount, encodedLength; uint64_t extentStart, extentCount, encodedLength;
uint8_t encode[32]; uint8_t encode[32];
AllocateExtent(increaseBlocks, &extentStart, &extentCount); if (!AllocateExtent(increaseBlocks, &extentStart, &extentCount)) {
return false;
}
if (extentStart == previousExtentStart + previousExtentCount) { if (extentStart == previousExtentStart + previousExtentCount) {
dataAttribute->count--; dataAttribute->count--;
@ -604,7 +627,7 @@ void ResizeNode(DirectoryEntry *entry, uint64_t newSize) {
if (offsetIntoExtentList + encodedLength > (uint64_t) (dataAttribute->size - dataAttribute->dataOffset)) { if (offsetIntoExtentList + encodedLength > (uint64_t) (dataAttribute->size - dataAttribute->dataOffset)) {
Log("Unimplemented - indirection past L1.\n"); Log("Unimplemented - indirection past L1.\n");
exit(1); EsFSError();
} }
memcpy(extents + offsetIntoExtentList, encode, encodedLength); memcpy(extents + offsetIntoExtentList, encode, encodedLength);
@ -615,8 +638,10 @@ void ResizeNode(DirectoryEntry *entry, uint64_t newSize) {
} }
} else { } else {
Log("Unimplemented - node truncation.\n"); Log("Unimplemented - node truncation.\n");
exit(1); EsFSError();
} }
return true;
} }
#if 0 #if 0
@ -702,7 +727,7 @@ void NewDirectoryEntry(DirectoryEntry *entry, uint8_t nodeType, EsUniqueIdentifi
entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0); entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0);
} }
void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, DirectoryEntryReference *outputReference, bool AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, DirectoryEntryReference *outputReference,
DirectoryEntryReference directoryReference) { DirectoryEntryReference directoryReference) {
// Log("add %s to %s\n", name, path); // Log("add %s to %s\n", name, path);
@ -710,7 +735,7 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
DirectoryEntry directory; DirectoryEntry directory;
ReadDirectoryEntryReference(directoryReference, &directory); if (!ReadDirectoryEntryReference(directoryReference, &directory)) return false;
AttributeData *dataAttribute = (AttributeData *) FindAttribute(&directory, ESFS_ATTRIBUTE_DATA); AttributeData *dataAttribute = (AttributeData *) FindAttribute(&directory, ESFS_ATTRIBUTE_DATA);
AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY); AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY);
@ -720,12 +745,15 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
if (!(directoryAttribute->childNodes % superblock.directoryEntriesPerBlock)) { if (!(directoryAttribute->childNodes % superblock.directoryEntriesPerBlock)) {
// Log("increasing directory to fit %ld entries\n========={\n", (directory.fileSize + superblock.blockSize) / sizeof(DirectoryEntry)); // Log("increasing directory to fit %ld entries\n========={\n", (directory.fileSize + superblock.blockSize) / sizeof(DirectoryEntry));
ResizeNode(&directory, directory.fileSize + superblock.blockSize); if (!ResizeNode(&directory, directory.fileSize + superblock.blockSize)) return false;
// Log("========}\n"); // Log("========}\n");
} }
directoryAttribute->childNodes++; directoryAttribute->childNodes++;
WriteDirectoryEntryReference(directoryReference, &directory);
if (!WriteDirectoryEntryReference(directoryReference, &directory)) {
return false;
}
} }
// Step 2: Create the directory entry, and write it to the directory. // Step 2: Create the directory entry, and write it to the directory.
@ -736,7 +764,10 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
{ {
NewDirectoryEntry(&entry, nodeType, directory.identifier, name); NewDirectoryEntry(&entry, nodeType, directory.identifier, name);
// Log("\tchild nodes: %ld\n", directoryAttribute->childNodes); // Log("\tchild nodes: %ld\n", directoryAttribute->childNodes);
AccessNode(&directory, &entry, (directoryAttribute->childNodes - 1) * sizeof(DirectoryEntry), sizeof(DirectoryEntry), &reference, false);
if (!AccessNode(&directory, &entry, (directoryAttribute->childNodes - 1) * sizeof(DirectoryEntry), sizeof(DirectoryEntry), &reference, false)) {
return false;
}
} }
// Step 3: Add the node into the index. // Step 3: Add the node into the index.
@ -756,14 +787,20 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
// Directory is empty - create the root vertex. // Directory is empty - create the root vertex.
uint64_t _unused; uint64_t _unused;
AllocateExtent(1, &directoryAttribute->indexRootBlock, &_unused);
if (!AllocateExtent(1, &directoryAttribute->indexRootBlock, &_unused)) {
return false;
}
blocks[0] = directoryAttribute->indexRootBlock; blocks[0] = directoryAttribute->indexRootBlock;
vertex->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; vertex->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */;
vertex->offset = ESFS_INDEX_KEY_OFFSET; vertex->offset = ESFS_INDEX_KEY_OFFSET;
memcpy(vertex->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4); memcpy(vertex->signature, ESFS_INDEX_VERTEX_SIGNATURE, 4);
// Log("rootBlock = %ld for %s\n", directoryAttribute->indexRootBlock, path); // Log("rootBlock = %ld for %s\n", directoryAttribute->indexRootBlock, path);
} else { } else {
ReadBlock(blocks[0], 1, vertex); if (!ReadBlock(blocks[0], 1, vertex)) {
return false;
}
// Log("start = %ld for %s\n", blocks[0], path); // Log("start = %ld for %s\n", blocks[0], path);
} }
@ -772,7 +809,7 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
if (ESFS_VERTEX_KEY(vertex, i)->value == newKey) { if (ESFS_VERTEX_KEY(vertex, i)->value == newKey) {
// The key is already in the tree. // The key is already in the tree.
Log("The file already exists."); Log("The file already exists.");
exit(1); EsFSError();
} }
} }
@ -781,7 +818,11 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
if ((i == vertex->count || newKey < key->value) && key->child) { if ((i == vertex->count || newKey < key->value) && key->child) {
blocks[++depth] = key->child; blocks[++depth] = key->child;
ReadBlock(key->child, 1, vertex);
if (!ReadBlock(key->child, 1, vertex)) {
return false;
}
goto next; goto next;
} }
} }
@ -809,7 +850,7 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
// Create a new sibling. // Create a new sibling.
uint64_t siblingBlock = 0, _unused; uint64_t siblingBlock = 0, _unused;
AllocateExtent(1, &siblingBlock, &_unused); if (!AllocateExtent(1, &siblingBlock, &_unused)) return false;
IndexVertex *sibling = (IndexVertex *) _buffer0; IndexVertex *sibling = (IndexVertex *) _buffer0;
sibling->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; sibling->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */;
sibling->offset = ESFS_INDEX_KEY_OFFSET; sibling->offset = ESFS_INDEX_KEY_OFFSET;
@ -829,7 +870,7 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
depth++; depth++;
uint64_t _unused; uint64_t _unused;
AllocateExtent(1, &blocks[0], &_unused); if (!AllocateExtent(1, &blocks[0], &_unused)) return false;
parent->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */; parent->maxCount = (superblock.blockSize - ESFS_INDEX_KEY_OFFSET) / sizeof(IndexKey) - 1 /* +1 key */;
parent->offset = ESFS_INDEX_KEY_OFFSET; parent->offset = ESFS_INDEX_KEY_OFFSET;
@ -841,7 +882,9 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
parent->keys[0].child = blocks[1]; parent->keys[0].child = blocks[1];
directoryAttribute->indexRootBlock = blocks[0]; directoryAttribute->indexRootBlock = blocks[0];
} else { } else {
ReadBlock(blocks[depth - 1], 1, parent); if (!ReadBlock(blocks[depth - 1], 1, parent)) {
return false;
}
} }
IndexKey *parentKeys = (IndexKey *) ((uint8_t *) parent + parent->offset); IndexKey *parentKeys = (IndexKey *) ((uint8_t *) parent + parent->offset);
@ -886,8 +929,8 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
sibling->checksum = 0; sibling->checksum = CalculateCRC32(sibling, superblock.blockSize, 0); sibling->checksum = 0; sibling->checksum = CalculateCRC32(sibling, superblock.blockSize, 0);
vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock.blockSize, 0); vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock.blockSize, 0);
WriteBlock(siblingBlock, 1, sibling); if (!WriteBlock(siblingBlock, 1, sibling)) return false;
WriteBlock(blocks[depth], 1, vertex); if (!WriteBlock(blocks[depth], 1, vertex)) return false;
// Check if the parent vertex is full. // Check if the parent vertex is full.
@ -898,33 +941,49 @@ void AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
// Write the block. // Write the block.
vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock.blockSize, 0); vertex->checksum = 0; vertex->checksum = CalculateCRC32(vertex, superblock.blockSize, 0);
WriteBlock(blocks[depth], 1, vertex); if (!WriteBlock(blocks[depth], 1, vertex)) return false;
} }
if (outputEntry) *outputEntry = entry; if (outputEntry) *outputEntry = entry;
if (outputReference) *outputReference = reference; if (outputReference) *outputReference = reference;
// PrintTree(directoryAttribute->indexRootBlock); // PrintTree(directoryAttribute->indexRootBlock);
WriteDirectoryEntryReference(directoryReference, &directory); if (!WriteDirectoryEntryReference(directoryReference, &directory)) {
return false;
}
return true;
} }
void MountVolume() { bool MountVolume() {
// Read the superblock. // Read the superblock.
blockSize = ESFS_BOOT_SUPER_BLOCK_SIZE; blockSize = ESFS_BOOT_SUPER_BLOCK_SIZE;
ReadBlock(1, 1, &superblock);
if (!ReadBlock(1, 1, &superblock)) {
return false;
}
if (superblock.mounted) { if (superblock.mounted) {
Log("EsFS: Volume not unmounted, exiting...\n"); Log("EsFS: Volume not unmounted, exiting...\n");
exit(1); EsFSError();
} }
superblock.mounted = 1; superblock.mounted = 1;
WriteBlock(1, 1, &superblock);
if (!WriteBlock(1, 1, &superblock)) {
return false;
}
blockSize = superblock.blockSize; blockSize = superblock.blockSize;
// Read the group descriptor table. // Read the group descriptor table.
groupDescriptorTable = (GroupDescriptor *) malloc(superblock.groupCount * sizeof(GroupDescriptor) + superblock.blockSize - 1); groupDescriptorTable = (GroupDescriptor *) malloc(superblock.groupCount * sizeof(GroupDescriptor) + superblock.blockSize - 1);
ReadBlock(superblock.gdtFirstBlock, (superblock.groupCount * sizeof(GroupDescriptor) + superblock.blockSize - 1) / superblock.blockSize, groupDescriptorTable);
if (!ReadBlock(superblock.gdtFirstBlock, (superblock.groupCount * sizeof(GroupDescriptor) + superblock.blockSize - 1) / superblock.blockSize, groupDescriptorTable)) {
return false;
}
return true;
} }
void UnmountVolume() { void UnmountVolume() {
@ -939,11 +998,14 @@ void UnmountVolume() {
bool FindNode(const char *cName, DirectoryEntry *node, DirectoryEntryReference directoryReference) { bool FindNode(const char *cName, DirectoryEntry *node, DirectoryEntryReference directoryReference) {
DirectoryEntry directory; DirectoryEntry directory;
ReadDirectoryEntryReference(directoryReference, &directory); if (!ReadDirectoryEntryReference(directoryReference, &directory)) return false;
AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY); AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY);
for (uintptr_t i = 0; i < directoryAttribute->childNodes; i++) { for (uintptr_t i = 0; i < directoryAttribute->childNodes; i++) {
AccessNode(&directory, node, sizeof(DirectoryEntry) * i, sizeof(DirectoryEntry), NULL, true); if (!AccessNode(&directory, node, sizeof(DirectoryEntry) * i, sizeof(DirectoryEntry), NULL, true)) {
return false;
}
AttributeFilename *filename = (AttributeFilename *) FindAttribute(node, ESFS_ATTRIBUTE_FILENAME); AttributeFilename *filename = (AttributeFilename *) FindAttribute(node, ESFS_ATTRIBUTE_FILENAME);
if (filename->length == strlen(cName) && 0 == memcmp(filename->filename, cName, filename->length)) { if (filename->length == strlen(cName) && 0 == memcmp(filename->filename, cName, filename->length)) {
@ -973,7 +1035,7 @@ typedef struct ImportNode {
bool isFile; bool isFile;
} ImportNode; } ImportNode;
uint64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) { int64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) {
uint64_t totalSize = 0; uint64_t totalSize = 0;
for (uintptr_t i = 0; i < arrlenu(node.children); i++) { for (uintptr_t i = 0; i < arrlenu(node.children); i++) {
@ -989,24 +1051,36 @@ uint64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) {
DirectoryEntryReference reference; DirectoryEntryReference reference;
DirectoryEntry entry; DirectoryEntry entry;
AddNode(node.children[i].name, ESFS_NODE_TYPE_FILE, &entry, &reference, parentDirectory); if (!AddNode(node.children[i].name, ESFS_NODE_TYPE_FILE, &entry, &reference, parentDirectory)) {
ResizeNode(&entry, fileLength); return -1;
}
if (!ResizeNode(&entry, fileLength)) {
return -1;
}
totalSize += fileLength; totalSize += fileLength;
AccessNode(&entry, data, 0, fileLength, NULL, false); if (!AccessNode(&entry, data, 0, fileLength, NULL, false)) {
WriteDirectoryEntryReference(reference, &entry); return -1;
}
if (!WriteDirectoryEntryReference(reference, &entry)) {
return -1;
}
free(data); free(data);
} }
} else { } else {
DirectoryEntryReference reference; DirectoryEntryReference reference;
AddNode(node.children[i].name, ESFS_NODE_TYPE_DIRECTORY, NULL, &reference, parentDirectory); if (!AddNode(node.children[i].name, ESFS_NODE_TYPE_DIRECTORY, NULL, &reference, parentDirectory)) return -1;
uint64_t size = Import(node.children[i], reference); int64_t size = Import(node.children[i], reference);
if (size == -1) return -1;
DirectoryEntry directory; DirectoryEntry directory;
ReadDirectoryEntryReference(reference, &directory); if (!ReadDirectoryEntryReference(reference, &directory)) return -1;
AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY); AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&directory, ESFS_ATTRIBUTE_DIRECTORY);
directoryAttribute->totalSize = size; directoryAttribute->totalSize = size;
WriteDirectoryEntryReference(reference, &directory); if (!WriteDirectoryEntryReference(reference, &directory)) return -1;
totalSize += size; totalSize += size;
} }
} }
@ -1015,18 +1089,18 @@ uint64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) {
} }
#endif #endif
void Format(uint64_t driveSize, const char *volumeName, EsUniqueIdentifier osInstallation, bool Format(uint64_t driveSize, const char *volumeName, EsUniqueIdentifier osInstallation,
void *kernel, size_t kernelBytes) { void *kernel, size_t kernelBytes) {
assert(sizeof(Superblock) == 8192); assert(sizeof(Superblock) == 8192);
if (driveSize < ESFS_DRIVE_MINIMUM_SIZE) { if (driveSize < ESFS_DRIVE_MINIMUM_SIZE) {
Log("Error: Cannot create a drive of %d bytes (too small).\n", (int) driveSize); Log("Error: Cannot create a drive of %d bytes (too small).\n", (int) driveSize);
exit(1); EsFSError();
} }
if (strlen(volumeName) > ESFS_MAXIMUM_VOLUME_NAME_LENGTH) { if (strlen(volumeName) > ESFS_MAXIMUM_VOLUME_NAME_LENGTH) {
Log("Error: Volume name '%s' is too long; must be <= %d bytes.\n", volumeName, (int) ESFS_MAXIMUM_VOLUME_NAME_LENGTH); Log("Error: Volume name '%s' is too long; must be <= %d bytes.\n", volumeName, (int) ESFS_MAXIMUM_VOLUME_NAME_LENGTH);
exit(1); EsFSError();
} }
// Format the volume. // Format the volume.
@ -1092,9 +1166,15 @@ void Format(uint64_t driveSize, const char *volumeName, EsUniqueIdentifier osIns
entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0); entry->checksum = CalculateCRC32(entry, sizeof(DirectoryEntry), 0);
} }
WriteBytes(blockCoreNodes * superblock.blockSize, sizeof(coreNodes), &coreNodes); if (!WriteBytes(blockCoreNodes * superblock.blockSize, sizeof(coreNodes), &coreNodes)) {
return false;
}
superblock.checksum = CalculateCRC32(&superblock, sizeof(Superblock), 0); superblock.checksum = CalculateCRC32(&superblock, sizeof(Superblock), 0);
WriteBytes(ESFS_BOOT_SUPER_BLOCK_SIZE, ESFS_BOOT_SUPER_BLOCK_SIZE, &superblock);
if (!WriteBytes(ESFS_BOOT_SUPER_BLOCK_SIZE, ESFS_BOOT_SUPER_BLOCK_SIZE, &superblock)) {
return false;
}
{ {
GroupDescriptor *buffer = (GroupDescriptor *) malloc(superblock.groupCount * sizeof(GroupDescriptor)); GroupDescriptor *buffer = (GroupDescriptor *) malloc(superblock.groupCount * sizeof(GroupDescriptor));
@ -1112,34 +1192,52 @@ void Format(uint64_t driveSize, const char *volumeName, EsUniqueIdentifier osIns
buffer[i].blockBitmap = blockGroup0Bitmap; buffer[i].blockBitmap = blockGroup0Bitmap;
buffer[i].bitmapChecksum = CalculateCRC32(firstGroupBitmap, sizeof(firstGroupBitmap), 0); buffer[i].bitmapChecksum = CalculateCRC32(firstGroupBitmap, sizeof(firstGroupBitmap), 0);
buffer[i].largestExtent = superblock.blocksPerGroup - superblock.blocksUsed; buffer[i].largestExtent = superblock.blocksPerGroup - superblock.blocksUsed;
WriteBytes(blockGroup0Bitmap * superblock.blockSize, sizeof(firstGroupBitmap), &firstGroupBitmap);
if (!WriteBytes(blockGroup0Bitmap * superblock.blockSize, sizeof(firstGroupBitmap), &firstGroupBitmap)) {
return false;
}
} }
buffer[i].checksum = CalculateCRC32(buffer + i, sizeof(GroupDescriptor), 0); buffer[i].checksum = CalculateCRC32(buffer + i, sizeof(GroupDescriptor), 0);
} }
WriteBytes(superblock.gdtFirstBlock * superblock.blockSize, superblock.groupCount * sizeof(GroupDescriptor), buffer); if (!WriteBytes(superblock.gdtFirstBlock * superblock.blockSize, superblock.groupCount * sizeof(GroupDescriptor), buffer)) {
return false;
}
free(buffer); free(buffer);
} }
} }
// Add the kernel. // Add the kernel.
{ if (MountVolume()) {
MountVolume();
DirectoryEntryReference reference = superblock.kernel; DirectoryEntryReference reference = superblock.kernel;
DirectoryEntry entry; DirectoryEntry entry;
EsUniqueIdentifier unused = {}; EsUniqueIdentifier unused = {};
NewDirectoryEntry(&entry, ESFS_NODE_TYPE_FILE, unused, "Kernel"); NewDirectoryEntry(&entry, ESFS_NODE_TYPE_FILE, unused, "Kernel");
WriteDirectoryEntryReference(reference, &entry);
ResizeNode(&entry, kernelBytes); if (WriteDirectoryEntryReference(reference, &entry)) {
AccessNode(&entry, kernel, 0, kernelBytes, NULL, false); if (ResizeNode(&entry, kernelBytes)) {
WriteDirectoryEntryReference(reference, &entry); if (AccessNode(&entry, kernel, 0, kernelBytes, NULL, false)) {
WriteDirectoryEntryReference(reference, &entry);
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
UnmountVolume(); UnmountVolume();
} else {
return false;
} }
return true;
} }
#endif #endif

View File

@ -321,6 +321,10 @@ DEFINE_INTERFACE_STRING(InstallerCompleteFromOther, "Installation has completed
DEFINE_INTERFACE_STRING(InstallerCompleteFromUSB, "Installation has completed successfully. Disconnect the installation USB, and restart your computer."); DEFINE_INTERFACE_STRING(InstallerCompleteFromUSB, "Installation has completed successfully. Disconnect the installation USB, and restart your computer.");
DEFINE_INTERFACE_STRING(InstallerVolumeLabel, "Essence HD"); DEFINE_INTERFACE_STRING(InstallerVolumeLabel, "Essence HD");
DEFINE_INTERFACE_STRING(InstallerUseMBR, "Use legacy BIOS boot (select for older computers)"); DEFINE_INTERFACE_STRING(InstallerUseMBR, "Use legacy BIOS boot (select for older computers)");
DEFINE_INTERFACE_STRING(InstallerFailedArchiveCRCError, "The installation data has been corrupted. Create a new installation USB or disk, and try again.");
DEFINE_INTERFACE_STRING(InstallerFailedGeneric, "The installation could not complete. This likely means that the drive you selected is failing. Try installing on a different drive.");
DEFINE_INTERFACE_STRING(InstallerFailedResources, "The installation could not complete. Your computer does not have enough memory to install " SYSTEM_BRAND_SHORT);
DEFINE_INTERFACE_STRING(InstallerNotSupported, "Your computer does not meet the minimum system requirements to install " SYSTEM_BRAND_SHORT ". Remove the installer, and restart your computer.");
// TODO System Monitor. // TODO System Monitor.

View File

@ -1108,7 +1108,6 @@ void DoCommand(const char *l) {
FILE *f = fopen("bin/temp.dat", "wb"); FILE *f = fopen("bin/temp.dat", "wb");
uint64_t crc64 = 0, uncompressed = 0; uint64_t crc64 = 0, uncompressed = 0;
GatherFilesForInstallerArchive(f, "root", "", &crc64, &uncompressed); GatherFilesForInstallerArchive(f, "root", "", &crc64, &uncompressed);
fwrite(&crc64, 1, sizeof(crc64), f);
uint32_t sizeMB = ftell(f) / 1000000; uint32_t sizeMB = ftell(f) / 1000000;
fclose(f); fclose(f);
printf("Compressing %d MB...\n", sizeMB); printf("Compressing %d MB...\n", sizeMB);
@ -1117,8 +1116,9 @@ void DoCommand(const char *l) {
lstat("bin/installer_archive.dat", &s); lstat("bin/installer_archive.dat", &s);
printf("Compressed to %d MB.\n", (uint32_t) (s.st_size / 1000000)); printf("Compressed to %d MB.\n", (uint32_t) (s.st_size / 1000000));
unlink("bin/temp.dat"); unlink("bin/temp.dat");
f = fopen("bin/installer_metadata.dat", "ab"); f = fopen("bin/installer_metadata.dat", "wb");
fwrite(&uncompressed, 1, sizeof(uncompressed), f); fwrite(&uncompressed, 1, sizeof(uncompressed), f);
fwrite(&crc64, 1, sizeof(crc64), f);
fclose(f); fclose(f);
} else if (0 == strcmp(l, "config")) { } else if (0 == strcmp(l, "config")) {
BuildUtilities(); BuildUtilities();

View File

@ -129,6 +129,8 @@ File FileOpen(const char *path, char mode) {
#endif #endif
#define EsFSError() exit(1)
#include "../shared/hash.cpp" #include "../shared/hash.cpp"
#include "../shared/partitions.cpp" #include "../shared/partitions.cpp"
#include "build_common.h" #include "build_common.h"
@ -1058,7 +1060,7 @@ void BuildBootloader(Application *application) {
File _drive; File _drive;
uint64_t _partitionOffset; uint64_t _partitionOffset;
void ReadBlock(uint64_t block, uint64_t count, void *buffer) { bool ReadBlock(uint64_t block, uint64_t count, void *buffer) {
FileSeek(_drive, block * blockSize + _partitionOffset); FileSeek(_drive, block * blockSize + _partitionOffset);
// printf("read of block %ld\n", block); // printf("read of block %ld\n", block);
@ -1066,9 +1068,11 @@ void ReadBlock(uint64_t block, uint64_t count, void *buffer) {
Log("Error: Could not read blocks %d->%d of drive.\n", (int) block, (int) (block + count)); Log("Error: Could not read blocks %d->%d of drive.\n", (int) block, (int) (block + count));
exit(1); exit(1);
} }
return true;
} }
void WriteBlock(uint64_t block, uint64_t count, void *buffer) { bool WriteBlock(uint64_t block, uint64_t count, void *buffer) {
FileSeek(_drive, block * blockSize + _partitionOffset); FileSeek(_drive, block * blockSize + _partitionOffset);
assert(block < 4294967296); assert(block < 4294967296);
@ -1076,15 +1080,19 @@ void WriteBlock(uint64_t block, uint64_t count, void *buffer) {
Log("Error: Could not write to blocks %d->%d of drive.\n", (int) block, (int) (block + count)); Log("Error: Could not write to blocks %d->%d of drive.\n", (int) block, (int) (block + count));
exit(1); exit(1);
} }
return true;
} }
void WriteBytes(uint64_t offset, uint64_t count, void *buffer) { bool WriteBytes(uint64_t offset, uint64_t count, void *buffer) {
FileSeek(_drive, offset + _partitionOffset); FileSeek(_drive, offset + _partitionOffset);
if (FileWrite(_drive, count, buffer) != count) { if (FileWrite(_drive, count, buffer) != count) {
Log("Error: Could not write to bytes %d->%d of drive.\n", (int) offset, (int) (offset + count)); Log("Error: Could not write to bytes %d->%d of drive.\n", (int) offset, (int) (offset + count));
exit(1); exit(1);
} }
return true;
} }
void Install(const char *driveFile, uint64_t partitionSize, const char *partitionLabel) { void Install(const char *driveFile, uint64_t partitionSize, const char *partitionLabel) {