windows-shell-add-symlink-20080206
[openafs.git] / src / WINNT / client_exp / gui2fs.cpp
index 6865a63..3bfc1b8 100644 (file)
@@ -7,12 +7,15 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+#include "stdafx.h"
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
 extern "C" {
 #include <afs/param.h>
 #include <afs/stds.h>
 }
 
-#include "stdafx.h"
 #include <errno.h>
 #include <time.h>
 
@@ -21,21 +24,25 @@ extern "C" {
 #include "results_dlg.h"
 #include "volume_inf.h"
 #include "mount_points_dlg.h"
+#include "symlinks_dlg.h"
 #include "hourglass.h"
 #include "down_servers_dlg.h"
 
 extern "C" {
-#include <afs/param.h>
-#include <osi.h>
+#include <rx/rx_globals.h>
 #include "fs.h"
 #include "fs_utils.h"
 #include <afsint.h>
+#include <afs/cellconfig.h>
+#include <afs/vldbint.h>
+#include <afs/volser.h>
 #include <afs/auth.h>
+#include <WINNT\afsreg.h>
+#include <cm.h>
 }
 
-
 #define PCCHAR(str)            ((char *)(const char *)(str))
-
+#define VL_NOENT                (363524L)
 
 #define        MAXHOSTS 13
 #define        OMAXHOSTS 8
@@ -48,65 +55,73 @@ extern "C" {
 #define MAXHOSTCHARS           64
 #define MAXHOSTSPERCELL                8
 
-struct afsconf_cell {
-       char name[MAXCELLCHARS];
-    short numServers;
-    short flags;
-    struct sockaddr_in hostAddr[MAXHOSTSPERCELL];
-    char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];
-    char *linkedCell;
-};
-
 static char space[MAXSIZE];
 static char tspace[1024];
 
+static struct ubik_client *uclient;
+static int rxInitDone = 0;
+static char pn[] = "fs";
+
 // #define     LOGGING_ON              // Enable this to log certain pioctl calls
 
 #ifdef LOGGING_ON
 static char *szLogFileName = "afsguilog.txt";
 #endif
 
+static int
+VLDBInit(int noAuthFlag, struct afsconf_cell *info)
+{
+    afs_int32 code;
+
+    code = ugen_ClientInit(noAuthFlag, (char *)AFSDIR_CLIENT_ETC_DIRPATH, 
+                          info->name, 0, &uclient, 
+                           NULL, pn, rxkad_clear,
+                           VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
+                           0, 0, USER_SERVICE_ID);
+    rxInitDone = 1;
+    return code;
+}
 
 FILE *OpenFile(char *file, char *rwp)
 {
-       char wdir[256];
-       long code;
-       long tlen;
-       FILE *fp;
+    char wdir[256];
+    long code;
+    long tlen;
+    FILE *fp;
 
-       code = GetWindowsDirectory(wdir, sizeof(wdir));
-       if (code == 0 || code > sizeof(wdir)) 
-               return FALSE;
+    code = GetWindowsDirectory(wdir, sizeof(wdir));
+    if (code == 0 || code > sizeof(wdir)) 
+        return FALSE;
 
-       /* add trailing backslash, if required */
-       tlen = strlen(wdir);
-       if (wdir[tlen - 1] != '\\')
-               strcat(wdir, "\\");
+    /* add trailing backslash, if required */
+    tlen = strlen(wdir);
+    if (wdir[tlen - 1] != '\\')
+        strcat(wdir, "\\");
 
-       strcat(wdir, file);
+    strcat(wdir, file);
 
-       fp = fopen(wdir, rwp);
+    fp = fopen(wdir, rwp);
 
-       return fp;
-}
+    return fp;
+}       
 
 CString StripPath(CString& strPath)
 {
-       int nIndex = strPath.ReverseFind('\\');
+    int nIndex = strPath.ReverseFind('\\');
 
-       CString strFile = strPath.Mid(nIndex + 1);
-       if (strFile.IsEmpty())
-               return strPath;
+    CString strFile = strPath.Mid(nIndex + 1);
+    if (strFile.IsEmpty())
+        return strPath;
 
-       return strFile;
+    return strFile;
 }
 
 CStringArray& StripPath(CStringArray& files)
 {
-       for (int i = 0; i < files.GetSize(); i++)
-               files[i] = StripPath(files[i]);
+    for (int i = 0; i < files.GetSize(); i++)
+        files[i] = StripPath(files[i]);
 
-       return files;
+    return files;
 }
 
 void Flush(const CStringArray& files)
@@ -115,46 +130,46 @@ void Flush(const CStringArray& files)
     struct ViceIoctl blob;
     int error = 0;
 
-       HOURGLASS hourglass;
-
-       for (int i = 0; i < files.GetSize(); i++) {
-               blob.in_size = blob.out_size = 0;
+    HOURGLASS hourglass;
 
-               code = pioctl(PCCHAR(files[i]), VIOCFLUSH, &blob, 0);
-               if (code) {
-                       error = 1;
-                       if (errno == EMFILE)
-                               ShowMessageBox(IDS_FLUSH_FAILED, MB_ICONEXCLAMATION, IDS_FLUSH_FAILED, files[i]);
-                       else 
-                               ShowMessageBox(IDS_FLUSH_ERROR, MB_ICONEXCLAMATION, IDS_FLUSH_ERROR, files[i], strerror(errno));
-               }
-    }
+    for (int i = 0; i < files.GetSize(); i++) {
+        blob.in_size = blob.out_size = 0;
+
+        code = pioctl(PCCHAR(files[i]), VIOCFLUSH, &blob, 0);
+        if (code) {
+            error = 1;
+            if (errno == EMFILE)
+                ShowMessageBox(IDS_FLUSH_FAILED, MB_ICONERROR, IDS_FLUSH_FAILED, files[i]);
+            else 
+                ShowMessageBox(IDS_FLUSH_ERROR, MB_ICONERROR, IDS_FLUSH_ERROR, files[i], strerror(errno));
+        }
+    }   
 
-       if (!error)
-               ShowMessageBox(IDS_FLUSH_OK, MB_ICONEXCLAMATION, IDS_FLUSH_OK);
-}
+    if (!error)
+        ShowMessageBox(IDS_FLUSH_OK, MB_ICONINFORMATION, IDS_FLUSH_OK);
+}       
 
 void FlushVolume(const CStringArray& files)
 {
     register LONG code;
     struct ViceIoctl blob;
-       int error = 0;
+    int error = 0;
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       for (int i = 0; i < files.GetSize(); i++) {
-               blob.in_size = blob.out_size = 0;
+    for (int i = 0; i < files.GetSize(); i++) {
+        blob.in_size = blob.out_size = 0;
 
-               code = pioctl(PCCHAR(files[i]), VIOC_FLUSHVOLUME, &blob, 0);
-               if (code) {
-                       error = 1;
-                       ShowMessageBox(IDS_FLUSH_VOLUME_ERROR, MB_ICONEXCLAMATION, IDS_FLUSH_VOLUME_ERROR, files[i], strerror(errno));
-               }
-    }
+        code = pioctl(PCCHAR(files[i]), VIOC_FLUSHVOLUME, &blob, 0);
+        if (code) {
+            error = 1;
+            ShowMessageBox(IDS_FLUSH_VOLUME_ERROR, MB_ICONERROR, IDS_FLUSH_VOLUME_ERROR, files[i], strerror(errno));
+        }
+    }   
 
-       if (!code)
-               ShowMessageBox(IDS_FLUSH_VOLUME_OK, MB_ICONEXCLAMATION, IDS_FLUSH_VOLUME_OK);
-}
+    if (!code)
+        ShowMessageBox(IDS_FLUSH_VOLUME_OK, MB_ICONINFORMATION, IDS_FLUSH_VOLUME_OK);
+}       
 
 void WhichCell(CStringArray& files)
 {
@@ -164,33 +179,33 @@ void WhichCell(CStringArray& files)
     CString str;
     CString str2;
 
-       CStringArray results;
+    CStringArray results;
 
     error = 0;
 
-       HOURGLASS hourglass;
-
-       for (int i = 0; i < files.GetSize(); i++) {
-               blob.in_size = 0;
-               blob.out_size = MAXSIZE;
-               blob.out = space;
-
-               code = pioctl(PCCHAR(files[i]), VIOC_FILE_CELL_NAME, &blob, 1);
-               if (code) {
-                       if (code == ENOENT) {
-                               LoadString (str, IDS_CANT_GET_CELL);
-                               results.Add(str);
-                       } else
-                               results.Add(GetAfsError(errno));
-               } else
-                       results.Add(space);
-       }
+    HOURGLASS hourglass;
 
-       LoadString (str, IDS_SHOW_CELL);
-       LoadString (str2, IDS_SHOW_CELL_COLUMN);
-       CResultsDlg dlg(SHOW_CELL_HELP_ID);
-       dlg.SetContents(str, str2, StripPath(files), results);
-       dlg.DoModal();
+    for (int i = 0; i < files.GetSize(); i++) {
+        blob.in_size = 0;
+        blob.out_size = MAXSIZE;
+        blob.out = space;
+
+        code = pioctl(PCCHAR(files[i]), VIOC_FILE_CELL_NAME, &blob, 1);
+        if (code) {
+            if (code == ENOENT) {
+                LoadString (str, IDS_CANT_GET_CELL);
+                results.Add(str);
+            } else
+                results.Add(GetAfsError(errno));
+        } else
+            results.Add(space);
+    }       
+
+    LoadString (str, IDS_SHOW_CELL);
+    LoadString (str2, IDS_SHOW_CELL_COLUMN);
+    CResultsDlg dlg(SHOW_CELL_HELP_ID);
+    dlg.SetContents(str, str2, StripPath(files), results);
+    dlg.DoModal();
 }
 
 void WSCellCmd()
@@ -198,7 +213,7 @@ void WSCellCmd()
     register LONG code;
     struct ViceIoctl blob;
     
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
     blob.in_size = 0;
     blob.in = (char *) 0;
@@ -208,10 +223,10 @@ void WSCellCmd()
     code = pioctl((char *) 0, VIOC_GET_WS_CELL, &blob, 1);
 
     if (code) {
-               //Die(errno, (char *) 0);
+        //Die(errno, (char *) 0);
     }
     //else
-               //printf("This workstation belongs to cell '%s'\n", space);
+    //printf("This workstation belongs to cell '%s'\n", space);
 }
 
 BOOL CheckVolumes()
@@ -223,13 +238,13 @@ BOOL CheckVolumes()
     blob.out_size = 0;
     code = pioctl(0, VIOCCKBACK, &blob, 1);
     if (code) {
-               ShowMessageBox(IDS_CHECK_VOLUMES_ERROR, MB_ICONEXCLAMATION, IDS_CHECK_VOLUMES_ERROR, GetAfsError(errno, CString()));
-               return FALSE;
+        ShowMessageBox(IDS_CHECK_VOLUMES_ERROR, MB_ICONERROR, IDS_CHECK_VOLUMES_ERROR, GetAfsError(errno, CString()));
+        return FALSE;
     }
 
-    ShowMessageBox(IDS_CHECK_VOLUMES_OK, MB_OK, IDS_CHECK_VOLUMES_OK);
+    ShowMessageBox(IDS_CHECK_VOLUMES_OK, MB_OK|MB_ICONINFORMATION, IDS_CHECK_VOLUMES_OK);
 
-       return TRUE;
+    return TRUE;
 }
 
 void SetCacheSizeCmd(LONG nNewCacheSize)
@@ -237,98 +252,142 @@ void SetCacheSizeCmd(LONG nNewCacheSize)
     register LONG code;
     struct ViceIoctl blob;
     
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       blob.in = (char *) &nNewCacheSize;
+    blob.in = (char *) &nNewCacheSize;
     blob.in_size = sizeof(LONG);
     blob.out_size = 0;
 
     code = pioctl(0, VIOCSETCACHESIZE, &blob, 1);
     //if (code)
-       //      Die(errno, (char *) 0);
+    // Die(errno, (char *) 0);
     //else
