mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-31 03:58:38 -05:00 
			
		
		
		
	sys: major change in device management: introduce FspDeviceGlobalLock and remove FSP_FSVOL_DEVICE_EXTENSION::DeleteResource; makes locking coarse-grained but more generic and safe
This commit is contained in:
		| @@ -320,10 +320,6 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) | |||||||
|         FsvolDeviceExtension->InitDoneFsvrt = 1; |         FsvolDeviceExtension->InitDoneFsvrt = 1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* initialize our delete lock */ |  | ||||||
|     ExInitializeResourceLite(&FsvolDeviceExtension->DeleteResource); |  | ||||||
|     FsvolDeviceExtension->InitDoneDelRsc = 1; |  | ||||||
|  |  | ||||||
|     /* create our Ioq */ |     /* create our Ioq */ | ||||||
|     IrpTimeout.QuadPart = FsvolDeviceExtension->VolumeParams.IrpTimeout * 10000ULL; |     IrpTimeout.QuadPart = FsvolDeviceExtension->VolumeParams.IrpTimeout * 10000ULL; | ||||||
|         /* convert millis to nanos */ |         /* convert millis to nanos */ | ||||||
| @@ -441,10 +437,6 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject) | |||||||
|         ExDeleteResourceLite(&FsvolDeviceExtension->FileRenameResource); |         ExDeleteResourceLite(&FsvolDeviceExtension->FileRenameResource); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* finalize our delete lock */ |  | ||||||
|     if (FsvolDeviceExtension->InitDoneDelRsc) |  | ||||||
|         ExDeleteResourceLite(&FsvolDeviceExtension->DeleteResource); |  | ||||||
|  |  | ||||||
|     /* is there a virtual disk? */ |     /* is there a virtual disk? */ | ||||||
|     if (FsvolDeviceExtension->InitDoneFsvrt) |     if (FsvolDeviceExtension->InitDoneFsvrt) | ||||||
|     { |     { | ||||||
| @@ -938,3 +930,5 @@ VOID FspDeviceDeleteAll(VOID) | |||||||
|  |  | ||||||
|     FspDeviceDeleteList(DeviceObjects, DeviceObjectCount); |     FspDeviceDeleteList(DeviceObjects, DeviceObjectCount); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | ERESOURCE FspDeviceGlobalResource; | ||||||
|   | |||||||
| @@ -36,6 +36,7 @@ NTSTATUS DriverEntry( | |||||||
|     FspDriverMultiVersionInitialize(); |     FspDriverMultiVersionInitialize(); | ||||||
|  |  | ||||||
|     FspDriverObject = DriverObject; |     FspDriverObject = DriverObject; | ||||||
|  |     ExInitializeResourceLite(&FspDeviceGlobalResource); | ||||||
|  |  | ||||||
|     /* create the file system control device objects */ |     /* create the file system control device objects */ | ||||||
|     UNICODE_STRING DeviceSddl; |     UNICODE_STRING DeviceSddl; | ||||||
| @@ -182,8 +183,9 @@ VOID FspUnload( | |||||||
|  |  | ||||||
|     FspFsctlDiskDeviceObject = 0; |     FspFsctlDiskDeviceObject = 0; | ||||||
|     FspFsctlNetDeviceObject = 0; |     FspFsctlNetDeviceObject = 0; | ||||||
|     FspDeviceDeleteAll(); |     //FspDeviceDeleteAll(); | ||||||
|  |  | ||||||
|  |     ExDeleteResourceLite(&FspDeviceGlobalResource); | ||||||
|     FspDriverObject = 0; |     FspDriverObject = 0; | ||||||
|  |  | ||||||
| #pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName") | #pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName") | ||||||
|   | |||||||
| @@ -742,14 +742,13 @@ typedef struct | |||||||
| typedef struct | typedef struct | ||||||
| { | { | ||||||
|     FSP_DEVICE_EXTENSION Base; |     FSP_DEVICE_EXTENSION Base; | ||||||
|     UINT32 InitDoneFsvrt:1, InitDoneDelRsc:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, |     UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, | ||||||
|         InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1; |         InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1; | ||||||
|     PDEVICE_OBJECT FsctlDeviceObject; |     PDEVICE_OBJECT FsctlDeviceObject; | ||||||
|     PDEVICE_OBJECT FsvrtDeviceObject; |     PDEVICE_OBJECT FsvrtDeviceObject; | ||||||
|     HANDLE MupHandle; |     HANDLE MupHandle; | ||||||
|     PVPB SwapVpb; |     PVPB SwapVpb; | ||||||
|     FSP_DELAYED_WORK_ITEM DeleteVolumeDelayedWorkItem; |     FSP_DELAYED_WORK_ITEM DeleteVolumeDelayedWorkItem; | ||||||
|     ERESOURCE DeleteResource; |  | ||||||
|     FSP_FSCTL_VOLUME_PARAMS VolumeParams; |     FSP_FSCTL_VOLUME_PARAMS VolumeParams; | ||||||
|     UNICODE_STRING VolumePrefix; |     UNICODE_STRING VolumePrefix; | ||||||
|     FSP_IOQ *Ioq; |     FSP_IOQ *Ioq; | ||||||
| @@ -825,6 +824,18 @@ NTSTATUS FspDeviceCopyList( | |||||||
| VOID FspDeviceDeleteList( | VOID FspDeviceDeleteList( | ||||||
|     PDEVICE_OBJECT *DeviceObjects, ULONG DeviceObjectCount); |     PDEVICE_OBJECT *DeviceObjects, ULONG DeviceObjectCount); | ||||||
| VOID FspDeviceDeleteAll(VOID); | VOID FspDeviceDeleteAll(VOID); | ||||||
|  | static inline | ||||||
|  | VOID FspDeviceGlobalLock(VOID) | ||||||
|  | { | ||||||
|  |     extern ERESOURCE FspDeviceGlobalResource; | ||||||
|  |     ExAcquireResourceExclusiveLite(&FspDeviceGlobalResource, TRUE); | ||||||
|  | } | ||||||
|  | static inline | ||||||
|  | VOID FspDeviceGlobalUnlock(VOID) | ||||||
|  | { | ||||||
|  |     extern ERESOURCE FspDeviceGlobalResource; | ||||||
|  |     ExReleaseResourceLite(&FspDeviceGlobalResource); | ||||||
|  | } | ||||||
| #define FspFsvolDeviceStoppedStatus(DeviceObject)\ | #define FspFsvolDeviceStoppedStatus(DeviceObject)\ | ||||||
|     STATUS_VOLUME_DISMOUNTED |     STATUS_VOLUME_DISMOUNTED | ||||||
|     //(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\ |     //(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\ | ||||||
| @@ -1021,6 +1032,7 @@ extern FAST_IO_DISPATCH FspFastIoDispatch; | |||||||
| extern CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks; | extern CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks; | ||||||
| extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; | extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; | ||||||
| extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[]; | extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[]; | ||||||
|  | extern ERESOURCE FspDeviceGlobalResource; | ||||||
| extern WCHAR FspFileDescDirectoryPatternMatchAll[]; | extern WCHAR FspFileDescDirectoryPatternMatchAll[]; | ||||||
| extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache; | extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,12 +8,18 @@ | |||||||
|  |  | ||||||
| NTSTATUS FspVolumeCreate( | NTSTATUS FspVolumeCreate( | ||||||
|     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||||
|  | static NTSTATUS FspVolumeCreateNoLock( | ||||||
|  |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||||
| static WORKER_THREAD_ROUTINE FspVolumeCreateRegisterMup; | static WORKER_THREAD_ROUTINE FspVolumeCreateRegisterMup; | ||||||
| VOID FspVolumeDelete( | VOID FspVolumeDelete( | ||||||
|     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||||
|  | static VOID FspVolumeDeleteNoLock( | ||||||
|  |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||||
| static WORKER_THREAD_ROUTINE FspVolumeDeleteDelayed; | static WORKER_THREAD_ROUTINE FspVolumeDeleteDelayed; | ||||||
| NTSTATUS FspVolumeMount( | NTSTATUS FspVolumeMount( | ||||||
|     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||||
|  | static NTSTATUS FspVolumeMountNoLock( | ||||||
|  |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||||
| NTSTATUS FspVolumeRedirQueryPathEx( | NTSTATUS FspVolumeRedirQueryPathEx( | ||||||
|     PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); |     PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||||
| NTSTATUS FspVolumeGetName( | NTSTATUS FspVolumeGetName( | ||||||
| @@ -27,14 +33,17 @@ NTSTATUS FspVolumeWork( | |||||||
|  |  | ||||||
| #ifdef ALLOC_PRAGMA | #ifdef ALLOC_PRAGMA | ||||||
| #pragma alloc_text(PAGE, FspVolumeCreate) | #pragma alloc_text(PAGE, FspVolumeCreate) | ||||||
|  | #pragma alloc_text(PAGE, FspVolumeCreateNoLock) | ||||||
| #pragma alloc_text(PAGE, FspVolumeCreateRegisterMup) | #pragma alloc_text(PAGE, FspVolumeCreateRegisterMup) | ||||||
| // ! #pragma alloc_text(PAGE, FspVolumeDelete) | // ! #pragma alloc_text(PAGE, FspVolumeDelete) | ||||||
|  | // ! #pragma alloc_text(PAGE, FspVolumeDeleteNoLock) | ||||||
| // ! #pragma alloc_text(PAGE, FspVolumeDeleteDelayed) | // ! #pragma alloc_text(PAGE, FspVolumeDeleteDelayed) | ||||||
| // ! #pragma alloc_text(PAGE, FspVolumeMount) | // ! #pragma alloc_text(PAGE, FspVolumeMount) | ||||||
|  | // ! #pragma alloc_text(PAGE, FspVolumeMountNoLock) | ||||||
|  | #pragma alloc_text(PAGE, FspVolumeRedirQueryPathEx) | ||||||
| #pragma alloc_text(PAGE, FspVolumeGetName) | #pragma alloc_text(PAGE, FspVolumeGetName) | ||||||
| #pragma alloc_text(PAGE, FspVolumeTransact) | #pragma alloc_text(PAGE, FspVolumeTransact) | ||||||
| #pragma alloc_text(PAGE, FspVolumeStop) | #pragma alloc_text(PAGE, FspVolumeStop) | ||||||
| #pragma alloc_text(PAGE, FspVolumeRedirQueryPathEx) |  | ||||||
| #pragma alloc_text(PAGE, FspVolumeWork) | #pragma alloc_text(PAGE, FspVolumeWork) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -50,6 +59,16 @@ typedef struct | |||||||
|  |  | ||||||
| NTSTATUS FspVolumeCreate( | NTSTATUS FspVolumeCreate( | ||||||
|     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||||
|  | { | ||||||
|  |     NTSTATUS Result; | ||||||
|  |     FspDeviceGlobalLock(); | ||||||
|  |     Result = FspVolumeCreateNoLock(FsctlDeviceObject, Irp, IrpSp); | ||||||
|  |     FspDeviceGlobalUnlock(); | ||||||
|  |     return Result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static NTSTATUS FspVolumeCreateNoLock( | ||||||
|  |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||||
| { | { | ||||||
|     PAGED_CODE(); |     PAGED_CODE(); | ||||||
|  |  | ||||||
| @@ -239,6 +258,14 @@ static VOID FspVolumeCreateRegisterMup(PVOID Context) | |||||||
|  |  | ||||||
| VOID FspVolumeDelete( | VOID FspVolumeDelete( | ||||||
|     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||||
|  | { | ||||||
|  |     FspDeviceGlobalLock(); | ||||||
|  |     FspVolumeDeleteNoLock(FsctlDeviceObject, Irp, IrpSp); | ||||||
|  |     FspDeviceGlobalUnlock(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static VOID FspVolumeDeleteNoLock( | ||||||
|  |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||||
| { | { | ||||||
|     // !PAGED_CODE(); |     // !PAGED_CODE(); | ||||||
|  |  | ||||||
| @@ -249,9 +276,6 @@ VOID FspVolumeDelete( | |||||||
|     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); |     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); | ||||||
|     IrpSp->FileObject->FsContext2 = 0; |     IrpSp->FileObject->FsContext2 = 0; | ||||||
|  |  | ||||||
|     /* acquire the volume device DeleteResource */ |  | ||||||
|     ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE); |  | ||||||
|  |  | ||||||
|     /* stop the I/O queue */ |     /* stop the I/O queue */ | ||||||
|     FspIoqStop(FsvolDeviceExtension->Ioq); |     FspIoqStop(FsvolDeviceExtension->Ioq); | ||||||
|  |  | ||||||
| @@ -319,9 +343,6 @@ VOID FspVolumeDelete( | |||||||
|         FsvolDeviceExtension->MupHandle = 0; |         FsvolDeviceExtension->MupHandle = 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* release the volume device DeleteResource */ |  | ||||||
|     ExReleaseResourceLite(&FsvolDeviceExtension->DeleteResource); |  | ||||||
|  |  | ||||||
|     /* release the volume device object */ |     /* release the volume device object */ | ||||||
|     FspDeviceDereference(FsvolDeviceObject); |     FspDeviceDereference(FsvolDeviceObject); | ||||||
| } | } | ||||||
| @@ -344,9 +365,11 @@ static VOID FspVolumeDeleteDelayed(PVOID Context) | |||||||
|     IoReleaseVpbSpinLock(Irql); |     IoReleaseVpbSpinLock(Irql); | ||||||
|     if (DeleteVpb) |     if (DeleteVpb) | ||||||
|     { |     { | ||||||
|  |         FspDeviceGlobalLock(); | ||||||
|         FspFreeExternal(FsvolDeviceExtension->SwapVpb); |         FspFreeExternal(FsvolDeviceExtension->SwapVpb); | ||||||
|         FsvolDeviceExtension->SwapVpb = 0; |         FsvolDeviceExtension->SwapVpb = 0; | ||||||
|         FspDeviceDereference(FsvolDeviceObject); |         FspDeviceDereference(FsvolDeviceObject); | ||||||
|  |         FspDeviceGlobalUnlock(); | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
| @@ -357,6 +380,16 @@ static VOID FspVolumeDeleteDelayed(PVOID Context) | |||||||
|  |  | ||||||
| NTSTATUS FspVolumeMount( | NTSTATUS FspVolumeMount( | ||||||
|     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||||
|  | { | ||||||
|  |     NTSTATUS Result; | ||||||
|  |     FspDeviceGlobalLock(); | ||||||
|  |     Result = FspVolumeMountNoLock(FsctlDeviceObject, Irp, IrpSp); | ||||||
|  |     FspDeviceGlobalUnlock(); | ||||||
|  |     return Result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static NTSTATUS FspVolumeMountNoLock( | ||||||
|  |     PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||||
| { | { | ||||||
|     // !PAGED_CODE(); |     // !PAGED_CODE(); | ||||||
|  |  | ||||||
| @@ -386,14 +419,12 @@ NTSTATUS FspVolumeMount( | |||||||
|                     FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); |                     FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); | ||||||
|                     if (FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject) |                     if (FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject) | ||||||
|                     { |                     { | ||||||
|                         ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE); |  | ||||||
|                         if (!FspIoqStopped(FsvolDeviceExtension->Ioq)) |                         if (!FspIoqStopped(FsvolDeviceExtension->Ioq)) | ||||||
|                         { |                         { | ||||||
|                             Result = STATUS_SUCCESS; |                             Result = STATUS_SUCCESS; | ||||||
|                             /* break out of the loop without FspDeviceDereference or DeleteResource release! */ |                             /* break out of the loop without FspDeviceDereference */ | ||||||
|                             break; |                             break; | ||||||
|                         } |                         } | ||||||
|                         ExReleaseResourceLite(&FsvolDeviceExtension->DeleteResource); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 FspDeviceDereference(DeviceObjects[i]); |                 FspDeviceDereference(DeviceObjects[i]); | ||||||
| @@ -405,10 +436,10 @@ NTSTATUS FspVolumeMount( | |||||||
|  |  | ||||||
|     /* |     /* | ||||||
|      * At this point the volume device object we are going to use in the VPB |      * At this point the volume device object we are going to use in the VPB | ||||||
|      * has been FspDeviceReference'ed and the volume DeleteResource has been acquired. |      * has been FspDeviceReference'd. | ||||||
|  |      * | ||||||
|      * We will increment the VPB's ReferenceCount so that we can do a delayed delete |      * We will increment the VPB's ReferenceCount so that we can do a delayed delete | ||||||
|      * of the volume device later on. Once done with the VPB we can release the |      * of the volume device later on. | ||||||
|      * DeleteResource. [The volume device remains FspDeviceReference'ed!] |  | ||||||
|      */ |      */ | ||||||
|     ASSERT(0 != FsvolDeviceObject && 0 != FsvolDeviceExtension); |     ASSERT(0 != FsvolDeviceObject && 0 != FsvolDeviceExtension); | ||||||
|     IoAcquireVpbSpinLock(&Irql); |     IoAcquireVpbSpinLock(&Irql); | ||||||
| @@ -417,9 +448,6 @@ NTSTATUS FspVolumeMount( | |||||||
|     Vpb->SerialNumber = FsvolDeviceExtension->VolumeParams.VolumeSerialNumber; |     Vpb->SerialNumber = FsvolDeviceExtension->VolumeParams.VolumeSerialNumber; | ||||||
|     IoReleaseVpbSpinLock(Irql); |     IoReleaseVpbSpinLock(Irql); | ||||||
|  |  | ||||||
|     /* done with mounting; release the DeleteResource */ |  | ||||||
|     ExReleaseResourceLite(&FsvolDeviceExtension->DeleteResource); |  | ||||||
|  |  | ||||||
|     Irp->IoStatus.Information = 0; |     Irp->IoStatus.Information = 0; | ||||||
|     return STATUS_SUCCESS; |     return STATUS_SUCCESS; | ||||||
| } | } | ||||||
| @@ -449,9 +477,6 @@ NTSTATUS FspVolumeRedirQueryPathEx( | |||||||
|     NTSTATUS Result; |     NTSTATUS Result; | ||||||
|     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); |     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); | ||||||
|  |  | ||||||
|     /* acquire our DeleteResource */ |  | ||||||
|     ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE); |  | ||||||
|  |  | ||||||
|     Result = STATUS_BAD_NETWORK_PATH; |     Result = STATUS_BAD_NETWORK_PATH; | ||||||
|     if (!FspIoqStopped(FsvolDeviceExtension->Ioq)) |     if (!FspIoqStopped(FsvolDeviceExtension->Ioq)) | ||||||
|     { |     { | ||||||
| @@ -469,9 +494,6 @@ NTSTATUS FspVolumeRedirQueryPathEx( | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* release the DeleteResource */ |  | ||||||
|     ExReleaseResourceLite(&FsvolDeviceExtension->DeleteResource); |  | ||||||
|  |  | ||||||
|     return Result; |     return Result; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user