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 = calloc(1, sizeof( AFSDriverStatusRespCB));
193 if( !DeviceIoControl( hDevHandle,
194 IOCTL_AFS_STATUS_REQUEST,
198 sizeof( AFSDriverStatusRespCB),
203 // Error condition back from driver
205 DWORD gle = GetLastError();
207 if (gle && IoctlDebug() ) {
212 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
215 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
221 fprintf(stderr,"RDR_Ready CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
222 AFS_SYMLINK,gle,buf);
230 if (bytesReturned == sizeof(AFSDriverStatusRespCB))
232 ready = ( respBuffer->Status == AFS_DRIVER_STATUS_READY );
241 if (hDevHandle != INVALID_HANDLE_VALUE)
242 CloseHandle(hDevHandle);
248 DisableServiceManagerCheck(void)
251 static BOOL smcheck = 0;
256 if (RegOpenKey (HKEY_LOCAL_MACHINE,
257 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
259 DWORD dwSize = sizeof(BOOL);
260 DWORD dwType = REG_DWORD;
261 RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
273 LPSTR lpszMachineName,
274 LPSTR lpszServiceName,
275 DWORD *lpdwCurrentState)
278 SC_HANDLE schSCManager = NULL;
279 SC_HANDLE schService = NULL;
280 DWORD fdwDesiredAccess = 0;
281 SERVICE_STATUS ssServiceStatus = {0};
284 *lpdwCurrentState = 0;
286 fdwDesiredAccess = GENERIC_READ;
288 schSCManager = OpenSCManager(lpszMachineName,
292 if(schSCManager == NULL)
298 schService = OpenService(schSCManager,
302 if(schService == NULL)
308 fRet = QueryServiceStatus(schService,
317 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
321 CloseServiceHandle(schService);
322 CloseServiceHandle(schSCManager);
328 UnicodeToANSI(LPCWSTR lpInputString, LPSTR lpszOutputString, int nOutStringLen)
332 GetCPInfo(CP_ACP, &CodePageInfo);
334 if (CodePageInfo.MaxCharSize > 1) {
335 // Only supporting non-Unicode strings
336 int reqLen = WideCharToMultiByte( CP_ACP, 0,
338 NULL, 0, NULL, NULL);
339 if ( reqLen > nOutStringLen)
343 if (WideCharToMultiByte( CP_ACP,
347 nOutStringLen, NULL, NULL) == 0)
353 // Looks like unicode, better translate it
354 if (WideCharToMultiByte( CP_ACP,
358 nOutStringLen, NULL, NULL) == 0)
366 GetLSAPrincipalName(char * pszUser, DWORD dwUserSize)
368 KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
369 PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
371 PKERB_EXTERNAL_NAME pClientName = NULL;
372 PUNICODE_STRING pDomainName = NULL;
374 HANDLE hLogon = INVALID_HANDLE_VALUE;
377 NTSTATUS ntSubStatus = 0;
378 WCHAR * wchUser = NULL;
383 ntStatus = LsaConnectUntrusted( &hLogon);
384 if (FAILED(ntStatus))
387 Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
388 Name.Length = (USHORT)(sizeof(MICROSOFT_KERBEROS_NAME_A) - sizeof(char));
389 Name.MaximumLength = Name.Length;
391 ntStatus = LsaLookupAuthenticationPackage( hLogon, &Name, &PackageId);
392 if (FAILED(ntStatus))
395 memset(&CacheRequest, 0, sizeof(KERB_QUERY_TKT_CACHE_REQUEST));
396 CacheRequest.MessageType = KerbRetrieveTicketMessage;
397 CacheRequest.LogonId.LowPart = 0;
398 CacheRequest.LogonId.HighPart = 0;
400 ntStatus = LsaCallAuthenticationPackage( hLogon,
403 sizeof(CacheRequest),
407 if (FAILED(ntStatus) || FAILED(ntSubStatus))
410 /* We have a ticket in the response */
411 pClientName = pTicketResponse->Ticket.ClientName;
412 pDomainName = &pTicketResponse->Ticket.DomainName;
414 /* We want to return ClientName @ DomainName */
417 for ( sCount = 0; sCount < pClientName->NameCount; sCount++)
419 dwSize += pClientName->Names[sCount].Length;
421 dwSize += pDomainName->Length + sizeof(WCHAR);
423 if ( dwSize / sizeof(WCHAR) > dwUserSize )
426 wchUser = malloc(dwSize);
430 for ( sCount = 0, wchUser[0] = L'\0'; sCount < pClientName->NameCount; sCount++)
432 StringCbCatNW( wchUser, dwSize,
433 pClientName->Names[sCount].Buffer,
434 pClientName->Names[sCount].Length);
436 StringCbCatNW( wchUser, dwSize,
438 pDomainName->Length);
440 if ( !UnicodeToANSI( wchUser, pszUser, dwUserSize) )
450 if ( hLogon != INVALID_HANDLE_VALUE)
451 LsaDeregisterLogonProcess(hLogon);
453 if ( pTicketResponse ) {
454 SecureZeroMemory(pTicketResponse,ResponseSize);
455 LsaFreeReturnBuffer(pTicketResponse);
462 // Recursively evaluate drivestr to find the final
463 // dos drive letter to which the source is mapped.
466 DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
468 char device[MAX_PATH];
470 if ( QueryDosDevice(drivestr, device, MAX_PATH) )
472 if ( device[0] == '\\' &&
476 isalpha(device[4]) &&
479 device[0] = device[4];
482 if ( DriveSubstitution(device, subststr, substlen) )
486 subststr[0] = device[0];
492 if ( device[0] == '\\' &&
502 strncpy(&subststr[1], &device[7], substlen-1);
503 subststr[substlen-1] = '\0';
512 // drivestr - is "<drive-letter>:"
515 DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
517 DWORD dwResult, dwResultEnum;
519 DWORD cbBuffer = 16384; // 16K is a good size
520 DWORD cEntries = -1; // enumerate all possible entries
521 LPNETRESOURCE lpnrLocal; // pointer to enumerated structures
524 char subststr[MAX_PATH];
525 char device[MAX_PATH];
528 // Handle drive letter substitution created with "SUBST <drive> <path>".
529 // If a substitution has occurred, use the target drive letter instead
532 if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
534 if (subststr[0] == '\\' &&
537 if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
546 // Check for \Device\AFSRedirector
548 if (QueryDosDevice(drivestr, device, MAX_PATH) &&
549 _strnicmp( device, "\\Device\\AFSRedirector", strlen("\\Device\\AFSRedirector")) == 0) {
554 // Call the WNetOpenEnum function to begin the enumeration.
556 dwResult = WNetOpenEnum(RESOURCE_CONNECTED,
559 NULL, // NULL first time the function is called
560 &hEnum); // handle to the resource
562 if (dwResult != NO_ERROR)
566 // Call the GlobalAlloc function to allocate resources.
568 lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
569 if (lpnrLocal == NULL)
574 // Initialize the buffer.
576 ZeroMemory(lpnrLocal, cbBuffer);
578 // Call the WNetEnumResource function to continue
582 dwResultEnum = WNetEnumResource(hEnum, // resource handle
583 &cEntries, // defined locally as -1
584 lpnrLocal, // LPNETRESOURCE
585 &cbBuffer); // buffer size
587 // If the call succeeds, loop through the structures.
589 if (dwResultEnum == NO_ERROR) {
590 for (i = 0; i < cEntries; i++) {
591 if (lpnrLocal[i].lpLocalName &&
592 toupper(lpnrLocal[i].lpLocalName[0]) == toupper(drivestr[0])) {
594 // Skip the two backslashes at the start of the UNC device name
596 if ( _strnicmp( &(lpnrLocal[i].lpRemoteName[2]), NetbiosName, strlen(NetbiosName)) == 0 )
606 else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
609 while (dwResultEnum != ERROR_NO_MORE_ITEMS);
612 // Call the GlobalFree function to free the memory.
614 GlobalFree((HGLOBAL) lpnrLocal);
616 // Call WNetCloseEnum to end the enumeration.
618 dwResult = WNetCloseEnum(hEnum);
624 DriveIsGlobalAutoMapped(char *drivestr)
628 DWORD dwSubMountSize;
629 char szSubMount[260];
632 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
633 AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
634 0, KEY_QUERY_VALUE, &hKey);
635 if (dwResult != ERROR_SUCCESS)
638 dwSubMountSize = sizeof(szSubMount);
640 dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
643 if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
650 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
654 char netbiosName[MAX_NB_NAME_LENGTH]="AFS";
655 DWORD CurrentState = 0;
656 char HostName[64] = "";
657 char tbuffer[MAX_PATH]="";
659 char szUser[128] = "";
660 char szClient[MAX_PATH] = "";
661 char szPath[MAX_PATH] = "";
664 DWORD ioctlDebug = IoctlDebug();
667 DWORD dwSize = sizeof(szUser);
668 BOOL usingRDR = FALSE;
671 int sharingViolation;
673 memset(HostName, '\0', sizeof(HostName));
674 gethostname(HostName, sizeof(HostName));
675 if (!DisableServiceManagerCheck() &&
676 GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
677 CurrentState != SERVICE_RUNNING)
681 fprintf(stderr, "pioctl GetServiceStatus(%s) == %d\r\n",
682 HostName, CurrentState);
693 fprintf(stderr, "pioctl Redirector is ready\r\n");
697 if (RegOpenKey (HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, &hk) == 0)
699 DWORD dwSize = sizeof(netbiosName);
700 DWORD dwType = REG_SZ;
701 RegQueryValueExA (hk, "NetbiosName", NULL, &dwType, (PBYTE)netbiosName, &dwSize);
706 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
712 gle = GetLastError();
713 fprintf(stderr, "pioctl Unable to open \"HKLM\\%s\" using NetbiosName = \"AFS\" GLE=0x%x\r\n",
714 HostName, CurrentState, gle);
721 fprintf(stderr, "pioctl Redirector is not ready\r\n");
725 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", netbiosName, sizeof(netbiosName)))
726 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
730 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
736 drivep = strchr(fileNamep, ':');
737 if (drivep && (drivep - fileNamep) >= 1) {
738 tbuffer[0] = *(drivep - 1);
742 driveType = GetDriveType(tbuffer);
746 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
747 DriveIsGlobalAutoMapped(tbuffer))
748 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
753 if (DriveIsGlobalAutoMapped(tbuffer))
754 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
758 } else if (fileNamep[0] == fileNamep[1] &&
759 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
761 int count = 0, i = 0;
763 while (count < 4 && fileNamep[i]) {
764 tbuffer[i] = fileNamep[i];
765 if ( tbuffer[i] == '\\' ||
770 if (fileNamep[i] == 0 || (fileNamep[i-1] != '\\' && fileNamep[i-1] != '/'))
773 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
775 char curdir[MAX_PATH]="";
777 GetCurrentDirectory(sizeof(curdir), curdir);
778 if ( curdir[1] == ':' ) {
779 tbuffer[0] = curdir[0];
783 driveType = GetDriveType(tbuffer);
787 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
788 DriveIsGlobalAutoMapped(tbuffer))
789 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
794 if (DriveIsGlobalAutoMapped(tbuffer))
795 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
799 } else if (curdir[0] == curdir[1] &&
800 (curdir[0] == '\\' || curdir[0] == '/'))
802 int count = 0, i = 0;
804 while (count < 4 && curdir[i]) {
805 tbuffer[i] = curdir[i];
806 if ( tbuffer[i] == '\\' ||
811 if (curdir[i] == 0 || (curdir[i-1] != '\\' && curdir[i-1] != '/'))
814 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
819 /* No file name starting with drive colon specified, use UNC name */
820 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
825 fprintf(stderr, "pioctl filename = \"%s\"\r\n", tbuffer);
832 * Try to find the correct path and authentication
834 dwAttrib = GetFileAttributes(tbuffer);
835 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
838 gle = GetLastError();
839 if (gle && ioctlDebug ) {
843 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
846 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
852 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
859 /* with the redirector interface, fail immediately. there is nothing to retry */
863 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", szClient, sizeof(szClient)))
864 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
866 if (RegOpenKey (HKEY_CURRENT_USER,
867 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
869 DWORD dwType = REG_SZ;
870 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
877 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
880 sprintf(szPath, "\\\\%s", szClient);
881 memset (&nr, 0x00, sizeof(NETRESOURCE));
882 nr.dwType=RESOURCETYPE_DISK;
884 nr.lpRemoteName=szPath;
885 res = WNetAddConnection2(&nr,NULL,szUser,0);
889 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
896 sprintf(szPath, "\\\\%s\\all", szClient);
897 res = WNetAddConnection2(&nr,NULL,szUser,0);
901 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
909 goto try_lsa_principal;
911 dwAttrib = GetFileAttributes(tbuffer);
912 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
913 gle = GetLastError();
914 if (gle && ioctlDebug ) {
918 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
921 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
927 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
939 dwAttrib == INVALID_FILE_ATTRIBUTES) {
942 dwSize = sizeof(szUser);
943 if (GetLSAPrincipalName(szUser, dwSize)) {
946 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
949 sprintf(szPath, "\\\\%s", szClient);
950 memset (&nr, 0x00, sizeof(NETRESOURCE));
951 nr.dwType=RESOURCETYPE_DISK;
953 nr.lpRemoteName=szPath;
954 res = WNetAddConnection2(&nr,NULL,szUser,0);
958 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
965 sprintf(szPath, "\\\\%s\\all", szClient);
966 res = WNetAddConnection2(&nr,NULL,szUser,0);
970 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
980 dwAttrib = GetFileAttributes(tbuffer);
981 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
982 gle = GetLastError();
983 if (gle && ioctlDebug ) {
987 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
990 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
996 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
1008 dwAttrib == INVALID_FILE_ATTRIBUTES) {
1009 dwSize = sizeof(szUser);
1010 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
1013 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
1016 sprintf(szPath, "\\\\%s", szClient);
1017 memset (&nr, 0x00, sizeof(NETRESOURCE));
1018 nr.dwType=RESOURCETYPE_DISK;
1020 nr.lpRemoteName=szPath;
1021 res = WNetAddConnection2(&nr,NULL,szUser,0);
1025 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1031 sprintf(szPath, "\\\\%s\\all", szClient);
1032 res = WNetAddConnection2(&nr,NULL,szUser,0);
1036 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1043 dwAttrib = GetFileAttributes(tbuffer);
1044 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
1045 gle = GetLastError();
1046 if (gle && ioctlDebug ) {
1050 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1053 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1059 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
1067 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
1072 if ( dwAttrib != (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1073 fprintf(stderr, "GetFileAttributes(%s) returned: 0x%08X\r\n",
1078 /* tbuffer now contains the correct path; now open the file */
1079 sharingViolation = 0;
1081 if (sharingViolation)
1083 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
1084 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1085 FILE_FLAG_WRITE_THROUGH, NULL);
1087 } while (fh == INVALID_HANDLE_VALUE &&
1088 GetLastError() == ERROR_SHARING_VIOLATION &&
1089 sharingViolation < 100);
1092 if (fh == INVALID_HANDLE_VALUE)
1095 /* return fh and success code */
1101 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
1106 DWORD ioctlDebug = IoctlDebug();
1109 rcount = (long)(reqp->mp - reqp->data);
1113 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
1116 return EINVAL; /* not supposed to happen */
1119 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
1120 /* failed to write */
1121 gle = GetLastError();
1125 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
1131 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
1132 /* failed to read */
1133 gle = GetLastError();
1137 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
1143 reqp->nbytes = ioCount; /* set # of bytes available */
1144 reqp->mp = reqp->data; /* restart marshalling */
1146 /* return success */
1151 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1153 memcpy(reqp->mp, &val, 4);
1159 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1163 /* not enough data left */
1164 if (reqp->nbytes < 4) {
1165 if ( IoctlDebug() ) {
1167 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1174 memcpy(valp, reqp->mp, 4);
1180 /* includes marshalling NULL pointer as a null (0 length) string */
1182 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1188 count = (int)strlen(stringp) + 1;/* space required including null */
1193 count += utf8_prefix_size;
1196 /* watch for buffer overflow */
1197 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1198 if ( IoctlDebug() ) {
1200 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1207 memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1208 reqp->mp += utf8_prefix_size;
1209 count -= utf8_prefix_size;
1213 memcpy(reqp->mp, stringp, count);
1220 /* take a path with a drive letter, possibly relative, and return a full path
1221 * without the drive letter. This is the full path relative to the working
1222 * dir for that drive letter. The input and output paths can be the same.
1225 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1228 char origPath[1000];
1237 if (pathp[0] != 0 && pathp[1] == ':') {
1238 /* there's a drive letter there */
1246 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1247 firstp[0] == '/' && firstp[1] == '/') {
1248 /* UNC path - strip off the server and sharename */
1250 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1251 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1255 if ( firstp[i] == 0 ) {
1256 strcpy(outPathp,"\\");
1258 strcpy(outPathp,&firstp[--i]);
1260 for (p=outPathp ;*p; p++) {
1265 } else if (firstp[0] == '\\' || firstp[0] == '/') {
1266 /* already an absolute pathname, just copy it back */
1267 strcpy(outPathp, firstp);
1268 for (p=outPathp ;*p; p++) {
1275 GetCurrentDirectory(sizeof(origPath), origPath);
1278 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
1279 /* a drive has been specified and it isn't our current drive.
1280 * to get path, switch to it first. Must case-fold drive letters
1281 * for user convenience.
1284 newPath[0] = *pathp;
1287 if (!SetCurrentDirectory(newPath)) {
1288 code = GetLastError();
1290 if ( IoctlDebug() ) {
1292 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1300 /* now get the absolute path to the current wdir in this drive */
1301 GetCurrentDirectory(sizeof(tpath), tpath);
1302 if (tpath[1] == ':')
1303 strcpy(outPathp, tpath + 2); /* skip drive letter */
1304 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
1305 tpath[0] == '/' && tpath[1] == '/') {
1306 /* UNC path - strip off the server and sharename */
1308 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1309 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1313 if ( tpath[i] == 0 ) {
1314 strcpy(outPathp,"\\");
1316 strcpy(outPathp,&tpath[--i]);
1319 /* this should never happen */
1320 strcpy(outPathp, tpath);
1323 /* if there is a non-null name after the drive, append it */
1325 int len = (int)strlen(outPathp);
1326 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1327 strcat(outPathp, "\\");
1328 strcat(outPathp, firstp);
1331 /* finally, if necessary, switch back to our home drive letter */
1333 SetCurrentDirectory(origPath);
1336 for (p=outPathp ;*p; p++) {
1344 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1346 fs_ioctlRequest_t preq;
1349 char fullPath[1000];
1356 * The pioctl operations for creating a mount point and a symlink are broken.
1357 * Instead of 'pathp' referring to the directory object in which the symlink
1358 * or mount point within which the new object is to be created, 'pathp' refers
1359 * to the object itself. This results in a problem when the object being created
1360 * is located within the Freelance root.afs volume. \\afs\foo will not be a
1361 * valid share name since the 'foo' object does not yet exist. Therefore,
1362 * \\afs\foo\_._.afs_ioctl_._ cannot be opened. Instead in these two cases
1363 * we must force the use of the \\afs\all\foo form of the path.
1365 * We cannot use this form in all cases because of smb submounts which are
1366 * not located within the Freelance local root.
1369 case VIOC_AFS_CREATE_MT_PT:
1372 (pathp[0] == '\\' && pathp[1] == '\\' ||
1373 pathp[0] == '/' && pathp[1] == '/')) {
1374 for (all = count = j = 0; pathp[j]; j++) {
1375 if (pathp[j] == '\\' || pathp[j] == '/')
1378 /* Test to see if the second component is 'all' */
1381 for (i=0; pathp[i+j]; i++) {
1384 if (pathp[i+j] != 'a' &&
1385 pathp[i+j] != 'A') {
1392 if (pathp[i+j] != 'l' &&
1393 pathp[i+j] != 'L') {
1413 * if count is three and the second component is not 'all',
1414 * then we are attempting to create an object in the
1415 * Freelance root.afs volume. Substitute the path.
1418 if (count == 3 && !all) {
1419 /* Normalize the name to use \\afs\all as the root */
1420 for (count = i = j = 0; pathp[j] && i < sizeof(altPath); j++) {
1421 if (pathp[j] == '\\' || pathp[j] == '/') {
1422 altPath[i++] = '\\';
1429 altPath[i++] = '\\';
1433 altPath[i++] = pathp[j];
1442 code = GetIoctlHandle(pathp, &reqHandle);
1451 /* init the request structure */
1452 InitFSRequest(&preq);
1454 /* marshall the opcode, the path name and the input parameters */
1455 MarshallLong(&preq, opcode);
1456 /* when marshalling the path, remove the drive letter, since we already
1457 * used the drive letter to find the AFS daemon; we don't need it any more.
1458 * Eventually we'll expand relative path names here, too, since again, only
1459 * we understand those.
1462 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1464 CloseHandle(reqHandle);
1469 strcpy(fullPath, "");
1472 MarshallString(&preq, fullPath, is_utf8);
1473 if (blobp->in_size) {
1474 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
1478 memcpy(preq.mp, blobp->in, blobp->in_size);
1479 preq.mp += blobp->in_size;
1482 /* now make the call */
1483 code = Transceive(reqHandle, &preq);
1485 CloseHandle(reqHandle);
1489 /* now unmarshall the return value */
1490 if (UnmarshallLong(&preq, &temp) != 0) {
1491 CloseHandle(reqHandle);
1496 CloseHandle(reqHandle);
1497 errno = CMtoUNIXerror(temp);
1498 if ( IoctlDebug() ) {
1500 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1506 /* otherwise, unmarshall the output parameters */
1507 if (blobp->out_size) {
1508 temp = blobp->out_size;
1509 if (preq.nbytes < temp)
1511 memcpy(blobp->out, preq.mp, temp);
1512 blobp->out_size = temp;
1515 /* and return success */
1516 CloseHandle(reqHandle);
1521 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1523 return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1527 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1529 return pioctl_int(pathp, opcode, blobp, follow, FALSE);