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