From e7238c8a529af289fcdcc4d6368b3f703e2c470f Mon Sep 17 00:00:00 2001 From: nakst <> Date: Fri, 4 Feb 2022 22:15:46 +0000 Subject: [PATCH] add APIs for applications to add and remove custom mount points --- apps/file_manager/main.cpp | 37 ++++--- apps/installer.cpp | 2 + apps/installer.ini | 1 + desktop/api.cpp | 208 +++++++++++++++++++------------------ desktop/desktop.cpp | 73 ++++++------- desktop/os.header | 37 +++---- desktop/posix.cpp | 19 +++- kernel/drivers.cpp | 13 ++- kernel/files.cpp | 28 ++--- kernel/module.h | 17 +-- kernel/objects.cpp | 4 +- kernel/syscall.cpp | 35 ++++++- util/api_table.ini | 3 +- 13 files changed, 251 insertions(+), 226 deletions(-) diff --git a/apps/file_manager/main.cpp b/apps/file_manager/main.cpp index d3b099e..516abd8 100644 --- a/apps/file_manager/main.cpp +++ b/apps/file_manager/main.cpp @@ -99,6 +99,7 @@ struct HistoryEntry { struct Drive { char *prefix; size_t prefixBytes; + EsObjectID deviceID; EsVolumeInformation information; }; @@ -424,14 +425,16 @@ void DriveRefreshFolders(bool removed, const char *prefix, size_t prefixBytes) { foldersToRefresh.Free(); } -void DriveRemove(const char *prefix, size_t prefixBytes) { - if (!prefixBytes || prefix[0] == '|') return; +void DriveRemove(EsObjectID deviceID) { + char *prefix = nullptr; + size_t prefixBytes = 0; EsMutexAcquire(&drivesMutex); bool found = false; for (uintptr_t index = 0; index < drives.Length(); index++) { - if (0 == EsStringCompareRaw(prefix, prefixBytes, drives[index].prefix, drives[index].prefixBytes)) { - EsHeapFree(drives[index].prefix); + if (drives[index].deviceID == deviceID) { + prefix = drives[index].prefix; + prefixBytes = drives[index].prefixBytes; drives.Delete(index); found = true; @@ -447,17 +450,25 @@ void DriveRemove(const char *prefix, size_t prefixBytes) { EsAssert(found); EsMutexRelease(&drivesMutex); DriveRefreshFolders(true, prefix, prefixBytes); + EsHeapFree(prefix); } -void DriveAdd(const char *prefix, size_t prefixBytes) { - if (!prefixBytes || prefix[0] == '|') return; - +void DriveAdd(EsHandle deviceHandle, EsObjectID deviceID) { + // TODO Proper prefix allocation algorithm for drives. + static int nextPrefix = 1; + char prefix[16]; + bool isBootFileSystem = EsDeviceControl(deviceHandle, ES_DEVICE_CONTROL_FS_IS_BOOT, 0, nullptr) == 1; + size_t prefixBytes = EsStringFormat(prefix, sizeof(prefix), "%fd:", ES_STRING_FORMAT_SIMPLE, isBootFileSystem ? 0 : nextPrefix); + if (!isBootFileSystem) nextPrefix++; + EsMutexAcquire(&drivesMutex); Drive drive = {}; drive.prefix = (char *) EsHeapAllocate(prefixBytes, false); EsMemoryCopy(drive.prefix, prefix, prefixBytes); drive.prefixBytes = prefixBytes; + drive.deviceID = deviceID; + EsMountPointAdd(prefix, prefixBytes, deviceHandle); EsMountPointGetVolumeInformation(prefix, prefixBytes, &drive.information); drives.Add(drive); @@ -528,8 +539,8 @@ void _start() { // Enumerate drives. - EsMountPointEnumerate([] (const char *prefix, size_t prefixBytes, EsGeneric) { - DriveAdd(prefix, prefixBytes); + EsDeviceEnumerate([] (EsMessageDevice device, EsGeneric) { + if (device.type == ES_DEVICE_FILE_SYSTEM) DriveAdd(device.handle, device.id); }, 0); // Process messages. @@ -585,10 +596,10 @@ void _start() { loadedFolders.Free(); thumbnailCache.Free(); #endif - } else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) { - DriveAdd(message->registerFileSystem.mountPoint->prefix, message->registerFileSystem.mountPoint->prefixBytes); - } else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) { - DriveRemove(message->unregisterFileSystem.mountPoint->prefix, message->unregisterFileSystem.mountPoint->prefixBytes); + } else if (message->type == ES_MSG_DEVICE_CONNECTED && message->device.type == ES_DEVICE_FILE_SYSTEM) { + DriveAdd(message->device.handle, message->device.id); + } else if (message->type == ES_MSG_DEVICE_DISCONNECTED && message->device.type == ES_DEVICE_FILE_SYSTEM) { + DriveRemove(message->device.id); } else if (message->type == ES_MSG_FILE_MANAGER_FILE_MODIFIED) { char *_path = (char *) EsHeapAllocate(message->user.context2.u, false); EsConstantBufferRead(message->user.context1.u, _path); diff --git a/apps/installer.cpp b/apps/installer.cpp index 1a5a91b..50465e6 100644 --- a/apps/installer.cpp +++ b/apps/installer.cpp @@ -2,6 +2,8 @@ // It is released under the terms of the MIT license -- see LICENSE.md. // Written by: nakst. +// TODO Update to use the new mount point APIs. + #define ES_PRIVATE_APIS #define INSTALLER diff --git a/apps/installer.ini b/apps/installer.ini index 52f4300..a1a9ef1 100644 --- a/apps/installer.ini +++ b/apps/installer.ini @@ -5,6 +5,7 @@ permission_all_devices=1 permission_shutdown=1 hidden=1 is_installer=1 +disabled=1 [build] source=apps/installer.cpp diff --git a/desktop/api.cpp b/desktop/api.cpp index ae3979a..8a7c97a 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -87,11 +87,6 @@ struct ThreadLocalStorage { uint64_t timerAdjustTicks; }; -struct MountPoint : EsMountPoint { - EsVolumeInformation information; - bool removing; -}; - struct Timer { EsTimer id; double afterMs; @@ -193,7 +188,8 @@ struct { EsHandle desktopRequestPipe, desktopResponsePipe; - Array<MountPoint> mountPoints; + EsMutex mountPointsMutex; + Array<EsMountPoint> mountPoints2; Array<EsMessageDevice> connectedDevices; bool foundBootFileSystem; EsProcessStartupInformation *startupInformation; @@ -245,7 +241,8 @@ EsSystemConfigurationGroup *SystemConfigurationGetGroup(const char *section, ptr uint8_t *ApplicationStartupInformationToBuffer(const _EsApplicationStartupInformation *information, size_t *dataBytes = nullptr); char *SystemConfigurationGroupReadString(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, size_t *valueBytes = nullptr); int64_t SystemConfigurationGroupReadInteger(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, int64_t defaultValue = 0); -MountPoint *NodeFindMountPoint(const char *prefix, size_t prefixBytes); +bool NodeFindMountPoint(const char *prefix, size_t prefixBytes, EsMountPoint *result, bool mutexTaken); +EsError MountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base, bool addedByApplication); EsWindow *WindowFromWindowID(EsObjectID id); void POSIXCleanup(); extern "C" void _init(); @@ -276,49 +273,101 @@ uintptr_t APISyscallCheckForCrash(uintptr_t argument0, uintptr_t argument1, uint } #endif -MountPoint *NodeAddMountPoint(const char *prefix, size_t prefixBytes, EsHandle base, bool queryInformation) { - MountPoint mountPoint = {}; - EsAssert(prefixBytes < sizeof(mountPoint.prefix)); - EsMemoryCopy(mountPoint.prefix, prefix, prefixBytes); - mountPoint.base = base; - mountPoint.prefixBytes = prefixBytes; +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 (queryInformation) { - EsSyscall(ES_SYSCALL_VOLUME_GET_INFORMATION, base, (uintptr_t) &mountPoint.information, 0, 0); - } + 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; - return api.mountPoints.Add(mountPoint); -} - -MountPoint *NodeFindMountPoint(const char *prefix, size_t prefixBytes) { - for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { - MountPoint *mountPoint = &api.mountPoints[i]; - - if (prefixBytes >= mountPoint->prefixBytes - && 0 == EsMemoryCompare(prefix, mountPoint->prefix, mountPoint->prefixBytes) - && !mountPoint->removing) { - return mountPoint; + 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; + } } } - return nullptr; + 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) { - MountPoint *mountPoint = NodeFindMountPoint(prefix, prefixBytes); - if (!mountPoint) return false; - EsSyscall(ES_SYSCALL_VOLUME_GET_INFORMATION, mountPoint->base, (uintptr_t) &mountPoint->information, 0, 0); - EsMemoryCopy(information, &mountPoint->information, sizeof(EsVolumeInformation)); - return true; -} + EsMutexAcquire(&api.mountPointsMutex); + EsMountPoint mountPoint; + bool found = NodeFindMountPoint(prefix, prefixBytes, &mountPoint, true); -void EsMountPointEnumerate(EsMountPointEnumerationCallback callback, EsGeneric context) { - EsMessageMutexCheck(); - - for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { - MountPoint *mountPoint = &api.mountPoints[i]; - callback(mountPoint->prefix, mountPoint->prefixBytes, context); + 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) { @@ -330,17 +379,24 @@ void EsDeviceEnumerate(EsDeviceEnumerationCallback callback, EsGeneric context) } EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node) { - EsMountPoint *mountPoint = NodeFindMountPoint(path, pathBytes); + // 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); - if (!mountPoint) { - return ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME; + 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); } - node->handle = mountPoint->base; - path += mountPoint->prefixBytes; - pathBytes -= mountPoint->prefixBytes; - - return 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) { @@ -1069,7 +1125,7 @@ EsMessage *EsMessageReceive() { FreeUnusedStyles(true /* include permanent styles */); theming.loadedStyles.Free(); SystemConfigurationUnload(); - api.mountPoints.Free(); + api.mountPoints2.Free(); api.postBox.Free(); api.timers.Free(); gui.animatingElements.Free(); @@ -1089,13 +1145,6 @@ EsMessage *EsMessageReceive() { #endif EsProcessTerminateCurrent(); } - } else if (message.message.type == ES_MSG_UNREGISTER_FILE_SYSTEM) { - for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { - if (api.mountPoints[i].information.id == message.message.unregisterFileSystem.id) { - EsHandleClose(api.mountPoints[i].base); - api.mountPoints.Delete(i); - } - } } EsMessageMutexRelease(); @@ -1291,49 +1340,6 @@ EsMessage *EsMessageReceive() { return &message.message; } - } else if (type == ES_MSG_REGISTER_FILE_SYSTEM) { - EsMessageRegisterFileSystem *m = &message.message.registerFileSystem; - - int64_t index = 1; // TODO This is incorrect! - - while (true) { - bool seen = false; - - for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { - if (index == EsIntegerParse(api.mountPoints[i].prefix, api.mountPoints[i].prefixBytes)) { - seen = true; - break; - } - } - - if (seen) { - index++; - } else { - break; - } - } - - bool isBootFileSystem = m->isBootFileSystem; - char prefix[16]; - size_t prefixBytes = EsStringFormat(prefix, sizeof(prefix), "%fd:", ES_STRING_FORMAT_SIMPLE, isBootFileSystem ? 0 : index); - - m->mountPoint = NodeAddMountPoint(prefix, prefixBytes, m->rootDirectory, true); - - if (isBootFileSystem) { - api.foundBootFileSystem = true; - } - - if (m->mountPoint) { - return &message.message; - } - } else if (type == ES_MSG_UNREGISTER_FILE_SYSTEM) { - for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { - if (api.mountPoints[i].information.id == message.message.unregisterFileSystem.id) { - message.message.unregisterFileSystem.mountPoint = &api.mountPoints[i]; - api.mountPoints[i].removing = true; - return &message.message; - } - } } else if (type == ES_MSG_DEVICE_CONNECTED) { api.connectedDevices.Add(message.message.device); return &message.message; @@ -1561,7 +1567,7 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) { path = EsSystemConfigurationReadString(EsLiteral("paths"), EsLiteral("fonts")); NodeOpen(path, EsCStringLength(path), ES_NODE_DIRECTORY, &node); - NodeAddMountPoint(EsLiteral("|Fonts:"), node.handle, false); + MountPointAdd(EsLiteral("|Fonts:"), node.handle, false); EsHeapFree(path); SettingsLoadDefaults(); @@ -1586,7 +1592,7 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) { for (uintptr_t i = 0; i < header->initialMountPointCount; i++) { const EsMountPoint *mountPoint = (const EsMountPoint *) EsBufferRead(&buffer, sizeof(EsMountPoint)); - NodeAddMountPoint(mountPoint->prefix, mountPoint->prefixBytes, mountPoint->base, true); + MountPointAdd(mountPoint->prefix, mountPoint->prefixBytes, mountPoint->base, false); } for (uintptr_t i = 0; i < header->initialDeviceCount; i++) { diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp index bd1b12c..8288e71 100644 --- a/desktop/desktop.cpp +++ b/desktop/desktop.cpp @@ -655,6 +655,10 @@ int CursorLocatorMessage(EsElement *element, EsMessage *message) { } int ProcessGlobalKeyboardShortcuts(EsElement *, EsMessage *message) { + if (!desktop.setupDesktopUIComplete) { + return 0; + } + if (message->type == ES_MSG_KEY_DOWN) { bool ctrlOnly = message->keyboard.modifiers == ES_MODIFIER_CTRL; uint32_t scancode = ScancodeMapToLabel(message->keyboard.scancode); @@ -1866,7 +1870,8 @@ bool ApplicationInstanceStart(_EsApplicationStartupInformation *startupInformati arguments.permissions |= ES_PERMISSION_PROCESS_OPEN; arguments.permissions |= ES_PERMISSION_POSIX_SUBSYSTEM; - MountPoint root = *NodeFindMountPoint(EsLiteral("0:")); + EsMountPoint root; + EsAssert(NodeFindMountPoint(EsLiteral("0:"), &root, false)); root.prefixBytes = EsStringFormat(root.prefix, sizeof(root.prefix), "|POSIX:"); initialMountPoints.Add(root); @@ -1879,26 +1884,20 @@ bool ApplicationInstanceStart(_EsApplicationStartupInformation *startupInformati } if (application->permissions & APPLICATION_PERMISSION_ALL_FILES) { - // We will inform the process of new and removed mount points on the message thread, - // in response to ES_MSG_REGISTER_FILE_SYSTEM and ES_MSG_UNREGISTER_FILE_SYSTEM. - EsMessageMutexCheck(); - - for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { - initialMountPoints.Add(api.mountPoints[i]); - handleDuplicateList.Add(api.mountPoints[i].base); - handleModeDuplicateList.Add(0); - } - arguments.permissions |= ES_PERMISSION_GET_VOLUME_INFORMATION; - } else { - MountPoint fonts = *NodeFindMountPoint(EsLiteral("|Fonts:")); + } + + { + EsMountPoint fonts; + EsAssert(NodeFindMountPoint(EsLiteral("|Fonts:"), &fonts, false)); initialMountPoints.Add(fonts); handleDuplicateList.Add(fonts.base); handleModeDuplicateList.Add(2 /* prevent write */); } - if (application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) { - for (uintptr_t i = 0; i < api.connectedDevices.Length(); i++) { + for (uintptr_t i = 0; i < api.connectedDevices.Length(); i++) { + if ((application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) + || ((application->permissions & APPLICATION_PERMISSION_ALL_FILES) && api.connectedDevices[i].type == ES_DEVICE_FILE_SYSTEM)) { initialDevices.Add(api.connectedDevices[i]); handleDuplicateList.Add(api.connectedDevices[i].handle); handleModeDuplicateList.Add(0); @@ -3153,24 +3152,18 @@ void DesktopSendMessage(EsMessage *message) { EmbeddedWindowDestroyed(message->embeddedWindowDestroyedID); } else if (message->type == ES_MSG_APPLICATION_CRASH) { ApplicationInstanceCrashed(message); - } else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) { - EsHandle rootDirectory = message->registerFileSystem.rootDirectory; - - for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { - ApplicationProcess *process = desktop.allApplicationProcesses[i]; - - if (process->application && (process->application->permissions & APPLICATION_PERMISSION_ALL_FILES)) { - message->registerFileSystem.rootDirectory = EsSyscall(ES_SYSCALL_HANDLE_SHARE, rootDirectory, process->handle, 0, 0); - EsMessagePostRemote(process->handle, message); - } - } } else if (message->type == ES_MSG_DEVICE_CONNECTED) { EsHandle handle = message->device.handle; + EsPrint("Desktop received ES_MSG_DEVICE_CONNECTED with ID %d and type %z.\n", + message->device.id, EnumLookupNameFromValue(enumStrings_EsDeviceType, message->device.type)); + for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { ApplicationProcess *process = desktop.allApplicationProcesses[i]; + if (!process->application) continue; - if (process->application && (process->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES)) { + if ((process->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) + || ((process->application->permissions & APPLICATION_PERMISSION_ALL_FILES) && message->device.type == ES_DEVICE_FILE_SYSTEM)) { message->device.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, handle, process->handle, 0, 0); EsMessagePostRemote(process->handle, message); } @@ -3193,26 +3186,22 @@ void DesktopSendMessage(EsMessage *message) { } else { // The screen resolution will be correctly queried in DesktopSetup. } + } else if (message->device.type == ES_DEVICE_FILE_SYSTEM) { + if (EsDeviceControl(message->device.handle, ES_DEVICE_CONTROL_FS_IS_BOOT, 0, 0) == 1) { + // Mount the boot file system at "0:". + MountPointAdd("0:", 2, message->device.handle, false); + api.foundBootFileSystem = true; + } } - } else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM || message->type == ES_MSG_DEVICE_DISCONNECTED) { + } else if (message->type == ES_MSG_DEVICE_DISCONNECTED) { for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { ApplicationProcess *process = desktop.allApplicationProcesses[i]; + if (!process->application) continue; - if (!process->application) { - continue; + if ((process->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) + || ((process->application->permissions & APPLICATION_PERMISSION_ALL_FILES) && message->device.type == ES_DEVICE_FILE_SYSTEM)) { + EsMessagePostRemote(process->handle, message); } - - if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) { - if (~process->application->permissions & APPLICATION_PERMISSION_ALL_FILES) { - continue; - } - } else if (message->type == ES_MSG_DEVICE_DISCONNECTED) { - if (~process->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) { - continue; - } - } - - EsMessagePostRemote(process->handle, message); } } else if (message->type == ES_MSG_KEY_DOWN) { ProcessGlobalKeyboardShortcuts(nullptr, message); diff --git a/desktop/os.header b/desktop/os.header index 306a2b5..9ce931b 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -337,6 +337,7 @@ define ES_ERROR_CANCELLED (-73) define ES_ERROR_BLOCK_ACCESS_INVALID (-74) define ES_ERROR_DEVICE_REMOVED (-75) define ES_ERROR_TOO_MANY_FILES_WITH_NAME (-76) +define ES_ERROR_MOUNT_POINT_ALREADY_EXISTS (-77) define ES_INVALID_HANDLE ((EsHandle) (0)) define ES_CURRENT_THREAD ((EsHandle) (0x10)) @@ -1047,8 +1048,6 @@ enum EsMessageType { ES_MSG_INSTANCE_CREATE = 0x6002 ES_MSG_DEVICE_CONNECTED = 0x6003 ES_MSG_DEVICE_DISCONNECTED = 0x6004 - ES_MSG_REGISTER_FILE_SYSTEM = 0x6005 - ES_MSG_UNREGISTER_FILE_SYSTEM = 0x6006 // Instance messages: ES_MSG_INSTANCE_OPEN = 0x6800 @@ -1176,6 +1175,8 @@ enum EsDeviceControlType { ES_DEVICE_CONTROL_BLOCK_DETECT_FS = 0x1004 // Detect file systems. All existing file systems must have been unmounted. ES_DEVICE_CONTROL_CLOCK_READ = 0x2001 + + ES_DEVICE_CONTROL_FS_IS_BOOT = 0x3001 } function_pointer int EsElementCallback(struct EsElement *element, struct EsMessage *message); @@ -1297,12 +1298,6 @@ struct EsSnapshotProcesses { EsSnapshotProcessesItem processes[]; } -struct EsMountPoint { - char prefix[16]; - size_t prefixBytes; - EsHandle base; -}; - struct EsProcessCreateData { EsHandle systemData; EsHandle subsystemData; @@ -1799,20 +1794,9 @@ struct EsMessageTabOperation { EsError error; }; -struct EsMessageRegisterFileSystem { - EsHandle rootDirectory; - bool isBootFileSystem; - EsMountPoint *mountPoint; -}; - -struct EsMessageUnregisterFileSystem { - EsObjectID id; - EsMountPoint *mountPoint; -}; - struct EsMessageDevice { EsObjectID id; - EsHandle handle; + EsHandle handle; // Not set in ES_MSG_DEVICE_DISCONNECTED. This handle is owned by the system, and is closed on receiving the disconnected message within EsMessageReceive. EsDeviceType type; }; @@ -1888,8 +1872,6 @@ struct EsMessage { EsMessageEyedrop eyedrop; EsMessageCreateInstance createInstance; EsMessageTabOperation tabOperation; - EsMessageRegisterFileSystem registerFileSystem; - EsMessageUnregisterFileSystem unregisterFileSystem; EsMessageDevice device; EsObjectID embeddedWindowDestroyedID; }; @@ -1972,6 +1954,13 @@ struct EsListViewEnumString { STRING string; }; +private struct EsMountPoint { + char prefix[16]; + size_t prefixBytes; + uintptr_t base; + bool addedByApplication; +}; + // Function pointer types. function_pointer void EsThreadEntryCallback(EsGeneric argument); @@ -1980,7 +1969,6 @@ function_pointer int EsCRTComparisonCallback(const void *left, const void *right function_pointer void EsTimerCallback(EsGeneric argument); function_pointer void EsMenuCallback(EsMenu *menu, EsGeneric context); function_pointer void EsUndoCallback(const void *item, EsUndoManager *manager, EsMessage *message); -function_pointer void EsMountPointEnumerationCallback(const char *prefix, size_t prefixBytes, EsGeneric context); function_pointer void EsDeviceEnumerationCallback(EsMessageDevice device, EsGeneric context); function_pointer void EsListViewEnumerateVisibleItemsCallback(EsListView *view, EsElement *item, uint32_t group, EsListViewIndex index); function_pointer void EsFontEnumerationCallback(const EsFontInformation *information, EsGeneric context); @@ -2058,7 +2046,8 @@ function void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flag // These calls require permission_all_files. function bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, EsVolumeInformation *information); // Returns false if the mount point does not exist. -function void EsMountPointEnumerate(EsMountPointEnumerationCallback callback, EsGeneric context); +function EsError EsMountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base); // The system maintains a duplicate of the base handle. +function bool EsMountPointRemove(const char *prefix, size_t prefixBytes); // Returns false if the mount point does not exist. You can only remove mount points you added with EsMountPointAdd. function void EsOpenDocumentQueryInformation(STRING filePath, EsOpenDocumentInformation *information); function void _EsPathAnnouncePathMoved(STRING oldPath, STRING newPath); // Set oldPathBytes = 0 to make the file manager refresh the path. function void _EsOpenDocumentEnumerate(EsBuffer *outputBuffer); diff --git a/desktop/posix.cpp b/desktop/posix.cpp index c4a101f..6eb32c6 100644 --- a/desktop/posix.cpp +++ b/desktop/posix.cpp @@ -14,7 +14,7 @@ extern "C" void *ProcessorTLSRead(uintptr_t offset); extern "C" void ProcessorTLSWrite(uintptr_t offset, void *value); extern ptrdiff_t tlsStorageOffset; -EsMountPoint *NodeFindMountPoint(const char *prefix, size_t prefixBytes); +bool NodeFindMountPoint(const char *prefix, size_t prefixBytes, EsMountPoint *result, bool mutexTaken); EsProcessStartupInformation *ProcessGetStartupInformation(); #define _POSIX_SOURCE @@ -50,6 +50,7 @@ struct ChildProcess { char *workingDirectory; Array<ChildProcess> childProcesses; Array<void *> _argv; +EsHandle posixMountPointBase; #ifdef ES_ARCH_X86_64 Elf64_Phdr *tlsHeader; @@ -165,6 +166,14 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long // EsPrint(":: %z %x %x %x\n", syscallNames[n], a1, a2, a3); } + if (posixMountPointBase) { + // It doesn't matter if multiple threads try to do this at the same time, + // they'll all get the same result. + EsMountPoint mountPoint; + EsAssert(NodeFindMountPoint(EsLiteral("|POSIX:"), &mountPoint, false)); + posixMountPointBase = mountPoint.base; + } + long returnValue = 0; _EsPOSIXSyscall syscall = { n, a1, a2, a3, a4, a5, a6 }; @@ -212,7 +221,7 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long size_t pathBytes; char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false); syscall.arguments[0] = (long) path; - syscall.arguments[4] = (long) NodeFindMountPoint(EsLiteral("|POSIX:"))->base; + syscall.arguments[4] = (long) posixMountPointBase; syscall.arguments[6] = (long) pathBytes; returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); // EsPrint("SYS_open '%s' with handle %d\n", pathBytes, path, returnValue); @@ -306,7 +315,7 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long case SYS_unlink: { _EsNodeInformation node; - node.handle = NodeFindMountPoint(EsLiteral("|POSIX:"))->base; + node.handle = posixMountPointBase; size_t pathBytes; char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false); EsError error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_FILE_WRITE, (uintptr_t) &node); @@ -326,7 +335,7 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long case SYS_truncate: { _EsNodeInformation node; - node.handle = NodeFindMountPoint(EsLiteral("|POSIX:"))->base; + node.handle = posixMountPointBase; size_t pathBytes; char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false); EsError error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) path, pathBytes, ES_NODE_FAIL_IF_NOT_FOUND | ES_FILE_WRITE, (uintptr_t) &node); @@ -404,7 +413,7 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long syscall.arguments[1] = (long) pathBytes; syscall.arguments[2] = (long) newEnvironment; syscall.arguments[3] = (long) environmentSize; - syscall.arguments[4] = (long) NodeFindMountPoint(EsLiteral("|POSIX:"))->base; + syscall.arguments[4] = (long) posixMountPointBase; returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0); } break; diff --git a/kernel/drivers.cpp b/kernel/drivers.cpp index a808b9e..76654f3 100644 --- a/kernel/drivers.cpp +++ b/kernel/drivers.cpp @@ -80,14 +80,17 @@ void KDeviceDestroy(KDevice *device) { KMutexRelease(&deviceTreeMutex); } -void KDeviceOpenHandle(KDevice *device) { +void KDeviceOpenHandle(KDevice *device, uint32_t handleFlags) { + if (device->trackHandle && (handleFlags & K_DEVICE_HANDLE_TRACKED)) device->trackHandle(device, true); KMutexAcquire(&deviceTreeMutex); if (!device->handles) KernelPanic("KDeviceOpenHandle - Device %s has no handles.\n", device); device->handles++; KMutexRelease(&deviceTreeMutex); } -void KDeviceCloseHandle(KDevice *device) { +void KDeviceCloseHandle(KDevice *device, uint32_t handleFlags) { + if (device->trackHandle && (handleFlags & K_DEVICE_HANDLE_TRACKED)) device->trackHandle(device, false); + KMutexAcquire(&deviceTreeMutex); if (!device->handles) KernelPanic("KDeviceCloseHandle - Device %s has no handles.\n", device); @@ -131,7 +134,7 @@ void DeviceRemovedRecurse(KDevice *device) { } } -void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type) { +void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type, uint32_t handleFlags) { KMutexAcquire(&deviceTreeMutex); if (device->flags & K_DEVICE_VISIBLE_TO_USER) { @@ -143,14 +146,14 @@ void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type) { KMutexRelease(&deviceTreeMutex); - KDeviceOpenHandle(device); + KDeviceOpenHandle(device, handleFlags); _EsMessageWithObject m; EsMemoryZero(&m, sizeof(m)); m.message.type = ES_MSG_DEVICE_CONNECTED; m.message.device.id = device->objectID; m.message.device.type = type; - m.message.device.handle = DesktopOpenHandle(device, 0, KERNEL_OBJECT_DEVICE); + m.message.device.handle = DesktopOpenHandle(device, handleFlags, KERNEL_OBJECT_DEVICE); if (m.message.device.handle) { if (!DesktopSendMessage(&m)) { diff --git a/kernel/files.cpp b/kernel/files.cpp index ab9d31c..c22b636 100644 --- a/kernel/files.cpp +++ b/kernel/files.cpp @@ -1881,38 +1881,22 @@ void FSRegisterBootFileSystem(KFileSystem *fileSystem, EsUniqueIdentifier identi FSRegisterFileSystem(fileSystem); } -void FSFileSystemDeviceRemoved(KDevice *device) { +void FSTrackUserFileSystemHandle(KDevice *device, bool opened) { KFileSystem *fileSystem = (KFileSystem *) device; - _EsMessageWithObject m; - EsMemoryZero(&m, sizeof(m)); - m.message.type = ES_MSG_UNREGISTER_FILE_SYSTEM; - m.message.unregisterFileSystem.id = fileSystem->objectID; - DesktopSendMessage(&m); + if (opened) FSNodeOpenHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT, FS_NODE_OPEN_HANDLE_STANDARD); + else FSNodeCloseHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT); } void FSRegisterFileSystem(KFileSystem *fileSystem) { - fileSystem->removed = FSFileSystemDeviceRemoved; - + fileSystem->trackHandle = FSTrackUserFileSystemHandle; MMObjectCacheRegister(&fileSystem->cachedDirectoryEntries, FSTrimCachedDirectoryEntry, sizeof(FSDirectoryEntry) + 16 /* approximate average name bytes */ + fileSystem->directoryEntryDataBytes); MMObjectCacheRegister(&fileSystem->cachedNodes, FSTrimCachedNode, sizeof(FSFile) + fileSystem->nodeDataBytes); fileSystem->rootDirectory->directoryEntry->directoryChildren = fileSystem->rootDirectoryInitialChildren; FSNodeOpenHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT, fileSystem->isBootFileSystem ? FS_NODE_OPEN_HANDLE_STANDARD : FS_NODE_OPEN_HANDLE_FIRST); - - _EsMessageWithObject m; - EsMemoryZero(&m, sizeof(m)); - m.message.type = ES_MSG_REGISTER_FILE_SYSTEM; - m.message.registerFileSystem.isBootFileSystem = fileSystem->isBootFileSystem; - m.message.registerFileSystem.rootDirectory = DesktopOpenHandle(fileSystem->rootDirectory, _ES_NODE_DIRECTORY_WRITE, KERNEL_OBJECT_NODE); - - if (m.message.registerFileSystem.rootDirectory) { - if (!DesktopSendMessage(&m)) { - DesktopCloseHandle(m.message.registerFileSystem.rootDirectory); // This will check that the handle is still valid. - } - } - - KDeviceSendConnectedMessage(fileSystem, ES_DEVICE_FILE_SYSTEM); + KDeviceSendConnectedMessage(fileSystem, ES_DEVICE_FILE_SYSTEM, K_DEVICE_HANDLE_TRACKED); + FSNodeCloseHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT); } void FSRegisterBlockDevice(KBlockDevice *device) { diff --git a/kernel/module.h b/kernel/module.h index f13851a..d48bf7b 100644 --- a/kernel/module.h +++ b/kernel/module.h @@ -495,10 +495,13 @@ struct KDevice { EsObjectID objectID; // These callbacks are called with the deviceTreeMutex locked, and are all optional. - void (*shutdown)(KDevice *device); // Called when the computer is about to shutdown. - void (*dumpState)(KDevice *device); // Dump the entire state of the device for debugging. - void (*removed)(KDevice *device); // Called when the device is removed. Called after the children are informed. - void (*destroy)(KDevice *device); // Called just before the device is destroyed. + void (*shutdown)(KDevice *device); // Called when the computer is about to shutdown. + void (*dumpState)(KDevice *device); // Dump the entire state of the device for debugging. + void (*removed)(KDevice *device); // Called when the device is removed. Called after the children are informed. + void (*destroy)(KDevice *device); // Called just before the device is destroyed. + void (*trackHandle)(KDevice *device, bool opened); // Called when a handle to the device with K_DEVICE_HANDLE_TRACKED is opened/closed. + +#define K_DEVICE_HANDLE_TRACKED (1 << 0) }; struct KDriver { @@ -524,11 +527,11 @@ void KDeviceAttachAll(KDevice *parentDevice, const char *cParentDriver); bool KDeviceAttachByName(KDevice *parentDevice, const char *cName); KDevice *KDeviceCreate(const char *cDebugName, KDevice *parent, size_t bytes /* must be at least the size of a KDevice */); -void KDeviceOpenHandle(KDevice *device); +void KDeviceOpenHandle(KDevice *device, uint32_t handleFlags = ES_FLAGS_DEFAULT); void KDeviceDestroy(KDevice *device); // Call if initialisation of the device failed. Otherwise use KDeviceCloseHandle. -void KDeviceCloseHandle(KDevice *device); // The device creator is responsible for one handle after the creating it. The device is destroyed once all handles are closed. +void KDeviceCloseHandle(KDevice *device, uint32_t handleFlags = ES_FLAGS_DEFAULT); // The device creator is responsible for one handle after the creating it. The device is destroyed once all handles are closed. void KDeviceRemoved(KDevice *device); // Call when a child device is removed. Must be called only once! -void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type); // Send a message to Desktop to inform it the device was connected. +void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type, uint32_t handleFlags = ES_FLAGS_DEFAULT); // Send a message to Desktop to inform it the device was connected. #include <bin/generated_code/kernel_config.h> diff --git a/kernel/objects.cpp b/kernel/objects.cpp index 9f95047..dbaae4e 100644 --- a/kernel/objects.cpp +++ b/kernel/objects.cpp @@ -190,7 +190,7 @@ bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags) { } break; case KERNEL_OBJECT_DEVICE: { - KDeviceOpenHandle((KDevice *) object); + KDeviceOpenHandle((KDevice *) object, flags); } break; default: { @@ -351,7 +351,7 @@ void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags) { } break; case KERNEL_OBJECT_DEVICE: { - KDeviceCloseHandle((KDevice *) object); + KDeviceCloseHandle((KDevice *) object, flags); } break; default: { diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 554b1f5..4bf9f6c 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -651,18 +651,37 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_NODE_OPEN) { _EsNodeInformation information; SYSCALL_READ(&information, argument3, sizeof(_EsNodeInformation)); - SYSCALL_HANDLE_2(information.handle, KERNEL_OBJECT_NODE, _directory); - KNode *directory = (KNode *) _directory.object; + SYSCALL_HANDLE_2(information.handle, (KernelObjectType) (KERNEL_OBJECT_NODE | KERNEL_OBJECT_DEVICE), _directory); + + KNode *directory = nullptr; + uint64_t directoryFlags = 0; + + if (_directory.type == KERNEL_OBJECT_DEVICE) { + KDevice *device = (KDevice *) _directory.object; + + if (device->type == ES_DEVICE_FILE_SYSTEM) { + KFileSystem *fileSystem = (KFileSystem *) device; + directory = fileSystem->rootDirectory; + directoryFlags = _ES_NODE_DIRECTORY_WRITE; + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); + } + } else if (_directory.type == KERNEL_OBJECT_NODE) { + directory = (KNode *) _directory.object; + directoryFlags = _directory.flags; + } else { + EsAssert(false); + } if (directory->directoryEntry->type != ES_NODE_DIRECTORY) { SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); } - if ((~_directory.flags & _ES_NODE_DIRECTORY_WRITE) && needWritePermission) { + if ((~directoryFlags & _ES_NODE_DIRECTORY_WRITE) && needWritePermission) { SYSCALL_RETURN(ES_ERROR_PERMISSION_NOT_GRANTED, false); } - if (~_directory.flags & _ES_NODE_DIRECTORY_WRITE) { + if (~directoryFlags & _ES_NODE_DIRECTORY_WRITE) { flags |= _ES_NODE_NO_WRITE_BASE; } @@ -1604,6 +1623,14 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_DEVICE_CONTROL) { } else { SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); } + } else if (device->type == ES_DEVICE_FILE_SYSTEM) { + KFileSystem *fileSystem = (KFileSystem *) device; + + if (type == ES_DEVICE_CONTROL_FS_IS_BOOT) { + SYSCALL_RETURN(fileSystem->isBootFileSystem ? 1 : 0, false); + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); + } } else { SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); } diff --git a/util/api_table.ini b/util/api_table.ini index 5124f5a..744844c 100644 --- a/util/api_table.ini +++ b/util/api_table.ini @@ -161,8 +161,10 @@ EsStringFormatTemporary=159 EsStringFormatV=160 EsStringFormatAppend=161 EsStringFormatAppendV=162 +EsMountPointAdd=163 EsSystemConfigurationReadFileTypes=164 EsImageLoad=165 +EsMountPointRemove=166 EsCRTabs=168 EsCRTacosf=169 EsCRTasinf=170 @@ -369,7 +371,6 @@ EsElementRepaintForScroll=372 EsMemoryFaultRange=373 EsDrawBitmapScaled=374 EsRectangleCenter=375 -EsMountPointEnumerate=376 EsMountPointGetVolumeInformation=377 EsListViewInvalidateAll=378 EsListViewGetFocusedItem=379