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();
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);
834 * Try to find the correct path and authentication
836 dwAttrib = GetFileAttributes(tbuffer);
837 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
840 gle = GetLastError();
841 if (gle && ioctlDebug ) {
845 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
848 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
854 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
861 /* with the redirector interface, fail immediately. there is nothing to retry */
865 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", szClient, sizeof(szClient)))
866 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
868 if (RegOpenKey (HKEY_CURRENT_USER,
869 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
871 DWORD dwType = REG_SZ;
872 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
879 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
882 sprintf(szPath, "\\\\%s", szClient);
883 memset (&nr, 0x00, sizeof(NETRESOURCE));
884 nr.dwType=RESOURCETYPE_DISK;
886 nr.lpRemoteName=szPath;
887 res = WNetAddConnection2(&nr,NULL,szUser,0);
891 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
898 sprintf(szPath, "\\\\%s\\all", szClient);
899 res = WNetAddConnection2(&nr,NULL,szUser,0);
903 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
911 goto try_lsa_principal;
913 dwAttrib = GetFileAttributes(tbuffer);
914 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
915 gle = GetLastError();
916 if (gle && ioctlDebug ) {
920 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
923 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
929 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
941 dwAttrib == INVALID_FILE_ATTRIBUTES) {
944 dwSize = sizeof(szUser);
945 if (GetLSAPrincipalName(szUser, dwSize)) {
948 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
951 sprintf(szPath, "\\\\%s", szClient);
952 memset (&nr, 0x00, sizeof(NETRESOURCE));
953 nr.dwType=RESOURCETYPE_DISK;
955 nr.lpRemoteName=szPath;
956 res = WNetAddConnection2(&nr,NULL,szUser,0);
960 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
967 sprintf(szPath, "\\\\%s\\all", szClient);
968 res = WNetAddConnection2(&nr,NULL,szUser,0);
972 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
982 dwAttrib = GetFileAttributes(tbuffer);
983 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
984 gle = GetLastError();
985 if (gle && ioctlDebug ) {
989 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
992 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
998 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
1010 dwAttrib == INVALID_FILE_ATTRIBUTES) {
1011 dwSize = sizeof(szUser);
1012 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
1015 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
1018 sprintf(szPath, "\\\\%s", szClient);
1019 memset (&nr, 0x00, sizeof(NETRESOURCE));
1020 nr.dwType=RESOURCETYPE_DISK;
1022 nr.lpRemoteName=szPath;
1023 res = WNetAddConnection2(&nr,NULL,szUser,0);
1027 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1033 sprintf(szPath, "\\\\%s\\all", szClient);
1034 res = WNetAddConnection2(&nr,NULL,szUser,0);
1038 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1045 dwAttrib = GetFileAttributes(tbuffer);
1046 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
1047 gle = GetLastError();
1048 if (gle && ioctlDebug ) {
1052 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1055 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1061 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
1069 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
1074 if ( dwAttrib != (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1075 fprintf(stderr, "GetFileAttributes(%s) returned: 0x%08X\r\n",
1080 /* tbuffer now contains the correct path; now open the file */
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);
1094 if (fh == INVALID_HANDLE_VALUE)
1097 /* return fh and success code */
1103 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
1108 DWORD ioctlDebug = IoctlDebug();
1111 rcount = (long)(reqp->mp - reqp->data);
1115 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
1118 return EINVAL; /* not supposed to happen */
1121 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
1122 /* failed to write */
1123 gle = GetLastError();
1127 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
1133 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
1134 /* failed to read */
1135 gle = GetLastError();
1139 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
1145 reqp->nbytes = ioCount; /* set # of bytes available */
1146 reqp->mp = reqp->data; /* restart marshalling */
1148 /* return success */
1153 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1155 memcpy(reqp->mp, &val, 4);
1161 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1165 /* not enough data left */
1166 if (reqp->nbytes < 4) {
1167 if ( IoctlDebug() ) {
1169 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1176 memcpy(valp, reqp->mp, 4);
1182 /* includes marshalling NULL pointer as a null (0 length) string */
1184 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1190 count = (int)strlen(stringp) + 1;/* space required including null */
1195 count += utf8_prefix_size;
1198 /* watch for buffer overflow */
1199 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1200 if ( IoctlDebug() ) {
1202 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1209 memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1210 reqp->mp += utf8_prefix_size;
1211 count -= utf8_prefix_size;
1215 memcpy(reqp->mp, stringp, count);
1222 /* take a path with a drive letter, possibly relative, and return a full path
1223 * without the drive letter. This is the full path relative to the working
1224 * dir for that drive letter. The input and output paths can be the same.
1227 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1230 char origPath[1000];
1239 if (pathp[0] != 0 && pathp[1] == ':') {
1240 /* there's a drive letter there */
1248 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1249 firstp[0] == '/' && firstp[1] == '/') {
1250 /* UNC path - strip off the server and sharename */
1252 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1253 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1257 if ( firstp[i] == 0 ) {
1258 strcpy(outPathp,"\\");
1260 strcpy(outPathp,&firstp[--i]);
1262 for (p=outPathp ;*p; p++) {
1267 } else if (firstp[0] == '\\' || firstp[0] == '/') {
1268 /* already an absolute pathname, just copy it back */
1269 strcpy(outPathp, firstp);
1270 for (p=outPathp ;*p; p++) {
1277 GetCurrentDirectory(sizeof(origPath), origPath);
1280 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
1281 /* a drive has been specified and it isn't our current drive.
1282 * to get path, switch to it first. Must case-fold drive letters
1283 * for user convenience.
1286 newPath[0] = *pathp;
1289 if (!SetCurrentDirectory(newPath)) {
1290 code = GetLastError();
1292 if ( IoctlDebug() ) {
1294 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1302 /* now get the absolute path to the current wdir in this drive */
1303 GetCurrentDirectory(sizeof(tpath), tpath);
1304 if (tpath[1] == ':')
1305 strcpy(outPathp, tpath + 2); /* skip drive letter */
1306 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
1307 tpath[0] == '/' && tpath[1] == '/') {
1308 /* UNC path - strip off the server and sharename */
1310 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1311 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1315 if ( tpath[i] == 0 ) {
1316 strcpy(outPathp,"\\");
1318 strcpy(outPathp,&tpath[--i]);
1321 /* this should never happen */
1322 strcpy(outPathp, tpath);
1325 /* if there is a non-null name after the drive, append it */
1327 int len = (int)strlen(outPathp);
1328 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1329 strcat(outPathp, "\\");
1330 strcat(outPathp, firstp);
1333 /* finally, if necessary, switch back to our home drive letter */
1335 SetCurrentDirectory(origPath);
1338 for (p=outPathp ;*p; p++) {
1346 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1348 fs_ioctlRequest_t preq;
1351 char fullPath[1000];
1358 * The pioctl operations for creating a mount point and a symlink are broken.
1359 * Instead of 'pathp' referring to the directory object in which the symlink
1360 * or mount point within which the new object is to be created, 'pathp' refers
1361 * to the object itself. This results in a problem when the object being created
1362 * is located within the Freelance root.afs volume. \\afs\foo will not be a
1363 * valid share name since the 'foo' object does not yet exist. Therefore,
1364 * \\afs\foo\_._.afs_ioctl_._ cannot be opened. Instead in these two cases
1365 * we must force the use of the \\afs\all\foo form of the path.
1367 * We cannot use this form in all cases because of smb submounts which are
1368 * not located within the Freelance local root.
1371 case VIOC_AFS_CREATE_MT_PT:
1374 (pathp[0] == '\\' && pathp[1] == '\\' ||
1375 pathp[0] == '/' && pathp[1] == '/')) {
1376 for (all = count = j = 0; pathp[j]; j++) {
1377 if (pathp[j] == '\\' || pathp[j] == '/')
1380 /* Test to see if the second component is 'all' */
1383 for (i=0; pathp[i+j]; i++) {
1386 if (pathp[i+j] != 'a' &&
1387 pathp[i+j] != 'A') {
1394 if (pathp[i+j] != 'l' &&
1395 pathp[i+j] != 'L') {
1415 * if count is three and the second component is not 'all',
1416 * then we are attempting to create an object in the
1417 * Freelance root.afs volume. Substitute the path.
1420 if (count == 3 && !all) {
1421 /* Normalize the name to use \\afs\all as the root */
1422 for (count = i = j = 0; pathp[j] && i < sizeof(altPath); j++) {
1423 if (pathp[j] == '\\' || pathp[j] == '/') {
1424 altPath[i++] = '\\';
1431 altPath[i++] = '\\';
1435 altPath[i++] = pathp[j];
1444 code = GetIoctlHandle(pathp, &reqHandle);
1453 /* init the request structure */
1454 InitFSRequest(&preq);
1456 /* marshall the opcode, the path name and the input parameters */
1457 MarshallLong(&preq, opcode);
1458 /* when marshalling the path, remove the drive letter, since we already
1459 * used the drive letter to find the AFS daemon; we don't need it any more.
1460 * Eventually we'll expand relative path names here, too, since again, only
1461 * we understand those.
1464 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1466 CloseHandle(reqHandle);
1471 strcpy(fullPath, "");
1474 MarshallString(&preq, fullPath, is_utf8);
1475 if (blobp->in_size) {
1476 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
1480 memcpy(preq.mp, blobp->in, blobp->in_size);
1481 preq.mp += blobp->in_size;
1484 /* now make the call */
1485 code = Transceive(reqHandle, &preq);
1487 CloseHandle(reqHandle);
1491 /* now unmarshall the return value */
1492 if (UnmarshallLong(&preq, &temp) != 0) {
1493 CloseHandle(reqHandle);
1498 CloseHandle(reqHandle);
1499 errno = CMtoUNIXerror(temp);
1500 if ( IoctlDebug() ) {
1502 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1508 /* otherwise, unmarshall the output parameters */
1509 if (blobp->out_size) {
1510 temp = blobp->out_size;
1511 if (preq.nbytes < temp)
1513 memcpy(blobp->out, preq.mp, temp);
1514 blobp->out_size = temp;
1517 /* and return success */
1518 CloseHandle(reqHandle);
1523 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1525 return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1529 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1531 return pioctl_int(pathp, opcode, blobp, follow, FALSE);