windows-parseacl-20080319
[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 *EmptyAcl(char *astr)
561 {
562     register struct Acl *tp;
563     int junk;
564
565     tp = (struct Acl *)malloc(sizeof (struct Acl));
566     tp->nplus = tp->nminus = 0;
567     tp->pluslist = tp->minuslist = 0;
568     tp->dfs = 0;
569     if (astr == NULL || sscanf(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell) <= 0) {
570         tp->dfs = 0;
571         tp->cell[0] = '\0';
572     }
573     return tp;
574 }
575
576 struct Acl *
577 ParseAcl (char *astr)
578 {
579     int nplus, nminus, i, trights, ret;
580     char tname[MAXNAME];
581     struct AclEntry *first, *next, *last, *tl;
582     struct Acl *ta;
583
584     ta = EmptyAcl(NULL);
585     if (astr == NULL || strlen(astr) == 0)
586         return ta;
587
588     ret = sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
589     if (ret <= 0) {
590         free(ta);
591         return NULL;
592     }
593     astr = SkipLine(astr);
594     ret = sscanf(astr, "%d", &ta->nminus);
595     if (ret <= 0) {
596         free(ta);
597         return NULL;
598     }
599     astr = SkipLine(astr);
600
601     nplus = ta->nplus;
602     nminus = ta->nminus;
603
604     last = 0;
605     first = 0;
606     for(i=0;i<nplus;i++) {
607         ret = sscanf(astr, "%100s %d", tname, &trights); 
608         if (ret <= 0)
609             goto nplus_err;
610         astr = SkipLine(astr);
611         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
612         if (tl == NULL)
613             goto nplus_err;
614         if (!first) 
615             first = tl;
616         strcpy(tl->name, tname);
617         tl->rights = trights;
618         tl->next = 0;
619         if (last) 
620             last->next = tl;
621         last = tl;
622     }
623     ta->pluslist = first;
624
625     last = 0;
626     first = 0;
627     for(i=0;i<nminus;i++) {
628         ret = sscanf(astr, "%100s %d", tname, &trights);
629         if (ret <= 0)
630             goto nminus_err;
631         astr = SkipLine(astr);
632         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
633         if (tl == NULL)
634             goto nminus_err;
635         if (!first) 
636             first = tl;
637         strcpy(tl->name, tname);
638         tl->rights = trights;
639         tl->next = 0;
640         if (last) 
641             last->next = tl;
642         last = tl;
643     }
644     ta->minuslist = first;
645
646   exit:
647     return ta;
648
649   nminus_err:
650     for (;first; first = next) {
651         next = first->next;
652         free(first);
653     }   
654     first = ta->pluslist;
655
656   nplus_err:
657     for (;first; first = next) {
658         next = first->next;
659         free(first);
660     }   
661     free(ta);
662     return NULL;
663 }
664
665 /* clean up an access control list of its bad entries; return 1 if we made
666    any changes to the list, and 0 otherwise */
667 extern "C" int CleanAcl(struct Acl *aa)
668 {
669     register struct AclEntry *te, **le, *ne;
670     int changes;
671
672     HOURGLASS hourglass;
673
674     /* Don't correct DFS ACL's for now */
675     if (aa->dfs)
676         return 0;
677
678     /* prune out bad entries */
679     changes = 0;            /* count deleted entries */
680     le = &aa->pluslist;
681     for(te = aa->pluslist; te; te = ne) {
682         ne = te->next;
683         if (BadName(te->name)) {
684             /* zap this dude */
685             *le = te->next;
686             aa->nplus--;
687             free(te);
688             changes++;
689         }
690         else
691             le = &te->next;
692     }
693
694     le = &aa->minuslist;
695     
696     for(te = aa->minuslist; te; te = ne) {
697         ne = te->next;
698         if (BadName(te->name)) {
699             /* zap this dude */
700             *le = te->next;
701             aa->nminus--;
702             free(te);
703             changes++;
704         }
705         else
706             le = &te->next;
707     }   
708
709     return changes;
710 }
711
712 void CleanACL(CStringArray& names)
713 {
714     register LONG code;
715     register struct Acl *ta;
716     struct ViceIoctl blob;
717     int changes;
718
719     ShowMessageBox(IDS_CLEANACL_MSG, MB_OK|MB_ICONINFORMATION, IDS_CLEANACL_MSG);
720
721     HOURGLASS hourglass;
722
723     for (int i = 0; i < names.GetSize(); i++) {
724         blob.out_size = MAXSIZE;
725         blob.in_size = 0;
726         blob.out = space;
727
728         code = pioctl(PCCHAR(names[i]), VIOCGETAL, &blob, 1);
729         if (code) {
730             ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONERROR, 0, names[i], GetAfsError(errno));
731             continue;
732         }
733
734         ta = ParseAcl(space);
735         if (ta == NULL) {
736             ShowMessageBox(IDS_INVALID_ACL_DATA, MB_ICONERROR, IDS_INVALID_ACL_DATA);
737             continue;
738         }
739         if (ta->dfs) {
740             ShowMessageBox(IDS_CLEANACL_NOT_SUPPORTED, MB_ICONERROR, IDS_CLEANACL_NOT_SUPPORTED, names[i]);
741             continue;
742         }
743
744         changes = CleanAcl(ta);
745         if (!changes)
746             continue;
747
748         /* now set the acl */
749         blob.in = AclToString(ta);
750         blob.in_size = strlen((char *)blob.in) + 1;
751         blob.out_size = 0;
752                 
753         code = pioctl(PCCHAR(names[i]), VIOCSETAL, &blob, 1);
754         if (code) {
755             if (errno == EINVAL) {
756                 ShowMessageBox(IDS_CLEANACL_INVALID_ARG, MB_ICONERROR, IDS_CLEANACL_INVALID_ARG, names[i]);
757                 continue;
758             }
759             else {
760                 ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONERROR, 0, names[i], GetAfsError(errno));
761                 continue;
762             }
763         }
764     }
765 }       
766
767 // Derived from fs.c's ListAclCmd
768 BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& strNegative)
769 {
770     register LONG code;
771     register struct Acl *ta;
772     struct ViceIoctl blob;
773     struct AclEntry *te;
774     int idf = 0; //getidf(as, parm_listacl_id);
775
776     HOURGLASS hourglass;
777
778     blob.out_size = MAXSIZE;
779     blob.in_size = idf;
780     blob.in = blob.out = space;
781         
782     code = pioctl(PCCHAR(strDir), VIOCGETAL, &blob, 1);
783     if (code) {
784         ShowMessageBox(IDS_GETRIGHTS_ERROR, MB_ICONERROR, IDS_GETRIGHTS_ERROR, strDir, GetAfsError(errno));
785         return FALSE;
786     }
787
788     ta = ParseAcl(space);
789     if (ta == NULL) {
790         ShowMessageBox(IDS_INVALID_ACL_DATA, MB_ICONERROR, IDS_INVALID_ACL_DATA);
791         return FALSE;
792     }
793     if (ta->dfs) {
794         ShowMessageBox(IDS_DFSACL_ERROR, MB_ICONERROR, IDS_DFSACL_ERROR);
795         return FALSE;
796     }
797
798 //      if (ta->dfs)
799 //              printf("  Default cell = %s\n", ta->cell);
800
801     CString strRight;
802
803     if (ta->nplus > 0) {
804         for (te = ta->pluslist; te; te = te->next) {
805             strNormal.Add(te->name);
806             strNormal.Add(GetRightsString(te->rights, ta->dfs));
807         }
808     }
809
810     if (ta->nminus > 0) {
811         for (te = ta->minuslist; te; te = te->next) {
812             strNegative.Add(te->name);
813             strNegative.Add(GetRightsString(te->rights, ta->dfs));
814         }
815     }
816
817     return TRUE;
818 }
819
820 struct AclEntry *FindList(register struct AclEntry *pCurEntry, const char *entryName)
821 {
822     while (pCurEntry) {
823         if (!foldcmp(pCurEntry->name, PCCHAR(entryName)))
824             return pCurEntry;
825         pCurEntry = pCurEntry->next;
826     }
827     
828     return 0;
829 }
830
831 void ChangeList (struct Acl *pAcl, BYTE bNormalRights, const char *entryName, LONG nEntryRights)
832 {
833     ASSERT(pAcl);
834     ASSERT(entryName);
835     
836     struct AclEntry *pEntry;
837
838     HOURGLASS hourglass;
839
840     pEntry = (bNormalRights ? pAcl->pluslist : pAcl->minuslist);
841     pEntry = FindList(pEntry, entryName);
842
843     /* Found the item already in the list. */
844     if (pEntry) {
845         pEntry->rights = nEntryRights;
846         if (bNormalRights)
847             pAcl->nplus -= PruneList(&pAcl->pluslist, pAcl->dfs);
848         else
849             pAcl->nminus -= PruneList(&pAcl->minuslist, pAcl->dfs);
850         return;
851     }
852
853     /* Otherwise we make a new item and plug in the new data. */
854     pEntry = (struct AclEntry *) malloc(sizeof (struct AclEntry));
855     ASSERT(pEntry);
856         
857     strcpy(pEntry->name, entryName);
858     pEntry->rights = nEntryRights;
859     
860     if (bNormalRights) {
861         pEntry->next = pAcl->pluslist;
862         pAcl->pluslist = pEntry;
863         pAcl->nplus++;
864         if (nEntryRights == 0 || nEntryRights == -1)
865             pAcl->nplus -= PruneList(&pAcl->pluslist, pAcl->dfs);
866     }
867     else {
868         pEntry->next = pAcl->minuslist;
869         pAcl->minuslist = pEntry;
870         pAcl->nminus++;
871         if (nEntryRights == 0)
872             pAcl->nminus -= PruneList(&pAcl->minuslist, pAcl->dfs);
873     }
874 }
875
876 enum rtype {add, destroy, deny};
877
878 LONG Convert(const register char *arights, int dfs, enum rtype *rtypep)
879 {
880     register int i, len;
881     LONG mode;
882     register char tc;
883
884     *rtypep = add;      /* add rights, by default */
885
886     if (!strcmp(arights,"read")) 
887         return PRSFS_READ | PRSFS_LOOKUP;
888     if (!strcmp(arights, "write")) 
889         return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK;
890     if (!strcmp(arights, "mail")) 
891         return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
892     if (!strcmp(arights, "all")) 
893         return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
894     
895     if (!strcmp(arights, "none")) {
896         *rtypep = destroy; /* Remove entire entry */
897         return 0;
898     }
899
900     len = strlen(arights);
901     mode = 0;
902
903     for (i = 0; i < len; i++) {
904         tc = *arights++;
905         if (tc == 'r') mode |= PRSFS_READ;
906         else if (tc == 'l') mode |= PRSFS_LOOKUP;
907         else if (tc == 'i') mode |= PRSFS_INSERT;
908         else if (tc == 'd') mode |= PRSFS_DELETE;
909         else if (tc == 'w') mode |= PRSFS_WRITE;
910         else if (tc == 'k') mode |= PRSFS_LOCK;
911         else if (tc == 'a') mode |= PRSFS_ADMINISTER;
912         else {
913             fprintf(stderr, "illegal rights character '%c'.\n", tc);
914             exit(1);
915         }
916     }   
917     return mode;
918 }
919
920 BOOL SaveACL(const CString& strCellName, const CString& strDir, const CStringArray& normal, const CStringArray& negative)
921 {
922     register LONG code;
923     struct ViceIoctl blob;
924     struct Acl *pAcl;
925     LONG rights;
926     enum rtype rtype;
927
928     HOURGLASS hourglass;
929
930     // Create a new ACL
931     pAcl = EmptyAcl(strCellName);
932
933     // Set its normal rights
934     int i;
935     for (i = 0; i < normal.GetSize(); i += 2) {
936         rights = Convert(normal[i + 1], 0, &rtype);
937         ChangeList(pAcl, TRUE, normal[i], rights);
938     }
939
940     // Set its negative rights
941     for (i = 0; i < negative.GetSize(); i += 2) {
942         rights = Convert(negative[i + 1], 0, &rtype);
943         ChangeList(pAcl, FALSE, negative[i], rights);
944     }
945
946     // Write the ACL
947     blob.in = AclToString(pAcl);
948     blob.out_size = 0;
949     blob.in_size = 1 + strlen((const char *)blob.in);
950
951     code = pioctl(PCCHAR(strDir), VIOCSETAL, &blob, 1);
952     if (code) {
953         if (errno == EINVAL)
954             ShowMessageBox(IDS_SAVE_ACL_EINVAL_ERROR, MB_ICONERROR, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
955         else
956             ShowMessageBox(IDS_SAVE_ACL_ERROR, MB_ICONERROR, IDS_SAVE_ACL_ERROR, strDir, GetAfsError(errno, strDir));
957     }       
958
959     ZapAcl(pAcl);
960
961     return (code == 0);
962 }
963
964 BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringArray& negative, BOOL bClear)
965 {
966     register LONG code;
967     struct ViceIoctl blob;
968     struct Acl *pToAcl;
969     int idf = 0; // getidf(as, parm_copyacl_id);
970
971     HOURGLASS hourglass;
972
973     // Get ACL to copy to
974     blob.out_size = MAXSIZE;
975     blob.in_size = idf;
976     blob.in = blob.out = space;
977         
978     code = pioctl(PCCHAR(strToDir), VIOCGETAL, &blob, 1);
979     if (code) {
980         ShowMessageBox(IDS_ACL_READ_ERROR, MB_ICONERROR, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
981         return FALSE;
982     }
983         
984     if (bClear) 
985         pToAcl = EmptyAcl(space);
986     else 
987         pToAcl = ParseAcl(space);
988
989     if (pToAcl == NULL) {
990         ShowMessageBox(IDS_INVALID_ACL_DATA, MB_ICONERROR, IDS_INVALID_ACL_DATA);
991         return FALSE;
992     }
993
994     CleanAcl(pToAcl);
995
996     if (pToAcl->dfs) {
997         ShowMessageBox(IDS_NO_DFS_COPY_ACL, MB_ICONERROR, IDS_NO_DFS_COPY_ACL, strToDir);
998         ZapAcl(pToAcl);
999         return FALSE;
1000     }
1001
1002     enum rtype rtype;
1003
1004     // Set normal rights
1005     int i;
1006     for (i = 0; i < normal.GetSize(); i += 2) {
1007         LONG rights = Convert(normal[i + 1], 0, &rtype);
1008         ChangeList(pToAcl, TRUE, normal[i], rights);
1009     }
1010
1011     // Set negative rights
1012     for (i = 0; i < negative.GetSize(); i += 2) {
1013         LONG rights = Convert(negative[i + 1], 0, &rtype);
1014         ChangeList(pToAcl, FALSE, normal[i], rights);
1015     }
1016
1017     // Save modified ACL
1018     blob.in = AclToString(pToAcl);
1019     blob.out_size = 0;
1020     blob.in_size = 1 + strlen((char *)blob.in);
1021
1022     code = pioctl(PCCHAR(strToDir), VIOCSETAL, &blob, 1);
1023     if (code) {
1024         ZapAcl(pToAcl);
1025         if (errno == EINVAL)
1026             ShowMessageBox(IDS_COPY_ACL_EINVAL_ERROR, MB_ICONERROR, IDS_COPY_ACL_EINVAL_ERROR, strToDir);
1027         else 
1028             ShowMessageBox(IDS_COPY_ACL_ERROR, MB_ICONERROR, IDS_COPY_ACL_ERROR, strToDir, GetAfsError(errno, strToDir));
1029         return FALSE;
1030     }
1031
1032     ZapAcl(pToAcl);
1033
1034     ShowMessageBox(IDS_COPY_ACL_OK, MB_OK|MB_ICONINFORMATION, IDS_COPY_ACL_OK);
1035
1036     return TRUE;
1037 }
1038
1039 CString ParseMountPoint(const CString strFile, CString strMountPoint)
1040 {
1041     CString strType;
1042     CString strVolume;
1043     CString strCell;
1044     CString strMountPointInfo;
1045
1046     if (strMountPoint[0] == '#')
1047         strType = "Regular";
1048     else if (strMountPoint[0] == '%')
1049         strType = "Read/Write";
1050
1051     int nColon = strMountPoint.Find(':');
1052     if (nColon >= 0) {
1053         strCell = strMountPoint.Mid(1, nColon - 1);
1054         strVolume = strMountPoint.Mid(nColon + 1);
1055     } else
1056         strVolume = strMountPoint.Mid(1);
1057
1058     strMountPointInfo = strFile + "\t" + strVolume + "\t" + strCell + "\t" + strType;
1059
1060     return strMountPointInfo;
1061 }       
1062
1063 CString ParseSymlink(const CString strFile, CString strSymlink)
1064 {
1065     CString strSymlinkInfo;
1066
1067     strSymlinkInfo = strFile + "\t" + strSymlink;
1068
1069     return strSymlinkInfo;
1070 }       
1071
1072 BOOL IsPathInAfs(const CHAR *strPath)
1073 {
1074     struct ViceIoctl blob;
1075     int code;
1076
1077     HOURGLASS hourglass;
1078
1079     char buf[512];
1080     sprintf(buf, "IsPathInAfs(%s)", strPath);
1081     OutputDebugString(buf);
1082
1083     blob.in_size = 0;
1084     blob.out_size = MAXSIZE;
1085     blob.out = space;
1086
1087     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1088
1089     sprintf(buf, "VIOC_FILE_CELL_NAME=%d", code);
1090     OutputDebugString(buf);
1091
1092     if (code) {
1093         if ((errno == EINVAL) || (errno == ENOENT))
1094         return FALSE;
1095     }
1096     return TRUE;
1097 }
1098
1099 static int 
1100 IsFreelanceRoot(char *apath)
1101 {
1102     struct ViceIoctl blob;
1103     afs_int32 code;
1104
1105     blob.in_size = 0;
1106     blob.out_size = MAXSIZE;
1107     blob.out = space;
1108
1109     code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
1110     if (code == 0)
1111         return !strcmp("Freelance.Local.Root",space);
1112     return 1;   /* assume it is because it is more restrictive that way */
1113 }
1114
1115 const char * NetbiosName(void)
1116 {
1117     static char buffer[1024] = "AFS";
1118     HKEY  parmKey;
1119     DWORD code;
1120     DWORD dummyLen;
1121     DWORD enabled = 0;
1122
1123     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1124                          0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
1125     if (code == ERROR_SUCCESS) {
1126         dummyLen = sizeof(buffer);
1127         code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
1128                                (LPBYTE)buffer, &dummyLen);
1129         RegCloseKey (parmKey);
1130     } else {
1131         strcpy(buffer, "AFS");
1132     }
1133     return buffer;
1134 }
1135
1136 #define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
1137
1138 static BOOL IsAdmin (void)
1139 {
1140     static BOOL fAdmin = FALSE;
1141     static BOOL fTested = FALSE;
1142
1143     if (!fTested)
1144     {
1145         /* Obtain the SID for the AFS client admin group.  If the group does
1146          * not exist, then assume we have AFS client admin privileges.
1147          */
1148         PSID psidAdmin = NULL;
1149         DWORD dwSize, dwSize2;
1150         char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
1151         char *pszRefDomain = NULL;
1152         SID_NAME_USE snu = SidTypeGroup;
1153
1154         dwSize = sizeof(pszAdminGroup);
1155
1156         if (!GetComputerName(pszAdminGroup, &dwSize)) {
1157             /* Can't get computer name.  We return false in this case.
1158                Retain fAdmin and fTested. This shouldn't happen.*/
1159             return FALSE;
1160         }
1161
1162         dwSize = 0;
1163         dwSize2 = 0;
1164
1165         strcat(pszAdminGroup,"\\");
1166         strcat(pszAdminGroup, AFSCLIENT_ADMIN_GROUPNAME);
1167
1168         LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
1169         /* that should always fail. */
1170
1171         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1172             /* if we can't find the group, then we allow the operation */
1173             fAdmin = TRUE;
1174             return TRUE;
1175         }
1176
1177         if (dwSize == 0 || dwSize2 == 0) {
1178             /* Paranoia */
1179             fAdmin = TRUE;
1180             return TRUE;
1181         }
1182
1183         psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
1184         pszRefDomain = (char *)malloc(dwSize2);
1185
1186         if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
1187             /* We can't lookup the group now even though we looked it up earlier.  
1188                Could this happen? */
1189             fAdmin = TRUE;
1190         } else {
1191             /* Then open our current ProcessToken */
1192             HANDLE hToken;
1193
1194             if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
1195             {
1196
1197                 if (!CheckTokenMembership(hToken, psidAdmin, &fAdmin)) {
1198                     /* We'll have to allocate a chunk of memory to store the list of
1199                      * groups to which this user belongs; find out how much memory
1200                      * we'll need.
1201                      */
1202                     DWORD dwSize = 0;
1203                     PTOKEN_GROUPS pGroups;
1204
1205                     GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
1206
1207                     pGroups = (PTOKEN_GROUPS)malloc(dwSize);
1208
1209                     /* Allocate that buffer, and read in the list of groups. */
1210                     if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
1211                     {
1212                         /* Look through the list of group SIDs and see if any of them
1213                          * matches the AFS Client Admin group SID.
1214                          */
1215                         size_t iGroup = 0;
1216                         for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
1217                         {
1218                             if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
1219                                 fAdmin = TRUE;
1220                             }
1221                         }
1222                     }
1223
1224                     if (pGroups)
1225                         free(pGroups);
1226                 }
1227
1228                 /* if do not have permission because we were not explicitly listed
1229                  * in the Admin Client Group let's see if we are the SYSTEM account
1230                  */
1231                 if (!fAdmin) {
1232                     PTOKEN_USER pTokenUser;
1233                     SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
1234                     PSID pSidLocalSystem = 0;
1235                     DWORD gle;
1236
1237                     GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
1238
1239                     pTokenUser = (PTOKEN_USER)malloc(dwSize);
1240
1241                     if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
1242                         gle = GetLastError();
1243
1244                     if (AllocateAndInitializeSid( &SIDAuth, 1,
1245                                                   SECURITY_LOCAL_SYSTEM_RID,
1246                                                   0, 0, 0, 0, 0, 0, 0,
1247                                                   &pSidLocalSystem))
1248                     {
1249                         if (EqualSid(pTokenUser->User.Sid, pSidLocalSystem)) {
1250                             fAdmin = TRUE;
1251                         }
1252
1253                         FreeSid(pSidLocalSystem);
1254                     }
1255
1256                     if ( pTokenUser )
1257                         free(pTokenUser);
1258                 }
1259             }
1260         }
1261
1262         free(psidAdmin);
1263         free(pszRefDomain);
1264
1265         fTested = TRUE;
1266     }
1267
1268     return fAdmin;
1269 }
1270
1271 /* return a static pointer to a buffer */
1272 static char *Parent(char *apath)
1273 {
1274     register char *tp;
1275
1276     strcpy(tspace, apath);
1277     tp = strrchr(tspace, '\\');
1278     if (tp) {
1279         *(tp+1) = 0;    /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
1280     }
1281     else {
1282         fs_ExtractDriveLetter(apath, tspace);
1283         strcat(tspace, ".");
1284     }
1285     
1286     return tspace;
1287 }
1288
1289 static afs_int32
1290 GetCell(char *fname, char *cellname)
1291 {
1292     afs_int32 code;
1293     struct ViceIoctl blob;
1294
1295     blob.in_size = 0;
1296     blob.out_size = MAXCELLCHARS;
1297     blob.out = cellname;
1298
1299     code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1);
1300     return code ? errno : 0;
1301 }
1302
1303
1304 BOOL ListMount(CStringArray& files)
1305 {
1306     register LONG code;
1307     struct ViceIoctl blob;
1308     int error;
1309     char orig_name[1024];                       /* Original name, may be modified */
1310     char true_name[1024];                       /* ``True'' dirname (e.g., symlink target) */
1311     char parent_dir[1024];                      /* Parent directory of true name */
1312     register char *last_component;      /* Last component of true name */
1313     CStringArray mountPoints;
1314     
1315     HOURGLASS hourglass;
1316
1317     error = 0;
1318
1319     for (int i = 0; i < files.GetSize(); i++) {
1320         strcpy(orig_name, files[i]);
1321         strcpy(true_name, orig_name);
1322
1323         /*
1324          * Find rightmost slash, if any.
1325          */
1326         last_component = (char *)strrchr(true_name, '\\');
1327         if (last_component) {
1328             /*
1329              * Found it.  Designate everything before it as the parent directory,
1330              * everything after it as the final component.
1331              */
1332             strncpy(parent_dir, true_name, last_component - true_name + 1);
1333             parent_dir[last_component - true_name + 1] = 0;
1334             last_component++;   /* Skip the slash */
1335
1336             if (!IsPathInAfs(parent_dir)) {
1337                 const char * nbname = NetbiosName();
1338                 int len = strlen(nbname);
1339
1340                 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
1341                     parent_dir[len+2] == '\\' &&
1342                     parent_dir[len+3] == '\0' &&
1343                     !strnicmp(nbname,&parent_dir[2],len))
1344                 {
1345                     sprintf(parent_dir,"\\\\%s\\all\\", nbname);
1346                 }
1347             }
1348         }
1349         else {
1350             /*
1351              * No slash appears in the given file name.  Set parent_dir to the current
1352              * directory, and the last component as the given name.
1353              */
1354             fs_ExtractDriveLetter(true_name, parent_dir);
1355             strcat(parent_dir, ".");
1356             last_component = true_name;
1357             fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
1358         }
1359
1360         blob.in = last_component;
1361         blob.in_size = strlen(last_component) + 1;
1362         blob.out_size = MAXSIZE;
1363         blob.out = space;
1364         memset(space, 0, MAXSIZE);
1365
1366         code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
1367         if (code == 0) {
1368             int nPos = strlen(space) - 1;
1369             if (space[nPos] == '.')
1370                 space[nPos] = 0;
1371             mountPoints.Add(ParseMountPoint(StripPath(files[i]), space));
1372         } else {
1373             error = 1;
1374             if (errno == EINVAL)
1375                 mountPoints.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
1376             else
1377                 mountPoints.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
1378         }
1379     }
1380
1381     CMountPointsDlg dlg;
1382     dlg.SetMountPoints(mountPoints);
1383     dlg.DoModal();
1384
1385     return !error;
1386 }
1387
1388 BOOL MakeMount(const CString& strDir, const CString& strVolName, const CString& strCellName, BOOL bRW)
1389 {
1390     register LONG code;
1391     register char *cellName;
1392     char localCellName[128];
1393     struct afsconf_cell info;
1394 #if 0
1395     struct vldbentry vldbEntry;
1396 #endif
1397     struct ViceIoctl blob;
1398     char * parent;
1399     char path[1024] = "";
1400
1401     HOURGLASS hourglass;
1402
1403     ASSERT(strVolName.GetLength() < 64);
1404
1405     if (strCellName.GetLength() > 0)    /* cell name specified */
1406         cellName = PCCHAR(strCellName);
1407     else
1408         cellName = (char *) 0;
1409
1410     parent = Parent(PCCHAR(strDir));
1411     if (!IsPathInAfs(parent)) {
1412         const char * nbname = NetbiosName();
1413         int len = strlen(nbname);
1414
1415         if (parent[0] == '\\' && parent[1] == '\\' &&
1416             parent[len+2] == '\\' &&
1417             parent[len+3] == '\0' &&
1418             !strnicmp(nbname,&parent[2],len))
1419         {
1420             sprintf(path,"%sall\\%s", parent, &(PCCHAR(strDir)[strlen(parent)]));
1421             parent = Parent(path);
1422             if (!IsPathInAfs(parent)) {
1423                 ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONERROR, IDS_MAKE_MP_NOT_AFS_ERROR);
1424                 return FALSE;
1425             }
1426         } else {
1427             ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONERROR, IDS_MAKE_MP_NOT_AFS_ERROR);
1428             return FALSE;
1429         }
1430     }
1431
1432     if ( strlen(path) == 0 )
1433         strcpy(path, PCCHAR(strDir));
1434
1435     if ( IsFreelanceRoot(parent) ) {
1436         if ( !IsAdmin() ) {
1437             ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
1438             return FALSE;
1439         }
1440
1441         if (!cellName) {
1442             blob.in_size = 0;
1443             blob.out_size = sizeof(localCellName);
1444             blob.out = localCellName;
1445             code = pioctl(parent, VIOC_GET_WS_CELL, &blob, 1);
1446             if (!code)
1447                 cellName = localCellName;
1448         }
1449     } else {
1450         if (!cellName)
1451             GetCell(parent,space);
1452     }
1453
1454     code = GetCellName(cellName?cellName:space, &info);
1455     if (code) {
1456         return FALSE;
1457     }
1458
1459 #if 0
1460     code = VLDBInit(1, &info);
1461     if (code == 0) {
1462         /* make the check.  Don't complain if there are problems with init */
1463         code = ubik_VL_GetEntryByNameO(uclient, 0, PCCHAR(strVolName), &vldbEntry);
1464         if (code == VL_NOENT) {
1465             ShowMessageBox(IDS_WARNING, MB_ICONWARNING, IDS_VOLUME_NOT_IN_CELL_WARNING, 
1466                             PCCHAR(strVolName), cellName ? cellName : space);
1467         }
1468     }
1469     if (rxInitDone) 
1470         rx_Finalize();
1471 #endif
1472
1473     if (bRW)    /* if -rw specified */
1474         strcpy(space, "%");
1475     else
1476         strcpy(space, "#");
1477
1478     /* If cellular mount point, prepend cell prefix */
1479     if (cellName) {
1480         strcat(space, info.name);
1481         strcat(space, ":");
1482     }   
1483
1484     strcat(space, strVolName);  /* append volume name */
1485     strcat(space, ".");         /* stupid convention; these end with a period */
1486
1487     /* create symlink with a special pioctl for Windows NT, since it doesn't
1488      * have a symlink system call.
1489      */
1490     blob.out_size = 0;
1491     blob.in_size = 1 + strlen(space);
1492     blob.in = space;
1493     blob.out = NULL;
1494     code = pioctl(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
1495
1496     if (code) {
1497         ShowMessageBox(IDS_MOUNT_POINT_ERROR, MB_ICONERROR, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
1498         return FALSE;
1499     }
1500     
1501     return TRUE;
1502 }
1503
1504 /*
1505 */
1506 long fs_ExtractDriveLetter(const char *inPathp, char *outPathp)
1507 {
1508     if (inPathp[0] != 0 && inPathp[1] == ':') {
1509         /* there is a drive letter */
1510         *outPathp++ = *inPathp++;
1511         *outPathp++ = *inPathp++;
1512         *outPathp++ = 0;
1513     }
1514     else *outPathp = 0;
1515
1516     return 0;
1517 }       
1518
1519 /* strip the drive letter from a component */
1520 long fs_StripDriveLetter(const char *inPathp, char *outPathp, long outSize)
1521 {
1522     char tempBuffer[1000];
1523     strcpy(tempBuffer, inPathp);
1524     if (tempBuffer[0] != 0 && tempBuffer[1] == ':') {
1525         /* drive letter present */
1526         strcpy(outPathp, tempBuffer+2);
1527     }
1528     else {
1529         /* no drive letter present */
1530         strcpy(outPathp, tempBuffer);
1531     }
1532     return 0;
1533 }       
1534
1535
1536 BOOL RemoveSymlink(const char * linkName)
1537 {
1538     BOOL error = FALSE;
1539     INT code=0;
1540     struct ViceIoctl blob;
1541     char tbuffer[1024];
1542     char lsbuffer[1024];
1543     char tpbuffer[1024];
1544     char *tp;
1545     
1546     HOURGLASS hourglass;
1547
1548     tp = (char *) strrchr(linkName, '\\');
1549     if (!tp)
1550         tp = (char *) strrchr(linkName, '/');
1551     if (tp) {
1552         strncpy(tbuffer, linkName, code=tp-linkName+1);  /* the dir name */
1553         tbuffer[code] = 0;
1554         tp++;   /* skip the slash */
1555
1556         if (!IsPathInAfs(tbuffer)) {
1557             const char * nbname = NetbiosName();
1558             int len = strlen(nbname);
1559
1560             if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1561                  tbuffer[len+2] == '\\' &&
1562                  tbuffer[len+3] == '\0' &&
1563                  !strnicmp(nbname,&tbuffer[2],len))
1564             {
1565                 sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1566             }
1567         }
1568     }
1569     else {
1570         fs_ExtractDriveLetter(linkName, tbuffer);
1571         strcat(tbuffer, ".");
1572         fs_StripDriveLetter(tp, tpbuffer, 0);
1573         tp=tpbuffer;
1574     }
1575
1576     if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
1577         ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
1578         return FALSE;
1579     }
1580
1581     blob.in = tp;
1582     blob.in_size = strlen(tp)+1;
1583     blob.out = lsbuffer;
1584     blob.out_size = sizeof(lsbuffer);
1585     code = pioctl(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
1586     if (code)
1587         return FALSE;
1588     blob.out_size = 0;
1589     blob.in = tp;
1590     blob.in_size = strlen(tp)+1;
1591     return (pioctl(tbuffer, VIOC_DELSYMLINK, &blob, 0)==0);
1592 }       
1593
1594 BOOL IsSymlink(const char * true_name)
1595 {
1596     char parent_dir[MAXSIZE];           /*Parent directory of true name*/
1597     char strip_name[MAXSIZE];
1598     struct ViceIoctl blob;
1599     char *last_component;
1600     int code;
1601
1602     HOURGLASS hourglass;
1603
1604     char buf[512];
1605     sprintf(buf, "IsSymlink(%s)", true_name);
1606     OutputDebugString(buf);
1607
1608     last_component = (char *) strrchr(true_name, '\\');
1609     if (!last_component)
1610         last_component = (char *) strrchr(true_name, '/');
1611     if (last_component) {
1612         /*
1613          * Found it.  Designate everything before it as the parent directory,
1614          * everything after it as the final component.
1615          */
1616         strncpy(parent_dir, true_name, last_component - true_name + 1);
1617         parent_dir[last_component - true_name + 1] = 0;
1618         last_component++;   /*Skip the slash*/
1619
1620         if (!IsPathInAfs(parent_dir)) {
1621             const char * nbname = NetbiosName();
1622             int len = strlen(nbname);
1623
1624             if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
1625                  parent_dir[len+2] == '\\' &&
1626                  parent_dir[len+3] == '\0' &&
1627                  !strnicmp(nbname,&parent_dir[2],len))
1628             {
1629                 sprintf(parent_dir,"\\\\%s\\all\\", nbname);
1630             }
1631         }
1632     }
1633     else {
1634         /*
1635          * No slash appears in the given file name.  Set parent_dir to the current
1636          * directory, and the last component as the given name.
1637          */
1638         fs_ExtractDriveLetter(true_name, parent_dir);
1639         strcat(parent_dir, ".");
1640         last_component = strip_name;
1641         fs_StripDriveLetter(true_name, strip_name, sizeof(strip_name));
1642     }
1643
1644     sprintf(buf, "last_component=%s", last_component);
1645     OutputDebugString(buf);
1646
1647     blob.in = last_component;
1648     blob.in_size = strlen(last_component)+1;
1649     blob.out_size = MAXSIZE;
1650     blob.out = space;
1651     memset(space, 0, MAXSIZE);
1652     code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
1653     return (code==0);
1654 }       
1655
1656
1657 BOOL IsMountPoint(const char * name)
1658 {
1659     register LONG code = 0;
1660     struct ViceIoctl blob;
1661     char tbuffer[1024];
1662     char lsbuffer[1024];
1663     register char *tp;
1664     char szCurItem[1024];
1665
1666     HOURGLASS hourglass;
1667
1668     strcpy(szCurItem, name);
1669         
1670     char buf[512];
1671     sprintf(buf, "IsMountPoint(%s)", name);
1672     OutputDebugString(buf);
1673
1674     tp = (char *)strrchr(szCurItem, '\\');
1675     if (tp) {
1676         strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
1677         tbuffer[code] = 0;
1678         tp++;   /* skip the slash */
1679
1680         if (!IsPathInAfs(tbuffer)) {
1681             const char * nbname = NetbiosName();
1682             int len = strlen(nbname);
1683
1684             if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1685                  tbuffer[len+2] == '\\' &&
1686                  tbuffer[len+3] == '\0' &&
1687                  !strnicmp(nbname,&tbuffer[2],len))
1688             {
1689                 sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1690             }
1691         }
1692     } else {
1693         fs_ExtractDriveLetter(szCurItem, tbuffer);
1694         strcat(tbuffer, ".");
1695         tp = szCurItem;
1696         fs_StripDriveLetter(tp, tp, 0);
1697     }
1698
1699     sprintf(buf, "last_component=%s", tp);
1700     OutputDebugString(buf);
1701
1702     blob.in = tp;
1703     blob.in_size = strlen(tp)+1;
1704     blob.out = lsbuffer;
1705     blob.out_size = sizeof(lsbuffer);
1706
1707     code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
1708
1709     return (code==0);
1710 }       
1711
1712
1713 /*
1714  * Delete AFS mount points.  Variables are used as follows:
1715  *       tbuffer: Set to point to the null-terminated directory name of the mount point
1716  *          (or ``.'' if none is provided)
1717  *      tp: Set to point to the actual name of the mount point to nuke.
1718  */
1719 BOOL RemoveMount(CStringArray& files)
1720 {
1721     register LONG code = 0;
1722     struct ViceIoctl blob;
1723     char tbuffer[1024];
1724     register char *tp;
1725     char szCurItem[1024];
1726     BOOL error = FALSE;
1727     CStringArray results;
1728     CString str;
1729     CString str2;
1730
1731     HOURGLASS hourglass;
1732
1733     for (int i = 0; i < files.GetSize(); i++) {
1734         if (!IsMountPoint(files[i])) {
1735             error = TRUE;
1736             if (errno == EINVAL)
1737                 results.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
1738             else
1739                 results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
1740             continue;   // don't bother trying
1741         }
1742
1743         strcpy(szCurItem, files[i]);
1744         
1745         tp = (char *)strrchr(szCurItem, '\\');
1746         if (tp) {
1747             strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
1748             tbuffer[code] = 0;
1749             tp++;   /* skip the slash */
1750
1751             if (!IsPathInAfs(tbuffer)) {
1752                 const char * nbname = NetbiosName();
1753                 int len = strlen(nbname);
1754
1755                 if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1756                     tbuffer[len+2] == '\\' &&
1757                     tbuffer[len+3] == '\0' &&
1758                     !strnicmp(nbname,&tbuffer[2],len))
1759                 {
1760                     sprintf(tbuffer,"\\\\%s\\all\\", nbname);
1761                 }
1762             }
1763         } else {
1764             fs_ExtractDriveLetter(szCurItem, tbuffer);
1765             strcat(tbuffer, ".");
1766             tp = szCurItem;
1767             fs_StripDriveLetter(tp, tp, 0);
1768         }
1769
1770         if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
1771             results.Add(GetMessageString(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, StripPath(files[i])));
1772             error = TRUE;
1773             continue;   /* skip */
1774         }
1775
1776         blob.out_size = 0;
1777         blob.in = tp;
1778         blob.in_size = strlen(tp)+1;
1779
1780         code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
1781         if (code) {
1782             error = TRUE;
1783             results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
1784         } else
1785             results.Add(GetMessageString(IDS_DELETED));
1786     }   
1787
1788     LoadString (str, IDS_REMOVE_MP);
1789     LoadString (str2, IDS_REMOVE_MP_COLUMN);
1790     CResultsDlg dlg(REMOVE_MOUNT_POINTS_HELP_ID);
1791     dlg.SetContents(str, str2, StripPath(files), results);
1792     dlg.DoModal();
1793
1794     return !error;
1795 }
1796
1797 BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
1798 {
1799     register LONG code;
1800     struct ViceIoctl blob;
1801     struct VolumeStatus *status;
1802     char *name;
1803
1804     HOURGLASS hourglass;
1805
1806     volInfo.m_strFilePath = strFile;
1807     volInfo.m_strFileName = StripPath(strFile);
1808
1809     /*
1810         volInfo.m_strName = "VolumeName";
1811         volInfo.m_nID = 10;
1812         volInfo.m_nQuota = 20 * 1024 * 1024;
1813         volInfo.m_nNewQuota = volInfo.m_nQuota;
1814         volInfo.m_nUsed = volInfo.m_nQuota / 2;
1815         volInfo.m_nPartSize = 50 * 1024 * 1024;
1816         volInfo.m_nPartFree = 30 * 1024 * 1024;
1817         volInfo.m_nDup = -1;
1818         return TRUE;
1819      */
1820
1821     blob.out_size = MAXSIZE;
1822     blob.in_size = 0;
1823     blob.out = space;
1824
1825     code = pioctl(PCCHAR(strFile), VIOCGETVOLSTAT, &blob, 1);
1826     if (code) {
1827         volInfo.m_strErrorMsg = GetAfsError(errno, strFile);
1828         return FALSE;
1829     }
1830
1831     status = (VolumeStatus *)space;
1832     name = (char *)status + sizeof(*status);
1833
1834     volInfo.m_strName = name;
1835     volInfo.m_nID = status->Vid;
1836     volInfo.m_nQuota = status->MaxQuota;
1837     volInfo.m_nNewQuota = status->MaxQuota;
1838     volInfo.m_nUsed = status->BlocksInUse;
1839     volInfo.m_nPartSize = status->PartMaxBlocks;
1840     volInfo.m_nPartFree = status->PartBlocksAvail;
1841     volInfo.m_nDup = -1;
1842
1843     return TRUE;
1844 }
1845         
1846 BOOL SetVolInfo(CVolInfo& volInfo)
1847 {
1848     register LONG code;
1849     struct ViceIoctl blob;
1850     struct VolumeStatus *status;
1851     char *input;
1852
1853     HOURGLASS hourglass;
1854
1855     blob.out_size = MAXSIZE;
1856     blob.in_size = sizeof(*status) + 3; /* for the three terminating nulls */
1857     blob.out = space;
1858     blob.in = space;
1859
1860     status = (VolumeStatus *)space;
1861     status->MinQuota = -1;
1862     status->MaxQuota = volInfo.m_nNewQuota;
1863         
1864     input = (char *)status + sizeof(*status);
1865     *(input++) = '\0';  /* never set name: this call doesn't change vldb */
1866     *(input++) = '\0';  // No offmsg
1867     *(input++) = '\0';  // No motd
1868
1869 #ifdef LOGGING_ON
1870     FILE *fp = OpenFile(szLogFileName, "a");
1871     if (fp) {
1872         fprintf(fp, "\nSetVolInfo() pioctl parms:\n");
1873         fprintf(fp, "\tpathp = %s\n\topcode = VIOCSETVOLSTAT (%d)\n\tblobp = %ld\n", PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob);
1874         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);
1875         fprintf(fp, "\t\t\tstatus->MinQuota = %ld\n", status->MinQuota);
1876         fprintf(fp, "\t\t\tstatus->MaxQuota = %ld\n", status->MaxQuota);
1877         fprintf(fp, "\t\t\tOther status fields aren't set\n");
1878         fprintf(fp, "\t\t\t3 nulls follow the VolumeStatus structure.\n");
1879         fprintf(fp, "\tfollow = 1\n");
1880         fclose(fp);             
1881     }
1882 #endif
1883
1884     code = pioctl(PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob, 1);
1885     if (code) {
1886         ShowMessageBox(IDS_SET_QUOTA_ERROR, MB_ICONERROR, IDS_SET_QUOTA_ERROR, GetAfsError(errno, volInfo.m_strName));
1887         return FALSE;
1888     }
1889
1890     return TRUE;
1891 }
1892
1893 int GetCellName(char *cellNamep, struct afsconf_cell *infop)
1894 {
1895     strcpy(infop->name, cellNamep);
1896     return 0;
1897 }
1898
1899 BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bFast)
1900 {
1901     register LONG code;
1902     struct ViceIoctl blob;
1903     register LONG j;
1904     LONG temp = 0;
1905     struct afsconf_cell info;
1906     struct chservinfo checkserv;
1907
1908     HOURGLASS hourglass;
1909
1910     memset(&checkserv, 0, sizeof(struct chservinfo));
1911     blob.in_size = sizeof(struct chservinfo);
1912     blob.in = (caddr_t)&checkserv;
1913
1914     blob.out_size = MAXSIZE;
1915     blob.out = space;
1916     memset(space, 0, sizeof(afs_int32));        /* so we assure zero when nothing is copied back */
1917
1918     if (nCellsToCheck == SPECIFIC_CELL) {
1919         temp = 2;
1920         GetCellName(PCCHAR(strCellName), &info);
1921         strcpy(checkserv.tbuffer,info.name);
1922         checkserv.tsize = strlen(info.name) + 1;
1923     } else {
1924         if (nCellsToCheck != ALL_CELLS)
1925             temp = 2;
1926         strcpy(checkserv.tbuffer, "\0");
1927         checkserv.tsize = 0;
1928     }
1929     if (bFast)
1930         temp |= 1;      /* set fast flag */
1931     
1932     checkserv.magic = 0x12345678;       /* XXX */
1933     checkserv.tflags = temp;
1934     checkserv.tinterval = -1;   /* don't change current interval */
1935
1936     code = pioctl(0, VIOCCKSERV, &blob, 1);
1937     if (code) {
1938         ShowMessageBox(IDS_CHECK_SERVERS_ERROR, MB_ICONERROR, IDS_CHECK_SERVERS_ERROR, GetAfsError(errno, CString()));
1939         return FALSE;
1940     }
1941
1942     memcpy(&temp, space, sizeof(LONG));
1943
1944     if (temp == 0) {
1945         ShowMessageBox(IDS_ALL_SERVERS_RUNNING, MB_OK|MB_ICONINFORMATION, IDS_ALL_SERVERS_RUNNING);
1946         return TRUE;
1947     }
1948
1949     CStringArray servers;
1950     for (j = 0; j < MAXHOSTS; j++) {
1951         memcpy(&temp, space + j * sizeof(LONG), sizeof(LONG));
1952         if (temp == 0)
1953             break;
1954
1955         char *name = hostutil_GetNameByINet(temp);
1956         servers.Add(name);
1957     }
1958
1959     CDownServersDlg dlg;
1960     dlg.SetServerNames(servers);
1961     dlg.DoModal();
1962
1963     return TRUE;
1964 }       
1965
1966 BOOL GetTokenInfo(CStringArray& tokenInfo)
1967 {
1968     int cellNum;
1969     int rc;
1970     time_t current_time;
1971     time_t tokenExpireTime;
1972     char *expireString;
1973     char userName[100];
1974 //      char s[100];
1975     struct ktc_principal serviceName, clientName;
1976     struct ktc_token token;
1977
1978     CString strTokenInfo;
1979     CString strUserName;
1980     CString strCellName;
1981     CString strExpir;
1982
1983 //      tokenInfo.Add("");
1984 //      return TRUE;
1985
1986
1987     HOURGLASS hourglass;
1988
1989 //      printf("\nTokens held by the Cache Manager:\n\n");
1990     cellNum = 0;
1991     current_time = time(0);
1992
1993     while (1) {
1994         rc = ktc_ListTokens(cellNum, &cellNum, &serviceName);
1995         if (rc == KTC_NOENT) {
1996             /* end of list */
1997 //          printf("   --End of list --\n");
1998             break;
1999         }
2000         else if (rc == KTC_NOCM) {
2001             ShowMessageBox(IDS_GET_TOKENS_NO_AFS_SERVICE);
2002 //          printf("AFS service may not have started\n");
2003             break;
2004         }
2005         else if (rc) {
2006             ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR, MB_ICONERROR, IDS_GET_TOKENS_UNEXPECTED_ERROR, rc);
2007             return FALSE;
2008 //          printf("Unexpected error, code %d\n", rc);
2009 //          exit(1);
2010         }
2011         else {
2012             rc = ktc_GetToken(&serviceName, &token, sizeof(token), &clientName);
2013             if (rc) {
2014                 ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR2, MB_ICONERROR, IDS_GET_TOKENS_UNEXPECTED_ERROR2, 
2015                                 serviceName.name, serviceName.instance, serviceName.cell, rc);
2016                 continue;
2017             }
2018
2019             tokenExpireTime = token.endTime;
2020
2021             strcpy(userName, clientName.name);
2022             if (clientName.instance[0] != 0) {
2023                 strcat(userName, ".");
2024                 strcat(userName, clientName.instance);
2025             }
2026
2027             BOOL bShowName = FALSE;
2028
2029             if (userName[0] == '\0')
2030                 ; //printf("Tokens");
2031 // AFS ID is not returned at this time.
2032 //          else if (strncmp(userName, "AFS ID", 6) == 0)
2033 //              printf("User's (%s) tokens", userName);
2034 //              sscanf(userName, "(AFS ID %s)", szAfsID);
2035             else if (strncmp(userName, "Unix UID", 8) == 0)
2036                 ; //printf("Tokens");
2037             else
2038                 strUserName = userName;
2039 //              printf("User %s's tokens", userName);
2040                         
2041 //              printf(" for %s%s%s@%s ", serviceName.name, serviceName.instance[0] ? "." : "", serviceName.instance, serviceName.cell);
2042             strCellName = serviceName.cell;
2043                         
2044             if (tokenExpireTime <= current_time)
2045                 strExpir = "[>> Expired <<]";
2046 //              printf("[>> Expired <<]\n");
2047             else {
2048                 expireString = ctime(&tokenExpireTime);
2049                 expireString += 4;       /* Skip day of week */
2050                 expireString[12] = '\0'; /* Omit secs & year */
2051 //              printf("[Expires %s]\n", expireString);
2052                 strExpir.Format("%s", expireString);
2053             }
2054
2055             strTokenInfo = strUserName + "\t" + strCellName + "\t" + strExpir + "\t" + strCellName;
2056             tokenInfo.Add(strTokenInfo);
2057         }
2058     }
2059
2060 //      printf("Press <Enter> or <Return> when finished: ");
2061 //      gets(s);
2062     return TRUE;
2063 }
2064
2065 UINT MakeSymbolicLink(const char *strName, const char *strTarget)
2066 {
2067     struct ViceIoctl blob;
2068     char space[MAXSIZE];
2069     char * parent;
2070     char path[1024] = "";
2071     UINT code;
2072
2073     HOURGLASS hourglass;
2074     static char message[2048];
2075
2076     strcpy(path, strName);
2077     parent = Parent(path);
2078
2079     sprintf(message,"MakeSymbolicLink: name = %s target = %s parent = %s\n",strName,strTarget, parent);
2080     OutputDebugString(message);
2081
2082     if ( IsFreelanceRoot(parent) && !IsAdmin() ) {
2083         ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
2084         return FALSE;
2085     }
2086
2087     LPTSTR lpsz = new TCHAR[strlen(strTarget)+1];
2088     _tcscpy(lpsz, strName);
2089     strcpy(space, strTarget);
2090     blob.out_size = 0;
2091     blob.in_size = 1 + strlen(space);
2092     blob.in = space;
2093     blob.out = NULL;
2094     code=pioctl(lpsz, VIOC_SYMLINK, &blob, 0);
2095     delete lpsz;
2096     if (code != 0)
2097         return code;
2098     return FALSE;
2099 }
2100
2101 void ListSymbolicLinkPath(const char *strName,char *strPath,UINT nlenPath)
2102 {
2103     ASSERT(nlenPath<MAX_PATH);
2104     struct ViceIoctl blob;
2105     char orig_name[MAX_PATH+1];         /*Original name, may be modified*/
2106     char true_name[MAX_PATH+1];         /*``True'' dirname (e.g., symlink target)*/
2107     char parent_dir[MAX_PATH+1];                /*Parent directory of true name*/
2108     char *last_component;       /*Last component of true name*/
2109     UINT code;    
2110
2111     HOURGLASS hourglass;
2112
2113     strcpy(orig_name, strName);
2114     strcpy(true_name, orig_name);
2115     /*
2116      * Find rightmost slash, if any.
2117      */
2118     last_component = (char *) strrchr(true_name, '\\');
2119     if (!last_component)
2120         last_component = (char *) strrchr(true_name, '/');
2121     if (last_component) {
2122         /*
2123          * Found it.  Designate everything before it as the parent directory,
2124          * everything after it as the final component.
2125          */
2126         strncpy(parent_dir, true_name, last_component - true_name + 1);
2127         parent_dir[last_component - true_name + 1] = 0;
2128         last_component++;   /*Skip the slash*/
2129
2130         if (!IsPathInAfs(parent_dir)) {
2131             const char * nbname = NetbiosName();
2132             int len = strlen(nbname);
2133
2134             if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
2135                  parent_dir[len+2] == '\\' &&
2136                  parent_dir[len+3] == '\0' &&
2137                  !strnicmp(nbname,&parent_dir[2],len))
2138             {
2139                 sprintf(parent_dir,"\\\\%s\\all\\", nbname);
2140             }
2141         }
2142     }
2143     else {
2144         /*
2145          * No slash appears in the given file name.  Set parent_dir to the current
2146          * directory, and the last component as the given name.
2147          */
2148         fs_ExtractDriveLetter(true_name, parent_dir);
2149         strcat(parent_dir, ".");
2150         last_component = true_name;
2151         fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
2152     }
2153     blob.in = last_component;
2154     blob.in_size = strlen(last_component)+1;
2155     blob.out_size = MAXSIZE;
2156     blob.out = space;
2157     memset(space, 0, MAXSIZE);
2158     if ((code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1)))
2159         strcpy(space,"???");
2160     ASSERT(strlen(space)<MAX_PATH);
2161     strncpy(strPath,space,nlenPath);
2162 }       
2163
2164 BOOL ListSymlink(CStringArray& files)
2165 {
2166     register LONG code;
2167     struct ViceIoctl blob;
2168     int error;
2169     char orig_name[1024];                       /* Original name, may be modified */
2170     char true_name[1024];                       /* ``True'' dirname (e.g., symlink target) */
2171     char parent_dir[1024];                      /* Parent directory of true name */
2172     register char *last_component;      /* Last component of true name */
2173     CStringArray symlinks;
2174     
2175     HOURGLASS hourglass;
2176
2177     error = 0;
2178
2179     for (int i = 0; i < files.GetSize(); i++) {
2180         strcpy(orig_name, files[i]);
2181         strcpy(true_name, orig_name);
2182
2183         /*
2184          * Find rightmost slash, if any.
2185          */
2186         last_component = (char *)strrchr(true_name, '\\');
2187         if (last_component) {
2188             /*
2189              * Found it.  Designate everything before it as the parent directory,
2190              * everything after it as the final component.
2191              */
2192             strncpy(parent_dir, true_name, last_component - true_name + 1);
2193             parent_dir[last_component - true_name + 1] = 0;
2194             last_component++;   /* Skip the slash */
2195
2196             if (!IsPathInAfs(parent_dir)) {
2197                 const char * nbname = NetbiosName();
2198                 int len = strlen(nbname);
2199
2200                 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
2201                     parent_dir[len+2] == '\\' &&
2202                     parent_dir[len+3] == '\0' &&
2203                     !strnicmp(nbname,&parent_dir[2],len))
2204                 {
2205                     sprintf(parent_dir,"\\\\%s\\all\\", nbname);
2206                 }
2207             }
2208         }
2209         else {
2210             /*
2211              * No slash appears in the given file name.  Set parent_dir to the current
2212              * directory, and the last component as the given name.
2213              */
2214             fs_ExtractDriveLetter(true_name, parent_dir);
2215             strcat(parent_dir, ".");
2216             last_component = true_name;
2217             fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
2218         }
2219
2220         blob.in = last_component;
2221         blob.in_size = strlen(last_component) + 1;
2222         blob.out_size = MAXSIZE;
2223         blob.out = space;
2224         memset(space, 0, MAXSIZE);
2225
2226         code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
2227         if (code == 0) {
2228             int nPos = strlen(space) - 1;
2229             if (space[nPos] == '.')
2230                 space[nPos] = 0;
2231             symlinks.Add(ParseSymlink(StripPath(files[i]), space));
2232         } else {
2233             error = 1;
2234             if (errno == EINVAL)
2235                 symlinks.Add(GetMessageString(IDS_NOT_SYMLINK_ERROR, StripPath(files[i])));
2236             else
2237                 symlinks.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
2238         }
2239     }
2240
2241     CSymlinksDlg dlg;
2242     dlg.SetSymlinks(symlinks);
2243     dlg.DoModal();
2244
2245     return !error;
2246 }
2247