diff --git a/apps/file_manager/commands.cpp b/apps/file_manager/commands.cpp index 425f88a..e407593 100644 --- a/apps/file_manager/commands.cpp +++ b/apps/file_manager/commands.cpp @@ -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 { diff --git a/apps/file_manager/folder.cpp b/apps/file_manager/folder.cpp index 5016ef5..df46230 100644 --- a/apps/file_manager/folder.cpp +++ b/apps/file_manager/folder.cpp @@ -17,7 +17,7 @@ Array 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; diff --git a/apps/script_console.cpp b/apps/script_console.cpp index 353f68a..35017c0 100644 --- a/apps/script_console.cpp +++ b/apps/script_console.cpp @@ -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"); diff --git a/boot/x86/esfs-stage2.s b/boot/x86/esfs-stage2.s index 992e2c1..45e1646 100644 --- a/boot/x86/esfs-stage2.s +++ b/boot/x86/esfs-stage2.s @@ -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 diff --git a/desktop/api.cpp b/desktop/api.cpp index 2aaf7cc..f6c7aa1 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -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; diff --git a/desktop/api_tests.cpp b/desktop/api_tests.cpp index dcf7264..52c7de5 100644 --- a/desktop/api_tests.cpp +++ b/desktop/api_tests.cpp @@ -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 diff --git a/desktop/files.cpp b/desktop/files.cpp index 0505a0a..aee47ae 100644 --- a/desktop/files.cpp +++ b/desktop/files.cpp @@ -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; } diff --git a/desktop/os.header b/desktop/os.header index 204986f..05cb15a 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -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); diff --git a/drivers/esfs2.cpp b/drivers/esfs2.cpp index f597624..c40283c 100644 --- a/drivers/esfs2.cpp +++ b/drivers/esfs2.cpp @@ -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); } diff --git a/kernel/files.cpp b/kernel/files.cpp index f9cdc78..2b0c629 100644 --- a/kernel/files.cpp +++ b/kernel/files.cpp @@ -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 *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); diff --git a/kernel/module.h b/kernel/module.h index d48bf7b..6e0ad50 100644 --- a/kernel/module.h +++ b/kernel/module.h @@ -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. diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index d50d518..33e9e70 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -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) { diff --git a/shared/esfs2.h b/shared/esfs2.h index ce7a491..56c3005 100644 --- a/shared/esfs2.h +++ b/shared/esfs2.h @@ -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 { diff --git a/util/build.c b/util/build.c index f88eb90..fe7741c 100644 --- a/util/build.c +++ b/util/build.c @@ -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"); diff --git a/util/start.script b/util/start.script index 29aafc0..4a4b53c 100644 --- a/util/start.script +++ b/util/start.script @@ -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;