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>
34 #include <cm_scache.h>
40 #include <pioctl_nt.h>
42 #include <lanahelper.h>
44 static char AFSConfigKeyName[] =
45 "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
47 #define FS_IOCTLREQUEST_MAXSIZE 8192
48 /* big structure for representing and storing an IOCTL request */
49 typedef struct fs_ioctlRequest {
50 char *mp; /* marshalling/unmarshalling ptr */
51 long nbytes; /* bytes received (when unmarshalling) */
52 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
56 CMtoUNIXerror(int cm_code)
59 case CM_ERROR_TIMEDOUT:
61 case CM_ERROR_NOACCESS:
63 case CM_ERROR_NOSUCHFILE:
71 case CM_ERROR_CROSSDEVLINK:
77 case CM_ERROR_READONLY:
79 case CM_ERROR_WOULDBLOCK:
81 case CM_ERROR_NOSUCHCELL:
82 return ESRCH; /* hack */
83 case CM_ERROR_NOSUCHVOLUME:
84 return EPIPE; /* hack */
85 case CM_ERROR_NOMORETOKENS:
86 return EDOM; /* hack */
87 case CM_ERROR_TOOMANYBUFS:
88 return EFBIG; /* hack */
95 InitFSRequest(fs_ioctlRequest_t * rp)
102 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
105 char netbiosName[MAX_NB_NAME_LENGTH];
106 char tbuffer[256]="";
110 drivep = strchr(fileNamep, ':');
111 if (drivep && (drivep - fileNamep) >= 1) {
112 tbuffer[0] = *(drivep - 1);
114 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
115 } else if (fileNamep[0] == fileNamep[1] &&
116 fileNamep[0] == '\\')
118 int count = 0, i = 0;
120 while (count < 4 && fileNamep[i]) {
121 tbuffer[i] = fileNamep[i];
122 if ( tbuffer[i++] == '\\' )
125 if (fileNamep[i] == 0)
128 strcat(tbuffer, SMB_IOCTL_FILENAME);
132 GetCurrentDirectory(sizeof(curdir), curdir);
133 if ( curdir[1] == ':' ) {
134 tbuffer[0] = curdir[0];
136 strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
137 } else if (curdir[0] == curdir[1] &&
140 int count = 0, i = 0;
142 while (count < 4 && curdir[i]) {
143 tbuffer[i] = curdir[i];
144 if ( tbuffer[i++] == '\\' )
150 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
155 /* No file name starting with drive colon specified, use UNC name */
156 lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
157 sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
161 /* now open the file */
162 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
163 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
164 FILE_FLAG_WRITE_THROUGH, NULL);
166 if (fh == INVALID_HANDLE_VALUE) {
168 char szUser[64] = "";
169 char szClient[MAX_PATH] = "";
170 char szPath[MAX_PATH] = "";
174 if (GetLastError() != ERROR_DOWNGRADE_DETECTED)
177 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
178 sprintf(szPath, "\\\\%s", szClient);
180 /* We should probably be using GetUserNameEx() for this */
181 if (RegOpenKey (HKEY_CURRENT_USER,
182 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
184 DWORD dwSize = sizeof(szUser);
185 DWORD dwType = REG_SZ;
186 RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
190 memset (&nr, 0x00, sizeof(NETRESOURCE));
191 nr.dwType=RESOURCETYPE_DISK;
193 nr.lpRemoteName=szPath;
194 res = WNetAddConnection2(&nr,NULL,szUser,0);
198 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
199 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
200 FILE_FLAG_WRITE_THROUGH, NULL);
202 if (fh == INVALID_HANDLE_VALUE)
206 /* return fh and success code */
212 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
217 rcount = reqp->mp - reqp->data;
219 return EINVAL; /* not supposed to happen */
221 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
222 /* failed to write */
223 return GetLastError();
226 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
228 return GetLastError();
231 reqp->nbytes = ioCount; /* set # of bytes available */
232 reqp->mp = reqp->data; /* restart marshalling */
239 MarshallLong(fs_ioctlRequest_t * reqp, long val)
241 memcpy(reqp->mp, &val, 4);
247 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
249 /* not enough data left */
250 if (reqp->nbytes < 4) {
254 memcpy(valp, reqp->mp, 4);
260 /* includes marshalling NULL pointer as a null (0 length) string */
262 MarshallString(fs_ioctlRequest_t * reqp, char *stringp)
267 count = strlen(stringp) + 1; /* space required including null */
271 /* watch for buffer overflow */
272 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data))
276 memcpy(reqp->mp, stringp, count);
283 /* take a path with a drive letter, possibly relative, and return a full path
284 * without the drive letter. This is the full path relative to the working
285 * dir for that drive letter. The input and output paths can be the same.
288 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
298 if (pathp[0] != 0 && pathp[1] == ':') {
299 /* there's a drive letter there */
307 if ( firstp[0] == '\\' && firstp[1] == '\\') {
308 /* UNC path - strip off the server and sharename */
310 for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
311 if ( firstp[i] == '\\' || firstp[i] == '/' ) {
315 if ( firstp[i] == 0 ) {
316 strcpy(outPathp,"\\");
318 strcpy(outPathp,&firstp[--i]);
321 } else if (firstp[0] == '\\' || firstp[0] == '/') {
322 /* already an absolute pathname, just copy it back */
323 strcpy(outPathp, firstp);
327 GetCurrentDirectory(sizeof(origPath), origPath);
330 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
331 /* a drive has been specified and it isn't our current drive.
332 * to get path, switch to it first. Must case-fold drive letters
333 * for user convenience.
339 if (!SetCurrentDirectory(newPath)) {
340 code = GetLastError();
345 /* now get the absolute path to the current wdir in this drive */
346 GetCurrentDirectory(sizeof(tpath), tpath);
348 strcpy(outPathp, tpath + 2); /* skip drive letter */
349 else if ( tpath[0] == '\\' && tpath[1] == '\\') {
350 /* UNC path - strip off the server and sharename */
352 for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
353 if ( tpath[i] == '\\' || tpath[i] == '/' ) {
357 if ( tpath[i] == 0 ) {
358 strcpy(outPathp,"\\");
360 strcpy(outPathp,&tpath[--i]);
363 /* this should never happen */
364 strcpy(outPathp, tpath);
367 /* if there is a non-null name after the drive, append it */
369 int len = strlen(outPathp);
370 if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
371 strcat(outPathp, "\\");
372 strcat(outPathp, firstp);
375 /* finally, if necessary, switch back to our home drive letter */
377 SetCurrentDirectory(origPath);
384 pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
386 fs_ioctlRequest_t preq;
392 code = GetIoctlHandle(pathp, &reqHandle);
401 /* init the request structure */
402 InitFSRequest(&preq);
404 /* marshall the opcode, the path name and the input parameters */
405 MarshallLong(&preq, opcode);
406 /* when marshalling the path, remove the drive letter, since we already
407 * used the drive letter to find the AFS daemon; we don't need it any more.
408 * Eventually we'll expand relative path names here, too, since again, only
409 * we understand those.
412 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
414 CloseHandle(reqHandle);
419 strcpy(fullPath, "");
422 MarshallString(&preq, fullPath);
423 if (blobp->in_size) {
424 memcpy(preq.mp, blobp->in, blobp->in_size);
425 preq.mp += blobp->in_size;
428 /* now make the call */
429 code = Transceive(reqHandle, &preq);
431 CloseHandle(reqHandle);
435 /* now unmarshall the return value */
436 UnmarshallLong(&preq, &temp);
438 CloseHandle(reqHandle);
439 errno = CMtoUNIXerror(temp);
443 /* otherwise, unmarshall the output parameters */
444 if (blobp->out_size) {
445 temp = blobp->out_size;
446 if (preq.nbytes < temp)
448 memcpy(blobp->out, preq.mp, temp);
449 blobp->out_size = temp;
452 /* and return success */
453 CloseHandle(reqHandle);