windows-unicode-support-20080509
authorAsanka Herath <asanka@secure-endpoints.com>
Fri, 9 May 2008 15:49:36 +0000 (15:49 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Fri, 9 May 2008 15:49:36 +0000 (15:49 +0000)
LICENSE MIT

This delta provides a fairly complete implementation of Unicode character
set support for the Windows Cache Manager and supporting tools including
fs.exe, symlink.exe, the pioctl library, and the explorer shell extension.

New Build requirements:

In order to build the Microsoft IDN Mitigation APIs SDK 1.1 is now required.
This SDK provides the normalization.h header and the redistribution
install packages required to install normaliz.dll.   The AFSDEV_INCLUDE
path must be modified to point to the directory containing normalization.h.
There are no lib files for this package.

Cache Manager:

The CM SMB server has been modified to negotiate the use of UNICODE.
By default it is on.  The "fs smbunicode" command can be used to disable
UNICODE at runtime.

cm_utils now contains UNICODE normalization and conversion routines built
on top of the IDN Mitigation APIs.

All input strings are normalized with UNICODE Normalization Form C.

The pioctl interface now supports UTF8 strings in addition to ANSI.
UTF8 strings are prefixed with <ESC> % 8 as per the ISO 2022 extension.

Pioctl Library:

New apps should use the pioctl_utf8() function instead of pioctl().
pioctl() is for ANSI strings and provides backward compatibility
with third party apps.

fs.exe and symlink.exe:

Converted to Unicode applications.  All strings are now communicated
using UTF-8.

Explorer Shell Extension:

Converted to a Unicode DLL.  All strings are now communicated using
UTF-8.  Fonts on U.S. Windows distributions are not fully populated.
As a result not all of the characters can be displayed in all of the
dialog boxes.

Still to do:

1. Add Unicode normalization to AFS directory entries and mountpoint
   and symlink target strings.

2. Use the Unicode version of GetCurrentDirectory in fs_utils.c

3. Update the installers to install the IDN Mitigation APIs on XP
   and 2003.  Vista already has them and they are not supported on
   pre XP SP2 releases.

37 files changed:
README-NT
src/WINNT/afsd/NTMakefile
src/WINNT/afsd/afsd_init.c
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_ioctl.h
src/WINNT/afsd/cm_utils.c
src/WINNT/afsd/cm_utils.h
src/WINNT/afsd/fs.c
src/WINNT/afsd/fs_utils.c
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb.h
src/WINNT/afsd/smb3.c
src/WINNT/afsd/smb3.h
src/WINNT/afsd/smb_iocons.h
src/WINNT/afsd/smb_ioctl.c
src/WINNT/afsd/symlink.c
src/WINNT/client_exp/afs_shl_ext.cpp
src/WINNT/client_exp/copy_acl_dlg.cpp
src/WINNT/client_exp/gui2fs.cpp
src/WINNT/client_exp/gui2fs.h
src/WINNT/client_exp/help.cpp
src/WINNT/client_exp/help.h
src/WINNT/client_exp/hourglass.h
src/WINNT/client_exp/klog_dlg.cpp
src/WINNT/client_exp/msgs.cpp
src/WINNT/client_exp/partition_info_dlg.cpp
src/WINNT/client_exp/set_afs_acl.cpp
src/WINNT/client_exp/shell_ext.cpp
src/WINNT/client_exp/shell_ext.h
src/WINNT/client_exp/submounts_dlg.cpp
src/WINNT/client_exp/unlog_dlg.cpp
src/WINNT/client_exp/volumeinfo.cpp
src/config/NTMakefile.i386_w2k
src/libafsauthent/afsauthent.def
src/ntbuild.bat
src/sys/pioctl_nt.c
src/sys/pioctl_nt.h

index 5a4158a..15e8216 100644 (file)
--- a/README-NT
+++ b/README-NT
@@ -58,10 +58,12 @@ versions are supported:
     Microsoft Visual Studio .NET 2003
       available via a MSDN subscription
 
-    Microsoft Visual Studio .NET 2005 (required for AMD64 builds)
+    Microsoft Visual Studio .NET 2005
       available via a MSDN subscription
       (recommended - required for 64-bit builds)
 
+    Microsoft Visual Studio 2008 is not supported
+
 The following Microsoft SDK is required:
 
     Microsoft Platform SDK for Windows XP SP2 or Server 2003 SP1 or Vista
@@ -78,6 +80,10 @@ The Microsoft HTML Help Workshop is required:
 
     http://www.microsoft.com/downloads/details.aspx?familyid=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en
 
+The Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1 is required:
+
+    http://www.microsoft.com/downloads/details.aspx?FamilyId=AD6158D7-DDBA-416A-9109-07607425A815&displaylang=en
+
 The NSIS installer requires about 14 MB of storage. The following 
 version is supported:
 
@@ -174,6 +180,7 @@ The header files that are required from a Microsoft SDK/DDK are:
    npapi.h    (Windows 2000,XP,2003 builds)
    netcfgx.h  (NSIS Loopback Adapter installer - Windows 2000,XP,2003 builds)
    netcfgn.h  (NSIS Loopback Adapter installer - Windows 2000,XP,2003 builds)
+   normalization.h (AFS Cache Manager)
 
 These files come from the following Microsoft DDKs/SDKs:
 
@@ -184,6 +191,9 @@ These files come from the following Microsoft DDKs/SDKs:
         Windows XP/2003 DDK - inc/wxp/
 
 
+   normalization.h:
+        Microsoft IDN Mitigation APIs 1.1 - include/
+
 STEP D. Configure NTBUILD.BAT.
 
 The NTBUILD.BAT file copied to the OpenAFS base directory must be 
index 9beb79e..4dadd5e 100644 (file)
@@ -5,7 +5,7 @@
 # License.  For details, see the LICENSE file in the top-level source
 # directory or online at http://www.openafs.org/dl/license10.html
 
-AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL"  -I..\kfw\inc\loadfuncs -I..\kfw\inc\krb5 -I..\kfw\inc\leash
+AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL" /DSMB_UNICODE -I..\kfw\inc\loadfuncs -I..\kfw\inc\krb5 -I..\kfw\inc\leash
 AFSDEV_NETGUI = 1
 RELDIR=WINNT\afsd
 !INCLUDE ..\..\config\NTMakefile.$(SYS_NAME)
index 14a3fff..a9e3954 100644 (file)
@@ -995,6 +995,15 @@ int afsd_InitCM(char **reasonP)
     }
 #endif /* AFS_FREELANCE_CLIENT */
 
+    dummyLen = sizeof(smb_UseUnicode);
+    code = RegQueryValueEx(parmKey, "NegotiateUnicode", NULL, NULL,
+                           (BYTE *) &smb_UseUnicode, &dummyLen);
+    if (code != ERROR_SUCCESS) {
+        smb_UseUnicode = 1; /* default on */
+    }
+    afsi_log("SMB Server Unicode Support is %s",
+              smb_UseUnicode ? "enabled" : "disabled");
+
     dummyLen = sizeof(smb_hideDotFiles);
     code = RegQueryValueEx(parmKey, "HideDotFiles", NULL, NULL,
                            (BYTE *) &smb_hideDotFiles, &dummyLen);
@@ -1243,6 +1252,8 @@ int afsd_InitCM(char **reasonP)
         
     cm_InitCallback();
 
+    cm_InitNormalization();
+
     code = cm_InitMappedMemory(virtualCache, cm_CachePath, stats, volumes, cells, cm_chunkSize, cacheBlocks, blockSize);
     afsi_log("cm_InitMappedMemory code %x", code);
     if (code != 0) {
@@ -1776,7 +1787,9 @@ LONG __stdcall afsd_ExceptionFilter(EXCEPTION_POINTERS *ep)
   
 void afsd_SetUnhandledExceptionFilter()
 {
+#ifndef NOTRACE
     SetUnhandledExceptionFilter(afsd_ExceptionFilter);
+#endif
 }
   
 #ifdef _DEBUG
index 91b3dbf..2c8e9c0 100644 (file)
@@ -45,6 +45,9 @@
 #define PIOCTL_LOGON   0x1
 #define MAX_PATH 260
 
+static const char utf8_prefix[] = UTF8_PREFIX;
+static const int  utf8_prefix_size = sizeof(utf8_prefix) -  sizeof(char);
+
 osi_mutex_t cm_Afsdsbmt_Lock;
 
 extern afs_int32 cryptall;
@@ -199,6 +202,7 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
     char * relativePath;
     char * lastComponent = NULL;
     afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
+    int free_path = FALSE;
 
     relativePath = ioctlp->inDatap;
     /* setup the next data value for the caller to use */
@@ -219,11 +223,47 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
         * file system API.  Therefore, they are not OEM characters but 
         * whatever the display character set is.
         */
+
     // TranslateExtendedChars(relativePath);
 
     /* This is usually nothing, but for StatMountPoint it is the file name. */
     // TranslateExtendedChars(ioctlp->inDatap);
 
+    /* If the string starts with our UTF-8 prefix (which is the
+       sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
+       strings), we assume that the provided path is UTF-8.  Otherwise
+       we have to convert the string to UTF-8, since that is what we
+       want to use everywhere else.*/
+
+    if (memcmp(relativePath, utf8_prefix, utf8_prefix_size) == 0) {
+        int len, normalized_len;
+        char * normalized_path;
+
+        /* String is UTF-8 */
+        relativePath += utf8_prefix_size;
+        ioctlp->flags |= SMB_IOCTLFLAG_USEUTF8;
+
+        len = (ioctlp->inDatap - relativePath);
+
+        normalized_len = cm_NormalizeUtf8String(relativePath, len, NULL, 0);
+
+        if (normalized_len > len) {
+            normalized_path = malloc(normalized_len);
+            free_path = TRUE;
+        } else {
+            normalized_path = relativePath;
+        }
+
+        cm_NormalizeUtf8String(relativePath, len, normalized_path, normalized_len);
+
+        if (normalized_path != relativePath)
+            relativePath = normalized_path;
+    } else {
+        /* Not a UTF-8 string */
+        /* TODO: If this is an OEM string, we should convert it to
+           UTF-8. */
+    }
+
     if (relativePath[0] == relativePath[1] &&
          relativePath[1] == '\\' && 
          !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) 
@@ -257,6 +297,8 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
             free(sharePath);
             if (code) {
                osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
                 return code;
            }
 
@@ -279,6 +321,8 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
            cm_ReleaseSCache(substRootp);
             if (code) {
                osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
                 return code;
            }
         } else {
@@ -304,6 +348,8 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
                              userp, shareName, reqp, &substRootp);
             if (code) {
                osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
+                if (free_path)
+                    free(relativePath);
                 return code;
            }
 
@@ -327,6 +373,8 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
            if (code) {
                cm_ReleaseSCache(substRootp);
                osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
+                if (free_path)
+                    free(relativePath);
                 return code;
            }
         }
@@ -336,6 +384,8 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
                          userp, ioctlp->tidPathp, reqp, &substRootp);
         if (code) {
            osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
+            if (free_path)
+                free(relativePath);
             return code;
        }
         
@@ -358,6 +408,8 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
         if (code) {
            cm_ReleaseSCache(substRootp);
            osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
+            if (free_path)
+                free(relativePath);
             return code;
        }
     }
@@ -367,6 +419,9 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
 
     /* and return success */
     osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
+
+    if (free_path)
+        free(relativePath);
     return 0;
 }
 
@@ -458,8 +513,47 @@ long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
     char tbuffer[1024];
     char *tp, *jp;
     cm_scache_t *substRootp = NULL;
+    char *inpathp;
+    int free_path = FALSE;
+
+    inpathp = ioctlp->inDatap;
+
+    /* If the string starts with our UTF-8 prefix (which is the
+       sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
+       strings), we assume that the provided path is UTF-8.  Otherwise
+       we have to convert the string to UTF-8, since that is what we
+       want to use everywhere else.*/
 
-    StringCbCopyA(tbuffer, sizeof(tbuffer), ioctlp->inDatap);
+    if (memcmp(inpathp, utf8_prefix, utf8_prefix_size) == 0) {
+        int len, normalized_len;
+        char * normalized_path;
+
+        /* String is UTF-8 */
+        inpathp += utf8_prefix_size;
+        ioctlp->flags |= SMB_IOCTLFLAG_USEUTF8;
+
+        len = strlen(inpathp) + 1;
+
+        normalized_len = cm_NormalizeUtf8String(inpathp, len, NULL, 0);
+
+        if (normalized_len > len) {
+            normalized_path = malloc(normalized_len);
+            free_path = TRUE;
+        } else {
+            normalized_path = inpathp;
+        }
+
+        cm_NormalizeUtf8String(inpathp, len, normalized_path, normalized_len);
+
+        if (normalized_path != inpathp)
+            inpathp = normalized_path;
+    } else {
+        /* Not a UTF-8 string */
+        /* TODO: If this is an OEM string, we should convert it to
+           UTF-8. */
+    }
+
+    StringCbCopyA(tbuffer, sizeof(tbuffer), inpathp);
     tp = strrchr(tbuffer, '\\');
     jp = strrchr(tbuffer, '/');
     if (!tp)
@@ -469,7 +563,7 @@ long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
     if (!tp) {
         StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
         if (leafp) 
-            StringCbCopyA(leafp, LEAF_SIZE, ioctlp->inDatap);
+            StringCbCopyA(leafp, LEAF_SIZE, inpathp);
     }
     else {
         *tp = 0;
@@ -477,6 +571,10 @@ long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
             StringCbCopyA(leafp, LEAF_SIZE, tp+1);
     }   
 
+    if (free_path)
+        free(inpathp);
+    inpathp = NULL;             /* We don't need this from this point on */
+
     if (tbuffer[0] == tbuffer[1] &&
         tbuffer[1] == '\\' && 
         !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
@@ -858,6 +956,7 @@ long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_cell_t *cellp;
     cm_req_t req;
     struct rx_connection * callp;
+    int len;
 
     cm_InitReq(&req);
 
@@ -890,11 +989,17 @@ long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
         cp = ioctlp->inDatap;
         memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
         cp += sizeof(AFSFetchVolumeStatus);
-        StringCbCopyA(volName, sizeof(volName), cp);
-        cp += strlen(volName)+1;
-        StringCbCopyA(offLineMsg, sizeof(offLineMsg), cp);
-        cp +=  strlen(offLineMsg)+1;
-        StringCbCopyA(motd, sizeof(motd), cp);
+
+        len = strlen(cp) + 1;
+        cm_NormalizeUtf8String(cp, len, volName, sizeof(volName));
+        cp += len;
+
+        len = strlen(cp) + 1;
+        cm_NormalizeUtf8String(cp, len, offLineMsg, sizeof(offLineMsg));
+        cp +=  len;
+
+        len = strlen(cp) + 1;
+        cm_NormalizeUtf8String(cp, len, motd, sizeof(motd));
         storeStat.Mask = 0;
         if (volStat.MinQuota != -1) {
             storeStat.MinQuota = volStat.MinQuota;
@@ -1936,7 +2041,9 @@ long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
         return code;
 
     /* Translate chars for the mount point name */
+    if (!(ioctlp->flags & SMB_IOCTLFLAG_USEUTF8)) {
     TranslateExtendedChars(leaf);
+    }
 
     /* 
      * The fs command allows the user to specify partial cell names on NT.  These must
@@ -2006,19 +2113,45 @@ long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_attr_t tattr;
     char *cp;
     cm_req_t req;
+    char *symlp;
+    int free_syml = FALSE;
 
     cm_InitReq(&req);
 
     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
     if (code) return code;
 
+    if (!(ioctlp->flags & SMB_IOCTLFLAG_USEUTF8)) {
     /* Translate chars for the link name */
     TranslateExtendedChars(leaf);
 
     /* Translate chars for the linked to name */
     TranslateExtendedChars(ioctlp->inDatap);
+    }
+
+    symlp = ioctlp->inDatap;           /* contents of link */
 
-    cp = ioctlp->inDatap;              /* contents of link */
+    {
+        char * normalized;
+        int normalized_len;
+
+        int len = strlen(symlp) + 1;
+
+        normalized_len = cm_NormalizeUtf8String(symlp, len, NULL, 0);
+        if (normalized_len > len) {
+            normalized = malloc(normalized_len);
+            free_syml = TRUE;
+        } else {
+            normalized = symlp;
+        }
+
+        cm_NormalizeUtf8String(symlp, len, normalized, normalized_len);
+
+        if (symlp != normalized)
+            symlp = normalized;
+    }
+
+    cp = symlp;
 
 #ifdef AFS_FREELANCE_CLIENT
     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
@@ -2054,6 +2187,9 @@ long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     cm_ReleaseSCache(dscp);
 
+    if (free_syml)
+        free(symlp);
+
     return code;
 }
 
@@ -2922,11 +3058,43 @@ long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
   return 0;
 }
 
+long cm_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user * userp)
+{
+    long result = 0;
+#ifdef SMB_UNICODE
+    long cmd;
+
+    cm_SkipIoctlPath(ioctlp);
+
+    memcpy(&cmd, ioctlp->inDatap, sizeof(long));
+
+    if (cmd & 2) {
+        /* Setting the Unicode flag */
+        LONG newflag;
+
+        newflag = ((cmd & 1) == 1);
+
+        InterlockedExchange(&smb_UseUnicode, newflag);
+    }
+
+    result = smb_UseUnicode;
+#else
+    result = 2;
+#endif
+
+    memcpy(ioctlp->outDatap, &result, sizeof(result));
+    ioctlp->outDatap += sizeof(result);
+
+    return 0;
+}
+
 long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp)
 {
     long cmd;
     afsUUID uuid;
 
+    cm_SkipIoctlPath(ioctlp);
+
     memcpy(&cmd, ioctlp->inDatap, sizeof(long));
 
     if (cmd) {             /* generate a new UUID */
@@ -2941,6 +3109,8 @@ long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp)
     return 0;
 }
 
+
+
 /* 
  * functions to dump contents of various structures. 
  * In debug build (linked with crt debug library) will dump allocated but not freed memory
@@ -3153,7 +3323,6 @@ long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
     struct VolStatTest * testp;
     cm_req_t req;
     afs_uint32 n;
-    size_t len;
 
     cm_InitReq(&req);
 
index be3715f..934959a 100644 (file)
@@ -100,6 +100,12 @@ extern char *         cm_sysName;
 extern unsigned int   cm_sysNameCount;
 extern char *         cm_sysNameList[MAXNUMSYSNAMES];
 
+/* Paths that are passed into pioctl calls can be specified using
+   UTF-8.  These strings are prefixed with UTF8_PREFIX defined below.
+   The sequence ESC '%' 'G' is used by ISO-2022 to designate UTF-8
+   strings. */
+#define UTF8_PREFIX "\33%G"
+
 /* flags for rxstats pioctl */
 
 #define AFSCALL_RXSTATS_MASK    0x7     /* Valid flag bits */
@@ -223,6 +229,8 @@ extern long cm_IoctlGetFileType(smb_ioctl_t *ioctlp, cm_user_t *userp);
 
 extern long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp);
 
+extern long cm_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user * userp);
+
 #endif /* __CM_IOCTL_INTERFACES_ONLY__ */
 
 #endif /*  __CM_IOCTL_H_ENV__ */
index 8b26f50..fc1d8fb 100644 (file)
@@ -69,6 +69,9 @@
 #include <osi.h>
 #include <rx/rx.h>
 
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+
 
 static osi_once_t cm_utilsOnce;
 
@@ -359,3 +362,276 @@ void cm_FreeSpace(cm_space_t *tsp)
        cm_spaceListp = tsp;
         lock_ReleaseWrite(&cm_utilsLock);
 }
+
+/* This is part of the Microsoft Internationalized Domain Name
+   Mitigation APIs. */
+#include <normalization.h>
+
+int
+(WINAPI *pNormalizeString)( __in NORM_FORM NormForm,
+                            __in_ecount(cwSrcLength) LPCWSTR lpSrcString,
+                            __in int cwSrcLength,
+                            __out_ecount(cwDstLength) LPWSTR lpDstString,
+                            __in int cwDstLength ) = NULL;
+
+BOOL
+(WINAPI *pIsNormalizedString)( __in NORM_FORM NormForm,
+                               __in_ecount(cwLength) LPCWSTR lpString,
+                               __in int cwLength ) = NULL;
+
+
+#define NLSDLLNAME "Normaliz.dll"
+#define NLSMAXCCH  1024
+#define NLSERRCCH  8
+
+#define AFS_NORM_FORM NormalizationC
+
+long cm_InitNormalization(void)
+{
+    HMODULE h_Nls;
+
+    if (pNormalizeString != NULL)
+        return 0;
+
+    h_Nls = LoadLibrary(NLSDLLNAME);
+    if (h_Nls == INVALID_HANDLE_VALUE) {
+        afsi_log("Can't load " NLSDLLNAME ": LastError=%d", GetLastError());
+        return 1;
+    }
+
+    pNormalizeString = GetProcAddress(h_Nls, "NormalizeString");
+    pIsNormalizedString = GetProcAddress(h_Nls, "IsNormalizedString");
+
+    return (pNormalizeString && pIsNormalizedString);
+}
+
+/* \brief Normalize a UTF-16 string.
+
+   If the supplied destination buffer is
+   insufficient or NULL, then a new buffer will be allocated to hold
+   the normalized string.
+
+   \param[in] src : Source UTF-16 string.  Length is specified in
+       cch_src.
+
+   \param[in] cch_src : The character count in cch_src is assumed to
+       be tight and include the terminating NULL character if there is
+       one.  If the NULL is absent, the resulting string will not be
+       NULL terminated.
+
+   \param[out] ext_dest : The destination buffer.  Can be NULL, in
+       which case *pcch_dest MUST be NULL.
+
+   \param[in,out] pcch_dest : On entry *pcch_dest contains a count of
+       characters in the destination buffer.  On exit, it will contain
+       a count of characters that were copied to the destination
+       buffer.
+
+   Returns a pointer to the buffer containing the normalized string or
+   NULL if the call was unsuccessful.  If the returned destination
+   buffer is different fron the supplied buffer and non-NULL, it
+   should be freed using free().
+*/
+static wchar_t * 
+NormalizeUtf16String(const wchar_t * src, int cch_src, wchar_t * ext_dest, int *pcch_dest)
+{
+    if ((pIsNormalizedString && (*pIsNormalizedString)(AFS_NORM_FORM, src, cch_src)) ||
+        (!pNormalizeString)) {
+
+        int rv;
+        DWORD gle;
+        int tries = 10;
+        wchar_t * dest;
+        int cch_dest = *pcch_dest;
+
+        dest = ext_dest;
+
+        while (tries-- > 0) {
+
+            rv = (*pNormalizeString)(AFS_NORM_FORM, src, cch_src, dest, cch_dest);
+
+            if (rv <= 0 && (gle = GetLastError()) != ERROR_SUCCESS) {
+#ifdef DEBUG
+                osi_Log1(afsd_logp, "NormalizeUtf16String error = %d", gle);
+#endif
+                if (gle == ERROR_INSUFFICIENT_BUFFER) {
+
+                    /* The buffer wasn't big enough.  We are going to
+                       try allocating one. */
+
+                    cch_dest = (-rv) + NLSERRCCH;
+                    goto cont;
+
+                } else {
+                    /* Something else is wrong */
+                    break;
+                }
+
+            } else if (rv < 0) { /* rv < 0 && gle == ERROR_SUCCESS */
+
+                /* Technically not one of the expected outcomes */
+                break;
+
+            } else {            /* rv > 0 || (rv == 0 && gle == ERROR_SUCCESS) */
+
+                /* Possibly succeeded */
+
+                if (rv == 0) { /* Succeeded and the return string is empty */
+                    *pcch_dest = 0;
+                    return dest;
+                }
+
+                if (cch_dest == 0) {
+                    /* Nope.  We only calculated the required size of the buffer */
+
+                    cch_dest = rv + NLSERRCCH;
+                    goto cont;
+                }
+
+                *pcch_dest = rv;
+
+                /* Success! */
+                return dest;
+            }
+
+        cont:
+            if (dest != ext_dest && dest)
+                free(dest);
+            dest = malloc(cch_dest * sizeof(wchar_t));
+        }
+
+        /* Failed */
+
+        if (dest != ext_dest && dest)
+            free(dest);
+
+        *pcch_dest = 0;
+        return NULL;
+    } else {
+
+        /* No need to or unable to normalize.  Just copy the string */
+        if (SUCCEEDED(StringCchCopyNW(ext_dest, *pcch_dest, src, cch_src))) {
+            *pcch_dest = cch_src;
+            return ext_dest;
+        } else {
+            *pcch_dest = 0;
+            return NULL;
+        }
+    }
+}
+
+/* \brief Normalize a UTF-16 string into a UTF-8 string.
+
+   \param[in] src : Source string.
+
+   \param[in] cch_src : Count of characters in src. If the count includes the
+       NULL terminator, then the resulting string will be NULL
+       terminated.  If it is -1, then src is assumed to be NULL
+       terminated.
+
+   \param[out] adest : Destination buffer.
+
+   \param[in] cch_adest : Number of characters in the destination buffer.
+
+   Returns the number of characters stored into cch_adest. This will
+   include the terminating NULL if cch_src included the terminating
+   NULL or was -1.  If this is 0, then the operation was unsuccessful.
+ */
+long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
+                                   char * adest, int cch_adest)
+{
+    if (cch_src < 0) {
+        size_t cch;
+
+        if (FAILED(StringCchLengthW(src, NLSMAXCCH, &cch)))
+            return CM_ERROR_TOOBIG;
+
+        cch_src = cch+1;
+    }
+
+    {
+        wchar_t nbuf[NLSMAXCCH];
+        wchar_t * normalized;
+        int cch_norm = NLSMAXCCH;
+
+        normalized = NormalizeUtf16String(src, cch_src, nbuf, &cch_norm);
+        if (normalized) {
+            cch_adest = WideCharToMultiByte(CP_UTF8, 0, normalized, cch_norm,
+                                            adest, cch_adest, NULL, 0);
+
+            if (normalized != nbuf && normalized)
+                free(normalized);
+
+            return cch_adest;
+
+        } else {
+
+            return 0;
+
+        }
+    }
+}
+
+
+/* \brief Normalize a UTF-8 string.
+
+   \param[in] src String to normalize.
+
+   \param[in] cch_src : Count of characters in src.  If this value is
+       -1, then src is assumed to be NULL terminated.  The translated
+       string will be NULL terminated only if this is -1 or the count
+       includes the terminating NULL.
+
+   \param[out] adest : Destination string.
+
+   \param[in] cch_adest : Number of characters in the destination
+       string.
+
+   Returns the number of characters stored into adest or 0 if the call
+   was unsuccessful.
+ */
+long cm_NormalizeUtf8String(const char * src, int cch_src,
+                            char * adest, int cch_adest)
+{
+    wchar_t wsrcbuf[NLSMAXCCH];
+    wchar_t *wnorm;
+    int cch;
+    int cch_norm;
+
+    /* Get some edge cases out first, so we don't have to worry about
+       cch_src being 0 etc. */
+    if (cch_src == 0) {
+        return 0;
+    } else if (*src == '\0') {
+        *adest = '\0';
+        return 1;
+    }
+
+    cch = MultiByteToWideChar(CP_UTF8, 0, src, cch_src * sizeof(char),
+                             wsrcbuf, NLSMAXCCH);
+
+    if (cch == 0) {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        return 0;
+    }
+
+    cch_norm = 0;
+    wnorm = NormalizeUtf16String(wsrcbuf, cch, NULL, &cch_norm);
+    if (wnorm == NULL) {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        return 0;
+    }
+
+    cch = WideCharToMultiByte(CP_UTF8, 0, wnorm, cch_norm,
+                              adest, cch_adest * sizeof(char),
+                              NULL, FALSE);
+
+    if (wnorm)
+        free(wnorm);
+
+    return cch;
+}
index 2f51478..06523bf 100644 (file)
@@ -28,4 +28,9 @@ extern long cm_MapRPCError(long error, cm_req_t *reqp);
 extern long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp);
 extern long cm_MapVLRPCError(long error, cm_req_t *reqp);
 