-       //      printf("New cache size set.\n");
+    // printf("New cache size set.\n");
 }
 
 void WhereIs(CStringArray& files)
 {
     register LONG code;
     struct ViceIoctl blob;
-       CStringArray servers;
-       CStringArray resultFiles;
-       CString str;
-       CString str2;
-
-       HOURGLASS hourglass;
-
-       for (int i = 0; i < files.GetSize(); i++) {
-               blob.out_size = MAXSIZE;
-               blob.in_size = 0;
-               blob.out = space;
-               memset(space, 0, sizeof(space));
-
-               code = pioctl(PCCHAR(files[i]), VIOCWHEREIS, &blob, 1);
-               if (code) {
-                       resultFiles.Add(StripPath(files[i]));
-                       servers.Add(GetAfsError(errno));
-                       continue;
-               }
-               
-               LONG *hosts = (LONG *)space;
-               BOOL bFirst = TRUE;
-               str = "";
-
-               for (int j = 0; j < MAXHOSTS; j++) {
-                       if (hosts[j] == 0)
-                               break;
-                       char *hostName = hostutil_GetNameByINet(hosts[j]);
-                       if (bFirst) {
-                               resultFiles.Add(StripPath(files[i]));
-                               bFirst = FALSE;
-                       } else
-                               resultFiles.Add(" ");
-                       servers.Add(hostName);
-               }
-       }
+    CStringArray servers;
+    CStringArray resultFiles;
+    CString str;
+    CString str2;
 
-       LoadString (str, IDS_SHOW_FS);
-       LoadString (str2, IDS_SHOW_FS_COLUMN);
-       CResultsDlg dlg(SHOW_FILE_SERVERS_HELP_ID);
-       dlg.SetContents(str, str2, resultFiles, servers);
-       dlg.DoModal();
+    HOURGLASS hourglass;
+
+    for (int i = 0; i < files.GetSize(); i++) {
+        blob.out_size = MAXSIZE;
+        blob.in_size = 0;
+        blob.out = space;
+        memset(space, 0, sizeof(space));
+
+        code = pioctl(PCCHAR(files[i]), VIOCWHEREIS, &blob, 1);
+        if (code) {
+            resultFiles.Add(StripPath(files[i]));
+            servers.Add(GetAfsError(errno));
+            continue;
+        }
+
+        LONG *hosts = (LONG *)space;
+        BOOL bFirst = TRUE;
+        str = "";
+
+        for (int j = 0; j < MAXHOSTS; j++) {
+            if (hosts[j] == 0)
+                break;
+            char *hostName = hostutil_GetNameByINet(hosts[j]);
+            if (bFirst) {
+                resultFiles.Add(StripPath(files[i]));
+                bFirst = FALSE;
+            } else
+                resultFiles.Add(" ");
+            servers.Add(hostName);
+        }
+    }
+
+    LoadString (str, IDS_SHOW_FS);
+    LoadString (str2, IDS_SHOW_FS_COLUMN);
+    CResultsDlg dlg(SHOW_FILE_SERVERS_HELP_ID);
+    dlg.SetContents(str, str2, resultFiles, servers);
+    dlg.DoModal();
+}       
+
+static int
+CMtoUNIXerror(int cm_code)
+{
+    switch (cm_code) {
+    case CM_ERROR_TIMEDOUT:
+       return ETIMEDOUT;
+    case CM_ERROR_NOACCESS:
+       return EACCES;
+    case CM_ERROR_NOSUCHFILE:
+       return ENOENT;
+    case CM_ERROR_INVAL:
+       return EINVAL;
+    case CM_ERROR_BADFD:
+       return EBADF;
+    case CM_ERROR_EXISTS:
+       return EEXIST;
+    case CM_ERROR_CROSSDEVLINK:
+       return EXDEV;
+    case CM_ERROR_NOTDIR:
+       return ENOTDIR;
+    case CM_ERROR_ISDIR:
+       return EISDIR;
+    case CM_ERROR_READONLY:
+       return EROFS;
+    case CM_ERROR_WOULDBLOCK:
+       return EWOULDBLOCK;
+    case CM_ERROR_NOSUCHCELL:
+       return ESRCH;           /* hack */
+    case CM_ERROR_NOSUCHVOLUME:
+       return EPIPE;           /* hack */
+    case CM_ERROR_NOMORETOKENS:
+       return EDOM;            /* hack */
+    case CM_ERROR_TOOMANYBUFS:
+       return EFBIG;           /* hack */
+    default:
+       if (cm_code > 0 && cm_code < EILSEQ)
+           return cm_code;
+       else
+           return ENOTTY;
+    }
 }
 
 CString GetAfsError(int code, const char *filename)
 {
     CString strMsg;
 
-       if (code == EINVAL) {
-               if (filename)
-                   strMsg.Format("Invalid argument; it is possible that the file is not in AFS");
-               else 
-                       strMsg.Format("Invalid argument");
+    code = CMtoUNIXerror(code);
+
+    if (code == EINVAL) {
+        if (filename)
+            strMsg.Format("Invalid argument; it is possible that the file is not in AFS");
+        else 
+            strMsg.Format("Invalid argument");
     } else if (code == ENOENT) {
-               if (filename) 
-                       strMsg.Format("The file does not exist");
-               else 
-                       strMsg.Format("No such file returned");
+        if (filename) 
+            strMsg.Format("The file does not exist");
+        else 
+            strMsg.Format("No such file returned");
     } else if (code == EROFS)  {
-               strMsg.Format("You can not change a backup or readonly volume");
+        strMsg.Format("You can not change a backup or readonly volume");
     } else if (code == EACCES || code == EPERM) {
-               strMsg.Format("You do not have the required rights to do this operation");
+        strMsg.Format("You do not have the required rights to do this operation");
     } else if (code == ENODEV) {
-               strMsg.Format("AFS service may not have started");
+        strMsg.Format("AFS service may not have started");
     } else if (code == ESRCH) {
-               strMsg.Format("Cell name not recognized");
+        strMsg.Format("Cell name not recognized");
     } else if (code == ETIMEDOUT) {
-               strMsg.Format("Connection timed out");
+        strMsg.Format("Connection timed out");
     } else if (code == EPIPE) {
-               strMsg.Format("Volume name or ID not recognized");
+        strMsg.Format("Volume name or ID not recognized");
     } else {
-               strMsg.Format("Error 0x%x occurred", code);
+        strMsg.Format("Error 0x%x occurred", code);
     }
 
-       return strMsg;
+    return strMsg;
 }
 
 
@@ -345,9 +404,9 @@ struct AclEntry {
 };
 
 struct Acl {
-    int dfs;                           //      Originally true if a dfs acl; now also the type
-                                                       //      of the acl (1, 2, or 3, corresponding to object,
-                                                       //      initial dir, or initial object).
+    int dfs;                   //      Originally true if a dfs acl; now also the type
+                                //     of the acl (1, 2, or 3, corresponding to object,
+                               //      initial dir, or initial object).
     sec_rgy_name_t cell;       //      DFS cell name
     int nplus;
     int nminus;
@@ -391,41 +450,41 @@ extern "C" int PruneList (struct AclEntry **ae, int dfs)
     struct AclEntry *te, *ne;
     LONG ctr = 0;
     
-       for (te = *ae; te; te = ne) {
+    for (te = *ae; te; te = ne) {
         if ((!dfs && te->rights == 0) || te->rights == -1) {
             *lp = te->next;
             ne = te->next;
             free(te);
             ctr++;
-               }
+        }
         else {
             ne = te->next;
             lp = &te->next;
-               }
+        }
     }
     
-       return ctr;
+    return ctr;
 }
 
 char *SkipLine (register char *astr)
 {
     while (*astr != '\n') 
-               astr++;
+        astr++;
     
-       astr++;
+    astr++;
     
-       return astr;
+    return astr;
 }
 
 /* tell if a name is 23 or -45 (digits or minus digits), which are bad names we must prune */
-static BadName(register char *aname)
+static int BadName(register char *aname)
 {
     register int tc;
 
-       /* all must be '-' or digit to be bad */
+    /* all must be '-' or digit to be bad */
     while (tc = *aname++) {
-               if ((tc != '-') && (tc < '0' || tc > '9')) 
-                       return 0;
+        if ((tc != '-') && (tc < '0' || tc > '9')) 
+            return 0;
     }
 
     return 1;
@@ -433,18 +492,18 @@ static BadName(register char *aname)
 
 CString GetRightsString(register LONG arights, int dfs)
 {
-       CString str;
+    CString str;
 
     if (!dfs) {
-               if (arights & PRSFS_READ) str += "r";
-               if (arights & PRSFS_LOOKUP) str += "l";
-               if (arights & PRSFS_INSERT) str += "i";
-               if (arights & PRSFS_DELETE) str += "d";
-               if (arights & PRSFS_WRITE) str += "w";
-               if (arights & PRSFS_LOCK) str += "k";
-               if (arights & PRSFS_ADMINISTER) str += "a";
+        if (arights & PRSFS_READ) str += "r";
+        if (arights & PRSFS_LOOKUP) str += "l";
+        if (arights & PRSFS_INSERT) str += "i";
+        if (arights & PRSFS_DELETE) str += "d";
+        if (arights & PRSFS_WRITE) str += "w";
+        if (arights & PRSFS_LOCK) str += "k";
+        if (arights & PRSFS_ADMINISTER) str += "a";
     } else {
-               ASSERT(FALSE);
+        ASSERT(FALSE);
 /*
                if (arights & DFS_READ) str += "r"; else str += "-";
                if (arights & DFS_WRITE) str += "w"; else printf("-");
@@ -454,9 +513,9 @@ CString GetRightsString(register LONG arights, int dfs)
                if (arights & DFS_DELETE) str += "d"; else printf("-");
                if (arights & (DFS_USRALL)) str += "+";
 */
-       }       
+    }  
 
-       return str;
+    return str;
 }
 
 char *AclToString(struct Acl *acl)
@@ -467,22 +526,22 @@ char *AclToString(struct Acl *acl)
     struct AclEntry *tp;
     
     if (acl->dfs)
-               sprintf(dfsstring, " dfs:%d %s", acl->dfs, acl->cell);
+        sprintf(dfsstring, " dfs:%d %s", acl->dfs, acl->cell);
     else
-               dfsstring[0] = '\0';
+        dfsstring[0] = '\0';
     sprintf(mydata, "%d%s\n%d\n", acl->nplus, dfsstring, acl->nminus);
     
-       for(tp = acl->pluslist; tp; tp = tp->next) {
+    for(tp = acl->pluslist; tp; tp = tp->next) {
         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
         strcat(mydata, tstring);
     }
     
-       for(tp = acl->minuslist; tp; tp = tp->next) {
+    for(tp = acl->minuslist; tp; tp = tp->next) {
         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
         strcat(mydata, tstring);
     }
     
-       return mydata;
+    return mydata;
 }
 
 struct Acl *EmptyAcl(const CString& strCellName)
@@ -559,42 +618,42 @@ extern "C" int CleanAcl(struct Acl *aa)
     register struct AclEntry *te, **le, *ne;
     int changes;
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
     /* Don't correct DFS ACL's for now */
     if (aa->dfs)
-               return 0;
+        return 0;
 
     /* prune out bad entries */
     changes = 0;           /* count deleted entries */
     le = &aa->pluslist;
     for(te = aa->pluslist; te; te = ne) {
-               ne = te->next;
-               if (BadName(te->name)) {
-                       /* zap this dude */
-                       *le = te->next;
-                       aa->nplus--;
-                       free(te);
-                       changes++;
-               }
-               else
-                       le = &te->next;
+        ne = te->next;
+        if (BadName(te->name)) {
+            /* zap this dude */
+            *le = te->next;
+            aa->nplus--;
+            free(te);
+            changes++;
+        }
+        else
+            le = &te->next;
     }
 
     le = &aa->minuslist;
     
-       for(te = aa->minuslist; te; te = ne) {
-               ne = te->next;
-               if (BadName(te->name)) {
-                       /* zap this dude */
-                       *le = te->next;
-                       aa->nminus--;
-                       free(te);
-                       changes++;
-               }
-               else
-                       le = &te->next;
-    }
+    for(te = aa->minuslist; te; te = ne) {
+        ne = te->next;
+        if (BadName(te->name)) {
+            /* zap this dude */
+            *le = te->next;
+            aa->nminus--;
+            free(te);
+            changes++;
+        }
+        else
+            le = &te->next;
+    }   
 
     return changes;
 }
@@ -606,49 +665,49 @@ void CleanACL(CStringArray& names)
     struct ViceIoctl blob;
     int changes;
 
