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;
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue