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