-       ShowMessageBox(IDS_CLEANACL_MSG, MB_OK, IDS_CLEANACL_MSG);
+    ShowMessageBox(IDS_CLEANACL_MSG, MB_OK|MB_ICONINFORMATION, IDS_CLEANACL_MSG);
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       for (int i = 0; i < names.GetSize(); i++) {
-               blob.out_size = MAXSIZE;
-               blob.in_size = 0;
-               blob.out = space;
+    for (int i = 0; i < names.GetSize(); i++) {
+        blob.out_size = MAXSIZE;
+        blob.in_size = 0;
+        blob.out = space;
 
-               code = pioctl(PCCHAR(names[i]), VIOCGETAL, &blob, 1);
-               if (code) {
-                       ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONEXCLAMATION, 0, names[i], GetAfsError(errno));
-                       continue;
-               }
-               
-               ta = ParseAcl(space);
-               if (ta->dfs) {
-                       ShowMessageBox(IDS_CLEANACL_NOT_SUPPORTED, MB_ICONEXCLAMATION, IDS_CLEANACL_NOT_SUPPORTED, names[i]);
-                       continue;
-               }
+        code = pioctl(PCCHAR(names[i]), VIOCGETAL, &blob, 1);
+        if (code) {
+            ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONERROR, 0, names[i], GetAfsError(errno));
+            continue;
+        }
+
+        ta = ParseAcl(space);
+        if (ta->dfs) {
+            ShowMessageBox(IDS_CLEANACL_NOT_SUPPORTED, MB_ICONERROR, IDS_CLEANACL_NOT_SUPPORTED, names[i]);
+            continue;
+        }
 
-               changes = CleanAcl(ta);
-               if (!changes)
-                       continue;
+        changes = CleanAcl(ta);
+        if (!changes)
+            continue;
 
-               /* now set the acl */
-               blob.in = AclToString(ta);
-               blob.in_size = strlen((char *)blob.in) + 1;
-               blob.out_size = 0;
+        /* now set the acl */
+        blob.in = AclToString(ta);
+        blob.in_size = strlen((char *)blob.in) + 1;
+        blob.out_size = 0;
                
-               code = pioctl(PCCHAR(names[i]), VIOCSETAL, &blob, 1);
-               if (code) {
-                       if (errno == EINVAL) {
-                               ShowMessageBox(IDS_CLEANACL_INVALID_ARG, MB_ICONEXCLAMATION, IDS_CLEANACL_INVALID_ARG, names[i]);
-                               continue;
-                       }
-                       else {
-                               ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONEXCLAMATION, 0, names[i], GetAfsError(errno));
-                               continue;
-                       }
-               }
-       }
-}
+        code = pioctl(PCCHAR(names[i]), VIOCSETAL, &blob, 1);
+        if (code) {
+            if (errno == EINVAL) {
+                ShowMessageBox(IDS_CLEANACL_INVALID_ARG, MB_ICONERROR, IDS_CLEANACL_INVALID_ARG, names[i]);
+                continue;
+            }
+            else {
+                ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONERROR, 0, names[i], GetAfsError(errno));
+                continue;
+            }
+        }
+    }
+}       
 
 // Derived from fs.c's ListAclCmd
 BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& strNegative)
@@ -659,70 +718,70 @@ BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& str
     struct AclEntry *te;
     int idf = 0; //getidf(as, parm_listacl_id);
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       blob.out_size = MAXSIZE;
-       blob.in_size = idf;
-       blob.in = blob.out = space;
+    blob.out_size = MAXSIZE;
+    blob.in_size = idf;
+    blob.in = blob.out = space;
        
-       code = pioctl(PCCHAR(strDir), VIOCGETAL, &blob, 1);
-       if (code) {
-               ShowMessageBox(IDS_GETRIGHTS_ERROR, MB_ICONEXCLAMATION, IDS_GETRIGHTS_ERROR, strDir, GetAfsError(errno));
-               return FALSE;
-       }
+    code = pioctl(PCCHAR(strDir), VIOCGETAL, &blob, 1);
+    if (code) {
+        ShowMessageBox(IDS_GETRIGHTS_ERROR, MB_ICONERROR, IDS_GETRIGHTS_ERROR, strDir, GetAfsError(errno));
+        return FALSE;
+    }
 
-       ta = ParseAcl(space);
-       if (ta->dfs) {
-               ShowMessageBox(IDS_DFSACL_ERROR, MB_ICONEXCLAMATION, IDS_DFSACL_ERROR);
-               return FALSE;
-       }
+    ta = ParseAcl(space);
+    if (ta->dfs) {
+        ShowMessageBox(IDS_DFSACL_ERROR, MB_ICONERROR, IDS_DFSACL_ERROR);
+        return FALSE;
+    }
 
 //     if (ta->dfs)
 //             printf("  Default cell = %s\n", ta->cell);
 
-       CString strRight;
+    CString strRight;
 
-       if (ta->nplus > 0) {
-               for (te = ta->pluslist; te; te = te->next) {
-                       strNormal.Add(te->name);
-                       strNormal.Add(GetRightsString(te->rights, ta->dfs));
-               }
-       }
+    if (ta->nplus > 0) {
+        for (te = ta->pluslist; te; te = te->next) {
+            strNormal.Add(te->name);
+            strNormal.Add(GetRightsString(te->rights, ta->dfs));
+        }
+    }
 
-       if (ta->nminus > 0) {
-               for (te = ta->minuslist; te; te = te->next) {
-                       strNegative.Add(te->name);
-                       strNegative.Add(GetRightsString(te->rights, ta->dfs));
-               }
-       }
+    if (ta->nminus > 0) {
+        for (te = ta->minuslist; te; te = te->next) {
+            strNegative.Add(te->name);
+            strNegative.Add(GetRightsString(te->rights, ta->dfs));
+        }
+    }
 
