Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / sys / pioctl_nt.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <windows.h>
17 #include <winioctl.h>
18 #define SECURITY_WIN32
19 #include <security.h>
20 #include <nb30.h>
21 #include <tchar.h>
22 #include <strsafe.h>
23
24 #include <osi.h>
25
26 #include <cm.h>
27 #include <cm_nls.h>
28 #include <cm_server.h>
29 #include <cm_cell.h>
30 #include <cm_user.h>
31 #include <cm_conn.h>
32 #include <cm_scache.h>
33 #include <cm_buf.h>
34 #include <cm_dir.h>
35 #include <cm_utils.h>
36 #include <cm_ioctl.h>
37 #include <smb_iocons.h>
38 #include <smb.h>
39 #include <pioctl_nt.h>
40 #include <WINNT/afsreg.h>
41 #include <lanahelper.h>
42
43 #include <krb5.h>
44 #include <..\WINNT\afsrdr\common\AFSUserDefines.h>
45 #include <..\WINNT\afsrdr\common\AFSUserIoctl.h>
46 #include <..\WINNT\afsrdr\common\AFSUserStructs.h>
47
48 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
49
50 static const char utf8_prefix[] = UTF8_PREFIX;
51 static const int utf8_prefix_size = sizeof(utf8_prefix) - sizeof(char);
52
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 */
59 } fs_ioctlRequest_t;
60
61
62 static int
63 CMtoUNIXerror(int cm_code)
64 {
65 switch (cm_code) {
66 case CM_ERROR_TIMEDOUT:
67 return ETIMEDOUT;
68 case CM_ERROR_NOACCESS:
69 return EACCES;
70 case CM_ERROR_NOSUCHFILE:
71 case CM_ERROR_NOSUCHPATH:
72 case CM_ERROR_BPLUS_NOMATCH:
73 return ENOENT;
74 case CM_ERROR_INVAL:
75 return EINVAL;
76 case CM_ERROR_BADFD:
77 return EBADF;
78 case CM_ERROR_EXISTS:
79 case CM_ERROR_INEXACT_MATCH:
80 return EEXIST;
81 case CM_ERROR_CROSSDEVLINK:
82 return EXDEV;
83 case CM_ERROR_NOTDIR:
84 return ENOTDIR;
85 case CM_ERROR_ISDIR:
86 return EISDIR;
87 case CM_ERROR_READONLY:
88 return EROFS;
89 case CM_ERROR_WOULDBLOCK:
90 return EWOULDBLOCK;
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:
100 return EBUSY;
101 case CM_ERROR_ALLDOWN:
102 return ENOSYS; /* hack */
103 case CM_ERROR_ALLOFFLINE:
104 return ENXIO; /* hack */
105 default:
106 if (cm_code > 0 && cm_code < EILSEQ)
107 return cm_code;
108 else
109 return ENOTTY;
110 }
111 }
112
113 static void
114 InitFSRequest(fs_ioctlRequest_t * rp)
115 {
116 rp->mp = rp->data;
117 rp->nbytes = 0;
118 }
119
120 static BOOL
121 IoctlDebug(void)
122 {
123 static int init = 0;
124 static BOOL debug = 0;
125
126 if ( !init ) {
127 HKEY hk;
128
129 if (RegOpenKey (HKEY_LOCAL_MACHINE,
130 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
131 {
132 DWORD dwSize = sizeof(BOOL);
133 DWORD dwType = REG_DWORD;
134 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
135 RegCloseKey (hk);
136 }
137
138 init = 1;
139 }
140
141 return debug;
142 }
143
144 static BOOL
145 RDR_Ready(void)
146 {
147 HANDLE hDevHandle = NULL;
148 DWORD bytesReturned;
149 AFSDriverStatusRespCB *respBuffer = NULL;
150 DWORD rc = 0;
151 BOOL ready = FALSE;
152
153 hDevHandle = CreateFileW( AFS_SYMLINK_W,
154 GENERIC_READ | GENERIC_WRITE,
155 FILE_SHARE_READ | FILE_SHARE_WRITE,
156 NULL,
157 OPEN_EXISTING,
158 0,
159 NULL);
160 if( hDevHandle == INVALID_HANDLE_VALUE)
161 {
162 DWORD gle = GetLastError();
163
164 if (gle && IoctlDebug() ) {
165 char buf[4096];
166 int saveerrno;
167
168 saveerrno = errno;
169 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
170 NULL,
171 gle,
172 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
173 buf,
174 4096,
175 NULL
176 ) )
177 {
178 fprintf(stderr,"RDR_Ready CreateFile(%S) failed: 0x%X\r\n\t[%s]\r\n",
179 AFS_SYMLINK_W,gle,buf);
180 }
181 errno = saveerrno;
182 }
183 return FALSE;
184 }
185
186 //
187 // Allocate a response buffer.
188 //
189 respBuffer = calloc(1, sizeof( AFSDriverStatusRespCB));
190 if( respBuffer)
191 {
192
193 if( !DeviceIoControl( hDevHandle,
194 IOCTL_AFS_STATUS_REQUEST,
195 NULL,
196 0,
197 (void *)respBuffer,
198 sizeof( AFSDriverStatusRespCB),
199 &bytesReturned,
200 NULL))
201 {
202 //
203 // Error condition back from driver
204 //
205 DWORD gle = GetLastError();
206
207 if (gle && IoctlDebug() ) {
208 char buf[4096];
209 int saveerrno;
210
211 saveerrno = errno;
212 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
213 NULL,
214 gle,
215 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
216 buf,
217 4096,
218 NULL
219 ) )
220 {
221 fprintf(stderr,"RDR_Ready CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
222 AFS_SYMLINK,gle,buf);
223 }
224 errno = saveerrno;
225 }
226 rc = -1;
227 goto cleanup;
228 }
229
230 if (bytesReturned == sizeof(AFSDriverStatusRespCB))
231 {
232 ready = ( respBuffer->Status == AFS_DRIVER_STATUS_READY );
233 }
234 } else
235 rc = ENOMEM;
236
237 cleanup:
238 if (respBuffer)
239 free( respBuffer);
240
241 if (hDevHandle != INVALID_HANDLE_VALUE)
242 CloseHandle(hDevHandle);
243
244 return ready;
245 }
246
247 static BOOL
248 DisableServiceManagerCheck(void)
249 {
250 static int init = 0;
251 static BOOL smcheck = 0;
252
253 if ( !init ) {
254 HKEY hk;
255
256 if (RegOpenKey (HKEY_LOCAL_MACHINE,
257 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
258 {
259 DWORD dwSize = sizeof(BOOL);
260 DWORD dwType = REG_DWORD;
261 RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
262 RegCloseKey (hk);
263 }
264
265 init = 1;
266 }
267
268 return smcheck;
269 }
270
271 static DWORD
272 GetServiceStatus(
273 LPSTR lpszMachineName,
274 LPSTR lpszServiceName,
275 DWORD *lpdwCurrentState)
276 {
277 DWORD hr = NOERROR;
278 SC_HANDLE schSCManager = NULL;
279 SC_HANDLE schService = NULL;
280 DWORD fdwDesiredAccess = 0;
281 SERVICE_STATUS ssServiceStatus = {0};
282 BOOL fRet = FALSE;
283
284 *lpdwCurrentState = 0;
285
286 fdwDesiredAccess = GENERIC_READ;
287
288 schSCManager = OpenSCManager(lpszMachineName,
289 NULL,
290 fdwDesiredAccess);
291
292 if(schSCManager == NULL)
293 {
294 hr = GetLastError();
295 goto cleanup;
296 }
297
298 schService = OpenService(schSCManager,
299 lpszServiceName,
300 fdwDesiredAccess);
301
302 if(schService == NULL)
303 {
304 hr = GetLastError();
305 goto cleanup;
306 }
307
308 fRet = QueryServiceStatus(schService,
309 &ssServiceStatus);
310
311 if(fRet == FALSE)
312 {
313 hr = GetLastError();
314 goto cleanup;
315 }
316
317 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
318
319 cleanup:
320
321 CloseServiceHandle(schService);
322 CloseServiceHandle(schSCManager);
323
324 return(hr);
325 }
326
327 static BOOL
328 UnicodeToANSI(LPCWSTR lpInputString, LPSTR lpszOutputString, int nOutStringLen)
329 {
330 CPINFO CodePageInfo;
331
332 GetCPInfo(CP_ACP, &CodePageInfo);
333
334 if (CodePageInfo.MaxCharSize > 1) {
335 // Only supporting non-Unicode strings
336 int reqLen = WideCharToMultiByte( CP_ACP, 0,
337 lpInputString, -1,
338 NULL, 0, NULL, NULL);
339 if ( reqLen > nOutStringLen)
340 {
341 return FALSE;
342 } else {
343 if (WideCharToMultiByte( CP_ACP,
344 WC_COMPOSITECHECK,
345 lpInputString, -1,
346 lpszOutputString,
347 nOutStringLen, NULL, NULL) == 0)
348 return FALSE;
349 }
350 }
351 else
352 {
353 // Looks like unicode, better translate it
354 if (WideCharToMultiByte( CP_ACP,
355 WC_COMPOSITECHECK,
356 lpInputString, -1,
357 lpszOutputString,
358 nOutStringLen, NULL, NULL) == 0)
359 return FALSE;
360 }
361
362 return TRUE;
363 }
364
365 static BOOL
366 GetLSAPrincipalName(char * pszUser, DWORD dwUserSize)
367 {
368 KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
369 PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
370 ULONG ResponseSize;
371 PKERB_EXTERNAL_NAME pClientName = NULL;
372 PUNICODE_STRING pDomainName = NULL;
373 LSA_STRING Name;
374 HANDLE hLogon = INVALID_HANDLE_VALUE;
375 ULONG PackageId;
376 NTSTATUS ntStatus;
377 NTSTATUS ntSubStatus = 0;
378 WCHAR * wchUser = NULL;
379 DWORD dwSize;
380 SHORT sCount;
381 BOOL bRet = FALSE;
382
383 ntStatus = LsaConnectUntrusted( &hLogon);
384 if (FAILED(ntStatus))
385 goto cleanup;
386
387 Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
388 Name.Length = (USHORT)(sizeof(MICROSOFT_KERBEROS_NAME_A) - sizeof(char));
389 Name.MaximumLength = Name.Length;
390
391 ntStatus = LsaLookupAuthenticationPackage( hLogon, &Name, &PackageId);
392 if (FAILED(ntStatus))
393 goto cleanup;
394
395 memset(&CacheRequest, 0, sizeof(KERB_QUERY_TKT_CACHE_REQUEST));
396 CacheRequest.MessageType = KerbRetrieveTicketMessage;
397 CacheRequest.LogonId.LowPart = 0;
398 CacheRequest.LogonId.HighPart = 0;
399
400 ntStatus = LsaCallAuthenticationPackage( hLogon,
401 PackageId,
402 &CacheRequest,
403 sizeof(CacheRequest),
404 &pTicketResponse,
405 &ResponseSize,
406 &ntSubStatus);
407 if (FAILED(ntStatus) || FAILED(ntSubStatus))
408 goto cleanup;
409
410 /* We have a ticket in the response */
411 pClientName = pTicketResponse->Ticket.ClientName;
412 pDomainName = &pTicketResponse->Ticket.DomainName;
413
414 /* We want to return ClientName @ DomainName */
415
416 dwSize = 0;
417 for ( sCount = 0; sCount < pClientName->NameCount; sCount++)
418 {
419 dwSize += pClientName->Names[sCount].Length;
420 }
421 dwSize += pDomainName->Length + sizeof(WCHAR);
422
423 if ( dwSize / sizeof(WCHAR) > dwUserSize )
424 goto cleanup;
425
426 wchUser = malloc(dwSize);
427 if (wchUser == NULL)
428 goto cleanup;
429
430 for ( sCount = 0, wchUser[0] = L'\0'; sCount < pClientName->NameCount; sCount++)
431 {
432 StringCbCatNW( wchUser, dwSize,
433 pClientName->Names[sCount].Buffer,
434 pClientName->Names[sCount].Length);
435 }
436 StringCbCatNW( wchUser, dwSize,
437 pDomainName->Buffer,
438 pDomainName->Length);
439
440 if ( !UnicodeToANSI( wchUser, pszUser, dwUserSize) )
441 goto cleanup;
442
443 bRet = TRUE;
444
445 cleanup:
446
447 if (wchUser)
448 free(wchUser);
449
450 if ( hLogon != INVALID_HANDLE_VALUE)
451 LsaDeregisterLogonProcess(hLogon);
452
453 if ( pTicketResponse ) {
454 SecureZeroMemory(pTicketResponse,ResponseSize);
455 LsaFreeReturnBuffer(pTicketResponse);
456 }
457
458 return bRet;
459 }
460
461 //
462 // Recursively evaluate drivestr to find the final
463 // dos drive letter to which the source is mapped.
464 //
465 static BOOL
466 DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
467 {
468 char device[MAX_PATH];
469
470 if ( QueryDosDevice(drivestr, device, MAX_PATH) )
471 {
472 if ( device[0] == '\\' &&
473 device[1] == '?' &&
474 device[2] == '?' &&
475 device[3] == '\\' &&
476 isalpha(device[4]) &&
477 device[5] == ':')
478 {
479 device[0] = device[4];
480 device[1] = ':';
481 device[2] = '\0';
482 if ( DriveSubstitution(device, subststr, substlen) )
483 {
484 return TRUE;
485 } else {
486 subststr[0] = device[0];
487 subststr[1] = ':';
488 subststr[2] = '\0';
489 return TRUE;
490 }
491 } else
492 if ( device[0] == '\\' &&
493 device[1] == '?' &&
494 device[2] == '?' &&
495 device[3] == '\\' &&
496 device[4] == 'U' &&
497 device[5] == 'N' &&
498 device[6] == 'C' &&
499 device[7] == '\\')
500 {
501 subststr[0] = '\\';
502 strncpy(&subststr[1], &device[7], substlen-1);
503 subststr[substlen-1] = '\0';
504 return TRUE;
505 }
506 }
507
508 return FALSE;
509 }
510
511 //
512 // drivestr - is "<drive-letter>:"
513 //
514 static BOOL
515 DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
516 {
517 DWORD dwResult, dwResultEnum;
518 HANDLE hEnum;
519 DWORD cbBuffer = 16384; // 16K is a good size
520 DWORD cEntries = -1; // enumerate all possible entries
521 LPNETRESOURCE lpnrLocal; // pointer to enumerated structures
522 DWORD i;
523 BOOL bIsAFS = FALSE;
524 char subststr[MAX_PATH];
525 char device[MAX_PATH];
526
527 //
528 // Handle drive letter substitution created with "SUBST <drive> <path>".
529 // If a substitution has occurred, use the target drive letter instead
530 // of the source.
531 //
532 if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
533 {
534 if (subststr[0] == '\\' &&
535 subststr[1] == '\\')
536 {
537 if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
538 return TRUE;
539 else
540 return FALSE;
541 }
542 drivestr = subststr;
543 }
544
545 //
546 // Check for \Device\AFSRedirector
547 //
548 if (QueryDosDevice(drivestr, device, MAX_PATH) &&
549 _strnicmp( device, "\\Device\\AFSRedirector", strlen("\\Device\\AFSRedirector")) == 0) {
550 return TRUE;
551 }
552
553 //
554 // Call the WNetOpenEnum function to begin the enumeration.
555 //
556 dwResult = WNetOpenEnum(RESOURCE_CONNECTED,
557 RESOURCETYPE_DISK,
558 RESOURCEUSAGE_ALL,
559 NULL, // NULL first time the function is called
560 &hEnum); // handle to the resource
561
562 if (dwResult != NO_ERROR)
563 return FALSE;
564
565 //
566 // Call the GlobalAlloc function to allocate resources.
567 //
568 lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
569 if (lpnrLocal == NULL)
570 return FALSE;
571
572 do {
573 //
574 // Initialize the buffer.
575 //
576 ZeroMemory(lpnrLocal, cbBuffer);
577 //
578 // Call the WNetEnumResource function to continue
579 // the enumeration.
580 //
581 cEntries = -1;
582 dwResultEnum = WNetEnumResource(hEnum, // resource handle
583 &cEntries, // defined locally as -1
584 lpnrLocal, // LPNETRESOURCE
585 &cbBuffer); // buffer size
586 //
587 // If the call succeeds, loop through the structures.
588 //
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])) {
593 //
594 // Skip the two backslashes at the start of the UNC device name
595 //
596 if ( _strnicmp( &(lpnrLocal[i].lpRemoteName[2]), NetbiosName, strlen(NetbiosName)) == 0 )
597 {
598 bIsAFS = TRUE;
599 break;
600 }
601 }
602 }
603 }
604 // Process errors.
605 //
606 else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
607 break;
608 }
609 while (dwResultEnum != ERROR_NO_MORE_ITEMS);
610
611 //
612 // Call the GlobalFree function to free the memory.
613 //
614 GlobalFree((HGLOBAL) lpnrLocal);
615 //
616 // Call WNetCloseEnum to end the enumeration.
617 //
618 dwResult = WNetCloseEnum(hEnum);
619
620 return bIsAFS;
621 }
622
623 static BOOL
624 DriveIsGlobalAutoMapped(char *drivestr)
625 {
626 DWORD dwResult;
627 HKEY hKey;
628 DWORD dwSubMountSize;
629 char szSubMount[260];
630 DWORD dwType;
631
632 dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
633 AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
634 0, KEY_QUERY_VALUE, &hKey);
635 if (dwResult != ERROR_SUCCESS)
636 return FALSE;
637
638 dwSubMountSize = sizeof(szSubMount);
639 dwType = REG_SZ;
640 dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
641 RegCloseKey(hKey);
642
643 if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
644 return TRUE;
645 else
646 return FALSE;
647 }
648
649 static long
650 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
651 {
652 HKEY hk;
653 char *drivep = NULL;
654 char netbiosName[MAX_NB_NAME_LENGTH]="AFS";
655 DWORD CurrentState = 0;
656 char HostName[64] = "";
657 char tbuffer[MAX_PATH]="";
658 HANDLE fh;
659 char szUser[128] = "";
660 char szClient[MAX_PATH] = "";
661 char szPath[MAX_PATH] = "";
662 NETRESOURCE nr;
663 DWORD res;
664 DWORD ioctlDebug = IoctlDebug();
665 DWORD gle;
666 DWORD dwAttrib;
667 DWORD dwSize = sizeof(szUser);
668 BOOL usingRDR = FALSE;
669 int saveerrno;
670 UINT driveType;
671 int sharingViolation;
672
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)
678 {
679 if ( ioctlDebug ) {
680 saveerrno = errno;
681 fprintf(stderr, "pioctl GetServiceStatus(%s) == %d\r\n",
682 HostName, CurrentState);
683 errno = saveerrno;
684 }
685 return -1;
686 }
687
688 if (RDR_Ready()) {
689 usingRDR = TRUE;
690
691 if ( ioctlDebug ) {
692 saveerrno = errno;
693 fprintf(stderr, "pioctl Redirector is ready\r\n");
694 errno = saveerrno;
695 }
696
697 if (RegOpenKey (HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, &hk) == 0)
698 {
699 DWORD dwSize = sizeof(netbiosName);
700 DWORD dwType = REG_SZ;
701 RegQueryValueExA (hk, "NetbiosName", NULL, &dwType, (PBYTE)netbiosName, &dwSize);
702 RegCloseKey (hk);
703
704 if ( ioctlDebug ) {
705 saveerrno = errno;
706 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
707 errno = saveerrno;
708 }
709 } else {
710 if ( ioctlDebug ) {
711 saveerrno = errno;
712 gle = GetLastError();
713 fprintf(stderr, "pioctl Unable to open \"HKLM\\%s\" using NetbiosName = \"AFS\" GLE=0x%x\r\n",
714 HostName, CurrentState, gle);
715 errno = saveerrno;
716 }
717 }
718 } else {
719 if ( ioctlDebug ) {
720 saveerrno = errno;
721 fprintf(stderr, "pioctl Redirector is not ready\r\n");
722 errno = saveerrno;
723 }
724
725 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", netbiosName, sizeof(netbiosName)))
726 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
727
728 if ( ioctlDebug ) {
729 saveerrno = errno;
730 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
731 errno = saveerrno;
732 }
733 }
734
735 if (fileNamep) {
736 drivep = strchr(fileNamep, ':');
737 if (drivep && (drivep - fileNamep) >= 1) {
738 tbuffer[0] = *(drivep - 1);
739 tbuffer[1] = ':';
740 tbuffer[2] = '\0';
741
742 driveType = GetDriveType(tbuffer);
743 switch (driveType) {
744 case DRIVE_UNKNOWN:
745 case DRIVE_REMOTE:
746 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
747 DriveIsGlobalAutoMapped(tbuffer))
748 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
749 else
750 return -1;
751 break;
752 default:
753 if (DriveIsGlobalAutoMapped(tbuffer))
754 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
755 else
756 return -1;
757 }
758 } else if (fileNamep[0] == fileNamep[1] &&
759 (fileNamep[0] == '\\' || fileNamep[0] == '/'))
760 {
761 int count = 0, i = 0;
762
763 while (count < 4 && fileNamep[i]) {
764 tbuffer[i] = fileNamep[i];
765 if ( tbuffer[i] == '\\' ||
766 tbuffer[i] == '/')
767 count++;
768 i++;
769 }
770 if (fileNamep[i] == 0 || (fileNamep[i-1] != '\\' && fileNamep[i-1] != '/'))
771 tbuffer[i++] = '\\';
772 tbuffer[i] = 0;
773 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
774 } else {
775 char curdir[MAX_PATH]="";
776
777 GetCurrentDirectory(sizeof(curdir), curdir);
778 if ( curdir[1] == ':' ) {
779 tbuffer[0] = curdir[0];
780 tbuffer[1] = ':';
781 tbuffer[2] = '\0';
782
783 driveType = GetDriveType(tbuffer);
784 switch (driveType) {
785 case DRIVE_UNKNOWN:
786 case DRIVE_REMOTE:
787 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
788 DriveIsGlobalAutoMapped(tbuffer))
789 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
790 else
791 return -1;
792 break;
793 default:
794 if (DriveIsGlobalAutoMapped(tbuffer))
795 strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
796 else
797 return -1;
798 }
799 } else if (curdir[0] == curdir[1] &&
800 (curdir[0] == '\\' || curdir[0] == '/'))
801 {
802 int count = 0, i = 0;
803
804 while (count < 4 && curdir[i]) {
805 tbuffer[i] = curdir[i];
806 if ( tbuffer[i] == '\\' ||
807 tbuffer[i] == '/')
808 count++;
809 i++;
810 }
811 if (curdir[i] == 0 || (curdir[i-1] != '\\' && curdir[i-1] != '/'))
812 tbuffer[i++] = '\\';
813 tbuffer[i] = 0;
814 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
815 }
816 }
817 }
818 if (!tbuffer[0]) {
819 /* No file name starting with drive colon specified, use UNC name */
820 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
821 }
822
823 if ( ioctlDebug ) {
824 saveerrno = errno;
825 fprintf(stderr, "pioctl filename = \"%s\"\r\n", tbuffer);
826 errno = saveerrno;
827 }
828
829 fflush(stdout);
830
831 /*
832 * Try to find the correct path and authentication
833 */
834 dwAttrib = GetFileAttributes(tbuffer);
835 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
836 int gonext = 0;
837
838 gle = GetLastError();
839 if (gle && ioctlDebug ) {
840 char buf[4096];
841
842 saveerrno = errno;
843 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
844 NULL,
845 gle,
846 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
847 buf,
848 4096,
849 NULL
850 ) )
851 {
852 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
853 tbuffer,gle,buf);
854 }
855 errno = saveerrno;
856 SetLastError(gle);
857 }
858
859 /* with the redirector interface, fail immediately. there is nothing to retry */
860 if (usingRDR)
861 return -1;
862
863 if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", szClient, sizeof(szClient)))
864 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
865
866 if (RegOpenKey (HKEY_CURRENT_USER,
867 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
868 {
869 DWORD dwType = REG_SZ;
870 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
871 RegCloseKey (hk);
872 }
873
874 if ( szUser[0] ) {
875 if ( ioctlDebug ) {
876 saveerrno = errno;
877 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
878 errno = saveerrno;
879 }
880 sprintf(szPath, "\\\\%s", szClient);
881 memset (&nr, 0x00, sizeof(NETRESOURCE));
882 nr.dwType=RESOURCETYPE_DISK;
883 nr.lpLocalName=0;
884 nr.lpRemoteName=szPath;
885 res = WNetAddConnection2(&nr,NULL,szUser,0);
886 if (res) {
887 if ( ioctlDebug ) {
888 saveerrno = errno;
889 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
890 szPath,szUser,res);
891 errno = saveerrno;
892 }
893 gonext = 1;
894 }
895
896 sprintf(szPath, "\\\\%s\\all", szClient);
897 res = WNetAddConnection2(&nr,NULL,szUser,0);
898 if (res) {
899 if ( ioctlDebug ) {
900 saveerrno = errno;
901 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
902 szPath,szUser,res);
903 errno = saveerrno;
904 }
905 gonext = 1;
906 }
907
908 if (gonext)
909 goto try_lsa_principal;
910
911 dwAttrib = GetFileAttributes(tbuffer);
912 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
913 gle = GetLastError();
914 if (gle && ioctlDebug ) {
915 char buf[4096];
916
917 saveerrno = errno;
918 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
919 NULL,
920 gle,
921 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
922 buf,
923 4096,
924 NULL
925 ) )
926 {
927 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
928 tbuffer,gle,buf);
929 }
930 errno = saveerrno;
931 SetLastError(gle);
932 }
933 }
934 }
935 }
936
937 try_lsa_principal:
938 if (!usingRDR &&
939 dwAttrib == INVALID_FILE_ATTRIBUTES) {
940 int gonext = 0;
941
942 dwSize = sizeof(szUser);
943 if (GetLSAPrincipalName(szUser, dwSize)) {
944 if ( ioctlDebug ) {
945 saveerrno = errno;
946 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
947 errno = saveerrno;
948 }
949 sprintf(szPath, "\\\\%s", szClient);
950 memset (&nr, 0x00, sizeof(NETRESOURCE));
951 nr.dwType=RESOURCETYPE_DISK;
952 nr.lpLocalName=0;
953 nr.lpRemoteName=szPath;
954 res = WNetAddConnection2(&nr,NULL,szUser,0);
955 if (res) {
956 if ( ioctlDebug ) {
957 saveerrno = errno;
958 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
959 szPath,szUser,res);
960 errno = saveerrno;
961 }
962 gonext = 1;
963 }
964
965 sprintf(szPath, "\\\\%s\\all", szClient);
966 res = WNetAddConnection2(&nr,NULL,szUser,0);
967 if (res) {
968 if ( ioctlDebug ) {
969 saveerrno = errno;
970 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
971 szPath,szUser,res);
972 errno = saveerrno;
973 }
974 gonext = 1;
975 }
976
977 if (gonext)
978 goto try_sam_compat;
979
980 dwAttrib = GetFileAttributes(tbuffer);
981 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
982 gle = GetLastError();
983 if (gle && ioctlDebug ) {
984 char buf[4096];
985
986 saveerrno = errno;
987 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
988 NULL,
989 gle,
990 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
991 buf,
992 4096,
993 NULL
994 ) )
995 {
996 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
997 tbuffer,gle,buf);
998 }
999 errno = saveerrno;
1000 SetLastError(gle);
1001 }
1002 }
1003 }
1004 }
1005
1006 try_sam_compat:
1007 if (!usingRDR &&
1008 dwAttrib == INVALID_FILE_ATTRIBUTES) {
1009 dwSize = sizeof(szUser);
1010 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
1011 if ( ioctlDebug ) {
1012 saveerrno = errno;
1013 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
1014 errno = saveerrno;
1015 }
1016 sprintf(szPath, "\\\\%s", szClient);
1017 memset (&nr, 0x00, sizeof(NETRESOURCE));
1018 nr.dwType=RESOURCETYPE_DISK;
1019 nr.lpLocalName=0;
1020 nr.lpRemoteName=szPath;
1021 res = WNetAddConnection2(&nr,NULL,szUser,0);
1022 if (res) {
1023 if ( ioctlDebug ) {
1024 saveerrno = errno;
1025 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1026 szPath,szUser,res);
1027 errno = saveerrno;
1028 }
1029 }
1030
1031 sprintf(szPath, "\\\\%s\\all", szClient);
1032 res = WNetAddConnection2(&nr,NULL,szUser,0);
1033 if (res) {
1034 if ( ioctlDebug ) {
1035 saveerrno = errno;
1036 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1037 szPath,szUser,res);
1038 errno = saveerrno;
1039 }
1040 return -1;
1041 }
1042
1043 dwAttrib = GetFileAttributes(tbuffer);
1044 if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
1045 gle = GetLastError();
1046 if (gle && ioctlDebug ) {
1047 char buf[4096];
1048
1049 saveerrno = errno;
1050 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1051 NULL,
1052 gle,
1053 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1054 buf,
1055 4096,
1056 NULL
1057 ) )
1058 {
1059 fprintf(stderr,"pioctl GetFileAttributes(%s) failed: 0x%X\r\n\t[%s]\r\n",
1060 tbuffer,gle,buf);
1061 }
1062 errno = saveerrno;
1063 }
1064 return -1;
1065 }
1066 } else {
1067 fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
1068 return -1;
1069 }
1070 }
1071
1072 if ( dwAttrib != (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
1073 fprintf(stderr, "GetFileAttributes(%s) returned: 0x%08X\r\n",
1074 tbuffer, dwAttrib);
1075 return -1;
1076 }
1077
1078 /* tbuffer now contains the correct path; now open the file */
1079 sharingViolation = 0;
1080 do {
1081 if (sharingViolation)
1082 Sleep(100);
1083 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
1084 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1085 FILE_FLAG_WRITE_THROUGH, NULL);
1086 sharingViolation++;
1087 } while (fh == INVALID_HANDLE_VALUE &&
1088 GetLastError() == ERROR_SHARING_VIOLATION &&
1089 sharingViolation < 100);
1090 fflush(stdout);
1091
1092 if (fh == INVALID_HANDLE_VALUE)
1093 return -1;
1094
1095 /* return fh and success code */
1096 *handlep = fh;
1097 return 0;
1098 }
1099
1100 static long
1101 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
1102 {
1103 long rcount;
1104 long ioCount;
1105 DWORD gle;
1106 DWORD ioctlDebug = IoctlDebug();
1107 int save;
1108
1109 rcount = (long)(reqp->mp - reqp->data);
1110 if (rcount <= 0) {
1111 if ( ioctlDebug ) {
1112 save = errno;
1113 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
1114 errno = save;
1115 }
1116 return EINVAL; /* not supposed to happen */
1117 }
1118
1119 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
1120 /* failed to write */
1121 gle = GetLastError();
1122
1123 if ( ioctlDebug ) {
1124 save = errno;
1125 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
1126 errno = save;
1127 }
1128 return gle;
1129 }
1130
1131 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
1132 /* failed to read */
1133 gle = GetLastError();
1134
1135 if ( ioctlDebug ) {
1136 save = errno;
1137 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
1138 errno = save;
1139 }
1140 if (gle == ERROR_NOT_SUPPORTED) {
1141 errno = EINVAL;
1142 return -1;
1143 }
1144 return gle;
1145 }
1146
1147 reqp->nbytes = ioCount; /* set # of bytes available */
1148 reqp->mp = reqp->data; /* restart marshalling */
1149
1150 /* return success */
1151 return 0;
1152 }
1153
1154 static long
1155 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1156 {
1157 memcpy(reqp->mp, &val, 4);
1158 reqp->mp += 4;
1159 return 0;
1160 }
1161
1162 static long
1163 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1164 {
1165 int save;
1166
1167 /* not enough data left */
1168 if (reqp->nbytes < 4) {
1169 if ( IoctlDebug() ) {
1170 save = errno;
1171 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1172 reqp->nbytes);
1173 errno = save;
1174 }
1175 return -1;
1176 }
1177
1178 memcpy(valp, reqp->mp, 4);
1179 reqp->mp += 4;
1180 reqp->nbytes -= 4;
1181 return 0;
1182 }
1183
1184 /* includes marshalling NULL pointer as a null (0 length) string */
1185 static long
1186 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1187 {
1188 int count;
1189 int save;
1190
1191 if (stringp)
1192 count = (int)strlen(stringp) + 1;/* space required including null */
1193 else
1194 count = 1;
1195
1196 if (is_utf8) {
1197 count += utf8_prefix_size;
1198 }
1199
1200 /* watch for buffer overflow */
1201 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1202 if ( IoctlDebug() ) {
1203 save = errno;
1204 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1205 errno = save;
1206 }
1207 return -1;
1208 }
1209
1210 if (is_utf8) {
1211 memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1212 reqp->mp += utf8_prefix_size;
1213 count -= utf8_prefix_size;
1214 }
1215
1216 if (stringp)
1217 memcpy(reqp->mp, stringp, count);
1218 else
1219 *(reqp->mp) = 0;
1220 reqp->mp += count;
1221 return 0;
1222 }
1223
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.
1227 */
1228 static long
1229 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1230 {
1231 char tpath[1000];
1232 char origPath[1000];
1233 char *firstp;
1234 long code;
1235 int pathHasDrive;
1236 int doSwitch;
1237 char newPath[3];
1238 char * p;
1239 int save;
1240
1241 if (pathp[0] != 0 && pathp[1] == ':') {
1242 /* there's a drive letter there */
1243 firstp = pathp + 2;
1244 pathHasDrive = 1;
1245 } else {
1246 firstp = pathp;
1247 pathHasDrive = 0;
1248 }
1249
1250 if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1251 firstp[0] == '/' && firstp[1] == '/') {
1252 /* UNC path - strip off the server and sharename */
1253 int i, count;
1254 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1255 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1256 count++;
1257 }
1258 }
1259 if ( firstp[i] == 0 ) {
1260 strcpy(outPathp,"\\");
1261 } else {
1262 strcpy(outPathp,&firstp[--i]);
1263 }
1264 for (p=outPathp ;*p; p++) {
1265 if (*p == '/')
1266 *p = '\\';
1267 }
1268 return 0;
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++) {
1273 if (*p == '/')
1274 *p = '\\';
1275 }
1276 return 0;
1277 }
1278
1279 GetCurrentDirectory(sizeof(origPath), origPath);
1280
1281 doSwitch = 0;
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.
1286 */
1287 doSwitch = 1;
1288 newPath[0] = *pathp;
1289 newPath[1] = ':';
1290 newPath[2] = 0;
1291 if (!SetCurrentDirectory(newPath)) {
1292 code = GetLastError();
1293
1294 if ( IoctlDebug() ) {
1295 save = errno;
1296 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1297 newPath, code);
1298 errno = save;
1299 }
1300 return code;
1301 }
1302 }
1303
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 */
1311 int i, count;
1312 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1313 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1314 count++;
1315 }
1316 }
1317 if ( tpath[i] == 0 ) {
1318 strcpy(outPathp,"\\");
1319 } else {
1320 strcpy(outPathp,&tpath[--i]);
1321 }
1322 } else {
1323 /* this should never happen */
1324 strcpy(outPathp, tpath);
1325 }
1326
1327 /* if there is a non-null name after the drive, append it */
1328 if (*firstp != 0) {
1329 int len = (int)strlen(outPathp);
1330 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1331 strcat(outPathp, "\\");
1332 strcat(outPathp, firstp);
1333 }
1334
1335 /* finally, if necessary, switch back to our home drive letter */
1336 if (doSwitch) {
1337 SetCurrentDirectory(origPath);
1338 }
1339
1340 for (p=outPathp ;*p; p++) {
1341 if (*p == '/')
1342 *p = '\\';
1343 }
1344 return 0;
1345 }
1346
1347 static int
1348 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1349 {
1350 fs_ioctlRequest_t preq;
1351 long code;
1352 long temp;
1353 char fullPath[1000];
1354 char altPath[1024];
1355 HANDLE reqHandle;
1356 int save;
1357 int i,j,count,all;
1358
1359 /*
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.
1368 *
1369 * We cannot use this form in all cases because of smb submounts which are
1370 * not located within the Freelance local root.
1371 */
1372 switch ( opcode ) {
1373 case VIOC_AFS_CREATE_MT_PT:
1374 case VIOC_SYMLINK:
1375 if (pathp &&
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] == '/')
1380 count++;
1381
1382 /* Test to see if the second component is 'all' */
1383 if (count == 3) {
1384 all = 1;
1385 for (i=0; pathp[i+j]; i++) {
1386 switch(i) {
1387 case 0:
1388 if (pathp[i+j] != 'a' &&
1389 pathp[i+j] != 'A') {
1390 all = 0;
1391 goto notall;
1392 }
1393 break;
1394 case 1:
1395 case 2:
1396 if (pathp[i+j] != 'l' &&
1397 pathp[i+j] != 'L') {
1398 all = 0;
1399 goto notall;
1400 }
1401 break;
1402 default:
1403 all = 0;
1404 goto notall;
1405 }
1406 }
1407 if (i != 3)
1408 all = 0;
1409 }
1410
1411 notall:
1412 if (all)
1413 break;
1414 }
1415
1416 /*
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.
1420 */
1421
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++] = '\\';
1427 count++;
1428
1429 if (count == 3) {
1430 altPath[i++] = 'a';
1431 altPath[i++] = 'l';
1432 altPath[i++] = 'l';
1433 altPath[i++] = '\\';
1434 count++;
1435 }
1436 } else {
1437 altPath[i++] = pathp[j];
1438 }
1439 }
1440 altPath[i] = '\0';
1441 pathp = altPath;
1442 }
1443 }
1444 }
1445
1446 code = GetIoctlHandle(pathp, &reqHandle);
1447 if (code) {
1448 if (pathp)
1449 errno = EINVAL;
1450 else
1451 errno = ENODEV;
1452 return code;
1453 }
1454
1455 /* init the request structure */
1456 InitFSRequest(&preq);
1457
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.
1464 */
1465 if (pathp) {
1466 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1467 if (code) {
1468 CloseHandle(reqHandle);
1469 errno = EINVAL;
1470 return code;
1471 }
1472 } else {
1473 strcpy(fullPath, "");
1474 }
1475
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)) {
1479 errno = E2BIG;
1480 return -1;
1481 }
1482 memcpy(preq.mp, blobp->in, blobp->in_size);
1483 preq.mp += blobp->in_size;
1484 }
1485
1486 /* now make the call */
1487 code = Transceive(reqHandle, &preq);
1488 if (code) {
1489 CloseHandle(reqHandle);
1490 return code;
1491 }
1492
1493 /* now unmarshall the return value */
1494 if (UnmarshallLong(&preq, &temp) != 0) {
1495 CloseHandle(reqHandle);
1496 return -1;
1497 }
1498
1499 if (temp != 0) {
1500 CloseHandle(reqHandle);
1501 errno = CMtoUNIXerror(temp);
1502 if ( IoctlDebug() ) {
1503 save = errno;
1504 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1505 errno = save;
1506 }
1507 return -1;
1508 }
1509
1510 /* otherwise, unmarshall the output parameters */
1511 if (blobp->out_size) {
1512 temp = blobp->out_size;
1513 if (preq.nbytes < temp)
1514 temp = preq.nbytes;
1515 memcpy(blobp->out, preq.mp, temp);
1516 blobp->out_size = temp;
1517 }
1518
1519 /* and return success */
1520 CloseHandle(reqHandle);
1521 return 0;
1522 }
1523
1524 int
1525 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1526 {
1527 return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1528 }
1529
1530 int
1531 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1532 {
1533 return pioctl_int(pathp, opcode, blobp, follow, FALSE);
1534 }
1535