1547f3a424e7449eda38b0c3a92d76dc2d077f43
[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 <winsock2.h>
7 #else
8 #include <netdb.h>
9 #endif /* !DJGPP */
10 #include <stdlib.h>
11 #include <malloc.h>
12 #include <string.h>
13
14 #include <rx/rx.h>
15
16 #include "afsd.h"
17 #ifdef AFS_FREELANCE_CLIENT
18 #include "cm_freelance.h"
19 #include "stdio.h"
20
21 extern void afsi_log(char *pattern, ...);
22
23 int cm_noLocalMountPoints;
24 int cm_fakeDirSize;
25 int cm_fakeDirCallback=0;
26 int cm_fakeGettingCallback=0;
27 int cm_fakeDirVersion = 0x8;
28 cm_localMountPoint_t* cm_localMountPoints;
29 osi_mutex_t cm_Freelance_Lock;
30 int cm_localMountPointChangeFlag = 0;
31 int cm_freelanceEnabled = 0;
32
33 void cm_InitFakeRootDir();
34
35 void cm_InitFreelance() {
36   
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         
107
108         // yj: when we get here, we've figured out how much memory we need and 
109         // allocated the appropriate space for it. we now prceed to fill
110         // it up with entries.
111         curPage = 0;
112         curDirEntry = 0;
113         curDirEntryInPage = 0;
114         curChunk = 0;
115         
116         // fields in the directory entry that are unused.
117         fakeEntry.flag = 1;
118         fakeEntry.length = 0;
119         fakeEntry.next = 0;
120         fakeEntry.fid.unique = htonl(1);
121
122         // the first page is special, it uses fakeDirHeader instead of fakePageHeader
123         // we fill up the page with dirEntries that belong there and we make changes
124         // to the fakeDirHeader.header.freeBitmap along the way. Then when we're done
125         // filling up the dirEntries in this page, we copy the fakeDirHeader into 
126         // the top of the page.
127
128         // init the freeBitmap array
129         for (i=0; i<8; i++) 
130                 fakeDirHeader.header.freeBitmap[i]=0;
131
132         fakeDirHeader.header.freeBitmap[0] = 0xff;
133         fakeDirHeader.header.freeBitmap[1] = 0x7f;
134         
135
136         // we start counting at 13 because the 0th to 12th chunks are used for header
137         curChunk = 13;
138
139         // stick the first 2 entries "." and ".." in
140         fakeEntry.fid.unique = htonl(1);
141         fakeEntry.fid.vnode = htonl(1);
142         strcpy(fakeEntry.name, ".");
143         currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
144         memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
145         curChunk++; curDirEntryInPage++;
146         strcpy(fakeEntry.name, "..");
147         currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
148         memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
149         curChunk++; curDirEntryInPage++;
150
151         // keep putting stuff into page 0 if
152         // 1. we're not done with all entries
153         // 2. we have less than CM_DIR_EPP entries in page 0
154         // 3. we're not out of chunks in page 0
155
156         while( (curDirEntry!=cm_noLocalMountPoints) && 
157                    (curDirEntryInPage < CM_DIR_EPP) &&
158                    (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0) <= CPP)) 
159         {
160
161                 noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
162                 fakeEntry.fid.vnode = htonl(curDirEntry + 2);
163                 currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
164
165                 memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
166                 strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)->namep);
167                 curDirEntry++;
168                 curDirEntryInPage++;
169                 for (i=0; i<noChunks; i++) {
170                         t1 = (curChunk + i) / 8;
171                         t2 = curChunk + i - (t1*8);
172                         fakeDirHeader.header.freeBitmap[t1] |= (1 << t2);
173                 }
174                 curChunk+=noChunks;
175         }
176
177         // when we get here, we're done with filling in the entries for page 0
178         // copy in the header info
179
180         memcpy(cm_FakeRootDir, &fakeDirHeader, 13 * CM_DIR_CHUNKSIZE);
181
182         curPage++;
183
184         // ok, page 0's done. Move on to the next page.
185         while (curDirEntry!=cm_noLocalMountPoints) {
186                 // setup a new page
187                 curChunk = 1;                   // the zeroth chunk is reserved for page header
188                 curDirEntryInPage = 0; 
189                 for (i=0; i<8; i++) {
190                         fakePageHeader.freeBitmap[i]=0;
191                 }
192                 fakePageHeader.freeCount = 0;
193                 fakePageHeader.pgcount = 0;
194                 fakePageHeader.tag = htons(1234);
195                 
196                 // while we're on the same page...
197                 while ( (curDirEntry!=cm_noLocalMountPoints) &&
198                                 (curDirEntryInPage < CM_DIR_EPP) &&
199                             (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0) <= CPP))
200                 {
201                         // add an entry to this page
202
203                         noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
204                         fakeEntry.fid.vnode=htonl(curDirEntry+2);
205                         currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
206                         memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
207                         strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)->namep);
208                         curDirEntry++;
209                         curDirEntryInPage++;
210                         for (i=0; i<noChunks; i++) {
211                                 t1 = (curChunk + i) / 8;
212                                 t2 = curChunk + i - (t1*8);
213                                 fakePageHeader.freeBitmap[t1] |= (1 << t2);
214                         }
215                         curChunk+=noChunks;
216                 }
217                 memcpy(cm_FakeRootDir + curPage * CM_DIR_PAGESIZE, &fakePageHeader, sizeof(fakePageHeader));
218
219                 curPage++;
220         }
221         
222         // we know the fakeDir is setup properly, so we claim that we have callback
223         cm_fakeDirCallback=1;
224
225         // when we get here, we've set up everything! done!
226
227
228 }
229
230 int cm_FakeRootFid(cm_fid_t *fidp)
231 {
232       fidp->cell = 0x1;            /* root cell */
233       fidp->volume = 0x20000001;   /* root.afs ? */
234       fidp->vnode = 0x1;
235       fidp->unique = 0x1;
236       return 0;
237 }
238   
239 int cm_getLocalMountPointChange() {
240   return cm_localMountPointChangeFlag;
241 }
242
243 int cm_clearLocalMountPointChange() {
244   cm_localMountPointChangeFlag = 0;
245 }
246
247 /* called directly from ioctl */
248 /* called while not holding freelance lock */
249 int cm_noteLocalMountPointChange() {
250   lock_ObtainMutex(&cm_Freelance_Lock);
251   cm_fakeDirVersion++;
252   cm_localMountPointChangeFlag = 1;
253   lock_ReleaseMutex(&cm_Freelance_Lock);
254   return 1;
255 }
256
257 int cm_reInitLocalMountPoints() {
258         cm_fid_t aFid;
259         int i, hash;
260         cm_scache_t *scp, **lscpp, *tscp;
261
262         
263         printf("\n\n----- reinitialization starts ----- \n");
264
265
266         // first we invalidate all the SCPs that were created
267         // for the local mount points
268
269         printf("Invalidating local mount point scp...  ");
270
271         aFid.cell = 0x1;
272         aFid.volume=0x20000001;
273         aFid.unique=0x1;
274         aFid.vnode=0x2;
275
276         lock_ObtainWrite(&cm_scacheLock);
277         lock_ObtainMutex(&cm_Freelance_Lock);  /* always scache then freelance lock */
278         for (i=0; i<cm_noLocalMountPoints; i++) {
279                 hash = CM_SCACHE_HASH(&aFid);
280                 for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
281                         if (scp->fid.volume == aFid.volume &&
282                                 scp->fid.vnode == aFid.vnode &&
283                                 scp->fid.unique == aFid.unique 
284                                 ) {
285
286                                 // mark the scp to be reused
287                                 lock_ReleaseWrite(&cm_scacheLock);
288                                 lock_ObtainMutex(&scp->mx);
289                                 cm_DiscardSCache(scp);
290                                 lock_ReleaseMutex(&scp->mx);
291                                 cm_CallbackNotifyChange(scp);
292                                 lock_ObtainWrite(&cm_scacheLock);
293                                 scp->refCount--;
294
295                                 // take the scp out of the hash
296                                 lscpp = &cm_hashTablep[hash];
297                                 for (tscp=*lscpp; tscp; lscpp = &tscp->nextp, tscp = *lscpp) {
298                                         if (tscp == scp) break;
299                                 }
300                                 *lscpp = scp->nextp;
301                                 scp->flags &= ~CM_SCACHEFLAG_INHASH;
302
303
304                         }
305                 }
306                 aFid.vnode = aFid.vnode + 1;
307         }
308         lock_ReleaseWrite(&cm_scacheLock);
309         printf("\tall old scp cleared!\n");
310
311         // we must free the memory that was allocated in the prev
312         // cm_InitLocalMountPoints call
313         printf("Removing old localmountpoints...  ");
314         free(cm_localMountPoints);
315         printf("\tall old localmountpoints cleared!\n");
316
317         // now re-init the localmountpoints
318         printf("Creating new localmountpoints...  ");
319         cm_InitLocalMountPoints();
320         printf("\tcreated new set of localmountpoints!\n");
321         
322         
323         // now we have to free the memory allocated in cm_initfakerootdir
324         printf("Removing old fakedir...  ");
325         free(cm_FakeRootDir);
326         printf("\t\told fakedir removed!\n");
327
328         // then we re-create that dir
329         printf("Creating new fakedir...  ");
330         cm_InitFakeRootDir();
331         printf("\t\tcreated new fakedir!\n");   
332
333         lock_ReleaseMutex(&cm_Freelance_Lock);
334
335         printf("----- reinit complete -----\n\n");
336         return 0;
337 }
338
339
340 // yj: open up the ini file and read all the local mount 
341 // points that are stored there. Part of the initialization
342 // process for the freelance client.
343 /* to be called while holding freelance lock unless during init. */
344 long cm_InitLocalMountPoints() {
345         
346         FILE *fp;
347         char line[200];
348         int i;
349         char* t;
350         cm_localMountPoint_t* aLocalMountPoint;
351         char hdir[120];
352
353         cm_GetConfigDir(hdir);
354         strcat(hdir, AFS_FREELANCE_INI);
355         // open the ini file for reading
356         fp = fopen(hdir, "r");
357
358         // if we fail to open the file, create an empty one
359         if (!fp) {
360           fp = fopen(hdir, "w");
361           fputs("0\n", fp);
362           fclose(fp);
363           return 0;  /* success */
364         }
365
366         // we successfully opened the file
367 #ifdef DEBUG
368         fprintf(stderr, "opened afs_freelance.ini\n");
369 #endif
370         
371         // now we read the first line to see how many entries
372         // there are
373         fgets(line, 200, fp);
374
375         // if the line is empty at any point when we're reading
376         // we're screwed. report error and return.
377         if (*line==0) {
378                 afsi_log("error occurred while reading afs_freelance.ini");
379                 fprintf(stderr, "error occurred while reading afs_freelance.ini");
380                 return -1;
381         }
382
383         // get the number of entries there are from the first line
384         // that we read
385         cm_noLocalMountPoints = atoi(line);
386
387         // create space to store the local mount points
388         cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
389         aLocalMountPoint = cm_localMountPoints;
390                 
391         // now we read n lines and parse them into local mount points
392         // where n is the number of local mount points there are, as
393         // determined above.
394         // Each line in the ini file represents 1 local mount point and 
395         // is in the format xxx#yyy:zzz, where xxx is the directory
396         // entry name, yyy is the cell name and zzz is the volume name.
397         // #yyy:zzz together make up the mount point.
398         for (i=0; i<cm_noLocalMountPoints; i++) {
399                 fgets(line, 200, fp);
400                 // check that the line is not empty
401                 if (line[0]==0) {
402                         afsi_log("error occurred while parsing entry in %s: empty line in line %d", AFS_FREELANCE_INI, i);
403                         fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: empty line in line %d", i);
404                         return -1;
405                 }
406                 // line is not empty, so let's parse it
407                 t = strchr(line, '#');
408                 // make sure that there is a '#' separator in the line
409                 if (!t) {
410                         afsi_log("error occurred while parsing entry in %s: no # separator in line %d", AFS_FREELANCE_INI, i);
411                         fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # separator in line %d", i);
412                         return -1;
413                 }
414                 aLocalMountPoint->namep=malloc(t-line+1);
415                 memcpy(aLocalMountPoint->namep, line, t-line);
416                 *(aLocalMountPoint->namep + (t-line)) = 0;
417                 aLocalMountPoint->mountPointStringp=malloc(strlen(line) - (t-line) + 1);
418                 memcpy(aLocalMountPoint->mountPointStringp, t, strlen(line)-(t-line)-2);
419                 *(aLocalMountPoint->mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
420 #ifdef DEBUG
421                 fprintf(stderr, "found mount point: name %s, string %s\n",
422                         aLocalMountPoint->namep,
423                         aLocalMountPoint->mountPointStringp);
424 #endif
425                 
426                 aLocalMountPoint++;
427
428         }
429         fclose(fp);
430         return 0;
431 }
432
433
434 int cm_getNoLocalMountPoints() {
435         return cm_noLocalMountPoints;
436 }
437
438 cm_localMountPoint_t* cm_getLocalMountPoint(int vnode) {
439         return 0;
440 }
441
442 long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, cm_fid_t *fidp)
443 {
444     FILE *fp;
445     char hfile[120];
446     char line[200];
447     char fullname[200];
448     int n;
449
450     /* before adding, verify the cell name; if it is not a valid cell,
451        don't add the mount point */
452     /* major performance issue? */
453     if (!cm_GetCell_Gen(cellname, fullname, CM_FLAG_CREATE))
454       return -1;
455 #if 0
456     if (strcmp(cellname, fullname) != 0)   /* no partial matches allowed */
457       return -1;
458 #endif
459     
460     lock_ObtainMutex(&cm_Freelance_Lock);
461
462      cm_GetConfigDir(hfile);
463      strcat(hfile, AFS_FREELANCE_INI);
464      fp = fopen(hfile, "r+");
465      if (!fp)
466        return CM_ERROR_INVAL;
467      fgets(line, 200, fp);
468      n = atoi(line);
469      n++;
470      fseek(fp, 0, SEEK_SET);
471      fprintf(fp, "%d", n);
472      fseek(fp, 0, SEEK_END);
473      fprintf(fp, "%s#%s:%s\n", filename, fullname, volume);
474      fclose(fp);
475      lock_ReleaseMutex(&cm_Freelance_Lock);
476
477      /*cm_reInitLocalMountPoints(&vnode);*/
478      if (fidp) {
479        fidp->unique = 1;
480        fidp->vnode = cm_noLocalMountPoints + 1;   /* vnode value of last mt pt */
481      }
482      cm_noteLocalMountPointChange();
483      
484      return 0;
485 }
486
487 long cm_FreelanceRemoveMount(char *toremove)
488 {
489      int i, n;
490      char* cp;
491      char line[200];
492      char shortname[200];
493      char hfile[120], hfile2[120];
494      FILE *fp1, *fp2;
495      int found=0;
496
497     lock_ObtainMutex(&cm_Freelance_Lock);
498
499      cm_GetConfigDir(hfile);
500      strcat(hfile, AFS_FREELANCE_INI);
501      strcpy(hfile2, hfile);
502      strcat(hfile2, "2");
503      fp1=fopen(hfile, "r+");
504      if (!fp1)
505        return CM_ERROR_INVAL;
506      fp2=fopen(hfile2, "w+");
507      if (!fp2) {
508        fclose(fp1);
509        return CM_ERROR_INVAL;
510      }
511
512      fgets(line, 200, fp1);
513      n=atoi(line);
514      fprintf(fp2, "%d\n", n-1);
515
516      for (i=0; i<n; i++) {
517           fgets(line, 200, fp1);
518           cp=strchr(line, '#');
519           memcpy(shortname, line, cp-line);
520           shortname[cp-line]=0;
521
522           if (strcmp(shortname, toremove)==0) {
523
524           } else {
525             found = 1;
526             fputs(line, fp2);
527           }
528      }
529
530      fclose(fp1);
531      fclose(fp2);
532      if (!found)
533        return CM_ERROR_NOSUCHFILE;
534
535      unlink(hfile);
536      rename(hfile2, hfile);
537
538      lock_ReleaseMutex(&cm_Freelance_Lock);
539
540      cm_noteLocalMountPointChange();
541      return 0;
542 }
543
544 #endif /* AFS_FREELANCE_CLIENT */