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