sys: Tidy up header includes
[openafs.git] / src / sys / pioctl_nt.c
index c4eb7fa..e5b3795 100644 (file)
@@ -1,49 +1,19 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
-/* AFSIFS portions copyright (c) 2005
- * the regents of the university of michigan
- * all rights reserved
- * 
- * permission is granted to use, copy, create derivative works and
- * redistribute this software and such derivative works for any purpose,
- * so long as the name of the university of michigan is not used in
- * any advertising or publicity pertaining to the use or distribution
- * of this software without specific, written prior authorization.  if
- * the above copyright notice or any other identification of the
- * university of michigan is included in any copy of any portion of
- * this software, then the disclaimer below must also be included.
- * 
- * this software is provided as is, without representation from the
- * university of michigan as to its fitness for any purpose, and without
- * warranty by the university of michigan of any kind, either express
- * or implied, including without limitation the implied warranties of
- * merchantability and fitness for a particular purpose.  the regents
- * of the university of michigan shall not be liable for any damages,
- * including special, indirect, incidental, or consequential damages, 
- * with respect to any claim arising out or in connection with the use
- * of the software, even if it has been or is hereafter advised of the
- * possibility of such damages.
- */
 
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <afs/stds.h>
 
-RCSID
-    ("$Header$");
+#include <roken.h>
 
-#include <afs/stds.h>
 #include <windows.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
 #include <winioctl.h>
 #include <winsock2.h>
 #define SECURITY_WIN32
@@ -53,12 +23,14 @@ RCSID
 #include <osi.h>
 
 #include <cm.h>
-#include <cm_dir.h>
+#include <cm_nls.h>
+#include <cm_server.h>
 #include <cm_cell.h>
 #include <cm_user.h>
 #include <cm_conn.h>
 #include <cm_scache.h>
 #include <cm_buf.h>
+#include <cm_dir.h>
 #include <cm_utils.h>
 #include <cm_ioctl.h>
 
@@ -66,13 +38,15 @@ RCSID
 #include <pioctl_nt.h>
 #include <WINNT/afsreg.h>
 #include <lanahelper.h>
