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
);
1140 if (gle
== ERROR_NOT_SUPPORTED
) {
1147 reqp
->nbytes
= ioCount
; /* set # of bytes available */
1148 reqp
->mp
= reqp
->data
; /* restart marshalling */
1150 /* return success */
1155 MarshallLong(fs_ioctlRequest_t
* reqp
, long val
)
1157 memcpy(reqp
->mp
, &val
, 4);
1163 UnmarshallLong(fs_ioctlRequest_t
* reqp
, long *valp
)
1167 /* not enough data left */
1168 if (reqp
->nbytes
< 4) {
1169 if ( IoctlDebug() ) {
1171 fprintf(stderr
, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1178 memcpy(valp
, reqp
->mp
, 4);
1184 /* includes marshalling NULL pointer as a null (0 length) string */
1186 MarshallString(fs_ioctlRequest_t
* reqp
, char *stringp
, int is_utf8
)
1192 count
= (int)strlen(stringp
) + 1;/* space required including null */
1197 count
+= utf8_prefix_size
;
1200 /* watch for buffer overflow */
1201 if ((reqp
->mp
- reqp
->data
) + count
> sizeof(reqp
->data
)) {
1202 if ( IoctlDebug() ) {
1204 fprintf(stderr
, "pioctl MarshallString buffer overflow\r\n");
1211 memcpy(reqp
->mp
, utf8_prefix
, utf8_prefix_size
);
1212 reqp
->mp
+= utf8_prefix_size
;
1213 count
-= utf8_prefix_size
;
1217 memcpy(reqp
->mp
, stringp
, count
);
1224 /* take a path with a drive letter, possibly relative, and return a full path
1225 * without the drive letter. This is the full path relative to the working
1226 * dir for that drive letter. The input and output paths can be the same.
1229 fs_GetFullPath(char *pathp
, char *outPathp
, long outSize
)
1232 char origPath
[1000];
1241 if (pathp
[0] != 0 && pathp
[1] == ':') {
1242 /* there's a drive letter there */
1250 if ( firstp
[0] == '\\' && firstp
[1] == '\\' ||
1251 firstp
[0] == '/' && firstp
[1] == '/') {
1252 /* UNC path - strip off the server and sharename */
1254 for ( i
=2,count
=2; count
< 4 && firstp
[i
]; i
++ ) {
1255 if ( firstp
[i
] == '\\' || firstp
[i
] == '/' ) {
1259 if ( firstp
[i
] == 0 ) {
1260 strcpy(outPathp
,"\\");
1262 strcpy(outPathp
,&firstp
[--i
]);
1264 for (p
=outPathp
;*p
; p
++) {
1269 } else if (firstp
[0] == '\\' || firstp
[0] == '/') {
1270 /* already an absolute pathname, just copy it back */
1271 strcpy(outPathp
, firstp
);
1272 for (p
=outPathp
;*p
; p
++) {
1279 GetCurrentDirectory(sizeof(origPath
), origPath
);
1282 if (pathHasDrive
&& (*pathp
& ~0x20) != (origPath
[0] & ~0x20)) {
1283 /* a drive has been specified and it isn't our current drive.
1284 * to get path, switch to it first. Must case-fold drive letters
1285 * for user convenience.
1288 newPath
[0] = *pathp
;
1291 if (!SetCurrentDirectory(newPath
)) {
1292 code
= GetLastError();
1294 if ( IoctlDebug() ) {
1296 fprintf(stderr
, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1304 /* now get the absolute path to the current wdir in this drive */
1305 GetCurrentDirectory(sizeof(tpath
), tpath
);
1306 if (tpath
[1] == ':')
1307 strcpy(outPathp
, tpath
+ 2); /* skip drive letter */
1308 else if ( tpath
[0] == '\\' && tpath
[1] == '\\'||
1309 tpath
[0] == '/' && tpath
[1] == '/') {
1310 /* UNC path - strip off the server and sharename */
1312 for ( i
=2,count
=2; count
< 4 && tpath
[i
]; i
++ ) {
1313 if ( tpath
[i
] == '\\' || tpath
[i
] == '/' ) {
1317 if ( tpath
[i
] == 0 ) {
1318 strcpy(outPathp
,"\\");
1320 strcpy(outPathp
,&tpath
[--i
]);
1323 /* this should never happen */
1324 strcpy(outPathp
, tpath
);
1327 /* if there is a non-null name after the drive, append it */
1329 int len
= (int)strlen(outPathp
);
1330 if (outPathp
[len
-1] != '\\' && outPathp
[len
-1] != '/')
1331 strcat(outPathp
, "\\");
1332 strcat(outPathp
, firstp
);
1335 /* finally, if necessary, switch back to our home drive letter */
1337 SetCurrentDirectory(origPath
);
1340 for (p
=outPathp
;*p
; p
++) {
1348 pioctl_int(char *pathp
, afs_int32 opcode
, struct ViceIoctl
*blobp
, afs_int32 follow
, afs_int32 is_utf8
)
1350 fs_ioctlRequest_t preq
;
1353 char fullPath
[1000];
1360 * The pioctl operations for creating a mount point and a symlink are broken.
1361 * Instead of 'pathp' referring to the directory object in which the symlink
1362 * or mount point within which the new object is to be created, 'pathp' refers
1363 * to the object itself. This results in a problem when the object being created
1364 * is located within the Freelance root.afs volume. \\afs\foo will not be a
1365 * valid share name since the 'foo' object does not yet exist. Therefore,
1366 * \\afs\foo\_._.afs_ioctl_._ cannot be opened. Instead in these two cases
1367 * we must force the use of the \\afs\all\foo form of the path.
1369 * We cannot use this form in all cases because of smb submounts which are
1370 * not located within the Freelance local root.
1373 case VIOC_AFS_CREATE_MT_PT
:
1376 (pathp
[0] == '\\' && pathp
[1] == '\\' ||
1377 pathp
[0] == '/' && pathp
[1] == '/')) {
1378 for (all
= count
= j
= 0; pathp
[j
]; j
++) {
1379 if (pathp
[j
] == '\\' || pathp
[j
] == '/')
1382 /* Test to see if the second component is 'all' */
1385 for (i
=0; pathp
[i
+j
]; i
++) {
1388 if (pathp
[i
+j
] != 'a' &&
1389 pathp
[i
+j
] != 'A') {
1396 if (pathp
[i
+j
] != 'l' &&
1397 pathp
[i
+j
] != 'L') {
1417 * if count is three and the second component is not 'all',
1418 * then we are attempting to create an object in the
1419 * Freelance root.afs volume. Substitute the path.
1422 if (count
== 3 && !all
) {
1423 /* Normalize the name to use \\afs\all as the root */
1424 for (count
= i
= j
= 0; pathp
[j
] && i
< sizeof(altPath
); j
++) {
1425 if (pathp
[j
] == '\\' || pathp
[j
] == '/') {
1426 altPath
[i
++] = '\\';
1433 altPath
[i
++] = '\\';
1437 altPath
[i
++] = pathp
[j
];
1446 code
= GetIoctlHandle(pathp
, &reqHandle
);
1455 /* init the request structure */
1456 InitFSRequest(&preq
);
1458 /* marshall the opcode, the path name and the input parameters */
1459 MarshallLong(&preq
, opcode
);
1460 /* when marshalling the path, remove the drive letter, since we already
1461 * used the drive letter to find the AFS daemon; we don't need it any more.
1462 * Eventually we'll expand relative path names here, too, since again, only
1463 * we understand those.
1466 code
= fs_GetFullPath(pathp
, fullPath
, sizeof(fullPath
));
1468 CloseHandle(reqHandle
);
1473 strcpy(fullPath
, "");
1476 MarshallString(&preq
, fullPath
, is_utf8
);
1477 if (blobp
->in_size
) {
1478 if (blobp
->in_size
> sizeof(preq
.data
) - (preq
.mp
- preq
.data
)*sizeof(char)) {
1482 memcpy(preq
.mp
, blobp
->in
, blobp
->in_size
);
1483 preq
.mp
+= blobp
->in_size
;
1486 /* now make the call */
1487 code
= Transceive(reqHandle
, &preq
);
1489 CloseHandle(reqHandle
);
1493 /* now unmarshall the return value */
1494 if (UnmarshallLong(&preq
, &temp
) != 0) {
1495 CloseHandle(reqHandle
);
1500 CloseHandle(reqHandle
);
1501 errno
= CMtoUNIXerror(temp
);
1502 if ( IoctlDebug() ) {
1504 fprintf(stderr
, "pioctl temp != 0: 0x%X\r\n",temp
);
1510 /* otherwise, unmarshall the output parameters */
1511 if (blobp
->out_size
) {
1512 temp
= blobp
->out_size
;
1513 if (preq
.nbytes
< temp
)
1515 memcpy(blobp
->out
, preq
.mp
, temp
);
1516 blobp
->out_size
= temp
;
1519 /* and return success */
1520 CloseHandle(reqHandle
);
1525 pioctl_utf8(char * pathp
, afs_int32 opcode
, struct ViceIoctl
* blobp
, afs_int32 follow
)
1527 return pioctl_int(pathp
, opcode
, blobp
, follow
, TRUE
);
1531 pioctl(char * pathp
, afs_int32 opcode
, struct ViceIoctl
* blobp
, afs_int32 follow
)
1533 return pioctl_int(pathp
, opcode
, blobp
, follow
, FALSE
);