Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / WINNT / client_exp / gui2fs.cpp
1 /*
2  * Copyright (C) 1997  Transarc Corporation.
3  * All rights reserved.
4  *
5  */
6
7 extern "C" {
8 #include <afs/param.h>
9 #include <afs/stds.h>
10 }
11
12 #include "stdafx.h"
13 #include <errno.h>
14 #include <time.h>
15
16 #include "gui2fs.h"
17 #include "msgs.h"
18 #include "results_dlg.h"
19 #include "volume_inf.h"
20 #include "mount_points_dlg.h"
21 #include "hourglass.h"
22 #include "down_servers_dlg.h"
23
24 extern "C" {
25 #include <afs/param.h>
26 #include <osi.h>
27 #include "fs.h"
28 #include "fs_utils.h"
29 #include <afsint.h>
30 #include <afs/auth.h>
31 }
32
33
34 #define PCCHAR(str)             ((char *)(const char *)(str))
35
36
37 #define MAXHOSTS 13
38 #define OMAXHOSTS 8
39 #define MAXNAME 100
40 #define MAXSIZE 2048
41 #define MAXINSIZE 1300    /* pioctl complains if data is larger than this */
42 #define VMSGSIZE 128      /* size of msg buf in volume hdr */
43
44 #define MAXCELLCHARS            64
45 #define MAXHOSTCHARS            64
46 #define MAXHOSTSPERCELL         8
47
48 struct afsconf_cell {
49         char name[MAXCELLCHARS];
50     short numServers;
51     short flags;
52     struct sockaddr_in hostAddr[MAXHOSTSPERCELL];
53     char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];
54     char *linkedCell;
55 };
56
57 static char space[MAXSIZE];
58 static char tspace[1024];
59
60 // #define      LOGGING_ON              // Enable this to log certain pioctl calls
61
62 #ifdef  LOGGING_ON
63 static char *szLogFileName = "afsguilog.txt";
64 #endif
65
66
67 FILE *OpenFile(char *file, char *rwp)
68 {
69         char wdir[256];
70         long code;
71         long tlen;
72         FILE *fp;
73
74         code = GetWindowsDirectory(wdir, sizeof(wdir));
75         if (code == 0 || code > sizeof(wdir)) 
76                 return FALSE;
77
78         /* add trailing backslash, if required */
79         tlen = strlen(wdir);
80         if (wdir[tlen - 1] != '\\')
81                 strcat(wdir, "\\");
82
83         strcat(wdir, file);
84
85         fp = fopen(wdir, rwp);
86
87         return fp;
88 }
89
90 CString StripPath(CString& strPath)
91 {
92         int nIndex = strPath.ReverseFind('\\');
93
94         CString strFile = strPath.Mid(nIndex + 1);
95         if (strFile.IsEmpty())
96                 return strPath;
97
98         return strFile;
99 }
100
101 CStringArray& StripPath(CStringArray& files)
102 {
103         for (int i = 0; i < files.GetSize(); i++)
104                 files[i] = StripPath(files[i]);
105
106         return files;
107 }
108
109 void Flush(const CStringArray& files)
110 {
111     register LONG code;
112     struct ViceIoctl blob;
113     int error = 0;
114
115         HOURGLASS hourglass;
116
117         for (int i = 0; i < files.GetSize(); i++) {
118                 blob.in_size = blob.out_size = 0;
119
120                 code = pioctl(PCCHAR(files[i]), VIOCFLUSH, &blob, 0);
121                 if (code) {
122                         error = 1;
123                         if (errno == EMFILE)
124                                 ShowMessageBox(IDS_FLUSH_FAILED, MB_ICONEXCLAMATION, IDS_FLUSH_FAILED, files[i]);
125                         else 
126                                 ShowMessageBox(IDS_FLUSH_ERROR, MB_ICONEXCLAMATION, IDS_FLUSH_ERROR, files[i], strerror(errno));
127                 }
128     }
129
130         if (!error)
131                 ShowMessageBox(IDS_FLUSH_OK, MB_ICONEXCLAMATION, IDS_FLUSH_OK);
132 }
133
134 void FlushVolume(const CStringArray& files)
135 {
136     register LONG code;
137     struct ViceIoctl blob;
138         int error = 0;
139
140         HOURGLASS hourglass;
141
142         for (int i = 0; i < files.GetSize(); i++) {
143                 blob.in_size = blob.out_size = 0;
144
145                 code = pioctl(PCCHAR(files[i]), VIOC_FLUSHVOLUME, &blob, 0);
146                 if (code) {
147                         error = 1;
148                         ShowMessageBox(IDS_FLUSH_VOLUME_ERROR, MB_ICONEXCLAMATION, IDS_FLUSH_VOLUME_ERROR, files[i], strerror(errno));
149                 }
150     }
151
152         if (!code)
153                 ShowMessageBox(IDS_FLUSH_VOLUME_OK, MB_ICONEXCLAMATION, IDS_FLUSH_VOLUME_OK);
154 }
155
156 void WhichCell(CStringArray& files)
157 {
158     register LONG code;
159     struct ViceIoctl blob;
160     int error;
161     CString str;
162     CString str2;
163
164         CStringArray results;
165
166     error = 0;
167
168         HOURGLASS hourglass;
169
170         for (int i = 0; i < files.GetSize(); i++) {
171                 blob.in_size = 0;
172                 blob.out_size = MAXSIZE;
173                 blob.out = space;
174
175                 code = pioctl(PCCHAR(files[i]), VIOC_FILE_CELL_NAME, &blob, 1);
176                 if (code) {
177                         if (code == ENOENT) {
178                                 LoadString (str, IDS_CANT_GET_CELL);
179                                 results.Add(str);
180                         } else
181                                 results.Add(GetAfsError(errno));
182                 } else
183                         results.Add(space);
184         }
185
186         LoadString (str, IDS_SHOW_CELL);
187         LoadString (str2, IDS_SHOW_CELL_COLUMN);
188         CResultsDlg dlg(SHOW_CELL_HELP_ID);
189         dlg.SetContents(str, str2, StripPath(files), results);
190         dlg.DoModal();
191 }
192
193 void WSCellCmd()
194 {
195     register LONG code;
196     struct ViceIoctl blob;
197     
198         HOURGLASS hourglass;
199
200     blob.in_size = 0;
201     blob.in = (char *) 0;
202     blob.out_size = MAXSIZE;
203     blob.out = space;
204
205     code = pioctl((char *) 0, VIOC_GET_WS_CELL, &blob, 1);
206
207     if (code) {
208                 //Die(errno, (char *) 0);
209     }
210     //else
211                 //printf("This workstation belongs to cell '%s'\n", space);
212 }
213
214 BOOL CheckVolumes()
215 {
216     register LONG code;
217     struct ViceIoctl blob;
218     
219     blob.in_size = 0;
220     blob.out_size = 0;
221     code = pioctl(0, VIOCCKBACK, &blob, 1);
222     if (code) {
223                 ShowMessageBox(IDS_CHECK_VOLUMES_ERROR, MB_ICONEXCLAMATION, IDS_CHECK_VOLUMES_ERROR, GetAfsError(errno, CString()));
224                 return FALSE;
225     }
226
227     ShowMessageBox(IDS_CHECK_VOLUMES_OK, MB_OK, IDS_CHECK_VOLUMES_OK);
228
229         return TRUE;
230 }
231
232 void SetCacheSizeCmd(LONG nNewCacheSize)
233 {
234     register LONG code;
235     struct ViceIoctl blob;
236     
237         HOURGLASS hourglass;
238
239         blob.in = (char *) &nNewCacheSize;
240     blob.in_size = sizeof(LONG);
241     blob.out_size = 0;
242
243     code = pioctl(0, VIOCSETCACHESIZE, &blob, 1);
244     //if (code)
245         //      Die(errno, (char *) 0);
246     //else
247         //      printf("New cache size set.\n");
248 }
249
250 void WhereIs(CStringArray& files)
251 {
252     register LONG code;
253     struct ViceIoctl blob;
254         CStringArray servers;
255         CStringArray resultFiles;
256         CString str;
257         CString str2;
258
259         HOURGLASS hourglass;
260
261         for (int i = 0; i < files.GetSize(); i++) {
262                 blob.out_size = MAXSIZE;
263                 blob.in_size = 0;
264                 blob.out = space;
265                 memset(space, 0, sizeof(space));
266
267                 code = pioctl(PCCHAR(files[i]), VIOCWHEREIS, &blob, 1);
268                 if (code) {
269                         resultFiles.Add(StripPath(files[i]));
270                         servers.Add(GetAfsError(errno));
271                         continue;
272                 }
273                 
274                 LONG *hosts = (LONG *)space;
275                 BOOL bFirst = TRUE;
276                 str = "";
277
278                 for (int j = 0; j < MAXHOSTS; j++) {
279                         if (hosts[j] == 0)
280                                 break;
281                         char *hostName = hostutil_GetNameByINet(hosts[j]);
282                         if (bFirst) {
283                                 resultFiles.Add(StripPath(files[i]));
284                                 bFirst = FALSE;
285                         } else
286                                 resultFiles.Add(" ");
287                         servers.Add(hostName);
288                 }
289         }
290
291         LoadString (str, IDS_SHOW_FS);
292         LoadString (str2, IDS_SHOW_FS_COLUMN);
293         CResultsDlg dlg(SHOW_FILE_SERVERS_HELP_ID);
294         dlg.SetContents(str, str2, resultFiles, servers);
295         dlg.DoModal();
296 }
297
298 CString GetAfsError(int code, const char *filename)
299 {
300     CString strMsg;
301
302         if (code == EINVAL) {
303                 if (filename)
304                     strMsg.Format("Invalid argument; it is possible that the file is not in AFS");
305                 else 
306                         strMsg.Format("Invalid argument");
307     } else if (code == ENOENT) {
308                 if (filename) 
309                         strMsg.Format("The file does not exist");
310                 else 
311                         strMsg.Format("No such file returned");
312     } else if (code == EROFS)  {
313                 strMsg.Format("You can not change a backup or readonly volume");
314     } else if (code == EACCES || code == EPERM) {
315                 strMsg.Format("You do not have the required rights to do this operation");
316     } else if (code == ENODEV) {
317                 strMsg.Format("AFS service may not have started");
318     } else if (code == ESRCH) {
319                 strMsg.Format("Cell name not recognized");
320     } else if (code == ETIMEDOUT) {
321                 strMsg.Format("Connection timed out");
322     } else if (code == EPIPE) {
323                 strMsg.Format("Volume name or ID not recognized");
324     } else {
325                 strMsg.Format("Error 0x%x occurred", code);
326     }
327
328         return strMsg;
329 }
330
331
332 /************************************************************************
333 ************************** ACL Code *************************************
334 ************************************************************************/
335
336 typedef char sec_rgy_name_t[1025];      /* A DCE definition */
337
338 struct AclEntry {
339     struct AclEntry *next;
340     char name[MAXNAME];
341     LONG rights;
342 };
343
344 struct Acl {
345     int dfs;                            //      Originally true if a dfs acl; now also the type
346                                                         //      of the acl (1, 2, or 3, corresponding to object,
347                                                         //      initial dir, or initial object).
348     sec_rgy_name_t cell;        //      DFS cell name
349     int nplus;
350     int nminus;
351     struct AclEntry *pluslist;
352     struct AclEntry *minuslist;
353 };
354
355 int foldcmp (register char *a, register char *b)
356 {
357     register char t, u;
358     while (1) {
359         t = *a++;
360         u = *b++;
361         if (t >= 'A' && t <= 'Z') t += 0x20;
362         if (u >= 'A' && u <= 'Z') u += 0x20;
363         if (t != u) return 1;
364         if (t == 0) return 0;
365     }
366 }
367
368 void ZapList(struct AclEntry *alist)
369 {
370     register struct AclEntry *tp, *np;
371
372     for (tp = alist; tp; tp = np) {
373         np = tp->next;
374         free(tp);
375     }
376 }
377
378 void ZapAcl (struct Acl *acl)
379 {
380     ZapList(acl->pluslist);
381     ZapList(acl->minuslist);
382     free(acl);
383 }
384
385 int PruneList (struct AclEntry **ae, int dfs)
386 {
387     struct AclEntry **lp = ae;
388     struct AclEntry *te, *ne;
389     LONG ctr = 0;
390     
391         for (te = *ae; te; te = ne) {
392         if ((!dfs && te->rights == 0) || te->rights == -1) {
393             *lp = te->next;
394             ne = te->next;
395             free(te);
396             ctr++;
397                 }
398         else {
399             ne = te->next;
400             lp = &te->next;
401                 }
402     }
403     
404         return ctr;
405 }
406
407 char *SkipLine (register char *astr)
408 {
409     while (*astr != '\n') 
410                 astr++;
411     
412         astr++;
413     
414         return astr;
415 }
416
417 /* tell if a name is 23 or -45 (digits or minus digits), which are bad names we must prune */
418 static BadName(register char *aname)
419 {
420     register int tc;
421
422         /* all must be '-' or digit to be bad */
423     while (tc = *aname++) {
424                 if ((tc != '-') && (tc < '0' || tc > '9')) 
425                         return 0;
426     }
427
428     return 1;
429 }
430
431 CString GetRightsString(register LONG arights, int dfs)
432 {
433         CString str;
434
435     if (!dfs) {
436                 if (arights & PRSFS_READ) str += "r";
437                 if (arights & PRSFS_LOOKUP) str += "l";
438                 if (arights & PRSFS_INSERT) str += "i";
439                 if (arights & PRSFS_DELETE) str += "d";
440                 if (arights & PRSFS_WRITE) str += "w";
441                 if (arights & PRSFS_LOCK) str += "k";
442                 if (arights & PRSFS_ADMINISTER) str += "a";
443     } else {
444                 ASSERT(FALSE);
445 /*
446                 if (arights & DFS_READ) str += "r"; else str += "-";
447                 if (arights & DFS_WRITE) str += "w"; else printf("-");
448                 if (arights & DFS_EXECUTE) str += "x"; else printf("-");
449                 if (arights & DFS_CONTROL) str += "c"; else printf("-");
450                 if (arights & DFS_INSERT) str += "i"; else printf("-");
451                 if (arights & DFS_DELETE) str += "d"; else printf("-");
452                 if (arights & (DFS_USRALL)) str += "+";
453 */
454         }       
455
456         return str;
457 }
458
459 char *AclToString(struct Acl *acl)
460 {
461     static char mydata[MAXSIZE];
462     char tstring[MAXSIZE];
463     char dfsstring[30];
464     struct AclEntry *tp;
465     
466     if (acl->dfs)
467                 sprintf(dfsstring, " dfs:%d %s", acl->dfs, acl->cell);
468     else
469                 dfsstring[0] = '\0';
470     sprintf(mydata, "%d%s\n%d\n", acl->nplus, dfsstring, acl->nminus);
471     
472         for(tp = acl->pluslist; tp; tp = tp->next) {
473         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
474         strcat(mydata, tstring);
475     }
476     
477         for(tp = acl->minuslist; tp; tp = tp->next) {
478         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
479         strcat(mydata, tstring);
480     }
481     
482         return mydata;
483 }
484
485 struct Acl *EmptyAcl(const CString& strCellName)
486 {
487     register struct Acl *tp;
488     
489     tp = (struct Acl *)malloc(sizeof (struct Acl));
490     tp->nplus = tp->nminus = 0;
491     tp->pluslist = tp->minuslist = 0;
492     tp->dfs = 0;
493     strcpy(tp->cell, strCellName);
494
495     return tp;
496 }
497
498 struct Acl *ParseAcl(char *astr)
499 {
500     int nplus, nminus, i, trights;
501     char tname[MAXNAME];
502     struct AclEntry *first, *last, *tl;
503     struct Acl *ta;
504
505     ta = (struct Acl *) malloc (sizeof (struct Acl));
506     ta->dfs = 0;
507     sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
508     astr = SkipLine(astr);
509     sscanf(astr, "%d", &ta->nminus);
510     astr = SkipLine(astr);
511
512     nplus = ta->nplus;
513     nminus = ta->nminus;
514
515     last = 0;
516     first = 0;
517     for(i = 0; i < nplus; i++) {
518         sscanf(astr, "%100s %d", tname, &trights);
519         astr = SkipLine(astr);
520         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
521         if (!first)
522                         first = tl;
523         strcpy(tl->name, tname);
524         tl->rights = trights;
525         tl->next = 0;
526         if (last)
527                         last->next = tl;
528         last = tl;
529     }
530     ta->pluslist = first;
531
532     last = 0;
533     first = 0;
534     for(i=0; i < nminus; i++) {
535         sscanf(astr, "%100s %d", tname, &trights);
536         astr = SkipLine(astr);
537         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
538         if (!first) 
539                         first = tl;
540         strcpy(tl->name, tname);
541         tl->rights = trights;
542         tl->next = 0;
543         if (last) 
544                         last->next = tl;
545         last = tl;
546     }
547     ta->minuslist = first;
548
549     return ta;
550 }
551
552 /* clean up an access control list of its bad entries; return 1 if we made
553    any changes to the list, and 0 otherwise */
554 int CleanAcl(struct Acl *aa)
555 {
556     register struct AclEntry *te, **le, *ne;
557     int changes;
558
559         HOURGLASS hourglass;
560
561     /* Don't correct DFS ACL's for now */
562     if (aa->dfs)
563                 return 0;
564
565     /* prune out bad entries */
566     changes = 0;            /* count deleted entries */
567     le = &aa->pluslist;
568     for(te = aa->pluslist; te; te = ne) {
569                 ne = te->next;
570                 if (BadName(te->name)) {
571                         /* zap this dude */
572                         *le = te->next;
573                         aa->nplus--;
574                         free(te);
575                         changes++;
576                 }
577                 else
578                         le = &te->next;
579     }
580
581     le = &aa->minuslist;
582     
583         for(te = aa->minuslist; te; te = ne) {
584                 ne = te->next;
585                 if (BadName(te->name)) {
586                         /* zap this dude */
587                         *le = te->next;
588                         aa->nminus--;
589                         free(te);
590                         changes++;
591                 }
592                 else
593                         le = &te->next;
594     }
595
596     return changes;
597 }
598
599 void CleanACL(CStringArray& names)
600 {
601     register LONG code;
602     register struct Acl *ta;
603     struct ViceIoctl blob;
604     int changes;
605
606         ShowMessageBox(IDS_CLEANACL_MSG, MB_OK, IDS_CLEANACL_MSG);
607
608         HOURGLASS hourglass;
609
610         for (int i = 0; i < names.GetSize(); i++) {
611                 blob.out_size = MAXSIZE;
612                 blob.in_size = 0;
613                 blob.out = space;
614
615                 code = pioctl(PCCHAR(names[i]), VIOCGETAL, &blob, 1);
616                 if (code) {
617                         ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONEXCLAMATION, 0, names[i], GetAfsError(errno));
618                         continue;
619                 }
620                 
621                 ta = ParseAcl(space);
622                 if (ta->dfs) {
623                         ShowMessageBox(IDS_CLEANACL_NOT_SUPPORTED, MB_ICONEXCLAMATION, IDS_CLEANACL_NOT_SUPPORTED, names[i]);
624                         continue;
625                 }
626
627                 changes = CleanAcl(ta);
628                 if (!changes)
629                         continue;
630
631                 /* now set the acl */
632                 blob.in = AclToString(ta);
633                 blob.in_size = strlen((char *)blob.in) + 1;
634                 blob.out_size = 0;
635                 
636                 code = pioctl(PCCHAR(names[i]), VIOCSETAL, &blob, 1);
637                 if (code) {
638                         if (errno == EINVAL) {
639                                 ShowMessageBox(IDS_CLEANACL_INVALID_ARG, MB_ICONEXCLAMATION, IDS_CLEANACL_INVALID_ARG, names[i]);
640                                 continue;
641                         }
642                         else {
643                                 ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONEXCLAMATION, 0, names[i], GetAfsError(errno));
644                                 continue;
645                         }
646                 }
647         }
648 }
649
650 // Derived from fs.c's ListAclCmd
651 BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& strNegative)
652 {
653     register LONG code;
654     register struct Acl *ta;
655     struct ViceIoctl blob;
656     struct AclEntry *te;
657     int idf = 0; //getidf(as, parm_listacl_id);
658
659         HOURGLASS hourglass;
660
661         blob.out_size = MAXSIZE;
662         blob.in_size = idf;
663         blob.in = blob.out = space;
664         
665         code = pioctl(PCCHAR(strDir), VIOCGETAL, &blob, 1);
666         if (code) {
667                 ShowMessageBox(IDS_GETRIGHTS_ERROR, MB_ICONEXCLAMATION, IDS_GETRIGHTS_ERROR, strDir, GetAfsError(errno));
668                 return FALSE;
669         }
670
671         ta = ParseAcl(space);
672         if (ta->dfs) {
673                 ShowMessageBox(IDS_DFSACL_ERROR, MB_ICONEXCLAMATION, IDS_DFSACL_ERROR);
674                 return FALSE;
675         }
676
677 //      if (ta->dfs)
678 //              printf("  Default cell = %s\n", ta->cell);
679
680         CString strRight;
681
682         if (ta->nplus > 0) {
683                 for (te = ta->pluslist; te; te = te->next) {
684                         strNormal.Add(te->name);
685                         strNormal.Add(GetRightsString(te->rights, ta->dfs));
686                 }
687         }
688
689         if (ta->nminus > 0) {
690                 for (te = ta->minuslist; te; te = te->next) {
691                         strNegative.Add(te->name);
692                         strNegative.Add(GetRightsString(te->rights, ta->dfs));
693                 }
694         }
695
696         return TRUE;
697 }
698
699 struct AclEntry *FindList(register struct AclEntry *pCurEntry, const char *entryName)
700 {
701     while (pCurEntry) {
702         if (!foldcmp(pCurEntry->name, PCCHAR(entryName)))
703                         return pCurEntry;
704                 pCurEntry = pCurEntry->next;
705     }
706     
707         return 0;
708 }
709
710 void ChangeList (struct Acl *pAcl, BYTE bNormalRights, const char *entryName, LONG nEntryRights)
711 {
712         ASSERT(pAcl);
713         ASSERT(entryName);
714     
715         struct AclEntry *pEntry;
716
717         HOURGLASS hourglass;
718
719     pEntry = (bNormalRights ? pAcl->pluslist : pAcl->minuslist);
720     pEntry = FindList(pEntry, entryName);
721
722         /* Found the item already in the list. */
723     if (pEntry) {
724         pEntry->rights = nEntryRights;
725         if (bNormalRights)
726             pAcl->nplus -= PruneList(&pAcl->pluslist, pAcl->dfs);
727         else
728             pAcl->nminus -= PruneList(&pAcl->minuslist, pAcl->dfs);
729         return;
730     }
731
732     /* Otherwise we make a new item and plug in the new data. */
733     pEntry = (struct AclEntry *) malloc(sizeof (struct AclEntry));
734     ASSERT(pEntry);
735         
736         strcpy(pEntry->name, entryName);
737     pEntry->rights = nEntryRights;
738     
739         if (bNormalRights) {
740         pEntry->next = pAcl->pluslist;
741         pAcl->pluslist = pEntry;
742         pAcl->nplus++;
743         if (nEntryRights == 0 || nEntryRights == -1)
744                         pAcl->nplus -= PruneList(&pAcl->pluslist, pAcl->dfs);
745     }
746     else {
747         pEntry->next = pAcl->minuslist;
748         pAcl->minuslist = pEntry;
749         pAcl->nminus++;
750         if (nEntryRights == 0)
751                         pAcl->nminus -= PruneList(&pAcl->minuslist, pAcl->dfs);
752     }
753 }
754
755 enum rtype {add, destroy, deny};
756
757 LONG Convert(const register char *arights, int dfs, enum rtype *rtypep)
758 {
759     register int i, len;
760     LONG mode;
761     register char tc;
762
763     *rtypep = add;      /* add rights, by default */
764
765         if (!strcmp(arights,"read")) 
766                 return PRSFS_READ | PRSFS_LOOKUP;
767         if (!strcmp(arights, "write")) 
768                 return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK;
769         if (!strcmp(arights, "mail")) 
770                 return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
771         if (!strcmp(arights, "all")) 
772                 return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
773     
774         if (!strcmp(arights, "none")) {
775                 *rtypep = destroy; /* Remove entire entry */
776                 return 0;
777     }
778
779     len = strlen(arights);
780     mode = 0;
781
782     for (i = 0; i < len; i++) {
783         tc = *arights++;
784                 if (tc == 'r') mode |= PRSFS_READ;
785                 else if (tc == 'l') mode |= PRSFS_LOOKUP;
786                 else if (tc == 'i') mode |= PRSFS_INSERT;
787                 else if (tc == 'd') mode |= PRSFS_DELETE;
788                 else if (tc == 'w') mode |= PRSFS_WRITE;
789                 else if (tc == 'k') mode |= PRSFS_LOCK;
790                 else if (tc == 'a') mode |= PRSFS_ADMINISTER;
791                 else {
792                         fprintf(stderr, "illegal rights character '%c'.\n", tc);
793                         exit(1);
794                 }
795     }
796     return mode;
797 }
798
799 BOOL SaveACL(const CString& strCellName, const CString& strDir, const CStringArray& normal, const CStringArray& negative)
800 {
801     register LONG code;
802     struct ViceIoctl blob;
803     struct Acl *pAcl;
804     LONG rights;
805         enum rtype rtype;
806
807         HOURGLASS hourglass;
808
809         // Create a new ACL
810         pAcl = EmptyAcl(strCellName);
811
812         // Set its normal rights
813         for (int i = 0; i < normal.GetSize(); i += 2) {
814                 rights = Convert(normal[i + 1], 0, &rtype);
815                 ChangeList(pAcl, TRUE, normal[i], rights);
816         }
817
818         // Set its negative rights
819         for (i = 0; i < negative.GetSize(); i += 2) {
820                 rights = Convert(negative[i + 1], 0, &rtype);
821                 ChangeList(pAcl, FALSE, negative[i], rights);
822         }
823
824         // Write the ACL
825         blob.in = AclToString(pAcl);
826         blob.out_size = 0;
827         blob.in_size = 1 + strlen((const char *)blob.in);
828         
829         code = pioctl(PCCHAR(strDir), VIOCSETAL, &blob, 1);
830         if (code) {
831                 if (errno == EINVAL)
832                         ShowMessageBox(IDS_SAVE_ACL_EINVAL_ERROR, MB_ICONEXCLAMATION, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
833                 else
834                         ShowMessageBox(IDS_SAVE_ACL_ERROR, MB_ICONEXCLAMATION, IDS_SAVE_ACL_ERROR, strDir, GetAfsError(errno, strDir));
835         }
836
837         ZapAcl(pAcl);
838
839     return (code == 0);
840 }
841
842 BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringArray& negative, BOOL bClear)
843 {
844     register LONG code;
845     struct ViceIoctl blob;
846     struct Acl *pToAcl;
847     int idf = 0; // getidf(as, parm_copyacl_id);
848
849         HOURGLASS hourglass;
850
851         // Get ACL to copy to
852         blob.out_size = MAXSIZE;
853         blob.in_size = idf;
854         blob.in = blob.out = space;
855         
856         code = pioctl(PCCHAR(strToDir), VIOCGETAL, &blob, 1);
857         if (code) {
858                 ShowMessageBox(IDS_ACL_READ_ERROR, MB_ICONEXCLAMATION, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
859                 return FALSE;
860         }
861         
862         if (bClear) 
863                 pToAcl = EmptyAcl(space);
864         else 
865                 pToAcl = ParseAcl(space);
866         
867         CleanAcl(pToAcl);
868         
869         if (pToAcl->dfs) {
870                 ShowMessageBox(IDS_NO_DFS_COPY_ACL, MB_ICONEXCLAMATION, IDS_NO_DFS_COPY_ACL, strToDir);
871                 ZapAcl(pToAcl);
872                 return FALSE;
873         }
874
875         enum rtype rtype;
876
877         // Set normal rights
878         for (int i = 0; i < normal.GetSize(); i += 2) {
879                 LONG rights = Convert(normal[i + 1], 0, &rtype);
880                 ChangeList(pToAcl, TRUE, normal[i], rights);
881         }
882
883         // Set negative rights
884         for (i = 0; i < negative.GetSize(); i += 2) {
885                 LONG rights = Convert(negative[i + 1], 0, &rtype);
886                 ChangeList(pToAcl, FALSE, normal[i], rights);
887         }
888
889         // Save modified ACL
890         blob.in = AclToString(pToAcl);
891         blob.out_size = 0;
892         blob.in_size = 1 + strlen((char *)blob.in);
893         
894         code = pioctl(PCCHAR(strToDir), VIOCSETAL, &blob, 1);
895         if (code) {
896                 ZapAcl(pToAcl);
897                 if (errno == EINVAL)
898                         ShowMessageBox(IDS_COPY_ACL_EINVAL_ERROR, MB_ICONEXCLAMATION, IDS_COPY_ACL_EINVAL_ERROR, strToDir);
899                 else 
900                         ShowMessageBox(IDS_COPY_ACL_ERROR, MB_ICONEXCLAMATION, IDS_COPY_ACL_ERROR, strToDir, GetAfsError(errno, strToDir));
901                 return FALSE;
902         }
903
904         ZapAcl(pToAcl);
905
906         ShowMessageBox(IDS_COPY_ACL_OK, MB_OK, IDS_COPY_ACL_OK);
907
908     return TRUE;
909 }
910
911 CString ParseMountPoint(const CString strFile, CString strMountPoint)
912 {
913         CString strType;
914         CString strVolume;
915         CString strCell;
916         CString strMountPointInfo;
917
918         if (strMountPoint[0] == '#')
919                 strType = "Regular";
920         else if (strMountPoint[0] == '%')
921                 strType = "Read/Write";
922
923         int nColon = strMountPoint.Find(':');
924         if (nColon >= 0) {
925                 strCell = strMountPoint.Mid(1, nColon - 1);
926                 strVolume = strMountPoint.Mid(nColon + 1);
927         } else
928                 strVolume = strMountPoint.Mid(1);
929
930         strMountPointInfo = strFile + "\t" + strVolume + "\t" + strCell + "\t" + strType;
931
932         return strMountPointInfo;
933 }
934
935 BOOL ListMount(CStringArray& files)
936 {
937     register LONG code;
938     struct ViceIoctl blob;
939     int error;
940     char orig_name[1024];                       /* Original name, may be modified */
941     char true_name[1024];                       /* ``True'' dirname (e.g., symlink target) */
942     char parent_dir[1024];                      /* Parent directory of true name */
943     register char *last_component;      /* Last component of true name */
944         CStringArray mountPoints;
945     
946         HOURGLASS hourglass;
947
948     error = 0;
949
950     for (int i = 0; i < files.GetSize(); i++) {
951                 strcpy(orig_name, files[i]);
952                 strcpy(true_name, orig_name);
953
954                 /*
955                  * Find rightmost slash, if any.
956                  */
957                 last_component = (char *)strrchr(true_name, '\\');
958                 if (last_component) {
959                         /*
960                          * Found it.  Designate everything before it as the parent directory,
961                          * everything after it as the final component.
962                          */
963                         strncpy(parent_dir, true_name, last_component - true_name + 1);
964                         parent_dir[last_component - true_name + 1] = 0;
965                         last_component++;   /* Skip the slash */
966                 }
967                 else {
968                         /*
969                          * No slash appears in the given file name.  Set parent_dir to the current
970                          * directory, and the last component as the given name.
971                          */
972                         fs_ExtractDriveLetter(true_name, parent_dir);
973                         strcat(parent_dir, ".");
974                         last_component = true_name;
975                         fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
976                 }
977
978                 blob.in = last_component;
979                 blob.in_size = strlen(last_component) + 1;
980                 blob.out_size = MAXSIZE;
981                 blob.out = space;
982                 memset(space, 0, MAXSIZE);
983
984                 code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
985                 if (code == 0) {
986                         int nPos = strlen(space) - 1;
987                         if (space[nPos] == '.')
988                                 space[nPos] = 0;
989                         mountPoints.Add(ParseMountPoint(StripPath(files[i]), space));
990                 } else {
991                         error = 1;
992                         if (errno == EINVAL)
993                                 mountPoints.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
994                         else
995                                 mountPoints.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
996                 }
997         }
998
999         CMountPointsDlg dlg;
1000         dlg.SetMountPoints(mountPoints);
1001         dlg.DoModal();
1002
1003         return !error;
1004 }
1005
1006 static BOOL InAFS(register char *apath)
1007 {
1008     struct ViceIoctl blob;
1009     register LONG code;
1010
1011         HOURGLASS hourglass;
1012
1013     blob.in_size = 0;
1014     blob.out_size = MAXSIZE;
1015     blob.out = space;
1016
1017     code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
1018     if (code) {
1019                 if ((errno == EINVAL) || (errno == ENOENT))
1020                         return FALSE;
1021     }
1022     
1023         return TRUE;
1024 }
1025
1026 /* return a static pointer to a buffer */
1027 static char *Parent(char *apath)
1028 {
1029     register char *tp;
1030
1031     strcpy(tspace, apath);
1032     tp = strrchr(tspace, '\\');
1033     if (tp) {
1034                 *(tp+1) = 0;    /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
1035     }
1036     else {
1037                 fs_ExtractDriveLetter(apath, tspace);
1038         strcat(tspace, ".");
1039     }
1040     
1041         return tspace;
1042 }
1043
1044 BOOL MakeMount(const CString& strDir, const CString& strVolName, const CString& strCellName, BOOL bRW)
1045 {
1046     register LONG code;
1047     register char *cellName;
1048     char localCellName[1000];
1049     struct ViceIoctl blob;
1050
1051         HOURGLASS hourglass;
1052
1053         ASSERT(strVolName.GetLength() < 64);
1054
1055 /*
1056
1057 defect #3069
1058
1059     if (as->parms[5].items && !as->parms[2].items) {
1060         fprintf(stderr,"fs: must provide cell when creating cellular mount point.\n");
1061         return FALSE;
1062     }
1063 */
1064
1065     if (strCellName.GetLength() > 0)    /* cell name specified */
1066                 cellName = PCCHAR(strCellName);
1067     else
1068                 cellName = (char *) 0;
1069
1070     if (!InAFS(Parent(PCCHAR(strDir)))) {
1071                 ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_MP_NOT_AFS_ERROR);
1072                 return FALSE;
1073     }
1074
1075     if (cellName) {
1076                 blob.in_size = 0;
1077                 blob.out_size = MAXSIZE;
1078                 blob.out = space;
1079                 code = pioctl(Parent(PCCHAR(strDir)), VIOC_FILE_CELL_NAME, &blob, 1);
1080     }
1081
1082     strcpy(localCellName, (cellName? cellName : space));
1083
1084     if (bRW)    /* if -rw specified */
1085                 strcpy(space, "%");
1086     else
1087                 strcpy(space, "#");
1088
1089     /* If cellular mount point, prepend cell prefix */
1090         if (cellName) {
1091                 strcat(space, localCellName);
1092                 strcat(space, ":");
1093     }
1094
1095     strcat(space, strVolName);  /* append volume name */
1096     strcat(space, ".");         /* stupid convention; these end with a period */
1097
1098     /* create symlink with a special pioctl for Windows NT, since it doesn't
1099      * have a symlink system call.
1100      */
1101     blob.out_size = 0;
1102     blob.in_size = 1 + strlen(space);
1103     blob.in = space;
1104     blob.out = NULL;
1105     code = pioctl(PCCHAR(strDir), VIOC_AFS_CREATE_MT_PT, &blob, 0);
1106
1107     if (code) {
1108                 ShowMessageBox(IDS_MOUNT_POINT_ERROR, MB_ICONEXCLAMATION, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
1109                 return FALSE;
1110     }
1111     
1112         return TRUE;
1113 }
1114
1115 /*
1116  * Delete AFS mount points.  Variables are used as follows:
1117  *       tbuffer: Set to point to the null-terminated directory name of the mount point
1118  *          (or ``.'' if none is provided)
1119  *      tp: Set to point to the actual name of the mount point to nuke.
1120  */
1121 BOOL RemoveMount(CStringArray& files)
1122 {
1123     register LONG code = 0;
1124     struct ViceIoctl blob;
1125     char tbuffer[1024];
1126     char lsbuffer[1024];
1127     register char *tp;
1128         BOOL error = FALSE;
1129         CStringArray results;
1130         CString str;
1131         CString str2;
1132
1133         HOURGLASS hourglass;
1134
1135     for (int i = 0; i < files.GetSize(); i++) {
1136                 char szCurItem[1024];
1137                 strcpy(szCurItem, files[i]);
1138         
1139                 tp = (char *)strrchr(szCurItem, '\\');
1140                 if (tp) {
1141                         strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
1142                         tbuffer[code] = 0;
1143                         tp++;   /* skip the slash */
1144                 } else {
1145                         fs_ExtractDriveLetter(szCurItem, tbuffer);
1146                         strcat(tbuffer, ".");
1147                         tp = szCurItem;
1148                         fs_StripDriveLetter(tp, tp, 0);
1149                 }
1150
1151                 blob.in = tp;
1152                 blob.in_size = strlen(tp)+1;
1153                 blob.out = lsbuffer;
1154                 blob.out_size = sizeof(lsbuffer);
1155
1156                 code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
1157                 if (code) {
1158                         error = TRUE;
1159                         if (errno == EINVAL)
1160                                 results.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
1161                         else
1162                                 results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
1163                         continue;       // don't bother trying
1164                 }
1165                 
1166                 blob.out_size = 0;
1167                 blob.in = tp;
1168                 blob.in_size = strlen(tp)+1;
1169                 
1170                 code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
1171                 if (code) {
1172                         error = TRUE;
1173                         results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
1174                 } else
1175                         results.Add(GetMessageString(IDS_DELETED));
1176     }
1177
1178         LoadString (str, IDS_REMOVE_MP);
1179         LoadString (str2, IDS_REMOVE_MP_COLUMN);
1180         CResultsDlg dlg(REMOVE_MOUNT_POINTS_HELP_ID);
1181         dlg.SetContents(str, str2, StripPath(files), results);
1182         dlg.DoModal();
1183
1184     return !error;
1185 }
1186
1187 BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
1188 {
1189     register LONG code;
1190     struct ViceIoctl blob;
1191     struct VolumeStatus *status;
1192     char *name;
1193
1194         HOURGLASS hourglass;
1195
1196         volInfo.m_strFilePath = strFile;
1197     volInfo.m_strFileName = StripPath(strFile);
1198
1199 /*
1200         volInfo.m_strName = "VolumeName";
1201         volInfo.m_nID = 10;
1202         volInfo.m_nQuota = 20 * 1024 * 1024;
1203         volInfo.m_nNewQuota = volInfo.m_nQuota;
1204         volInfo.m_nUsed = volInfo.m_nQuota / 2;
1205         volInfo.m_nPartSize = 50 * 1024 * 1024;
1206         volInfo.m_nPartFree = 30 * 1024 * 1024;
1207         volInfo.m_nDup = -1;
1208         return TRUE;
1209 */
1210
1211         blob.out_size = MAXSIZE;
1212         blob.in_size = 0;
1213         blob.out = space;
1214
1215         code = pioctl(PCCHAR(strFile), VIOCGETVOLSTAT, &blob, 1);
1216         if (code) {
1217                 volInfo.m_strErrorMsg = GetAfsError(errno, strFile);
1218                 return FALSE;
1219         }
1220
1221         status = (VolumeStatus *)space;
1222         name = (char *)status + sizeof(*status);
1223
1224         volInfo.m_strName = name;
1225         volInfo.m_nID = status->Vid;
1226         volInfo.m_nQuota = status->MaxQuota;
1227         volInfo.m_nNewQuota = status->MaxQuota;
1228         volInfo.m_nUsed = status->BlocksInUse;
1229         volInfo.m_nPartSize = status->PartMaxBlocks;
1230         volInfo.m_nPartFree = status->PartBlocksAvail;
1231         volInfo.m_nDup = -1;
1232
1233     return TRUE;
1234 }
1235         
1236 BOOL SetVolInfo(CVolInfo& volInfo)
1237 {
1238     register LONG code;
1239     struct ViceIoctl blob;
1240     struct VolumeStatus *status;
1241     char *input;
1242
1243         HOURGLASS hourglass;
1244
1245         blob.out_size = MAXSIZE;
1246         blob.in_size = sizeof(*status) + 3;     /* for the three terminating nulls */
1247         blob.out = space;
1248         blob.in = space;
1249         
1250         status = (VolumeStatus *)space;
1251         status->MinQuota = -1;
1252         status->MaxQuota = volInfo.m_nNewQuota;
1253         
1254         input = (char *)status + sizeof(*status);
1255         *(input++) = '\0';      /* never set name: this call doesn't change vldb */
1256         *(input++) = '\0';      // No offmsg
1257         *(input++) = '\0';      // No motd
1258
1259 #ifdef LOGGING_ON
1260         FILE *fp = OpenFile(szLogFileName, "a");
1261         if (fp) {
1262                 fprintf(fp, "\nSetVolInfo() pioctl parms:\n");
1263                 fprintf(fp, "\tpathp = %s\n\topcode = VIOCSETVOLSTAT (%d)\n\tblobp = %ld\n", PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob);
1264                 fprintf(fp, "\t\tblobp.in = %ld (VolumeStatus *status)\n\t\tblobp.in_size = %ld\n\t\tblobp.out = %ld ((VolumeStatus *status))\n\t\tblobp.out_size = %ld\n", blob.in, blob.in_size, blob.out, blob.out_size);
1265                 fprintf(fp, "\t\t\tstatus->MinQuota = %ld\n", status->MinQuota);
1266                 fprintf(fp, "\t\t\tstatus->MaxQuota = %ld\n", status->MaxQuota);
1267                 fprintf(fp, "\t\t\tOther status fields aren't set\n");
1268                 fprintf(fp, "\t\t\t3 nulls follow the VolumeStatus structure.\n");
1269                 fprintf(fp, "\tfollow = 1\n");
1270                 fclose(fp);             
1271         }
1272 #endif
1273
1274         code = pioctl(PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob, 1);
1275         if (code) {
1276                 ShowMessageBox(IDS_SET_QUOTA_ERROR, MB_ICONEXCLAMATION, IDS_SET_QUOTA_ERROR, GetAfsError(errno, volInfo.m_strName));
1277                 return FALSE;
1278         }
1279
1280     return TRUE;
1281 }
1282
1283 int GetCellName(char *cellNamep, struct afsconf_cell *infop)
1284 {
1285         strcpy(infop->name, cellNamep);
1286     return 0;
1287 }
1288
1289 BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bFast)
1290 {
1291     register LONG code;
1292     struct ViceIoctl blob;
1293     register LONG j;
1294     LONG temp = 0;
1295     struct afsconf_cell info;
1296     struct chservinfo checkserv;
1297
1298         HOURGLASS hourglass;
1299
1300     memset(&checkserv, 0, sizeof(struct chservinfo));
1301     blob.in_size = sizeof(struct chservinfo);
1302     blob.in = (caddr_t)&checkserv;
1303
1304     blob.out_size = MAXSIZE;
1305     blob.out = space;
1306     memset(space, 0, sizeof(LONG));     /* so we assure zero when nothing is copied back */
1307
1308     /* prepare flags for checkservers command */
1309         if (nCellsToCheck == LOCAL_CELL)
1310                 temp = 2;       /* default to checking local cell only */
1311     else if (nCellsToCheck == ALL_CELLS)
1312                 temp &= ~2;     /* turn off local cell check */
1313
1314         if (bFast)
1315                 temp |= 1;      /* set fast flag */
1316     
1317     checkserv.magic = 0x12345678;       /* XXX */
1318     checkserv.tflags = temp;
1319
1320     /* now copy in optional cell name, if specified */
1321     if (nCellsToCheck == SPECIFIC_CELL) {
1322                 GetCellName(PCCHAR(strCellName), &info);
1323                 strcpy(checkserv.tbuffer,info.name);
1324                 checkserv.tsize = strlen(info.name) + 1;
1325     } else {
1326                 strcpy(checkserv.tbuffer, "\0");
1327                 checkserv.tsize = 0;
1328         }
1329
1330         checkserv.tinterval = -1;       /* don't change current interval */
1331
1332     code = pioctl(0, VIOCCKSERV, &blob, 1);
1333     if (code) {
1334                 ShowMessageBox(IDS_CHECK_SERVERS_ERROR, MB_ICONEXCLAMATION, IDS_CHECK_SERVERS_ERROR, GetAfsError(errno, CString()));
1335                 return FALSE;
1336     }
1337
1338     memcpy(&temp, space, sizeof(LONG));
1339
1340         if (temp == 0) {
1341                 ShowMessageBox(IDS_ALL_SERVERS_RUNNING, MB_OK, IDS_ALL_SERVERS_RUNNING);
1342                 return TRUE;
1343         }
1344
1345         CStringArray servers;
1346         for (j = 0; j < MAXHOSTS; j++) {
1347                 memcpy(&temp, space + j * sizeof(LONG), sizeof(LONG));
1348                 if (temp == 0)
1349                         break;
1350                 
1351                 char *name = hostutil_GetNameByINet(temp);
1352                 servers.Add(name);
1353         }
1354
1355         CDownServersDlg dlg;
1356         dlg.SetServerNames(servers);
1357         dlg.DoModal();
1358
1359     return TRUE;
1360 }
1361
1362 BOOL GetTokenInfo(CStringArray& tokenInfo)
1363 {
1364         int cellNum;
1365         int rc;
1366         int current_time;
1367         long tokenExpireTime;
1368         char *expireString;
1369         char userName[100];
1370 //      char s[100];
1371         struct ktc_principal serviceName, clientName;
1372         struct ktc_token token;
1373         
1374         CString strTokenInfo;
1375         CString strUserName;
1376         CString strCellName;
1377         CString strExpir;
1378
1379 //      tokenInfo.Add("");
1380 //      return TRUE;
1381
1382
1383         HOURGLASS hourglass;
1384
1385 //      printf("\nTokens held by the Cache Manager:\n\n");
1386         cellNum = 0;
1387         current_time = time(0);
1388
1389         while (1) {
1390                 rc = ktc_ListTokens(cellNum, &cellNum, &serviceName);
1391                 if (rc == KTC_NOENT) {
1392                         /* end of list */
1393 //                      printf("   --End of list --\n");
1394                         break;
1395                 }
1396                 else if (rc == KTC_NOCM) {
1397                         ShowMessageBox(IDS_GET_TOKENS_NO_AFS_SERVICE);
1398 //                      printf("AFS service may not have started\n");
1399                         break;
1400                 }
1401                 else if (rc) {
1402                         ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR, MB_ICONEXCLAMATION, IDS_GET_TOKENS_UNEXPECTED_ERROR, rc);
1403                         return FALSE;
1404 //                      printf("Unexpected error, code %d\n", rc);
1405 //                      exit(1);
1406                 }
1407                 else {
1408                         rc = ktc_GetToken(&serviceName, &token, sizeof(token), &clientName);
1409                         if (rc) {
1410                                 ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR2, MB_ICONEXCLAMATION, IDS_GET_TOKENS_UNEXPECTED_ERROR2, 
1411                                         serviceName.name, serviceName.instance, serviceName.cell, rc);
1412                                 continue;
1413                         }
1414
1415                         tokenExpireTime = token.endTime;
1416                         
1417                         strcpy(userName, clientName.name);
1418                         if (clientName.instance[0] != 0) {
1419                                 strcat(userName, ".");
1420                                 strcat(userName, clientName.instance);
1421                         }
1422
1423                         BOOL bShowName = FALSE;
1424
1425                         if (userName[0] == '\0')
1426                                 ; //printf("Tokens");
1427 // AFS ID is not returned at this time.
1428 //                      else if (strncmp(userName, "AFS ID", 6) == 0)
1429 //                              printf("User's (%s) tokens", userName);
1430 //                              sscanf(userName, "(AFS ID %s)", szAfsID);
1431                         else if (strncmp(userName, "Unix UID", 8) == 0)
1432                                 ; //printf("Tokens");
1433                         else
1434                                 strUserName = userName;
1435 //                              printf("User %s's tokens", userName);
1436                         
1437 //                      printf(" for %s%s%s@%s ", serviceName.name, serviceName.instance[0] ? "." : "", serviceName.instance, serviceName.cell);
1438                         strCellName = serviceName.cell;
1439                         
1440                         if (tokenExpireTime <= current_time)
1441                                 strExpir = "[>> Expired <<]";
1442 //                              printf("[>> Expired <<]\n");
1443                         else {
1444                                 expireString = ctime(&tokenExpireTime);
1445                                 expireString += 4;       /* Skip day of week */
1446                                 expireString[12] = '\0'; /* Omit secs & year */
1447 //                              printf("[Expires %s]\n", expireString);
1448                                 strExpir.Format("%s", expireString);
1449                         }
1450                 
1451                         strTokenInfo = strUserName + "\t" + strCellName + "\t" + strExpir + "\t" + strCellName;
1452                         tokenInfo.Add(strTokenInfo);
1453                 }
1454         }
1455
1456 //      printf("Press <Enter> or <Return> when finished: ");
1457 //      gets(s);
1458         return TRUE;
1459 }
1460
1461 BOOL IsPathInAfs(const CString& strPath)
1462 {
1463     struct ViceIoctl blob;
1464     int code;
1465
1466     blob.in_size = 0;
1467     blob.out_size = MAXSIZE;
1468     blob.out = space;
1469
1470     code = pioctl(PCCHAR(strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1471     if (code) {
1472         if ((errno == EINVAL) || (errno == ENOENT)) return FALSE;
1473     }
1474     return TRUE;
1475 }
1476