-#include <../WINNT/afsrdr/kif.h>
 
 #include <loadfuncs-krb5.h>
 #include <krb5.h>
 
 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 {
@@ -90,12 +64,15 @@ CMtoUNIXerror(int cm_code)
     case CM_ERROR_NOACCESS:
        return EACCES;
     case CM_ERROR_NOSUCHFILE:
+    case CM_ERROR_NOSUCHPATH:
+    case CM_ERROR_BPLUS_NOMATCH:
        return ENOENT;
     case CM_ERROR_INVAL:
        return EINVAL;
     case CM_ERROR_BADFD:
        return EBADF;
     case CM_ERROR_EXISTS:
+    case CM_ERROR_INEXACT_MATCH:
        return EEXIST;
     case CM_ERROR_CROSSDEVLINK:
        return EXDEV;
@@ -115,6 +92,12 @@ CMtoUNIXerror(int cm_code)
        return EDOM;            /* hack */
     case CM_ERROR_TOOMANYBUFS:
        return EFBIG;           /* hack */
+    case CM_ERROR_ALLBUSY:
+        return EBUSY;
+    case CM_ERROR_ALLDOWN:
+        return ENOSYS;          /* hack */
+    case CM_ERROR_ALLOFFLINE:
+        return ENXIO;           /* hack */
     default:
        if (cm_code > 0 && cm_code < EILSEQ)
            return cm_code;
@@ -139,7 +122,7 @@ IoctlDebug(void)
     if ( !init ) {
         HKEY hk;
 
-        if (RegOpenKey (HKEY_LOCAL_MACHINE, 
+        if (RegOpenKey (HKEY_LOCAL_MACHINE,
                          TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
         {
             DWORD dwSize = sizeof(BOOL);
@@ -154,6 +137,85 @@ IoctlDebug(void)
     return debug;
 }
 
+static BOOL
+DisableServiceManagerCheck(void)
+{
+    static int init = 0;
+    static BOOL smcheck = 0;
+
+    if ( !init ) {
+        HKEY hk;
+
+        if (RegOpenKey (HKEY_LOCAL_MACHINE,
+                         TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
+        {
+            DWORD dwSize = sizeof(BOOL);
+            DWORD dwType = REG_DWORD;
+            RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
+            RegCloseKey (hk);
+        }
+
+        init = 1;
+    }
+
+    return smcheck;
+}
+
+static DWORD
+GetServiceStatus(
+    LPSTR lpszMachineName,
+    LPSTR lpszServiceName,
+    DWORD *lpdwCurrentState)
+{
+    DWORD           hr               = NOERROR;
+    SC_HANDLE       schSCManager     = NULL;
+    SC_HANDLE       schService       = NULL;
+    DWORD           fdwDesiredAccess = 0;
+    SERVICE_STATUS  ssServiceStatus  = {0};
+    BOOL            fRet             = FALSE;
+
+    *lpdwCurrentState = 0;
+
+    fdwDesiredAccess = GENERIC_READ;
+
+    schSCManager = OpenSCManager(lpszMachineName,
+                                 NULL,
+                                 fdwDesiredAccess);
+
+    if(schSCManager == NULL)
+    {
+        hr = GetLastError();
+        goto cleanup;
+    }
+
+    schService = OpenService(schSCManager,
+                             lpszServiceName,
+                             fdwDesiredAccess);
+
+    if(schService == NULL)
+    {
+        hr = GetLastError();
+        goto cleanup;
+    }
+
+    fRet = QueryServiceStatus(schService,
+                              &ssServiceStatus);
+
+    if(fRet == FALSE)
+    {
+        hr = GetLastError();
+        goto cleanup;
+    }
+
+    *lpdwCurrentState = ssServiceStatus.dwCurrentState;
+
+cleanup:
+
+    CloseServiceHandle(schService);
+    CloseServiceHandle(schSCManager);
+
+    return(hr);
+}
 
 // krb5 functions
 DECL_FUNC_PTR(krb5_cc_default_name);
@@ -256,8 +318,11 @@ LoadFuncs(
     if (error) return 0;
     return 1;
 }
-
+#if defined(_IA64_) || defined(_AMD64_)
+#define KERB5DLL "krb5_64.dll"
+#else
 #define KERB5DLL "krb5_32.dll"
+#endif
 static BOOL
 IsKrb5Available()
 {
@@ -309,7 +374,7 @@ GetLSAPrincipalName(char * szUser, DWORD *dwSize)
         szUser[*dwSize-1] = '\0';
         success = 1;
     }
-    *dwSize = strlen(pname);
+    *dwSize = (DWORD)strlen(pname);
 
   cleanup:
     if (pname)
@@ -326,12 +391,193 @@ GetLSAPrincipalName(char * szUser, DWORD *dwSize)
     return success;
 }
 
+//
+// Recursively evaluate drivestr to find the final
+// dos drive letter to which the source is mapped.
+//
+static BOOL
+DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
+{
+    char device[MAX_PATH];
+
+    if ( QueryDosDevice(drivestr, device, MAX_PATH) )
+    {
+        if ( device[0] == '\\' &&
+             device[1] == '?' &&
+             device[2] == '?' &&
+             device[3] == '\\' &&
+             isalpha(device[4]) &&
+             device[5] == ':')
+        {
+            device[0] = device[4];
+            device[1] = ':';
+            device[2] = '\0';
+            if ( DriveSubstitution(device, subststr, substlen) )
+            {
+                return TRUE;
+            } else {
+                subststr[0] = device[0];
+                subststr[1] = ':';
+                subststr[2] = '\0';
+                return TRUE;
+            }
+        } else
+        if ( device[0] == '\\' &&
+             device[1] == '?' &&
+             device[2] == '?' &&
+             device[3] == '\\' &&
+             device[4] == 'U' &&
+             device[5] == 'N' &&
+             device[6] == 'C' &&
+             device[7] == '\\')
+        {
+             subststr[0] = '\\';
+             strncpy(&subststr[1], &device[7], substlen-1);
+             subststr[substlen-1] = '\0';
+             return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+//
+// drivestr - is "<drive-letter>:"
+//
+static BOOL
+DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
+{
+    DWORD dwResult, dwResultEnum;
+    HANDLE hEnum;
+    DWORD cbBuffer = 16384;     // 16K is a good size
+    DWORD cEntries = -1;        // enumerate all possible entries
+    LPNETRESOURCE lpnrLocal;    // pointer to enumerated structures
+    DWORD i;
+    BOOL  bIsAFS = FALSE;
+    char  subststr[MAX_PATH];
+
+    //
+    // Handle drive letter substitution created with "SUBST <drive> <path>".
+    // If a substitution has occurred, use the target drive letter instead
+    // of the source.
+    //
+    if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
+    {
+        if (subststr[0] == '\\' &&
+            subststr[1] == '\\')
+        {
+            if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
+                return TRUE;
+            else
+                return FALSE;
+        }
+        drivestr = subststr;
+    }
+
+    //
+    // Call the WNetOpenEnum function to begin the enumeration.
+    //
+    dwResult = WNetOpenEnum(RESOURCE_CONNECTED,
+                            RESOURCETYPE_DISK,
+                            RESOURCEUSAGE_ALL,
+                            NULL,       // NULL first time the function is called
+                            &hEnum);    // handle to the resource
+
+    if (dwResult != NO_ERROR)
+        return FALSE;
+
+    //
+    // Call the GlobalAlloc function to allocate resources.
+    //
+    lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
+    if (lpnrLocal == NULL)
+        return FALSE;
+
+    do {
+        //
+        // Initialize the buffer.
+        //
+        ZeroMemory(lpnrLocal, cbBuffer);
+        //
+        // Call the WNetEnumResource function to continue
+        //  the enumeration.
+        //
+        cEntries = -1;
+        dwResultEnum = WNetEnumResource(hEnum,          // resource handle
+                                        &cEntries,      // defined locally as -1
+                                        lpnrLocal,      // LPNETRESOURCE
+                                        &cbBuffer);     // buffer size
+        //
+        // If the call succeeds, loop through the structures.
+        //
+        if (dwResultEnum == NO_ERROR) {
+            for (i = 0; i < cEntries; i++) {
+                if (lpnrLocal[i].lpLocalName &&
+                    toupper(lpnrLocal[i].lpLocalName[0]) == toupper(drivestr[0])) {
+                    //
+                    // Skip the two backslashes at the start of the UNC device name
+                    //
+                    if ( _strnicmp( &(lpnrLocal[i].lpRemoteName[2]), NetbiosName, strlen(NetbiosName)) == 0 )
+                    {
+                        bIsAFS = TRUE;
+                        break;
+                    }
+                }
+            }
+        }
+        // Process errors.
+        //
+        else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
+            break;
+    }
+    while (dwResultEnum != ERROR_NO_MORE_ITEMS);
+
+    //
+    // Call the GlobalFree function to free the memory.
+    //
+    GlobalFree((HGLOBAL) lpnrLocal);
+    //
+    // Call WNetCloseEnum to end the enumeration.
+    //
+    dwResult = WNetCloseEnum(hEnum);
+
+    return bIsAFS;
+}
+
+static BOOL
+DriveIsGlobalAutoMapped(char *drivestr)
+{
+    DWORD dwResult;
+    HKEY hKey;
+    DWORD dwSubMountSize;
+    char szSubMount[260];
+    DWORD dwType;
+
+    dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                            AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
+                            0, KEY_QUERY_VALUE, &hKey);
+    if (dwResult != ERROR_SUCCESS)
+        return FALSE;
+
+    dwSubMountSize = sizeof(szSubMount);
+    dwType = REG_SZ;
+    dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
+    RegCloseKey(hKey);
+
+    if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
+        return TRUE;
+    else
+        return FALSE;
+}
+
 static long
 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
 {
-    char *drivep;
+    char *drivep = NULL;
     char netbiosName[MAX_NB_NAME_LENGTH];
-    char tbuffer[256]="";
+    DWORD CurrentState = 0;
+    char  HostName[64] = "";
+    char tbuffer[MAX_PATH]="";
     HANDLE fh;
     HKEY hk;
     char szUser[128] = "";
@@ -342,15 +588,44 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
     DWORD ioctlDebug = IoctlDebug();
     DWORD gle;
     DWORD dwSize = sizeof(szUser);
+    int saveerrno;
+    UINT driveType;
+    int sharingViolation;
+
+    memset(HostName, '\0', sizeof(HostName));
+    gethostname(HostName, sizeof(HostName));
+    if (!DisableServiceManagerCheck() &&
+        GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
+       CurrentState != SERVICE_RUNNING)
+       return -1;
+
+    // Populate the Netbios Name
+    lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
 
-#ifndef AFSIFS
     if (fileNamep) {
         drivep = strchr(fileNamep, ':');
         if (drivep && (drivep - fileNamep) >= 1) {
             tbuffer[0] = *(drivep - 1);
             tbuffer[1] = ':';
-            strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
-        } else if (fileNamep[0] == fileNamep[1] && 
+            tbuffer[2] = '\0';
+
+            driveType = GetDriveType(tbuffer);
+            switch (driveType) {
+            case DRIVE_UNKNOWN:
+            case DRIVE_REMOTE:
+                if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
+                    DriveIsGlobalAutoMapped(tbuffer))
+                    strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
+                else
+                    return -1;
+                break;
+            default:
+                if (DriveIsGlobalAutoMapped(tbuffer))
+                    strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
+                else
+                    return -1;
+            }
+        } else if (fileNamep[0] == fileNamep[1] &&
                   (fileNamep[0] == '\\' || fileNamep[0] == '/'))
         {
             int count = 0, i = 0;
@@ -362,20 +637,37 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
                     count++;
                i++;
             }
-            if (fileNamep[i] == 0)
+            if (fileNamep[i] == 0 || (fileNamep[i-1] != '\\' && fileNamep[i-1] != '/'))
                 tbuffer[i++] = '\\';
             tbuffer[i] = 0;
-            strcat(tbuffer, SMB_IOCTL_FILENAME);
+            strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
         } else {
-            char curdir[256]="";
+            char curdir[MAX_PATH]="";
 
             GetCurrentDirectory(sizeof(curdir), curdir);
             if ( curdir[1] == ':' ) {
                 tbuffer[0] = curdir[0];
                 tbuffer[1] = ':';
-                strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
+                tbuffer[2] = '\0';
+
+                driveType = GetDriveType(tbuffer);
+                switch (driveType) {
+                case DRIVE_UNKNOWN:
+                case DRIVE_REMOTE:
+                    if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
+                        DriveIsGlobalAutoMapped(tbuffer))
+                        strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
+                    else
+                        return -1;
+                    break;
+                default:
+                    if (DriveIsGlobalAutoMapped(tbuffer))
+                        strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
+                    else
+                        return -1;
+                }
             } else if (curdir[0] == curdir[1] &&
-                       (curdir[0] == '\\' || curdir[0] == '/')) 
+                       (curdir[0] == '\\' || curdir[0] == '/'))
             {
                 int count = 0, i = 0;
 
@@ -386,7 +678,7 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
                        count++;
                    i++;
                 }
-                if (tbuffer[i] == 0)
+                if (curdir[i] == 0 || (curdir[i-1] != '\\' && curdir[i-1] != '/'))
                     tbuffer[i++] = '\\';
                 tbuffer[i] = 0;
                 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
@@ -395,34 +687,30 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
     }
     if (!tbuffer[0]) {
         /* No file name starting with drive colon specified, use UNC name */
-        lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
         sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
     }
-#else   
-    sprintf(tbuffer,"\\\\.\\afscom\\ioctl");
-#endif 
 
     fflush(stdout);
     /* now open the file */
-    fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
-                   FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-                   FILE_FLAG_WRITE_THROUGH, NULL);
-
-       fflush(stdout);
+    sharingViolation = 0;
+    do {
+        if (sharingViolation)
+            Sleep(100);
+        fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
+                        FILE_SHARE_READ, NULL, OPEN_EXISTING,
+                        FILE_FLAG_WRITE_THROUGH, NULL);
+        sharingViolation++;
+    } while (fh == INVALID_HANDLE_VALUE &&
+             GetLastError() == ERROR_SHARING_VIOLATION &&
+             sharingViolation < 100);
+    fflush(stdout);
 
-#ifdef AFSIFS
     if (fh == INVALID_HANDLE_VALUE) {
-        return -1;
-    }
-#endif
-       
-       if (fh == INVALID_HANDLE_VALUE) {
-        int  gonext = 0;
-
         gle = GetLastError();
         if (gle && ioctlDebug ) {
             char buf[4096];
 
+            saveerrno = errno;
             if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                                NULL,
                                gle,
@@ -435,11 +723,18 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
                 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
                         tbuffer,gle,buf);
             }
+            errno = saveerrno;
+            SetLastError(gle);
         }
+    }
+
+    if (fh == INVALID_HANDLE_VALUE &&
+        GetLastError() != ERROR_SHARING_VIOLATION) {
+        int  gonext = 0;
 
         lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
 
-        if (RegOpenKey (HKEY_CURRENT_USER, 
+        if (RegOpenKey (HKEY_CURRENT_USER,
                          TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
         {
             DWORD dwType = REG_SZ;
@@ -448,9 +743,11 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
         }
 
         if ( szUser[0] ) {
-            if ( ioctlDebug )
+            if ( ioctlDebug ) {
+                saveerrno = errno;
                 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
-
+                errno = saveerrno;
+            }
             sprintf(szPath, "\\\\%s", szClient);
             memset (&nr, 0x00, sizeof(NETRESOURCE));
             nr.dwType=RESOURCETYPE_DISK;
@@ -459,8 +756,10 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
             res = WNetAddConnection2(&nr,NULL,szUser,0);
             if (res) {
                 if ( ioctlDebug ) {
+                    saveerrno = errno;
                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
                              szPath,szUser,res);
+                    errno = saveerrno;
                 }
                 gonext = 1;
             }
@@ -469,8 +768,10 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
             res = WNetAddConnection2(&nr,NULL,szUser,0);
             if (res) {
                 if ( ioctlDebug ) {
+                    saveerrno = errno;
                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
                              szPath,szUser,res);
+                    errno = saveerrno;
                 }
                 gonext = 1;
             }
@@ -478,15 +779,24 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
             if (gonext)
                 goto try_lsa_principal;
 
-            fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
-                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-                             FILE_FLAG_WRITE_THROUGH, NULL);
+            sharingViolation = 0;
+            do {
+                if (sharingViolation)
+                    Sleep(100);
+                fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
+                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
+                                FILE_FLAG_WRITE_THROUGH, NULL);
+                sharingViolation++;
+            } while (fh == INVALID_HANDLE_VALUE &&
+                     GetLastError() == ERROR_SHARING_VIOLATION &&
+                     sharingViolation < 100);
             fflush(stdout);
             if (fh == INVALID_HANDLE_VALUE) {
                 gle = GetLastError();
                 if (gle && ioctlDebug ) {
                     char buf[4096];
 
+                    saveerrno = errno;
                     if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                                         NULL,
                                         gle,
@@ -499,20 +809,25 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
                         fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
                                  tbuffer,gle,buf);
                     }
+                    errno = saveerrno;
+                    SetLastError(gle);
                 }
             }
         }
     }
 
   try_lsa_principal:
-    if (fh == INVALID_HANDLE_VALUE) {
+    if (fh == INVALID_HANDLE_VALUE &&
+        GetLastError() != ERROR_SHARING_VIOLATION) {
         int  gonext = 0;
 
         dwSize = sizeof(szUser);
         if (GetLSAPrincipalName(szUser, &dwSize)) {
-            if ( ioctlDebug )
+            if ( ioctlDebug ) {
+                saveerrno = errno;
                 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
-
+                errno = saveerrno;
+            }
             sprintf(szPath, "\\\\%s", szClient);
             memset (&nr, 0x00, sizeof(NETRESOURCE));
             nr.dwType=RESOURCETYPE_DISK;
@@ -521,8 +836,10 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
             res = WNetAddConnection2(&nr,NULL,szUser,0);
             if (res) {
                 if ( ioctlDebug ) {
+                    saveerrno = errno;
                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
                              szPath,szUser,res);
+                    errno = saveerrno;
                 }
                 gonext = 1;
             }
@@ -531,8 +848,10 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
             res = WNetAddConnection2(&nr,NULL,szUser,0);
             if (res) {
                 if ( ioctlDebug ) {
+                    saveerrno = errno;
                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
                              szPath,szUser,res);
+                    errno = saveerrno;
                 }
                 gonext = 1;
             }
@@ -540,15 +859,24 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
             if (gonext)
                 goto try_sam_compat;
 
-            fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
-                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-                             FILE_FLAG_WRITE_THROUGH, NULL);
+            sharingViolation = 0;
+            do {
+                if (sharingViolation)
+                    Sleep(100);
+                fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
+                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
+                                FILE_FLAG_WRITE_THROUGH, NULL);
+                sharingViolation++;
+            } while (fh == INVALID_HANDLE_VALUE &&
+                     GetLastError() == ERROR_SHARING_VIOLATION &&
+                     sharingViolation < 100);
             fflush(stdout);
             if (fh == INVALID_HANDLE_VALUE) {
                 gle = GetLastError();
                 if (gle && ioctlDebug ) {
                     char buf[4096];
 
+                    saveerrno = errno;
                     if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                                         NULL,
                                         gle,
@@ -561,18 +889,23 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
                         fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
                                  tbuffer,gle,buf);
                     }
