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