704d4ece6e1ef885056752556058fcd4c14dfd9c
[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 #include "stdafx.h"
11 #include <winsock2.h>
12 #include <ws2tcpip.h>
13
14 extern "C" {
15 #include <afs/param.h>
16 #include <afs/stds.h>
17 }
18
19 #include <errno.h>
20 #include <time.h>
21
22 #include "gui2fs.h"
23 #include "msgs.h"
24 #include "results_dlg.h"
25 #include "volume_inf.h"
26 #include "mount_points_dlg.h"
27 #include "symlinks_dlg.h"
28 #include "hourglass.h"
29 #include "down_servers_dlg.h"
30
31 extern "C" {
32 #include <rx/rx_globals.h>
33 #include "fs.h"
34 #include "fs_utils.h"
35 #include <afsint.h>
36 #include <afs/cellconfig.h>
37 #include <afs/vldbint.h>
38 #include <afs/volser.h>
39 #include <afs/auth.h>
40 #include <WINNT\afsreg.h>
41 #include <cm.h>
42 }
43
44 #define PCCHAR(str)             ((char *)(const char *)(str))
45 #define VL_NOENT                (363524L)
46
47 #define MAXHOSTS 13
48 #define OMAXHOSTS 8
49 #define MAXNAME 100
50 #define MAXSIZE 2048
51 #define MAXINSIZE 1300    /* pioctl complains if data is larger than this */
52 #define VMSGSIZE 128      /* size of msg buf in volume hdr */
53
54 #define MAXCELLCHARS            64
55 #define MAXHOSTCHARS            64
56 #define MAXHOSTSPERCELL         8
57
58 static char space[MAXSIZE];
59 static char tspace[1024];
60
61 static struct ubik_client *uclient;
62 static int rxInitDone = 0;
63 static char pn[] = "fs";
64
65 // #define      LOGGING_ON              // Enable this to log certain pioctl calls
66
67 #ifdef  LOGGING_ON
68 static char *szLogFileName = "afsguilog.txt";
69 #endif
70
71 static int
72 VLDBInit(int noAuthFlag, struct afsconf_cell *info)
73 {
74     afs_int32 code;
75
76     code = ugen_ClientInit(noAuthFlag, (char *)AFSDIR_CLIENT_ETC_DIRPATH, 
77                            info->name, 0, &uclient, 
78                            NULL, pn, rxkad_clear,
79                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
80                            0, 0, USER_SERVICE_ID);
81     rxInitDone = 1;
82     return code;
83 }
84
85 FILE *OpenFile(char *file, char *rwp)
86 {
87     char wdir[256];
88     long code;
89     long tlen;
90     FILE *fp;
91
92     code = GetWindowsDirectory(wdir, sizeof(wdir));
93     if (code == 0 || code > sizeof(wdir)) 
94         return FALSE;
95
96     /* add trailing backslash, if required */
97     tlen = strlen(wdir);
98     if (wdir[tlen - 1] != '\\')
99         strcat(wdir, "\\");
100
101     strcat(wdir, file);
102
103     fp = fopen(wdir, rwp);
104
105     return fp;
106 }       
107
108 CString StripPath(CString& strPath)
109 {
110     int nIndex = strPath.ReverseFind('\\');
111
112     CString strFile = strPath.Mid(nIndex + 1);
113     if (strFile.IsEmpty())
114         return strPath;
115
116     return strFile;
117 }
118
119 CStringArray& StripPath(CStringArray& files)
120 {
121     for (int i = 0; i < files.GetSize(); i++)
122         files[i] = StripPath(files[i]);
123
124     return files;
125 }
126
127 void Flush(const CStringArray& files)
128 {
129     register LONG code;
130     struct ViceIoctl blob;
131     int error = 0;
132
133     HOURGLASS hourglass;
134
135     for (int i = 0; i < files.GetSize(); i++) {
136         blob.in_size = blob.out_size = 0;
137
138         code = pioctl(PCCHAR(files[i]), VIOCFLUSH, &blob, 0);
139         if (code) {
140             error = 1;
141             if (errno == EMFILE)
142                 ShowMessageBox(IDS_FLUSH_FAILED, MB_ICONERROR, IDS_FLUSH_FAILED, files[i]);
143             else 
144                 ShowMessageBox(IDS_FLUSH_ERROR, MB_ICONERROR, IDS_FLUSH_ERROR, files[i], strerror(errno));
145         }
146     }   
147
148     if (!error)
149         ShowMessageBox(IDS_FLUSH_OK, MB_ICONINFORMATION, IDS_FLUSH_OK);
150 }       
151
152 void FlushVolume(const CStringArray& files)
153 {
154     register LONG code;
155     struct ViceIoctl blob;
156     int error = 0;
157
158     HOURGLASS hourglass;
159
160     for (int i = 0; i < files.GetSize(); i++) {
161         blob.in_size = blob.out_size = 0;
162
163         code = pioctl(PCCHAR(files[i]), VIOC_FLUSHVOLUME, &blob, 0);
164         if (code) {
165             error = 1;
166             ShowMessageBox(IDS_FLUSH_VOLUME_ERROR, MB_ICONERROR, IDS_FLUSH_VOLUME_ERROR, files[i], strerror(errno));
167         }
168     }   
169
170     if (!code)
171         ShowMessageBox(IDS_FLUSH_VOLUME_OK, MB_ICONINFORMATION, IDS_FLUSH_VOLUME_OK);
172 }       
173
174 void WhichCell(CStringArray& files)
175 {
176     register LONG code;
177     struct ViceIoctl blob;
178     int error;
179     CString str;
180     CString str2;
181
182     CStringArray results;
183
184     error = 0;
185
186     HOURGLASS hourglass;
187
188     for (int i = 0; i < files.GetSize(); i++) {
189         blob.in_size = 0;
190         blob.out_size = MAXSIZE;
191         blob.out = space;
192
193         code = pioctl(PCCHAR(files[i]), VIOC_FILE_CELL_NAME, &blob, 1);
194         if (code) {
195             if (code == ENOENT) {
196                 LoadString (str, IDS_CANT_GET_CELL);
197                 results.Add(str);
198             } else
199                 results.Add(GetAfsError(errno));
200         } else
201             results.Add(space);
202     }       
203
204     LoadString (str, IDS_SHOW_CELL);
205     LoadString (str2, IDS_SHOW_CELL_COLUMN);
206     CResultsDlg dlg(SHOW_CELL_HELP_ID);
207     dlg.SetContents(str, str2, StripPath(files), results);
208     dlg.DoModal();
209 }
210
211 void WSCellCmd()
212 {
213     register LONG code;
214     struct ViceIoctl blob;
215     
216     HOURGLASS hourglass;
217
218     blob.in_size = 0;
219     blob.in = (char *) 0;
220     blob.out_size = MAXSIZE;
221     blob.out = space;
222
223     code = pioctl((char *) 0, VIOC_GET_WS_CELL, &blob, 1);
224
225     if (code) {
226         //Die(errno, (char *) 0);
227     }
228     //else
229     //printf("This workstation belongs to cell '%s'\n", space);
230 }
231
232 BOOL CheckVolumes()
233 {
234     register LONG code;
235     struct ViceIoctl blob;
236     
237     blob.in_size = 0;
238     blob.out_size = 0;
239     code = pioctl(0, VIOCCKBACK, &blob, 1);
240     if (code) {
241         ShowMessageBox(IDS_CHECK_VOLUMES_ERROR, MB_ICONERROR, IDS_CHECK_VOLUMES_ERROR, GetAfsError(errno, CString()));
242         return FALSE;
243     }
244
245     ShowMessageBox(IDS_CHECK_VOLUMES_OK, MB_OK|MB_ICONINFORMATION, IDS_CHECK_VOLUMES_OK);
246
247     return TRUE;
248 }
249
250 void SetCacheSizeCmd(LONG nNewCacheSize)
251 {
252     register LONG code;
253     struct ViceIoctl blob;
254     
255     HOURGLASS hourglass;
256
257     blob.in = (char *) &nNewCacheSize;
258     blob.in_size = sizeof(LONG);
259     blob.out_size = 0;
260
261     code = pioctl(0, VIOCSETCACHESIZE, &blob, 1);
262     //if (code)
263     //  Die(errno, (char *) 0);
264     //else
265     //  printf("New cache size set.\n");
266 }
267
268 void WhereIs(CStringArray& files)
269 {
270     register LONG code;
271     struct ViceIoctl blob;
272     CStringArray servers;
273     CStringArray resultFiles;
274     CString str;
275     CString str2;
276
277     HOURGLASS hourglass;
278
279     for (int i = 0; i < files.GetSize(); i++) {
280         blob.out_size = MAXSIZE;
281         blob.in_size = 0;
282         blob.out = space;
283         memset(space, 0, sizeof(space));
284
285         code = pioctl(PCCHAR(files[i]), VIOCWHEREIS, &blob, 1);
286         if (code) {
287             resultFiles.Add(StripPath(files[i]));
288             servers.Add(GetAfsError(errno));
289             continue;
290         }
291
292         LONG *hosts = (LONG *)space;
293         BOOL bFirst = TRUE;
294         str = "";
295
296         for (int j = 0; j < MAXHOSTS; j++) {
297             if (hosts[j] == 0)
298                 break;
299             char *hostName = hostutil_GetNameByINet(hosts[j]);
300             if (bFirst) {
301                 resultFiles.Add(StripPath(files[i]));
302                 bFirst = FALSE;
303             } else
304                 resultFiles.Add(" ");
305             servers.Add(hostName);
306         }
307     }
308
309     LoadString (str, IDS_SHOW_FS);
310     LoadString (str2, IDS_SHOW_FS_COLUMN);
311     CResultsDlg dlg(SHOW_FILE_SERVERS_HELP_ID);
312     dlg.SetContents(str, str2, resultFiles, servers);
313     dlg.DoModal();
314 }       
315
316 static int
317 CMtoUNIXerror(int cm_code)
318 {
319     switch (cm_code) {
320     case CM_ERROR_TIMEDOUT:
321         return ETIMEDOUT;
322     case CM_ERROR_NOACCESS:
323         return EACCES;
324     case CM_ERROR_NOSUCHFILE:
325         return ENOENT;
326     case CM_ERROR_INVAL:
327         return EINVAL;
328     case CM_ERROR_BADFD:
329         return EBADF;
330     case CM_ERROR_EXISTS:
331         return EEXIST;
332     case CM_ERROR_CROSSDEVLINK:
333         return EXDEV;
334     case CM_ERROR_NOTDIR:
335         return ENOTDIR;
336     case CM_ERROR_ISDIR:
337         return EISDIR;
338     case CM_ERROR_READONLY:
339         return EROFS;
340     case CM_ERROR_WOULDBLOCK:
341         return EWOULDBLOCK;
342     case CM_ERROR_NOSUCHCELL:
343         return ESRCH;           /* hack */
344     case CM_ERROR_NOSUCHVOLUME:
345         return EPIPE;           /* hack */
346     case CM_ERROR_NOMORETOKENS:
347         return EDOM;            /* hack */
348     case CM_ERROR_TOOMANYBUFS:
349         return EFBIG;           /* hack */
350     default:
351         if (cm_code > 0 && cm_code < EILSEQ)
352             return cm_code;
353         else
354             return ENOTTY;
355     }
356 }
357
358 CString GetAfsError(int code, const char *filename)
359 {
360     CString strMsg;
361
362     code = CMtoUNIXerror(code);
363
364     if (code == EINVAL) {
365         if (filename)
366             strMsg.Format("Invalid argument; it is possible that the file is not in AFS");
367         else 
368             strMsg.Format("Invalid argument");
369     } else if (code == ENOENT) {
370         if (filename) 
371             strMsg.Format("The file does not exist");
372         else 
373             strMsg.Format("No such file returned");
374     } else if (code == EROFS)  {
375         strMsg.Format("You can not change a backup or readonly volume");
376     } else if (code == EACCES || code == EPERM) {
377         strMsg.Format("You do not have the required rights to do this operation");
378     } else if (code == ENODEV) {
379         strMsg.Format("AFS service may not have started");
380     } else if (code == ESRCH) {
381         strMsg.Format("Cell name not recognized");
382     } else if (code == ETIMEDOUT) {
383         strMsg.Format("Connection timed out");
384     } else if (code == EPIPE) {
385         strMsg.Format("Volume name or ID not recognized");
386     } else {
387         strMsg.Format("Error 0x%x occurred", code);
388     }
389
390     return strMsg;
391 }
392
393
394 /************************************************************************
395 ************************** ACL Code *************************************
396 ************************************************************************/
397
398 typedef char sec_rgy_name_t[1025];      /* A DCE definition */
399
400 struct AclEntry {
401     struct AclEntry *next;
402     char name[MAXNAME];
403     LONG rights;
404 };
405
406 struct Acl {
407     int dfs;                    //      Originally true if a dfs acl; now also the type
408                                 //      of the acl (1, 2, or 3, corresponding to object,
409                                 //      initial dir, or initial object).
410     sec_rgy_name_t cell;        //      DFS cell name
411     int nplus;
412     int nminus;
413     struct AclEntry *pluslist;
414     struct AclEntry *minuslist;
415 };
416
417 int foldcmp (register char *a, register char *b)
418 {
419     register char t, u;
420     while (1) {
421         t = *a++;
422         u = *b++;
423         if (t >= 'A' && t <= 'Z') t += 0x20;
424         if (u >= 'A' && u <= 'Z') u += 0x20;
425         if (t != u) return 1;
426         if (t == 0) return 0;
427     }
428 }
429
430 extern "C" void ZapList(struct AclEntry *alist)
431 {
432     register struct AclEntry *tp, *np;
433
434     for (tp = alist; tp; tp = np) {
435         np = tp->next;
436         free(tp);
437     }
438 }
439
440 extern "C" void ZapAcl (struct Acl *acl)
441 {
442     ZapList(acl->pluslist);
443     ZapList(acl->minuslist);
444     free(acl);
445 }
446
447 extern "C" int PruneList (struct AclEntry **ae, int dfs)
448 {
449     struct AclEntry **lp = ae;
450     struct AclEntry *te, *ne;
451     LONG ctr = 0;
452     
453     for (te = *ae; te; te = ne) {
454         if ((!dfs && te->rights == 0) || te->rights == -1) {
455             *lp = te->next;
456             ne = te->next;
457             free(te);
458             ctr++;
459         }
460         else {
461             ne = te->next;
462             lp = &te->next;
463         }
464     }
465     
466     return ctr;
467 }
468
469 char *SkipLine (register char *astr)
470 {
471     while (*astr != '\n') 
472         astr++;
473     
474     astr++;
475     
476     return astr;
477 }
478
479 /* tell if a name is 23 or -45 (digits or minus digits), which are bad names we must prune */
480 static int BadName(register char *aname)
481 {
482     register int tc;
483
484     /* all must be '-' or digit to be bad */
485     while (tc = *aname++) {
486         if ((tc != '-') && (tc < '0' || tc > '9')) 
487             return 0;
488     }
489
490     return 1;
491 }
492
493 CString GetRightsString(register LONG arights, int dfs)
494 {
495     CString str;
496
497     if (!dfs) {
498         if (arights & PRSFS_READ) str += "r";
499         if (arights & PRSFS_LOOKUP) str += "l";
500         if (arights & PRSFS_INSERT) str += "i";
501         if (arights & PRSFS_DELETE) str += "d";
502         if (arights & PRSFS_WRITE) str += "w";
503         if (arights & PRSFS_LOCK) str += "k";
504         if (arights & PRSFS_ADMINISTER) str += "a";
505     } else {
506         ASSERT(FALSE);
507 /*
508                 if (arights & DFS_READ) str += "r"; else str += "-";
509                 if (arights & DFS_WRITE) str += "w"; else printf("-");
510                 if (arights & DFS_EXECUTE) str += "x"; else printf("-");
511                 if (arights & DFS_CONTROL) str += "c"; else printf("-");
512                 if (arights & DFS_INSERT) str += "i"; else printf("-");
513                 if (arights & DFS_DELETE) str += "d"; else printf("-");
514                 if (arights & (DFS_USRALL)) str += "+";
515 */
516     }   
517
518     return str;
519 }
520
521 char *AclToString(struct Acl *acl)
522 {
523     static char mydata[MAXSIZE];
524     char tstring[MAXSIZE];
525     char dfsstring[30];
526     struct AclEntry *tp;
527     
528     if (acl->dfs)
529         sprintf(dfsstring, " dfs:%d %s", acl->dfs, acl->cell);
530     else
531         dfsstring[0] = '\0';
532     sprintf(mydata, "%d%s\n%d\n", acl->nplus, dfsstring, acl->nminus);
533     
534     for(tp = acl->pluslist; tp; tp = tp->next) {
535         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
536         strcat(mydata, tstring);
537     }
538     
539     for(tp = acl->minuslist; tp; tp = tp->next) {
540         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
541         strcat(mydata, tstring);
542     }
543     
544     return mydata;
545 }
546
547 struct Acl *EmptyAcl(const CString& strCellName)
548 {
549     register struct Acl *tp;
550     
551     tp = (struct Acl *)malloc(sizeof (struct Acl));
552     tp->nplus = tp->nminus = 0;
553     tp->pluslist = tp->minuslist = 0;
554     tp->dfs = 0;
555     strcpy(tp->cell, strCellName);
556
557     return tp;
558 }
559
560 struct Acl *ParseAcl(char *astr)
561 {
562     int nplus, nminus, i, trights;
563     char tname[MAXNAME];
564     struct AclEntry *first, *last, *tl;
565     struct Acl *ta;
566
567     ta = (struct Acl *) malloc (sizeof (struct Acl));
568     ta->dfs = 0;
569     sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
570     astr = SkipLine(astr);
571     sscanf(astr, "%d", &ta->nminus);
572     astr = SkipLine(astr);
573
574     nplus = ta->nplus;
575     nminus = ta->nminus;
576
577     last = 0;
578     first = 0;
579     for(i = 0; i < nplus; i++) {
580         sscanf(astr, "%100s %d", tname, &trights);
581         astr = SkipLine(astr);
582         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
583         if (!first)
584                         first = tl;
585         strcpy(tl->name, tname);
586         tl->rights = trights;
587         tl->next = 0;
588         if (last)
589                         last->next = tl;
590         last = tl;
591     }
592     ta->pluslist = first;
593
594     last = 0;
595     first = 0;
596     for(i=0; i < nminus; i++) {
597         sscanf(astr, "%100s %d", tname, &trights);
598         astr = SkipLine(astr);
599         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
600         if (!first) 
601                         first = tl;
602         strcpy(tl->name, tname);
603         tl->rights = trights;
604         tl->next = 0;
605         if (last) 
606                         last->next = tl;
607         last = tl;
608     }
609     ta->minuslist = first;
610
611     return ta;
612 }
613
614 /* clean up an access control list of its bad entries; return 1 if we made
615    any changes to the list, and 0 otherwise */
616 extern "C" int CleanAcl(struct Acl *aa)
617 {
618     register struct AclEntry *te, **le, *ne;
619     int changes;
620
621     HOURGLASS hourglass;
622
623     /* Don't correct DFS ACL's for now */
624     if (aa->dfs)
625         return 0;
626
627     /* prune out bad entries */
628     changes = 0;            /* count deleted entries */
629     le = &aa->pluslist;
630     for(te = aa->pluslist; te; te = ne) {
631         ne = te->next;
632         if (BadName(te->name)) {
633             /* zap this dude */
634             *le = te->next;
635             aa->nplus--;
636             free(te);
637             changes++;
638         }
639         else
640             le = &te->next;
641     }
642
643     le = &aa->minuslist;
644     
645     for(te = aa->minuslist; te; te = ne) {
646         ne = te->next;
647         if (BadName(te->name)) {
648             /* zap this dude */
649             *le = te->next;
650             aa->nminus--;
651             free(te);
652             changes++;
653         }
654         else
655             le = &te->next;
656     }   
657
658     return changes;
659 }
660
661 void CleanACL(CStringArray& names)
662 {
663     register LONG code;
664     register struct Acl *ta;
665     struct ViceIoctl blob;
666     int changes;
667
668     ShowMessageBox(IDS_CLEANACL_MSG, MB_OK|MB_ICONINFORMATION, IDS_CLEANACL_MSG);
669
670     HOURGLASS hourglass;
671
672     for (int i = 0; i < names.GetSize(); i++) {
673         blob.out_size = MAXSIZE;
674         blob.in_size = 0;
675         blob.out = space;
676
677         code = pioctl(PCCHAR(names[i]), VIOCGETAL, &blob, 1);
678         if (code) {
679             ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONERROR, 0, names[i], GetAfsError(errno));
680             continue;
681         }
682
683         ta = ParseAcl(space);
684         if (ta->dfs) {
685             ShowMessageBox(IDS_CLEANACL_NOT_SUPPORTED, MB_ICONERROR, IDS_CLEANACL_NOT_SUPPORTED, names[i]);
686             continue;
687         }
688
689         changes = CleanAcl(ta);
690         if (!changes)
691             continue;
692
693         /* now set the acl */
694         blob.in = AclToString(ta);
695         blob.in_size = strlen((char *)blob.in) + 1;
696         blob.out_size = 0;
697                 
698         code = pioctl(PCCHAR(names[i]), VIOCSETAL, &blob, 1);
699         if (code) {
700             if (errno == EINVAL) {
701                 ShowMessageBox(IDS_CLEANACL_INVALID_ARG, MB_ICONERROR, IDS_CLEANACL_INVALID_ARG, names[i]);
702                 continue;
703             }
704             else {
705                 ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONERROR, 0, names[i], GetAfsError(errno));
706                 continue;
707             }
708         }
709     }
710 }       
711
712 // Derived from fs.c's ListAclCmd
713 BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& strNegative)
714 {
715     register LONG code;
716     register struct Acl *ta;
717     struct ViceIoctl blob;
718     struct AclEntry *te;
719     int idf = 0; //getidf(as, parm_listacl_id);
720
721     HOURGLASS hourglass;
722
723     blob.out_size = MAXSIZE;
724     blob.in_size = idf;
725     blob.in = blob.out = space;
726         
727     code = pioctl(PCCHAR(strDir), VIOCGETAL, &blob, 1);
728     if (code) {
729         ShowMessageBox(IDS_GETRIGHTS_ERROR, MB_ICONERROR, IDS_GETRIGHTS_ERROR, strDir, GetAfsError(errno));
730         return FALSE;
731     }
732
733     ta = ParseAcl(space);
734     if (ta->dfs) {
735         ShowMessageBox(IDS_DFSACL_ERROR, MB_ICONERROR, IDS_DFSACL_ERROR);
736         return FALSE;
737     }
738
739 //      if (ta->dfs)
740 //              printf("  Default cell = %s\n", ta->cell);
741
742     CString strRight;
743
744     if (ta->nplus > 0) {
745         for (te = ta->pluslist; te; te = te->next) {
746             strNormal.Add(te->name);
747             strNormal.Add(GetRightsString(te->rights, ta->dfs));
748         }
749     }
750
751     if (ta->nminus > 0) {
752         for (te = ta->minuslist; te; te = te->next) {
753             strNegative.Add(te->name);
754             strNegative.Add(GetRightsString(te->rights, ta->dfs));
755         }
756     }
757
758     return TRUE;
759 }
760
761 struct AclEntry *FindList(register struct AclEntry *pCurEntry, const char *entryName)
762 {
763     while (pCurEntry) {
764         if (!foldcmp(pCurEntry->name, PCCHAR(entryName)))
765             return pCurEntry;
766         pCurEntry = pCurEntry->next;
767     }
768     
769     return 0;
770 }
771
772 void ChangeList (struct Acl *pAcl, BYTE bNormalRights, const char *entryName, LONG nEntryRights)
773 {
774     ASSERT(pAcl);
775     ASSERT(entryName);
776     
777     struct AclEntry *pEntry;
778
779     HOURGLASS hourglass;
780
781     pEntry = (bNormalRights ? pAcl->pluslist : pAcl->minuslist);
782     pEntry = FindList(pEntry, entryName);
783
784     /* Found the item already in the list. */
785     if (pEntry) {
786         pEntry->rights = nEntryRights;
787         if (bNormalRights)
788             pAcl->nplus -= PruneList(&pAcl->pluslist, pAcl->dfs);
789         else
790             pAcl->nminus -= PruneList(&pAcl->minuslist, pAcl->dfs);
791         return;
792     }
793
794     /* Otherwise we make a new item and plug in the new data. */
795     pEntry = (struct AclEntry *) malloc(sizeof (struct AclEntry));
796     ASSERT(pEntry);
797         
798     strcpy(pEntry->name, entryName);
799     pEntry->rights = nEntryRights;
800     
801     if (bNormalRights) {
802         pEntry->next = pAcl->pluslist;
803         pAcl->pluslist = pEntry;
804         pAcl->nplus++;
805         if (nEntryRights == 0 || nEntryRights == -1)
806             pAcl->nplus -= PruneList(&pAcl->pluslist, pAcl->dfs);
807     }
808     else {
809         pEntry->next = pAcl->minuslist;
810         pAcl->minuslist = pEntry;
811         pAcl->nminus++;
812         if (nEntryRights == 0)
813             pAcl->nminus -= PruneList(&pAcl->minuslist, pAcl->dfs);
814     }
815 }
816
817 enum rtype {add, destroy, deny};
818
819 LONG Convert(const register char *arights, int dfs, enum rtype *rtypep)
820 {
821     register int i, len;
822     LONG mode;
823     register char tc;
824
825     *rtypep = add;      /* add rights, by default */
826
827     if (!strcmp(arights,"read")) 
828         return PRSFS_READ | PRSFS_LOOKUP;
829     if (!strcmp(arights, "write")) 
830         return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK;
831     if (!strcmp(arights, "mail")) 
832         return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
833     if (!strcmp(arights, "all")) 
834         return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
835     
836     if (!strcmp(arights, "none")) {
837         *rtypep = destroy; /* Remove entire entry */
838         return 0;
839     }
840
841     len = strlen(arights);
842     mode = 0;
843
844     for (i = 0; i < len; i++) {
845         tc = *arights++;
846         if (tc == 'r') mode |= PRSFS_READ;
847         else if (tc == 'l') mode |= PRSFS_LOOKUP;
848         else if (tc == 'i') mode |= PRSFS_INSERT;
849         else if (tc == 'd') mode |= PRSFS_DELETE;
850         else if (tc == 'w') mode |= PRSFS_WRITE;
851         else if (tc == 'k') mode |= PRSFS_LOCK;
852         else if (tc == 'a') mode |= PRSFS_ADMINISTER;
853         else {
854             fprintf(stderr, "illegal rights character '%c'.\n", tc);
855             exit(1);
856         }
857     }   
858     return mode;
859 }
860
861 BOOL SaveACL(const CString& strCellName, const CString& strDir, const CStringArray& normal, const CStringArray& negative)
862 {
863     register LONG code;
864     struct ViceIoctl blob;
865     struct Acl *pAcl;
866     LONG rights;
867     enum rtype rtype;
868
869     HOURGLASS hourglass;
870
871     // Create a new ACL
872     pAcl = EmptyAcl(strCellName);
873
874     // Set its normal rights
875     int i;
876     for (i = 0; i < normal.GetSize(); i += 2) {
877         rights = Convert(normal[i + 1], 0, &rtype);
878         ChangeList(pAcl, TRUE, normal[i], rights);
879     }
880
881     // Set its negative rights
882     for (i = 0; i < negative.GetSize(); i += 2) {
883         rights = Convert(negative[i + 1], 0, &rtype);
884         ChangeList(pAcl, FALSE, negative[i], rights);
885     }
886
887     // Write the ACL
888     blob.in = AclToString(pAcl);
889     blob.out_size = 0;
890     blob.in_size = 1 + strlen((const char *)blob.in);
891
892     code = pioctl(PCCHAR(strDir), VIOCSETAL, &blob, 1);
893     if (code) {
894         if (errno == EINVAL)
895             ShowMessageBox(IDS_SAVE_ACL_EINVAL_ERROR, MB_ICONERROR, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
896         else
897             ShowMessageBox(IDS_SAVE_ACL_ERROR, MB_ICONERROR, IDS_SAVE_ACL_ERROR, strDir, GetAfsError(errno, strDir));
898     }       
899
900     ZapAcl(pAcl);
901
902     return (code == 0);
903 }
904
905 BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringArray& negative, BOOL bClear)
906 {
907     register LONG code;
908     struct ViceIoctl blob;
909     struct Acl *pToAcl;
910     int idf = 0; // getidf(as, parm_copyacl_id);
911
912     HOURGLASS hourglass;
913
914     // Get ACL to copy to
915     blob.out_size = MAXSIZE;
916     blob.in_size = idf;
917     blob.in = blob.out = space;
918         
919     code = pioctl(PCCHAR(strToDir), VIOCGETAL, &blob, 1);
920     if (code) {
921         ShowMessageBox(IDS_ACL_READ_ERROR, MB_ICONERROR, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
922         return FALSE;
923     }
924         
925     if (bClear) 
926         pToAcl = EmptyAcl(space);
927     else 
928         pToAcl = ParseAcl(space);
929
930     CleanAcl(pToAcl);
931
932     if (pToAcl->dfs) {
933         ShowMessageBox(IDS_NO_DFS_COPY_ACL, MB_ICONERROR, IDS_NO_DFS_COPY_ACL, strToDir);
934         ZapAcl(pToAcl);
935         return FALSE;
936     }
937
938     enum rtype rtype;
939
940     // Set normal rights
941     int i;
942     for (i = 0; i < normal.GetSize(); i += 2) {
943         LONG rights = Convert(normal[i + 1], 0, &rtype);
944         ChangeList(pToAcl, TRUE, normal[i], rights);
945     }
946
947     // Set negative rights
948     for (i = 0; i < negative.GetSize(); i += 2) {
949         LONG rights = Convert(negative[i + 1], 0, &rtype);
950         ChangeList(pToAcl, FALSE, normal[i], rights);
951     }
952
953     // Save modified ACL
954     blob.in = AclToString(pToAcl);
955     blob.out_size = 0;
956     blob.in_size = 1 + strlen((char *)blob.in);
957
958     code = pioctl(PCCHAR(strToDir), VIOCSETAL, &blob, 1);
959     if (code) {
960         ZapAcl(pToAcl);
961         if (errno == EINVAL)
962             ShowMessageBox(IDS_COPY_ACL_EINVAL_ERROR, MB_ICONERROR, IDS_COPY_ACL_EINVAL_ERROR, strToDir);
963         else 
964             ShowMessageBox(IDS_COPY_ACL_ERROR, MB_ICONERROR, IDS_COPY_ACL_ERROR, strToDir, GetAfsError(errno, strToDir));
965         return FALSE;
966     }
967
968     ZapAcl(pToAcl);
969
970     ShowMessageBox(IDS_COPY_ACL_OK, MB_OK|MB_ICONINFORMATION, IDS_COPY_ACL_OK);
971
972     return TRUE;
973 }
974
975 CString ParseMountPoint(const CString strFile, CString strMountPoint)
976 {
977     CString strType;
978     CString strVolume;
979     CString strCell;
980     CString strMountPointInfo;
981
982     if (strMountPoint[0] == '#')
983         strType = "Regular";
984     else if (strMountPoint[0] == '%')
985         strType = "Read/Write";
986
987     int nColon = strMountPoint.Find(':');
988     if (nColon >= 0) {
989         strCell = strMountPoint.Mid(1, nColon - 1);
990         strVolume = strMountPoint.Mid(nColon + 1);
991     } else
992         strVolume = strMountPoint.Mid(1);
993
994     strMountPointInfo = strFile + "\t" + strVolume + "\t" + strCell + "\t" + strType;
995
996     return strMountPointInfo;
997 }       
998
999 CString ParseSymlink(const CString strFile, CString strSymlink)
1000 {
1001     CString strSymlinkInfo;
1002
1003     strSymlinkInfo = strFile + "\t" + strSymlink;
1004
1005     return strSymlinkInfo;
1006 }       
1007
1008 BOOL IsPathInAfs(const CHAR *strPath)
1009 {
1010     struct ViceIoctl blob;
1011     int code;
1012
1013     HOURGLASS hourglass;
1014
1015     char buf[512];
1016     sprintf(buf, "IsPathInAfs(%s)", strPath);
1017     OutputDebugString(buf);
1018
1019     blob.in_size = 0;
1020     blob.out_size = MAXSIZE;
1021     blob.out = space;
1022
1023     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1024
1025     sprintf(buf, "VIOC_FILE_CELL_NAME=%d", code);
1026     OutputDebugString(buf);
1027
1028     if (code) {
1029         if ((errno == EINVAL) || (errno == ENOENT))
1030         return FALSE;
1031     }
1032     return TRUE;
1033 }
1034
1035 static int 
1036 IsFreelanceRoot(char *apath)
1037 {
1038     struct ViceIoctl blob;
1039     afs_int32 code;
1040
1041     blob.in_size = 0;
1042     blob.out_size = MAXSIZE;
1043     blob.out = space;
1044
1045     code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
1046     if (code == 0)
1047         return !strcmp("Freelance.Local.Root",space);
1048     return 1;   /* assume it is because it is more restrictive that way */
1049 }
1050
1051 const char * NetbiosName(void)
1052 {
1053     static char buffer[1024] = "AFS";
1054     HKEY  parmKey;
1055     DWORD code;
1056     DWORD dummyLen;
1057     DWORD enabled = 0;
1058
1059     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1060                          0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
1061     if (code == ERROR_SUCCESS) {
1062         dummyLen = sizeof(buffer);
1063         code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
1064                                (LPBYTE)buffer, &dummyLen);
1065         RegCloseKey (parmKey);
1066     } else {
1067         strcpy(buffer, "AFS");
1068     }
1069     return buffer;
1070 }
1071
1072 #define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
1073
1074 static BOOL IsAdmin (void)
1075 {
1076     static BOOL fAdmin = FALSE;
1077     static BOOL fTested = FALSE;
1078
1079     if (!fTested)
1080     {
1081         /* Obtain the SID for the AFS client admin group.  If the group does
1082          * not exist, then assume we have AFS client admin privileges.
1083          */
1084         PSID psidAdmin = NULL;
1085         DWORD dwSize, dwSize2;
1086         char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
1087         char *pszRefDomain = NULL;
1088         SID_NAME_USE snu = SidTypeGroup;
1089
1090         dwSize = sizeof(pszAdminGroup);
1091
1092         if (!GetComputerName(pszAdminGroup, &dwSize)) {
1093             /* Can't get computer name.  We return false in this case.
1094                Retain fAdmin and fTested. This shouldn't happen.*/
1095             return FALSE;
1096         }
1097
1098         dwSize = 0;
1099         dwSize2 = 0;
1100
1101         strcat(pszAdminGroup,"\\");
1102         strcat(pszAdminGroup, AFSCLIENT_ADMIN_GROUPNAME);
1103
1104         LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
1105         /* that should always fail. */
1106
1107         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1108             /* if we can't find the group, then we allow the operation */
1109             fAdmin = TRUE;
1110             return TRUE;
1111         }
1112
1113         if (dwSize == 0 || dwSize2 == 0) {
1114             /* Paranoia */
1115             fAdmin = TRUE;
1116             return TRUE;
1117         }
1118
1119         psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
1120         pszRefDomain = (char *)malloc(dwSize2);
1121
1122         if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
1123             /* We can't lookup the group now even though we looked it up earlier.  
1124                Could this happen? */
1125             fAdmin = TRUE;
1126         } else {
1127             /* Then open our current ProcessToken */
1128             HANDLE hToken;
1129
1130             if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
1131             {
1132
1133                 if (!CheckTokenMembership(hToken, psidAdmin, &fAdmin)) {
1134                     /* We'll have to allocate a chunk of memory to store the list of
1135                      * groups to which this user belongs; find out how much memory
1136                      * we'll need.
1137                      */
1138                     DWORD dwSize = 0;
1139                     PTOKEN_GROUPS pGroups;
1140
1141                     GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
1142
1143                     pGroups = (PTOKEN_GROUPS)malloc(dwSize);
1144
1145                     /* Allocate that buffer, and read in the list of groups. */
1146                     if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
1147                     {
1148                         /* Look through the list of group SIDs and see if any of them
1149                          * matches the AFS Client Admin group SID.
1150                          */
1151                         size_t iGroup = 0;
1152                         for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
1153                         {
1154                             if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
1155                                 fAdmin = TRUE;
1156                             }
1157                         }
1158                     }
1159
1160                     if (pGroups)
1161                         free(pGroups);
1162                 }
1163
1164                 /* if do not have permission because we were not explicitly listed
1165                  * in the Admin Client Group let's see if we are the SYSTEM account
1166                  */
1167                 if (!fAdmin) {
1168                     PTOKEN_USER pTokenUser;
1169                     SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
1170                     PSID pSidLocalSystem = 0;
1171                     DWORD gle;
1172
1173                     GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
1174
1175                     pTokenUser = (PTOKEN_USER)malloc(dwSize);
1176
1177                     if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
1178                         gle = GetLastError();
1179
1180                     if (AllocateAndInitializeSid( &SIDAuth, 1,
1181                                                   SECURITY_LOCAL_SYSTEM_RID,
1182                                                   0, 0, 0, 0, 0, 0, 0,
1183                                                   &pSidLocalSystem))
1184                     {
1185                         if (EqualSid(pTokenUser->User.Sid, pSidLocalSystem)) {
1186                             fAdmin = TRUE;
1187                         }
1188
1189                         FreeSid(pSidLocalSystem);
1190                     }
1191
1192                     if ( pTokenUser )
1193                         free(pTokenUser);
1194                 }
1195             }
1196         }
1197
1198         free(psidAdmin);
1199         free(pszRefDomain);
1200
1201         fTested = TRUE;
1202     }
1203
1204     return fAdmin;
1205 }
1206
1207 /* return a static pointer to a buffer */
1208 static char *Parent(char *apath)
1209 {
1210     register char *tp;
1211
1212     strcpy(tspace, apath);
1213     tp = strrchr(tspace, '\\');
1214     if (tp) {
1215         *(tp+1) = 0;    /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
1216     }
1217     else {
1218         fs_ExtractDriveLetter(apath, tspace);
1219         strcat(tspace, ".");
1220     }
1221     
1222     return tspace;
1223 }
1224
1225 static afs_int32
1226 GetCell(char *fname, char *cellname)
1227 {
1228     afs_int32 code;
1229     struct ViceIoctl blob;
1230
1231     blob.in_size = 0;
1232     blob.out_size = MAXCELLCHARS;
1233     blob.out = cellname;
1234
1235     code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1);
1236     return code ? errno : 0;
1237 }
1238
1239
1240 BOOL ListMount(CStringArray& files)
1241 {
1242     register LONG code;
1243     struct ViceIoctl blob;
1244     int error;
1245     char orig_name[1024];                       /* Original name, may be modified */
1246     char true_name[1024];                       /* ``True'' dirname (e.g., symlink target) */
1247     char parent_dir[1024];                      /* Parent directory of true name */
1248     register char *last_component;      /* Last component of true name */
1249     CStringArray mountPoints;
1250     
1251     HOURGLASS hourglass;
1252
1253     error = 0;
1254
1255     for (int i = 0; i < files.GetSize(); i++) {
1256         strcpy(orig_name, files[i]);
1257         strcpy(true_name, orig_name);
1258
1259         /*
1260          * Find rightmost slash, if any.
1261          */
1262         last_component = (char *)strrchr(true_name, '\\');
1263         if (last_component) {
1264             /*
1265              * Found it.  Designate everything before it as the parent directory,
1266              * everything after it as the final component.
1267              */
1268             strncpy(parent_dir, true_name, last_component - true_name + 1);
1269             parent_dir[last_component - true_name + 1] = 0;
1270             last_component++;   /* Skip the slash */
1271
1272             if (!IsPathInAfs(parent_dir)) {
1273                 const char * nbname = NetbiosName();
1274                 int len = strlen(nbname);
1275
1276                 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
1277                     parent_dir[len+2] == '\\' &&
1278                     parent_dir[len+3] == '\0' &&
1279                     !strnicmp(nbname,&parent_dir[2],len))
1280                 {
1281                     sprintf(parent_dir,"\\\\%s\\all\\", nbname);
1282                 }
1283             }
1284         }
1285         else {
1286             /*
1287              * No slash appears in the given file name.  Set parent_dir to the current
1288              * directory, and the last component as the given name.
1289              */
1290             fs_ExtractDriveLetter(true_name, parent_dir);
1291             strcat(parent_dir, ".");
1292             last_component = true_name;
1293             fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
1294         }
1295
1296         blob.in = last_component;
1297         blob.in_size = strlen(last_component) + 1;
1298         blob.out_size = MAXSIZE;
1299         blob.out = space;
1300         memset(space, 0, MAXSIZE);
1301
1302         code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
1303         if (code == 0) {
1304             int nPos = strlen(space) - 1;
1305             if (space[nPos] == '.')
1306                 space[nPos] = 0;
1307             mountPoints.Add(ParseMountPoint(StripPath(files[i]), space));
1308         } else {
1309             error = 1;
1310             if (errno == EINVAL)
1311                 mountPoints.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
1312             else
1313                 mountPoints.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
1314         }
1315     }
1316
1317     CMountPointsDlg dlg;
1318     dlg.SetMountPoints(mountPoints);
1319     dlg.DoModal();
1320
1321     return !error;
1322 }
1323
1324 BOOL MakeMount(const CString& strDir, const CString& strVolName, const CString& strCellName, BOOL bRW)
1325 {
1326     register LONG code;
1327     register char *cellName;
1328     char localCellName[128];
1329     struct afsconf_cell info;
1330 #if 0
1331     struct vldbentry vldbEntry;
1332 #endif
1333     struct ViceIoctl blob;
1334     char * parent;
1335     char path[1024] = "";
1336
1337     HOURGLASS hourglass;
1338
1339     ASSERT(strVolName.GetLength() < 64);
1340
1341     if (strCellName.GetLength() > 0)    /* cell name specified */
1342         cellName = PCCHAR(strCellName);
1343     else
1344         cellName = (char *) 0;
1345
1346     parent = Parent(PCCHAR(strDir));
1347     if (!IsPathInAfs(parent)) {
1348         const char * nbname = NetbiosName();
1349         int len = strlen(nbname);
1350
1351         if (parent[0] == '\\' && parent[1] == '\\' &&
1352             parent[len+2] == '\\' &&
1353             parent[len+3] == '\0' &&
1354             !strnicmp(nbname,&parent[2],len))
1355         {
1356             sprintf(path,"%sall\\%s", parent, &(PCCHAR(strDir)[strlen(parent)]));
1357             parent = Parent(path);
1358             if (!IsPathInAfs(parent)) {
1359                 ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONERROR, IDS_MAKE_MP_NOT_AFS_ERROR);
1360                 return FALSE;
1361             }
1362         } else {
1363             ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONERROR, IDS_MAKE_MP_NOT_AFS_ERROR);
1364             return FALSE;
1365         }
1366     }
1367
1368     if ( strlen(path) == 0 )
1369         strcpy(path, PCCHAR(strDir));
1370
1371     if ( IsFreelanceRoot(parent) ) {
1372         if ( !IsAdmin() ) {
1373             ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
1374             return FALSE;
1375         }
1376
1377         if (!cellName) {
1378             blob.in_size = 0;
1379             blob.out_size = sizeof(localCellName);
1380             blob.out = localCellName;
1381             code = pioctl(parent, VIOC_GET_WS_CELL, &blob, 1);
1382             if (!code)
1383                 cellName = localCellName;
1384         }
1385     } else {
1386         if (!cellName)
1387             GetCell(parent,space);
1388     }
1389
1390     code = GetCellName(cellName?cellName:space, &info);
1391     if (code) {
1392         return FALSE;
1393     }
1394
1395 #if 0
1396     code = VLDBInit(1, &info);
1397     if (code == 0) {
1398         /* make the check.  Don't complain if there are problems with init */
1399         code = ubik_VL_GetEntryByNameO(uclient, 0, PCCHAR(strVolName), &vldbEntry);
1400         if (code == VL_NOENT) {
1401             ShowMessageBox(IDS_WARNING, MB_ICONWARNING, IDS_VOLUME_NOT_IN_CELL_WARNING, 
1402                             PCCHAR(strVolName), cellName ? cellName : space);
1403         }
1404     }
1405     if (rxInitDone) 
1406         rx_Finalize();
1407 #endif
1408
1409     if (bRW)    /* if -rw specified */
1410         strcpy(space, "%");
1411     else
1412         strcpy(space, "#");
1413
1414     /* If cellular mount point, prepend cell prefix */
1415     if (cellName) {
1416         strcat(space, info.name);
1417         strcat(space, ":");
1418     }   
1419
1420     strcat(space, strVolName);  /* append volume name */
1421     strcat(space, ".");         /* stupid convention; these end with a period */
1422
1423     /* create symlink with a special pioctl for Windows NT, since it doesn't
1424      * have a symlink system call.
1425      */
1426     blob.out_size = 0;
1427     blob.in_size = 1 + strlen(space);
1428     blob.in = space;
1429     blob.out = NULL;
1430     code = pioctl(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
1431
1432     if (code) {
1433         ShowMessageBox(IDS_MOUNT_POINT_ERROR, MB_ICONERROR, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
1434         return FALSE;
1435     }
1436     
1437     return TRUE;
1438 }
1439
1440 /*
1441 */
1442 long fs_ExtractDriveLetter(const char *inPathp, char *outPathp)
1443 {
1444     if (inPathp[0] != 0 && inPathp[1] == ':') {
1445         /* there is a drive letter */
1446         *outPathp++ = *inPathp++;
1447         *outPathp++ = *inPathp++;
1448         *outPathp++ = 0;
1449     }
1450     else *outPathp = 0;
1451
1452     return 0;
1453 }       
1454
1455 /* strip the drive letter from a component */
1456 long fs_StripDriveLetter(const char *inPathp, char *outPathp, long outSize)
1457 {
1458     char tempBuffer[1000];
1459     strcpy(tempBuffer, inPathp);
1460     if (tempBuffer[0] != 0 && tempBuffer[1] == ':') {
1461         /* drive letter present */
1462         strcpy(outPathp, tempBuffer+2);
1463     }
1464     else {
1465         /* no drive letter present */
1466         strcpy(outPathp, tempBuffer);
1467     }
1468     return 0;
1469 }       
1470
1471
1472 BOOL RemoveSymlink(const char * linkName)
1473 {
1474     BOOL error = FALSE;
1475     INT code=0;
1476     struct ViceIoctl blob;
1477     char tbuffer[1024];
1478     char lsbuffer[1024];
1479     char tpbuffer[1024];
1480     char *tp;
1481     
1482     HOURGLASS hourglass;
1483
1484     tp = (char *) strrchr(linkName, '\\');
1485     if (!tp)
1486         tp = (char *) strrchr(linkName, '/');
1487     if (tp) {
1488         strncpy(tbuffer, linkName, code=tp-linkName+1);  /* the dir name */
1489         tbuffer[code] = 0;
1490         tp++;   /* skip the slash */
1491
1492         if (!IsPathInAfs(tbuffer)) {
1493             const char * nbname = NetbiosName();
1494             int len = strlen(nbname);
1495
1496             if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1497                  tbuffer[len+2] == '\\' &&
1498                  tbuffer[len+3] == '\0' &&
1499                  !strnicmp(nbname,&tbuffer[2],len))
1500             {
1501                 sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1502             }
1503         }
1504     }
1505     else {
1506         fs_ExtractDriveLetter(linkName, tbuffer);
1507         strcat(tbuffer, ".");
1508         fs_StripDriveLetter(tp, tpbuffer, 0);
1509         tp=tpbuffer;
1510     }
1511
1512     if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
1513         ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
1514         return FALSE;
1515     }
1516
1517     blob.in = tp;
1518     blob.in_size = strlen(tp)+1;
1519     blob.out = lsbuffer;
1520     blob.out_size = sizeof(lsbuffer);
1521     code = pioctl(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
1522     if (code)
1523         return FALSE;
1524     blob.out_size = 0;
1525     blob.in = tp;
1526     blob.in_size = strlen(tp)+1;
1527     return (pioctl(tbuffer, VIOC_DELSYMLINK, &blob, 0)==0);
1528 }       
1529
1530 BOOL IsSymlink(const char * true_name)
1531 {
1532     char parent_dir[MAXSIZE];           /*Parent directory of true name*/
1533     char strip_name[MAXSIZE];
1534     struct ViceIoctl blob;
1535     char *last_component;
1536     int code;
1537
1538     HOURGLASS hourglass;
1539
1540     char buf[512];
1541     sprintf(buf, "IsSymlink(%s)", true_name);
1542     OutputDebugString(buf);
1543
1544     last_component = (char *) strrchr(true_name, '\\');
1545     if (!last_component)
1546         last_component = (char *) strrchr(true_name, '/');
1547     if (last_component) {
1548         /*
1549          * Found it.  Designate everything before it as the parent directory,
1550          * everything after it as the final component.
1551          */
1552         strncpy(parent_dir, true_name, last_component - true_name + 1);
1553         parent_dir[last_component - true_name + 1] = 0;
1554         last_component++;   /*Skip the slash*/
1555
1556         if (!IsPathInAfs(parent_dir)) {
1557             const char * nbname = NetbiosName();
1558             int len = strlen(nbname);
1559
1560             if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
1561                  parent_dir[len+2] == '\\' &&
1562                  parent_dir[len+3] == '\0' &&
1563                  !strnicmp(nbname,&parent_dir[2],len))
1564             {
1565                 sprintf(parent_dir,"\\\\%s\\all\\", nbname);
1566             }
1567         }
1568     }
1569     else {
1570         /*
1571          * No slash appears in the given file name.  Set parent_dir to the current
1572          * directory, and the last component as the given name.
1573          */
1574         fs_ExtractDriveLetter(true_name, parent_dir);
1575         strcat(parent_dir, ".");
1576         last_component = strip_name;
1577         fs_StripDriveLetter(true_name, strip_name, sizeof(strip_name));
1578     }
1579
1580     sprintf(buf, "last_component=%s", last_component);
1581     OutputDebugString(buf);
1582
1583     blob.in = last_component;
1584     blob.in_size = strlen(last_component)+1;
1585     blob.out_size = MAXSIZE;
1586     blob.out = space;
1587     memset(space, 0, MAXSIZE);
1588     code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
1589     return (code==0);
1590 }       
1591
1592
1593 BOOL IsMountPoint(const char * name)
1594 {
1595     register LONG code = 0;
1596     struct ViceIoctl blob;
1597     char tbuffer[1024];
1598     char lsbuffer[1024];
1599     register char *tp;
1600     char szCurItem[1024];
1601
1602     HOURGLASS hourglass;
1603
1604     strcpy(szCurItem, name);
1605         
1606     char buf[512];
1607     sprintf(buf, "IsMountPoint(%s)", name);
1608     OutputDebugString(buf);
1609
1610     tp = (char *)strrchr(szCurItem, '\\');
1611     if (tp) {
1612         strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
1613         tbuffer[code] = 0;
1614         tp++;   /* skip the slash */
1615
1616         if (!IsPathInAfs(tbuffer)) {
1617             const char * nbname = NetbiosName();
1618             int len = strlen(nbname);
1619
1620             if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1621                  tbuffer[len+2] == '\\' &&
1622                  tbuffer[len+3] == '\0' &&
1623                  !strnicmp(nbname,&tbuffer[2],len))
1624             {
1625                 sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1626             }
1627         }
1628     } else {
1629         fs_ExtractDriveLetter(szCurItem, tbuffer);
1630         strcat(tbuffer, ".");
1631         tp = szCurItem;
1632         fs_StripDriveLetter(tp, tp, 0);
1633     }
1634
1635     sprintf(buf, "last_component=%s", tp);
1636     OutputDebugString(buf);
1637
1638     blob.in = tp;
1639     blob.in_size = strlen(tp)+1;
1640     blob.out = lsbuffer;
1641     blob.out_size = sizeof(lsbuffer);
1642
1643     code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
1644
1645     return (code==0);
1646 }       
1647
1648
1649 /*
1650  * Delete AFS mount points.  Variables are used as follows:
1651  *       tbuffer: Set to point to the null-terminated directory name of the mount point
1652  *          (or ``.'' if none is provided)
1653  *      tp: Set to point to the actual name of the mount point to nuke.
1654  */
1655 BOOL RemoveMount(CStringArray& files)
1656 {
1657     register LONG code = 0;
1658     struct ViceIoctl blob;
1659     char tbuffer[1024];
1660     register char *tp;
1661     char szCurItem[1024];
1662     BOOL error = FALSE;
1663     CStringArray results;
1664     CString str;
1665     CString str2;
1666
1667     HOURGLASS hourglass;
1668
1669     for (int i = 0; i < files.GetSize(); i++) {
1670         if (!IsMountPoint(files[i])) {
1671             error = TRUE;
1672             if (errno == EINVAL)
1673                 results.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
1674             else
1675                 results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
1676             continue;   // don't bother trying
1677         }
1678
1679         strcpy(szCurItem, files[i]);
1680         
1681         tp = (char *)strrchr(szCurItem, '\\');
1682         if (tp) {
1683             strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
1684             tbuffer[code] = 0;
1685             tp++;   /* skip the slash */
1686
1687             if (!IsPathInAfs(tbuffer)) {
1688                 const char * nbname = NetbiosName();
1689                 int len = strlen(nbname);
1690
1691                 if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1692                     tbuffer[len+2] == '\\' &&
1693                     tbuffer[len+3] == '\0' &&
1694                     !strnicmp(nbname,&tbuffer[2],len))
1695                 {
1696                     sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1697                 }
1698             }
1699         } else {
1700             fs_ExtractDriveLetter(szCurItem, tbuffer);
1701             strcat(tbuffer, ".");
1702             tp = szCurItem;
1703             fs_StripDriveLetter(tp, tp, 0);
1704         }
1705
1706         if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
1707             results.Add(GetMessageString(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, StripPath(files[i])));
1708             error = TRUE;
1709             continue;   /* skip */
1710         }
1711
1712         blob.out_size = 0;
1713         blob.in = tp;
1714         blob.in_size = strlen(tp)+1;
1715
1716         code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
1717         if (code) {
1718             error = TRUE;
1719             results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
1720         } else
1721             results.Add(GetMessageString(IDS_DELETED));
1722     }   
1723
1724     LoadString (str, IDS_REMOVE_MP);
1725     LoadString (str2, IDS_REMOVE_MP_COLUMN);
1726     CResultsDlg dlg(REMOVE_MOUNT_POINTS_HELP_ID);
1727     dlg.SetContents(str, str2, StripPath(files), results);
1728     dlg.DoModal();
1729
1730     return !error;
1731 }
1732
1733 BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
1734 {
1735     register LONG code;
1736     struct ViceIoctl blob;
1737     struct VolumeStatus *status;
1738     char *name;
1739
1740     HOURGLASS hourglass;
1741
1742     volInfo.m_strFilePath = strFile;
1743     volInfo.m_strFileName = StripPath(strFile);
1744
1745     /*
1746         volInfo.m_strName = "VolumeName";
1747         volInfo.m_nID = 10;
1748         volInfo.m_nQuota = 20 * 1024 * 1024;
1749         volInfo.m_nNewQuota = volInfo.m_nQuota;
1750         volInfo.m_nUsed = volInfo.m_nQuota / 2;
1751         volInfo.m_nPartSize = 50 * 1024 * 1024;
1752         volInfo.m_nPartFree = 30 * 1024 * 1024;
1753         volInfo.m_nDup = -1;
1754         return TRUE;
1755      */
1756
1757     blob.out_size = MAXSIZE;
1758     blob.in_size = 0;
1759     blob.out = space;
1760
1761     code = pioctl(PCCHAR(strFile), VIOCGETVOLSTAT, &blob, 1);
1762     if (code) {
1763         volInfo.m_strErrorMsg = GetAfsError(errno, strFile);
1764         return FALSE;
1765     }
1766
1767     status = (VolumeStatus *)space;
1768     name = (char *)status + sizeof(*status);
1769
1770     volInfo.m_strName = name;
1771     volInfo.m_nID = status->Vid;
1772     volInfo.m_nQuota = status->MaxQuota;
1773     volInfo.m_nNewQuota = status->MaxQuota;
1774     volInfo.m_nUsed = status->BlocksInUse;
1775     volInfo.m_nPartSize = status->PartMaxBlocks;
1776     volInfo.m_nPartFree = status->PartBlocksAvail;
1777     volInfo.m_nDup = -1;
1778
1779     return TRUE;
1780 }
1781         
1782 BOOL SetVolInfo(CVolInfo& volInfo)
1783 {
1784     register LONG code;
1785     struct ViceIoctl blob;
1786     struct VolumeStatus *status;
1787     char *input;
1788
1789     HOURGLASS hourglass;
1790
1791     blob.out_size = MAXSIZE;
1792     blob.in_size = sizeof(*status) + 3; /* for the three terminating nulls */
1793     blob.out = space;
1794     blob.in = space;
1795
1796     status = (VolumeStatus *)space;
1797     status->MinQuota = -1;
1798     status->MaxQuota = volInfo.m_nNewQuota;
1799         
1800     input = (char *)status + sizeof(*status);
1801     *(input++) = '\0';  /* never set name: this call doesn't change vldb */
1802     *(input++) = '\0';  // No offmsg
1803     *(input++) = '\0';  // No motd
1804
1805 #ifdef LOGGING_ON
1806     FILE *fp = OpenFile(szLogFileName, "a");
1807     if (fp) {
1808         fprintf(fp, "\nSetVolInfo() pioctl parms:\n");
1809         fprintf(fp, "\tpathp = %s\n\topcode = VIOCSETVOLSTAT (%d)\n\tblobp = %ld\n", PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob);
1810         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);
1811         fprintf(fp, "\t\t\tstatus->MinQuota = %ld\n", status->MinQuota);
1812         fprintf(fp, "\t\t\tstatus->MaxQuota = %ld\n", status->MaxQuota);
1813         fprintf(fp, "\t\t\tOther status fields aren't set\n");
1814         fprintf(fp, "\t\t\t3 nulls follow the VolumeStatus structure.\n");
1815         fprintf(fp, "\tfollow = 1\n");
1816         fclose(fp);             
1817     }
1818 #endif
1819
1820     code = pioctl(PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob, 1);
1821     if (code) {
1822         ShowMessageBox(IDS_SET_QUOTA_ERROR, MB_ICONERROR, IDS_SET_QUOTA_ERROR, GetAfsError(errno, volInfo.m_strName));
1823         return FALSE;
1824     }
1825
1826     return TRUE;
1827 }
1828
1829 int GetCellName(char *cellNamep, struct afsconf_cell *infop)
1830 {
1831     strcpy(infop->name, cellNamep);
1832     return 0;
1833 }
1834
1835 BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bFast)
1836 {
1837     register LONG code;
1838     struct ViceIoctl blob;
1839     register LONG j;
1840     LONG temp = 0;
1841     struct afsconf_cell info;
1842     struct chservinfo checkserv;
1843
1844     HOURGLASS hourglass;
1845
1846     memset(&checkserv, 0, sizeof(struct chservinfo));
1847     blob.in_size = sizeof(struct chservinfo);
1848     blob.in = (caddr_t)&checkserv;
1849
1850     blob.out_size = MAXSIZE;
1851     blob.out = space;
1852     memset(space, 0, sizeof(afs_int32));        /* so we assure zero when nothing is copied back */
1853
1854     if (nCellsToCheck == SPECIFIC_CELL) {
1855         temp = 2;
1856         GetCellName(PCCHAR(strCellName), &info);
1857         strcpy(checkserv.tbuffer,info.name);
1858         checkserv.tsize = strlen(info.name) + 1;
1859     } else {
1860         if (nCellsToCheck != ALL_CELLS)
1861             temp = 2;
1862         strcpy(checkserv.tbuffer, "\0");
1863         checkserv.tsize = 0;
1864     }
1865     if (bFast)
1866         temp |= 1;      /* set fast flag */
1867     
1868     checkserv.magic = 0x12345678;       /* XXX */
1869     checkserv.tflags = temp;
1870     checkserv.tinterval = -1;   /* don't change current interval */
1871
1872     code = pioctl(0, VIOCCKSERV, &blob, 1);
1873     if (code) {
1874         ShowMessageBox(IDS_CHECK_SERVERS_ERROR, MB_ICONERROR, IDS_CHECK_SERVERS_ERROR, GetAfsError(errno, CString()));
1875         return FALSE;
1876     }
1877
1878     memcpy(&temp, space, sizeof(LONG));
1879
1880     if (temp == 0) {
1881         ShowMessageBox(IDS_ALL_SERVERS_RUNNING, MB_OK|MB_ICONINFORMATION, IDS_ALL_SERVERS_RUNNING);
1882         return TRUE;
1883     }
1884
1885     CStringArray servers;
1886     for (j = 0; j < MAXHOSTS; j++) {
1887         memcpy(&temp, space + j * sizeof(LONG), sizeof(LONG));
1888         if (temp == 0)
1889             break;
1890
1891         char *name = hostutil_GetNameByINet(temp);
1892         servers.Add(name);
1893     }
1894
1895     CDownServersDlg dlg;
1896     dlg.SetServerNames(servers);
1897     dlg.DoModal();
1898
1899     return TRUE;
1900 }       
1901
1902 BOOL GetTokenInfo(CStringArray& tokenInfo)
1903 {
1904     int cellNum;
1905     int rc;
1906     time_t current_time;
1907     time_t tokenExpireTime;
1908     char *expireString;
1909     char userName[100];
1910 //      char s[100];
1911     struct ktc_principal serviceName, clientName;
1912     struct ktc_token token;
1913
1914     CString strTokenInfo;
1915     CString strUserName;
1916     CString strCellName;
1917     CString strExpir;
1918
1919 //      tokenInfo.Add("");
1920 //      return TRUE;
1921
1922
1923     HOURGLASS hourglass;
1924
1925 //      printf("\nTokens held by the Cache Manager:\n\n");
1926     cellNum = 0;
1927     current_time = time(0);
1928
1929     while (1) {
1930         rc = ktc_ListTokens(cellNum, &cellNum, &serviceName);
1931         if (rc == KTC_NOENT) {
1932             /* end of list */
1933 //          printf("   --End of list --\n");
1934             break;
1935         }
1936         else if (rc == KTC_NOCM) {
1937             ShowMessageBox(IDS_GET_TOKENS_NO_AFS_SERVICE);
1938 //          printf("AFS service may not have started\n");
1939             break;
1940         }
1941         else if (rc) {
1942             ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR, MB_ICONERROR, IDS_GET_TOKENS_UNEXPECTED_ERROR, rc);
1943             return FALSE;
1944 //          printf("Unexpected error, code %d\n", rc);
1945 //          exit(1);
1946         }
1947         else {
1948             rc = ktc_GetToken(&serviceName, &token, sizeof(token), &clientName);
1949             if (rc) {
1950                 ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR2, MB_ICONERROR, IDS_GET_TOKENS_UNEXPECTED_ERROR2, 
1951                                 serviceName.name, serviceName.instance, serviceName.cell, rc);
1952                 continue;
1953             }
1954
1955             tokenExpireTime = token.endTime;
1956
1957             strcpy(userName, clientName.name);
1958             if (clientName.instance[0] != 0) {
1959                 strcat(userName, ".");
1960                 strcat(userName, clientName.instance);
1961             }
1962
1963             BOOL bShowName = FALSE;
1964
1965             if (userName[0] == '\0')
1966                 ; //printf("Tokens");
1967 // AFS ID is not returned at this time.
1968 //          else if (strncmp(userName, "AFS ID", 6) == 0)
1969 //              printf("User's (%s) tokens", userName);
1970 //              sscanf(userName, "(AFS ID %s)", szAfsID);
1971             else if (strncmp(userName, "Unix UID", 8) == 0)
1972                 ; //printf("Tokens");
1973             else
1974                 strUserName = userName;
1975 //              printf("User %s's tokens", userName);
1976                         
1977 //              printf(" for %s%s%s@%s ", serviceName.name, serviceName.instance[0] ? "." : "", serviceName.instance, serviceName.cell);
1978             strCellName = serviceName.cell;
1979                         
1980             if (tokenExpireTime <= current_time)
1981                 strExpir = "[>> Expired <<]";
1982 //              printf("[>> Expired <<]\n");
1983             else {
1984                 expireString = ctime(&tokenExpireTime);
1985                 expireString += 4;       /* Skip day of week */
1986                 expireString[12] = '\0'; /* Omit secs & year */
1987 //              printf("[Expires %s]\n", expireString);
1988                 strExpir.Format("%s", expireString);
1989             }
1990
1991             strTokenInfo = strUserName + "\t" + strCellName + "\t" + strExpir + "\t" + strCellName;
1992             tokenInfo.Add(strTokenInfo);
1993         }
1994     }
1995
1996 //      printf("Press <Enter> or <Return> when finished: ");
1997 //      gets(s);
1998     return TRUE;
1999 }
2000
2001 UINT MakeSymbolicLink(const char *strName, const char *strTarget)
2002 {
2003     struct ViceIoctl blob;
2004     char space[MAXSIZE];
2005     char * parent;
2006     char path[1024] = "";
2007     UINT code;
2008
2009     HOURGLASS hourglass;
2010     static char message[2048];
2011
2012     strcpy(path, strName);
2013     parent = Parent(path);
2014
2015     sprintf(message,"MakeSymbolicLink: name = %s target = %s parent = %s\n",strName,strTarget, parent);
2016     OutputDebugString(message);
2017
2018     if ( IsFreelanceRoot(parent) && !IsAdmin() ) {
2019         ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
2020         return FALSE;
2021     }
2022
2023     LPTSTR lpsz = new TCHAR[strlen(strTarget)+1];
2024     _tcscpy(lpsz, strName);
2025     strcpy(space, strTarget);
2026     blob.out_size = 0;
2027     blob.in_size = 1 + strlen(space);
2028     blob.in = space;
2029     blob.out = NULL;
2030     code=pioctl(lpsz, VIOC_SYMLINK, &blob, 0);
2031     delete lpsz;
2032     if (code != 0)
2033         return code;
2034     return FALSE;
2035 }
2036
2037 void ListSymbolicLinkPath(const char *strName,char *strPath,UINT nlenPath)
2038 {
2039     ASSERT(nlenPath<MAX_PATH);
2040     struct ViceIoctl blob;
2041     char orig_name[MAX_PATH+1];         /*Original name, may be modified*/
2042     char true_name[MAX_PATH+1];         /*``True'' dirname (e.g., symlink target)*/
2043     char parent_dir[MAX_PATH+1];                /*Parent directory of true name*/
2044     char *last_component;       /*Last component of true name*/
2045     UINT code;    
2046
2047     HOURGLASS hourglass;
2048
2049     strcpy(orig_name, strName);
2050     strcpy(true_name, orig_name);
2051     /*
2052      * Find rightmost slash, if any.
2053      */
2054     last_component = (char *) strrchr(true_name, '\\');
2055     if (!last_component)
2056         last_component = (char *) strrchr(true_name, '/');
2057     if (last_component) {
2058         /*
2059          * Found it.  Designate everything before it as the parent directory,
2060          * everything after it as the final component.
2061          */
2062         strncpy(parent_dir, true_name, last_component - true_name + 1);
2063         parent_dir[last_component - true_name + 1] = 0;
2064         last_component++;   /*Skip the slash*/
2065
2066         if (!IsPathInAfs(parent_dir)) {
2067             const char * nbname = NetbiosName();
2068             int len = strlen(nbname);
2069
2070             if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
2071                  parent_dir[len+2] == '\\' &&
2072                  parent_dir[len+3] == '\0' &&
2073                  !strnicmp(nbname,&parent_dir[2],len))
2074             {
2075                 sprintf(parent_dir,"\\\\%s\\all\\", nbname);
2076             }
2077         }
2078     }
2079     else {
2080         /*
2081          * No slash appears in the given file name.  Set parent_dir to the current
2082          * directory, and the last component as the given name.
2083          */
2084         fs_ExtractDriveLetter(true_name, parent_dir);
2085         strcat(parent_dir, ".");
2086         last_component = true_name;
2087         fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
2088     }
2089     blob.in = last_component;
2090     blob.in_size = strlen(last_component)+1;
2091     blob.out_size = MAXSIZE;
2092     blob.out = space;
2093     memset(space, 0, MAXSIZE);
2094     if ((code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1)))
2095         strcpy(space,"???");
2096     ASSERT(strlen(space)<MAX_PATH);
2097     strncpy(strPath,space,nlenPath);
2098 }       
2099
2100 BOOL ListSymlink(CStringArray& files)
2101 {
2102     register LONG code;
2103     struct ViceIoctl blob;
2104     int error;
2105     char orig_name[1024];                       /* Original name, may be modified */
2106     char true_name[1024];                       /* ``True'' dirname (e.g., symlink target) */
2107     char parent_dir[1024];                      /* Parent directory of true name */
2108     register char *last_component;      /* Last component of true name */
2109     CStringArray symlinks;
2110     
2111     HOURGLASS hourglass;
2112
2113     error = 0;
2114
2115     for (int i = 0; i < files.GetSize(); i++) {
2116         strcpy(orig_name, files[i]);
2117         strcpy(true_name, orig_name);
2118
2119         /*
2120          * Find rightmost slash, if any.
2121          */
2122         last_component = (char *)strrchr(true_name, '\\');
2123         if (last_component) {
2124             /*
2125              * Found it.  Designate everything before it as the parent directory,
2126              * everything after it as the final component.
2127              */
2128             strncpy(parent_dir, true_name, last_component - true_name + 1);
2129             parent_dir[last_component - true_name + 1] = 0;
2130             last_component++;   /* Skip the slash */
2131
2132             if (!IsPathInAfs(parent_dir)) {
2133                 const char * nbname = NetbiosName();
2134                 int len = strlen(nbname);
2135
2136                 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
2137                     parent_dir[len+2] == '\\' &&
2138                     parent_dir[len+3] == '\0' &&
2139                     !strnicmp(nbname,&parent_dir[2],len))
2140                 {
2141                     sprintf(parent_dir,"\\\\%s\\all\\", nbname);
2142                 }
2143             }
2144         }
2145         else {
2146             /*
2147              * No slash appears in the given file name.  Set parent_dir to the current
2148              * directory, and the last component as the given name.
2149              */
2150             fs_ExtractDriveLetter(true_name, parent_dir);
2151             strcat(parent_dir, ".");
2152             last_component = true_name;
2153             fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
2154         }
2155
2156         blob.in = last_component;
2157         blob.in_size = strlen(last_component) + 1;
2158         blob.out_size = MAXSIZE;
2159         blob.out = space;
2160         memset(space, 0, MAXSIZE);
2161
2162         code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
2163         if (code == 0) {
2164             int nPos = strlen(space) - 1;
2165             if (space[nPos] == '.')
2166                 space[nPos] = 0;
2167             symlinks.Add(ParseSymlink(StripPath(files[i]), space));
2168         } else {
2169             error = 1;
2170             if (errno == EINVAL)
2171                 symlinks.Add(GetMessageString(IDS_NOT_SYMLINK_ERROR, StripPath(files[i])));
2172             else
2173                 symlinks.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
2174         }
2175     }
2176
2177     CSymlinksDlg dlg;
2178     dlg.SetSymlinks(symlinks);
2179     dlg.DoModal();
2180
2181     return !error;
2182 }
2183