+                    errno = saveerrno;
+                    SetLastError(gle);
                 }
             }
         }
     }
 
   try_sam_compat:
-    if ( fh == INVALID_HANDLE_VALUE ) {
+    if (fh == INVALID_HANDLE_VALUE &&
+        GetLastError() != ERROR_SHARING_VIOLATION) {
         dwSize = sizeof(szUser);
         if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
-            if ( ioctlDebug )
+            if ( ioctlDebug ) {
+                saveerrno = errno;
                 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
-
+                errno = saveerrno;
+            }
             sprintf(szPath, "\\\\%s", szClient);
             memset (&nr, 0x00, sizeof(NETRESOURCE));
             nr.dwType=RESOURCETYPE_DISK;
@@ -581,8 +914,10 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
             res = WNetAddConnection2(&nr,NULL,szUser,0);
             if (res) {
                 if ( ioctlDebug ) {
+                    saveerrno = errno;
                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
                              szPath,szUser,res);
+                    errno = saveerrno;
                 }
             }
 
@@ -590,21 +925,32 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
             res = WNetAddConnection2(&nr,NULL,szUser,0);
             if (res) {
                 if ( ioctlDebug ) {
+                    saveerrno = errno;
                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
                              szPath,szUser,res);
+                    errno = saveerrno;
                 }
                 return -1;
             }
 