+extern long cm_InitNormalization(void);
+extern long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
+                                          char * adest, int cch_adest);
+extern long cm_NormalizeUtf8String(const char * src, int cch_src,
+                                   char * adest, int cch_adest);
 #endif /*  __CM_UTILS_H_ENV__ */
index 076cc32..aa38069 100644 (file)
@@ -251,7 +251,7 @@ InAFS(char *apath)
     blob.out_size = MAXSIZE;
     blob.out = space;
 
-    code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
+    code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
     if (code) {
        if ((errno == EINVAL) || (errno == ENOENT)) 
             return 0;
@@ -269,7 +269,7 @@ IsFreelanceRoot(char *apath)
     blob.out_size = MAXSIZE;
     blob.out = space;
 
-    code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
+    code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
     if (code == 0)
         return !stricmp("Freelance.Local.Root",space);
     return 1;   /* assume it is because it is more restrictive that way */
@@ -612,7 +612,6 @@ ParseAcl (char *astr)
     }
     ta->minuslist = first;
 
-  exit:
     return ta;
 
   nminus_err:
@@ -929,7 +928,7 @@ SetACLCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = MAXSIZE;
        blob.in_size = idf;
        blob.in = blob.out = space;
-       code = pioctl(ti->data, VIOCGETAL, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
        if (code) {
            Die(errno, ti->data);
            error = 1;
@@ -992,7 +991,7 @@ SetACLCmd(struct cmd_syndesc *as, void *arock)
        blob.in = AclToString(ta);
        blob.out_size=0;
        blob.in_size = 1+(long)strlen(blob.in);
-       code = pioctl(ti->data, VIOCSETAL, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
        if (code) {
            if (errno == EINVAL) {
                if (ta->dfs) {
@@ -1069,7 +1068,7 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
     blob.out_size = MAXSIZE;
     blob.in_size = idf;
     blob.in = blob.out = space;
-    code = pioctl(as->parms[0].items->data, VIOCGETAL, &blob, 1);
+    code = pioctl_utf8(as->parms[0].items->data, VIOCGETAL, &blob, 1);
     if (code) {
        Die(errno, as->parms[0].items->data);
        return 1;
@@ -1086,7 +1085,7 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = MAXSIZE;
        blob.in_size = idf;
        blob.in = blob.out = space;
-       code = pioctl(ti->data, VIOCGETAL, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
        if (code) {
            Die(errno, ti->data);
            error = 1;
@@ -1130,7 +1129,7 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
        blob.in = AclToString(ta);
        blob.out_size=0;
        blob.in_size = 1+(long)strlen(blob.in);
-       code = pioctl(ti->data, VIOCSETAL, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
        if (code) {
            if (errno == EINVAL) {
                fprintf(stderr,
@@ -1148,7 +1147,7 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
     return error;
 }
 
-/* pioctl() call to get the cellname of a pathname */
+/* pioctl_utf8() call to get the cellname of a pathname */
 static afs_int32
 GetCell(char *fname, char *cellname)
 {
@@ -1159,7 +1158,7 @@ GetCell(char *fname, char *cellname)
     blob.out_size = MAXCELLCHARS;
     blob.out = cellname;
 
-    code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1);
+    code = pioctl_utf8(fname, VIOC_FILE_CELL_NAME, &blob, 1);
     return code;
 }
 
@@ -1258,7 +1257,7 @@ CleanACLCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
-       code = pioctl(ti->data, VIOCGETAL, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
        if (code) {
            Die(errno, ti->data);
             error = 1;
@@ -1289,7 +1288,7 @@ CleanACLCmd(struct cmd_syndesc *as, void *arock)
            blob.in=AclToString(ta);
            blob.in_size = (long)strlen(blob.in)+1;
            blob.out_size = 0;
-           code = pioctl(ti->data, VIOCSETAL, &blob, 1);
+           code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
            if (code) {
                if (errno == EINVAL) {
                    fprintf(stderr,
@@ -1352,7 +1351,7 @@ ListACLCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = MAXSIZE;
        blob.in_size = idf;
        blob.in = blob.out = space;
-       code = pioctl(ti->data, VIOCGETAL, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
        if (code) {
            Die(errno, ti->data);
             error = 1;
@@ -1415,7 +1414,7 @@ FlushAllCmd(struct cmd_syndesc *as, void *arock)
     struct ViceIoctl blob;
 
     blob.in_size = blob.out_size = 0;
-    code = pioctl(NULL, VIOC_FLUSHALL, &blob, 0);
+    code = pioctl_utf8(NULL, VIOC_FLUSHALL, &blob, 0);
     if (code) {
        fprintf(stderr, "Error flushing all ");
        return 1;
@@ -1434,7 +1433,7 @@ FlushVolumeCmd(struct cmd_syndesc *as, void *arock)
     SetDotDefault(&as->parms[0].items);
     for(ti=as->parms[0].items; ti; ti=ti->next) {
        blob.in_size = blob.out_size = 0;
-       code = pioctl(ti->data, VIOC_FLUSHVOLUME, &blob, 0);
+       code = pioctl_utf8(ti->data, VIOC_FLUSHVOLUME, &blob, 0);
        if (code) {
            fprintf(stderr, "Error flushing volume ");
             perror(ti->data);
@@ -1468,7 +1467,7 @@ FlushCmd(struct cmd_syndesc *as, void *arock)
         blob.in = &options;
 
        blob.out_size = 0;
-       code = pioctl(ti->data, VIOCFLUSH, &blob, 0);
+       code = pioctl_utf8(ti->data, VIOCFLUSH, &blob, 0);
        if (code) {
            if (errno == EMFILE) {
                fprintf(stderr, "%s: Can't flush active file %s\n", pn, 
@@ -1550,7 +1549,7 @@ SetVolCmd(struct cmd_syndesc *as, void *arock) {
            input += strlen(motd) + 1;
        } else 
             *(input++) = '\0';
-       code = pioctl(ti->data,VIOCSETVOLSTAT, &blob, 1);
+       code = pioctl_utf8(ti->data,VIOCSETVOLSTAT, &blob, 1);
        if (code) {
            Die(errno, ti->data);
            error = 1;
@@ -1619,7 +1618,7 @@ ExamineCmd(struct cmd_syndesc *as, void *arock)
 
         blob.out_size = sizeof(cm_fid_t);
         blob.out = (char *) &fid;
-        if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
+        if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1)) {
             options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
             options.fid = fid;
         } else {
@@ -1631,12 +1630,12 @@ ExamineCmd(struct cmd_syndesc *as, void *arock)
         blob.out_size = sizeof(filetype);
         blob.out = &filetype;
 
-        code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
+        code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
 
         blob.out_size = MAXCELLCHARS;
         blob.out = cell;
 
-        code = pioctl(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
+        code = pioctl_utf8(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
         printf("%s %s (%u.%u.%u) contained in cell %s\n",
                 filetypestr(filetype),
                 ti->data, fid.volume, fid.vnode, fid.unique,
@@ -1644,7 +1643,7 @@ ExamineCmd(struct cmd_syndesc *as, void *arock)
 
        blob.out_size = 2 * sizeof(afs_uint32);
         blob.out = (char *) &owner;
-       if (0 == pioctl(ti->data, VIOCGETOWNER, &blob, 1)) {
+       if (0 == pioctl_utf8(ti->data, VIOCGETOWNER, &blob, 1)) {
            char oname[PR_MAXNAMELEN] = "(unknown)";
             char confDir[257];
 
@@ -1658,7 +1657,7 @@ ExamineCmd(struct cmd_syndesc *as, void *arock)
 
        blob.out = space;
        blob.out_size = MAXSIZE;
-       code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
        if (code == 0) {
             status = (VolumeStatus *)space;
             name = (char *)status + sizeof(*status);
@@ -1671,7 +1670,7 @@ ExamineCmd(struct cmd_syndesc *as, void *arock)
         }
 
         errno = 0;
-        code = pioctl(ti->data, VIOC_PATH_AVAILABILITY, &blob, 1);
+        code = pioctl_utf8(ti->data, VIOC_PATH_AVAILABILITY, &blob, 1);
         switch (errno) {
         case 0:
             printf("Volume is online\n");
@@ -1713,7 +1712,7 @@ ListQuotaCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
-       code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
        if (code) {
            Die(errno, ti->data);
             error = 1;
@@ -1759,7 +1758,7 @@ WhereIsCmd(struct cmd_syndesc *as, void *arock)
         
         blob.out_size = sizeof(cm_fid_t);
         blob.out = (char *) &fid;
-        if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
+        if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1)) {
             options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
             options.fid = fid;
         } else {
@@ -1771,12 +1770,12 @@ WhereIsCmd(struct cmd_syndesc *as, void *arock)
         blob.out_size = sizeof(filetype);
         blob.out = &filetype;
 
-        code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
+        code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
 
         blob.out_size = MAXSIZE;
        blob.out = space;
        memset(space, 0, sizeof(space));
-       code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCWHEREIS, &blob, 1);
        if (code) {
            Die(errno, ti->data);
             error = 1;
@@ -1817,7 +1816,7 @@ DiskFreeCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
-       code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
        if (code) {
            Die(errno, ti->data);
             error = 1;
@@ -1846,7 +1845,7 @@ QuotaCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = MAXSIZE;
        blob.in_size = 0;
        blob.out = space;
-       code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
        if (code) {
            Die(errno, ti->data);
             error = 1;
@@ -1994,7 +1993,7 @@ ListMountCmd(struct cmd_syndesc *as, void *arock)
        blob.out = space;
        memset(space, 0, MAXSIZE);
 
-       code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
+       code = pioctl_utf8(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
 
        if (code == 0) {
            printf("'%s' is a %smount point for volume '%s'\n",
@@ -2091,7 +2090,7 @@ MakeMountCmd(struct cmd_syndesc *as, void *arock)
            blob.in_size = 0;
            blob.out_size = sizeof(localCellName);
            blob.out = localCellName;
-           code = pioctl(parent, VIOC_GET_WS_CELL, &blob, 1);
+           code = pioctl_utf8(parent, VIOC_GET_WS_CELL, &blob, 1);
            if (!code)
                cellName = localCellName;
        }
@@ -2142,7 +2141,7 @@ MakeMountCmd(struct cmd_syndesc *as, void *arock)
     blob.in_size = 1 + (long)strlen(space);
     blob.in = space;
     blob.out = NULL;
-    code = pioctl(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
+    code = pioctl_utf8(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
 #else /* not WIN32 */
     code = symlink(space, path);
 #endif /* not WIN32 */
@@ -2203,7 +2202,7 @@ RemoveMountCmd(struct cmd_syndesc *as, void *arock) {
        blob.in_size = (long)strlen(tp)+1;
        blob.out = lsbuffer;
        blob.out_size = sizeof(lsbuffer);
-       code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
+       code = pioctl_utf8(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
        if (code) {
            if (errno == EINVAL) {
                fprintf(stderr,"%s: '%s' is not a mount point.\n", pn, ti->data);
@@ -2223,7 +2222,7 @@ RemoveMountCmd(struct cmd_syndesc *as, void *arock) {
         blob.out_size = 0;
        blob.in = tp;
        blob.in_size = (long)strlen(tp)+1;
-       code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
+       code = pioctl_utf8(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
        if (code) {
            Die(errno, ti->data);
             error = 1;
@@ -2306,7 +2305,7 @@ CheckServersCmd(struct cmd_syndesc *as, void *arock)
 #endif /* WIN32 */
     }
 
-    code = pioctl(0, VIOCCKSERV, &blob, 1);
+    code = pioctl_utf8(0, VIOCCKSERV, &blob, 1);
     if (code) {
        if ((errno == EACCES) && (checkserv.tinterval > 0)) {
            printf("Must be root to change -interval\n");
@@ -2376,7 +2375,7 @@ MessagesCmd(struct cmd_syndesc *as, void *arock)
     if (code)
         return 1;
 
-    code = pioctl(0, VIOC_GAG, &blob, 1);
+    code = pioctl_utf8(0, VIOC_GAG, &blob, 1);
     if (code) {
        Die(errno, 0);
         return 1;
@@ -2392,7 +2391,7 @@ CheckVolumesCmd(struct cmd_syndesc *as, void *arock)
     
     blob.in_size = 0;
     blob.out_size = 0;
-    code = pioctl(0, VIOCCKBACK, &blob, 1);
+    code = pioctl_utf8(0, VIOCCKBACK, &blob, 1);
     if (code) {
        Die(errno, 0);
        return 1;
@@ -2436,7 +2435,7 @@ SetCacheSizeCmd(struct cmd_syndesc *as, void *arock)
     blob.in = (char *) &temp;
     blob.in_size = sizeof(afs_int32);
     blob.out_size = 0;
-    code = pioctl(0, VIOCSETCACHESIZE, &blob, 1);
+    code = pioctl_utf8(0, VIOCSETCACHESIZE, &blob, 1);
     if (code) {
        Die(errno, (char *) 0);
         return 1;
@@ -2458,7 +2457,7 @@ GetCacheParmsCmd(struct cmd_syndesc *as, void *arock)
     blob.in_size = 0;
     blob.out_size = sizeof(parms);
     blob.out = (char *) &parms;
-    code = pioctl(0, VIOCGETCACHEPARMS, &blob, 1);
+    code = pioctl_utf8(0, VIOCGETCACHEPARMS, &blob, 1);
     if (code) {
        Die(errno, NULL);
         return 1;
@@ -2494,7 +2493,7 @@ ListCellsCmd(struct cmd_syndesc *as, void *arock)
        blob.in_size = sizeof(afs_int32);
        blob.in = space;
        blob.out = space;
-       code = pioctl(0, VIOCGETCELL, &blob, 1);
+       code = pioctl_utf8(0, VIOCGETCELL, &blob, 1);
        if (code < 0) {
            if (errno == EDOM) 
                 break; /* done with the list */
@@ -2545,7 +2544,7 @@ ListAliasesCmd(struct cmd_syndesc *as, void *arock)
        blob.in_size = sizeof(afs_int32);
        blob.in = space;
        blob.out = space;
-       code = pioctl(0, VIOC_GETALIAS, &blob, 1);
+       code = pioctl_utf8(0, VIOC_GETALIAS, &blob, 1);
        if (code < 0) {
            if (errno == EDOM)
                break;          /* done with the list */
@@ -2592,7 +2591,7 @@ CallBackRxConnCmd(struct cmd_syndesc *as, void *arock)
     blob.in = (char *) &hostAddr;
     blob.out = (char *) &hostAddr;
     
-    code = pioctl(0, VIOC_CBADDR, &blob, 1);
+    code = pioctl_utf8(0, VIOC_CBADDR, &blob, 1);
     if (code < 0) {
        Die(errno, 0);
        return 1;
@@ -2667,7 +2666,7 @@ NewCellCmd(struct cmd_syndesc *as, void *arock)
     blob.in_size = size;
     blob.in = space;
     blob.out_size = 0;
-    code = pioctl(0, VIOCNEWCELL, &blob, 1);
+    code = pioctl_utf8(0, VIOCNEWCELL, &blob, 1);
     if (code < 0)
        Die(errno, 0);
     return 0;
@@ -2685,7 +2684,7 @@ NewCellCmd(struct cmd_syndesc *as, void *arock)
     blob.out_size = MAXSIZE;
     blob.out = space;
 
-    code = pioctl((char *) 0, VIOCNEWCELL, &blob, 1);
+    code = pioctl_utf8((char *) 0, VIOCNEWCELL, &blob, 1);
 
     if (code) {
         Die(errno, (char *) 0);
@@ -2719,7 +2718,7 @@ NewAliasCmd(struct cmd_syndesc *as, void *arock)
     blob.in = space;
     blob.out_size = 0;
     blob.out = space;
-    code = pioctl(0, VIOC_NEWALIAS, &blob, 1);
+    code = pioctl_utf8(0, VIOC_NEWALIAS, &blob, 1);
     if (code < 0) {
        if (errno == EEXIST) {
            fprintf(stderr,
@@ -2765,7 +2764,7 @@ WhichCellCmd(struct cmd_syndesc *as, void *arock)
 
         blob.out_size = sizeof(cm_fid_t);
         blob.out = (char *) &fid;
-        if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
+        if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1)) {
             options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
             options.fid = fid;
         } else {
@@ -2777,12 +2776,12 @@ WhichCellCmd(struct cmd_syndesc *as, void *arock)
         blob.out_size = sizeof(filetype);
         blob.out = &filetype;
 
-        code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
+        code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
 
         blob.out_size = MAXCELLCHARS;
         blob.out = cell;
 
-        code = pioctl(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
+        code = pioctl_utf8(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
        if (code) {
            if (errno == ENOENT)
                fprintf(stderr,"%s: no such cell as '%s'\n", pn, ti->data);
@@ -2809,7 +2808,7 @@ WSCellCmd(struct cmd_syndesc *as, void *arock)
     blob.out_size = MAXSIZE;
     blob.out = space;
 
-    code = pioctl(NULL, VIOC_GET_WS_CELL, &blob, 1);
+    code = pioctl_utf8(NULL, VIOC_GET_WS_CELL, &blob, 1);
 
     if (code) {
        Die(errno, NULL);
@@ -2871,7 +2870,7 @@ MonitorCmd(struct cmd_syndesc *as, void *arock)
     blob.out_size = sizeof(afs_int32);
     blob.in = (char *) &hostAddr;
     blob.out = (char *) &hostAddr;
-    code = pioctl(0, VIOC_AFS_MARINER_HOST, &blob, 1);
+    code = pioctl_utf8(0, VIOC_AFS_MARINER_HOST, &blob, 1);
     if (code) {
        Die(errno, 0);
        return 1;
@@ -2934,7 +2933,7 @@ SysNameCmd(struct cmd_syndesc *as, void *arock)
         *(input++) = '\0';
     }
     memcpy(space, &setp, sizeof(afs_int32));
-    code = pioctl(0, VIOC_AFS_SYSNAME, &blob, 1);
+    code = pioctl_utf8(0, VIOC_AFS_SYSNAME, &blob, 1);
     if (code) {
         Die(errno, 0);
         return 1;
@@ -3040,7 +3039,7 @@ static int ExportAfsCmd(struct cmd_syndesc *as, void *arock)
     blob.in_size = sizeof(afs_int32);
     blob.out = (char *) &exportcall;
     blob.out_size = sizeof(afs_int32);
-    code = pioctl(0, VIOC_EXPORTAFS, &blob, 1);
+    code = pioctl_utf8(0, VIOC_EXPORTAFS, &blob, 1);
     if (code) {
        if (errno == ENODEV) {
            fprintf(stderr,
@@ -3090,7 +3089,7 @@ GetCellCmd(struct cmd_syndesc *as, void *arock)
        }
        blob.in_size = 1+(long)strlen(info.name);
        blob.in = info.name;
-       code = pioctl(0, VIOC_GETCELLSTATUS, &blob, 1);
+       code = pioctl_utf8(0, VIOC_GETCELLSTATUS, &blob, 1);
        if (code) {
            if (errno == ENOENT)
                fprintf(stderr,"%s: the cell named '%s' does not exist\n", pn, info.name);
@@ -3166,7 +3165,7 @@ static int SetCellCmd(struct cmd_syndesc *as, void *arock)
        blob.in = (caddr_t) &args;
        blob.out_size = 0;
        blob.out = (caddr_t) 0;
-       code = pioctl(0, VIOC_SETCELLSTATUS, &blob, 1);
+       code = pioctl_utf8(0, VIOC_SETCELLSTATUS, &blob, 1);
        if (code) {
            Die(errno, info.name);      /* XXX added cell name to Die() call */
             error = 1;
@@ -3218,7 +3217,7 @@ pokeServers(void)
 {
     int code;
     cm_SSetPref_t *ssp;
-    code = pioctl(0, VIOC_SETSPREFS, &gblob, 1);
+    code = pioctl_utf8(0, VIOC_SETSPREFS, &gblob, 1);
 
     ssp = (cm_SSetPref_t *)space;
     gblob.in_size = (long)(((char *)&(ssp->servers[0])) - (char *)ssp);
@@ -3236,14 +3235,14 @@ pokeServers(void)
 {
     int code;
 
-    code = pioctl(0, VIOC_SETSPREFS, &gblob, 1);
+    code = pioctl_utf8(0, VIOC_SETSPREFS, &gblob, 1);
     if (code && (errno == EINVAL)) {
        struct setspref *ssp;
        ssp = (struct setspref *)gblob.in;
        if (!(ssp->flags & DBservers)) {
            gblob.in = (void *)&(ssp->servers[0]);
            gblob.in_size -= ((char *)&(ssp->servers[0])) - (char *)ssp;
-           code = pioctl(0, VIOC_SETSPREFS33, &gblob, 1);
+           code = pioctl_utf8(0, VIOC_SETSPREFS33, &gblob, 1);
            return code ? errno : 0;
        }
        fprintf(stderr,
@@ -3617,7 +3616,7 @@ GetPrefCmd(struct cmd_syndesc *as, void *arock)
         in->num_servers = (MAXSIZE - 2*sizeof(short))/sizeof(struct cm_SPref);
         in->flags = vlservers; 
 
-        code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
+        code = pioctl_utf8(0, VIOC_GETSPREFS, &blob, 1);
         if (code){
             perror("getserverprefs pioctl");
             Die (errno,0);
@@ -3689,7 +3688,7 @@ GetPrefCmd(struct cmd_syndesc *as, void *arock)
            (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
        in->flags = vlservers;
 
-       code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
+       code = pioctl_utf8(0, VIOC_GETSPREFS, &blob, 1);
        if (code) {
            perror("getserverprefs pioctl");
            return 1;
@@ -3716,6 +3715,52 @@ GetPrefCmd(struct cmd_syndesc *as, void *arock)
 }
 #endif /* WIN32 */
 
+static afs_int32
+SmbUnicodeCmd(struct cmd_syndesc * asp, void * arock)
+{
+    long inValue = 0;
+    long outValue = 0;
+    long code;
+
+    struct ViceIoctl blob;
+
+    if (asp->parms[0].items) {
+        /* On */
+
+        inValue = 3;
+    } else if (asp->parms[1].items) {
+        /* Off */
+
+        inValue = 2;
+    }
+
+    if (inValue != 0 && !IsAdmin()) {
+        fprintf (stderr, "Permission denied: Requires AFS Client Administrator access.\n");
+        return EACCES;
+    }
+
+    blob.in_size = sizeof(inValue);
+    blob.in = (char *) &inValue;
+    blob.out_size = sizeof(outValue);
+    blob.out = (char *) &outValue;
+
+    code = pioctl_utf8(NULL, VIOC_UNICODECTL, &blob, 1);
+    if (code) {
+        Die(errno, NULL);
+        return code;
+    }
+
+    if (outValue != 2) {
+        printf("Unicode support is %s%s.\n",
+               ((outValue != 0)? "enabled":"disabled"),
+               ((inValue != 0)? " for new SMB connections":""));
+    } else {
+        printf("Unicode support is absent in this installation of OpenAFS.\n");
+    }
+
+    return 0;
+}
+
 static int
 UuidCmd(struct cmd_syndesc *asp, void *arock)
 {
@@ -3747,7 +3792,7 @@ UuidCmd(struct cmd_syndesc *asp, void *arock)
     blob.out_size = sizeof(outValue);
     blob.out = (char *) &outValue;
 
-    code = pioctl(NULL, VIOC_UUIDCTL, &blob, 1);
+    code = pioctl_utf8(NULL, VIOC_UUIDCTL, &blob, 1);
     if (code) {
         Die(errno, NULL);
         return code;
@@ -3806,7 +3851,7 @@ TraceCmd(struct cmd_syndesc *asp, void *arock)
     blob.out_size = sizeof(long);
     blob.out = (char *) &outValue;
         
-    code = pioctl(NULL, VIOC_TRACECTL, &blob, 1);
+    code = pioctl_utf8(NULL, VIOC_TRACECTL, &blob, 1);
     if (code) {
         Die(errno, NULL);
         return code;
@@ -3887,14 +3932,14 @@ StoreBehindCmd(struct cmd_syndesc *as, void *arock)
     /* once per -file */
     for (ti = as->parms[1].items; ti; ti = ti->next) {
        /* Do this solely to see if the file is there */
-       code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOCWHEREIS, &blob, 1);
        if (code) {
            Die(errno, ti->data);
            error = 1;
            continue;
        }
 
-       code = pioctl(ti->data, VIOC_STOREBEHIND, &blob, 1);
+       code = pioctl_utf8(ti->data, VIOC_STOREBEHIND, &blob, 1);
        if (code) {
            Die(errno, ti->data);
            error = 1;
@@ -3918,7 +3963,7 @@ StoreBehindCmd(struct cmd_syndesc *as, void *arock)
      */
     if (!as->parms[1].items || (allfiles != -1)) {
        tsb.sb_default = allfiles;
-       code = pioctl(0, VIOC_STOREBEHIND, &blob, 1);
+       code = pioctl_utf8(0, VIOC_STOREBEHIND, &blob, 1);
        if (code) {
            Die(errno, ((allfiles == -1) ? 0 : "-allfiles"));
            error = 1;
@@ -3961,7 +4006,7 @@ SetCryptCmd(struct cmd_syndesc *as, void *arock)
     blob.in = (char *) &flag;
     blob.in_size = sizeof(flag);
     blob.out_size = 0;
-    code = pioctl(0, VIOC_SETRXKCRYPT, &blob, 1);
+    code = pioctl_utf8(0, VIOC_SETRXKCRYPT, &blob, 1);
     if (code)
         Die(code, NULL);
     return 0;
@@ -3979,7 +4024,7 @@ GetCryptCmd(struct cmd_syndesc *as, void *arock)
     blob.out_size = sizeof(flag);
     blob.out = space;
 
-    code = pioctl(0, VIOC_GETRXKCRYPT, &blob, 1);
+    code = pioctl_utf8(0, VIOC_GETRXKCRYPT, &blob, 1);
 
     if (code) 
         Die(code, NULL);
@@ -4025,7 +4070,7 @@ MemDumpCmd(struct cmd_syndesc *asp, void *arock)
     blob.out_size = sizeof(long);
     blob.out = (char *) &outValue;
 
-    code = pioctl(NULL, VIOC_TRACEMEMDUMP, &blob, 1);
+    code = pioctl_utf8(NULL, VIOC_TRACEMEMDUMP, &blob, 1);
     if (code) {
         Die(errno, NULL);
         return code;
@@ -4217,7 +4262,7 @@ GetClientAddrsCmd(struct cmd_syndesc *as, void *arock)
        in->num_servers =
            (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
        /* returns addr in network byte order */
-       code = pioctl(0, VIOC_GETCPREFS, &blob, 1);
+       code = pioctl_utf8(0, VIOC_GETCPREFS, &blob, 1);
        if (code) {
            perror("getClientInterfaceAddr pioctl");
            return 1;
@@ -4306,7 +4351,7 @@ SetClientAddrsCmd(struct cmd_syndesc *as, void *arock)
     }
     blob.in_size = sizeUsed - sizeof(struct spref);
 
-    code = pioctl(0, VIOC_SETCPREFS, &blob, 1);        /* network order */
+    code = pioctl_utf8(0, VIOC_SETCPREFS, &blob, 1);   /* network order */
     if (code) {
        Die(errno, 0);
        error = 1;
@@ -4417,7 +4462,7 @@ FlushMountCmd(struct cmd_syndesc *as, void *arock)
        blob.out_size = 0;
        memset(space, 0, MAXSIZE);
 
-       code = pioctl(parent_dir, VIOC_AFS_FLUSHMOUNT, &blob, 1);
+       code = pioctl_utf8(parent_dir, VIOC_AFS_FLUSHMOUNT, &blob, 1);
 
        if (code != 0) {
            if (errno == EINVAL) {
@@ -4457,7 +4502,7 @@ RxStatProcCmd(struct cmd_syndesc *as, void *arock)
     blob.in_size = sizeof(afs_int32);
     blob.out_size = 0;
 
-    code = pioctl(NULL, VIOC_RXSTAT_PROC, &blob, 1);
+    code = pioctl_utf8(NULL, VIOC_RXSTAT_PROC, &blob, 1);
     if (code != 0) {
        Die(errno, NULL);
        return 1;
@@ -4491,7 +4536,7 @@ RxStatPeerCmd(struct cmd_syndesc *as, void *arock)
     blob.in_size = sizeof(afs_int32);
     blob.out_size = 0;
 
-    code = pioctl(NULL, VIOC_RXSTAT_PEER, &blob, 1);
+    code = pioctl_utf8(NULL, VIOC_RXSTAT_PEER, &blob, 1);
     if (code != 0) {
        Die(errno, NULL);
        return 1;
@@ -4571,7 +4616,7 @@ TestVolStatCmd(struct cmd_syndesc *as, void *arock)
     blob.in_size = sizeof(test);
     blob.out_size = 0;
 
-    code = pioctl(NULL, VIOC_VOLSTAT_TEST, &blob, 1);
+    code = pioctl_utf8(NULL, VIOC_VOLSTAT_TEST, &blob, 1);
     if (code != 0) {
        Die(errno, NULL);
        return 1;
@@ -4584,10 +4629,55 @@ TestVolStatCmd(struct cmd_syndesc *as, void *arock)
 #include "AFS_component_version_number.c"
 #endif
 
-main(int argc, char **argv)
+static void
+FreeUtf8CmdLine(int argc, char ** argv)
+{
+    int i;
+    for (i=0; i < argc; i++) {
+        if (argv[i])
+            free(argv[i]);
+    }
+    free(argv);
+}
+
+static char **
+MakeUtf8Cmdline(int argc, const wchar_t **wargv)
+{
+    char ** argv;
+    int i;
+
+    argv = calloc(argc, sizeof(argv[0]));
+    if (argv == NULL)
+        return NULL;
+
+    for (i=0; i < argc; i++) {
+        int s;
+
+        s = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, FALSE);
+        if (s == 0 ||
+            (argv[i] = calloc(s+1, sizeof(char))) == NULL) {
+            break;
+        }
+
+        s = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], s+1, NULL, FALSE);
+        if (s == 0) {
+            break;
+        }
+    }
+
+    if (i < argc) {
+        FreeUtf8CmdLine(argc, argv);
+        return NULL;
+    }
+
+    return argv;
+}
+
+int wmain(int argc, wchar_t **wargv)
 {
     afs_int32 code;
     struct cmd_syndesc *ts;
+    char ** argv;
 
 #ifdef AFS_AIX32_ENV
     /*
@@ -4609,6 +4699,8 @@ main(int argc, char **argv)
     WSAStartup(0x0101, &WSAjunk);
 #endif /* WIN32 */
 
+    argv = MakeUtf8Cmdline(argc, wargv);
+
     /* try to find volume location information */
     osi_Init();
 
@@ -4885,11 +4977,17 @@ main(int argc, char **argv)
     cmd_AddParm(ts, "-volume",  CMD_SINGLE, CMD_OPTIONAL, "volume name or number");
     cmd_AddParm(ts, "-state",   CMD_SINGLE, CMD_OPTIONAL, "new volume state: online, busy, offline, down");
 
+    ts = cmd_CreateSyntax("smbunicode", SmbUnicodeCmd, NULL, "enable or disable Unicode on new SMB connections");
+    cmd_AddParm(ts, "-on", CMD_FLAG, CMD_OPTIONAL, "enable Unicode on new connections");
+    cmd_AddParm(ts, "-off", CMD_FLAG, CMD_OPTIONAL, "disable Unicode on new connections");
+
     code = cmd_Dispatch(argc, argv);
 
     if (rxInitDone) 
         rx_Finalize();
     
+    FreeUtf8CmdLine(argc, argv);
+    
     return code;
 }
 
index 884fc8e..84c990a 100644 (file)
@@ -74,8 +74,7 @@ long fs_GetFullPath(char *pathp, char *outPathp, long outSize)
                /* there's a drive letter there */
         firstp = pathp+2;
         pathHasDrive = 1;
-    }
-    else {
+    } else {
         firstp = pathp;
                pathHasDrive = 0;
        }   
@@ -86,7 +85,7 @@ long fs_GetFullPath(char *pathp, char *outPathp, long outSize)
         return 0;
     }
         
-    GetCurrentDirectory(sizeof(origPath), origPath);
+    GetCurrentDirectoryA(sizeof(origPath), origPath);
         
        doSwitch = 0;
     if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
@@ -98,14 +97,14 @@ long fs_GetFullPath(char *pathp, char *outPathp, long outSize)
         newPath[0] = *pathp;
         newPath[1] = ':';
         newPath[2] = 0;
-        if (!SetCurrentDirectory(newPath)) {
+        if (!SetCurrentDirectoryA(newPath)) {
                        code = GetLastError();
             return code;
         }
     }
         
     /* now get the absolute path to the current wdir in this drive */
-    GetCurrentDirectory(sizeof(tpath), tpath);
+    GetCurrentDirectoryA(sizeof(tpath), tpath);
     strcpy(outPathp, tpath+2); /* skip drive letter */
        /* if there is a non-null name after the drive, append it */
        if (*firstp != 0) {
@@ -115,7 +114,7 @@ long fs_GetFullPath(char *pathp, char *outPathp, long outSize)
 
        /* finally, if necessary, switch back to our home drive letter */
     if (doSwitch) {
-               SetCurrentDirectory(origPath);
+        SetCurrentDirectoryA(origPath);
     }
         
     return 0;
@@ -197,9 +196,9 @@ void fs_utils_InitMountRoot()
     char *pmount=mountRoot;
     DWORD len=sizeof(mountRoot)-1;
     printf("int mountroot \n");
-    if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, 
+    if ((RegOpenKeyExA(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, 
                       (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey)!= ERROR_SUCCESS)
-         || (RegQueryValueEx(parmKey, "Mountroot", NULL, NULL,(LPBYTE)(mountRoot), &len)!= ERROR_SUCCESS)
+        || (RegQueryValueExA(parmKey, "Mountroot", NULL, NULL,(LPBYTE)(mountRoot), &len)!= ERROR_SUCCESS)
          || (len==sizeof(mountRoot)-1)
          ) 
         strcpy(mountRoot, "\\afs"); 
index 94ef258..5b13317 100644 (file)
@@ -31,6 +31,9 @@
 #include "smb.h"
 #include "lanahelper.h"
 
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+
 /* These characters are illegal in Windows filenames */
 static char *illegalChars = "\\/:*?\"<>|";
 
@@ -133,6 +136,9 @@ smb_dirSearch_t *smb_lastDirSearchp;
 /* hide dot files? */
 int smb_hideDotFiles;
 
+/* Negotiate Unicode support? */
+LONG smb_UseUnicode;
+
 /* global state about V3 protocols */
 int smb_useV3;         /* try to negotiate V3 */
 
@@ -2065,7 +2071,7 @@ static smb_packet_t *GetPacket(void)
         smb_packetFreeListp = tbp->nextp;
     lock_ReleaseWrite(&smb_globalLock);
     if (!tbp) {
-        tbp = calloc(65540,1);
+        tbp = calloc(sizeof(*tbp),1);
         tbp->magic = SMB_PACKETMAGIC;
         tbp->ncbp = NULL;
         tbp->vcp = NULL;
@@ -2078,7 +2084,7 @@ static smb_packet_t *GetPacket(void)
         tbp->ncb_length = 0;
         tbp->flags = 0;
         tbp->spacep = NULL;
-        
+        tbp->stringsp = NULL;
     }
     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
 
@@ -2091,6 +2097,7 @@ smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
     tbp = GetPacket();
     memcpy(tbp, pkt, sizeof(smb_packet_t));
     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
+    tbp->stringsp = NULL;
     if (tbp->vcp)
        smb_HoldVC(tbp->vcp);
     return tbp;
@@ -2118,6 +2125,18 @@ static NCB *GetNCB(void)
     return ncbp;
 }
 
+static void FreeSMBStrings(smb_packet_t * pkt)
+{
+    cm_space_t * s;
+    cm_space_t * ns;
+
+    for (s = pkt->stringsp; s; s = ns) {
+        ns = s->nextp;
+        cm_FreeSpace(s);
+    }
+    pkt->stringsp = NULL;
+}
+
 void smb_FreePacket(smb_packet_t *tbp)
 {
     smb_vc_t * vcp = NULL;
@@ -2138,6 +2157,7 @@ void smb_FreePacket(smb_packet_t *tbp)
     tbp->oddByte = 0;
     tbp->ncb_length = 0;
     tbp->flags = 0;
+    FreeSMBStrings(tbp);
     lock_ReleaseWrite(&smb_globalLock);
 
     if (vcp)
@@ -2345,6 +2365,8 @@ void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
     *parmDatap++ = parmValue & 0xff;
 }
 
+
+
 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
 {
     char *lastSlashp;
@@ -2365,14 +2387,286 @@ void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp
     }
 }
 
-unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
+unsigned char *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
+                                   char **chainpp, int flags)
 {
+    size_t cb;
+
     if (*inp++ != 0x4) 
         return NULL;
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    cb = sizeof(pktp->data) - (inp - pktp->data);
+    if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        cb = sizeof(pktp->data);
+    }
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+unsigned char *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
+                               char ** chainpp, int flags)
+{
+    size_t cb;
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    cb = sizeof(pktp->data) - (inp - pktp->data);
+    if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        cb = sizeof(pktp->data);
+    }
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+unsigned char *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
+                                 size_t cb, char ** chainpp, int flags)
+{
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+unsigned char *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
+                                  size_t cch, char ** chainpp, int flags)
+{
+    size_t cb = cch;
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+    else
+        cb = cch * sizeof(wchar_t);
+#endif
+
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+unsigned char *smb_ParseStringBuf(const unsigned char * bufbase,
+                                  cm_space_t ** stringspp,
+                                  unsigned char *inp, size_t *pcb_max,
+                                  char **chainpp, int flags)
+{
+#ifdef SMB_UNICODE
+    if (!(flags & SMB_STRF_FORCEASCII)) {
+        size_t cch_src;
+        int    cb_dest;
+        cm_space_t * spacep;
+        int    null_terms = 0;
+
+        if (bufbase && ((inp - bufbase) % 2) != 0) {
+            inp++;              /* unicode strings are always word aligned */
+        }
+
+        if (*pcb_max > 0) {
+            if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
+                                        &cch_src))) {
+                cch_src = *pcb_max / sizeof(wchar_t);
+                *pcb_max = 0;
+                null_terms = 0;
+            } else {
+                *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
+                null_terms = 1;
+            }
+        } else {
+            return NULL;
+        }
+
+        spacep = cm_GetSpace();
+        spacep->nextp = *stringspp;
+        *stringspp = spacep;
+
+        if (cch_src == 0) {
+            if (chainpp) {
+                *chainpp = inp + sizeof(wchar_t);
+            }
+
+            spacep->data[0] = '\0';
+            return spacep->data;
+        }
+
+        cb_dest = cm_NormalizeUtf16StringToUtf8((const wchar_t *) inp, cch_src,
+                                                spacep->data, sizeof(spacep->data));
+        if (cb_dest == 0) {
+            *stringspp = spacep->nextp;
+            cm_FreeSpace(spacep);
+#ifdef DEBUG_UNICODE
+            DebugBreak();
+#endif
+            return NULL;
+        }
+
+        if (chainpp)
+            *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
+
+        if (cb_dest == 0) {
+#ifdef DEBUG_UNICODE
+            DebugBreak();
+#endif
+        } else if (spacep->data[cb_dest - 1] != 0) {
+            spacep->data[cb_dest++] = 0;
+        }
+
+        return spacep->data;
+
+    } else {
+#endif
+        /* Not using Unicode */
     if (chainpp) {
-        *chainpp = inp + strlen(inp) + 1;      /* skip over null-terminated string */
+            *chainpp = inp + strlen(inp) + 1;
     }
+        if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
+            OemToChar(inp, inp);
     return inp;
+#ifdef SMB_UNICODE
+    }
+#endif
+}
+
+unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
+                                  unsigned char * str,
+                                  size_t * plen, int flags)
+{
+    size_t buffersize;
+    int align = 0;
+
+    if (outp == NULL) {
+        /* we are only calculating the required size */
+#ifdef SMB_UNICODE
+
+        if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
+            int nchars;
+
+            nchars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+                                         str, -1, NULL, 0);
+            if (nchars == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+
+                if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
+                    nchars = MultiByteToWideChar(1252 /* ANSI - Latin1 */,
+                                                 0, str, -1, NULL, 0);
+                else
+                    nchars = MultiByteToWideChar(CP_OEMCP,
+                                                 0, str, -1, NULL, 0);
+            }
+
+            if (nchars == 0) {
+                osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
+                         osi_LogSaveString(smb_logp, str),
+                         GetLastError());
+                if (plen)
+                    *plen = 0;
+                return NULL;
+            }
+
+            if (plen)
+                *plen = sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1 : nchars);
+
+            return (unsigned char *) 1; /* return TRUE if we are using unicode */
+        }
+        else
+#endif
+        {
+            /* Storing ANSI */
+            size_t len;
+
+            len = strlen(str);
+            if (plen)
+                *plen = ((flags & SMB_STRF_IGNORENULL)? len: len+1);
+
+            return NULL;
+        }
+    }
+
+    /* Number of bytes left in the buffer. */
+    if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
+        align = ((outp - pktp->data) % 2);
+        buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
+    } else {
+        align = (((size_t) outp) % 2);
+        buffersize = sizeof(pktp->data);
+    }
+
+#ifdef SMB_UNICODE
+
+    if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
+        int nchars;
+
+        if (align)
+            *outp++ = '\0';
+
+        if (*str == '\0') {
+
+            if (buffersize < sizeof(wchar_t))
+                return NULL;
+
+            *((wchar_t *) outp) = L'\0';
+            if (plen && !(flags & SMB_STRF_IGNORENULL))
+                *plen += sizeof(wchar_t);
+            return outp + sizeof(wchar_t);
+        }
+
+        nchars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+                                     str, -1, (wchar_t *) outp, buffersize);
+        if (nchars == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+
+            /* If we failed to translate the string from UTF-8 to
+               UTF-16, then chances are the string wasn't UTF-8 to
+               begin with.  If StoreAnsiFileNames is set and this is
+               possibly an ANSI file name, we try assuming that the
+               source name is in ANSI.  otherwise we try OEM. */
+
+            if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
+                nchars = MultiByteToWideChar(1252 /* ANSI - Latin1 */,
+                                             0, str, -1, (wchar_t *) outp, buffersize);
+            else
+                nchars = MultiByteToWideChar(CP_OEMCP,
+                                             0, str, -1, (wchar_t *) outp, buffersize);
+        }
+
+        if (nchars == 0) {
+            /* Both 1252 and OEM should translate to Unicode without a
+               complaint.  This is something else. */
+            osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
+                     osi_LogSaveString(smb_logp, str),
+                     GetLastError());
+            return NULL;
+        }
+
+        if (plen)
+            *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
+
+        return outp + sizeof(wchar_t) * nchars;
+    }
+    else
+#endif
+    {
+        /* Storing ANSI */
+        size_t len;
+
+        len = strlen(str); len++;
+        if (len > buffersize)
+            return NULL;
+
+        strcpy(outp, str);
+        if (plen)
+            *plen += ((flags & SMB_STRF_IGNORENULL)? len - 1: len);
+
+        return outp + len;
+    }
 }
 
 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
@@ -2394,6 +2688,23 @@ unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *length
     return inp;
 }      
 
+unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
+{
+    int tlen;
+
+    if (*inp++ != 0x1) return NULL;
+    tlen = inp[0] + (inp[1]<<8);
+    inp += 2;          /* skip length field */
+        
+    if (chainpp) {
+        *chainpp = inp + tlen;
+    }  
+
+    if (lengthp) *lengthp = tlen;
+        
+    return inp;
+}
+
 /* format a packet as a response */
 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
 {
@@ -2427,6 +2738,10 @@ void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op
     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
 #endif
     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
+#ifdef SMB_UNICODE
+    if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
+        outp->flg2 |= SMB_FLAGS2_UNICODE;
+#endif
 
     /* copy fields in generic packet area */
     op->wctp = &outp->wct;
@@ -2831,6 +3146,7 @@ long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return CM_ERROR_BADOP;
 }
 
+/* SMB_COM_ECHO */
 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short EchoCount, i;
@@ -2851,6 +3167,7 @@ long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
+/* SMB_COM_READ_RAW */
 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -3012,6 +3329,7 @@ long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     return 0;
 }
 
+/* SMB_COM_NEGOTIATE */
 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *namep;
@@ -3131,7 +3449,8 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
          * and NT Find *
          * and NT SMB's *
          * and raw mode 
-         * and DFS */
+         * and DFS
+         * and Unicode */
         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
 #ifdef DFS_SUPPORT
                NTNEGOTIATE_CAPABILITY_DFS |
@@ -3146,6 +3465,12 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if ( smb_authType == SMB_AUTH_EXTENDED )
             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
 
+#ifdef SMB_UNICODE
+        if ( smb_UseUnicode ) {
+            caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
+        }
+#endif
+
         smb_SetSMBParmLong(outp, 9, caps);
         time(&unixTime);
         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
@@ -3521,6 +3846,7 @@ long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return 0;
 }
 
+/* SMB_COM_TREE_CONNECT */
 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
 {
     smb_tid_t *tidp;
@@ -3531,17 +3857,13 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     int shareFound;
     char *tp;
     char *pathp;
-    char *passwordp;
     cm_user_t *userp;
 
     osi_Log0(smb_logp, "SMB receive tree connect");
 
     /* parse input parameters */
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-    passwordp = smb_ParseASCIIBlock(tp, &tp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
     tp = strrchr(pathp, '\\');
     if (!tp)
         return CM_ERROR_BADSMB;
@@ -3575,23 +3897,6 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     return 0;
 }
 
-unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
-{
-    int tlen;
-
-    if (*inp++ != 0x1) return NULL;
-    tlen = inp[0] + (inp[1]<<8);
-    inp += 2;          /* skip length field */
-        
-    if (chainpp) {
-        *chainpp = inp + tlen;
-    }  
-
-    if (lengthp) *lengthp = tlen;
-        
-    return inp;
-}
-
 /* set maskp to the mask part of the incoming path.
  * Mask is 11 bytes long (8.3 with the dot elided).
  * Returns true if succeeds with a valid name, otherwise it does
@@ -3709,6 +4014,10 @@ char *smb_FindMask(char *pathp)
         return pathp;  /* no slash, return the entire path */
 }       
 
+/* SMB_COM_SEARCH for a volume label
+
+   (This is called from smb_ReceiveCoreSearchDir() and not an actual
+   dispatch function.) */
 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned char *pathp;
@@ -3722,10 +4031,9 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
 
     /* pull pathname and stat block out of request */
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
+    pathp = smb_ParseASCIIBlock(inp, tp, (char **) &tp,
+                                SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
     osi_assertx(pathp != NULL, "null path");
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
     osi_assertx(statBlockp != NULL, "null statBlock");
     if (statLen == 0) {
@@ -3768,6 +4076,9 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     *tp++ = 0;
     *tp++ = 0;
 
+    /* The filename is a UCHAR buffer that is ASCII even if Unicode
+       was negotiated. */
+
     /* finally, null-terminated 8.3 pathname, which we set to AFS */
     memset(tp, ' ', 13);
     strcpy(tp, "AFS");
@@ -3863,6 +4174,7 @@ smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
     return code;
 }
 
+/* SMB_COM_SEARCH */
 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int attribute;
@@ -3918,9 +4230,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     caseFold = CM_FLAG_CASEFOLD;
 
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp,
+                                SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
 
     /* bail out if request looks bad */
@@ -4337,6 +4648,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             strncpy(op, actualName, 13);
             if (smb_StoreAnsiFilenames)
                 CharToOem(op, op);
+            /* This is a UCHAR field, which is ASCII even if Unicode
+               is negotiated. */
 
             /* Uppercase if requested by client */
             if (!KNOWS_LONG_NAMES(inp))
@@ -4404,8 +4717,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     return code;
 }      
 
+
 /* verify that this is a valid path to a directory.  I don't know why they
  * don't use the get file attributes call.
+ *
+ * SMB_COM_CHECK_DIRECTORY
  */
 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
@@ -4422,11 +4738,9 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     cm_InitReq(&req);
 
     pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADFD;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
     osi_Log1(smb_logp, "SMB receive check path %s",
              osi_LogSaveString(smb_logp, pathp));
         
@@ -4489,6 +4803,7 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     return code;
 }      
 
+/* SMB_COM_SET_INFORMATION */
 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp;
@@ -4510,11 +4825,9 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
 
     pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
                
     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
              dosTime, attribute);
@@ -4604,6 +4917,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return code;
 }
 
+
 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp;
@@ -4622,15 +4936,12 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     cm_InitReq(&req);
 
     pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
         
     if (*pathp == 0)           /* null path */
         pathp = "\\";
-    else
-        if (smb_StoreAnsiFilenames)
-            OemToChar(pathp,pathp);
 
     osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
              osi_LogSaveString(smb_logp, pathp));
@@ -4770,6 +5081,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return 0;
 }      
 
+/* SMB_COM_TREE_DISCONNECT */
 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tid_t *tidp;
@@ -4788,6 +5100,7 @@ long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_
     return 0;
 }
 
+/* SMB_COM_0PEN */
 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_fid_t *fidp;
@@ -4807,9 +5120,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_InitReq(&req);
 
     pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
        
     osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
 
@@ -4994,6 +5305,7 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     return code;
 }
 
+/* SMB_COM_DELETE */
 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int attribute;
@@ -5015,9 +5327,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     attribute = smb_GetSMBParm(inp, 0);
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     osi_Log1(smb_logp, "SMB receive unlink %s",
              osi_LogSaveString(smb_logp, pathp));
@@ -5521,6 +5831,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     return code;
 }
 
+/* SMB_COM_RENAME */
 long 
 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
@@ -5530,12 +5841,8 @@ smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     long code;
 
     tp = smb_GetSMBData(inp, NULL);
-    oldPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(oldPathp,oldPathp);
-    newPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(newPathp,newPathp);
+    oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
              osi_LogSaveString(smb_logp, oldPathp),
@@ -5590,6 +5897,7 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
     return 0;
 }
 
+
 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     long code = 0;
@@ -5608,9 +5916,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     cm_InitReq(&req);
 
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
@@ -5697,6 +6003,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     return code;
 }
 
+/* SMB_COM_FLUSH */
 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -6003,6 +6310,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     return code;
 }
 
+/* SMB_COM_CLOSE */
 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -6465,6 +6773,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
     return code;
 }
 
+/* SMB_COM_WRITE */
 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fd;
@@ -6669,6 +6978,7 @@ long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     return 0;
 }
 
+/* SMB_COM_WRITE_RAW */
 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
 {
     osi_hyper_t offset;
@@ -6847,6 +7157,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     return 0;
 }
 
+/* SMB_COM_READ */
 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -6944,6 +7255,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return code;
 }
 
+/* SMB_COM_CREATE_DIRECTORY */
 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp;
@@ -6968,9 +7280,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     initialModeBits = 0777;
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     if (strcmp(pathp, "\\") == 0)
         return CM_ERROR_EXISTS;
@@ -7063,6 +7373,7 @@ BOOL smb_IsLegalFilename(char *filename)
     return TRUE;
 }        
 
+/* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp;
@@ -7098,9 +7409,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        initialModeBits &= ~0222;
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
@@ -7262,6 +7571,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
+/* SMB_COM_SEEK */
 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     long code = 0;
@@ -7436,9 +7746,11 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                 /* Raw Write */
                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
             else {
-                osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",opName,vcp,vcp->lana,vcp->lsn);
+                osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
+                         opName,vcp,vcp->lana,vcp->lsn);
                 code = (*(dp->procp)) (vcp, inp, outp);
-                osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
+                osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",
+                         code,vcp,vcp->lana,vcp->lsn);
 #ifdef LOG_PACKET
                 if ( code == CM_ERROR_BADSMB ||
                      code == CM_ERROR_BADOP )
@@ -7455,8 +7767,9 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                osi_Log3(smb_logp, "Request %s straddled session startup, "
                           "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
             }
-        }
-        else {
+
+            FreeSMBStrings(inp);
+        } else {
             /* bad opcode, fail the request, after displaying it */
             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
 #ifdef LOG_PACKET
@@ -7976,8 +8289,10 @@ void smb_Server(VOID *parmp)
         smbp = (smb_t *)bufp->data;
         outbufp->flags = 0;
 
+#ifndef NOTRACE
         __try
         {
+#endif
             if (smbp->com == 0x1d) {
                 /* Special handling for Write Raw */
                 raw_write_cont_t rwc;
@@ -8015,9 +8330,11 @@ void smb_Server(VOID *parmp)
                 /* TODO: what else needs to be serialized? */
                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
             }
+#ifndef NOTRACE        
         }
         __except( smb_ServerExceptionFilter() ) {
         }
+#endif
 
         smb_concurrentCalls--;
 
@@ -8316,6 +8633,7 @@ void smb_Listener(void *parmp)
                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
                 smbp->rcls = errClass;
             }
+
             smb_SendPacket(vcp, outp);
             smb_FreePacket(outp);
 
@@ -9290,6 +9608,7 @@ char *smb_GetSharename()
 void smb_LogPacket(smb_packet_t *packet)
 {
     BYTE *vp, *cp;
+    smb_t * smbp;
     unsigned length, paramlen, datalen, i, j;
     char buf[81];
     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
@@ -9298,11 +9617,12 @@ void smb_LogPacket(smb_packet_t *packet)
 
     osi_Log0(smb_logp, "*** SMB packet dump ***");
 
+    smbp = (smb_t *) packet->data;
     vp = (BYTE *) packet->data;
 
-    datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
-    length = paramlen + 2 + datalen;
-
+    paramlen = smbp->wct * 2;
+    datalen = *((WORD *) (smbp->vdata + paramlen));
+    length = sizeof(*smbp) + paramlen + 1 + datalen;
 
     for (i=0;i < length; i+=16)
     {
index 86ec4a9..4565440 100644 (file)
@@ -64,6 +64,7 @@ typedef struct smb {
 
 #define KNOWS_LONG_NAMES(inp) ((((smb_t *)inp)->flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES)?1:0)
 #define WANTS_DFS_PATHNAMES(inp) ((((smb_t *)inp)->flg2 & SMB_FLAGS2_DFS_PATHNAMES)?1:0)
+#define WANTS_UNICODE(inp) ((((smb_t *)inp)->flg2 & SMB_FLAGS2_UNICODE)?1:0)
 
 /* Information Levels */
 #define SMB_INFO_STANDARD               1
@@ -125,6 +126,8 @@ typedef struct smb {
 #define SMB_PACKETSIZE 32768 /* was 8400 */
 /* raw mode is considered obsolete and cannot be used with message signing */
 #define SMB_MAXRAWSIZE  65536
+/* max STRING characters per packet per request */
+#define SMB_STRINGBUFSIZE 4096
 
 /* Negotiate protocol constants */
 /* Security */
@@ -186,6 +189,7 @@ typedef struct smb_packet {
     unsigned char oddByte;
     unsigned short ncb_length;
     unsigned char flags;
+    cm_space_t *stringsp;               /* decoded strings from this packet */
 } smb_packet_t;
 
 /* smb_packet flags */
@@ -242,6 +246,7 @@ typedef struct smb_vc {
 #define SMB_VCFLAG_SESSX_RCVD  0x40    /* we received at least one session setups on this vc */
 #define SMB_VCFLAG_AUTH_IN_PROGRESS 0x80 /* a SMB NT extended authentication is in progress */
 #define SMB_VCFLAG_CLEAN_IN_PROGRESS 0x100
+#define SMB_VCFLAG_USEUNICODE   0x200   /* une UNICODE for STRING fields (NTLM 0.12 or later) */
 
 /* one per user session */
 typedef struct smb_user {
@@ -338,11 +343,13 @@ typedef struct smb_ioctl {
 
     /* uid pointer */
     smb_user_t *uidp;
+
 } smb_ioctl_t;
 
 /* flags for smb_ioctl_t */
 #define SMB_IOCTLFLAG_DATAIN   1       /* reading data from client to server */
 #define SMB_IOCTLFLAG_LOGON    2       /* got tokens from integrated logon */
+#define SMB_IOCTLFLAG_USEUTF8   4       /* this request is using UTF-8 strings */
 
 /* one per file ID; these are really file descriptors */
 typedef struct smb_fid {
@@ -622,7 +629,30 @@ extern void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmVa
 extern void smb_StripLastComponent(char *outPathp, char **lastComponentp,
        char *inPathp);
 
-extern unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp);
+#define SMB_STRF_FORCEASCII (1<<0)
+#define SMB_STRF_ANSIPATH   (1<<1)
+#define SMB_STRF_IGNORENULL (1<<2)
+
+extern unsigned char *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
+                                          char **chainpp, int flags);
+
+extern unsigned char *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
+                                      char ** chainpp, int flags);
+
+extern unsigned char *smb_ParseStringBuf(const unsigned char * bufbase,
+                                         cm_space_t ** stringspp,
+                                         unsigned char *inp, size_t *pcb_max,
+                                         char **chainpp, int flags);
+
+extern unsigned char *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
+                                        size_t cb, char ** chainpp, int flags);
+
+extern unsigned char *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
+                                         size_t cch, char ** chainpp, int flags);
+
+extern unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
+                                         unsigned char * str,
+                                         size_t * plen, int flags);
 
 extern unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp,
        int *lengthp);
@@ -678,6 +708,7 @@ extern char smb_ServerLanManager[];
 extern int smb_ServerLanManagerLength;
 extern GUID smb_ServerGUID;
 extern LSA_STRING smb_lsaLogonOrigin;
+extern LONG smb_UseUnicode;
 
 /* used for getting a challenge for SMB auth */
 typedef struct _MSV1_0_LM20_CHALLENGE_REQUEST {  
@@ -709,8 +740,6 @@ extern int smb_ChainFID(int fid, smb_packet_t *inp);
 
 extern unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp);
 
-extern unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp);
-
 extern unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp);
 
 extern int smb_SUser(cm_user_t *userp);
index 27c6e1a..fa40cae 100644 (file)
@@ -133,15 +133,6 @@ int smb_V3IsStarMask(char *maskp)
     return 0;
 }
 
-unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
-{
-    if (chainpp) {
-        /* skip over null-terminated string */
-        *chainpp = inp + strlen(inp) + 1;
-    }
-    return inp;
-}   
-
 void OutputDebugF(char * format, ...) {
     va_list args;
     int len;
@@ -676,6 +667,7 @@ long smb_GetNormalizedUsername(char * usern, const char * accountName, const cha
  * sending a session setup packet, which means that we can't rely on a
  * UID in subsequent packets.  Though in practice we get one anyway.
  */
+/* SMB_COM_SESSION_SETUP_ANDX */
 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *tp;
@@ -711,21 +703,23 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
 
             if (code == CM_ERROR_GSSCONTINUE) {
+                size_t cb_data = 0;
+
                 smb_SetSMBParm(outp, 2, 0);
                 smb_SetSMBParm(outp, 3, secBlobOutLength);
-                smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+
                 tp = smb_GetSMBData(outp, NULL);
                 if (secBlobOutLength) {
                     memcpy(tp, secBlobOut, secBlobOutLength);
                     free(secBlobOut);
                     tp += secBlobOutLength;
+                    cb_data += secBlobOutLength;
                 }      
-                memcpy(tp,smb_ServerOS,smb_ServerOSLength);
-                tp += smb_ServerOSLength;
-                memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
-                tp += smb_ServerLanManagerLength;
-                memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
-                tp += smb_ServerDomainNameLength;
+                tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
+                tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
+                tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
+
+                smb_SetSMBDataLength(outp, cb_data);
             }
 
             /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
@@ -754,8 +748,8 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             csPwd = tp;
             tp += csPwdLength;
 
-            accountName = smb_ParseString(tp, &tp);
-            primaryDomain = smb_ParseString(tp, NULL);
+            accountName = smb_ParseString(inp, tp, &tp, 0);
+            primaryDomain = smb_ParseString(inp, tp, NULL, 0);
 
             OutputDebugF("Account Name: %s",accountName);
             OutputDebugF("Primary Domain: %s", primaryDomain);
@@ -802,8 +796,8 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         ciPwd = tp;
         tp += ciPwdLength;
 
-        accountName = smb_ParseString(tp, &tp);
-        primaryDomain = smb_ParseString(tp, NULL);
+        accountName = smb_ParseString(inp, tp, &tp, 0);
+        primaryDomain = smb_ParseString(inp, tp, NULL, 0);
 
         OutputDebugF("Account Name: %s",accountName);
         OutputDebugF("Primary Domain: %s", primaryDomain);
@@ -836,6 +830,12 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
             vcp->flags |= SMB_VCFLAG_STATUS32;
         }       
+
+#ifdef SMB_UNICODE
+        if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
+            vcp->flags |= SMB_VCFLAG_USEUNICODE;
+        }
+#endif
         lock_ReleaseMutex(&vcp->mx);
     }
 
@@ -918,33 +918,37 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
     if (vcp->flags & SMB_VCFLAG_USENT) {
         if (smb_authType == SMB_AUTH_EXTENDED) {
+            size_t cb_data = 0;
+
             smb_SetSMBParm(outp, 3, secBlobOutLength);
-            smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+
             tp = smb_GetSMBData(outp, NULL);
             if (secBlobOutLength) {
                 memcpy(tp, secBlobOut, secBlobOutLength);
                 free(secBlobOut);
                 tp += secBlobOutLength;
+                cb_data +=  secBlobOutLength;
             }  
-            memcpy(tp,smb_ServerOS,smb_ServerOSLength);
-            tp += smb_ServerOSLength;
-            memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
-            tp += smb_ServerLanManagerLength;
-            memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
-            tp += smb_ServerDomainNameLength;
+
+            tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
+            tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
+            tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
+
+            smb_SetSMBDataLength(outp, cb_data);
         } else {
             smb_SetSMBDataLength(outp, 0);
         }
     } else {
         if (smb_authType == SMB_AUTH_EXTENDED) {
-            smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+            size_t cb_data = 0;
+
             tp = smb_GetSMBData(outp, NULL);
-            memcpy(tp,smb_ServerOS,smb_ServerOSLength);
-            tp += smb_ServerOSLength;
-            memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
-            tp += smb_ServerLanManagerLength;
-            memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
-            tp += smb_ServerDomainNameLength;
+
+            tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
+            tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
+            tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
+
+            smb_SetSMBDataLength(outp, cb_data);
         } else {
             smb_SetSMBDataLength(outp, 0);
         }
@@ -953,6 +957,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     return 0;
 }
 
+/* SMB_COM_LOGOFF_ANDX */
 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_user_t *uidp;
@@ -1000,6 +1005,7 @@ long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 #define SMB_SUPPORT_SEARCH_BITS        0x0001
 #define SMB_SHARE_IS_IN_DFS            0x0002
 
+/* SMB_COM_TREE_CONNECT_ANDX */
 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tid_t *tidp;
@@ -1019,11 +1025,9 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
 
     /* parse input parameters */
     tp = smb_GetSMBData(inp, NULL);
-    passwordp = smb_ParseString(tp, &tp);
-    pathp = smb_ParseString(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-    servicep = smb_ParseString(tp, &tp);
+    passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
+    pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
 
     tp = strrchr(pathp, '\\');
     if (!tp) {
@@ -1031,9 +1035,10 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     }
     strcpy(shareName, tp+1);
 
-    osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
+    osi_Log3(smb_logp, "Tree connect pathp[%s] shareName[%s] service[%s]",
              osi_LogSaveString(smb_logp, pathp),
-             osi_LogSaveString(smb_logp, shareName));
+             osi_LogSaveString(smb_logp, shareName),
+             osi_LogSaveString(smb_logp, servicep));
 
     if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
 #ifndef NO_IPC
@@ -1104,18 +1109,16 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     ((smb_t *)inp)->tid = newTid;
     tp = smb_GetSMBData(outp, NULL);
     if (!ipc) {
-        /* XXX - why is this a drive letter? */
-        *tp++ = 'A';
-        *tp++ = ':';
-        *tp++ = 0;
-        *tp++ = 'A';
-        *tp++ = 'F';
-        *tp++ = 'S';
-        *tp++ = 0;
-        smb_SetSMBDataLength(outp, 7);
+        size_t cb_data = 0;
+
+        tp = smb_UnparseString(outp, tp, "A:", &cb_data, SMB_STRF_FORCEASCII);
+        tp = smb_UnparseString(outp, tp, "AFS", &cb_data, 0);
+        smb_SetSMBDataLength(outp, cb_data);
     } else {
-        strcpy(tp, "IPC");
-        smb_SetSMBDataLength(outp, 4);
+        size_t cb_data = 0;
+
+        tp = smb_UnparseString(outp, tp, "IPC", &cb_data, SMB_STRF_FORCEASCII);
+        smb_SetSMBDataLength(outp, cb_data);
     }
 
     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
@@ -1167,6 +1170,10 @@ smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
         tp->com = 0x32;
     }
     tp->flags |= SMB_TRAN2PFLAG_ALLOC;
+#ifdef SMB_UNICODE
+    if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
+        tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
+#endif
     return tp;
 }
 
@@ -1226,9 +1233,37 @@ void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
         if (t2p->datap)
             free(t2p->datap);
     }       
+    while (t2p->stringsp) {
+        cm_space_t * ns;
+
+        ns = t2p->stringsp;
+        t2p->stringsp = ns->nextp;
+        cm_FreeSpace(ns);
+    }
     free(t2p);
 }
 
+unsigned char *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
+                                     char ** chainpp, int flags)
+{
+    size_t cb;
+
+#ifdef SMB_UNICODE
+    if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    cb = p->totalParms - (inp - (unsigned char *)p->parmsp);
+    if (inp < (unsigned char *) p->parmsp ||
+        inp > ((unsigned char *) p->parmsp) + p->totalParms) {
+        DebugBreak();
+        cb = p->totalParms;
+    }
+
+    return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
+                              inp, &cb, chainpp, flags);
+}
+
 /* called with a VC, an input packet to respond to, and an error code.
  * sends an error response.
  */
@@ -1331,6 +1366,8 @@ void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp
     smb_SendPacket(vcp, tp);
 }   
 
+
+/* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tran2Packet_t *asp;
@@ -1453,31 +1490,32 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
-/* ANSI versions.  The unicode versions support arbitrary length
-   share names, but we don't support unicode yet. */
+/* ANSI versions. */
+
+#pragma pack(push, 1)
 
 typedef struct smb_rap_share_info_0 {
-    char        shi0_netname[13];
+    BYTE                shi0_netname[13];
 } smb_rap_share_info_0_t;
 
 typedef struct smb_rap_share_info_1 {
-    char                       shi1_netname[13];
-    char                       shi1_pad;
+    BYTE                shi1_netname[13];
+    BYTE                shi1_pad;
     WORD                       shi1_type;
     DWORD                      shi1_remark; /* char *shi1_remark; data offset */
 } smb_rap_share_info_1_t;
 
 typedef struct smb_rap_share_info_2 {
-    char                       shi2_netname[13];
-    char                       shi2_pad;
-    unsigned short             shi2_type;
+    BYTE               shi2_netname[13];
+    BYTE               shi2_pad;
+    WORD               shi2_type;
     DWORD                      shi2_remark; /* char *shi2_remark; data offset */
-    unsigned short             shi2_permissions;
-    unsigned short             shi2_max_uses;
-    unsigned short             shi2_current_uses;
+    WORD               shi2_permissions;
+    WORD               shi2_max_uses;
+    WORD               shi2_current_uses;
     DWORD                      shi2_path;  /* char *shi2_path; data offset */
-    unsigned short             shi2_passwd[9];
-    unsigned short             shi2_pad2;
+    WORD               shi2_passwd[9];
+    WORD               shi2_pad2;
 } smb_rap_share_info_2_t;
 
 #define SMB_RAP_MAX_SHARES 512
@@ -1488,6 +1526,8 @@ typedef struct smb_rap_share_list {
     smb_rap_share_info_0_t * shares;
 } smb_rap_share_list_t;
 
+#pragma pack(pop)
+
 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
     smb_rap_share_list_t * sp;
     char * name;
@@ -1510,6 +1550,7 @@ int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp
         return 0;
 }       
 
+/* RAP NetShareEnumRequest */
 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     smb_tran2Packet_t *outp;
@@ -1540,8 +1581,18 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     osi_hyper_t thyper;
 
     tp = p->parmsp + 1; /* skip over function number (always 0) */
-    (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
-    (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
+
+    {
+        char * cdescp;
+
+        cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+        if (strcmp(cdescp, "WrLeh"))
+            return CM_ERROR_INVAL;
+        cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+        if (strcmp(cdescp, "B13BWz"))
+            return CM_ERROR_INVAL;
+    }
+
     infoLevel = tp[0];
     bufsize = tp[1];
 
@@ -1549,6 +1600,18 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
         return CM_ERROR_INVAL;
     }
 
+    /* We are supposed to use the same ASCII data structure even if
+       Unicode is negotiated, which ultimately means that the share
+       names that we return must be at most 13 characters in length,
+       including the NULL terminator.
+
+       The RAP specification states that shares with names longer than
+       12 characters should not be included in the enumeration.
+       However, since we support prefix cell references and since many
+       cell names are going to exceed 12 characters, we lie and send
+       the first 12 characters.
+    */
+
     /* first figure out how many shares there are */
     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                       KEY_QUERY_VALUE, &hkParam);
@@ -1624,8 +1687,10 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
         for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
             len = sizeof(thisShare);
             rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
-            if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
-                strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
+            if (rv == ERROR_SUCCESS &&
+                strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
+                strncpy(shares[cshare].shi1_netname, thisShare,
+                        sizeof(shares->shi1_netname)-1);
                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
                 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
                 cshare++;
@@ -1673,6 +1738,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     return code;
 }
 
+/* RAP NetShareGetInfo */
 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     smb_tran2Packet_t *outp;
@@ -1696,9 +1762,24 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     cm_InitReq(&req);
 
     tp = p->parmsp + 1; /* skip over function number (always 1) */
-    (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
-    (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
-    shareName = smb_ParseString( (char *) tp, (char **) &tp);
+
+    {
+        char * cdescp;
+
+        cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+        if (strcmp(cdescp, "zWrLh"))
+
+            return CM_ERROR_INVAL;
+
+        cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+        if (strcmp(cdescp, "B13") &&
+            strcmp(cdescp, "B13BWz") &&
+            strcmp(cdescp, "B13BWzWWWzB9B"))
+
+            return CM_ERROR_INVAL;
+    }
+    shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+
     infoLevel = *tp++;
     bufsize = *tp++;
     
@@ -1793,16 +1874,19 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     return code;
 }
 
+#pragma pack(push, 1)
+
 typedef struct smb_rap_wksta_info_10 {
     DWORD      wki10_computername;     /*char *wki10_computername;*/
     DWORD      wki10_username; /* char *wki10_username; */
     DWORD      wki10_langroup; /* char *wki10_langroup;*/
-    unsigned char      wki10_ver_major;
-    unsigned char      wki10_ver_minor;
+    BYTE       wki10_ver_major;
+    BYTE       wki10_ver_minor;
     DWORD      wki10_logon_domain;     /*char *wki10_logon_domain;*/
     DWORD      wki10_oth_domains; /* char *wki10_oth_domains;*/
 } smb_rap_wksta_info_10_t;
 
+#pragma pack(pop)
 
 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
@@ -1818,8 +1902,20 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     smb_user_t *uidp;
 
     tp = p->parmsp + 1; /* Skip over function number */
-    (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
-    (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
+
+    {
+        char * cdescp;
+
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+                                       SMB_STRF_FORCEASCII);
+        if (strcmp(cdescp, "WrLh"))
+            return CM_ERROR_INVAL;
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+                                       SMB_STRF_FORCEASCII);
+        if (strcmp(cdescp, "zzzBBzz"))
+            return CM_ERROR_INVAL;
+    }
+
     infoLevel = *tp++;
     bufsize = *tp++;
 
@@ -1885,18 +1981,22 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     return code;
 }
 
+#pragma pack(push, 1)
+
 typedef struct smb_rap_server_info_0 {
-    char    sv0_name[16];
+    BYTE    sv0_name[16];
 } smb_rap_server_info_0_t;
 
 typedef struct smb_rap_server_info_1 {
-    char            sv1_name[16];
-    char            sv1_version_major;
-    char            sv1_version_minor;
-    unsigned long   sv1_type;
-    DWORD           *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
+    BYTE            sv1_name[16];
+    BYTE            sv1_version_major;
+    BYTE            sv1_version_minor;
+    DWORD           sv1_type;
+    DWORD           sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
 } smb_rap_server_info_1_t;
 
+#pragma pack(pop)
+
 char smb_ServerComment[] = "OpenAFS Client";
 int smb_ServerCommentLen = sizeof(smb_ServerComment);
 
@@ -1918,8 +2018,21 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
     char * cstrp;
 
     tp = p->parmsp + 1; /* Skip over function number */
-    (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
-    (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
+
+    {
+        char * cdescp;
+
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+                                       SMB_STRF_FORCEASCII);
+        if (strcmp(cdescp, "WrLh"))
+            return CM_ERROR_INVAL;
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+                                       SMB_STRF_FORCEASCII);
+        if (strcmp(cdescp, "B16") ||
+            strcmp(cdescp, "B16BBDz"))
+            return CM_ERROR_INVAL;
+    }
+
     infoLevel = *tp++;
     bufsize = *tp++;
 
@@ -1954,7 +2067,7 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
 
         info1->sv1_version_major = 5;
         info1->sv1_version_minor = 1;
-        info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
+        info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
 
         strcpy(cstrp, smb_ServerComment);
 
@@ -1973,6 +2086,7 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
     return code;
 }
 
+/* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tran2Packet_t *asp;
@@ -2091,6 +2205,7 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
+/* TRANS2_OPEN2 */
 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     char *pathp;
@@ -2139,9 +2254,8 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     if (attributes & SMB_ATTR_READONLY) 
         initialModeBits &= ~0222;
         
-    pathp = (char *) (&p->parmsp[14]);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
+                                  SMB_STRF_ANSIPATH);
     
     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
 
@@ -2488,44 +2602,21 @@ long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     return CM_ERROR_BAD_LEVEL;
 }
 
+/* TRANS2_QUERY_FS_INFORMATION */
 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     smb_tran2Packet_t *outp;
     smb_tran2QFSInfo_t qi;
     int responseSize;
-    static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
+    size_t sz = 0;
         
     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
 
     switch (p->parmsp[0]) {
     case SMB_INFO_ALLOCATION: 
+        /* alloc info */
        responseSize = sizeof(qi.u.allocInfo); 
-       break;
-    case SMB_INFO_VOLUME: 
-       responseSize = sizeof(qi.u.volumeInfo); 
-       break;
-    case SMB_QUERY_FS_VOLUME_INFO: 
-       responseSize = sizeof(qi.u.FSvolumeInfo); 
-       break;
-    case SMB_QUERY_FS_SIZE_INFO: 
-       responseSize = sizeof(qi.u.FSsizeInfo); 
-       break;
-    case SMB_QUERY_FS_DEVICE_INFO: 
-       responseSize = sizeof(qi.u.FSdeviceInfo); 
-       break;
-    case SMB_QUERY_FS_ATTRIBUTE_INFO: 
-       responseSize = sizeof(qi.u.FSattributeInfo); 
-       break;
-    case SMB_INFO_UNIX:        /* CIFS Unix Info */
-    case SMB_INFO_MACOS:       /* Mac FS Info */
-    default: 
-       return CM_ERROR_BADOP;
-    }
 
-    outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
-    switch (p->parmsp[0]) {
-    case SMB_INFO_ALLOCATION: 
-        /* alloc info */
         qi.u.allocInfo.FSID = 0;
         qi.u.allocInfo.sectorsPerAllocUnit = 1;
         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
@@ -2535,23 +2626,34 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
 
     case SMB_INFO_VOLUME: 
         /* volume info */
-        qi.u.volumeInfo.vsn = 1234;
-        qi.u.volumeInfo.vnCount = 4;
+        qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
+        qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
+
         /* we're supposed to pad it out with zeroes to the end */
         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
-        memcpy(qi.u.volumeInfo.label, "AFS", 4);
+        smb_UnparseString(op, qi.u.volumeInfo.label, "AFS", &sz, 0);
+
+        responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
         break;
 
     case SMB_QUERY_FS_VOLUME_INFO: 
         /* FS volume info */
-        memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
+       responseSize = sizeof(qi.u.FSvolumeInfo);
+
+        {
+            FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
+            memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
+        }
+
         qi.u.FSvolumeInfo.vsn = 1234;
-        qi.u.FSvolumeInfo.vnCount = 8;
-        memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
+        qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
+        memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
         break;
 
     case SMB_QUERY_FS_SIZE_INFO: 
         /* FS size info */
+       responseSize = sizeof(qi.u.FSsizeInfo); 
+
         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
        qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
@@ -2562,12 +2664,15 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
 
     case SMB_QUERY_FS_DEVICE_INFO: 
         /* FS device info */
+       responseSize = sizeof(qi.u.FSdeviceInfo); 
+
         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
         break;
 
     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
         /* FS attribute info */
+
         /* attributes, defined in WINNT.H:
          *     FILE_CASE_SENSITIVE_SEARCH      0x1
          *     FILE_CASE_PRESERVED_NAMES       0x2
@@ -2578,12 +2683,35 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
          *        despite our protestations to the contrary.
          */
         qi.u.FSattributeInfo.attributes = 0x4003;
+        /* The maxCompLength is supposed to be in bytes */
+#ifdef SMB_UNICODE
+        if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
+            qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
+        else {
+#endif
         qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
-        qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
-        memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
+#ifdef SMB_UNICODE
+        }
+#endif
+        smb_UnparseString(op, qi.u.FSattributeInfo.FSname, "AFS", &sz, 0);
+        qi.u.FSattributeInfo.FSnameLength = sz;
+
+       responseSize =
+            sizeof(qi.u.FSattributeInfo.attributes) +
+            sizeof(qi.u.FSattributeInfo.maxCompLength) +
+            sizeof(qi.u.FSattributeInfo.FSnameLength) +
+            sz;
+
         break;
+
+    case SMB_INFO_UNIX:        /* CIFS Unix Info */
+    case SMB_INFO_MACOS:       /* Mac FS Info */
+    default: 
+       return CM_ERROR_BADOP;
     }   
         
+    outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
+        
     /* copy out return data, and set corresponding sizes */
     outp->totalParms = 0;
     outp->totalData = responseSize;
@@ -2678,6 +2806,7 @@ long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
     return code;
 }
 
+/* TRANS2_QUERY_PATH_INFORMATION */
 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     smb_tran2Packet_t *outp;
@@ -2689,7 +2818,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     unsigned short attributes;
     unsigned long extAttributes;
     char shortName[13];
-    unsigned int len;
+    size_t len;
     cm_user_t *userp;
     cm_space_t *spacep;
     cm_scache_t *scp, *dscp;
@@ -2729,9 +2858,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return 0;
     }
 
-    pathp = (char *)(&p->parmsp[3]);
-    if (smb_StoreAnsiFilenames)
-       OemToChar(pathp,pathp);
+    pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
               osi_LogSaveString(smb_logp, pathp));
 
@@ -2867,6 +2994,8 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         
     lock_ConvertWToR(&scp->rw);
 
+    len = 0;
+
     /* now we have the status in the cache entry, and everything is locked.
      * Marshall the output data.
      */
@@ -2874,20 +3003,19 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
         code = cm_GetShortName(pathp, userp, &req,
                                 tidPathp, scp->fid.vnode, shortName,
-                                (size_t *) &len);
+                               &len);
         if (code) {
             goto done;
         }
 
-       qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
+        smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, 0);
+       qpi.u.QPfileAltNameInfo.fileNameLength = len;
 
         goto done;
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
-       len = (unsigned int)strlen(lastComp);
-       qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
+        smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, 0);
+       qpi.u.QPfileNameInfo.fileNameLength = len;
 
         goto done;
     }
@@ -2963,9 +3091,9 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
        qpi.u.QPfileAllInfo.mode = 0;
        qpi.u.QPfileAllInfo.alignmentRequirement = 0;
-       len = (unsigned int)strlen(lastComp);
-       qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
+
+        smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, 0);
+       qpi.u.QPfileAllInfo.fileNameLength = len;
     }
 
     /* send and free the packets */
@@ -2985,6 +3113,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return 0;
 }
 
+/* TRANS2_SET_PATH_INFORMATION */
 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
 #if 0
@@ -3018,9 +3147,8 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         return 0;
     }
 
-    pathp = (char *)(&p->parmsp[3]);
-    if (smb_StoreAnsiFilenames)
-       OemToChar(pathp,pathp);
+    pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
+
     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
               osi_LogSaveString(smb_logp, pathp));
 
@@ -3212,6 +3340,7 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
 #endif
 }
 
+/* TRANS2_QUERY_FILE_INFORMATION */
 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     smb_tran2Packet_t *outp;
@@ -3322,7 +3451,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qfi.u.QFeaInfo.eaSize = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
-        unsigned long len;
+        size_t len = 0;
         char *name;
 
        lock_ReleaseRead(&scp->rw);
@@ -3333,10 +3462,10 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         else
             name = "\\";       /* probably can't happen */
        lock_ReleaseMutex(&fidp->mx);
-        len = (unsigned long)strlen(name);
-        outp->totalData = ((len+1)*2) + 4;     /* this is actually what we want to return */
-        qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
+
+        smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, 0);
+        outp->totalData = len + 4;     /* this is actually what we want to return */
+        qfi.u.QFfileNameInfo.fileNameLength = len;
     }
 
     /* send and free the packets */
@@ -3359,6 +3488,8 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return 0;
 }       
 
+
+/* TRANS2_SET_FILE_INFORMATION */
 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     long code = 0;
@@ -3547,6 +3678,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     return 0;
 }
 
+/* TRANS2_FSCTL */
 long 
 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3554,6 +3686,7 @@ smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_IOCTL2 */
 long 
 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3561,6 +3694,7 @@ smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_FIND_NOTIFY_FIRST */
 long 
 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3568,6 +3702,7 @@ smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_FIND_NOTIFY_NEXT */
 long 
 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3575,6 +3710,7 @@ smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_CREATE_DIRECTORY */
 long 
 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3582,6 +3718,7 @@ smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_SESSION_SETUP */
 long 
 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3599,6 +3736,7 @@ struct smb_v2_referral {
     USHORT NetworkAddressOffset;
 };
 
+/* TRANS2_GET_DFS_REFERRAL */
 long 
 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
@@ -3805,6 +3943,7 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #endif /* DFS_SUPPORT */
 }
 
+/* TRANS2_REPORT_DFS_INCONSISTENCY */
 long 
 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3830,10 +3969,8 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
     long code = 0;
     cm_scache_t *scp;
     cm_scache_t *targetScp;                    /* target if scp is a symlink */
-    char *dptr;
     afs_uint32 dosTime;
     FILETIME ft;
-    int shortTemp;
     unsigned short attr;
     unsigned long lattr;
     smb_dirListPatch_t *patchp;
@@ -3876,37 +4013,27 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
         if (mustFake || code) { 
             lock_ReleaseWrite(&scp->rw);
 
-            dptr = patchp->dptr;
-
             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
                errors in the client. */
             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+                smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
+
                 /* 1969-12-31 23:59:59 +00 */
                 ft.dwHighDateTime = 0x19DB200;
                 ft.dwLowDateTime = 0x5BB78980;
 
                 /* copy to Creation Time */
-                *((FILETIME *)dptr) = ft;
-                dptr += 8;
-
-                /* copy to Last Access Time */
-                *((FILETIME *)dptr) = ft;
-                dptr += 8;
-
-                /* copy to Last Write Time */
-                *((FILETIME *)dptr) = ft;
-                dptr += 8;
-
-                /* copy to Change Time */
-                *((FILETIME *)dptr) = ft;
-                dptr += 24;
+                fa->creationTime = ft;
+                fa->lastAccessTime = ft;
+                fa->lastWriteTime = ft;
+                fa->lastChangeTime = ft;
 
                 switch (scp->fileType) {
                 case CM_SCACHETYPE_DIRECTORY:
                 case CM_SCACHETYPE_MOUNTPOINT:
                 case CM_SCACHETYPE_SYMLINK:
                 case CM_SCACHETYPE_INVALID:
-                    *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
+                    fa->extFileAttributes = SMB_ATTR_DIRECTORY;
                     break;
                 default:
                     /* if we get here we either have a normal file
@@ -3917,49 +4044,24 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                      * and odd means it is to be treated as a file.
                      */
                     if (mustFake && (scp->fid.vnode & 0x1))
-                        *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
+                        fa->extFileAttributes = SMB_ATTR_DIRECTORY;
                     else
-                        *((u_long *)dptr) = SMB_ATTR_NORMAL;
+                        fa->extFileAttributes = SMB_ATTR_NORMAL;
                         
                 }
                 /* merge in hidden attribute */
                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
-                    *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
+                    fa->extFileAttributes |= SMB_ATTR_HIDDEN;
                 }
-                dptr += 4;
             } else {
+                smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+
                 /* 1969-12-31 23:59:58 +00*/
                 dosTime = 0xEBBFBF7D;
 
-                /* and copy out date */
-                shortTemp = (dosTime>>16) & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-
-                /* copy out creation time */
-                shortTemp = dosTime & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-
-                /* and copy out date */
-                shortTemp = (dosTime>>16) & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-                       
-                /* copy out access time */
-                shortTemp = dosTime & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-
-                /* and copy out date */
-                shortTemp = (dosTime>>16) & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-                       
-                /* copy out mod time */
-                shortTemp = dosTime & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 10;
+                fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
+                fa->lastAccessDateTime = fa->creationDateTime;
+                fa->lastWriteDateTime = fa->creationDateTime;
 
                 /* set the attribute */
                 switch (scp->fileType) {
@@ -3967,16 +4069,14 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 case CM_SCACHETYPE_MOUNTPOINT:
                 case CM_SCACHETYPE_SYMLINK:
                 case CM_SCACHETYPE_INVALID:
-                    attr = SMB_ATTR_DIRECTORY;
+                    fa->attributes = SMB_ATTR_DIRECTORY;
                 default:
-                    attr = SMB_ATTR_NORMAL;
+                    fa->attributes = SMB_ATTR_NORMAL;
                 }
                 /* merge in hidden (dot file) attribute */
                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
-                    attr |= SMB_ATTR_HIDDEN;
+                    fa->attributes |= SMB_ATTR_HIDDEN;
                 }       
-                *dptr++ = attr & 0xff;
-                *dptr++ = (attr >> 8) & 0xff;
             }
             
             cm_ReleaseSCache(scp);
@@ -4009,33 +4109,20 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
 
         lock_ConvertWToR(&scp->rw);
 
-        dptr = patchp->dptr;
-
         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+            smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
+
             /* get filetime */
             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
 
-            /* copy to Creation Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
-
-            /* copy to Last Access Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
-
-            /* copy to Last Write Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
-
-            /* copy to Change Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
+            fa->creationTime = ft;
+            fa->lastAccessTime = ft;
+            fa->lastWriteTime = ft;
+            fa->lastChangeTime = ft;
 
             /* Use length for both file length and alloc length */
-            *((LARGE_INTEGER *)dptr) = scp->length;
-            dptr += 8;
-            *((LARGE_INTEGER *)dptr) = scp->length;
-            dptr += 8;
+            fa->endOfFile = scp->length;
+            fa->allocationSize = scp->length;
 
             /* Copy attributes */
             lattr = smb_ExtAttributes(scp);
@@ -4053,49 +4140,23 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 else
                     lattr |= SMB_ATTR_HIDDEN;
             }
-            *((u_long *)dptr) = lattr;
-            dptr += 4;
+
+            fa->extFileAttributes = lattr;
         } else {
+            smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+
             /* get dos time */
             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
 
-            /* and copy out date */
-            shortTemp = (dosTime>>16) & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* copy out creation time */
-            shortTemp = dosTime & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* and copy out date */
-            shortTemp = (dosTime>>16) & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* copy out access time */
-            shortTemp = dosTime & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* and copy out date */
-            shortTemp = (dosTime>>16) & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* copy out mod time */
-            shortTemp = dosTime & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
+            fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
+            fa->lastAccessDateTime = fa->creationDateTime;
+            fa->lastWriteDateTime = fa->creationDateTime;
 
             /* copy out file length and alloc length,
              * using the same for both
              */
-            *((u_long *)dptr) = scp->length.LowPart;
-            dptr += 4;
-            *((u_long *)dptr) = scp->length.LowPart;
-            dptr += 4;
+            fa->dataSize = scp->length.LowPart;
+            fa->allocationSize = scp->length.LowPart;
 
             /* finally copy out attributes as short */
             attr = smb_Attributes(scp);
@@ -4106,8 +4167,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 else
                     lattr |= SMB_ATTR_HIDDEN;
             }
-            *dptr++ = attr & 0xff;
-            *dptr++ = (attr >> 8) & 0xff;
+            fa->attributes = attr;
         }
 
         lock_ReleaseRead(&scp->rw);
@@ -4267,6 +4327,8 @@ int smb_V3MatchMask(char *namep, char *maskp, int flags)
    the usual mechanism. 
    
    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
+
+   TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
    */
 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
@@ -4277,16 +4339,16 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     int maxCount;
     smb_dirListPatch_t *dirListPatchesp;
     smb_dirListPatch_t *curPatchp;
-    long orbytes;                      /* # of bytes in this output record */
-    long ohbytes;                      /* # of bytes, except file name */
-    long onbytes;                      /* # of bytes in name, incl. term. null */
+    size_t orbytes;                    /* # of bytes in this output record */
+    size_t ohbytes;                    /* # of bytes, except file name */
+    size_t onbytes;                    /* # of bytes in name, incl. term. null */
     cm_scache_t *scp = NULL;
     cm_scache_t *targetscp = NULL;
     cm_user_t *userp = NULL;
     char *op;                          /* output data ptr */
     char *origOp;                      /* original value of op */
     cm_space_t *spacep;                        /* for pathname buffer */
-    long maxReturnData;                        /* max # of return data */
+    unsigned long maxReturnData;       /* max # of return data */
     long maxReturnParms;               /* max # of return parms */
     long bytesInBuffer;                        /* # data bytes in the output buffer */
     char *maskp;                       /* mask part of path */
@@ -4302,6 +4364,8 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     cm_dirEntry_t * dep = NULL;
     cm_req_t req;
     char * s;
+    void * attrp = NULL;
+    smb_tran2Find_t * fp;
 
     cm_InitReq(&req);
 
@@ -4317,7 +4381,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     maxCount = p->parmsp[1];
     infoLevel = p->parmsp[3];
     searchFlags = p->parmsp[2];
-    pathp = ((char *) p->parmsp) + 12; /* points to path */
+    pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
     nextCookie = 0;
     maskp = strrchr(pathp, '\\');
     if (maskp == NULL) 
@@ -4333,27 +4397,42 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     switch ( infoLevel ) {
     case SMB_INFO_STANDARD:
        s = "InfoStandard";
+        ohbytes = sizeof(fp->u.FstandardInfo);
        break;
+
     case SMB_INFO_QUERY_EA_SIZE:
+        ohbytes = sizeof(fp->u.FeaSizeInfo);
        s = "InfoQueryEaSize";
        break;
+
     case SMB_INFO_QUERY_EAS_FROM_LIST:
+        ohbytes = sizeof(fp->u.FeasFromListInfo);
        s = "InfoQueryEasFromList";
        break;
+
     case SMB_FIND_FILE_DIRECTORY_INFO:
        s = "FindFileDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileDirectoryInfo);
        break;
+
     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
        s = "FindFileFullDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
        break;
+
     case SMB_FIND_FILE_NAMES_INFO:
        s = "FindFileNamesInfo";
+        ohbytes = sizeof(fp->u.FfileNamesInfo);
        break;
+
     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
        s = "FindFileBothDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
        break;
+
     default:
        s = "unknownInfoLevel";
+        ohbytes = 0;
     }
 
     osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
@@ -4362,7 +4441,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
              attribute, infoLevel, maxCount, searchFlags);
     
-    if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+    if (ohbytes == 0) {
         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
         return CM_ERROR_INVAL;
     }
@@ -4370,6 +4449,9 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;    /* no resume keys */
 
+    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+        ohbytes += 4;
+
     dirListPatchesp = NULL;
 
     maxReturnData = p->maxReturnData;
@@ -4478,6 +4560,8 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         op += 4;
     }
 
+    fp = (smb_tran2Find_t *) op;
+
     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
         && targetscp->fid.vnode != 0
         && !cm_Is8Dot3(maskp)) {
@@ -4520,29 +4604,10 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
     }
 
-    /* Check if the name will fit */
-    if (infoLevel < 0x101)
-        ohbytes = 23;           /* pre-NT */
-    else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-        ohbytes = 12;           /* NT names only */
-    else
-        ohbytes = 64;           /* NT */
-
-    if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
-        ohbytes += 26;          /* Short name & length */
-
-    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
-        ohbytes += 4;           /* if resume key required */
-    }
-
-    if (infoLevel != SMB_INFO_STANDARD
-        && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
-        && infoLevel != SMB_FIND_FILE_NAMES_INFO)
-        ohbytes += 4;           /* EASIZE */
-
     /* add header to name & term. null */
-    onbytes = (int)strlen(maskp);
-    orbytes = ohbytes + onbytes + 1;
+    onbytes = 0;
+    smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH);
+    orbytes = ohbytes + onbytes;
 
     /* now, we round up the record to a 4 byte alignment, and we make
      * sure that we have enough room here for even the aligned version
@@ -4570,42 +4635,80 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
      * preceded by its length.
      */
     /* First zero everything else */
-    memset(origOp, 0, ohbytes);
+    memset(origOp, 0, orbytes);
 
-    if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
-        *(origOp + ohbytes - 1) = (unsigned char) onbytes;
-    else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-        *((u_long *)(op + 8)) = onbytes;
-    else
-        *((u_long *)(op + 60)) = onbytes;
-    strcpy(origOp+ohbytes, maskp);
-    if (smb_StoreAnsiFilenames)
-        CharToOem(origOp+ohbytes, origOp+ohbytes);
+    onbytes = 0;
+    smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH);
 
