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>
19 #define SECURITY_WIN32
29 #include <cm_server.h>
33 #include <cm_scache.h>
38 #include <smb_iocons.h>
40 #include <pioctl_nt.h>
41 #include <WINNT/afsreg.h>
42 #include <lanahelper.h>
45 #include <..\WINNT\afsrdr\common\AFSUserDefines.h>
46 #include <..\WINNT\afsrdr\common\AFSUserIoctl.h>
47 #include <..\WINNT\afsrdr\common\AFSUserStructs.h>
49 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
51 static const char utf8_prefix[] = UTF8_PREFIX;
52 static const int utf8_prefix_size = sizeof(utf8_prefix) - sizeof(char);
54 #define FS_IOCTLREQUEST_MAXSIZE 8192
55 /* big structure for representing and storing an IOCTL request */
56 typedef struct fs_ioctlRequest {
57 char *mp; /* marshalling/unmarshalling ptr */
58 long nbytes; /* bytes received (when unmarshalling) */
59 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
64 CMtoUNIXerror(int cm_code)
67 case CM_ERROR_TIMEDOUT:
69 case CM_ERROR_NOACCESS:
71 case CM_ERROR_NOSUCHFILE:
72 case CM_ERROR_NOSUCHPATH:
73 case CM_ERROR_BPLUS_NOMATCH:
80 case CM_ERROR_INEXACT_MATCH:
82 case CM_ERROR_CROSSDEVLINK:
88 case CM_ERROR_READONLY:
90 case CM_ERROR_WOULDBLOCK:
92 case CM_ERROR_NOSUCHCELL:
93 return ESRCH; /* hack */
94 case CM_ERROR_NOSUCHVOLUME:
95 return EPIPE; /* hack */
96 case CM_ERROR_NOMORETOKENS:
97 return EDOM; /* hack */
98 case CM_ERROR_TOOMANYBUFS:
99 return EFBIG; /* hack */
100 case CM_ERROR_ALLBUSY:
102 case CM_ERROR_ALLDOWN:
103 return ENOSYS; /* hack */
104 case CM_ERROR_ALLOFFLINE:
105 return ENXIO; /* hack */
107 if (cm_code > 0 && cm_code < EILSEQ)
115 InitFSRequest(fs_ioctlRequest_t * rp)
125 static BOOL debug = 0;
130 if (RegOpenKey (HKEY_LOCAL_MACHINE,
131 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
133 DWORD dwSize = sizeof(BOOL);
134 DWORD dwType = REG_DWORD;
135 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
148 HANDLE hDevHandle = NULL;
150 AFSDriverStatusRespCB *respBuffer = NULL;
154 hDevHandle = CreateFileW( AFS_SYMLINK_W,
155 GENERIC_READ | GENERIC_WRITE,
156 FILE_SHARE_READ | FILE_SHARE_WRITE,
161 if( hDevHandle == INVALID_HANDLE_VALUE)
163 DWORD gle = GetLastError();
165 if (gle && IoctlDebug() ) {
170 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
173 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
179 fprintf(stderr,"RDR_Ready CreateFile(%S) failed: 0x%X\r\n\t[%s]\r\n",
180 AFS_SYMLINK_W,gle,buf);
188 // Allocate a response buffer.
190 respBuffer = (AFSDriverStatusRespCB *)malloc( sizeof( AFSDriverStatusRespCB));
194 memset( respBuffer, '\0', sizeof( AFSDriverStatusRespCB));
196 if( !DeviceIoControl( hDevHandle,
197 IOCTL_AFS_STATUS_REQUEST,
201 sizeof( AFSDriverStatusRespCB),
206 // Error condition back from driver
208 DWORD gle = GetLastError();
210 if (gle && IoctlDebug() ) {
215 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
218 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
224 fprintf(stderr,"RDR_Ready CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
225 AFS_SYMLINK,gle,buf);
233 if (bytesReturned == sizeof(AFSDriverStatusRespCB))
235 ready = ( respBuffer->Status == AFS_DRIVER_STATUS_READY );
244 if (hDevHandle != INVALID_HANDLE_VALUE)
245 CloseHandle(hDevHandle);
251 DisableServiceManagerCheck(void)
254 static BOOL smcheck = 0;
259 if (RegOpenKey (HKEY_LOCAL_MACHINE,
260 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
262 DWORD dwSize = sizeof(BOOL);
263 DWORD dwType = REG_DWORD;
264 RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
276 LPSTR lpszMachineName,
277 LPSTR lpszServiceName,
278 DWORD *lpdwCurrentState)
281 SC_HANDLE schSCManager = NULL;
282 SC_HANDLE schService = NULL;
283 DWORD fdwDesiredAccess = 0;
284 SERVICE_STATUS ssServiceStatus = {0};
287 *lpdwCurrentState = 0;
289 fdwDesiredAccess = GENERIC_READ;
291 schSCManager = OpenSCManager(lpszMachineName,
295 if(schSCManager == NULL)
301 schService = OpenService(schSCManager,
305 if(schService == NULL)
311 fRet = QueryServiceStatus(schService,
320 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
324 CloseServiceHandle(schService);
325 CloseServiceHandle(schSCManager);
331 UnicodeToANSI(LPCWSTR lpInputString, LPSTR lpszOutputString, int nOutStringLen)
335 GetCPInfo(CP_ACP, &CodePageInfo);
337 if (CodePageInfo.MaxCharSize > 1) {
338 // Only supporting non-Unicode strings
339 int reqLen = WideCharToMultiByte( CP_ACP, 0,
341 NULL, 0, NULL, NULL);
342 if ( reqLen > nOutStringLen)
346 if (WideCharToMultiByte( CP_ACP,
350 nOutStringLen, NULL, NULL) == 0)
356 // Looks like unicode, better translate it
357 if (WideCharToMultiByte( CP_ACP,
361 nOutStringLen, NULL, NULL) == 0)
369 GetLSAPrincipalName(char * pszUser, DWORD dwUserSize)
371 KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
372 PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
374 PKERB_EXTERNAL_NAME pClientName = NULL;
375 PUNICODE_STRING pDomainName = NULL;
377 HANDLE hLogon = INVALID_HANDLE_VALUE;
380 NTSTATUS ntSubStatus = 0;
381 WCHAR * wchUser = NULL;
386 ntStatus = LsaConnectUntrusted( &hLogon);
387 if (FAILED(ntStatus))
390 Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
391 Name.Length = (USHORT)(sizeof(MICROSOFT_KERBEROS_NAME_A) - sizeof(char));
392 Name.MaximumLength = Name.Length;
394 ntStatus = LsaLookupAuthenticationPackage( hLogon, &Name, &PackageId);
395 if (FAILED(ntStatus))
398 memset(&CacheRequest, 0, sizeof(KERB_QUERY_TKT_CACHE_REQUEST));
399 CacheRequest.MessageType = KerbRetrieveTicketMessage;
400 CacheRequest.LogonId.LowPart = 0;
401 CacheRequest.LogonId.HighPart = 0;
403 ntStatus = LsaCallAuthenticationPackage( hLogon,
406 sizeof(CacheRequest),
410 if (FAILED(ntStatus) || FAILED(ntSubStatus))
413 /* We have a ticket in the response */
414 pClientName = pTicketResponse->Ticket.ClientName;
415 pDomainName = &pTicketResponse->Ticket.DomainName;
417 /* We want to return ClientName @ DomainName */
420 for ( sCount = 0; sCount < pClientName->NameCount; sCount++)
422 dwSize += pClientName->Names[sCount].Length;
424 dwSize += pDomainName->Length + sizeof(WCHAR);
426 if ( dwSize / sizeof(WCHAR) > dwUserSize )
429 wchUser = malloc(dwSize);
433 for ( sCount = 0, wchUser[0] = L'\0'; sCount < pClientName->NameCount; sCount++)
435 StringCbCatNW( wchUser, dwSize,
436 pClientName->Names[sCount].Buffer,
437 pClientName->Names[sCount].Length);
439 StringCbCatNW( wchUser, dwSize,
441 pDomainName->Length);
443 if ( !UnicodeToANSI( wchUser, pszUser, dwUserSize) )
453 if ( hLogon != INVALID_HANDLE_VALUE)
454 LsaDeregisterLogonProcess(hLogon);
456 if ( pTicketResponse ) {
457 SecureZeroMemory(pTicketResponse,ResponseSize);
458 LsaFreeReturnBuffer(pTicketResponse);
465 // Recursively evaluate drivestr to find the final
466 // dos drive letter to which the source is mapped.
469 DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
471 char device[MAX_PATH];
473 if ( QueryDosDevice(drivestr, device, MAX_PATH) )
475 if ( device[0] == '\\' &&
479 isalpha(device[4]) &&
482 device[0] = device[4];
485 if ( DriveSubstitution(device, subststr, substlen) )
489 subststr[0] = device[0];
495 if ( device[0] == '\\' &&
505 strncpy(&subststr[1], &device[7], substlen-1);
506 subststr[substlen-1] = '\0';
515 // drivestr - is "<drive-letter>:"
518 DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
520 DWORD dwResult, dwResultEnum;
522 DWORD cbBuffer = 16384; // 16K is a good size
523 DWORD cEntries = -1; // enumerate all possible entries
524 LPNETRESOURCE lpnrLocal; // pointer to enumerated structures
527 char subststr[MAX_PATH];
528 char device[MAX_PATH];
531 // Handle drive letter substitution created with "SUBST <drive> <path>".
532 // If a substitution has occurred, use the target drive letter instead
535 if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
537 if (subststr[0] == '\\' &&
540 if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
549 // Check for \Device\AFSRedirector
551 if (QueryDosDevice(drivestr, device, MAX_PATH) &&
552 _strnicmp( device, "\\Device\\AFSRedirector", strlen("\\Device\\AFSRedirector")) == 0) {
557 // Call the WNetOpenEnum function to begin the enumeration.
559 dwResult = WNetOpenEnum(RESOURCE_CONNECTED,
562 NULL, // NULL first time the function is called
563 &hEnum); // handle to the resource
565 if (dwResult != NO_ERROR)
569 // Call the GlobalAlloc function to allocate resources.
571 lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
572 if (lpnrLocal == NULL)
577 // Initialize the buffer.
579 ZeroMemory(lpnrLocal, cbBuffer);
581 // Call the WNetEnumResource function to continue
585 dwResultEnum = WNetEnumResource(hEnum, // resource handle
586 &cEntries, // defined locally as -1
587 lpnrLocal, // LPNETRESOURCE
588 &cbBuffer); // buffer size
590 // If the call succeeds, loop through the structures.
592 if (dwResultEnum == NO_ERROR) {
593 for (i = 0; i < cEntries; i++) {
594 if (lpnrLocal[i].lpLocalName &&
595 toupper(lpnrLocal[i].lpLocalName[0]) == toupper(drivestr[0])) {
597 // Skip the two backslashes at the start of the UNC device name
599 if ( _strnicmp( &(lpnrLocal[i].lpRemoteName[2]), NetbiosName, strlen(NetbiosName)) == 0 )
609 else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
612 while (dwResultEnum != ERROR_NO_MORE_ITEMS);
615 // Call the GlobalFree function to free the memory.
617 GlobalFree((HGLOBAL) lpnrLocal);
619 // Call WNetCloseEnum to end the enumeration.
621 dwResult = WNetCloseEnum(hEnum);
627 DriveIsGlobalAutoMapped(char *drivestr)
631 DWORD dwSubMountSize;
632 char szSubMount[260];
635 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
636 AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
637 0, KEY_QUERY_VALUE, &hKey);
638 if (dwResult != ERROR_SUCCESS)
641 dwSubMountSize = sizeof(szSubMount);
643 dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
646 if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
653 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
657 char netbiosName[MAX_NB_NAME_LENGTH]="AFS";
658 DWORD CurrentState = 0;
659 char HostName[64] = "";
660 char tbuffer[MAX_PATH]="";
662 char szUser[128] = "";
663 char szClient[MAX_PATH] = "";
664 char szPath[MAX_PATH] = "";
667 DWORD ioctlDebug = IoctlDebug();
669 DWORD dwSize = sizeof(szUser);
670 BOOL usingRDR = FALSE;
673 int sharingViolation;
675 memset(HostName, '\0', sizeof(HostName));
676 gethostname(HostName, sizeof(HostName));
677 if (!DisableServiceManagerCheck() &&
678 GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
679 CurrentState != SERVICE_RUNNING)
683 fprintf(stderr, "pioctl GetServiceStatus(%s) == %d\r\n",
684 HostName, CurrentState);
695 fprintf(stderr, "pioctl Redirector is ready\r\n");
699 if (RegOpenKey (HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, &hk) == 0)
701 DWORD dwSize = sizeof(netbiosName);
702 DWORD dwType = REG_SZ;
703 RegQueryValueExA (hk, "NetbiosName", NULL, &dwType, (PBYTE)netbiosName, &dwSize);
708 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
714 gle = GetLastError();
715 fprintf(stderr, "pioctl Unable to open \"HKLM\\%s\" using NetbiosName = \"AFS\" GLE=0x%x\r\n",
716 HostName, CurrentState, gle);
723 fprintf(stderr, "pioctl Redirector is not ready\r\n");
727 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", netbiosName, sizeof(netbiosName)))
728 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
732 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
738 drivep = strchr(fileNamep, ':');
739 if (drivep && (drivep - fileNamep) >= 1) {
740 tbuffer[0] = *(drivep - 1);
744 driveType = GetDriveType(tbuffer);
748 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
749 DriveIsGlobalAutoMapped(tbuffer))
750 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
755 if (DriveIsGlobalAutoMapped(tbuffer))
756 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
760 } else if (fileNamep[0] == fileNamep[1] &&
761 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
763 int count = 0, i = 0;
765 while (count < 4 && fileNamep[i]) {
766 tbuffer[i] = fileNamep[i];
767 if ( tbuffer[i] == '\\' ||
772 if (fileNamep[i] == 0 || (fileNamep[i-1] != '\\' && fileNamep[i-1] != '/'))
775 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
777 char curdir[MAX_PATH]="";
779 GetCurrentDirectory(sizeof(curdir), curdir);
780 if ( curdir[1] == ':' ) {
781 tbuffer[0] = curdir[0];
785 driveType = GetDriveType(tbuffer);
789 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
790 DriveIsGlobalAutoMapped(tbuffer))
791 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
796 if (DriveIsGlobalAutoMapped(tbuffer))
797 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
801 } else if (curdir[0] == curdir[1] &&
802 (curdir[0] == '\\' || curdir[0] == '/'))
804 int count = 0, i = 0;
806 while (count < 4 && curdir[i]) {
807 tbuffer[i] = curdir[i];
808 if ( tbuffer[i] == '\\' ||
813 if (curdir[i] == 0 || (curdir[i-1] != '\\' && curdir[i-1] != '/'))
816 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
821 /* No file name starting with drive colon specified, use UNC name */
822 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
827 fprintf(stderr, "pioctl filename = \"%s\"\r\n", tbuffer);
832 /* now open the file */
833 sharingViolation = 0;
835 if (sharingViolation)
837 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
838 FILE_SHARE_READ, NULL, OPEN_EXISTING,
839 FILE_FLAG_WRITE_THROUGH, NULL);
841 } while (fh == INVALID_HANDLE_VALUE &&
842 GetLastError() == ERROR_SHARING_VIOLATION &&
843 sharingViolation < 100);
846 if (fh == INVALID_HANDLE_VALUE) {
847 gle = GetLastError();
848 if (gle && ioctlDebug ) {
852 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
855 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
861 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
869 if (fh == INVALID_HANDLE_VALUE &&
870 GetLastError() != ERROR_SHARING_VIOLATION) {
873 /* with the redirector interface, fail immediately. there is nothing to retry */
877 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", szClient, sizeof(szClient)))
878 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
880 if (RegOpenKey (HKEY_CURRENT_USER,
881 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
883 DWORD dwType = REG_SZ;
884 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
891 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
894 sprintf(szPath, "\\\\%s", szClient);
895 memset (&nr, 0x00, sizeof(NETRESOURCE));
896 nr.dwType=RESOURCETYPE_DISK;
898 nr.lpRemoteName=szPath;
899 res = WNetAddConnection2(&nr,NULL,szUser,0);
903 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
910 sprintf(szPath, "\\\\%s\\all", szClient);
911 res = WNetAddConnection2(&nr,NULL,szUser,0);
915 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
923 goto try_lsa_principal;
925 sharingViolation = 0;
927 if (sharingViolation)
929 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
930 FILE_SHARE_READ, NULL, OPEN_EXISTING,
931 FILE_FLAG_WRITE_THROUGH, NULL);
933 } while (fh == INVALID_HANDLE_VALUE &&
934 GetLastError() == ERROR_SHARING_VIOLATION &&
935 sharingViolation < 100);
937 if (fh == INVALID_HANDLE_VALUE) {
938 gle = GetLastError();
939 if (gle && ioctlDebug ) {
943 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
946 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
952 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
964 fh == INVALID_HANDLE_VALUE &&
965 GetLastError() != ERROR_SHARING_VIOLATION) {
968 dwSize = sizeof(szUser);
969 if (GetLSAPrincipalName(szUser, dwSize)) {
972 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
975 sprintf(szPath, "\\\\%s", szClient);
976 memset (&nr, 0x00, sizeof(NETRESOURCE));
977 nr.dwType=RESOURCETYPE_DISK;
979 nr.lpRemoteName=szPath;
980 res = WNetAddConnection2(&nr,NULL,szUser,0);
984 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
991 sprintf(szPath, "\\\\%s\\all", szClient);
992 res = WNetAddConnection2(&nr,NULL,szUser,0);
996 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1004 goto try_sam_compat;
1006 sharingViolation = 0;
1008 if (sharingViolation)
1010 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
1011 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1012 FILE_FLAG_WRITE_THROUGH, NULL);
1014 } while (fh == INVALID_HANDLE_VALUE &&
1015 GetLastError() == ERROR_SHARING_VIOLATION &&
1016 sharingViolation < 100);
1018 if (fh == INVALID_HANDLE_VALUE) {
1019 gle = GetLastError();
1020 if (gle && ioctlDebug ) {
1024 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1027 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1033 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
1045 fh == INVALID_HANDLE_VALUE &&
1046 GetLastError() != ERROR_SHARING_VIOLATION) {
1047 dwSize = sizeof(szUser);
1048 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
1051 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
1054 sprintf(szPath, "\\\\%s", szClient);
1055 memset (&nr, 0x00, sizeof(NETRESOURCE));
1056 nr.dwType=RESOURCETYPE_DISK;
1058 nr.lpRemoteName=szPath;
1059 res = WNetAddConnection2(&nr,NULL,szUser,0);
1063 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1069 sprintf(szPath, "\\\\%s\\all", szClient);
1070 res = WNetAddConnection2(&nr,NULL,szUser,0);
1074 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1081 sharingViolation = 0;
1083 if (sharingViolation)
1085 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
1086 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1087 FILE_FLAG_WRITE_THROUGH, NULL);
1089 } while (fh == INVALID_HANDLE_VALUE &&
1090 GetLastError() == ERROR_SHARING_VIOLATION &&
1091 sharingViolation < 100);
1093 if (fh == INVALID_HANDLE_VALUE) {
1094 gle = GetLastError();
1095 if (gle && ioctlDebug ) {
1099 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1102 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1108 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
1116 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
1121 if (fh == INVALID_HANDLE_VALUE)
1124 /* return fh and success code */
1130 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
1135 DWORD ioctlDebug = IoctlDebug();
1138 rcount = (long)(reqp->mp - reqp->data);
1142 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
1145 return EINVAL; /* not supposed to happen */
1148 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
1149 /* failed to write */
1150 gle = GetLastError();
1154 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
1160 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
1161 /* failed to read */
1162 gle = GetLastError();
1166 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
1172 reqp->nbytes = ioCount; /* set # of bytes available */
1173 reqp->mp = reqp->data; /* restart marshalling */
1175 /* return success */
1180 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1182 memcpy(reqp->mp, &val, 4);
1188 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1192 /* not enough data left */
1193 if (reqp->nbytes < 4) {
1194 if ( IoctlDebug() ) {
1196 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1203 memcpy(valp, reqp->mp, 4);
1209 /* includes marshalling NULL pointer as a null (0 length) string */
1211 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1217 count = (int)strlen(stringp) + 1;/* space required including null */
1222 count += utf8_prefix_size;
1225 /* watch for buffer overflow */
1226 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1227 if ( IoctlDebug() ) {
1229 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1236 memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1237 reqp->mp += utf8_prefix_size;
1238 count -= utf8_prefix_size;
1242 memcpy(reqp->mp, stringp, count);
1249 /* take a path with a drive letter, possibly relative, and return a full path
1250 * without the drive letter. This is the full path relative to the working
1251 * dir for that drive letter. The input and output paths can be the same.
1254 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1257 char origPath[1000];
1266 if (pathp[0] != 0 && pathp[1] == ':') {
1267 /* there's a drive letter there */
1275 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1276 firstp[0] == '/' && firstp[1] == '/') {
1277 /* UNC path - strip off the server and sharename */
1279 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1280 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1284 if ( firstp[i] == 0 ) {
1285 strcpy(outPathp,"\\");
1287 strcpy(outPathp,&firstp[--i]);
1289 for (p=outPathp ;*p; p++) {
1294 } else if (firstp[0] == '\\' || firstp[0] == '/') {
1295 /* already an absolute pathname, just copy it back */
1296 strcpy(outPathp, firstp);
1297 for (p=outPathp ;*p; p++) {
1304 GetCurrentDirectory(sizeof(origPath), origPath);
1307 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
1308 /* a drive has been specified and it isn't our current drive.
1309 * to get path, switch to it first. Must case-fold drive letters
1310 * for user convenience.
1313 newPath[0] = *pathp;
1316 if (!SetCurrentDirectory(newPath)) {
1317 code = GetLastError();
1319 if ( IoctlDebug() ) {
1321 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1329 /* now get the absolute path to the current wdir in this drive */
1330 GetCurrentDirectory(sizeof(tpath), tpath);
1331 if (tpath[1] == ':')
1332 strcpy(outPathp, tpath + 2); /* skip drive letter */
1333 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
1334 tpath[0] == '/' && tpath[1] == '/') {
1335 /* UNC path - strip off the server and sharename */
1337 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1338 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1342 if ( tpath[i] == 0 ) {
1343 strcpy(outPathp,"\\");
1345 strcpy(outPathp,&tpath[--i]);
1348 /* this should never happen */
1349 strcpy(outPathp, tpath);
1352 /* if there is a non-null name after the drive, append it */
1354 int len = (int)strlen(outPathp);
1355 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1356 strcat(outPathp, "\\");
1357 strcat(outPathp, firstp);
1360 /* finally, if necessary, switch back to our home drive letter */
1362 SetCurrentDirectory(origPath);
1365 for (p=outPathp ;*p; p++) {
1373 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1375 fs_ioctlRequest_t preq;
1378 char fullPath[1000];
1385 * The pioctl operations for creating a mount point and a symlink are broken.
1386 * Instead of 'pathp' referring to the directory object in which the symlink
1387 * or mount point within which the new object is to be created, 'pathp' refers
1388 * to the object itself. This results in a problem when the object being created
1389 * is located within the Freelance root.afs volume. \\afs\foo will not be a
1390 * valid share name since the 'foo' object does not yet exist. Therefore,
1391 * \\afs\foo\_._.afs_ioctl_._ cannot be opened. Instead in these two cases
1392 * we must force the use of the \\afs\all\foo form of the path.
1394 * We cannot use this form in all cases because of smb submounts which are
1395 * not located within the Freelance local root.
1398 case VIOC_AFS_CREATE_MT_PT:
1401 (pathp[0] == '\\' && pathp[1] == '\\' ||
1402 pathp[0] == '/' && pathp[1] == '/')) {
1403 for (all = count = j = 0; pathp[j]; j++) {
1404 if (pathp[j] == '\\' || pathp[j] == '/')
1407 /* Test to see if the second component is 'all' */
1410 for (i=0; pathp[i+j]; i++) {
1413 if (pathp[i+j] != 'a' &&
1414 pathp[i+j] != 'A') {
1421 if (pathp[i+j] != 'l' &&
1422 pathp[i+j] != 'L') {
1442 * if count is three and the second component is not 'all',
1443 * then we are attempting to create an object in the
1444 * Freelance root.afs volume. Substitute the path.
1447 if (count == 3 && !all) {
1448 /* Normalize the name to use \\afs\all as the root */
1449 for (count = i = j = 0; pathp[j] && i < sizeof(altPath); j++) {
1450 if (pathp[j] == '\\' || pathp[j] == '/') {
1451 altPath[i++] = '\\';
1458 altPath[i++] = '\\';
1462 altPath[i++] = pathp[j];
1471 code = GetIoctlHandle(pathp, &reqHandle);
1480 /* init the request structure */
1481 InitFSRequest(&preq);
1483 /* marshall the opcode, the path name and the input parameters */
1484 MarshallLong(&preq, opcode);
1485 /* when marshalling the path, remove the drive letter, since we already
1486 * used the drive letter to find the AFS daemon; we don't need it any more.
1487 * Eventually we'll expand relative path names here, too, since again, only
1488 * we understand those.
1491 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1493 CloseHandle(reqHandle);
1498 strcpy(fullPath, "");
1501 MarshallString(&preq, fullPath, is_utf8);
1502 if (blobp->in_size) {
1503 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
1507 memcpy(preq.mp, blobp->in, blobp->in_size);
1508 preq.mp += blobp->in_size;
1511 /* now make the call */
1512 code = Transceive(reqHandle, &preq);
1514 CloseHandle(reqHandle);
1518 /* now unmarshall the return value */
1519 if (UnmarshallLong(&preq, &temp) != 0) {
1520 CloseHandle(reqHandle);
1525 CloseHandle(reqHandle);
1526 errno = CMtoUNIXerror(temp);
1527 if ( IoctlDebug() ) {
1529 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1535 /* otherwise, unmarshall the output parameters */
1536 if (blobp->out_size) {
1537 temp = blobp->out_size;
1538 if (preq.nbytes < temp)
1540 memcpy(blobp->out, preq.mp, temp);
1541 blobp->out_size = temp;
1544 /* and return success */
1545 CloseHandle(reqHandle);
1550 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1552 return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1556 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1558 return pioctl_int(pathp, opcode, blobp, follow, FALSE);