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