-            fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
-                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-                             FILE_FLAG_WRITE_THROUGH, NULL);
+            sharingViolation = 0;
+            do {
+                if (sharingViolation)
+                    Sleep(100);
+                fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
+                                FILE_SHARE_READ, NULL, OPEN_EXISTING,
+                                FILE_FLAG_WRITE_THROUGH, NULL);
+                sharingViolation++;
+            } while (fh == INVALID_HANDLE_VALUE &&
+                     GetLastError() == ERROR_SHARING_VIOLATION &&
+                     sharingViolation < 100);
             fflush(stdout);
             if (fh == INVALID_HANDLE_VALUE) {
                 gle = GetLastError();
                 if (gle && ioctlDebug ) {
                     char buf[4096];
 
+                    saveerrno = errno;
                     if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                                         NULL,
                                         gle,
@@ -617,6 +963,7 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
                         fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
                                  tbuffer,gle,buf);
                     }
+                    errno = saveerrno;
                 }
                 return -1;
             }
@@ -626,6 +973,9 @@ GetIoctlHandle(char *fileNamep, HANDLE * handlep)
         }
     }
 
+    if (fh == INVALID_HANDLE_VALUE)
+        return -1;
+
     /* return fh and success code */
     *handlep = fh;
     return 0;
@@ -637,22 +987,28 @@ Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
     long rcount;
     long ioCount;
     DWORD gle;