-       return TRUE;
+    return TRUE;
 }
 
 struct AclEntry *FindList(register struct AclEntry *pCurEntry, const char *entryName)
 {
     while (pCurEntry) {
         if (!foldcmp(pCurEntry->name, PCCHAR(entryName)))
-                       return pCurEntry;
-               pCurEntry = pCurEntry->next;
+            return pCurEntry;
+        pCurEntry = pCurEntry->next;
     }
     
-       return 0;
+    return 0;
 }
 
 void ChangeList (struct Acl *pAcl, BYTE bNormalRights, const char *entryName, LONG nEntryRights)
 {
-       ASSERT(pAcl);
-       ASSERT(entryName);
+    ASSERT(pAcl);
+    ASSERT(entryName);
     
-       struct AclEntry *pEntry;
+    struct AclEntry *pEntry;
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
     pEntry = (bNormalRights ? pAcl->pluslist : pAcl->minuslist);
     pEntry = FindList(pEntry, entryName);
 
-       /* Found the item already in the list. */
+    /* Found the item already in the list. */
     if (pEntry) {
         pEntry->rights = nEntryRights;
         if (bNormalRights)
@@ -736,22 +795,22 @@ void ChangeList (struct Acl *pAcl, BYTE bNormalRights, const char *entryName, LO
     pEntry = (struct AclEntry *) malloc(sizeof (struct AclEntry));
     ASSERT(pEntry);
        
-       strcpy(pEntry->name, entryName);
+    strcpy(pEntry->name, entryName);
     pEntry->rights = nEntryRights;
     
-       if (bNormalRights) {
+    if (bNormalRights) {
         pEntry->next = pAcl->pluslist;
         pAcl->pluslist = pEntry;
         pAcl->nplus++;
         if (nEntryRights == 0 || nEntryRights == -1)
-                       pAcl->nplus -= PruneList(&pAcl->pluslist, pAcl->dfs);
+            pAcl->nplus -= PruneList(&pAcl->pluslist, pAcl->dfs);
     }
     else {
         pEntry->next = pAcl->minuslist;
         pAcl->minuslist = pEntry;
         pAcl->nminus++;
         if (nEntryRights == 0)
-                       pAcl->nminus -= PruneList(&pAcl->minuslist, pAcl->dfs);
+            pAcl->nminus -= PruneList(&pAcl->minuslist, pAcl->dfs);
     }
 }
 
@@ -765,18 +824,18 @@ LONG Convert(const register char *arights, int dfs, enum rtype *rtypep)
 
     *rtypep = add;     /* add rights, by default */
 
-       if (!strcmp(arights,"read")) 
-               return PRSFS_READ | PRSFS_LOOKUP;
-       if (!strcmp(arights, "write")) 
-               return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK;
-       if (!strcmp(arights, "mail")) 
-               return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
-       if (!strcmp(arights, "all")) 
-               return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
+    if (!strcmp(arights,"read")) 
+        return PRSFS_READ | PRSFS_LOOKUP;
+    if (!strcmp(arights, "write")) 
+        return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK;
+    if (!strcmp(arights, "mail")) 
+        return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
+    if (!strcmp(arights, "all")) 
+        return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
     
-       if (!strcmp(arights, "none")) {
-               *rtypep = destroy; /* Remove entire entry */
-               return 0;
+    if (!strcmp(arights, "none")) {
+        *rtypep = destroy; /* Remove entire entry */
+        return 0;
     }
 
     len = strlen(arights);
@@ -784,18 +843,18 @@ LONG Convert(const register char *arights, int dfs, enum rtype *rtypep)
 
     for (i = 0; i < len; i++) {
         tc = *arights++;
-               if (tc == 'r') mode |= PRSFS_READ;
-               else if (tc == 'l') mode |= PRSFS_LOOKUP;
-               else if (tc == 'i') mode |= PRSFS_INSERT;
-               else if (tc == 'd') mode |= PRSFS_DELETE;
-               else if (tc == 'w') mode |= PRSFS_WRITE;
-               else if (tc == 'k') mode |= PRSFS_LOCK;
-               else if (tc == 'a') mode |= PRSFS_ADMINISTER;
-               else {
-                       fprintf(stderr, "illegal rights character '%c'.\n", tc);
-                       exit(1);
-               }
-    }
+        if (tc == 'r') mode |= PRSFS_READ;
+        else if (tc == 'l') mode |= PRSFS_LOOKUP;
+        else if (tc == 'i') mode |= PRSFS_INSERT;
+        else if (tc == 'd') mode |= PRSFS_DELETE;
+        else if (tc == 'w') mode |= PRSFS_WRITE;
+        else if (tc == 'k') mode |= PRSFS_LOCK;
+        else if (tc == 'a') mode |= PRSFS_ADMINISTER;
+        else {
+            fprintf(stderr, "illegal rights character '%c'.\n", tc);
+            exit(1);
+        }
+    }   
     return mode;
 }
 
@@ -805,39 +864,40 @@ BOOL SaveACL(const CString& strCellName, const CString& strDir, const CStringArr
     struct ViceIoctl blob;
     struct Acl *pAcl;
     LONG rights;
-       enum rtype rtype;
+    enum rtype rtype;
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       // Create a new ACL
-       pAcl = EmptyAcl(strCellName);
+    // Create a new ACL
+    pAcl = EmptyAcl(strCellName);
 
-       // Set its normal rights
-       for (int i = 0; i < normal.GetSize(); i += 2) {
-               rights = Convert(normal[i + 1], 0, &rtype);
-               ChangeList(pAcl, TRUE, normal[i], rights);
-       }
+    // Set its normal rights
+    int i;
+    for (i = 0; i < normal.GetSize(); i += 2) {
+        rights = Convert(normal[i + 1], 0, &rtype);
+        ChangeList(pAcl, TRUE, normal[i], rights);
+    }
 
-       // Set its negative rights
-       for (i = 0; i < negative.GetSize(); i += 2) {
-               rights = Convert(negative[i + 1], 0, &rtype);
-               ChangeList(pAcl, FALSE, negative[i], rights);
-       }
+    // Set its negative rights
+    for (i = 0; i < negative.GetSize(); i += 2) {
+        rights = Convert(negative[i + 1], 0, &rtype);
+        ChangeList(pAcl, FALSE, negative[i], rights);
+    }
 
-       // Write the ACL
-       blob.in = AclToString(pAcl);
-       blob.out_size = 0;
-       blob.in_size = 1 + strlen((const char *)blob.in);
-       
-       code = pioctl(PCCHAR(strDir), VIOCSETAL, &blob, 1);
-       if (code) {
-               if (errno == EINVAL)
-                       ShowMessageBox(IDS_SAVE_ACL_EINVAL_ERROR, MB_ICONEXCLAMATION, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
-               else
-                       ShowMessageBox(IDS_SAVE_ACL_ERROR, MB_ICONEXCLAMATION, IDS_SAVE_ACL_ERROR, strDir, GetAfsError(errno, strDir));
-       }
+    // Write the ACL
+    blob.in = AclToString(pAcl);
+    blob.out_size = 0;
+    blob.in_size = 1 + strlen((const char *)blob.in);
 
-       ZapAcl(pAcl);
+    code = pioctl(PCCHAR(strDir), VIOCSETAL, &blob, 1);
+    if (code) {
+        if (errno == EINVAL)
+            ShowMessageBox(IDS_SAVE_ACL_EINVAL_ERROR, MB_ICONERROR, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
+        else
+            ShowMessageBox(IDS_SAVE_ACL_ERROR, MB_ICONERROR, IDS_SAVE_ACL_ERROR, strDir, GetAfsError(errno, strDir));
+    }       
+
+    ZapAcl(pAcl);
 
     return (code == 0);
 }
@@ -849,162 +909,101 @@ BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringA
     struct Acl *pToAcl;
     int idf = 0; // getidf(as, parm_copyacl_id);
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       // Get ACL to copy to
-       blob.out_size = MAXSIZE;
-       blob.in_size = idf;
-       blob.in = blob.out = space;
-       
-       code = pioctl(PCCHAR(strToDir), VIOCGETAL, &blob, 1);
-       if (code) {
-               ShowMessageBox(IDS_ACL_READ_ERROR, MB_ICONEXCLAMATION, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
-               return FALSE;
-       }
-       
-       if (bClear) 
-               pToAcl = EmptyAcl(space);
-       else 
-               pToAcl = ParseAcl(space);
+    // Get ACL to copy to
+    blob.out_size = MAXSIZE;
+    blob.in_size = idf;
+    blob.in = blob.out = space;
        
-       CleanAcl(pToAcl);
+    code = pioctl(PCCHAR(strToDir), VIOCGETAL, &blob, 1);
+    if (code) {
+        ShowMessageBox(IDS_ACL_READ_ERROR, MB_ICONERROR, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
+        return FALSE;
+    }
        
-       if (pToAcl->dfs) {
-               ShowMessageBox(IDS_NO_DFS_COPY_ACL, MB_ICONEXCLAMATION, IDS_NO_DFS_COPY_ACL, strToDir);
-               ZapAcl(pToAcl);
-               return FALSE;
-       }
+    if (bClear) 
+        pToAcl = EmptyAcl(space);
+    else 
+        pToAcl = ParseAcl(space);
 
-       enum rtype rtype;
+    CleanAcl(pToAcl);
 
-       // Set normal rights
-       for (int i = 0; i < normal.GetSize(); i += 2) {
-               LONG rights = Convert(normal[i + 1], 0, &rtype);
-               ChangeList(pToAcl, TRUE, normal[i], rights);
-       }
+    if (pToAcl->dfs) {
+        ShowMessageBox(IDS_NO_DFS_COPY_ACL, MB_ICONERROR, IDS_NO_DFS_COPY_ACL, strToDir);
+        ZapAcl(pToAcl);
+        return FALSE;
+    }
 
-       // Set negative rights
-       for (i = 0; i < negative.GetSize(); i += 2) {
-               LONG rights = Convert(negative[i + 1], 0, &rtype);
-               ChangeList(pToAcl, FALSE, normal[i], rights);
-       }
+    enum rtype rtype;
 
-       // Save modified ACL
-       blob.in = AclToString(pToAcl);
-       blob.out_size = 0;
-       blob.in_size = 1 + strlen((char *)blob.in);
-       
-       code = pioctl(PCCHAR(strToDir), VIOCSETAL, &blob, 1);
-       if (code) {
-               ZapAcl(pToAcl);
-               if (errno == EINVAL)
-                       ShowMessageBox(IDS_COPY_ACL_EINVAL_ERROR, MB_ICONEXCLAMATION, IDS_COPY_ACL_EINVAL_ERROR, strToDir);
-               else 
-                       ShowMessageBox(IDS_COPY_ACL_ERROR, MB_ICONEXCLAMATION, IDS_COPY_ACL_ERROR, strToDir, GetAfsError(errno, strToDir));
-               return FALSE;
-       }
+    // Set normal rights
+    int i;
+    for (i = 0; i < normal.GetSize(); i += 2) {
+        LONG rights = Convert(normal[i + 1], 0, &rtype);
+        ChangeList(pToAcl, TRUE, normal[i], rights);
+    }
+
+    // Set negative rights
+    for (i = 0; i < negative.GetSize(); i += 2) {
+        LONG rights = Convert(negative[i + 1], 0, &rtype);
+        ChangeList(pToAcl, FALSE, normal[i], rights);
+    }
+
+    // Save modified ACL
+    blob.in = AclToString(pToAcl);
+    blob.out_size = 0;
+    blob.in_size = 1 + strlen((char *)blob.in);
+
+    code = pioctl(PCCHAR(strToDir), VIOCSETAL, &blob, 1);
+    if (code) {
+        ZapAcl(pToAcl);
+        if (errno == EINVAL)
+            ShowMessageBox(IDS_COPY_ACL_EINVAL_ERROR, MB_ICONERROR, IDS_COPY_ACL_EINVAL_ERROR, strToDir);
+        else 
+            ShowMessageBox(IDS_COPY_ACL_ERROR, MB_ICONERROR, IDS_COPY_ACL_ERROR, strToDir, GetAfsError(errno, strToDir));
+        return FALSE;
+    }
 
-       ZapAcl(pToAcl);
+    ZapAcl(pToAcl);
 
-       ShowMessageBox(IDS_COPY_ACL_OK, MB_OK, IDS_COPY_ACL_OK);
+    ShowMessageBox(IDS_COPY_ACL_OK, MB_OK|MB_ICONINFORMATION, IDS_COPY_ACL_OK);
 
     return TRUE;
 }
 
 CString ParseMountPoint(const CString strFile, CString strMountPoint)
 {
-       CString strType;
-       CString strVolume;
-       CString strCell;
-       CString strMountPointInfo;
-
-       if (strMountPoint[0] == '#')
-               strType = "Regular";
-       else if (strMountPoint[0] == '%')
-               strType = "Read/Write";
-
-       int nColon = strMountPoint.Find(':');
-       if (nColon >= 0) {
-               strCell = strMountPoint.Mid(1, nColon - 1);
-               strVolume = strMountPoint.Mid(nColon + 1);
-       } else
-               strVolume = strMountPoint.Mid(1);
-
-       strMountPointInfo = strFile + "\t" + strVolume + "\t" + strCell + "\t" + strType;
-
-       return strMountPointInfo;
-}
+    CString strType;
+    CString strVolume;
+    CString strCell;
+    CString strMountPointInfo;
 
-BOOL ListMount(CStringArray& files)
-{
-    register LONG code;
-    struct ViceIoctl blob;
-    int error;
-    char orig_name[1024];                      /* Original name, may be modified */
-    char true_name[1024];                      /* ``True'' dirname (e.g., symlink target) */
-    char parent_dir[1024];                     /* Parent directory of true name */
-    register char *last_component;     /* Last component of true name */
-       CStringArray mountPoints;
-    
-       HOURGLASS hourglass;
+    if (strMountPoint[0] == '#')
+        strType = "Regular";
+    else if (strMountPoint[0] == '%')
+        strType = "Read/Write";
 
-    error = 0;
+    int nColon = strMountPoint.Find(':');
+    if (nColon >= 0) {
+        strCell = strMountPoint.Mid(1, nColon - 1);
+        strVolume = strMountPoint.Mid(nColon + 1);
+    } else
+        strVolume = strMountPoint.Mid(1);
 
-    for (int i = 0; i < files.GetSize(); i++) {
-               strcpy(orig_name, files[i]);
-               strcpy(true_name, orig_name);
-
-               /*
-                * Find rightmost slash, if any.
-                */
-               last_component = (char *)strrchr(true_name, '\\');
-               if (last_component) {
-                       /*
-                        * Found it.  Designate everything before it as the parent directory,
-                        * everything after it as the final component.
-                        */
-                       strncpy(parent_dir, true_name, last_component - true_name + 1);
-                       parent_dir[last_component - true_name + 1] = 0;
-                       last_component++;   /* Skip the slash */
-               }
-               else {
-                       /*
-                        * No slash appears in the given file name.  Set parent_dir to the current
-                        * directory, and the last component as the given name.
-                        */
-                       fs_ExtractDriveLetter(true_name, parent_dir);
-                       strcat(parent_dir, ".");
-                       last_component = true_name;
-                       fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
-               }
+    strMountPointInfo = strFile + "\t" + strVolume + "\t" + strCell + "\t" + strType;
 
-               blob.in = last_component;
-               blob.in_size = strlen(last_component) + 1;
-               blob.out_size = MAXSIZE;
-               blob.out = space;
-               memset(space, 0, MAXSIZE);
-
-               code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
-               if (code == 0) {
-                       int nPos = strlen(space) - 1;
-                       if (space[nPos] == '.')
-                               space[nPos] = 0;
-                       mountPoints.Add(ParseMountPoint(StripPath(files[i]), space));
-               } else {
-                       error = 1;
-                       if (errno == EINVAL)
-                               mountPoints.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
-                       else
-                               mountPoints.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
-               }
-       }
+    return strMountPointInfo;
+}       
 
-       CMountPointsDlg dlg;
-       dlg.SetMountPoints(mountPoints);
-       dlg.DoModal();
+CString ParseSymlink(const CString strFile, CString strSymlink)
+{
+    CString strSymlinkInfo;
 
-       return !error;
-}
+    strSymlinkInfo = strFile + "\t" + strSymlink;
+
+    return strSymlinkInfo;
+}       
 
 BOOL IsPathInAfs(const CHAR *strPath)
 {
@@ -1013,16 +1012,198 @@ BOOL IsPathInAfs(const CHAR *strPath)
 
     HOURGLASS hourglass;
 
+    char buf[512];
+    sprintf(buf, "IsPathInAfs(%s)", strPath);
+    OutputDebugString(buf);
+
     blob.in_size = 0;
     blob.out_size = MAXSIZE;
     blob.out = space;
 
     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
-    if (code)
+
+    sprintf(buf, "VIOC_FILE_CELL_NAME=%d", code);
+    OutputDebugString(buf);
+
+    if (code) {
+       if ((errno == EINVAL) || (errno == ENOENT))
         return FALSE;
+    }
     return TRUE;
 }
 
+static int 
+IsFreelanceRoot(char *apath)
+{
+    struct ViceIoctl blob;
+    afs_int32 code;
+
+    blob.in_size = 0;
+    blob.out_size = MAXSIZE;
+    blob.out = space;
+
+    code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
+    if (code == 0)
+        return !strcmp("Freelance.Local.Root",space);
+    return 1;   /* assume it is because it is more restrictive that way */
+}
+
+const char * NetbiosName(void)
+{
+    static char buffer[1024] = "AFS";
+    HKEY  parmKey;
+    DWORD code;
+    DWORD dummyLen;
+    DWORD enabled = 0;
+
+    code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+                         0, KEY_QUERY_VALUE, &parmKey);
+    if (code == ERROR_SUCCESS) {
+        dummyLen = sizeof(buffer);
+        code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
+                              (LPBYTE)buffer, &dummyLen);
+        RegCloseKey (parmKey);
+    } else {
+       strcpy(buffer, "AFS");
+    }
+    return buffer;
+}
+
+#define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
+
+static BOOL IsAdmin (void)
+{
+    static BOOL fAdmin = FALSE;
+    static BOOL fTested = FALSE;
+
+    if (!fTested)
+    {
+        /* Obtain the SID for the AFS client admin group.  If the group does
+         * not exist, then assume we have AFS client admin privileges.
+         */
+        PSID psidAdmin = NULL;
+        DWORD dwSize, dwSize2;
+        char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
+        char *pszRefDomain = NULL;
+        SID_NAME_USE snu = SidTypeGroup;
+
+        dwSize = sizeof(pszAdminGroup);
+
+        if (!GetComputerName(pszAdminGroup, &dwSize)) {
+            /* Can't get computer name.  We return false in this case.
+               Retain fAdmin and fTested. This shouldn't happen.*/
+            return FALSE;
+        }
+
+        dwSize = 0;
+        dwSize2 = 0;
+
+        strcat(pszAdminGroup,"\\");
+        strcat(pszAdminGroup, AFSCLIENT_ADMIN_GROUPNAME);
+
+        LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
+        /* that should always fail. */
+
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+            /* if we can't find the group, then we allow the operation */
+            fAdmin = TRUE;
+            return TRUE;
+        }
+
+        if (dwSize == 0 || dwSize2 == 0) {
+            /* Paranoia */
+            fAdmin = TRUE;
+            return TRUE;
+        }
+
+        psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
+        pszRefDomain = (char *)malloc(dwSize2);
+
+        if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
+            /* We can't lookup the group now even though we looked it up earlier.  
+               Could this happen? */
+            fAdmin = TRUE;
+        } else {
+            /* Then open our current ProcessToken */
+            HANDLE hToken;
+
+            if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
+            {
+
+                if (!CheckTokenMembership(hToken, psidAdmin, &fAdmin)) {
+                    /* We'll have to allocate a chunk of memory to store the list of
+                     * groups to which this user belongs; find out how much memory
+                     * we'll need.
+                     */
+                    DWORD dwSize = 0;
+                    PTOKEN_GROUPS pGroups;
+
+                    GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
+
+                    pGroups = (PTOKEN_GROUPS)malloc(dwSize);
+
+                    /* Allocate that buffer, and read in the list of groups. */
+                    if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
+                    {
+                        /* Look through the list of group SIDs and see if any of them
+                         * matches the AFS Client Admin group SID.
+                         */
+                        size_t iGroup = 0;
+                        for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
+                        {
+                            if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
+                                fAdmin = TRUE;
+                            }
+                        }
+                    }
+
+                    if (pGroups)
+                        free(pGroups);
+                }
+
+                /* if do not have permission because we were not explicitly listed
+                 * in the Admin Client Group let's see if we are the SYSTEM account
+                 */
+                if (!fAdmin) {
+                    PTOKEN_USER pTokenUser;
+                    SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
+                    PSID pSidLocalSystem = 0;
+                    DWORD gle;
+
+                    GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
+
+                    pTokenUser = (PTOKEN_USER)malloc(dwSize);
+
+                    if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
+                        gle = GetLastError();
+
+                    if (AllocateAndInitializeSid( &SIDAuth, 1,
+                                                  SECURITY_LOCAL_SYSTEM_RID,
+                                                  0, 0, 0, 0, 0, 0, 0,
+                                                  &pSidLocalSystem))
+                    {
+                        if (EqualSid(pTokenUser->User.Sid, pSidLocalSystem)) {
+                            fAdmin = TRUE;
+                        }
+
+                        FreeSid(pSidLocalSystem);
+                    }
+
+                    if ( pTokenUser )
+                        free(pTokenUser);
+                }
+            }
+        }
+
+        free(psidAdmin);
+        free(pszRefDomain);
+
+        fTested = TRUE;
+    }
+
+    return fAdmin;
+}
+
 /* return a static pointer to a buffer */
 static char *Parent(char *apath)
 {
@@ -1031,66 +1212,210 @@ static char *Parent(char *apath)
     strcpy(tspace, apath);
     tp = strrchr(tspace, '\\');
     if (tp) {
-               *(tp+1) = 0;    /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
+        *(tp+1) = 0;   /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
     }
     else {
-               fs_ExtractDriveLetter(apath, tspace);
+        fs_ExtractDriveLetter(apath, tspace);
        strcat(tspace, ".");
     }
     
-       return tspace;
+    return tspace;
 }
 
