add APIs for applications to add and remove custom mount points

This commit is contained in:
nakst 2022-02-04 22:15:46 +00:00
parent 2c79bd4367
commit e7238c8a52
13 changed files with 251 additions and 226 deletions

View File

@ -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);

View File

@ -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

View File

@ -5,6 +5,7 @@ permission_all_devices=1
permission_shutdown=1
hidden=1
is_installer=1
disabled=1
[build]
source=apps/installer.cpp

View File

@ -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++) {

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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)) {

View File

@ -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) {

View File

@ -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>

View File

@ -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: {

View File

@ -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);
}

View File

@ -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