files: storing file content type

This commit is contained in:
nakst 2022-03-21 14:25:58 +00:00
parent 82ccd24c61
commit a0fe4d31e9
15 changed files with 158 additions and 53 deletions

View File

@ -337,7 +337,7 @@ void CommandPasteTask(EsUserTask *userTask, EsGeneric _task) {
EsDirectoryChild information;
if (EsPathQueryInformation(STRING(source), &information)) {
if (ES_SUCCESS == EsPathQueryInformation(STRING(source), &information)) {
if (information.fileSize == -1) {
// TODO Support progress on volumes that don't report total directory sizes.
} else {

View File

@ -17,7 +17,7 @@ Array<Folder *> foldersWithNoAttachedInstances;
bool FSDirHandlesPath(String path) {
EsDirectoryChild information;
if (EsPathQueryInformation(STRING(path), &information)) {
if (ES_SUCCESS == EsPathQueryInformation(STRING(path), &information)) {
return information.type == ES_NODE_DIRECTORY;
} else {
return false;
@ -91,7 +91,7 @@ EsError FSDirEnumerate(Folder *folder) {
void FSDirGetTotalSize(Folder *folder) {
EsDirectoryChild information;
if (EsPathQueryInformation(STRING(folder->path), &information)) {
if (ES_SUCCESS == EsPathQueryInformation(STRING(folder->path), &information)) {
folder->spaceUsed = information.fileSize;
folder->spaceTotal = 0;
}
@ -464,7 +464,7 @@ void FolderFileUpdatedAtPath(String path, Instance *instance) {
String file = PathGetName(path);
String folder = PathGetParent(path);
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++) {
if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue;

View File

@ -378,8 +378,8 @@ int ExternalFileAppend(ExecutionContext *context, Value *returnValue) {
int ExternalFileGetSize(ExecutionContext *context, Value *returnValue) {
STACK_POP_STRING(entryText, entryBytes);
EsDirectoryChild information;
bool exists = EsPathQueryInformation(entryText, entryBytes, &information);
if (!exists) RETURN_ERROR(ES_ERROR_FILE_DOES_NOT_EXIST);
EsError error = EsPathQueryInformation(entryText, entryBytes, &information);
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);
returnValue->i = information.fileSize;
return EXTCALL_RETURN_ERR_UNMANAGED;
@ -1011,7 +1011,7 @@ void EnterCommand(Instance *instance) {
uint8_t newline = '\n';
EsFileWriteSync(globalCommandHistoryFile.handle, EsFileGetSize(globalCommandHistoryFile.handle), dataBytes, data);
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));
EsTextDisplayCreate(commandLogRow, ES_FLAGS_DEFAULT, EsStyleIntern(&stylePromptText), "\u2661");

View File

@ -132,7 +132,7 @@ LoadEachExtent:
%endmacro
%macro FilesystemSpecificCode 0
KernelDataStreamPosition: dw 0x850
KernelDataStreamPosition: dw 0x860
ErrorBadFilesystem: db "Invalid boot EsFS volume.",0
ErrorUnexpectedFileProblem: db "The kernel file could not be loaded.",0
%endmacro

View File

@ -1227,7 +1227,7 @@ void EsInstanceSaveComplete(EsInstance *instance, EsFileStore *file, bool succes
}
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) {
success = false;

View File

@ -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
const Test tests[] = {
@ -1323,6 +1361,7 @@ const Test tests[] = {
TEST(POSIXSubsystemTest, 120),
TEST(RestartTest, 1200),
TEST(ResizeFileTest, 600),
TEST(FileContentTypeTest, 60),
};
#ifndef API_TESTS_FOR_RUNNER

View File

@ -71,16 +71,17 @@ bool EsPathExists(const char *path, ptrdiff_t pathBytes, EsNodeType *type) {
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);
_EsNodeInformation 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);
information->type = node.type;
information->fileSize = node.fileSize;
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) {
@ -94,8 +95,8 @@ EsError EsPathCreate(const char *path, ptrdiff_t pathBytes, EsNodeType type, boo
return ES_SUCCESS;
}
EsError EsFileControl(EsHandle file, uint32_t flags) {
return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, flags, 0, 0);
EsError EsFileControl(EsHandle file, EsFileControlOperation operation, const void *data, size_t dataBytes) {
return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, operation, (uintptr_t) data, dataBytes);
}
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) {
information.handle = node.handle;
information.size = node.fileSize;
information.contentType = node.contentType;
}
information.error = result;
@ -245,7 +247,7 @@ EsFileOffsetDifference EsFileStoreGetSize(EsFileStore *file) {
} else if (file->type == FILE_STORE_PATH) {
EsDirectoryChild information;
if (EsPathQueryInformation(file->path, file->pathBytes, &information)) {
if (ES_SUCCESS == EsPathQueryInformation(file->path, file->pathBytes, &information)) {
return file->pathBytes;
} else {
return -1;
@ -576,7 +578,7 @@ EsError EsFileWriteAllGatherFromHandle(EsHandle handle, const void **data, const
offset += sizes[i];
}
error = EsFileControl(handle, ES_FILE_CONTROL_FLUSH);
error = EsFileControl(handle, ES_FILE_CONTROL_FLUSH, nullptr, 0);
return error;
}

View File

@ -760,8 +760,9 @@ inttype EsConnectionOpenFlags uint32_t none {
ES_CONNECTION_OPEN_WAIT = bit 0
};
inttype EsFileControlFlags uint32_t none {
ES_FILE_CONTROL_FLUSH = bit 0
inttype EsFileControlOperation uint32_t none {
ES_FILE_CONTROL_FLUSH = 0 // data/dataBytes ignored
ES_FILE_CONTROL_SET_CONTENT_TYPE = 1 // data EsUniqueIdentifier; dataBytes ignored
};
inttype EsElementUpdateContentFlags uint32_t none {
@ -838,6 +839,7 @@ inttype EsProcessCreationFlags uint32_t none {
inttype EsVolumeFlags uint32_t none {
ES_VOLUME_READ_ONLY = bit 0
ES_VOLUME_STORES_CONTENT_TYPE = bit 1
};
inttype EsPathMoveFlags uint32_t none {
@ -1340,6 +1342,7 @@ struct EsFileInformation {
EsHandle handle;
EsFileOffset size;
EsError error;
EsUniqueIdentifier contentType; // Zeroed if unsupported, or not initialised.
};
struct EsDirectoryChild {
@ -1348,6 +1351,7 @@ struct EsDirectoryChild {
EsNodeType type;
EsFileOffsetDifference fileSize; // -1 if unsupported.
EsFileOffsetDifference directoryChildren; // ES_DIRECTORY_CHILDREN_UNKNOWN if unsupported.
EsUniqueIdentifier contentType; // Zeroed if unsupported, or not initialised.
};
struct EsPoint {
@ -1635,6 +1639,7 @@ private struct _EsNodeInformation {
EsFileOffset fileSize;
EsFileOffsetDifference directoryChildren;
EsNodeType type;
EsUniqueIdentifier contentType;
};
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 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 EsFileOffset EsFileGetSize(EsHandle handle);
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 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 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 bool EsFileStoreWriteAll(EsFileStore *file, const void *data, size_t dataBytes) @buffer_in(data, dataBytes);

View File

@ -9,7 +9,6 @@
// 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 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.
#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.
AttributeDirectory *directoryAttribute = (AttributeDirectory *) FindAttribute(&file->entry, ESFS_ATTRIBUTE_DIRECTORY);
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) {
metadata.totalSize = entry->fileSize;
metadata.contentType = entry->contentType;
}
EsError error = FSDirectoryEntryFound(node, &metadata, &reference,
@ -1819,6 +1822,7 @@ static EsError Scan(const char *name, size_t nameLength, KNode *_directory) {
}
} else {
metadata.totalSize = entry->fileSize;
metadata.contentType = entry->contentType;
}
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->directoryEntryDataBytes = sizeof(DirectoryEntryReference);
volume->nodeDataBytes = sizeof(FSNode);
volume->volumeFlags |= ES_VOLUME_STORES_CONTENT_TYPE;
FSRegisterBootFileSystem(volume, volume->superblock.osInstallation);
}

View File

@ -67,7 +67,8 @@ EsError FSNodeDelete(KNode *node);
EsError FSNodeMove(KNode *node, KNode *destination, const char *newName, size_t nameNameBytes);
EsError FSFileResize(KNode *node, EsFileOffset newSizeBytes);
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 FSTrimCachedDirectoryEntry(MMObjectCache *);
EsError FSBlockDeviceAccess(KBlockDeviceAccessRequest request);
@ -96,6 +97,10 @@ EsFileOffset FSNodeGetTotalSize(KNode *node) {
return node->directoryEntry->totalSize;
}
EsUniqueIdentifier FSNodeGetContentType(KNode *node) {
return node->directoryEntry->contentType;
}
char *FSNodeGetName(KNode *node, size_t *bytes) {
KWriterLockAssertLocked(&node->writerLock);
*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;
}
EsError FSFileControl(KNode *node, uint32_t flags) {
EsError FSFileControlFlush(KNode *node) {
FSFile *file = (FSFile *) node;
if (flags & ES_FILE_CONTROL_FLUSH) {
KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE);
EsDefer(KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE));
KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE);
EsDefer(KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE));
CCSpaceFlush(&file->cache);
CCSpaceFlush(&file->cache);
KWriterLockTake(&file->writerLock, K_LOCK_EXCLUSIVE);
EsDefer(KWriterLockReturn(&file->writerLock, K_LOCK_EXCLUSIVE));
KWriterLockTake(&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);
if (error != ES_SUCCESS) return error;
EsError error = FSFileCreateAndResizeOnFileSystem(file, file->directoryEntry->totalSize);
if (error != ES_SUCCESS) return error;
if (file->fileSystem->sync) {
// TODO Should we also sync the parent?
FSDirectory *parent = file->directoryEntry->parent;
if (file->fileSystem->sync) {
// TODO Should we also sync the parent?
FSDirectory *parent = file->directoryEntry->parent;
if (parent) KWriterLockTake(&parent->writerLock, K_LOCK_EXCLUSIVE);
file->fileSystem->sync(parent, file);
if (parent) KWriterLockReturn(&parent->writerLock, K_LOCK_EXCLUSIVE);
}
if (parent) KWriterLockTake(&parent->writerLock, K_LOCK_EXCLUSIVE);
file->fileSystem->sync(parent, file);
if (parent) KWriterLockReturn(&parent->writerLock, K_LOCK_EXCLUSIVE);
}
if (file->error != ES_SUCCESS) {
EsError error = file->error;
file->error = ES_SUCCESS;
return error;
}
if (file->error != ES_SUCCESS) {
EsError error = file->error;
file->error = ES_SUCCESS;
return error;
}
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.
//////////////////////////////////////////
@ -669,6 +684,7 @@ void _FSDirectoryEnumerateVisit(AVLItem<FSDirectoryEntry> *item, K_USER_BUFFER E
output->fileSize = entry->totalSize;
output->directoryChildren = entry->directoryChildren;
output->nameBytes = nameBytes;
output->contentType = entry->contentType;
_FSDirectoryEnumerateVisit(item->children[0], 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++;
}
__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.
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.
// 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);
@ -1888,6 +1905,7 @@ void FSTrackUserFileSystemHandle(KDevice *device, bool opened) {
}
void FSRegisterFileSystem(KFileSystem *fileSystem) {
if (!fileSystem->write) fileSystem->volumeFlags |= ES_VOLUME_READ_ONLY;
fileSystem->trackHandle = FSTrackUserFileSystemHandle;
MMObjectCacheRegister(&fileSystem->cachedDirectoryEntries, FSTrimCachedDirectoryEntry,
sizeof(FSDirectoryEntry) + 16 /* approximate average name bytes */ + fileSystem->directoryEntryDataBytes);

View File

@ -805,6 +805,7 @@ struct KNodeMetadata {
bool removingNodeFromCache, removingThisFromCache;
EsFileOffset totalSize;
EsFileOffsetDifference directoryChildren; // ES_DIRECTORY_CHILDREN_UNKNOWN if not supported by the file system.
EsUniqueIdentifier contentType;
};
struct KNode {
@ -840,6 +841,8 @@ struct KFileSystem : KDevice {
char name[64];
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 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);
EsFileOffset FSNodeGetTotalSize(KNode *node);
EsUniqueIdentifier FSNodeGetContentType(KNode *node);
char *FSNodeGetName(KNode *node, size_t *bytes); // For debugging use only.

View File

@ -628,7 +628,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_VOLUME_GET_INFORMATION) {
information.spaceUsed = fileSystem->spaceUsed;
information.spaceTotal = fileSystem->spaceTotal;
information.id = fileSystem->objectID;
information.flags = fileSystem->write ? ES_FLAGS_DEFAULT : ES_VOLUME_READ_ONLY;
information.flags = fileSystem->volumeFlags;
information.installationIdentifier = fileSystem->installationIdentifier;
information.identifier = fileSystem->identifier;
@ -702,6 +702,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_NODE_OPEN) {
information.type = _information.node->directoryEntry->type;
information.fileSize = _information.node->directoryEntry->totalSize;
information.directoryChildren = _information.node->directoryEntry->directoryChildren;
information.contentType = _information.node->directoryEntry->contentType;
information.handle = currentProcess->handleTable.OpenHandle(_information.node, flags, KERNEL_OBJECT_NODE);
SYSCALL_WRITE(argument3, &information, sizeof(_EsNodeInformation));
@ -1187,13 +1188,26 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_DIRECTORY_ENUMERATE) {
}
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) {
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) {

View File

@ -111,9 +111,10 @@ typedef struct DirectoryEntry {
/* 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.
/* 64 */ EsUniqueIdentifier parent; // Identifier of the parent directory.
/* 80 */ EsUniqueIdentifier contentType; // Identifier of the file content type.
#define ESFS_ATTRIBUTE_OFFSET (80)
/* 80 */ uint8_t attributes[1024 - ESFS_ATTRIBUTE_OFFSET]; // Attribute list.
#define ESFS_ATTRIBUTE_OFFSET (96)
/* 96 */ uint8_t attributes[1024 - ESFS_ATTRIBUTE_OFFSET]; // Attribute list.
} DirectoryEntry;
typedef struct GroupDescriptor {

View File

@ -59,6 +59,7 @@ FILE *systemLog;
char compilerPath[4096];
int argc;
char **argv;
bool runningTests;
#ifndef PATH_MAX
#define PATH_MAX 1024
@ -985,13 +986,17 @@ void BuildAndRun(int optimise, bool compile, int debug, int emulator, int log) {
Run(emulator, log, debug);
}
exit(encounteredErrors ? 1 : 0);
if (!runningTests) {
exit(encounteredErrors ? 1 : 0);
}
}
void RunTests(int singleTest) {
// TODO Capture emulator memory dump if a test causes a EsPanic.
// TODO Using SMP/KVM if available in the optimised test runs.
runningTests = true;
int successCount = 0, failureCount = 0;
CallSystem("mkdir -p root/Essence/Settings/API\\ Tests");
FILE *testFailures = fopen("bin/Logs/Test Failures.txt", "wb");

View File

@ -15,6 +15,10 @@ str compilerPath #persist;
int compilerIndex #persist;
bool runningMakefiles #persist;
/////////////////////////////////////////////////////////////
// Environment setup
/////////////////////////////////////////////////////////////
void Setup(bool forAutomation) {
assert PersistRead("bin/start.script.persist");
@ -109,6 +113,10 @@ void Setup(bool forAutomation) {
}
}
/////////////////////////////////////////////////////////////
// Command interface
/////////////////////////////////////////////////////////////
void DoCommand(str command) {
if command == "line-count" {
int count = 0;
@ -215,6 +223,10 @@ void Start() {
}
}
/////////////////////////////////////////////////////////////
// Automation scripts
/////////////////////////////////////////////////////////////
void GenerateOVF() {
str[] template = StringSplitByCharacter(FileReadAll("util/template.ovf"):assert(), "$", true);
assert template:len() == 5;