time_t-pointer-conversions-20040908
[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 time_t 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     osi_Log0(afsd_logp,"cm_InitFakeRootDir fakeDirCallback=1");
276         cm_fakeDirCallback=1;
277
278         // when we get here, we've set up everything! done!
279 }
280
281 int cm_FakeRootFid(cm_fid_t *fidp)
282 {
283       fidp->cell = AFS_FAKE_ROOT_CELL_ID;            /* root cell */
284       fidp->volume = AFS_FAKE_ROOT_VOL_ID;   /* root.afs ? */
285       fidp->vnode = 0x1;
286       fidp->unique = 0x1;
287       return 0;
288 }
289   
290 /* called directly from ioctl */
291 /* called while not holding freelance lock */
292 int cm_noteLocalMountPointChange() {
293     lock_ObtainMutex(&cm_Freelance_Lock);
294     cm_fakeDirVersion++;
295     cm_localMountPointChangeFlag = 1;
296     lock_ReleaseMutex(&cm_Freelance_Lock);
297     return 1;
298 }
299
300 int cm_getLocalMountPointChange() {
301     return cm_localMountPointChangeFlag;
302 }
303
304 int cm_clearLocalMountPointChange() {
305     cm_localMountPointChangeFlag = 0;
306     return 0;
307 }
308
309 int cm_reInitLocalMountPoints() {
310         cm_fid_t aFid;
311         int i, hash;
312         cm_scache_t *scp, **lscpp, *tscp;
313         
314         osi_Log0(afsd_logp,"----- freelance reinitialization starts ----- ");
315
316         // first we invalidate all the SCPs that were created
317         // for the local mount points
318
319         osi_Log0(afsd_logp,"Invalidating local mount point scp...  ");
320
321         aFid.cell = AFS_FAKE_ROOT_CELL_ID;
322         aFid.volume=AFS_FAKE_ROOT_VOL_ID;
323         aFid.unique=0x1;
324         aFid.vnode=0x2;
325
326         lock_ObtainWrite(&cm_scacheLock);
327         lock_ObtainMutex(&cm_Freelance_Lock);  /* always scache then freelance lock */
328         for (i=0; i<cm_noLocalMountPoints; i++) {
329                 hash = CM_SCACHE_HASH(&aFid);
330                 for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
331                         if (scp->fid.volume == aFid.volume &&
332                                 scp->fid.vnode == aFid.vnode &&
333                                 scp->fid.unique == aFid.unique 
334                                 ) {
335
336                                 // mark the scp to be reused
337                                 lock_ReleaseWrite(&cm_scacheLock);
338                                 lock_ObtainMutex(&scp->mx);
339                                 cm_DiscardSCache(scp);
340                                 lock_ReleaseMutex(&scp->mx);
341                                 cm_CallbackNotifyChange(scp);
342                                 lock_ObtainWrite(&cm_scacheLock);
343                                 scp->refCount--;
344
345                                 // take the scp out of the hash
346                                 lscpp = &cm_hashTablep[hash];
347                                 for (tscp=*lscpp; tscp; lscpp = &tscp->nextp, tscp = *lscpp) {
348                                         if (tscp == scp) break;
349                                 }
350                                 *lscpp = scp->nextp;
351                                 scp->flags &= ~CM_SCACHEFLAG_INHASH;
352
353
354                         }
355                 }
356                 aFid.vnode = aFid.vnode + 1;
357         }
358         lock_ReleaseWrite(&cm_scacheLock);
359         osi_Log0(afsd_logp,"\tall old scp cleared!");
360
361         // we must free the memory that was allocated in the prev
362         // cm_InitLocalMountPoints call
363         osi_Log0(afsd_logp,"Removing old localmountpoints...  ");
364         free(cm_localMountPoints);
365         osi_Log0(afsd_logp,"\tall old localmountpoints cleared!");
366
367         // now re-init the localmountpoints
368         osi_Log0(afsd_logp,"Creating new localmountpoints...  ");
369         cm_InitLocalMountPoints();
370         osi_Log0(afsd_logp,"\tcreated new set of localmountpoints!");
371         
372         
373         // now we have to free the memory allocated in cm_initfakerootdir
374         osi_Log0(afsd_logp,"Removing old fakedir...  ");
375         free(cm_FakeRootDir);
376         osi_Log0(afsd_logp,"\t\told fakedir removed!");
377
378         // then we re-create that dir
379         osi_Log0(afsd_logp,"Creating new fakedir...  ");
380         cm_InitFakeRootDir();
381         osi_Log0(afsd_logp,"\t\tcreated new fakedir!");
382
383         lock_ReleaseMutex(&cm_Freelance_Lock);
384
385         osi_Log0(afsd_logp,"----- freelance reinit complete -----");
386         return 0;
387 }
388
389
390 // yj: open up the ini file and read all the local mount 
391 // points that are stored there. Part of the initialization
392 // process for the freelance client.
393 /* to be called while holding freelance lock unless during init. */
394 long cm_InitLocalMountPoints() {
395         FILE *fp;
396     int i;
397         char line[512];
398         char* t;
399         cm_localMountPoint_t* aLocalMountPoint;
400         char hdir[120];
401     long code;
402     char rootCellName[256];
403 #if !defined(DJGPP)
404     HKEY hkFreelance = 0;
405     DWORD dwType, dwSize;
406     DWORD dwMountPoints;
407     DWORD dwIndex;
408     FILETIME ftLastWriteTime;
409     afs_uint32 unixTime;
410 #endif
411
412 #if !defined(DJGPP)
413     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
414                         "SOFTWARE\\OpenAFS\\Client\\Freelance",
415                                                 0,
416                         KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
417                         &hkFreelance) == ERROR_SUCCESS) {
418
419         RegQueryInfoKey( hkFreelance,
420                          NULL,  /* lpClass */
421                          NULL,  /* lpcClass */
422                          NULL,  /* lpReserved */
423                          NULL,  /* lpcSubKeys */
424                          NULL,  /* lpcMaxSubKeyLen */
425                          NULL,  /* lpcMaxClassLen */
426                          &dwMountPoints, /* lpcValues */
427                          NULL,  /* lpcMaxValueNameLen */
428                          NULL,  /* lpcMaxValueLen */
429                          NULL,  /* lpcbSecurityDescriptor */
430                          &ftLastWriteTime /* lpftLastWriteTime */
431                          );
432
433         smb_UnixTimeFromLargeSearchTime(&FakeFreelanceModTime, &ftLastWriteTime);
434
435         if ( dwMountPoints == 0 ) {
436             sprintf(line,"%s#%s:root.cell.\n",rootCellName,rootCellName);
437             dwType = REG_SZ;
438             dwSize = strlen(line) + 1;
439             RegSetValueEx( hkFreelance, "0", 0, dwType, line, dwSize);
440             sprintf(line,".%s%%%s:root.cell.\n",rootCellName,rootCellName);
441             dwSize = strlen(line) + 1;
442             RegSetValueEx( hkFreelance, "1", 0, dwType, line, dwSize);
443             dwMountPoints = 2;
444         }
445
446         // get the number of entries there are from the first line
447         // that we read
448         cm_noLocalMountPoints = dwMountPoints;
449
450         // create space to store the local mount points
451         cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
452         aLocalMountPoint = cm_localMountPoints;
453
454         // now we read n lines and parse them into local mount points
455         // where n is the number of local mount points there are, as
456         // determined above.
457         // Each line in the ini file represents 1 local mount point and 
458         // is in the format xxx#yyy:zzz, where xxx is the directory
459         // entry name, yyy is the cell name and zzz is the volume name.
460         // #yyy:zzz together make up the mount point.
461         for ( dwIndex = 0 ; dwIndex < dwMountPoints; dwIndex++ ) {
462             TCHAR szValueName[16];
463             DWORD dwValueSize = 16;
464             dwSize = sizeof(line);
465             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
466                           &dwType, line, &dwSize);
467
468             // line is not empty, so let's parse it
469             t = strchr(line, '#');
470             if (!t)
471                 t = strchr(line, '%');
472             // make sure that there is a '#' or '%' separator in the line
473             if (!t) {
474                 afsi_log("error occurred while parsing entry in %s: no # or %% separator in line %d", AFS_FREELANCE_INI, dwIndex);
475                 fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # or %% separator in line %d", dwIndex);
476                 cm_noLocalMountPoints--;
477                 continue;
478             }
479             aLocalMountPoint->namep=malloc(t-line+1);
480             memcpy(aLocalMountPoint->namep, line, t-line);
481             *(aLocalMountPoint->namep + (t-line)) = 0;
482                 
483             aLocalMountPoint->mountPointStringp=malloc(strlen(line) - (t-line) + 1);
484             memcpy(aLocalMountPoint->mountPointStringp, t, strlen(line)-(t-line)-2);
485             *(aLocalMountPoint->mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
486     
487             osi_Log2(afsd_logp,"found mount point: name %s, string %s",
488                       osi_LogSaveString(afsd_logp,aLocalMountPoint->namep),
489                       osi_LogSaveString(afsd_logp,aLocalMountPoint->mountPointStringp));
490
491             aLocalMountPoint++;
492         }
493
494         RegCloseKey(hkFreelance);
495         return 0;
496     }
497 #endif
498
499     /* What follows is the old code to read freelance mount points 
500      * out of a text file modified to copy the data into the registry
501      */
502         cm_GetConfigDir(hdir);
503         strcat(hdir, AFS_FREELANCE_INI);
504         // open the ini file for reading
505         fp = fopen(hdir, "r");
506
507         // if we fail to open the file, create an empty one
508         if (!fp) {
509         fp = fopen(hdir, "w");
510         code = cm_GetRootCellName(rootCellName);
511         if (code == 0) {
512             fputs("1\n", fp);
513             fprintf(fp,"%s#%s:root.cell.\n",rootCellName,rootCellName);
514             fprintf(fp,".%s%%%s:root.cell.\n",rootCellName,rootCellName);
515             fclose(fp);
516             fp = fopen(hdir, "r");
517         } else {
518             fputs("0\n", fp);
519             fclose(fp);
520             return 0;  /* success */
521         }
522         }
523
524         // we successfully opened the file
525         osi_Log0(afsd_logp,"opened afs_freelance.ini");
526         
527 #if !defined(DJGPP)
528     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
529                     "SOFTWARE\\OpenAFS\\Client\\Freelance",
530                     0,
531                     NULL,
532                     REG_OPTION_NON_VOLATILE,
533                     KEY_READ|KEY_WRITE,
534                     NULL,
535                     &hkFreelance,
536                     NULL);
537     dwIndex = 0;
538 #endif
539
540         // now we read the first line to see how many entries
541         // there are
542         fgets(line, sizeof(line), fp);
543
544         // if the line is empty at any point when we're reading
545         // we're screwed. report error and return.
546         if (*line==0) {
547                 afsi_log("error occurred while reading afs_freelance.ini");
548                 fprintf(stderr, "error occurred while reading afs_freelance.ini");
549                 return -1;
550         }
551
552         // get the number of entries there are from the first line
553         // that we read
554         cm_noLocalMountPoints = atoi(line);
555
556         // create space to store the local mount points
557         cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
558         aLocalMountPoint = cm_localMountPoints;
559                 
560         // now we read n lines and parse them into local mount points
561         // where n is the number of local mount points there are, as
562         // determined above.
563         // Each line in the ini file represents 1 local mount point and 
564         // is in the format xxx#yyy:zzz, where xxx is the directory
565         // entry name, yyy is the cell name and zzz is the volume name.
566         // #yyy:zzz together make up the mount point.
567         for (i=0; i<cm_noLocalMountPoints; i++) {
568                 fgets(line, sizeof(line), fp);
569                 // check that the line is not empty
570                 if (line[0]==0) {
571                         afsi_log("error occurred while parsing entry in %s: empty line in line %d", AFS_FREELANCE_INI, i);
572                         fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: empty line in line %d", i);
573                         return -1;
574                 }
575
576 #if !defined(DJGPP)
577         if ( hkFreelance ) {
578             char szIndex[16];
579             /* we are migrating to the registry */
580             sprintf(szIndex,"%d",dwIndex++);
581             dwType = REG_SZ;
582             dwSize = strlen(line) + 1;
583             RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
584         }
585 #endif 
586
587                 // line is not empty, so let's parse it
588                 t = strchr(line, '#');
589         if (!t)
590             t = strchr(line, '%');
591                 // make sure that there is a '#' or '%' separator in the line
592                 if (!t) {
593                         afsi_log("error occurred while parsing entry in %s: no # or %% separator in line %d", AFS_FREELANCE_INI, i);
594                         fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # or %% separator in line %d", i);
595                         return -1;
596                 }
597                 aLocalMountPoint->namep=malloc(t-line+1);
598                 memcpy(aLocalMountPoint->namep, line, t-line);
599                 *(aLocalMountPoint->namep + (t-line)) = 0;
600                 
601         aLocalMountPoint->mountPointStringp=malloc(strlen(line) - (t-line) + 1);
602                 memcpy(aLocalMountPoint->mountPointStringp, t, strlen(line)-(t-line)-2);
603                 *(aLocalMountPoint->mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
604     
605         osi_Log2(afsd_logp,"found mount point: name %s, string %s",
606                   aLocalMountPoint->namep,
607                   aLocalMountPoint->mountPointStringp);
608
609         aLocalMountPoint++;
610         }
611         fclose(fp);
612 #if !defined(DJGPP)
613     if ( hkFreelance ) {
614         RegCloseKey(hkFreelance);
615         DeleteFile(hdir);
616     }
617 #endif
618         return 0;
619 }
620
621 int cm_getNoLocalMountPoints() {
622         return cm_noLocalMountPoints;
623 }
624
625 cm_localMountPoint_t* cm_getLocalMountPoint(int vnode) {
626         return 0;
627 }
628
629 long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp)
630 {
631     FILE *fp;
632     char hfile[120];
633     char line[512];
634     char fullname[200];
635     int n;
636     int alias = 0;
637 #if !defined(DJGPP)
638     HKEY hkFreelance = 0;
639     DWORD dwType, dwSize;
640     DWORD dwMountPoints;
641     DWORD dwIndex;
642 #endif
643
644     /* before adding, verify the cell name; if it is not a valid cell,
645        don't add the mount point.
646        allow partial matches as a means of poor man's alias. */
647     /* major performance issue? */
648     osi_Log4(afsd_logp,"Freelance Add Mount request: filename=%s cellname=%s volume=%s %s",
649               osi_LogSaveString(afsd_logp,filename), 
650               osi_LogSaveString(afsd_logp,cellname), 
651               osi_LogSaveString(afsd_logp,volume), 
652               rw ? "rw" : "ro");
653     if (cellname[0] == '.') {
654         if (!cm_GetCell_Gen(&cellname[1], fullname, CM_FLAG_CREATE))
655             return -1;
656     } else {
657         if (!cm_GetCell_Gen(cellname, fullname, CM_FLAG_CREATE))
658             return -1;
659     }
660     
661     osi_Log1(afsd_logp,"Freelance Adding Mount for Cell: %s", 
662               osi_LogSaveString(afsd_logp,cellname));
663
664     lock_ObtainMutex(&cm_Freelance_Lock);
665
666 #if !defined(DJGPP)
667     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
668                       "SOFTWARE\\OpenAFS\\Client\\Freelance",
669                       0,
670                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
671                       &hkFreelance) == ERROR_SUCCESS) {
672
673         RegQueryInfoKey( hkFreelance,
674                          NULL,  /* lpClass */
675                          NULL,  /* lpcClass */
676                          NULL,  /* lpReserved */
677                          NULL,  /* lpcSubKeys */
678                          NULL,  /* lpcMaxSubKeyLen */
679                          NULL,  /* lpcMaxClassLen */
680                          &dwMountPoints, /* lpcValues */
681                          NULL,  /* lpcMaxValueNameLen */
682                          NULL,  /* lpcMaxValueLen */
683                          NULL,  /* lpcbSecurityDescriptor */
684                          NULL   /* lpftLastWriteTime */
685                          );
686
687         if (rw)
688             sprintf(line, "%s%%%s:%s\n", filename, fullname, volume);
689         else
690             sprintf(line, "%s#%s:%s\n", filename, fullname, volume);
691
692         /* If we are adding a new value, there must be an unused name
693          * within the range 0 to dwMountPoints 
694          */
695         for ( dwIndex = 0; dwIndex <= dwMountPoints; dwIndex++ ) {
696             char szIndex[16];
697             sprintf(szIndex, "%d", dwIndex);
698             if (RegQueryValueEx( hkFreelance, szIndex, 0, &dwType, NULL, &dwSize) != ERROR_SUCCESS) {
699                 /* found an unused value */
700                 dwType = REG_SZ;
701                 dwSize = strlen(line) + 1;
702                 RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
703                 break;
704             }
705         }
706         RegCloseKey(hkFreelance);
707     } else 
708 #endif
709     {
710         cm_GetConfigDir(hfile);
711         strcat(hfile, AFS_FREELANCE_INI);
712         fp = fopen(hfile, "r+");
713         if (!fp)
714             return CM_ERROR_INVAL;
715         fgets(line, sizeof(line), fp);
716         n = atoi(line);
717         n++;
718         fseek(fp, 0, SEEK_SET);
719         fprintf(fp, "%d", n);
720         fseek(fp, 0, SEEK_END);
721         if (rw)
722             fprintf(fp, "%s%%%s:%s\n", filename, fullname, volume);
723         else
724             fprintf(fp, "%s#%s:%s\n", filename, fullname, volume);
725         fclose(fp);
726     }
727     lock_ReleaseMutex(&cm_Freelance_Lock);
728
729     /* cm_reInitLocalMountPoints(); */
730     if (fidp) {
731         fidp->unique = 1;
732         fidp->vnode = cm_noLocalMountPoints + 1;   /* vnode value of last mt pt */
733     }
734     cm_noteLocalMountPointChange();
735     return 0;
736 }
737
738 long cm_FreelanceRemoveMount(char *toremove)
739 {
740     int i, n;
741     char* cp;
742     char line[512];
743     char shortname[200];
744     char hfile[120], hfile2[120];
745     FILE *fp1, *fp2;
746     int found=0;
747 #if !defined(DJGPP)
748     HKEY hkFreelance = 0;
749     DWORD dwType, dwSize;
750     DWORD dwMountPoints;
751     DWORD dwIndex;
752 #endif
753
754     lock_ObtainMutex(&cm_Freelance_Lock);
755
756
757 #if !defined(DJGPP)
758     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
759                       "SOFTWARE\\OpenAFS\\Client\\Freelance",
760                       0,
761                       KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
762                       &hkFreelance) == ERROR_SUCCESS) {
763
764         RegQueryInfoKey( hkFreelance,
765                          NULL,  /* lpClass */
766                          NULL,  /* lpcClass */
767                          NULL,  /* lpReserved */
768                          NULL,  /* lpcSubKeys */
769                          NULL,  /* lpcMaxSubKeyLen */
770                          NULL,  /* lpcMaxClassLen */
771                          &dwMountPoints, /* lpcValues */
772                          NULL,  /* lpcMaxValueNameLen */
773                          NULL,  /* lpcMaxValueLen */
774                          NULL,  /* lpcbSecurityDescriptor */
775                          NULL   /* lpftLastWriteTime */
776                          );
777
778         for ( dwIndex = 0; dwIndex < dwMountPoints; dwIndex++ ) {
779             TCHAR szValueName[16];
780             DWORD dwValueSize = 16;
781             dwSize = sizeof(line);
782             RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
783                           &dwType, line, &dwSize);
784
785             cp=strchr(line, '#');
786             if (!cp)
787                 cp=strchr(line, '%');
788             memcpy(shortname, line, cp-line);
789             shortname[cp-line]=0;
790
791             if (!strcmp(shortname, toremove)) {
792                 RegDeleteValue( hkFreelance, szValueName );
793                 break;
794             }
795         }
796         RegCloseKey(hkFreelance);
797     } else 
798 #endif
799     {
800         cm_GetConfigDir(hfile);
801         strcat(hfile, AFS_FREELANCE_INI);
802         strcpy(hfile2, hfile);
803         strcat(hfile2, "2");
804         fp1=fopen(hfile, "r+");
805         if (!fp1)
806             return CM_ERROR_INVAL;
807         fp2=fopen(hfile2, "w+");
808         if (!fp2) {
809             fclose(fp1);
810             return CM_ERROR_INVAL;
811         }
812
813         fgets(line, sizeof(line), fp1);
814         n=atoi(line);
815         fprintf(fp2, "%d\n", n-1);
816
817         for (i=0; i<n; i++) {
818             fgets(line, sizeof(line), fp1);
819             cp=strchr(line, '#');
820             if (!cp)
821                 cp=strchr(line, '%');
822             memcpy(shortname, line, cp-line);
823             shortname[cp-line]=0;
824
825             if (strcmp(shortname, toremove)==0) {
826
827             } else {
828                 found = 1;
829                 fputs(line, fp2);
830             }
831         }
832
833         fclose(fp1);
834         fclose(fp2);
835         if (!found)
836             return CM_ERROR_NOSUCHFILE;
837
838         unlink(hfile);
839         rename(hfile2, hfile);
840     }
841     
842     lock_ReleaseMutex(&cm_Freelance_Lock);
843     cm_noteLocalMountPointChange();
844     return 0;
845 }
846
847 #endif /* AFS_FREELANCE_CLIENT */