Remove flock usage from InternalCreateFile in PAL (#16752)
[platform/upstream/coreclr.git] / src / pal / src / file / shmfilelockmgr.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*++
6
7
8
9 Module Name:
10
11     shmfilelockmgr.cpp
12
13 Abstract:
14     Shared memory based file lock manager
15
16
17
18 --*/
19
20 #include "pal/thread.hpp"
21 #include "pal/malloc.hpp"
22 #include "pal/dbgmsg.h"
23 #include "shmfilelockmgr.hpp"
24
25 using namespace CorUnix;
26
27 SET_DEFAULT_DEBUG_CHANNEL(FILE);
28
29 PAL_ERROR
30 FILEAddNewLockedRgn(
31     SHMFILELOCKS* fileLocks,
32     PVOID pvControllerInstance, 
33     SHMFILELOCKRGNS *insertAfter,
34     UINT64 lockRgnStart, 
35     UINT64 nbBytesToLock, 
36     LOCK_TYPE lockType
37     );
38
39 PAL_ERROR
40 FILELockFileRegion(
41     SHMPTR shmFileLocks,
42     PVOID pvControllerInstance,
43     UINT64 lockRgnStart, 
44     UINT64 nbBytesToLock,
45     LOCK_TYPE lockAction
46     );
47
48 PAL_ERROR
49 FILEUnlockFileRegion(
50     SHMPTR shmFileLocks,
51     PVOID pvControllerInstance, 
52     UINT64 unlockRgnStart, 
53     UINT64 nbBytesToUnlock,
54     LOCK_TYPE unlockType
55     );
56
57 void
58 FILECleanUpLockedRgn(
59     SHMPTR shmFileLocks,
60     DWORD dwAccessRights,
61     PVOID pvControllerInstance
62     );
63
64 PAL_ERROR
65 FILEGetSHMFileLocks(
66     LPCSTR filename,
67     SHMPTR *pshmFileLocks,
68     BOOL noCreate
69     );
70
71 /* return TRUE if LockToTest region is behind lockRgn, FALSE otherwise */
72 #define IS_LOCK_BEFORE(LockToTest, lockRgn) \
73     (((LockToTest)->lockRgnStart + (LockToTest)->nbBytesLocked) <= \
74                                                         (lockRgn)->lockRgnStart)
75
76 /* return TRUE if LockToTest region intersect with lockRgn, FALSE otherwise */
77 #define IS_LOCK_INTERSECT(LockToTest, lockRgn) \
78     (!IS_LOCK_BEFORE(LockToTest, lockRgn) && !IS_LOCK_BEFORE(lockRgn, LockToTest))
79
80 /* return TRUE if LockToTest region and lockRgn have the same file pointer and 
81    the same process Id, FALSE otherwise */
82 #define IS_LOCK_HAVE_SAME_OWNER(LockToTest, lockRgn) \
83     (((LockToTest)->pvControllerInstance == (lockRgn)->pvControllerInstance) && \
84      ((LockToTest)->processId == (lockRgn)->processId))
85
86 /* return TRUE if LockToTest region and lockRgn represent the same lock, 
87    FALSE otherwise*/
88 #define IS_LOCK_EQUAL(LockToTest, lockRgn) \
89         (((LockToTest)->processId == (lockRgn)->processId)           && \
90          ((LockToTest)->pvControllerInstance == (lockRgn)->pvControllerInstance)   && \
91          ((LockToTest)->lockRgnStart == (lockRgn)->lockRgnStart)     && \
92          ((LockToTest)->nbBytesLocked == (lockRgn)->nbBytesLocked)   && \
93          ((LockToTest)->lockType == (lockRgn)->lockType))
94
95 PAL_ERROR
96 CSharedMemoryFileLockMgr::GetLockControllerForFile(
97     CPalThread *pThread,                // IN, OPTIONAL
98     LPCSTR szFileName,
99     DWORD dwAccessRights,
100     DWORD dwShareMode,
101     IFileLockController **ppLockController  // OUT
102     )
103 {
104     PAL_ERROR palError = NO_ERROR;
105     SHMPTR shmFileLocks = NULL;
106     SHMFILELOCKS* fileLocks = NULL;
107     CSharedMemoryFileLockController *pController = NULL;
108
109     SHMLock();
110
111     palError = FILEGetSHMFileLocks(szFileName, &shmFileLocks, FALSE);
112     if (NO_ERROR != palError)
113     {
114         goto GetLockControllerForFileExit;
115     }
116
117     if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE || fileLocks == NULL)
118     {
119         ASSERT("Unable to get pointer from shm pointer.\n");
120         palError = ERROR_INTERNAL_ERROR;
121         goto GetLockControllerForFileExit;
122     }
123         
124     if(SHARE_MODE_NOT_INITALIZED == fileLocks->share_mode)
125     {
126         /* this is the first time this file is open */
127         fileLocks->share_mode = (int) dwShareMode;
128     }
129     /* start checking for dwDesired access and dwShareMode conditions */
130     else if(0 == fileLocks->share_mode)
131     {
132         /* file is exclusively locked */
133         palError = ERROR_SHARING_VIOLATION;
134         goto GetLockControllerForFileExit;
135     }
136     /* check for if the desired access is allowed by the share mode */
137     else if( (dwAccessRights & GENERIC_READ) && 
138              !(fileLocks->share_mode & FILE_SHARE_READ) )
139     {
140         palError = ERROR_SHARING_VIOLATION;
141         goto GetLockControllerForFileExit;     
142     }
143     else if( (dwAccessRights & GENERIC_WRITE) && 
144              !(fileLocks->share_mode & FILE_SHARE_WRITE) )
145     {
146         palError = ERROR_SHARING_VIOLATION;
147         goto GetLockControllerForFileExit;     
148     }
149     /* The case when changing to a conflicting share mode is particular.
150        The general rule is: changing from conflicting share mode is invalid
151        (i.e changing from FILE_SHARE_WRITE to FILE_SHARE_READ is invalid).
152        However, if one of the share flags is the same
153        (i.e changing from FILE_SHARE_WRITE to FILE_SHARE_READ | FILE_SHARE_WRITE)
154        the result is valid. (Please note that FILE_SHARE_READ is ignored
155        in this case).
156     */
157     else if( (dwShareMode & FILE_SHARE_READ) && 
158              !(dwShareMode & FILE_SHARE_WRITE) &&
159              !(fileLocks->share_mode & FILE_SHARE_READ))
160                          
161     {
162         palError = ERROR_SHARING_VIOLATION;
163         goto GetLockControllerForFileExit;     
164     }
165     else if( (dwShareMode & FILE_SHARE_WRITE) && 
166              !(dwShareMode & FILE_SHARE_READ) &&
167              !(fileLocks->share_mode & FILE_SHARE_WRITE))
168     {
169         palError = ERROR_SHARING_VIOLATION;
170         goto GetLockControllerForFileExit;     
171     }
172     /* Changing to a less permissive sharing permissions is valid
173        if the file handle doesn't have an access right that conflicts with
174        the sharing permissions we are trying to set
175        (ex: changing from FILE_SHARE_READ|FILE_SHARE_WRITE to FILE_SHARE_WRITE
176        isn't valid if the file descriptor still has a GENERIC_READ permission).
177     */     
178     else if( (fileLocks->nbReadAccess) && 
179              !(dwShareMode & FILE_SHARE_READ) )
180     {
181         palError = ERROR_SHARING_VIOLATION;
182         goto GetLockControllerForFileExit;     
183     }
184     else if( (fileLocks->nbWriteAccess) && 
185              !(dwShareMode & FILE_SHARE_WRITE) )
186     {
187         palError = ERROR_SHARING_VIOLATION;
188         goto GetLockControllerForFileExit;     
189     }
190
191     /* we are trying to change to a less restrictive sharing permission set 
192        keep the current permissions */  
193     if( (dwShareMode & FILE_SHARE_READ) && 
194               !(fileLocks->share_mode & FILE_SHARE_READ) )
195     {
196         dwShareMode = fileLocks->share_mode;
197     }
198
199     if( (dwShareMode & FILE_SHARE_WRITE) && 
200               !(fileLocks->share_mode & FILE_SHARE_WRITE) )
201     {
202         dwShareMode = fileLocks->share_mode;
203     }
204
205     pController = InternalNew<CSharedMemoryFileLockController>(dwAccessRights, shmFileLocks);
206     if (NULL == pController)
207     {
208         palError = ERROR_OUTOFMEMORY;
209         goto GetLockControllerForFileExit;
210     }
211
212     //
213     // pController now owns the shared memory pointer, so make sure we
214     // don't attempt to free it below.
215     //
216
217     shmFileLocks = NULL;
218
219     /* set the share mode again, it's possible that the share mode is now more
220     restrictive than the previous mode set. */
221     fileLocks->share_mode = dwShareMode;
222     if( dwAccessRights & GENERIC_READ )
223     {
224         fileLocks->nbReadAccess++;  
225     }
226     if( dwAccessRights & GENERIC_WRITE )
227     {
228         fileLocks->nbWriteAccess++;
229     }
230
231     // ************** NOTE **************
232     // If you add any error paths after this point you must communicate the value of dwAccessRights to
233     // FILECleanUpLockedRgn() in the cleanup code below so that it can correctly undo the changes to
234     // fileLocks->nbReadAccess and nbWriteAccess made above.
235     // ************** NOTE **************
236
237 GetLockControllerForFileExit:
238
239     if (NO_ERROR == palError)
240     {
241         *ppLockController = pController;
242     }
243     else
244     {
245         if (NULL != pController)
246         {
247             pController->ReleaseController();
248         }
249
250         if (NULL != shmFileLocks)
251         {
252             FILECleanUpLockedRgn(
253                 shmFileLocks,
254                 0,
255                 NULL
256                 );
257         }
258     }
259
260     SHMRelease();
261
262     return palError;
263 }
264
265 PAL_ERROR
266 CSharedMemoryFileLockMgr::GetFileShareModeForFile(
267    LPCSTR szFileName,
268    DWORD* pdwShareMode)
269 {
270     PAL_ERROR palError = NO_ERROR;
271     *pdwShareMode = SHARE_MODE_NOT_INITALIZED;
272     SHMPTR shmFileLocks = NULL;
273     SHMFILELOCKS* fileLocks = NULL;
274
275     SHMLock();
276
277     palError = FILEGetSHMFileLocks(szFileName, &shmFileLocks, TRUE);
278     if (NO_ERROR != palError || shmFileLocks == NULL)
279     {
280         goto GetLockControllerForFileExit;
281     }
282
283     if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE)
284     {
285         ASSERT("Unable to get pointer from shm pointer.\n");
286         palError = ERROR_INTERNAL_ERROR;
287         goto GetLockControllerForFileExit;
288     }
289
290     *pdwShareMode = fileLocks->share_mode;
291
292 GetLockControllerForFileExit:
293
294     if (NULL != shmFileLocks)
295     {
296       FILECleanUpLockedRgn(
297                 shmFileLocks,
298                 0,
299                 NULL
300                 );
301     }
302
303     SHMRelease();
304
305     return palError;
306 }
307
308 PAL_ERROR
309 CSharedMemoryFileLockController::GetTransactionLock(
310     CPalThread *pThread,                // IN, OPTIONAL
311     FileTransactionLockType eLockType,
312     DWORD dwOffsetLow,
313     DWORD dwOffsetHigh,
314     DWORD nNumberOfBytesToLockLow,
315     DWORD nNumberOfBytesToLockHigh,
316     IFileTransactionLock **ppTransactionLock    // OUT
317     )
318 {
319     PAL_ERROR palError = NO_ERROR;
320     UINT64 lockRgnStart;
321     UINT64 nbBytesToLock;
322
323     lockRgnStart  = ((UINT64)dwOffsetHigh) << 32  | dwOffsetLow;
324     nbBytesToLock = ((UINT64)nNumberOfBytesToLockHigh) << 32  | 
325                              nNumberOfBytesToLockLow;
326
327     palError = FILELockFileRegion(
328         m_shmFileLocks,
329         reinterpret_cast<PVOID>(this),
330         lockRgnStart, 
331         nbBytesToLock,
332         RDWR_LOCK_RGN
333         );
334
335     if (NO_ERROR == palError)
336     {
337         *ppTransactionLock = InternalNew<CSharedMemoryFileTransactionLock>(m_shmFileLocks,
338                                                                            reinterpret_cast<PVOID>(this),
339                                                                            lockRgnStart, 
340                                                                            nbBytesToLock);
341         if (NULL == *ppTransactionLock)
342         {
343             palError = ERROR_OUTOFMEMORY;
344             FILEUnlockFileRegion(
345                 m_shmFileLocks,
346                 reinterpret_cast<PVOID>(this),
347                 lockRgnStart, 
348                 nbBytesToLock,
349                 RDWR_LOCK_RGN
350                 );
351         }
352     }
353
354     return palError;
355 }
356
357 PAL_ERROR
358 CSharedMemoryFileLockController::CreateFileLock(
359     CPalThread *pThread,                // IN, OPTIONAL
360     DWORD dwOffsetLow,
361     DWORD dwOffsetHigh,
362     DWORD nNumberOfBytesToLockLow,
363     DWORD nNumberOfBytesToLockHigh,
364     FileLockExclusivity eFileLockExclusivity,
365     FileLockWaitMode eFileLockWaitMode
366     )
367 {
368     PAL_ERROR palError = NO_ERROR;
369     UINT64 lockRgnStart;
370     UINT64 nbBytesToLock;
371
372     if (ExclusiveFileLock != eFileLockExclusivity
373         || FailImmediately != eFileLockWaitMode)
374     {
375         ASSERT("LockFileEx functionality not yet supported");
376         palError = ERROR_NOT_SUPPORTED;
377         goto CreateFileLockExit;
378     }
379
380     lockRgnStart  = ((UINT64)dwOffsetHigh) << 32  | dwOffsetLow;
381     nbBytesToLock = ((UINT64)nNumberOfBytesToLockHigh) << 32  | 
382                              nNumberOfBytesToLockLow;
383
384     palError = FILELockFileRegion(
385         m_shmFileLocks,
386         reinterpret_cast<PVOID>(this),
387         lockRgnStart, 
388         nbBytesToLock,
389         USER_LOCK_RGN
390         );
391
392 CreateFileLockExit:
393
394     return palError;
395 }
396
397 PAL_ERROR
398 CSharedMemoryFileLockController::ReleaseFileLock(
399     CPalThread *pThread,                // IN, OPTIONAL
400     DWORD dwOffsetLow,
401     DWORD dwOffsetHigh,
402     DWORD nNumberOfBytesToUnlockLow,
403     DWORD nNumberOfBytesToUnlockHigh
404     )
405 {
406     PAL_ERROR palError = NO_ERROR;
407     UINT64 unlockRgnStart;
408     UINT64 nbBytesToUnlock;
409
410     unlockRgnStart  = ((UINT64)dwOffsetHigh) << 32  | dwOffsetLow;
411     nbBytesToUnlock = ((UINT64)nNumberOfBytesToUnlockHigh) << 32  | 
412                              nNumberOfBytesToUnlockLow;
413
414     palError = FILEUnlockFileRegion(
415         m_shmFileLocks,
416         reinterpret_cast<PVOID>(this),
417         unlockRgnStart, 
418         nbBytesToUnlock,
419         USER_LOCK_RGN
420         );
421
422     return palError;
423 }
424
425 void
426 CSharedMemoryFileLockController::ReleaseController()
427 {
428     if (NULL != m_shmFileLocks)
429     {
430         FILECleanUpLockedRgn(
431             m_shmFileLocks,
432             m_dwAccessRights,
433             reinterpret_cast<PVOID>(this)
434             );
435     }
436
437     InternalDelete(this);
438 }
439
440 void
441 CSharedMemoryFileTransactionLock::ReleaseLock()
442 {
443     FILEUnlockFileRegion(
444         m_shmFileLocks,
445         m_pvControllerInstance,
446         m_lockRgnStart, 
447         m_nbBytesToLock,
448         RDWR_LOCK_RGN
449         );
450
451     InternalDelete(this);
452 }
453
454 PAL_ERROR
455 FILELockFileRegion(
456     SHMPTR shmFileLocks,
457     PVOID pvControllerInstance,
458     UINT64 lockRgnStart, 
459     UINT64 nbBytesToLock,
460     LOCK_TYPE lockAction
461     )
462 {
463     PAL_ERROR palError = NO_ERROR;
464     SHMFILELOCKRGNS *curLock, *prevLock, *insertAfter, 
465                      lockRgn, fakeLock = {0,0,0,0};
466     SHMFILELOCKS *fileLocks;
467
468     SHMLock();
469     
470     /* nothing to do if the region to lock is empty */
471     if (nbBytesToLock == 0) 
472     {
473         TRACE("Locking an empty region (%I64d, %I64d)\n", lockRgnStart, nbBytesToLock);
474         goto EXIT;
475     }
476     
477     if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE || fileLocks == NULL)
478     {
479         ASSERT("Unable to get pointer from shm pointer.\n");
480         palError = ERROR_INTERNAL_ERROR;
481         goto EXIT;
482     }
483
484     if (fileLocks->fileLockedRgns != 0)
485     {        
486         prevLock = &fakeLock;
487         
488         if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLock, fileLocks->fileLockedRgns) 
489             == FALSE)
490         {
491             ASSERT("Unable to get pointer from shm pointer.\n");
492             palError = ERROR_INTERNAL_ERROR;
493             goto EXIT;
494         }
495         
496         lockRgn.lockRgnStart = lockRgnStart;
497         lockRgn.nbBytesLocked = nbBytesToLock;
498         lockRgn.pvControllerInstance = pvControllerInstance;
499         lockRgn.processId = GetCurrentProcessId();
500         lockRgn.lockType = lockAction;
501
502         while((curLock != NULL) && IS_LOCK_BEFORE(curLock, &lockRgn))
503         {            
504             prevLock = curLock; 
505             if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLock, curLock->next) == FALSE)
506             {
507                 ASSERT("Unable to get pointer from shm pointer.\n");
508                 palError = ERROR_INTERNAL_ERROR;
509                 goto EXIT;
510             }
511         }
512                 
513         while((curLock != NULL) && IS_LOCK_INTERSECT(curLock, &lockRgn))
514         {
515             /* we couldn't lock the requested region if it overlap with other 
516                region locked explicitly (by LockFile call) by other file pointer */
517             if ((lockAction == USER_LOCK_RGN) || 
518                 ((curLock->lockType  == USER_LOCK_RGN) && 
519                  !IS_LOCK_HAVE_SAME_OWNER(curLock, &lockRgn)))
520             {
521                 WARN("The requested lock region overlaps an existing locked region\n");
522                 palError = ERROR_LOCK_VIOLATION;
523                 goto EXIT;
524             }
525             
526             prevLock = curLock; 
527             if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLock, curLock->next) == FALSE)
528             {
529                 ASSERT("Unable to get pointer from shm pointer.\n");
530                 palError = ERROR_INTERNAL_ERROR;
531                 goto EXIT;
532             }
533         }
534         
535         /* save the previous lock in case we need to insert the requested lock */
536         insertAfter = prevLock;         
537                 
538         while(((curLock != NULL) && IS_LOCK_INTERSECT(&lockRgn, curLock)))
539         {
540             /* we couldn't lock the requested region if it overlap with other region 
541                locked explicitly (by LockFile call) by other file pointer */
542             if ((lockAction == USER_LOCK_RGN) || 
543                 ((curLock->lockType  == USER_LOCK_RGN) &&  
544                  !IS_LOCK_HAVE_SAME_OWNER(curLock, &lockRgn)))
545             {
546                 WARN("The requested lock region overlaps an existing locked region\n");
547                 palError = ERROR_LOCK_VIOLATION;
548                 goto EXIT;
549             }
550             
551             prevLock = curLock; 
552             if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLock, curLock->next) == FALSE)
553             {
554                 ASSERT("Unable to get pointer from shm pointer.\n");
555                 palError = ERROR_INTERNAL_ERROR;
556                 goto EXIT;
557             }
558         }
559        
560         if (insertAfter == &fakeLock) 
561         {
562             insertAfter = NULL;
563         }
564
565         palError = FILEAddNewLockedRgn(
566             fileLocks,
567             pvControllerInstance,
568             insertAfter,
569             lockRgnStart,
570             nbBytesToLock,
571             lockAction
572             );
573
574         if (NO_ERROR != palError)
575         {
576             WARN("Couldn't add the new locked region into SHM\n");
577             goto EXIT;
578         }
579     }
580     else /* lock region list is empty. */
581     {
582         palError = FILEAddNewLockedRgn(
583             fileLocks,
584             pvControllerInstance,
585             NULL,
586             lockRgnStart,
587             nbBytesToLock,
588             lockAction
589             );
590         
591         if (NO_ERROR != palError)
592         {
593             ERROR("Couldn't add the first file locked region \n");
594             goto EXIT;
595         }
596     }  
597
598 EXIT:
599     SHMRelease();
600     return palError;
601 }
602
603 PAL_ERROR
604 FILEUnlockFileRegion(
605     SHMPTR shmFileLocks,
606     PVOID pvControllerInstance,
607     UINT64 unlockRgnStart, 
608     UINT64 nbBytesToUnlock,
609     LOCK_TYPE unlockType
610     )
611 {
612     PAL_ERROR palError = NO_ERROR;
613     SHMFILELOCKRGNS *prevLock = NULL, *curLockRgn = NULL, unlockRgn;
614     SHMPTR shmcurLockRgn;
615     SHMFILELOCKS *fileLocks;
616
617     SHMLock();
618
619     
620     /* check if the region to unlock is empty or not */
621     if (nbBytesToUnlock == 0) 
622     {
623         palError = ERROR_NOT_LOCKED;
624         WARN("Attempt to unlock an empty region\n");
625         goto EXIT;
626     }
627     
628     if ((SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE) || 
629         (fileLocks == NULL) ||
630         (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, fileLocks->fileLockedRgns) == FALSE))
631     {
632         ASSERT("Unable to get pointer from shm pointer.\n");
633         palError = ERROR_INTERNAL_ERROR;
634         goto EXIT;
635     }
636     
637     unlockRgn.processId = GetCurrentProcessId();
638     unlockRgn.pvControllerInstance = pvControllerInstance;
639     unlockRgn.lockRgnStart = unlockRgnStart;
640     unlockRgn.nbBytesLocked = nbBytesToUnlock;
641     unlockRgn.lockType = unlockType;
642
643     shmcurLockRgn = fileLocks->fileLockedRgns;
644     
645     while((curLockRgn != NULL) && !IS_LOCK_EQUAL(curLockRgn, &unlockRgn))
646     {
647         prevLock = curLockRgn; 
648         shmcurLockRgn = curLockRgn->next;
649         if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
650         {
651             ASSERT("Unable to get pointer from shm pointer.\n");
652             goto EXIT;
653         }
654     }
655     
656     if (curLockRgn != NULL) 
657     {
658         TRACE("removing the lock region (%I64u, %I64u)\n", 
659                curLockRgn->lockRgnStart, curLockRgn->nbBytesLocked);
660
661         if (prevLock == NULL) 
662         {
663             /* removing the first lock */
664             fileLocks->fileLockedRgns = curLockRgn->next;
665         }
666         else
667         {
668             prevLock->next = curLockRgn->next;
669         }
670         free(shmcurLockRgn);
671     }
672     else
673     {
674         /* the lock doesn't exist */
675         WARN("Attempt to unlock a non locked region\n");
676         palError = ERROR_NOT_LOCKED;
677         goto EXIT;
678     }
679     
680 EXIT:    
681     SHMRelease();
682     return palError;
683 }
684
685
686 PAL_ERROR
687 FILEGetSHMFileLocks(
688     LPCSTR filename,
689     SHMPTR *pshmFileLocks,
690     BOOL noCreate
691     )
692 {
693     PAL_ERROR palError = NO_ERROR;
694     SHMPTR shmPtrRet = 0;
695     SHMFILELOCKS *filelocksPtr, *nextFilelocksPtr;
696     char *unix_filename;
697
698     SHMLock();
699
700     shmPtrRet = SHMGetInfo(SIID_FILE_LOCKS);
701
702     while(shmPtrRet != 0)
703     {        
704         if ( (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, filelocksPtr, shmPtrRet) == FALSE) ||
705              (SHMPTR_TO_TYPED_PTR_BOOL(char, unix_filename, filelocksPtr->unix_filename) == FALSE))
706         {
707             ASSERT("Unable to get pointer from shm pointer.\n");
708             palError = ERROR_INTERNAL_ERROR;
709             goto EXIT;
710         }
711
712         if (unix_filename == NULL)
713         {
714             ERROR("Unexpected lock file name value.\n");
715             palError = ERROR_INTERNAL_ERROR;
716             goto EXIT;
717         }
718         
719         if (strcmp(unix_filename, filename) == 0)
720         {
721             filelocksPtr->refCount++;
722             goto EXIT;
723         }
724         
725         shmPtrRet = filelocksPtr->next;
726     }
727
728     /* the file has never been locked before.*/
729     shmPtrRet = 0;
730     if (noCreate)
731     {
732       goto EXIT;
733     }
734
735     TRACE("Create a new entry in the file lock list in SHM\n");
736
737     /* Create a new entry in the file lock list in SHM */
738     if ((shmPtrRet = malloc(sizeof(SHMFILELOCKS))) == 0)
739     {
740         ERROR("Can't allocate SHMFILELOCKS structure\n");
741         palError = ERROR_NOT_ENOUGH_MEMORY;
742         goto EXIT;
743     }
744
745     if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, filelocksPtr, shmPtrRet) == FALSE)
746     {
747         ASSERT("Unable to get pointer from shm pointer.\n");
748         palError = ERROR_INTERNAL_ERROR;
749         goto CLEANUP1;
750     }
751
752     filelocksPtr->unix_filename = strdup(filename);
753     if (filelocksPtr->unix_filename == 0)
754     {
755         ERROR("Can't allocate shared memory for filename\n");
756         palError = ERROR_NOT_ENOUGH_MEMORY;
757         goto CLEANUP1;
758     }
759
760     filelocksPtr->fileLockedRgns = 0;
761     filelocksPtr->prev = 0;
762     filelocksPtr->next = SHMGetInfo(SIID_FILE_LOCKS);
763     filelocksPtr->refCount = 1;
764     filelocksPtr->share_mode = SHARE_MODE_NOT_INITALIZED;
765     filelocksPtr->nbReadAccess = 0;
766     filelocksPtr->nbWriteAccess = 0;
767
768     if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, nextFilelocksPtr, filelocksPtr->next) == FALSE)
769     {
770         ASSERT("Unable to get pointer from shm pointer.\n");
771         palError = ERROR_INTERNAL_ERROR;
772         goto CLEANUP2;
773     }
774     
775     if (nextFilelocksPtr != NULL)
776     {
777         nextFilelocksPtr->prev = shmPtrRet;
778     }
779
780     SHMSetInfo(SIID_FILE_LOCKS, shmPtrRet);
781     goto EXIT;
782
783 CLEANUP2:
784     free(filelocksPtr->unix_filename);
785 CLEANUP1:
786     free(shmPtrRet);
787     shmPtrRet = 0;
788 EXIT:    
789     SHMRelease();
790
791     if (NO_ERROR == palError)
792     {
793         *pshmFileLocks = shmPtrRet;
794     }
795     
796     return palError;
797 }
798
799 PAL_ERROR
800 FILEAddNewLockedRgn(
801     SHMFILELOCKS* fileLocks,
802     PVOID pvControllerInstance, 
803     SHMFILELOCKRGNS *insertAfter,
804     UINT64 lockRgnStart, 
805     UINT64 nbBytesToLock, 
806     LOCK_TYPE lockType
807     )
808 {
809     PAL_ERROR palError = NO_ERROR;
810     SHMFILELOCKRGNS *newLockRgn, *lockRgnPtr;
811     SHMPTR shmNewLockRgn = NULL;
812
813     if ((fileLocks == NULL) || (pvControllerInstance == NULL))
814     {
815         ASSERT("Invalid Null parameter.\n");
816         return FALSE;
817     }
818
819     SHMLock();
820     
821     /* Create a new entry for the new locked region */
822     TRACE("Create a new entry for the new lock region (%I64u %I64u)\n", 
823           lockRgnStart, nbBytesToLock);
824     
825     if ((shmNewLockRgn = malloc(sizeof(SHMFILELOCKRGNS))) == NULL)
826     {
827         ERROR("Can't allocate SHMFILELOCKRGNS structure\n");
828         palError = ERROR_NOT_ENOUGH_MEMORY;
829         goto EXIT;
830     }
831
832     if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, newLockRgn, shmNewLockRgn) == FALSE)
833     {
834         ASSERT("Unable to get pointer from shm pointer.\n");
835         palError = ERROR_INTERNAL_ERROR;
836         goto EXIT;
837     }
838     
839     newLockRgn->processId = GetCurrentProcessId();
840     newLockRgn->pvControllerInstance = pvControllerInstance;
841     newLockRgn->lockRgnStart = lockRgnStart;
842     newLockRgn->nbBytesLocked = nbBytesToLock;
843     newLockRgn->lockType = lockType;
844     
845     /* All locked regions with the same offset should be sorted ascending */
846     /* the sort is based on the length of the locked byte range */
847     if (insertAfter != NULL)
848     {
849         if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, lockRgnPtr, insertAfter->next) == FALSE)
850         {
851             ASSERT("Unable to get pointer from shm pointer.\n");
852             palError = ERROR_INTERNAL_ERROR;
853             goto EXIT;
854         }
855     }
856     else
857     {
858         if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, lockRgnPtr, fileLocks->fileLockedRgns) == FALSE)
859         {
860             ASSERT("Unable to get pointer from shm pointer.\n");
861             palError = ERROR_INTERNAL_ERROR;
862             goto EXIT;
863         }
864     }
865     
866     while(lockRgnPtr != NULL)
867     {
868         if ( (lockRgnPtr->lockRgnStart == newLockRgn->lockRgnStart) &&
869              (newLockRgn->nbBytesLocked > lockRgnPtr->nbBytesLocked))
870         {
871             insertAfter = lockRgnPtr;
872             if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, lockRgnPtr, lockRgnPtr->next) == FALSE)
873             {
874                 ASSERT("Unable to get pointer from shm pointer.\n");
875                 palError = ERROR_INTERNAL_ERROR;
876                 goto EXIT;
877             }
878             continue;
879         }
880
881         break;
882     }
883     
884     if (insertAfter != NULL)
885     {       
886         TRACE("Adding lock after the lock rgn (%I64d %I64d)\n", 
887               insertAfter->lockRgnStart,insertAfter->nbBytesLocked);
888         newLockRgn->next = insertAfter->next;
889         insertAfter->next = shmNewLockRgn;
890     }
891     else
892     {
893         TRACE("adding lock into the head of the list\n");
894         newLockRgn->next = fileLocks->fileLockedRgns;
895         fileLocks->fileLockedRgns = shmNewLockRgn;
896     }
897
898 EXIT:
899
900     if (NO_ERROR != palError && NULL != shmNewLockRgn)
901     {
902         free(shmNewLockRgn);
903     }
904    
905     SHMRelease();
906     
907     return palError;
908 }
909
910 void
911 FILECleanUpLockedRgn(
912     SHMPTR shmFileLocks,
913     DWORD dwAccessRights,
914     PVOID pvControllerInstance
915     )
916 {
917     SHMFILELOCKRGNS *curLockRgn = NULL, *prevLock = NULL;
918     SHMFILELOCKS *fileLocks, *prevFileLocks, *nextFileLocks;
919     SHMPTR shmcurLockRgn;    
920
921     SHMLock();
922
923     if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE)
924     {
925         ASSERT("Unable to get pointer from shm pointer.\n");
926         goto EXIT;
927     }
928
929     if (fileLocks != NULL)
930     {
931         if(fileLocks->fileLockedRgns !=0)
932         {        
933             shmcurLockRgn = fileLocks->fileLockedRgns;
934             if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
935             {
936                 ASSERT("Unable to get pointer from shm pointer.\n");
937                 goto EXIT;
938             }
939             
940             while(curLockRgn != NULL)
941             {
942                 if ((curLockRgn->pvControllerInstance == pvControllerInstance) && 
943                     (curLockRgn->processId == GetCurrentProcessId()))
944                 {
945                     /* found the locked rgn to remove from SHM */
946                     TRACE("Removing the locked region (%I64u, %I64u) from SMH\n", 
947                           curLockRgn->lockRgnStart, curLockRgn->nbBytesLocked);
948                     
949                     if (prevLock == NULL) 
950                     {
951                         /* removing the first lock */
952                         fileLocks->fileLockedRgns = curLockRgn->next;
953                         free(shmcurLockRgn);
954                         shmcurLockRgn = fileLocks->fileLockedRgns;
955                         if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
956                         {
957                             ASSERT("Unable to get pointer from shm pointer.\n");
958                             goto EXIT;
959                         }
960                     }
961                     else
962                     {
963                         prevLock->next = curLockRgn->next;
964                         free(shmcurLockRgn);
965                         shmcurLockRgn = prevLock->next;
966                         if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
967                         {
968                             ASSERT("Unable to get pointer from shm pointer.\n");
969                             goto EXIT;
970                         }
971                     }
972                     continue;
973                 }
974                 
975                 prevLock = curLockRgn;
976                 shmcurLockRgn = curLockRgn->next;
977                 if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
978                 {
979                     ASSERT("Unable to get pointer from shm pointer.\n");
980                     goto EXIT;
981                 }
982             }
983         }
984     
985         if (dwAccessRights & GENERIC_READ)
986         {   
987             fileLocks->nbReadAccess--;      
988         }
989         if (dwAccessRights & GENERIC_WRITE)
990         {
991             fileLocks->nbWriteAccess--; 
992         }  
993
994         /* remove the SHMFILELOCKS structure from SHM if there's no more locked 
995            region left and no more reference to it */        
996         if ((--(fileLocks->refCount) == 0) && (fileLocks->fileLockedRgns == 0))
997         {            
998             TRACE("Removing the SHMFILELOCKS structure from SHM\n");
999
1000             if ( (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, prevFileLocks, fileLocks->prev) == FALSE) ||
1001                  (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, nextFileLocks, fileLocks->next) == FALSE))
1002             {
1003                 ASSERT("Unable to get pointer from shm pointer.\n");
1004                 goto EXIT;
1005             }
1006
1007             if (prevFileLocks == NULL) 
1008             {
1009                 /* removing the first lock file*/
1010                 SHMSetInfo(SIID_FILE_LOCKS, fileLocks->next);
1011             }
1012             else
1013             {
1014                 prevFileLocks->next = fileLocks->next;
1015             }
1016
1017             if (nextFileLocks != NULL)
1018             {
1019                 nextFileLocks->prev = fileLocks->prev;
1020             }
1021
1022             if (fileLocks->unix_filename)
1023                 free(fileLocks->unix_filename);
1024
1025             free(shmFileLocks);
1026         }
1027     }    
1028 EXIT:
1029     SHMRelease();
1030     return;
1031 }
1032