-    /* Short name if requested and needed */
-    if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+    switch (infoLevel) {
+    case SMB_INFO_STANDARD:
+        fp->u.FstandardInfo.fileNameLength = onbytes;
+        attrp = &fp->u.FstandardInfo.fileAttrs;
+        break;
+
+    case SMB_INFO_QUERY_EA_SIZE:
+        fp->u.FeaSizeInfo.fileNameLength = onbytes;
+        attrp = &fp->u.FeaSizeInfo.fileAttrs;
+        fp->u.FeaSizeInfo.eaSize = 0;
+        break;
+
+    case SMB_INFO_QUERY_EAS_FROM_LIST:
+        fp->u.FeasFromListInfo.fileNameLength = onbytes;
+        attrp = &fp->u.FeasFromListInfo.fileAttrs;
+        fp->u.FeasFromListInfo.eaSize = 0;
+        break;
+
+    case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
         if (NeedShortName) {
-            strcpy(op + 70, shortName);
-            if (smb_StoreAnsiFilenames)
-                CharToOem(op + 70, op + 70);
-            *(op + 68) = (char)(shortNameEnd - shortName);
-        }
+#ifdef SMB_UNICODE
+            int nchars;
+
+            nchars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
+                                         shortName, -1,
+                                         fp->u.FfileBothDirectoryInfo.shortName,
+                                         sizeof(fp->u.FfileBothDirectoryInfo.shortName) / sizeof(wchar_t));
+            if (nchars > 0)
+                fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
+            else
+                fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
+            fp->u.FfileBothDirectoryInfo.reserved = 0;
+#else
+            strcpy(fp->u.FfileBothDirectoryInfo.shortName,
+                   shortName);
+            fp->u.FfileBothDirectoryInfo.shortNameLength = strlen(shortName);
+#endif
     }
