Windows Explorer Shell Extension: Remove OutputDebugString calls
[openafs.git] / src / WINNT / client_exp / gui2fs.cpp
index 350a3f6..0c14029 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,22 +24,33 @@ 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>
+#include <cm_nls.h>
+#include <osi.h>
+#include <cm_user.h>
+#include <cm_scache.h>
+#include <cm_ioctl.h>
 }
 
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
 
 #define PCCHAR(str)            ((char *)(const char *)(str))
-
+#define VL_NOENT                (363524L)
 
 #define        MAXHOSTS 13
 #define        OMAXHOSTS 8
@@ -49,32 +63,119 @@ 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
 
-FILE *OpenFile(char *file, char *rwp)
+#ifdef UNICODE
+class CStringUtf8 : public CStringA
+{
+public:
+    CStringUtf8(const CStringW& csw) : CStringA()
+    {
+        SetString(csw);
+    }
+
+    CStringUtf8(const char * cp) : CStringA(cp) {}
+
+    CStringUtf8() :CStringA() {}
+
+    void SetString(const CStringW& csw)
+    {
+        char buffer[1024];
+        int rv;
+
+        rv = WideCharToMultiByte(CP_UTF8, 0, csw, -1,
+                                 buffer, sizeof(buffer),
+                                 NULL, FALSE);
+
+        if (rv != 0) {
+            CStringA::SetString(buffer);
+        } else {
+            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+                int cb_req;
+
+                cb_req = WideCharToMultiByte(CP_UTF8, 0, csw, -1, NULL, 0, NULL, FALSE);
+                if (cb_req != 0) {
+                    cb_req ++;
+
+                    WideCharToMultiByte(CP_UTF8, 0, csw, -1, CStringA::GetBuffer(cb_req), cb_req, NULL, FALSE);
+                    CStringA::ReleaseBuffer();
+                }
+            } else {
+#ifdef DEBUG
+                DebugBreak();
+#endif
+            }
+        }
+    }
+
+    static CString _Utf8ToCString(const char * ustr)
+    {
+        CString cs;
+        int cch;
+
+        cch = MultiByteToWideChar(CP_UTF8, 0, ustr, -1, NULL, 0);
+        if (cch == 0) {
+            cs.Empty();
+            return cs;
+        }
+
+        cch++;
+        cch = MultiByteToWideChar(CP_UTF8, 0, ustr, -1, cs.GetBuffer(cch), cch);
+        cs.ReleaseBuffer();
+
+        return cs;
+    }
+};
+
+long pioctl_T(const CString& path, long opcode, struct ViceIoctl * blob, int follow)
+{
+    CStringUtf8 upath(path);
+
+    return pioctl_utf8(PCCHAR(upath), opcode, blob, follow);
+}
+
+#define Utf8ToCString(cs) CStringUtf8::_Utf8ToCString(cs)
+#else
+#define pioctl_T(path, op, vblob, follow) pioctl(PCCHAR(path), op, vblob, follow)
+#define Utf8ToCString(cs) (cs)
+#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;
+}
+
+static FILE *
+OpenFile(char *file, char *rwp)
 {
     char wdir[256];
     long code;
     long tlen;
     FILE *fp;
 
-    code = GetWindowsDirectory(wdir, sizeof(wdir));
+    code = GetWindowsDirectoryA(wdir, sizeof(wdir));
     if (code == 0 || code > sizeof(wdir)) 
         return FALSE;
 
@@ -111,7 +212,7 @@ CStringArray& StripPath(CStringArray& files)
 
 void Flush(const CStringArray& files)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     int error = 0;
 
@@ -120,23 +221,23 @@ void Flush(const CStringArray& files)
     for (int i = 0; i < files.GetSize(); i++) {
         blob.in_size = blob.out_size = 0;
 
-        code = pioctl(PCCHAR(files[i]), VIOCFLUSH, &blob, 0);
+        code = pioctl_T(files[i], VIOCFLUSH, &blob, 0);
         if (code) {
             error = 1;
             if (errno == EMFILE)
-                ShowMessageBox(IDS_FLUSH_FAILED, MB_ICONEXCLAMATION, IDS_FLUSH_FAILED, files[i]);
+                ShowMessageBox(IDS_FLUSH_FAILED, MB_ICONERROR, IDS_FLUSH_FAILED, files[i]);
             else 
-                ShowMessageBox(IDS_FLUSH_ERROR, MB_ICONEXCLAMATION, IDS_FLUSH_ERROR, files[i], strerror(errno));
+                ShowMessageBox(IDS_FLUSH_ERROR, MB_ICONERROR, IDS_FLUSH_ERROR, files[i], strerror(errno));
         }
     }   
 
     if (!error)
-        ShowMessageBox(IDS_FLUSH_OK, MB_ICONEXCLAMATION, IDS_FLUSH_OK);
+        ShowMessageBox(IDS_FLUSH_OK, MB_ICONINFORMATION, IDS_FLUSH_OK);
 }       
 
 void FlushVolume(const CStringArray& files)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     int error = 0;
 
@@ -145,20 +246,20 @@ void FlushVolume(const CStringArray& files)
     for (int i = 0; i < files.GetSize(); i++) {
         blob.in_size = blob.out_size = 0;
 
-        code = pioctl(PCCHAR(files[i]), VIOC_FLUSHVOLUME, &blob, 0);
+        code = pioctl_T(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));
+            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);
+        ShowMessageBox(IDS_FLUSH_VOLUME_OK, MB_ICONINFORMATION, IDS_FLUSH_VOLUME_OK);
 }       
 
 void WhichCell(CStringArray& files)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     int error;
     CString str;
@@ -175,15 +276,17 @@ void WhichCell(CStringArray& files)
         blob.out_size = MAXSIZE;
         blob.out = space;
 
-        code = pioctl(PCCHAR(files[i]), VIOC_FILE_CELL_NAME, &blob, 1);
+        code = pioctl_T(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);
+        } else {
+            space[MAXSIZE - 1] = '\0';
+            results.Add(Utf8ToCString(space));
+        }
     }       
 
     LoadString (str, IDS_SHOW_CELL);
@@ -195,7 +298,7 @@ void WhichCell(CStringArray& files)
 
 void WSCellCmd()
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     
     HOURGLASS hourglass;
@@ -216,25 +319,25 @@ void WSCellCmd()
 
 BOOL CheckVolumes()
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     
     blob.in_size = 0;
     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()));
+        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;
 }
 
 void SetCacheSizeCmd(LONG nNewCacheSize)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     
     HOURGLASS hourglass;
@@ -252,7 +355,7 @@ void SetCacheSizeCmd(LONG nNewCacheSize)
 
 void WhereIs(CStringArray& files)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     CStringArray servers;
     CStringArray resultFiles;
@@ -267,7 +370,7 @@ void WhereIs(CStringArray& files)
         blob.out = space;
         memset(space, 0, sizeof(space));
 
