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>
33 #include <cm_scache.h>
39 #include <pioctl_nt.h>
41 static char AFSConfigKeyName[] =
42 "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
44 #define FS_IOCTLREQUEST_MAXSIZE 8192
45 /* big structure for representing and storing an IOCTL request */
46 typedef struct fs_ioctlRequest {
47 char *mp; /* marshalling/unmarshalling ptr */
48 long nbytes; /* bytes received (when unmarshalling) */
49 char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
52 static int CMtoUNIXerror(int cm_code)
55 case CM_ERROR_TIMEDOUT: return ETIMEDOUT;
56 case CM_ERROR_NOACCESS: return EACCES;
57 case CM_ERROR_NOSUCHFILE: return ENOENT;
58 case CM_ERROR_INVAL: return EINVAL;
59 case CM_ERROR_BADFD: return EBADF;
60 case CM_ERROR_EXISTS: return EEXIST;
61 case CM_ERROR_CROSSDEVLINK: return EXDEV;
62 case CM_ERROR_NOTDIR: return ENOTDIR;
63 case CM_ERROR_ISDIR: return EISDIR;
64 case CM_ERROR_READONLY: return EROFS;
65 case CM_ERROR_WOULDBLOCK: return EWOULDBLOCK;
66 case CM_ERROR_NOSUCHCELL: return ESRCH; /* hack */
67 case CM_ERROR_NOSUCHVOLUME: return EPIPE; /* hack */
68 case CM_ERROR_NOMORETOKENS: return EDOM; /* hack */
69 case CM_ERROR_TOOMANYBUFS: return EFBIG; /* hack */
70 default: return ENOTTY;
74 static void InitFSRequest(fs_ioctlRequest_t *rp)
80 static long GetIoctlHandle(char *fileNamep, HANDLE *handlep)
93 drivep = strchr(fileNamep, ':');
94 if (drivep && (drivep - fileNamep) >= 1) {
95 tbuffer[0] = *(drivep-1);
97 strcpy(tbuffer+2, SMB_IOCTL_FILENAME);
99 strcpy(tbuffer, SMB_IOCTL_FILENAME);
102 /* No file name specified, use UNC name */
103 /* First look for gateway host in Registry */
104 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
105 0, KEY_QUERY_VALUE, &parmKey);
106 if (code != ERROR_SUCCESS)
108 dummyLen = sizeof(hostName);
109 code = RegQueryValueEx(parmKey, "Gateway", NULL, NULL,
110 hostName, &dummyLen);
111 RegCloseKey (parmKey);
112 if (code == ERROR_SUCCESS)
115 /* No gateway name in registry; use ourself */
116 #ifndef AFS_WIN95_ENV
117 gethostname(hostName, sizeof(hostName));
119 /* DJGPP version of gethostname gets the NetBIOS
120 name of the machine, so that is what we are using for
121 the AFS server name instead of the DNS name. */
122 hostsize = sizeof(hostName);
123 GetComputerName(hostName, &hostsize);
124 #endif /* AFS_WIN95_ENV */
127 ctemp = strchr(hostName, '.'); /* turn ntafs.* into ntafs */
128 if (ctemp) *ctemp = 0;
132 sprintf(tbuffer, "\\\\%s-AFS\\all%s",
133 hostName, SMB_IOCTL_FILENAME);
137 /* now open the file */
138 fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
139 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
140 OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
142 if (fh == INVALID_HANDLE_VALUE)
145 /* return fh and success code */
150 static long Transceive(HANDLE handle, fs_ioctlRequest_t *reqp)
155 rcount = reqp->mp - reqp->data;
156 if (rcount <= 0) return EINVAL; /* not supposed to happen */
158 if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
159 /* failed to write */
160 return GetLastError();
163 if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
165 return GetLastError();
168 reqp->nbytes = ioCount; /* set # of bytes available */
169 reqp->mp = reqp->data; /* restart marshalling */
175 static long MarshallLong(fs_ioctlRequest_t *reqp, long val)
177 memcpy(reqp->mp, &val, 4);
182 static long UnmarshallLong(fs_ioctlRequest_t *reqp, long *valp)
184 /* not enough data left */
185 if (reqp->nbytes < 4) { return -1; }
187 memcpy(valp, reqp->mp, 4);
193 /* includes marshalling NULL pointer as a null (0 length) string */
194 static long MarshallString(fs_ioctlRequest_t *reqp, char *stringp)
199 count = strlen(stringp) + 1; /* space required including null */
202 /* watch for buffer overflow */
203 if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) return -1;
205 if (stringp) memcpy(reqp->mp, stringp, count);
206 else *(reqp->mp) = 0;
211 /* take a path with a drive letter, possibly relative, and return a full path
212 * without the drive letter. This is the full path relative to the working
213 * dir for that drive letter. The input and output paths can be the same.
215 static long fs_GetFullPath(char *pathp, char *outPathp, long outSize)
225 if (pathp[0] != 0 && pathp[1] == ':') {
226 /* there's a drive letter there */
235 if (*firstp == '\\' || *firstp == '/') {
236 /* already an absolute pathname, just copy it back */
237 strcpy(outPathp, firstp);
241 GetCurrentDirectory(sizeof(origPath), origPath);
244 if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
245 /* a drive has been specified and it isn't our current drive.
246 * to get path, switch to it first. Must case-fold drive letters
247 * for user convenience.
253 if (!SetCurrentDirectory(newPath)) {
254 code = GetLastError();
259 /* now get the absolute path to the current wdir in this drive */
260 GetCurrentDirectory(sizeof(tpath), tpath);
261 strcpy(outPathp, tpath+2); /* skip drive letter */
262 /* if there is a non-null name after the drive, append it */
264 strcat(outPathp, "\\");
265 strcat(outPathp, firstp);
268 /* finally, if necessary, switch back to our home drive letter */
270 SetCurrentDirectory(origPath);
276 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow)
278 fs_ioctlRequest_t preq;
284 code = GetIoctlHandle(pathp, &reqHandle);
293 /* init the request structure */
294 InitFSRequest(&preq);
296 /* marshall the opcode, the path name and the input parameters */
297 MarshallLong(&preq, opcode);
298 /* when marshalling the path, remove the drive letter, since we already
299 * used the drive letter to find the AFS daemon; we don't need it any more.
300 * Eventually we'll expand relative path names here, too, since again, only
301 * we understand those.
304 code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
306 CloseHandle(reqHandle);
312 strcpy(fullPath, "");
315 MarshallString(&preq, fullPath);
316 if (blobp->in_size) {
317 memcpy(preq.mp, blobp->in, blobp->in_size);
318 preq.mp += blobp->in_size;
321 /* now make the call */
322 code = Transceive(reqHandle, &preq);
324 CloseHandle(reqHandle);
328 /* now unmarshall the return value */
329 UnmarshallLong(&preq, &temp);
331 CloseHandle(reqHandle);
332 errno = CMtoUNIXerror(temp);
336 /* otherwise, unmarshall the output parameters */
337 if (blobp->out_size) {
338 temp = blobp->out_size;
339 if (preq.nbytes < temp) temp = preq.nbytes;
340 memcpy(blobp->out, preq.mp, temp);
341 blobp->out_size = temp;
344 /* and return success */
345 CloseHandle(reqHandle);