+        /* Fallthrough */
+
+    case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+        fp->u.FfileFullDirectoryInfo.eaSize = 0;
+        /* Fallthrough */
+
+    case SMB_FIND_FILE_DIRECTORY_INFO:
+        fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
+        fp->u.FfileDirectoryInfo.fileIndex = 0;
+        attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
+        fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
+        break;
+
+    case SMB_FIND_FILE_NAMES_INFO:
+        fp->u.FfileNamesInfo.nextEntryOffset = 0;
+        fp->u.FfileNamesInfo.fileIndex = 0;
+        fp->u.FfileNamesInfo.fileNameLength = onbytes;
+        break;
 
-    /* NextEntryOffset and FileIndex */
-    if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
-        int entryOffset = orbytes + align;
-        *((u_long *)op) = 0;
-        *((u_long *)(op+4)) = 0;
+    default:
+        /* we shouldn't hit this case */
+        osi_assertx(FALSE, "Unknown query type");
     }
 
     if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+        osi_assert(attrp != NULL);
+
         curPatchp = malloc(sizeof(*curPatchp));
         osi_QAdd((osi_queue_t **) &dirListPatchesp,
                  &curPatchp->q);
-        curPatchp->dptr = op;
-        if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
-            curPatchp->dptr += 8;
+        curPatchp->dptr = attrp;
 
         if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
             curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