-        code = pioctl(PCCHAR(files[i]), VIOCWHEREIS, &blob, 1);
+        code = pioctl_T(files[i], VIOCWHEREIS, &blob, 1);
         if (code) {
             resultFiles.Add(StripPath(files[i]));
             servers.Add(GetAfsError(errno));
@@ -298,34 +401,78 @@ void WhereIs(CStringArray& files)
     dlg.DoModal();
 }       
 
-CString GetAfsError(int code, const char *filename)
+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 TCHAR *filename)
 {
     CString strMsg;
 
+    code = CMtoUNIXerror(code);
+
     if (code == EINVAL) {
         if (filename)
-            strMsg.Format("Invalid argument; it is possible that the file is not in AFS");
+            strMsg.Format(_T("Invalid argument; it is possible that the file is not in AFS"));
         else 
-            strMsg.Format("Invalid argument");
+            strMsg.Format(_T("Invalid argument"));
     } else if (code == ENOENT) {
         if (filename) 
-            strMsg.Format("The file does not exist");
+            strMsg.Format(_T("The file does not exist"));
         else 
-            strMsg.Format("No such file returned");
+            strMsg.Format(_T("No such file returned"));
     } else if (code == EROFS)  {
-        strMsg.Format("You can not change a backup or readonly volume");
+        strMsg.Format(_T("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(_T("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(_T("AFS service may not have started"));
     } else if (code == ESRCH) {
-        strMsg.Format("Cell name not recognized");
+        strMsg.Format(_T("Cell name not recognized"));
     } else if (code == ETIMEDOUT) {
-        strMsg.Format("Connection timed out");
+        strMsg.Format(_T("Connection timed out"));
     } else if (code == EPIPE) {
-        strMsg.Format("Volume name or ID not recognized");
+        strMsg.Format(_T("Volume name or ID not recognized"));
     } else {
-        strMsg.Format("Error 0x%x occurred", code);
+        strMsg.Format(_T("Error 0x%x occurred"), code);
     }
 
     return strMsg;
@@ -355,9 +502,9 @@ struct Acl {
     struct AclEntry *minuslist;
 };
 
-int foldcmp (register char *a, register char *b)
+int foldcmp (char *a, char *b)
 {
-    register char t, u;
+    char t, u;
     while (1) {
         t = *a++;
         u = *b++;
@@ -370,7 +517,7 @@ int foldcmp (register char *a, register char *b)
 
 extern "C" void ZapList(struct AclEntry *alist)
 {
-    register struct AclEntry *tp, *np;
+    struct AclEntry *tp, *np;
 
     for (tp = alist; tp; tp = np) {
         np = tp->next;
@@ -407,7 +554,7 @@ extern "C" int PruneList (struct AclEntry **ae, int dfs)
     return ctr;
 }
 
-char *SkipLine (register char *astr)
+char *SkipLine (char *astr)
 {
     while (*astr != '\n') 
         astr++;
@@ -418,9 +565,9 @@ char *SkipLine (register char *astr)
 }
 
 /* tell if a name is 23 or -45 (digits or minus digits), which are bad names we must prune */
-static int BadName(register char *aname)
+static int BadName(char *aname)
 {
-    register int tc;
+    int tc;
 
     /* all must be '-' or digit to be bad */
     while (tc = *aname++) {
@@ -431,28 +578,28 @@ static int BadName(register char *aname)
     return 1;
 }
 
-CString GetRightsString(register LONG arights, int dfs)
+CString GetRightsString(LONG arights, int dfs)
 {
     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 += _T("r");
+        if (arights & PRSFS_LOOKUP) str += _T("l");
+        if (arights & PRSFS_INSERT) str += _T("i");
+        if (arights & PRSFS_DELETE) str += _T("d");
+        if (arights & PRSFS_WRITE) str += _T("w");
+        if (arights & PRSFS_LOCK) str += _T("k");
+        if (arights & PRSFS_ADMINISTER) str += _T("a");
     } else {
         ASSERT(FALSE);
 /*
-               if (arights & DFS_READ) str += "r"; else str += "-";
-               if (arights & DFS_WRITE) str += "w"; else printf("-");
-               if (arights & DFS_EXECUTE) str += "x"; else printf("-");
-               if (arights & DFS_CONTROL) str += "c"; else printf("-");
-               if (arights & DFS_INSERT) str += "i"; else printf("-");
-               if (arights & DFS_DELETE) str += "d"; else printf("-");
-               if (arights & (DFS_USRALL)) str += "+";
+               if (arights & DFS_READ) str += _T("r"); else str += _T("-");
+               if (arights & DFS_WRITE) str += _T("w"); else printf(_T("-"));
+               if (arights & DFS_EXECUTE) str += _T("x"); else printf(_T("-"));
+               if (arights & DFS_CONTROL) str += _T("c"); else printf(_T("-"));
+               if (arights & DFS_INSERT) str += _T("i"); else printf(_T("-"));
+               if (arights & DFS_DELETE) str += _T("d"); else printf(_T("-"));
+               if (arights & (DFS_USRALL)) str += _T("+");
 */
     }  
 
@@ -487,29 +634,57 @@ char *AclToString(struct Acl *acl)
 
 struct Acl *EmptyAcl(const CString& strCellName)
 {
-    register struct Acl *tp;
+    struct Acl *tp;
+    CStringUtf8 ustrCell(strCellName);
     
     tp = (struct Acl *)malloc(sizeof (struct Acl));
     tp->nplus = tp->nminus = 0;
     tp->pluslist = tp->minuslist = 0;
     tp->dfs = 0;
-    strcpy(tp->cell, strCellName);
+    StringCbCopyA(tp->cell, sizeof(tp->cell), ustrCell);
+
+    return tp;
+}
+
+struct Acl *EmptyAcl(char *astr)
+{
+    struct Acl *tp;
+    int junk;
 
+    tp = (struct Acl *)malloc(sizeof (struct Acl));
+    tp->nplus = tp->nminus = 0;
+    tp->pluslist = tp->minuslist = 0;
+    tp->dfs = 0;
+    if (astr == NULL || sscanf(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell) <= 0) {
+        tp->dfs = 0;
+        tp->cell[0] = '\0';
+    }
     return tp;
 }
 
-struct Acl *ParseAcl(char *astr)
+struct Acl *
+ParseAcl (char *astr)
 {
-    int nplus, nminus, i, trights;
+    int nplus, nminus, i, trights, ret;
     char tname[MAXNAME];
-    struct AclEntry *first, *last, *tl;
+    struct AclEntry *first, *next, *last, *tl;
     struct Acl *ta;
 
-    ta = (struct Acl *) malloc (sizeof (struct Acl));
-    ta->dfs = 0;
-    sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
+    ta = EmptyAcl(NULL);
+    if (astr == NULL || strlen(astr) == 0)
+        return ta;
+
+    ret = sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
+    if (ret <= 0) {
+        free(ta);
+        return NULL;
+    }
     astr = SkipLine(astr);
-    sscanf(astr, "%d", &ta->nminus);
+    ret = sscanf(astr, "%d", &ta->nminus);
+    if (ret <= 0) {
+        free(ta);
+        return NULL;
+    }
     astr = SkipLine(astr);
 
     nplus = ta->nplus;
@@ -517,46 +692,69 @@ struct Acl *ParseAcl(char *astr)
 
     last = 0;
     first = 0;
-    for(i = 0; i < nplus; i++) {
-        sscanf(astr, "%100s %d", tname, &trights);
+    for(i=0;i<nplus;i++) {
+        ret = sscanf(astr, "%100s %d", tname, &trights); 
+        if (ret <= 0)
+            goto nplus_err;
         astr = SkipLine(astr);
         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
-        if (!first)
-                       first = tl;
+        if (tl == NULL)
+            goto nplus_err;
+        if (!first) 
+            first = tl;
         strcpy(tl->name, tname);
         tl->rights = trights;
         tl->next = 0;
-        if (last)
-                       last->next = tl;
+        if (last) 
+            last->next = tl;
         last = tl;
     }
     ta->pluslist = first;
 
     last = 0;
     first = 0;
-    for(i=0; i < nminus; i++) {
-        sscanf(astr, "%100s %d", tname, &trights);
+    for(i=0;i<nminus;i++) {
+        ret = sscanf(astr, "%100s %d", tname, &trights);
+        if (ret <= 0)
+            goto nminus_err;
         astr = SkipLine(astr);
         tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
+        if (tl == NULL)
+            goto nminus_err;
         if (!first) 
-                       first = tl;
+            first = tl;
         strcpy(tl->name, tname);
         tl->rights = trights;
         tl->next = 0;
         if (last) 
-                       last->next = tl;
+            last->next = tl;
         last = tl;
     }
     ta->minuslist = first;
 
     return ta;
+
+  nminus_err:
+    for (;first; first = next) {
+        next = first->next;
+        free(first);
+    }   
+    first = ta->pluslist;
+
+  nplus_err:
+    for (;first; first = next) {
+        next = first->next;
+        free(first);
+    }   
+    free(ta);
+    return NULL;
 }
 
 /* clean up an access control list of its bad entries; return 1 if we made
    any changes to the list, and 0 otherwise */
 extern "C" int CleanAcl(struct Acl *aa)
 {
-    register struct AclEntry *te, **le, *ne;
+    struct AclEntry *te, **le, *ne;
     int changes;
 
     HOURGLASS hourglass;
@@ -601,12 +799,12 @@ extern "C" int CleanAcl(struct Acl *aa)
 
 void CleanACL(CStringArray& names)
 {
-    register LONG code;
-    register struct Acl *ta;
+    LONG code;
+    struct Acl *ta;
     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;
 
@@ -615,15 +813,19 @@ void CleanACL(CStringArray& names)
         blob.in_size = 0;
         blob.out = space;
 
-        code = pioctl(PCCHAR(names[i]), VIOCGETAL, &blob, 1);
+        code = pioctl_T(names[i], VIOCGETAL, &blob, 1);
         if (code) {
-            ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONEXCLAMATION, 0, names[i], GetAfsError(errno));
+            ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONERROR, 0, names[i], GetAfsError(errno));
             continue;
         }
 
         ta = ParseAcl(space);
+        if (ta == NULL) {
+            ShowMessageBox(IDS_INVALID_ACL_DATA, MB_ICONERROR, IDS_INVALID_ACL_DATA);
+            continue;
+        }
         if (ta->dfs) {
-            ShowMessageBox(IDS_CLEANACL_NOT_SUPPORTED, MB_ICONEXCLAMATION, IDS_CLEANACL_NOT_SUPPORTED, names[i]);
+            ShowMessageBox(IDS_CLEANACL_NOT_SUPPORTED, MB_ICONERROR, IDS_CLEANACL_NOT_SUPPORTED, names[i]);
             continue;
         }
 
@@ -636,14 +838,14 @@ void CleanACL(CStringArray& names)
         blob.in_size = strlen((char *)blob.in) + 1;
         blob.out_size = 0;
                
-        code = pioctl(PCCHAR(names[i]), VIOCSETAL, &blob, 1);
+        code = pioctl_T(names[i], VIOCSETAL, &blob, 1);
         if (code) {
             if (errno == EINVAL) {
-                ShowMessageBox(IDS_CLEANACL_INVALID_ARG, MB_ICONEXCLAMATION, IDS_CLEANACL_INVALID_ARG, names[i]);
+                ShowMessageBox(IDS_CLEANACL_INVALID_ARG, MB_ICONERROR, IDS_CLEANACL_INVALID_ARG, names[i]);
                 continue;
             }
             else {
-                ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONEXCLAMATION, 0, names[i], GetAfsError(errno));
+                ShowMessageBox(IDS_CLEANACL_ERROR, MB_ICONERROR, 0, names[i], GetAfsError(errno));
                 continue;
             }
         }
@@ -653,8 +855,8 @@ void CleanACL(CStringArray& names)
 // Derived from fs.c's ListAclCmd
 BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& strNegative)
 {
-    register LONG code;
-    register struct Acl *ta;
+    LONG code;
+    struct Acl *ta;
     struct ViceIoctl blob;
     struct AclEntry *te;
     int idf = 0; //getidf(as, parm_listacl_id);
@@ -665,15 +867,19 @@ BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& str
     blob.in_size = idf;
     blob.in = blob.out = space;
        
-    code = pioctl(PCCHAR(strDir), VIOCGETAL, &blob, 1);
+    code = pioctl_T(strDir, VIOCGETAL, &blob, 1);
     if (code) {
-        ShowMessageBox(IDS_GETRIGHTS_ERROR, MB_ICONEXCLAMATION, IDS_GETRIGHTS_ERROR, strDir, GetAfsError(errno));
+        ShowMessageBox(IDS_GETRIGHTS_ERROR, MB_ICONERROR, IDS_GETRIGHTS_ERROR, strDir, GetAfsError(errno));
         return FALSE;
     }
 
     ta = ParseAcl(space);
+    if (ta == NULL) {
+        ShowMessageBox(IDS_INVALID_ACL_DATA, MB_ICONERROR, IDS_INVALID_ACL_DATA);
+        return FALSE;
+    }
     if (ta->dfs) {
-        ShowMessageBox(IDS_DFSACL_ERROR, MB_ICONEXCLAMATION, IDS_DFSACL_ERROR);
+        ShowMessageBox(IDS_DFSACL_ERROR, MB_ICONERROR, IDS_DFSACL_ERROR);
         return FALSE;
     }
 
@@ -699,7 +905,7 @@ BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& str
     return TRUE;
 }
 
-struct AclEntry *FindList(register struct AclEntry *pCurEntry, const char *entryName)
+struct AclEntry *FindList(struct AclEntry *pCurEntry, const char *entryName)
 {
     while (pCurEntry) {
         if (!foldcmp(pCurEntry->name, PCCHAR(entryName)))
@@ -710,17 +916,18 @@ struct AclEntry *FindList(register struct AclEntry *pCurEntry, const char *entry
     return 0;
 }
 
-void ChangeList (struct Acl *pAcl, BYTE bNormalRights, const char *entryName, LONG nEntryRights)
+void ChangeList(struct Acl *pAcl, BYTE bNormalRights, const CString & entryName, LONG nEntryRights)
 {
     ASSERT(pAcl);
     ASSERT(entryName);
     
     struct AclEntry *pEntry;
+    CStringUtf8 uEntryName(entryName);
 
     HOURGLASS hourglass;
 
     pEntry = (bNormalRights ? pAcl->pluslist : pAcl->minuslist);
-    pEntry = FindList(pEntry, entryName);
+    pEntry = FindList(pEntry, uEntryName);
 
     /* Found the item already in the list. */
     if (pEntry) {
@@ -736,7 +943,7 @@ 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, uEntryName);
     pEntry->rights = nEntryRights;
     
     if (bNormalRights) {
@@ -757,42 +964,41 @@ void ChangeList (struct Acl *pAcl, BYTE bNormalRights, const char *entryName, LO
 
 enum rtype {add, destroy, deny};
 
-LONG Convert(const register char *arights, int dfs, enum rtype *rtypep)
+static LONG Convert(const CString& strRights, int dfs, enum rtype *rtypep)
 {
-    register int i, len;
+    int i, len;
     LONG mode;
-    register char tc;
 
     *rtypep = add;     /* add rights, by default */
 
-    if (!strcmp(arights,"read")) 
+    if (strRights == _T("read")) 
         return PRSFS_READ | PRSFS_LOOKUP;
-    if (!strcmp(arights, "write")) 
+    if (strRights == _T("write")) 
         return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK;
-    if (!strcmp(arights, "mail")) 
+    if (strRights == _T("mail")) 
         return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
-    if (!strcmp(arights, "all")) 
+    if (strRights == _T("all")) 
         return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
     
-    if (!strcmp(arights, "none")) {
+    if (strRights == _T("none")) {
         *rtypep = destroy; /* Remove entire entry */
         return 0;
     }
 
-    len = strlen(arights);
+    len = strRights.GetLength();
     mode = 0;
 
     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;
+        TCHAR c = strRights[i];
+        if (c == _T('r')) mode |= PRSFS_READ;
+        else if (c == _T('l')) mode |= PRSFS_LOOKUP;
+        else if (c == _T('i')) mode |= PRSFS_INSERT;
+        else if (c == _T('d')) mode |= PRSFS_DELETE;
+        else if (c == _T('w')) mode |= PRSFS_WRITE;
+        else if (c == _T('k')) mode |= PRSFS_LOCK;
+        else if (c == _T('a')) mode |= PRSFS_ADMINISTER;
         else {
-            fprintf(stderr, "illegal rights character '%c'.\n", tc);
+            fprintf(stderr, "illegal rights character '%c'.\n", c);
             exit(1);
         }
     }   
@@ -801,7 +1007,7 @@ LONG Convert(const register char *arights, int dfs, enum rtype *rtypep)
 
 BOOL SaveACL(const CString& strCellName, const CString& strDir, const CStringArray& normal, const CStringArray& negative)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     struct Acl *pAcl;
     LONG rights;
@@ -830,12 +1036,12 @@ BOOL SaveACL(const CString& strCellName, const CString& strDir, const CStringArr
     blob.out_size = 0;
     blob.in_size = 1 + strlen((const char *)blob.in);
 
-    code = pioctl(PCCHAR(strDir), VIOCSETAL, &blob, 1);
+    code = pioctl_T(strDir, VIOCSETAL, &blob, 1);
     if (code) {
         if (errno == EINVAL)
-            ShowMessageBox(IDS_SAVE_ACL_EINVAL_ERROR, MB_ICONEXCLAMATION, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
+            ShowMessageBox(IDS_SAVE_ACL_EINVAL_ERROR, MB_ICONERROR, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
         else
-            ShowMessageBox(IDS_SAVE_ACL_ERROR, MB_ICONEXCLAMATION, IDS_SAVE_ACL_ERROR, strDir, GetAfsError(errno, strDir));
+            ShowMessageBox(IDS_SAVE_ACL_ERROR, MB_ICONERROR, IDS_SAVE_ACL_ERROR, strDir, GetAfsError(errno, strDir));
     }       
 
     ZapAcl(pAcl);
@@ -845,7 +1051,7 @@ BOOL SaveACL(const CString& strCellName, const CString& strDir, const CStringArr
 
 BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringArray& negative, BOOL bClear)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     struct Acl *pToAcl;
     int idf = 0; // getidf(as, parm_copyacl_id);
@@ -857,9 +1063,9 @@ BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringA
     blob.in_size = idf;
     blob.in = blob.out = space;
        
-    code = pioctl(PCCHAR(strToDir), VIOCGETAL, &blob, 1);
+    code = pioctl_T(strToDir, VIOCGETAL, &blob, 1);
     if (code) {
-        ShowMessageBox(IDS_ACL_READ_ERROR, MB_ICONEXCLAMATION, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
+        ShowMessageBox(IDS_ACL_READ_ERROR, MB_ICONERROR, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
         return FALSE;
     }
        
@@ -868,10 +1074,15 @@ BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringA
     else 
         pToAcl = ParseAcl(space);
 
+    if (pToAcl == NULL) {
+        ShowMessageBox(IDS_INVALID_ACL_DATA, MB_ICONERROR, IDS_INVALID_ACL_DATA);
+        return FALSE;
+    }
+
     CleanAcl(pToAcl);
 
     if (pToAcl->dfs) {
-        ShowMessageBox(IDS_NO_DFS_COPY_ACL, MB_ICONEXCLAMATION, IDS_NO_DFS_COPY_ACL, strToDir);
+        ShowMessageBox(IDS_NO_DFS_COPY_ACL, MB_ICONERROR, IDS_NO_DFS_COPY_ACL, strToDir);
         ZapAcl(pToAcl);
         return FALSE;
     }
@@ -896,19 +1107,19 @@ BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringA
     blob.out_size = 0;
     blob.in_size = 1 + strlen((char *)blob.in);
 
-    code = pioctl(PCCHAR(strToDir), VIOCSETAL, &blob, 1);
+    code = pioctl_T(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);
+            ShowMessageBox(IDS_COPY_ACL_EINVAL_ERROR, MB_ICONERROR, IDS_COPY_ACL_EINVAL_ERROR, strToDir);
         else 
-            ShowMessageBox(IDS_COPY_ACL_ERROR, MB_ICONEXCLAMATION, IDS_COPY_ACL_ERROR, strToDir, GetAfsError(errno, strToDir));
+            ShowMessageBox(IDS_COPY_ACL_ERROR, MB_ICONERROR, IDS_COPY_ACL_ERROR, strToDir, GetAfsError(errno, strToDir));
         return FALSE;
     }
 
     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;
 }
@@ -932,30 +1143,48 @@ CString ParseMountPoint(const CString strFile, CString strMountPoint)
     } else
         strVolume = strMountPoint.Mid(1);
 
-    strMountPointInfo = strFile + "\t" + strVolume + "\t" + strCell + "\t" + strType;
+    strMountPointInfo = strFile + _T("\t") + strVolume + _T("\t") + strCell + _T("\t") + strType;
 
     return strMountPointInfo;
 }       
 
-BOOL IsPathInAfs(const CHAR *strPath)
+CString ParseSymlink(const CString strFile, CString strSymlink)
+{
+    CString strSymlinkInfo;
+
+    strSymlinkInfo = strFile + _T("\t") + strSymlink;
+
+    return strSymlinkInfo;
+}       
+
+BOOL IsPathInAfs(const CString & strPath)
 {
     struct ViceIoctl blob;
+    cm_ioctlQueryOptions_t options;
+    cm_fid_t fid;
     int code;
 
     HOURGLASS hourglass;
 
-    blob.in_size = 0;
-    blob.out_size = MAXSIZE;
-    blob.out = space;
+    memset(&options, 0, sizeof(options));
+    options.size = sizeof(options);
+    options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
+    options.literal = 1;
+    blob.in_size = options.size;    /* no variable length data */
+    blob.in = &options;
+    blob.out_size = sizeof(cm_fid_t);
+    blob.out = (char *) &fid;
 
-    code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
-    if (code)
+    code = pioctl_T(strPath, VIOCGETFID, &blob, 1);
+    if (code) {
+       if ((errno == EINVAL) || (errno == ENOENT))
         return FALSE;
+    }
     return TRUE;
 }
 
 static int 
-IsFreelanceRoot(char *apath)
+IsFreelanceRoot(const CString& apath)
 {
     struct ViceIoctl blob;
     afs_int32 code;
@@ -964,13 +1193,13 @@ IsFreelanceRoot(char *apath)
     blob.out_size = MAXSIZE;
     blob.out = space;
 
-    code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
+    code = pioctl_T(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 const char * NetbiosName(void)
 {
     static char buffer[1024] = "AFS";
     HKEY  parmKey;
@@ -979,10 +1208,10 @@ const char * NetbiosName(void)
     DWORD enabled = 0;
 
     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
-                         0, KEY_QUERY_VALUE, &parmKey);
+                         0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
         dummyLen = sizeof(buffer);
-        code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
+        code = RegQueryValueExA(parmKey, "NetbiosName", NULL, NULL,
                               (LPBYTE)buffer, &dummyLen);
         RegCloseKey (parmKey);
     } else {
@@ -991,6 +1220,24 @@ const char * NetbiosName(void)
     return buffer;
 }
 
+static void FixNetbiosPath(CString& path)
+{
+    if (!IsPathInAfs(path)) {
+        CString nbroot;
+        const char * nbname = NetbiosName();
+
+#ifdef UNICODE
+        nbroot.Format(_T("\\\\%S\\"), nbname);
+#else
+        nbroot.Format(_T("\\\\%s\\"), nbname);
+#endif
+
+        if (nbroot.CompareNoCase(path) == 0) {
+            path.Append(_T("all\\"));
+        }
+    }
+}
+
 #define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
 
 static BOOL IsAdmin (void)
@@ -1005,8 +1252,8 @@ static BOOL IsAdmin (void)
          */
         PSID psidAdmin = NULL;
         DWORD dwSize, dwSize2;
-        char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
-        char *pszRefDomain = NULL;
+        TCHAR pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
+        TCHAR *pszRefDomain = NULL;
         SID_NAME_USE snu = SidTypeGroup;
 
         dwSize = sizeof(pszAdminGroup);
@@ -1020,8 +1267,8 @@ static BOOL IsAdmin (void)
         dwSize = 0;
         dwSize2 = 0;
 
-        strcat(pszAdminGroup,"\\");
-        strcat(pszAdminGroup, AFSCLIENT_ADMIN_GROUPNAME);
+        lstrcat(pszAdminGroup, _T("\\"));
+        lstrcat(pszAdminGroup, _T(AFSCLIENT_ADMIN_GROUPNAME));
 
         LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
         /* that should always fail. */
@@ -1039,7 +1286,7 @@ static BOOL IsAdmin (void)
         }
 
         psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
-        pszRefDomain = (char *)malloc(dwSize2);
+        pszRefDomain = (TCHAR *)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.  
@@ -1126,48 +1373,75 @@ static BOOL IsAdmin (void)
     return fAdmin;
 }
 
-/* return a static pointer to a buffer */
-static char *Parent(char *apath)
+CString Parent(const CString& path)
 {
-    register char *tp;
+    int last_slash = path.ReverseFind(_T('\\'));
 
-    strcpy(tspace, apath);
-    tp = strrchr(tspace, '\\');
-    if (tp) {
-        *(tp+1) = 0;   /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
+    if (last_slash != -1) {
+        CString ret = path.Left(last_slash + 1);
+        return ret;
+    } else {
+        if (path.GetLength() >= 2 && path[1] == _T(':')) {
+            CString ret = path.Left(2);
+            ret.AppendChar(_T('.'));
+            return ret;
+        } else {
+            CString ret = _T(".");
+            return ret;
+        }
     }
-    else {
-        fs_ExtractDriveLetter(apath, tspace);
-       strcat(tspace, ".");
     }
     
-    return tspace;
+CString LastComponent(const CString& path)
+{
+    int last_slash = path.ReverseFind(_T('\\'));
+
+    if (last_slash != -1) {
+        CString ret = path.Mid(last_slash + 1);
+        return ret;
+    } else {
+        if (path.GetLength() >= 2 && path[1] == _T(':')) {
+            CString ret = path.Mid(2);
+            return ret;
+        } else {
+            CString ret = path;
+            return ret;
+        }
+    }
 }
 
-static afs_int32
-GetCell(char *fname, char *cellname)
+static CString
+GetCell(const CString & path)
 {
+    char cellname[MAXCELLCHARS];
     afs_int32 code;
     struct ViceIoctl blob;
 
     blob.in_size = 0;
-    blob.out_size = MAXCELLCHARS;
+    blob.out_size = sizeof(cellname);
     blob.out = cellname;
 
-    code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1);
-    return code ? errno : 0;
+    code = pioctl_T(path, VIOC_FILE_CELL_NAME, &blob, 1);
+    if (code) {
+        CString s;
+        s.Empty();
+
+        return s;
+    } else {
+        return Utf8ToCString(cellname);
+    }
 }
 
 
 BOOL ListMount(CStringArray& files)
 {
-    register LONG code;
+    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 */
+
+    CString parent_dir;                /* Parent directory of true name */
+    CStringUtf8 last_component;                /* Last component of true name */
+
     CStringArray mountPoints;
     
     HOURGLASS hourglass;
@@ -1175,58 +1449,43 @@ BOOL ListMount(CStringArray& files)
     error = 0;
 
     for (int i = 0; i < files.GetSize(); i++) {
-        strcpy(orig_name, files[i]);
-        strcpy(true_name, orig_name);
+        int last_slash = files[i].ReverseFind(_T('\\'));
 
-        /*
-         * 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);
-               }
+        if (last_slash != -1) {
+            last_component.SetString( files[i].Mid(last_slash + 1) );
+            parent_dir.SetString( files[i].Left(last_slash + 1) );
+            FixNetbiosPath(parent_dir);
+        } else {
+            // The path is of the form "C:foo" or just "foo".  If
+            // there is a drive, then use the current directory of
+            // that drive.  Otherwise we just use '.'.
+
+            if (files[i].GetLength() >= 2 && files[i][1] == _T(':')) {
+                parent_dir.Format(_T("%c:."), files[i][0]);
+                last_component.SetString( files[i].Mid(2) );
+            } else {
+                parent_dir.SetString( _T("."));
+                last_component.SetString( files[i] );
            }
         }
-        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.in_size = last_component.GetLength() + 1;
+        blob.in = last_component.GetBuffer();
         blob.out_size = MAXSIZE;
         blob.out = space;
         memset(space, 0, MAXSIZE);
 
-        code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
+        code = pioctl_T(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
+
+        last_component.ReleaseBuffer();
+
         if (code == 0) {
-            int nPos = strlen(space) - 1;
+            int nPos;
+            space[MAXSIZE - 1] = '\0';
+            nPos = strlen(space) - 1;
             if (space[nPos] == '.')
                 space[nPos] = 0;
-            mountPoints.Add(ParseMountPoint(StripPath(files[i]), space));
+            mountPoints.Add(ParseMountPoint(StripPath(files[i]), Utf8ToCString(space)));
         } else {
             error = 1;
             if (errno == EINVAL)
@@ -1243,99 +1502,55 @@ BOOL ListMount(CStringArray& files)
     return !error;
 }
 
-BOOL MakeMount(const CString& strDir, const CString& strVolName, const CString& strCellName, BOOL bRW)
+BOOL
+MakeMount(const CString& strDir,
+          const CString& strVolName,
+          const CString& strInCellName,
+          BOOL bRW)
 {
-    register LONG code;
-    register char *cellName;
-    char localCellName[128];
-    struct afsconf_cell info;
+    LONG code;
     struct ViceIoctl blob;
-    char * parent;
-    char path[1024] = "";
-
     HOURGLASS hourglass;
 
     ASSERT(strVolName.GetLength() < 64);
 
-    if (strCellName.GetLength() > 0)   /* cell name specified */
-        cellName = PCCHAR(strCellName);
-    else
-        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_ICONEXCLAMATION, IDS_MAKE_MP_NOT_AFS_ERROR);
-               return FALSE;
-           }
-       } else {
-           ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_MP_NOT_AFS_ERROR);
+    CString strParent = Parent(strDir);
+
+    FixNetbiosPath(strParent);
+    if (!IsPathInAfs(strParent)) {
+           ShowMessageBox(IDS_MAKE_MP_NOT_AFS_ERROR, MB_ICONERROR, IDS_MAKE_MP_NOT_AFS_ERROR);
            return FALSE;
        }
-    }
 
-    if ( strlen(path) == 0 )
-       strcpy(path, PCCHAR(strDir));
+    CString strPath = strParent + LastComponent(strDir);
 
-    if ( IsFreelanceRoot(parent) ) {
-       if ( !IsAdmin() ) {
-           ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONEXCLAMATION, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
+    if ( IsFreelanceRoot(strParent) && !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);
-    }
+    CString strMount;
 
-    code = GetCellName(cellName?cellName:space, &info);
-    if (code) {
-       return FALSE;
-    }
-
-    if (bRW)   /* if -rw specified */
-        strcpy(space, "%");
-    else
-        strcpy(space, "#");
+    strMount.Format(_T("%c%s%s%s."),
+                    ((bRW)?_T('%'):_T('#')),
+                    strInCellName,
+                    ((strInCellName.IsEmpty())?_T(""):_T(":")),
+                    strVolName);
 
-    /* If cellular mount point, prepend cell prefix */
-    if (cellName) {
-        strcat(space, info.name);
-        strcat(space, ":");
-    }   
+    CStringUtf8 ustrMount(strMount);
 
-    strcat(space, strVolName); /* append volume name */
-    strcat(space, ".");                /* stupid convention; these end with a period */
-
-    /* create symlink with a special pioctl for Windows NT, since it doesn't
-     * have a symlink system call.
-     */
     blob.out_size = 0;
-    blob.in_size = 1 + strlen(space);
-    blob.in = space;
+    blob.in_size = ustrMount.GetLength() + 1;
+    blob.in = ustrMount.GetBuffer();
     blob.out = NULL;
-    code = pioctl(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
+
+    code = pioctl_T(strPath, VIOC_AFS_CREATE_MT_PT, &blob, 0);
+
+    ustrMount.ReleaseBuffer();
 
     if (code) {
-        ShowMessageBox(IDS_MOUNT_POINT_ERROR, MB_ICONEXCLAMATION, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
+        ShowMessageBox(IDS_MOUNT_POINT_ERROR, MB_ICONERROR, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
         return FALSE;
     }
     
@@ -1374,162 +1589,90 @@ long fs_StripDriveLetter(const char *inPathp, char *outPathp, long outSize)
 }       
 
 
-BOOL RemoveSymlink(const char * linkName)
+BOOL RemoveSymlink(const CString& strName)
 {
     BOOL error = FALSE;
     INT code=0;
     struct ViceIoctl blob;
-    char tbuffer[1024];
     char lsbuffer[1024];
-    char tpbuffer[1024];
-    char *tp;
     
     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 */
-
-       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(linkName, tbuffer);
-        strcat(tbuffer, ".");
-        fs_StripDriveLetter(tp, tpbuffer, 0);
-        tp=tpbuffer;
-    }
+    CString strParent = Parent(strName);
+    CStringUtf8 ustrLast(LastComponent(strName));
+    FixNetbiosPath(strParent);
 
-    if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
-       ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONEXCLAMATION, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
+    if ( IsFreelanceRoot(strParent) && !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.in_size = ustrLast.GetLength() + 1;
+    blob.in = ustrLast.GetBuffer();
     blob.out = lsbuffer;
     blob.out_size = sizeof(lsbuffer);
-    code = pioctl(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
+    code = pioctl_T(strParent, VIOC_LISTSYMLINK, &blob, 0);
+    ustrLast.ReleaseBuffer();
     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);
+    blob.in_size = ustrLast.GetLength() + 1;
+    blob.in = ustrLast.GetBuffer();
+
+    code = pioctl_T(strParent, VIOC_DELSYMLINK, &blob, 0);
+
+    ustrLast.ReleaseBuffer();
+
+    return (code == 0);
 }       
 
-BOOL IsSymlink(const char * true_name)
+BOOL IsSymlink(const CString& strName)
 {
-    char parent_dir[MAXSIZE];          /*Parent directory of true name*/
-    char strip_name[MAXSIZE];
     struct ViceIoctl blob;
-    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*/
+    CStringUtf8 ustrLast(LastComponent(strName));
+    CString strParent = Parent(strName);
 
-       if (!IsPathInAfs(parent_dir)) {
-           const char * nbname = NetbiosName();
-           int len = strlen(nbname);
+    FixNetbiosPath(strParent);
 
-           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;
-        fs_StripDriveLetter(true_name, strip_name, sizeof(strip_name));
-    }
-
-    blob.in = last_component;
-    blob.in_size = strlen(last_component)+1;
+    blob.in_size = ustrLast.GetLength() + 1;
+    blob.in = ustrLast.GetBuffer();
     blob.out_size = MAXSIZE;
     blob.out = space;
     memset(space, 0, MAXSIZE);
-    code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
+
+    code = pioctl_T(strParent, VIOC_LISTSYMLINK, &blob, 1);
+
+    ustrLast.ReleaseBuffer();
+
     return (code==0);
 }       
 
 
-BOOL IsMountPoint(const char * name)
+BOOL IsMountPoint(const CString& path)
 {
-    register LONG code = 0;
+    LONG code = 0;
     struct ViceIoctl blob;
-    char tbuffer[1024];
     char lsbuffer[1024];
-    register char *tp;
-    char szCurItem[1024];
 
-    strcpy(szCurItem, name);
-       
-    tp = (char *)strrchr(szCurItem, '\\');
-    if (tp) {
-        strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
-        tbuffer[code] = 0;
-        tp++;   /* skip the slash */
+    HOURGLASS hourglass;
 
-       if (!IsPathInAfs(tbuffer)) {
-           const char * nbname = NetbiosName();
-           int len = strlen(nbname);
+    CString parent = Parent(path);
+    FixNetbiosPath(parent);
 
-           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);
-    }
+    CStringUtf8 mountpoint(LastComponent(path));
 
-    blob.in = tp;
-    blob.in_size = strlen(tp)+1;
+    blob.in_size = mountpoint.GetLength() + 1;
+    blob.in = mountpoint.GetBuffer();
     blob.out = lsbuffer;
     blob.out_size = sizeof(lsbuffer);
 
-    code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
+    code = pioctl_T(parent, VIOC_AFS_STAT_MT_PT, &blob, 0);
+
+    mountpoint.ReleaseBuffer();
 
     return (code==0);
 }       
@@ -1543,11 +1686,8 @@ BOOL IsMountPoint(const char * name)
  */
 BOOL RemoveMount(CStringArray& files)
 {
-    register LONG code = 0;
+    LONG code = 0;
     struct ViceIoctl blob;
-    char tbuffer[1024];
-    register char *tp;
-    char szCurItem[1024];
     BOOL error = FALSE;
     CStringArray results;
     CString str;
@@ -1565,44 +1705,24 @@ BOOL RemoveMount(CStringArray& files)
             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 */
-
-           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);
-        }
+        CString parent = Parent(files[i]);
+        CStringUtf8 mountpoint(LastComponent(files[i]));
+        FixNetbiosPath(parent);
 
-       if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
+        if ( IsFreelanceRoot(parent) && !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;
+        blob.in_size = mountpoint.GetLength() + 1;
+        blob.in = mountpoint.GetBuffer();
+
+        code = pioctl_T(parent, VIOC_AFS_DELETE_MT_PT, &blob, 0);
+
+        mountpoint.ReleaseBuffer();
 
-        code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
         if (code) {
             error = TRUE;
             results.Add(GetMessageString(IDS_ERROR, GetAfsError(errno, StripPath(files[i]))));
@@ -1621,7 +1741,7 @@ BOOL RemoveMount(CStringArray& files)
 
 BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     struct VolumeStatus *status;
     char *name;
@@ -1647,8 +1767,8 @@ BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
     blob.in_size = 0;
     blob.out = space;
 
-    code = pioctl(PCCHAR(strFile), VIOCGETVOLSTAT, &blob, 1);
-    if (code) {
+    code = pioctl_T(strFile, VIOCGETVOLSTAT, &blob, 1);
+    if (code || blob.out_size < sizeof(*status)) {
         volInfo.m_strErrorMsg = GetAfsError(errno, strFile);
         return FALSE;
     }
@@ -1656,7 +1776,7 @@ BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
     status = (VolumeStatus *)space;
     name = (char *)status + sizeof(*status);
 
-    volInfo.m_strName = name;
+    volInfo.m_strName = Utf8ToCString(name);
     volInfo.m_nID = status->Vid;
     volInfo.m_nQuota = status->MaxQuota;
     volInfo.m_nNewQuota = status->MaxQuota;
@@ -1670,7 +1790,7 @@ BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
        
 BOOL SetVolInfo(CVolInfo& volInfo)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
     struct VolumeStatus *status;
     char *input;
@@ -1706,26 +1826,27 @@ BOOL SetVolInfo(CVolInfo& volInfo)
     }
 #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));
+    code = pioctl_T(volInfo.m_strFilePath, VIOCSETVOLSTAT, &blob, 1);
+    if (code || blob.out_size < sizeof(*status)) {
+        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)
+void GetCellName(const CString& cellNamep, struct afsconf_cell *infop)
 {
-    strcpy(infop->name, cellNamep);
-    return 0;
+    CStringUtf8 uCellName(cellNamep);
+
+    StringCbCopyA(infop->name, sizeof(infop->name), uCellName);
 }
 
 BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bFast)
 {
-    register LONG code;
+    LONG code;
     struct ViceIoctl blob;
-    register LONG j;
+    LONG j;
     LONG temp = 0;
     struct afsconf_cell info;
     struct chservinfo checkserv;
@@ -1742,7 +1863,7 @@ BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bF
 
     if (nCellsToCheck == SPECIFIC_CELL) {
        temp = 2;
-        GetCellName(PCCHAR(strCellName), &info);
+        GetCellName(strCellName, &info);
         strcpy(checkserv.tbuffer,info.name);
         checkserv.tsize = strlen(info.name) + 1;
     } else {
@@ -1758,16 +1879,16 @@ BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bF
     checkserv.tflags = temp;
     checkserv.tinterval = -1;  /* don't change current interval */
 
-    code = pioctl(0, VIOCCKSERV, &blob, 1);
+    code = pioctl_utf8(0, VIOCCKSERV, &blob, 1);
     if (code) {
-        ShowMessageBox(IDS_CHECK_SERVERS_ERROR, MB_ICONEXCLAMATION, IDS_CHECK_SERVERS_ERROR, GetAfsError(errno, CString()));
+        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);
+        ShowMessageBox(IDS_ALL_SERVERS_RUNNING, MB_OK|MB_ICONINFORMATION, IDS_ALL_SERVERS_RUNNING);
         return TRUE;
     }
 
@@ -1828,7 +1949,7 @@ BOOL GetTokenInfo(CStringArray& tokenInfo)
             break;
         }
         else if (rc) {
-            ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR, MB_ICONEXCLAMATION, IDS_GET_TOKENS_UNEXPECTED_ERROR, 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);
@@ -1836,7 +1957,7 @@ BOOL GetTokenInfo(CStringArray& tokenInfo)
         else {
             rc = ktc_GetToken(&serviceName, &token, sizeof(token), &clientName);
             if (rc) {
-                ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR2, MB_ICONEXCLAMATION, IDS_GET_TOKENS_UNEXPECTED_ERROR2, 
+                ShowMessageBox(IDS_GET_TOKENS_UNEXPECTED_ERROR2, MB_ICONERROR, IDS_GET_TOKENS_UNEXPECTED_ERROR2, 
                                 serviceName.name, serviceName.instance,        serviceName.cell, rc);
                 continue;
             }
@@ -1874,7 +1995,11 @@ BOOL GetTokenInfo(CStringArray& tokenInfo)
                 expireString += 4;      /* Skip day of week */
                 expireString[12] = '\0'; /* Omit secs & year */
 //             printf("[Expires %s]\n", expireString);
-                strExpir.Format("%s", expireString);
+#ifdef UNICODE
+                strExpir.Format(_T("%S"), expireString);
+#else
+                strExpir.Format(_T("%s"), expireString);
+#endif
             }
 
             strTokenInfo = strUserName + "\t" + strCellName + "\t" + strExpir + "\t" + strCellName;
@@ -1887,65 +2012,34 @@ BOOL GetTokenInfo(CStringArray& tokenInfo)
     return TRUE;
 }
 
-UINT MakeSymbolicLink(const char *strName, const char *strDir)
+UINT MakeSymbolicLink(const CString& strName, const CString& strTarget)
 {
     struct ViceIoctl blob;
-    char space[MAXSIZE];
-    char * parent;
-    char path[1024] = "";
     UINT code;
-
     HOURGLASS hourglass;
-    static char message[2048];
-
-    strcpy(path, strDir);
-    parent = Parent(path);
 
-    sprintf(message,"MakeSymbolicLink: path = %s parent = %s\n",path,parent);
-    OutputDebugString(message);
+    CString strParent = Parent(strName);
+    FixNetbiosPath(strParent);
 
-    /*lets confirm its a good symlink*/
-    if (!IsPathInAfs(path)) {
-       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, &strDir[strlen(parent)]);
-           parent = Parent(path);
-           sprintf(message,"MakeSymbolicLink: new path = %s parent = %s\n",path,parent);
-           OutputDebugString(message);
-
-           if (!IsPathInAfs(parent)) {
-               ShowMessageBox(IDS_MAKE_LNK_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_LNK_NOT_AFS_ERROR);
-               return TRUE;
-           }
-       } else {
-           ShowMessageBox(IDS_MAKE_LNK_NOT_AFS_ERROR, MB_ICONEXCLAMATION, IDS_MAKE_LNK_NOT_AFS_ERROR);
-           return TRUE;
-       }
-    }
-
-    if ( IsFreelanceRoot(parent) && !IsAdmin() ) {
-       ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONEXCLAMATION, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
+    if ( IsFreelanceRoot(strParent) && !IsAdmin() ) {
+       ShowMessageBox(IDS_NOT_AFS_CLIENT_ADMIN_ERROR, MB_ICONERROR, IDS_NOT_AFS_CLIENT_ADMIN_ERROR);
        return FALSE;
     }
 
-    LPTSTR lpsz = new TCHAR[strlen(strDir)+1];
-    _tcscpy(lpsz, strName);
-    strcpy(space, strDir);
+    CStringUtf8 ustrTarget(strTarget);
+
+    blob.in_size = ustrTarget.GetLength() + 1;
+    blob.in = ustrTarget.GetBuffer();
     blob.out_size = 0;
-    blob.in_size = 1 + strlen(space);
-    blob.in = space;
     blob.out = NULL;
-    code=pioctl(lpsz, VIOC_SYMLINK, &blob, 0);
-    delete lpsz;
+
+    code = pioctl_T(strName, VIOC_SYMLINK, &blob, 0);
+
+    ustrTarget.ReleaseBuffer();
+
     if (code != 0)
         return code;
-    return FALSE;
+    return 0;
 }
 
 void ListSymbolicLinkPath(const char *strName,char *strPath,UINT nlenPath)
@@ -2010,3 +2104,63 @@ void ListSymbolicLinkPath(const char *strName,char *strPath,UINT nlenPath)
     ASSERT(strlen(space)<MAX_PATH);
     strncpy(strPath,space,nlenPath);
 }       
+
+BOOL ListSymlink(CStringArray& files)
+{
+    LONG code;
+    struct ViceIoctl blob;
+    int error;
+    CStringArray symlinks;
+    
+    HOURGLASS hourglass;
+
+    error = 0;
+
+    for (int i = 0; i < files.GetSize(); i++) {
+
+        CString strParent = Parent(files[i]);
+        CStringUtf8 ustrLast(LastComponent(files[i]));
+
+        FixNetbiosPath(strParent);
+
+        blob.in_size = ustrLast.GetLength() + 1;
+        blob.in = ustrLast.GetBuffer();
+        blob.out_size = MAXSIZE;
+        blob.out = space;
+        memset(space, 0, MAXSIZE);
+
+        code = pioctl_T(strParent, VIOC_LISTSYMLINK, &blob, 1);
+
+        ustrLast.ReleaseBuffer();
+
+        if (code == 0) {
+            CString syml;
+            int len;
+
+            space[MAXSIZE - 1] = '\0';
+            syml = Utf8ToCString(space);
+            len = syml.GetLength();
+
+            if (len > 0) {
+                if (syml[len - 1] == _T('.'))
+                    syml.Truncate(len - 1);
+            }
+
+            symlinks.Add(ParseSymlink(StripPath(files[i]), syml));
+
+        } 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;
+}
+