-       char *data;
+    DWORD ioctlDebug = IoctlDebug();
+    int save;
 
-    rcount = reqp->mp - reqp->data;
+    rcount = (long)(reqp->mp - reqp->data);
     if (rcount <= 0) {
-        if ( IoctlDebug() )
+        if ( ioctlDebug ) {
+            save = errno;
             fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
+            errno = save;
+        }
        return EINVAL;          /* not supposed to happen */
     }
 
-#ifndef AFSIFS
     if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
        /* failed to write */
        gle = GetLastError();
 
-        if ( IoctlDebug() )
+        if ( ioctlDebug ) {
+            save = errno;
             fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
+            errno = save;
+        }
         return gle;
     }
 
@@ -660,21 +1016,13 @@ Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
        /* failed to read */
        gle = GetLastError();
 
-        if ( IoctlDebug() )
+        if ( ioctlDebug ) {
+            save = errno;
             fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
+            errno = save;
+        }
         return gle;
     }
-#else
-    /* ioctl completes as one operation, so copy input to a new buffer, and use as output buffer */
-    data = malloc(rcount);
-    memcpy(data, reqp->data, rcount);
-    if (!DeviceIoControl(handle, IOCTL_AFSRDR_IOCTL, data, rcount, reqp->data, sizeof(reqp->data), &ioCount, NULL))
-    {
-        free(data);
-        return GetLastError();
-    }
-    free(data);
-#endif
 
     reqp->nbytes = ioCount;    /* set # of bytes available */
     reqp->mp = reqp->data;     /* restart marshalling */
