mirror of https://gitlab.com/nakst/essence
				
				
				
			fix POSIX file IO; move userland file IO code into separate file
This commit is contained in:
		
							parent
							
								
									e7238c8a52
								
							
						
					
					
						commit
						a80944332e
					
				
							
								
								
									
										254
									
								
								desktop/api.cpp
								
								
								
								
							
							
						
						
									
										254
									
								
								desktop/api.cpp
								
								
								
								
							| 
						 | 
					@ -189,7 +189,7 @@ struct {
 | 
				
			||||||
	EsHandle desktopRequestPipe, desktopResponsePipe;
 | 
						EsHandle desktopRequestPipe, desktopResponsePipe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EsMutex mountPointsMutex;
 | 
						EsMutex mountPointsMutex;
 | 
				
			||||||
	Array<EsMountPoint> mountPoints2;
 | 
						Array<EsMountPoint> mountPoints;
 | 
				
			||||||
	Array<EsMessageDevice> connectedDevices;
 | 
						Array<EsMessageDevice> connectedDevices;
 | 
				
			||||||
	bool foundBootFileSystem;
 | 
						bool foundBootFileSystem;
 | 
				
			||||||
	EsProcessStartupInformation *startupInformation;
 | 
						EsProcessStartupInformation *startupInformation;
 | 
				
			||||||
| 
						 | 
					@ -256,6 +256,7 @@ extern "C" void _init();
 | 
				
			||||||
#include "inspector.cpp"
 | 
					#include "inspector.cpp"
 | 
				
			||||||
#include "desktop.cpp"
 | 
					#include "desktop.cpp"
 | 
				
			||||||
#include "settings.cpp"
 | 
					#include "settings.cpp"
 | 
				
			||||||
 | 
					#include "files.cpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const void *const apiTable[] = {
 | 
					const void *const apiTable[] = {
 | 
				
			||||||
#include <bin/generated_code/api_array.h>
 | 
					#include <bin/generated_code/api_array.h>
 | 
				
			||||||
| 
						 | 
					@ -273,103 +274,6 @@ uintptr_t APISyscallCheckForCrash(uintptr_t argument0, uintptr_t argument1, uint
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EsError MountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base, bool addedByApplication) {
 | 
					 | 
				
			||||||
	EsMutexAcquire(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	bool duplicate = NodeFindMountPoint(prefix, prefixBytes, nullptr, true);
 | 
					 | 
				
			||||||
	EsError error = ES_SUCCESS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (duplicate) {
 | 
					 | 
				
			||||||
		error = ES_ERROR_MOUNT_POINT_ALREADY_EXISTS;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		EsMountPoint mountPoint = {};
 | 
					 | 
				
			||||||
		EsAssert(prefixBytes < sizeof(mountPoint.prefix));
 | 
					 | 
				
			||||||
		EsMemoryCopy(mountPoint.prefix, prefix, prefixBytes);
 | 
					 | 
				
			||||||
		mountPoint.base = EsSyscall(ES_SYSCALL_HANDLE_SHARE, base, ES_CURRENT_PROCESS, 0, 0);
 | 
					 | 
				
			||||||
		mountPoint.prefixBytes = prefixBytes;
 | 
					 | 
				
			||||||
		mountPoint.addedByApplication = addedByApplication;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ES_CHECK_ERROR(mountPoint.base)) {
 | 
					 | 
				
			||||||
			error = ES_ERROR_INSUFFICIENT_RESOURCES;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if (!api.mountPoints2.Add(mountPoint)) {
 | 
					 | 
				
			||||||
				EsHandleClose(mountPoint.base);
 | 
					 | 
				
			||||||
				error = ES_ERROR_INSUFFICIENT_RESOURCES;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsMutexRelease(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	return error;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsError EsMountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base) {
 | 
					 | 
				
			||||||
	return MountPointAdd(prefix, prefixBytes, base, true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool NodeFindMountPoint(const char *prefix, size_t prefixBytes, EsMountPoint *result, bool mutexTaken) {
 | 
					 | 
				
			||||||
	if (!mutexTaken) EsMutexAcquire(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	bool found = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (uintptr_t i = 0; i < api.mountPoints2.Length(); i++) {
 | 
					 | 
				
			||||||
		EsMountPoint *mountPoint = &api.mountPoints2[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (prefixBytes >= mountPoint->prefixBytes && 0 == EsMemoryCompare(prefix, mountPoint->prefix, mountPoint->prefixBytes)) {
 | 
					 | 
				
			||||||
			// Only permanent mount points can be used retrieved with NodeFindMountPoint when mutexTaken = false,
 | 
					 | 
				
			||||||
			// because mount points added by the application can be removed as soon as we release the mutex,
 | 
					 | 
				
			||||||
			// and the base handle would be closed.
 | 
					 | 
				
			||||||
			EsAssert(mutexTaken || !mountPoint->addedByApplication);
 | 
					 | 
				
			||||||
			if (result) EsMemoryCopy(result, mountPoint, sizeof(EsMountPoint));
 | 
					 | 
				
			||||||
			found = true;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!mutexTaken) EsMutexRelease(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	return found;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool EsMountPointRemove(const char *prefix, size_t prefixBytes) {
 | 
					 | 
				
			||||||
	EsMutexAcquire(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	bool found = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (uintptr_t i = 0; i < api.mountPoints2.Length(); i++) {
 | 
					 | 
				
			||||||
		EsMountPoint *mountPoint = &api.mountPoints2[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (prefixBytes >= mountPoint->prefixBytes && 0 == EsMemoryCompare(prefix, mountPoint->prefix, mountPoint->prefixBytes)) {
 | 
					 | 
				
			||||||
			EsAssert(mountPoint->addedByApplication);
 | 
					 | 
				
			||||||
			EsHandleClose(mountPoint->base);
 | 
					 | 
				
			||||||
			api.mountPoints2.Delete(i);
 | 
					 | 
				
			||||||
			found = true;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsMutexRelease(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	return found;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, EsVolumeInformation *information) {
 | 
					 | 
				
			||||||
	EsMutexAcquire(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	EsMountPoint mountPoint;
 | 
					 | 
				
			||||||
	bool found = NodeFindMountPoint(prefix, prefixBytes, &mountPoint, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (found) {
 | 
					 | 
				
			||||||
		_EsNodeInformation node;
 | 
					 | 
				
			||||||
		node.handle = mountPoint.base;
 | 
					 | 
				
			||||||
		EsError error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) "/", 1, ES_NODE_DIRECTORY, (uintptr_t) &node);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (error == ES_SUCCESS) {
 | 
					 | 
				
			||||||
			EsSyscall(ES_SYSCALL_VOLUME_GET_INFORMATION, node.handle, (uintptr_t) information, 0, 0);
 | 
					 | 
				
			||||||
			EsHandleClose(node.handle);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			EsMemoryZero(information, sizeof(EsVolumeInformation));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsMutexRelease(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	return found;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EsDeviceEnumerate(EsDeviceEnumerationCallback callback, EsGeneric context) {
 | 
					void EsDeviceEnumerate(EsDeviceEnumerationCallback callback, EsGeneric context) {
 | 
				
			||||||
	EsMessageMutexCheck();
 | 
						EsMessageMutexCheck();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -378,27 +282,6 @@ void EsDeviceEnumerate(EsDeviceEnumerationCallback callback, EsGeneric context)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node) {
 | 
					 | 
				
			||||||
	// TODO I really don't like having to acquire a mutex to open a node.
 | 
					 | 
				
			||||||
	// 	This could be replaced with a writer lock!
 | 
					 | 
				
			||||||
	// 	(...but we don't have writer locks in userland yet.)
 | 
					 | 
				
			||||||
	EsMutexAcquire(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsMountPoint mountPoint;
 | 
					 | 
				
			||||||
	bool found = NodeFindMountPoint(path, pathBytes, &mountPoint, true);
 | 
					 | 
				
			||||||
	EsError error = ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (found) {
 | 
					 | 
				
			||||||
		node->handle = mountPoint.base;
 | 
					 | 
				
			||||||
		path += mountPoint.prefixBytes;
 | 
					 | 
				
			||||||
		pathBytes -= mountPoint.prefixBytes;
 | 
					 | 
				
			||||||
		error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) path, pathBytes, flags, (uintptr_t) node);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsMutexRelease(&api.mountPointsMutex);
 | 
					 | 
				
			||||||
	return error;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsSystemConfigurationItem *SystemConfigurationGetItem(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, bool createIfNeeded) {
 | 
					EsSystemConfigurationItem *SystemConfigurationGetItem(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, bool createIfNeeded) {
 | 
				
			||||||
	if (keyBytes == -1) keyBytes = EsCStringLength(key);
 | 
						if (keyBytes == -1) keyBytes = EsCStringLength(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -653,41 +536,6 @@ int EsMessageSend(EsElement *element, EsMessage *message) {
 | 
				
			||||||
	return response;
 | 
						return response;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void _EsPathAnnouncePathMoved(const char *oldPath, ptrdiff_t oldPathBytes, const char *newPath, ptrdiff_t newPathBytes) {
 | 
					 | 
				
			||||||
	if (oldPathBytes == -1) oldPathBytes = EsCStringLength(oldPath);
 | 
					 | 
				
			||||||
	if (newPathBytes == -1) newPathBytes = EsCStringLength(newPath);
 | 
					 | 
				
			||||||
	size_t bufferBytes = 1 + sizeof(uintptr_t) * 2 + oldPathBytes + newPathBytes;
 | 
					 | 
				
			||||||
	char *buffer = (char *) EsHeapAllocate(bufferBytes, false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (buffer) {
 | 
					 | 
				
			||||||
		buffer[0] = DESKTOP_MSG_ANNOUNCE_PATH_MOVED;
 | 
					 | 
				
			||||||
		EsMemoryCopy(buffer + 1, &oldPathBytes, sizeof(uintptr_t));
 | 
					 | 
				
			||||||
		EsMemoryCopy(buffer + 1 + sizeof(uintptr_t), &newPathBytes, sizeof(uintptr_t));
 | 
					 | 
				
			||||||
		EsMemoryCopy(buffer + 1 + sizeof(uintptr_t) * 2, oldPath, oldPathBytes);
 | 
					 | 
				
			||||||
		EsMemoryCopy(buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes, newPath, newPathBytes);
 | 
					 | 
				
			||||||
		MessageDesktop(buffer, bufferBytes);
 | 
					 | 
				
			||||||
		EsHeapFree(buffer);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EsOpenDocumentQueryInformation(const char *path, ptrdiff_t pathBytes, EsOpenDocumentInformation *information) {
 | 
					 | 
				
			||||||
	if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
					 | 
				
			||||||
	char *buffer = (char *) EsHeapAllocate(pathBytes + 1, false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (buffer) {
 | 
					 | 
				
			||||||
		buffer[0] = DESKTOP_MSG_QUERY_OPEN_DOCUMENT;
 | 
					 | 
				
			||||||
		EsMemoryCopy(buffer + 1, path, pathBytes);
 | 
					 | 
				
			||||||
		EsBuffer response = { .out = (uint8_t *) information, .bytes = sizeof(EsOpenDocumentInformation) };
 | 
					 | 
				
			||||||
		MessageDesktop(buffer, pathBytes + 1, ES_INVALID_HANDLE, &response);
 | 
					 | 
				
			||||||
		EsHeapFree(buffer);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void _EsOpenDocumentEnumerate(EsBuffer *outputBuffer) {
 | 
					 | 
				
			||||||
	uint8_t m = DESKTOP_MSG_LIST_OPEN_DOCUMENTS;
 | 
					 | 
				
			||||||
	MessageDesktop(&m, 1, ES_INVALID_HANDLE, outputBuffer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EsApplicationRunTemporary(const char *path, ptrdiff_t pathBytes) {
 | 
					void EsApplicationRunTemporary(const char *path, ptrdiff_t pathBytes) {
 | 
				
			||||||
	if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
						if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
				
			||||||
	char *buffer = (char *) EsHeapAllocate(pathBytes + 1, false);
 | 
						char *buffer = (char *) EsHeapAllocate(pathBytes + 1, false);
 | 
				
			||||||
| 
						 | 
					@ -798,62 +646,6 @@ void InstanceClose(EsInstance *instance) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileStoreCloseHandle(EsFileStore *fileStore) {
 | 
					 | 
				
			||||||
	EsMessageMutexCheck(); // TODO Remove this limitation?
 | 
					 | 
				
			||||||
	EsAssert(fileStore->handles < 0x80000000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (--fileStore->handles) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (fileStore->type == FILE_STORE_HANDLE) {
 | 
					 | 
				
			||||||
		if (fileStore->handle) {
 | 
					 | 
				
			||||||
			EsHandleClose(fileStore->handle);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (fileStore->type == FILE_STORE_PATH || fileStore->type == FILE_STORE_EMBEDDED_FILE) {
 | 
					 | 
				
			||||||
		// The path is stored after the file store allocation.
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsHeapFree(fileStore);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsFileStore *FileStoreCreateFromPath(const char *path, size_t pathBytes) {
 | 
					 | 
				
			||||||
	EsFileStore *fileStore = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore) + pathBytes, false);
 | 
					 | 
				
			||||||
	if (!fileStore) return nullptr;
 | 
					 | 
				
			||||||
	EsMemoryZero(fileStore, sizeof(EsFileStore));
 | 
					 | 
				
			||||||
	fileStore->type = FILE_STORE_PATH;
 | 
					 | 
				
			||||||
	fileStore->handles = 1;
 | 
					 | 
				
			||||||
	fileStore->error = ES_SUCCESS;
 | 
					 | 
				
			||||||
	fileStore->path = (char *) (fileStore + 1);
 | 
					 | 
				
			||||||
	fileStore->pathBytes = pathBytes;
 | 
					 | 
				
			||||||
	EsMemoryCopy(fileStore->path, path, pathBytes);
 | 
					 | 
				
			||||||
	return fileStore;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsFileStore *FileStoreCreateFromHandle(EsHandle handle) {
 | 
					 | 
				
			||||||
	EsFileStore *fileStore = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore), true);
 | 
					 | 
				
			||||||
	if (!fileStore) return nullptr;
 | 
					 | 
				
			||||||
	fileStore->type = FILE_STORE_HANDLE;
 | 
					 | 
				
			||||||
	fileStore->handles = 1;
 | 
					 | 
				
			||||||
	fileStore->error = ES_SUCCESS;
 | 
					 | 
				
			||||||
	fileStore->handle = handle;
 | 
					 | 
				
			||||||
	return fileStore;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsFileStore *FileStoreCreateFromEmbeddedFile(const EsBundle *bundle, const char *name, size_t nameBytes) {
 | 
					 | 
				
			||||||
	EsFileStore *fileStore = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore) + nameBytes, false);
 | 
					 | 
				
			||||||
	if (!fileStore) return nullptr;
 | 
					 | 
				
			||||||
	EsMemoryZero(fileStore, sizeof(EsFileStore));
 | 
					 | 
				
			||||||
	fileStore->type = FILE_STORE_EMBEDDED_FILE;
 | 
					 | 
				
			||||||
	fileStore->handles = 1;
 | 
					 | 
				
			||||||
	fileStore->error = ES_SUCCESS;
 | 
					 | 
				
			||||||
	fileStore->path = (char *) (fileStore + 1);
 | 
					 | 
				
			||||||
	fileStore->pathBytes = nameBytes;
 | 
					 | 
				
			||||||
	fileStore->bundle = bundle;
 | 
					 | 
				
			||||||
	EsMemoryCopy(fileStore->path, name, nameBytes);
 | 
					 | 
				
			||||||
	return fileStore;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void InstanceCreateFileStore(APIInstance *instance, EsHandle handle) {
 | 
					void InstanceCreateFileStore(APIInstance *instance, EsHandle handle) {
 | 
				
			||||||
	if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
 | 
						if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
 | 
				
			||||||
	instance->fileStore = FileStoreCreateFromHandle(handle);
 | 
						instance->fileStore = FileStoreCreateFromHandle(handle);
 | 
				
			||||||
| 
						 | 
					@ -1125,7 +917,7 @@ EsMessage *EsMessageReceive() {
 | 
				
			||||||
				FreeUnusedStyles(true /* include permanent styles */);
 | 
									FreeUnusedStyles(true /* include permanent styles */);
 | 
				
			||||||
				theming.loadedStyles.Free();
 | 
									theming.loadedStyles.Free();
 | 
				
			||||||
				SystemConfigurationUnload();
 | 
									SystemConfigurationUnload();
 | 
				
			||||||
				api.mountPoints2.Free();
 | 
									api.mountPoints.Free();
 | 
				
			||||||
				api.postBox.Free();
 | 
									api.postBox.Free();
 | 
				
			||||||
				api.timers.Free();
 | 
									api.timers.Free();
 | 
				
			||||||
				gui.animatingElements.Free();
 | 
									gui.animatingElements.Free();
 | 
				
			||||||
| 
						 | 
					@ -1925,46 +1717,6 @@ void EsInstanceSetActiveUndoManager(EsInstance *_instance, EsUndoManager *manage
 | 
				
			||||||
	EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_REDO), !manager->redoStack.Length());
 | 
						EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_REDO), !manager->redoStack.Length());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const void *EsBundleFind(const EsBundle *bundle, const char *_name, ptrdiff_t nameBytes, size_t *byteCount) {
 | 
					 | 
				
			||||||
	if (!bundle) {
 | 
					 | 
				
			||||||
		bundle = &bundleDefault;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (nameBytes == -1) {
 | 
					 | 
				
			||||||
		nameBytes = EsCStringLength(_name);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (bundle->bytes != -1) {
 | 
					 | 
				
			||||||
		if ((size_t) bundle->bytes < sizeof(BundleHeader) 
 | 
					 | 
				
			||||||
				|| (size_t) (bundle->bytes - sizeof(BundleHeader)) / sizeof(BundleFile) < bundle->base->fileCount
 | 
					 | 
				
			||||||
				|| bundle->base->signature != BUNDLE_SIGNATURE || bundle->base->version != 1) {
 | 
					 | 
				
			||||||
			return nullptr;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const BundleHeader *header = bundle->base;
 | 
					 | 
				
			||||||
	const BundleFile *files = (const BundleFile *) (header + 1);
 | 
					 | 
				
			||||||
	uint64_t name = CalculateCRC64(_name, nameBytes, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (uintptr_t i = 0; i < header->fileCount; i++) {
 | 
					 | 
				
			||||||
		if (files[i].nameCRC64 == name) {
 | 
					 | 
				
			||||||
			if (byteCount) {
 | 
					 | 
				
			||||||
				*byteCount = files[i].bytes;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (bundle->bytes != -1) {
 | 
					 | 
				
			||||||
				if (files[i].offset >= (size_t) bundle->bytes || files[i].bytes > (size_t) (bundle->bytes - files[i].offset)) {
 | 
					 | 
				
			||||||
					return nullptr;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return (const uint8_t *) header + files[i].offset;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nullptr;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct EsUserTask {
 | 
					struct EsUserTask {
 | 
				
			||||||
	EsUserTaskCallback callback;
 | 
						EsUserTaskCallback callback;
 | 
				
			||||||
	EsGeneric data;
 | 
						EsGeneric data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,516 @@
 | 
				
			||||||
 | 
					EsError EsPathDelete(const char *path, ptrdiff_t pathBytes) {
 | 
				
			||||||
 | 
						_EsNodeInformation node;
 | 
				
			||||||
 | 
						if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
				
			||||||
 | 
						EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_FILE_WRITE, &node);
 | 
				
			||||||
 | 
						if (ES_CHECK_ERROR(error)) return error;
 | 
				
			||||||
 | 
						error = EsSyscall(ES_SYSCALL_NODE_DELETE, node.handle, 0, 0, 0);
 | 
				
			||||||
 | 
						EsHandleClose(node.handle);
 | 
				
			||||||
 | 
						return error;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsError EsFileDelete(EsHandle handle) {
 | 
				
			||||||
 | 
						return EsSyscall(ES_SYSCALL_NODE_DELETE, handle, 0, 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *EsFileMap(const char *path, ptrdiff_t pathBytes, size_t *fileSize, uint32_t flags) {
 | 
				
			||||||
 | 
						EsFileInformation information = EsFileOpen(path, pathBytes, 
 | 
				
			||||||
 | 
								ES_NODE_FAIL_IF_NOT_FOUND | ((flags & ES_MEMORY_MAP_OBJECT_READ_WRITE) ? ES_FILE_WRITE : ES_FILE_READ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ES_CHECK_ERROR(information.error)) {
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *base = EsMemoryMapObject(information.handle, 0, information.size, flags); 
 | 
				
			||||||
 | 
						EsHandleClose(information.handle);
 | 
				
			||||||
 | 
						if (fileSize) *fileSize = information.size;
 | 
				
			||||||
 | 
						return base;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsError EsPathMove(const char *oldPath, ptrdiff_t oldPathBytes, const char *newPath, ptrdiff_t newPathBytes, uint32_t flags) {
 | 
				
			||||||
 | 
						if (oldPathBytes == -1) oldPathBytes = EsCStringLength(oldPath);
 | 
				
			||||||
 | 
						if (newPathBytes == -1) newPathBytes = EsCStringLength(newPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (newPathBytes && newPath[newPathBytes - 1] == '/') {
 | 
				
			||||||
 | 
							newPathBytes--;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_EsNodeInformation node = {};
 | 
				
			||||||
 | 
						_EsNodeInformation directory = {};
 | 
				
			||||||
 | 
						EsError error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = NodeOpen(oldPath, oldPathBytes, ES_NODE_FAIL_IF_NOT_FOUND, &node);
 | 
				
			||||||
 | 
						if (error != ES_SUCCESS) return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uintptr_t s = 0;
 | 
				
			||||||
 | 
						for (intptr_t i = 0; i < newPathBytes; i++) if (newPath[i] == '/') s = i + 1;
 | 
				
			||||||
 | 
						error = NodeOpen(newPath, s, ES_NODE_DIRECTORY | ES_NODE_FAIL_IF_NOT_FOUND, &directory);
 | 
				
			||||||
 | 
						if (error != ES_SUCCESS) { EsHandleClose(node.handle); return error; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = EsSyscall(ES_SYSCALL_NODE_MOVE, node.handle, directory.handle, (uintptr_t) newPath + s, newPathBytes - s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (error == ES_ERROR_VOLUME_MISMATCH && (flags & ES_PATH_MOVE_ALLOW_COPY_AND_DELETE) && (node.type == ES_NODE_FILE)) {
 | 
				
			||||||
 | 
							// The paths are on different file systems, so we cannot directly move the file.
 | 
				
			||||||
 | 
							// Instead we need to copy the file to the new path, and then delete the old file.
 | 
				
			||||||
 | 
							// TODO Does it matter that this isn't atomic?
 | 
				
			||||||
 | 
							error = EsFileCopy(oldPath, oldPathBytes, newPath, newPathBytes);
 | 
				
			||||||
 | 
							if (error == ES_SUCCESS) error = EsPathDelete(oldPath, oldPathBytes);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsHandleClose(node.handle);
 | 
				
			||||||
 | 
						EsHandleClose(directory.handle);
 | 
				
			||||||
 | 
						return error;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EsPathExists(const char *path, ptrdiff_t pathBytes, EsNodeType *type) {
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
						EsHandleClose(node.handle);
 | 
				
			||||||
 | 
						if (type) *type = node.type;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool 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;
 | 
				
			||||||
 | 
						EsHandleClose(node.handle);
 | 
				
			||||||
 | 
						information->type = node.type;
 | 
				
			||||||
 | 
						information->fileSize = node.fileSize;
 | 
				
			||||||
 | 
						information->directoryChildren = node.directoryChildren;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsError EsPathCreate(const char *path, ptrdiff_t pathBytes, EsNodeType type, bool createLeadingDirectories) {
 | 
				
			||||||
 | 
						if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
				
			||||||
 | 
						_EsNodeInformation node = {};
 | 
				
			||||||
 | 
						EsError error = NodeOpen(path, pathBytes, 
 | 
				
			||||||
 | 
								ES_NODE_FAIL_IF_FOUND | type | (createLeadingDirectories ? ES_NODE_CREATE_DIRECTORIES : 0), 
 | 
				
			||||||
 | 
								&node);
 | 
				
			||||||
 | 
						if (error != ES_SUCCESS) return error;
 | 
				
			||||||
 | 
						EsHandleClose(node.handle);
 | 
				
			||||||
 | 
						return ES_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsError EsFileControl(EsHandle file, uint32_t flags) {
 | 
				
			||||||
 | 
						return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, flags, 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ptrdiff_t EsDirectoryEnumerateChildrenFromHandle(EsHandle directory, EsDirectoryChild *buffer, size_t size) {
 | 
				
			||||||
 | 
						if (!size) return 0;
 | 
				
			||||||
 | 
						return EsSyscall(ES_SYSCALL_DIRECTORY_ENUMERATE, directory, (uintptr_t) buffer, size, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ptrdiff_t EsDirectoryEnumerateChildren(const char *path, ptrdiff_t pathBytes, EsDirectoryChild **buffer) {
 | 
				
			||||||
 | 
						*buffer = nullptr;
 | 
				
			||||||
 | 
						if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_EsNodeInformation node;
 | 
				
			||||||
 | 
						EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_NODE_DIRECTORY, &node);
 | 
				
			||||||
 | 
						if (error != ES_SUCCESS) return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (node.directoryChildren == ES_DIRECTORY_CHILDREN_UNKNOWN) {
 | 
				
			||||||
 | 
							node.directoryChildren = 4194304 / sizeof(EsDirectoryChild); // TODO Grow the buffer until all entries fit.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (node.directoryChildren == 0) {
 | 
				
			||||||
 | 
							// Empty directory.
 | 
				
			||||||
 | 
							*buffer = nullptr;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*buffer = (EsDirectoryChild *) EsHeapAllocate(sizeof(EsDirectoryChild) * node.directoryChildren, true);
 | 
				
			||||||
 | 
						ptrdiff_t result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*buffer) {
 | 
				
			||||||
 | 
							result = EsDirectoryEnumerateChildrenFromHandle(node.handle, *buffer, node.directoryChildren);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ES_CHECK_ERROR(result)) { 
 | 
				
			||||||
 | 
								EsHeapFree(*buffer); 
 | 
				
			||||||
 | 
								*buffer = nullptr; 
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							result = ES_ERROR_INSUFFICIENT_RESOURCES;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsHandleClose(node.handle);
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsFileInformation EsFileOpen(const char *path, ptrdiff_t pathLength, uint32_t flags) {
 | 
				
			||||||
 | 
						if (pathLength == -1) {
 | 
				
			||||||
 | 
							pathLength = EsCStringLength(path);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_EsNodeInformation node;
 | 
				
			||||||
 | 
						EsError result = NodeOpen(path, pathLength, flags, &node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (result == ES_SUCCESS && node.type == ES_NODE_DIRECTORY && (~flags & ES_NODE_DIRECTORY /* for internal use only */)) {
 | 
				
			||||||
 | 
							result = ES_ERROR_INCORRECT_NODE_TYPE;
 | 
				
			||||||
 | 
							EsHandleClose(node.handle);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsFileInformation information = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (result == ES_SUCCESS) {
 | 
				
			||||||
 | 
							information.handle = node.handle;
 | 
				
			||||||
 | 
							information.size = node.fileSize;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						information.error = result;
 | 
				
			||||||
 | 
						return information;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t EsFileReadSync(EsHandle handle, EsFileOffset offset, size_t size, void *buffer) {
 | 
				
			||||||
 | 
						intptr_t result = EsSyscall(ES_SYSCALL_FILE_READ_SYNC, handle, offset, size, (uintptr_t) buffer);
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t EsFileWriteSync(EsHandle handle, EsFileOffset offset, size_t size, const void *buffer) {
 | 
				
			||||||
 | 
						intptr_t result = EsSyscall(ES_SYSCALL_FILE_WRITE_SYNC, handle, offset, size, (uintptr_t) buffer);
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsFileOffset EsFileGetSize(EsHandle handle) {
 | 
				
			||||||
 | 
						return EsSyscall(ES_SYSCALL_FILE_GET_SIZE, handle, 0, 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsError EsFileResize(EsHandle handle, EsFileOffset newSize) {
 | 
				
			||||||
 | 
						return EsSyscall(ES_SYSCALL_FILE_RESIZE, handle, newSize, 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *EsFileStoreReadAll(EsFileStore *file, size_t *fileSize) {
 | 
				
			||||||
 | 
						if (file->error != ES_SUCCESS) return nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (file->type == FILE_STORE_HANDLE) {
 | 
				
			||||||
 | 
							return EsFileReadAllFromHandle(file->handle, fileSize, &file->error);
 | 
				
			||||||
 | 
						} else if (file->type == FILE_STORE_PATH) {
 | 
				
			||||||
 | 
							return EsFileReadAll(file->path, file->pathBytes, fileSize, &file->error);
 | 
				
			||||||
 | 
						} else if (file->type == FILE_STORE_EMBEDDED_FILE) {
 | 
				
			||||||
 | 
							size_t _fileSize;
 | 
				
			||||||
 | 
							const void *data = EsBundleFind(file->bundle, file->path, file->pathBytes, &_fileSize);
 | 
				
			||||||
 | 
							void *copy = EsHeapAllocate(_fileSize, false);
 | 
				
			||||||
 | 
							if (!copy) return nullptr;
 | 
				
			||||||
 | 
							if (fileSize) *fileSize = _fileSize;
 | 
				
			||||||
 | 
							EsMemoryCopy(copy, data, _fileSize);
 | 
				
			||||||
 | 
							return copy;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							EsAssert(false);
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EsFileStoreWriteAll(EsFileStore *file, const void *data, size_t dataBytes) {
 | 
				
			||||||
 | 
						if (file->error == ES_SUCCESS) {
 | 
				
			||||||
 | 
							if (file->type == FILE_STORE_HANDLE) {
 | 
				
			||||||
 | 
								file->error = EsFileWriteAllFromHandle(file->handle, data, dataBytes);
 | 
				
			||||||
 | 
							} else if (file->type == FILE_STORE_PATH) {
 | 
				
			||||||
 | 
								file->error = EsFileWriteAll(file->path, file->pathBytes, data, dataBytes);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								EsAssert(false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return file->error == ES_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EsFileStoreAppend(EsFileStore *file, const void *data, size_t dataBytes) {
 | 
				
			||||||
 | 
						if (file->error == ES_SUCCESS) {
 | 
				
			||||||
 | 
							if (file->type == FILE_STORE_HANDLE) {
 | 
				
			||||||
 | 
								EsError error = EsFileWriteSync(file->handle, EsFileGetSize(file->handle), dataBytes, data);
 | 
				
			||||||
 | 
								if (ES_CHECK_ERROR(error)) file->error = error;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								EsAssert(false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return file->error == ES_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsFileOffsetDifference EsFileStoreGetSize(EsFileStore *file) {
 | 
				
			||||||
 | 
						if (file->type == FILE_STORE_HANDLE) {
 | 
				
			||||||
 | 
							return EsFileGetSize(file->handle);
 | 
				
			||||||
 | 
						} else if (file->type == FILE_STORE_PATH) {
 | 
				
			||||||
 | 
							EsDirectoryChild information;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (EsPathQueryInformation(file->path, file->pathBytes, &information)) {
 | 
				
			||||||
 | 
								return file->pathBytes;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (file->type == FILE_STORE_EMBEDDED_FILE) {
 | 
				
			||||||
 | 
							size_t size;
 | 
				
			||||||
 | 
							EsBundleFind(file->bundle, file->path, file->pathBytes, &size);
 | 
				
			||||||
 | 
							return size;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							EsAssert(false);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flags) {
 | 
				
			||||||
 | 
						if (file->type == FILE_STORE_HANDLE) {
 | 
				
			||||||
 | 
							EsFileOffsetDifference size = EsFileStoreGetSize(file);
 | 
				
			||||||
 | 
							if (size == -1) return nullptr;
 | 
				
			||||||
 | 
							*fileSize = size;
 | 
				
			||||||
 | 
							return EsMemoryMapObject(file->handle, 0, size, flags); 
 | 
				
			||||||
 | 
						} else if (file->type == FILE_STORE_PATH) {
 | 
				
			||||||
 | 
							return EsFileMap(file->path, file->pathBytes, fileSize, flags);
 | 
				
			||||||
 | 
						} else if (file->type == FILE_STORE_EMBEDDED_FILE) {
 | 
				
			||||||
 | 
							return (void *) EsBundleFind(file->bundle, file->path, file->pathBytes, fileSize);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							EsAssert(false);
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsError MountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base, bool addedByApplication) {
 | 
				
			||||||
 | 
						EsMutexAcquire(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						bool duplicate = NodeFindMountPoint(prefix, prefixBytes, nullptr, true);
 | 
				
			||||||
 | 
						EsError error = ES_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (duplicate) {
 | 
				
			||||||
 | 
							error = ES_ERROR_MOUNT_POINT_ALREADY_EXISTS;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							EsMountPoint mountPoint = {};
 | 
				
			||||||
 | 
							EsAssert(prefixBytes < sizeof(mountPoint.prefix));
 | 
				
			||||||
 | 
							EsMemoryCopy(mountPoint.prefix, prefix, prefixBytes);
 | 
				
			||||||
 | 
							mountPoint.base = EsSyscall(ES_SYSCALL_HANDLE_SHARE, base, ES_CURRENT_PROCESS, 0, 0);
 | 
				
			||||||
 | 
							mountPoint.prefixBytes = prefixBytes;
 | 
				
			||||||
 | 
							mountPoint.addedByApplication = addedByApplication;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ES_CHECK_ERROR(mountPoint.base)) {
 | 
				
			||||||
 | 
								error = ES_ERROR_INSUFFICIENT_RESOURCES;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (!api.mountPoints.Add(mountPoint)) {
 | 
				
			||||||
 | 
									EsHandleClose(mountPoint.base);
 | 
				
			||||||
 | 
									error = ES_ERROR_INSUFFICIENT_RESOURCES;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsMutexRelease(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						return error;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsError EsMountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base) {
 | 
				
			||||||
 | 
						return MountPointAdd(prefix, prefixBytes, base, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool NodeFindMountPoint(const char *prefix, size_t prefixBytes, EsMountPoint *result, bool mutexTaken) {
 | 
				
			||||||
 | 
						if (!mutexTaken) EsMutexAcquire(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
 | 
				
			||||||
 | 
							EsMountPoint *mountPoint = &api.mountPoints[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (prefixBytes >= mountPoint->prefixBytes && 0 == EsMemoryCompare(prefix, mountPoint->prefix, mountPoint->prefixBytes)) {
 | 
				
			||||||
 | 
								// Only permanent mount points can be used retrieved with NodeFindMountPoint when mutexTaken = false,
 | 
				
			||||||
 | 
								// because mount points added by the application can be removed as soon as we release the mutex,
 | 
				
			||||||
 | 
								// and the base handle would be closed.
 | 
				
			||||||
 | 
								EsAssert(mutexTaken || !mountPoint->addedByApplication);
 | 
				
			||||||
 | 
								if (result) EsMemoryCopy(result, mountPoint, sizeof(EsMountPoint));
 | 
				
			||||||
 | 
								found = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mutexTaken) EsMutexRelease(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EsMountPointRemove(const char *prefix, size_t prefixBytes) {
 | 
				
			||||||
 | 
						EsMutexAcquire(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
 | 
				
			||||||
 | 
							EsMountPoint *mountPoint = &api.mountPoints[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (prefixBytes >= mountPoint->prefixBytes && 0 == EsMemoryCompare(prefix, mountPoint->prefix, mountPoint->prefixBytes)) {
 | 
				
			||||||
 | 
								EsAssert(mountPoint->addedByApplication);
 | 
				
			||||||
 | 
								EsHandleClose(mountPoint->base);
 | 
				
			||||||
 | 
								api.mountPoints.Delete(i);
 | 
				
			||||||
 | 
								found = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsMutexRelease(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, EsVolumeInformation *information) {
 | 
				
			||||||
 | 
						EsMutexAcquire(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						EsMountPoint mountPoint;
 | 
				
			||||||
 | 
						bool found = NodeFindMountPoint(prefix, prefixBytes, &mountPoint, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (found) {
 | 
				
			||||||
 | 
							_EsNodeInformation node;
 | 
				
			||||||
 | 
							node.handle = mountPoint.base;
 | 
				
			||||||
 | 
							EsError error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) "/", 1, ES_NODE_DIRECTORY, (uintptr_t) &node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (error == ES_SUCCESS) {
 | 
				
			||||||
 | 
								EsSyscall(ES_SYSCALL_VOLUME_GET_INFORMATION, node.handle, (uintptr_t) information, 0, 0);
 | 
				
			||||||
 | 
								EsHandleClose(node.handle);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								EsMemoryZero(information, sizeof(EsVolumeInformation));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsMutexRelease(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node) {
 | 
				
			||||||
 | 
						// TODO I really don't like having to acquire a mutex to open a node.
 | 
				
			||||||
 | 
						// 	This could be replaced with a writer lock!
 | 
				
			||||||
 | 
						// 	(...but we don't have writer locks in userland yet.)
 | 
				
			||||||
 | 
						EsMutexAcquire(&api.mountPointsMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsMountPoint mountPoint;
 | 
				
			||||||
 | 
						bool found = NodeFindMountPoint(path, pathBytes, &mountPoint, true);
 | 
				
			||||||
 | 
						EsError error = ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (found) {
 | 
				
			||||||
 | 
							node->handle = mountPoint.base;
 | 
				
			||||||
 | 
							path += mountPoint.prefixBytes;
 | 
				
			||||||
 | 
							pathBytes -= mountPoint.prefixBytes;
 | 
				
			||||||
 | 
							error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) path, pathBytes, flags, (uintptr_t) node);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsMutexRelease(&api.mountPointsMutex);
 | 
				
			||||||
 | 
						return error;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _EsPathAnnouncePathMoved(const char *oldPath, ptrdiff_t oldPathBytes, const char *newPath, ptrdiff_t newPathBytes) {
 | 
				
			||||||
 | 
						if (oldPathBytes == -1) oldPathBytes = EsCStringLength(oldPath);
 | 
				
			||||||
 | 
						if (newPathBytes == -1) newPathBytes = EsCStringLength(newPath);
 | 
				
			||||||
 | 
						size_t bufferBytes = 1 + sizeof(uintptr_t) * 2 + oldPathBytes + newPathBytes;
 | 
				
			||||||
 | 
						char *buffer = (char *) EsHeapAllocate(bufferBytes, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buffer) {
 | 
				
			||||||
 | 
							buffer[0] = DESKTOP_MSG_ANNOUNCE_PATH_MOVED;
 | 
				
			||||||
 | 
							EsMemoryCopy(buffer + 1, &oldPathBytes, sizeof(uintptr_t));
 | 
				
			||||||
 | 
							EsMemoryCopy(buffer + 1 + sizeof(uintptr_t), &newPathBytes, sizeof(uintptr_t));
 | 
				
			||||||
 | 
							EsMemoryCopy(buffer + 1 + sizeof(uintptr_t) * 2, oldPath, oldPathBytes);
 | 
				
			||||||
 | 
							EsMemoryCopy(buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes, newPath, newPathBytes);
 | 
				
			||||||
 | 
							MessageDesktop(buffer, bufferBytes);
 | 
				
			||||||
 | 
							EsHeapFree(buffer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EsOpenDocumentQueryInformation(const char *path, ptrdiff_t pathBytes, EsOpenDocumentInformation *information) {
 | 
				
			||||||
 | 
						if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
				
			||||||
 | 
						char *buffer = (char *) EsHeapAllocate(pathBytes + 1, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buffer) {
 | 
				
			||||||
 | 
							buffer[0] = DESKTOP_MSG_QUERY_OPEN_DOCUMENT;
 | 
				
			||||||
 | 
							EsMemoryCopy(buffer + 1, path, pathBytes);
 | 
				
			||||||
 | 
							EsBuffer response = { .out = (uint8_t *) information, .bytes = sizeof(EsOpenDocumentInformation) };
 | 
				
			||||||
 | 
							MessageDesktop(buffer, pathBytes + 1, ES_INVALID_HANDLE, &response);
 | 
				
			||||||
 | 
							EsHeapFree(buffer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _EsOpenDocumentEnumerate(EsBuffer *outputBuffer) {
 | 
				
			||||||
 | 
						uint8_t m = DESKTOP_MSG_LIST_OPEN_DOCUMENTS;
 | 
				
			||||||
 | 
						MessageDesktop(&m, 1, ES_INVALID_HANDLE, outputBuffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FileStoreCloseHandle(EsFileStore *fileStore) {
 | 
				
			||||||
 | 
						EsMessageMutexCheck(); // TODO Remove this limitation?
 | 
				
			||||||
 | 
						EsAssert(fileStore->handles < 0x80000000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (--fileStore->handles) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fileStore->type == FILE_STORE_HANDLE) {
 | 
				
			||||||
 | 
							if (fileStore->handle) {
 | 
				
			||||||
 | 
								EsHandleClose(fileStore->handle);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (fileStore->type == FILE_STORE_PATH || fileStore->type == FILE_STORE_EMBEDDED_FILE) {
 | 
				
			||||||
 | 
							// The path is stored after the file store allocation.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsHeapFree(fileStore);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsFileStore *FileStoreCreateFromPath(const char *path, size_t pathBytes) {
 | 
				
			||||||
 | 
						EsFileStore *fileStore = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore) + pathBytes, false);
 | 
				
			||||||
 | 
						if (!fileStore) return nullptr;
 | 
				
			||||||
 | 
						EsMemoryZero(fileStore, sizeof(EsFileStore));
 | 
				
			||||||
 | 
						fileStore->type = FILE_STORE_PATH;
 | 
				
			||||||
 | 
						fileStore->handles = 1;
 | 
				
			||||||
 | 
						fileStore->error = ES_SUCCESS;
 | 
				
			||||||
 | 
						fileStore->path = (char *) (fileStore + 1);
 | 
				
			||||||
 | 
						fileStore->pathBytes = pathBytes;
 | 
				
			||||||
 | 
						EsMemoryCopy(fileStore->path, path, pathBytes);
 | 
				
			||||||
 | 
						return fileStore;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsFileStore *FileStoreCreateFromHandle(EsHandle handle) {
 | 
				
			||||||
 | 
						EsFileStore *fileStore = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore), true);
 | 
				
			||||||
 | 
						if (!fileStore) return nullptr;
 | 
				
			||||||
 | 
						fileStore->type = FILE_STORE_HANDLE;
 | 
				
			||||||
 | 
						fileStore->handles = 1;
 | 
				
			||||||
 | 
						fileStore->error = ES_SUCCESS;
 | 
				
			||||||
 | 
						fileStore->handle = handle;
 | 
				
			||||||
 | 
						return fileStore;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EsFileStore *FileStoreCreateFromEmbeddedFile(const EsBundle *bundle, const char *name, size_t nameBytes) {
 | 
				
			||||||
 | 
						EsFileStore *fileStore = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore) + nameBytes, false);
 | 
				
			||||||
 | 
						if (!fileStore) return nullptr;
 | 
				
			||||||
 | 
						EsMemoryZero(fileStore, sizeof(EsFileStore));
 | 
				
			||||||
 | 
						fileStore->type = FILE_STORE_EMBEDDED_FILE;
 | 
				
			||||||
 | 
						fileStore->handles = 1;
 | 
				
			||||||
 | 
						fileStore->error = ES_SUCCESS;
 | 
				
			||||||
 | 
						fileStore->path = (char *) (fileStore + 1);
 | 
				
			||||||
 | 
						fileStore->pathBytes = nameBytes;
 | 
				
			||||||
 | 
						fileStore->bundle = bundle;
 | 
				
			||||||
 | 
						EsMemoryCopy(fileStore->path, name, nameBytes);
 | 
				
			||||||
 | 
						return fileStore;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const void *EsBundleFind(const EsBundle *bundle, const char *_name, ptrdiff_t nameBytes, size_t *byteCount) {
 | 
				
			||||||
 | 
						if (!bundle) {
 | 
				
			||||||
 | 
							bundle = &bundleDefault;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nameBytes == -1) {
 | 
				
			||||||
 | 
							nameBytes = EsCStringLength(_name);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bundle->bytes != -1) {
 | 
				
			||||||
 | 
							if ((size_t) bundle->bytes < sizeof(BundleHeader) 
 | 
				
			||||||
 | 
									|| (size_t) (bundle->bytes - sizeof(BundleHeader)) / sizeof(BundleFile) < bundle->base->fileCount
 | 
				
			||||||
 | 
									|| bundle->base->signature != BUNDLE_SIGNATURE || bundle->base->version != 1) {
 | 
				
			||||||
 | 
								return nullptr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const BundleHeader *header = bundle->base;
 | 
				
			||||||
 | 
						const BundleFile *files = (const BundleFile *) (header + 1);
 | 
				
			||||||
 | 
						uint64_t name = CalculateCRC64(_name, nameBytes, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (uintptr_t i = 0; i < header->fileCount; i++) {
 | 
				
			||||||
 | 
							if (files[i].nameCRC64 == name) {
 | 
				
			||||||
 | 
								if (byteCount) {
 | 
				
			||||||
 | 
									*byteCount = files[i].bytes;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (bundle->bytes != -1) {
 | 
				
			||||||
 | 
									if (files[i].offset >= (size_t) bundle->bytes || files[i].bytes > (size_t) (bundle->bytes - files[i].offset)) {
 | 
				
			||||||
 | 
										return nullptr;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (const uint8_t *) header + files[i].offset;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ extern "C" void *ProcessorTLSRead(uintptr_t offset);
 | 
				
			||||||
extern "C" void ProcessorTLSWrite(uintptr_t offset, void *value);
 | 
					extern "C" void ProcessorTLSWrite(uintptr_t offset, void *value);
 | 
				
			||||||
extern ptrdiff_t tlsStorageOffset;
 | 
					extern ptrdiff_t tlsStorageOffset;
 | 
				
			||||||
bool NodeFindMountPoint(const char *prefix, size_t prefixBytes, EsMountPoint *result, bool mutexTaken);
 | 
					bool NodeFindMountPoint(const char *prefix, size_t prefixBytes, EsMountPoint *result, bool mutexTaken);
 | 
				
			||||||
 | 
					EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node);
 | 
				
			||||||
EsProcessStartupInformation *ProcessGetStartupInformation();
 | 
					EsProcessStartupInformation *ProcessGetStartupInformation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define _POSIX_SOURCE
 | 
					#define _POSIX_SOURCE
 | 
				
			||||||
| 
						 | 
					@ -51,6 +52,7 @@ char *workingDirectory;
 | 
				
			||||||
Array<ChildProcess> childProcesses;
 | 
					Array<ChildProcess> childProcesses;
 | 
				
			||||||
Array<void *> _argv;
 | 
					Array<void *> _argv;
 | 
				
			||||||
EsHandle posixMountPointBase;
 | 
					EsHandle posixMountPointBase;
 | 
				
			||||||
 | 
					EsMutex posixMountPointBaseMutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef ES_ARCH_X86_64
 | 
					#ifdef ES_ARCH_X86_64
 | 
				
			||||||
Elf64_Phdr *tlsHeader;
 | 
					Elf64_Phdr *tlsHeader;
 | 
				
			||||||
| 
						 | 
					@ -163,15 +165,19 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((uintptr_t) n < sizeof(syscallNames) / sizeof(syscallNames[0])) {
 | 
						if ((uintptr_t) n < sizeof(syscallNames) / sizeof(syscallNames[0])) {
 | 
				
			||||||
		// EsPrint(":: %z %x %x %x\n", syscallNames[n], a1, a2, a3);
 | 
							EsPrint(":: %z %x %x %x\n", syscallNames[n], a1, a2, a3);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (posixMountPointBase) {
 | 
						if (!posixMountPointBase) {
 | 
				
			||||||
		// It doesn't matter if multiple threads try to do this at the same time,
 | 
							EsMutexAcquire(&posixMountPointBaseMutex);
 | 
				
			||||||
		// they'll all get the same result.
 | 
					
 | 
				
			||||||
		EsMountPoint mountPoint;
 | 
							if (!posixMountPointBase) {
 | 
				
			||||||
		EsAssert(NodeFindMountPoint(EsLiteral("|POSIX:"), &mountPoint, false));
 | 
								_EsNodeInformation node;
 | 
				
			||||||
		posixMountPointBase = mountPoint.base;
 | 
								EsAssert(ES_SUCCESS == NodeOpen(EsLiteral("|POSIX:/"), ES_NODE_DIRECTORY | _ES_NODE_DIRECTORY_WRITE, &node));
 | 
				
			||||||
 | 
								posixMountPointBase = node.handle;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							EsMutexRelease(&posixMountPointBaseMutex);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	long returnValue = 0;
 | 
						long returnValue = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -199,11 +199,7 @@ void *EsFileReadAllFromHandle(EsHandle handle, size_t *fileSize, EsError *error)
 | 
				
			||||||
	EsFileOffset size = EsFileGetSize(handle);
 | 
						EsFileOffset size = EsFileGetSize(handle);
 | 
				
			||||||
	if (fileSize) *fileSize = size;
 | 
						if (fileSize) *fileSize = size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef KERNEL
 | 
					 | 
				
			||||||
	void *buffer = EsHeapAllocate(size + 1, false, K_PAGED);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	void *buffer = EsHeapAllocate(size + 1, false);
 | 
						void *buffer = EsHeapAllocate(size + 1, false);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!buffer) {
 | 
						if (!buffer) {
 | 
				
			||||||
		if (error) *error = ES_ERROR_INSUFFICIENT_RESOURCES;
 | 
							if (error) *error = ES_ERROR_INSUFFICIENT_RESOURCES;
 | 
				
			||||||
| 
						 | 
					@ -215,11 +211,7 @@ void *EsFileReadAllFromHandle(EsHandle handle, size_t *fileSize, EsError *error)
 | 
				
			||||||
	uintptr_t result = EsFileReadSync(handle, 0, size, buffer);
 | 
						uintptr_t result = EsFileReadSync(handle, 0, size, buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (size != result) {
 | 
						if (size != result) {
 | 
				
			||||||
#ifdef KERNEL
 | 
					 | 
				
			||||||
		EsHeapFree(buffer, size + 1, K_PAGED);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
		EsHeapFree(buffer);
 | 
							EsHeapFree(buffer);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		buffer = nullptr;
 | 
							buffer = nullptr;
 | 
				
			||||||
		if (error) *error = (EsError) result;
 | 
							if (error) *error = (EsError) result;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -314,133 +306,6 @@ void *EsMemoryMapObject(EsHandle sharedMemoryRegion, uintptr_t offset, size_t si
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EsFileInformation EsFileOpen(const char *path, ptrdiff_t pathLength, uint32_t flags) {
 | 
					 | 
				
			||||||
	if (pathLength == -1) {
 | 
					 | 
				
			||||||
		pathLength = EsCStringLength(path);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	_EsNodeInformation node;
 | 
					 | 
				
			||||||
	EsError result = NodeOpen(path, pathLength, flags, &node);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (result == ES_SUCCESS && node.type == ES_NODE_DIRECTORY && (~flags & ES_NODE_DIRECTORY /* for internal use only */)) {
 | 
					 | 
				
			||||||
		result = ES_ERROR_INCORRECT_NODE_TYPE;
 | 
					 | 
				
			||||||
		EsHandleClose(node.handle);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsFileInformation information = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (result == ES_SUCCESS) {
 | 
					 | 
				
			||||||
		information.handle = node.handle;
 | 
					 | 
				
			||||||
		information.size = node.fileSize;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	information.error = result;
 | 
					 | 
				
			||||||
	return information;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
size_t EsFileReadSync(EsHandle handle, EsFileOffset offset, size_t size, void *buffer) {
 | 
					 | 
				
			||||||
	intptr_t result = EsSyscall(ES_SYSCALL_FILE_READ_SYNC, handle, offset, size, (uintptr_t) buffer);
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
size_t EsFileWriteSync(EsHandle handle, EsFileOffset offset, size_t size, const void *buffer) {
 | 
					 | 
				
			||||||
	intptr_t result = EsSyscall(ES_SYSCALL_FILE_WRITE_SYNC, handle, offset, size, (uintptr_t) buffer);
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsFileOffset EsFileGetSize(EsHandle handle) {
 | 
					 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_FILE_GET_SIZE, handle, 0, 0, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsError EsFileResize(EsHandle handle, EsFileOffset newSize) {
 | 
					 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_FILE_RESIZE, handle, newSize, 0, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *EsFileStoreReadAll(EsFileStore *file, size_t *fileSize) {
 | 
					 | 
				
			||||||
	if (file->error != ES_SUCCESS) return nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (file->type == FILE_STORE_HANDLE) {
 | 
					 | 
				
			||||||
		return EsFileReadAllFromHandle(file->handle, fileSize, &file->error);
 | 
					 | 
				
			||||||
	} else if (file->type == FILE_STORE_PATH) {
 | 
					 | 
				
			||||||
		return EsFileReadAll(file->path, file->pathBytes, fileSize, &file->error);
 | 
					 | 
				
			||||||
	} else if (file->type == FILE_STORE_EMBEDDED_FILE) {
 | 
					 | 
				
			||||||
		size_t _fileSize;
 | 
					 | 
				
			||||||
		const void *data = EsBundleFind(file->bundle, file->path, file->pathBytes, &_fileSize);
 | 
					 | 
				
			||||||
		void *copy = EsHeapAllocate(_fileSize, false);
 | 
					 | 
				
			||||||
		if (!copy) return nullptr;
 | 
					 | 
				
			||||||
		if (fileSize) *fileSize = _fileSize;
 | 
					 | 
				
			||||||
		EsMemoryCopy(copy, data, _fileSize);
 | 
					 | 
				
			||||||
		return copy;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		EsAssert(false);
 | 
					 | 
				
			||||||
		return nullptr;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool EsFileStoreWriteAll(EsFileStore *file, const void *data, size_t dataBytes) {
 | 
					 | 
				
			||||||
	if (file->error == ES_SUCCESS) {
 | 
					 | 
				
			||||||
		if (file->type == FILE_STORE_HANDLE) {
 | 
					 | 
				
			||||||
			file->error = EsFileWriteAllFromHandle(file->handle, data, dataBytes);
 | 
					 | 
				
			||||||
		} else if (file->type == FILE_STORE_PATH) {
 | 
					 | 
				
			||||||
			file->error = EsFileWriteAll(file->path, file->pathBytes, data, dataBytes);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			EsAssert(false);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return file->error == ES_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool EsFileStoreAppend(EsFileStore *file, const void *data, size_t dataBytes) {
 | 
					 | 
				
			||||||
	if (file->error == ES_SUCCESS) {
 | 
					 | 
				
			||||||
		if (file->type == FILE_STORE_HANDLE) {
 | 
					 | 
				
			||||||
			EsError error = EsFileWriteSync(file->handle, EsFileGetSize(file->handle), dataBytes, data);
 | 
					 | 
				
			||||||
			if (ES_CHECK_ERROR(error)) file->error = error;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			EsAssert(false);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return file->error == ES_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsFileOffsetDifference EsFileStoreGetSize(EsFileStore *file) {
 | 
					 | 
				
			||||||
	if (file->type == FILE_STORE_HANDLE) {
 | 
					 | 
				
			||||||
		return EsFileGetSize(file->handle);
 | 
					 | 
				
			||||||
	} else if (file->type == FILE_STORE_PATH) {
 | 
					 | 
				
			||||||
		EsDirectoryChild information;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (EsPathQueryInformation(file->path, file->pathBytes, &information)) {
 | 
					 | 
				
			||||||
			return file->pathBytes;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (file->type == FILE_STORE_EMBEDDED_FILE) {
 | 
					 | 
				
			||||||
		size_t size;
 | 
					 | 
				
			||||||
		EsBundleFind(file->bundle, file->path, file->pathBytes, &size);
 | 
					 | 
				
			||||||
		return size;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		EsAssert(false);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flags) {
 | 
					 | 
				
			||||||
	if (file->type == FILE_STORE_HANDLE) {
 | 
					 | 
				
			||||||
		EsFileOffsetDifference size = EsFileStoreGetSize(file);
 | 
					 | 
				
			||||||
		if (size == -1) return nullptr;
 | 
					 | 
				
			||||||
		*fileSize = size;
 | 
					 | 
				
			||||||
		return EsMemoryMapObject(file->handle, 0, size, flags); 
 | 
					 | 
				
			||||||
	} else if (file->type == FILE_STORE_PATH) {
 | 
					 | 
				
			||||||
		return EsFileMap(file->path, file->pathBytes, fileSize, flags);
 | 
					 | 
				
			||||||
	} else if (file->type == FILE_STORE_EMBEDDED_FILE) {
 | 
					 | 
				
			||||||
		return (void *) EsBundleFind(file->bundle, file->path, file->pathBytes, fileSize);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		EsAssert(false);
 | 
					 | 
				
			||||||
		return nullptr;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uintptr_t EsWait(EsHandle *handles, size_t count, uintptr_t timeoutMs) {
 | 
					uintptr_t EsWait(EsHandle *handles, size_t count, uintptr_t timeoutMs) {
 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_WAIT, (uintptr_t) handles, count, timeoutMs, 0);
 | 
						return EsSyscall(ES_SYSCALL_WAIT, (uintptr_t) handles, count, timeoutMs, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -465,49 +330,6 @@ EsObjectID EsProcessGetID(EsHandle process) {
 | 
				
			||||||
	return id;
 | 
						return id;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ptrdiff_t EsDirectoryEnumerateChildrenFromHandle(EsHandle directory, EsDirectoryChild *buffer, size_t size) {
 | 
					 | 
				
			||||||
	if (!size) return 0;
 | 
					 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_DIRECTORY_ENUMERATE, directory, (uintptr_t) buffer, size, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef KERNEL
 | 
					 | 
				
			||||||
ptrdiff_t EsDirectoryEnumerateChildren(const char *path, ptrdiff_t pathBytes, EsDirectoryChild **buffer) {
 | 
					 | 
				
			||||||
	*buffer = nullptr;
 | 
					 | 
				
			||||||
	if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	_EsNodeInformation node;
 | 
					 | 
				
			||||||
	EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_NODE_DIRECTORY, &node);
 | 
					 | 
				
			||||||
	if (error != ES_SUCCESS) return error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (node.directoryChildren == ES_DIRECTORY_CHILDREN_UNKNOWN) {
 | 
					 | 
				
			||||||
		node.directoryChildren = 4194304 / sizeof(EsDirectoryChild); // TODO Grow the buffer until all entries fit.
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (node.directoryChildren == 0) {
 | 
					 | 
				
			||||||
		// Empty directory.
 | 
					 | 
				
			||||||
		*buffer = nullptr;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	*buffer = (EsDirectoryChild *) EsHeapAllocate(sizeof(EsDirectoryChild) * node.directoryChildren, true);
 | 
					 | 
				
			||||||
	ptrdiff_t result;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (*buffer) {
 | 
					 | 
				
			||||||
		result = EsDirectoryEnumerateChildrenFromHandle(node.handle, *buffer, node.directoryChildren);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ES_CHECK_ERROR(result)) { 
 | 
					 | 
				
			||||||
			EsHeapFree(*buffer); 
 | 
					 | 
				
			||||||
			*buffer = nullptr; 
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		result = ES_ERROR_INSUFFICIENT_RESOURCES;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsHandleClose(node.handle);
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EsBatch(EsBatchCall *calls, size_t count) {
 | 
					void EsBatch(EsBatchCall *calls, size_t count) {
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
	for (uintptr_t i = 0; i < count; i++) {
 | 
						for (uintptr_t i = 0; i < count; i++) {
 | 
				
			||||||
| 
						 | 
					@ -519,106 +341,6 @@ void EsBatch(EsBatchCall *calls, size_t count) {
 | 
				
			||||||
	EsSyscall(ES_SYSCALL_BATCH, (uintptr_t) calls, count, 0, 0);
 | 
						EsSyscall(ES_SYSCALL_BATCH, (uintptr_t) calls, count, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EsError EsPathDelete(const char *path, ptrdiff_t pathBytes) {
 | 
					 | 
				
			||||||
	_EsNodeInformation node;
 | 
					 | 
				
			||||||
	if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
					 | 
				
			||||||
	EsError error = NodeOpen(path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_FILE_WRITE, &node);
 | 
					 | 
				
			||||||
	if (ES_CHECK_ERROR(error)) return error;
 | 
					 | 
				
			||||||
	error = EsSyscall(ES_SYSCALL_NODE_DELETE, node.handle, 0, 0, 0);
 | 
					 | 
				
			||||||
	EsHandleClose(node.handle);
 | 
					 | 
				
			||||||
	return error;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsError EsFileDelete(EsHandle handle) {
 | 
					 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_NODE_DELETE, handle, 0, 0, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *EsFileMap(const char *path, ptrdiff_t pathBytes, size_t *fileSize, uint32_t flags) {
 | 
					 | 
				
			||||||
	EsFileInformation information = EsFileOpen(path, pathBytes, 
 | 
					 | 
				
			||||||
			ES_NODE_FAIL_IF_NOT_FOUND | ((flags & ES_MEMORY_MAP_OBJECT_READ_WRITE) ? ES_FILE_WRITE : ES_FILE_READ));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ES_CHECK_ERROR(information.error)) {
 | 
					 | 
				
			||||||
		return nullptr;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *base = EsMemoryMapObject(information.handle, 0, information.size, flags); 
 | 
					 | 
				
			||||||
	EsHandleClose(information.handle);
 | 
					 | 
				
			||||||
	if (fileSize) *fileSize = information.size;
 | 
					 | 
				
			||||||
	return base;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsError EsPathMove(const char *oldPath, ptrdiff_t oldPathBytes, const char *newPath, ptrdiff_t newPathBytes, uint32_t flags) {
 | 
					 | 
				
			||||||
	if (oldPathBytes == -1) oldPathBytes = EsCStringLength(oldPath);
 | 
					 | 
				
			||||||
	if (newPathBytes == -1) newPathBytes = EsCStringLength(newPath);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (newPathBytes && newPath[newPathBytes - 1] == '/') {
 | 
					 | 
				
			||||||
		newPathBytes--;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	_EsNodeInformation node = {};
 | 
					 | 
				
			||||||
	_EsNodeInformation directory = {};
 | 
					 | 
				
			||||||
	EsError error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	error = NodeOpen(oldPath, oldPathBytes, ES_NODE_FAIL_IF_NOT_FOUND, &node);
 | 
					 | 
				
			||||||
	if (error != ES_SUCCESS) return error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uintptr_t s = 0;
 | 
					 | 
				
			||||||
	for (intptr_t i = 0; i < newPathBytes; i++) if (newPath[i] == '/') s = i + 1;
 | 
					 | 
				
			||||||
	error = NodeOpen(newPath, s, ES_NODE_DIRECTORY | ES_NODE_FAIL_IF_NOT_FOUND, &directory);
 | 
					 | 
				
			||||||
	if (error != ES_SUCCESS) { EsHandleClose(node.handle); return error; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	error = EsSyscall(ES_SYSCALL_NODE_MOVE, node.handle, directory.handle, (uintptr_t) newPath + s, newPathBytes - s);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (error == ES_ERROR_VOLUME_MISMATCH && (flags & ES_PATH_MOVE_ALLOW_COPY_AND_DELETE) && (node.type == ES_NODE_FILE)) {
 | 
					 | 
				
			||||||
		// The paths are on different file systems, so we cannot directly move the file.
 | 
					 | 
				
			||||||
		// Instead we need to copy the file to the new path, and then delete the old file.
 | 
					 | 
				
			||||||
		// TODO Does it matter that this isn't atomic?
 | 
					 | 
				
			||||||
		error = EsFileCopy(oldPath, oldPathBytes, newPath, newPathBytes);
 | 
					 | 
				
			||||||
		if (error == ES_SUCCESS) error = EsPathDelete(oldPath, oldPathBytes);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EsHandleClose(node.handle);
 | 
					 | 
				
			||||||
	EsHandleClose(directory.handle);
 | 
					 | 
				
			||||||
	return error;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool EsPathExists(const char *path, ptrdiff_t pathBytes, EsNodeType *type) {
 | 
					 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
	EsHandleClose(node.handle);
 | 
					 | 
				
			||||||
	if (type) *type = node.type;
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool 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;
 | 
					 | 
				
			||||||
	EsHandleClose(node.handle);
 | 
					 | 
				
			||||||
	information->type = node.type;
 | 
					 | 
				
			||||||
	information->fileSize = node.fileSize;
 | 
					 | 
				
			||||||
	information->directoryChildren = node.directoryChildren;
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsError EsPathCreate(const char *path, ptrdiff_t pathBytes, EsNodeType type, bool createLeadingDirectories) {
 | 
					 | 
				
			||||||
	if (pathBytes == -1) pathBytes = EsCStringLength(path);
 | 
					 | 
				
			||||||
	_EsNodeInformation node = {};
 | 
					 | 
				
			||||||
	EsError error = NodeOpen(path, pathBytes, 
 | 
					 | 
				
			||||||
			ES_NODE_FAIL_IF_FOUND | type | (createLeadingDirectories ? ES_NODE_CREATE_DIRECTORIES : 0), 
 | 
					 | 
				
			||||||
			&node);
 | 
					 | 
				
			||||||
	if (error != ES_SUCCESS) return error;
 | 
					 | 
				
			||||||
	EsHandleClose(node.handle);
 | 
					 | 
				
			||||||
	return ES_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EsError EsFileControl(EsHandle file, uint32_t flags) {
 | 
					 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, flags, 0, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EsConstantBufferRead(EsHandle buffer, void *output) {
 | 
					void EsConstantBufferRead(EsHandle buffer, void *output) {
 | 
				
			||||||
	EsSyscall(ES_SYSCALL_CONSTANT_BUFFER_READ, buffer, (uintptr_t) output, 0, 0);
 | 
						EsSyscall(ES_SYSCALL_CONSTANT_BUFFER_READ, buffer, (uintptr_t) output, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -644,7 +366,6 @@ EsHandle EsProcessOpen(uint64_t pid) {
 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_PROCESS_OPEN, pid, 0, 0, 0);
 | 
						return EsSyscall(ES_SYSCALL_PROCESS_OPEN, pid, 0, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef KERNEL
 | 
					 | 
				
			||||||
EsHandle EsConstantBufferShare(EsHandle constantBuffer, EsHandle targetProcess) {
 | 
					EsHandle EsConstantBufferShare(EsHandle constantBuffer, EsHandle targetProcess) {
 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_HANDLE_SHARE, constantBuffer, targetProcess, 0, 0);
 | 
						return EsSyscall(ES_SYSCALL_HANDLE_SHARE, constantBuffer, targetProcess, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -656,7 +377,6 @@ EsHandle EsConstantBufferCreate(const void *data, size_t dataBytes, EsHandle tar
 | 
				
			||||||
size_t EsConstantBufferGetSize(EsHandle buffer) {
 | 
					size_t EsConstantBufferGetSize(EsHandle buffer) {
 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_CONSTANT_BUFFER_READ, buffer, 0, 0, 0);
 | 
						return EsSyscall(ES_SYSCALL_CONSTANT_BUFFER_READ, buffer, 0, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
EsError EsAddressResolve(const char *domain, ptrdiff_t domainBytes, uint32_t flags, EsAddress *address) {
 | 
					EsError EsAddressResolve(const char *domain, ptrdiff_t domainBytes, uint32_t flags, EsAddress *address) {
 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_DOMAIN_NAME_RESOLVE, (uintptr_t) domain, domainBytes, (uintptr_t) address, flags);
 | 
						return EsSyscall(ES_SYSCALL_DOMAIN_NAME_RESOLVE, (uintptr_t) domain, domainBytes, (uintptr_t) address, flags);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue