ddbd0e6a66ae384586dd59cbcbbbd6149825da35
[openafs.git] / src / WINNT / afsd / cm_freelance.c
1 #include <afs/param.h>
2 #include <afs/stds.h>
3
4 #ifndef DJGPP
5 #include <windows.h>
6 #include <winreg.h>
7 #include <winsock2.h>
8 #else
9 #include <netdb.h>
10 #endif /* !DJGPP */
11 #include <stdlib.h>
12 #include <malloc.h>
13 #include <string.h>
14
15 #include <rx/rx.h>
16
17 #include "afsd.h"
18 #ifdef AFS_FREELANCE_CLIENT
19 #include "cm_freelance.h"
20 #include "stdio.h"
21
22 extern void afsi_log(char *pattern, ...);
23
24 int cm_noLocalMountPoints;
25 int cm_fakeDirSize;
26 int cm_fakeDirCallback=0;
27 int cm_fakeGettingCallback=0;
28 int cm_fakeDirVersion = 0x8;
29 cm_localMountPoint_t* cm_localMountPoints;
30 osi_mutex_t cm_Freelance_Lock;
31 int cm_localMountPointChangeFlag = 0;
32 int cm_freelanceEnabled = 0;
33 afs_uint32    FakeFreelanceModTime = 0x3b49f6e2;
34
35 void cm_InitFakeRootDir();
36
37 #if !defined(DJGPP)
38 void cm_FreelanceChangeNotifier(void * parmp) {
39     HANDLE hFreelanceChangeEvent = 0;
40     HKEY   hkFreelance = 0;
41
42     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
43                       "SOFTWARE\\OpenAFS\\Client\\Freelance",
44                       0,
45                       KEY_NOTIFY,
46                       &hkFreelance) == ERROR_SUCCESS) {
47
48         hFreelanceChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
49         if (hFreelanceChangeEvent == NULL) {
50             RegCloseKey(hkFreelance);
51             return;
52         }
53     }
54
55     while ( TRUE ) {
56     /* check hFreelanceChangeEvent to see if it is set. 
57      * if so, call cm_noteLocalMountPointChange()
58      */
59         if (RegNotifyChangeKeyValue( hkFreelance,   /* hKey */
60                                      FALSE,         /* bWatchSubtree */
61                                      REG_NOTIFY_CHANGE_LAST_SET, /* dwNotifyFilter */
62                                      hFreelanceChangeEvent, /* hEvent */
63                                      TRUE          /* fAsynchronous */
64                                      ) != ERROR_SUCCESS) {
65             RegCloseKey(hkFreelance);
66             CloseHandle(hFreelanceChangeEvent);
67             return;
68         }
69
70         if (WaitForSingleObject(hFreelanceChangeEvent, INFINITE) == WAIT_OBJECT_0)
71         {
72             cm_noteLocalMountPointChange();
73         }
74     }
75 }
76 #endif
77
78 void cm_InitFreelance() {
79 #if !defined(DJGPP)
80     thread_t phandle;
81     int lpid;
82 #endif
83
84         lock_InitializeMutex(&cm_Freelance_Lock, "Freelance Lock");
85
86         // yj: first we make a call to cm_initLocalMountPoints
87         // to read all the local mount points from an ini file
88         cm_InitLocalMountPoints();
89
90         // then we make a call to InitFakeRootDir to create
91         // a fake root directory based on the local mount points
92         cm_InitFakeRootDir();
93         // --- end of yj code
94
95 #if !defined(DJGPP)
96     /* Start the registry monitor */
97     phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceChangeNotifier,
98                           NULL, 0, &lpid, "cm_FreelanceChangeNotifier");
99         osi_assert(phandle != NULL);
100         thrd_CloseHandle(phandle);
101 #endif
102 }
103
104 /* yj: Initialization of the fake root directory */
105 /* to be called while holding freelance lock unless during init. */
106 void cm_InitFakeRootDir() {
107         
108         int i, t1, t2;
109         char* currentPos;
110         int noChunks;
111
112         // allocate space for the fake info
113         cm_dirHeader_t fakeDirHeader;
114         cm_dirEntry_t fakeEntry;
115         cm_pageHeader_t fakePageHeader;
116
117         // i'm going to calculate how much space is needed for
118         // this fake root directory. we have these rules:
119         // 1. there are cm_noLocalMountPoints number of entries
120         // 2. each page is CM_DIR_PAGESIZE in size
121         // 3. the first 13 chunks of the first page are used for
122         //    some header stuff
123         // 4. the first chunk of all subsequent pages are used
124         //    for page header stuff
125         // 5. a max of CM_DIR_EPP entries are allowed per page
126         // 6. each entry takes 1 or more chunks, depending on 
127         //    the size of the mount point string, as determined
128         //    by cm_NameEntries
129         // 7. each chunk is CM_DIR_CHUNKSIZE bytes
130
131         int CPP = CM_DIR_PAGESIZE / CM_DIR_CHUNKSIZE;
132         int curChunk = 13;      // chunks 0 - 12 are used for header stuff
133                                                 // of the first page in the directory
134         int curPage = 0;
135         int curDirEntry = 0;
136         int curDirEntryInPage = 0;
137         int sizeOfCurEntry;
138         int dirSize;
139
140         /* Reserve 2 directory chunks for "." and ".." */
141         curChunk += 2;
142
143         while (curDirEntry!=cm_noLocalMountPoints) {
144                 sizeOfCurEntry = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
145                 if ((curChunk + sizeOfCurEntry >= CPP) ||
146                         (curDirEntryInPage + 1 >= CM_DIR_EPP)) {
147                         curPage++;
148                         curDirEntryInPage = 0;
149                         curChunk = 1;
150                 }
151                 curChunk += sizeOfCurEntry;
152                 curDirEntry++;
153                 curDirEntryInPage++;
154         }
155
156         dirSize = (curPage+1) *  CM_DIR_PAGESIZE;
157         cm_FakeRootDir = malloc(dirSize);
158         cm_fakeDirSize = dirSize;
159
160         // yj: when we get here, we've figured out how much memory we need and 
161         // allocated the appropriate space for it. we now prceed to fill
162         // it up with entries.
163         curPage = 0;
164         curDirEntry = 0;
165         curDirEntryInPage = 0;
166         curChunk = 0;
167         
168         // fields in the directory entry that are unused.
169         fakeEntry.flag = 1;
170         fakeEntry.length = 0;
171         fakeEntry.next = 0;
172         fakeEntry.fid.unique = htonl(1);
173
174         // the first page is special, it uses fakeDirHeader instead of fakePageHeader
175         // we fill up the page with dirEntries that belong there and we make changes
176         // to the fakeDirHeader.header.freeBitmap along the way. Then when we're done
177         // filling up the dirEntries in this page, we copy the fakeDirHeader into 
178         // the top of the page.
179
180         // init the freeBitmap array
181         for (i=0; i<8; i++) 
182                 fakeDirHeader.header.freeBitmap[i]=0;
183
184         fakeDirHeader.header.freeBitmap[0] = 0xff;
185         fakeDirHeader.header.freeBitmap[1] = 0x7f;
186         
187
188         // we start counting at 13 because the 0th to 12th chunks are used for header
189         curChunk = 13;
190
191         // stick the first 2 entries "." and ".." in
192         fakeEntry.fid.unique = htonl(1);
193         fakeEntry.fid.vnode = htonl(1);
194         strcpy(fakeEntry.name, ".");
195         currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
196         memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
197         curChunk++; curDirEntryInPage++;
198         strcpy(fakeEntry.name, "..");
199         currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
200         memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
201         curChunk++; curDirEntryInPage++;
202
203         // keep putting stuff into page 0 if
204         // 1. we're not done with all entries
205         // 2. we have less than CM_DIR_EPP entries in page 0
206         // 3. we're not out of chunks in page 0
207
208         while( (curDirEntry!=cm_noLocalMountPoints) && 
209                    (curDirEntryInPage < CM_DIR_EPP) &&
210                    (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0) <= CPP)) 
211         {
212
213                 noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
214                 fakeEntry.fid.vnode = htonl(curDirEntry + 2);
215                 currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
216
217                 memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
218                 strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)->namep);
219                 curDirEntry++;
220                 curDirEntryInPage++;
221                 for (i=0; i<noChunks; i++) {
222                         t1 = (curChunk + i) / 8;
223                         t2 = curChunk + i - (t1*8);
224                         fakeDirHeader.header.freeBitmap[t1] |= (1 << t2);
225                 }
226                 curChunk+=noChunks;
227         }
228
229         // when we get here, we're done with filling in the entries for page 0
230         // copy in the header info
231
232         memcpy(cm_FakeRootDir, &fakeDirHeader, 13 * CM_DIR_CHUNKSIZE);
233
234         curPage++;
235
236         // ok, page 0's done. Move on to the next page.
237         while (curDirEntry!=cm_noLocalMountPoints) {
238                 // setup a new page
239                 curChunk = 1;                   // the zeroth chunk is reserved for page header
240                 curDirEntryInPage = 0; 
241                 for (i=0; i<8; i++) {
242                         fakePageHeader.freeBitmap[i]=0;
243                 }
244                 fakePageHeader.freeCount = 0;
245                 fakePageHeader.pgcount = 0;
246                 fakePageHeader.tag = htons(1234);
247                 
248                 // while we're on the same page...
249                 while ( (curDirEntry!=cm_noLocalMountPoints) &&
250                                 (curDirEntryInPage < CM_DIR_EPP) &&
251                             (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0) <= CPP))
252                 {
253                         // add an entry to this page
254
255                         noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
256                         fakeEntry.fid.vnode=htonl(curDirEntry+2);
257                         currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
258                         memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
259                         strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)->namep);
260                         curDirEntry++;
261                         curDirEntryInPage++;
262                         for (i=0; i<noChunks; i++) {
263                                 t1 = (curChunk + i) / 8;
264                                 t2 = curChunk + i - (t1*8);
265                                 fakePageHeader.freeBitmap[t1] |= (1 << t2);
266                         }
267                         curChunk+=noChunks;
268                 }
269                 memcpy(cm_FakeRootDir + curPage * CM_DIR_PAGESIZE, &fakePageHeader, sizeof(fakePageHeader));
270
271                 curPage++;
272         }
273         
274         // we know the fakeDir is setup properly, so we claim that we have callback
275         cm_fakeDirCallback=1;
276
277         // when we get here, we've set up everything! done!
278 }
279
280 int cm_FakeRootFid(cm_fid_t *fidp)
281 {
282       fidp->cell = AFS_FAKE_ROOT_CELL_ID;            /* root cell */
283       fidp->volume = AFS_FAKE_ROOT_VOL_ID;   /* root.afs ? */
284       fidp->vnode = 0x1;
285       fidp->unique = 0x1;
286       return 0;
287 }
288   
289 /* called directly from ioctl */
290 /* called while not holding freelance lock */
291 int cm_noteLocalMountPointChange() {
292     lock_ObtainMutex(&cm_Freelance_Lock);
293     cm_fakeDirVersion++;
294     cm_localMountPointChangeFlag = 1;
295     lock_ReleaseMutex(&cm_Freelance_Lock);
296     return 1;
297 }
298
299 int cm_getLocalMountPointChange() {
300     return cm_localMountPointChangeFlag;
301 }
302
303 int cm_clearLocalMountPointChange() {
304     cm_localMountPointChangeFlag = 0;
305     return 0;
306 }
307
308 int cm_reInitLocalMountPoints() {
309         cm_fid_t aFid;
310         int i, hash;
311         cm_scache_t *scp, **lscpp, *tscp;
312         
313         osi_Log0(afsd_logp,"----- freelance reinitialization starts ----- ");
314
315         // first we invalidate all the SCPs that were created
316         // for the local mount points
317
318         osi_Log0(afsd_logp,"Invalidating local mount point scp...  ");
319
320         aFid.cell = AFS_FAKE_ROOT_CELL_ID;
321         aFid.volume=AFS_FAKE_ROOT_VOL_ID;
322         aFid.unique=0x1;
323         aFid.vnode=0x2;
324
325         lock_ObtainWrite(&cm_scacheLock);
326         lock_ObtainMutex(&cm_Freelance_Lock);  /* always scache then freelance lock */
327         for (i=0; i<cm_noLocalMountPoints; i++) {
328                 hash = CM_SCACHE_HASH(&aFid);
329                 for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
330                         if (scp->fid.volume == aFid.volume &&
331                                 scp->fid.vnode == aFid.vnode &&
332                                 scp->fid.unique == aFid.unique 
333                                 ) {
334
335                                 // mark the scp to be reused
336                                 lock_ReleaseWrite(&cm_scacheLock);
337                                 lock_ObtainMutex(&scp->mx);
338                                 cm_DiscardSCache(scp);
339                                 lock_ReleaseMutex(&scp->mx);
340                                 cm_CallbackNotifyChange(scp);
341                                 lock_ObtainWrite(&cm_scacheLock);
342                                 scp->refCount--;
343
344                                 // take the scp out of the hash
345                                 lscpp = &cm_hashTablep[hash];
346                                 for (tscp=*lscpp; tscp; lscpp = &tscp->nextp, tscp = *lscpp) {
347                                         if (tscp == scp) break;
348                                 }
349                                 *lscpp = scp->nextp;
350                                 scp->flags &= ~CM_SCACHEFLAG_INHASH;
351
352
353                         }
354                 }
355                 aFid.vnode = aFid.vnode + 1;
356         }
357         lock_ReleaseWrite(&cm_scacheLock);
358         osi_Log0(afsd_logp,"\tall old scp cleared!");
359
360         // we must free the memory that was allocated in the prev
361         // cm_InitLocalMountPoints call
362         osi_Log0(afsd_logp,"Removing old localmountpoints...  ");
363         free(cm_localMountPoints);
364         osi_Log0(afsd_logp,"\tall old localmountpoints cleared!");
365
366         // now re-init the localmountpoints
367         osi_Log0(afsd_logp,"Creating new localmountpoints...  ");
368         cm_InitLocalMountPoints();
369         osi_Log0(afsd_logp,"\tcreated new set of localmountpoints!");
370         
371         
372         // now we have to free the memory allocated in cm_initfakerootdir
373         osi_Log0(afsd_logp,"Removing old fakedir...  ");
374         free(cm_FakeRootDir);
375         osi_Log0(afsd_logp,"\t\told fakedir removed!");
376
377         // then we re-create that dir
378         osi_Log0(afsd_logp,"Creating new fakedir...  ");
379         cm_InitFakeRootDir();
380         osi_Log0(afsd_logp,"\t\tcreated new fakedir!");
381
382         lock_ReleaseMutex(&cm_Freelance_Lock);
383
384         osi_Log0(afsd_logp,"----- freelance reinit complete -----");
385         return 0;
386 }
387
388
389 // yj: open up the ini file and read all the local mount 
390 // points that are stored there. Part of the initialization
391 // process for the freelance client.
392 /* to be called while holding freelance lock unless during init. */
393 long cm_InitLocalMountPoints() {
394         FILE *fp;
395     int i;
396         char line[512];
397         char* t;
398         cm_localMountPoint_t* aLocalMountPoint;
399         char hdir[120];
400     long code;
401     char rootCellName[256];
402 #if !defined(DJGPP)
403     HKEY hkFreelance = 0;
404     DWORD dwType, dwSize;
405     DWORD dwMountPoints;
406     DWORD dwIndex;
407     FILETIME ftLastWriteTime;
408     afs_uint32 unixTime;
409 #endif
410
411 #if !defined(DJGPP)
412     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
413                         "SOFTWARE\\OpenAFS\\Client\\Freelance",
414                                                 0,
415                         KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
416                         &hkFreelance) == ERROR_SUCCESS) {
417
418         RegQueryInfoKey( hkFreelance,
419                          NULL,  /* lpClass */
420                          NULL,  /* lpcClass */
421                          NULL,  /* lpReserved */
422                          NULL,  /* lpcSubKeys */
423                          NULL,  /* lpcMaxSubKeyLen */
424                          NULL,  /* lpcMaxClassLen */
425                          &dwMountPoints, /* lpcValues */
426                          NULL,  /* lpcMaxValueNameLen */
427                          NULL,  /* lpcMaxValueLen */
428                          NULL,  /* lpcbSecurityDescriptor */
429                          &ftLastWriteTime /* lpftLastWriteTime */
430                          );
431
432         smb_UnixTimeFromLargeSearchTime(&FakeFreelanceModTime, &ftLastWriteTime);
433
434         if ( dwMountPoints == 0 ) {
435             sprintf(line,"%s#%s:root.cell.\n",rootCellName,rootCellName);
436             dwType = REG_SZ;
437             dwSize = strlen(line) + 1;
438             RegSetValueEx( hkFreelance, "0", 0, dwType, line, dwSize);
439             sprintf(line,".%s%%%s:root.cell.\n",rootCellName,rootCellName);
440             dwSize = strlen(line) + 1;
441             RegSetValueEx( hkFreelance, "1", 0, dwType, line, dwSize);
442             dwMountPoints = 2;
443         }
444
445         // get the number of entries there are from the first line
446         // that we read
447         cm_noLocalMountPoints = dwMountPoints;
448
449         // create space to store the local mount points
450         cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
451         aLocalMountPoint = cm_localMountPoints;
452
453         // now we read n lines and parse them into local mount points
454         // where n is the number of local mount points there are, as
455         // determined above.
456         // Each line in the ini file represents 1 local mount point and 
457         // is in the format xxx#yyy:zzz, where xxx is the directory
458         // entry name, yyy is the cell name and zzz is the volume name.
459         // #yyy:zzz together make up the mount point.
460         for ( dwIndex = 0 ; dwIndex < dwMountPoints; dwIndex++ ) {
461             TCHAR szValueName[16];
462             DWORD dwValueSize = 16;
463             dwSize = sizeof(line);
464             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
465                           &dwType, line, &dwSize);
466
467             // line is not empty, so let's parse it
468             t = strchr(line, '#');
469             if (!t)
470                 t = strchr(line, '%');
471             // make sure that there is a '#' or '%' separator in the line
472             if (!t) {
473                 afsi_log("error occurred while parsing entry in %s: no # or %% separator in line %d", AFS_FREELANCE_INI, dwIndex);
474                 fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # or %% separator in line %d", dwIndex);
475                 cm_noLocalMountPoints--;
476                 continue;
477             }
478             aLocalMountPoint->namep=malloc(t-line+1);
479             memcpy(aLocalMountPoint->namep, line, t-line);
480             *(aLocalMountPoint->namep + (t-line)) = 0;
481                 
482             aLocalMountPoint->mountPointStringp=malloc(strlen(line) - (t-line) + 1);
483             memcpy(aLocalMountPoint->mountPointStringp, t, strlen(line)-(t-line)-2);
484             *(aLocalMountPoint->mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
485     
486             osi_Log2(afsd_logp,"found mount point: name %s, string %s",
487                       osi_LogSaveString(afsd_logp,aLocalMountPoint->namep),
488                       osi_LogSaveString(afsd_logp,aLocalMountPoint->mountPointStringp));
489
490             aLocalMountPoint++;
491         }
492
493         RegCloseKey(hkFreelance);
494         return 0;
495     }
496 #endif
497
498     /* What follows is the old code to read freelance mount points 
499      * out of a text file modified to copy the data into the registry
500      */
501         cm_GetConfigDir(hdir);
502         strcat(hdir, AFS_FREELANCE_INI);
503         // open the ini file for reading
504         fp = fopen(hdir, "r");
505
506         // if we fail to open the file, create an empty one
507         if (!fp) {
508         fp = fopen(hdir, "w");
509         code = cm_GetRootCellName(rootCellName);
510         if (code == 0) {
511             fputs("1\n", fp);
512             fprintf(fp,"%s#%s:root.cell.\n",rootCellName,rootCellName);
513             fprintf(fp,".%s%%%s:root.cell.\n",rootCellName,rootCellName);
514             fclose(fp);
515             fopen(hdir, "r");
516         } else {
517             fputs("0\n", fp);
518             fclose(fp);
519             return 0;  /* success */
520         }
521         }
522
523         // we successfully opened the file
524         osi_Log0(afsd_logp,"opened afs_freelance.ini");
525         
526 #if !defined(DJGPP)
527     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
528                     "SOFTWARE\\OpenAFS\\Client\\Freelance",
529                     0,
530                     NULL,
531                     REG_OPTION_NON_VOLATILE,
532                     KEY_READ|KEY_WRITE,
533                     NULL,
534                     &hkFreelance,
535                     NULL);
536     dwIndex = 0;
537 #endif
538
539         // now we read the first line to see how many entries
540         // there are
541         fgets(line, sizeof(line), fp);
542
543         // if the line is empty at any point when we're reading
544         // we're screwed. report error and return.
545         if (*line==0) {
546                 afsi_log("error occurred while reading afs_freelance.ini");
547                 fprintf(stderr, "error occurred while reading afs_freelance.ini");
548                 return -1;
549         }
550
551         // get the number of entries there are from the first line
552         // that we read
553         cm_noLocalMountPoints = atoi(line);
554
555         // create space to store the local mount points
556         cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
557         aLocalMountPoint = cm_localMountPoints;
558                 
559         // now we read n lines and parse them into local mount points
560         // where n is the number of local mount points there are, as
561         // determined above.
562         // Each line in the ini file represents 1 local mount point and 
563         // is in the format xxx#yyy:zzz, where xxx is the directory
564         // entry name, yyy is the cell name and zzz is the volume name.
565         // #yyy:zzz together make up the mount point.
566         for (i=0; i<cm_noLocalMountPoints; i++) {
567                 fgets(line, sizeof(line), fp);
568                 // check that the line is not empty
569                 if (line[0]==0) {
570                         afsi_log("error occurred while parsing entry in %s: empty line in line %d", AFS_FREELANCE_INI, i);
571                         fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: empty line in line %d", i);
572                         return -1;
573                 }
574
575 #if !defined(DJGPP)
576         if ( hkFreelance ) {
577             char szIndex[16];
578             /* we are migrating to the registry */
579             sprintf(szIndex,"%d",dwIndex++);
580             dwType = REG_SZ;
581             dwSize = strlen(line) + 1;
582             RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
583         }
584 #endif 
585
586                 // line is not empty, so let's parse it
587                 t = strchr(line, '#');
588         if (!t)
589             t = strchr(line, '%');
590                 // make sure that there is a '#' or '%' separator in the line
591                 if (!t) {
592                         afsi_log("error occurred while parsing entry in %s: no # or %% separator in line %d", AFS_FREELANCE_INI, i);
593                         fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # or %% separator in line %d", i);
594                         return -1;
595                 }
596                 aLocalMountPoint->namep=malloc(t-line+1);
597                 memcpy(aLocalMountPoint->namep, line, t-line);
598                 *(aLocalMountPoint->namep + (t-line)) = 0;
599                 
600         aLocalMountPoint->mountPointStringp=malloc(strlen(line) - (t-line) + 1);
601                 memcpy(aLocalMountPoint->mountPointStringp, t, strlen(line)-(t-line)-2);
602                 *(aLocalMountPoint->mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
603     
604         osi_Log2(afsd_logp,"found mount point: name %s, string %s",
605                   aLocalMountPoint->namep,
606                   aLocalMountPoint->mountPointStringp);
607
608         aLocalMountPoint++;
609         }
610         fclose(fp);
611 #if !defined(DJGPP)
612     if ( hkFreelance ) {
613         RegCloseKey(hkFreelance);
614         DeleteFile(hdir);
615     }
616 #endif
617         return 0;
618 }
619
620 int cm_getNoLocalMountPoints() {
621         return cm_noLocalMountPoints;
622 }
623
624 cm_localMountPoint_t* cm_getLocalMountPoint(int vnode) {
625         return 0;
626 }
627
628 long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp)
629 {
630     FILE *fp;
631     char hfile[120];
632     char line[512];
633     char fullname[200];
634     int n;
635     int alias = 0;
636 #if !defined(DJGPP)
637     HKEY hkFreelance = 0;
638     DWORD dwType, dwSize;
639     DWORD dwMountPoints;
640     DWORD dwIndex;
641 #endif
642
643     /* before adding, verify the cell name; if it is not a valid cell,
644        don't add the mount point.
645        allow partial matches as a means of poor man's alias. */
646     /* major performance issue? */
647     osi_Log4(afsd_logp,"Freelance Add Mount request: filename=%s cellname=%s volume=%s %s",
648               osi_LogSaveString(afsd_logp,filename), 
649               osi_LogSaveString(afsd_logp,cellname), 
650               osi_LogSaveString(afsd_logp,volume), 
651               rw ? "rw" : "ro");
652     if (cellname[0] == '.') {
653         if (!cm_GetCell_Gen(&cellname[1], fullname, CM_FLAG_CREATE))
654             return -1;
655     } else {
656         if (!cm_GetCell_Gen(cellname, fullname, CM_FLAG_CREATE))
657             return -1;
658     }
659     
660     osi_Log1(afsd_logp,"Freelance Adding Mount for Cell: %s", 
661               osi_LogSaveString(afsd_logp,cellname));
662
663     lock_ObtainMutex(&cm_Freelance_Lock);
664
665 #if !defined(DJGPP)
666     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
667                       "SOFTWARE\\OpenAFS\\Client\\Freelance",
668                       0,
669                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
670                       &hkFreelance) == ERROR_SUCCESS) {
671
672         RegQueryInfoKey( hkFreelance,
673                          NULL,  /* lpClass */
674                          NULL,  /* lpcClass */
675                          NULL,  /* lpReserved */
676                          NULL,  /* lpcSubKeys */
677                          NULL,  /* lpcMaxSubKeyLen */
678                          NULL,  /* lpcMaxClassLen */
679                          &dwMountPoints, /* lpcValues */
680                          NULL,  /* lpcMaxValueNameLen */
681                          NULL,  /* lpcMaxValueLen */
682                          NULL,  /* lpcbSecurityDescriptor */
683                          NULL   /* lpftLastWriteTime */
684                          );
685
686         if (rw)
687             sprintf(line, "%s%%%s:%s\n", filename, fullname, volume);
688         else
689             sprintf(line, "%s#%s:%s\n", filename, fullname, volume);
690
691         /* If we are adding a new value, there must be an unused name
692          * within the range 0 to dwMountPoints 
693          */
694         for ( dwIndex = 0; dwIndex <= dwMountPoints; dwIndex++ ) {
695             char szIndex[16];
696             sprintf(szIndex, "%d", dwIndex);
697             if (RegQueryValueEx( hkFreelance, szIndex, 0, &dwType, NULL, &dwSize) != ERROR_SUCCESS) {
698                 /* found an unused value */
699                 dwType = REG_SZ;
700                 dwSize = strlen(line) + 1;
701                 RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
702                 break;
703             }
704         }
705         RegCloseKey(hkFreelance);
706     } else 
707 #endif
708     {
709         cm_GetConfigDir(hfile);
710         strcat(hfile, AFS_FREELANCE_INI);
711         fp = fopen(hfile, "r+");
712         if (!fp)
713             return CM_ERROR_INVAL;
714         fgets(line, sizeof(line), fp);
715         n = atoi(line);
716         n++;
717         fseek(fp, 0, SEEK_SET);
718         fprintf(fp, "%d", n);
719         fseek(fp, 0, SEEK_END);
720         if (rw)
721             fprintf(fp, "%s%%%s:%s\n", filename, fullname, volume);
722         else
723             fprintf(fp, "%s#%s:%s\n", filename, fullname, volume);
724         fclose(fp);
725     }
726     lock_ReleaseMutex(&cm_Freelance_Lock);
727
728     /* cm_reInitLocalMountPoints(); */
729     if (fidp) {
730         fidp->unique = 1;
731         fidp->vnode = cm_noLocalMountPoints + 1;   /* vnode value of last mt pt */
732     }
733     cm_noteLocalMountPointChange();
734     return 0;
735 }
736
737 long cm_FreelanceRemoveMount(char *toremove)
738 {
739     int i, n;
740     char* cp;
741     char line[512];
742     char shortname[200];
743     char hfile[120], hfile2[120];
744     FILE *fp1, *fp2;
745     int found=0;
746 #if !defined(DJGPP)
747     HKEY hkFreelance = 0;
748     DWORD dwType, dwSize;
749     DWORD dwMountPoints;
750     DWORD dwIndex;
751 #endif
752
753     lock_ObtainMutex(&cm_Freelance_Lock);
754
755
756 #if !defined(DJGPP)
757     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
758                       "SOFTWARE\\OpenAFS\\Client\\Freelance",
759                       0,
760                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
761                       &hkFreelance) == ERROR_SUCCESS) {
762
763         RegQueryInfoKey( hkFreelance,
764                          NULL,  /* lpClass */
765                          NULL,  /* lpcClass */
766                          NULL,  /* lpReserved */
767                          NULL,  /* lpcSubKeys */
768                          NULL,  /* lpcMaxSubKeyLen */
769                          NULL,  /* lpcMaxClassLen */
770                          &dwMountPoints, /* lpcValues */
771                          NULL,  /* lpcMaxValueNameLen */
772                          NULL,  /* lpcMaxValueLen */
773                          NULL,  /* lpcbSecurityDescriptor */
774                          NULL   /* lpftLastWriteTime */
775                          );
776
777         for ( dwIndex = 0; dwIndex < dwMountPoints; dwIndex++ ) {
778             TCHAR szValueName[16];
779             DWORD dwValueSize = 16;
780             dwSize = sizeof(line);
781             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
782                           &dwType, line, &dwSize);
783
784             cp=strchr(line, '#');
785             if (!cp)
786                 cp=strchr(line, '%');
787             memcpy(shortname, line, cp-line);
788             shortname[cp-line]=0;
789
790             if (!strcmp(shortname, toremove)) {
791                 RegDeleteValue( hkFreelance, szValueName );
792                 break;
793             }
794         }
795         RegCloseKey(hkFreelance);
796     } else 
797 #endif
798     {
799         cm_GetConfigDir(hfile);
800         strcat(hfile, AFS_FREELANCE_INI);
801         strcpy(hfile2, hfile);
802         strcat(hfile2, "2");
803         fp1=fopen(hfile, "r+");
804         if (!fp1)
805             return CM_ERROR_INVAL;
806         fp2=fopen(hfile2, "w+");
807         if (!fp2) {
808             fclose(fp1);
809             return CM_ERROR_INVAL;
810         }
811
812         fgets(line, sizeof(line), fp1);
813         n=atoi(line);
814         fprintf(fp2, "%d\n", n-1);
815
816         for (i=0; i<n; i++) {
817             fgets(line, sizeof(line), fp1);
818             cp=strchr(line, '#');
819             if (!cp)
820                 cp=strchr(line, '%');
821             memcpy(shortname, line, cp-line);
822             shortname[cp-line]=0;
823
824             if (strcmp(shortname, toremove)==0) {
825
826             } else {
827                 found = 1;
828                 fputs(line, fp2);
829             }
830         }
831
832         fclose(fp1);
833         fclose(fp2);
834         if (!found)
835             return CM_ERROR_NOSUCHFILE;
836
837         unlink(hfile);
838         rename(hfile2, hfile);
839     }
840     
841     lock_ReleaseMutex(&cm_Freelance_Lock);
842     cm_noteLocalMountPointChange();
843     return 0;
844 }
845
846 #endif /* AFS_FREELANCE_CLIENT */