-BOOL MakeMount(const CString& strDir, const CString& strVolName, const CString& strCellName, BOOL bRW)
+static afs_int32
+GetCell(char *fname, char *cellname)
 {
-    register LONG code;
-    register char *cellName;
-    char localCellName[1000];
+    afs_int32 code;
     struct ViceIoctl blob;
 
-       HOURGLASS hourglass;
+    blob.in_size = 0;
+    blob.out_size = MAXCELLCHARS;
+    blob.out = cellname;
+
+    code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1);
+    return code ? errno : 0;
+}
 
-       ASSERT(strVolName.GetLength() < 64);
 
-/*
+BOOL ListMount(CStringArray& files)
+{
+    register LONG code;
+    struct ViceIoctl blob;
+    int error;
+    char orig_name[1024];                      /* Original name, may be modified */
+    char true_name[1024];                      /* ``True'' dirname (e.g., symlink target) */
+    char parent_dir[1024];                     /* Parent directory of true name */
+    register char *last_component;     /* Last component of true name */
+    CStringArray mountPoints;
+    
+    HOURGLASS hourglass;
 
-defect #3069
+    error = 0;
 
-    if (as->parms[5].items && !as->parms[2].items) {
-       fprintf(stderr,"fs: must provide cell when creating cellular mount point.\n");
-       return FALSE;
+    for (int i = 0; i < files.GetSize(); i++) {
+        strcpy(orig_name, files[i]);
+        strcpy(true_name, orig_name);
+
+        /*
+         * Find rightmost slash, if any.
+         */
+        last_component = (char *)strrchr(true_name, '\\');
+        if (last_component) {
+            /*
+             * Found it.  Designate everything before it as the parent directory,
+             * everything after it as the final component.
+             */
+            strncpy(parent_dir, true_name, last_component - true_name + 1);
+            parent_dir[last_component - true_name + 1] = 0;
+            last_component++;   /* Skip the slash */
+
+           if (!IsPathInAfs(parent_dir)) {
+               const char * nbname = NetbiosName();
+               int len = strlen(nbname);
+
+               if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
+                   parent_dir[len+2] == '\\' &&
+                   parent_dir[len+3] == '\0' &&
+                   !strnicmp(nbname,&parent_dir[2],len))
+               {
+                   sprintf(parent_dir,"\\\\%s\\all\\", nbname);
+               }
+           }
+        }
+        else {
+            /*
+             * No slash appears in the given file name.  Set parent_dir to the current
+             * directory, and the last component as the given name.
+             */
+            fs_ExtractDriveLetter(true_name, parent_dir);
+            strcat(parent_dir, ".");
+            last_component = true_name;
+            fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
+        }
+
+        blob.in = last_component;
+        blob.in_size = strlen(last_component) + 1;
+        blob.out_size = MAXSIZE;
+        blob.out = space;
+        memset(space, 0, MAXSIZE);
+
+        code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
+        if (code == 0) {
+            int nPos = strlen(space) - 1;
+            if (space[nPos] == '.')
+                space[nPos] = 0;
+            mountPoints.Add(ParseMountPoint(StripPath(files[i]), space));
+        } else {
+            error = 1;
+            if (errno == EINVAL)
+                mountPoints.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
+            else
+                mountPoints.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
+        }
     }
-*/
+
+    CMountPointsDlg dlg;
+    dlg.SetMountPoints(mountPoints);
+    dlg.DoModal();
+
+    return !error;
+}
+
+BOOL MakeMount(const CString& strDir, const CString& strVolName, const CString& strCellName, BOOL bRW)
+{
+    register LONG code;
+    register char *cellName;
+    char localCellName[128];
+    struct afsconf_cell info;
+#if 0
+    struct vldbentry vldbEntry;
+#endif
+    struct ViceIoctl blob;
+    char * parent;
+    char path[1024] = "";
+
+    HOURGLASS hourglass;
+
+    ASSERT(strVolName.GetLength() < 64);
 
     if (strCellName.GetLength() > 0)   /* cell name specified */
-               cellName = PCCHAR(strCellName);
+        cellName = PCCHAR(strCellName);
     else
-               cellName = (char *) 0;
-
-    if (!IsPathInAfs(Parent(PCCHAR(strDir)))) {
-               ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_MP_NOT_AFS_ERROR);
+        cellName = (char *) 0;
+
+    parent = Parent(PCCHAR(strDir));
+    if (!IsPathInAfs(parent)) {
+       const char * nbname = NetbiosName();
+       int len = strlen(nbname);
+
+       if (parent[0] == '\\' && parent[1] == '\\' &&
+           parent[len+2] == '\\' &&
+           parent[len+3] == '\0' &&
+           !strnicmp(nbname,&parent[2],len))
+       {
+           sprintf(path,"%sall\\%s", parent, &(PCCHAR(strDir)[strlen(parent)]));
+           parent = Parent(path);
+           if (!IsPathInAfs(parent)) {
+               ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONERROR, IDS_MAKE_MP_NOT_AFS_ERROR);
                return FALSE;
+           }
+       } else {
+           ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONERROR, IDS_MAKE_MP_NOT_AFS_ERROR);
+           return FALSE;
+       }
     }
 
