windows-gui2fs-20050831
[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 #include <WINNT\afsreg.h>
35 }
36
37
38 #define PCCHAR(str)             ((char *)(const char *)(str))
39
40
41 #define MAXHOSTS 13
42 #define OMAXHOSTS 8
43 #define MAXNAME 100
44 #define MAXSIZE 2048
45 #define MAXINSIZE 1300    /* pioctl complains if data is larger than this */
46 #define VMSGSIZE 128      /* size of msg buf in volume hdr */
47
48 #define MAXCELLCHARS            64
49 #define MAXHOSTCHARS            64
50 #define MAXHOSTSPERCELL         8
51
52 struct afsconf_cell {
53         char name[MAXCELLCHARS];
54     short numServers;
55     short flags;
56     struct sockaddr_in hostAddr[MAXHOSTSPERCELL];
57     char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];
58     char *linkedCell;
59 };
60
61 static char space[MAXSIZE];
62 static char tspace[1024];
63
64 // #define      LOGGING_ON              // Enable this to log certain pioctl calls
65
66 #ifdef  LOGGING_ON
67 static char *szLogFileName = "afsguilog.txt";
68 #endif
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 extern "C" 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 extern "C" void ZapAcl (struct Acl *acl)
382 {
383     ZapList(acl->pluslist);
384     ZapList(acl->minuslist);
385     free(acl);
386 }
387
388 extern "C" 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 int 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 extern "C" 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     int i;
817     for (i = 0; i < normal.GetSize(); i += 2) {
818         rights = Convert(normal[i + 1], 0, &rtype);
819         ChangeList(pAcl, TRUE, normal[i], rights);
820     }
821
822     // Set its negative rights
823     for (i = 0; i < negative.GetSize(); i += 2) {
824         rights = Convert(negative[i + 1], 0, &rtype);
825         ChangeList(pAcl, FALSE, negative[i], rights);
826     }
827
828     // Write the ACL
829     blob.in = AclToString(pAcl);
830     blob.out_size = 0;
831     blob.in_size = 1 + strlen((const char *)blob.in);
832
833     code = pioctl(PCCHAR(strDir), VIOCSETAL, &blob, 1);
834     if (code) {
835         if (errno == EINVAL)
836             ShowMessageBox(IDS_SAVE_ACL_EINVAL_ERROR, MB_ICONEXCLAMATION, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
837         else
838             ShowMessageBox(IDS_SAVE_ACL_ERROR, MB_ICONEXCLAMATION, IDS_SAVE_ACL_ERROR, strDir, GetAfsError(errno, strDir));
839     }       
840
841     ZapAcl(pAcl);
842
843     return (code == 0);
844 }
845
846 BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringArray& negative, BOOL bClear)
847 {
848     register LONG code;
849     struct ViceIoctl blob;
850     struct Acl *pToAcl;
851     int idf = 0; // getidf(as, parm_copyacl_id);
852
853     HOURGLASS hourglass;
854
855     // Get ACL to copy to
856     blob.out_size = MAXSIZE;
857     blob.in_size = idf;
858     blob.in = blob.out = space;
859         
860     code = pioctl(PCCHAR(strToDir), VIOCGETAL, &blob, 1);
861     if (code) {
862         ShowMessageBox(IDS_ACL_READ_ERROR, MB_ICONEXCLAMATION, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
863         return FALSE;
864     }
865         
866     if (bClear) 
867         pToAcl = EmptyAcl(space);
868     else 
869         pToAcl = ParseAcl(space);
870
871     CleanAcl(pToAcl);
872
873     if (pToAcl->dfs) {
874         ShowMessageBox(IDS_NO_DFS_COPY_ACL, MB_ICONEXCLAMATION, IDS_NO_DFS_COPY_ACL, strToDir);
875         ZapAcl(pToAcl);
876         return FALSE;
877     }
878
879     enum rtype rtype;
880
881     // Set normal rights
882     int i;
883     for (i = 0; i < normal.GetSize(); i += 2) {
884         LONG rights = Convert(normal[i + 1], 0, &rtype);
885         ChangeList(pToAcl, TRUE, normal[i], rights);
886     }
887
888     // Set negative rights
889     for (i = 0; i < negative.GetSize(); i += 2) {
890         LONG rights = Convert(negative[i + 1], 0, &rtype);
891         ChangeList(pToAcl, FALSE, normal[i], rights);
892     }
893
894     // Save modified ACL
895     blob.in = AclToString(pToAcl);
896     blob.out_size = 0;
897     blob.in_size = 1 + strlen((char *)blob.in);
898
899     code = pioctl(PCCHAR(strToDir), VIOCSETAL, &blob, 1);
900     if (code) {
901         ZapAcl(pToAcl);
902         if (errno == EINVAL)
903             ShowMessageBox(IDS_COPY_ACL_EINVAL_ERROR, MB_ICONEXCLAMATION, IDS_COPY_ACL_EINVAL_ERROR, strToDir);
904         else 
905             ShowMessageBox(IDS_COPY_ACL_ERROR, MB_ICONEXCLAMATION, IDS_COPY_ACL_ERROR, strToDir, GetAfsError(errno, strToDir));
906         return FALSE;
907     }
908
909     ZapAcl(pToAcl);
910
911     ShowMessageBox(IDS_COPY_ACL_OK, MB_OK, IDS_COPY_ACL_OK);
912
913     return TRUE;
914 }
915
916 CString ParseMountPoint(const CString strFile, CString strMountPoint)
917 {
918     CString strType;
919     CString strVolume;
920     CString strCell;
921     CString strMountPointInfo;
922
923     if (strMountPoint[0] == '#')
924         strType = "Regular";
925     else if (strMountPoint[0] == '%')
926         strType = "Read/Write";
927
928     int nColon = strMountPoint.Find(':');
929     if (nColon >= 0) {
930         strCell = strMountPoint.Mid(1, nColon - 1);
931         strVolume = strMountPoint.Mid(nColon + 1);
932     } else
933         strVolume = strMountPoint.Mid(1);
934
935     strMountPointInfo = strFile + "\t" + strVolume + "\t" + strCell + "\t" + strType;
936
937     return strMountPointInfo;
938 }       
939
940 BOOL IsPathInAfs(const CHAR *strPath)
941 {
942     struct ViceIoctl blob;
943     int code;
944
945     HOURGLASS hourglass;
946
947     blob.in_size = 0;
948     blob.out_size = MAXSIZE;
949     blob.out = space;
950
951     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
952     if (code)
953         return FALSE;
954     return TRUE;
955 }
956
957 static int 
958 IsFreelanceRoot(char *apath)
959 {
960     struct ViceIoctl blob;
961     afs_int32 code;
962
963     blob.in_size = 0;
964     blob.out_size = MAXSIZE;
965     blob.out = space;
966
967     code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
968     if (code == 0)
969         return !strcmp("Freelance.Local.Root",space);
970     return 1;   /* assume it is because it is more restrictive that way */
971 }
972
973 const char * NetbiosName(void)
974 {
975     static char buffer[1024] = "AFS";
976     HKEY  parmKey;
977     DWORD code;
978     DWORD dummyLen;
979     DWORD enabled = 0;
980
981     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
982                          0, KEY_QUERY_VALUE, &parmKey);
983     if (code == ERROR_SUCCESS) {
984         dummyLen = sizeof(buffer);
985         code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
986                                (LPBYTE)buffer, &dummyLen);
987         RegCloseKey (parmKey);
988     } else {
989         strcpy(buffer, "AFS");
990     }
991     return buffer;
992 }
993
994 #define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
995
996 static BOOL IsAdmin (void)
997 {
998     static BOOL fAdmin = FALSE;
999     static BOOL fTested = FALSE;
1000
1001     if (!fTested)
1002     {
1003         /* Obtain the SID for the AFS client admin group.  If the group does
1004          * not exist, then assume we have AFS client admin privileges.
1005          */
1006         PSID psidAdmin = NULL;
1007         DWORD dwSize, dwSize2;
1008         char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
1009         char *pszRefDomain = NULL;
1010         SID_NAME_USE snu = SidTypeGroup;
1011
1012         dwSize = sizeof(pszAdminGroup);
1013
1014         if (!GetComputerName(pszAdminGroup, &dwSize)) {
1015             /* Can't get computer name.  We return false in this case.
1016                Retain fAdmin and fTested. This shouldn't happen.*/
1017             return FALSE;
1018         }
1019
1020         dwSize = 0;
1021         dwSize2 = 0;
1022
1023         strcat(pszAdminGroup,"\\");
1024         strcat(pszAdminGroup, AFSCLIENT_ADMIN_GROUPNAME);
1025
1026         LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
1027         /* that should always fail. */
1028
1029         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1030             /* if we can't find the group, then we allow the operation */
1031             fAdmin = TRUE;
1032             return TRUE;
1033         }
1034
1035         if (dwSize == 0 || dwSize2 == 0) {
1036             /* Paranoia */
1037             fAdmin = TRUE;
1038             return TRUE;
1039         }
1040
1041         psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
1042         pszRefDomain = (char *)malloc(dwSize2);
1043
1044         if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
1045             /* We can't lookup the group now even though we looked it up earlier.  
1046                Could this happen? */
1047             fAdmin = TRUE;
1048         } else {
1049             /* Then open our current ProcessToken */
1050             HANDLE hToken;
1051
1052             if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
1053             {
1054
1055                 if (!CheckTokenMembership(hToken, psidAdmin, &fAdmin)) {
1056                     /* We'll have to allocate a chunk of memory to store the list of
1057                      * groups to which this user belongs; find out how much memory
1058                      * we'll need.
1059                      */
1060                     DWORD dwSize = 0;
1061                     PTOKEN_GROUPS pGroups;
1062
1063                     GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
1064
1065                     pGroups = (PTOKEN_GROUPS)malloc(dwSize);
1066
1067                     /* Allocate that buffer, and read in the list of groups. */
1068                     if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
1069                     {
1070                         /* Look through the list of group SIDs and see if any of them
1071                          * matches the AFS Client Admin group SID.
1072                          */
1073                         size_t iGroup = 0;
1074                         for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
1075                         {
1076                             if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
1077                                 fAdmin = TRUE;
1078                             }
1079                         }
1080                     }
1081
1082                     if (pGroups)
1083                         free(pGroups);
1084                 }
1085
1086                 /* if do not have permission because we were not explicitly listed
1087                  * in the Admin Client Group let's see if we are the SYSTEM account
1088                  */
1089                 if (!fAdmin) {
1090                     PTOKEN_USER pTokenUser;
1091                     SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
1092                     PSID pSidLocalSystem = 0;
1093                     DWORD gle;
1094
1095                     GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
1096
1097                     pTokenUser = (PTOKEN_USER)malloc(dwSize);
1098
1099                     if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
1100                         gle = GetLastError();
1101
1102                     if (AllocateAndInitializeSid( &SIDAuth, 1,
1103                                                   SECURITY_LOCAL_SYSTEM_RID,
1104                                                   0, 0, 0, 0, 0, 0, 0,
1105                                                   &pSidLocalSystem))
1106                     {
1107                         if (EqualSid(pTokenUser->User.Sid, pSidLocalSystem)) {
1108                             fAdmin = TRUE;
1109                         }
1110
1111                         FreeSid(pSidLocalSystem);
1112                     }
1113
1114                     if ( pTokenUser )
1115                         free(pTokenUser);
1116                 }
1117             }
1118         }
1119
1120         free(psidAdmin);
1121         free(pszRefDomain);
1122
1123         fTested = TRUE;
1124     }
1125
1126     return fAdmin;
1127 }
1128
1129 /* return a static pointer to a buffer */
1130 static char *Parent(char *apath)
1131 {
1132     register char *tp;
1133
1134     strcpy(tspace, apath);
1135     tp = strrchr(tspace, '\\');
1136     if (tp) {
1137         *(tp+1) = 0;    /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
1138     }
1139     else {
1140         fs_ExtractDriveLetter(apath, tspace);
1141         strcat(tspace, ".");
1142     }
1143     
1144     return tspace;
1145 }
1146
1147 static afs_int32
1148 GetCell(char *fname, char *cellname)
1149 {
1150     afs_int32 code;
1151     struct ViceIoctl blob;
1152
1153     blob.in_size = 0;
1154     blob.out_size = MAXCELLCHARS;
1155     blob.out = cellname;
1156
1157     code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1);
1158     return code ? errno : 0;
1159 }
1160
1161
1162 BOOL ListMount(CStringArray& files)
1163 {
1164     register LONG code;
1165     struct ViceIoctl blob;
1166     int error;
1167     char orig_name[1024];                       /* Original name, may be modified */
1168     char true_name[1024];                       /* ``True'' dirname (e.g., symlink target) */
1169     char parent_dir[1024];                      /* Parent directory of true name */
1170     register char *last_component;      /* Last component of true name */
1171     CStringArray mountPoints;
1172     
1173     HOURGLASS hourglass;
1174
1175     error = 0;
1176
1177     for (int i = 0; i < files.GetSize(); i++) {
1178         strcpy(orig_name, files[i]);
1179         strcpy(true_name, orig_name);
1180
1181         /*
1182          * Find rightmost slash, if any.
1183          */
1184         last_component = (char *)strrchr(true_name, '\\');
1185         if (last_component) {
1186             /*
1187              * Found it.  Designate everything before it as the parent directory,
1188              * everything after it as the final component.
1189              */
1190             strncpy(parent_dir, true_name, last_component - true_name + 1);
1191             parent_dir[last_component - true_name + 1] = 0;
1192             last_component++;   /* Skip the slash */
1193
1194             if (!IsPathInAfs(parent_dir)) {
1195                 const char * nbname = NetbiosName();
1196                 int len = strlen(nbname);
1197
1198                 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
1199                     parent_dir[len+2] == '\\' &&
1200                     parent_dir[len+3] == '\0' &&
1201                     !strnicmp(nbname,&parent_dir[2],len))
1202                 {
1203                     sprintf(parent_dir,"\\\\%s\\all\\", nbname);
1204                 }
1205             }
1206         }
1207         else {
1208             /*
1209              * No slash appears in the given file name.  Set parent_dir to the current
1210              * directory, and the last component as the given name.
1211              */
1212             fs_ExtractDriveLetter(true_name, parent_dir);
1213             strcat(parent_dir, ".");
1214             last_component = true_name;
1215             fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
1216         }
1217
1218         blob.in = last_component;
1219         blob.in_size = strlen(last_component) + 1;
1220         blob.out_size = MAXSIZE;
1221         blob.out = space;
1222         memset(space, 0, MAXSIZE);
1223
1224         code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
1225         if (code == 0) {
1226             int nPos = strlen(space) - 1;
1227             if (space[nPos] == '.')
1228                 space[nPos] = 0;
1229             mountPoints.Add(ParseMountPoint(StripPath(files[i]), space));
1230         } else {
1231             error = 1;
1232             if (errno == EINVAL)
1233                 mountPoints.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
1234             else
1235                 mountPoints.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
1236         }
1237     }
1238
1239     CMountPointsDlg dlg;
1240     dlg.SetMountPoints(mountPoints);
1241     dlg.DoModal();
1242
1243     return !error;
1244 }
1245
1246 BOOL MakeMount(const CString& strDir, const CString& strVolName, const CString& strCellName, BOOL bRW)
1247 {
1248     register LONG code;
1249     register char *cellName;
1250     char localCellName[128];
1251     struct afsconf_cell info;
1252     struct ViceIoctl blob;
1253     char * parent;
1254     char path[1024] = "";
1255
1256     HOURGLASS hourglass;
1257
1258     ASSERT(strVolName.GetLength() < 64);
1259
1260     if (strCellName.GetLength() > 0)    /* cell name specified */
1261         cellName = PCCHAR(strCellName);
1262     else
1263         cellName = (char *) 0;
1264
1265     parent = Parent(PCCHAR(strDir));
1266     if (!IsPathInAfs(parent)) {
1267         const char * nbname = NetbiosName();
1268         int len = strlen(nbname);
1269
1270         if (parent[0] == '\\' && parent[1] == '\\' &&
1271             parent[len+2] == '\\' &&
1272             parent[len+3] == '\0' &&
1273             !strnicmp(nbname,&parent[2],len))
1274         {
1275             sprintf(path,"%sall\\%s", parent, &(PCCHAR(strDir)[strlen(parent)]));
1276             parent = Parent(path);
1277             if (!IsPathInAfs(parent)) {
1278                 ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_MP_NOT_AFS_ERROR);
1279                 return FALSE;
1280             }
1281         } else {
1282             ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_MP_NOT_AFS_ERROR);
1283             return FALSE;
1284         }
1285     }
1286
1287     if ( strlen(path) == 0 )
1288         strcpy(path, PCCHAR(strDir));
1289
1290     if ( IsFreelanceRoot(parent) ) {
1291         if ( !IsAdmin() ) {
1292             ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONEXCLAMATION, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
1293             return FALSE;
1294         }
1295
1296         if (!cellName) {
1297             blob.in_size = 0;
1298             blob.out_size = sizeof(localCellName);
1299             blob.out = localCellName;
1300             code = pioctl(parent, VIOC_GET_WS_CELL, &blob, 1);
1301             if (!code)
1302                 cellName = localCellName;
1303         }
1304     } else {
1305         if (!cellName)
1306             GetCell(parent,space);
1307     }
1308
1309     code = GetCellName(cellName?cellName:space, &info);
1310     if (code) {
1311         return FALSE;
1312     }
1313
1314     if (bRW)    /* if -rw specified */
1315         strcpy(space, "%");
1316     else
1317         strcpy(space, "#");
1318
1319     /* If cellular mount point, prepend cell prefix */
1320     if (cellName) {
1321         strcat(space, info.name);
1322         strcat(space, ":");
1323     }   
1324
1325     strcat(space, strVolName);  /* append volume name */
1326     strcat(space, ".");         /* stupid convention; these end with a period */
1327
1328     /* create symlink with a special pioctl for Windows NT, since it doesn't
1329      * have a symlink system call.
1330      */
1331     blob.out_size = 0;
1332     blob.in_size = 1 + strlen(space);
1333     blob.in = space;
1334     blob.out = NULL;
1335     code = pioctl(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
1336
1337     if (code) {
1338         ShowMessageBox(IDS_MOUNT_POINT_ERROR, MB_ICONEXCLAMATION, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
1339         return FALSE;
1340     }
1341     
1342     return TRUE;
1343 }
1344
1345 /*
1346 */
1347 long fs_ExtractDriveLetter(const char *inPathp, char *outPathp)
1348 {
1349     if (inPathp[0] != 0 && inPathp[1] == ':') {
1350         /* there is a drive letter */
1351         *outPathp++ = *inPathp++;
1352         *outPathp++ = *inPathp++;
1353         *outPathp++ = 0;
1354     }
1355     else *outPathp = 0;
1356
1357     return 0;
1358 }       
1359
1360 /* strip the drive letter from a component */
1361 long fs_StripDriveLetter(const char *inPathp, char *outPathp, long outSize)
1362 {
1363     char tempBuffer[1000];
1364     strcpy(tempBuffer, inPathp);
1365     if (tempBuffer[0] != 0 && tempBuffer[1] == ':') {
1366         /* drive letter present */
1367         strcpy(outPathp, tempBuffer+2);
1368     }
1369     else {
1370         /* no drive letter present */
1371         strcpy(outPathp, tempBuffer);
1372     }
1373     return 0;
1374 }       
1375
1376
1377 BOOL RemoveSymlink(const char * linkName)
1378 {
1379     BOOL error = FALSE;
1380     INT code=0;
1381     struct ViceIoctl blob;
1382     char tbuffer[1024];
1383     char lsbuffer[1024];
1384     char tpbuffer[1024];
1385     char *tp;
1386     
1387     HOURGLASS hourglass;
1388
1389     tp = (char *) strrchr(linkName, '\\');
1390     if (!tp)
1391         tp = (char *) strrchr(linkName, '/');
1392     if (tp) {
1393         strncpy(tbuffer, linkName, code=tp-linkName+1);  /* the dir name */
1394         tbuffer[code] = 0;
1395         tp++;   /* skip the slash */
1396
1397         if (!IsPathInAfs(tbuffer)) {
1398             const char * nbname = NetbiosName();
1399             int len = strlen(nbname);
1400
1401             if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1402                  tbuffer[len+2] == '\\' &&
1403                  tbuffer[len+3] == '\0' &&
1404                  !strnicmp(nbname,&tbuffer[2],len))
1405             {
1406                 sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1407             }
1408         }
1409     }
1410     else {
1411         fs_ExtractDriveLetter(linkName, tbuffer);
1412         strcat(tbuffer, ".");
1413         fs_StripDriveLetter(tp, tpbuffer, 0);
1414         tp=tpbuffer;
1415     }
1416
1417     if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
1418         ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONEXCLAMATION, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
1419         return FALSE;
1420     }
1421
1422     blob.in = tp;
1423     blob.in_size = strlen(tp)+1;
1424     blob.out = lsbuffer;
1425     blob.out_size = sizeof(lsbuffer);
1426     code = pioctl(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
1427     if (code)
1428         return FALSE;
1429     blob.out_size = 0;
1430     blob.in = tp;
1431     blob.in_size = strlen(tp)+1;
1432     return (pioctl(tbuffer, VIOC_DELSYMLINK, &blob, 0)==0);
1433 }       
1434
1435 BOOL IsSymlink(const char * true_name)
1436 {
1437     char parent_dir[MAXSIZE];           /*Parent directory of true name*/
1438     char strip_name[MAXSIZE];
1439     struct ViceIoctl blob;
1440     char *last_component;
1441     int code;
1442
1443     HOURGLASS hourglass;
1444
1445     last_component = (char *) strrchr(true_name, '\\');
1446     if (!last_component)
1447         last_component = (char *) strrchr(true_name, '/');
1448     if (last_component) {
1449         /*
1450          * Found it.  Designate everything before it as the parent directory,
1451          * everything after it as the final component.
1452          */
1453         strncpy(parent_dir, true_name, last_component - true_name + 1);
1454         parent_dir[last_component - true_name + 1] = 0;
1455         last_component++;   /*Skip the slash*/
1456
1457         if (!IsPathInAfs(parent_dir)) {
1458             const char * nbname = NetbiosName();
1459             int len = strlen(nbname);
1460
1461             if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
1462                  parent_dir[len+2] == '\\' &&
1463                  parent_dir[len+3] == '\0' &&
1464                  !strnicmp(nbname,&parent_dir[2],len))
1465             {
1466                 sprintf(parent_dir,"\\\\%s\\all\\", nbname);
1467             }
1468         }
1469     }
1470     else {
1471         /*
1472          * No slash appears in the given file name.  Set parent_dir to the current
1473          * directory, and the last component as the given name.
1474          */
1475         fs_ExtractDriveLetter(true_name, parent_dir);
1476         strcat(parent_dir, ".");
1477         last_component = strip_name;
1478         fs_StripDriveLetter(true_name, strip_name, sizeof(strip_name));
1479     }
1480
1481     blob.in = last_component;
1482     blob.in_size = strlen(last_component)+1;
1483     blob.out_size = MAXSIZE;
1484     blob.out = space;
1485     memset(space, 0, MAXSIZE);
1486     code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
1487     return (code==0);
1488 }       
1489
1490
1491 BOOL IsMountPoint(const char * name)
1492 {
1493     register LONG code = 0;
1494     struct ViceIoctl blob;
1495     char tbuffer[1024];
1496     char lsbuffer[1024];
1497     register char *tp;
1498     char szCurItem[1024];
1499
1500     strcpy(szCurItem, name);
1501         
1502     tp = (char *)strrchr(szCurItem, '\\');
1503     if (tp) {
1504         strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
1505         tbuffer[code] = 0;
1506         tp++;   /* skip the slash */
1507
1508         if (!IsPathInAfs(tbuffer)) {
1509             const char * nbname = NetbiosName();
1510             int len = strlen(nbname);
1511
1512             if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1513                  tbuffer[len+2] == '\\' &&
1514                  tbuffer[len+3] == '\0' &&
1515                  !strnicmp(nbname,&tbuffer[2],len))
1516             {
1517                 sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1518             }
1519         }
1520     } else {
1521         fs_ExtractDriveLetter(szCurItem, tbuffer);
1522         strcat(tbuffer, ".");
1523         tp = szCurItem;
1524         fs_StripDriveLetter(tp, tp, 0);
1525     }
1526
1527     blob.in = tp;
1528     blob.in_size = strlen(tp)+1;
1529     blob.out = lsbuffer;
1530     blob.out_size = sizeof(lsbuffer);
1531
1532     code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
1533
1534     return (code==0);
1535 }       
1536
1537
1538 /*
1539  * Delete AFS mount points.  Variables are used as follows:
1540  *       tbuffer: Set to point to the null-terminated directory name of the mount point
1541  *          (or ``.'' if none is provided)
1542  *      tp: Set to point to the actual name of the mount point to nuke.
1543  */
1544 BOOL RemoveMount(CStringArray& files)
1545 {
1546     register LONG code = 0;
1547     struct ViceIoctl blob;
1548     char tbuffer[1024];
1549     char lsbuffer[1024];
1550     register char *tp;
1551     char szCurItem[1024];
1552     BOOL error = FALSE;
1553     CStringArray results;
1554     CString str;
1555     CString str2;
1556
1557     HOURGLASS hourglass;
1558
1559     for (int i = 0; i < files.GetSize(); i++) {
1560         if (!IsMountPoint(files[i])) {
1561             error = TRUE;
1562             if (errno == EINVAL)
1563                 results.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
1564             else
1565                 results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
1566             continue;   // don't bother trying
1567         }
1568
1569         strcpy(szCurItem, files[i]);
1570         
1571         tp = (char *)strrchr(szCurItem, '\\');
1572         if (tp) {
1573             strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
1574             tbuffer[code] = 0;
1575             tp++;   /* skip the slash */
1576
1577             if (!IsPathInAfs(tbuffer)) {
1578                 const char * nbname = NetbiosName();
1579                 int len = strlen(nbname);
1580
1581                 if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1582                     tbuffer[len+2] == '\\' &&
1583                     tbuffer[len+3] == '\0' &&
1584                     !strnicmp(nbname,&tbuffer[2],len))
1585                 {
1586                     sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1587                 }
1588             }
1589         } else {
1590             fs_ExtractDriveLetter(szCurItem, tbuffer);
1591             strcat(tbuffer, ".");
1592             tp = szCurItem;
1593             fs_StripDriveLetter(tp, tp, 0);
1594         }
1595
1596         if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
1597             results.Add(GetMessageString(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, StripPath(files[i])));
1598             error = TRUE;
1599             continue;   /* skip */
1600         }
1601
1602         blob.out_size = 0;
1603         blob.in = tp;
1604         blob.in_size = strlen(tp)+1;
1605
1606         code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
1607         if (code) {
1608             error = TRUE;
1609             results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
1610         } else
1611             results.Add(GetMessageString(IDS_DELETED));
1612     }   
1613
1614     LoadString (str, IDS_REMOVE_MP);
1615     LoadString (str2, IDS_REMOVE_MP_COLUMN);
1616     CResultsDlg dlg(REMOVE_MOUNT_POINTS_HELP_ID);
1617     dlg.SetContents(str, str2, StripPath(files), results);
1618     dlg.DoModal();
1619
1620     return !error;
1621 }
1622
1623 BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
1624 {
1625     register LONG code;
1626     struct ViceIoctl blob;
1627     struct VolumeStatus *status;
1628     char *name;
1629
1630     HOURGLASS hourglass;
1631
1632     volInfo.m_strFilePath = strFile;
1633     volInfo.m_strFileName = StripPath(strFile);
1634
1635     /*
1636         volInfo.m_strName = "VolumeName";
1637         volInfo.m_nID = 10;
1638         volInfo.m_nQuota = 20 * 1024 * 1024;
1639         volInfo.m_nNewQuota = volInfo.m_nQuota;
1640         volInfo.m_nUsed = volInfo.m_nQuota / 2;
1641         volInfo.m_nPartSize = 50 * 1024 * 1024;
1642         volInfo.m_nPartFree = 30 * 1024 * 1024;
1643         volInfo.m_nDup = -1;
1644         return TRUE;
1645      */
1646
1647     blob.out_size = MAXSIZE;
1648     blob.in_size = 0;
1649     blob.out = space;
1650
1651     code = pioctl(PCCHAR(strFile), VIOCGETVOLSTAT, &blob, 1);
1652     if (code) {
1653         volInfo.m_strErrorMsg = GetAfsError(errno, strFile);
1654         return FALSE;
1655     }
1656
1657     status = (VolumeStatus *)space;
1658     name = (char *)status + sizeof(*status);
1659
1660     volInfo.m_strName = name;
1661     volInfo.m_nID = status->Vid;
1662     volInfo.m_nQuota = status->MaxQuota;
1663     volInfo.m_nNewQuota = status->MaxQuota;
1664     volInfo.m_nUsed = status->BlocksInUse;
1665     volInfo.m_nPartSize = status->PartMaxBlocks;
1666     volInfo.m_nPartFree = status->PartBlocksAvail;
1667     volInfo.m_nDup = -1;
1668
1669     return TRUE;
1670 }
1671         
1672 BOOL SetVolInfo(CVolInfo& volInfo)
1673 {
1674     register LONG code;
1675     struct ViceIoctl blob;
1676     struct VolumeStatus *status;
1677     char *input;
1678
1679     HOURGLASS hourglass;
1680
1681     blob.out_size = MAXSIZE;
1682     blob.in_size = sizeof(*status) + 3; /* for the three terminating nulls */
1683     blob.out = space;
1684     blob.in = space;
1685
1686     status = (VolumeStatus *)space;
1687     status->MinQuota = -1;
1688     status->MaxQuota = volInfo.m_nNewQuota;
1689         
1690     input = (char *)status + sizeof(*status);
1691     *(input++) = '\0';  /* never set name: this call doesn't change vldb */
1692     *(input++) = '\0';  // No offmsg
1693     *(input++) = '\0';  // No motd
1694
1695 #ifdef LOGGING_ON
1696     FILE *fp = OpenFile(szLogFileName, "a");
1697     if (fp) {
1698         fprintf(fp, "\nSetVolInfo() pioctl parms:\n");
1699         fprintf(fp, "\tpathp = %s\n\topcode = VIOCSETVOLSTAT (%d)\n\tblobp = %ld\n", PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob);
1700         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);
1701         fprintf(fp, "\t\t\tstatus->MinQuota = %ld\n", status->MinQuota);
1702         fprintf(fp, "\t\t\tstatus->MaxQuota = %ld\n", status->MaxQuota);
1703         fprintf(fp, "\t\t\tOther status fields aren't set\n");
1704         fprintf(fp, "\t\t\t3 nulls follow the VolumeStatus structure.\n");
1705         fprintf(fp, "\tfollow = 1\n");
1706         fclose(fp);             
1707     }
1708 #endif
1709
1710     code = pioctl(PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob, 1);
1711     if (code) {
1712         ShowMessageBox(IDS_SET_QUOTA_ERROR, MB_ICONEXCLAMATION, IDS_SET_QUOTA_ERROR, GetAfsError(errno, volInfo.m_strName));
1713         return FALSE;
1714     }
1715
1716     return TRUE;
1717 }
1718
1719 int GetCellName(char *cellNamep, struct afsconf_cell *infop)
1720 {
1721     strcpy(infop->name, cellNamep);
1722     return 0;
1723 }
1724
1725 BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bFast)
1726 {
1727     register LONG code;
1728     struct ViceIoctl blob;
1729     register LONG j;
1730     LONG temp = 0;
1731     struct afsconf_cell info;
1732     struct chservinfo checkserv;
1733
1734     HOURGLASS hourglass;
1735
1736     memset(&checkserv, 0, sizeof(struct chservinfo));
1737     blob.in_size = sizeof(struct chservinfo);
1738     blob.in = (caddr_t)&checkserv;
1739
1740     blob.out_size = MAXSIZE;
1741     blob.out = space;
1742     memset(space, 0, sizeof(LONG));     /* so we assure zero when nothing is copied back */
1743
1744     /* prepare flags for checkservers command */
1745     if (nCellsToCheck == LOCAL_CELL)
1746         temp = 2;       /* default to checking local cell only */
1747     else if (nCellsToCheck == ALL_CELLS)
1748         temp &= ~2;     /* turn off local cell check */
1749
1750     if (bFast)
1751         temp |= 1;      /* set fast flag */
1752     
1753     checkserv.magic = 0x12345678;       /* XXX */
1754     checkserv.tflags = temp;
1755
1756     /* now copy in optional cell name, if specified */
1757     if (nCellsToCheck == SPECIFIC_CELL) {
1758         GetCellName(PCCHAR(strCellName), &info);
1759         strcpy(checkserv.tbuffer,info.name);
1760         checkserv.tsize = strlen(info.name) + 1;
1761     } else {
1762         strcpy(checkserv.tbuffer, "\0");
1763         checkserv.tsize = 0;
1764     }
1765
1766     checkserv.tinterval = -1;   /* don't change current interval */
1767
1768     code = pioctl(0, VIOCCKSERV, &blob, 1);
1769     if (code) {
1770         ShowMessageBox(IDS_CHECK_SERVERS_ERROR, MB_ICONEXCLAMATION, IDS_CHECK_SERVERS_ERROR, GetAfsError(errno, CString()));
1771         return FALSE;
1772     }
1773
1774     memcpy(&temp, space, sizeof(LONG));
1775
1776     if (temp == 0) {
1777         ShowMessageBox(IDS_ALL_SERVERS_RUNNING, MB_OK, IDS_ALL_SERVERS_RUNNING);
1778         return TRUE;
1779     }
1780
1781     CStringArray servers;
1782     for (j = 0; j < MAXHOSTS; j++) {
1783         memcpy(&temp, space + j * sizeof(LONG), sizeof(LONG));
1784         if (temp == 0)
1785             break;
1786
1787         char *name = hostutil_GetNameByINet(temp);
1788         servers.Add(name);
1789     }
1790
1791     CDownServersDlg dlg;
1792     dlg.SetServerNames(servers);
1793     dlg.DoModal();
1794
1795     return TRUE;
1796 }       
1797
1798 BOOL GetTokenInfo(CStringArray& tokenInfo)
1799 {
1800     int cellNum;
1801     int rc;
1802     time_t current_time;
1803     time_t tokenExpireTime;
1804     char *expireString;
1805     char userName[100];
1806 //      char s[100];
1807     struct ktc_principal serviceName, clientName;
1808     struct ktc_token token;
1809
1810     CString strTokenInfo;
1811     CString strUserName;
1812     CString strCellName;
1813     CString strExpir;
1814
1815 //      tokenInfo.Add("");
1816 //      return TRUE;
1817
1818
1819     HOURGLASS hourglass;
1820
1821 //      printf("\nTokens held by the Cache Manager:\n\n");
1822     cellNum = 0;
1823     current_time = time(0);
1824
1825     while (1) {
1826         rc = ktc_ListTokens(cellNum, &cellNum, &serviceName);
1827         if (rc == KTC_NOENT) {
1828             /* end of list */
1829 //          printf("   --End of list --\n");
1830             break;
1831         }
1832         else if (rc == KTC_NOCM) {
1833             ShowMessageBox(IDS_GET_TOKENS_NO_AFS_SERVICE);
1834 //          printf("AFS service may not have started\n");
1835             break;
1836         }
1837         else if (rc) {
1838             ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR, MB_ICONEXCLAMATION, IDS_GET_TOKENS_UNEXPECTED_ERROR, rc);
1839             return FALSE;
1840 //          printf("Unexpected error, code %d\n", rc);
1841 //          exit(1);
1842         }
1843         else {
1844             rc = ktc_GetToken(&serviceName, &token, sizeof(token), &clientName);
1845             if (rc) {
1846                 ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR2, MB_ICONEXCLAMATION, IDS_GET_TOKENS_UNEXPECTED_ERROR2, 
1847                                 serviceName.name, serviceName.instance, serviceName.cell, rc);
1848                 continue;
1849             }
1850
1851             tokenExpireTime = token.endTime;
1852
1853             strcpy(userName, clientName.name);
1854             if (clientName.instance[0] != 0) {
1855                 strcat(userName, ".");
1856                 strcat(userName, clientName.instance);
1857             }
1858
1859             BOOL bShowName = FALSE;
1860
1861             if (userName[0] == '\0')
1862                 ; //printf("Tokens");
1863 // AFS ID is not returned at this time.
1864 //          else if (strncmp(userName, "AFS ID", 6) == 0)
1865 //              printf("User's (%s) tokens", userName);
1866 //              sscanf(userName, "(AFS ID %s)", szAfsID);
1867             else if (strncmp(userName, "Unix UID", 8) == 0)
1868                 ; //printf("Tokens");
1869             else
1870                 strUserName = userName;
1871 //              printf("User %s's tokens", userName);
1872                         
1873 //              printf(" for %s%s%s@%s ", serviceName.name, serviceName.instance[0] ? "." : "", serviceName.instance, serviceName.cell);
1874             strCellName = serviceName.cell;
1875                         
1876             if (tokenExpireTime <= current_time)
1877                 strExpir = "[>> Expired <<]";
1878 //              printf("[>> Expired <<]\n");
1879             else {
1880                 expireString = ctime(&tokenExpireTime);
1881                 expireString += 4;       /* Skip day of week */
1882                 expireString[12] = '\0'; /* Omit secs & year */
1883 //              printf("[Expires %s]\n", expireString);
1884                 strExpir.Format("%s", expireString);
1885             }
1886
1887             strTokenInfo = strUserName + "\t" + strCellName + "\t" + strExpir + "\t" + strCellName;
1888             tokenInfo.Add(strTokenInfo);
1889         }
1890     }
1891
1892 //      printf("Press <Enter> or <Return> when finished: ");
1893 //      gets(s);
1894     return TRUE;
1895 }
1896
1897 UINT MakeSymbolicLink(const char *strName, const char *strDir)
1898 {
1899     struct ViceIoctl blob;
1900     char space[MAXSIZE];
1901     char * parent;
1902     char path[1024] = "";
1903     UINT code;
1904
1905     HOURGLASS hourglass;
1906     static char message[2048];
1907
1908     strcpy(path, strDir);
1909     parent = Parent(path);
1910
1911     sprintf(message,"MakeSymbolicLink: path = %s parent = %s\n",path,parent);
1912     OutputDebugString(message);
1913
1914     /*lets confirm its a good symlink*/
1915     if (!IsPathInAfs(path)) {
1916         const char * nbname = NetbiosName();
1917         int len = strlen(nbname);
1918
1919         if (parent[0] == '\\' && parent[1] == '\\' &&
1920             parent[len+2] == '\\' &&
1921             parent[len+3] == '\0' &&
1922             !strnicmp(nbname,&parent[2],len))
1923         {
1924             sprintf(path,"%sall\\%s", parent, &strDir[strlen(parent)]);
1925             parent = Parent(path);
1926             sprintf(message,"MakeSymbolicLink: new path = %s parent = %s\n",path,parent);
1927             OutputDebugString(message);
1928
1929             if (!IsPathInAfs(parent)) {
1930                 ShowMessageBox(IDS_MAKE_LNK_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_LNK_NOT_AFS_ERROR);
1931                 return TRUE;
1932             }
1933         } else {
1934             ShowMessageBox(IDS_MAKE_LNK_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_LNK_NOT_AFS_ERROR);
1935             return TRUE;
1936         }
1937     }
1938
1939     if ( IsFreelanceRoot(parent) && !IsAdmin() ) {
1940         ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONEXCLAMATION, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
1941         return FALSE;
1942     }
1943
1944     LPTSTR lpsz = new TCHAR[strlen(strDir)+1];
1945     _tcscpy(lpsz, strName);
1946     strcpy(space, strDir);
1947     blob.out_size = 0;
1948     blob.in_size = 1 + strlen(space);
1949     blob.in = space;
1950     blob.out = NULL;
1951     code=pioctl(lpsz, VIOC_SYMLINK, &blob, 0);
1952     delete lpsz;
1953     if (code != 0)
1954         return code;
1955     return FALSE;
1956 }
1957
1958 void ListSymbolicLinkPath(const char *strName,char *strPath,UINT nlenPath)
1959 {
1960     ASSERT(nlenPath<MAX_PATH);
1961     struct ViceIoctl blob;
1962     char orig_name[MAX_PATH+1];         /*Original name, may be modified*/
1963     char true_name[MAX_PATH+1];         /*``True'' dirname (e.g., symlink target)*/
1964     char parent_dir[MAX_PATH+1];                /*Parent directory of true name*/
1965     char *last_component;       /*Last component of true name*/
1966     UINT code;    
1967
1968     HOURGLASS hourglass;
1969
1970     strcpy(orig_name, strName);
1971     strcpy(true_name, orig_name);
1972     /*
1973      * Find rightmost slash, if any.
1974      */
1975     last_component = (char *) strrchr(true_name, '\\');
1976     if (!last_component)
1977         last_component = (char *) strrchr(true_name, '/');
1978     if (last_component) {
1979         /*
1980          * Found it.  Designate everything before it as the parent directory,
1981          * everything after it as the final component.
1982          */
1983         strncpy(parent_dir, true_name, last_component - true_name + 1);
1984         parent_dir[last_component - true_name + 1] = 0;
1985         last_component++;   /*Skip the slash*/
1986
1987         if (!IsPathInAfs(parent_dir)) {
1988             const char * nbname = NetbiosName();
1989             int len = strlen(nbname);
1990
1991             if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
1992                  parent_dir[len+2] == '\\' &&
1993                  parent_dir[len+3] == '\0' &&
1994                  !strnicmp(nbname,&parent_dir[2],len))
1995             {
1996                 sprintf(parent_dir,"\\\\%s\\all\\", nbname);
1997             }
1998         }
1999     }
2000     else {
2001         /*
2002          * No slash appears in the given file name.  Set parent_dir to the current
2003          * directory, and the last component as the given name.
2004          */
2005         fs_ExtractDriveLetter(true_name, parent_dir);
2006         strcat(parent_dir, ".");
2007         last_component = true_name;
2008         fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
2009     }
2010     blob.in = last_component;
2011     blob.in_size = strlen(last_component)+1;
2012     blob.out_size = MAXSIZE;
2013     blob.out = space;
2014     memset(space, 0, MAXSIZE);
2015     if ((code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1)))
2016         strcpy(space,"???");
2017     ASSERT(strlen(space)<MAX_PATH);
2018     strncpy(strPath,space,nlenPath);
2019 }