@@ -4674,6 +4777,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 }
 
 
+/* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     int attribute;
@@ -4687,9 +4791,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     smb_dirListPatch_t *curPatchp = 0;
     cm_buf_t *bufferp;
     long temp;
-    long orbytes;                      /* # of bytes in this output record */
-    long ohbytes;                      /* # of bytes, except file name */
-    long onbytes;                      /* # of bytes in name, incl. term. null */
+    size_t orbytes;                    /* # of bytes in this output record */
+    size_t ohbytes;                    /* # of bytes, except file name */
+    size_t onbytes;                    /* # of bytes in name, incl. term. null */
     osi_hyper_t dirLength;
     osi_hyper_t bufferOffset;
     osi_hyper_t curOffset;
@@ -4707,8 +4811,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     char *op;                  /* output data ptr */
     char *origOp;                      /* original value of op */
     cm_space_t *spacep;                /* for pathname buffer */
-    long maxReturnData;                /* max # of return data */
-    long maxReturnParms;               /* max # of return parms */
+    unsigned long maxReturnData;               /* max # of return data */
+    unsigned long maxReturnParms;              /* max # of return parms */
     long bytesInBuffer;                /* # data bytes in the output buffer */
     int starPattern;
     char *maskp;                       /* mask part of path */
@@ -4717,7 +4821,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     int eos;
     smb_tran2Packet_t *outp;   /* response packet */
     char *tidPathp;
-    int align;
+    unsigned int align;
     char shortName[13];                /* 8.3 name if needed */
     int NeedShortName;
     int foundInexact;
@@ -4725,7 +4829,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     int fileType;
     cm_fid_t fid;
     cm_req_t req;
+    void * attrp;
     char * s;
+    smb_tran2Find_t * fp;
 
     cm_InitReq(&req);
 
@@ -4736,9 +4842,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         maxCount = p->parmsp[1];
         infoLevel = p->parmsp[3];
         searchFlags = p->parmsp[2];
-        pathp = ((char *) p->parmsp) + 12;     /* points to path */
-        if (smb_StoreAnsiFilenames)
-            OemToChar(pathp,pathp);
+        pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
         nextCookie = 0;
         maskp = strrchr(pathp, '\\');
         if (maskp == NULL) 
@@ -4766,7 +4870,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 return code;
             }
         }
-#endif
+#endif  /* NOFINDFIRSTOPTIMIZE */
         dir_enums++;
 
         dsp = smb_NewDirSearch(1);
@@ -4795,27 +4899,42 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     switch ( infoLevel ) {
     case SMB_INFO_STANDARD:
        s = "InfoStandard";
+        ohbytes = sizeof(fp->u.FstandardInfo);
        break;
+
     case SMB_INFO_QUERY_EA_SIZE:
+        ohbytes = sizeof(fp->u.FeaSizeInfo);
        s = "InfoQueryEaSize";
        break;
+
     case SMB_INFO_QUERY_EAS_FROM_LIST:
+        ohbytes = sizeof(fp->u.FeasFromListInfo);
        s = "InfoQueryEasFromList";
        break;
+
     case SMB_FIND_FILE_DIRECTORY_INFO:
        s = "FindFileDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileDirectoryInfo);
        break;
+
     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
        s = "FindFileFullDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
        break;
+
     case SMB_FIND_FILE_NAMES_INFO:
        s = "FindFileNamesInfo";
+        ohbytes = sizeof(fp->u.FfileNamesInfo);
        break;
+
     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
        s = "FindFileBothDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
        break;
+
     default:
        s = "unknownInfoLevel";
+        ohbytes = 0;
     }
 
     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
@@ -4827,7 +4946,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
               p->opcode, dsp->cookie, nextCookie);
 
-    if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+    if (ohbytes == 0) {
         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
         smb_ReleaseDirSearch(dsp);
         return CM_ERROR_INVAL;
@@ -4836,6 +4955,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;    /* no resume keys */
 
+    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+        ohbytes += 4;
+
     dirListPatchesp = NULL;
 
     maxReturnData = p->maxReturnData;
@@ -4981,6 +5103,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             /* skip over resume key */
             op += 4;
 
+        fp = (smb_tran2Find_t *) op;
+
         /* make sure that curOffset.LowPart doesn't point to the first
          * 32 bytes in the 2nd through last dir page, and that it doesn't
          * point at the first 13 32-byte chunks in the first dir page,
@@ -5189,29 +5313,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             }
 
             /* finally check if this name will fit */
-
-            /* standard dir entry stuff */
-            if (infoLevel < 0x101)
-                ohbytes = 23;  /* pre-NT */
-            else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-                ohbytes = 12;  /* NT names only */
-            else
-                ohbytes = 64;  /* NT */
-
-            if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
-                ohbytes += 26; /* Short name & length */
-
-            if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
-                ohbytes += 4;  /* if resume key required */
-            }   
-
-            if ( infoLevel != SMB_INFO_STANDARD && 
-                 infoLevel != SMB_FIND_FILE_DIRECTORY_INFO &&
-                 infoLevel != SMB_FIND_FILE_NAMES_INFO)
-                ohbytes += 4;  /* EASIZE */
-
-            /* add header to name & term. null */
-            orbytes = onbytes + ohbytes + 1;
+            onbytes = 0;
+            smb_UnparseString(opx, NULL, dep->name, &onbytes, SMB_STRF_ANSIPATH);
+            orbytes = ohbytes + onbytes;
 
             /* now, we round up the record to a 4 byte alignment,
              * and we make sure that we have enough room here for
@@ -5223,6 +5327,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 align = (4 - (orbytes & 3)) & 3;
             else
                 align = 0;
+
             if (orbytes + bytesInBuffer + align > maxReturnData) {
                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
                           maxReturnData);
@@ -5234,38 +5339,77 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              * Put out the name, preceded by its length.
              */
             /* First zero everything else */
-            memset(origOp, 0, ohbytes);
+            memset(origOp, 0, orbytes);
 
-            if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
-                *(origOp + ohbytes - 1) = (unsigned char) onbytes;
-            else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-                *((u_long *)(op + 8)) = onbytes;
-            else
-                *((u_long *)(op + 60)) = onbytes;
-            strcpy(origOp+ohbytes, dep->name);
-            if (smb_StoreAnsiFilenames)
-                CharToOem(origOp+ohbytes, origOp+ohbytes);
+            onbytes = 0;
+            smb_UnparseString(opx, origOp + ohbytes, dep->name, &onbytes, SMB_STRF_ANSIPATH);
 
-            /* Short name if requested and needed */
-            if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+            switch (infoLevel) {
+            case SMB_INFO_STANDARD:
+                fp->u.FstandardInfo.fileNameLength = onbytes;
+                attrp = &fp->u.FstandardInfo.fileAttrs;
+                break;
+
+            case SMB_INFO_QUERY_EA_SIZE:
+                fp->u.FeaSizeInfo.fileNameLength = onbytes;
+                attrp = &fp->u.FeaSizeInfo.fileAttrs;
+                fp->u.FeaSizeInfo.eaSize = 0;
+                break;
+
+            case SMB_INFO_QUERY_EAS_FROM_LIST:
+                fp->u.FeasFromListInfo.fileNameLength = onbytes;
+                attrp = &fp->u.FeasFromListInfo.fileAttrs;
+                fp->u.FeasFromListInfo.eaSize = 0;
+                break;
+
+            case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
                 if (NeedShortName) {
-                    strcpy(op + 70, shortName);
-                    if (smb_StoreAnsiFilenames)
-                        CharToOem(op + 70, op + 70);
-                    *(op + 68) = (char)(shortNameEnd - shortName);
+#ifdef SMB_UNICODE
+                    int nchars;
+
+                    nchars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
+                                                 shortName, -1,
+                                                 fp->u.FfileBothDirectoryInfo.shortName,
+                                                 sizeof(fp->u.FfileBothDirectoryInfo.shortName) / sizeof(wchar_t));
+                    if (nchars > 0)
+                        fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
+                    else
+                        fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
+                    fp->u.FfileBothDirectoryInfo.reserved = 0;
+#else
+                    strcpy(fp->u.FfileBothDirectoryInfo.shortName,
+                           shortName);
+                    fp->u.FfileBothDirectoryInfo.shortNameLength = strlen(shortName);
+#endif
                 }
