11 #include <WINNT/afsreg.h>
15 #ifdef AFS_FREELANCE_CLIENT
16 #include "cm_freelance.h"
19 extern void afsi_log(char *pattern, ...);
21 static int cm_noLocalMountPoints = 0;
22 char * cm_FakeRootDir = NULL;
23 int cm_fakeDirSize = 0;
24 int cm_fakeDirCallback=0;
25 int cm_fakeGettingCallback=0;
26 static cm_localMountPoint_t* cm_localMountPoints;
27 osi_mutex_t cm_Freelance_Lock;
28 static int cm_localMountPointChangeFlag = 0;
29 int cm_freelanceEnabled = 1;
30 time_t FakeFreelanceModTime = 0x3b49f6e2;
32 static int freelance_ShutdownFlag = 0;
33 static HANDLE hFreelanceChangeEvent = 0;
34 static HANDLE hFreelanceSymlinkChangeEvent = 0;
36 void cm_InitFakeRootDir();
38 void cm_FreelanceChangeNotifier(void * parmp) {
41 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
42 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
45 &hkFreelance) == ERROR_SUCCESS) {
47 hFreelanceChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
48 if (hFreelanceChangeEvent == NULL) {
49 RegCloseKey(hkFreelance);
55 /* check hFreelanceChangeEvent to see if it is set.
56 * if so, call cm_noteLocalMountPointChange()
58 if (RegNotifyChangeKeyValue( hkFreelance, /* hKey */
59 FALSE, /* bWatchSubtree */
60 REG_NOTIFY_CHANGE_LAST_SET, /* dwNotifyFilter */
61 hFreelanceChangeEvent, /* hEvent */
62 TRUE /* fAsynchronous */
64 RegCloseKey(hkFreelance);
65 CloseHandle(hFreelanceChangeEvent);
66 hFreelanceChangeEvent = 0;
70 if (WaitForSingleObject(hFreelanceChangeEvent, INFINITE) == WAIT_OBJECT_0)
72 if (freelance_ShutdownFlag == 1) {
73 RegCloseKey(hkFreelance);
74 CloseHandle(hFreelanceChangeEvent);
75 hFreelanceChangeEvent = 0;
78 cm_noteLocalMountPointChange(FALSE);
83 void cm_FreelanceSymlinkChangeNotifier(void * parmp) {
86 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
87 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
90 &hkFreelance) == ERROR_SUCCESS) {
92 hFreelanceSymlinkChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
93 if (hFreelanceSymlinkChangeEvent == NULL) {
94 RegCloseKey(hkFreelance);
100 /* check hFreelanceSymlinkChangeEvent to see if it is set.
101 * if so, call cm_noteLocalMountPointSymlinkChange()
103 if (RegNotifyChangeKeyValue( hkFreelance, /* hKey */
104 FALSE, /* bWatchSubtree */
105 REG_NOTIFY_CHANGE_LAST_SET, /* dwNotifyFilter */
106 hFreelanceSymlinkChangeEvent, /* hEvent */
107 TRUE /* fAsynchronous */
108 ) != ERROR_SUCCESS) {
109 RegCloseKey(hkFreelance);
110 CloseHandle(hFreelanceSymlinkChangeEvent);
111 hFreelanceSymlinkChangeEvent = 0;
115 if (WaitForSingleObject(hFreelanceSymlinkChangeEvent, INFINITE) == WAIT_OBJECT_0)
117 if (freelance_ShutdownFlag == 1) {
118 RegCloseKey(hkFreelance);
119 CloseHandle(hFreelanceSymlinkChangeEvent);
120 hFreelanceSymlinkChangeEvent = 0;
123 cm_noteLocalMountPointChange(FALSE);
129 cm_FreelanceShutdown(void)
131 freelance_ShutdownFlag = 1;
132 if (hFreelanceChangeEvent != 0)
133 thrd_SetEvent(hFreelanceChangeEvent);
134 if (hFreelanceSymlinkChangeEvent != 0)
135 thrd_SetEvent(hFreelanceSymlinkChangeEvent);
138 void cm_InitFreelance() {
142 lock_InitializeMutex(&cm_Freelance_Lock, "Freelance Lock", LOCK_HIERARCHY_FREELANCE_GLOBAL);
144 lock_ObtainMutex(&cm_Freelance_Lock);
145 // yj: first we make a call to cm_initLocalMountPoints
146 // to read all the local mount points from the registry
147 cm_InitLocalMountPoints();
149 // then we make a call to InitFakeRootDir to create
150 // a fake root directory based on the local mount points
151 cm_InitFakeRootDir();
152 // --- end of yj code
153 lock_ReleaseMutex(&cm_Freelance_Lock);
155 /* Start the registry monitor */
156 phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceChangeNotifier,
157 NULL, 0, &lpid, "cm_FreelanceChangeNotifier");
158 osi_assertx(phandle != NULL, "cm_FreelanceChangeNotifier thread create failure");
159 thrd_CloseHandle(phandle);
161 phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceSymlinkChangeNotifier,
162 NULL, 0, &lpid, "cm_FreelanceSymlinkChangeNotifier");
163 osi_assertx(phandle != NULL, "cm_FreelanceSymlinkChangeNotifier thread create failure");
164 thrd_CloseHandle(phandle);
167 /* yj: Initialization of the fake root directory */
168 /* to be called while holding freelance lock. */
169 void cm_InitFakeRootDir() {
174 // allocate space for the fake info
175 cm_dirHeader_t fakeDirHeader;
176 cm_dirEntry_t fakeEntry;
177 cm_pageHeader_t fakePageHeader;
179 // i'm going to calculate how much space is needed for
180 // this fake root directory. we have these rules:
181 // 1. there are cm_noLocalMountPoints number of entries
182 // 2. each page is CM_DIR_PAGESIZE in size
183 // 3. the first 13 chunks of the first page are used for
185 // 4. the first chunk of all subsequent pages are used
186 // for page header stuff
187 // 5. a max of CM_DIR_EPP entries are allowed per page
188 // 6. each entry takes 1 or more chunks, depending on
189 // the size of the mount point string, as determined
191 // 7. each chunk is CM_DIR_CHUNKSIZE bytes
193 int CPP = CM_DIR_PAGESIZE / CM_DIR_CHUNKSIZE;
194 int curChunk = 13; // chunks 0 - 12 are used for header stuff
195 // of the first page in the directory
198 int curDirEntryInPage = 0;
202 /* Reserve 2 directory chunks for "." and ".." */
205 while (curDirEntry<cm_noLocalMountPoints) {
206 sizeOfCurEntry = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
207 if ((curChunk + sizeOfCurEntry >= CPP) ||
208 (curDirEntryInPage + 1 >= CM_DIR_EPP)) {
210 curDirEntryInPage = 0;
213 curChunk += sizeOfCurEntry;
218 dirSize = (curPage+1) * CM_DIR_PAGESIZE;
219 if (cm_fakeDirSize != dirSize) {
221 free(cm_FakeRootDir);
222 cm_FakeRootDir = calloc(dirSize, 1);
223 cm_fakeDirSize = dirSize;
226 // yj: when we get here, we've figured out how much memory we need and
227 // allocated the appropriate space for it. we now prceed to fill
228 // it up with entries.
231 curDirEntryInPage = 0;
234 // fields in the directory entry that are unused.
236 fakeEntry.length = 0;
238 fakeEntry.fid.unique = htonl(1);
240 // the first page is special, it uses fakeDirHeader instead of fakePageHeader
241 // we fill up the page with dirEntries that belong there and we make changes
242 // to the fakeDirHeader.header.freeBitmap along the way. Then when we're done
243 // filling up the dirEntries in this page, we copy the fakeDirHeader into
244 // the top of the page.
246 // init the freeBitmap array
248 fakeDirHeader.header.freeBitmap[i]=0;
250 fakeDirHeader.header.freeBitmap[0] = 0xff;
251 fakeDirHeader.header.freeBitmap[1] = 0x7f;
254 // we start counting at 13 because the 0th to 12th chunks are used for header
257 // stick the first 2 entries "." and ".." in
258 fakeEntry.fid.vnode = htonl(1);
259 strcpy(fakeEntry.name, ".");
260 currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
261 memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
262 curChunk++; curDirEntryInPage++;
263 strcpy(fakeEntry.name, "..");
264 currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
265 memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
266 curChunk++; curDirEntryInPage++;
268 // keep putting stuff into page 0 if
269 // 1. we're not done with all entries
270 // 2. we have less than CM_DIR_EPP entries in page 0
271 // 3. we're not out of chunks in page 0
273 while( (curDirEntry<cm_noLocalMountPoints) &&
274 (curDirEntryInPage < CM_DIR_EPP) &&
275 (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0) <= CPP))
278 noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
279 /* enforce the rule that only directories have odd vnode values */
280 fakeEntry.fid.vnode = htonl((curDirEntry + 1) * 2);
281 fakeEntry.fid.unique = htonl(curDirEntry + 1);
282 currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
284 memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
285 strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)->namep);
288 for (i=0; i<noChunks; i++) {
289 t1 = (curChunk + i) / 8;
290 t2 = curChunk + i - (t1*8);
291 fakeDirHeader.header.freeBitmap[t1] |= (1 << t2);
296 // when we get here, we're done with filling in the entries for page 0
297 // copy in the header info
299 memcpy(cm_FakeRootDir, &fakeDirHeader, 13 * CM_DIR_CHUNKSIZE);
303 // ok, page 0's done. Move on to the next page.
304 while (curDirEntry<cm_noLocalMountPoints) {
306 curChunk = 1; // the zeroth chunk is reserved for page header
307 curDirEntryInPage = 0;
308 for (i=0; i<8; i++) {
309 fakePageHeader.freeBitmap[i]=0;
311 fakePageHeader.freeCount = 0;
312 fakePageHeader.pgcount = 0;
313 fakePageHeader.tag = htons(1234);
315 // while we're on the same page...
316 while ( (curDirEntry<cm_noLocalMountPoints) &&
317 (curDirEntryInPage < CM_DIR_EPP) &&
318 (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0) <= CPP))
320 // add an entry to this page
322 noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)->namep, 0);
323 /* enforce the rule that only directories have odd vnode values */
324 fakeEntry.fid.vnode = htonl((curDirEntry + 1) * 2);
325 fakeEntry.fid.unique = htonl(curDirEntry + 1);
326 currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
327 memcpy(currentPos, &fakeEntry, CM_DIR_CHUNKSIZE);
328 strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)->namep);
331 for (i=0; i<noChunks; i++) {
332 t1 = (curChunk + i) / 8;
333 t2 = curChunk + i - (t1*8);
334 fakePageHeader.freeBitmap[t1] |= (1 << t2);
338 memcpy(cm_FakeRootDir + curPage * CM_DIR_PAGESIZE, &fakePageHeader, sizeof(fakePageHeader));
343 // we know the fakeDir is setup properly, so we claim that we have callback
344 osi_Log0(afsd_logp,"cm_InitFakeRootDir fakeDirCallback=1");
345 cm_fakeDirCallback=1;
347 // when we get here, we've set up everything! done!
350 int cm_FakeRootFid(cm_fid_t *fidp)
353 AFS_FAKE_ROOT_CELL_ID, /* root cell */
354 AFS_FAKE_ROOT_VOL_ID, /* root.afs ? */
359 /* called directly from ioctl */
360 /* called while not holding freelance lock */
361 int cm_noteLocalMountPointChange(afs_int32 locked) {
363 lock_ObtainMutex(&cm_Freelance_Lock);
364 cm_data.fakeDirVersion++;
365 cm_localMountPointChangeFlag = 1;
367 lock_ReleaseMutex(&cm_Freelance_Lock);
371 int cm_getLocalMountPointChange() {
372 return cm_localMountPointChangeFlag;
375 int cm_clearLocalMountPointChange() {
376 cm_localMountPointChangeFlag = 0;
380 int cm_reInitLocalMountPoints() {
383 cm_scache_t *scp, **lscpp, *tscp;
385 osi_Log0(afsd_logp,"----- freelance reinitialization starts ----- ");
387 // first we invalidate all the SCPs that were created
388 // for the local mount points
390 osi_Log0(afsd_logp,"Invalidating local mount point scp... ");
392 lock_ObtainWrite(&cm_scacheLock);
393 lock_ObtainMutex(&cm_Freelance_Lock); /* always scache then freelance lock */
394 for (i=0; i<=cm_noLocalMountPoints; i++) {
396 cm_SetFid(&aFid, AFS_FAKE_ROOT_CELL_ID, AFS_FAKE_ROOT_VOL_ID, 1, 1);
398 cm_SetFid(&aFid, AFS_FAKE_ROOT_CELL_ID, AFS_FAKE_ROOT_VOL_ID, i*2, i);
399 hash = CM_SCACHE_HASH(&aFid);
400 for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
401 if (scp != cm_data.rootSCachep && cm_FidCmp(&scp->fid, &aFid) == 0) {
402 // mark the scp to be reused
403 cm_HoldSCacheNoLock(scp);
404 lock_ReleaseMutex(&cm_Freelance_Lock);
405 lock_ReleaseWrite(&cm_scacheLock);
406 lock_ObtainWrite(&scp->rw);
407 cm_DiscardSCache(scp);
409 // take the scp out of the hash
410 lock_ObtainWrite(&cm_scacheLock);
411 for (lscpp = &cm_data.scacheHashTablep[hash], tscp = cm_data.scacheHashTablep[hash];
413 lscpp = &tscp->nextp, tscp = tscp->nextp) {
417 scp->flags &= ~CM_SCACHEFLAG_INHASH;
422 lock_ReleaseWrite(&scp->rw);
423 lock_ReleaseWrite(&cm_scacheLock);
424 cm_CallbackNotifyChange(scp);
425 lock_ObtainWrite(&cm_scacheLock);
426 cm_ReleaseSCacheNoLock(scp);
427 lock_ObtainMutex(&cm_Freelance_Lock);
431 lock_ReleaseWrite(&cm_scacheLock);
432 osi_Log0(afsd_logp,"\tall old scp cleared!");
434 // we must free the memory that was allocated in the prev
435 // cm_InitLocalMountPoints call
436 osi_Log0(afsd_logp,"Removing old localmountpoints... ");
437 free(cm_localMountPoints);
438 cm_localMountPoints = NULL;
439 cm_noLocalMountPoints = 0;
440 osi_Log0(afsd_logp,"\tall old localmountpoints cleared!");
442 // now re-init the localmountpoints
443 osi_Log0(afsd_logp,"Creating new localmountpoints... ");
444 cm_InitLocalMountPoints();
445 osi_Log0(afsd_logp,"\tcreated new set of localmountpoints!");
447 // then we re-create that dir
448 osi_Log0(afsd_logp,"Creating new fakedir... ");
449 cm_InitFakeRootDir();
450 osi_Log0(afsd_logp,"\t\tcreated new fakedir!");
452 lock_ReleaseMutex(&cm_Freelance_Lock);
454 osi_Log0(afsd_logp,"----- freelance reinit complete -----");
459 // yj: open up the registry and read all the local mount
460 // points that are stored there. Part of the initialization
461 // process for the freelance client.
462 /* to be called while holding freelance lock. */
463 long cm_InitLocalMountPoints() {
468 cm_localMountPoint_t* aLocalMountPoint;
471 char rootCellName[256];
472 HKEY hkFreelance = 0, hkFreelanceSymlinks = 0;
473 DWORD dwType, dwSize;
474 DWORD dwMountPoints = 0;
476 DWORD dwSymlinks = 0;
477 FILETIME ftLastWriteTime;
479 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
480 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
482 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
483 &hkFreelance) == ERROR_SUCCESS) {
485 RegQueryInfoKey( hkFreelance,
488 NULL, /* lpReserved */
489 NULL, /* lpcSubKeys */
490 NULL, /* lpcMaxSubKeyLen */
491 NULL, /* lpcMaxClassLen */
492 &dwMountPoints, /* lpcValues */
493 NULL, /* lpcMaxValueNameLen */
494 NULL, /* lpcMaxValueLen */
495 NULL, /* lpcbSecurityDescriptor */
496 &ftLastWriteTime /* lpftLastWriteTime */
499 cm_UnixTimeFromLargeSearchTime(&FakeFreelanceModTime, &ftLastWriteTime);
501 if ( dwMountPoints == 0 ) {
502 rootCellName[0] = '.';
503 code = cm_GetRootCellName(&rootCellName[1]);
505 lock_ReleaseMutex(&cm_Freelance_Lock);
506 cm_FreelanceAddMount(&rootCellName[1], &rootCellName[1], "root.cell.", 0, NULL);
507 cm_FreelanceAddMount(rootCellName, &rootCellName[1], "root.cell.", 1, NULL);
508 cm_FreelanceAddMount(".root", &rootCellName[1], "root.afs.", 1, NULL);
509 lock_ObtainMutex(&cm_Freelance_Lock);
514 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
515 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
518 REG_OPTION_NON_VOLATILE,
519 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
521 &hkFreelanceSymlinks,
522 NULL) == ERROR_SUCCESS) {
524 RegQueryInfoKey( hkFreelanceSymlinks,
527 NULL, /* lpReserved */
528 NULL, /* lpcSubKeys */
529 NULL, /* lpcMaxSubKeyLen */
530 NULL, /* lpcMaxClassLen */
531 &dwSymlinks, /* lpcValues */
532 NULL, /* lpcMaxValueNameLen */
533 NULL, /* lpcMaxValueLen */
534 NULL, /* lpcbSecurityDescriptor */
535 NULL /* lpftLastWriteTime */
539 // get the number of entries there are from the first line
541 cm_noLocalMountPoints = dwMountPoints + dwSymlinks;
543 // create space to store the local mount points
544 cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
545 aLocalMountPoint = cm_localMountPoints;
547 // now we read n lines and parse them into local mount points
548 // where n is the number of local mount points there are, as
550 // Each line in the ini file represents 1 local mount point and
551 // is in the format xxx#yyy:zzz, where xxx is the directory
552 // entry name, yyy is the cell name and zzz is the volume name.
553 // #yyy:zzz together make up the mount point.
554 for ( dwIndex = 0 ; dwIndex < dwMountPoints; dwIndex++ ) {
555 TCHAR szValueName[16];
556 DWORD dwValueSize = 16;
557 dwSize = sizeof(line);
558 if (RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
559 &dwType, line, &dwSize))
561 afsi_log("RegEnumValue(hkFreelance) failed");
562 cm_noLocalMountPoints--;
566 afsi_log("Mountpoint[%d] = %s",dwIndex, line);
568 /* find the trailing dot; null terminate after it */
569 t2 = strrchr(line, '.');
573 for ( t=line;*t;t++ ) {
574 if ( !isprint(*t) ) {
575 afsi_log("error occurred while parsing mountpoint entry [%d]: non-printable character", dwIndex);
576 fprintf(stderr, "error occurred while parsing mountpoint entry [%d]: non-printable character", dwIndex);
577 cm_noLocalMountPoints--;
582 // line is not empty, so let's parse it
583 t = strchr(line, '#');
585 t = strchr(line, '%');
586 // make sure that there is a '#' or '%' separator in the line
588 afsi_log("error occurred while parsing mountpoint entry [%d]: no # or %% separator", dwIndex);
589 fprintf(stderr, "error occurred while parsing mountpoint entry [%d]: no # or %% separator", dwIndex);
590 cm_noLocalMountPoints--;
594 aLocalMountPoint->fileType = CM_SCACHETYPE_MOUNTPOINT;
595 aLocalMountPoint->namep=malloc(t-line+1);
596 strncpy(aLocalMountPoint->namep, line, t-line);
597 aLocalMountPoint->namep[t-line] = '\0';
599 /* copy the mount point string */
600 aLocalMountPoint->mountPointStringp=malloc(strlen(t));
601 strncpy(aLocalMountPoint->mountPointStringp, t, strlen(t)-1);
602 aLocalMountPoint->mountPointStringp[strlen(t)-1] = '\0';
604 osi_Log2(afsd_logp,"found mount point: name %s, string %s",
605 osi_LogSaveString(afsd_logp,aLocalMountPoint->namep),
606 osi_LogSaveString(afsd_logp,aLocalMountPoint->mountPointStringp));
611 for ( dwIndex = 0 ; dwIndex < dwSymlinks; dwIndex++ ) {
612 TCHAR szValueName[16];
613 DWORD dwValueSize = 16;
614 dwSize = sizeof(line);
615 if (RegEnumValue( hkFreelanceSymlinks, dwIndex, szValueName, &dwValueSize, NULL,
616 &dwType, line, &dwSize))
618 afsi_log("RegEnumValue(hkFreelanceSymlinks) failed");
619 cm_noLocalMountPoints--;
623 afsi_log("Symlink[%d] = %s",dwIndex, line);
625 /* find the trailing dot; null terminate after it */
626 t2 = strrchr(line, '.');
630 for ( t=line;*t;t++ ) {
631 if ( !isprint(*t) ) {
632 afsi_log("error occurred while parsing symlink entry [%d]: non-printable character", dwIndex);
633 fprintf(stderr, "error occurred while parsing symlink entry [%d]: non-printable character", dwIndex);
634 cm_noLocalMountPoints--;
639 // line is not empty, so let's parse it
640 t = strchr(line, ':');
642 // make sure that there is a ':' separator in the line
644 afsi_log("error occurred while parsing symlink entry [%d]: no ':' separator", dwIndex);
645 fprintf(stderr, "error occurred while parsing symlink entry [%d]: no ':' separator", dwIndex);
646 cm_noLocalMountPoints--;
650 aLocalMountPoint->fileType = CM_SCACHETYPE_SYMLINK;
651 aLocalMountPoint->namep=malloc(t-line+1);
652 strncpy(aLocalMountPoint->namep, line, t-line);
653 aLocalMountPoint->namep[t-line] = '\0';
655 /* copy the symlink string */
656 aLocalMountPoint->mountPointStringp=malloc(strlen(t)-1);
657 strncpy(aLocalMountPoint->mountPointStringp, t+1, strlen(t)-2);
658 aLocalMountPoint->mountPointStringp[strlen(t)-2] = '\0';
660 osi_Log2(afsd_logp,"found symlink: name %s, string %s",
661 osi_LogSaveString(afsd_logp,aLocalMountPoint->namep),
662 osi_LogSaveString(afsd_logp,aLocalMountPoint->mountPointStringp));
667 if ( hkFreelanceSymlinks )
668 RegCloseKey( hkFreelanceSymlinks );
669 RegCloseKey(hkFreelance);
673 /* What follows is the old code to read freelance mount points
674 * out of a text file modified to copy the data into the registry
676 cm_GetConfigDir(hdir, sizeof(hdir));
677 strcat(hdir, AFS_FREELANCE_INI);
678 // open the ini file for reading
679 fp = fopen(hdir, "r");
681 /* look in the Windows directory where we used to store the file */
682 GetWindowsDirectory(hdir, sizeof(hdir));
684 strcat(hdir, AFS_FREELANCE_INI);
685 fp = fopen(hdir, "r");
688 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
689 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
692 REG_OPTION_NON_VOLATILE,
700 RegCloseKey(hkFreelance);
701 rootCellName[0] = '.';
702 code = cm_GetRootCellName(&rootCellName[1]);
704 lock_ReleaseMutex(&cm_Freelance_Lock);
705 cm_FreelanceAddMount(&rootCellName[1], &rootCellName[1], "root.cell.", 0, NULL);
706 cm_FreelanceAddMount(rootCellName, &rootCellName[1], "root.cell.", 1, NULL);
707 cm_FreelanceAddMount(".root", &rootCellName[1], "root.afs.", 1, NULL);
708 lock_ObtainMutex(&cm_Freelance_Lock);
713 // we successfully opened the file
714 osi_Log0(afsd_logp,"opened afs_freelance.ini");
716 // now we read the first line to see how many entries
718 fgets(line, sizeof(line), fp);
720 // if the line is empty at any point when we're reading
721 // we're screwed. report error and return.
723 afsi_log("error occurred while reading afs_freelance.ini");
724 fprintf(stderr, "error occurred while reading afs_freelance.ini");
728 // get the number of entries there are from the first line
730 cm_noLocalMountPoints = atoi(line);
732 if (cm_noLocalMountPoints > 0) {
733 // create space to store the local mount points
734 cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
735 aLocalMountPoint = cm_localMountPoints;
738 // now we read n lines and parse them into local mount points
739 // where n is the number of local mount points there are, as
741 // Each line in the ini file represents 1 local mount point and
742 // is in the format xxx#yyy:zzz, where xxx is the directory
743 // entry name, yyy is the cell name and zzz is the volume name.
744 // #yyy:zzz together make up the mount point.
745 for (i=0; i<cm_noLocalMountPoints; i++) {
746 fgets(line, sizeof(line), fp);
747 // check that the line is not empty
749 afsi_log("error occurred while parsing entry in %s: empty line in line %d", AFS_FREELANCE_INI, i);
750 fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: empty line in line %d", i);
754 /* find the trailing dot; null terminate after it */
755 t2 = strrchr(line, '.');
761 /* we are migrating to the registry */
762 sprintf(szIndex,"%d",dwIndex++);
764 dwSize = (DWORD)strlen(line) + 1;
765 RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
768 // line is not empty, so let's parse it
769 t = strchr(line, '#');
771 t = strchr(line, '%');
772 // make sure that there is a '#' or '%' separator in the line
774 afsi_log("error occurred while parsing entry in %s: no # or %% separator in line %d", AFS_FREELANCE_INI, i);
775 fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # or %% separator in line %d", i);
778 aLocalMountPoint->namep=malloc(t-line+1);
779 memcpy(aLocalMountPoint->namep, line, t-line);
780 *(aLocalMountPoint->namep + (t-line)) = 0;
782 aLocalMountPoint->mountPointStringp=malloc(strlen(line) - (t-line) + 1);
783 memcpy(aLocalMountPoint->mountPointStringp, t, strlen(line)-(t-line)-1);
784 *(aLocalMountPoint->mountPointStringp + (strlen(line)-(t-line)-1)) = 0;
786 osi_Log2(afsd_logp,"found mount point: name %s, string %s",
787 aLocalMountPoint->namep,
788 aLocalMountPoint->mountPointStringp);
794 RegCloseKey(hkFreelance);
800 int cm_getNoLocalMountPoints() {
801 return cm_noLocalMountPoints;
804 long cm_FreelanceMountPointExists(char * filename, int prefix_ok)
810 HKEY hkFreelance = 0;
811 DWORD dwType, dwSize;
815 lock_ObtainMutex(&cm_Freelance_Lock);
817 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
818 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
820 KEY_READ|KEY_QUERY_VALUE,
821 &hkFreelance) == ERROR_SUCCESS)
823 RegQueryInfoKey( hkFreelance,
826 NULL, /* lpReserved */
827 NULL, /* lpcSubKeys */
828 NULL, /* lpcMaxSubKeyLen */
829 NULL, /* lpcMaxClassLen */
830 &dwMountPoints, /* lpcValues */
831 NULL, /* lpcMaxValueNameLen */
832 NULL, /* lpcMaxValueLen */
833 NULL, /* lpcbSecurityDescriptor */
834 NULL /* lpftLastWriteTime */
837 for ( dwIndex = 0; dwIndex < dwMountPoints; dwIndex++ ) {
838 TCHAR szValueName[16];
839 DWORD dwValueSize = 16;
840 dwSize = sizeof(line);
841 RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
842 &dwType, line, &dwSize);
844 cp=strchr(line, '#');
846 cp=strchr(line, '%');
847 memcpy(shortname, line, cp-line);
848 shortname[cp-line]=0;
850 if (!strcmp(shortname, filename)) {
855 for ( dwIndex = 0; dwIndex < dwMountPoints; dwIndex++ ) {
856 TCHAR szValueName[16];
857 DWORD dwValueSize = 16;
858 dwSize = sizeof(line);
859 RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
860 &dwType, line, &dwSize);
862 cp=strchr(line, '#');
864 cp=strchr(line, '%');
865 memcpy(shortname, line, cp-line);
866 shortname[cp-line]=0;
868 if (!cm_stricmp_utf8(shortname, filename)) {
873 if (prefix_ok && strlen(shortname) - strlen(filename) == 1 && !strncmp(shortname, filename, strlen(filename))) {
878 RegCloseKey(hkFreelance);
881 lock_ReleaseMutex(&cm_Freelance_Lock);
886 long cm_FreelanceSymlinkExists(char * filename, int prefix_ok)
892 HKEY hkFreelance = 0;
893 DWORD dwType, dwSize;
897 lock_ObtainMutex(&cm_Freelance_Lock);
899 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
900 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
902 KEY_READ|KEY_QUERY_VALUE,
903 &hkFreelance) == ERROR_SUCCESS)
905 RegQueryInfoKey( hkFreelance,
908 NULL, /* lpReserved */
909 NULL, /* lpcSubKeys */
910 NULL, /* lpcMaxSubKeyLen */
911 NULL, /* lpcMaxClassLen */
912 &dwSymlinks, /* lpcValues */
913 NULL, /* lpcMaxValueNameLen */
914 NULL, /* lpcMaxValueLen */
915 NULL, /* lpcbSecurityDescriptor */
916 NULL /* lpftLastWriteTime */
919 for ( dwIndex = 0; dwIndex < dwSymlinks; dwIndex++ ) {
920 TCHAR szValueName[16];
921 DWORD dwValueSize = 16;
922 dwSize = sizeof(line);
923 RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
924 &dwType, line, &dwSize);
926 cp=strchr(line, ':');
927 memcpy(shortname, line, cp-line);
928 shortname[cp-line]=0;
930 if (!strcmp(shortname, filename)) {
935 if (prefix_ok && strlen(shortname) - strlen(filename) == 1 && !strncmp(shortname, filename, strlen(filename))) {
940 for ( dwIndex = 0; dwIndex < dwSymlinks; dwIndex++ ) {
941 TCHAR szValueName[16];
942 DWORD dwValueSize = 16;
943 dwSize = sizeof(line);
944 RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
945 &dwType, line, &dwSize);
947 cp=strchr(line, ':');
948 memcpy(shortname, line, cp-line);
949 shortname[cp-line]=0;
951 if (!cm_stricmp_utf8(shortname, filename)) {
956 RegCloseKey(hkFreelance);
959 lock_ReleaseMutex(&cm_Freelance_Lock);
964 long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp)
969 char fullname[CELL_MAXNAMELEN];
972 HKEY hkFreelance = 0;
973 DWORD dwType, dwSize;
978 /* before adding, verify the cell name; if it is not a valid cell,
979 don't add the mount point.
980 allow partial matches as a means of poor man's alias. */
981 /* major performance issue? */
982 osi_Log4(afsd_logp,"Freelance Add Mount request: filename=%s cellname=%s volume=%s %s",
983 osi_LogSaveString(afsd_logp,filename),
984 osi_LogSaveString(afsd_logp,cellname),
985 osi_LogSaveString(afsd_logp,volume),
988 if ( filename[0] == '\0' || cellname[0] == '\0' || volume[0] == '\0' )
989 return CM_ERROR_INVAL;
991 if (cellname[0] == '.') {
992 if (!cm_GetCell_Gen(&cellname[1], fullname, CM_FLAG_CREATE))
993 return CM_ERROR_INVAL;
995 if (!cm_GetCell_Gen(cellname, fullname, CM_FLAG_CREATE))
996 return CM_ERROR_INVAL;
999 if ( cm_FreelanceMountPointExists(filename, 0) ||
1000 cm_FreelanceSymlinkExists(filename, 0) ) {
1001 code = CM_ERROR_EXISTS;
1005 osi_Log1(afsd_logp,"Freelance Adding Mount for Cell: %s",
1006 osi_LogSaveString(afsd_logp,cellname));
1008 lock_ObtainMutex(&cm_Freelance_Lock);
1010 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
1011 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
1013 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
1014 &hkFreelance) == ERROR_SUCCESS) {
1016 RegQueryInfoKey( hkFreelance,
1018 NULL, /* lpcClass */
1019 NULL, /* lpReserved */
1020 NULL, /* lpcSubKeys */
1021 NULL, /* lpcMaxSubKeyLen */
1022 NULL, /* lpcMaxClassLen */
1023 &dwMountPoints, /* lpcValues */
1024 NULL, /* lpcMaxValueNameLen */
1025 NULL, /* lpcMaxValueLen */
1026 NULL, /* lpcbSecurityDescriptor */
1027 NULL /* lpftLastWriteTime */
1031 sprintf(line, "%s%%%s:%s", filename, fullname, volume);
1033 sprintf(line, "%s#%s:%s", filename, fullname, volume);
1035 /* If we are adding a new value, there must be an unused name
1036 * within the range 0 to dwMountPoints
1038 for ( dwIndex = 0; dwIndex <= dwMountPoints; dwIndex++ ) {
1042 dwSize = sizeof(szMount);
1043 sprintf(szIndex, "%d", dwIndex);
1044 if (RegQueryValueEx( hkFreelance, szIndex, 0, &dwType, szMount, &dwSize) != ERROR_SUCCESS) {
1045 /* found an unused value */
1047 dwSize = (DWORD)strlen(line) + 1;
1048 RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
1051 int len = (int)strlen(filename);
1052 if ( dwType == REG_SZ && !strncmp(filename, szMount, len) &&
1053 (szMount[len] == '%' || szMount[len] == '#')) {
1054 /* Replace the existing value */
1056 dwSize = (DWORD)strlen(line) + 1;
1057 RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
1062 RegCloseKey(hkFreelance);
1065 cm_GetConfigDir(hfile, sizeof(hfile));
1066 strcat(hfile, AFS_FREELANCE_INI);
1067 fp = fopen(hfile, "r+");
1069 return CM_ERROR_INVAL;
1070 fgets(line, sizeof(line), fp);
1073 fseek(fp, 0, SEEK_SET);
1074 fprintf(fp, "%d", n);
1075 fseek(fp, 0, SEEK_END);
1077 fprintf(fp, "%s%%%s:%s\n", filename, fullname, volume);
1079 fprintf(fp, "%s#%s:%s\n", filename, fullname, volume);
1083 /* Do this while we are holding the lock */
1084 cm_noteLocalMountPointChange(TRUE);
1085 lock_ReleaseMutex(&cm_Freelance_Lock);
1091 clientchar_t *cpath;
1095 cpath = cm_FsStringToClientStringAlloc(filename, -1, NULL);
1097 return CM_ERROR_NOSUCHPATH;
1099 if (cm_getLocalMountPointChange()) { // check for changes
1100 cm_clearLocalMountPointChange(); // clear the changefile
1101 cm_reInitLocalMountPoints(); // start reinit
1104 code = cm_NameI(cm_data.rootSCachep, cpath,
1105 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1106 cm_rootUserp, NULL, &req, &scp);
1111 cm_ReleaseSCache(scp);
1117 long cm_FreelanceRemoveMount(char *toremove)
1122 char shortname[200];
1123 char hfile[260], hfile2[260];
1126 HKEY hkFreelance = 0;
1127 DWORD dwType, dwSize;
1128 DWORD dwMountPoints;
1131 lock_ObtainMutex(&cm_Freelance_Lock);
1133 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
1134 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
1136 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
1137 &hkFreelance) == ERROR_SUCCESS) {
1139 RegQueryInfoKey( hkFreelance,
1141 NULL, /* lpcClass */
1142 NULL, /* lpReserved */
1143 NULL, /* lpcSubKeys */
1144 NULL, /* lpcMaxSubKeyLen */
1145 NULL, /* lpcMaxClassLen */
1146 &dwMountPoints, /* lpcValues */
1147 NULL, /* lpcMaxValueNameLen */
1148 NULL, /* lpcMaxValueLen */
1149 NULL, /* lpcbSecurityDescriptor */
1150 NULL /* lpftLastWriteTime */
1153 for ( dwIndex = 0; dwIndex < dwMountPoints; dwIndex++ ) {
1154 TCHAR szValueName[16];
1155 DWORD dwValueSize = 16;
1156 dwSize = sizeof(line);
1157 RegEnumValue( hkFreelance, dwIndex, szValueName, &dwValueSize, NULL,
1158 &dwType, line, &dwSize);
1160 cp=strchr(line, '#');
1162 cp=strchr(line, '%');
1163 memcpy(shortname, line, cp-line);
1164 shortname[cp-line]=0;
1166 if (!strcmp(shortname, toremove)) {
1167 RegDeleteValue( hkFreelance, szValueName );
1172 RegCloseKey(hkFreelance);
1175 cm_GetConfigDir(hfile, sizeof(hfile));
1176 strcat(hfile, AFS_FREELANCE_INI);
1177 strcpy(hfile2, hfile);
1178 strcat(hfile2, "2");
1179 fp1=fopen(hfile, "r+");
1181 return CM_ERROR_INVAL;
1182 fp2=fopen(hfile2, "w+");
1185 return CM_ERROR_INVAL;
1188 fgets(line, sizeof(line), fp1);
1190 fprintf(fp2, "%d\n", n-1);
1192 for (i=0; i<n; i++) {
1193 fgets(line, sizeof(line), fp1);
1194 cp=strchr(line, '#');
1196 cp=strchr(line, '%');
1197 memcpy(shortname, line, cp-line);
1198 shortname[cp-line]=0;
1200 if (strcmp(shortname, toremove)==0) {
1212 rename(hfile2, hfile);
1217 /* Do this while we are holding the lock */
1218 cm_noteLocalMountPointChange(TRUE);
1220 lock_ReleaseMutex(&cm_Freelance_Lock);
1221 return (found ? 0 : CM_ERROR_NOSUCHFILE);
1224 long cm_FreelanceAddSymlink(char *filename, char *destination, cm_fid_t *fidp)
1227 char fullname[CELL_MAXNAMELEN];
1229 HKEY hkFreelanceSymlinks = 0;
1230 DWORD dwType, dwSize;
1233 afs_uint32 code = 0;
1236 * before adding, verify the filename. If it is already in use, either as
1237 * as mount point or a cellname, do not permit the creation of the symlink.
1239 osi_Log2(afsd_logp,"Freelance Add Symlink request: filename=%s destination=%s",
1240 osi_LogSaveString(afsd_logp,filename),
1241 osi_LogSaveString(afsd_logp,destination));
1243 if ( filename[0] == '\0' || destination[0] == '\0' )
1244 return CM_ERROR_INVAL;
1247 if (filename[0] == '.') {
1248 cm_GetCell_Gen(&filename[1], fullname, CM_FLAG_CREATE);
1249 if (cm_stricmp_utf8(&filename[1],fullname) == 0) {
1250 code = CM_ERROR_EXISTS;
1254 cm_GetCell_Gen(filename, fullname, CM_FLAG_CREATE);
1255 if (cm_stricmp_utf8(filename,fullname) == 0) {
1256 code = CM_ERROR_EXISTS;
1261 if ( cm_FreelanceMountPointExists(filename, 0) ||
1262 cm_FreelanceSymlinkExists(filename, 0) ) {
1263 code = CM_ERROR_EXISTS;
1267 lock_ObtainMutex(&cm_Freelance_Lock);
1269 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1270 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
1273 REG_OPTION_NON_VOLATILE,
1274 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
1276 &hkFreelanceSymlinks,
1277 NULL) == ERROR_SUCCESS) {
1279 RegQueryInfoKey( hkFreelanceSymlinks,
1281 NULL, /* lpcClass */
1282 NULL, /* lpReserved */
1283 NULL, /* lpcSubKeys */
1284 NULL, /* lpcMaxSubKeyLen */
1285 NULL, /* lpcMaxClassLen */
1286 &dwSymlinks, /* lpcValues */
1287 NULL, /* lpcMaxValueNameLen */
1288 NULL, /* lpcMaxValueLen */
1289 NULL, /* lpcbSecurityDescriptor */
1290 NULL /* lpftLastWriteTime */
1293 sprintf(line, "%s:%s.", filename, destination);
1295 /* If we are adding a new value, there must be an unused name
1296 * within the range 0 to dwSymlinks
1298 for ( dwIndex = 0; dwIndex <= dwSymlinks; dwIndex++ ) {
1302 dwSize = sizeof(szLink);
1303 sprintf(szIndex, "%d", dwIndex);
1304 if (RegQueryValueEx( hkFreelanceSymlinks, szIndex, 0, &dwType, szLink, &dwSize) != ERROR_SUCCESS) {
1305 /* found an unused value */
1307 dwSize = (DWORD)strlen(line) + 1;
1308 RegSetValueEx( hkFreelanceSymlinks, szIndex, 0, dwType, line, dwSize);
1311 int len = (int)strlen(filename);
1312 if ( dwType == REG_SZ && !strncmp(filename, szLink, len) && szLink[len] == ':') {
1313 /* Replace the existing value */
1315 dwSize = (DWORD)strlen(line) + 1;
1316 RegSetValueEx( hkFreelanceSymlinks, szIndex, 0, dwType, line, dwSize);
1321 RegCloseKey(hkFreelanceSymlinks);
1324 /* Do this while we are holding the lock */
1325 cm_noteLocalMountPointChange(TRUE);
1326 lock_ReleaseMutex(&cm_Freelance_Lock);
1332 clientchar_t *cpath;
1336 cpath = cm_FsStringToClientStringAlloc(filename, -1, NULL);
1338 code = CM_ERROR_NOSUCHPATH;
1340 if (cm_getLocalMountPointChange()) { // check for changes
1341 cm_clearLocalMountPointChange(); // clear the changefile
1342 cm_reInitLocalMountPoints(); // start reinit
1345 code = cm_NameI(cm_data.rootSCachep, cpath,
1346 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1347 cm_rootUserp, NULL, &req, &scp);
1351 cm_ReleaseSCache(scp);
1359 long cm_FreelanceRemoveSymlink(char *toremove)
1363 char shortname[200];
1365 HKEY hkFreelanceSymlinks = 0;
1366 DWORD dwType, dwSize;
1370 lock_ObtainMutex(&cm_Freelance_Lock);
1372 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
1373 AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
1375 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
1376 &hkFreelanceSymlinks) == ERROR_SUCCESS) {
1378 RegQueryInfoKey( hkFreelanceSymlinks,
1380 NULL, /* lpcClass */
1381 NULL, /* lpReserved */
1382 NULL, /* lpcSubKeys */
1383 NULL, /* lpcMaxSubKeyLen */
1384 NULL, /* lpcMaxClassLen */
1385 &dwSymlinks, /* lpcValues */
1386 NULL, /* lpcMaxValueNameLen */
1387 NULL, /* lpcMaxValueLen */
1388 NULL, /* lpcbSecurityDescriptor */
1389 NULL /* lpftLastWriteTime */
1392 for ( dwIndex = 0; dwIndex < dwSymlinks; dwIndex++ ) {
1393 TCHAR szValueName[16];
1394 DWORD dwValueSize = 16;
1395 dwSize = sizeof(line);
1396 RegEnumValue( hkFreelanceSymlinks, dwIndex, szValueName, &dwValueSize, NULL,
1397 &dwType, line, &dwSize);
1399 cp=strchr(line, ':');
1400 memcpy(shortname, line, cp-line);
1401 shortname[cp-line]=0;
1403 if (!strcmp(shortname, toremove)) {
1404 RegDeleteValue( hkFreelanceSymlinks, szValueName );
1409 RegCloseKey(hkFreelanceSymlinks);
1413 /* Do this while we are holding the lock */
1414 cm_noteLocalMountPointChange(TRUE);
1416 lock_ReleaseMutex(&cm_Freelance_Lock);
1417 return (found ? 0 : CM_ERROR_NOSUCHFILE);
1421 cm_FreelanceFetchMountPointString(cm_scache_t *scp)
1423 lock_ObtainMutex(&cm_Freelance_Lock);
1424 if (!scp->mountPointStringp[0] &&
1425 scp->fid.cell == AFS_FAKE_ROOT_CELL_ID &&
1426 scp->fid.volume == AFS_FAKE_ROOT_VOL_ID &&
1427 scp->fid.unique <= cm_noLocalMountPoints) {
1428 strncpy(scp->mountPointStringp, cm_localMountPoints[scp->fid.unique-1].mountPointStringp, MOUNTPOINTLEN);
1429 scp->mountPointStringp[MOUNTPOINTLEN-1] = 0; /* null terminate */
1431 lock_ReleaseMutex(&cm_Freelance_Lock);
1437 cm_FreelanceFetchFileType(cm_scache_t *scp)
1439 lock_ObtainMutex(&cm_Freelance_Lock);
1440 if (scp->fid.cell == AFS_FAKE_ROOT_CELL_ID &&
1441 scp->fid.volume == AFS_FAKE_ROOT_VOL_ID &&
1442 scp->fid.unique <= cm_noLocalMountPoints)
1444 scp->fileType = cm_localMountPoints[scp->fid.unique-1].fileType;
1446 if ( scp->fileType == CM_SCACHETYPE_SYMLINK &&
1447 !strnicmp(cm_localMountPoints[scp->fid.unique-1].mountPointStringp, "msdfs:", strlen("msdfs:")) )
1449 scp->fileType = CM_SCACHETYPE_DFSLINK;
1452 scp->fileType = CM_SCACHETYPE_INVALID;
1454 lock_ReleaseMutex(&cm_Freelance_Lock);
1458 #endif /* AFS_FREELANCE_CLIENT */