mirror of https://gitlab.com/nakst/essence
add APIs for applications to add and remove custom mount points
This commit is contained in:
parent
2c79bd4367
commit
e7238c8a52
|
@ -99,6 +99,7 @@ struct HistoryEntry {
|
||||||
struct Drive {
|
struct Drive {
|
||||||
char *prefix;
|
char *prefix;
|
||||||
size_t prefixBytes;
|
size_t prefixBytes;
|
||||||
|
EsObjectID deviceID;
|
||||||
EsVolumeInformation information;
|
EsVolumeInformation information;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -424,14 +425,16 @@ void DriveRefreshFolders(bool removed, const char *prefix, size_t prefixBytes) {
|
||||||
foldersToRefresh.Free();
|
foldersToRefresh.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DriveRemove(const char *prefix, size_t prefixBytes) {
|
void DriveRemove(EsObjectID deviceID) {
|
||||||
if (!prefixBytes || prefix[0] == '|') return;
|
char *prefix = nullptr;
|
||||||
|
size_t prefixBytes = 0;
|
||||||
EsMutexAcquire(&drivesMutex);
|
EsMutexAcquire(&drivesMutex);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for (uintptr_t index = 0; index < drives.Length(); index++) {
|
for (uintptr_t index = 0; index < drives.Length(); index++) {
|
||||||
if (0 == EsStringCompareRaw(prefix, prefixBytes, drives[index].prefix, drives[index].prefixBytes)) {
|
if (drives[index].deviceID == deviceID) {
|
||||||
EsHeapFree(drives[index].prefix);
|
prefix = drives[index].prefix;
|
||||||
|
prefixBytes = drives[index].prefixBytes;
|
||||||
drives.Delete(index);
|
drives.Delete(index);
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
|
@ -447,17 +450,25 @@ void DriveRemove(const char *prefix, size_t prefixBytes) {
|
||||||
EsAssert(found);
|
EsAssert(found);
|
||||||
EsMutexRelease(&drivesMutex);
|
EsMutexRelease(&drivesMutex);
|
||||||
DriveRefreshFolders(true, prefix, prefixBytes);
|
DriveRefreshFolders(true, prefix, prefixBytes);
|
||||||
|
EsHeapFree(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DriveAdd(const char *prefix, size_t prefixBytes) {
|
void DriveAdd(EsHandle deviceHandle, EsObjectID deviceID) {
|
||||||
if (!prefixBytes || prefix[0] == '|') return;
|
// 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);
|
EsMutexAcquire(&drivesMutex);
|
||||||
|
|
||||||
Drive drive = {};
|
Drive drive = {};
|
||||||
drive.prefix = (char *) EsHeapAllocate(prefixBytes, false);
|
drive.prefix = (char *) EsHeapAllocate(prefixBytes, false);
|
||||||
EsMemoryCopy(drive.prefix, prefix, prefixBytes);
|
EsMemoryCopy(drive.prefix, prefix, prefixBytes);
|
||||||
drive.prefixBytes = prefixBytes;
|
drive.prefixBytes = prefixBytes;
|
||||||
|
drive.deviceID = deviceID;
|
||||||
|
EsMountPointAdd(prefix, prefixBytes, deviceHandle);
|
||||||
EsMountPointGetVolumeInformation(prefix, prefixBytes, &drive.information);
|
EsMountPointGetVolumeInformation(prefix, prefixBytes, &drive.information);
|
||||||
drives.Add(drive);
|
drives.Add(drive);
|
||||||
|
|
||||||
|
@ -528,8 +539,8 @@ void _start() {
|
||||||
|
|
||||||
// Enumerate drives.
|
// Enumerate drives.
|
||||||
|
|
||||||
EsMountPointEnumerate([] (const char *prefix, size_t prefixBytes, EsGeneric) {
|
EsDeviceEnumerate([] (EsMessageDevice device, EsGeneric) {
|
||||||
DriveAdd(prefix, prefixBytes);
|
if (device.type == ES_DEVICE_FILE_SYSTEM) DriveAdd(device.handle, device.id);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// Process messages.
|
// Process messages.
|
||||||
|
@ -585,10 +596,10 @@ void _start() {
|
||||||
loadedFolders.Free();
|
loadedFolders.Free();
|
||||||
thumbnailCache.Free();
|
thumbnailCache.Free();
|
||||||
#endif
|
#endif
|
||||||
} else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) {
|
} else if (message->type == ES_MSG_DEVICE_CONNECTED && message->device.type == ES_DEVICE_FILE_SYSTEM) {
|
||||||
DriveAdd(message->registerFileSystem.mountPoint->prefix, message->registerFileSystem.mountPoint->prefixBytes);
|
DriveAdd(message->device.handle, message->device.id);
|
||||||
} else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) {
|
} else if (message->type == ES_MSG_DEVICE_DISCONNECTED && message->device.type == ES_DEVICE_FILE_SYSTEM) {
|
||||||
DriveRemove(message->unregisterFileSystem.mountPoint->prefix, message->unregisterFileSystem.mountPoint->prefixBytes);
|
DriveRemove(message->device.id);
|
||||||
} else if (message->type == ES_MSG_FILE_MANAGER_FILE_MODIFIED) {
|
} else if (message->type == ES_MSG_FILE_MANAGER_FILE_MODIFIED) {
|
||||||
char *_path = (char *) EsHeapAllocate(message->user.context2.u, false);
|
char *_path = (char *) EsHeapAllocate(message->user.context2.u, false);
|
||||||
EsConstantBufferRead(message->user.context1.u, _path);
|
EsConstantBufferRead(message->user.context1.u, _path);
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// It is released under the terms of the MIT license -- see LICENSE.md.
|
// It is released under the terms of the MIT license -- see LICENSE.md.
|
||||||
// Written by: nakst.
|
// Written by: nakst.
|
||||||
|
|
||||||
|
// TODO Update to use the new mount point APIs.
|
||||||
|
|
||||||
#define ES_PRIVATE_APIS
|
#define ES_PRIVATE_APIS
|
||||||
#define INSTALLER
|
#define INSTALLER
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ permission_all_devices=1
|
||||||
permission_shutdown=1
|
permission_shutdown=1
|
||||||
hidden=1
|
hidden=1
|
||||||
is_installer=1
|
is_installer=1
|
||||||
|
disabled=1
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
source=apps/installer.cpp
|
source=apps/installer.cpp
|
||||||
|
|
208
desktop/api.cpp
208
desktop/api.cpp
|
@ -87,11 +87,6 @@ struct ThreadLocalStorage {
|
||||||
uint64_t timerAdjustTicks;
|
uint64_t timerAdjustTicks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MountPoint : EsMountPoint {
|
|
||||||
EsVolumeInformation information;
|
|
||||||
bool removing;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Timer {
|
struct Timer {
|
||||||
EsTimer id;
|
EsTimer id;
|
||||||
double afterMs;
|
double afterMs;
|
||||||
|
@ -193,7 +188,8 @@ struct {
|
||||||
|
|
||||||
EsHandle desktopRequestPipe, desktopResponsePipe;
|
EsHandle desktopRequestPipe, desktopResponsePipe;
|
||||||
|
|
||||||
Array<MountPoint> mountPoints;
|
EsMutex mountPointsMutex;
|
||||||
|
Array<EsMountPoint> mountPoints2;
|
||||||
Array<EsMessageDevice> connectedDevices;
|
Array<EsMessageDevice> connectedDevices;
|
||||||
bool foundBootFileSystem;
|
bool foundBootFileSystem;
|
||||||
EsProcessStartupInformation *startupInformation;
|
EsProcessStartupInformation *startupInformation;
|
||||||
|
@ -245,7 +241,8 @@ EsSystemConfigurationGroup *SystemConfigurationGetGroup(const char *section, ptr
|
||||||
uint8_t *ApplicationStartupInformationToBuffer(const _EsApplicationStartupInformation *information, size_t *dataBytes = nullptr);
|
uint8_t *ApplicationStartupInformationToBuffer(const _EsApplicationStartupInformation *information, size_t *dataBytes = nullptr);
|
||||||
char *SystemConfigurationGroupReadString(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, size_t *valueBytes = 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);
|
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);
|
EsWindow *WindowFromWindowID(EsObjectID id);
|
||||||
void POSIXCleanup();
|
void POSIXCleanup();
|
||||||
extern "C" void _init();
|
extern "C" void _init();
|
||||||
|
@ -276,49 +273,101 @@ uintptr_t APISyscallCheckForCrash(uintptr_t argument0, uintptr_t argument1, uint
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MountPoint *NodeAddMountPoint(const char *prefix, size_t prefixBytes, EsHandle base, bool queryInformation) {
|
EsError MountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base, bool addedByApplication) {
|
||||||
MountPoint mountPoint = {};
|
EsMutexAcquire(&api.mountPointsMutex);
|
||||||
EsAssert(prefixBytes < sizeof(mountPoint.prefix));
|
bool duplicate = NodeFindMountPoint(prefix, prefixBytes, nullptr, true);
|
||||||
EsMemoryCopy(mountPoint.prefix, prefix, prefixBytes);
|
EsError error = ES_SUCCESS;
|
||||||
mountPoint.base = base;
|
|
||||||
mountPoint.prefixBytes = prefixBytes;
|
|
||||||
|
|
||||||
if (queryInformation) {
|
if (duplicate) {
|
||||||
EsSyscall(ES_SYSCALL_VOLUME_GET_INFORMATION, base, (uintptr_t) &mountPoint.information, 0, 0);
|
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);
|
if (ES_CHECK_ERROR(mountPoint.base)) {
|
||||||
}
|
error = ES_ERROR_INSUFFICIENT_RESOURCES;
|
||||||
|
} else {
|
||||||
MountPoint *NodeFindMountPoint(const char *prefix, size_t prefixBytes) {
|
if (!api.mountPoints2.Add(mountPoint)) {
|
||||||
for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
|
EsHandleClose(mountPoint.base);
|
||||||
MountPoint *mountPoint = &api.mountPoints[i];
|
error = ES_ERROR_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
if (prefixBytes >= mountPoint->prefixBytes
|
|
||||||
&& 0 == EsMemoryCompare(prefix, mountPoint->prefix, mountPoint->prefixBytes)
|
|
||||||
&& !mountPoint->removing) {
|
|
||||||
return mountPoint;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, EsVolumeInformation *information) {
|
||||||
MountPoint *mountPoint = NodeFindMountPoint(prefix, prefixBytes);
|
EsMutexAcquire(&api.mountPointsMutex);
|
||||||
if (!mountPoint) return false;
|
EsMountPoint mountPoint;
|
||||||
EsSyscall(ES_SYSCALL_VOLUME_GET_INFORMATION, mountPoint->base, (uintptr_t) &mountPoint->information, 0, 0);
|
bool found = NodeFindMountPoint(prefix, prefixBytes, &mountPoint, true);
|
||||||
EsMemoryCopy(information, &mountPoint->information, sizeof(EsVolumeInformation));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EsMountPointEnumerate(EsMountPointEnumerationCallback callback, EsGeneric context) {
|
if (found) {
|
||||||
EsMessageMutexCheck();
|
_EsNodeInformation node;
|
||||||
|
node.handle = mountPoint.base;
|
||||||
for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
|
EsError error = EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) "/", 1, ES_NODE_DIRECTORY, (uintptr_t) &node);
|
||||||
MountPoint *mountPoint = &api.mountPoints[i];
|
|
||||||
callback(mountPoint->prefix, mountPoint->prefixBytes, context);
|
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) {
|
||||||
|
@ -330,17 +379,24 @@ void EsDeviceEnumerate(EsDeviceEnumerationCallback callback, EsGeneric context)
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node) {
|
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) {
|
EsMountPoint mountPoint;
|
||||||
return ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME;
|
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;
|
EsMutexRelease(&api.mountPointsMutex);
|
||||||
path += mountPoint->prefixBytes;
|
return error;
|
||||||
pathBytes -= mountPoint->prefixBytes;
|
|
||||||
|
|
||||||
return EsSyscall(ES_SYSCALL_NODE_OPEN, (uintptr_t) path, pathBytes, flags, (uintptr_t) node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EsSystemConfigurationItem *SystemConfigurationGetItem(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, bool createIfNeeded) {
|
EsSystemConfigurationItem *SystemConfigurationGetItem(EsSystemConfigurationGroup *group, const char *key, ptrdiff_t keyBytes, bool createIfNeeded) {
|
||||||
|
@ -1069,7 +1125,7 @@ EsMessage *EsMessageReceive() {
|
||||||
FreeUnusedStyles(true /* include permanent styles */);
|
FreeUnusedStyles(true /* include permanent styles */);
|
||||||
theming.loadedStyles.Free();
|
theming.loadedStyles.Free();
|
||||||
SystemConfigurationUnload();
|
SystemConfigurationUnload();
|
||||||
api.mountPoints.Free();
|
api.mountPoints2.Free();
|
||||||
api.postBox.Free();
|
api.postBox.Free();
|
||||||
api.timers.Free();
|
api.timers.Free();
|
||||||
gui.animatingElements.Free();
|
gui.animatingElements.Free();
|
||||||
|
@ -1089,13 +1145,6 @@ EsMessage *EsMessageReceive() {
|
||||||
#endif
|
#endif
|
||||||
EsProcessTerminateCurrent();
|
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();
|
EsMessageMutexRelease();
|
||||||
|
@ -1291,49 +1340,6 @@ EsMessage *EsMessageReceive() {
|
||||||
|
|
||||||
return &message.message;
|
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) {
|
} else if (type == ES_MSG_DEVICE_CONNECTED) {
|
||||||
api.connectedDevices.Add(message.message.device);
|
api.connectedDevices.Add(message.message.device);
|
||||||
return &message.message;
|
return &message.message;
|
||||||
|
@ -1561,7 +1567,7 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) {
|
||||||
|
|
||||||
path = EsSystemConfigurationReadString(EsLiteral("paths"), EsLiteral("fonts"));
|
path = EsSystemConfigurationReadString(EsLiteral("paths"), EsLiteral("fonts"));
|
||||||
NodeOpen(path, EsCStringLength(path), ES_NODE_DIRECTORY, &node);
|
NodeOpen(path, EsCStringLength(path), ES_NODE_DIRECTORY, &node);
|
||||||
NodeAddMountPoint(EsLiteral("|Fonts:"), node.handle, false);
|
MountPointAdd(EsLiteral("|Fonts:"), node.handle, false);
|
||||||
EsHeapFree(path);
|
EsHeapFree(path);
|
||||||
|
|
||||||
SettingsLoadDefaults();
|
SettingsLoadDefaults();
|
||||||
|
@ -1586,7 +1592,7 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) {
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < header->initialMountPointCount; i++) {
|
for (uintptr_t i = 0; i < header->initialMountPointCount; i++) {
|
||||||
const EsMountPoint *mountPoint = (const EsMountPoint *) EsBufferRead(&buffer, sizeof(EsMountPoint));
|
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++) {
|
for (uintptr_t i = 0; i < header->initialDeviceCount; i++) {
|
||||||
|
|
|
@ -655,6 +655,10 @@ int CursorLocatorMessage(EsElement *element, EsMessage *message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int ProcessGlobalKeyboardShortcuts(EsElement *, EsMessage *message) {
|
int ProcessGlobalKeyboardShortcuts(EsElement *, EsMessage *message) {
|
||||||
|
if (!desktop.setupDesktopUIComplete) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (message->type == ES_MSG_KEY_DOWN) {
|
if (message->type == ES_MSG_KEY_DOWN) {
|
||||||
bool ctrlOnly = message->keyboard.modifiers == ES_MODIFIER_CTRL;
|
bool ctrlOnly = message->keyboard.modifiers == ES_MODIFIER_CTRL;
|
||||||
uint32_t scancode = ScancodeMapToLabel(message->keyboard.scancode);
|
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_PROCESS_OPEN;
|
||||||
arguments.permissions |= ES_PERMISSION_POSIX_SUBSYSTEM;
|
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:");
|
root.prefixBytes = EsStringFormat(root.prefix, sizeof(root.prefix), "|POSIX:");
|
||||||
initialMountPoints.Add(root);
|
initialMountPoints.Add(root);
|
||||||
|
|
||||||
|
@ -1879,26 +1884,20 @@ bool ApplicationInstanceStart(_EsApplicationStartupInformation *startupInformati
|
||||||
}
|
}
|
||||||
|
|
||||||
if (application->permissions & APPLICATION_PERMISSION_ALL_FILES) {
|
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;
|
arguments.permissions |= ES_PERMISSION_GET_VOLUME_INFORMATION;
|
||||||
} else {
|
}
|
||||||
MountPoint fonts = *NodeFindMountPoint(EsLiteral("|Fonts:"));
|
|
||||||
|
{
|
||||||
|
EsMountPoint fonts;
|
||||||
|
EsAssert(NodeFindMountPoint(EsLiteral("|Fonts:"), &fonts, false));
|
||||||
initialMountPoints.Add(fonts);
|
initialMountPoints.Add(fonts);
|
||||||
handleDuplicateList.Add(fonts.base);
|
handleDuplicateList.Add(fonts.base);
|
||||||
handleModeDuplicateList.Add(2 /* prevent write */);
|
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]);
|
initialDevices.Add(api.connectedDevices[i]);
|
||||||
handleDuplicateList.Add(api.connectedDevices[i].handle);
|
handleDuplicateList.Add(api.connectedDevices[i].handle);
|
||||||
handleModeDuplicateList.Add(0);
|
handleModeDuplicateList.Add(0);
|
||||||
|
@ -3153,24 +3152,18 @@ void DesktopSendMessage(EsMessage *message) {
|
||||||
EmbeddedWindowDestroyed(message->embeddedWindowDestroyedID);
|
EmbeddedWindowDestroyed(message->embeddedWindowDestroyedID);
|
||||||
} else if (message->type == ES_MSG_APPLICATION_CRASH) {
|
} else if (message->type == ES_MSG_APPLICATION_CRASH) {
|
||||||
ApplicationInstanceCrashed(message);
|
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) {
|
} else if (message->type == ES_MSG_DEVICE_CONNECTED) {
|
||||||
EsHandle handle = message->device.handle;
|
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++) {
|
for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) {
|
||||||
ApplicationProcess *process = desktop.allApplicationProcesses[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);
|
message->device.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, handle, process->handle, 0, 0);
|
||||||
EsMessagePostRemote(process->handle, message);
|
EsMessagePostRemote(process->handle, message);
|
||||||
}
|
}
|
||||||
|
@ -3193,26 +3186,22 @@ void DesktopSendMessage(EsMessage *message) {
|
||||||
} else {
|
} else {
|
||||||
// The screen resolution will be correctly queried in DesktopSetup.
|
// 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++) {
|
for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) {
|
||||||
ApplicationProcess *process = desktop.allApplicationProcesses[i];
|
ApplicationProcess *process = desktop.allApplicationProcesses[i];
|
||||||
|
if (!process->application) continue;
|
||||||
|
|
||||||
if (!process->application) {
|
if ((process->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES)
|
||||||
continue;
|
|| ((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) {
|
} else if (message->type == ES_MSG_KEY_DOWN) {
|
||||||
ProcessGlobalKeyboardShortcuts(nullptr, message);
|
ProcessGlobalKeyboardShortcuts(nullptr, message);
|
||||||
|
|
|
@ -337,6 +337,7 @@ define ES_ERROR_CANCELLED (-73)
|
||||||
define ES_ERROR_BLOCK_ACCESS_INVALID (-74)
|
define ES_ERROR_BLOCK_ACCESS_INVALID (-74)
|
||||||
define ES_ERROR_DEVICE_REMOVED (-75)
|
define ES_ERROR_DEVICE_REMOVED (-75)
|
||||||
define ES_ERROR_TOO_MANY_FILES_WITH_NAME (-76)
|
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_INVALID_HANDLE ((EsHandle) (0))
|
||||||
define ES_CURRENT_THREAD ((EsHandle) (0x10))
|
define ES_CURRENT_THREAD ((EsHandle) (0x10))
|
||||||
|
@ -1047,8 +1048,6 @@ enum EsMessageType {
|
||||||
ES_MSG_INSTANCE_CREATE = 0x6002
|
ES_MSG_INSTANCE_CREATE = 0x6002
|
||||||
ES_MSG_DEVICE_CONNECTED = 0x6003
|
ES_MSG_DEVICE_CONNECTED = 0x6003
|
||||||
ES_MSG_DEVICE_DISCONNECTED = 0x6004
|
ES_MSG_DEVICE_DISCONNECTED = 0x6004
|
||||||
ES_MSG_REGISTER_FILE_SYSTEM = 0x6005
|
|
||||||
ES_MSG_UNREGISTER_FILE_SYSTEM = 0x6006
|
|
||||||
|
|
||||||
// Instance messages:
|
// Instance messages:
|
||||||
ES_MSG_INSTANCE_OPEN = 0x6800
|
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_BLOCK_DETECT_FS = 0x1004 // Detect file systems. All existing file systems must have been unmounted.
|
||||||
|
|
||||||
ES_DEVICE_CONTROL_CLOCK_READ = 0x2001
|
ES_DEVICE_CONTROL_CLOCK_READ = 0x2001
|
||||||
|
|
||||||
|
ES_DEVICE_CONTROL_FS_IS_BOOT = 0x3001
|
||||||
}
|
}
|
||||||
|
|
||||||
function_pointer int EsElementCallback(struct EsElement *element, struct EsMessage *message);
|
function_pointer int EsElementCallback(struct EsElement *element, struct EsMessage *message);
|
||||||
|
@ -1297,12 +1298,6 @@ struct EsSnapshotProcesses {
|
||||||
EsSnapshotProcessesItem processes[];
|
EsSnapshotProcessesItem processes[];
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EsMountPoint {
|
|
||||||
char prefix[16];
|
|
||||||
size_t prefixBytes;
|
|
||||||
EsHandle base;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EsProcessCreateData {
|
struct EsProcessCreateData {
|
||||||
EsHandle systemData;
|
EsHandle systemData;
|
||||||
EsHandle subsystemData;
|
EsHandle subsystemData;
|
||||||
|
@ -1799,20 +1794,9 @@ struct EsMessageTabOperation {
|
||||||
EsError error;
|
EsError error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EsMessageRegisterFileSystem {
|
|
||||||
EsHandle rootDirectory;
|
|
||||||
bool isBootFileSystem;
|
|
||||||
EsMountPoint *mountPoint;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EsMessageUnregisterFileSystem {
|
|
||||||
EsObjectID id;
|
|
||||||
EsMountPoint *mountPoint;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EsMessageDevice {
|
struct EsMessageDevice {
|
||||||
EsObjectID id;
|
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;
|
EsDeviceType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1888,8 +1872,6 @@ struct EsMessage {
|
||||||
EsMessageEyedrop eyedrop;
|
EsMessageEyedrop eyedrop;
|
||||||
EsMessageCreateInstance createInstance;
|
EsMessageCreateInstance createInstance;
|
||||||
EsMessageTabOperation tabOperation;
|
EsMessageTabOperation tabOperation;
|
||||||
EsMessageRegisterFileSystem registerFileSystem;
|
|
||||||
EsMessageUnregisterFileSystem unregisterFileSystem;
|
|
||||||
EsMessageDevice device;
|
EsMessageDevice device;
|
||||||
EsObjectID embeddedWindowDestroyedID;
|
EsObjectID embeddedWindowDestroyedID;
|
||||||
};
|
};
|
||||||
|
@ -1972,6 +1954,13 @@ struct EsListViewEnumString {
|
||||||
STRING string;
|
STRING string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private struct EsMountPoint {
|
||||||
|
char prefix[16];
|
||||||
|
size_t prefixBytes;
|
||||||
|
uintptr_t base;
|
||||||
|
bool addedByApplication;
|
||||||
|
};
|
||||||
|
|
||||||
// Function pointer types.
|
// Function pointer types.
|
||||||
|
|
||||||
function_pointer void EsThreadEntryCallback(EsGeneric argument);
|
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 EsTimerCallback(EsGeneric argument);
|
||||||
function_pointer void EsMenuCallback(EsMenu *menu, EsGeneric context);
|
function_pointer void EsMenuCallback(EsMenu *menu, EsGeneric context);
|
||||||
function_pointer void EsUndoCallback(const void *item, EsUndoManager *manager, EsMessage *message);
|
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 EsDeviceEnumerationCallback(EsMessageDevice device, EsGeneric context);
|
||||||
function_pointer void EsListViewEnumerateVisibleItemsCallback(EsListView *view, EsElement *item, uint32_t group, EsListViewIndex index);
|
function_pointer void EsListViewEnumerateVisibleItemsCallback(EsListView *view, EsElement *item, uint32_t group, EsListViewIndex index);
|
||||||
function_pointer void EsFontEnumerationCallback(const EsFontInformation *information, EsGeneric context);
|
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.
|
// 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 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 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 _EsPathAnnouncePathMoved(STRING oldPath, STRING newPath); // Set oldPathBytes = 0 to make the file manager refresh the path.
|
||||||
function void _EsOpenDocumentEnumerate(EsBuffer *outputBuffer);
|
function void _EsOpenDocumentEnumerate(EsBuffer *outputBuffer);
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
extern "C" void *ProcessorTLSRead(uintptr_t offset);
|
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;
|
||||||
EsMountPoint *NodeFindMountPoint(const char *prefix, size_t prefixBytes);
|
bool NodeFindMountPoint(const char *prefix, size_t prefixBytes, EsMountPoint *result, bool mutexTaken);
|
||||||
EsProcessStartupInformation *ProcessGetStartupInformation();
|
EsProcessStartupInformation *ProcessGetStartupInformation();
|
||||||
|
|
||||||
#define _POSIX_SOURCE
|
#define _POSIX_SOURCE
|
||||||
|
@ -50,6 +50,7 @@ struct ChildProcess {
|
||||||
char *workingDirectory;
|
char *workingDirectory;
|
||||||
Array<ChildProcess> childProcesses;
|
Array<ChildProcess> childProcesses;
|
||||||
Array<void *> _argv;
|
Array<void *> _argv;
|
||||||
|
EsHandle posixMountPointBase;
|
||||||
|
|
||||||
#ifdef ES_ARCH_X86_64
|
#ifdef ES_ARCH_X86_64
|
||||||
Elf64_Phdr *tlsHeader;
|
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);
|
// 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;
|
long returnValue = 0;
|
||||||
_EsPOSIXSyscall syscall = { n, a1, a2, a3, a4, a5, a6 };
|
_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;
|
size_t pathBytes;
|
||||||
char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false);
|
char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false);
|
||||||
syscall.arguments[0] = (long) path;
|
syscall.arguments[0] = (long) path;
|
||||||
syscall.arguments[4] = (long) NodeFindMountPoint(EsLiteral("|POSIX:"))->base;
|
syscall.arguments[4] = (long) posixMountPointBase;
|
||||||
syscall.arguments[6] = (long) pathBytes;
|
syscall.arguments[6] = (long) pathBytes;
|
||||||
returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0);
|
returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0);
|
||||||
// EsPrint("SYS_open '%s' with handle %d\n", pathBytes, path, returnValue);
|
// 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: {
|
case SYS_unlink: {
|
||||||
_EsNodeInformation node;
|
_EsNodeInformation node;
|
||||||
node.handle = NodeFindMountPoint(EsLiteral("|POSIX:"))->base;
|
node.handle = posixMountPointBase;
|
||||||
size_t pathBytes;
|
size_t pathBytes;
|
||||||
char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false);
|
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);
|
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: {
|
case SYS_truncate: {
|
||||||
_EsNodeInformation node;
|
_EsNodeInformation node;
|
||||||
node.handle = NodeFindMountPoint(EsLiteral("|POSIX:"))->base;
|
node.handle = posixMountPointBase;
|
||||||
size_t pathBytes;
|
size_t pathBytes;
|
||||||
char *path = EsPOSIXConvertPath((const char *) a1, &pathBytes, false);
|
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);
|
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[1] = (long) pathBytes;
|
||||||
syscall.arguments[2] = (long) newEnvironment;
|
syscall.arguments[2] = (long) newEnvironment;
|
||||||
syscall.arguments[3] = (long) environmentSize;
|
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);
|
returnValue = EsSyscall(ES_SYSCALL_POSIX, (uintptr_t) &syscall, 0, 0, 0);
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -80,14 +80,17 @@ void KDeviceDestroy(KDevice *device) {
|
||||||
KMutexRelease(&deviceTreeMutex);
|
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);
|
KMutexAcquire(&deviceTreeMutex);
|
||||||
if (!device->handles) KernelPanic("KDeviceOpenHandle - Device %s has no handles.\n", device);
|
if (!device->handles) KernelPanic("KDeviceOpenHandle - Device %s has no handles.\n", device);
|
||||||
device->handles++;
|
device->handles++;
|
||||||
KMutexRelease(&deviceTreeMutex);
|
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);
|
KMutexAcquire(&deviceTreeMutex);
|
||||||
|
|
||||||
if (!device->handles) KernelPanic("KDeviceCloseHandle - Device %s has no handles.\n", device);
|
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);
|
KMutexAcquire(&deviceTreeMutex);
|
||||||
|
|
||||||
if (device->flags & K_DEVICE_VISIBLE_TO_USER) {
|
if (device->flags & K_DEVICE_VISIBLE_TO_USER) {
|
||||||
|
@ -143,14 +146,14 @@ void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type) {
|
||||||
|
|
||||||
KMutexRelease(&deviceTreeMutex);
|
KMutexRelease(&deviceTreeMutex);
|
||||||
|
|
||||||
KDeviceOpenHandle(device);
|
KDeviceOpenHandle(device, handleFlags);
|
||||||
|
|
||||||
_EsMessageWithObject m;
|
_EsMessageWithObject m;
|
||||||
EsMemoryZero(&m, sizeof(m));
|
EsMemoryZero(&m, sizeof(m));
|
||||||
m.message.type = ES_MSG_DEVICE_CONNECTED;
|
m.message.type = ES_MSG_DEVICE_CONNECTED;
|
||||||
m.message.device.id = device->objectID;
|
m.message.device.id = device->objectID;
|
||||||
m.message.device.type = type;
|
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 (m.message.device.handle) {
|
||||||
if (!DesktopSendMessage(&m)) {
|
if (!DesktopSendMessage(&m)) {
|
||||||
|
|
|
@ -1881,38 +1881,22 @@ void FSRegisterBootFileSystem(KFileSystem *fileSystem, EsUniqueIdentifier identi
|
||||||
FSRegisterFileSystem(fileSystem);
|
FSRegisterFileSystem(fileSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSFileSystemDeviceRemoved(KDevice *device) {
|
void FSTrackUserFileSystemHandle(KDevice *device, bool opened) {
|
||||||
KFileSystem *fileSystem = (KFileSystem *) device;
|
KFileSystem *fileSystem = (KFileSystem *) device;
|
||||||
_EsMessageWithObject m;
|
if (opened) FSNodeOpenHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT, FS_NODE_OPEN_HANDLE_STANDARD);
|
||||||
EsMemoryZero(&m, sizeof(m));
|
else FSNodeCloseHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT);
|
||||||
m.message.type = ES_MSG_UNREGISTER_FILE_SYSTEM;
|
|
||||||
m.message.unregisterFileSystem.id = fileSystem->objectID;
|
|
||||||
DesktopSendMessage(&m);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSRegisterFileSystem(KFileSystem *fileSystem) {
|
void FSRegisterFileSystem(KFileSystem *fileSystem) {
|
||||||
fileSystem->removed = FSFileSystemDeviceRemoved;
|
fileSystem->trackHandle = FSTrackUserFileSystemHandle;
|
||||||
|
|
||||||
MMObjectCacheRegister(&fileSystem->cachedDirectoryEntries, FSTrimCachedDirectoryEntry,
|
MMObjectCacheRegister(&fileSystem->cachedDirectoryEntries, FSTrimCachedDirectoryEntry,
|
||||||
sizeof(FSDirectoryEntry) + 16 /* approximate average name bytes */ + fileSystem->directoryEntryDataBytes);
|
sizeof(FSDirectoryEntry) + 16 /* approximate average name bytes */ + fileSystem->directoryEntryDataBytes);
|
||||||
MMObjectCacheRegister(&fileSystem->cachedNodes, FSTrimCachedNode,
|
MMObjectCacheRegister(&fileSystem->cachedNodes, FSTrimCachedNode,
|
||||||
sizeof(FSFile) + fileSystem->nodeDataBytes);
|
sizeof(FSFile) + fileSystem->nodeDataBytes);
|
||||||
fileSystem->rootDirectory->directoryEntry->directoryChildren = fileSystem->rootDirectoryInitialChildren;
|
fileSystem->rootDirectory->directoryEntry->directoryChildren = fileSystem->rootDirectoryInitialChildren;
|
||||||
FSNodeOpenHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT, fileSystem->isBootFileSystem ? FS_NODE_OPEN_HANDLE_STANDARD : FS_NODE_OPEN_HANDLE_FIRST);
|
FSNodeOpenHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT, fileSystem->isBootFileSystem ? FS_NODE_OPEN_HANDLE_STANDARD : FS_NODE_OPEN_HANDLE_FIRST);
|
||||||
|
KDeviceSendConnectedMessage(fileSystem, ES_DEVICE_FILE_SYSTEM, K_DEVICE_HANDLE_TRACKED);
|
||||||
_EsMessageWithObject m;
|
FSNodeCloseHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSRegisterBlockDevice(KBlockDevice *device) {
|
void FSRegisterBlockDevice(KBlockDevice *device) {
|
||||||
|
|
|
@ -495,10 +495,13 @@ struct KDevice {
|
||||||
EsObjectID objectID;
|
EsObjectID objectID;
|
||||||
|
|
||||||
// These callbacks are called with the deviceTreeMutex locked, and are all optional.
|
// 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 (*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 (*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 (*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 (*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 {
|
struct KDriver {
|
||||||
|
@ -524,11 +527,11 @@ void KDeviceAttachAll(KDevice *parentDevice, const char *cParentDriver);
|
||||||
bool KDeviceAttachByName(KDevice *parentDevice, const char *cName);
|
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 */);
|
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 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 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>
|
#include <bin/generated_code/kernel_config.h>
|
||||||
|
|
||||||
|
|
|
@ -190,7 +190,7 @@ bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags) {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case KERNEL_OBJECT_DEVICE: {
|
case KERNEL_OBJECT_DEVICE: {
|
||||||
KDeviceOpenHandle((KDevice *) object);
|
KDeviceOpenHandle((KDevice *) object, flags);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
@ -351,7 +351,7 @@ void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags) {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case KERNEL_OBJECT_DEVICE: {
|
case KERNEL_OBJECT_DEVICE: {
|
||||||
KDeviceCloseHandle((KDevice *) object);
|
KDeviceCloseHandle((KDevice *) object, flags);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
|
|
@ -651,18 +651,37 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_NODE_OPEN) {
|
||||||
_EsNodeInformation information;
|
_EsNodeInformation information;
|
||||||
SYSCALL_READ(&information, argument3, sizeof(_EsNodeInformation));
|
SYSCALL_READ(&information, argument3, sizeof(_EsNodeInformation));
|
||||||
|
|
||||||
SYSCALL_HANDLE_2(information.handle, KERNEL_OBJECT_NODE, _directory);
|
SYSCALL_HANDLE_2(information.handle, (KernelObjectType) (KERNEL_OBJECT_NODE | KERNEL_OBJECT_DEVICE), _directory);
|
||||||
KNode *directory = (KNode *) _directory.object;
|
|
||||||
|
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) {
|
if (directory->directoryEntry->type != ES_NODE_DIRECTORY) {
|
||||||
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true);
|
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);
|
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;
|
flags |= _ES_NODE_NO_WRITE_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1604,6 +1623,14 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_DEVICE_CONTROL) {
|
||||||
} else {
|
} else {
|
||||||
SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true);
|
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 {
|
} else {
|
||||||
SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true);
|
SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,8 +161,10 @@ EsStringFormatTemporary=159
|
||||||
EsStringFormatV=160
|
EsStringFormatV=160
|
||||||
EsStringFormatAppend=161
|
EsStringFormatAppend=161
|
||||||
EsStringFormatAppendV=162
|
EsStringFormatAppendV=162
|
||||||
|
EsMountPointAdd=163
|
||||||
EsSystemConfigurationReadFileTypes=164
|
EsSystemConfigurationReadFileTypes=164
|
||||||
EsImageLoad=165
|
EsImageLoad=165
|
||||||
|
EsMountPointRemove=166
|
||||||
EsCRTabs=168
|
EsCRTabs=168
|
||||||
EsCRTacosf=169
|
EsCRTacosf=169
|
||||||
EsCRTasinf=170
|
EsCRTasinf=170
|
||||||
|
@ -369,7 +371,6 @@ EsElementRepaintForScroll=372
|
||||||
EsMemoryFaultRange=373
|
EsMemoryFaultRange=373
|
||||||
EsDrawBitmapScaled=374
|
EsDrawBitmapScaled=374
|
||||||
EsRectangleCenter=375
|
EsRectangleCenter=375
|
||||||
EsMountPointEnumerate=376
|
|
||||||
EsMountPointGetVolumeInformation=377
|
EsMountPointGetVolumeInformation=377
|
||||||
EsListViewInvalidateAll=378
|
EsListViewInvalidateAll=378
|
||||||
EsListViewGetFocusedItem=379
|
EsListViewGetFocusedItem=379
|
||||||
|
|
Loading…
Reference in New Issue