Windows: reset local mount point count during freelance re-initialization
[openafs.git] / src / WINNT / afsd / cm_freelance.c
1 #include <afs/param.h>
2 #include <afs/stds.h>
3
4 #include <windows.h>
5 #include <winreg.h>
6 #include <winsock2.h>
7 #include <stdlib.h>
8 #include <malloc.h>
9 #include <string.h>
10
11 #include <WINNT/afsreg.h>
12 #include "afsd.h"
13 #include <rx/rx.h>
14
15 #ifdef AFS_FREELANCE_CLIENT
16 #include "cm_freelance.h"
17 #include "stdio.h"
18
19 extern void afsi_log(char *pattern, ...);
20
21 static int cm_noLocalMountPoints = 0;
22 char * cm_FakeRootDir = NULL;
23 int cm_fakeDirSize = 0;
24 int cm_fakeDirCallback=0;
25 int cm_fakeGettingCallback=0;
26 static cm_localMountPoint_t* cm_localMountPoints;
27 osi_mutex_t cm_Freelance_Lock;
28 static int cm_localMountPointChangeFlag = 0;
29 int cm_freelanceEnabled = 1;
30 time_t FakeFreelanceModTime = 0x3b49f6e2;
31
32 static int freelance_ShutdownFlag = 0;
33 static HANDLE hFreelanceChangeEvent = 0;
34 static HANDLE hFreelanceSymlinkChangeEvent = 0;
35
36 void cm_InitFakeRootDir();
37
38 void cm_FreelanceChangeNotifier(void * parmp) {
39     HKEY   hkFreelance = 0;
40
41     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
42                       AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
43                       0,
44                       KEY_NOTIFY,
45                       &hkFreelance) == ERROR_SUCCESS) {
46
47         hFreelanceChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
48         if (hFreelanceChangeEvent == NULL) {
49             RegCloseKey(hkFreelance);
50             return;
51         }
52     }
53
54     while ( TRUE ) {
55     /* check hFreelanceChangeEvent to see if it is set. 
56      * if so, call cm_noteLocalMountPointChange()
57      */
58         if (RegNotifyChangeKeyValue( hkFreelance,   /* hKey */
59                                      FALSE,         /* bWatchSubtree */
60                                      REG_NOTIFY_CHANGE_LAST_SET, /* dwNotifyFilter */
61                                      hFreelanceChangeEvent, /* hEvent */
62                                      TRUE          /* fAsynchronous */
63                                      ) != ERROR_SUCCESS) {
64             RegCloseKey(hkFreelance);
65             CloseHandle(hFreelanceChangeEvent);
66             hFreelanceChangeEvent = 0;
67             return;
68         }
69
70         if (WaitForSingleObject(hFreelanceChangeEvent, INFINITE) == WAIT_OBJECT_0)
71         {
72             if (freelance_ShutdownFlag == 1) {     
73                 RegCloseKey(hkFreelance);          
74                 CloseHandle(hFreelanceChangeEvent);
75                 hFreelanceChangeEvent = 0;         
76                 return;                            
77             }                                      
78             cm_noteLocalMountPointChange();
79         }
80     }
81 }
82
83 void cm_FreelanceSymlinkChangeNotifier(void * parmp) {
84     HKEY   hkFreelance = 0;
85
86     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
87                       AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
88                       0,
89                       KEY_NOTIFY,
90                       &hkFreelance) == ERROR_SUCCESS) {
91
92         hFreelanceSymlinkChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
93         if (hFreelanceSymlinkChangeEvent == NULL) {
94             RegCloseKey(hkFreelance);
95             return;
96         }
97     }
98
99     while ( TRUE ) {
100     /* check hFreelanceSymlinkChangeEvent to see if it is set. 
101      * if so, call cm_noteLocalMountPointSymlinkChange()
102      */
103         if (RegNotifyChangeKeyValue( hkFreelance,   /* hKey */
104                                      FALSE,         /* bWatchSubtree */
105                                      REG_NOTIFY_CHANGE_LAST_SET, /* dwNotifyFilter */
106                                      hFreelanceSymlinkChangeEvent, /* hEvent */
107                                      TRUE          /* fAsynchronous */
108                                      ) != ERROR_SUCCESS) {
109             RegCloseKey(hkFreelance);
110             CloseHandle(hFreelanceSymlinkChangeEvent);
111             hFreelanceSymlinkChangeEvent = 0;
112             return;
113         }
114
115         if (WaitForSingleObject(hFreelanceSymlinkChangeEvent, INFINITE) == WAIT_OBJECT_0)
116         {
117             if (freelance_ShutdownFlag == 1) {     
118                 RegCloseKey(hkFreelance);          
119                 CloseHandle(hFreelanceSymlinkChangeEvent);
120                 hFreelanceSymlinkChangeEvent = 0;         
121                 return;                            
122             }                                      
123             cm_noteLocalMountPointChange();
124         }
125     }
126 }
127
128 void                                          
129 cm_FreelanceShutdown(void)                    
130 {                                             
131     freelance_ShutdownFlag = 1;               
132     if (hFreelanceChangeEvent != 0)           
133         thrd_SetEvent(hFreelanceChangeEvent); 
134     if (hFreelanceSymlinkChangeEvent != 0)           
135         thrd_SetEvent(hFreelanceSymlinkChangeEvent); 
136 }                                             
137
138 void cm_InitFreelance() {
139     thread_t phandle;
140     int lpid;
141
142     lock_InitializeMutex(&cm_Freelance_Lock, "Freelance Lock", LOCK_HIERARCHY_FREELANCE_GLOBAL);
143
144     lock_ObtainMutex(&cm_Freelance_Lock);
145     // yj: first we make a call to cm_initLocalMountPoints
146     // to read all the local mount points from the registry
147     cm_InitLocalMountPoints();
148
149     // then we make a call to InitFakeRootDir to create
150     // a fake root directory based on the local mount points
151     cm_InitFakeRootDir();
152     // --- end of yj code
153     lock_ReleaseMutex(&cm_Freelance_Lock);
154
155     /* Start the registry monitor */
156     phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceChangeNotifier,
157                           NULL, 0, &lpid, "cm_FreelanceChangeNotifier");
158     osi_assertx(phandle != NULL, "cm_FreelanceChangeNotifier thread create failure");
159     thrd_CloseHandle(phandle);
160
161     phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceSymlinkChangeNotifier,
162                           NULL, 0, &lpid, "cm_FreelanceSymlinkChangeNotifier");
163     osi_assertx(phandle != NULL, "cm_FreelanceSymlinkChangeNotifier thread create failure");
164     thrd_CloseHandle(phandle);
165 }
166
167 /* yj: Initialization of the fake root directory */
168 /* to be called while holding freelance lock. */
169 void cm_InitFakeRootDir() {
170     int i, t1, t2;
171     char* currentPos;
172     int noChunks;
173
174     // allocate space for the fake info
175     cm_dirHeader_t fakeDirHeader;
176     cm_dirEntry_t fakeEntry;
177     cm_pageHeader_t fakePageHeader;
178
179     // i'm going to calculate how much space is needed for
180     // this fake root directory. we have these rules:
181     // 1. there are cm_noLocalMountPoints number of entries
182     // 2. each page is CM_DIR_PAGESIZE in size
183     // 3. the first 13 chunks of the first page are used for
184     //    some header stuff
185     // 4. the first chunk of all subsequent pages are used
186     //    for page header stuff
187     // 5. a max of CM_DIR_EPP entries are allowed per page
188     // 6. each entry takes 1 or more chunks, depending on 
189     //    the size of the mount point string, as determined
190     //    by cm_NameEntries
191     // 7. each chunk is CM_DIR_CHUNKSIZE bytes
192
193     int CPP = CM_DIR_PAGESIZE / CM_DIR_CHUNKSIZE;
194     int curChunk = 13;  // chunks 0 - 12 are used for header stuff
195                         // of the first page in the directory
196     int curPage = 0;
197     int curDirEntry = 0;
198     int curDirEntryInPage = 0;
199     int sizeOfCurEntry;
200     int dirSize;
201
202     /* Reserve 2 directory chunks for "." and ".." */
203     curChunk += 2;
204
205     while (curDirEntry<cm_noLocalMountPoints) {
206         sizeOfCurEntry = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
207         if ((curChunk + sizeOfCurEntry >= CPP) ||
208              (curDirEntryInPage + 1 >= CM_DIR_EPP)) {
209             curPage++;
210             curDirEntryInPage = 0;
211             curChunk = 1;
212         }
213         curChunk += sizeOfCurEntry;
214         curDirEntry++;
215         curDirEntryInPage++;
216     }
217
218     dirSize = (curPage+1) *  CM_DIR_PAGESIZE;
219     if (cm_fakeDirSize != dirSize) {
220         if (cm_FakeRootDir)
221             free(cm_FakeRootDir);
222         cm_FakeRootDir = malloc(dirSize);
223         cm_fakeDirSize = dirSize;
224     }
225
226     // yj: when we get here, we've figured out how much memory we need and 
227     // allocated the appropriate space for it. we now prceed to fill
228     // it up with entries.
229     curPage = 0;
230     curDirEntry = 0;
231     curDirEntryInPage = 0;
232     curChunk = 0;
233
234     // fields in the directory entry that are unused.
235     fakeEntry.flag = 1;
236     fakeEntry.length = 0;
237     fakeEntry.next = 0;
238     fakeEntry.fid.unique = htonl(1);
239
240     // the first page is special, it uses fakeDirHeader instead of fakePageHeader
241     // we fill up the page with dirEntries that belong there and we make changes
242     // to the fakeDirHeader.header.freeBitmap along the way. Then when we're done
243     // filling up the dirEntries in this page, we copy the fakeDirHeader into 
244     // the top of the page.
245
246     // init the freeBitmap array
247     for (i=0; i<8; i++) 
248         fakeDirHeader.header.freeBitmap[i]=0;
249
250     fakeDirHeader.header.freeBitmap[0] = 0xff;
251     fakeDirHeader.header.freeBitmap[1] = 0x7f;
252
253
254     // we start counting at 13 because the 0th to 12th chunks are used for header
255     curChunk = 13;
256
257     // stick the first 2 entries "." and ".." in
258     fakeEntry.fid.vnode = htonl(1);
259     strcpy(fakeEntry.name, ".");
260     currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
261     memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
262     curChunk++; curDirEntryInPage++;
263     strcpy(fakeEntry.name, "..");
264     currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
265     memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
266     curChunk++; curDirEntryInPage++;
267
268     // keep putting stuff into page 0 if
269     // 1. we're not done with all entries
270     // 2. we have less than CM_DIR_EPP entries in page 0
271     // 3. we're not out of chunks in page 0
272
273     while( (curDirEntry<cm_noLocalMountPoints) && 
274            (curDirEntryInPage < CM_DIR_EPP) &&
275            (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0) <= CPP)) 
276     {       
277
278         noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
279         /* enforce the rule that only directories have odd vnode values */
280         fakeEntry.fid.vnode = htonl((curDirEntry + 1) * 2);
281         fakeEntry.fid.unique = htonl(curDirEntry + 1);
282         currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
283
284         memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
285         strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)->namep);
286         curDirEntry++;
287         curDirEntryInPage++;
288         for (i=0; i<noChunks; i++) {
289             t1 = (curChunk + i) / 8;
290             t2 = curChunk + i - (t1*8);
291             fakeDirHeader.header.freeBitmap[t1] |= (1 << t2);
292         }
293         curChunk+=noChunks;
294     }
295
296     // when we get here, we're done with filling in the entries for page 0
297     // copy in the header info
298
299     memcpy(cm_FakeRootDir, &fakeDirHeader, 13 * CM_DIR_CHUNKSIZE);
300
301     curPage++;
302
303     // ok, page 0's done. Move on to the next page.
304     while (curDirEntry<cm_noLocalMountPoints) {
305         // setup a new page
306         curChunk = 1;                   // the zeroth chunk is reserved for page header
307         curDirEntryInPage = 0; 
308         for (i=0; i<8; i++) {
309             fakePageHeader.freeBitmap[i]=0;
310         }
311         fakePageHeader.freeCount = 0;
312         fakePageHeader.pgcount = 0;
313         fakePageHeader.tag = htons(1234);
314
315         // while we're on the same page...
316         while ( (curDirEntry<cm_noLocalMountPoints) &&
317                 (curDirEntryInPage < CM_DIR_EPP) &&
318                 (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0) <= CPP))
319         {
320             // add an entry to this page
321
322             noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
323             /* enforce the rule that only directories have odd vnode values */
324             fakeEntry.fid.vnode = htonl((curDirEntry + 1) * 2);
325             fakeEntry.fid.unique = htonl(curDirEntry + 1);
326             currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
327             memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
328             strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)->namep);
329             curDirEntry++;
330             curDirEntryInPage++;
331             for (i=0; i<noChunks; i++) {
332                 t1 = (curChunk + i) / 8;
333                 t2 = curChunk + i - (t1*8);
334                 fakePageHeader.freeBitmap[t1] |= (1 << t2);
335             }
336             curChunk+=noChunks;
337         }
338         memcpy(cm_FakeRootDir + curPage * CM_DIR_PAGESIZE, &fakePageHeader, sizeof(fakePageHeader));
339
340         curPage++;
341     }
342
343     // we know the fakeDir is setup properly, so we claim that we have callback
344     osi_Log0(afsd_logp,"cm_InitFakeRootDir fakeDirCallback=1");
345     cm_fakeDirCallback=1;
346
347     // when we get here, we've set up everything! done!
348 }
349
350 int cm_FakeRootFid(cm_fid_t *fidp)
351 {
352     cm_SetFid(fidp, 
353               AFS_FAKE_ROOT_CELL_ID,            /* root cell */
354               AFS_FAKE_ROOT_VOL_ID,            /* root.afs ? */
355               1, 1);
356     return 0;
357 }
358   
359 /* called directly from ioctl */
360 /* called while not holding freelance lock */
361 int cm_noteLocalMountPointChange(void) {
362     lock_ObtainMutex(&cm_Freelance_Lock);
363     cm_data.fakeDirVersion++;
364     cm_localMountPointChangeFlag = 1;
365     lock_ReleaseMutex(&cm_Freelance_Lock);
366     return 1;
367 }
368
369 int cm_getLocalMountPointChange() {
370     return cm_localMountPointChangeFlag;
371 }
372
373 int cm_clearLocalMountPointChange() {
374     cm_localMountPointChangeFlag = 0;
375     return 0;
376 }
377
378 int cm_reInitLocalMountPoints() {
379     cm_fid_t aFid;
380     int i, hash;
381     cm_scache_t *scp, **lscpp, *tscp;
382         
383     osi_Log0(afsd_logp,"----- freelance reinitialization starts ----- ");
384
385     // first we invalidate all the SCPs that were created
386     // for the local mount points
387
388     osi_Log0(afsd_logp,"Invalidating local mount point scp...  ");
389
390     lock_ObtainWrite(&cm_scacheLock);
391     lock_ObtainMutex(&cm_Freelance_Lock);  /* always scache then freelance lock */
392     for (i=0; i<=cm_noLocalMountPoints; i++) {
393         if (i == 0)
394             cm_SetFid(&aFid, AFS_FAKE_ROOT_CELL_ID, AFS_FAKE_ROOT_VOL_ID, 1, 1);
395         else
396             cm_SetFid(&aFid, AFS_FAKE_ROOT_CELL_ID, AFS_FAKE_ROOT_VOL_ID, i*2, i);
397         hash = CM_SCACHE_HASH(&aFid);
398         for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
399             if (scp != cm_data.rootSCachep && cm_FidCmp(&scp->fid, &aFid) == 0) {
400                 // mark the scp to be reused
401                 cm_HoldSCacheNoLock(scp);
402                 lock_ReleaseMutex(&cm_Freelance_Lock);
403                 lock_ReleaseWrite(&cm_scacheLock);
404                 lock_ObtainWrite(&scp->rw);
405                 cm_DiscardSCache(scp);
406
407                 // take the scp out of the hash
408                 lock_ObtainWrite(&cm_scacheLock);
409                 for (lscpp = &cm_data.scacheHashTablep[hash], tscp = cm_data.scacheHashTablep[hash]; 
410                      tscp; 
411                      lscpp = &tscp->nextp, tscp = tscp->nextp) {
412                     if (tscp == scp) {
413                         *lscpp = scp->nextp;
414                         scp->nextp = NULL;
415                         scp->flags &= ~CM_SCACHEFLAG_INHASH;
416                         break;
417                     }
418                 }
419
420                 lock_ReleaseWrite(&scp->rw);
421                 lock_ReleaseWrite(&cm_scacheLock);
422                 cm_CallbackNotifyChange(scp);
423                 lock_ObtainWrite(&cm_scacheLock);
424                 cm_ReleaseSCacheNoLock(scp);
425                 lock_ObtainMutex(&cm_Freelance_Lock);
426             }
427         }
428     }
429     lock_ReleaseWrite(&cm_scacheLock);
430     osi_Log0(afsd_logp,"\tall old scp cleared!");
431
432     // we must free the memory that was allocated in the prev
433     // cm_InitLocalMountPoints call
434     osi_Log0(afsd_logp,"Removing old localmountpoints...  ");
435     free(cm_localMountPoints);
436     cm_localMountPoints = NULL;
437     cm_noLocalMountPoints = 0;
438     osi_Log0(afsd_logp,"\tall old localmountpoints cleared!");
439
440     // now re-init the localmountpoints
441     osi_Log0(afsd_logp,"Creating new localmountpoints...  ");
442     cm_InitLocalMountPoints();
443     osi_Log0(afsd_logp,"\tcreated new set of localmountpoints!");
444
445     // then we re-create that dir
446     osi_Log0(afsd_logp,"Creating new fakedir...  ");
447     cm_InitFakeRootDir();
448     osi_Log0(afsd_logp,"\t\tcreated new fakedir!");
449
450     lock_ReleaseMutex(&cm_Freelance_Lock);
451
452     osi_Log0(afsd_logp,"----- freelance reinit complete -----");
453     return 0;
454 }
455
456
457 // yj: open up the registry and read all the local mount 
458 // points that are stored there. Part of the initialization
459 // process for the freelance client.
460 /* to be called while holding freelance lock. */
461 long cm_InitLocalMountPoints() {
462     FILE *fp;
463     int i;
464     char line[512];
465     char*t, *t2;
466     cm_localMountPoint_t* aLocalMountPoint;
467     char hdir[260];
468     long code;
469     char rootCellName[256];
470     HKEY hkFreelance = 0, hkFreelanceSymlinks = 0;
471     DWORD dwType, dwSize;
472     DWORD dwMountPoints = 0;
473     DWORD dwIndex;
474     DWORD dwSymlinks = 0;
475     FILETIME ftLastWriteTime;
476
477     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
478                       AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
479                       0,
480                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
481                       &hkFreelance) == ERROR_SUCCESS) {
482
483         RegQueryInfoKey( hkFreelance,
484                          NULL,  /* lpClass */
485                          NULL,  /* lpcClass */
486                          NULL,  /* lpReserved */
487                          NULL,  /* lpcSubKeys */
488                          NULL,  /* lpcMaxSubKeyLen */
489                          NULL,  /* lpcMaxClassLen */
490                          &dwMountPoints, /* lpcValues */
491                          NULL,  /* lpcMaxValueNameLen */
492                          NULL,  /* lpcMaxValueLen */
493                          NULL,  /* lpcbSecurityDescriptor */
494                          &ftLastWriteTime /* lpftLastWriteTime */
495                          );
496
497         cm_UnixTimeFromLargeSearchTime(&FakeFreelanceModTime, &ftLastWriteTime);
498
499         if ( dwMountPoints == 0 ) {
500             rootCellName[0] = '.';
501             code = cm_GetRootCellName(&rootCellName[1]);
502             if (code == 0) {
503                 lock_ReleaseMutex(&cm_Freelance_Lock);
504                 cm_FreelanceAddMount(&rootCellName[1], &rootCellName[1], "root.cell.", 0, NULL);
505                 cm_FreelanceAddMount(rootCellName, &rootCellName[1], "root.cell.", 1, NULL);
506                 cm_FreelanceAddMount(".root", &rootCellName[1], "root.afs.", 1, NULL);
507                 lock_ObtainMutex(&cm_Freelance_Lock);
508                 dwMountPoints = 3;
509             }
510         }
511
512         if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
513                           AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
514                           0,
515                           NULL,
516                           REG_OPTION_NON_VOLATILE,
517                           KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
518                           NULL,
519                           &hkFreelanceSymlinks,
520                           NULL) == ERROR_SUCCESS) {
521
522             RegQueryInfoKey( hkFreelanceSymlinks,
523                              NULL,  /* lpClass */
524                              NULL,  /* lpcClass */
525                              NULL,  /* lpReserved */
526                              NULL,  /* lpcSubKeys */
527                              NULL,  /* lpcMaxSubKeyLen */
528                              NULL,  /* lpcMaxClassLen */
529                              &dwSymlinks, /* lpcValues */
530                              NULL,  /* lpcMaxValueNameLen */
531                              NULL,  /* lpcMaxValueLen */
532                              NULL,  /* lpcbSecurityDescriptor */
533                              NULL   /* lpftLastWriteTime */
534                              );
535         }
536
537         // get the number of entries there are from the first line
538         // that we read
539         cm_noLocalMountPoints = dwMountPoints + dwSymlinks;
540
541         // create space to store the local mount points
542         cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
543         aLocalMountPoint = cm_localMountPoints;
544
545         // now we read n lines and parse them into local mount points
546         // where n is the number of local mount points there are, as
547         // determined above.
548         // Each line in the ini file represents 1 local mount point and 
549         // is in the format xxx#yyy:zzz, where xxx is the directory
550         // entry name, yyy is the cell name and zzz is the volume name.
551         // #yyy:zzz together make up the mount point.
552         for ( dwIndex = 0 ; dwIndex < dwMountPoints; dwIndex++ ) {
553             TCHAR szValueName[16];
554             DWORD dwValueSize = 16;
555             dwSize = sizeof(line);
556             if (RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
557                           &dwType, line, &dwSize))
558             {
559                 afsi_log("RegEnumValue(hkFreelance) failed");
560                 cm_noLocalMountPoints--;
561                 continue;
562             }
563
564             afsi_log("Mountpoint[%d] = %s",dwIndex, line);
565
566             /* find the trailing dot; null terminate after it */
567             t2 = strrchr(line, '.');
568             if (t2)
569                 *(t2+1) = '\0';
570
571             for ( t=line;*t;t++ ) {
572                 if ( !isprint(*t) ) {
573                     afsi_log("error occurred while parsing mountpoint entry [%d]: non-printable character", dwIndex);
574                     fprintf(stderr, "error occurred while parsing mountpoint entry [%d]: non-printable character", dwIndex);
575                     cm_noLocalMountPoints--;
576                     continue;
577                 }
578             }
579
580             // line is not empty, so let's parse it
581             t = strchr(line, '#');
582             if (!t)
583                 t = strchr(line, '%');
584             // make sure that there is a '#' or '%' separator in the line
585             if (!t) {
586                 afsi_log("error occurred while parsing mountpoint entry [%d]: no # or %% separator", dwIndex);
587                 fprintf(stderr, "error occurred while parsing mountpoint entry [%d]: no # or %% separator", dwIndex);
588                 cm_noLocalMountPoints--;
589                 continue;
590             }
591
592             aLocalMountPoint->fileType = CM_SCACHETYPE_MOUNTPOINT;
593             aLocalMountPoint->namep=malloc(t-line+1);
594             strncpy(aLocalMountPoint->namep, line, t-line);
595             aLocalMountPoint->namep[t-line] = '\0';
596                 
597             /* copy the mount point string */
598             aLocalMountPoint->mountPointStringp=malloc(strlen(t));
599             strncpy(aLocalMountPoint->mountPointStringp, t, strlen(t)-1);
600             aLocalMountPoint->mountPointStringp[strlen(t)-1] = '\0';
601     
602             osi_Log2(afsd_logp,"found mount point: name %s, string %s",
603                       osi_LogSaveString(afsd_logp,aLocalMountPoint->namep),
604                       osi_LogSaveString(afsd_logp,aLocalMountPoint->mountPointStringp));
605
606             aLocalMountPoint++;
607         }
608
609         for ( dwIndex = 0 ; dwIndex < dwSymlinks; dwIndex++ ) {
610             TCHAR szValueName[16];
611             DWORD dwValueSize = 16;
612             dwSize = sizeof(line);
613             if (RegEnumValue( hkFreelanceSymlinks, dwIndex, szValueName, &dwValueSize, NULL,
614                               &dwType, line, &dwSize))
615             {
616                 afsi_log("RegEnumValue(hkFreelanceSymlinks) failed");
617                 cm_noLocalMountPoints--;
618                 continue;
619             }
620
621             afsi_log("Symlink[%d] = %s",dwIndex, line);
622
623             /* find the trailing dot; null terminate after it */
624             t2 = strrchr(line, '.');
625             if (t2)
626                 *(t2+1) = '\0';
627
628             for ( t=line;*t;t++ ) {
629                 if ( !isprint(*t) ) {
630                     afsi_log("error occurred while parsing symlink entry [%d]: non-printable character", dwIndex);
631                     fprintf(stderr, "error occurred while parsing symlink entry [%d]: non-printable character", dwIndex);
632                     cm_noLocalMountPoints--;
633                     continue;
634                 }
635             }
636
637             // line is not empty, so let's parse it
638             t = strchr(line, ':');
639
640             // make sure that there is a ':' separator in the line
641             if (!t) {
642                 afsi_log("error occurred while parsing symlink entry [%d]: no ':' separator", dwIndex);
643                 fprintf(stderr, "error occurred while parsing symlink entry [%d]: no ':' separator", dwIndex);
644                 cm_noLocalMountPoints--;
645                 continue;
646             }
647
648             aLocalMountPoint->fileType = CM_SCACHETYPE_SYMLINK;
649             aLocalMountPoint->namep=malloc(t-line+1);
650             strncpy(aLocalMountPoint->namep, line, t-line);
651             aLocalMountPoint->namep[t-line] = '\0';
652                 
653             /* copy the symlink string */
654             aLocalMountPoint->mountPointStringp=malloc(strlen(t)-1);
655             strncpy(aLocalMountPoint->mountPointStringp, t+1, strlen(t)-2);
656             aLocalMountPoint->mountPointStringp[strlen(t)-2] = '\0';
657     
658             osi_Log2(afsd_logp,"found symlink: name %s, string %s",
659                       osi_LogSaveString(afsd_logp,aLocalMountPoint->namep),
660                       osi_LogSaveString(afsd_logp,aLocalMountPoint->mountPointStringp));
661
662             aLocalMountPoint++;
663         }
664
665         if ( hkFreelanceSymlinks )
666             RegCloseKey( hkFreelanceSymlinks );
667         RegCloseKey(hkFreelance);
668         return 0;
669     }
670
671     /* What follows is the old code to read freelance mount points 
672      * out of a text file modified to copy the data into the registry
673      */
674     cm_GetConfigDir(hdir, sizeof(hdir));
675     strcat(hdir, AFS_FREELANCE_INI);
676     // open the ini file for reading
677     fp = fopen(hdir, "r");
678     if (!fp) {
679         /* look in the Windows directory where we used to store the file */
680         GetWindowsDirectory(hdir, sizeof(hdir));
681         strcat(hdir,"\\");
682         strcat(hdir, AFS_FREELANCE_INI);
683         fp = fopen(hdir, "r");
684     }
685
686     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
687                     AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
688                     0,
689                     NULL,
690                     REG_OPTION_NON_VOLATILE,
691                     KEY_READ|KEY_WRITE,
692                     NULL,
693                     &hkFreelance,
694                     NULL);
695     dwIndex = 0;
696
697     if (!fp) {
698         RegCloseKey(hkFreelance);
699         rootCellName[0] = '.';
700         code = cm_GetRootCellName(&rootCellName[1]);
701         if (code == 0) {
702             lock_ReleaseMutex(&cm_Freelance_Lock);
703             cm_FreelanceAddMount(&rootCellName[1], &rootCellName[1], "root.cell.", 0, NULL);
704             cm_FreelanceAddMount(rootCellName, &rootCellName[1], "root.cell.", 1, NULL);
705             cm_FreelanceAddMount(".root", &rootCellName[1], "root.afs.", 1, NULL);
706             lock_ObtainMutex(&cm_Freelance_Lock);
707         }
708         return 0;
709     }
710
711     // we successfully opened the file
712     osi_Log0(afsd_logp,"opened afs_freelance.ini");
713         
714     // now we read the first line to see how many entries
715     // there are
716     fgets(line, sizeof(line), fp);
717
718     // if the line is empty at any point when we're reading
719     // we're screwed. report error and return.
720     if (*line==0) {
721         afsi_log("error occurred while reading afs_freelance.ini");
722         fprintf(stderr, "error occurred while reading afs_freelance.ini");
723         return -1;
724     }
725
726     // get the number of entries there are from the first line
727     // that we read
728     cm_noLocalMountPoints = atoi(line);
729
730     if (cm_noLocalMountPoints > 0) {
731         // create space to store the local mount points
732         cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
733         aLocalMountPoint = cm_localMountPoints;
734     }
735
736     // now we read n lines and parse them into local mount points
737     // where n is the number of local mount points there are, as
738     // determined above.
739     // Each line in the ini file represents 1 local mount point and 
740     // is in the format xxx#yyy:zzz, where xxx is the directory
741     // entry name, yyy is the cell name and zzz is the volume name.
742     // #yyy:zzz together make up the mount point.
743     for (i=0; i<cm_noLocalMountPoints; i++) {
744         fgets(line, sizeof(line), fp);
745         // check that the line is not empty
746         if (line[0]==0) {
747             afsi_log("error occurred while parsing entry in %s: empty line in line %d", AFS_FREELANCE_INI, i);
748             fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: empty line in line %d", i);
749             return -1;
750         }
751
752         /* find the trailing dot; null terminate after it */
753         t2 = strrchr(line, '.');
754         if (t2)
755             *(t2+1) = '\0';
756
757         if ( hkFreelance ) {
758             char szIndex[16];
759             /* we are migrating to the registry */
760             sprintf(szIndex,"%d",dwIndex++);
761             dwType = REG_SZ;
762             dwSize = (DWORD)strlen(line) + 1;
763             RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
764         }
765
766         // line is not empty, so let's parse it
767         t = strchr(line, '#');
768         if (!t)
769             t = strchr(line, '%');
770         // make sure that there is a '#' or '%' separator in the line
771         if (!t) {
772             afsi_log("error occurred while parsing entry in %s: no # or %% separator in line %d", AFS_FREELANCE_INI, i);
773             fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # or %% separator in line %d", i);
774             return -1;
775         }
776         aLocalMountPoint->namep=malloc(t-line+1);
777         memcpy(aLocalMountPoint->namep, line, t-line);
778         *(aLocalMountPoint->namep + (t-line)) = 0;
779
780         aLocalMountPoint->mountPointStringp=malloc(strlen(line) - (t-line) + 1);
781         memcpy(aLocalMountPoint->mountPointStringp, t, strlen(line)-(t-line)-1);
782         *(aLocalMountPoint->mountPointStringp + (strlen(line)-(t-line)-1)) = 0;
783
784         osi_Log2(afsd_logp,"found mount point: name %s, string %s",
785                   aLocalMountPoint->namep,
786                   aLocalMountPoint->mountPointStringp);
787
788         aLocalMountPoint++;
789     }
790     fclose(fp);
791     if ( hkFreelance ) {
792         RegCloseKey(hkFreelance);
793         DeleteFile(hdir);
794     }
795     return 0;
796 }
797
798 int cm_getNoLocalMountPoints() {
799     return cm_noLocalMountPoints;
800 }
801
802 long cm_FreelanceMountPointExists(char * filename, int prefix_ok)
803 {
804     char* cp;
805     char line[512];
806     char shortname[200];
807     int found = 0;
808     HKEY hkFreelance = 0;
809     DWORD dwType, dwSize;
810     DWORD dwMountPoints;
811     DWORD dwIndex;
812         
813     lock_ObtainMutex(&cm_Freelance_Lock);
814
815     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
816                       AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
817                       0,
818                       KEY_READ|KEY_QUERY_VALUE,
819                       &hkFreelance) == ERROR_SUCCESS) 
820     {
821         RegQueryInfoKey( hkFreelance,
822                          NULL,  /* lpClass */
823                          NULL,  /* lpcClass */
824                          NULL,  /* lpReserved */
825                          NULL,  /* lpcSubKeys */
826                          NULL,  /* lpcMaxSubKeyLen */
827                          NULL,  /* lpcMaxClassLen */
828                          &dwMountPoints, /* lpcValues */
829                          NULL,  /* lpcMaxValueNameLen */
830                          NULL,  /* lpcMaxValueLen */
831                          NULL,  /* lpcbSecurityDescriptor */
832                          NULL   /* lpftLastWriteTime */
833                          );
834
835         for ( dwIndex = 0; dwIndex < dwMountPoints; dwIndex++ ) {
836             TCHAR szValueName[16];
837             DWORD dwValueSize = 16;
838             dwSize = sizeof(line);
839             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
840                           &dwType, line, &dwSize);
841
842             cp=strchr(line, '#');
843             if (!cp)
844                 cp=strchr(line, '%');
845             memcpy(shortname, line, cp-line);
846             shortname[cp-line]=0;
847
848             if (!strcmp(shortname, filename)) {
849                 found = 1;
850                 break;
851             }
852         }
853         for ( dwIndex = 0; dwIndex < dwMountPoints; dwIndex++ ) {
854             TCHAR szValueName[16];
855             DWORD dwValueSize = 16;
856             dwSize = sizeof(line);
857             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
858                           &dwType, line, &dwSize);
859
860             cp=strchr(line, '#');
861             if (!cp)
862                 cp=strchr(line, '%');
863             memcpy(shortname, line, cp-line);
864             shortname[cp-line]=0;
865
866             if (!cm_stricmp_utf8(shortname, filename)) {
867                 found = 1;
868                 break;
869             }
870
871             if (prefix_ok && strlen(shortname) - strlen(filename) == 1 && !strncmp(shortname, filename, strlen(filename))) {
872                 found = 1;
873                 break;
874             }
875         }
876         RegCloseKey(hkFreelance);
877     }
878
879     lock_ReleaseMutex(&cm_Freelance_Lock);
880
881     return found;
882 }
883
884 long cm_FreelanceSymlinkExists(char * filename, int prefix_ok)
885 {
886     char* cp;
887     char line[512];
888     char shortname[200];
889     int found = 0;
890     HKEY hkFreelance = 0;
891     DWORD dwType, dwSize;
892     DWORD dwSymlinks;
893     DWORD dwIndex;
894         
895     lock_ObtainMutex(&cm_Freelance_Lock);
896
897     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
898                       AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
899                       0,
900                       KEY_READ|KEY_QUERY_VALUE,
901                       &hkFreelance) == ERROR_SUCCESS) 
902     {
903         RegQueryInfoKey( hkFreelance,
904                          NULL,  /* lpClass */
905                          NULL,  /* lpcClass */
906                          NULL,  /* lpReserved */
907                          NULL,  /* lpcSubKeys */
908                          NULL,  /* lpcMaxSubKeyLen */
909                          NULL,  /* lpcMaxClassLen */
910                          &dwSymlinks, /* lpcValues */
911                          NULL,  /* lpcMaxValueNameLen */
912                          NULL,  /* lpcMaxValueLen */
913                          NULL,  /* lpcbSecurityDescriptor */
914                          NULL   /* lpftLastWriteTime */
915                          );
916
917         for ( dwIndex = 0; dwIndex < dwSymlinks; dwIndex++ ) {
918             TCHAR szValueName[16];
919             DWORD dwValueSize = 16;
920             dwSize = sizeof(line);
921             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
922                           &dwType, line, &dwSize);
923
924             cp=strchr(line, ':');
925             memcpy(shortname, line, cp-line);
926             shortname[cp-line]=0;
927
928             if (!strcmp(shortname, filename)) {
929                 found = 1;
930                 break;
931             }
932
933             if (prefix_ok && strlen(shortname) - strlen(filename) == 1 && !strncmp(shortname, filename, strlen(filename))) {
934                 found = 1;
935                 break;
936             }
937         }
938         for ( dwIndex = 0; dwIndex < dwSymlinks; dwIndex++ ) {
939             TCHAR szValueName[16];
940             DWORD dwValueSize = 16;
941             dwSize = sizeof(line);
942             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
943                           &dwType, line, &dwSize);
944
945             cp=strchr(line, ':');
946             memcpy(shortname, line, cp-line);
947             shortname[cp-line]=0;
948
949             if (!cm_stricmp_utf8(shortname, filename)) {
950                 found = 1;
951                 break;
952             }
953         }
954         RegCloseKey(hkFreelance);
955     }
956
957     lock_ReleaseMutex(&cm_Freelance_Lock);
958
959     return found;
960 }
961
962 long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp)
963 {
964     FILE *fp;
965     char hfile[260];
966     char line[512];
967     char fullname[CELL_MAXNAMELEN];
968     int n;
969     int alias = 0;
970     HKEY hkFreelance = 0;
971     DWORD dwType, dwSize;
972     DWORD dwMountPoints;
973     DWORD dwIndex;
974
975     /* before adding, verify the cell name; if it is not a valid cell,
976        don't add the mount point.
977        allow partial matches as a means of poor man's alias. */
978     /* major performance issue? */
979     osi_Log4(afsd_logp,"Freelance Add Mount request: filename=%s cellname=%s volume=%s %s",
980               osi_LogSaveString(afsd_logp,filename), 
981               osi_LogSaveString(afsd_logp,cellname), 
982               osi_LogSaveString(afsd_logp,volume), 
983               rw ? "rw" : "ro");
984
985     if ( filename[0] == '\0' || cellname[0] == '\0' || volume[0] == '\0' )
986         return -1;
987
988     if (cellname[0] == '.') {
989         if (!cm_GetCell_Gen(&cellname[1], fullname, CM_FLAG_CREATE))
990             return -1;
991     } else {
992         if (!cm_GetCell_Gen(cellname, fullname, CM_FLAG_CREATE))
993             return -1;
994     }
995
996     if ( cm_FreelanceMountPointExists(filename, 0) ||
997          cm_FreelanceSymlinkExists(filename, 0) )
998         return -1;
999     
1000     osi_Log1(afsd_logp,"Freelance Adding Mount for Cell: %s", 
1001               osi_LogSaveString(afsd_logp,cellname));
1002
1003     lock_ObtainMutex(&cm_Freelance_Lock);
1004
1005     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
1006                       AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
1007                       0,
1008                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
1009                       &hkFreelance) == ERROR_SUCCESS) {
1010
1011         RegQueryInfoKey( hkFreelance,
1012                          NULL,  /* lpClass */
1013                          NULL,  /* lpcClass */
1014                          NULL,  /* lpReserved */
1015                          NULL,  /* lpcSubKeys */
1016                          NULL,  /* lpcMaxSubKeyLen */
1017                          NULL,  /* lpcMaxClassLen */
1018                          &dwMountPoints, /* lpcValues */
1019                          NULL,  /* lpcMaxValueNameLen */
1020                          NULL,  /* lpcMaxValueLen */
1021                          NULL,  /* lpcbSecurityDescriptor */
1022                          NULL   /* lpftLastWriteTime */
1023                          );
1024
1025         if (rw)
1026             sprintf(line, "%s%%%s:%s", filename, fullname, volume);
1027         else
1028             sprintf(line, "%s#%s:%s", filename, fullname, volume);
1029
1030         /* If we are adding a new value, there must be an unused name
1031          * within the range 0 to dwMountPoints 
1032          */
1033         for ( dwIndex = 0; dwIndex <= dwMountPoints; dwIndex++ ) {
1034             char szIndex[16];
1035             char szMount[1024];
1036
1037             dwSize = sizeof(szMount);
1038             sprintf(szIndex, "%d", dwIndex);
1039             if (RegQueryValueEx( hkFreelance, szIndex, 0, &dwType, szMount, &dwSize) != ERROR_SUCCESS) {
1040                 /* found an unused value */
1041                 dwType = REG_SZ;
1042                 dwSize = (DWORD)strlen(line) + 1;
1043                 RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
1044                 break;
1045             } else {
1046                 int len = (int)strlen(filename);
1047                 if ( dwType == REG_SZ && !strncmp(filename, szMount, len) && 
1048                      (szMount[len] == '%' || szMount[len] == '#')) {
1049                     /* Replace the existing value */
1050                     dwType = REG_SZ;
1051                     dwSize = (DWORD)strlen(line) + 1;
1052                     RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
1053                     break;
1054                 }
1055             }
1056         }
1057         RegCloseKey(hkFreelance);
1058     } else 
1059     {
1060         cm_GetConfigDir(hfile, sizeof(hfile));
1061         strcat(hfile, AFS_FREELANCE_INI);
1062         fp = fopen(hfile, "r+");
1063         if (!fp)
1064             return CM_ERROR_INVAL;
1065         fgets(line, sizeof(line), fp);
1066         n = atoi(line);
1067         n++;
1068         fseek(fp, 0, SEEK_SET);
1069         fprintf(fp, "%d", n);
1070         fseek(fp, 0, SEEK_END);
1071         if (rw)
1072             fprintf(fp, "%s%%%s:%s\n", filename, fullname, volume);
1073         else
1074             fprintf(fp, "%s#%s:%s\n", filename, fullname, volume);
1075         fclose(fp);
1076     }
1077
1078     /* Do this while we are holding the lock */
1079     cm_data.fakeDirVersion++;
1080     cm_localMountPointChangeFlag = 1;
1081     lock_ReleaseMutex(&cm_Freelance_Lock);
1082
1083     if (fidp) {
1084         cm_req_t req;
1085         afs_uint32 code;
1086         cm_scache_t *scp;
1087         clientchar_t *cpath;
1088
1089         cm_InitReq(&req);
1090
1091         cpath = cm_FsStringToClientStringAlloc(filename, -1, NULL);        
1092         if (!cpath)
1093             return CM_ERROR_NOSUCHPATH;
1094         code = cm_NameI(cm_data.rootSCachep, cpath,
1095                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1096                         cm_rootUserp, NULL, &req, &scp);
1097         free(cpath);
1098         if (code)
1099             return code;
1100         *fidp = scp->fid;
1101         cm_ReleaseSCache(scp);
1102     }
1103     
1104     return 0;
1105 }
1106
1107 long cm_FreelanceRemoveMount(char *toremove)
1108 {
1109     int i, n;
1110     char* cp;
1111     char line[512];
1112     char shortname[200];
1113     char hfile[260], hfile2[260];
1114     FILE *fp1, *fp2;
1115     int found=0;
1116     HKEY hkFreelance = 0;
1117     DWORD dwType, dwSize;
1118     DWORD dwMountPoints;
1119     DWORD dwIndex;
1120
1121     lock_ObtainMutex(&cm_Freelance_Lock);
1122
1123     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
1124                       AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
1125                       0,
1126                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
1127                       &hkFreelance) == ERROR_SUCCESS) {
1128
1129         RegQueryInfoKey( hkFreelance,
1130                          NULL,  /* lpClass */
1131                          NULL,  /* lpcClass */
1132                          NULL,  /* lpReserved */
1133                          NULL,  /* lpcSubKeys */
1134                          NULL,  /* lpcMaxSubKeyLen */
1135                          NULL,  /* lpcMaxClassLen */
1136                          &dwMountPoints, /* lpcValues */
1137                          NULL,  /* lpcMaxValueNameLen */
1138                          NULL,  /* lpcMaxValueLen */
1139                          NULL,  /* lpcbSecurityDescriptor */
1140                          NULL   /* lpftLastWriteTime */
1141                          );
1142
1143         for ( dwIndex = 0; dwIndex < dwMountPoints; dwIndex++ ) {
1144             TCHAR szValueName[16];
1145             DWORD dwValueSize = 16;
1146             dwSize = sizeof(line);
1147             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
1148                           &dwType, line, &dwSize);
1149
1150             cp=strchr(line, '#');
1151             if (!cp)
1152                 cp=strchr(line, '%');
1153             memcpy(shortname, line, cp-line);
1154             shortname[cp-line]=0;
1155
1156             if (!strcmp(shortname, toremove)) {
1157                 RegDeleteValue( hkFreelance, szValueName );
1158                 found = 1;
1159                 break;
1160             }
1161         }
1162         RegCloseKey(hkFreelance);
1163     } else 
1164     {
1165         cm_GetConfigDir(hfile, sizeof(hfile));
1166         strcat(hfile, AFS_FREELANCE_INI);
1167         strcpy(hfile2, hfile);
1168         strcat(hfile2, "2");
1169         fp1=fopen(hfile, "r+");
1170         if (!fp1)
1171             return CM_ERROR_INVAL;
1172         fp2=fopen(hfile2, "w+");
1173         if (!fp2) {
1174             fclose(fp1);
1175             return CM_ERROR_INVAL;
1176         }
1177
1178         fgets(line, sizeof(line), fp1);
1179         n=atoi(line);
1180         fprintf(fp2, "%d\n", n-1);
1181
1182         for (i=0; i<n; i++) {
1183             fgets(line, sizeof(line), fp1);
1184             cp=strchr(line, '#');
1185             if (!cp)
1186                 cp=strchr(line, '%');
1187             memcpy(shortname, line, cp-line);
1188             shortname[cp-line]=0;
1189
1190             if (strcmp(shortname, toremove)==0) {
1191
1192             } else {
1193                 found = 1;
1194                 fputs(line, fp2);
1195             }
1196         }
1197
1198         fclose(fp1);
1199         fclose(fp2);
1200         if (found) {
1201             unlink(hfile);
1202             rename(hfile2, hfile);
1203         }
1204     }
1205
1206     if (found) {
1207         /* Do this while we are holding the lock */
1208         cm_data.fakeDirVersion++;
1209         cm_localMountPointChangeFlag = 1;
1210     }
1211     lock_ReleaseMutex(&cm_Freelance_Lock);
1212     return (found ? 0 : CM_ERROR_NOSUCHFILE);
1213 }
1214
1215 long cm_FreelanceAddSymlink(char *filename, char *destination, cm_fid_t *fidp)
1216 {
1217     char line[512];
1218     char fullname[CELL_MAXNAMELEN];
1219     int alias = 0;
1220     HKEY hkFreelanceSymlinks = 0;
1221     DWORD dwType, dwSize;
1222     DWORD dwSymlinks;
1223     DWORD dwIndex;
1224
1225     /* before adding, verify the filename.  If it is already in use, either as 
1226      * as mount point or a cellname, do not permit the creation of the symlink.
1227      */
1228     osi_Log2(afsd_logp,"Freelance Add Symlink request: filename=%s destination=%s",
1229               osi_LogSaveString(afsd_logp,filename), 
1230               osi_LogSaveString(afsd_logp,destination));
1231     
1232     if ( filename[0] == '\0' || destination[0] == '\0' )
1233         return CM_ERROR_INVAL;
1234
1235     fullname[0] = '\0';
1236     if (filename[0] == '.') {
1237         cm_GetCell_Gen(&filename[1], fullname, CM_FLAG_CREATE);
1238         if (cm_stricmp_utf8(&filename[1],fullname) == 0)
1239             return CM_ERROR_EXISTS;
1240     } else {
1241         cm_GetCell_Gen(filename, fullname, CM_FLAG_CREATE);
1242         if (cm_stricmp_utf8(filename,fullname) == 0)
1243             return CM_ERROR_EXISTS;
1244     }
1245
1246     if ( cm_FreelanceMountPointExists(filename, 0) ||
1247          cm_FreelanceSymlinkExists(filename, 0) )
1248         return CM_ERROR_EXISTS;
1249
1250     lock_ObtainMutex(&cm_Freelance_Lock);
1251
1252     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1253                         AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
1254                         0,
1255                         NULL,
1256                         REG_OPTION_NON_VOLATILE,
1257                         KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
1258                         NULL,
1259                         &hkFreelanceSymlinks,
1260                         NULL) == ERROR_SUCCESS) {
1261
1262         RegQueryInfoKey( hkFreelanceSymlinks,
1263                          NULL,  /* lpClass */
1264                          NULL,  /* lpcClass */
1265                          NULL,  /* lpReserved */
1266                          NULL,  /* lpcSubKeys */
1267                          NULL,  /* lpcMaxSubKeyLen */
1268                          NULL,  /* lpcMaxClassLen */
1269                          &dwSymlinks, /* lpcValues */
1270                          NULL,  /* lpcMaxValueNameLen */
1271                          NULL,  /* lpcMaxValueLen */
1272                          NULL,  /* lpcbSecurityDescriptor */
1273                          NULL   /* lpftLastWriteTime */
1274                          );
1275
1276         sprintf(line, "%s:%s.", filename, destination);
1277
1278         /* If we are adding a new value, there must be an unused name
1279          * within the range 0 to dwSymlinks 
1280          */
1281         for ( dwIndex = 0; dwIndex <= dwSymlinks; dwIndex++ ) {
1282             char szIndex[16];
1283             char szLink[1024];
1284
1285             dwSize = sizeof(szLink);
1286             sprintf(szIndex, "%d", dwIndex);
1287             if (RegQueryValueEx( hkFreelanceSymlinks, szIndex, 0, &dwType, szLink, &dwSize) != ERROR_SUCCESS) {
1288                 /* found an unused value */
1289                 dwType = REG_SZ;
1290                 dwSize = (DWORD)strlen(line) + 1;
1291                 RegSetValueEx( hkFreelanceSymlinks, szIndex, 0, dwType, line, dwSize);
1292                 break;
1293             } else {
1294                 int len = (int)strlen(filename);
1295                 if ( dwType == REG_SZ && !strncmp(filename, szLink, len) && szLink[len] == ':') {
1296                     /* Replace the existing value */
1297                     dwType = REG_SZ;
1298                     dwSize = (DWORD)strlen(line) + 1;
1299                     RegSetValueEx( hkFreelanceSymlinks, szIndex, 0, dwType, line, dwSize);
1300                     break;
1301                 }
1302             }
1303         }
1304         RegCloseKey(hkFreelanceSymlinks);
1305     } 
1306
1307     /* Do this while we are holding the lock */
1308     cm_data.fakeDirVersion++;
1309     cm_localMountPointChangeFlag = 1;
1310     lock_ReleaseMutex(&cm_Freelance_Lock);
1311
1312     if (fidp) {
1313         cm_req_t req;
1314         afs_uint32 code;
1315         cm_scache_t *scp;
1316         clientchar_t *cpath;
1317
1318         cm_InitReq(&req);
1319
1320         cpath = cm_FsStringToClientStringAlloc(filename, -1, NULL);        
1321         if (!cpath)
1322             return CM_ERROR_NOSUCHPATH;
1323         code = cm_NameI(cm_data.rootSCachep, cpath,
1324                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1325                         cm_rootUserp, NULL, &req, &scp);
1326         free(cpath);
1327         if (code)
1328             return code;
1329         *fidp = scp->fid;
1330         cm_ReleaseSCache(scp);
1331     }
1332
1333     return 0;
1334 }
1335
1336 long cm_FreelanceRemoveSymlink(char *toremove)
1337 {
1338     char* cp;
1339     char line[512];
1340     char shortname[200];
1341     int found=0;
1342     HKEY hkFreelanceSymlinks = 0;
1343     DWORD dwType, dwSize;
1344     DWORD dwSymlinks;
1345     DWORD dwIndex;
1346
1347     lock_ObtainMutex(&cm_Freelance_Lock);
1348
1349     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
1350                       AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
1351                       0,
1352                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
1353                       &hkFreelanceSymlinks) == ERROR_SUCCESS) {
1354
1355         RegQueryInfoKey( hkFreelanceSymlinks,
1356                          NULL,  /* lpClass */
1357                          NULL,  /* lpcClass */
1358                          NULL,  /* lpReserved */
1359                          NULL,  /* lpcSubKeys */
1360                          NULL,  /* lpcMaxSubKeyLen */
1361                          NULL,  /* lpcMaxClassLen */
1362                          &dwSymlinks, /* lpcValues */
1363                          NULL,  /* lpcMaxValueNameLen */
1364                          NULL,  /* lpcMaxValueLen */
1365                          NULL,  /* lpcbSecurityDescriptor */
1366                          NULL   /* lpftLastWriteTime */
1367                          );
1368
1369         for ( dwIndex = 0; dwIndex < dwSymlinks; dwIndex++ ) {
1370             TCHAR szValueName[16];
1371             DWORD dwValueSize = 16;
1372             dwSize = sizeof(line);
1373             RegEnumValue( hkFreelanceSymlinks, dwIndex, szValueName, &dwValueSize, NULL,
1374                           &dwType, line, &dwSize);
1375
1376             cp=strchr(line, ':');
1377             memcpy(shortname, line, cp-line);
1378             shortname[cp-line]=0;
1379
1380             if (!strcmp(shortname, toremove)) {
1381                 RegDeleteValue( hkFreelanceSymlinks, szValueName );
1382                 found = 1;
1383                 break;
1384             }
1385         }
1386         RegCloseKey(hkFreelanceSymlinks);
1387     }
1388     
1389     if (found) {
1390         /* Do this while we are holding the lock */
1391         cm_data.fakeDirVersion++;
1392         cm_localMountPointChangeFlag = 1;
1393     }
1394     lock_ReleaseMutex(&cm_Freelance_Lock);
1395     return (found ? 0 : CM_ERROR_NOSUCHFILE);
1396 }
1397
1398 long
1399 cm_FreelanceFetchMountPointString(cm_scache_t *scp)
1400 {
1401     lock_ObtainMutex(&cm_Freelance_Lock);
1402     if (!scp->mountPointStringp[0] && 
1403         scp->fid.cell == AFS_FAKE_ROOT_CELL_ID &&
1404         scp->fid.volume == AFS_FAKE_ROOT_VOL_ID && 
1405         scp->fid.unique <= cm_noLocalMountPoints) {
1406         strncpy(scp->mountPointStringp, cm_localMountPoints[scp->fid.unique-1].mountPointStringp, MOUNTPOINTLEN);
1407         scp->mountPointStringp[MOUNTPOINTLEN-1] = 0;    /* null terminate */
1408     }
1409     lock_ReleaseMutex(&cm_Freelance_Lock);
1410
1411     return 0;
1412 }
1413
1414 long 
1415 cm_FreelanceFetchFileType(cm_scache_t *scp)
1416 {
1417     lock_ObtainMutex(&cm_Freelance_Lock);
1418     if (scp->fid.cell == AFS_FAKE_ROOT_CELL_ID &&
1419         scp->fid.volume == AFS_FAKE_ROOT_VOL_ID && 
1420         scp->fid.unique <= cm_noLocalMountPoints) 
1421     {
1422         scp->fileType = cm_localMountPoints[scp->fid.unique-1].fileType;
1423     
1424         if ( scp->fileType == CM_SCACHETYPE_SYMLINK &&
1425              !strnicmp(cm_localMountPoints[scp->fid.unique-1].mountPointStringp, "msdfs:", strlen("msdfs:")) )
1426         {
1427             scp->fileType = CM_SCACHETYPE_DFSLINK;
1428         } 
1429     } else {
1430         scp->fileType = CM_SCACHETYPE_INVALID;
1431     }
1432     lock_ReleaseMutex(&cm_Freelance_Lock);
1433
1434     return 0;
1435 }
1436 #endif /* AFS_FREELANCE_CLIENT */