freelance-compute-dirsize-correctly-20011009
[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 int cm_noLocalMountPoints;
22 int cm_fakeDirSize;
23 int cm_fakeDirCallback=0;
24 int cm_fakeGettingCallback=0;
25 int cm_fakeDirVersion = 0x8;
26 cm_localMountPoint_t* cm_localMountPoints;
27 osi_mutex_t cm_Freelance_Lock;
28 int cm_localMountPointChangeFlag = 0;
29 int cm_freelanceEnabled = 0;
30
31 void cm_InitFakeRootDir();
32
33 void cm_InitFreelance() {
34   
35         lock_InitializeMutex(&cm_Freelance_Lock, "Freelance Lock");
36   
37         // yj: first we make a call to cm_initLocalMountPoints
38         // to read all the local mount points from an ini file
39         cm_InitLocalMountPoints();
40         
41         // then we make a call to InitFakeRootDir to create
42         // a fake root directory based on the local mount points
43         cm_InitFakeRootDir();
44
45         // --- end of yj code
46 }
47
48 /* yj: Initialization of the fake root directory */
49 /* to be called while holding freelance lock unless during init. */
50 void cm_InitFakeRootDir() {
51         
52         int i, j, t1, t2;
53         char* currentPos;
54         int noChunks;
55         char mask;
56         
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
87         while (curDirEntry!=cm_noLocalMountPoints) {
88                 sizeOfCurEntry = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
89                 if ((curChunk + sizeOfCurEntry >= CPP) ||
90                         (curDirEntryInPage + 1 >= CM_DIR_EPP)) {
91                         curPage++;
92                         curDirEntryInPage = 0;
93                         curChunk = 1;
94                 }
95                 curChunk += sizeOfCurEntry;
96                 curDirEntry++;
97                 curDirEntryInPage++;
98         }
99
100         dirSize = (curPage+1) *  CM_DIR_PAGESIZE;
101         cm_FakeRootDir = malloc(dirSize);
102         cm_fakeDirSize = dirSize;
103
104         
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 }
227
228 int cm_FakeRootFid(cm_fid_t *fidp)
229 {
230   fidp->cell = 0x1;            /* root cell */
231         fidp->volume = 0x20000001;   /* root.afs ? */
232         fidp->vnode = 0x1;
233         fidp->unique = 0x1;
234 }
235   
236 int cm_getLocalMountPointChange() {
237   return cm_localMountPointChangeFlag;
238 }
239
240 int cm_clearLocalMountPointChange() {
241   cm_localMountPointChangeFlag = 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, j, hash;
257         cm_scache_t *scp, **lscpp, *tscp;
258
259         
260         printf("\n\n----- reinitialization starts ----- \n");
261
262
263         // first we invalidate all the SCPs that were created
264         // for the local mount points
265
266         printf("Invalidating local mount point scp...  ");
267
268         aFid.cell = 0x1;
269         aFid.volume=0x20000001;
270         aFid.unique=0x1;
271         aFid.vnode=0x2;
272
273         lock_ObtainWrite(&cm_scacheLock);
274         lock_ObtainMutex(&cm_Freelance_Lock);  /* always scache then freelance lock */
275         for (i=0; i<cm_noLocalMountPoints; i++) {
276                 hash = CM_SCACHE_HASH(&aFid);
277                 for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
278                         if (scp->fid.volume == aFid.volume &&
279                                 scp->fid.vnode == aFid.vnode &&
280                                 scp->fid.unique == aFid.unique 
281                                 ) {
282
283                                 // mark the scp to be reused
284                                 lock_ReleaseWrite(&cm_scacheLock);
285                                 lock_ObtainMutex(&scp->mx);
286                                 cm_DiscardSCache(scp);
287                                 lock_ReleaseMutex(&scp->mx);
288                                 cm_CallbackNotifyChange(scp);
289                                 lock_ObtainWrite(&cm_scacheLock);
290                                 scp->refCount--;
291
292                                 // take the scp out of the hash
293                                 lscpp = &cm_hashTablep[hash];
294                                 for (tscp=*lscpp; tscp; lscpp = &tscp->nextp, tscp = *lscpp) {
295                                         if (tscp == scp) break;
296                                 }
297                                 *lscpp = scp->nextp;
298                                 scp->flags &= ~CM_SCACHEFLAG_INHASH;
299
300
301                         }
302                 }
303                 aFid.vnode = aFid.vnode + 1;
304         }
305         lock_ReleaseWrite(&cm_scacheLock);
306         printf("\tall old scp cleared!\n");
307
308         // we must free the memory that was allocated in the prev
309         // cm_InitLocalMountPoints call
310         printf("Removing old localmountpoints...  ");
311         free(cm_localMountPoints);
312         printf("\tall old localmountpoints cleared!\n");
313
314         // now re-init the localmountpoints
315         printf("Creating new localmountpoints...  ");
316         cm_InitLocalMountPoints();
317         printf("\tcreated new set of localmountpoints!\n");
318         
319         
320         // now we have to free the memory allocated in cm_initfakerootdir
321         printf("Removing old fakedir...  ");
322         free(cm_FakeRootDir);
323         printf("\t\told fakedir removed!\n");
324
325         // then we re-create that dir
326         printf("Creating new fakedir...  ");
327         cm_InitFakeRootDir();
328         printf("\t\tcreated new fakedir!\n");   
329
330         lock_ReleaseMutex(&cm_Freelance_Lock);
331
332         printf("----- reinit complete -----\n\n");
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         
342         FILE *fp;
343         char line[200];
344         int n, i;
345         char* t;
346         cm_localMountPoint_t* aLocalMountPoint;
347         char hdir[120];
348
349         cm_GetConfigDir(hdir);
350         strcat(hdir, AFS_FREELANCE_INI);
351         // open the ini file for reading
352         fp = fopen(hdir, "r");
353
354         // if we fail to open the file, create an empty one
355         if (!fp) {
356           fp = fopen(hdir, "w");
357           fputs("0\n", fp);
358           fclose(fp);
359           return 0;  /* success */
360         }
361
362         // we successfully opened the file
363 #ifdef DEBUG
364         fprintf(stderr, "opened afs_freelance.ini\n");
365 #endif
366         
367         // now we read the first line to see how many entries
368         // there are
369         fgets(line, 200, fp);
370
371         // if the line is empty at any point when we're reading
372         // we're screwed. report error and return.
373         if (*line==0) {
374                 afsi_log("error occurred while reading afs_freelance.ini");
375                 fprintf(stderr, "error occurred while reading afs_freelance.ini");
376                 return -1;
377         }
378
379         // get the number of entries there are from the first line
380         // that we read
381         cm_noLocalMountPoints = atoi(line);
382
383         // create space to store the local mount points
384         cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
385         aLocalMountPoint = cm_localMountPoints;
386                 
387         // now we read n lines and parse them into local mount points
388         // where n is the number of local mount points there are, as
389         // determined above.
390         // Each line in the ini file represents 1 local mount point and 
391         // is in the format xxx#yyy:zzz, where xxx is the directory
392         // entry name, yyy is the cell name and zzz is the volume name.
393         // #yyy:zzz together make up the mount point.
394         for (i=0; i<cm_noLocalMountPoints; i++) {
395                 fgets(line, 200, fp);
396                 // check that the line is not empty
397                 if (line[0]==0) {
398                         afsi_log("error occurred while parsing entry in %s: empty line in line %d", AFS_FREELANCE_INI, i);
399                         fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: empty line in line %d", i);
400                         return -1;
401                 }
402                 // line is not empty, so let's parse it
403                 t = strchr(line, '#');
404                 // make sure that there is a '#' separator in the line
405                 if (!t) {
406                         afsi_log("error occurred while parsing entry in %s: no # separator in line %d", AFS_FREELANCE_INI, i);
407                         fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # separator in line %d", i);
408                         return -1;
409                 }
410                 aLocalMountPoint->namep=malloc(t-line+1);
411                 memcpy(aLocalMountPoint->namep, line, t-line);
412                 *(aLocalMountPoint->namep + (t-line)) = 0;
413                 aLocalMountPoint->mountPointStringp=malloc(strlen(line) - (t-line) + 1);
414                 memcpy(aLocalMountPoint->mountPointStringp, t, strlen(line)-(t-line)-2);
415                 *(aLocalMountPoint->mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
416 #ifdef DEBUG
417                 fprintf(stderr, "found mount point: name %s, string %s\n",
418                         aLocalMountPoint->namep,
419                         aLocalMountPoint->mountPointStringp);
420 #endif
421                 
422                 aLocalMountPoint++;
423
424         }
425         fclose(fp);
426         return 0;
427 }
428
429
430 int cm_getNoLocalMountPoints() {
431         return cm_noLocalMountPoints;
432 }
433
434 cm_localMountPoint_t* cm_getLocalMountPoint(int vnode) {
435         return 0;
436 }
437
438 long cm_FreelanceAddMount(char *filename, char *cellname, char *volume)
439 {
440     FILE *fp;
441     char hfile[120];
442     char line[200];
443     int n;
444
445     lock_ObtainMutex(&cm_Freelance_Lock);
446
447      cm_GetConfigDir(hfile);
448      strcat(hfile, AFS_FREELANCE_INI);
449      fp = fopen(hfile, "r+");
450      if (!fp)
451        return CM_ERROR_INVAL;
452      fgets(line, 200, fp);
453      n = atoi(line);
454      n++;
455      fseek(fp, 0, SEEK_SET);
456      fprintf(fp, "%d", n);
457      fseek(fp, 0, SEEK_END);
458      fprintf(fp, "%s#%s:%s\n", filename, cellname, volume);
459      fclose(fp);
460      lock_ReleaseMutex(&cm_Freelance_Lock);
461
462      cm_noteLocalMountPointChange();
463
464      return 0;
465 }
466
467 long cm_FreelanceRemoveMount(char *toremove)
468 {
469      int i, n, t1, t2;
470      char* cp;
471      char line[200];
472      char shortname[200];
473      char hfile[120], hfile2[120];
474      FILE *fp1, *fp2;
475      char cmd[200];
476      int found=0;
477
478     lock_ObtainMutex(&cm_Freelance_Lock);
479
480      cm_GetConfigDir(hfile);
481      strcat(hfile, AFS_FREELANCE_INI);
482      strcpy(hfile2, hfile);
483      strcat(hfile2, "2");
484      fp1=fopen(hfile, "r+");
485      if (!fp1)
486        return CM_ERROR_INVAL;
487      fp2=fopen(hfile2, "w+");
488      if (!fp2) {
489        fclose(fp1);
490        return CM_ERROR_INVAL;
491      }
492
493      fgets(line, 200, fp1);
494      n=atoi(line);
495      fprintf(fp2, "%d\n", n-1);
496
497      for (i=0; i<n; i++) {
498           fgets(line, 200, fp1);
499           cp=strchr(line, '#');
500           memcpy(shortname, line, cp-line);
501           shortname[cp-line]=0;
502
503           if (strcmp(shortname, toremove)==0) {
504
505           } else {
506             found = 1;
507             fputs(line, fp2);
508           }
509      }
510
511      fclose(fp1);
512      fclose(fp2);
513      if (!found)
514        return CM_ERROR_NOSUCHFILE;
515
516      unlink(hfile);
517      rename(hfile2, hfile);
518
519      lock_ReleaseMutex(&cm_Freelance_Lock);
520
521      cm_noteLocalMountPointChange();
522      return 0;
523 }
524
525 #endif /* AFS_FREELANCE_CLIENT */