Windows: Direct IO Support for Service
[openafs.git] / src / WINNT / afsd / cm_memmap.c
1
2 #include <afsconfig.h>
3 #include <afs/param.h>
4 #include <roken.h>
5
6 #include <windows.h>
7 #include <tchar.h>
8 #include "afsd.h"
9 #include "cm_memmap.h"
10
11 extern void afsi_log(char *pattern, ...);
12 extern DWORD cm_ValidateCache;
13
14 static HANDLE hMemoryMappedFile = NULL;
15 static HANDLE hCacheHeap = NULL;
16
17 afs_uint64
18 GranularityAdjustment(afs_uint64 size)
19 {
20     SYSTEM_INFO sysInfo;
21     static afs_uint64 qwGranularity = 0;
22
23     if ( !qwGranularity ) {
24         GetSystemInfo(&sysInfo);
25         afsi_log("Granularity - %lX", sysInfo.dwAllocationGranularity);
26         qwGranularity = sysInfo.dwAllocationGranularity;
27     }
28
29     size = (size + (qwGranularity - 1)) & ~(qwGranularity - 1);
30     return size;
31 }
32
33 afs_uint64
34 ComputeSizeOfConfigData(void)
35 {
36     afs_uint64 size;
37     size = sizeof(cm_config_data_t);
38     return size;
39 }
40
41 afs_uint64
42 ComputeSizeOfVolumes(DWORD maxvols)
43 {
44     afs_uint64 size;
45     size = maxvols * sizeof(cm_volume_t);
46     return size;
47 }
48
49 afs_uint64
50 ComputeSizeOfCellHT(DWORD maxcells)
51 {
52     afs_uint64 size;
53     size = cm_NextHighestPowerOf2((afs_uint32)(maxcells/7)) * sizeof(cm_cell_t *);
54     return size;
55 }
56
57 afs_uint64
58 ComputeSizeOfVolumeHT(DWORD maxvols)
59 {
60     afs_uint64 size;
61     size = cm_NextHighestPowerOf2((afs_uint32)(maxvols/7)) * sizeof(cm_volume_t *);
62     return size;
63 }
64
65 afs_uint64
66 ComputeSizeOfCells(DWORD maxcells)
67 {
68     afs_uint64 size;
69     size = maxcells * sizeof(cm_cell_t);
70     return size;
71 }
72
73 afs_uint64
74 ComputeSizeOfACLCache(DWORD stats)
75 {
76     afs_uint64 size;
77     size = 2 * (stats + 10) * sizeof(cm_aclent_t);
78     return size;
79 }
80
81 afs_uint64
82 ComputeSizeOfSCache(DWORD stats)
83 {
84     afs_uint64 size;
85     size = (stats + 10) * sizeof(cm_scache_t);
86     return size;
87 }
88
89 afs_uint64
90 ComputeSizeOfSCacheHT(DWORD stats)
91 {
92     afs_uint64 size;
93     size = cm_NextHighestPowerOf2(stats / 2 ) * sizeof(cm_scache_t *);;
94     return size;
95 }
96
97 afs_uint64
98 ComputeSizeOfDNLCache(void)
99 {
100     afs_uint64 size;
101     size = NHSIZE * sizeof(cm_nc_t *) + NCSIZE * sizeof(cm_nc_t);
102     return size;
103 }
104
105 afs_uint64
106 ComputeSizeOfDataBuffers(afs_uint64 cacheBlocks, DWORD blockSize)
107 {
108     afs_uint64 size;
109     size = cacheBlocks * blockSize;
110     return size;
111 }
112
113 afs_uint64
114 ComputeSizeOfDataHT(afs_uint64 cacheBlocks)
115 {
116     afs_uint64 size;
117     size = cm_NextHighestPowerOf2((afs_uint32)(cacheBlocks/7)) * sizeof(cm_buf_t *);
118     return size;
119 }
120
121 afs_uint64
122 ComputeSizeOfDataHeaders(afs_uint64 cacheBlocks)
123 {
124     afs_uint64 size;
125     size = cacheBlocks * sizeof(cm_buf_t);
126     return size;
127 }
128
129 afs_uint64
130 ComputeSizeOfMappingFile(DWORD stats, DWORD maxVols, DWORD maxCells, DWORD chunkSize, afs_uint64 cacheBlocks, DWORD blockSize)
131 {
132     afs_uint64 size;
133
134     size       =  ComputeSizeOfConfigData()
135                +  ComputeSizeOfVolumes(maxVols)
136                +  4 * ComputeSizeOfVolumeHT(maxVols)
137                +  ComputeSizeOfCells(maxCells)
138                +  2 * ComputeSizeOfCellHT(maxCells)
139                +  ComputeSizeOfACLCache(stats)
140                +  ComputeSizeOfSCache(stats)
141                +  ComputeSizeOfSCacheHT(stats)
142                +  ComputeSizeOfDNLCache()
143                +  ComputeSizeOfDataBuffers(cacheBlocks, blockSize)
144                +  2 * ComputeSizeOfDataHT(cacheBlocks)
145                +  ComputeSizeOfDataHeaders(cacheBlocks);
146     return size;
147 }
148
149 /* Create a security attribute structure suitable for use when the cache file
150  * is created.  What we mainly want is that only the administrator should be
151  * able to do anything with the file.  We create an ACL with only one entry,
152  * an entry that grants all rights to the administrator.
153  */
154 PSECURITY_ATTRIBUTES CreateCacheFileSA()
155 {
156     PSECURITY_ATTRIBUTES psa;
157     PSECURITY_DESCRIPTOR psd;
158     SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
159     PSID AdminSID;
160     DWORD AdminSIDlength;
161     PACL AdminOnlyACL;
162     DWORD ACLlength;
163
164     /* Get Administrator SID */
165     AllocateAndInitializeSid(&authority, 2,
166                               SECURITY_BUILTIN_DOMAIN_RID,
167                               DOMAIN_ALIAS_RID_ADMINS,
168                               0, 0, 0, 0, 0, 0,
169                               &AdminSID);
170
171     /* Create Administrator-only ACL */
172     AdminSIDlength = GetLengthSid(AdminSID);
173     ACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
174         + AdminSIDlength - sizeof(DWORD);
175     AdminOnlyACL = GlobalAlloc(GMEM_FIXED, ACLlength);
176     InitializeAcl(AdminOnlyACL, ACLlength, ACL_REVISION);
177     AddAccessAllowedAce(AdminOnlyACL, ACL_REVISION,
178                          STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
179                          AdminSID);
180
181     /* Create security descriptor */
182     psd = GlobalAlloc(GMEM_FIXED, sizeof(SECURITY_DESCRIPTOR));
183     InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
184     SetSecurityDescriptorDacl(psd, TRUE, AdminOnlyACL, FALSE);
185
186     /* Create security attributes structure */
187     psa = GlobalAlloc(GMEM_FIXED, sizeof(SECURITY_ATTRIBUTES));
188     psa->nLength = sizeof(SECURITY_ATTRIBUTES);
189     psa->lpSecurityDescriptor = psd;
190     psa->bInheritHandle = FALSE;
191
192     return psa;
193 }
194
195
196 /* Free a security attribute structure created by CreateCacheFileSA() */
197 VOID FreeCacheFileSA(PSECURITY_ATTRIBUTES psa)
198 {
199     BOOL b1, b2;
200     PACL pAcl;
201
202     GetSecurityDescriptorDacl(psa->lpSecurityDescriptor, &b1, &pAcl, &b2);
203     GlobalFree(pAcl);
204     GlobalFree(psa->lpSecurityDescriptor);
205     GlobalFree(psa);
206 }
207
208 int
209 cm_IsCacheValid(void)
210 {
211     int rc = 1;
212
213     afsi_log("Validating Cache Contents");
214
215     if (cm_ValidateACLCache()) {
216         afsi_log("ACL Cache validation failure");
217         rc = 0;
218     } else if (cm_ValidateDCache()) {
219         afsi_log("Data Cache validation failure");
220         rc = 0;
221     } else if (cm_ValidateVolume()) {
222         afsi_log("Volume validation failure");
223         rc = 0;
224     } else if (cm_ValidateCell()) {
225         afsi_log("Cell validation failure");
226         rc = 0;
227     } else if (cm_ValidateSCache()) {
228         afsi_log("Stat Cache validation failure");
229         rc = 0;
230     }
231
232     return rc;
233 }
234
235 int
236 cm_ShutdownMappedMemory(void)
237 {
238     cm_config_data_t * config_data_p = (cm_config_data_t *)cm_data.baseAddress;
239     int dirty = 0;
240
241     afsi_log("Closing AFS Cache:");
242     afsi_log("  Base Address   = %p", config_data_p);
243     afsi_log("  stats          = %u", cm_data.stats);
244     afsi_log("  chunkSize      = %u", cm_data.chunkSize);
245     afsi_log("  blockSize      = %u", cm_data.blockSize);
246     afsi_log("  bufferSize     = %I64u", cm_data.bufferSize);
247     afsi_log("  cacheType      = %u", cm_data.cacheType);
248     afsi_log("  volumeHashTableSize = %u", cm_data.volumeHashTableSize);
249     afsi_log("  currentVolumes = %u", cm_data.currentVolumes);
250     afsi_log("  maxVolumes     = %u", cm_data.maxVolumes);
251     afsi_log("  cellHashTableSize = %u", cm_data.cellHashTableSize);
252     afsi_log("  currentCells   = %u", cm_data.currentCells);
253     afsi_log("  maxCells       = %u", cm_data.maxCells);
254     afsi_log("  scacheHashTableSize  = %u", cm_data.scacheHashTableSize);
255     afsi_log("  currentSCaches = %u", cm_data.currentSCaches);
256     afsi_log("  maxSCaches     = %u", cm_data.maxSCaches);
257
258     cm_ShutdownDCache();
259     cm_ShutdownSCache();
260     cm_ShutdownACLCache();
261     cm_ShutdownCell();
262     cm_ShutdownVolume();
263
264     if (hCacheHeap) {
265         HeapFree(hCacheHeap, 0, cm_data.baseAddress);
266         HeapDestroy(hCacheHeap);
267         afsi_log("Memory Heap has been destroyed");
268     } else {
269         if (cm_ValidateCache == 2)
270             dirty = !cm_IsCacheValid();
271
272         *config_data_p = cm_data;
273         config_data_p->dirty = dirty;
274         UnmapViewOfFile(config_data_p);
275         CloseHandle(hMemoryMappedFile);
276         hMemoryMappedFile = NULL;
277         afsi_log("Memory Mapped File has been closed");
278     }
279     return 0;
280 }
281
282 int
283 cm_ValidateMappedMemory(char * cachePath)
284 {
285     HANDLE hf = INVALID_HANDLE_VALUE, hm;
286     PSECURITY_ATTRIBUTES psa;
287     BY_HANDLE_FILE_INFORMATION fileInfo;
288     int newFile = 1;
289     afs_uint64 mappingSize;
290     char * baseAddress = NULL;
291     cm_config_data_t * config_data_p;
292
293     psa = CreateCacheFileSA();
294     hf = CreateFile( cachePath,
295                      GENERIC_READ | GENERIC_WRITE,
296                      FILE_SHARE_READ | FILE_SHARE_WRITE,
297                      psa,
298                      OPEN_EXISTING,
299                      FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
300                      FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_FLAG_RANDOM_ACCESS,
301                      NULL);
302     FreeCacheFileSA(psa);
303
304     if (hf == INVALID_HANDLE_VALUE) {
305         fprintf(stderr, "Error creating cache file \"%s\" error %d\n",
306                  cachePath, GetLastError());
307         return CM_ERROR_INVAL;
308     }
309
310     /* The file is being re-used; check to see if the existing data can be reused */
311     if ( !GetFileInformationByHandle(hf, &fileInfo) ) {
312         CloseHandle(hf);
313         fprintf(stderr, "Unable to obtain File Information\n");
314         return CM_ERROR_INVAL;
315     }
316
317     afsi_log("Existing File Size: %08X:%08X",
318               fileInfo.nFileSizeHigh,
319               fileInfo.nFileSizeLow);
320
321     hm = CreateFileMapping( hf,
322                             NULL,
323                             PAGE_READWRITE,
324                             0,
325                             sizeof(cm_config_data_t),
326                             NULL);
327     if (hm == NULL) {
328         if (GetLastError() == ERROR_DISK_FULL) {
329             fprintf(stderr, "Error creating file mapping for \"%s\": disk full (%lX)\n",
330                      cachePath, sizeof(cm_config_data_t));
331
332             hm = CreateFileMapping( hf,
333                                     NULL,
334                                     PAGE_READWRITE,
335                                     0,
336                                     fileInfo.nFileSizeLow,
337                                     NULL);
338             if (hm == NULL) {
339                 if (GetLastError() == ERROR_DISK_FULL) {
340                     CloseHandle(hf);
341                     return CM_ERROR_TOOMANYBUFS;
342                 } else {
343                     fprintf(stderr,"Error creating file mapping for \"%s\": %d\n",
344                               cachePath, GetLastError());
345                     CloseHandle(hf);
346                     return CM_ERROR_INVAL;
347                 }
348             } else {
349                 fprintf(stderr, "Retry with file size (%lX) succeeds",
350                          fileInfo.nFileSizeLow);
351             }
352         } else {
353             afsi_log("Error creating file mapping for \"%s\": %d",
354                       cachePath, GetLastError());
355             CloseHandle(hf);
356             return CM_ERROR_INVAL;
357         }
358     }
359
360     config_data_p = MapViewOfFile( hm,
361                                    FILE_MAP_READ,
362                                    0, 0,
363                                    sizeof(cm_config_data_t));
364     if ( config_data_p == NULL ) {
365         fprintf(stderr, "Unable to MapViewOfFile\n");
366         if (hf != INVALID_HANDLE_VALUE)
367             CloseHandle(hf);
368         CloseHandle(hm);
369         return CM_ERROR_INVAL;
370     }
371
372     if ( config_data_p->size != sizeof(cm_config_data_t) ) {
373         fprintf(stderr, "AFSCache Header Size 0x%08X != afsd_service Header Size 0x%08X\n",
374                 config_data_p->size, sizeof(cm_config_data_t));
375         UnmapViewOfFile(config_data_p);
376         CloseHandle(hm);
377         CloseHandle(hf);
378         return CM_ERROR_INVAL;
379     }
380
381     if ( config_data_p->magic != CM_CONFIG_DATA_MAGIC ) {
382         fprintf(stderr, "AFSCache Magic 0x%08X != afsd_service Magic 0x%08X\n",
383                 config_data_p->magic, CM_CONFIG_DATA_MAGIC);
384         UnmapViewOfFile(config_data_p);
385         CloseHandle(hm);
386         CloseHandle(hf);
387         return CM_ERROR_INVAL;
388     }
389
390     if ( config_data_p->dirty ) {
391         fprintf(stderr, "Previous session terminated prematurely\n");
392         UnmapViewOfFile(config_data_p);
393         CloseHandle(hm);
394         CloseHandle(hf);
395         return CM_ERROR_INVAL;
396     }
397
398     mappingSize = config_data_p->bufferSize;
399     baseAddress = config_data_p->baseAddress;
400     UnmapViewOfFile(config_data_p);
401     CloseHandle(hm);
402
403     hm = CreateFileMapping( hf,
404                             NULL,
405                             PAGE_READWRITE,
406                             (DWORD)(mappingSize >> 32),
407                             (DWORD)(mappingSize & 0xFFFFFFFF),
408                             NULL);
409     if (hm == NULL) {
410         if (GetLastError() == ERROR_DISK_FULL) {
411             fprintf(stderr, "Error creating file mapping for \"%s\": disk full [2]\n",
412                   cachePath);
413             CloseHandle(hf);
414             return CM_ERROR_TOOMANYBUFS;
415         }
416         fprintf(stderr, "Error creating file mapping for \"%s\": %d\n",
417                 cachePath, GetLastError());
418         CloseHandle(hf);
419         return CM_ERROR_INVAL;
420     }
421
422     baseAddress = MapViewOfFileEx( hm,
423                                    FILE_MAP_ALL_ACCESS,
424                                    0, 0,
425                                    (SIZE_T)mappingSize,
426                                    baseAddress );
427     if (baseAddress == NULL) {
428         fprintf(stderr, "Error mapping view of file: %d\n", GetLastError());
429         baseAddress = MapViewOfFile( hm,
430                                      FILE_MAP_ALL_ACCESS,
431                                      0, 0,
432                                      (SIZE_T)mappingSize);
433         if (baseAddress == NULL) {
434             CloseHandle(hm);
435             if (hf != INVALID_HANDLE_VALUE)
436                 CloseHandle(hf);
437             return CM_ERROR_INVAL;
438         }
439         fprintf(stderr, "Unable to re-load cache file at base address\n");
440         CloseHandle(hm);
441         if (hf != INVALID_HANDLE_VALUE)
442             CloseHandle(hf);
443         return CM_ERROR_INVAL;
444     }
445     CloseHandle(hm);
446
447     config_data_p = (cm_config_data_t *) baseAddress;
448
449     fprintf(stderr,"AFS Cache data:\n");
450     fprintf(stderr,"  Header size    = %u\n", config_data_p->size);
451     fprintf(stderr,"  Magic          = %08x\n", config_data_p->magic);
452     fprintf(stderr,"  Base Address   = %p\n", baseAddress);
453     fprintf(stderr,"  stats          = %u\n", config_data_p->stats);
454     fprintf(stderr,"  chunkSize      = %u\n", config_data_p->chunkSize);
455     fprintf(stderr,"  blockSize      = %u\n", config_data_p->blockSize);
456     fprintf(stderr,"  bufferSize     = %I64u\n", config_data_p->bufferSize);
457     fprintf(stderr,"  cacheType      = %u\n", config_data_p->cacheType);
458     fprintf(stderr,"  dirty          = %u\n", config_data_p->dirty);
459     fprintf(stderr,"  volumeHashTableSize = %u\n", config_data_p->volumeHashTableSize);
460     fprintf(stderr,"  currentVolumes = %u\n", config_data_p->currentVolumes);
461     fprintf(stderr,"  maxVolumes     = %u\n", config_data_p->maxVolumes);
462     fprintf(stderr,"  cellHashTableSize = %u\n", config_data_p->cellHashTableSize);
463     fprintf(stderr,"  currentCells   = %u\n", config_data_p->currentCells);
464     fprintf(stderr,"  maxCells       = %u\n", config_data_p->maxCells);
465     fprintf(stderr,"  scacheHashTableSize  = %u\n", config_data_p->scacheHashTableSize);
466     fprintf(stderr,"  currentSCaches = %u\n", config_data_p->currentSCaches);
467     fprintf(stderr,"  maxSCaches     = %u\n", config_data_p->maxSCaches);
468     cm_data = *config_data_p;
469
470     // perform validation of persisted data structures
471     // if there is a failure, start from scratch
472     if (!cm_IsCacheValid()) {
473         fprintf(stderr,"Cache file fails validation test\n");
474         UnmapViewOfFile(config_data_p);
475         return CM_ERROR_INVAL;
476     }
477
478     fprintf(stderr,"Cache passes validation test\n");
479     UnmapViewOfFile(config_data_p);
480     return 0;
481 }
482
483 DWORD
484 GetVolSerialNumber(char * cachePath)
485 {
486     char rootpath[128];
487     int  i = 0;
488     DWORD serial = 0;
489
490     if ( cachePath[0] == '\\' && cachePath[1] == '\\' ||
491          cachePath[0] == '/' && cachePath[1] == '/' )
492     {
493         rootpath[0]=rootpath[1]='\\';
494         for ( i=2; cachePath[i]; i++ ) {
495             rootpath[i] = cachePath[i];
496             if ( cachePath[i] == '\\' || cachePath[i] == '/' ) {
497                 i++;
498                 break;
499             }
500         }
501     } else if ( cachePath[1] == ':' ) {
502         rootpath[0] = cachePath[0];
503         rootpath[1] = ':';
504         i = 2;
505     }
506
507     for ( ; cachePath[i]; i++ ) {
508         rootpath[i] = cachePath[i];
509         if ( cachePath[i] == '\\' || cachePath[i] == '/' ) {
510             i++;
511             break;
512         }
513     }
514     rootpath[i] = '\0';
515
516     GetVolumeInformation(rootpath, NULL, 0, &serial, NULL, NULL, NULL, 0);
517     return serial;
518 }
519
520 BOOL GetTextualSid( PSID pSid, PBYTE TextualSid, LPDWORD lpdwBufferLen )
521 {
522     PSID_IDENTIFIER_AUTHORITY psia;
523     DWORD dwSubAuthorities;
524     DWORD dwSidRev=SID_REVISION;
525     DWORD dwCounter;
526     DWORD dwSidSize;
527
528     // Validate the binary SID.
529     if(!IsValidSid(pSid))
530         return FALSE;
531
532     // Get the identifier authority value from the SID.
533
534     psia = GetSidIdentifierAuthority(pSid);
535
536     // Get the number of subauthorities in the SID.
537
538     dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
539
540     // Compute the buffer length.
541     // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
542
543     dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1);
544
545     // Check input buffer length.
546     // If too small, indicate the proper size and set the last error.
547
548     if (TextualSid == NULL || *lpdwBufferLen < dwSidSize)
549     {
550         *lpdwBufferLen = dwSidSize;
551         SetLastError(ERROR_INSUFFICIENT_BUFFER);
552         return FALSE;
553     }
554
555     // Add 'S' prefix and revision number to the string.
556     dwSidSize=sprintf(TextualSid, "S-%lu-", dwSidRev );
557
558     // Add a SID identifier authority to the string.
559     if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
560     {
561         dwSidSize+=sprintf(TextualSid + strlen(TextualSid),
562                     "0x%02hx%02hx%02hx%02hx%02hx%02hx",
563                     (USHORT)psia->Value[0],
564                     (USHORT)psia->Value[1],
565                     (USHORT)psia->Value[2],
566                     (USHORT)psia->Value[3],
567                     (USHORT)psia->Value[4],
568                     (USHORT)psia->Value[5]);
569     }
570     else
571     {
572         dwSidSize+=sprintf(TextualSid + strlen(TextualSid),
573                     "%lu",
574                     (ULONG)(psia->Value[5]      )   +
575                     (ULONG)(psia->Value[4] <<  8)   +
576                     (ULONG)(psia->Value[3] << 16)   +
577                     (ULONG)(psia->Value[2] << 24)   );
578     }
579
580     // Add SID subauthorities to the string.
581     //
582     for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
583     {
584         dwSidSize+=sprintf(TextualSid + dwSidSize, "-%lu",
585                     *GetSidSubAuthority(pSid, dwCounter) );
586     }
587
588     return TRUE;
589 }
590
591 PBYTE
592 IsSubAuthValid( PBYTE SidData, DWORD SidLength )
593 {
594     PBYTE       sidPtr;
595
596     sidPtr = NULL;
597     if ( SidLength % sizeof(DWORD) == 0 )  {
598         for ( sidPtr = SidData + SidLength - 5*sizeof(DWORD);
599               sidPtr >= SidData;
600               sidPtr -= sizeof(DWORD) )
601             if ( ((PDWORD)sidPtr)[1] == 0x05000000 &&
602                  ((PDWORD)sidPtr)[2] == 0x00000015 )
603                 break;
604         if ( sidPtr < SidData )
605             sidPtr = NULL;
606     }
607     return sidPtr;
608 }
609
610 BOOL
611 GetMachineSid(PBYTE SidBuffer, DWORD SidSize)
612 {
613     HKEY        hKey;
614     PBYTE       vData;
615     DWORD       dwType;
616     DWORD       dwLen;
617     PBYTE       pSid;
618     DWORD       dwStatus;
619
620     if (!SidBuffer)
621         return FALSE;
622
623     //
624     // Read the last subauthority of the current computer SID
625     //
626     if( RegOpenKey( HKEY_LOCAL_MACHINE, "SECURITY\\SAM\\Domains\\Account",
627                     &hKey) != ERROR_SUCCESS ) {
628         return FALSE;
629     }
630     dwLen = 0;
631     vData = NULL;
632     RegQueryValueEx( hKey, "V", NULL, &dwType, vData, &dwLen );
633     vData = (PBYTE) malloc( dwLen );
634     dwStatus = RegQueryValueEx( hKey, "V", NULL, &dwType, vData, &dwLen );
635     RegCloseKey( hKey );
636     if( dwStatus != ERROR_SUCCESS ) {
637         return FALSE;
638     }
639
640     //
641     // Make sure that we're dealing with a SID we understand
642     //
643     pSid = IsSubAuthValid( vData, dwLen );
644
645     if( !pSid || SidSize < dwLen - (pSid - vData)) {
646         free(vData);
647         return FALSE;
648     }
649
650     memset(SidBuffer, 0, SidSize);
651     memcpy(SidBuffer, pSid, dwLen - (pSid - vData) );
652     free(vData);
653     return TRUE;
654 }
655
656 int
657 cm_InitMappedMemory(DWORD virtualCache, char * cachePath, DWORD stats, DWORD maxVols, DWORD maxCells,
658                     DWORD chunkSize, afs_uint64 cacheBlocks, afs_uint32 blockSize)
659 {
660     afs_uint64 mappingSize;
661     int newCache = 1;
662     DWORD volumeSerialNumber = 0;
663     DWORD sidStringSize = 0;
664     DWORD rc;
665     CHAR  machineSid[6 * sizeof(DWORD)]="";
666     char * baseAddress = NULL;
667     cm_config_data_t * config_data_p;
668     char * p;
669
670     volumeSerialNumber = GetVolSerialNumber(cachePath);
671     GetMachineSid(machineSid, sizeof(machineSid));
672
673     mappingSize = ComputeSizeOfMappingFile(stats, maxVols, maxCells, chunkSize, cacheBlocks, blockSize);
674
675     if ( virtualCache ) {
676         hCacheHeap = HeapCreate( HEAP_GENERATE_EXCEPTIONS, 0, 0);
677
678         baseAddress = HeapAlloc(hCacheHeap, 0, mappingSize);
679
680         if (baseAddress == NULL) {
681             afsi_log("Error allocating Virtual Memory gle=%d",
682                      GetLastError());
683             return CM_ERROR_INVAL;
684         }
685         newCache = 1;
686     } else {
687         HANDLE hf = INVALID_HANDLE_VALUE, hm;
688         PSECURITY_ATTRIBUTES psa;
689
690         psa = CreateCacheFileSA();
691         hf = CreateFile( cachePath,
692                          GENERIC_READ | GENERIC_WRITE,
693                          FILE_SHARE_READ | FILE_SHARE_WRITE,
694                          psa,
695                          OPEN_ALWAYS,
696                          FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
697                          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_FLAG_RANDOM_ACCESS,
698                          NULL);
699         FreeCacheFileSA(psa);
700
701         if (hf == INVALID_HANDLE_VALUE) {
702             afsi_log("Error creating cache file \"%s\" error %d",
703                       cachePath, GetLastError());
704             return CM_ERROR_INVAL;
705         }
706
707         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
708             BY_HANDLE_FILE_INFORMATION fileInfo;
709
710             /* The file is being re-used; check to see if the existing data can be reused */
711             afsi_log("Cache File \"%s\" already exists", cachePath);
712
713             if ( GetFileInformationByHandle(hf, &fileInfo) ) {
714                 afs_uint64 filesize;
715                 afsi_log("Existing File Size: %08X:%08X",
716                           fileInfo.nFileSizeHigh,
717                           fileInfo.nFileSizeLow);
718                 filesize = fileInfo.nFileSizeHigh;
719                 filesize <<= 32;
720                 filesize += fileInfo.nFileSizeLow;
721                 if (filesize > GranularityAdjustment(mappingSize)) {
722                     psa = CreateCacheFileSA();
723                     hf = CreateFile( cachePath,
724                                      GENERIC_READ | GENERIC_WRITE,
725                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
726                                      psa,
727                                      TRUNCATE_EXISTING,
728                                      FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
729                                      FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_FLAG_RANDOM_ACCESS,
730                                      NULL);
731                     FreeCacheFileSA(psa);
732
733                     if (hf == INVALID_HANDLE_VALUE) {
734                         afsi_log("Error creating cache file \"%s\" error %d",
735                                   cachePath, GetLastError());
736                         return CM_ERROR_INVAL;
737                     }
738
739                     GetFileInformationByHandle(hf, &fileInfo);
740                     afsi_log("     New File Size: %08X:%08X",
741                               fileInfo.nFileSizeHigh,
742                               fileInfo.nFileSizeLow);
743                 }
744             }
745
746             hm = CreateFileMapping( hf,
747                                     NULL,
748                                     PAGE_READWRITE,
749                                     0,
750                                     sizeof(cm_config_data_t),
751                                     NULL);
752             if (hm == NULL) {
753                 if (GetLastError() == ERROR_DISK_FULL) {
754                     afsi_log("Error creating file mapping for \"%s\": disk full (%lX)",
755                               cachePath, sizeof(cm_config_data_t));
756
757                     hm = CreateFileMapping( hf,
758                                             NULL,
759                                             PAGE_READWRITE,
760                                             (DWORD)(mappingSize >> 32),
761                                             (DWORD)(mappingSize & 0xFFFFFFFF),
762                                             NULL);
763                     if (hm == NULL) {
764                         if (GetLastError() == ERROR_DISK_FULL) {
765                             CloseHandle(hf);
766                             return CM_ERROR_TOOMANYBUFS;
767                         } else {
768                             afsi_log("Error creating file mapping for \"%s\": %d",
769                                       cachePath, GetLastError());
770                             CloseHandle(hf);
771                             return CM_ERROR_INVAL;
772                         }
773                     } else {
774                         afsi_log("Retry with mapping size (%lX) succeeds", mappingSize);
775                     }
776                 } else {
777                     afsi_log("Error creating file mapping for \"%s\": %d",
778                               cachePath, GetLastError());
779                     CloseHandle(hf);
780                     return CM_ERROR_INVAL;
781                 }
782             }
783
784             config_data_p = MapViewOfFile( hm,
785                                            FILE_MAP_READ,
786                                            0, 0,
787                                            sizeof(cm_config_data_t));
788             if ( config_data_p == NULL ) {
789                 if (hf != INVALID_HANDLE_VALUE)
790                     CloseHandle(hf);
791                 CloseHandle(hm);
792                 return CM_ERROR_INVAL;
793             }
794
795             if ( config_data_p->size == sizeof(cm_config_data_t) &&
796                  config_data_p->magic == CM_CONFIG_DATA_MAGIC &&
797                  config_data_p->stats == stats &&
798                  config_data_p->maxVolumes == maxVols &&
799                  config_data_p->maxCells == maxCells &&
800                  config_data_p->chunkSize == chunkSize &&
801                  config_data_p->buf_nbuffers == cacheBlocks &&
802                  config_data_p->blockSize == blockSize &&
803                  config_data_p->bufferSize == mappingSize)
804             {
805                 if ( config_data_p->dirty ) {
806                     afsi_log("Previous session terminated prematurely");
807                 } else {
808                     baseAddress = config_data_p->baseAddress;
809                     newCache = 0;
810                 }
811             } else {
812                 afsi_log("Configuration changed or Not a persistent cache file");
813             }
814             UnmapViewOfFile(config_data_p);
815             CloseHandle(hm);
816         }
817
818         hm = CreateFileMapping( hf,
819                                 NULL,
820                                 PAGE_READWRITE,
821                                 (DWORD)(mappingSize >> 32),
822                                 (DWORD)(mappingSize & 0xFFFFFFFF),
823                                 NULL);
824         if (hm == NULL) {
825             if (GetLastError() == ERROR_DISK_FULL) {
826                 afsi_log("Error creating file mapping for \"%s\": disk full [2]",
827                           cachePath);
828                 return CM_ERROR_TOOMANYBUFS;
829             }
830             afsi_log("Error creating file mapping for \"%s\": %d",
831                       cachePath, GetLastError());
832             return CM_ERROR_INVAL;
833         }
834         baseAddress = MapViewOfFileEx( hm,
835                                        FILE_MAP_ALL_ACCESS,
836                                        0,
837                                        0,
838                                        (SIZE_T)mappingSize,
839                                        baseAddress );
840         if (baseAddress == NULL) {
841             afsi_log("Error mapping view of file: %d", GetLastError());
842             baseAddress = MapViewOfFile( hm,
843                                          FILE_MAP_ALL_ACCESS,
844                                          0,
845                                          0,
846                                          (SIZE_T)mappingSize);
847             if (baseAddress == NULL) {
848                 if (hf != INVALID_HANDLE_VALUE)
849                     CloseHandle(hf);
850                 CloseHandle(hm);
851                 return CM_ERROR_INVAL;
852             }
853             newCache = 1;
854         }
855         CloseHandle(hm);
856         hMemoryMappedFile = hf;
857     }
858
859     config_data_p = (cm_config_data_t *) baseAddress;
860
861     if (!newCache) {
862         afsi_log("Reusing existing AFS Cache data:");
863         cm_data = *config_data_p;
864
865         afsi_log("  Map Address    = %p", baseAddress);
866         afsi_log("  baseAddress    = %p", config_data_p->baseAddress);
867         afsi_log("  stats          = %u", config_data_p->stats);
868         afsi_log("  chunkSize      = %u", config_data_p->chunkSize);
869         afsi_log("  blockSize      = %u", config_data_p->blockSize);
870         afsi_log("  bufferSize     = %I64u", config_data_p->bufferSize);
871         afsi_log("  cacheType      = %u", config_data_p->cacheType);
872         afsi_log("  volumeHashTableSize  = %u", config_data_p->volumeHashTableSize);
873         afsi_log("  currentVolumes = %u", config_data_p->currentVolumes);
874         afsi_log("  maxVolumes     = %u", config_data_p->maxVolumes);
875         afsi_log("  cellHashTableSize = %u", config_data_p->cellHashTableSize);
876         afsi_log("  currentCells   = %u", config_data_p->currentCells);
877         afsi_log("  maxCells       = %u", config_data_p->maxCells);
878         afsi_log("  scacheHashTableSize  = %u", config_data_p->scacheHashTableSize);
879         afsi_log("  currentSCaches = %u", config_data_p->currentSCaches);
880         afsi_log("  maxSCaches     = %u", config_data_p->maxSCaches);
881
882         /*
883          * perform validation of persisted data structures
884          * if there is a failure, start from scratch
885          *
886          * if the baseAddress changed then the embedded pointers
887          * within the data structures are no longer valid.
888          * in theory we could walk the tree and adjust the pointer
889          * values based on the offet but that has not been
890          * implemented.
891          */
892         if (baseAddress != cm_data.baseAddress ||
893             cm_ValidateCache && !cm_IsCacheValid()) {
894             newCache = 1;
895         }
896     }
897
898     if ( newCache ) {
899         afsi_log("Building AFS Cache from scratch");
900         memset(&cm_data, 0, sizeof(cm_config_data_t));
901         cm_data.size = sizeof(cm_config_data_t);
902         cm_data.magic = CM_CONFIG_DATA_MAGIC;
903         cm_data.baseAddress = baseAddress;
904         cm_data.stats = stats;
905         cm_data.chunkSize = chunkSize;
906         cm_data.blockSize = blockSize;
907         cm_data.bufferSize = mappingSize;
908
909         cm_data.scacheHashTableSize = cm_NextHighestPowerOf2(stats / 2);
910         cm_data.volumeHashTableSize = cm_NextHighestPowerOf2((afs_uint32)(maxVols/7));
911         cm_data.cellHashTableSize = cm_NextHighestPowerOf2((afs_uint32)(maxCells/7));
912         if (virtualCache) {
913             cm_data.cacheType = CM_BUF_CACHETYPE_VIRTUAL;
914         } else {
915             cm_data.cacheType = CM_BUF_CACHETYPE_FILE;
916         }
917
918         cm_data.buf_nbuffers = cacheBlocks;
919         cm_data.buf_nOrigBuffers = cacheBlocks;
920         cm_data.buf_usedCount = 0;
921         cm_data.buf_blockSize = blockSize;
922         cm_data.buf_hashSize = cm_NextHighestPowerOf2((afs_uint32)(cacheBlocks/7));
923
924         cm_data.mountRootGen = 0;
925
926         baseAddress += ComputeSizeOfConfigData();
927         cm_data.volumeBaseAddress = (cm_volume_t *) baseAddress;
928         baseAddress += ComputeSizeOfVolumes(maxVols);
929         cm_data.volumeNameHashTablep = (cm_volume_t **)baseAddress;
930         baseAddress += ComputeSizeOfVolumeHT(maxVols);
931         cm_data.volumeRWIDHashTablep = (cm_volume_t **)baseAddress;
932         baseAddress += ComputeSizeOfVolumeHT(maxVols);
933         cm_data.volumeROIDHashTablep = (cm_volume_t **)baseAddress;
934         baseAddress += ComputeSizeOfVolumeHT(maxVols);
935         cm_data.volumeBKIDHashTablep = (cm_volume_t **)baseAddress;
936         baseAddress += ComputeSizeOfVolumeHT(maxVols);
937         cm_data.cellNameHashTablep = (cm_cell_t **)baseAddress;
938         baseAddress += ComputeSizeOfCellHT(maxCells);
939         cm_data.cellIDHashTablep = (cm_cell_t **)baseAddress;
940         baseAddress += ComputeSizeOfCellHT(maxCells);
941         cm_data.cellBaseAddress = (cm_cell_t *) baseAddress;
942         baseAddress += ComputeSizeOfCells(maxCells);
943         cm_data.aclBaseAddress = (cm_aclent_t *) baseAddress;
944         baseAddress += ComputeSizeOfACLCache(stats);
945         cm_data.scacheBaseAddress = (cm_scache_t *) baseAddress;
946         baseAddress += ComputeSizeOfSCache(stats);
947         cm_data.scacheHashTablep = (cm_scache_t **) baseAddress;
948         baseAddress += ComputeSizeOfSCacheHT(stats);
949         cm_data.dnlcBaseAddress = (cm_nc_t *) baseAddress;
950         baseAddress += ComputeSizeOfDNLCache();
951         cm_data.buf_scacheHashTablepp = (cm_buf_t **) baseAddress;
952         baseAddress += ComputeSizeOfDataHT(cacheBlocks);
953         cm_data.buf_fileHashTablepp = (cm_buf_t **) baseAddress;
954         baseAddress += ComputeSizeOfDataHT(cacheBlocks);
955         cm_data.bufHeaderBaseAddress = (cm_buf_t *) baseAddress;
956         baseAddress += ComputeSizeOfDataHeaders(cacheBlocks);
957         cm_data.bufDataBaseAddress = (char *) baseAddress;
958         baseAddress += ComputeSizeOfDataBuffers(cacheBlocks, blockSize);
959         cm_data.bufEndOfData = (char *) baseAddress;
960         cm_data.buf_dirtyListp = NULL;
961         cm_data.buf_dirtyListEndp = NULL;
962         /* Make sure the fakeDirVersion is always increasing */
963         cm_data.fakeDirVersion = time(NULL);
964         cm_data.fakeUnique = 0;
965         UuidCreate((UUID *)&cm_data.Uuid);
966         cm_data.volSerialNumber = volumeSerialNumber;
967         memcpy(cm_data.Sid, machineSid, sizeof(machineSid));
968
969         /*
970          * make sure that the file is fully allocated
971          * by writing a non-zero byte to the end
972          */
973         cm_data.baseAddress[mappingSize-1] = 0xFF;
974     } else {
975         int gennew = 0;
976
977         if ( volumeSerialNumber == 0 || volumeSerialNumber != cm_data.volSerialNumber ) {
978             gennew = 1;
979             afsi_log("Volume serial number change, generating new UUID");
980             afsi_log("Old volume Serial Number: 0x%x", cm_data.volSerialNumber);
981         } else if ( machineSid[0] && memcmp(machineSid, cm_data.Sid, sizeof(machineSid))) {
982             gennew = 1;
983             afsi_log("Machine Sid changed, generating new UUID");
984             GetTextualSid( (PSID)cm_data.Sid, NULL, &sidStringSize );
985             if (sidStringSize) {
986                 p = malloc(sidStringSize * sizeof(TCHAR));
987                 if (p) {
988                     rc = GetTextualSid( (PSID)cm_data.Sid, p, &sidStringSize );
989                     afsi_log("Old Machine SID: %s", rc ? p : "unknown");
990                     free(p);
991                 }
992             } else {
993                 afsi_log("Old Machine SID: unknown");
994             }
995         }
996
997         if (gennew) {
998             UuidCreate((UUID *)&cm_data.Uuid);
999             cm_data.volSerialNumber = volumeSerialNumber;
1000             memcpy(cm_data.Sid, machineSid, sizeof(machineSid));
1001         }
1002     }
1003
1004     afsi_log("Volume Serial Number: 0x%x", cm_data.volSerialNumber);
1005
1006     GetTextualSid( (PSID)cm_data.Sid, NULL, &sidStringSize );
1007     if (sidStringSize) {
1008         p = malloc(sidStringSize * sizeof(TCHAR));
1009         if (p) {
1010             rc = GetTextualSid( (PSID)cm_data.Sid, p, &sidStringSize );
1011             afsi_log("Machine SID: %s", rc ? p : "unknown");
1012             free(p);
1013         }
1014     } else {
1015         afsi_log("Machine SID: unknown");
1016     }
1017
1018     UuidToString((UUID *)&cm_data.Uuid, &p);
1019     afsi_log("Initializing Uuid to %s",p);
1020     RpcStringFree(&p);
1021
1022     afsi_log("Initializing Volume Data");
1023     cm_InitVolume(newCache, maxVols);
1024
1025     afsi_log("Initializing Cell Data");
1026     cm_InitCell(newCache, maxCells);
1027
1028     afsi_log("Initializing ACL Data");
1029     cm_InitACLCache(newCache, 2*stats);
1030
1031     afsi_log("Initializing Stat Data");
1032     cm_InitSCache(newCache, stats);
1033
1034     afsi_log("Initializing Data Buffers");
1035     cm_InitDCache(newCache, 0, cacheBlocks);
1036
1037     *config_data_p = cm_data;
1038     config_data_p->dirty = 1;
1039
1040     afsi_log("Cache Initialization Complete");
1041     return 0;
1042 }
1043