2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #define SECURITY_WIN32
28 #include <cm_server.h>
32 #include <cm_scache.h>
37 #include <smb_iocons.h>
39 #include <pioctl_nt.h>
40 #include <WINNT/afsreg.h>
41 #include <lanahelper.h>
44 #include <..\WINNT\afsrdr\common\AFSUserDefines.h>
45 #include <..\WINNT\afsrdr\common\AFSUserIoctl.h>
46 #include <..\WINNT\afsrdr\common\AFSUserStructs.h>
48 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
50 static const char utf8_prefix[] = UTF8_PREFIX;
51 static const int utf8_prefix_size = sizeof(utf8_prefix) - sizeof(char);
53 #define FS_IOCTLREQUEST_MAXSIZE 8192
54 /* big structure for representing and storing an IOCTL request */
55 typedef struct fs_ioctlRequest {
56 char *mp; /* marshalling/unmarshalling ptr */
57 long nbytes; /* bytes received (when unmarshalling) */
58 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
63 CMtoUNIXerror(int cm_code)
66 case CM_ERROR_TIMEDOUT:
68 case CM_ERROR_NOACCESS:
70 case CM_ERROR_NOSUCHFILE:
71 case CM_ERROR_NOSUCHPATH:
72 case CM_ERROR_BPLUS_NOMATCH:
79 case CM_ERROR_INEXACT_MATCH:
81 case CM_ERROR_CROSSDEVLINK:
87 case CM_ERROR_READONLY:
89 case CM_ERROR_WOULDBLOCK:
91 case CM_ERROR_NOSUCHCELL:
92 return ESRCH; /* hack */
93 case CM_ERROR_NOSUCHVOLUME:
94 return EPIPE; /* hack */
95 case CM_ERROR_NOMORETOKENS:
96 return EDOM; /* hack */
97 case CM_ERROR_TOOMANYBUFS:
98 return EFBIG; /* hack */
99 case CM_ERROR_ALLBUSY:
101 case CM_ERROR_ALLDOWN:
102 return ENOSYS; /* hack */
103 case CM_ERROR_ALLOFFLINE:
104 return ENXIO; /* hack */
106 if (cm_code > 0 && cm_code < EILSEQ)
114 InitFSRequest(fs_ioctlRequest_t * rp)
124 static BOOL debug = 0;
129 if (RegOpenKey (HKEY_LOCAL_MACHINE,
130 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
132 DWORD dwSize = sizeof(BOOL);
133 DWORD dwType = REG_DWORD;
134 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
147 HANDLE hDevHandle = NULL;
149 AFSDriverStatusRespCB *respBuffer = NULL;
153 hDevHandle = CreateFileW( AFS_SYMLINK_W,
154 GENERIC_READ | GENERIC_WRITE,
155 FILE_SHARE_READ | FILE_SHARE_WRITE,
160 if( hDevHandle == INVALID_HANDLE_VALUE)
162 DWORD gle = GetLastError();
164 if (gle && IoctlDebug() ) {
169 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
172 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
178 fprintf(stderr,"RDR_Ready CreateFile(%S) failed: 0x%X\r\n\t[%s]\r\n",
179 AFS_SYMLINK_W,gle,buf);
187 // Allocate a response buffer.
189 respBuffer = (AFSDriverStatusRespCB *)malloc( sizeof( AFSDriverStatusRespCB));
193 memset( respBuffer, '\0', sizeof( AFSDriverStatusRespCB));
195 if( !DeviceIoControl( hDevHandle,
196 IOCTL_AFS_STATUS_REQUEST,
200 sizeof( AFSDriverStatusRespCB),
205 // Error condition back from driver
207 DWORD gle = GetLastError();
209 if (gle && IoctlDebug() ) {
214 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
217 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
223 fprintf(stderr,"RDR_Ready CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
224 AFS_SYMLINK,gle,buf);
232 if (bytesReturned == sizeof(AFSDriverStatusRespCB))
234 ready = ( respBuffer->Status == AFS_DRIVER_STATUS_READY );
243 if (hDevHandle != INVALID_HANDLE_VALUE)
244 CloseHandle(hDevHandle);
250 DisableServiceManagerCheck(void)
253 static BOOL smcheck = 0;
258 if (RegOpenKey (HKEY_LOCAL_MACHINE,
259 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
261 DWORD dwSize = sizeof(BOOL);
262 DWORD dwType = REG_DWORD;
263 RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
275 LPSTR lpszMachineName,
276 LPSTR lpszServiceName,
277 DWORD *lpdwCurrentState)
280 SC_HANDLE schSCManager = NULL;
281 SC_HANDLE schService = NULL;
282 DWORD fdwDesiredAccess = 0;
283 SERVICE_STATUS ssServiceStatus = {0};
286 *lpdwCurrentState = 0;
288 fdwDesiredAccess = GENERIC_READ;
290 schSCManager = OpenSCManager(lpszMachineName,
294 if(schSCManager == NULL)
300 schService = OpenService(schSCManager,
304 if(schService == NULL)
310 fRet = QueryServiceStatus(schService,
319 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
323 CloseServiceHandle(schService);
324 CloseServiceHandle(schSCManager);
330 UnicodeToANSI(LPCWSTR lpInputString, LPSTR lpszOutputString, int nOutStringLen)
334 GetCPInfo(CP_ACP, &CodePageInfo);
336 if (CodePageInfo.MaxCharSize > 1) {
337 // Only supporting non-Unicode strings
338 int reqLen = WideCharToMultiByte( CP_ACP, 0,
340 NULL, 0, NULL, NULL);
341 if ( reqLen > nOutStringLen)
345 if (WideCharToMultiByte( CP_ACP,
349 nOutStringLen, NULL, NULL) == 0)
355 // Looks like unicode, better translate it
356 if (WideCharToMultiByte( CP_ACP,
360 nOutStringLen, NULL, NULL) == 0)
368 GetLSAPrincipalName(char * pszUser, DWORD dwUserSize)
370 KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
371 PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
373 PKERB_EXTERNAL_NAME pClientName = NULL;
374 PUNICODE_STRING pDomainName = NULL;
376 HANDLE hLogon = INVALID_HANDLE_VALUE;
379 NTSTATUS ntSubStatus = 0;
380 WCHAR * wchUser = NULL;
385 ntStatus = LsaConnectUntrusted( &hLogon);
386 if (FAILED(ntStatus))
389 Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
390 Name.Length = (USHORT)(sizeof(MICROSOFT_KERBEROS_NAME_A) - sizeof(char));
391 Name.MaximumLength = Name.Length;
393 ntStatus = LsaLookupAuthenticationPackage( hLogon, &Name, &PackageId);
394 if (FAILED(ntStatus))
397 memset(&CacheRequest, 0, sizeof(KERB_QUERY_TKT_CACHE_REQUEST));
398 CacheRequest.MessageType = KerbRetrieveTicketMessage;
399 CacheRequest.LogonId.LowPart = 0;
400 CacheRequest.LogonId.HighPart = 0;
402 ntStatus = LsaCallAuthenticationPackage( hLogon,
405 sizeof(CacheRequest),
409 if (FAILED(ntStatus) || FAILED(ntSubStatus))
412 /* We have a ticket in the response */
413 pClientName = pTicketResponse->Ticket.ClientName;
414 pDomainName = &pTicketResponse->Ticket.DomainName;
416 /* We want to return ClientName @ DomainName */
419 for ( sCount = 0; sCount < pClientName->NameCount; sCount++)
421 dwSize += pClientName->Names[sCount].Length;
423 dwSize += pDomainName->Length + sizeof(WCHAR);
425 if ( dwSize / sizeof(WCHAR) > dwUserSize )
428 wchUser = malloc(dwSize);
432 for ( sCount = 0, wchUser[0] = L'\0'; sCount < pClientName->NameCount; sCount++)
434 StringCbCatNW( wchUser, dwSize,
435 pClientName->Names[sCount].Buffer,
436 pClientName->Names[sCount].Length);
438 StringCbCatNW( wchUser, dwSize,
440 pDomainName->Length);
442 if ( !UnicodeToANSI( wchUser, pszUser, dwUserSize) )
452 if ( hLogon != INVALID_HANDLE_VALUE)
453 LsaDeregisterLogonProcess(hLogon);
455 if ( pTicketResponse ) {
456 SecureZeroMemory(pTicketResponse,ResponseSize);
457 LsaFreeReturnBuffer(pTicketResponse);
464 // Recursively evaluate drivestr to find the final
465 // dos drive letter to which the source is mapped.
468 DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
470 char device[MAX_PATH];
472 if ( QueryDosDevice(drivestr, device, MAX_PATH) )
474 if ( device[0] == '\\' &&
478 isalpha(device[4]) &&
481 device[0] = device[4];
484 if ( DriveSubstitution(device, subststr, substlen) )
488 subststr[0] = device[0];
494 if ( device[0] == '\\' &&
504 strncpy(&subststr[1], &device[7], substlen-1);
505 subststr[substlen-1] = '\0';
514 // drivestr - is "<drive-letter>:"
517 DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
519 DWORD dwResult, dwResultEnum;
521 DWORD cbBuffer = 16384; // 16K is a good size
522 DWORD cEntries = -1; // enumerate all possible entries
523 LPNETRESOURCE lpnrLocal; // pointer to enumerated structures
526 char subststr[MAX_PATH];
527 char device[MAX_PATH];
530 // Handle drive letter substitution created with "SUBST <drive> <path>".
531 // If a substitution has occurred, use the target drive letter instead
534 if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
536 if (subststr[0] == '\\' &&
539 if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
548 // Check for \Device\AFSRedirector
550 if (QueryDosDevice(drivestr, device, MAX_PATH) &&
551 _strnicmp( device, "\\Device\\AFSRedirector", strlen("\\Device\\AFSRedirector")) == 0) {
556 // Call the WNetOpenEnum function to begin the enumeration.
558 dwResult = WNetOpenEnum(RESOURCE_CONNECTED,
561 NULL, // NULL first time the function is called
562 &hEnum); // handle to the resource
564 if (dwResult != NO_ERROR)
568 // Call the GlobalAlloc function to allocate resources.
570 lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
571 if (lpnrLocal == NULL)
576 // Initialize the buffer.
578 ZeroMemory(lpnrLocal, cbBuffer);
580 // Call the WNetEnumResource function to continue
584 dwResultEnum = WNetEnumResource(hEnum, // resource handle
585 &cEntries, // defined locally as -1
586 lpnrLocal, // LPNETRESOURCE
587 &cbBuffer); // buffer size
589 // If the call succeeds, loop through the structures.
591 if (dwResultEnum == NO_ERROR) {
592 for (i = 0; i < cEntries; i++) {
593 if (lpnrLocal[i].lpLocalName &&
594 toupper(lpnrLocal[i].lpLocalName[0]) == toupper(drivestr[0])) {
596 // Skip the two backslashes at the start of the UNC device name
598 if ( _strnicmp( &(lpnrLocal[i].lpRemoteName[2]), NetbiosName, strlen(NetbiosName)) == 0 )
608 else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
611 while (dwResultEnum != ERROR_NO_MORE_ITEMS);
614 // Call the GlobalFree function to free the memory.
616 GlobalFree((HGLOBAL) lpnrLocal);
618 // Call WNetCloseEnum to end the enumeration.
620 dwResult = WNetCloseEnum(hEnum);
626 DriveIsGlobalAutoMapped(char *drivestr)
630 DWORD dwSubMountSize;
631 char szSubMount[260];
634 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
635 AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
636 0, KEY_QUERY_VALUE, &hKey);
637 if (dwResult != ERROR_SUCCESS)
640 dwSubMountSize = sizeof(szSubMount);
642 dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
645 if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
652 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
656 char netbiosName[MAX_NB_NAME_LENGTH]="AFS";
657 DWORD CurrentState = 0;
658 char HostName[64] = "";
659 char tbuffer[MAX_PATH]="";
661 char szUser[128] = "";
662 char szClient[MAX_PATH] = "";
663 char szPath[MAX_PATH] = "";
666 DWORD ioctlDebug = IoctlDebug();
668 DWORD dwSize = sizeof(szUser);
669 BOOL usingRDR = FALSE;
672 int sharingViolation;
674 memset(HostName, '\0', sizeof(HostName));
675 gethostname(HostName, sizeof(HostName));
676 if (!DisableServiceManagerCheck() &&
677 GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
678 CurrentState != SERVICE_RUNNING)
682 fprintf(stderr, "pioctl GetServiceStatus(%s) == %d\r\n",
683 HostName, CurrentState);
694 fprintf(stderr, "pioctl Redirector is ready\r\n");
698 if (RegOpenKey (HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, &hk) == 0)
700 DWORD dwSize = sizeof(netbiosName);
701 DWORD dwType = REG_SZ;
702 RegQueryValueExA (hk, "NetbiosName", NULL, &dwType, (PBYTE)netbiosName, &dwSize);
707 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
713 gle = GetLastError();
714 fprintf(stderr, "pioctl Unable to open \"HKLM\\%s\" using NetbiosName = \"AFS\" GLE=0x%x\r\n",
715 HostName, CurrentState, gle);
722 fprintf(stderr, "pioctl Redirector is not ready\r\n");
726 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", netbiosName, sizeof(netbiosName)))
727 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
731 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
737 drivep = strchr(fileNamep, ':');
738 if (drivep && (drivep - fileNamep) >= 1) {
739 tbuffer[0] = *(drivep - 1);
743 driveType = GetDriveType(tbuffer);
747 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
748 DriveIsGlobalAutoMapped(tbuffer))
749 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
754 if (DriveIsGlobalAutoMapped(tbuffer))
755 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
759 } else if (fileNamep[0] == fileNamep[1] &&
760 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
762 int count = 0, i = 0;
764 while (count < 4 && fileNamep[i]) {
765 tbuffer[i] = fileNamep[i];
766 if ( tbuffer[i] == '\\' ||
771 if (fileNamep[i] == 0 || (fileNamep[i-1] != '\\' && fileNamep[i-1] != '/'))
774 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
776 char curdir[MAX_PATH]="";
778 GetCurrentDirectory(sizeof(curdir), curdir);
779 if ( curdir[1] == ':' ) {
780 tbuffer[0] = curdir[0];
784 driveType = GetDriveType(tbuffer);
788 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
789 DriveIsGlobalAutoMapped(tbuffer))
790 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
795 if (DriveIsGlobalAutoMapped(tbuffer))
796 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
800 } else if (curdir[0] == curdir[1] &&
801 (curdir[0] == '\\' || curdir[0] == '/'))
803 int count = 0, i = 0;
805 while (count < 4 && curdir[i]) {
806 tbuffer[i] = curdir[i];
807 if ( tbuffer[i] == '\\' ||
812 if (curdir[i] == 0 || (curdir[i-1] != '\\' && curdir[i-1] != '/'))
815 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
820 /* No file name starting with drive colon specified, use UNC name */
821 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
826 fprintf(stderr, "pioctl filename = \"%s\"\r\n", tbuffer);
831 /* now open the file */
832 sharingViolation = 0;
834 if (sharingViolation)
836 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
837 FILE_SHARE_READ, NULL, OPEN_EXISTING,
838 FILE_FLAG_WRITE_THROUGH, NULL);
840 } while (fh == INVALID_HANDLE_VALUE &&
841 GetLastError() == ERROR_SHARING_VIOLATION &&
842 sharingViolation < 100);
845 if (fh == INVALID_HANDLE_VALUE) {
846 gle = GetLastError();
847 if (gle && ioctlDebug ) {
851 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
854 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
860 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
868 if (fh == INVALID_HANDLE_VALUE &&
869 GetLastError() != ERROR_SHARING_VIOLATION) {
872 /* with the redirector interface, fail immediately. there is nothing to retry */
876 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", szClient, sizeof(szClient)))
877 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
879 if (RegOpenKey (HKEY_CURRENT_USER,
880 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
882 DWORD dwType = REG_SZ;
883 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
890 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
893 sprintf(szPath, "\\\\%s", szClient);
894 memset (&nr, 0x00, sizeof(NETRESOURCE));
895 nr.dwType=RESOURCETYPE_DISK;
897 nr.lpRemoteName=szPath;
898 res = WNetAddConnection2(&nr,NULL,szUser,0);
902 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
909 sprintf(szPath, "\\\\%s\\all", szClient);
910 res = WNetAddConnection2(&nr,NULL,szUser,0);
914 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
922 goto try_lsa_principal;
924 sharingViolation = 0;
926 if (sharingViolation)
928 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
929 FILE_SHARE_READ, NULL, OPEN_EXISTING,
930 FILE_FLAG_WRITE_THROUGH, NULL);
932 } while (fh == INVALID_HANDLE_VALUE &&
933 GetLastError() == ERROR_SHARING_VIOLATION &&
934 sharingViolation < 100);
936 if (fh == INVALID_HANDLE_VALUE) {
937 gle = GetLastError();
938 if (gle && ioctlDebug ) {
942 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
945 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
951 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
963 fh == INVALID_HANDLE_VALUE &&
964 GetLastError() != ERROR_SHARING_VIOLATION) {
967 dwSize = sizeof(szUser);
968 if (GetLSAPrincipalName(szUser, dwSize)) {
971 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
974 sprintf(szPath, "\\\\%s", szClient);
975 memset (&nr, 0x00, sizeof(NETRESOURCE));
976 nr.dwType=RESOURCETYPE_DISK;
978 nr.lpRemoteName=szPath;
979 res = WNetAddConnection2(&nr,NULL,szUser,0);
983 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
990 sprintf(szPath, "\\\\%s\\all", szClient);
991 res = WNetAddConnection2(&nr,NULL,szUser,0);
995 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1003 goto try_sam_compat;
1005 sharingViolation = 0;
1007 if (sharingViolation)
1009 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
1010 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1011 FILE_FLAG_WRITE_THROUGH, NULL);
1013 } while (fh == INVALID_HANDLE_VALUE &&
1014 GetLastError() == ERROR_SHARING_VIOLATION &&
1015 sharingViolation < 100);
1017 if (fh == INVALID_HANDLE_VALUE) {
1018 gle = GetLastError();
1019 if (gle && ioctlDebug ) {
1023 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1026 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1032 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
1044 fh == INVALID_HANDLE_VALUE &&
1045 GetLastError() != ERROR_SHARING_VIOLATION) {
1046 dwSize = sizeof(szUser);
1047 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
1050 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
1053 sprintf(szPath, "\\\\%s", szClient);
1054 memset (&nr, 0x00, sizeof(NETRESOURCE));
1055 nr.dwType=RESOURCETYPE_DISK;
1057 nr.lpRemoteName=szPath;
1058 res = WNetAddConnection2(&nr,NULL,szUser,0);
1062 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1068 sprintf(szPath, "\\\\%s\\all", szClient);
1069 res = WNetAddConnection2(&nr,NULL,szUser,0);
1073 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1080 sharingViolation = 0;
1082 if (sharingViolation)
1084 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
1085 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1086 FILE_FLAG_WRITE_THROUGH, NULL);
1088 } while (fh == INVALID_HANDLE_VALUE &&
1089 GetLastError() == ERROR_SHARING_VIOLATION &&
1090 sharingViolation < 100);
1092 if (fh == INVALID_HANDLE_VALUE) {
1093 gle = GetLastError();
1094 if (gle && ioctlDebug ) {
1098 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1101 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1107 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
1115 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
1120 if (fh == INVALID_HANDLE_VALUE)
1123 /* return fh and success code */
1129 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
1134 DWORD ioctlDebug = IoctlDebug();
1137 rcount = (long)(reqp->mp - reqp->data);
1141 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
1144 return EINVAL; /* not supposed to happen */
1147 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
1148 /* failed to write */
1149 gle = GetLastError();
1153 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
1159 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
1160 /* failed to read */
1161 gle = GetLastError();
1165 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
1171 reqp->nbytes = ioCount; /* set # of bytes available */
1172 reqp->mp = reqp->data; /* restart marshalling */
1174 /* return success */
1179 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1181 memcpy(reqp->mp, &val, 4);
1187 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1191 /* not enough data left */
1192 if (reqp->nbytes < 4) {
1193 if ( IoctlDebug() ) {
1195 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1202 memcpy(valp, reqp->mp, 4);
1208 /* includes marshalling NULL pointer as a null (0 length) string */
1210 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1216 count = (int)strlen(stringp) + 1;/* space required including null */
1221 count += utf8_prefix_size;
1224 /* watch for buffer overflow */
1225 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1226 if ( IoctlDebug() ) {
1228 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1235 memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1236 reqp->mp += utf8_prefix_size;
1237 count -= utf8_prefix_size;
1241 memcpy(reqp->mp, stringp, count);
1248 /* take a path with a drive letter, possibly relative, and return a full path
1249 * without the drive letter. This is the full path relative to the working
1250 * dir for that drive letter. The input and output paths can be the same.
1253 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1256 char origPath[1000];
1265 if (pathp[0] != 0 && pathp[1] == ':') {
1266 /* there's a drive letter there */
1274 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1275 firstp[0] == '/' && firstp[1] == '/') {
1276 /* UNC path - strip off the server and sharename */
1278 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1279 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1283 if ( firstp[i] == 0 ) {
1284 strcpy(outPathp,"\\");
1286 strcpy(outPathp,&firstp[--i]);
1288 for (p=outPathp ;*p; p++) {
1293 } else if (firstp[0] == '\\' || firstp[0] == '/') {
1294 /* already an absolute pathname, just copy it back */
1295 strcpy(outPathp, firstp);
1296 for (p=outPathp ;*p; p++) {
1303 GetCurrentDirectory(sizeof(origPath), origPath);
1306 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
1307 /* a drive has been specified and it isn't our current drive.
1308 * to get path, switch to it first. Must case-fold drive letters
1309 * for user convenience.
1312 newPath[0] = *pathp;
1315 if (!SetCurrentDirectory(newPath)) {
1316 code = GetLastError();
1318 if ( IoctlDebug() ) {
1320 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1328 /* now get the absolute path to the current wdir in this drive */
1329 GetCurrentDirectory(sizeof(tpath), tpath);
1330 if (tpath[1] == ':')
1331 strcpy(outPathp, tpath + 2); /* skip drive letter */
1332 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
1333 tpath[0] == '/' && tpath[1] == '/') {
1334 /* UNC path - strip off the server and sharename */
1336 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1337 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1341 if ( tpath[i] == 0 ) {
1342 strcpy(outPathp,"\\");
1344 strcpy(outPathp,&tpath[--i]);
1347 /* this should never happen */
1348 strcpy(outPathp, tpath);
1351 /* if there is a non-null name after the drive, append it */
1353 int len = (int)strlen(outPathp);
1354 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1355 strcat(outPathp, "\\");
1356 strcat(outPathp, firstp);
1359 /* finally, if necessary, switch back to our home drive letter */
1361 SetCurrentDirectory(origPath);
1364 for (p=outPathp ;*p; p++) {
1372 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1374 fs_ioctlRequest_t preq;
1377 char fullPath[1000];
1384 * The pioctl operations for creating a mount point and a symlink are broken.
1385 * Instead of 'pathp' referring to the directory object in which the symlink
1386 * or mount point within which the new object is to be created, 'pathp' refers
1387 * to the object itself. This results in a problem when the object being created
1388 * is located within the Freelance root.afs volume. \\afs\foo will not be a
1389 * valid share name since the 'foo' object does not yet exist. Therefore,
1390 * \\afs\foo\_._.afs_ioctl_._ cannot be opened. Instead in these two cases
1391 * we must force the use of the \\afs\all\foo form of the path.
1393 * We cannot use this form in all cases because of smb submounts which are
1394 * not located within the Freelance local root.
1397 case VIOC_AFS_CREATE_MT_PT:
1400 (pathp[0] == '\\' && pathp[1] == '\\' ||
1401 pathp[0] == '/' && pathp[1] == '/')) {
1402 for (all = count = j = 0; pathp[j]; j++) {
1403 if (pathp[j] == '\\' || pathp[j] == '/')
1406 /* Test to see if the second component is 'all' */
1409 for (i=0; pathp[i+j]; i++) {
1412 if (pathp[i+j] != 'a' &&
1413 pathp[i+j] != 'A') {
1420 if (pathp[i+j] != 'l' &&
1421 pathp[i+j] != 'L') {
1441 * if count is three and the second component is not 'all',
1442 * then we are attempting to create an object in the
1443 * Freelance root.afs volume. Substitute the path.
1446 if (count == 3 && !all) {
1447 /* Normalize the name to use \\afs\all as the root */
1448 for (count = i = j = 0; pathp[j] && i < sizeof(altPath); j++) {
1449 if (pathp[j] == '\\' || pathp[j] == '/') {
1450 altPath[i++] = '\\';
1457 altPath[i++] = '\\';
1461 altPath[i++] = pathp[j];
1470 code = GetIoctlHandle(pathp, &reqHandle);
1479 /* init the request structure */
1480 InitFSRequest(&preq);
1482 /* marshall the opcode, the path name and the input parameters */
1483 MarshallLong(&preq, opcode);
1484 /* when marshalling the path, remove the drive letter, since we already
1485 * used the drive letter to find the AFS daemon; we don't need it any more.
1486 * Eventually we'll expand relative path names here, too, since again, only
1487 * we understand those.
1490 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1492 CloseHandle(reqHandle);
1497 strcpy(fullPath, "");
1500 MarshallString(&preq, fullPath, is_utf8);
1501 if (blobp->in_size) {
1502 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
1506 memcpy(preq.mp, blobp->in, blobp->in_size);
1507 preq.mp += blobp->in_size;
1510 /* now make the call */
1511 code = Transceive(reqHandle, &preq);
1513 CloseHandle(reqHandle);
1517 /* now unmarshall the return value */
1518 if (UnmarshallLong(&preq, &temp) != 0) {
1519 CloseHandle(reqHandle);
1524 CloseHandle(reqHandle);
1525 errno = CMtoUNIXerror(temp);
1526 if ( IoctlDebug() ) {
1528 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1534 /* otherwise, unmarshall the output parameters */
1535 if (blobp->out_size) {
1536 temp = blobp->out_size;
1537 if (preq.nbytes < temp)
1539 memcpy(blobp->out, preq.mp, temp);
1540 blobp->out_size = temp;
1543 /* and return success */
1544 CloseHandle(reqHandle);
1549 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1551 return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1555 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1557 return pioctl_int(pathp, opcode, blobp, follow, FALSE);