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>
23 #define SECURITY_WIN32
31 #include <cm_server.h>
35 #include <cm_scache.h>
42 #include <pioctl_nt.h>
43 #include <WINNT/afsreg.h>
44 #include <lanahelper.h>
46 #include <loadfuncs-krb5.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 */
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);
145 DisableServiceManagerCheck(void)
148 static BOOL smcheck = 0;
153 if (RegOpenKey (HKEY_LOCAL_MACHINE,
154 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
156 DWORD dwSize = sizeof(BOOL);
157 DWORD dwType = REG_DWORD;
158 RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
170 LPSTR lpszMachineName,
171 LPSTR lpszServiceName,
172 DWORD *lpdwCurrentState)
175 SC_HANDLE schSCManager = NULL;
176 SC_HANDLE schService = NULL;
177 DWORD fdwDesiredAccess = 0;
178 SERVICE_STATUS ssServiceStatus = {0};
181 *lpdwCurrentState = 0;
183 fdwDesiredAccess = GENERIC_READ;
185 schSCManager = OpenSCManager(lpszMachineName,
189 if(schSCManager == NULL)
195 schService = OpenService(schSCManager,
199 if(schService == NULL)
205 fRet = QueryServiceStatus(schService,
214 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
218 CloseServiceHandle(schService);
219 CloseServiceHandle(schSCManager);
225 DECL_FUNC_PTR(krb5_cc_default_name);
226 DECL_FUNC_PTR(krb5_cc_set_default_name);
227 DECL_FUNC_PTR(krb5_get_default_config_files);
228 DECL_FUNC_PTR(krb5_free_config_files);
229 DECL_FUNC_PTR(krb5_free_context);
230 DECL_FUNC_PTR(krb5_get_default_realm);
231 DECL_FUNC_PTR(krb5_free_default_realm);
232 DECL_FUNC_PTR(krb5_init_context);
233 DECL_FUNC_PTR(krb5_cc_default);
234 DECL_FUNC_PTR(krb5_parse_name);
235 DECL_FUNC_PTR(krb5_free_principal);
236 DECL_FUNC_PTR(krb5_cc_close);
237 DECL_FUNC_PTR(krb5_cc_get_principal);
238 DECL_FUNC_PTR(krb5_build_principal);
239 DECL_FUNC_PTR(krb5_c_random_make_octets);
240 DECL_FUNC_PTR(krb5_get_init_creds_password);
241 DECL_FUNC_PTR(krb5_free_cred_contents);
242 DECL_FUNC_PTR(krb5_cc_resolve);
243 DECL_FUNC_PTR(krb5_unparse_name);
244 DECL_FUNC_PTR(krb5_free_unparsed_name);
246 FUNC_INFO krb5_fi[] = {
247 MAKE_FUNC_INFO(krb5_cc_default_name),
248 MAKE_FUNC_INFO(krb5_cc_set_default_name),
249 MAKE_FUNC_INFO(krb5_get_default_config_files),
250 MAKE_FUNC_INFO(krb5_free_config_files),
251 MAKE_FUNC_INFO(krb5_free_context),
252 MAKE_FUNC_INFO(krb5_get_default_realm),
253 MAKE_FUNC_INFO(krb5_free_default_realm),
254 MAKE_FUNC_INFO(krb5_init_context),
255 MAKE_FUNC_INFO(krb5_cc_default),
256 MAKE_FUNC_INFO(krb5_parse_name),
257 MAKE_FUNC_INFO(krb5_free_principal),
258 MAKE_FUNC_INFO(krb5_cc_close),
259 MAKE_FUNC_INFO(krb5_cc_get_principal),
260 MAKE_FUNC_INFO(krb5_build_principal),
261 MAKE_FUNC_INFO(krb5_c_random_make_octets),
262 MAKE_FUNC_INFO(krb5_get_init_creds_password),
263 MAKE_FUNC_INFO(krb5_free_cred_contents),
264 MAKE_FUNC_INFO(krb5_cc_resolve),
265 MAKE_FUNC_INFO(krb5_unparse_name),
266 MAKE_FUNC_INFO(krb5_free_unparsed_name),
272 const char* dll_name,
274 HINSTANCE* ph, // [out, optional] - DLL handle
275 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
276 int cleanup, // cleanup function pointers and unload on error
277 int go_on, // continue loading even if some functions cannot be loaded
278 int silent // do not pop-up a system dialog if DLL cannot be loaded
287 if (pindex) *pindex = -1;
289 for (n = 0; fi[n].func_ptr_var; n++)
290 *(fi[n].func_ptr_var) = 0;
293 em = SetErrorMode(SEM_FAILCRITICALERRORS);
294 h = LoadLibrary(dll_name);
302 for (i = 0; (go_on || !error) && (i < n); i++)
304 void* p = (void*)GetProcAddress(h, fi[i].func_name);
310 *(fi[i].func_ptr_var) = p;
313 if (pindex) *pindex = last_i;
314 if (error && cleanup && !go_on) {
315 for (i = 0; i < n; i++) {
316 *(fi[i].func_ptr_var) = 0;
325 #if defined(_IA64_) || defined(_AMD64_)
326 #define KERB5DLL "krb5_64.dll"
328 #define KERB5DLL "krb5_32.dll"
333 static HINSTANCE hKrb5DLL = 0;
338 hKrb5DLL = LoadLibrary(KERB5DLL);
340 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0))
342 FreeLibrary(hKrb5DLL);
352 GetLSAPrincipalName(char * szUser, DWORD *dwSize)
354 krb5_context ctx = 0;
355 krb5_error_code code;
356 krb5_ccache mslsa_ccache=0;
357 krb5_principal princ = 0;
361 if (!IsKrb5Available())
364 if (code = pkrb5_init_context(&ctx))
367 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
370 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
373 if (code = pkrb5_unparse_name(ctx, princ, &pname))
376 if ( strlen(pname) < *dwSize ) {
377 strncpy(szUser, pname, *dwSize);
378 szUser[*dwSize-1] = '\0';
381 *dwSize = (DWORD)strlen(pname);
385 pkrb5_free_unparsed_name(ctx, pname);
388 pkrb5_free_principal(ctx, princ);
391 pkrb5_cc_close(ctx, mslsa_ccache);
394 pkrb5_free_context(ctx);
399 // Recursively evaluate drivestr to find the final
400 // dos drive letter to which the source is mapped.
403 DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
405 char device[MAX_PATH];
407 if ( QueryDosDevice(drivestr, device, MAX_PATH) )
409 if ( device[0] == '\\' &&
413 isalpha(device[4]) &&
416 device[0] = device[4];
419 if ( DriveSubstitution(device, subststr, substlen) )
423 subststr[0] = device[0];
429 if ( device[0] == '\\' &&
439 strncpy(&subststr[1], &device[7], substlen-1);
440 subststr[substlen-1] = '\0';
449 // drivestr - is "<drive-letter>:"
452 DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
454 DWORD dwResult, dwResultEnum;
456 DWORD cbBuffer = 16384; // 16K is a good size
457 DWORD cEntries = -1; // enumerate all possible entries
458 LPNETRESOURCE lpnrLocal; // pointer to enumerated structures
461 char subststr[MAX_PATH];
464 // Handle drive letter substitution created with "SUBST <drive> <path>".
465 // If a substitution has occurred, use the target drive letter instead
468 if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
470 if (subststr[0] == '\\' &&
473 if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
482 // Call the WNetOpenEnum function to begin the enumeration.
484 dwResult = WNetOpenEnum(RESOURCE_CONNECTED,
487 NULL, // NULL first time the function is called
488 &hEnum); // handle to the resource
490 if (dwResult != NO_ERROR)
494 // Call the GlobalAlloc function to allocate resources.
496 lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
497 if (lpnrLocal == NULL)
502 // Initialize the buffer.
504 ZeroMemory(lpnrLocal, cbBuffer);
506 // Call the WNetEnumResource function to continue
510 dwResultEnum = WNetEnumResource(hEnum, // resource handle
511 &cEntries, // defined locally as -1
512 lpnrLocal, // LPNETRESOURCE
513 &cbBuffer); // buffer size
515 // If the call succeeds, loop through the structures.
517 if (dwResultEnum == NO_ERROR) {
518 for (i = 0; i < cEntries; i++) {
519 if (lpnrLocal[i].lpLocalName &&
520 toupper(lpnrLocal[i].lpLocalName[0]) == toupper(drivestr[0])) {
522 // Skip the two backslashes at the start of the UNC device name
524 if ( _strnicmp( &(lpnrLocal[i].lpRemoteName[2]), NetbiosName, strlen(NetbiosName)) == 0 )
534 else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
537 while (dwResultEnum != ERROR_NO_MORE_ITEMS);
540 // Call the GlobalFree function to free the memory.
542 GlobalFree((HGLOBAL) lpnrLocal);
544 // Call WNetCloseEnum to end the enumeration.
546 dwResult = WNetCloseEnum(hEnum);
552 DriveIsGlobalAutoMapped(char *drivestr)
556 DWORD dwSubMountSize;
557 char szSubMount[260];
560 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
561 AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
562 0, KEY_QUERY_VALUE, &hKey);
563 if (dwResult != ERROR_SUCCESS)
566 dwSubMountSize = sizeof(szSubMount);
568 dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
571 if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
578 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
581 char netbiosName[MAX_NB_NAME_LENGTH];
582 DWORD CurrentState = 0;
583 char HostName[64] = "";
584 char tbuffer[MAX_PATH]="";
587 char szUser[128] = "";
588 char szClient[MAX_PATH] = "";
589 char szPath[MAX_PATH] = "";
592 DWORD ioctlDebug = IoctlDebug();
594 DWORD dwSize = sizeof(szUser);
597 int sharingViolation;
599 memset(HostName, '\0', sizeof(HostName));
600 gethostname(HostName, sizeof(HostName));
601 if (!DisableServiceManagerCheck() &&
602 GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
603 CurrentState != SERVICE_RUNNING)
606 // Populate the Netbios Name
607 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
610 drivep = strchr(fileNamep, ':');
611 if (drivep && (drivep - fileNamep) >= 1) {
612 tbuffer[0] = *(drivep - 1);
616 driveType = GetDriveType(tbuffer);
620 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
621 DriveIsGlobalAutoMapped(tbuffer))
622 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
627 if (DriveIsGlobalAutoMapped(tbuffer))
628 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
632 } else if (fileNamep[0] == fileNamep[1] &&
633 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
635 int count = 0, i = 0;
637 while (count < 4 && fileNamep[i]) {
638 tbuffer[i] = fileNamep[i];
639 if ( tbuffer[i] == '\\' ||
644 if (fileNamep[i] == 0)
647 strcat(tbuffer, SMB_IOCTL_FILENAME);
649 char curdir[MAX_PATH]="";
651 GetCurrentDirectory(sizeof(curdir), curdir);
652 if ( curdir[1] == ':' ) {
653 tbuffer[0] = curdir[0];
657 driveType = GetDriveType(tbuffer);
661 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
662 DriveIsGlobalAutoMapped(tbuffer))
663 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
668 if (DriveIsGlobalAutoMapped(tbuffer))
669 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
673 } else if (curdir[0] == curdir[1] &&
674 (curdir[0] == '\\' || curdir[0] == '/'))
676 int count = 0, i = 0;
678 while (count < 4 && curdir[i]) {
679 tbuffer[i] = curdir[i];
680 if ( tbuffer[i] == '\\' ||
688 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
693 /* No file name starting with drive colon specified, use UNC name */
694 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
698 /* now open the file */
699 sharingViolation = 0;
701 if (sharingViolation)
703 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
704 FILE_SHARE_READ, NULL, OPEN_EXISTING,
705 FILE_FLAG_WRITE_THROUGH, NULL);
707 } while (fh == INVALID_HANDLE_VALUE &&
708 GetLastError() == ERROR_SHARING_VIOLATION &&
709 sharingViolation < 100);
712 if (fh == INVALID_HANDLE_VALUE) {
713 gle = GetLastError();
714 if (gle && ioctlDebug ) {
718 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
721 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
727 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
735 if (fh == INVALID_HANDLE_VALUE &&
736 GetLastError() != ERROR_SHARING_VIOLATION) {
739 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
741 if (RegOpenKey (HKEY_CURRENT_USER,
742 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
744 DWORD dwType = REG_SZ;
745 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
752 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
755 sprintf(szPath, "\\\\%s", szClient);
756 memset (&nr, 0x00, sizeof(NETRESOURCE));
757 nr.dwType=RESOURCETYPE_DISK;
759 nr.lpRemoteName=szPath;
760 res = WNetAddConnection2(&nr,NULL,szUser,0);
764 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
771 sprintf(szPath, "\\\\%s\\all", szClient);
772 res = WNetAddConnection2(&nr,NULL,szUser,0);
776 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
784 goto try_lsa_principal;
786 sharingViolation = 0;
788 if (sharingViolation)
790 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
791 FILE_SHARE_READ, NULL, OPEN_EXISTING,
792 FILE_FLAG_WRITE_THROUGH, NULL);
794 } while (fh == INVALID_HANDLE_VALUE &&
795 GetLastError() == ERROR_SHARING_VIOLATION &&
796 sharingViolation < 100);
798 if (fh == INVALID_HANDLE_VALUE) {
799 gle = GetLastError();
800 if (gle && ioctlDebug ) {
804 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
807 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
813 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
824 if (fh == INVALID_HANDLE_VALUE &&
825 GetLastError() != ERROR_SHARING_VIOLATION) {
828 dwSize = sizeof(szUser);
829 if (GetLSAPrincipalName(szUser, &dwSize)) {
832 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
835 sprintf(szPath, "\\\\%s", szClient);
836 memset (&nr, 0x00, sizeof(NETRESOURCE));
837 nr.dwType=RESOURCETYPE_DISK;
839 nr.lpRemoteName=szPath;
840 res = WNetAddConnection2(&nr,NULL,szUser,0);
844 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
851 sprintf(szPath, "\\\\%s\\all", szClient);
852 res = WNetAddConnection2(&nr,NULL,szUser,0);
856 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
866 sharingViolation = 0;
868 if (sharingViolation)
870 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
871 FILE_SHARE_READ, NULL, OPEN_EXISTING,
872 FILE_FLAG_WRITE_THROUGH, NULL);
874 } while (fh == INVALID_HANDLE_VALUE &&
875 GetLastError() == ERROR_SHARING_VIOLATION &&
876 sharingViolation < 100);
878 if (fh == INVALID_HANDLE_VALUE) {
879 gle = GetLastError();
880 if (gle && ioctlDebug ) {
884 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
887 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
893 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
904 if (fh == INVALID_HANDLE_VALUE &&
905 GetLastError() != ERROR_SHARING_VIOLATION) {
906 dwSize = sizeof(szUser);
907 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
910 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
913 sprintf(szPath, "\\\\%s", szClient);
914 memset (&nr, 0x00, sizeof(NETRESOURCE));
915 nr.dwType=RESOURCETYPE_DISK;
917 nr.lpRemoteName=szPath;
918 res = WNetAddConnection2(&nr,NULL,szUser,0);
922 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
928 sprintf(szPath, "\\\\%s\\all", szClient);
929 res = WNetAddConnection2(&nr,NULL,szUser,0);
933 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
940 sharingViolation = 0;
942 if (sharingViolation)
944 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
945 FILE_SHARE_READ, NULL, OPEN_EXISTING,
946 FILE_FLAG_WRITE_THROUGH, NULL);
948 } while (fh == INVALID_HANDLE_VALUE &&
949 GetLastError() == ERROR_SHARING_VIOLATION &&
950 sharingViolation < 100);
952 if (fh == INVALID_HANDLE_VALUE) {
953 gle = GetLastError();
954 if (gle && ioctlDebug ) {
958 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
961 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
967 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
975 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
980 if (fh == INVALID_HANDLE_VALUE)
983 /* return fh and success code */
989 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
994 DWORD ioctlDebug = IoctlDebug();
997 rcount = (long)(reqp->mp - reqp->data);
1001 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
1004 return EINVAL; /* not supposed to happen */
1007 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
1008 /* failed to write */
1009 gle = GetLastError();
1013 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
1019 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
1020 /* failed to read */
1021 gle = GetLastError();
1025 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
1031 reqp->nbytes = ioCount; /* set # of bytes available */
1032 reqp->mp = reqp->data; /* restart marshalling */
1034 /* return success */
1039 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1041 memcpy(reqp->mp, &val, 4);
1047 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1051 /* not enough data left */
1052 if (reqp->nbytes < 4) {
1053 if ( IoctlDebug() ) {
1055 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1062 memcpy(valp, reqp->mp, 4);
1068 /* includes marshalling NULL pointer as a null (0 length) string */
1070 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1076 count = (int)strlen(stringp) + 1;/* space required including null */
1081 count += utf8_prefix_size;
1084 /* watch for buffer overflow */
1085 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1086 if ( IoctlDebug() ) {
1088 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1095 memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1096 reqp->mp += utf8_prefix_size;
1097 count -= utf8_prefix_size;
1101 memcpy(reqp->mp, stringp, count);
1108 /* take a path with a drive letter, possibly relative, and return a full path
1109 * without the drive letter. This is the full path relative to the working
1110 * dir for that drive letter. The input and output paths can be the same.
1113 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1116 char origPath[1000];
1125 if (pathp[0] != 0 && pathp[1] == ':') {
1126 /* there's a drive letter there */
1134 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1135 firstp[0] == '/' && firstp[1] == '/') {
1136 /* UNC path - strip off the server and sharename */
1138 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1139 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1143 if ( firstp[i] == 0 ) {
1144 strcpy(outPathp,"\\");
1146 strcpy(outPathp,&firstp[--i]);
1148 for (p=outPathp ;*p; p++) {
1153 } else if (firstp[0] == '\\' || firstp[0] == '/') {
1154 /* already an absolute pathname, just copy it back */
1155 strcpy(outPathp, firstp);
1156 for (p=outPathp ;*p; p++) {
1163 GetCurrentDirectory(sizeof(origPath), origPath);
1166 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
1167 /* a drive has been specified and it isn't our current drive.
1168 * to get path, switch to it first. Must case-fold drive letters
1169 * for user convenience.
1172 newPath[0] = *pathp;
1175 if (!SetCurrentDirectory(newPath)) {
1176 code = GetLastError();
1178 if ( IoctlDebug() ) {
1180 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1188 /* now get the absolute path to the current wdir in this drive */
1189 GetCurrentDirectory(sizeof(tpath), tpath);
1190 if (tpath[1] == ':')
1191 strcpy(outPathp, tpath + 2); /* skip drive letter */
1192 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
1193 tpath[0] == '/' && tpath[1] == '/') {
1194 /* UNC path - strip off the server and sharename */
1196 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1197 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1201 if ( tpath[i] == 0 ) {
1202 strcpy(outPathp,"\\");
1204 strcpy(outPathp,&tpath[--i]);
1207 /* this should never happen */
1208 strcpy(outPathp, tpath);
1211 /* if there is a non-null name after the drive, append it */
1213 int len = (int)strlen(outPathp);
1214 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1215 strcat(outPathp, "\\");
1216 strcat(outPathp, firstp);
1219 /* finally, if necessary, switch back to our home drive letter */
1221 SetCurrentDirectory(origPath);
1224 for (p=outPathp ;*p; p++) {
1232 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1234 fs_ioctlRequest_t preq;
1237 char fullPath[1000];
1241 code = GetIoctlHandle(pathp, &reqHandle);
1250 /* init the request structure */
1251 InitFSRequest(&preq);
1253 /* marshall the opcode, the path name and the input parameters */
1254 MarshallLong(&preq, opcode);
1255 /* when marshalling the path, remove the drive letter, since we already
1256 * used the drive letter to find the AFS daemon; we don't need it any more.
1257 * Eventually we'll expand relative path names here, too, since again, only
1258 * we understand those.
1261 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1263 CloseHandle(reqHandle);
1268 strcpy(fullPath, "");
1271 MarshallString(&preq, fullPath, is_utf8);
1272 if (blobp->in_size) {
1273 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
1277 memcpy(preq.mp, blobp->in, blobp->in_size);
1278 preq.mp += blobp->in_size;
1281 /* now make the call */
1282 code = Transceive(reqHandle, &preq);
1284 CloseHandle(reqHandle);
1288 /* now unmarshall the return value */
1289 if (UnmarshallLong(&preq, &temp) != 0) {
1290 CloseHandle(reqHandle);
1295 CloseHandle(reqHandle);
1296 errno = CMtoUNIXerror(temp);
1297 if ( IoctlDebug() ) {
1299 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1305 /* otherwise, unmarshall the output parameters */
1306 if (blobp->out_size) {
1307 temp = blobp->out_size;
1308 if (preq.nbytes < temp)
1310 memcpy(blobp->out, preq.mp, temp);
1311 blobp->out_size = temp;
1314 /* and return success */
1315 CloseHandle(reqHandle);
1320 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1322 return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1326 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1328 return pioctl_int(pathp, opcode, blobp, follow, FALSE);