+                /* Fallthrough */
+
+            case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+                fp->u.FfileFullDirectoryInfo.eaSize = 0;
+                /* Fallthrough */
+
+            case SMB_FIND_FILE_DIRECTORY_INFO:
+                fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
+                fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
+                attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
+                fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
+                break;
+
+            case SMB_FIND_FILE_NAMES_INFO:
+                fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
+                fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
+                fp->u.FfileNamesInfo.fileNameLength = onbytes;
+                attrp = NULL;
+                break;
+
+            default:
+                /* we shouldn't hit this case */
+                osi_assertx(FALSE, "Unknown query type");
             }
 
             /* now, adjust the # of entries copied */
             returnedNames++;
 
-            /* NextEntryOffset and FileIndex */
-            if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
-                int entryOffset = orbytes + align;
-                *((u_long *)op) = entryOffset;
-                *((u_long *)(op+4)) = nextEntryCookie;
-            }
-
             /* now we emit the attribute.  This is tricky, since
              * we need to really stat the file to find out what
              * type of entry we've got.  Right now, we're copying
@@ -5280,17 +5424,16 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              * safe to unlock the directory.
              */
             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+                osi_assert(attrp != NULL);
                 curPatchp = malloc(sizeof(*curPatchp));
                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
-                curPatchp->dptr = op;
-                if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
-                    curPatchp->dptr += 8;
+                curPatchp->dptr = attrp;
 
                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
-                }       
-                else    
+                } else {
                     curPatchp->flags = 0;
+                }
 
                 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
 
@@ -5307,7 +5450,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             bytesInBuffer += orbytes;
 
             /* and pad the record out */
-            while (--align >= 0) {
+            while (align-- > 0) {
                 *origOp++ = 0;
                 bytesInBuffer++;
             }
@@ -5408,6 +5551,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return 0;
 }
 
+/* SMB_COM_FIND_CLOSE2 */
 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int dirHandle;
@@ -5432,12 +5576,15 @@ long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     return 0;
 }
 
+
+/* SMB_COM_FIND_NOTIFY_CLOSE */
 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_SetSMBDataLength(outp, 0);
     return 0;
 }
 
+/* SMB_COM_OPEN_ANDX */
 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp;
@@ -5452,7 +5599,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_fid_t *fidp;
     int attributes;
     char *lastNamep;
-    afs_uint32 dosTime;
+    unsigned long dosTime;
     int openFun;
     int trunc;
     int openMode;
@@ -5482,9 +5629,8 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (attributes & SMB_ATTR_READONLY) 
        initialModeBits &= ~0222;
         
-    pathp = smb_GetSMBData(inp, NULL);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
+                                SMB_STRF_ANSIPATH);
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
@@ -5785,6 +5931,7 @@ static void smb_GetLockParams(unsigned char LockType,
     }
 }
 
+/* SMB_COM_LOCKING_ANDX */
 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     cm_req_t req;
@@ -6079,6 +6226,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return code;
 }
 
+/* SMB_COM_QUERY_INFORMATION2 */
 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -6166,6 +6314,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     return code;
 }       
 
+/* SMB_COM_SET_INFORMATION2 */
 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -6235,6 +6384,7 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     return code;
 }
 
+/* SMB_COM_WRITE_ANDX */
 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -6369,6 +6519,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return code;
 }
 
+/* SMB_COM_READ_ANDX */
 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -6523,6 +6674,7 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #define FILE_DELETE_ON_CLOSE      0x1000
 #define FILE_OPEN_BY_FILE_ID      0x2000
 
+/* SMB_COM_NT_CREATE_ANDX */
 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp, *realPathp;
@@ -6619,13 +6771,16 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (extAttributes & SMB_ATTR_READONLY) 
         initialModeBits &= ~0222;
 
-    pathp = smb_GetSMBData(inp, NULL);
+    if (nameLength == 0)
+        return CM_ERROR_INVAL;
+
+    pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
+                              NULL, SMB_STRF_ANSIPATH);
+
     /* Sometimes path is not null-terminated, so we make a copy. */
     realPathp = malloc(nameLength+1);
     memcpy(realPathp, pathp, nameLength);
     realPathp[nameLength] = 0;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(realPathp,realPathp);
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
@@ -7357,6 +7512,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
  * Instead, ultimately, would like to use a subroutine for common code.
  */
+
+/* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp, *realPathp;
@@ -7466,13 +7623,11 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         initialModeBits &= ~0222;
 
     pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
+    pathp = smb_ParseStringCch(inp, pathp, nameLength, NULL, SMB_STRF_ANSIPATH);
     /* Sometimes path is not null-terminated, so we make a copy. */
     realPathp = malloc(nameLength+1);
     memcpy(realPathp, pathp, nameLength);
     realPathp[nameLength] = 0;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(realPathp,realPathp);
-
     spacep = cm_GetSpace();
     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
 
@@ -8095,6 +8250,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     return 0;
 }
 
+/* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
        smb_packet_t *outp)
 {
@@ -8193,6 +8349,7 @@ unsigned char nullSecurityDesc[36] = {
                                         /* "null SID" group SID */
 };      
 
+/* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int parmOffset, parmCount, dataOffset, dataCount;
@@ -8261,6 +8418,10 @@ long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_pa
         return CM_ERROR_BUFFERTOOSMALL;
 }
 
+/* SMB_COM_NT_TRANSACT
+
+   SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
+ */
 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short function;
@@ -8274,20 +8435,20 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
         
     switch (function) {
-    case 1: 
+    case 1:                     /* NT_TRANSACT_CREATE */
         return smb_ReceiveNTTranCreate(vcp, inp, outp);
-    case 2:
+    case 2:                     /* NT_TRANSACT_IOCTL */
        osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
        break;
-    case 3:
+    case 3:                     /* NT_TRANSACT_SET_SECURITY_DESC */
        osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
        break;
-    case 4:
+    case 4:                     /* NT_TRANSACT_NOTIFY_CHANGE */
         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
-    case 5:
+    case 5:                     /* NT_TRANSACT_RENAME */
        osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
        break;
-    case 6:
+    case 6:                     /* NT_TRANSACT_QUERY_SECURITY_DESC */
         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
     case 7:
         osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
@@ -8530,6 +8691,7 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
 }       
 
+/* SMB_COM_NT_CANCEL */
 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned char *replyWctp;
@@ -8628,12 +8790,8 @@ long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 
     tp = smb_GetSMBData(inp, NULL);
-    oldPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(oldPathp,oldPathp);
-    newPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(newPathp,newPathp);
+    oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
+    newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
 
     osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
              osi_LogSaveString(smb_logp, oldPathp),
index 2ab214a..99209df 100644 (file)
@@ -30,10 +30,12 @@ typedef struct smb_tran2Packet {
        unsigned short res[6];          /* contains PidHigh */
         unsigned short *parmsp;                /* parms */
         unsigned char *datap;          /* data bytes */
+        cm_space_t * stringsp;          /* decoded strings */
 } smb_tran2Packet_t;
 
 /* for flags field */
 #define SMB_TRAN2PFLAG_ALLOC   1
+#define SMB_TRAN2PFLAG_USEUNICODE  2
 
 typedef struct smb_tran2Dispatch {
        long (*procp)(smb_vc_t *, smb_tran2Packet_t *, smb_packet_t *);
@@ -56,14 +58,14 @@ typedef struct smb_tran2QFSInfo {
         struct {
             unsigned long vsn;                 /* volume serial number */
             char vnCount;                      /* count of chars in label, incl null */
-            char label[12];                    /* pad out with nulls */
+            char /* STRING */ label[24];        /* pad out with nulls */
         } volumeInfo;
         struct {
             FILETIME      vct;         /* volume creation time */
             unsigned long vsn;         /* volume serial number */
             unsigned long vnCount;     /* length of volume label in bytes */
             char res[2];               /* reserved */
-            char label[10];            /* volume label */
+            char /* STRING */ label[20];       /* volume label */
         } FSvolumeInfo;
         struct {
             LARGE_INTEGER totalAllocUnits;     /* on the disk */
@@ -79,7 +81,7 @@ typedef struct smb_tran2QFSInfo {
             unsigned long attributes;
             unsigned long maxCompLength;       /* max path component length */
             unsigned long FSnameLength;                /* length of file system name */
-            unsigned char FSname[12];
+            unsigned char /* STRING */ FSname[24]; /* File system name */
         } FSattributeInfo;
     } u;
 } smb_tran2QFSInfo_t;
@@ -137,7 +139,7 @@ typedef struct {
        } QPfileEaInfo;
        struct {
            unsigned long  fileNameLength;
-           unsigned char  fileName[512];
+           unsigned char  fileName[512]; /* STRING */
        } QPfileNameInfo;
        struct {
            FILETIME       creationTime;
@@ -158,18 +160,18 @@ typedef struct {
            unsigned long  mode;
            unsigned long  alignmentRequirement;
            unsigned long  fileNameLength;
-           unsigned char  fileName[512];
+           unsigned char  fileName[512]; /* STRING */
        } QPfileAllInfo;
        struct {
            unsigned long  fileNameLength;
-           unsigned char  fileName[512];
+           unsigned char  fileName[512]; /* STRING */
        } QPfileAltNameInfo;
        struct {
            unsigned long  nextEntryOffset;
            unsigned long  streamNameLength;
            LARGE_INTEGER  streamSize;
            LARGE_INTEGER  streamAllocationSize;
-           unsigned char  fileName[512];
+           unsigned char  fileName[512]; /* STRING */
        } QPfileStreamInfo;
        struct {
            LARGE_INTEGER  compressedFileSize;
@@ -207,6 +209,79 @@ typedef struct {
        } QFfileNameInfo;
     } u;
 } smb_tran2QFileInfo_t;
+
+typedef struct {
+    unsigned long  creationDateTime;   /* SMB_DATE / SMB_TIME */
+    unsigned long  lastAccessDateTime; /* SMB_DATE / SMB_TIME */
+    unsigned long  lastWriteDateTime;  /* SMB_DATE / SMB_TIME */
+    unsigned long  dataSize;
+    unsigned long  allocationSize;
+    unsigned short attributes;
+} smb_V3FileAttrsShort;
+
+typedef struct {
+    FILETIME       creationTime;
+    FILETIME       lastAccessTime;
+    FILETIME       lastWriteTime;
+    FILETIME       lastChangeTime;
+    LARGE_INTEGER  endOfFile;
+    LARGE_INTEGER  allocationSize;
+    unsigned long  extFileAttributes;
+} smb_V3FileAttrsLong;
+
+typedef struct {
+    union {
+       struct {
+            smb_V3FileAttrsShort fileAttrs;
+           unsigned char  fileNameLength;
+            /* STRING fileName */
+       } FstandardInfo;
+
+       struct {
+            smb_V3FileAttrsShort fileAttrs;
+           unsigned long  eaSize;
+            unsigned char  fileNameLength;
+            /* STRING fileName */
+       } FeaSizeInfo, FeasFromListInfo;
+
+        struct {
+            unsigned long  nextEntryOffset;
+            unsigned long  fileIndex;
+            smb_V3FileAttrsLong fileAttrs;
+            unsigned long  fileNameLength;
+            /* STRING fileName */
+        } FfileDirectoryInfo;
+
+        struct {
+            unsigned long  nextEntryOffset;
+            unsigned long  fileIndex;
+            smb_V3FileAttrsLong fileAttrs;
+            unsigned long  fileNameLength;
+            unsigned long  eaSize;
+            /* STRING fileName */
+        } FfileFullDirectoryInfo;
+
+        struct {
+            unsigned long  nextEntryOffset;
+            unsigned long  fileIndex;
+            smb_V3FileAttrsLong fileAttrs;
+            unsigned long  fileNameLength;
+            unsigned long  eaSize;
+            unsigned char  shortNameLength;
+            unsigned char  reserved;
+            wchar_t        shortName[12];
+            /* STRING fileName */
+        } FfileBothDirectoryInfo;
+
+        struct {
+            unsigned long  nextEntryOffset;
+            unsigned long  fileIndex;
+            unsigned long  fileNameLength;
+            /* STRING fileName */
+        } FfileNamesInfo;
+    } u;
+} smb_tran2Find_t;
+
 #pragma pack(pop)
 
 /* more than enough opcodes for today, anyway */
index bf23849..8f73dac 100644 (file)
@@ -94,6 +94,7 @@ struct sbstruct {
 #define VIOC_UUIDCTL                    0x30
 #define VIOC_PATH_AVAILABILITY          0x31
 #define VIOC_GETFILETYPE                0x32
+#define VIOC_UNICODECTL                 0x33
 
 #define VIOC_VOLSTAT_TEST               0x3F
 /* Not to exceed SMB_IOCTL_MAXPROCS from smb_ioctl.h */
index 7f3715e..76a9d25 100644 (file)
@@ -82,6 +82,7 @@ void smb_InitIoctl(void)
         smb_ioctlProcsp[VIOC_PATH_AVAILABILITY] = cm_IoctlPathAvailability;
         smb_ioctlProcsp[VIOC_GETFILETYPE] = cm_IoctlGetFileType;
         smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = cm_IoctlVolStatTest;
+        smb_ioctlProcsp[VIOC_UNICODECTL] = cm_IoctlUnicodeControl;
 }
 
 /* called to make a fid structure into an IOCTL fid structure */
index 72da4c0..d9de596 100644 (file)
@@ -68,7 +68,7 @@ static int InAFS(register char *apath)
     blob.out_size = MAXSIZE;
     blob.out = space;
 
-    code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
+    code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
     if (code) {
        if ((errno == EINVAL) || (errno == ENOENT)) 
             return 0;
@@ -86,7 +86,7 @@ IsFreelanceRoot(char *apath)
     blob.out_size = MAXSIZE;
     blob.out = space;
 
-    code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
+    code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
     if (code == 0)
         return !stricmp("Freelance.Local.Root",space);
     return 1;   /* assume it is because it is more restrictive that way */
@@ -399,7 +399,7 @@ static ListLinkCmd(register struct cmd_syndesc *as, void *arock)
        blob.out = space;
        memset(space, 0, MAXSIZE);
 
-       code = pioctl(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
+       code = pioctl_utf8(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
 
        if (code == 0)
            printf("'%s' is a %ssymlink to '%s'\n",
@@ -460,6 +460,8 @@ static MakeLinkCmd(register struct cmd_syndesc *as, void *arock)
        return 1;
     }
 
+    fprintf(stderr, "Creating symlink [%s] to [%s]\n", path, as->parms[1].items->data);
+
     /* create symlink with a special pioctl for Windows NT, since it doesn't
      * have a symlink system call.
      */
@@ -467,7 +469,7 @@ static MakeLinkCmd(register struct cmd_syndesc *as, void *arock)
     blob.in_size = 1 + (long)strlen(as->parms[1].items->data);
     blob.in = as->parms[1].items->data;
     blob.out = NULL;
-    code = pioctl(path, VIOC_SYMLINK, &blob, 0);
+    code = pioctl_utf8(path, VIOC_SYMLINK, &blob, 0);
 #else /* not WIN32 */
     code = symlink(as->parms[1].items->data, path);
 #endif /* not WIN32 */
@@ -528,7 +530,7 @@ static RemoveLinkCmd(register struct cmd_syndesc *as, void *arock)
        blob.in_size = (int)strlen(tp)+1;
        blob.out = lsbuffer;
        blob.out_size = sizeof(lsbuffer);
-       code = pioctl(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
+       code = pioctl_utf8(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
        if (code) {
            if (errno == EINVAL)
                fprintf(stderr,"symlink: '%s' is not a symlink.\n", ti->data);
@@ -547,7 +549,7 @@ static RemoveLinkCmd(register struct cmd_syndesc *as, void *arock)
        blob.out_size = 0;
        blob.in = tp;
        blob.in_size = (long)strlen(tp)+1;
-       code = pioctl(tbuffer, VIOC_DELSYMLINK, &blob, 0);
+       code = pioctl_utf8(tbuffer, VIOC_DELSYMLINK, &blob, 0);
        if (code) {
            Die(errno, ti->data);
        }
@@ -555,14 +557,58 @@ static RemoveLinkCmd(register struct cmd_syndesc *as, void *arock)
     return code;
 }
 
+static void
+FreeUtf8CmdLine(int argc, char ** argv)
+{
+    int i;
+    for (i=0; i < argc; i++) {
+        if (argv[i])
+            free(argv[i]);
+    }
+    free(argv);
+}
+
+static char **
+MakeUtf8Cmdline(int argc, const wchar_t **wargv)
+{
+    char ** argv;
+    int i;
+
+    argv = calloc(argc, sizeof(argv[0]));
+    if (argv == NULL)
+        return NULL;
+
+    for (i=0; i < argc; i++) {
+        int s;
+
+        s = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, FALSE);
+        if (s == 0 ||
+            (argv[i] = calloc(s+1, sizeof(char))) == NULL) {
+            break;
+        }
+
+        s = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], s+1, NULL, FALSE);
+        if (s == 0) {
+            break;
+        }
+    }
+
+    if (i < argc) {
+        FreeUtf8CmdLine(argc, argv);
+        return NULL;
+    }
+
+    return argv;
+}
+
 static    struct ViceIoctl gblob;
 static int debug = 0;
 
-main(argc, argv)
-int argc;
-char **argv; {
+int wmain(int argc, wchar_t **wargv)
+{
     register afs_int32 code;
     register struct cmd_syndesc *ts;
+    char ** argv;
     
 #ifdef AFS_AIX32_ENV
     /*
@@ -586,6 +632,7 @@ char **argv; {
 
     /* try to find volume location information */
     
+    argv = MakeUtf8Cmdline(argc, wargv);
 
     osi_Init();
 
@@ -606,6 +653,8 @@ char **argv; {
     if (rxInitDone) rx_Finalize();
 #endif /* not WIN32 */
     
+    FreeUtf8CmdLine(argc, argv);
+    
     return code;
 }
 
index a9edeb9..a6bed8e 100644 (file)
@@ -24,6 +24,9 @@ extern "C" {
 extern "C" {
 #include "WINNT\afsreg.h"
 }
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+
 #ifdef _DEBUG
 #define new DEBUG_NEW
 #undef THIS_FILE
@@ -75,8 +78,10 @@ HINSTANCE g_hInstance;
 
 BOOL CAfsShlExt::InitInstance()
 {
+    extern EXPORTED HINSTANCE TaLocale_LoadCorrespondingModuleByName (HINSTANCE hInstance, LPSTR pszFilename, WORD wSearchPriority = MODULE_PRIORITY_BOOSTED);
+
     // Load our translated resources
-    TaLocale_LoadCorrespondingModuleByName (m_hInstance, TEXT("afs_shl_ext.dll"));
+    TaLocale_LoadCorrespondingModuleByName (m_hInstance, "afs_shl_ext.dll");
 
     // Register all OLE server (factories) as running.  This enables the
     //  OLE libraries to create objects from other applications.
@@ -115,8 +120,12 @@ STDAPI DllCanUnloadNow(void)
 
 int WideCharToLocal(LPTSTR pLocal, LPCWSTR pWide, DWORD dwChars)
 {
+#ifdef UNICODE
+    StringCchCopy(pLocal, dwChars, pWide);
+#else
     *pLocal = 0;
     WideCharToMultiByte( CP_ACP, 0, pWide, -1, pLocal, dwChars, NULL, NULL);
+#endif
     return lstrlen(pLocal);
 }
 
@@ -155,14 +164,12 @@ STDAPI DllRegisterServer(void)
     StringFromIID(IID_IShellExt, &pwsz);
     if(pwsz)
     {
+#ifdef UNICODE
+        StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
+#else
        WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
-       LPMALLOC pMalloc;
-       CoGetMalloc(1, &pMalloc);
-       if(pMalloc)
-       {
-           (pMalloc->Free)(pwsz);
-           (pMalloc->Release)();
-       }
+#endif
+        CoTaskMemFree(pwsz);
     } else {
        return E_FAIL;
     }
@@ -172,14 +179,15 @@ STDAPI DllRegisterServer(void)
     @="Y:\\DEST\\root.client\\usr\\vice\\etc\\afs_shl_ext.dll"
     "ThreadingModel"="Apartment"
     */
-    HMODULE hModule=GetModuleHandle("afs_shl_ext.dll");
+    HMODULE hModule=GetModuleHandle(TEXT("afs_shl_ext.dll"));
     DWORD z=GetModuleFileName(hModule,szModule,sizeof(szModule));
     wsprintf(szSubKey, TEXT("CLSID\\%s\\InprocServer32"),szCLSID);
     if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,szModule))!=NOERROR)
        return lResult;
 
     wsprintf(szSubKey, TEXT("CLSID\\%s\\InprocServer32"),szCLSID);
-    if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,"Apartment","ThreadingModel"))!=NOERROR)
+    if ((lResult=DoRegCLSID(HKEY_CLASSES_ROOT,szSubKey,
+                            TEXT("Apartment"),TEXT("ThreadingModel")))!=NOERROR)
        return lResult;
 
     /*
@@ -206,7 +214,7 @@ STDAPI DllRegisterServer(void)
     if(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
     {
         wsprintf(szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));
-        if ((lResult=DoRegCLSID(HKEY_LOCAL_MACHINE,szSubKey,STR_EXT_TITLE,szCLSID))!=NOERROR)
+        if ((lResult=DoRegCLSID(HKEY_LOCAL_MACHINE,szSubKey,_TEXT(STR_EXT_TITLE),szCLSID))!=NOERROR)
             return lResult;
     }
     wsprintf(szSubKey, TEXT("*\\shellex\\ContextMenuHandlers\\%s"),STR_EXT_TITLE);
@@ -276,7 +284,7 @@ STDAPI DllRegisterServer(void)
            TCHAR szData[MAX_PATH];
 
            //Create the value string.
-           lstrcpy(szData, STR_EXT_TITLE);
+           lstrcpy(szData, _TEXT(STR_EXT_TITLE));
 
            lResult = RegSetValueEx( hKey,
                                     szCLSID,
@@ -325,14 +333,12 @@ STDAPI DllUnregisterServer(void)
     StringFromIID(IID_IShellExt, &pwsz);
     if(pwsz)
     {
+#ifdef UNICODE
+        StringCbCopy(szCLSID, sizeof(szCLSID), pwsz);
+#else
        WideCharToMultiByte( CP_ACP, 0,pwsz, -1, szCLSID, sizeof(szCLSID), NULL, NULL);
-       LPMALLOC pMalloc;
-       CoGetMalloc(1, &pMalloc);
-       if(pMalloc)
-       {
-           (pMalloc->Free)(pwsz);
-           (pMalloc->Release)();
-       }
+#endif
+        CoTaskMemFree(pwsz);
     } else {
        return E_FAIL;
     }
index 04439c8..f334cd8 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include "stdafx.h"
+#include <shlwapi.h>
 #include <winsock2.h>
 #include <ws2tcpip.h>
 
@@ -72,7 +73,7 @@ void CCopyAclDlg::OnOK()
        m_bClear = m_Clear.GetCheck() == 1;
        m_ToDir.GetWindowText(m_strToDir);
        
-       if (access(m_strToDir, 0) == -1) {
+       if (PathIsDirectory(m_strToDir) == -1) {
                ShowMessageBox(IDS_DIR_DOES_NOT_EXIST_ERROR, MB_ICONEXCLAMATION, IDS_DIR_DOES_NOT_EXIST_ERROR, m_strToDir);
                return;
        }
@@ -100,7 +101,7 @@ void CCopyAclDlg::OnChangeToDir()
 
 void CCopyAclDlg::OnBrowse() 
 {
-       CFileDialog dlg(TRUE, 0, "*.*", OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY, 0, 0);
+    CFileDialog dlg(TRUE, 0, TEXT("*.*"), OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY, 0, 0);
 
        if (dlg.DoModal() == IDCANCEL)
                return;
index 9c1d3b7..13950a1 100644 (file)
@@ -41,6 +41,9 @@ extern "C" {
 #include <cm.h>
 }
 
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+
 #define PCCHAR(str)            ((char *)(const char *)(str))
 #define VL_NOENT                (363524L)
 
@@ -68,6 +71,83 @@ static char pn[] = "fs";
 static char *szLogFileName = "afsguilog.txt";
 #endif
 
+#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)
 {
@@ -82,14 +162,15 @@ VLDBInit(int noAuthFlag, struct afsconf_cell *info)
     return code;
 }
 
-FILE *OpenFile(char *file, char *rwp)
+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;
 
@@ -135,7 +216,7 @@ 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)
@@ -160,7 +241,7 @@ 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_ICONERROR, IDS_FLUSH_VOLUME_ERROR, files[i], strerror(errno));
@@ -190,15 +271,16 @@ 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 {
+            results.Add(Utf8ToCString(space));
+        }
     }       
 
     LoadString (str, IDS_SHOW_CELL);
@@ -282,7 +364,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));
@@ -355,7 +437,7 @@ CMtoUNIXerror(int cm_code)
     }
 }
 
-CString GetAfsError(int code, const char *filename)
+CString GetAfsError(int code, const TCHAR *filename)
 {
     CString strMsg;
 
@@ -363,28 +445,28 @@ CString GetAfsError(int code, const char *filename)
 
     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;
@@ -495,23 +577,23 @@ CString GetRightsString(register 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("+");
 */
     }  
 
@@ -547,12 +629,13 @@ char *AclToString(struct Acl *acl)
 struct Acl *EmptyAcl(const CString& strCellName)
 {
     register 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;
 }
@@ -643,7 +726,6 @@ ParseAcl (char *astr)
     }
     ta->minuslist = first;
 
-  exit:
     return ta;
 
   nminus_err:
@@ -725,7 +807,7 @@ 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_ICONERROR, 0, names[i], GetAfsError(errno));
             continue;
@@ -750,7 +832,7 @@ 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_ICONERROR, IDS_CLEANACL_INVALID_ARG, names[i]);
@@ -779,7 +861,7 @@ 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_ICONERROR, IDS_GETRIGHTS_ERROR, strDir, GetAfsError(errno));
         return FALSE;
@@ -828,17 +910,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) {
@@ -854,7 +937,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) {
@@ -875,42 +958,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;
     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);
         }
     }   
@@ -948,7 +1030,7 @@ 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_ICONERROR, IDS_SAVE_ACL_EINVAL_ERROR, strDir);
@@ -975,7 +1057,7 @@ 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_ICONERROR, IDS_ACL_READ_ERROR, strToDir, GetAfsError(errno, strToDir));
         return FALSE;
@@ -1019,7 +1101,7 @@ 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)
@@ -1055,7 +1137,7 @@ 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;
 }       
