mirror of https://gitlab.com/nakst/essence
files: storing file content type
This commit is contained in:
parent
82ccd24c61
commit
a0fe4d31e9
|
@ -337,7 +337,7 @@ void CommandPasteTask(EsUserTask *userTask, EsGeneric _task) {
|
||||||
|
|
||||||
EsDirectoryChild information;
|
EsDirectoryChild information;
|
||||||
|
|
||||||
if (EsPathQueryInformation(STRING(source), &information)) {
|
if (ES_SUCCESS == EsPathQueryInformation(STRING(source), &information)) {
|
||||||
if (information.fileSize == -1) {
|
if (information.fileSize == -1) {
|
||||||
// TODO Support progress on volumes that don't report total directory sizes.
|
// TODO Support progress on volumes that don't report total directory sizes.
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,7 +17,7 @@ Array<Folder *> foldersWithNoAttachedInstances;
|
||||||
bool FSDirHandlesPath(String path) {
|
bool FSDirHandlesPath(String path) {
|
||||||
EsDirectoryChild information;
|
EsDirectoryChild information;
|
||||||
|
|
||||||
if (EsPathQueryInformation(STRING(path), &information)) {
|
if (ES_SUCCESS == EsPathQueryInformation(STRING(path), &information)) {
|
||||||
return information.type == ES_NODE_DIRECTORY;
|
return information.type == ES_NODE_DIRECTORY;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -91,7 +91,7 @@ EsError FSDirEnumerate(Folder *folder) {
|
||||||
void FSDirGetTotalSize(Folder *folder) {
|
void FSDirGetTotalSize(Folder *folder) {
|
||||||
EsDirectoryChild information;
|
EsDirectoryChild information;
|
||||||
|
|
||||||
if (EsPathQueryInformation(STRING(folder->path), &information)) {
|
if (ES_SUCCESS == EsPathQueryInformation(STRING(folder->path), &information)) {
|
||||||
folder->spaceUsed = information.fileSize;
|
folder->spaceUsed = information.fileSize;
|
||||||
folder->spaceTotal = 0;
|
folder->spaceTotal = 0;
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,7 @@ void FolderFileUpdatedAtPath(String path, Instance *instance) {
|
||||||
String file = PathGetName(path);
|
String file = PathGetName(path);
|
||||||
String folder = PathGetParent(path);
|
String folder = PathGetParent(path);
|
||||||
EsDirectoryChild information = {};
|
EsDirectoryChild information = {};
|
||||||
bool add = EsPathQueryInformation(STRING(path), &information);
|
bool add = ES_SUCCESS == EsPathQueryInformation(STRING(path), &information);
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
||||||
if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue;
|
if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue;
|
||||||
|
|
|
@ -378,8 +378,8 @@ int ExternalFileAppend(ExecutionContext *context, Value *returnValue) {
|
||||||
int ExternalFileGetSize(ExecutionContext *context, Value *returnValue) {
|
int ExternalFileGetSize(ExecutionContext *context, Value *returnValue) {
|
||||||
STACK_POP_STRING(entryText, entryBytes);
|
STACK_POP_STRING(entryText, entryBytes);
|
||||||
EsDirectoryChild information;
|
EsDirectoryChild information;
|
||||||
bool exists = EsPathQueryInformation(entryText, entryBytes, &information);
|
EsError error = EsPathQueryInformation(entryText, entryBytes, &information);
|
||||||
if (!exists) RETURN_ERROR(ES_ERROR_FILE_DOES_NOT_EXIST);
|
if (error != ES_SUCCESS) RETURN_ERROR(ES_ERROR_FILE_DOES_NOT_EXIST);
|
||||||
if (information.type != ES_NODE_FILE) RETURN_ERROR(ES_ERROR_INCORRECT_NODE_TYPE);
|
if (information.type != ES_NODE_FILE) RETURN_ERROR(ES_ERROR_INCORRECT_NODE_TYPE);
|
||||||
returnValue->i = information.fileSize;
|
returnValue->i = information.fileSize;
|
||||||
return EXTCALL_RETURN_ERR_UNMANAGED;
|
return EXTCALL_RETURN_ERR_UNMANAGED;
|
||||||
|
@ -1011,7 +1011,7 @@ void EnterCommand(Instance *instance) {
|
||||||
uint8_t newline = '\n';
|
uint8_t newline = '\n';
|
||||||
EsFileWriteSync(globalCommandHistoryFile.handle, EsFileGetSize(globalCommandHistoryFile.handle), dataBytes, data);
|
EsFileWriteSync(globalCommandHistoryFile.handle, EsFileGetSize(globalCommandHistoryFile.handle), dataBytes, data);
|
||||||
EsFileWriteSync(globalCommandHistoryFile.handle, EsFileGetSize(globalCommandHistoryFile.handle), 1, &newline);
|
EsFileWriteSync(globalCommandHistoryFile.handle, EsFileGetSize(globalCommandHistoryFile.handle), 1, &newline);
|
||||||
EsFileControl(globalCommandHistoryFile.handle, ES_FILE_CONTROL_FLUSH);
|
EsFileControl(globalCommandHistoryFile.handle, ES_FILE_CONTROL_FLUSH, nullptr, 0);
|
||||||
|
|
||||||
EsPanel *commandLogRow = EsPanelCreate(instance->root, ES_CELL_H_FILL | ES_PANEL_STACK | ES_PANEL_HORIZONTAL, EsStyleIntern(&styleInputRow));
|
EsPanel *commandLogRow = EsPanelCreate(instance->root, ES_CELL_H_FILL | ES_PANEL_STACK | ES_PANEL_HORIZONTAL, EsStyleIntern(&styleInputRow));
|
||||||
EsTextDisplayCreate(commandLogRow, ES_FLAGS_DEFAULT, EsStyleIntern(&stylePromptText), "\u2661");
|
EsTextDisplayCreate(commandLogRow, ES_FLAGS_DEFAULT, EsStyleIntern(&stylePromptText), "\u2661");
|
||||||
|
|
|
@ -132,7 +132,7 @@ LoadEachExtent:
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|
||||||
%macro FilesystemSpecificCode 0
|
%macro FilesystemSpecificCode 0
|
||||||
KernelDataStreamPosition: dw 0x850
|
KernelDataStreamPosition: dw 0x860
|
||||||
ErrorBadFilesystem: db "Invalid boot EsFS volume.",0
|
ErrorBadFilesystem: db "Invalid boot EsFS volume.",0
|
||||||
ErrorUnexpectedFileProblem: db "The kernel file could not be loaded.",0
|
ErrorUnexpectedFileProblem: db "The kernel file could not be loaded.",0
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|
|
@ -1227,7 +1227,7 @@ void EsInstanceSaveComplete(EsInstance *instance, EsFileStore *file, bool succes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
file->error = EsFileControl(file->handle, ES_FILE_CONTROL_FLUSH);
|
file->error = EsFileControl(file->handle, ES_FILE_CONTROL_FLUSH, nullptr, 0);
|
||||||
|
|
||||||
if (file->error != ES_SUCCESS) {
|
if (file->error != ES_SUCCESS) {
|
||||||
success = false;
|
success = false;
|
||||||
|
|
|
@ -1305,6 +1305,44 @@ bool ResizeFileTest() {
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool FileContentTypeTest() {
|
||||||
|
int checkIndex = 0;
|
||||||
|
|
||||||
|
EsUniqueIdentifier identifier1, identifier2;
|
||||||
|
for (uintptr_t i = 0; i < 16; i++) identifier1.d[i] = i;
|
||||||
|
for (uintptr_t i = 0; i < 16; i++) identifier2.d[i] = 0;
|
||||||
|
|
||||||
|
size_t fileSize;
|
||||||
|
uint32_t *fileData = (uint32_t *) EsFileReadAll(EsLiteral("|Settings:/continue.txt"), &fileSize);
|
||||||
|
|
||||||
|
if (fileData) {
|
||||||
|
size_t count;
|
||||||
|
EsError error;
|
||||||
|
EsDirectoryChild *array = EsDirectoryEnumerate(EsLiteral("|Settings:/test"), &count, &error);
|
||||||
|
CHECK(error == ES_SUCCESS);
|
||||||
|
CHECK(count == 1);
|
||||||
|
CHECK(0 == EsMemoryCompare(&identifier1, &array[0].contentType, sizeof(EsUniqueIdentifier)));
|
||||||
|
EsFileInformation information = EsFileOpen(EsLiteral("|Settings:/test/a"), ES_FILE_WRITE | ES_NODE_CREATE_DIRECTORIES);
|
||||||
|
CHECK(information.error == ES_SUCCESS);
|
||||||
|
CHECK(0 == EsMemoryCompare(&identifier1, &information.contentType, sizeof(EsUniqueIdentifier)));
|
||||||
|
} else {
|
||||||
|
uint32_t c = 1;
|
||||||
|
CHECK(ES_SUCCESS == EsFileWriteAll(EsLiteral("|Settings:/continue.txt"), &c, sizeof(uint32_t)));
|
||||||
|
|
||||||
|
EsFileInformation information = EsFileOpen(EsLiteral("|Settings:/test/a"), ES_FILE_WRITE | ES_NODE_CREATE_DIRECTORIES);
|
||||||
|
CHECK(information.error == ES_SUCCESS);
|
||||||
|
CHECK(0 == EsMemoryCompare(&identifier2, &information.contentType, sizeof(EsUniqueIdentifier)));
|
||||||
|
CHECK(ES_SUCCESS == EsFileControl(information.handle, ES_FILE_CONTROL_SET_CONTENT_TYPE, &identifier1, sizeof(identifier1)));
|
||||||
|
|
||||||
|
EsSyscall(ES_SYSCALL_SHUTDOWN, ES_SHUTDOWN_ACTION_RESTART, 0, 0, 0);
|
||||||
|
while (EsMessageReceive());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const Test tests[] = {
|
const Test tests[] = {
|
||||||
|
@ -1323,6 +1361,7 @@ const Test tests[] = {
|
||||||
TEST(POSIXSubsystemTest, 120),
|
TEST(POSIXSubsystemTest, 120),
|
||||||
TEST(RestartTest, 1200),
|
TEST(RestartTest, 1200),
|
||||||
TEST(ResizeFileTest, 600),
|
TEST(ResizeFileTest, 600),
|
||||||
|
TEST(FileContentTypeTest, 60),
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef API_TESTS_FOR_RUNNER
|
#ifndef API_TESTS_FOR_RUNNER
|
||||||
|
|
|
@ -71,16 +71,17 @@ bool EsPathExists(const char *path, ptrdiff_t pathBytes, EsNodeType *type) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EsPathQueryInformation(const char *path, ptrdiff_t pathBytes, EsDirectoryChild *information) {
|
EsError EsPathQueryInformation(const char *path, ptrdiff_t pathBytes, EsDirectoryChild *information) {
|
||||||
if (pathBytes == -1) pathBytes = EsCStringLength(path);
|
if (pathBytes == -1) pathBytes = EsCStringLength(path);
|
||||||
_EsNodeInformation node = {};
|
_EsNodeInformation node = {};
|
||||||
EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND, &node);
|
EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND, &node);
|
||||||
if (error != ES_SUCCESS) return false;
|
if (error != ES_SUCCESS) return error;
|
||||||
EsHandleClose(node.handle);
|
EsHandleClose(node.handle);
|
||||||
information->type = node.type;
|
information->type = node.type;
|
||||||
information->fileSize = node.fileSize;
|
information->fileSize = node.fileSize;
|
||||||
information->directoryChildren = node.directoryChildren;
|
information->directoryChildren = node.directoryChildren;
|
||||||
return true;
|
information->contentType = node.contentType;
|
||||||
|
return ES_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError EsPathCreate(const char *path, ptrdiff_t pathBytes, EsNodeType type, bool createLeadingDirectories) {
|
EsError EsPathCreate(const char *path, ptrdiff_t pathBytes, EsNodeType type, bool createLeadingDirectories) {
|
||||||
|
@ -94,8 +95,8 @@ EsError EsPathCreate(const char *path, ptrdiff_t pathBytes, EsNodeType type, boo
|
||||||
return ES_SUCCESS;
|
return ES_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError EsFileControl(EsHandle file, uint32_t flags) {
|
EsError EsFileControl(EsHandle file, EsFileControlOperation operation, const void *data, size_t dataBytes) {
|
||||||
return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, flags, 0, 0);
|
return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, operation, (uintptr_t) data, dataBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t DirectoryEnumerateFromHandle(EsHandle directory, EsDirectoryChild *buffer, size_t size) {
|
ptrdiff_t DirectoryEnumerateFromHandle(EsHandle directory, EsDirectoryChild *buffer, size_t size) {
|
||||||
|
@ -167,6 +168,7 @@ EsFileInformation EsFileOpen(const char *path, ptrdiff_t pathLength, uint32_t fl
|
||||||
if (result == ES_SUCCESS) {
|
if (result == ES_SUCCESS) {
|
||||||
information.handle = node.handle;
|
information.handle = node.handle;
|
||||||
information.size = node.fileSize;
|
information.size = node.fileSize;
|
||||||
|
information.contentType = node.contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
information.error = result;
|
information.error = result;
|
||||||
|
@ -245,7 +247,7 @@ EsFileOffsetDifference EsFileStoreGetSize(EsFileStore *file) {
|
||||||
} else if (file->type == FILE_STORE_PATH) {
|
} else if (file->type == FILE_STORE_PATH) {
|
||||||
EsDirectoryChild information;
|
EsDirectoryChild information;
|
||||||
|
|
||||||
if (EsPathQueryInformation(file->path, file->pathBytes, &information)) {
|
if (ES_SUCCESS == EsPathQueryInformation(file->path, file->pathBytes, &information)) {
|
||||||
return file->pathBytes;
|
return file->pathBytes;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -576,7 +578,7 @@ EsError EsFileWriteAllGatherFromHandle(EsHandle handle, const void **data, const
|
||||||
offset += sizes[i];
|
offset += sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
error = EsFileControl(handle, ES_FILE_CONTROL_FLUSH);
|
error = EsFileControl(handle, ES_FILE_CONTROL_FLUSH, nullptr, 0);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -760,8 +760,9 @@ inttype EsConnectionOpenFlags uint32_t none {
|
||||||
ES_CONNECTION_OPEN_WAIT = bit 0
|
ES_CONNECTION_OPEN_WAIT = bit 0
|
||||||
};
|
};
|
||||||
|
|
||||||
inttype EsFileControlFlags uint32_t none {
|
inttype EsFileControlOperation uint32_t none {
|
||||||
ES_FILE_CONTROL_FLUSH = bit 0
|
ES_FILE_CONTROL_FLUSH = 0 // data/dataBytes ignored
|
||||||
|
ES_FILE_CONTROL_SET_CONTENT_TYPE = 1 // data EsUniqueIdentifier; dataBytes ignored
|
||||||
};
|
};
|
||||||
|
|
||||||
inttype EsElementUpdateContentFlags uint32_t none {
|
inttype EsElementUpdateContentFlags uint32_t none {
|
||||||
|
@ -838,6 +839,7 @@ inttype EsProcessCreationFlags uint32_t none {
|
||||||
|
|
||||||
inttype EsVolumeFlags uint32_t none {
|
inttype EsVolumeFlags uint32_t none {
|
||||||
ES_VOLUME_READ_ONLY = bit 0
|
ES_VOLUME_READ_ONLY = bit 0
|
||||||
|
ES_VOLUME_STORES_CONTENT_TYPE = bit 1
|
||||||
};
|
};
|
||||||
|
|
||||||
inttype EsPathMoveFlags uint32_t none {
|
inttype EsPathMoveFlags uint32_t none {
|
||||||
|
@ -1340,6 +1342,7 @@ struct EsFileInformation {
|
||||||
EsHandle handle;
|
EsHandle handle;
|
||||||
EsFileOffset size;
|
EsFileOffset size;
|
||||||
EsError error;
|
EsError error;
|
||||||
|
EsUniqueIdentifier contentType; // Zeroed if unsupported, or not initialised.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EsDirectoryChild {
|
struct EsDirectoryChild {
|
||||||
|
@ -1348,6 +1351,7 @@ struct EsDirectoryChild {
|
||||||
EsNodeType type;
|
EsNodeType type;
|
||||||
EsFileOffsetDifference fileSize; // -1 if unsupported.
|
EsFileOffsetDifference fileSize; // -1 if unsupported.
|
||||||
EsFileOffsetDifference directoryChildren; // ES_DIRECTORY_CHILDREN_UNKNOWN if unsupported.
|
EsFileOffsetDifference directoryChildren; // ES_DIRECTORY_CHILDREN_UNKNOWN if unsupported.
|
||||||
|
EsUniqueIdentifier contentType; // Zeroed if unsupported, or not initialised.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EsPoint {
|
struct EsPoint {
|
||||||
|
@ -1635,6 +1639,7 @@ private struct _EsNodeInformation {
|
||||||
EsFileOffset fileSize;
|
EsFileOffset fileSize;
|
||||||
EsFileOffsetDifference directoryChildren;
|
EsFileOffsetDifference directoryChildren;
|
||||||
EsNodeType type;
|
EsNodeType type;
|
||||||
|
EsUniqueIdentifier contentType;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EsVolumeInformation {
|
struct EsVolumeInformation {
|
||||||
|
@ -2137,7 +2142,7 @@ function EsError EsFileWriteAllGatherFromHandle(EsHandle handle, const void **da
|
||||||
function void *EsFileMap(STRING filePath, size_t *fileSize, uint32_t flags) @native();
|
function void *EsFileMap(STRING filePath, size_t *fileSize, uint32_t flags) @native();
|
||||||
function EsError EsFileCopy(STRING source, STRING destination, void **copyBuffer = ES_NULL, EsFileCopyCallback callback = ES_NULL, EsGeneric data = ES_NULL) @todo(); // If you are copying lots of files, you can reuse the temporary copy buffer by storing the output copyBuffer; call EsHeapFree on it after the last copy.
|
function EsError EsFileCopy(STRING source, STRING destination, void **copyBuffer = ES_NULL, EsFileCopyCallback callback = ES_NULL, EsGeneric data = ES_NULL) @todo(); // If you are copying lots of files, you can reuse the temporary copy buffer by storing the output copyBuffer; call EsHeapFree on it after the last copy.
|
||||||
|
|
||||||
function EsError EsFileControl(EsHandle file, EsFileControlFlags flags);
|
function EsError EsFileControl(EsHandle file, EsFileControlOperation operation, const void *data, size_t dataBytes) @buffer_in(data, dataBytes);
|
||||||
function EsFileInformation EsFileOpen(STRING path, EsFileOpenFlags flags);
|
function EsFileInformation EsFileOpen(STRING path, EsFileOpenFlags flags);
|
||||||
function EsFileOffset EsFileGetSize(EsHandle handle);
|
function EsFileOffset EsFileGetSize(EsHandle handle);
|
||||||
function size_t EsFileReadSync(EsHandle file, EsFileOffset offset, size_t size, void *buffer) @buffer_out(buffer, size);
|
function size_t EsFileReadSync(EsHandle file, EsFileOffset offset, size_t size, void *buffer) @buffer_out(buffer, size);
|
||||||
|
@ -2150,7 +2155,7 @@ function size_t EsPathFindUniqueName(char *buffer, size_t originalBytes, size_t
|
||||||
function EsError EsPathMove(STRING oldPath, STRING newPath, EsPathMoveFlags flags = ES_FLAGS_DEFAULT);
|
function EsError EsPathMove(STRING oldPath, STRING newPath, EsPathMoveFlags flags = ES_FLAGS_DEFAULT);
|
||||||
function bool EsPathExists(STRING filePath, EsNodeType *type = ES_NULL) @out(type); // Returns true if the file/directory exists.
|
function bool EsPathExists(STRING filePath, EsNodeType *type = ES_NULL) @out(type); // Returns true if the file/directory exists.
|
||||||
function EsError EsPathCreate(STRING filePath, EsNodeType type, bool createLeadingDirectories);
|
function EsError EsPathCreate(STRING filePath, EsNodeType type, bool createLeadingDirectories);
|
||||||
function bool EsPathQueryInformation(STRING filePath, EsDirectoryChild *information) @out(information);
|
function EsError EsPathQueryInformation(STRING filePath, EsDirectoryChild *information) @out(information);
|
||||||
|
|
||||||
function void *EsFileStoreReadAll(EsFileStore *file, size_t *fileSize) @heap_buffer_out(return, fileSize*) @out(fileSize); // Free with EsHeapFree.
|
function void *EsFileStoreReadAll(EsFileStore *file, size_t *fileSize) @heap_buffer_out(return, fileSize*) @out(fileSize); // Free with EsHeapFree.
|
||||||
function bool EsFileStoreWriteAll(EsFileStore *file, const void *data, size_t dataBytes) @buffer_in(data, dataBytes);
|
function bool EsFileStoreWriteAll(EsFileStore *file, const void *data, size_t dataBytes) @buffer_in(data, dataBytes);
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
// TODO Calling FSDirectoryEntryFound on all directory entries seen during scanning, even if they're not the target.
|
// TODO Calling FSDirectoryEntryFound on all directory entries seen during scanning, even if they're not the target.
|
||||||
// TODO Informing the block cache when a directory is truncated and its extents are freed.
|
// TODO Informing the block cache when a directory is truncated and its extents are freed.
|
||||||
// TODO Renaming directories does not work?
|
|
||||||
// TODO ESFS_CHECK_XXX are used to report out of memory errors, which shouldn't report KERNEL_PROBLEM_DAMAGED_FILESYSTEM.
|
// TODO ESFS_CHECK_XXX are used to report out of memory errors, which shouldn't report KERNEL_PROBLEM_DAMAGED_FILESYSTEM.
|
||||||
|
|
||||||
#define ESFS_CHECK(x, y) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", y "\n"); return false; }
|
#define ESFS_CHECK(x, y) if (!(x)) { KernelLog(LOG_ERROR, "EsFS", "damaged file system", y "\n"); return false; }
|
||||||
|
@ -342,6 +341,9 @@ static void Sync(KNode *_directory, KNode *node) {
|
||||||
// Get the most recent totalSize for the directory.
|
// Get the most recent totalSize for the directory.
|
||||||
AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&file->entry, ESFS_ATTRIBUTE_DIRECTORY);
|
AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&file->entry, ESFS_ATTRIBUTE_DIRECTORY);
|
||||||
directoryAttribute->totalSize = FSNodeGetTotalSize(node);
|
directoryAttribute->totalSize = FSNodeGetTotalSize(node);
|
||||||
|
} else if (file->type == ES_NODE_FILE) {
|
||||||
|
// Get the most recent contentType for the file.
|
||||||
|
file->entry.contentType = FSNodeGetContentType(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -422,6 +424,7 @@ static EsError Enumerate(KNode *node) {
|
||||||
}
|
}
|
||||||
} else if (metadata.type == ES_NODE_FILE) {
|
} else if (metadata.type == ES_NODE_FILE) {
|
||||||
metadata.totalSize = entry->fileSize;
|
metadata.totalSize = entry->fileSize;
|
||||||
|
metadata.contentType = entry->contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError error = FSDirectoryEntryFound(node, &metadata, &reference,
|
EsError error = FSDirectoryEntryFound(node, &metadata, &reference,
|
||||||
|
@ -1819,6 +1822,7 @@ static EsError Scan(const char *name, size_t nameLength, KNode *_directory) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
metadata.totalSize = entry->fileSize;
|
metadata.totalSize = entry->fileSize;
|
||||||
|
metadata.contentType = entry->contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata.type = entry->nodeType == ESFS_NODE_TYPE_DIRECTORY ? ES_NODE_DIRECTORY : ES_NODE_FILE;
|
metadata.type = entry->nodeType == ESFS_NODE_TYPE_DIRECTORY ? ES_NODE_DIRECTORY : ES_NODE_FILE;
|
||||||
|
@ -2009,6 +2013,7 @@ static void Register(KDevice *_parent) {
|
||||||
volume->rootDirectoryInitialChildren = rootDirectoryChildren;
|
volume->rootDirectoryInitialChildren = rootDirectoryChildren;
|
||||||
volume->directoryEntryDataBytes = sizeof(DirectoryEntryReference);
|
volume->directoryEntryDataBytes = sizeof(DirectoryEntryReference);
|
||||||
volume->nodeDataBytes = sizeof(FSNode);
|
volume->nodeDataBytes = sizeof(FSNode);
|
||||||
|
volume->volumeFlags |= ES_VOLUME_STORES_CONTENT_TYPE;
|
||||||
|
|
||||||
FSRegisterBootFileSystem(volume, volume->superblock.osInstallation);
|
FSRegisterBootFileSystem(volume, volume->superblock.osInstallation);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,8 @@ EsError FSNodeDelete(KNode *node);
|
||||||
EsError FSNodeMove(KNode *node, KNode *destination, const char *newName, size_t nameNameBytes);
|
EsError FSNodeMove(KNode *node, KNode *destination, const char *newName, size_t nameNameBytes);
|
||||||
EsError FSFileResize(KNode *node, EsFileOffset newSizeBytes);
|
EsError FSFileResize(KNode *node, EsFileOffset newSizeBytes);
|
||||||
ptrdiff_t FSDirectoryEnumerate(KNode *node, K_USER_BUFFER EsDirectoryChild *buffer, size_t bufferSize);
|
ptrdiff_t FSDirectoryEnumerate(KNode *node, K_USER_BUFFER EsDirectoryChild *buffer, size_t bufferSize);
|
||||||
EsError FSFileControl(KNode *node, uint32_t flags);
|
EsError FSFileControlFlush(KNode *node);
|
||||||
|
EsError FSFileControlSetContentType(KNode *node, EsUniqueIdentifier identifier);
|
||||||
bool FSTrimCachedNode(MMObjectCache *);
|
bool FSTrimCachedNode(MMObjectCache *);
|
||||||
bool FSTrimCachedDirectoryEntry(MMObjectCache *);
|
bool FSTrimCachedDirectoryEntry(MMObjectCache *);
|
||||||
EsError FSBlockDeviceAccess(KBlockDeviceAccessRequest request);
|
EsError FSBlockDeviceAccess(KBlockDeviceAccessRequest request);
|
||||||
|
@ -96,6 +97,10 @@ EsFileOffset FSNodeGetTotalSize(KNode *node) {
|
||||||
return node->directoryEntry->totalSize;
|
return node->directoryEntry->totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EsUniqueIdentifier FSNodeGetContentType(KNode *node) {
|
||||||
|
return node->directoryEntry->contentType;
|
||||||
|
}
|
||||||
|
|
||||||
char *FSNodeGetName(KNode *node, size_t *bytes) {
|
char *FSNodeGetName(KNode *node, size_t *bytes) {
|
||||||
KWriterLockAssertLocked(&node->writerLock);
|
KWriterLockAssertLocked(&node->writerLock);
|
||||||
*bytes = node->directoryEntry->item.key.longKeyBytes;
|
*bytes = node->directoryEntry->item.key.longKeyBytes;
|
||||||
|
@ -381,42 +386,52 @@ ptrdiff_t FSFileWriteSync(KNode *node, K_USER_BUFFER const void *buffer, EsFileO
|
||||||
return error == ES_SUCCESS ? bytes : error;
|
return error == ES_SUCCESS ? bytes : error;
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError FSFileControl(KNode *node, uint32_t flags) {
|
EsError FSFileControlFlush(KNode *node) {
|
||||||
FSFile *file = (FSFile *) node;
|
FSFile *file = (FSFile *) node;
|
||||||
|
|
||||||
if (flags & ES_FILE_CONTROL_FLUSH) {
|
KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE);
|
||||||
KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE);
|
EsDefer(KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE));
|
||||||
EsDefer(KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE));
|
|
||||||
|
|
||||||
CCSpaceFlush(&file->cache);
|
CCSpaceFlush(&file->cache);
|
||||||
|
|
||||||
KWriterLockTake(&file->writerLock, K_LOCK_EXCLUSIVE);
|
KWriterLockTake(&file->writerLock, K_LOCK_EXCLUSIVE);
|
||||||
EsDefer(KWriterLockReturn(&file->writerLock, K_LOCK_EXCLUSIVE));
|
EsDefer(KWriterLockReturn(&file->writerLock, K_LOCK_EXCLUSIVE));
|
||||||
|
|
||||||
__sync_fetch_and_and(&file->flags, ~NODE_MODIFIED);
|
__sync_fetch_and_and(&file->flags, ~NODE_MODIFIED);
|
||||||
|
|
||||||
EsError error = FSFileCreateAndResizeOnFileSystem(file, file->directoryEntry->totalSize);
|
EsError error = FSFileCreateAndResizeOnFileSystem(file, file->directoryEntry->totalSize);
|
||||||
if (error != ES_SUCCESS) return error;
|
if (error != ES_SUCCESS) return error;
|
||||||
|
|
||||||
if (file->fileSystem->sync) {
|
if (file->fileSystem->sync) {
|
||||||
// TODO Should we also sync the parent?
|
// TODO Should we also sync the parent?
|
||||||
FSDirectory *parent = file->directoryEntry->parent;
|
FSDirectory *parent = file->directoryEntry->parent;
|
||||||
|
|
||||||
if (parent) KWriterLockTake(&parent->writerLock, K_LOCK_EXCLUSIVE);
|
if (parent) KWriterLockTake(&parent->writerLock, K_LOCK_EXCLUSIVE);
|
||||||
file->fileSystem->sync(parent, file);
|
file->fileSystem->sync(parent, file);
|
||||||
if (parent) KWriterLockReturn(&parent->writerLock, K_LOCK_EXCLUSIVE);
|
if (parent) KWriterLockReturn(&parent->writerLock, K_LOCK_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file->error != ES_SUCCESS) {
|
if (file->error != ES_SUCCESS) {
|
||||||
EsError error = file->error;
|
EsError error = file->error;
|
||||||
file->error = ES_SUCCESS;
|
file->error = ES_SUCCESS;
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ES_SUCCESS;
|
return ES_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EsError FSFileControlSetContentType(KNode *node, EsUniqueIdentifier identifier) {
|
||||||
|
if (node->fileSystem->flags & ES_VOLUME_READ_ONLY) {
|
||||||
|
return ES_ERROR_FILE_ON_READ_ONLY_VOLUME;
|
||||||
|
} else if (~node->fileSystem->flags & ES_VOLUME_STORES_CONTENT_TYPE) {
|
||||||
|
return ES_ERROR_UNSUPPORTED;
|
||||||
|
} else {
|
||||||
|
node->directoryEntry->contentType = identifier;
|
||||||
|
__sync_fetch_and_or(&node->flags, NODE_MODIFIED); // Set the modified flag *after* making the modification.
|
||||||
|
return ES_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
// Directories.
|
// Directories.
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
|
@ -669,6 +684,7 @@ void _FSDirectoryEnumerateVisit(AVLItem<FSDirectoryEntry> *item, K_USER_BUFFER E
|
||||||
output->fileSize = entry->totalSize;
|
output->fileSize = entry->totalSize;
|
||||||
output->directoryChildren = entry->directoryChildren;
|
output->directoryChildren = entry->directoryChildren;
|
||||||
output->nameBytes = nameBytes;
|
output->nameBytes = nameBytes;
|
||||||
|
output->contentType = entry->contentType;
|
||||||
|
|
||||||
_FSDirectoryEnumerateVisit(item->children[0], buffer, bufferSize, position);
|
_FSDirectoryEnumerateVisit(item->children[0], buffer, bufferSize, position);
|
||||||
_FSDirectoryEnumerateVisit(item->children[1], buffer, bufferSize, position);
|
_FSDirectoryEnumerateVisit(item->children[1], buffer, bufferSize, position);
|
||||||
|
@ -808,9 +824,6 @@ EsError FSNodeCreate(FSDirectory *parent, const char *name, size_t nameBytes, Es
|
||||||
parent->directoryEntry->directoryChildren++;
|
parent->directoryEntry->directoryChildren++;
|
||||||
}
|
}
|
||||||
|
|
||||||
__sync_fetch_and_or(&parent->flags, NODE_MODIFIED);
|
|
||||||
__sync_fetch_and_or(&node->flags, NODE_MODIFIED);
|
|
||||||
|
|
||||||
// Only create directories immediately; files are created in FSWriteFromCache.
|
// Only create directories immediately; files are created in FSWriteFromCache.
|
||||||
|
|
||||||
if (type != ES_NODE_FILE) {
|
if (type != ES_NODE_FILE) {
|
||||||
|
@ -823,6 +836,10 @@ EsError FSNodeCreate(FSDirectory *parent, const char *name, size_t nameBytes, Es
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the modified flag *after* making the modification.
|
||||||
|
__sync_fetch_and_or(&parent->flags, NODE_MODIFIED);
|
||||||
|
__sync_fetch_and_or(&node->flags, NODE_MODIFIED);
|
||||||
|
|
||||||
// Put the node onto the object cache list.
|
// Put the node onto the object cache list.
|
||||||
// Since the parent directory is locked, it should stay around for long enough to be immediately found FSNodeTraverseLayer.
|
// Since the parent directory is locked, it should stay around for long enough to be immediately found FSNodeTraverseLayer.
|
||||||
if (node->flags & NODE_IN_CACHE_LIST) KernelPanic("FSNodeCreate - Node %x is already in the cache list.\n", node);
|
if (node->flags & NODE_IN_CACHE_LIST) KernelPanic("FSNodeCreate - Node %x is already in the cache list.\n", node);
|
||||||
|
@ -1888,6 +1905,7 @@ void FSTrackUserFileSystemHandle(KDevice *device, bool opened) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSRegisterFileSystem(KFileSystem *fileSystem) {
|
void FSRegisterFileSystem(KFileSystem *fileSystem) {
|
||||||
|
if (!fileSystem->write) fileSystem->volumeFlags |= ES_VOLUME_READ_ONLY;
|
||||||
fileSystem->trackHandle = FSTrackUserFileSystemHandle;
|
fileSystem->trackHandle = FSTrackUserFileSystemHandle;
|
||||||
MMObjectCacheRegister(&fileSystem->cachedDirectoryEntries, FSTrimCachedDirectoryEntry,
|
MMObjectCacheRegister(&fileSystem->cachedDirectoryEntries, FSTrimCachedDirectoryEntry,
|
||||||
sizeof(FSDirectoryEntry) + 16 /* approximate average name bytes */ + fileSystem->directoryEntryDataBytes);
|
sizeof(FSDirectoryEntry) + 16 /* approximate average name bytes */ + fileSystem->directoryEntryDataBytes);
|
||||||
|
|
|
@ -805,6 +805,7 @@ struct KNodeMetadata {
|
||||||
bool removingNodeFromCache, removingThisFromCache;
|
bool removingNodeFromCache, removingThisFromCache;
|
||||||
EsFileOffset totalSize;
|
EsFileOffset totalSize;
|
||||||
EsFileOffsetDifference directoryChildren; // ES_DIRECTORY_CHILDREN_UNKNOWN if not supported by the file system.
|
EsFileOffsetDifference directoryChildren; // ES_DIRECTORY_CHILDREN_UNKNOWN if not supported by the file system.
|
||||||
|
EsUniqueIdentifier contentType;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KNode {
|
struct KNode {
|
||||||
|
@ -840,6 +841,8 @@ struct KFileSystem : KDevice {
|
||||||
char name[64];
|
char name[64];
|
||||||
size_t nameBytes;
|
size_t nameBytes;
|
||||||
|
|
||||||
|
EsVolumeFlags volumeFlags; // Note: ES_VOLUME_READ_ONLY will be automatically set if you don't set the write() callback pointer.
|
||||||
|
|
||||||
size_t directoryEntryDataBytes; // The size of the driverData passed to FSDirectoryEntryFound and received in the load callback.
|
size_t directoryEntryDataBytes; // The size of the driverData passed to FSDirectoryEntryFound and received in the load callback.
|
||||||
size_t nodeDataBytes; // The average bytes allocated by the driver per node (used for managing cache sizes).
|
size_t nodeDataBytes; // The average bytes allocated by the driver per node (used for managing cache sizes).
|
||||||
|
|
||||||
|
@ -906,6 +909,7 @@ struct KNodeInformation {
|
||||||
KNodeInformation FSNodeOpen(const char *path, size_t pathBytes, uint32_t flags, KNode *baseDirectory = nullptr);
|
KNodeInformation FSNodeOpen(const char *path, size_t pathBytes, uint32_t flags, KNode *baseDirectory = nullptr);
|
||||||
|
|
||||||
EsFileOffset FSNodeGetTotalSize(KNode *node);
|
EsFileOffset FSNodeGetTotalSize(KNode *node);
|
||||||
|
EsUniqueIdentifier FSNodeGetContentType(KNode *node);
|
||||||
|
|
||||||
char *FSNodeGetName(KNode *node, size_t *bytes); // For debugging use only.
|
char *FSNodeGetName(KNode *node, size_t *bytes); // For debugging use only.
|
||||||
|
|
||||||
|
|
|
@ -628,7 +628,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_VOLUME_GET_INFORMATION) {
|
||||||
information.spaceUsed = fileSystem->spaceUsed;
|
information.spaceUsed = fileSystem->spaceUsed;
|
||||||
information.spaceTotal = fileSystem->spaceTotal;
|
information.spaceTotal = fileSystem->spaceTotal;
|
||||||
information.id = fileSystem->objectID;
|
information.id = fileSystem->objectID;
|
||||||
information.flags = fileSystem->write ? ES_FLAGS_DEFAULT : ES_VOLUME_READ_ONLY;
|
information.flags = fileSystem->volumeFlags;
|
||||||
information.installationIdentifier = fileSystem->installationIdentifier;
|
information.installationIdentifier = fileSystem->installationIdentifier;
|
||||||
information.identifier = fileSystem->identifier;
|
information.identifier = fileSystem->identifier;
|
||||||
|
|
||||||
|
@ -702,6 +702,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_NODE_OPEN) {
|
||||||
information.type = _information.node->directoryEntry->type;
|
information.type = _information.node->directoryEntry->type;
|
||||||
information.fileSize = _information.node->directoryEntry->totalSize;
|
information.fileSize = _information.node->directoryEntry->totalSize;
|
||||||
information.directoryChildren = _information.node->directoryEntry->directoryChildren;
|
information.directoryChildren = _information.node->directoryEntry->directoryChildren;
|
||||||
|
information.contentType = _information.node->directoryEntry->contentType;
|
||||||
information.handle = currentProcess->handleTable.OpenHandle(_information.node, flags, KERNEL_OBJECT_NODE);
|
information.handle = currentProcess->handleTable.OpenHandle(_information.node, flags, KERNEL_OBJECT_NODE);
|
||||||
SYSCALL_WRITE(argument3, &information, sizeof(_EsNodeInformation));
|
SYSCALL_WRITE(argument3, &information, sizeof(_EsNodeInformation));
|
||||||
|
|
||||||
|
@ -1187,13 +1188,26 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_DIRECTORY_ENUMERATE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_IMPLEMENT(ES_SYSCALL_FILE_CONTROL) {
|
SYSCALL_IMPLEMENT(ES_SYSCALL_FILE_CONTROL) {
|
||||||
SYSCALL_HANDLE(argument0, KERNEL_OBJECT_NODE, file, KNode);
|
SYSCALL_HANDLE_2(argument0, KERNEL_OBJECT_NODE, handle);
|
||||||
|
KNode *file = (KNode *) handle.object;
|
||||||
|
|
||||||
if (file->directoryEntry->type != ES_NODE_FILE) {
|
if (file->directoryEntry->type != ES_NODE_FILE) {
|
||||||
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true);
|
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true);
|
||||||
|
} else if ((handle.flags & (ES_FILE_WRITE_SHARED | ES_FILE_WRITE)) == 0) {
|
||||||
|
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_RETURN(FSFileControl(file, argument1), false);
|
EsError error = ES_ERROR_UNSUPPORTED;
|
||||||
|
|
||||||
|
if (argument1 == ES_FILE_CONTROL_FLUSH) {
|
||||||
|
error = FSFileControlFlush(file);
|
||||||
|
} else if (argument1 == ES_FILE_CONTROL_SET_CONTENT_TYPE) {
|
||||||
|
EsUniqueIdentifier identifier;
|
||||||
|
SYSCALL_READ(&identifier, argument2, sizeof(identifier));
|
||||||
|
error = FSFileControlSetContentType(file, identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCALL_RETURN(error, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_IMPLEMENT(ES_SYSCALL_BATCH) {
|
SYSCALL_IMPLEMENT(ES_SYSCALL_BATCH) {
|
||||||
|
|
|
@ -111,9 +111,10 @@ typedef struct DirectoryEntry {
|
||||||
/* 32 */ uint64_t creationTime, accessTime, modificationTime; // Timekeeping. In microseconds since 1st January 1970.
|
/* 32 */ uint64_t creationTime, accessTime, modificationTime; // Timekeeping. In microseconds since 1st January 1970.
|
||||||
/* 56 */ uint64_t fileSize; // The amount of data referenced by the data attribute in bytes.
|
/* 56 */ uint64_t fileSize; // The amount of data referenced by the data attribute in bytes.
|
||||||
/* 64 */ EsUniqueIdentifier parent; // Identifier of the parent directory.
|
/* 64 */ EsUniqueIdentifier parent; // Identifier of the parent directory.
|
||||||
|
/* 80 */ EsUniqueIdentifier contentType; // Identifier of the file content type.
|
||||||
|
|
||||||
#define ESFS_ATTRIBUTE_OFFSET (80)
|
#define ESFS_ATTRIBUTE_OFFSET (96)
|
||||||
/* 80 */ uint8_t attributes[1024 - ESFS_ATTRIBUTE_OFFSET]; // Attribute list.
|
/* 96 */ uint8_t attributes[1024 - ESFS_ATTRIBUTE_OFFSET]; // Attribute list.
|
||||||
} DirectoryEntry;
|
} DirectoryEntry;
|
||||||
|
|
||||||
typedef struct GroupDescriptor {
|
typedef struct GroupDescriptor {
|
||||||
|
|
|
@ -59,6 +59,7 @@ FILE *systemLog;
|
||||||
char compilerPath[4096];
|
char compilerPath[4096];
|
||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
|
bool runningTests;
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
#define PATH_MAX 1024
|
#define PATH_MAX 1024
|
||||||
|
@ -985,13 +986,17 @@ void BuildAndRun(int optimise, bool compile, int debug, int emulator, int log) {
|
||||||
Run(emulator, log, debug);
|
Run(emulator, log, debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(encounteredErrors ? 1 : 0);
|
if (!runningTests) {
|
||||||
|
exit(encounteredErrors ? 1 : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunTests(int singleTest) {
|
void RunTests(int singleTest) {
|
||||||
// TODO Capture emulator memory dump if a test causes a EsPanic.
|
// TODO Capture emulator memory dump if a test causes a EsPanic.
|
||||||
// TODO Using SMP/KVM if available in the optimised test runs.
|
// TODO Using SMP/KVM if available in the optimised test runs.
|
||||||
|
|
||||||
|
runningTests = true;
|
||||||
|
|
||||||
int successCount = 0, failureCount = 0;
|
int successCount = 0, failureCount = 0;
|
||||||
CallSystem("mkdir -p root/Essence/Settings/API\\ Tests");
|
CallSystem("mkdir -p root/Essence/Settings/API\\ Tests");
|
||||||
FILE *testFailures = fopen("bin/Logs/Test Failures.txt", "wb");
|
FILE *testFailures = fopen("bin/Logs/Test Failures.txt", "wb");
|
||||||
|
|
|
@ -15,6 +15,10 @@ str compilerPath #persist;
|
||||||
int compilerIndex #persist;
|
int compilerIndex #persist;
|
||||||
bool runningMakefiles #persist;
|
bool runningMakefiles #persist;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// Environment setup
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void Setup(bool forAutomation) {
|
void Setup(bool forAutomation) {
|
||||||
assert PersistRead("bin/start.script.persist");
|
assert PersistRead("bin/start.script.persist");
|
||||||
|
|
||||||
|
@ -109,6 +113,10 @@ void Setup(bool forAutomation) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// Command interface
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void DoCommand(str command) {
|
void DoCommand(str command) {
|
||||||
if command == "line-count" {
|
if command == "line-count" {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -215,6 +223,10 @@ void Start() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// Automation scripts
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void GenerateOVF() {
|
void GenerateOVF() {
|
||||||
str[] template = StringSplitByCharacter(FileReadAll("util/template.ovf"):assert(), "$", true);
|
str[] template = StringSplitByCharacter(FileReadAll("util/template.ovf"):assert(), "$", true);
|
||||||
assert template:len() == 5;
|
assert template:len() == 5;
|
||||||
|
|
Loading…
Reference in New Issue