-    if (cellName) {
-               blob.in_size = 0;
-               blob.out_size = MAXSIZE;
-               blob.out = space;
-               code = pioctl(Parent(PCCHAR(strDir)), VIOC_FILE_CELL_NAME, &blob, 1);
+    if ( strlen(path) == 0 )
+       strcpy(path, PCCHAR(strDir));
+
+    if ( IsFreelanceRoot(parent) ) {
+       if ( !IsAdmin() ) {
+           ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
+           return FALSE;
+       }
+
+       if (!cellName) {
+           blob.in_size = 0;
+           blob.out_size = sizeof(localCellName);
+           blob.out = localCellName;
+           code = pioctl(parent, VIOC_GET_WS_CELL, &blob, 1);
+           if (!code)
+               cellName = localCellName;
+       }
+    } else {
+       if (!cellName)
+           GetCell(parent,space);
+    }
+
+    code = GetCellName(cellName?cellName:space, &info);
+    if (code) {
+       return FALSE;
     }
 
-    strcpy(localCellName, (cellName? cellName : space));
+#if 0
+    code = VLDBInit(1, &info);
+    if (code == 0) {
+       /* make the check.  Don't complain if there are problems with init */
+       code = ubik_VL_GetEntryByNameO(uclient, 0, PCCHAR(strVolName), &vldbEntry);
+       if (code == VL_NOENT) {
+           ShowMessageBox(IDS_WARNING, MB_ICONWARNING, IDS_VOLUME_NOT_IN_CELL_WARNING, 
+                           PCCHAR(strVolName), cellName ? cellName : space);
+       }
+    }
+    if (rxInitDone) 
+        rx_Finalize();
+#endif
 
     if (bRW)   /* if -rw specified */
-               strcpy(space, "%");
+        strcpy(space, "%");
     else
-               strcpy(space, "#");
+        strcpy(space, "#");
 
     /* If cellular mount point, prepend cell prefix */
-       if (cellName) {
-               strcat(space, localCellName);
-               strcat(space, ":");
-    }
+    if (cellName) {
+        strcat(space, info.name);
+        strcat(space, ":");
+    }   
 
     strcat(space, strVolName); /* append volume name */
     strcat(space, ".");                /* stupid convention; these end with a period */
@@ -1102,128 +1427,223 @@ defect #3069
     blob.in_size = 1 + strlen(space);
     blob.in = space;
     blob.out = NULL;
-    code = pioctl(PCCHAR(strDir), VIOC_AFS_CREATE_MT_PT, &blob, 0);
+    code = pioctl(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
 
     if (code) {
-               ShowMessageBox(IDS_MOUNT_POINT_ERROR, MB_ICONEXCLAMATION, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
-               return FALSE;
+        ShowMessageBox(IDS_MOUNT_POINT_ERROR, MB_ICONERROR, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
+        return FALSE;
     }
     
-       return TRUE;
+    return TRUE;
 }
 
 /*
 */
 long fs_ExtractDriveLetter(const char *inPathp, char *outPathp)
 {
-       if (inPathp[0] != 0 && inPathp[1] == ':') {
-               /* there is a drive letter */
-                *outPathp++ = *inPathp++;
-                *outPathp++ = *inPathp++;
-                *outPathp++ = 0;
-        }
-       else *outPathp = 0;
+    if (inPathp[0] != 0 && inPathp[1] == ':') {
+        /* there is a drive letter */
+        *outPathp++ = *inPathp++;
+        *outPathp++ = *inPathp++;
+        *outPathp++ = 0;
+    }
+    else *outPathp = 0;
 
-        return 0;
-}
+    return 0;
+}       
 
 /* strip the drive letter from a component */
 long fs_StripDriveLetter(const char *inPathp, char *outPathp, long outSize)
 {
-       char tempBuffer[1000];
-        strcpy(tempBuffer, inPathp);
-        if (tempBuffer[0] != 0 && tempBuffer[1] == ':') {
-               /* drive letter present */
-                strcpy(outPathp, tempBuffer+2);
-        }
-        else {
-               /* no drive letter present */
-               strcpy(outPathp, tempBuffer);
-       }
-        return 0;
-}
+    char tempBuffer[1000];
+    strcpy(tempBuffer, inPathp);
+    if (tempBuffer[0] != 0 && tempBuffer[1] == ':') {
+        /* drive letter present */
+        strcpy(outPathp, tempBuffer+2);
+    }
+    else {
+        /* no drive letter present */
+        strcpy(outPathp, tempBuffer);
+    }
+    return 0;
+}       
 
 
 BOOL RemoveSymlink(const char * linkName)
 {
-       BOOL error = FALSE;
+    BOOL error = FALSE;
     INT code=0;
     struct ViceIoctl blob;
     char tbuffer[1024];
     char lsbuffer[1024];
-       char tpbuffer[1024];
+    char tpbuffer[1024];
     char *tp;
     
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       tp = (char *) strrchr(linkName, '\\');
-       if (!tp)
-           tp = (char *) strrchr(linkName, '/');
-       if (tp) {
-           strncpy(tbuffer, linkName, code=tp-linkName+1);  /* the dir name */
-            tbuffer[code] = 0;
-           tp++;   /* skip the slash */
-       }
-       else {
-           fs_ExtractDriveLetter(linkName, tbuffer);
-           strcat(tbuffer, ".");
-         fs_StripDriveLetter(tp, tpbuffer, 0);
-                tp=tpbuffer;
+    tp = (char *) strrchr(linkName, '\\');
+    if (!tp)
+        tp = (char *) strrchr(linkName, '/');
+    if (tp) {
+        strncpy(tbuffer, linkName, code=tp-linkName+1);  /* the dir name */
+        tbuffer[code] = 0;
+        tp++;   /* skip the slash */
+
+       if (!IsPathInAfs(tbuffer)) {
+           const char * nbname = NetbiosName();
+           int len = strlen(nbname);
+
+           if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
+                tbuffer[len+2] == '\\' &&
+                tbuffer[len+3] == '\0' &&
+                !strnicmp(nbname,&tbuffer[2],len))
+           {
+               sprintf(tbuffer,"\\\\%s\\all\\", nbname);
+           }
        }
-       blob.in = tp;
-       blob.in_size = strlen(tp)+1;
-       blob.out = lsbuffer;
-       blob.out_size = sizeof(lsbuffer);
-       code = pioctl(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
-       if (code)
-               return FALSE;
-       blob.out_size = 0;
-       blob.in = tp;
-       blob.in_size = strlen(tp)+1;
-       return (pioctl(tbuffer, VIOC_DELSYMLINK, &blob, 0)==0);
-}
+    }
+    else {
+        fs_ExtractDriveLetter(linkName, tbuffer);
+        strcat(tbuffer, ".");
+        fs_StripDriveLetter(tp, tpbuffer, 0);
+        tp=tpbuffer;
+    }
+
+    if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
+       ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
+       return FALSE;
+    }
+
+    blob.in = tp;
+    blob.in_size = strlen(tp)+1;
+    blob.out = lsbuffer;
+    blob.out_size = sizeof(lsbuffer);
+    code = pioctl(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
+    if (code)
+        return FALSE;
+    blob.out_size = 0;
+    blob.in = tp;
+    blob.in_size = strlen(tp)+1;
+    return (pioctl(tbuffer, VIOC_DELSYMLINK, &blob, 0)==0);
+}       
 
 BOOL IsSymlink(const char * true_name)
 {
     char parent_dir[MAXSIZE];          /*Parent directory of true name*/
-       char strip_name[MAXSIZE];
+    char strip_name[MAXSIZE];
     struct ViceIoctl blob;
-       char *last_component;
+    char *last_component;
     int code;
 
     HOURGLASS hourglass;
 
-       last_component = (char *) strrchr(true_name, '\\');
-       if (!last_component)
-           last_component = (char *) strrchr(true_name, '/');
-       if (last_component) {
-           /*
-            * Found it.  Designate everything before it as the parent directory,
-            * everything after it as the final component.
-            */
-           strncpy(parent_dir, true_name, last_component - true_name + 1);
-           parent_dir[last_component - true_name + 1] = 0;
-           last_component++;   /*Skip the slash*/
+    char buf[512];
+    sprintf(buf, "IsSymlink(%s)", true_name);
+    OutputDebugString(buf);
+
+    last_component = (char *) strrchr(true_name, '\\');
+    if (!last_component)
+        last_component = (char *) strrchr(true_name, '/');
+    if (last_component) {
+        /*
+         * Found it.  Designate everything before it as the parent directory,
+         * everything after it as the final component.
+         */
+        strncpy(parent_dir, true_name, last_component - true_name + 1);
+        parent_dir[last_component - true_name + 1] = 0;
+        last_component++;   /*Skip the slash*/
+
+       if (!IsPathInAfs(parent_dir)) {
+           const char * nbname = NetbiosName();
+           int len = strlen(nbname);
+
+           if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
+                parent_dir[len+2] == '\\' &&
+                parent_dir[len+3] == '\0' &&
+                !strnicmp(nbname,&parent_dir[2],len))
+           {
+               sprintf(parent_dir,"\\\\%s\\all\\", nbname);
+           }
        }
-       else {
-           /*
-            * No slash appears in the given file name.  Set parent_dir to the current
-            * directory, and the last component as the given name.
-            */
-           fs_ExtractDriveLetter(true_name, parent_dir);
-           strcat(parent_dir, ".");
-           last_component = strip_name;
+    }
+    else {
+        /*
+         * No slash appears in the given file name.  Set parent_dir to the current
+         * directory, and the last component as the given name.
+         */
+        fs_ExtractDriveLetter(true_name, parent_dir);
+        strcat(parent_dir, ".");
+        last_component = strip_name;
         fs_StripDriveLetter(true_name, strip_name, sizeof(strip_name));
+    }
+
+    sprintf(buf, "last_component=%s", last_component);
+    OutputDebugString(buf);
+
+    blob.in = last_component;
+    blob.in_size = strlen(last_component)+1;
+    blob.out_size = MAXSIZE;
+    blob.out = space;
+    memset(space, 0, MAXSIZE);
+    code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
+    return (code==0);
+}       
+
+
+BOOL IsMountPoint(const char * name)
+{
+    register LONG code = 0;
+    struct ViceIoctl blob;
+    char tbuffer[1024];
+    char lsbuffer[1024];
+    register char *tp;
+    char szCurItem[1024];
+
+    HOURGLASS hourglass;
+
+    strcpy(szCurItem, name);
+       
+    char buf[512];
+    sprintf(buf, "IsMountPoint(%s)", name);
+    OutputDebugString(buf);
+
+    tp = (char *)strrchr(szCurItem, '\\');
+    if (tp) {
+        strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
+        tbuffer[code] = 0;
+        tp++;   /* skip the slash */
+
+       if (!IsPathInAfs(tbuffer)) {
+           const char * nbname = NetbiosName();
+           int len = strlen(nbname);
+
+           if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
+                tbuffer[len+2] == '\\' &&
+                tbuffer[len+3] == '\0' &&
+                !strnicmp(nbname,&tbuffer[2],len))
+           {
+               sprintf(tbuffer,"\\\\%s\\all\\", nbname);
+           }
        }
+    } else {
+        fs_ExtractDriveLetter(szCurItem, tbuffer);
+        strcat(tbuffer, ".");
+        tp = szCurItem;
+        fs_StripDriveLetter(tp, tp, 0);
+    }
 
-       blob.in = last_component;
-       blob.in_size = strlen(last_component)+1;
-       blob.out_size = MAXSIZE;
-       blob.out = space;
-       memset(space, 0, MAXSIZE);
-       code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
-       return (code==0);
-}
+    sprintf(buf, "last_component=%s", tp);
+    OutputDebugString(buf);
+
+    blob.in = tp;
+    blob.in_size = strlen(tp)+1;
+    blob.out = lsbuffer;
+    blob.out_size = sizeof(lsbuffer);
+
+    code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
+
+    return (code==0);
+}       
 
 
 /*
@@ -1237,63 +1657,75 @@ BOOL RemoveMount(CStringArray& files)
     register LONG code = 0;
     struct ViceIoctl blob;
     char tbuffer[1024];
-    char lsbuffer[1024];
     register char *tp;
-       BOOL error = FALSE;
-       CStringArray results;
-       CString str;
-       CString str2;
+    char szCurItem[1024];
+    BOOL error = FALSE;
+    CStringArray results;
+    CString str;
+    CString str2;
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
     for (int i = 0; i < files.GetSize(); i++) {
-               char szCurItem[1024];
-               strcpy(szCurItem, files[i]);
+        if (!IsMountPoint(files[i])) {
+            error = TRUE;
+            if (errno == EINVAL)
+                results.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
+            else
+                results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
+            continue;  // don't bother trying
+        }
+
+        strcpy(szCurItem, files[i]);
        
-               tp = (char *)strrchr(szCurItem, '\\');
-               if (tp) {
-                       strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
-                       tbuffer[code] = 0;
-                       tp++;   /* skip the slash */
-               } else {
-                       fs_ExtractDriveLetter(szCurItem, tbuffer);
-                       strcat(tbuffer, ".");
-                       tp = szCurItem;
-                       fs_StripDriveLetter(tp, tp, 0);
+        tp = (char *)strrchr(szCurItem, '\\');
+        if (tp) {
+            strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
+            tbuffer[code] = 0;
+            tp++;   /* skip the slash */
+
+           if (!IsPathInAfs(tbuffer)) {
+               const char * nbname = NetbiosName();
+               int len = strlen(nbname);
+
+               if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
+                   tbuffer[len+2] == '\\' &&
+                   tbuffer[len+3] == '\0' &&
+                   !strnicmp(nbname,&tbuffer[2],len))
+               {
+                   sprintf(tbuffer,"\\\\%s\\all\\", nbname);
                }
+           }
+        } else {
+            fs_ExtractDriveLetter(szCurItem, tbuffer);
+            strcat(tbuffer, ".");
+            tp = szCurItem;
+            fs_StripDriveLetter(tp, tp, 0);
+        }
 
-               blob.in = tp;
-               blob.in_size = strlen(tp)+1;
-               blob.out = lsbuffer;
-               blob.out_size = sizeof(lsbuffer);
-
-               code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
-               if (code) {
-                       error = TRUE;
-                       if (errno == EINVAL)
-                               results.Add(GetMessageString(IDS_NOT_MOUNT_POINT_ERROR, StripPath(files[i])));
-                       else
-                               results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
-                       continue;       // don't bother trying
-               }
-               
-               blob.out_size = 0;
-               blob.in = tp;
-               blob.in_size = strlen(tp)+1;
-               
-               code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
-               if (code) {
-                       error = TRUE;
-                       results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
-               } else
-                       results.Add(GetMessageString(IDS_DELETED));
-    }
+       if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
+           results.Add(GetMessageString(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, StripPath(files[i])));
+            error = TRUE;
+            continue;   /* skip */
+        }
+
+        blob.out_size = 0;
+        blob.in = tp;
+        blob.in_size = strlen(tp)+1;
 
-       LoadString (str, IDS_REMOVE_MP);
-       LoadString (str2, IDS_REMOVE_MP_COLUMN);
-       CResultsDlg dlg(REMOVE_MOUNT_POINTS_HELP_ID);
-       dlg.SetContents(str, str2, StripPath(files), results);
-       dlg.DoModal();
+        code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
+        if (code) {
+            error = TRUE;
+            results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
+        } else
+            results.Add(GetMessageString(IDS_DELETED));
+    }   
+
+    LoadString (str, IDS_REMOVE_MP);
+    LoadString (str2, IDS_REMOVE_MP_COLUMN);
+    CResultsDlg dlg(REMOVE_MOUNT_POINTS_HELP_ID);
+    dlg.SetContents(str, str2, StripPath(files), results);
+    dlg.DoModal();
 
     return !error;
 }
