2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
19 #define SECURITY_WIN32
27 #include <cm_server.h>
31 #include <cm_scache.h>
38 #include <pioctl_nt.h>
39 #include <WINNT/afsreg.h>
40 #include <lanahelper.h>
42 #include <loadfuncs-krb5.h>
45 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
47 static const char utf8_prefix[] = UTF8_PREFIX;
48 static const int utf8_prefix_size = sizeof(utf8_prefix) - sizeof(char);
50 #define FS_IOCTLREQUEST_MAXSIZE 8192
51 /* big structure for representing and storing an IOCTL request */
52 typedef struct fs_ioctlRequest {
53 char *mp; /* marshalling/unmarshalling ptr */
54 long nbytes; /* bytes received (when unmarshalling) */
55 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
59 CMtoUNIXerror(int cm_code)
62 case CM_ERROR_TIMEDOUT:
64 case CM_ERROR_NOACCESS:
66 case CM_ERROR_NOSUCHFILE:
67 case CM_ERROR_NOSUCHPATH:
68 case CM_ERROR_BPLUS_NOMATCH:
75 case CM_ERROR_INEXACT_MATCH:
77 case CM_ERROR_CROSSDEVLINK:
83 case CM_ERROR_READONLY:
85 case CM_ERROR_WOULDBLOCK:
87 case CM_ERROR_NOSUCHCELL:
88 return ESRCH; /* hack */
89 case CM_ERROR_NOSUCHVOLUME:
90 return EPIPE; /* hack */
91 case CM_ERROR_NOMORETOKENS:
92 return EDOM; /* hack */
93 case CM_ERROR_TOOMANYBUFS:
94 return EFBIG; /* hack */
95 case CM_ERROR_ALLBUSY:
97 case CM_ERROR_ALLDOWN:
98 return ENOSYS; /* hack */
99 case CM_ERROR_ALLOFFLINE:
100 return ENXIO; /* hack */
102 if (cm_code > 0 && cm_code < EILSEQ)
110 InitFSRequest(fs_ioctlRequest_t * rp)
120 static BOOL debug = 0;
125 if (RegOpenKey (HKEY_LOCAL_MACHINE,
126 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
128 DWORD dwSize = sizeof(BOOL);
129 DWORD dwType = REG_DWORD;
130 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
141 DisableServiceManagerCheck(void)
144 static BOOL smcheck = 0;
149 if (RegOpenKey (HKEY_LOCAL_MACHINE,
150 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
152 DWORD dwSize = sizeof(BOOL);
153 DWORD dwType = REG_DWORD;
154 RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
166 LPSTR lpszMachineName,
167 LPSTR lpszServiceName,
168 DWORD *lpdwCurrentState)
171 SC_HANDLE schSCManager = NULL;
172 SC_HANDLE schService = NULL;
173 DWORD fdwDesiredAccess = 0;
174 SERVICE_STATUS ssServiceStatus = {0};
177 *lpdwCurrentState = 0;
179 fdwDesiredAccess = GENERIC_READ;
181 schSCManager = OpenSCManager(lpszMachineName,
185 if(schSCManager == NULL)
191 schService = OpenService(schSCManager,
195 if(schService == NULL)
201 fRet = QueryServiceStatus(schService,
210 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
214 CloseServiceHandle(schService);
215 CloseServiceHandle(schSCManager);
221 DECL_FUNC_PTR(krb5_cc_default_name);
222 DECL_FUNC_PTR(krb5_cc_set_default_name);
223 DECL_FUNC_PTR(krb5_get_default_config_files);
224 DECL_FUNC_PTR(krb5_free_config_files);
225 DECL_FUNC_PTR(krb5_free_context);
226 DECL_FUNC_PTR(krb5_get_default_realm);
227 DECL_FUNC_PTR(krb5_free_default_realm);
228 DECL_FUNC_PTR(krb5_init_context);
229 DECL_FUNC_PTR(krb5_cc_default);
230 DECL_FUNC_PTR(krb5_parse_name);
231 DECL_FUNC_PTR(krb5_free_principal);
232 DECL_FUNC_PTR(krb5_cc_close);
233 DECL_FUNC_PTR(krb5_cc_get_principal);
234 DECL_FUNC_PTR(krb5_build_principal);
235 DECL_FUNC_PTR(krb5_c_random_make_octets);
236 DECL_FUNC_PTR(krb5_get_init_creds_password);
237 DECL_FUNC_PTR(krb5_free_cred_contents);
238 DECL_FUNC_PTR(krb5_cc_resolve);
239 DECL_FUNC_PTR(krb5_unparse_name);
240 DECL_FUNC_PTR(krb5_free_unparsed_name);
242 FUNC_INFO krb5_fi[] = {
243 MAKE_FUNC_INFO(krb5_cc_default_name),
244 MAKE_FUNC_INFO(krb5_cc_set_default_name),
245 MAKE_FUNC_INFO(krb5_get_default_config_files),
246 MAKE_FUNC_INFO(krb5_free_config_files),
247 MAKE_FUNC_INFO(krb5_free_context),
248 MAKE_FUNC_INFO(krb5_get_default_realm),
249 MAKE_FUNC_INFO(krb5_free_default_realm),
250 MAKE_FUNC_INFO(krb5_init_context),
251 MAKE_FUNC_INFO(krb5_cc_default),
252 MAKE_FUNC_INFO(krb5_parse_name),
253 MAKE_FUNC_INFO(krb5_free_principal),
254 MAKE_FUNC_INFO(krb5_cc_close),
255 MAKE_FUNC_INFO(krb5_cc_get_principal),
256 MAKE_FUNC_INFO(krb5_build_principal),
257 MAKE_FUNC_INFO(krb5_c_random_make_octets),
258 MAKE_FUNC_INFO(krb5_get_init_creds_password),
259 MAKE_FUNC_INFO(krb5_free_cred_contents),
260 MAKE_FUNC_INFO(krb5_cc_resolve),
261 MAKE_FUNC_INFO(krb5_unparse_name),
262 MAKE_FUNC_INFO(krb5_free_unparsed_name),
268 const char* dll_name,
270 HINSTANCE* ph, // [out, optional] - DLL handle
271 int* pindex, // [out, optional] - index of last func loaded (-1 if none)
272 int cleanup, // cleanup function pointers and unload on error
273 int go_on, // continue loading even if some functions cannot be loaded
274 int silent // do not pop-up a system dialog if DLL cannot be loaded
283 if (pindex) *pindex = -1;
285 for (n = 0; fi[n].func_ptr_var; n++)
286 *(fi[n].func_ptr_var) = 0;
289 em = SetErrorMode(SEM_FAILCRITICALERRORS);
290 h = LoadLibrary(dll_name);
298 for (i = 0; (go_on || !error) && (i < n); i++)
300 void* p = (void*)GetProcAddress(h, fi[i].func_name);
306 *(fi[i].func_ptr_var) = p;
309 if (pindex) *pindex = last_i;
310 if (error && cleanup && !go_on) {
311 for (i = 0; i < n; i++) {
312 *(fi[i].func_ptr_var) = 0;
321 #if defined(_IA64_) || defined(_AMD64_)
322 #define KERB5DLL "krb5_64.dll"
324 #define KERB5DLL "krb5_32.dll"
329 static HINSTANCE hKrb5DLL = 0;
334 hKrb5DLL = LoadLibrary(KERB5DLL);
336 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0))
338 FreeLibrary(hKrb5DLL);
348 GetLSAPrincipalName(char * szUser, DWORD *dwSize)
350 krb5_context ctx = 0;
351 krb5_error_code code;
352 krb5_ccache mslsa_ccache=0;
353 krb5_principal princ = 0;
357 if (!IsKrb5Available())
360 if (code = pkrb5_init_context(&ctx))
363 if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
366 if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
369 if (code = pkrb5_unparse_name(ctx, princ, &pname))
372 if ( strlen(pname) < *dwSize ) {
373 strncpy(szUser, pname, *dwSize);
374 szUser[*dwSize-1] = '\0';
377 *dwSize = (DWORD)strlen(pname);
381 pkrb5_free_unparsed_name(ctx, pname);
384 pkrb5_free_principal(ctx, princ);
387 pkrb5_cc_close(ctx, mslsa_ccache);
390 pkrb5_free_context(ctx);
395 // Recursively evaluate drivestr to find the final
396 // dos drive letter to which the source is mapped.
399 DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
401 char device[MAX_PATH];
403 if ( QueryDosDevice(drivestr, device, MAX_PATH) )
405 if ( device[0] == '\\' &&
409 isalpha(device[4]) &&
412 device[0] = device[4];
415 if ( DriveSubstitution(device, subststr, substlen) )
419 subststr[0] = device[0];
425 if ( device[0] == '\\' &&
435 strncpy(&subststr[1], &device[7], substlen-1);
436 subststr[substlen-1] = '\0';
445 // drivestr - is "<drive-letter>:"
448 DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
450 DWORD dwResult, dwResultEnum;
452 DWORD cbBuffer = 16384; // 16K is a good size
453 DWORD cEntries = -1; // enumerate all possible entries
454 LPNETRESOURCE lpnrLocal; // pointer to enumerated structures
457 char subststr[MAX_PATH];
460 // Handle drive letter substitution created with "SUBST <drive> <path>".
461 // If a substitution has occurred, use the target drive letter instead
464 if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
466 if (subststr[0] == '\\' &&
469 if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
478 // Call the WNetOpenEnum function to begin the enumeration.
480 dwResult = WNetOpenEnum(RESOURCE_CONNECTED,
483 NULL, // NULL first time the function is called
484 &hEnum); // handle to the resource
486 if (dwResult != NO_ERROR)
490 // Call the GlobalAlloc function to allocate resources.
492 lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
493 if (lpnrLocal == NULL)
498 // Initialize the buffer.
500 ZeroMemory(lpnrLocal, cbBuffer);
502 // Call the WNetEnumResource function to continue
506 dwResultEnum = WNetEnumResource(hEnum, // resource handle
507 &cEntries, // defined locally as -1
508 lpnrLocal, // LPNETRESOURCE
509 &cbBuffer); // buffer size
511 // If the call succeeds, loop through the structures.
513 if (dwResultEnum == NO_ERROR) {
514 for (i = 0; i < cEntries; i++) {
515 if (lpnrLocal[i].lpLocalName &&
516 toupper(lpnrLocal[i].lpLocalName[0]) == toupper(drivestr[0])) {
518 // Skip the two backslashes at the start of the UNC device name
520 if ( _strnicmp( &(lpnrLocal[i].lpRemoteName[2]), NetbiosName, strlen(NetbiosName)) == 0 )
530 else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
533 while (dwResultEnum != ERROR_NO_MORE_ITEMS);
536 // Call the GlobalFree function to free the memory.
538 GlobalFree((HGLOBAL) lpnrLocal);
540 // Call WNetCloseEnum to end the enumeration.
542 dwResult = WNetCloseEnum(hEnum);
548 DriveIsGlobalAutoMapped(char *drivestr)
552 DWORD dwSubMountSize;
553 char szSubMount[260];
556 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
557 AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
558 0, KEY_QUERY_VALUE, &hKey);
559 if (dwResult != ERROR_SUCCESS)
562 dwSubMountSize = sizeof(szSubMount);
564 dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
567 if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
574 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
577 char netbiosName[MAX_NB_NAME_LENGTH];
578 DWORD CurrentState = 0;
579 char HostName[64] = "";
580 char tbuffer[MAX_PATH]="";
583 char szUser[128] = "";
584 char szClient[MAX_PATH] = "";
585 char szPath[MAX_PATH] = "";
588 DWORD ioctlDebug = IoctlDebug();
590 DWORD dwSize = sizeof(szUser);
593 int sharingViolation;
595 memset(HostName, '\0', sizeof(HostName));
596 gethostname(HostName, sizeof(HostName));
597 if (!DisableServiceManagerCheck() &&
598 GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
599 CurrentState != SERVICE_RUNNING)
602 // Populate the Netbios Name
603 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
606 drivep = strchr(fileNamep, ':');
607 if (drivep && (drivep - fileNamep) >= 1) {
608 tbuffer[0] = *(drivep - 1);
612 driveType = GetDriveType(tbuffer);
616 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
617 DriveIsGlobalAutoMapped(tbuffer))
618 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
623 if (DriveIsGlobalAutoMapped(tbuffer))
624 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
628 } else if (fileNamep[0] == fileNamep[1] &&
629 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
631 int count = 0, i = 0;
633 while (count < 4 && fileNamep[i]) {
634 tbuffer[i] = fileNamep[i];
635 if ( tbuffer[i] == '\\' ||
640 if (fileNamep[i] == 0 || (fileNamep[i-1] != '\\' && fileNamep[i-1] != '/'))
643 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
645 char curdir[MAX_PATH]="";
647 GetCurrentDirectory(sizeof(curdir), curdir);
648 if ( curdir[1] == ':' ) {
649 tbuffer[0] = curdir[0];
653 driveType = GetDriveType(tbuffer);
657 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
658 DriveIsGlobalAutoMapped(tbuffer))
659 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
664 if (DriveIsGlobalAutoMapped(tbuffer))
665 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
669 } else if (curdir[0] == curdir[1] &&
670 (curdir[0] == '\\' || curdir[0] == '/'))
672 int count = 0, i = 0;
674 while (count < 4 && curdir[i]) {
675 tbuffer[i] = curdir[i];
676 if ( tbuffer[i] == '\\' ||
681 if (curdir[i] == 0 || (curdir[i-1] != '\\' && curdir[i-1] != '/'))
684 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
689 /* No file name starting with drive colon specified, use UNC name */
690 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
694 /* now open the file */
695 sharingViolation = 0;
697 if (sharingViolation)
699 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
700 FILE_SHARE_READ, NULL, OPEN_EXISTING,
701 FILE_FLAG_WRITE_THROUGH, NULL);
703 } while (fh == INVALID_HANDLE_VALUE &&
704 GetLastError() == ERROR_SHARING_VIOLATION &&
705 sharingViolation < 100);
708 if (fh == INVALID_HANDLE_VALUE) {
709 gle = GetLastError();
710 if (gle && ioctlDebug ) {
714 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
717 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
723 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
731 if (fh == INVALID_HANDLE_VALUE &&
732 GetLastError() != ERROR_SHARING_VIOLATION) {
735 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
737 if (RegOpenKey (HKEY_CURRENT_USER,
738 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
740 DWORD dwType = REG_SZ;
741 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
748 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
751 sprintf(szPath, "\\\\%s", szClient);
752 memset (&nr, 0x00, sizeof(NETRESOURCE));
753 nr.dwType=RESOURCETYPE_DISK;
755 nr.lpRemoteName=szPath;
756 res = WNetAddConnection2(&nr,NULL,szUser,0);
760 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
767 sprintf(szPath, "\\\\%s\\all", szClient);
768 res = WNetAddConnection2(&nr,NULL,szUser,0);
772 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
780 goto try_lsa_principal;
782 sharingViolation = 0;
784 if (sharingViolation)
786 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
787 FILE_SHARE_READ, NULL, OPEN_EXISTING,
788 FILE_FLAG_WRITE_THROUGH, NULL);
790 } while (fh == INVALID_HANDLE_VALUE &&
791 GetLastError() == ERROR_SHARING_VIOLATION &&
792 sharingViolation < 100);
794 if (fh == INVALID_HANDLE_VALUE) {
795 gle = GetLastError();
796 if (gle && ioctlDebug ) {
800 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
803 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
809 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
820 if (fh == INVALID_HANDLE_VALUE &&
821 GetLastError() != ERROR_SHARING_VIOLATION) {
824 dwSize = sizeof(szUser);
825 if (GetLSAPrincipalName(szUser, &dwSize)) {
828 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
831 sprintf(szPath, "\\\\%s", szClient);
832 memset (&nr, 0x00, sizeof(NETRESOURCE));
833 nr.dwType=RESOURCETYPE_DISK;
835 nr.lpRemoteName=szPath;
836 res = WNetAddConnection2(&nr,NULL,szUser,0);
840 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
847 sprintf(szPath, "\\\\%s\\all", szClient);
848 res = WNetAddConnection2(&nr,NULL,szUser,0);
852 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
862 sharingViolation = 0;
864 if (sharingViolation)
866 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
867 FILE_SHARE_READ, NULL, OPEN_EXISTING,
868 FILE_FLAG_WRITE_THROUGH, NULL);
870 } while (fh == INVALID_HANDLE_VALUE &&
871 GetLastError() == ERROR_SHARING_VIOLATION &&
872 sharingViolation < 100);
874 if (fh == INVALID_HANDLE_VALUE) {
875 gle = GetLastError();
876 if (gle && ioctlDebug ) {
880 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
883 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
889 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
900 if (fh == INVALID_HANDLE_VALUE &&
901 GetLastError() != ERROR_SHARING_VIOLATION) {
902 dwSize = sizeof(szUser);
903 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
906 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
909 sprintf(szPath, "\\\\%s", szClient);
910 memset (&nr, 0x00, sizeof(NETRESOURCE));
911 nr.dwType=RESOURCETYPE_DISK;
913 nr.lpRemoteName=szPath;
914 res = WNetAddConnection2(&nr,NULL,szUser,0);
918 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
924 sprintf(szPath, "\\\\%s\\all", szClient);
925 res = WNetAddConnection2(&nr,NULL,szUser,0);
929 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
936 sharingViolation = 0;
938 if (sharingViolation)
940 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
941 FILE_SHARE_READ, NULL, OPEN_EXISTING,
942 FILE_FLAG_WRITE_THROUGH, NULL);
944 } while (fh == INVALID_HANDLE_VALUE &&
945 GetLastError() == ERROR_SHARING_VIOLATION &&
946 sharingViolation < 100);
948 if (fh == INVALID_HANDLE_VALUE) {
949 gle = GetLastError();
950 if (gle && ioctlDebug ) {
954 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
957 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
963 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
971 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
976 if (fh == INVALID_HANDLE_VALUE)
979 /* return fh and success code */
985 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
990 DWORD ioctlDebug = IoctlDebug();
993 rcount = (long)(reqp->mp - reqp->data);
997 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
1000 return EINVAL; /* not supposed to happen */
1003 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
1004 /* failed to write */
1005 gle = GetLastError();
1009 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
1015 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
1016 /* failed to read */
1017 gle = GetLastError();
1021 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
1027 reqp->nbytes = ioCount; /* set # of bytes available */
1028 reqp->mp = reqp->data; /* restart marshalling */
1030 /* return success */
1035 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1037 memcpy(reqp->mp, &val, 4);
1043 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1047 /* not enough data left */
1048 if (reqp->nbytes < 4) {
1049 if ( IoctlDebug() ) {
1051 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1058 memcpy(valp, reqp->mp, 4);
1064 /* includes marshalling NULL pointer as a null (0 length) string */
1066 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1072 count = (int)strlen(stringp) + 1;/* space required including null */
1077 count += utf8_prefix_size;
1080 /* watch for buffer overflow */
1081 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1082 if ( IoctlDebug() ) {
1084 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1091 memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1092 reqp->mp += utf8_prefix_size;
1093 count -= utf8_prefix_size;
1097 memcpy(reqp->mp, stringp, count);
1104 /* take a path with a drive letter, possibly relative, and return a full path
1105 * without the drive letter. This is the full path relative to the working
1106 * dir for that drive letter. The input and output paths can be the same.
1109 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1112 char origPath[1000];
1121 if (pathp[0] != 0 && pathp[1] == ':') {
1122 /* there's a drive letter there */
1130 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1131 firstp[0] == '/' && firstp[1] == '/') {
1132 /* UNC path - strip off the server and sharename */
1134 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1135 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1139 if ( firstp[i] == 0 ) {
1140 strcpy(outPathp,"\\");
1142 strcpy(outPathp,&firstp[--i]);
1144 for (p=outPathp ;*p; p++) {
1149 } else if (firstp[0] == '\\' || firstp[0] == '/') {
1150 /* already an absolute pathname, just copy it back */
1151 strcpy(outPathp, firstp);
1152 for (p=outPathp ;*p; p++) {
1159 GetCurrentDirectory(sizeof(origPath), origPath);
1162 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
1163 /* a drive has been specified and it isn't our current drive.
1164 * to get path, switch to it first. Must case-fold drive letters
1165 * for user convenience.
1168 newPath[0] = *pathp;
1171 if (!SetCurrentDirectory(newPath)) {
1172 code = GetLastError();
1174 if ( IoctlDebug() ) {
1176 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1184 /* now get the absolute path to the current wdir in this drive */
1185 GetCurrentDirectory(sizeof(tpath), tpath);
1186 if (tpath[1] == ':')
1187 strcpy(outPathp, tpath + 2); /* skip drive letter */
1188 else if ( tpath[0] == '\\' && tpath[1] == '\\'||
1189 tpath[0] == '/' && tpath[1] == '/') {
1190 /* UNC path - strip off the server and sharename */
1192 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1193 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1197 if ( tpath[i] == 0 ) {
1198 strcpy(outPathp,"\\");
1200 strcpy(outPathp,&tpath[--i]);
1203 /* this should never happen */
1204 strcpy(outPathp, tpath);
1207 /* if there is a non-null name after the drive, append it */
1209 int len = (int)strlen(outPathp);
1210 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1211 strcat(outPathp, "\\");
1212 strcat(outPathp, firstp);
1215 /* finally, if necessary, switch back to our home drive letter */
1217 SetCurrentDirectory(origPath);
1220 for (p=outPathp ;*p; p++) {
1228 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1230 fs_ioctlRequest_t preq;
1233 char fullPath[1000];
1237 code = GetIoctlHandle(pathp, &reqHandle);
1246 /* init the request structure */
1247 InitFSRequest(&preq);
1249 /* marshall the opcode, the path name and the input parameters */
1250 MarshallLong(&preq, opcode);
1251 /* when marshalling the path, remove the drive letter, since we already
1252 * used the drive letter to find the AFS daemon; we don't need it any more.
1253 * Eventually we'll expand relative path names here, too, since again, only
1254 * we understand those.
1257 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1259 CloseHandle(reqHandle);
1264 strcpy(fullPath, "");
1267 MarshallString(&preq, fullPath, is_utf8);
1268 if (blobp->in_size) {
1269 if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
1273 memcpy(preq.mp, blobp->in, blobp->in_size);
1274 preq.mp += blobp->in_size;
1277 /* now make the call */
1278 code = Transceive(reqHandle, &preq);
1280 CloseHandle(reqHandle);
1284 /* now unmarshall the return value */
1285 if (UnmarshallLong(&preq, &temp) != 0) {
1286 CloseHandle(reqHandle);
1291 CloseHandle(reqHandle);
1292 errno = CMtoUNIXerror(temp);
1293 if ( IoctlDebug() ) {
1295 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1301 /* otherwise, unmarshall the output parameters */
1302 if (blobp->out_size) {
1303 temp = blobp->out_size;
1304 if (preq.nbytes < temp)
1306 memcpy(blobp->out, preq.mp, temp);
1307 blobp->out_size = temp;
1310 /* and return success */
1311 CloseHandle(reqHandle);
1316 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1318 return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1322 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1324 return pioctl_int(pathp, opcode, blobp, follow, FALSE);