Use calloc, rather than malloc/memset
[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                                (va_list *) 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                                     (va_list *) 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                                (va_list *) 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                                         (va_list *) 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                                         (va_list *) 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                                         (va_list *) 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         return gle;
1141     }
1142
1143     reqp->nbytes = ioCount;     /* set # of bytes available */
1144     reqp->mp = reqp->data;      /* restart marshalling */
1145
1146     /* return success */
1147     return 0;
1148 }
1149
1150 static long
1151 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1152 {
1153     memcpy(reqp->mp, &val, 4);
1154     reqp->mp += 4;
1155     return 0;
1156 }
1157
1158 static long
1159 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1160 {
1161     int save;
1162
1163     /* not enough data left */
1164     if (reqp->nbytes < 4) {
1165         if ( IoctlDebug() ) {
1166             save = errno;
1167             fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1168                      reqp->nbytes);
1169             errno = save;
1170         }
1171         return -1;
1172     }
1173
1174     memcpy(valp, reqp->mp, 4);
1175     reqp->mp += 4;
1176     reqp->nbytes -= 4;
1177     return 0;
1178 }
1179
1180 /* includes marshalling NULL pointer as a null (0 length) string */
1181 static long
1182 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1183 {
1184     int count;
1185     int save;
1186
1187     if (stringp)
1188         count = (int)strlen(stringp) + 1;/* space required including null */
1189     else
1190         count = 1;
1191
1192     if (is_utf8) {
1193         count += utf8_prefix_size;
1194     }
1195
1196     /* watch for buffer overflow */
1197     if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1198         if ( IoctlDebug() ) {
1199             save = errno;
1200             fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1201             errno = save;
1202         }
1203         return -1;
1204     }
1205
1206     if (is_utf8) {
1207         memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1208         reqp->mp += utf8_prefix_size;
1209         count -= utf8_prefix_size;
1210     }
1211
1212     if (stringp)
1213         memcpy(reqp->mp, stringp, count);
1214     else
1215         *(reqp->mp) = 0;
1216     reqp->mp += count;
1217     return 0;
1218 }
1219
1220 /* take a path with a drive letter, possibly relative, and return a full path
1221  * without the drive letter.  This is the full path relative to the working
1222  * dir for that drive letter.  The input and output paths can be the same.
1223  */
1224 static long
1225 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1226 {
1227     char tpath[1000];
1228     char origPath[1000];
1229     char *firstp;
1230     long code;
1231     int pathHasDrive;
1232     int doSwitch;
1233     char newPath[3];
1234     char * p;
1235     int save;
1236
1237     if (pathp[0] != 0 && pathp[1] == ':') {
1238         /* there's a drive letter there */
1239         firstp = pathp + 2;
1240         pathHasDrive = 1;
1241     } else {
1242         firstp = pathp;
1243         pathHasDrive = 0;
1244     }
1245
1246     if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1247          firstp[0] == '/' && firstp[1] == '/') {
1248         /* UNC path - strip off the server and sharename */
1249         int i, count;
1250         for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1251             if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1252                 count++;
1253             }
1254         }
1255         if ( firstp[i] == 0 ) {
1256             strcpy(outPathp,"\\");
1257         } else {
1258             strcpy(outPathp,&firstp[--i]);
1259         }
1260         for (p=outPathp ;*p; p++) {
1261             if (*p == '/')
1262                 *p = '\\';
1263         }
1264         return 0;
1265     } else if (firstp[0] == '\\' || firstp[0] == '/') {
1266         /* already an absolute pathname, just copy it back */
1267         strcpy(outPathp, firstp);
1268         for (p=outPathp ;*p; p++) {
1269             if (*p == '/')
1270                 *p = '\\';
1271         }
1272         return 0;
1273     }
1274
1275     GetCurrentDirectory(sizeof(origPath), origPath);
1276
1277     doSwitch = 0;
1278     if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
1279         /* a drive has been specified and it isn't our current drive.
1280          * to get path, switch to it first.  Must case-fold drive letters
1281          * for user convenience.
1282          */
1283         doSwitch = 1;
1284         newPath[0] = *pathp;
1285         newPath[1] = ':';
1286         newPath[2] = 0;
1287         if (!SetCurrentDirectory(newPath)) {
1288             code = GetLastError();
1289
1290             if ( IoctlDebug() ) {
1291                 save = errno;
1292                 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1293                          newPath, code);
1294                 errno = save;
1295             }
1296             return code;
1297         }
1298     }
1299
1300     /* now get the absolute path to the current wdir in this drive */
1301     GetCurrentDirectory(sizeof(tpath), tpath);
1302     if (tpath[1] == ':')
1303         strcpy(outPathp, tpath + 2);    /* skip drive letter */
1304     else if ( tpath[0] == '\\' && tpath[1] == '\\'||
1305               tpath[0] == '/' && tpath[1] == '/') {
1306         /* UNC path - strip off the server and sharename */
1307         int i, count;
1308         for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1309             if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1310                 count++;
1311             }
1312         }
1313         if ( tpath[i] == 0 ) {
1314             strcpy(outPathp,"\\");
1315         } else {
1316             strcpy(outPathp,&tpath[--i]);
1317         }
1318     } else {
1319         /* this should never happen */
1320         strcpy(outPathp, tpath);
1321     }
1322
1323     /* if there is a non-null name after the drive, append it */
1324     if (*firstp != 0) {
1325         int len = (int)strlen(outPathp);
1326         if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1327             strcat(outPathp, "\\");
1328         strcat(outPathp, firstp);
1329     }
1330
1331     /* finally, if necessary, switch back to our home drive letter */
1332     if (doSwitch) {
1333         SetCurrentDirectory(origPath);
1334     }
1335
1336     for (p=outPathp ;*p; p++) {
1337         if (*p == '/')
1338             *p = '\\';
1339     }
1340     return 0;
1341 }
1342
1343 static int
1344 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1345 {
1346     fs_ioctlRequest_t preq;
1347     long code;
1348     long temp;
1349     char fullPath[1000];
1350     char altPath[1024];
1351     HANDLE reqHandle;
1352     int save;
1353     int i,j,count,all;
1354
1355     /*
1356      * The pioctl operations for creating a mount point and a symlink are broken.
1357      * Instead of 'pathp' referring to the directory object in which the symlink
1358      * or mount point within which the new object is to be created, 'pathp' refers
1359      * to the object itself.  This results in a problem when the object being created
1360      * is located within the Freelance root.afs volume.  \\afs\foo will not be a
1361      * valid share name since the 'foo' object does not yet exist.  Therefore,
1362      * \\afs\foo\_._.afs_ioctl_._ cannot be opened.  Instead in these two cases
1363      * we must force the use of the \\afs\all\foo form of the path.
1364      *
1365      * We cannot use this form in all cases because of smb submounts which are
1366      * not located within the Freelance local root.
1367      */
1368     switch ( opcode ) {
1369     case VIOC_AFS_CREATE_MT_PT:
1370     case VIOC_SYMLINK:
1371         if (pathp &&
1372              (pathp[0] == '\\' && pathp[1] == '\\' ||
1373               pathp[0] == '/' && pathp[1] == '/')) {
1374             for (all = count = j = 0; pathp[j]; j++) {
1375                 if (pathp[j] == '\\' || pathp[j] == '/')
1376                     count++;
1377
1378                 /* Test to see if the second component is 'all' */
1379                 if (count == 3) {
1380                     all = 1;
1381                     for (i=0; pathp[i+j]; i++) {
1382                         switch(i) {
1383                         case 0:
1384                             if (pathp[i+j] != 'a' &&
1385                                 pathp[i+j] != 'A') {
1386                                 all = 0;
1387                                 goto notall;
1388                             }
1389                             break;
1390                         case 1:
1391                         case 2:
1392                             if (pathp[i+j] != 'l' &&
1393                                  pathp[i+j] != 'L') {
1394                                 all = 0;
1395                                 goto notall;
1396                             }
1397                             break;
1398                         default:
1399                             all = 0;
1400                             goto notall;
1401                         }
1402                     }
1403                     if (i != 3)
1404                         all = 0;
1405                 }
1406
1407               notall:
1408                 if (all)
1409                     break;
1410             }
1411
1412             /*
1413              * if count is three and the second component is not 'all',
1414              * then we are attempting to create an object in the
1415              * Freelance root.afs volume.  Substitute the path.
1416              */
1417
1418             if (count == 3 && !all) {
1419                 /* Normalize the name to use \\afs\all as the root */
1420                 for (count = i = j = 0; pathp[j] && i < sizeof(altPath); j++) {
1421                     if (pathp[j] == '\\' || pathp[j] == '/') {
1422                         altPath[i++] = '\\';
1423                         count++;
1424
1425                         if (count == 3) {
1426                             altPath[i++] = 'a';
1427                             altPath[i++] = 'l';
1428                             altPath[i++] = 'l';
1429                             altPath[i++] = '\\';
1430                             count++;
1431                         }
1432                     } else {
1433                         altPath[i++] = pathp[j];
1434                     }
1435                 }
1436                 altPath[i] = '\0';
1437                 pathp = altPath;
1438             }
1439         }
1440     }
1441
1442     code = GetIoctlHandle(pathp, &reqHandle);
1443     if (code) {
1444         if (pathp)
1445             errno = EINVAL;
1446         else
1447             errno = ENODEV;
1448         return code;
1449     }
1450
1451     /* init the request structure */
1452     InitFSRequest(&preq);
1453
1454     /* marshall the opcode, the path name and the input parameters */
1455     MarshallLong(&preq, opcode);
1456     /* when marshalling the path, remove the drive letter, since we already
1457      * used the drive letter to find the AFS daemon; we don't need it any more.
1458      * Eventually we'll expand relative path names here, too, since again, only
1459      * we understand those.
1460      */
1461     if (pathp) {
1462         code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1463         if (code) {
1464             CloseHandle(reqHandle);
1465             errno = EINVAL;
1466             return code;
1467         }
1468     } else {
1469         strcpy(fullPath, "");
1470     }
1471
1472     MarshallString(&preq, fullPath, is_utf8);
1473     if (blobp->in_size) {
1474         if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
1475             errno = E2BIG;
1476             return -1;
1477         }
1478         memcpy(preq.mp, blobp->in, blobp->in_size);
1479         preq.mp += blobp->in_size;
1480     }
1481
1482     /* now make the call */
1483     code = Transceive(reqHandle, &preq);
1484     if (code) {
1485         CloseHandle(reqHandle);
1486         return code;
1487     }
1488
1489     /* now unmarshall the return value */
1490     if (UnmarshallLong(&preq, &temp) != 0) {
1491         CloseHandle(reqHandle);
1492         return -1;
1493     }
1494
1495     if (temp != 0) {
1496         CloseHandle(reqHandle);
1497         errno = CMtoUNIXerror(temp);
1498         if ( IoctlDebug() ) {
1499             save = errno;
1500             fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1501             errno = save;
1502         }
1503         return -1;
1504     }
1505
1506     /* otherwise, unmarshall the output parameters */
1507     if (blobp->out_size) {
1508         temp = blobp->out_size;
1509         if (preq.nbytes < temp)
1510             temp = preq.nbytes;
1511         memcpy(blobp->out, preq.mp, temp);
1512         blobp->out_size = temp;
1513     }
1514
1515     /* and return success */
1516     CloseHandle(reqHandle);
1517     return 0;
1518 }
1519
1520 int
1521 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1522 {
1523     return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1524 }
1525
1526 int
1527 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1528 {
1529     return pioctl_int(pathp, opcode, blobp, follow, FALSE);
1530 }
1531