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