@@ -694,11 +1042,16 @@ MarshallLong(fs_ioctlRequest_t * reqp, long val)
 static long
 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
 {
+    int save;
+
     /* not enough data left */
     if (reqp->nbytes < 4) {
-        if ( IoctlDebug() )
+        if ( IoctlDebug() ) {
+            save = errno;
             fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
                      reqp->nbytes);
+            errno = save;
+        }
        return -1;
     }
 
@@ -710,22 +1063,36 @@ 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;
+    int save;
 
     if (stringp)
-       count = strlen(stringp) + 1;    /* space required including null */
+       count = (int)strlen(stringp) + 1;/* space required including null */
     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() )
+        if ( IoctlDebug() ) {
+            save = errno;
             fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
+            errno = save;
+        }
        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
@@ -748,34 +1115,8 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize)
     int pathHasDrive;
     int doSwitch;
     char newPath[3];
-    HANDLE rootDir;
-    wchar_t *wpath;
-    unsigned long length;
     char * p;
-
-#ifdef AFSIFS
-    if (!pathp)
-        return CM_ERROR_NOSUCHPATH;
-
-    //sprintf(tpath, "%c:\\", pathp[0]);
-    rootDir = CreateFile(pathp, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
-    if (rootDir == INVALID_HANDLE_VALUE)
-        return CM_ERROR_NOSUCHPATH;
-
-    wpath = tpath;
-    length = 0;
-    if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, wpath, 1000, &length, NULL))
-    {
-        CloseHandle(rootDir);
-        return CM_ERROR_NOSUCHPATH;
-    }
-    CloseHandle(rootDir);
-
-    code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, wpath, length/sizeof(wchar_t), outPathp, outSize/sizeof(wchar_t), NULL, NULL);
-
-//    strcpy(outPathp, tpath);
-    return 0;
-#endif
+    int save;
 
     if (pathp[0] != 0 && pathp[1] == ':') {
        /* there's a drive letter there */
@@ -786,7 +1127,7 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize)
        pathHasDrive = 0;
     }
 
