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>
25 #define SECURITY_WIN32
36 #include <cm_scache.h>
42 #include <pioctl_nt.h>
44 #include <lanahelper.h>
46 static char AFSConfigKeyName[] =
47 "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
49 #define FS_IOCTLREQUEST_MAXSIZE 8192
50 /* big structure for representing and storing an IOCTL request */
51 typedef struct fs_ioctlRequest {
52 char *mp; /* marshalling/unmarshalling ptr */
53 long nbytes; /* bytes received (when unmarshalling) */
54 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
58 CMtoUNIXerror(int cm_code)
61 case CM_ERROR_TIMEDOUT:
63 case CM_ERROR_NOACCESS:
65 case CM_ERROR_NOSUCHFILE:
73 case CM_ERROR_CROSSDEVLINK:
79 case CM_ERROR_READONLY:
81 case CM_ERROR_WOULDBLOCK:
83 case CM_ERROR_NOSUCHCELL:
84 return ESRCH; /* hack */
85 case CM_ERROR_NOSUCHVOLUME:
86 return EPIPE; /* hack */
87 case CM_ERROR_NOMORETOKENS:
88 return EDOM; /* hack */
89 case CM_ERROR_TOOMANYBUFS:
90 return EFBIG; /* hack */
97 InitFSRequest(fs_ioctlRequest_t * rp)
107 static BOOL debug = 0;
112 if (RegOpenKey (HKEY_LOCAL_MACHINE,
113 TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
115 DWORD dwSize = sizeof(BOOL);
116 DWORD dwType = REG_DWORD;
117 RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
128 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
131 char netbiosName[MAX_NB_NAME_LENGTH];
132 char tbuffer[256]="";
135 char szUser[128] = "";
136 char szClient[MAX_PATH] = "";
137 char szPath[MAX_PATH] = "";
140 DWORD ioctlDebug = IoctlDebug();
142 DWORD dwSize = sizeof(szUser);
145 drivep = strchr(fileNamep, ':');
146 if (drivep && (drivep - fileNamep) >= 1) {
147 tbuffer[0] = *(drivep - 1);
149 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
150 } else if (fileNamep[0] == fileNamep[1] &&
151 fileNamep[0] == '\\')
153 int count = 0, i = 0;
155 while (count < 4 && fileNamep[i]) {
156 tbuffer[i] = fileNamep[i];
157 if ( tbuffer[i++] == '\\' )
160 if (fileNamep[i] == 0)
163 strcat(tbuffer, SMB_IOCTL_FILENAME);
167 GetCurrentDirectory(sizeof(curdir), curdir);
168 if ( curdir[1] == ':' ) {
169 tbuffer[0] = curdir[0];
171 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
172 } else if (curdir[0] == curdir[1] &&
175 int count = 0, i = 0;
177 while (count < 4 && curdir[i]) {
178 tbuffer[i] = curdir[i];
179 if ( tbuffer[i++] == '\\' )
185 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
190 /* No file name starting with drive colon specified, use UNC name */
191 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
192 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
196 /* now open the file */
197 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
198 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
199 FILE_FLAG_WRITE_THROUGH, NULL);
201 if (fh == INVALID_HANDLE_VALUE) {
204 gle = GetLastError();
205 if (gle && ioctlDebug ) {
208 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
211 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
217 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%8X\r\n\t[%s]\r\n",
222 if (gle != ERROR_DOWNGRADE_DETECTED)
226 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
228 if (RegOpenKey (HKEY_CURRENT_USER,
229 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
231 DWORD dwType = REG_SZ;
232 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
238 fprintf(stderr, "pioctl logon user: [%s]\r\n",szUser);
240 sprintf(szPath, "\\\\%s", szClient);
241 memset (&nr, 0x00, sizeof(NETRESOURCE));
242 nr.dwType=RESOURCETYPE_DISK;
244 nr.lpRemoteName=szPath;
245 res = WNetAddConnection2(&nr,NULL,szUser,0);
248 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
254 sprintf(szPath, "\\\\%s\\all", szClient);
255 res = WNetAddConnection2(&nr,NULL,szUser,0);
258 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
267 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
268 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
269 FILE_FLAG_WRITE_THROUGH, NULL);
271 if (fh == INVALID_HANDLE_VALUE) {
272 gle = GetLastError();
273 if (gle && ioctlDebug ) {
276 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
279 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
285 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%8X\r\n\t[%s]\r\n",
294 if ( fh == INVALID_HANDLE_VALUE ) {
295 if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
297 fprintf(stderr, "pioctl logon user: [%s]\r\n",szUser);
299 sprintf(szPath, "\\\\%s", szClient);
300 memset (&nr, 0x00, sizeof(NETRESOURCE));
301 nr.dwType=RESOURCETYPE_DISK;
303 nr.lpRemoteName=szPath;
304 res = WNetAddConnection2(&nr,NULL,szUser,0);
307 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
312 sprintf(szPath, "\\\\%s\\all", szClient);
313 res = WNetAddConnection2(&nr,NULL,szUser,0);
316 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
322 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
323 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
324 FILE_FLAG_WRITE_THROUGH, NULL);
326 if (fh == INVALID_HANDLE_VALUE) {
327 gle = GetLastError();
328 if (gle && ioctlDebug ) {
331 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
334 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
340 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%8X\r\n\t[%s]\r\n",
349 /* return fh and success code */
355 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
361 rcount = reqp->mp - reqp->data;
364 fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
365 return EINVAL; /* not supposed to happen */
368 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
369 /* failed to write */
370 gle = GetLastError();
373 fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
377 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
379 gle = GetLastError();
382 fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
386 reqp->nbytes = ioCount; /* set # of bytes available */
387 reqp->mp = reqp->data; /* restart marshalling */
394 MarshallLong(fs_ioctlRequest_t * reqp, long val)
396 memcpy(reqp->mp, &val, 4);
402 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
404 /* not enough data left */
405 if (reqp->nbytes < 4) {
407 fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
412 memcpy(valp, reqp->mp, 4);
418 /* includes marshalling NULL pointer as a null (0 length) string */
420 MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
425 count = strlen(stringp) + 1; /* space required including null */
429 /* watch for buffer overflow */
430 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
432 fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
437 memcpy(reqp->mp, stringp, count);
444 /* take a path with a drive letter, possibly relative, and return a full path
445 * without the drive letter. This is the full path relative to the working
446 * dir for that drive letter. The input and output paths can be the same.
449 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
459 if (pathp[0] != 0 && pathp[1] == ':') {
460 /* there's a drive letter there */
468 if ( firstp[0] == '\\' && firstp[1] == '\\') {
469 /* UNC path - strip off the server and sharename */
471 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
472 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
476 if ( firstp[i] == 0 ) {
477 strcpy(outPathp,"\\");
479 strcpy(outPathp,&firstp[--i]);
482 } else if (firstp[0] == '\\' || firstp[0] == '/') {
483 /* already an absolute pathname, just copy it back */
484 strcpy(outPathp, firstp);
488 GetCurrentDirectory(sizeof(origPath), origPath);
491 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
492 /* a drive has been specified and it isn't our current drive.
493 * to get path, switch to it first. Must case-fold drive letters
494 * for user convenience.
500 if (!SetCurrentDirectory(newPath)) {
501 code = GetLastError();
504 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
510 /* now get the absolute path to the current wdir in this drive */
511 GetCurrentDirectory(sizeof(tpath), tpath);
513 strcpy(outPathp, tpath + 2); /* skip drive letter */
514 else if ( tpath[0] == '\\' && tpath[1] == '\\') {
515 /* UNC path - strip off the server and sharename */
517 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
518 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
522 if ( tpath[i] == 0 ) {
523 strcpy(outPathp,"\\");
525 strcpy(outPathp,&tpath[--i]);
528 /* this should never happen */
529 strcpy(outPathp, tpath);
532 /* if there is a non-null name after the drive, append it */
534 int len = strlen(outPathp);
535 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
536 strcat(outPathp, "\\");
537 strcat(outPathp, firstp);
540 /* finally, if necessary, switch back to our home drive letter */
542 SetCurrentDirectory(origPath);
549 pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
551 fs_ioctlRequest_t preq;
557 code = GetIoctlHandle(pathp, &reqHandle);
566 /* init the request structure */
567 InitFSRequest(&preq);
569 /* marshall the opcode, the path name and the input parameters */
570 MarshallLong(&preq, opcode);
571 /* when marshalling the path, remove the drive letter, since we already
572 * used the drive letter to find the AFS daemon; we don't need it any more.
573 * Eventually we'll expand relative path names here, too, since again, only
574 * we understand those.
577 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
579 CloseHandle(reqHandle);
584 strcpy(fullPath, "");
587 MarshallString(&preq, fullPath);
588 if (blobp->in_size) {
589 memcpy(preq.mp, blobp->in, blobp->in_size);
590 preq.mp += blobp->in_size;
593 /* now make the call */
594 code = Transceive(reqHandle, &preq);
596 CloseHandle(reqHandle);
600 /* now unmarshall the return value */
601 if (UnmarshallLong(&preq, &temp) != 0) {
602 CloseHandle(reqHandle);
607 CloseHandle(reqHandle);
608 errno = CMtoUNIXerror(temp);
610 fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
614 /* otherwise, unmarshall the output parameters */
615 if (blobp->out_size) {
616 temp = blobp->out_size;
617 if (preq.nbytes < temp)
619 memcpy(blobp->out, preq.mp, temp);
620 blobp->out_size = temp;
623 /* and return success */
624 CloseHandle(reqHandle);