e9fc2e92bcd6b25dfe862926ff417f852fbaae33
[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->dirty ) {
373         fprintf(stderr, "Previous session terminated prematurely\n");
374         UnmapViewOfFile(config_data_p);
375         CloseHandle(hm);
376         CloseHandle(hf);
377         return CM_ERROR_INVAL;
378     }
379
380     mappingSize = config_data_p->bufferSize;
381     baseAddress = config_data_p->baseAddress;
382     UnmapViewOfFile(config_data_p);
383     CloseHandle(hm);
384
385     hm = CreateFileMapping( hf,
386                             NULL,
387                             PAGE_READWRITE,
388                             (DWORD)(mappingSize >> 32),
389                             (DWORD)(mappingSize & 0xFFFFFFFF),
390                             NULL);
391     if (hm == NULL) {
392         if (GetLastError() == ERROR_DISK_FULL) {
393             fprintf(stderr, "Error creating file mapping for \"%s\": disk full [2]\n",
394                   cachePath);
395             CloseHandle(hf);
396             return CM_ERROR_TOOMANYBUFS;
397         }
398         fprintf(stderr, "Error creating file mapping for \"%s\": %d\n",
399                 cachePath, GetLastError());
400         CloseHandle(hf);
401         return CM_ERROR_INVAL;
402     }
403
404     baseAddress = MapViewOfFileEx( hm,
405                                    FILE_MAP_ALL_ACCESS,
406                                    0, 0,
407                                    (SIZE_T)mappingSize,
408                                    baseAddress );
409     if (baseAddress == NULL) {
410         fprintf(stderr, "Error mapping view of file: %d\n", GetLastError());
411         baseAddress = MapViewOfFile( hm,
412                                      FILE_MAP_ALL_ACCESS,
413                                      0, 0,
414                                      (SIZE_T)mappingSize);
415         if (baseAddress == NULL) {
416             CloseHandle(hm);
417             if (hf != INVALID_HANDLE_VALUE)
418                 CloseHandle(hf);
419             return CM_ERROR_INVAL;
420         }
421         fprintf(stderr, "Unable to re-load cache file at base address\n");
422         CloseHandle(hm);
423         if (hf != INVALID_HANDLE_VALUE)
424             CloseHandle(hf);
425         return CM_ERROR_INVAL;
426     }
427     CloseHandle(hm);
428
429     config_data_p = (cm_config_data_t *) baseAddress;
430
431     fprintf(stderr,"AFS Cache data:\n");
432     fprintf(stderr,"  Base Address   = %p\n",baseAddress);
433     fprintf(stderr,"  stats          = %u\n", config_data_p->stats);
434     fprintf(stderr,"  chunkSize      = %u\n", config_data_p->chunkSize);
435     fprintf(stderr,"  blockSize      = %u\n", config_data_p->blockSize);
436     fprintf(stderr,"  bufferSize     = %I64u\n", config_data_p->bufferSize);
437     fprintf(stderr,"  cacheType      = %u\n", config_data_p->cacheType);
438     fprintf(stderr,"  volumeHashTableSize = %u\n", config_data_p->volumeHashTableSize);
439     fprintf(stderr,"  currentVolumes = %u\n", config_data_p->currentVolumes);
440     fprintf(stderr,"  maxVolumes     = %u\n", config_data_p->maxVolumes);
441     fprintf(stderr,"  cellHashTableSize = %u\n", config_data_p->cellHashTableSize);
442     fprintf(stderr,"  currentCells   = %u\n", config_data_p->currentCells);
443     fprintf(stderr,"  maxCells       = %u\n", config_data_p->maxCells);
444     fprintf(stderr,"  scacheHashTableSize  = %u\n", config_data_p->scacheHashTableSize);
445     fprintf(stderr,"  currentSCaches = %u\n", config_data_p->currentSCaches);
446     fprintf(stderr,"  maxSCaches     = %u\n", config_data_p->maxSCaches);
447     cm_data = *config_data_p;
448
449     // perform validation of persisted data structures
450     // if there is a failure, start from scratch
451     if (!cm_IsCacheValid()) {
452         fprintf(stderr,"Cache file fails validation test\n");
453         UnmapViewOfFile(config_data_p);
454         return CM_ERROR_INVAL;
455     }
456
457     fprintf(stderr,"Cache passes validation test\n");
458     UnmapViewOfFile(config_data_p);
459     return 0;
460 }
461
462 DWORD
463 GetVolSerialNumber(char * cachePath)
464 {
465     char rootpath[128];
466     int  i = 0;
467     DWORD serial = 0;
468
469     if ( cachePath[0] == '\\' && cachePath[1] == '\\' ||
470          cachePath[0] == '/' && cachePath[1] == '/' )
471     {
472         rootpath[0]=rootpath[1]='\\';
473         for ( i=2; cachePath[i]; i++ ) {
474             rootpath[i] = cachePath[i];
475             if ( cachePath[i] == '\\' || cachePath[i] == '/' ) {
476                 i++;
477                 break;
478             }
479         }
480     } else if ( cachePath[1] == ':' ) {
481         rootpath[0] = cachePath[0];
482         rootpath[1] = ':';
483         i = 2;
484     }
485
486     for ( ; cachePath[i]; i++ ) {
487         rootpath[i] = cachePath[i];
488         if ( cachePath[i] == '\\' || cachePath[i] == '/' ) {
489             i++;
490             break;
491         }
492     }
493     rootpath[i] = '\0';
494
495     GetVolumeInformation(rootpath, NULL, 0, &serial, NULL, NULL, NULL, 0);
496     return serial;
497 }
498
499 BOOL GetTextualSid( PSID pSid, PBYTE TextualSid, LPDWORD lpdwBufferLen )
500 {
501     PSID_IDENTIFIER_AUTHORITY psia;
502     DWORD dwSubAuthorities;
503     DWORD dwSidRev=SID_REVISION;
504     DWORD dwCounter;
505     DWORD dwSidSize;
506
507     // Validate the binary SID.
508     if(!IsValidSid(pSid))
509         return FALSE;
510
511     // Get the identifier authority value from the SID.
512
513     psia = GetSidIdentifierAuthority(pSid);
514
515     // Get the number of subauthorities in the SID.
516
517     dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
518
519     // Compute the buffer length.
520     // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
521
522     dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1);
523
524     // Check input buffer length.
525     // If too small, indicate the proper size and set the last error.
526
527     if (TextualSid == NULL || *lpdwBufferLen < dwSidSize)
528     {
529         *lpdwBufferLen = dwSidSize;
530         SetLastError(ERROR_INSUFFICIENT_BUFFER);
531         return FALSE;
532     }
533
534     // Add 'S' prefix and revision number to the string.
535     dwSidSize=sprintf(TextualSid, "S-%lu-", dwSidRev );
536
537     // Add a SID identifier authority to the string.
538     if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
539     {
540         dwSidSize+=sprintf(TextualSid + strlen(TextualSid),
541                     "0x%02hx%02hx%02hx%02hx%02hx%02hx",
542                     (USHORT)psia->Value[0],
543                     (USHORT)psia->Value[1],
544                     (USHORT)psia->Value[2],
545                     (USHORT)psia->Value[3],
546                     (USHORT)psia->Value[4],
547                     (USHORT)psia->Value[5]);
548     }
549     else
550     {
551         dwSidSize+=sprintf(TextualSid + strlen(TextualSid),
552                     "%lu",
553                     (ULONG)(psia->Value[5]      )   +
554                     (ULONG)(psia->Value[4] <<  8)   +
555                     (ULONG)(psia->Value[3] << 16)   +
556                     (ULONG)(psia->Value[2] << 24)   );
557     }
558
559     // Add SID subauthorities to the string.
560     //
561     for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
562     {
563         dwSidSize+=sprintf(TextualSid + dwSidSize, "-%lu",
564                     *GetSidSubAuthority(pSid, dwCounter) );
565     }
566
567     return TRUE;
568 }
569
570 PBYTE
571 IsSubAuthValid( PBYTE SidData, DWORD SidLength )
572 {
573     PBYTE       sidPtr;
574
575     sidPtr = NULL;
576     if ( SidLength % sizeof(DWORD) == 0 )  {
577         for ( sidPtr = SidData + SidLength - 5*sizeof(DWORD);
578               sidPtr >= SidData;
579               sidPtr -= sizeof(DWORD) )
580             if ( ((PDWORD)sidPtr)[1] == 0x05000000 &&
581                  ((PDWORD)sidPtr)[2] == 0x00000015 )
582                 break;
583         if ( sidPtr < SidData )
584             sidPtr = NULL;
585     }
586     return sidPtr;
587 }
588
589 BOOL
590 GetMachineSid(PBYTE SidBuffer, DWORD SidSize)
591 {
592     HKEY        hKey;
593     PBYTE       vData;
594     DWORD       dwType;
595     DWORD       dwLen;
596     PBYTE       pSid;
597     DWORD       dwStatus;
598
599     if (!SidBuffer)
600         return FALSE;
601
602     //
603     // Read the last subauthority of the current computer SID
604     //
605     if( RegOpenKey( HKEY_LOCAL_MACHINE, "SECURITY\\SAM\\Domains\\Account",
606                     &hKey) != ERROR_SUCCESS ) {
607         return FALSE;
608     }
609     dwLen = 0;
610     vData = NULL;
611     RegQueryValueEx( hKey, "V", NULL, &dwType, vData, &dwLen );
612     vData = (PBYTE) malloc( dwLen );
613     dwStatus = RegQueryValueEx( hKey, "V", NULL, &dwType, vData, &dwLen );
614     RegCloseKey( hKey );
615     if( dwStatus != ERROR_SUCCESS ) {
616         return FALSE;
617     }
618
619     //
620     // Make sure that we're dealing with a SID we understand
621     //
622     pSid = IsSubAuthValid( vData, dwLen );
623
624     if( !pSid || SidSize < dwLen - (pSid - vData)) {
625         free(vData);
626         return FALSE;
627     }
628
629     memset(SidBuffer, 0, SidSize);
630     memcpy(SidBuffer, pSid, dwLen - (pSid - vData) );
631     free(vData);
632     return TRUE;
633 }
634
635 int
636 cm_InitMappedMemory(DWORD virtualCache, char * cachePath, DWORD stats, DWORD maxVols, DWORD maxCells,
637                     DWORD chunkSize, afs_uint64 cacheBlocks, afs_uint32 blockSize)
638 {
639     afs_uint64 mappingSize;
640     int newCache = 1;
641     DWORD volumeSerialNumber = 0;
642     DWORD sidStringSize = 0;
643     DWORD rc;
644     CHAR  machineSid[6 * sizeof(DWORD)]="";
645     char * baseAddress = NULL;
646     cm_config_data_t * config_data_p;
647     char * p;
648
649     volumeSerialNumber = GetVolSerialNumber(cachePath);
650     GetMachineSid(machineSid, sizeof(machineSid));
651
652     mappingSize = ComputeSizeOfMappingFile(stats, maxVols, maxCells, chunkSize, cacheBlocks, blockSize);
653
654     if ( virtualCache ) {
655         hCacheHeap = HeapCreate( HEAP_GENERATE_EXCEPTIONS, 0, 0);
656
657         baseAddress = HeapAlloc(hCacheHeap, 0, mappingSize);
658
659         if (baseAddress == NULL) {
660             afsi_log("Error allocating Virtual Memory gle=%d",
661                      GetLastError());
662             return CM_ERROR_INVAL;
663         }
664         newCache = 1;
665     } else {
666         HANDLE hf = INVALID_HANDLE_VALUE, hm;
667         PSECURITY_ATTRIBUTES psa;
668
669         psa = CreateCacheFileSA();
670         hf = CreateFile( cachePath,
671                          GENERIC_READ | GENERIC_WRITE,
672                          FILE_SHARE_READ | FILE_SHARE_WRITE,
673                          psa,
674                          OPEN_ALWAYS,
675                          FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
676                          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_FLAG_RANDOM_ACCESS,
677                          NULL);
678         FreeCacheFileSA(psa);
679
680         if (hf == INVALID_HANDLE_VALUE) {
681             afsi_log("Error creating cache file \"%s\" error %d",
682                       cachePath, GetLastError());
683             return CM_ERROR_INVAL;
684         }
685
686         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
687             BY_HANDLE_FILE_INFORMATION fileInfo;
688
689             /* The file is being re-used; check to see if the existing data can be reused */
690             afsi_log("Cache File \"%s\" already exists", cachePath);
691
692             if ( GetFileInformationByHandle(hf, &fileInfo) ) {
693                 afs_uint64 filesize;
694                 afsi_log("Existing File Size: %08X:%08X",
695                           fileInfo.nFileSizeHigh,
696                           fileInfo.nFileSizeLow);
697                 filesize = fileInfo.nFileSizeHigh;
698                 filesize <<= 32;
699                 filesize += fileInfo.nFileSizeLow;
700                 if (filesize > GranularityAdjustment(mappingSize)) {
701                     psa = CreateCacheFileSA();
702                     hf = CreateFile( cachePath,
703                                      GENERIC_READ | GENERIC_WRITE,
704                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
705                                      psa,
706                                      TRUNCATE_EXISTING,
707                                      FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
708                                      FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_FLAG_RANDOM_ACCESS,
709                                      NULL);
710                     FreeCacheFileSA(psa);
711
712                     if (hf == INVALID_HANDLE_VALUE) {
713                         afsi_log("Error creating cache file \"%s\" error %d",
714                                   cachePath, GetLastError());
715                         return CM_ERROR_INVAL;
716                     }
717
718                     GetFileInformationByHandle(hf, &fileInfo);
719                     afsi_log("     New File Size: %08X:%08X",
720                               fileInfo.nFileSizeHigh,
721                               fileInfo.nFileSizeLow);
722                 }
723             }
724
725             hm = CreateFileMapping( hf,
726                                     NULL,
727                                     PAGE_READWRITE,
728                                     0,
729                                     sizeof(cm_config_data_t),
730                                     NULL);
731             if (hm == NULL) {
732                 if (GetLastError() == ERROR_DISK_FULL) {
733                     afsi_log("Error creating file mapping for \"%s\": disk full (%lX)",
734                               cachePath, sizeof(cm_config_data_t));
735
736                     hm = CreateFileMapping( hf,
737                                             NULL,
738                                             PAGE_READWRITE,
739                                             (DWORD)(mappingSize >> 32),
740                                             (DWORD)(mappingSize & 0xFFFFFFFF),
741                                             NULL);
742                     if (hm == NULL) {
743                         if (GetLastError() == ERROR_DISK_FULL) {
744                             CloseHandle(hf);
745                             return CM_ERROR_TOOMANYBUFS;
746                         } else {
747                             afsi_log("Error creating file mapping for \"%s\": %d",
748                                       cachePath, GetLastError());
749                             CloseHandle(hf);
750                             return CM_ERROR_INVAL;
751                         }
752                     } else {
753                         afsi_log("Retry with mapping size (%lX) succeeds", mappingSize);
754                     }
755                 } else {
756                     afsi_log("Error creating file mapping for \"%s\": %d",
757                               cachePath, GetLastError());
758                     CloseHandle(hf);
759                     return CM_ERROR_INVAL;
760                 }
761             }
762
763             config_data_p = MapViewOfFile( hm,
764                                            FILE_MAP_READ,
765                                            0, 0,
766                                            sizeof(cm_config_data_t));
767             if ( config_data_p == NULL ) {
768                 if (hf != INVALID_HANDLE_VALUE)
769                     CloseHandle(hf);
770                 CloseHandle(hm);
771                 return CM_ERROR_INVAL;
772             }
773
774             if ( config_data_p->size == sizeof(cm_config_data_t) &&
775                  config_data_p->magic == CM_CONFIG_DATA_MAGIC &&
776                  config_data_p->stats == stats &&
777                  config_data_p->maxVolumes == maxVols &&
778                  config_data_p->maxCells == maxCells &&
779                  config_data_p->chunkSize == chunkSize &&
780                  config_data_p->buf_nbuffers == cacheBlocks &&
781                  config_data_p->blockSize == blockSize &&
782                  config_data_p->bufferSize == mappingSize)
783             {
784                 if ( config_data_p->dirty ) {
785                     afsi_log("Previous session terminated prematurely");
786                 } else {
787                     baseAddress = config_data_p->baseAddress;
788                     newCache = 0;
789                 }
790             } else {
791                 afsi_log("Configuration changed or Not a persistent cache file");
792             }
793             UnmapViewOfFile(config_data_p);
794             CloseHandle(hm);
795         }
796
797         hm = CreateFileMapping( hf,
798                                 NULL,
799                                 PAGE_READWRITE,
800                                 (DWORD)(mappingSize >> 32),
801                                 (DWORD)(mappingSize & 0xFFFFFFFF),
802                                 NULL);
803         if (hm == NULL) {
804             if (GetLastError() == ERROR_DISK_FULL) {
805                 afsi_log("Error creating file mapping for \"%s\": disk full [2]",
806                           cachePath);
807                 return CM_ERROR_TOOMANYBUFS;
808             }
809             afsi_log("Error creating file mapping for \"%s\": %d",
810                       cachePath, GetLastError());
811             return CM_ERROR_INVAL;
812         }
813         baseAddress = MapViewOfFileEx( hm,
814                                        FILE_MAP_ALL_ACCESS,
815                                        0,
816                                        0,
817                                        (SIZE_T)mappingSize,
818                                        baseAddress );
819         if (baseAddress == NULL) {
820             afsi_log("Error mapping view of file: %d", GetLastError());
821             baseAddress = MapViewOfFile( hm,
822                                          FILE_MAP_ALL_ACCESS,
823                                          0,
824                                          0,
825                                          (SIZE_T)mappingSize);
826             if (baseAddress == NULL) {
827                 if (hf != INVALID_HANDLE_VALUE)
828                     CloseHandle(hf);
829                 CloseHandle(hm);
830                 return CM_ERROR_INVAL;
831             }
832             newCache = 1;
833         }
834         CloseHandle(hm);
835         hMemoryMappedFile = hf;
836     }
837
838     config_data_p = (cm_config_data_t *) baseAddress;
839
840     if (!newCache) {
841         afsi_log("Reusing existing AFS Cache data:");
842         cm_data = *config_data_p;
843
844         afsi_log("  Map Address    = %p", baseAddress);
845         afsi_log("  baseAddress    = %p", config_data_p->baseAddress);
846         afsi_log("  stats          = %u", config_data_p->stats);
847         afsi_log("  chunkSize      = %u", config_data_p->chunkSize);
848         afsi_log("  blockSize      = %u", config_data_p->blockSize);
849         afsi_log("  bufferSize     = %I64u", config_data_p->bufferSize);
850         afsi_log("  cacheType      = %u", config_data_p->cacheType);
851         afsi_log("  volumeHashTableSize  = %u", config_data_p->volumeHashTableSize);
852         afsi_log("  currentVolumes = %u", config_data_p->currentVolumes);
853         afsi_log("  maxVolumes     = %u", config_data_p->maxVolumes);
854         afsi_log("  cellHashTableSize = %u", config_data_p->cellHashTableSize);
855         afsi_log("  currentCells   = %u", config_data_p->currentCells);
856         afsi_log("  maxCells       = %u", config_data_p->maxCells);
857         afsi_log("  scacheHashTableSize  = %u", config_data_p->scacheHashTableSize);
858         afsi_log("  currentSCaches = %u", config_data_p->currentSCaches);
859         afsi_log("  maxSCaches     = %u", config_data_p->maxSCaches);
860
861         /*
862          * perform validation of persisted data structures
863          * if there is a failure, start from scratch
864          *
865          * if the baseAddress changed then the embedded pointers
866          * within the data structures are no longer valid.
867          * in theory we could walk the tree and adjust the pointer
868          * values based on the offet but that has not been
869          * implemented.
870          */
871         if (baseAddress != cm_data.baseAddress ||
872             cm_ValidateCache && !cm_IsCacheValid()) {
873             newCache = 1;
874         }
875     }
876
877     if ( newCache ) {
878         afsi_log("Building AFS Cache from scratch");
879         memset(&cm_data, 0, sizeof(cm_config_data_t));
880         cm_data.size = sizeof(cm_config_data_t);
881         cm_data.magic = CM_CONFIG_DATA_MAGIC;
882         cm_data.baseAddress = baseAddress;
883         cm_data.stats = stats;
884         cm_data.chunkSize = chunkSize;
885         cm_data.blockSize = blockSize;
886         cm_data.bufferSize = mappingSize;
887
888         cm_data.scacheHashTableSize = cm_NextHighestPowerOf2(stats / 2);
889         cm_data.volumeHashTableSize = cm_NextHighestPowerOf2((afs_uint32)(maxVols/7));
890         cm_data.cellHashTableSize = cm_NextHighestPowerOf2((afs_uint32)(maxCells/7));
891         if (virtualCache) {
892             cm_data.cacheType = CM_BUF_CACHETYPE_VIRTUAL;
893         } else {
894             cm_data.cacheType = CM_BUF_CACHETYPE_FILE;
895         }
896
897         cm_data.buf_nbuffers = cacheBlocks;
898         cm_data.buf_nOrigBuffers = cacheBlocks;
899         cm_data.buf_usedCount = 0;
900         cm_data.buf_blockSize = blockSize;
901         cm_data.buf_hashSize = cm_NextHighestPowerOf2((afs_uint32)(cacheBlocks/7));
902
903         cm_data.mountRootGen = 0;
904
905         baseAddress += ComputeSizeOfConfigData();
906         cm_data.volumeBaseAddress = (cm_volume_t *) baseAddress;
907         baseAddress += ComputeSizeOfVolumes(maxVols);
908         cm_data.volumeNameHashTablep = (cm_volume_t **)baseAddress;
909         baseAddress += ComputeSizeOfVolumeHT(maxVols);
910         cm_data.volumeRWIDHashTablep = (cm_volume_t **)baseAddress;
911         baseAddress += ComputeSizeOfVolumeHT(maxVols);
912         cm_data.volumeROIDHashTablep = (cm_volume_t **)baseAddress;
913         baseAddress += ComputeSizeOfVolumeHT(maxVols);
914         cm_data.volumeBKIDHashTablep = (cm_volume_t **)baseAddress;
915         baseAddress += ComputeSizeOfVolumeHT(maxVols);
916         cm_data.cellNameHashTablep = (cm_cell_t **)baseAddress;
917         baseAddress += ComputeSizeOfCellHT(maxCells);
918         cm_data.cellIDHashTablep = (cm_cell_t **)baseAddress;
919         baseAddress += ComputeSizeOfCellHT(maxCells);
920         cm_data.cellBaseAddress = (cm_cell_t *) baseAddress;
921         baseAddress += ComputeSizeOfCells(maxCells);
922         cm_data.aclBaseAddress = (cm_aclent_t *) baseAddress;
923         baseAddress += ComputeSizeOfACLCache(stats);
924         cm_data.scacheBaseAddress = (cm_scache_t *) baseAddress;
925         baseAddress += ComputeSizeOfSCache(stats);
926         cm_data.scacheHashTablep = (cm_scache_t **) baseAddress;
927         baseAddress += ComputeSizeOfSCacheHT(stats);
928         cm_data.dnlcBaseAddress = (cm_nc_t *) baseAddress;
929         baseAddress += ComputeSizeOfDNLCache();
930         cm_data.buf_scacheHashTablepp = (cm_buf_t **) baseAddress;
931         baseAddress += ComputeSizeOfDataHT(cacheBlocks);
932         cm_data.buf_fileHashTablepp = (cm_buf_t **) baseAddress;
933         baseAddress += ComputeSizeOfDataHT(cacheBlocks);
934         cm_data.bufHeaderBaseAddress = (cm_buf_t *) baseAddress;
935         baseAddress += ComputeSizeOfDataHeaders(cacheBlocks);
936         cm_data.bufDataBaseAddress = (char *) baseAddress;
937         baseAddress += ComputeSizeOfDataBuffers(cacheBlocks, blockSize);
938         cm_data.bufEndOfData = (char *) baseAddress;
939         cm_data.buf_dirtyListp = NULL;
940         cm_data.buf_dirtyListEndp = NULL;
941         /* Make sure the fakeDirVersion is always increasing */
942         cm_data.fakeDirVersion = time(NULL);
943         cm_data.fakeUnique = 0;
944         UuidCreate((UUID *)&cm_data.Uuid);
945         cm_data.volSerialNumber = volumeSerialNumber;
946         memcpy(cm_data.Sid, machineSid, sizeof(machineSid));
947
948         /*
949          * make sure that the file is fully allocated
950          * by writing a non-zero byte to the end
951          */
952         cm_data.baseAddress[mappingSize-1] = 0xFF;
953     } else {
954         int gennew = 0;
955
956         if ( volumeSerialNumber == 0 || volumeSerialNumber != cm_data.volSerialNumber ) {
957             gennew = 1;
958             afsi_log("Volume serial number change, generating new UUID");
959             afsi_log("Old volume Serial Number: 0x%x", cm_data.volSerialNumber);
960         } else if ( machineSid[0] && memcmp(machineSid, cm_data.Sid, sizeof(machineSid))) {
961             gennew = 1;
962             afsi_log("Machine Sid changed, generating new UUID");
963             GetTextualSid( (PSID)cm_data.Sid, NULL, &sidStringSize );
964             if (sidStringSize) {
965                 p = malloc(sidStringSize * sizeof(TCHAR));
966                 if (p) {
967                     rc = GetTextualSid( (PSID)cm_data.Sid, p, &sidStringSize );
968                     afsi_log("Old Machine SID: %s", rc ? p : "unknown");
969                     free(p);
970                 }
971             } else {
972                 afsi_log("Old Machine SID: unknown");
973             }
974         }
975
976         if (gennew) {
977             UuidCreate((UUID *)&cm_data.Uuid);
978             cm_data.volSerialNumber = volumeSerialNumber;
979             memcpy(cm_data.Sid, machineSid, sizeof(machineSid));
980         }
981     }
982
983     afsi_log("Volume Serial Number: 0x%x", cm_data.volSerialNumber);
984
985     GetTextualSid( (PSID)cm_data.Sid, NULL, &sidStringSize );
986     if (sidStringSize) {
987         p = malloc(sidStringSize * sizeof(TCHAR));
988         if (p) {
989             rc = GetTextualSid( (PSID)cm_data.Sid, p, &sidStringSize );
990             afsi_log("Machine SID: %s", rc ? p : "unknown");
991             free(p);
992         }
993     } else {
994         afsi_log("Machine SID: unknown");
995     }
996
997     UuidToString((UUID *)&cm_data.Uuid, &p);
998     afsi_log("Initializing Uuid to %s",p);
999     RpcStringFree(&p);
1000
1001     afsi_log("Initializing Volume Data");
1002     cm_InitVolume(newCache, maxVols);
1003
1004     afsi_log("Initializing Cell Data");
1005     cm_InitCell(newCache, maxCells);
1006
1007     afsi_log("Initializing ACL Data");
1008     cm_InitACLCache(newCache, 2*stats);
1009
1010     afsi_log("Initializing Stat Data");
1011     cm_InitSCache(newCache, stats);
1012
1013     afsi_log("Initializing Data Buffers");
1014     cm_InitDCache(newCache, 0, cacheBlocks);
1015
1016     *config_data_p = cm_data;
1017     config_data_p->dirty = 1;
1018
1019     afsi_log("Cache Initialization Complete");
1020     return 0;
1021 }
1022