@@ -1064,30 +1146,31 @@ CString ParseSymlink(const CString strFile, CString strSymlink)
 {
     CString strSymlinkInfo;
 
-    strSymlinkInfo = strFile + "\t" + strSymlink;
+    strSymlinkInfo = strFile + _T("\t") + strSymlink;
 
     return strSymlinkInfo;
 }       
 
-BOOL IsPathInAfs(const CHAR *strPath)
+BOOL IsPathInAfs(const CString & strPath)
 {
     struct ViceIoctl blob;
     int code;
 
     HOURGLASS hourglass;
 
-    char buf[512];
-    sprintf(buf, "IsPathInAfs(%s)", strPath);
-    OutputDebugString(buf);
+    CString debugBuf;
+
+    debugBuf.Format(_T("IsPathInAfs(%s)"), strPath);
+    OutputDebugString(debugBuf);
 
     blob.in_size = 0;
     blob.out_size = MAXSIZE;
     blob.out = space;
 
-    code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
+    code = pioctl_T(strPath, VIOC_FILE_CELL_NAME, &blob, 1);
 
-    sprintf(buf, "VIOC_FILE_CELL_NAME=%d", code);
-    OutputDebugString(buf);
+    debugBuf.Format(_T("VIOC_FILE_CELL_NAME=%d"), code);
+    OutputDebugString(debugBuf);
 
     if (code) {
        if ((errno == EINVAL) || (errno == ENOENT))
@@ -1097,7 +1180,7 @@ BOOL IsPathInAfs(const CHAR *strPath)
 }
 
 static int 
-IsFreelanceRoot(char *apath)
+IsFreelanceRoot(const CString& apath)
 {
     struct ViceIoctl blob;
     afs_int32 code;
@@ -1106,13 +1189,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;
@@ -1120,11 +1203,11 @@ const char * NetbiosName(void)
     DWORD dummyLen;
     DWORD enabled = 0;
 
-    code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+    code = RegOpenKeyExA(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
                          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 {
@@ -1133,6 +1216,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)
@@ -1147,8 +1248,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);
@@ -1162,8 +1263,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. */
@@ -1181,7 +1282,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.  
@@ -1268,36 +1369,63 @@ 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);
+    }
 }
 
 
@@ -1306,10 +1434,10 @@ 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 */
+
+    CString parent_dir;                /* Parent directory of true name */
+    CStringUtf8 last_component;                /* Last component of true name */
+
     CStringArray mountPoints;
     
     HOURGLASS hourglass;
@@ -1317,58 +1445,41 @@ 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;
             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)
@@ -1385,113 +1496,52 @@ 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;
-#if 0
-    struct vldbentry vldbEntry;
-#endif
+    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_ICONERROR, IDS_MAKE_MP_NOT_AFS_ERROR);
-               return FALSE;
-           }
-       } else {
+    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_ICONERROR, 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;
-    }
+    strMount.Format(_T("%c%s%s%s."),
+                    ((bRW)?_T('%'):_T('#')),
+                    strInCellName,
+                    ((strInCellName.IsEmpty())?_T(""):_T(":")),
+                    strVolName);
 
-#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, "%");
-    else
-        strcpy(space, "#");
-
-    /* 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_ICONERROR, IDS_MOUNT_POINT_ERROR, GetAfsError(errno, strDir));
@@ -1533,178 +1583,112 @@ 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 */
+    CString strParent = Parent(strName);
+    CStringUtf8 ustrLast(LastComponent(strName));
+    FixNetbiosPath(strParent);
 
-       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;
-    }
-
-    if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
+    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;
 
-    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;
-        fs_StripDriveLetter(true_name, strip_name, sizeof(strip_name));
+        CString str;
+        str.Format(_T("IsSymlink(%s)"), strName);
+        OutputDebugString(str);
     }
 
-    sprintf(buf, "last_component=%s", last_component);
-    OutputDebugString(buf);
+    CStringUtf8 ustrLast(LastComponent(strName));
+    CString strParent = Parent(strName);
 
-    blob.in = last_component;
-    blob.in_size = strlen(last_component)+1;
+    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(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;
     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);
+    {
+        CString str;
+        str.Format(_T("IsMountPoint(%s)"), path);
+        OutputDebugString(str);
+    }
 
-    tp = (char *)strrchr(szCurItem, '\\');
-    if (tp) {
-        strncpy(tbuffer, szCurItem, code = tp - szCurItem + 1);  /* the dir name */
-        tbuffer[code] = 0;
-        tp++;   /* skip the slash */
+    CString parent = Parent(path);
+    FixNetbiosPath(parent);
 
-       if (!IsPathInAfs(tbuffer)) {
-           const char * nbname = NetbiosName();
-           int len = strlen(nbname);
+    CStringUtf8 mountpoint(LastComponent(path));
 
-           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 str;
+#ifdef UNICODE
+        str.Format(_T("last_component=%S"), mountpoint);
+#else
+        str.Format(_T("last_component=%s"), mountpoint);
+#endif
+        OutputDebugString(str);
     }
 
-    sprintf(buf, "last_component=%s", tp);
-    OutputDebugString(buf);
-
-    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);
 }       
@@ -1720,9 +1704,6 @@ BOOL RemoveMount(CStringArray& files)
 {
     register LONG code = 0;
     struct ViceIoctl blob;
-    char tbuffer[1024];
-    register char *tp;
-    char szCurItem[1024];
     BOOL error = FALSE;
     CStringArray results;
     CString str;
@@ -1740,44 +1721,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]))));
@@ -1822,7 +1783,7 @@ BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo)
     blob.in_size = 0;
     blob.out = space;
 
-    code = pioctl(PCCHAR(strFile), VIOCGETVOLSTAT, &blob, 1);
+    code = pioctl_T(strFile, VIOCGETVOLSTAT, &blob, 1);
     if (code) {
         volInfo.m_strErrorMsg = GetAfsError(errno, strFile);
         return FALSE;
@@ -1831,7 +1792,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;
@@ -1881,7 +1842,7 @@ BOOL SetVolInfo(CVolInfo& volInfo)
     }
 #endif
 
-    code = pioctl(PCCHAR(volInfo.m_strFilePath), VIOCSETVOLSTAT, &blob, 1);
+    code = pioctl_T(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;
@@ -1890,10 +1851,11 @@ BOOL SetVolInfo(CVolInfo& volInfo)
     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)
@@ -1917,7 +1879,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 {
@@ -1933,7 +1895,7 @@ 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_ICONERROR, IDS_CHECK_SERVERS_ERROR, GetAfsError(errno, CString()));
         return FALSE;
@@ -2049,7 +2011,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;
@@ -2062,40 +2028,41 @@ BOOL GetTokenInfo(CStringArray& tokenInfo)
     return TRUE;
 }
 
-UINT MakeSymbolicLink(const char *strName, const char *strTarget)
+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, strName);
-    parent = Parent(path);
+    CString strParent = Parent(strName);
+    FixNetbiosPath(strParent);
 
-    sprintf(message,"MakeSymbolicLink: name = %s target = %s parent = %s\n",strName,strTarget, parent);
-    OutputDebugString(message);
+    {
+        CString str;
+        str.Format(_T("MakeSymbolicLink: name = %s target = %s parent = %s\n"),
+                   strName, strTarget, strParent);
+        OutputDebugString(str);
+    }
 
-    if ( IsFreelanceRoot(parent) && !IsAdmin() ) {
+    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(strTarget)+1];
-    _tcscpy(lpsz, strName);
-    strcpy(space, strTarget);
+    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)
@@ -2166,10 +2133,6 @@ 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;
@@ -2177,58 +2140,33 @@ BOOL ListSymlink(CStringArray& files)
     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));
-        }
+        CString strParent = Parent(files[i]);
+        CStringUtf8 ustrLast(LastComponent(files[i]));
+
+        FixNetbiosPath(strParent);
 
-        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();
+
         if (code == 0) {
-            int nPos = strlen(space) - 1;
-            if (space[nPos] == '.')
-                space[nPos] = 0;
-            symlinks.Add(ParseSymlink(StripPath(files[i]), space));
+            CString syml = Utf8ToCString(space);
+            int 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)
index dccd1f3..4c6cbdd 100644 (file)
@@ -18,9 +18,8 @@ void WSCellCmd();
 void WhichCell(CStringArray& files);
 BOOL CheckVolumes();
 void SetCacheSize(LONG nNewCacheSize);
-void RemoveMountCmd(const CStringArray& files);
 void WhereIs(CStringArray& files);
-CString GetAfsError(int code, const char *filename = 0);
+CString GetAfsError(int code, const TCHAR *filename = 0);
 void CleanACL(CStringArray& names);
 BOOL GetRights(const CString& strDir, CStringArray& strNormal, CStringArray& strNegative);
 BOOL SaveACL(const CString& strCellName, const CString& strDir, const CStringArray& normal, const CStringArray& negative);
@@ -28,20 +27,16 @@ BOOL CopyACL(const CString& strToDir, const CStringArray& normal, const CStringA
 BOOL ListMount(CStringArray& files);
 BOOL MakeMount(const CString& strDir, const CString& strVolName, const CString& strCellName, BOOL bRW);
 BOOL RemoveMount(CStringArray& files);
-BOOL RemoveSymlink(const char *);
+BOOL RemoveSymlink(const CString& symlink);
 BOOL GetVolumeInfo(CString strFile, CVolInfo& volInfo);
 BOOL SetVolInfo(CVolInfo& volInfo);
 enum WHICH_CELLS { LOCAL_CELL = 0, SPECIFIC_CELL = 1, ALL_CELLS = 2 };
 BOOL CheckServers(const CString& strCellName, WHICH_CELLS nCellsToCheck, BOOL bFast);
 BOOL GetTokenInfo(CStringArray& tokenInfo);
-BOOL IsPathInAfs(const CHAR *strPath);
-int GetCellName(char *baseNamep, struct afsconf_cell *infop);
-long fs_StripDriveLetter(const char *inPathp, char *outPathp, long outSize);
-long fs_ExtractDriveLetter(const char *inPathp, char *outPathp);
-BOOL IsSymlink(const char * true_name);
-BOOL IsMountPoint(const char * name);
-UINT MakeSymbolicLink(const char *,const char *);
-void ListSymbolicLinkPath(const char *strName,char *strPath,UINT nlenPath);
+BOOL IsPathInAfs(const CString& strPath);
+BOOL IsSymlink(const CString& name);
+BOOL IsMountPoint(const CString& name);
+UINT MakeSymbolicLink(const CString&,const CString&);
+void ListSymbolicLinkPath(CString&,CString&,UINT nlenPath);
 BOOL ListSymlink(CStringArray& files);
-const char * NetbiosName(void);
 #endif //__GUI2FS_H__
index 10acc77..2f42628 100644 (file)
@@ -44,10 +44,9 @@ static BOOL IsWindowsNT (void)
 }
 
 
-
-void SetHelpPath(const char *pszDefaultHelpFilePath)
+void SetHelpPath(LPCTSTR pszDefaultHelpFilePath)
 {
-       CString str = pszDefaultHelpFilePath;
+    CString str(pszDefaultHelpFilePath);
        int nIndex = str.ReverseFind('\\');
        ASSERT(nIndex >= 0);
 
index 0dcab65..3907f79 100644 (file)
@@ -34,6 +34,6 @@
 #define EDIT_PATH_NAME_HELP_ID         46
 #define SYMLINK_HELP_ID                 47
 
-void SetHelpPath(const char *pszDefaultHelpFilePath);
+void SetHelpPath(LPCTSTR pszDefaultHelpFilePath);
 void ShowHelp(HWND hWnd, DWORD nHelpID);
 
index d78d2fa..0319f35 100755 (executable)
@@ -15,7 +15,7 @@ typedef class HOURGLASS
       HCURSOR m_OldCursor;
 
    public:
-      HOURGLASS (LPCSTR idCursor = IDC_WAIT)
+      HOURGLASS (LPTSTR idCursor = IDC_WAIT)
       {
          m_OldCursor = GetCursor();
          SetCursor (LoadCursor (NULL, idCursor));
index f715d5a..c7acc85 100644 (file)
@@ -31,17 +31,31 @@ extern "C" {
 static char THIS_FILE[] = __FILE__;
 #endif
 
+#ifdef UNICODE
+CStringA CStringToCStringA(const CString& str)
+{
+    CStringA astr(str);
+    return astr;
+}
+#define PCCHAR(str)     ((char *)(const char *)CStringToCStringA(str))
+#else
 #define PCCHAR(str)    ((char *)(const char *)str)
-
+#endif
 
 /////////////////////////////////////////////////////////////////////////////
 // CKlogDlg dialog
 
-int kl_Authenticate(const CString& strCellName, const CString& strName, const CString& strPassword, char **reason)
+int kl_Authenticate(const CString& strCellName, const CString& strName,
+                    const CString& strPassword, char **reason)
 {
        afs_int32 pw_exp;
 
-       return ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, PCCHAR(strName), "", PCCHAR(strCellName), PCCHAR(strPassword), 0, &pw_exp, 0, reason);
+       return ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION,
+                                          PCCHAR(strName), "",
+                                          PCCHAR(strCellName),
+                                          PCCHAR(strPassword),
+                                          0,
+                                          &pw_exp, 0, reason);
 }
 
 CKlogDlg::CKlogDlg(CWnd* pParent /*=NULL*/)
@@ -88,7 +102,7 @@ BOOL CKlogDlg::OnInitDialog()
                char defaultCell[256];
                long code = cm_GetRootCellName(defaultCell);
                if (code < 0)
-                       AfxMessageBox("Error determining root cell name.");
+                    AfxMessageBox(_T("Error determining root cell name."));
                else
                        m_strCellName = defaultCell;
        }
@@ -107,7 +121,8 @@ void CKlogDlg::OnOK()
        HOURGLASS hg;
 
        if (kl_Authenticate(m_strCellName, m_strName, m_strPassword, &reason)) {
-               AfxMessageBox(reason);
+            CString strReason(reason);
+            AfxMessageBox(strReason);
                return;
        }
 
index b6c854c..5ec7109 100644 (file)
@@ -16,7 +16,7 @@ extern "C" {
 #include <afs/stds.h>
 }
 
-#include <string.h>
+#include <tchar.h>
 #include <stdarg.h>
 
 #include "msgs.h"