@@ -1305,12 +1737,12 @@ BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
     struct VolumeStatus *status;
     char *name;
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       volInfo.m_strFilePath = strFile;
+    volInfo.m_strFilePath = strFile;
     volInfo.m_strFileName = StripPath(strFile);
 
-/*
+    /*
        volInfo.m_strName = "VolumeName";
        volInfo.m_nID = 10;
        volInfo.m_nQuota = 20 * 1024 * 1024;
@@ -1320,29 +1752,29 @@ BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
        volInfo.m_nPartFree = 30 * 1024 * 1024;
        volInfo.m_nDup = -1;
        return TRUE;
-*/
+     */
 
-       blob.out_size = MAXSIZE;
-       blob.in_size = 0;
-       blob.out = space;
+    blob.out_size = MAXSIZE;
+    blob.in_size = 0;
+    blob.out = space;
 
-       code = pioctl(PCCHAR(strFile), VIOCGETVOLSTAT, &blob, 1);
-       if (code) {
-               volInfo.m_strErrorMsg = GetAfsError(errno, strFile);
-               return FALSE;
-       }
+    code = pioctl(PCCHAR(strFile), VIOCGETVOLSTAT, &blob, 1);
+    if (code) {
+        volInfo.m_strErrorMsg = GetAfsError(errno, strFile);
+        return FALSE;
+    }
 
-       status = (VolumeStatus *)space;
-       name = (char *)status + sizeof(*status);
+    status = (VolumeStatus *)space;
+    name = (char *)status + sizeof(*status);
 
-       volInfo.m_strName = name;
-       volInfo.m_nID = status->Vid;
-       volInfo.m_nQuota = status->MaxQuota;
-       volInfo.m_nNewQuota = status->MaxQuota;
-       volInfo.m_nUsed = status->BlocksInUse;
-       volInfo.m_nPartSize = status->PartMaxBlocks;
-       volInfo.m_nPartFree = status->PartBlocksAvail;
-       volInfo.m_nDup = -1;
+    volInfo.m_strName = name;
+    volInfo.m_nID = status->Vid;
+    volInfo.m_nQuota = status->MaxQuota;
+    volInfo.m_nNewQuota = status->MaxQuota;
+    volInfo.m_nUsed = status->BlocksInUse;
+    volInfo.m_nPartSize = status->PartMaxBlocks;
+    volInfo.m_nPartFree = status->PartBlocksAvail;
+    volInfo.m_nDup = -1;
 
     return TRUE;
 }
@@ -1354,49 +1786,49 @@ BOOL SetVolInfo(CVolInfo& volInfo)
     struct VolumeStatus *status;
     char *input;
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
-       blob.out_size = MAXSIZE;
-       blob.in_size = sizeof(*status) + 3;     /* for the three terminating nulls */
-       blob.out = space;
-       blob.in = space;
-       
-       status = (VolumeStatus *)space;
-       status->MinQuota = -1;
-       status->MaxQuota = volInfo.m_nNewQuota;
+    blob.out_size = MAXSIZE;
+    blob.in_size = sizeof(*status) + 3;        /* for the three terminating nulls */
+    blob.out = space;
+    blob.in = space;
+
+    status = (VolumeStatus *)space;
+    status->MinQuota = -1;
+    status->MaxQuota = volInfo.m_nNewQuota;
        
-       input = (char *)status + sizeof(*status);
-       *(input++) = '\0';      /* never set name: this call doesn't change vldb */
-       *(input++) = '\0';      // No offmsg
-       *(input++) = '\0';      // No motd
+    input = (char *)status + sizeof(*status);
+    *(input++) = '\0'; /* never set name: this call doesn't change vldb */
+    *(input++) = '\0'; // No offmsg
+    *(input++) = '\0'; // No motd
 
 #ifdef LOGGING_ON
-       FILE *fp = OpenFile(szLogFileName, "a");
-       if (fp) {
-               fprintf(fp, "\nSetVolInfo() pioctl parms:\n");
-               fprintf(fp, "\tpathp = %s\n\topcode = VIOCSETVOLSTAT (%d)\n\tblobp = %ld\n", PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob);
-               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);
-               fprintf(fp, "\t\t\tstatus->MinQuota = %ld\n", status->MinQuota);
-               fprintf(fp, "\t\t\tstatus->MaxQuota = %ld\n", status->MaxQuota);
-               fprintf(fp, "\t\t\tOther status fields aren't set\n");
-               fprintf(fp, "\t\t\t3 nulls follow the VolumeStatus structure.\n");
-               fprintf(fp, "\tfollow = 1\n");
-               fclose(fp);             
-       }
+    FILE *fp = OpenFile(szLogFileName, "a");
+    if (fp) {
+        fprintf(fp, "\nSetVolInfo() pioctl parms:\n");
+        fprintf(fp, "\tpathp = %s\n\topcode = VIOCSETVOLSTAT (%d)\n\tblobp = %ld\n", PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob);
+        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);
+        fprintf(fp, "\t\t\tstatus->MinQuota = %ld\n", status->MinQuota);
+        fprintf(fp, "\t\t\tstatus->MaxQuota = %ld\n", status->MaxQuota);
+        fprintf(fp, "\t\t\tOther status fields aren't set\n");
+        fprintf(fp, "\t\t\t3 nulls follow the VolumeStatus structure.\n");
+        fprintf(fp, "\tfollow = 1\n");
+        fclose(fp);            
+    }
 #endif
 
-       code = pioctl(PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob, 1);
-       if (code) {
-               ShowMessageBox(IDS_SET_QUOTA_ERROR, MB_ICONEXCLAMATION, IDS_SET_QUOTA_ERROR, GetAfsError(errno, volInfo.m_strName));
-               return FALSE;
-       }
+    code = pioctl(PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob, 1);
+    if (code) {
+        ShowMessageBox(IDS_SET_QUOTA_ERROR, MB_ICONERROR, IDS_SET_QUOTA_ERROR, GetAfsError(errno, volInfo.m_strName));
+        return FALSE;
+    }
 
     return TRUE;
 }
 
 int GetCellName(char *cellNamep, struct afsconf_cell *infop)
 {
-       strcpy(infop->name, cellNamep);
+    strcpy(infop->name, cellNamep);
     return 0;
 }
 
@@ -1409,7 +1841,7 @@ BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bF
     struct afsconf_cell info;
     struct chservinfo checkserv;
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
     memset(&checkserv, 0, sizeof(struct chservinfo));
     blob.in_size = sizeof(struct chservinfo);
@@ -1417,230 +1849,336 @@ BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bF
 
     blob.out_size = MAXSIZE;
     blob.out = space;
-    memset(space, 0, sizeof(LONG));    /* so we assure zero when nothing is copied back */
-
-    /* prepare flags for checkservers command */
-       if (nCellsToCheck == LOCAL_CELL)
-               temp = 2;       /* default to checking local cell only */
-    else if (nCellsToCheck == ALL_CELLS)
-               temp &= ~2;     /* turn off local cell check */
+    memset(space, 0, sizeof(afs_int32));       /* so we assure zero when nothing is copied back */
 
-       if (bFast)
-               temp |= 1;      /* set fast flag */
+    if (nCellsToCheck == SPECIFIC_CELL) {
+       temp = 2;
+        GetCellName(PCCHAR(strCellName), &info);
+        strcpy(checkserv.tbuffer,info.name);
+        checkserv.tsize = strlen(info.name) + 1;
+    } else {
+       if (nCellsToCheck != ALL_CELLS)
+           temp = 2;
+        strcpy(checkserv.tbuffer, "\0");
+        checkserv.tsize = 0;
+    }
+    if (bFast)
+        temp |= 1;     /* set fast flag */
     
     checkserv.magic = 0x12345678;      /* XXX */
     checkserv.tflags = temp;
-
-    /* now copy in optional cell name, if specified */
-    if (nCellsToCheck == SPECIFIC_CELL) {
-               GetCellName(PCCHAR(strCellName), &info);
-               strcpy(checkserv.tbuffer,info.name);
-               checkserv.tsize = strlen(info.name) + 1;
-    } else {
-               strcpy(checkserv.tbuffer, "\0");
-               checkserv.tsize = 0;
-       }
-
-       checkserv.tinterval = -1;       /* don't change current interval */
+    checkserv.tinterval = -1;  /* don't change current interval */
 
     code = pioctl(0, VIOCCKSERV, &blob, 1);
     if (code) {
-               ShowMessageBox(IDS_CHECK_SERVERS_ERROR, MB_ICONEXCLAMATION, IDS_CHECK_SERVERS_ERROR, GetAfsError(errno, CString()));
-               return FALSE;
+        ShowMessageBox(IDS_CHECK_SERVERS_ERROR, MB_ICONERROR, IDS_CHECK_SERVERS_ERROR, GetAfsError(errno, CString()));
+        return FALSE;
     }
 
     memcpy(&temp, space, sizeof(LONG));
 
-       if (temp == 0) {
-               ShowMessageBox(IDS_ALL_SERVERS_RUNNING, MB_OK, IDS_ALL_SERVERS_RUNNING);
-               return TRUE;
-       }
+    if (temp == 0) {
+        ShowMessageBox(IDS_ALL_SERVERS_RUNNING, MB_OK|MB_ICONINFORMATION, IDS_ALL_SERVERS_RUNNING);
+        return TRUE;
+    }
 
-       CStringArray servers;
-       for (j = 0; j < MAXHOSTS; j++) {
-               memcpy(&temp, space + j * sizeof(LONG), sizeof(LONG));
-               if (temp == 0)
-                       break;
-               
-               char *name = hostutil_GetNameByINet(temp);
-               servers.Add(name);
-       }
+    CStringArray servers;
+    for (j = 0; j < MAXHOSTS; j++) {
+        memcpy(&temp, space + j * sizeof(LONG), sizeof(LONG));
+        if (temp == 0)
+            break;
+
+        char *name = hostutil_GetNameByINet(temp);
+        servers.Add(name);
+    }
 
-       CDownServersDlg dlg;
-       dlg.SetServerNames(servers);
-       dlg.DoModal();
+    CDownServersDlg dlg;
+    dlg.SetServerNames(servers);
+    dlg.DoModal();
 
     return TRUE;