-    if ( firstp[0] == '\\' && firstp[1] == '\\' || 
+    if ( firstp[0] == '\\' && firstp[1] == '\\' ||
         firstp[0] == '/' && firstp[1] == '/') {
         /* UNC path - strip off the server and sharename */
         int i, count;
@@ -830,9 +1171,12 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize)
        if (!SetCurrentDirectory(newPath)) {
            code = GetLastError();
 
-            if ( IoctlDebug() )
+            if ( IoctlDebug() ) {
+                save = errno;
                 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
                          newPath, code);
+                errno = save;
+            }
            return code;
        }
     }
@@ -862,8 +1206,8 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize)
 
     /* if there is a non-null name after the drive, append it */
     if (*firstp != 0) {
-        int len = strlen(outPathp);
-        if (outPathp[len-1] != '\\' && outPathp[len-1] != '/') 
+        int len = (int)strlen(outPathp);
+        if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
             strcat(outPathp, "\\");
         strcat(outPathp, firstp);
     }
@@ -880,14 +1224,15 @@ fs_GetFullPath(char *pathp, char *outPathp, long outSize)
     return 0;
 }
 
-long
-pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
+static int
+pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
 {
     fs_ioctlRequest_t preq;
     long code;
     long temp;
     char fullPath[1000];
     HANDLE reqHandle;
+    int save;
 
     code = GetIoctlHandle(pathp, &reqHandle);
     if (code) {
@@ -919,8 +1264,12 @@ 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;
+            return -1;
+        }
        memcpy(preq.mp, blobp->in, blobp->in_size);
        preq.mp += blobp->in_size;
     }
@@ -941,8 +1290,11 @@ pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
     if (temp != 0) {
        CloseHandle(reqHandle);
        errno = CMtoUNIXerror(temp);
-        if ( IoctlDebug() )
+        if ( IoctlDebug() ) {
+            save = errno;
             fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
+            errno = save;
+        }
        return -1;
     }
 
@@ -959,3 +1311,16 @@ pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
     CloseHandle(reqHandle);
     return 0;
 }
+
+int
+pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
+{
+    return pioctl_int(pathp, opcode, blobp, follow, TRUE);
+}
+
+int
+pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
+{
+    return pioctl_int(pathp, opcode, blobp, follow, FALSE);
+}
+