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