-}
+}       
 
 BOOL GetTokenInfo(CStringArray& tokenInfo)
 {
-       int cellNum;
-       int rc;
-       int current_time;
-       time_t tokenExpireTime;
-       char *expireString;
-       char userName[100];
+    int cellNum;
+    int rc;
+    time_t current_time;
+    time_t tokenExpireTime;
+    char *expireString;
+    char userName[100];
 //     char s[100];
-       struct ktc_principal serviceName, clientName;
-       struct ktc_token token;
-       
-       CString strTokenInfo;
-       CString strUserName;
-       CString strCellName;
-       CString strExpir;
+    struct ktc_principal serviceName, clientName;
+    struct ktc_token token;
+
+    CString strTokenInfo;
+    CString strUserName;
+    CString strCellName;
+    CString strExpir;
 
-//     tokenInfo.Add("");
+//      tokenInfo.Add("");
 //     return TRUE;
 
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
 //     printf("\nTokens held by the Cache Manager:\n\n");
-       cellNum = 0;
-       current_time = time(0);
-
-       while (1) {
-               rc = ktc_ListTokens(cellNum, &cellNum, &serviceName);
-               if (rc == KTC_NOENT) {
-                       /* end of list */
-//                     printf("   --End of list --\n");
-                       break;
-               }
-               else if (rc == KTC_NOCM) {
-                       ShowMessageBox(IDS_GET_TOKENS_NO_AFS_SERVICE);
-//                     printf("AFS service may not have started\n");
-                       break;
-               }
-               else if (rc) {
-                       ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR, MB_ICONEXCLAMATION, IDS_GET_TOKENS_UNEXPECTED_ERROR, rc);
-                       return FALSE;
-//                     printf("Unexpected error, code %d\n", rc);
-//                     exit(1);
-               }
-               else {
-                       rc = ktc_GetToken(&serviceName, &token, sizeof(token), &clientName);
-                       if (rc) {
-                               ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR2, MB_ICONEXCLAMATION, IDS_GET_TOKENS_UNEXPECTED_ERROR2, 
-                                       serviceName.name, serviceName.instance, serviceName.cell, rc);
-                               continue;
-                       }
-
-                       tokenExpireTime = token.endTime;
-                       
-                       strcpy(userName, clientName.name);
-                       if (clientName.instance[0] != 0) {
-                               strcat(userName, ".");
-                               strcat(userName, clientName.instance);
-                       }
+    cellNum = 0;
+    current_time = time(0);
+
+    while (1) {
+        rc = ktc_ListTokens(cellNum, &cellNum, &serviceName);
+        if (rc == KTC_NOENT) {
+            /* end of list */
+//         printf("   --End of list --\n");
+            break;
+        }
+        else if (rc == KTC_NOCM) {
+            ShowMessageBox(IDS_GET_TOKENS_NO_AFS_SERVICE);
+//         printf("AFS service may not have started\n");
+            break;
+        }
+        else if (rc) {
+            ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR, MB_ICONERROR, IDS_GET_TOKENS_UNEXPECTED_ERROR, rc);
+            return FALSE;
+//         printf("Unexpected error, code %d\n", rc);
+//         exit(1);
+        }
+        else {
+            rc = ktc_GetToken(&serviceName, &token, sizeof(token), &clientName);
+            if (rc) {
+                ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR2, MB_ICONERROR, IDS_GET_TOKENS_UNEXPECTED_ERROR2, 
+                                serviceName.name, serviceName.instance,        serviceName.cell, rc);
+                continue;
+            }
+
+            tokenExpireTime = token.endTime;
 
-                       BOOL bShowName = FALSE;
+            strcpy(userName, clientName.name);
+            if (clientName.instance[0] != 0) {
+                strcat(userName, ".");
+                strcat(userName, clientName.instance);
+            }
 
-                       if (userName[0] == '\0')
-                               ; //printf("Tokens");
+            BOOL bShowName = FALSE;
+
+            if (userName[0] == '\0')
+                ; //printf("Tokens");
 // AFS ID is not returned at this time.
-//                     else if (strncmp(userName, "AFS ID", 6) == 0)
-//                             printf("User's (%s) tokens", userName);
-//                             sscanf(userName, "(AFS ID %s)", szAfsID);
-                       else if (strncmp(userName, "Unix UID", 8) == 0)
-                               ; //printf("Tokens");
-                       else
-                               strUserName = userName;
-//                             printf("User %s's tokens", userName);
+//         else if (strncmp(userName, "AFS ID", 6) == 0)
+//             printf("User's (%s) tokens", userName);
+//             sscanf(userName, "(AFS ID %s)", szAfsID);
+           else if (strncmp(userName, "Unix UID", 8) == 0)
+                ; //printf("Tokens");
+            else
+                strUserName = userName;
+//             printf("User %s's tokens", userName);
                        
-//                     printf(" for %s%s%s@%s ", serviceName.name, serviceName.instance[0] ? "." : "", serviceName.instance, serviceName.cell);
-                       strCellName = serviceName.cell;
+//             printf(" for %s%s%s@%s ", serviceName.name, serviceName.instance[0] ? "." : "", serviceName.instance, serviceName.cell);
+            strCellName = serviceName.cell;
                        
-                       if (tokenExpireTime <= current_time)
-                               strExpir = "[>> Expired <<]";
-//                             printf("[>> Expired <<]\n");
-                       else {
-                               expireString = ctime(&tokenExpireTime);
-                               expireString += 4;       /* Skip day of week */
-                               expireString[12] = '\0'; /* Omit secs & year */
-//                             printf("[Expires %s]\n", expireString);
-                               strExpir.Format("%s", expireString);
-                       }
-               
-                       strTokenInfo = strUserName + "\t" + strCellName + "\t" + strExpir + "\t" + strCellName;
-                       tokenInfo.Add(strTokenInfo);
-               }
-       }
+            if (tokenExpireTime <= current_time)
+                strExpir = "[>> Expired <<]";
+//             printf("[>> Expired <<]\n");
+            else {
+                expireString = ctime(&tokenExpireTime);
+                expireString += 4;      /* Skip day of week */
+                expireString[12] = '\0'; /* Omit secs & year */
+//             printf("[Expires %s]\n", expireString);
+                strExpir.Format("%s", expireString);
+            }
+
+            strTokenInfo = strUserName + "\t" + strCellName + "\t" + strExpir + "\t" + strCellName;
+            tokenInfo.Add(strTokenInfo);
+        }
+    }
 
 //     printf("Press <Enter> or <Return> when finished: ");
 //     gets(s);
-       return TRUE;
+    return TRUE;
 }
 
-UINT MakeSymbolicLink(const char *strName ,const char *strDir)
+UINT MakeSymbolicLink(const char *strName, const char *strTarget)
 {
     struct ViceIoctl blob;
-       char space[MAXSIZE];
-       UINT code;
+    char space[MAXSIZE];
+    char * parent;
+    char path[1024] = "";
+    UINT code;
 
     HOURGLASS hourglass;
+    static char message[2048];
+
+    strcpy(path, strName);
+    parent = Parent(path);
+
+    sprintf(message,"MakeSymbolicLink: name = %s target = %s parent = %s\n",strName,strTarget, parent);
+    OutputDebugString(message);
+
+    if ( IsFreelanceRoot(parent) && !IsAdmin() ) {
+       ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
+       return FALSE;
+    }
 
-    /*lets confirm its a good symlink*/
-       if (!IsPathInAfs(strDir))
-               return 1;
-       LPTSTR lpsz = new TCHAR[strlen(strDir)+1];
-       _tcscpy(lpsz, strName);
-    strcpy(space, strDir);
+    LPTSTR lpsz = new TCHAR[strlen(strTarget)+1];
+    _tcscpy(lpsz, strName);
+    strcpy(space, strTarget);
     blob.out_size = 0;
     blob.in_size = 1 + strlen(space);
     blob.in = space;
     blob.out = NULL;
-    if ((code=pioctl(lpsz, VIOC_SYMLINK, &blob, 0))!=0)
-               return code;
-       return 0;
+    code=pioctl(lpsz, VIOC_SYMLINK, &blob, 0);
+    delete lpsz;
+    if (code != 0)
+        return code;
+    return FALSE;
 }
 
 void ListSymbolicLinkPath(const char *strName,char *strPath,UINT nlenPath)
 {
-       ASSERT(nlenPath<MAX_PATH);
+    ASSERT(nlenPath<MAX_PATH);
     struct ViceIoctl blob;
     char orig_name[MAX_PATH+1];                /*Original name, may be modified*/
     char true_name[MAX_PATH+1];                /*``True'' dirname (e.g., symlink target)*/
     char parent_dir[MAX_PATH+1];               /*Parent directory of true name*/
     char *last_component;      /*Last component of true name*/
-       UINT code;    
+    UINT code;    
 
-       HOURGLASS hourglass;
+    HOURGLASS hourglass;
 
     strcpy(orig_name, strName);
-       strcpy(true_name, orig_name);
+    strcpy(true_name, orig_name);
+    /*
+     * Find rightmost slash, if any.
+     */
+    last_component = (char *) strrchr(true_name, '\\');
+    if (!last_component)
+        last_component = (char *) strrchr(true_name, '/');
+    if (last_component) {
        /*
-        * Find rightmost slash, if any.
+        * Found it.  Designate everything before it as the parent directory,
+        * everything after it as the final component.
         */
-       last_component = (char *) strrchr(true_name, '\\');
-       if (!last_component)
-           last_component = (char *) strrchr(true_name, '/');
-       if (last_component) {
-           /*
-            * Found it.  Designate everything before it as the parent directory,
-            * everything after it as the final component.
-            */
-           strncpy(parent_dir, true_name, last_component - true_name + 1);
-           parent_dir[last_component - true_name + 1] = 0;
-           last_component++;   /*Skip the slash*/
+        strncpy(parent_dir, true_name, last_component - true_name + 1);
+        parent_dir[last_component - true_name + 1] = 0;
+        last_component++;   /*Skip the slash*/
+
+       if (!IsPathInAfs(parent_dir)) {
+           const char * nbname = NetbiosName();
+           int len = strlen(nbname);
+
+           if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
+                parent_dir[len+2] == '\\' &&
+                parent_dir[len+3] == '\0' &&
+                !strnicmp(nbname,&parent_dir[2],len))
+           {
+               sprintf(parent_dir,"\\\\%s\\all\\", nbname);
+           }
        }
-       else {
-           /*
-            * No slash appears in the given file name.  Set parent_dir to the current
-            * directory, and the last component as the given name.
-            */
-           fs_ExtractDriveLetter(true_name, parent_dir);
-           strcat(parent_dir, ".");
-           last_component = true_name;
+    }
+    else {
+        /*
+         * No slash appears in the given file name.  Set parent_dir to the current
+         * directory, and the last component as the given name.
+         */
+        fs_ExtractDriveLetter(true_name, parent_dir);
+        strcat(parent_dir, ".");
+        last_component = true_name;
+        fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
+    }
+    blob.in = last_component;
+    blob.in_size = strlen(last_component)+1;
+    blob.out_size = MAXSIZE;
+    blob.out = space;
+    memset(space, 0, MAXSIZE);
+    if ((code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1)))
+        strcpy(space,"???");
+    ASSERT(strlen(space)<MAX_PATH);
+    strncpy(strPath,space,nlenPath);
+}       
+
+BOOL ListSymlink(CStringArray& files)
+{
+    register LONG code;
+    struct ViceIoctl blob;
+    int error;
+    char orig_name[1024];                      /* Original name, may be modified */
+    char true_name[1024];                      /* ``True'' dirname (e.g., symlink target) */
+    char parent_dir[1024];                     /* Parent directory of true name */
+    register char *last_component;     /* Last component of true name */
+    CStringArray symlinks;
+    
+    HOURGLASS hourglass;
+
+    error = 0;
+
+    for (int i = 0; i < files.GetSize(); i++) {
+        strcpy(orig_name, files[i]);
+        strcpy(true_name, orig_name);
+
+        /*
+         * Find rightmost slash, if any.
+         */
+        last_component = (char *)strrchr(true_name, '\\');
+        if (last_component) {
+            /*
+             * Found it.  Designate everything before it as the parent directory,
+             * everything after it as the final component.
+             */
+            strncpy(parent_dir, true_name, last_component - true_name + 1);
+            parent_dir[last_component - true_name + 1] = 0;
+            last_component++;   /* Skip the slash */
+
+           if (!IsPathInAfs(parent_dir)) {
+               const char * nbname = NetbiosName();
+               int len = strlen(nbname);
+
+               if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
+                   parent_dir[len+2] == '\\' &&
+                   parent_dir[len+3] == '\0' &&
+                   !strnicmp(nbname,&parent_dir[2],len))
+               {
+                   sprintf(parent_dir,"\\\\%s\\all\\", nbname);
+               }
+           }
+        }
+        else {
+            /*
+             * No slash appears in the given file name.  Set parent_dir to the current
+             * directory, and the last component as the given name.
+             */
+            fs_ExtractDriveLetter(true_name, parent_dir);
+            strcat(parent_dir, ".");
+            last_component = true_name;
             fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
-       }
-       blob.in = last_component;
-       blob.in_size = strlen(last_component)+1;
-       blob.out_size = MAXSIZE;
-       blob.out = space;
-       memset(space, 0, MAXSIZE);
-       if ((code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1)))
-               strcpy(space,"???");
-       ASSERT(strlen(space)<MAX_PATH);
-       strncpy(strPath,space,nlenPath);
+        }
+
+        blob.in = last_component;
+        blob.in_size = strlen(last_component) + 1;
+        blob.out_size = MAXSIZE;
+        blob.out = space;
+        memset(space, 0, MAXSIZE);
+
+        code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
+        if (code == 0) {
+            int nPos = strlen(space) - 1;
+            if (space[nPos] == '.')
+                space[nPos] = 0;
+            symlinks.Add(ParseSymlink(StripPath(files[i]), space));
+        } else {
+            error = 1;
+            if (errno == EINVAL)
+                symlinks.Add(GetMessageString(IDS_NOT_SYMLINK_ERROR, StripPath(files[i])));
+            else
+                symlinks.Add(GetMessageString(IDS_LIST_MOUNT_POINT_ERROR, GetAfsError(errno, StripPath(files[i]))));
+        }
+    }
+
+    CSymlinksDlg dlg;
+    dlg.SetSymlinks(symlinks);
+    dlg.DoModal();
+
+    return !error;
 }
+
+