@@ -61,134 +61,134 @@ extern "C" {
 UINT ShowMessageBox (UINT Id, UINT Button, UINT Help, ...) {
 
     CString temp;
-    char *pszstring, 
+    TCHAR *pszstring, 
     *pszpaste, 
     *pszcut, 
     *pszdone,
     *pszconvert;
-    char chread;
+    TCHAR chread;
     va_list params;
     int x;
 
-    pszconvert = new char[255];        
+    pszconvert = new TCHAR[255];       
     va_start(params, Help);
     LoadString (temp, Id);
     pszstring = temp.GetBuffer(512);
-    strcpy(pszstring,pszstring);
+    _tcscpy(pszstring,pszstring);
     temp.ReleaseBuffer();
     // Look and see - is there a need to insert chars (95% of the time, there won't)
-    if (!strstr(pszstring, "%")) {
+    if (!_tcsstr(pszstring, _T("%"))) {
        delete pszconvert;
        return AfxMessageBox(pszstring, Button, Help);
     }   
 
-    x = strcspn(pszstring, "%");
-    pszdone = new char[512];
-    pszcut = new char[512];
-    pszpaste = new char[512];
-    strcpy(pszcut, &pszstring[x+2]);
-    strncpy(pszpaste, pszstring, x);
-    pszpaste[x] = '\0';
+    x = _tcscspn(pszstring, _T("%"));
+    pszdone = new TCHAR[512];
+    pszcut = new TCHAR[512];
+    pszpaste = new TCHAR[512];
+    _tcscpy(pszcut, &pszstring[x+2]);
+    _tcsncpy(pszpaste, pszstring, x);
+    pszpaste[x] = _T('\0');
     chread = pszstring[x+1];
 
     for ( ; ; ) {
 
        switch (chread) { 
-       case    'i' :
-       case    'd' :
+       case    _T('i') :
+       case    _T('d') :
        {           
            int anint = va_arg(params, int);
-           _itoa( anint, pszconvert, 10);
+           _itot( anint, pszconvert, 10);
            break;
        }
-       case    'u' :
+       case    _T('u') :
        {       
            UINT anuint = va_arg(params, UINT);
-           _itoa( anuint, pszconvert, 10);
+           _itot( anuint, pszconvert, 10);
            break;
        }
 
-       case    'x' :
-       case    'X' :   
+       case    _T('x') :
+       case    _T('X') :   
        {
            int ahex = va_arg(params, int);
-           _itoa( ahex, pszconvert, 16);
+           _itot( ahex, pszconvert, 16);
            break;
        }
-       case    'g' :
-       case    'f' :
-       case    'e' :   
+       case    _T('g') :
+       case    _T('f') :
+       case    _T('e') :   
        {
            double adbl = va_arg(params, double);
-           _gcvt( adbl, 10, pszconvert);
+            _stprintf(pszconvert, _T("%g"), adbl);
            break;
        }
-       case    's' :   
+       case    _T('s') :       
        {
-           char *pStr = va_arg(params, char*);
-           ASSERT(strlen(pStr) <= 255);
-           strcpy(pszconvert, pStr);
+           TCHAR *pStr = va_arg(params, TCHAR*);
+           ASSERT(_tcslen(pStr) <= 255);
+           _tcscpy(pszconvert, pStr);
            break;
        }
-       case    'l' :   
+       case    _T('l') :       
        {
            chread = pszdone[x+2];
            switch(chread) {
-           case        'x'     :
+           case        _T('x') :
            {
                long int alhex = va_arg(params, long int);
-               _ltoa(alhex, pszconvert, 16);
-               strcpy(pszcut, &pszcut[1]);
+               _ltot(alhex, pszconvert, 16);
+               _tcscpy(pszcut, &pszcut[1]);
                break;
            }
-           case        'd'     :
+           case        _T('d') :
                default         :
                {
                    long int along = va_arg(params, long int);
-                   _ltoa( along, pszconvert, 10);
+                   _ltot( along, pszconvert, 10);
                    // For the L, there will be one character after it,
                    //   so move ahead another letter
-                   strcpy(pszcut, &pszcut[1]);
+                   _tcscpy(pszcut, &pszcut[1]);
                    break;
                }
            }
            break;
        }
 
-       case    'c' :   
+       case    _T('c') :       
        {
            int letter = va_arg(params, int);
-           pszconvert[0] = (char)letter;
+           pszconvert[0] = (TCHAR)letter;
            pszconvert[1] = '\0'; 
            break;
        }
-       case    'a'     :
+       case    _T('a') :
        {
            CString zeta;
-           char* lsc;
+           TCHAR* lsc;
            UINT ls = va_arg(params, UINT);
            LoadString (zeta, ls);
            lsc = zeta.GetBuffer(255);
-           strcpy(pszconvert, lsc);
+           _tcscpy(pszconvert, lsc);
            zeta.ReleaseBuffer();
            break;
        }
-       case    'o'     :
+       case    _T('o') :
        {
            CString get = va_arg(params, CString);
-           char* ex = get.GetBuffer(255);
-           strcpy(pszconvert,ex);
+           TCHAR* ex = get.GetBuffer(255);
+           _tcscpy(pszconvert,ex);
            get.ReleaseBuffer();
            break;
        }
            default     :
            {   
-               strcpy(pszconvert, " Could not load message. Invalid %type in string table entry. ");
+               _tcscpy(pszconvert, _T(" Could not load message. Invalid %type in string table entry. "));
                delete pszdone;
-               pszdone = new char[strlen(pszpaste)+strlen(pszcut)+strlen(pszconvert)+5];
-               strcpy(pszdone, pszpaste);
-               strcat(pszdone, pszconvert);
-               strcat(pszdone, pszcut);
+               pszdone = new TCHAR[_tcslen(pszpaste)+_tcslen(pszcut)+_tcslen(pszconvert)+5];
+               _tcscpy(pszdone, pszpaste);
+               _tcscat(pszdone, pszconvert);
+               _tcscat(pszdone, pszcut);
                AfxMessageBox(pszdone, Button, Help);
                delete pszcut;
                delete pszpaste;
@@ -200,14 +200,14 @@ UINT ShowMessageBox (UINT Id, UINT Button, UINT Help, ...) {
        } // case
 
        delete pszdone;
-       pszdone = new char[strlen(pszpaste)+strlen(pszcut)+strlen(pszconvert)+5];
-       strcpy(pszdone, pszpaste);
-       strcat(pszdone, pszconvert);
-       strcat(pszdone, pszcut);
+       pszdone = new TCHAR[_tcslen(pszpaste)+_tcslen(pszcut)+_tcslen(pszconvert)+5];
+       _tcscpy(pszdone, pszpaste);
+       _tcscat(pszdone, pszconvert);
+       _tcscat(pszdone, pszcut);
        // Now pszdone holds the entire message.
        // Check to see if there are more insertions to be made or not
        
-       if (!strstr(pszdone, "%"))      {
+       if (!_tcsstr(pszdone, _T("%"))) {
            UINT rt_type = AfxMessageBox(pszdone, Button, Help);
            delete pszcut;
            delete pszpaste;
@@ -217,10 +217,10 @@ UINT ShowMessageBox (UINT Id, UINT Button, UINT Help, ...) {
        } // if
 
        // there are more insertions to make, prepare the strings to use.
-       x = strcspn(pszdone, "%");
-       strcpy(pszcut, &pszdone[x+2]);
-       strncpy(pszpaste, pszdone, x); 
-       pszpaste[x] = '\0';
+       x = _tcscspn(pszdone, _T("%"));
+       _tcscpy(pszcut, &pszdone[x+2]);
+       _tcsncpy(pszpaste, pszdone, x); 
+       pszpaste[x] = _T('\0');
        chread = pszdone[x+1];
        
     } // for
@@ -232,137 +232,137 @@ UINT ShowMessageBox (UINT Id, UINT Button, UINT Help, ...) {
 CString GetMessageString(UINT Id, ...)
 {
     CString temp;
-    char *pszstring, 
+    TCHAR *pszstring, 
     *pszpaste, 
     *pszcut, 
     *pszdone,
     *pszconvert;
-    char chread;
+    TCHAR chread;
     va_list params;
     int x;
     CString strMsg;
 
-    pszconvert = new char[255];        
+    pszconvert = new TCHAR[255];       
     va_start(params, Id);
     LoadString (temp, Id);
     pszstring = temp.GetBuffer(512);
-    strcpy(pszconvert,pszstring);
+    _tcscpy(pszconvert,pszstring);
     temp.ReleaseBuffer();
 
     // Look and see - is there a need to insert chars (95% of the time, there won't)
-    if (!strstr(pszstring, "%")) {
+    if (!_tcsstr(pszstring, _T("%"))) {
        strMsg = pszconvert;
        delete pszconvert;
        return strMsg;
     }   
 
-    x = strcspn(pszstring, "%");
-    pszdone = new char[512];
-    pszcut = new char[512];
-    pszpaste = new char[512];
-    strcpy(pszcut, &pszstring[x+2]);
-    strncpy(pszpaste, pszstring, x);
-    pszpaste[x] = '\0';
+    x = _tcscspn(pszstring, _T("%"));
+    pszdone = new TCHAR[512];
+    pszcut = new TCHAR[512];
+    pszpaste = new TCHAR[512];
+    _tcscpy(pszcut, &pszstring[x+2]);
+    _tcsncpy(pszpaste, pszstring, x);
+    pszpaste[x] = _T('\0');
     chread = pszstring[x+1];
 
     for ( ; ; ) {
 
        switch (chread) { 
-       case    'i' :
-       case    'd' :
+       case    _T('i') :
+       case    _T('d') :
        {           
            int anint = va_arg(params, int);
-           _itoa( anint, pszconvert, 10);
+           _itot( anint, pszconvert, 10);
            break;
        }
-       case    'u' :
+       case    _T('u') :
        {       
            UINT anuint = va_arg(params, UINT);
-           _itoa( anuint, pszconvert, 10);
+           _itot( anuint, pszconvert, 10);
            break;
        }
 
-       case    'x' :
-       case    'X' :   
+       case    _T('x') :
+       case    _T('X') :   
        {
            int ahex = va_arg(params, int);
-           _itoa( ahex, pszconvert, 16);
+           _itot( ahex, pszconvert, 16);
            break;
        }
-       case    'g' :
-       case    'f' :
-       case    'e' :   
+       case    _T('g') :
+       case    _T('f') :
+       case    _T('e') :   
        {
            double adbl = va_arg(params, double);
-           _gcvt( adbl, 10, pszconvert);
+            _stprintf(pszconvert, _T("%g"), adbl);
            break;
        }
-       case    's' :   
+       case    _T('s') :       
        {
-           char *pStr = va_arg(params, char*);
-           ASSERT(strlen(pStr) <= 255);
-           strcpy(pszconvert, pStr);
+           TCHAR *pStr = va_arg(params, TCHAR*);
+           ASSERT(_tcslen(pStr) <= 255);
+           _tcscpy(pszconvert, pStr);
            break;
        }
-       case    'l' :   
+       case    _T('l') :       
        {
            chread = pszdone[x+2];
            switch(chread) {
-           case        'x'     :
+           case        _T('x') :
            {
                long int alhex = va_arg(params, long int);
-               _ltoa(alhex, pszconvert, 16);
-               strcpy(pszcut, &pszcut[1]);
+               _ltot(alhex, pszconvert, 16);
+               _tcscpy(pszcut, &pszcut[1]);
                break;
            }
-           case        'd'     :
+           case        _T('d') :
                default         :
                {
                    long int along = va_arg(params, long int);
-                   _ltoa( along, pszconvert, 10);
+                   _ltot( along, pszconvert, 10);
                    // For the L, there will be one character after it,
                    //   so move ahead another letter
-                   strcpy(pszcut, &pszcut[1]);
+                   _tcscpy(pszcut, &pszcut[1]);
                    break;
                }
            }
            break;
        }       
 
-       case    'c' :   
+       case    _T('c') :       
        {
            int letter = va_arg(params, int);
-           pszconvert[0] = (char)letter;
-           pszconvert[1] = '\0'; 
+           pszconvert[0] = (TCHAR)letter;
+           pszconvert[1] = _T('\0'); 
            break;
        }
-       case    'a'     :
+       case    _T('a') :
        {
            CString zeta;
-           char* lsc;
+           TCHAR* lsc;
            UINT ls = va_arg(params, UINT);
            LoadString (zeta, ls);
            lsc = zeta.GetBuffer(255);
-           strcpy(pszconvert, lsc);
+           _tcscpy(pszconvert, lsc);
            zeta.ReleaseBuffer();
            break;
        }
-       case    'o'     :
+       case    _T('o') :
        {
            CString get = va_arg(params, CString);
-           char* ex = get.GetBuffer(255);
-           strcpy(pszconvert,ex);
+           TCHAR* ex = get.GetBuffer(255);
+           _tcscpy(pszconvert,ex);
            get.ReleaseBuffer();
            break;
        }
        default:
            {   
-               strcpy(pszconvert, " Could not load message. Invalid %type in string table entry. ");
+               _tcscpy(pszconvert, _T(" Could not load message. Invalid %type in string table entry. "));
                delete pszdone;
-               pszdone = new char[strlen(pszpaste)+strlen(pszcut)+strlen(pszconvert)+5];
-               strcpy(pszdone, pszpaste);
-               strcat(pszdone, pszconvert);
-               strcat(pszdone, pszcut);
+               pszdone = new TCHAR[_tcslen(pszpaste)+_tcslen(pszcut)+_tcslen(pszconvert)+5];
+               _tcscpy(pszdone, pszpaste);
+               _tcscat(pszdone, pszconvert);
+               _tcscat(pszdone, pszcut);
                strMsg = pszdone;
                delete pszcut;
                delete pszpaste;
@@ -374,14 +374,14 @@ CString GetMessageString(UINT Id, ...)
        } // case
 
        delete pszdone;
-       pszdone = new char[strlen(pszpaste)+strlen(pszcut)+strlen(pszconvert)+5];
-       strcpy(pszdone, pszpaste);
-       strcat(pszdone, pszconvert);
-       strcat(pszdone, pszcut);
+       pszdone = new TCHAR[_tcslen(pszpaste)+_tcslen(pszcut)+_tcslen(pszconvert)+5];
+       _tcscpy(pszdone, pszpaste);
+       _tcscat(pszdone, pszconvert);
+       _tcscat(pszdone, pszcut);
        // Now pszdone holds the entire message.
        // Check to see if there are more insertions to be made or not
        
-       if (!strstr(pszdone, "%"))      {
+       if (!_tcsstr(pszdone, _T("%"))) {
            strMsg = pszdone;
            delete pszcut;
            delete pszpaste;
@@ -391,10 +391,10 @@ CString GetMessageString(UINT Id, ...)
        } // if
 
        // there are more insertions to make, prepare the strings to use.
-       x = strcspn(pszdone, "%");
-       strcpy(pszcut, &pszdone[x+2]);
-       strncpy(pszpaste, pszdone, x); 
-       pszpaste[x] = '\0';
+       x = _tcscspn(pszdone, _T("%"));
+       _tcscpy(pszcut, &pszdone[x+2]);
+       _tcsncpy(pszpaste, pszdone, x); 
+       pszpaste[x] = _T('\0');
        chread = pszdone[x+1];
        
     } // for
@@ -404,8 +404,15 @@ CString GetMessageString(UINT Id, ...)
 
 void LoadString (CString &Str, UINT id)
 {
-    TCHAR szString[ 256 ];
+    extern EXPORTED void GetString (LPSTR pszTarget, int idsSource, int cchMax = cchRESOURCE);
+
+    char szString[ 256 ];
     GetString (szString, id);
+#ifdef UNICODE
+    CString wstr(szString);
+    Str = wstr;
+#else
     Str = szString;
+#endif
 }
 
index 881bf47..9d7d319 100644 (file)
@@ -69,18 +69,18 @@ BOOL CPartitionInfoDlg::OnInitDialog()
        ASSERT(m_nSize != 0);
 
        CString strSize;
-       strSize.Format("%ld", m_nSize);
+       strSize.Format(_T("%ld"), m_nSize);
        
        CString strFree;
-       strFree.Format("%ld", m_nFree);
+       strFree.Format(_T("%ld"), m_nFree);
        
        CString strPerUsed;
-       strPerUsed.Format("%d", ((m_nSize - m_nFree) * 100) / m_nSize);
+       strPerUsed.Format(_T("%d"), ((m_nSize - m_nFree) * 100) / m_nSize);
 
        m_Size.SetWindowText(strSize);
        m_Free.SetWindowText(strFree);
     percentUsed = ( double(m_nSize - m_nFree) * 100.0l ) / double(m_nSize);
-    strPerUsed.Format("%2.2lf", percentUsed );
+    strPerUsed.Format(_T("%2.2lf"), percentUsed );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
index 5da8a51..71da10e 100644 (file)
@@ -104,10 +104,10 @@ BOOL CSetAfsAcl::OnInitDialog()
 
         int i;
        for (i = 0; i < m_Normal.GetSize(); i += 2)
-               m_NormalRights.AddString(m_Normal[i + 1] + "\t" + m_Normal[i]);
+               m_NormalRights.AddString(m_Normal[i + 1] + _T("\t") + m_Normal[i]);
 
        for (i = 0; i < m_Negative.GetSize(); i += 2)
-               m_NegativeRights.AddString(m_Negative[i + 1] + "\t" + m_Negative[i]);
+               m_NegativeRights.AddString(m_Negative[i + 1] + _T("\t") + m_Negative[i]);
 
        CenterWindow();
 
@@ -162,13 +162,13 @@ void CSetAfsAcl::OnAdd()
        if (bNormal) {
                m_Normal.Add(name);
                m_Normal.Add(rights);
-               m_nCurSel = m_NormalRights.AddString(rights + "\t" + name);
+               m_nCurSel = m_NormalRights.AddString(rights + _T("\t") + name);
                m_NormalRights.SetSel(m_nCurSel);
                m_bShowingNormal = TRUE;
        } else {
                m_Negative.Add(name);
                m_Negative.Add(rights);
-               m_nCurSel = m_NegativeRights.AddString(rights + "\t" + name);
+               m_nCurSel = m_NegativeRights.AddString(rights + _T("\t") + name);
                m_NegativeRights.SetSel(m_nCurSel);
                m_bShowingNormal = FALSE;
        }
@@ -196,13 +196,13 @@ void CSetAfsAcl::OnCopy()
 
 void CSetAfsAcl::ShowRights(const CString& strRights)
 {
-       m_ReadPerm.SetCheck((strRights.Find("r") == -1) ? UNCHECKED : CHECKED);
-       m_WritePerm.SetCheck((strRights.Find("w") == -1) ? UNCHECKED : CHECKED);
-       m_LookupPerm.SetCheck((strRights.Find("l") == -1) ? UNCHECKED : CHECKED);
-       m_DeletePerm.SetCheck((strRights.Find("d") == -1) ? UNCHECKED : CHECKED);
-       m_InsertPerm.SetCheck((strRights.Find("i") == -1) ? UNCHECKED : CHECKED);
-       m_LockPerm.SetCheck((strRights.Find("k") == -1) ? UNCHECKED : CHECKED);
-       m_AdminPerm.SetCheck((strRights.Find("a") == -1) ? UNCHECKED : CHECKED);
+       m_ReadPerm.SetCheck((strRights.Find(_T("r")) == -1) ? UNCHECKED : CHECKED);
+       m_WritePerm.SetCheck((strRights.Find(_T("w")) == -1) ? UNCHECKED : CHECKED);
+       m_LookupPerm.SetCheck((strRights.Find(_T("l")) == -1) ? UNCHECKED : CHECKED);
+       m_DeletePerm.SetCheck((strRights.Find(_T("d")) == -1) ? UNCHECKED : CHECKED);
+       m_InsertPerm.SetCheck((strRights.Find(_T("i")) == -1) ? UNCHECKED : CHECKED);
+       m_LockPerm.SetCheck((strRights.Find(_T("k")) == -1) ? UNCHECKED : CHECKED);
+       m_AdminPerm.SetCheck((strRights.Find(_T("a")) == -1) ? UNCHECKED : CHECKED);
 }
 
 void CSetAfsAcl::OnSelChangeNormalRights() 
@@ -213,7 +213,7 @@ void CSetAfsAcl::OnSelChangeNormalRights()
 
        int nNum = m_NormalRights.GetSelCount();
        if (nNum != 1) {
-               ShowRights("");
+               ShowRights(_T(""));
                EnablePermChanges(FALSE);
                return;
        }
@@ -236,7 +236,7 @@ void CSetAfsAcl::OnSelChangeNegativeEntries()
 
        int nNum = m_NegativeRights.GetSelCount();
        if (nNum != 1) {
-               ShowRights("");
+               ShowRights(_T(""));
                EnablePermChanges(FALSE);
                return;
        }
@@ -256,19 +256,19 @@ CString CSetAfsAcl::MakeRightsString()
        CString str;
 
        if (m_ReadPerm.GetCheck() == CHECKED)
-               str += "r";
+               str += _T("r");
        if (m_LookupPerm.GetCheck() == CHECKED)
-               str += "l";
+               str += _T("l");
        if (m_InsertPerm.GetCheck() == CHECKED)
-               str += "i";
+               str += _T("i");
        if (m_DeletePerm.GetCheck() == CHECKED)
-               str += "d";
+               str += _T("d");
        if (m_WritePerm.GetCheck() == CHECKED)
-               str += "w";
+               str += _T("w");
        if (m_LockPerm.GetCheck() == CHECKED)
-               str += "k";
+               str += _T("k");
        if (m_AdminPerm.GetCheck() == CHECKED)
-               str += "a";
+               str += _T("a");
 
        return str;
 }
@@ -290,7 +290,7 @@ void CSetAfsAcl::OnPermChange()
 
        CString str = MakeRightsString();
        (*pRights)[(2 * m_nCurSel) + 1] = str;
-       str += "\t" + (*pRights)[(2 * m_nCurSel)];
+       str += _T("\t") + (*pRights)[(2 * m_nCurSel)];
 
        pRightsList->DeleteString(m_nCurSel);
        pRightsList->InsertString(m_nCurSel, str);
@@ -364,7 +364,7 @@ void CSetAfsAcl::OnNothingSelected()
     {
        m_NegativeRights.SetSel(i, FALSE);
     }
-    ShowRights("");                            // Show no rights
+    ShowRights(_T(""));                                // Show no rights
     EnablePermChanges(FALSE);          // Allow no rights changes
     m_Remove.EnableWindow(FALSE);              // Disable remove button
 }
index d923138..164ba6c 100644 (file)
@@ -54,7 +54,7 @@ static BOOL IsADir(const CString& strName)
 {
     struct _stat statbuf;
 
-    if (_stat(strName, &statbuf) < 0)
+    if (_tstat(strName, &statbuf) < 0)
        return FALSE;
 
     return statbuf.st_mode & _S_IFDIR;
@@ -79,9 +79,9 @@ CShellExt::CShellExt()
     m_bIsOverlayEnabled=FALSE;
     if (FAILED(hr))
        m_pAlloc = NULL;
-    RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &NPKey);
+    RegOpenKeyExA(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &NPKey);
     LSPsize=sizeof(ShellOption);
-    code=RegQueryValueEx(NPKey, "ShellOption", NULL,
+    code=RegQueryValueEx(NPKey, _T("ShellOption"), NULL,
                          &LSPtype, (LPBYTE)&ShellOption, &LSPsize);
     RegCloseKey (NPKey);
     m_bIsOverlayEnabled=((code==0) && (LSPtype==REG_DWORD) && ((ShellOption & OVERLAYENABLED)!=0));
@@ -206,11 +206,11 @@ STDMETHODIMP CShellExt::XMenuExt::QueryContextMenu(HMENU hMenu,UINT indexMenu,
            DeleteMenu (hMenu, iItem, MF_BYPOSITION);
            continue;
        }
-       if ((!lstrcmp(szItemText,"&Delete"))&&(pThis->m_bIsSymlink)) {  /*this is a symlink - don't present a delete menu!*/
+       if ((!lstrcmp(szItemText,_T("&Delete")))&&(pThis->m_bIsSymlink)) {      /*this is a symlink - don't present a delete menu!*/
            DeleteMenu (hMenu, iItem, MF_BYPOSITION);
            continue;
        }
-       if ((!lstrcmp(szItemText,"Cu&t"))&&(pThis->m_bIsSymlink)) {     /*same for cut*/
+       if ((!lstrcmp(szItemText,_T("Cu&t")))&&(pThis->m_bIsSymlink)) { /*same for cut*/
            DeleteMenu (hMenu, iItem, MF_BYPOSITION);
            continue;
        }
@@ -411,7 +411,7 @@ STDMETHODIMP CShellExt::XMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
     }
 
     case IDM_SYMBOLICLINK_ADD: {
-       CString msg=files.GetAt(0);
+       CStringA msg(files.GetAt(0));
        int i;
        if ((i=msg.ReverseFind('\\'))>0)
            msg=msg.Left(i+1);
@@ -531,7 +531,7 @@ STDMETHODIMP CShellExt::XMenuExt::GetCommandString(UINT_PTR idCmd, UINT uType,
     CString strMsg;
     LoadString (strMsg, nCmdStrID);
 
-    strncpy(pszName, strMsg, cchMax);
+    _tcsncpy((LPTSTR) pszName, strMsg, cchMax);
 
     return NOERROR;
 }
@@ -658,10 +658,14 @@ STDMETHODIMP CShellExt::XIconExt::GetOverlayInfo(LPWSTR pwszIconFile
     if(IsBadWritePtr(pdwFlags, sizeof(DWORD)))
        return E_INVALIDARG;
 
-    HMODULE hModule=GetModuleHandle("shell32.dll");
+    HMODULE hModule=GetModuleHandle(_T("shell32.dll"));
     TCHAR szModule[MAX_PATH];
     DWORD z=GetModuleFileName(hModule,szModule,sizeof(szModule));
+#ifndef UNICODE
     MultiByteToWideChar( CP_ACP,0,szModule,-1,pwszIconFile,cchMax); 
+#else
+    _tcsncpy(pwszIconFile, szModule, cchMax);
+#endif
     *pIndex = 30;
     *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
     return S_OK;
@@ -678,7 +682,11 @@ STDMETHODIMP CShellExt::XIconExt::GetPriority(int* pPriority)
 STDMETHODIMP CShellExt::XIconExt::IsMemberOf(LPCWSTR pwszPath,DWORD dwAttrib)
 {
     TCHAR szPath[MAX_PATH];
+#ifdef UNICODE
+    _tcscpy(szPath, pwszPath);
+#else
     WideCharToMultiByte( CP_ACP,0,pwszPath,-1,szPath,MAX_PATH,NULL,NULL);
+#endif
     if (IsSymlink(szPath))
        return S_OK;
     return S_FALSE;
index b2d4c1a..f445e12 100644 (file)
@@ -24,7 +24,7 @@ extern ULONG nICRefCount;     // IContextMenu ref count
 extern ULONG nTPRefCount;      // IQueryInfo ref count
 extern ULONG nXPRefCount;      // IPersistFile ref count
 
-#define STR_EXT_TITLE   TEXT("AfsClientContextMenu")
+#define STR_EXT_TITLE   "AfsClientContextMenu"
 #define STR_REG_PATH    TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers")
 
 /////////////////////////////////////////////////////////////////////////////
index 35a0ee8..1ebdde5 100644 (file)
@@ -45,10 +45,10 @@ static CSubmountInfo *ReadSubmtInfo(const CString& strShareName)
 
        DWORD len;
 
-       char pathName[1024];
+       TCHAR pathName[1024];
 
     HKEY hkSubmounts;
-    RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
+    RegCreateKeyExA( HKEY_LOCAL_MACHINE, 
                     AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
                     0, 
                     "AFS", 
@@ -61,7 +61,7 @@ static CSubmountInfo *ReadSubmtInfo(const CString& strShareName)
     DWORD dwType;
     DWORD status;
     len = sizeof(pathName);
-    status = RegQueryValueEx( hkSubmounts, (LPCSTR)PCCHAR(strShareName), 0,
+    status = RegQueryValueEx( hkSubmounts, strShareName, 0,
                               &dwType, (LPBYTE)pathName, &len);
     RegCloseKey( hkSubmounts );
 
@@ -169,7 +169,7 @@ BOOL CSubmountsDlg::FillSubmtList()
     DWORD dwIndex;
     DWORD dwSubmounts;
 
-    RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
+    RegCreateKeyExA( HKEY_LOCAL_MACHINE, 
                     AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
                     0, 
                     "AFS", 
@@ -195,7 +195,7 @@ BOOL CSubmountsDlg::FillSubmtList()
 
 
     for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
-        char submountName[256];
+        TCHAR submountName[256];
         DWORD submountNameLen = sizeof(submountName);
 
         RegEnumValue( hkSubmounts, dwIndex, submountName, &submountNameLen, NULL,
@@ -222,7 +222,7 @@ void CSubmountsDlg::OnDelete()
 
        ASSERT(!strSubmt.IsEmpty());
 
-       strShareName = strSubmt.SpanExcluding("=");
+       strShareName = strSubmt.SpanExcluding(_T("="));
 
        if (ShowMessageBox(IDS_REALLY_DELETE_SUBMT, MB_YESNO | MB_ICONQUESTION, IDS_REALLY_DELETE_SUBMT, strShareName) != IDYES)
                return;
@@ -251,7 +251,7 @@ static BOOL AddSubmt(CSubmountInfo *pInfo)
        HOURGLASS hourglass;
 
     HKEY hkSubmounts;
-    RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
+    RegCreateKeyExA( HKEY_LOCAL_MACHINE, 
                     AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
                     0, 
                     "AFS", 
@@ -261,8 +261,9 @@ static BOOL AddSubmt(CSubmountInfo *pInfo)
                     &hkSubmounts,
                     NULL );
 
-    DWORD status = RegSetValueEx( hkSubmounts, PCCHAR(pInfo->GetShareName()), 0, REG_SZ,
-                   (const BYTE *)PCCHAR(pInfo->GetPathName()), strlen(PCCHAR(pInfo->GetPathName())) + 1);
+    DWORD status = RegSetValueEx( hkSubmounts, pInfo->GetShareName(), 0, REG_SZ,
+                                  (const BYTE *)(const TCHAR *) pInfo->GetPathName(),
+                                  pInfo->GetPathName().GetLength() + 1);
 
     RegCloseKey(hkSubmounts);
        return (status == ERROR_SUCCESS);
@@ -273,7 +274,7 @@ static BOOL DeleteSubmt(CSubmountInfo *pInfo)
        HOURGLASS hourglass;
 
     HKEY hkSubmounts;
-    RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
+    RegCreateKeyExA( HKEY_LOCAL_MACHINE, 
                     AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
                     0, 
                     "AFS", 
@@ -283,7 +284,7 @@ static BOOL DeleteSubmt(CSubmountInfo *pInfo)
                     &hkSubmounts,
                     NULL );
 
-    DWORD status = RegDeleteValue( hkSubmounts, PCCHAR(pInfo->GetShareName()));
+    DWORD status = RegDeleteValue( hkSubmounts, pInfo->GetShareName());
 
     RegCloseKey(hkSubmounts);
        return (status == ERROR_SUCCESS);
@@ -325,7 +326,7 @@ void CSubmountsDlg::OnChange()
 
        ASSERT(!strSubmt.IsEmpty());
 
-       strShareName = strSubmt.SpanExcluding("=");
+       strShareName = strSubmt.SpanExcluding(_T("="));
 
        CSubmountInfo *pInfo = FindWork(strShareName);
        if (pInfo != 0)
index 923d846..b0cf9c6 100644 (file)
@@ -69,7 +69,7 @@ BOOL CUnlogDlg::OnInitDialog()
                char defaultCell[256];
                long code = cm_GetRootCellName(defaultCell);
                if (code < 0)
-                       AfxMessageBox("Error determining root cell name.");
+                    AfxMessageBox(_T("Error determining root cell name."));
                else
                        m_strCellName = defaultCell;
        }
@@ -83,21 +83,24 @@ int kl_Unlog(const CString& strCellName)
 {
        struct ktc_principal server;
        int code;
-       static char xreason[100];
 
        if (strCellName.IsEmpty())
                code = ktc_ForgetAllTokens();
        else {
-               strcpy(server.cell, strCellName);
+            CStringA astrCellName(strCellName);
+
+            strcpy(server.cell, astrCellName);
                server.instance[0] = '\0';
                strcpy(server.name, "afs");
                code = ktc_ForgetToken(&server);
        }
        
        if (code == KTC_NOCM)
-               AfxMessageBox("AFS service may not have started");
+            AfxMessageBox(_T("AFS service may not have started"));
        else if (code) {
-               sprintf(xreason, "Unexpected error, code %d", code);
+            CString xreason;
+
+            xreason.Format(_T("Unexpected error, code %d"), code);
                AfxMessageBox(xreason);
        }
        
index d200ef7..f077c4c 100644 (file)
@@ -233,10 +233,15 @@ void CVolumeInfo::ShowInfo()
 
                        if (nQuota != 0) {
                                LONG nPercentUsed = (m_pVolInfo[i].m_nUsed * 100) / nQuota;
-                               strEntry.Format("%s\t%s\t%ld\t%ldK\t%ldK\t%ld%%", m_pVolInfo[i].m_strFileName, m_pVolInfo[i].m_strName,
-                                       m_pVolInfo[i].m_nID, nQuota, m_pVolInfo[i].m_nUsed, nPercentUsed);
+                            strEntry.Format(_T("%s\t%s\t%ld\t%ldK\t%ldK\t%ld%%"),
+                                            m_pVolInfo[i].m_strFileName,
+                                            m_pVolInfo[i].m_strName,
+                                            m_pVolInfo[i].m_nID, nQuota,
+                                            m_pVolInfo[i].m_nUsed, nPercentUsed);
                        } else {
-                               strEntry.Format("%s\t%s\t%ld\tUnlimited\t%ldK", m_pVolInfo[i].m_strFileName, m_pVolInfo[i].m_strName,
+                            strEntry.Format(_T("%s\t%s\t%ld\tUnlimited\t%ldK"),
+                                            m_pVolInfo[i].m_strFileName,
+                                            m_pVolInfo[i].m_strName,
                                        m_pVolInfo[i].m_nID, m_pVolInfo[i].m_nUsed);
                        }
                }
index ac87904..872a2c9 100644 (file)
 
 #sanity checks 
 
+!IF ("$(CPU)" != "x86")
+CPU=i386
+!ENDIF
+
 !IF ("$(CPU)" != "i386")
 !ERROR Platform SDK not configured for i386
 !ENDIF
@@ -82,7 +86,7 @@ INCLUDE = $(AFSDEV_INCLUDE)
 LIB = $(AFSDEV_LIB)
 
 #define used in WinNT/2000 installation and program version display
-AFSPRODUCT_VER_MAJOR=0
+AFSPRODUCT_VER_MAJOR=2
 AFSPRODUCT_VER_MINOR=0
 AFSPRODUCT_VER_PATCH=0
 AFSPRODUCT_VER_BUILD=0
@@ -223,6 +227,7 @@ afscdefs =\
        -DAFS_64BIT_ENV \
        -DAFS_64BIT_CLIENT \
        -DAFS_LARGEFILE_ENV \
+        -DAFS_OLD_COM_ERR \
         $(AFSDEV_AUXCDEFINES)
 
 # Compiler switches (except include paths and preprocessor defines)
index 4dfa492..2e59483 100644 (file)
@@ -115,3 +115,4 @@ EXPORTS
        VOTE_GetSyncSite                                @113
        ubik_RefreshConn                                @114
         rx_SetSecurityConfiguration                     @115
+        pioctl_utf8                                     @116
index 846b659..6b0fd76 100755 (executable)
@@ -53,6 +53,9 @@ set NTDDKDIR=c:\progra~1\micros~5
 REM Location of netmpr.h/netspi.h (from Windows 95/98 DDK - 8.3 short name)
 SET W9XDDKDIR=c:\progra~1\micros~6
 
+REM Location of Microsoft IDN Normalization SDK
+set MSIDNNLS=C:\progra~1\MI5913~1
+
 REM ########################################################################
 REM NTMakefile optional definitions:
 REM
@@ -113,7 +116,7 @@ REM     AFSDEV_BIN = default build binary directories
 
 set AFSDEV_BUILDTYPE=%AFSBLD_TYPE%
 
-set AFSDEV_INCLUDE=%MSSDKDIR%\include;%MSVCDIR%\include
+set AFSDEV_INCLUDE=%MSSDKDIR%\include;%MSVCDIR%\include;%MSIDNNLS%\include
 IF "%AFSVER_CL%" == "1400" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
 IF "%AFSVER_CL%" == "1310" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
 IF "%AFSVER_CL%" == "1300" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
index 009d874..c385f74 100644 (file)
@@ -49,6 +49,9 @@ RCSID
 
 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
 
+static const char utf8_prefix[] = UTF8_PREFIX;
+static const int  utf8_prefix_size = sizeof(utf8_prefix) -  sizeof(char);
+
 #define FS_IOCTLREQUEST_MAXSIZE        8192
 /* big structure for representing and storing an IOCTL request */
 typedef struct fs_ioctlRequest {
@@ -763,7 +766,7 @@ UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
 
 /* includes marshalling NULL pointer as a null (0 length) string */
 static long
-MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
+MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
 {
     int count;
 
@@ -772,6 +775,10 @@ MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
     else
        count = 1;
 
+    if (is_utf8) {
+        count += utf8_prefix_size;
+    }
+
     /* watch for buffer overflow */
     if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
         if ( IoctlDebug() )
@@ -779,6 +786,12 @@ MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
        return -1;
     }
 
+    if (is_utf8) {
+        memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
+        reqp->mp += utf8_prefix_size;
+        count -= utf8_prefix_size;
+    }
+
     if (stringp)
        memcpy(reqp->mp, stringp, count);
     else
@@ -906,8 +919,8 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize)
     return 0;
 }
 
-long
-pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
+static long
+pioctl_int(char *pathp, long opcode, struct ViceIoctl *blobp, int follow, int is_utf8)
 {
     fs_ioctlRequest_t preq;
     long code;
@@ -945,7 +958,7 @@ pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
        strcpy(fullPath, "");
     }
 
-    MarshallString(&preq, fullPath);
+    MarshallString(&preq, fullPath, is_utf8);
     if (blobp->in_size) {
         if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
             errno = E2BIG;
@@ -989,3 +1002,16 @@ pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
     CloseHandle(reqHandle);
     return 0;
 }
+
+long
+pioctl_utf8(char * pathp, long opcode, struct ViceIoctl * blobp, int follow)
+{
+    return pioctl_int(pathp, opcode, blobp, follow, TRUE);
+}
+
+long
+pioctl(char * pathp, long opcode, struct ViceIoctl * blobp, int follow)
+{
+    return pioctl_int(pathp, opcode, blobp, follow, FALSE);
+}
+
index bdccd45..d84cfe7 100644 (file)
@@ -28,4 +28,7 @@ typedef struct ViceIoctl {
 extern long pioctl(char *pathp, long opcode, struct ViceIoctl *blob,
                   int follow);
 
+extern long pioctl_utf8(char *pathp, long opcode, struct ViceIoctl *blob,
+                        int follow);
+
 #endif /* OPENAFS_AFS_PIOCTL_H */