/* * INTERNAL.H * * Internal header for RSM Service * * Author: ErvinP * * (c) 2001 Microsoft Corporation * */ typedef struct _SESSION SESSION; typedef struct _WORKITEM WORKITEM; typedef struct _WORKGROUP WORKGROUP; typedef struct _LIBRARY LIBRARY; typedef struct _TRANSPORT TRANSPORT; typedef struct _PICKER PICKER; typedef struct _SLOT SLOT; typedef struct _DRIVE DRIVE; typedef struct _MEDIA_POOL MEDIA_POOL; typedef struct _PHYSICAL_MEDIA PHYSICAL_MEDIA; typedef struct _MEDIA_PARTITION MEDIA_PARTITION; typedef struct _OPERATOR_REQUEST OPERATOR_REQUEST; typedef struct _MEDIA_TYPE_OBJECT MEDIA_TYPE_OBJECT; typedef struct _OBJECT_HEADER OBJECT_HEADER; /* * RSM Object Types * * The media hierarchy is as follows: * ------------------------------ * * Library * Media Pool * Media Sub-Pool - a subset (child pool) of a media pool * ... * * Physical Media * - a connected set of partitions that have to move together * e.g. a cartridge or both sides of a disk * * Media Partition * - e.g. a side of a disk or catridge tape * * * Other library elements: * -------------------- * * Drives - for reading/writing data on media * * Slots - for passively storing media * * Changers - for moving media between and amongst slots and drives. * A changer consists of a moving transport with * one or more pickers. * * * Logical media ID - a persistent GUID which identifies a media partition. * * Media type object - represents a recognized media type * */ enum objectType { OBJECTTYPE_NONE = 0, OBJECTTYPE_LIBRARY, OBJECTTYPE_MEDIAPOOL, OBJECTTYPE_PHYSICALMEDIA, OBJECTTYPE_MEDIAPARTITION, OBJECTTYPE_DRIVE, OBJECTTYPE_SLOT, OBJECTTYPE_TRANSPORT, OBJECTTYPE_PICKER, OBJECTTYPE_MEDIATYPEOBJECT, // OBJECTTYPE_OPERATORREQUEST, // BUGBUG - keep in session queue }; /* * This is a common header for all RSM objects that have GUIDs. * It is used to sort guid-identified objects in our hash table. */ struct _OBJECT_HEADER { LIST_ENTRY hashListEntry; enum objectType objType; NTMS_GUID guid; ULONG refCount; BOOL isDeleted; }; enum libraryTypes { LIBTYPE_NONE = 0, LIBTYPE_UNKNOWN, LIBTYPE_STANDALONE, LIBTYPE_AUTOMATED, }; enum libraryStates { LIBSTATE_NONE = 0, LIBSTATE_INITIALIZING, LIBSTATE_ONLINE, LIBSTATE_OFFLINE, LIBSTATE_ERROR, }; struct _LIBRARY { OBJECT_HEADER objHeader; enum libraryStates state; enum libraryTypes type; LIST_ENTRY allLibrariesListEntry; // entry in g_allLibrariesList ULONG numMediaPools; LIST_ENTRY mediaPoolsList; ULONG numDrives; DRIVE *drives; ULONG numSlots; SLOT *slots; /* * One (and only one) slot may be designated as a cleaner * slot. That slot may receive a cleaner cartridge (via InjectNtmsCleaner). * A cleaner cartridge has a limited number of cleans that it is good for. */ #define NO_SLOT_INDEX (ULONG)(-1) ULONG cleanerSlotIndex; // index of cleaner slot or -1. ULONG numCleansLeftInCartridge; ULONG numTransports; TRANSPORT *transports; ULONG numTotalWorkItems; LIST_ENTRY freeWorkItemsList; LIST_ENTRY pendingWorkItemsList; LIST_ENTRY completeWorkItemsList; HANDLE somethingToDoEvent; /* * There is one thread per library. This is its handle. */ HANDLE hThread; CRITICAL_SECTION lock; }; enum mediaPoolTypes { MEDIAPOOLTYPE_NONE = 0, /* * These are the 3 standard pool types. */ MEDIAPOOLTYPE_FREE, MEDIAPOOLTYPE_IMPORT, MEDIAPOOLTYPE_UNRECOGNIZED, MEDIAPOOLTYPE_OTHER, }; struct _MEDIA_POOL { OBJECT_HEADER objHeader; /* * Entry in library's mediaPoolsList or * parent pool's childPoolsList. */ LIST_ENTRY mediaPoolsListEntry; LIBRARY *owningLibrary; /* * A media pool has a (default?) media type. */ MEDIA_TYPE_OBJECT *mediaTypeObj; /* * Media pools can be divided heirarchically into sub-pools. * If a pool is top-level, its parentPool pointer is NULL. */ MEDIA_POOL *parentPool; ULONG numChildPools; LIST_ENTRY childPoolsList; ULONG numPhysMedia; LIST_ENTRY physMediaList; HANDLE newMediaEvent; WCHAR name[NTMS_OBJECTNAME_LENGTH]; CRITICAL_SECTION lock; }; // BUGBUG - should this be in physical media or mediaTypeObj ? enum physicalMediaTypes { PHYSICALMEDIATYPE_NONE = 0, PHYSICALMEDIATYPE_SINGLEPARTITION, // e.g. 1 disk,tape PHYSICALMEDIATYPE_CARTRIDGE, }; enum physicalMediaStates { PHYSICALMEDIASTATE_NONE = 0, PHYSICALMEDIASTATE_INITIALIZING, PHYSICALMEDIASTATE_AVAILABLE, // i.e. in a slot PHYSICALMEDIASTATE_INUSE, // i.e. in a drive PHYSICALMEDIASTATE_RESERVED, }; struct _PHYSICAL_MEDIA { OBJECT_HEADER objHeader; LIST_ENTRY physMediaListEntry; // entry in pool partition's physMediaList enum physicalMediaStates state; /* * Pointer to application-defined media type object. */ MEDIA_TYPE_OBJECT *mediaTypeObj; MEDIA_POOL *owningMediaPool; SLOT *currentSlot; DRIVE *currentDrive; ULONG numPartitions; MEDIA_PARTITION *partitions; /* * The owning session of a physicalMedia also holds * the exclusive right to allocate partitions on it. */ SESSION *owningSession; ULONG numPartitionsOwnedBySession; HANDLE mediaFreeEvent; CRITICAL_SECTION lock; }; enum mediaPartitionTypes { MEDIAPARTITIONTYPE_NONE = 0, /* * Major types */ MEDIAPARTITIONTYPE_TAPE, MEDIAPARTITIONTYPE_DISK, /* * Subtypes */ // BUGBUG FINISH }; enum mediaPartitionStates { MEDIAPARTITIONSTATE_NONE = 0, MEDIAPARTITIONSTATE_AVAILABLE, MEDIAPARTITIONSTATE_ALLOCATED, MEDIAPARTITIONSTATE_MOUNTED, MEDIAPARTITIONSTATE_INUSE, MEDIAPARTITIONSTATE_DECOMMISSIONED, }; struct _MEDIA_PARTITION { OBJECT_HEADER objHeader; enum mediaPartitionTypes type; enum mediaPartitionTypes subType; enum mediaPartitionStates state; /* * When a media partition is 'complete', * it is no longer writeable. */ BOOLEAN isComplete; /* * Can the owning physical medium be moved * into a new media pool ? */ BOOLEAN allowImport; PHYSICAL_MEDIA *owningPhysicalMedia; /* * The logical media id is the persistent identifier * of a media partition that apps use to find it. */ GUID logicalMediaGuid; SESSION *owningSession; }; enum driveStates { DRIVESTATE_NONE = 0, DRIVESTATE_INITIALIZING, DRIVESTATE_AVAILABLE, DRIVESTATE_INUSE, DRIVESTATE_RESERVED, }; struct _DRIVE { OBJECT_HEADER objHeader; enum driveStates state; ULONG driveIndex; // index into library's drives array PHYSICAL_MEDIA *insertedMedia; WCHAR path[MAX_PATH+1]; LIBRARY *lib; }; enum slotStates { SLOTSTATE_NONE = 0, SLOTSTATE_EMPTY, SLOTSTATE_OCCUPIED, }; struct _SLOT { OBJECT_HEADER objHeader; enum slotStates state; UINT slotIndex; // index into library's slots array PHYSICAL_MEDIA *insertedMedia; /* * Is this the unique slot designated to hold the * library's cleaner cartridge ? */ BOOLEAN isCleanerSlot; GUID slotId; LIBRARY *lib; }; enum transportStates { TRANSPORTSTATE_NONE = 0, TRANSPORTSTATE_AVAILABLE, TRANSPORTSTATE_INUSE, }; struct _TRANSPORT { OBJECT_HEADER objHeader; enum transportStates state; ULONG transportIndex; // index into library's transports array ULONG numPickers; PICKER *pickers; LIBRARY *lib; }; struct _PICKER { OBJECT_HEADER objHeader; TRANSPORT *owningTransport; }; struct _SESSION { #define SESSION_SIG 'SmsR' ULONG sig; LIST_ENTRY allSessionsListEntry; // entry in g_allSessionsList LIST_ENTRY operatorRequestList; CRITICAL_SECTION lock; WCHAR serverName[NTMS_COMPUTERNAME_LENGTH]; WCHAR applicationName[NTMS_APPLICATIONNAME_LENGTH]; WCHAR clientName[NTMS_COMPUTERNAME_LENGTH]; WCHAR userName[NTMS_USERNAME_LENGTH]; }; struct _MEDIA_TYPE_OBJECT { OBJECT_HEADER objHeader; LIBRARY *lib; /* * The number of physical media pointing to this type * as their media type. */ ULONG numPhysMediaReferences; // BUGBUG FINISH - media type characteristics CRITICAL_SECTION lock; }; enum workItemStates { WORKITEMSTATE_NONE, /* * WorkItem is in one of the library queues: * free, pending, or complete. */ WORKITEMSTATE_FREE, WORKITEMSTATE_PENDING, WORKITEMSTATE_COMPLETE, /* * WorkItem is not in any library queue. * It is in transit or being staged in a workGroup. */ WORKITEMSTATE_STAGING, }; struct _WORKITEM { enum workItemStates state; LIST_ENTRY libListEntry; // entry in one of a libraries workItem lists LIST_ENTRY workGroupListEntry; // entry in work group workItemList LIBRARY *owningLib; /* * The current work group with which this * work item is associated. */ WORKGROUP *workGroup; // BUGBUG - ok to have a handle for each event ? HANDLE workItemCompleteEvent; /* * Fields describing the workItem's current operation. */ struct { ULONG opcode; ULONG options; HRESULT resultStatus; DRIVE *drive; PHYSICAL_MEDIA *physMedia; MEDIA_PARTITION *mediaPartition; ULONG lParam; NTMS_GUID guidArg; // in/out guid used by some ops PVOID buf; ULONG bufLen; SYSTEMTIME timeQueued; SYSTEMTIME timeCompleted; /* * Request identifier, used to cancel a pending workItem. */ NTMS_GUID requestGuid; // // BUGBUG - unscrubbed fields from NtmsDbWorkItem // clean this up. // // NtmsDbGuid m_PartitionId; // NtmsDbGuid m_AssocWorkItem; // short m_protected; // unsigned long m_Priority; } currentOp; }; /* * A WORKGROUP is a collection of WORKITEMs, * not necessarily all on the same library. */ struct _WORKGROUP { LIST_ENTRY workItemsList; ULONG numTotalWorkItems; ULONG numPendingWorkItems; HANDLE allWorkItemsCompleteEvent; HRESULT resultStatus; CRITICAL_SECTION lock; }; struct _OPERATOR_REQUEST { LIST_ENTRY sessionOpReqsListEntry; // entry in session's operatorRequestList SESSION *invokingSession; ULONG numWaitingThreads; // num threads waiting for completion // BUGBUG - I don't think we need an op request thread HANDLE hThread; // thread spawned for op request enum NtmsOpreqCommand opRequestCommand; enum NtmsOpreqState state; NTMS_GUID arg1Guid; NTMS_GUID arg2Guid; WCHAR appMessage[NTMS_MESSAGE_LENGTH]; WCHAR rsmMessage[NTMS_MESSAGE_LENGTH]; // NOTIFYICONDATA notifyData; // BUGBUG - use this in RSM Monitor app ? NTMS_GUID opReqGuid; SYSTEMTIME timeSubmitted; HANDLE completedEvent; }; /* * The number of free workItems with which we initialize a library. */ #define MIN_LIBRARY_WORKITEMS 0 /* * The maximum total number of workItems that we allow in a library pool. * We will allocate new workItems as needed up to this number. */ #define MAX_LIBRARY_WORKITEMS 10000 // BUGBUG ? /* * List macros -- not defined in winnt.h for some reason. */ #define InitializeListHead(ListHead) (\ (ListHead)->Flink = (ListHead)->Blink = (ListHead)) #define IsListEmpty(ListHead) \ ((ListHead)->Flink == (ListHead)) #define RemoveHeadList(ListHead) \ (ListHead)->Flink;\ {RemoveEntryList((ListHead)->Flink)} #define RemoveTailList(ListHead) \ (ListHead)->Blink;\ {RemoveEntryList((ListHead)->Blink)} #define RemoveEntryList(Entry) {\ PLIST_ENTRY _EX_Blink;\ PLIST_ENTRY _EX_Flink;\ _EX_Flink = (Entry)->Flink;\ _EX_Blink = (Entry)->Blink;\ _EX_Blink->Flink = _EX_Flink;\ _EX_Flink->Blink = _EX_Blink;\ } #define InsertTailList(ListHead,Entry) {\ PLIST_ENTRY _EX_Blink;\ PLIST_ENTRY _EX_ListHead;\ _EX_ListHead = (ListHead);\ _EX_Blink = _EX_ListHead->Blink;\ (Entry)->Flink = _EX_ListHead;\ (Entry)->Blink = _EX_Blink;\ _EX_Blink->Flink = (Entry);\ _EX_ListHead->Blink = (Entry);\ } #define InsertHeadList(ListHead,Entry) {\ PLIST_ENTRY _EX_Flink;\ PLIST_ENTRY _EX_ListHead;\ _EX_ListHead = (ListHead);\ _EX_Flink = _EX_ListHead->Flink;\ (Entry)->Flink = _EX_Flink;\ (Entry)->Blink = _EX_ListHead;\ _EX_Flink->Blink = (Entry);\ _EX_ListHead->Flink = (Entry);\ } #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) /* * Internal function prototypes */ BOOLEAN RSMServiceGlobalInit(); VOID RSMServiceGlobalShutdown(); DWORD RSMServiceHandler(IN DWORD dwOpcode, IN DWORD dwEventType, IN PVOID pEventData, IN PVOID pData); BOOL InitializeRSMService(); VOID ShutdownRSMService(); VOID RSMServiceLoop(); VOID StartLibraryManager(); LIBRARY *NewRSMLibrary(ULONG numDrives, ULONG numSlots, ULONG numTransports); VOID FreeRSMLibrary(LIBRARY *lib); LIBRARY *FindLibrary(LPNTMS_GUID libId); SLOT *FindLibrarySlot(LIBRARY *lib, LPNTMS_GUID slotId); BOOL ValidateSessionHandle(HANDLE hSession); BOOL ValidateWStr(LPCWSTR str); BOOL ValidateAStr(LPCSTR s); BOOL ValidateBuffer(PVOID buf, ULONG len); WORKITEM *NewWorkItem(LIBRARY *lib); VOID FreeWorkItem(WORKITEM *workItem); VOID EnqueueFreeWorkItem(LIBRARY *lib, WORKITEM *workItem); WORKITEM *DequeueFreeWorkItem(LIBRARY *lib, BOOL allocOrYieldIfNeeded); VOID EnqueuePendingWorkItem(LIBRARY *lib, WORKITEM *workItem); WORKITEM *DequeuePendingWorkItem(LIBRARY *lib, WORKITEM *specificWorkItem); WORKITEM *DequeuePendingWorkItemByGuid(LIBRARY *lib, LPNTMS_GUID lpRequestId); VOID EnqueueCompleteWorkItem(LIBRARY *lib, WORKITEM *workItem); WORKITEM *DequeueCompleteWorkItem(LIBRARY *lib, WORKITEM *specificWorkItem); BOOL StartLibrary(LIBRARY *lib); VOID HaltLibrary(LIBRARY *lib); DWORD __stdcall LibraryThread(void *context); VOID Library_DoWork(LIBRARY *lib); OPERATOR_REQUEST *NewOperatorRequest(DWORD dwRequest, LPCWSTR lpMessage, LPNTMS_GUID lpArg1Id, LPNTMS_GUID lpArg2Id); VOID FreeOperatorRequest(OPERATOR_REQUEST *opReq); BOOL EnqueueOperatorRequest(SESSION *thisSession, OPERATOR_REQUEST *opReq); OPERATOR_REQUEST *DequeueOperatorRequest(SESSION *thisSession, OPERATOR_REQUEST *specificOpReq, LPNTMS_GUID specificOpReqGuid); OPERATOR_REQUEST *FindOperatorRequest(SESSION *thisSession, LPNTMS_GUID opReqGuid); HRESULT CompleteOperatorRequest(SESSION *thisSession, LPNTMS_GUID lpRequestId, enum NtmsOpreqState completeState); DWORD __stdcall OperatorRequestThread(void *context); SESSION *NewSession(LPCWSTR lpServer, LPCWSTR lpApplication, LPCWSTR lpClientName, LPCWSTR lpUserName); VOID FreeSession(SESSION *thisSession); ULONG WStrNCpy(WCHAR *dest, const WCHAR *src, ULONG maxWChars); ULONG AsciiToWChar(WCHAR *dest, const char *src, ULONG maxChars); ULONG WCharToAscii(char *dest, WCHAR *src, ULONG maxChars); BOOL WStringsEqualN(PWCHAR s, PWCHAR p, BOOL caseSensitive, ULONG maxLen); VOID ConvertObjectInfoAToWChar(LPNTMS_OBJECTINFORMATIONW wObjInfo, LPNTMS_OBJECTINFORMATIONA aObjInfo); VOID InitGuidHash(); VOID InsertObjectInGuidHash(OBJECT_HEADER *obj); VOID RemoveObjectFromGuidHash(OBJECT_HEADER *obj); OBJECT_HEADER *FindObjectInGuidHash(NTMS_GUID *guid); MEDIA_POOL *NewMediaPool(LPCWSTR name, LPNTMS_GUID mediaType, LPSECURITY_ATTRIBUTES lpSecurityAttributes); MEDIA_POOL *FindMediaPool(LPNTMS_GUID mediaPoolId); MEDIA_POOL *FindMediaPoolByName(PWSTR poolName); PHYSICAL_MEDIA *FindPhysicalMedia(LPNTMS_GUID physMediaId); VOID RefObject(PVOID objectPtr); VOID DerefObject(PVOID objectPtr); PHYSICAL_MEDIA *NewPhysicalMedia(); HRESULT AllocatePhysicalMediaExclusive(SESSION *thisSession, PHYSICAL_MEDIA *physMedia, LPNTMS_GUID lpPartitionId, DWORD dwTimeoutMsec); HRESULT AllocateNextPartitionOnExclusiveMedia(SESSION *thisSession, PHYSICAL_MEDIA *physMedia, MEDIA_PARTITION **ppNextPartition); HRESULT AllocateMediaFromPool(SESSION *thisSession, MEDIA_POOL *mediaPool, DWORD dwTimeoutMsec, PHYSICAL_MEDIA **ppPhysMedia, BOOL opReqIfNeeded); MEDIA_PARTITION *FindMediaPartition(LPNTMS_GUID lpLogicalMediaId); HRESULT ReleaseMediaPartition(SESSION *thisSession, MEDIA_PARTITION *thisMediaPartition); MEDIA_POOL *FindMediaPoolByName(PWSTR poolName); MEDIA_POOL *FindMediaPoolByNameInLibrary(LIBRARY *lib, PWSTR poolName); HRESULT SetMediaPartitionState(MEDIA_PARTITION *mediaPart, enum mediaPartitionStates newState); HRESULT SetMediaPartitionComplete(MEDIA_PARTITION *mediaPart); HRESULT DeletePhysicalMedia(PHYSICAL_MEDIA *physMedia); VOID InsertPhysicalMediaInPool(MEDIA_POOL *mediaPool, PHYSICAL_MEDIA *physMedia); VOID RemovePhysicalMediaFromPool(PHYSICAL_MEDIA *physMedia); HRESULT MovePhysicalMediaToPool(MEDIA_POOL *destMediaPool, PHYSICAL_MEDIA *physMedia, BOOLEAN setMediaTypeToPoolType); BOOLEAN LockPhysicalMediaWithPool(PHYSICAL_MEDIA *physMedia); VOID UnlockPhysicalMediaWithPool(PHYSICAL_MEDIA *physMedia); BOOLEAN LockPhysicalMediaWithLibrary(PHYSICAL_MEDIA *physMedia); VOID UnlockPhysicalMediaWithLibrary(PHYSICAL_MEDIA *physMedia); HRESULT DeleteMediaPool(MEDIA_POOL *mediaPool); MEDIA_TYPE_OBJECT *NewMediaTypeObject(); VOID DestroyMediaTypeObject(MEDIA_TYPE_OBJECT *mediaTypeObj); MEDIA_TYPE_OBJECT *FindMediaTypeObject(LPNTMS_GUID lpMediaTypeId); HRESULT DeleteMediaTypeObject(MEDIA_TYPE_OBJECT *mediaTypeObj); VOID SetMediaType(PHYSICAL_MEDIA *physMedia, MEDIA_TYPE_OBJECT *mediaTypeObj); WORKGROUP *NewWorkGroup(); VOID FreeWorkGroup(WORKGROUP *workGroup); VOID FlushWorkGroup(WORKGROUP *workGroup); VOID FlushWorkItem(WORKITEM *workItem); HRESULT BuildMountWorkGroup(WORKGROUP *workGroup, LPNTMS_GUID lpMediaOrPartitionIds, LPNTMS_GUID lpDriveIds, DWORD dwCount, DWORD dwOptions, DWORD dwPriority); VOID BuildSingleMountWorkItem(WORKITEM *workItem, DRIVE *drive OPTIONAL, OBJECT_HEADER *mediaOrPartObj, ULONG dwOptions, int dwPriority); HRESULT BuildDismountWorkGroup(WORKGROUP *workGroup, LPNTMS_GUID lpMediaOrPartitionIds, DWORD dwCount, DWORD dwOptions); VOID BuildSingleDismountWorkItem(WORKITEM *workItem, OBJECT_HEADER *mediaOrPartObj, DWORD dwOptions); HRESULT ScheduleWorkGroup(WORKGROUP *workGroup); DRIVE *NewDrive(LIBRARY *lib, PWCHAR path); VOID FreeDrive(DRIVE *drive); DRIVE *FindDrive(LPNTMS_GUID driveId); VOID BuildEjectWorkItem(WORKITEM *workItem, PHYSICAL_MEDIA *physMedia, LPNTMS_GUID lpEjectOperation, ULONG dwAction); VOID BuildInjectWorkItem(WORKITEM *workItem, LPNTMS_GUID lpInjectOperation, ULONG dwAction); HRESULT StopCleanerInjection(LIBRARY *lib, LPNTMS_GUID lpInjectOperation); HRESULT StopCleanerEjection(LIBRARY *lib, LPNTMS_GUID lpEjectOperation); HRESULT DeleteLibrary(LIBRARY *lib); HRESULT DeleteDrive(DRIVE *drive); BOOL ServiceOneWorkItem(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceRemove(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceDisableChanger(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceDisableLibrary(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceEnableChanger(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceEnableLibrary(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceDisableDrive(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceEnableDrive(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceDisableMedia(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceEnableMedia(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceUpdateOmid(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceInventory(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceDoorAccess(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceEject(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceEjectCleaner(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceInject(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceInjectCleaner(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceProcessOmid(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceCleanDrive(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceDismount(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceMount(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceWriteScratch(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceClassify(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceReserveCleaner(LIBRARY *lib, WORKITEM *workItem); BOOL ServiceReleaseCleaner(LIBRARY *lib, WORKITEM *workItem); /* * Externs for internal global data. */ extern CRITICAL_SECTION g_globalServiceLock; extern LIST_ENTRY g_allLibrariesList; extern LIST_ENTRY g_allSessionsList; extern HANDLE g_terminateServiceEvent; extern HINSTANCE g_hInstance;