installer is still in the source tree but is no longer supported.
A new open source installer based on NSIS 2.0 replaces it.
+NOTE:
+In this release, there are two clients offered: an SMB version (as was
+included in all previous versions), and an IFS version (newly released).
+To build the IFS version, follow the directions below, but note that
+only the NSIS installer script can be correctly configured; the Wix
+installer will not work correctly. Also, the kernel module associated
+with the IFS version must be built separately, using the IFS kit or DDK
+build environment. While in the DDK build environment, enter into the
+afsrdr source directory, and execute 'build'. This will create the
+module to be packaged by the installer.
+
+
*********** Windows 2000/XP/2003 Build Process ****************
Building OpenAFS for Windows requires configuring a Windows
(3) Configure the environment variables:
- For a release build:
+ For a release build (SMB version):
(a) Execute the VCVARS32.BAT or VSVARS32.BAT file which part of the
Visual Studio environment you installed.
(c) Execute the NTBUILD.BAT file with the parameter "free"
- For a debug build:
+ For a release build (IFS version):
+
+ (a) Execute the VCVARS32.BAT or VSVARS32.BAT file which part of the
+ Visual Studio environment you installed.
+
+ (b) Execute the SETENV.BAT file with the parameters "/2000 /RETAIL"
+
+ (c) Execute the NTBUILD.BAT file with the parameter "free ifs"
+
+ For a debug build (SMB version):
(a) Execute the VCVARS32.BAT or VSVARS32.BAT file which part of the
Visual Studio environment you installed.
(c) Execute the NTBUILD.BAT file with the parameter "checked"
+ For a debug build (IFS version):
+
+ (a) Execute the VCVARS32.BAT or VSVARS32.BAT file which part of the
+ Visual Studio environment you installed.
+
+ (b) Execute the SETENV.BAT file with the parameters "/2000 /DEBUG"
+
+ (c) Execute the NTBUILD.BAT file with the parameter "checked ifs"
+
(4) Clean the work area:
nmake /f NTMakefile clean
$(IDLFILES):afsrpc.idl
midl $(MIDL_FLAGS) /no_robust $(AFSDEV_AUXMIDLFLAGS) /app_config $?
+RPCOBJS = $(OUT)\ifs_rpc.obj
+
+$(RPCOBJS):..\afsrdr\ifs_rpc.c
+ $(C2OBJ) ..\afsrdr\ifs_rpc.c
+
AFSDOBJS=\
+ $(OUT)\ifs_rpc.obj \
+ $(OUT)\rawops.obj \
+ $(OUT)\afsdifs.obj \
$(OUT)\afsd_init.obj \
$(OUT)\cm_cell.obj \
$(OUT)\cm_server.obj \
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
*/
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
#include <afs/param.h>
#include <afs/stds.h>
#include <crtdbg.h>
#endif
+#include "afsdifs.h"
+
HANDLE main_inst;
HWND main_wnd;
char main_statusText[100];
RECT main_rect;
osi_log_t *afsd_logp;
+HANDLE hAFSDWorkerThread[WORKER_THREADS], DoTerminate;
+
extern int traceOnPanic;
extern void afsd_DbgBreakAllocInit();
int nCmdShow)
{
MSG msg;
+ int i;
afsd_SetUnhandledExceptionFilter();
TranslateMessage(&msg);
DispatchMessage(&msg);
}
+
+#ifdef AFSIFS
+ WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
+ for (i = 0; i < WORKER_THREADS; i++)
+ CloseHandle(hAFSDWorkerThread[i]);
+ //CloseHandle(hAFSDMainThread);
+ RpcMgmtStopServerListening(NULL);
+#endif
+
return (msg.wParam);
}
HDC hDC;
TEXTMETRIC textmetric;
INT nLineHeight;
- long code;
+ long code, cnt;
char *reason;
/* remember this, since it is a useful thing for some of the Windows
if (code != 0)
osi_panic(reason, __FILE__, __LINE__);
- code = afsd_InitSMB(&reason, MessageBox);
+#ifndef AFSIFS
+ code = afsd_InitSMB(&reason, MessageBox);
+#else
+ code = ifs_Init(&reason);
+#endif
+
if (code != 0)
osi_panic(reason, __FILE__, __LINE__);
+#ifdef AFSIFS
+ DoTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_DoTerminate"));
+ if ( GetLastError() == ERROR_ALREADY_EXISTS )
+ afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_DoTerminate"));
+ for (cnt = 0; cnt < WORKER_THREADS; cnt++)
+ hAFSDWorkerThread[cnt] = CreateThread(NULL, 0, ifs_MainLoop, 0, 0, NULL);
+#endif
+
ShowWindow(hWnd, SW_SHOWMINNOACTIVE);
UpdateWindow(hWnd);
return (TRUE);
break;
case WM_DESTROY:
+#ifndef AFSIFS
RpcMgmtStopServerListening(NULL);
+#else
+ SetEvent(DoTerminate);
+#endif
PostQuitMessage(0);
break;
#define LOG_PACKET 1
#undef NOTSERVICE
+#define WORKER_THREADS 10
+
#define AFSD_HOOK_DLL "afsdhook.dll"
#define AFSD_INIT_HOOK "AfsdInitHook"
typedef BOOL ( APIENTRY * AfsdInitHook )(void);
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
*/
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
#include <afs/param.h>
#include <afs/stds.h>
#ifdef _DEBUG
#include <crtdbg.h>
#endif
+#include "afsdifs.h"
//#define REGISTER_POWER_NOTIFICATIONS 1
#include "afsd_flushvol.h"
static SERVICE_STATUS_HANDLE StatusHandle;
HANDLE hAFSDMainThread = NULL;
+#ifdef AFSIFS
+HANDLE hAFSDWorkerThread[WORKER_THREADS];
+#endif
-HANDLE WaitToTerminate;
+HANDLE WaitToTerminate, DoTerminate;
int GlobalStatus;
char tbuffer[512];
char *ptbuf[1];
HANDLE h;
+ int i;
if (filep)
sprintf(tbuffer, "Error at file %s, line %d: %s",
DebugBreak();
#endif
- SetEvent(WaitToTerminate);
+#ifndef AFSIFS
+ SetEvent(WaitToTerminate);
+#else
+ SetEvent(DoTerminate);
+ WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
+ for (i = 0; i < WORKER_THREADS; i++)
+ CloseHandle(hAFSDWorkerThread[i]);
+#endif
#ifdef JUMP
if (GetCurrentThreadId() == MainThreadId)
}
doneTrace:
+#ifndef AFSIFS
SetEvent(WaitToTerminate);
+#else
+ SetEvent(DoTerminate);
+#endif
break;
case SERVICE_CONTROL_INTERROGATE:
}
doneTrace:
+#ifndef AFSIFS
SetEvent(WaitToTerminate);
+#else
+ SetEvent(DoTerminate);
+#endif
dwRet = NO_ERROR;
break;
}
}
+#ifndef AFSIFS
for ( ; dwRetry < MAX_RETRIES; dwRetry++)
{
NETRESOURCE nr;
/* Disconnect any previous mappings */
dwResult = WNetCancelConnection2(szDriveToMapTo, 0, TRUE);
}
+#else
+ /* FIXFIX */
+#endif
}
RegCloseKey(hKey);
if (dwResult != ERROR_SUCCESS)
return;
- while (1) {
+#ifndef AFSIFS
+ while (1) {
dwDriveSize = sizeof(szDriveToMapTo);
dwSubMountSize = sizeof(szSubMount);
dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
}
+#else
+ /* FIXFIX */
+#endif
RegCloseKey(hKey);
}
#endif /* JUMP */
HMODULE hHookDll;
HMODULE hAdvApi32;
+ int cnt;
#ifdef _DEBUG
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ |
if ( GetLastError() == ERROR_ALREADY_EXISTS )
afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
+#ifdef AFSIFS
+ DoTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_DoTerminate"));
+ if ( GetLastError() == ERROR_ALREADY_EXISTS )
+ afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_DoTerminate"));
+#endif
+
#ifndef NOTSERVICE
hAdvApi32 = LoadLibrary("advapi32.dll");
if (hAdvApi32 == NULL)
ServiceStatus.dwWaitHint -= 5000;
SetServiceStatus(StatusHandle, &ServiceStatus);
#endif
+
+#ifndef AFSIFS
code = afsd_InitSMB(&reason, MessageBox);
if (code != 0) {
afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
osi_panic(reason, __FILE__, __LINE__);
}
+#else
+ code = ifs_Init(&reason);
+ if (code != 0) {
+ afsi_log("ifs_Init failed: %s (code = %d)", reason, code);
+ osi_panic(reason, __FILE__, __LINE__);
+ }
+ for (cnt = 0; cnt < WORKER_THREADS; cnt++)
+ hAFSDWorkerThread[cnt] = CreateThread(NULL, 0, ifs_MainLoop, 0, 0, NULL);
+#endif
/* allow an exit to be called post smb initialization */
hHookDll = LoadLibrary(AFSD_HOOK_DLL);
}
}
- WaitForSingleObject(WaitToTerminate, INFINITE);
+#ifndef AFSIFS
+ WaitForSingleObject(WaitToTerminate, INFINITE);
+#else
+ WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
+ for (cnt = 0; cnt < WORKER_THREADS; cnt++)
+ CloseHandle(hAFSDWorkerThread[cnt]);
+#endif
afsi_log("Received Termination Signal, Stopping Service");
printf("Hit <Enter> to terminate OpenAFS Client Service\n");
getchar();
+#ifndef AFSIFS
SetEvent(WaitToTerminate);
+#else
+ SetEvent(DoTerminate);
+#endif
}
}
--- /dev/null
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+#include <osi.h>
+#include "afsd.h"
+#include <winioctl.h>
+#include "..\afsrdr\kif.h"
+#include "..\afsrdr\ifs_rpc.h"
+
+#include "afsdifs.h"
+
+
+/****************************/
+/* parameters, macros, etc. */
+/****************************/
+#define IFSL_SUCCEEDED(st) (!(st & IFSL_FAIL_BASE))
+#define MAP_RETURN(code) if (code) return ifs_MapCmError(code);
+ /* defined in multiple places (search source) */
+#define BUF_FILEHASH(fidp) ((((fidp)->vnode+((fidp)->unique << 13) + ((fidp)->unique >> (32-13)) \
+ +(fidp)->volume+(fidp)->cell) \
+ /*& 0xffffffff*/))
+#define ROOTPATH "\\"
+//#define ROOTPATH "\\CITI.UMICH.EDU"
+#define TRANSFER_BUF_SIZE (2*1024*1024)
+#define SCPL_LOCK EnterCriticalSection(&scp_list_lock);
+#define SCPL_UNLOCK LeaveCriticalSection(&scp_list_lock);
+#define MAX_USERS 32
+
+/****************************/
+/* structs */
+/****************************/
+struct user_map_entry /* how we keep users straight. total of MAX_USERS of these */
+ {
+ LARGE_INTEGER id; /* internal id created by kernel */
+ cm_user_t *creds; /* global (thread-specific) var userp is set to this */
+ };
+
+struct scp_status /* one for each unique file in afs */
+ {
+ struct scp_status *next; /* stored in a global chain in a chain locked by SCPL_[UN]LOCK */
+ cm_scache_t *scp; /* file handle used with cm_ fns */
+ ULONG fid; /* internal id generated by BUF_FILEHASH from AFS's 128-bit FID */
+ };
+typedef struct scp_status scp_status_t;
+
+struct readdir_context /* temporary struct, allocated as necessary, for cm_Apply callback */
+ {
+ char *matchString; /* for matching against */
+ char *buf, *buf_pos; /* filling buffer to length, currently at buf_pos */
+ ULONG length;
+ ULONG count; /* number of entries packed so far */
+ };
+typedef struct readdir_context readdir_context_t;
+
+
+/****************************/
+/* global vars */
+/****************************/
+__declspec(thread) cm_user_t *userp;
+struct user_map_entry user_map[MAX_USERS];
+
+CRITICAL_SECTION mapLock, scp_list_lock;
+
+extern HANDLE DoTerminate;
+
+scp_status_t *scp_list_head = NULL;
+
+
+/****************************/
+/* error functions */
+/****************************/
+char *IfslErrorToText(unsigned long ifsl)
+{
+switch (ifsl)
+ {
+ case IFSL_SUCCESS:
+ return "success";
+ case IFSL_DOES_NOT_EXIST:
+ return "does not exist";
+ case IFSL_NOT_IMPLEMENTED:
+ return "not implemented";
+ case IFSL_END_OF_ENUM:
+ return "end of enum";
+ case IFSL_CANNOT_MAKE:
+ return "cannot make";
+ case IFSL_END_OF_FILE:
+ return "end of file";
+ case IFSL_NO_ACCESS:
+ return "no access";
+ case IFSL_BUFFER_TOO_SMALL:
+ return "buffer too small";
+ case IFSL_SHARING_VIOLATION:
+ return "sharing violation";
+ case IFSL_BAD_INPUT:
+ return "bad input";
+ case IFSL_GENERIC_FAILURE:
+ return "generic failure";
+ case IFSL_OPEN_CREATED:
+ return "open created";
+ case IFSL_OPEN_EXISTS:
+ return "open exists";
+ case IFSL_OPEN_OPENED:
+ return "opened";
+ case IFSL_OPEN_OVERWRITTEN:
+ return "overwritten";
+ case IFSL_OPEN_SUPERSCEDED:
+ return "supersceded";
+ case IFSL_BADFILENAME:
+ return "bad filename";
+ case IFSL_READONLY:
+ return "read only";
+ case IFSL_IS_A_DIR:
+ return "is a dir";
+ case IFSL_PATH_DOES_NOT_EXIST:
+ return "path does not exist";
+ case IFSL_IS_A_FILE:
+ return "is a file";
+ case IFSL_NOT_EMPTY:
+ return "dir not empty";
+ case IFSL_UNSPEC:
+ return "unspecified error";
+ default:
+ return "NOT FOUND";
+ }
+}
+
+unsigned long ifs_MapCmError(unsigned long code)
+{
+switch (code)
+ {
+ case CM_ERROR_STOPNOW:
+ case 0:
+ return IFSL_SUCCESS;
+ case CM_ERROR_NOSUCHCELL:
+ case CM_ERROR_NOSUCHVOLUME:
+ case CM_ERROR_NOSUCHFILE: // x
+ return IFSL_DOES_NOT_EXIST;
+ case CM_ERROR_NOSUCHPATH: // x
+ return IFSL_PATH_DOES_NOT_EXIST;
+ case CM_ERROR_BADNTFILENAME:
+ return IFSL_BADFILENAME;
+ case CM_ERROR_TIMEDOUT:
+ case CM_ERROR_ALLOFFLINE:
+ case CM_ERROR_CLOCKSKEW:
+ case CM_ERROR_REMOTECONN:
+ case CM_ERROR_ALLBUSY:
+ return IFSL_GENERIC_FAILURE;
+ case CM_ERROR_NOACCESS:
+ return IFSL_NO_ACCESS;
+ case CM_ERROR_RETRY:
+ case CM_ERROR_TOOBIG:
+ case CM_ERROR_BADFD:
+ case CM_ERROR_BADFDOP:
+ case CM_ERROR_CROSSDEVLINK:
+ return IFSL_GENERIC_FAILURE;
+ case CM_ERROR_EXISTS:
+ return IFSL_OPEN_EXISTS;
+ case CM_ERROR_BADOP:
+ case CM_ERROR_INVAL:
+ case CM_ERROR_UNKNOWN:
+ case CM_ERROR_BADSMB:
+ return IFSL_GENERIC_FAILURE;//TODO:? ERR - STATUS_NO_MORE_FILES;
+ case CM_ERROR_NOTDIR:
+ case CM_ERROR_ISDIR:
+ case CM_ERROR_READONLY:
+ return IFSL_BAD_INPUT;
+ case CM_ERROR_BUFFERTOOSMALL:
+ return IFSL_BUFFER_TOO_SMALL;
+ case CM_ERROR_WOULDBLOCK:
+ case CM_ERROR_BADSHARENAME:
+ case CM_ERROR_NOMORETOKENS:
+ case CM_ERROR_NOTEMPTY:
+ case CM_ERROR_USESTD:
+ case CM_ERROR_ATSYS:
+ return IFSL_GENERIC_FAILURE;
+ case CM_ERROR_NOFILES:
+ case CM_ERROR_BADTID:
+ return IFSL_END_OF_ENUM;
+ case CM_ERROR_PARTIALWRITE:
+ case CM_ERROR_NOIPC:
+ case CM_ERROR_RENAME_IDENTICAL:
+ case CM_ERROR_AMBIGUOUS_FILENAME:
+ return IFSL_GENERIC_FAILURE;
+ case IFSL_SHARING_VIOLATION:
+ return IFSL_SHARING_VIOLATION;
+ case IFSL_NOT_EMPTY:
+ return IFSL_NOT_EMPTY;
+ case CM_ERROR_SPACE:
+ case CM_ERROR_QUOTA:
+ return IFSL_OVERQUOTA;
+ }
+return IFSL_GENERIC_FAILURE;
+}
+
+
+/****************************/
+/* support fns */
+/****************************/
+cm_scache_t *ifs_FindScp(ULONG fid) /* walk list to find scp<->fid mapping */
+{
+scp_status_t *curr;
+
+SCPL_LOCK;
+
+curr = scp_list_head;
+while (curr)
+ {
+ if (curr->fid == fid)
+ {
+ SCPL_UNLOCK;
+ return curr->scp;
+ }
+ curr = curr->next;
+ }
+SCPL_UNLOCK;
+return NULL;
+}
+
+/* must call with scp write-locked. will always return correct results
+ unless network fails (it loops properly). */
+ifs_CheckAcl(cm_scache_t *scp, ULONG access, ULONG *granted)
+{
+long outRights, code;
+cm_req_t req;
+
+cm_InitReq(&req);
+
+/* ripped from cm_scache.c */
+while (1)
+ {
+ if (cm_HaveAccessRights(scp, userp, access, granted))
+ {
+ return 0;
+ }
+ else
+ {
+ /* we don't know the required access rights */
+ code = cm_GetAccessRights(scp, userp, &req);
+ MAP_RETURN(code);
+ continue;
+ }
+ }
+
+return 0;
+}
+
+/* extract data from scp. in ifs_ support function to centralize changes. */
+ifs_CopyInfo(cm_scache_t *scp, ULONG *attribs, LARGE_INTEGER *size,
+ LARGE_INTEGER *creation, LARGE_INTEGER *access,
+ LARGE_INTEGER *change, LARGE_INTEGER *written)
+{
+access->QuadPart = 0; /* these mappings are not quite correct. we have the */
+change->QuadPart = scp->clientModTime; /* right to leave them zero, if necessary. */
+written->QuadPart = scp->clientModTime;
+creation->QuadPart = scp->serverModTime;
+
+*attribs = 0;
+if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fileType == CM_SCACHETYPE_SYMLINK ||
+ scp->fileType == CM_SCACHETYPE_MOUNTPOINT/* ||
+ scp->fileType == 0*/)
+ *attribs |= FILE_ATTRIBUTE_DIRECTORY;
+
+/*if (!attribs && scp->fileType == CM_SCACHETYPE_FILE)
+ *attribs |= FILE_ATTRIBUTE_NORMAL;*/
+
+if (*attribs == FILE_ATTRIBUTE_DIRECTORY)
+ size->QuadPart = 0;
+else
+ *size = scp->length;
+
+return 0;
+}
+
+
+/* close and zero scp pointer. zeroing pointer should
+ help eliminate accessing discarded cache entries. */
+void ifs_InternalClose(cm_scache_t **scp)
+{
+osi_assert(scp && *scp);
+lock_ObtainMutex(&((*scp)->mx));
+cm_ReleaseSCache(*scp);
+if ((*scp)->refCount == 0) /* we haven't held scache for external use yet */
+ cm_DiscardSCache(*scp);
+lock_ReleaseMutex(&((*scp)->mx));
+*scp = NULL;
+}
+
+/* normalizes path by removing trailing slashes. separates last
+ path component with a null, so that *dirp points to parent path
+ and *filep points to filename. modifies string path. */
+BOOLEAN ifs_FindComponents(char *path, const char **dirp, const char **filep)
+{
+char *lastSep;
+BOOLEAN removed;
+static char emptyPath[] = "\\"; /* if the path contains only one component, this is the parent. */
+
+osi_assert(path);
+
+if (strlen(path))
+ removed = (path[strlen(path)-1] == '\\');
+else
+ removed = 1;
+
+lastSep = strrchr(path, '\\');
+while (lastSep == path + strlen(path) - 1)
+ {
+ *lastSep = '\0';
+ lastSep = strrchr(path, '\\');
+ }
+
+if (lastSep)
+ {
+ *lastSep = '\0';
+
+ *dirp = path;
+ *filep = lastSep + 1;
+ }
+else
+ {
+ lastSep = path + strlen(path);
+
+ *dirp = emptyPath;
+ *filep = path;
+ }
+
+return removed;
+}
+
+/* here to make maintenance easy */
+unsigned long ifs_ConvertFileName(wchar_t *in, unsigned int inchars, char *out, unsigned int outchars)
+{
+unsigned long code;
+
+code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, in, inchars, out, outchars-1, NULL, NULL);
+if (!code)
+ return IFSL_BADFILENAME;
+
+return 0;
+}
+
+/* called by rpc_ library to let us initialize environment.
+ call with id of zero to clear current thread auth. */
+ifs_ImpersonateClient(LARGE_INTEGER user_id)
+{
+int x, empty;
+
+if (!user_id.QuadPart)
+ {
+ userp = NULL;
+ return 0;
+ }
+
+empty = -1;
+EnterCriticalSection(&mapLock);
+for (x = 0; x < MAX_USERS; x++)
+ {
+ if (user_map[x].id.QuadPart == 0)
+ empty = x;
+ if (user_map[x].id.QuadPart == user_id.QuadPart)
+ goto done;
+ }
+if (empty == -1)
+ {
+ LeaveCriticalSection(&mapLock);
+ return -1;
+ }
+user_map[empty].id = user_id;
+user_map[empty].creds = cm_NewUser();
+x = empty;
+
+done:
+ userp = user_map[x].creds;
+LeaveCriticalSection(&mapLock);
+
+return 0;
+}
+
+
+/****************************/
+/* upcalls */
+/****************************/
+uc_namei(WCHAR *name, ULONG *fid) /* performs name<->fid mapping, and enters it into table */
+{
+char *buffer; /* we support semi-infinite path lengths */
+long code;
+cm_scache_t *scp, *dscp;
+char *dirp, *filep;
+cm_req_t req;
+scp_status_t *st;
+short len;
+
+cm_InitReq(&req);
+
+len = wcslen(name)+20; /* characters *should* map 1<->1, but in case */
+buffer = malloc(len);
+code = ifs_ConvertFileName(name, -1, buffer, len);
+if (code)
+ {
+ free(buffer);
+ MAP_RETURN(code);
+ }
+ifs_FindComponents(buffer, &dirp, &filep);
+
+code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
+if (code)
+ {
+ free(buffer);
+ MAP_RETURN(code);
+ }
+if (*filep)
+ code = cm_Lookup(dscp, filep, 0, userp, &req, &scp);
+else
+ cm_HoldSCache(scp = dscp);
+cm_ReleaseSCache(dscp);
+
+if (code)
+ {
+ free(buffer);
+ MAP_RETURN(code);
+ }
+
+SCPL_LOCK;
+st = malloc(sizeof(scp_status_t));
+st->scp = scp;
+st->fid = BUF_FILEHASH(&scp->fid);
+st->next = scp_list_head;
+scp_list_head = st;
+SCPL_UNLOCK;
+
+*fid = st->fid;
+free(buffer);
+
+return 0;
+}
+
+/* this should only be called right after open, so we do not need to stat file.
+ * we only check the server's restrictions. sharing violations are handled in the
+ * kernel. the access mode we grant sticks with the file_object until its death. */
+uc_check_access(ULONG fid, ULONG access, ULONG *granted)
+{
+ULONG afs_acc, afs_gr;
+cm_scache_t *scp;
+ULONG gr;
+BOOLEAN file, dir;
+
+gr = 0;
+
+scp = ifs_FindScp(fid);
+if (!scp)
+ return IFSL_BAD_INPUT;
+
+file = (scp->fileType == CM_SCACHETYPE_FILE);
+dir = !file;
+
+/* access definitions from prs_fs.h */
+afs_acc = 0;
+if (access & FILE_READ_DATA)
+ afs_acc |= PRSFS_READ;
+if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA)))
+ afs_acc |= PRSFS_WRITE;
+if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES)
+ afs_acc |= PRSFS_WRITE;
+if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY)))
+ afs_acc |= PRSFS_INSERT;
+if (dir && (access & FILE_LIST_DIRECTORY))
+ afs_acc |= PRSFS_LOOKUP;
+if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
+ afs_acc |= PRSFS_LOOKUP;
+if (file && (access & FILE_EXECUTE)) /* look at making this require write access */
+ afs_acc |= PRSFS_WRITE;
+if (dir && (access & FILE_TRAVERSE))
+ afs_acc |= PRSFS_READ;
+if (dir && (access & FILE_DELETE_CHILD))
+ afs_acc |= PRSFS_DELETE;
+if (/*file && */(access & DELETE))
+ afs_acc |= PRSFS_DELETE;
+
+/* check ACL with server */
+lock_ObtainMutex(&(scp->mx));
+ifs_CheckAcl(scp, afs_acc, &afs_gr);
+lock_ReleaseMutex(&(scp->mx));
+
+*granted = 0;
+if (afs_gr & PRSFS_READ)
+ *granted |= FILE_READ_DATA | FILE_EXECUTE;
+if (afs_gr & PRSFS_WRITE)
+ *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE; // last one hack
+if (afs_gr & PRSFS_INSERT)
+ *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0);
+if (afs_gr & PRSFS_LOOKUP)
+ *granted |= (dir ? FILE_LIST_DIRECTORY : 0) | FILE_READ_EA | FILE_READ_ATTRIBUTES;
+if (afs_gr & PRSFS_DELETE)
+ *granted |= FILE_DELETE_CHILD | DELETE;
+if (afs_gr & PRSFS_LOCK)
+ *granted |= 0;
+if (afs_gr & PRSFS_ADMINISTER)
+ *granted |= 0;
+
+* granted |= SYNCHRONIZE | READ_CONTROL;
+
+return 0;
+}
+
+uc_create(WCHAR *name, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid)
+{
+char *buffer; /* we support semi-infinite path lengths */
+long code;
+cm_scache_t *scp, *dscp;
+char *dirp, *filep;
+unsigned char removed;
+cm_req_t req;
+scp_status_t *st;
+cm_attr_t attr;
+short len;
+
+cm_InitReq(&req);
+
+len = wcslen(name)+20; /* characters *should* map 1<->1, but in case */
+buffer = malloc(len);
+code = ifs_ConvertFileName(name, -1, buffer, len);
+if (code)
+ {
+ free(buffer);
+ MAP_RETURN(code);
+ }
+removed = ifs_FindComponents(buffer, &dirp, &filep);
+
+/* lookup the parent directory, which must exist */
+code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
+if (code)
+ {
+ free(buffer);
+ MAP_RETURN(code);
+ }
+
+osi_assert(filep);
+if (*filep)
+ {
+ attr.mask = CM_ATTRMASK_LENGTH;
+ attr.length = alloc;
+
+ if (attribs & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ code = cm_MakeDir(dscp, filep, 0, &attr, userp, &req);
+ if (!code)
+ code = cm_Lookup(dscp, filep, 0, userp, &req, &scp);
+ }
+ else
+ {
+ /* for debugging strange error */
+ /*if (!strcmp(filep+strlen(filep)-3, "478") ||
+ !strcmp(filep+strlen(filep)-3, "503"))
+ _asm int 3;*/
+ code = cm_Create(dscp, filep, 0, &attr, &scp, userp, &req);
+ }
+ }
+cm_ReleaseSCache(dscp);
+
+if (code)
+ {
+ free(buffer);
+ MAP_RETURN(code);
+ }
+
+SCPL_LOCK;
+st = malloc(sizeof(scp_status_t));
+st->scp = scp;
+st->fid = BUF_FILEHASH(&scp->fid);
+st->next = scp_list_head;
+scp_list_head = st;
+SCPL_UNLOCK;
+
+*fid = st->fid;
+*granted = access;
+
+return 0;
+}
+
+/* this does not fill the attribs member completely. additional flags must
+ be added in the kernel, such as read-only. */
+uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation,
+ LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written)
+{
+cm_scache_t *scp;
+cm_req_t req;
+ULONG code;
+
+scp = ifs_FindScp(fid);
+if (!scp)
+ return IFSL_BAD_INPUT;
+
+/* stat file; don't want callback */
+cm_InitReq(&req);
+lock_ObtainMutex(&(scp->mx));
+cm_HoldUser(userp);
+code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
+cm_ReleaseUser(userp);
+
+if (code)
+ lock_ReleaseMutex(&(scp->mx));
+MAP_RETURN(code);
+
+code = ifs_CopyInfo(scp, attribs, size, creation, access, change, written);
+lock_ReleaseMutex(&(scp->mx));
+MAP_RETURN(code);
+
+return 0;
+}
+
+/* set atime, mtime, etc. */
+uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access,
+ LARGE_INTEGER change, LARGE_INTEGER written)
+{
+return IFSL_GENERIC_FAILURE;
+}
+
+//FIX/quota errors
+/* truncate or extend file, in cache and on server */
+uc_trunc(ULONG fid, LARGE_INTEGER size)
+{
+ULONG code, gr;
+cm_scache_t *scp;
+cm_req_t req;
+osi_hyper_t oldLen, writePos;
+long written;
+
+scp = ifs_FindScp(fid);
+if (!scp)
+ return IFSL_BAD_INPUT;
+
+/*code = ifs_CheckAcl(scp, FILE_WRITE_DATA, &gr);
+if (code)
+ return code;
+if (!(gr & FILE_WRITE_DATA))
+ return IFSL_NO_ACCESS;*/
+
+cm_InitReq(&req);
+lock_ObtainMutex(&(scp->mx));
+
+code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
+
+if (code)
+ lock_ReleaseMutex(&(scp->mx));
+MAP_RETURN(code);
+
+oldLen = scp->length;
+lock_ReleaseMutex(&(scp->mx));
+
+code = cm_SetLength(scp, &size, userp, &req);
+MAP_RETURN(code);
+/*code = cm_FSync(scp, userp, &req);
+MAP_RETURN(code);*/
+/*code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
+MAP_RETURN(code);*/
+
+#if 0
+/* attempt to write last byte of file. fails to help because of delayed writing. */
+if (oldLen.QuadPart < size.QuadPart)
+ {
+ writePos.QuadPart = size.QuadPart - 1;
+ WriteData(scp, writePos, 1, &"\0\0\0", userp, &written);
+ MAP_RETURN(code);
+ if (written != 1)
+ return IFSL_UNSPEC;
+ }
+#endif
+/*cm_SyncOp(scp, NULL,
+cm_Flush(*/
+//MAP_RETURN(code);
+
+return 0;
+}
+
+/* read data from a file */
+uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data)
+{
+ULONG code;
+cm_scache_t *scp;
+cm_req_t req;
+
+//_asm int 3;
+
+*read = 0;
+
+scp = ifs_FindScp(fid);
+if (!scp)
+ return IFSL_BAD_INPUT;
+
+if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
+ return IFSL_IS_A_DIR;
+
+code = ReadData(scp, offset, (unsigned long)length, data, userp, read);
+MAP_RETURN(code);
+
+return 0;
+}
+
+//FIX/ handle quota errors properly
+/* write data to a file */
+uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data)
+{
+ULONG code, gr;
+cm_scache_t *scp;
+cm_req_t req;
+
+scp = ifs_FindScp(fid);
+if (!scp)
+ return IFSL_BAD_INPUT;
+
+/*code = ifs_CheckAcl(scp, FILE_WRITE_DATA, &gr);
+if (code)
+ return code;
+if (!(gr & FILE_WRITE_DATA))
+ return IFSL_NO_ACCESS;*/
+
+if (offset.QuadPart == -1) // perhaps re-stat here?
+ offset = scp->length;
+code = WriteData(scp, offset, (unsigned long)length, data, userp, written);
+MAP_RETURN(code);
+
+return 0;
+}
+
+//need downcall for new length
+
+uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid)
+{
+int code;
+cm_req_t req;
+//struct vnode *node;
+cm_attr_t attr;
+wchar_t *buf;
+char *curdir, *curfile, *newdir, *newfile;
+cm_scache_t *dscp1, *dscp2, *scp;
+char b1[MAX_PATH], b2[MAX_PATH], b3[MAX_PATH];
+ULONG fid2;
+
+
+code = !(scp = ifs_FindScp(fid));
+if (!code)
+ code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH);
+if (!code)
+ code = ifs_ConvertFileName(new_name, -1, b2, MAX_PATH);
+if (!code)
+ code = ifs_ConvertFileName(new_dir, -1, b3, MAX_PATH);
+if (!code)
+ {
+ ifs_FindComponents(b1, &curdir, &curfile);
+ ifs_FindComponents(b2, &newdir, &newfile);
+ newdir = b3;
+ /*lock_ReleaseMutex(&scp->mx);
+ cm_FSync(scp, userp, &req);
+ if (scp->refCount != 1)
+ _asm int 3;
+ ifs_InternalClose(&scp);*/
+ uc_close(fid);
+ code = cm_NameI(cm_data.rootSCachep, curdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp1);
+ }
+if (!code)
+ {
+ if (!strcmp(curdir, newdir))
+ {
+ dscp2 = dscp1;
+ dscp1->refCount++;
+ }
+ else
+ code = cm_NameI(cm_data.rootSCachep, newdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp2);
+ if (!code)
+ {
+ code = cm_Rename(dscp1, curfile, dscp2, newfile, userp, &req);
+ //ifs_InternalClose(&dscp2);
+ //cm_InitReq(&req);
+ //code = cm_NameI(cm_rootSCachep, newdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp2);
+ if (!code)
+ {
+ code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH);
+ code = uc_namei(b1, new_fid);
+ //if (fid != fid2)
+ // _asm int 3;
+ //code = cm_Lookup(dscp2, newfile, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &node->scp);
+ }
+ ifs_InternalClose(&dscp2);
+ }
+ else
+ {
+ //code = cm_Lookup(dscp1, curfile, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &node->scp);
+ code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH);
+ code = uc_namei(b1, new_fid);
+ //if (fid != fid2)
+ // _asm int 3;
+ }
+ ifs_InternalClose(&dscp1);
+ }
+
+return 0;
+}
+
+ifs_ReaddirCallback(cm_scache_t *scp, cm_dirEntry_t *entry, void *param, osi_hyper_t *offset)
+{
+readdir_context_t *context;
+ULONG name_len, gr;
+readdir_data_t *info;
+char short_name[14], *endp;
+ULONG code;
+cm_req_t req;
+cm_scache_t *child_scp;
+cm_fid_t child_fid;
+int t;
+
+context = param;
+
+name_len = strlen(entry->name);
+
+info = (readdir_data_t *)context->buf_pos;
+if (context->length - (context->buf_pos - context->buf) < sizeof(readdir_data_t) + name_len * sizeof(WCHAR) + sizeof(LARGE_INTEGER))
+ {
+ if (context->count == 0)
+ return CM_ERROR_BUFFERTOOSMALL;
+ info->cookie = *offset;
+ return CM_ERROR_STOPNOW;
+ }
+
+if ((context->matchString && context->matchString[0] && (!strcmp(context->matchString, entry->name) || context->matchString[0]=='*')) ||
+ !(context->matchString && context->matchString[0]))
+ ;
+else
+ return 0;
+
+cm_InitReq(&req);
+cm_HoldUser(userp);
+child_scp = NULL;
+
+child_fid.cell = scp->fid.cell;
+child_fid.volume = scp->fid.volume;
+child_fid.vnode = ntohl(entry->fid.vnode);
+child_fid.unique = ntohl(entry->fid.unique);
+code = cm_GetSCache(&child_fid, &child_scp, userp, &req);
+//code = cm_Lookup(scp, entry->name, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &child_scp);
+if (code || !child_scp)
+ {
+ cm_ReleaseUser(userp);
+ return 0;
+ }
+
+//if (child_scp->refCount == 1)
+ {
+ lock_ObtainMutex(&child_scp->mx);
+ code = cm_SyncOp(child_scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK); // do not need callback
+ lock_ReleaseMutex(&child_scp->mx);
+ }
+
+if (code) /* perhaps blank fields we do not know, and continue. bad filents should not prevent readdirs. */
+ ;
+
+info->cookie = *offset;
+
+lock_ObtainMutex(&(child_scp->mx));
+code = ifs_CopyInfo(child_scp, &info->attribs, &info->size, &info->creation, &info->access, &info->change, &info->write);
+//ifs_CheckAcl(child_scp, FILE_WRITE_DATA, &gr); /* perhaps add flag to not loop, to avoid network traffic if not found*/
+//if (gr & FILE_READ_DATA && !(gr & FILE_WRITE_DATA))
+// info->attribs |= FILE_ATTRIBUTE_READONLY;
+lock_ReleaseMutex(&(child_scp->mx));
+ifs_InternalClose(&child_scp);
+MAP_RETURN(code);
+
+cm_Gen8Dot3Name(entry, short_name, &endp);
+*endp = '\0';
+info->short_name_length = sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, short_name, -1, info->short_name, 14))?t-1:0);
+info->name_length = sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, entry->name, -1, info->name, 600))?t-1:0);
+
+context->buf_pos = ((char*)info) + sizeof(readdir_data_t) + info->name_length;
+context->count++;
+
+info = (readdir_data_t *)context->buf_pos;
+info->cookie.QuadPart = -1;
+
+return 0;
+}
+
+uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len)
+{
+ULONG code;
+char buffer[2048];
+cm_req_t req;
+cm_scache_t *scp, *child_scp;
+readdir_context_t context;
+LARGE_INTEGER cookie;
+
+if (cookie_in.QuadPart == -1)
+ {
+ *len = 0;
+ *count = 0;
+ return 0;
+ }
+
+scp = ifs_FindScp(fid);
+if (!scp)
+ return IFSL_BAD_INPUT;
+code = ifs_ConvertFileName(filter, -1, buffer, 2048);
+if (code)
+ return code;
+
+cm_InitReq(&req);
+cm_HoldUser(userp);
+
+cookie = cookie_in;
+context.matchString = buffer;
+context.buf_pos = context.buf = data;
+context.length = *len;
+context.count = 0;
+*count = 0;
+
+//restart:
+
+((LARGE_INTEGER *)context.buf)->QuadPart = -1;
+
+code = cm_ApplyDir(scp, ifs_ReaddirCallback, &context, &cookie, userp, &req, NULL);
+
+context.buf_pos += sizeof(LARGE_INTEGER);
+
+if (code != CM_ERROR_STOPNOW)
+ goto done;
+
+//(*count)++;
+
+if (code)
+ goto done;
+
+//goto restart;
+
+code = 0;
+
+done:
+
+*count = context.count;
+
+cm_ReleaseUser(userp);
+*len = context.buf_pos - context.buf;
+
+code = ifs_MapCmError(code);
+return code;
+}
+
+uc_close(ULONG fid)
+{
+ULONG code;
+cm_scache_t *scp;
+cm_req_t req;
+scp_status_t *prev, *curr;
+
+scp = ifs_FindScp(fid);
+if (!scp)
+ return IFSL_BAD_INPUT;
+
+cm_InitReq(&req);
+cm_FSync(scp, userp, &req);
+
+SCPL_LOCK; /* perhaps this should be earlier */
+
+lock_ObtainMutex(&(scp->mx));
+cm_ReleaseSCache(scp);
+if (!scp->refCount)
+ cm_DiscardSCache(scp);
+lock_ReleaseMutex(&(scp->mx));
+
+prev = NULL, curr = scp_list_head;
+
+while (curr)
+ {
+ if (curr->fid == fid)
+ {
+ if (prev)
+ prev->next = curr->next;
+ else
+ scp_list_head = curr->next;
+ free(curr);
+ break;
+ }
+ prev = curr;
+ curr = curr->next;
+ }
+
+SCPL_UNLOCK;
+
+return 0;
+}
+
+uc_unlink(WCHAR *name)
+{
+char buffer[2048];
+long code;
+cm_scache_t *scp, *dscp;
+char *dirp, *filep;
+unsigned char removed;
+cm_req_t req;
+scp_status_t *st;
+
+cm_InitReq(&req);
+
+code = ifs_ConvertFileName(name, -1, buffer, 2048);
+MAP_RETURN(code);
+removed = ifs_FindComponents(buffer, &dirp, &filep);
+
+code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
+MAP_RETURN(code);
+if (*filep)
+ {
+ code = cm_Unlink(dscp, filep, userp, &req);
+ if (code)
+ code = cm_RemoveDir(dscp, filep, userp, &req);
+ }
+else
+ ; /* problem */
+cm_ReleaseSCache(dscp);
+MAP_RETURN(code);
+
+return 0;
+}
+
+
+int uc_ioctl_write(ULONG length, char *data, ULONG *key)
+{
+int code;
+cm_req_t req;
+smb_ioctl_t *iop;
+
+iop = malloc(sizeof(smb_ioctl_t));
+memset(iop, 0, sizeof(smb_ioctl_t));
+smb_IoctlPrepareWrite(NULL, iop);
+
+memcpy(iop->inDatap + iop->inCopied, data, length);
+iop->inCopied += length;
+*key = (ULONG)iop;
+
+return 0;
+}
+
+int uc_ioctl_read(ULONG key, ULONG *length, char *data)
+{
+int code;
+cm_req_t req;
+smb_ioctl_t *iop;
+
+iop = key;
+osi_assert(iop);
+
+cm_HoldUser(userp);
+smb_IoctlPrepareRead(NULL, iop, userp);
+cm_ReleaseUser(userp);
+
+*length = iop->outDatap - iop->outAllocp;
+memcpy(data, iop->outAllocp, *length);
+free(iop);
+
+return 0;
+}
+
+int ifs_Init(char **reason)
+{
+HANDLE kcom;
+
+//_asm int 3;
+kcom = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ /*FILE_FLAG_OVERLAPPED*/0, NULL);
+if (kcom == INVALID_HANDLE_VALUE)
+ {
+ *reason = "error creating communications file";
+ return CM_ERROR_REMOTECONN;
+ }
+CloseHandle(kcom);
+
+memset(user_map, 0, 32*sizeof(struct user_map_entry));
+InitializeCriticalSection(&mapLock);
+InitializeCriticalSection(&scp_list_lock);
+
+return 0;
+}
+
+ifs_TransactRpc(char *outbuf, int outlen, char *inbuf, int *inlen)
+{
+HANDLE hf;
+int ret;
+DWORD err, read = 0;
+DWORD inmax;
+
+if (!outbuf || !inbuf)
+ return IFSL_GENERIC_FAILURE;
+
+hf = CreateFile("\\\\.\\afscom\\downcall", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+if (hf == INVALID_HANDLE_VALUE)
+ return 0;
+
+inmax = *inlen;
+if (!DeviceIoControl(hf, IOCTL_AFSRDR_DOWNCALL, outbuf, outlen, inbuf, inmax, inlen, NULL))
+ {
+ CloseHandle(hf);
+ return IFSL_GENERIC_FAILURE;
+ }
+
+CloseHandle(hf);
+return inlen ? IFSL_SUCCESS : IFSL_GENERIC_FAILURE;
+}
+
+
+DWORD WINAPI ifs_MainLoop(LPVOID param)
+{
+HANDLE pipe;
+DWORD written;
+unsigned char *bufIn, *bufOut;
+DWORD lenIn, lenOut, status;
+DWORD err;
+OVERLAPPED olp;
+rpc_t rpc;
+BOOL st;
+
+bufIn = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE);
+bufOut = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE);
+if (!bufIn || !bufOut)
+ {
+ if (bufIn) VirtualFree(bufIn, 0, MEM_RELEASE);
+ if (bufOut) VirtualFree(bufOut, 0, MEM_RELEASE);
+ printf("could not allocate transfer bufs\n");
+ PostMessage(NULL, WM_CLOSE, 0, 0);
+ return 1;
+ }
+
+//_asm int 3;
+pipe = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ /*FILE_FLAG_OVERLAPPED*/0, NULL);
+if (pipe == INVALID_HANDLE_VALUE)
+ {
+ VirtualFree(bufIn, 0, MEM_RELEASE);
+ VirtualFree(bufOut, 0, MEM_RELEASE);
+ printf("error creating communications file\n");
+ PostMessage(NULL, WM_CLOSE, 0, 0);
+ return 1;
+ }
+
+//_asm int 3;
+while (1)
+ {
+ if (WaitForSingleObject(DoTerminate, 0) == WAIT_OBJECT_0)
+ break;
+ st = ReadFile(pipe, bufIn, TRANSFER_BUF_SIZE, &lenIn, NULL);
+ if (!st)
+ if (GetLastError() == ERROR_INVALID_HANDLE)
+ break;
+ else
+ continue;
+
+ ZeroMemory(&rpc, sizeof(rpc));
+ rpc.in_buf = rpc.in_pos = bufIn;
+ rpc.out_buf = rpc.out_pos = bufOut;
+
+ rpc_parse(&rpc);
+
+ st = WriteFile(pipe, rpc.out_buf, rpc.out_pos - rpc.out_buf, &written, NULL);
+ if (!st)
+ if (GetLastError() == ERROR_INVALID_HANDLE)
+ break;
+ else
+ continue;
+ }
+
+return 1;
+}
--- /dev/null
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+int ifs_Init(char **reason);
+DWORD WINAPI ifs_MainLoop(LPVOID);
+
+
+long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
+ cm_user_t *userp, long *readp);
+long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
+ cm_user_t *userp, long *readp);
lock_ReleaseWrite(&cm_callbackLock);
}
+#ifdef AFSIFS
+#define BUF_FILEHASH(fidp) ((((fidp)->vnode+((fidp)->unique << 13) + ((fidp)->unique >> (32-13)) \
+ +(fidp)->volume+(fidp)->cell) \
+ /*& 0xffffffff*/))
+#endif
+
/*
* When we lose a callback, may have to send change notification replies.
* Do not call with a lock on the scp.
Sleep(dwDelay);
if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+#ifndef AFSIFS
if (scp->flags & CM_SCACHEFLAG_ANYWATCH)
smb_NotifyChange(0,
FILE_NOTIFY_GENERIC_DIRECTORY_FILTER,
scp, NULL, NULL, TRUE);
+#else
+ dc_break_callback(BUF_FILEHASH(&scp->fid));
+#endif
} else {
cm_fid_t tfid;
cm_scache_t *dscp;
tfid.vnode = scp->parentVnode;
tfid.unique = scp->parentUnique;
dscp = cm_FindSCache(&tfid);
+#ifndef AFSIFS
if ( dscp &&
dscp->flags & CM_SCACHEFLAG_ANYWATCH )
smb_NotifyChange( 0,
FILE_NOTIFY_GENERIC_FILE_FILTER,
dscp, NULL, NULL, TRUE);
+#else
+ if (dscp)
+ dc_break_callback(BUF_FILEHASH(&dscp->fid));
+#endif
if (dscp)
cm_ReleaseSCache(dscp);
}
#include "cm_rpc.h"
#include <strsafe.h>
+#include <winioctl.h>
+#include <WINNT\afsrdr\kif.h>
#ifdef _DEBUG
#include <crtdbg.h>
long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
cm_scache_t **scpp)
{
- long code;
+ long code, length;
cm_scache_t *substRootp;
- char * relativePath = ioctlp->inDatap;
+ char * relativePath = ioctlp->inDatap, absRoot[100];
+ wchar_t absRoot_w[100];
+ HANDLE rootDir;
/* This is usually the file name, but for StatMountPoint it is the path. */
/* ioctlp->inDatap can be either of the form:
*/
TranslateExtendedChars(relativePath);
- if (relativePath[0] == relativePath[1] &&
+#ifdef AFSIFS
+ /* we have passed the whole path, including the afs prefix (pioctl_nt.c modified) */
+ /*_asm int 3;
+ sprintf(absRoot, "%c:", relativePath[0]);
+ rootDir = CreateFile(absRoot, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, absRoot_w, 100*sizeof(wchar_t), &length, NULL))
+ {
+ CloseHandle(rootDir);
+ return CM_ERROR_NOSUCHPATH;
+ }
+ CloseHandle(rootDir);
+
+ ifs_ConvertFileName(absRoot_w, length/sizeof(wchar_t), absRoot, 100);*/
+
+#if 0
+ switch (relativePath[0]) /* FIXFIX */
+ {
+ case 'y':
+ case 'Y':
+ absRoot = "\\ericjw\\test"; /* should use drivemap */
+ }
+#endif
+ code = cm_NameI(cm_data.rootSCachep, relativePath,
+ CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+ userp, ""/*absRoot*//*ioctlp->tidPathp*/, reqp, scpp);
+
+ if (code)
+ return code;
+
+ /* # of bytes of path */
+ code = strlen(ioctlp->inDatap) + 1;
+ ioctlp->inDatap += code;
+
+ /* This is usually nothing, but for StatMountPoint it is the file name. */
+ TranslateExtendedChars(ioctlp->inDatap);
+
+ return 0;
+#endif
+
+ if (relativePath[0] == relativePath[1] &&
relativePath[1] == '\\' &&
!_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName)))
{
uname = tp;
tp += strlen(tp) + 1;
- if (flags & PIOCTL_LOGON) {
+#ifndef AFSIFS /* no SMB username */
+ if (flags & PIOCTL_LOGON) {
/* SMB user name with which to associate tokens */
smbname = tp;
osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
osi_LogSaveString(smb_logp,uname));
}
+#endif
#ifndef DJGPP /* for win95, session key is back in pioctl */
/* uuid */
break;
}
- lock_ObtainMutex(&bufferp->mx);
+#ifdef AFSIFS
+ lock_ObtainMutex(&scp->mx);
+ if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
+ && (scp->bulkStatProgress.QuadPart <= thyper.QuadPart))
+ {
+ scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
+ cm_TryBulkStat(scp, &thyper, userp, reqp);
+ scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
+ scp->bulkStatProgress = thyper;
+ }
+ lock_ReleaseMutex(&scp->mx);
+#endif
+
+ lock_ObtainMutex(&bufferp->mx);
bufferOffset = thyper;
/* now get the data in the cache */
--- /dev/null
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+#include <osi.h>
+#include "afsd.h"
+
+#include "afsdifs.h"
+
+#define CM_BUF_SIZE 4096
+long buf_bufferSize = CM_BUF_SIZE;
+
+long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
+ cm_user_t *userp, long *readp)
+{
+ //osi_hyper_t offset;
+ long code;
+ cm_buf_t *bufferp;
+ osi_hyper_t fileLength;
+ osi_hyper_t thyper;
+ osi_hyper_t lastByte;
+ osi_hyper_t bufferOffset;
+ long bufIndex, nbytes;
+ int sequential = 0;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ bufferp = NULL;
+
+ lock_ObtainMutex(&scp->mx);
+
+ /* start by looking up the file's end */
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) goto done;
+
+ /* now we have the entry locked, look up the length */
+ fileLength = scp->length;
+
+ /* adjust count down so that it won't go past EOF */
+ thyper.LowPart = count;
+ thyper.HighPart = 0;
+ thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
+ lastByte = thyper;
+ if (LargeIntegerGreaterThan(thyper, fileLength)) {
+ /* we'd read past EOF, so just stop at fileLength bytes.
+ * Start by computing how many bytes remain in the file.
+ */
+ thyper = LargeIntegerSubtract(fileLength, offset);
+
+ /* if we are past EOF, read 0 bytes */
+ if (LargeIntegerLessThanZero(thyper))
+ count = 0;
+ else
+ count = thyper.LowPart;
+ }
+
+ *readp = count;
+
+ /* now, copy the data one buffer at a time,
+ * until we've filled the request packet
+ */
+ while (1) {
+ /* if we've copied all the data requested, we're done */
+ if (count <= 0) break;
+
+ /* otherwise, load up a buffer of data */
+ thyper.HighPart = offset.HighPart;
+ thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
+ if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
+ /* wrong buffer */
+ if (bufferp) {
+ buf_Release(bufferp);
+ bufferp = NULL;
+ }
+ lock_ReleaseMutex(&scp->mx);
+
+ lock_ObtainRead(&scp->bufCreateLock);
+ code = buf_Get(scp, &thyper, &bufferp);
+ lock_ReleaseRead(&scp->bufCreateLock);
+
+ lock_ObtainMutex(&scp->mx);
+ if (code) goto done;
+ bufferOffset = thyper;
+
+ /* now get the data in the cache */
+ while (1) {
+ code = cm_SyncOp(scp, bufferp, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK
+ | CM_SCACHESYNC_READ);
+ if (code) goto done;
+
+ if (cm_HaveBuffer(scp, bufferp, 0)) break;
+
+ /* otherwise, load the buffer and try again */
+ code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
+ if (code) break;
+ }
+ if (code) {
+ buf_Release(bufferp);
+ bufferp = NULL;
+ goto done;
+ }
+ } /* if (wrong buffer) ... */
+
+ /* now we have the right buffer loaded. Copy out the
+ * data from here to the user's buffer.
+ */
+ bufIndex = offset.LowPart & (buf_bufferSize - 1);
+
+ /* and figure out how many bytes we want from this buffer */
+ nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
+ if (nbytes > count) nbytes = count; /* don't go past EOF */
+
+ /* now copy the data */
+ memcpy(op, bufferp->datap + bufIndex, nbytes);
+
+ /* adjust counters, pointers, etc. */
+ op += nbytes;
+ count -= nbytes;
+ thyper.LowPart = nbytes;
+ thyper.HighPart = 0;
+ offset = LargeIntegerAdd(thyper, offset);
+ } /* while 1 */
+
+done:
+ lock_ReleaseMutex(&scp->mx);
+ //lock_ReleaseMutex(&fidp->mx);
+ if (bufferp) buf_Release(bufferp);
+
+ if (code == 0 && sequential)
+ cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
+
+ return code;
+}
+
+
+long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
+ cm_user_t *userp, long *writtenp)
+{
+ long code = 0;
+ long written = 0;
+ //cm_scache_t *scp;
+ osi_hyper_t fileLength; /* file's length at start of write */
+ osi_hyper_t minLength; /* don't read past this */
+ long nbytes; /* # of bytes to transfer this iteration */
+ cm_buf_t *bufferp;
+ osi_hyper_t thyper; /* hyper tmp variable */
+ osi_hyper_t bufferOffset;
+ long bufIndex; /* index in buffer where our data is */
+ int doWriteBack;
+ osi_hyper_t writeBackOffset; /* offset of region to write back when
+ * I/O is done */
+ DWORD filter = 0;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+
+ bufferp = NULL;
+ doWriteBack = 0;
+
+ //scp = fidp->scp;
+ lock_ObtainMutex(&scp->mx);
+
+ /* start by looking up the file's end */
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK
+ | CM_SCACHESYNC_SETSTATUS
+ | CM_SCACHESYNC_GETSTATUS);
+ if (code)
+ goto done;
+
+ /* make sure we have a writable FD */
+ /*if (!(fidp->flags & SMB_FID_OPENWRITE)) {
+ code = CM_ERROR_BADFDOP;
+ goto done;
+ } */
+
+ /* now we have the entry locked, look up the length */
+ fileLength = scp->length;
+ minLength = fileLength;
+ if (LargeIntegerGreaterThan(minLength, scp->serverLength))
+ minLength = scp->serverLength;
+
+ /* adjust file length if we extend past EOF */
+ thyper.LowPart = count;
+ thyper.HighPart = 0;
+ thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
+ if (LargeIntegerGreaterThan(thyper, fileLength)) {
+ /* we'd write past EOF, so extend the file */
+ scp->mask |= CM_SCACHEMASK_LENGTH;
+ scp->length = thyper;
+ filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
+ } else
+ filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
+
+ /* now, if the new position (thyper) and the old (offset) are in
+ * different storeback windows, remember to store back the previous
+ * storeback window when we're done with the write.
+ */
+ if ((thyper.LowPart & (-cm_chunkSize)) !=
+ (offset.LowPart & (-cm_chunkSize))) {
+ /* they're different */
+ doWriteBack = 1;
+ writeBackOffset.HighPart = offset.HighPart;
+ writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
+ }
+
+ *writtenp = count;
+
+ /* now, copy the data one buffer at a time, until we've filled the
+ * request packet */
+ while (1) {
+ /* if we've copied all the data requested, we're done */
+ if (count <= 0) break;
+
+ /* handle over quota or out of space */
+ if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
+ *writtenp = written;
+ break;
+ }
+
+ /* otherwise, load up a buffer of data */
+ thyper.HighPart = offset.HighPart;
+ thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
+ if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
+ /* wrong buffer */
+ if (bufferp) {
+ lock_ReleaseMutex(&bufferp->mx);
+ buf_Release(bufferp);
+ bufferp = NULL;
+ }
+ lock_ReleaseMutex(&scp->mx);
+
+ lock_ObtainRead(&scp->bufCreateLock);
+ code = buf_Get(scp, &thyper, &bufferp);
+ lock_ReleaseRead(&scp->bufCreateLock);
+
+ lock_ObtainMutex(&bufferp->mx);
+ lock_ObtainMutex(&scp->mx);
+ if (code) goto done;
+
+ bufferOffset = thyper;
+
+ /* now get the data in the cache */
+ while (1) {
+ code = cm_SyncOp(scp, bufferp, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK
+ | CM_SCACHESYNC_WRITE
+ | CM_SCACHESYNC_BUFLOCKED);
+ if (code)
+ goto done;
+
+ /* If we're overwriting the entire buffer, or
+ * if we're writing at or past EOF, mark the
+ * buffer as current so we don't call
+ * cm_GetBuffer. This skips the fetch from the
+ * server in those cases where we're going to
+ * obliterate all the data in the buffer anyway,
+ * or in those cases where there is no useful
+ * data at the server to start with.
+ *
+ * Use minLength instead of scp->length, since
+ * the latter has already been updated by this
+ * call.
+ */
+ if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength) ||
+ LargeIntegerEqualTo(offset, bufferp->offset) &&
+ (count >= buf_bufferSize ||
+ LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset, ConvertLongToLargeInteger(count)), minLength))) {
+ if (count < buf_bufferSize
+ && bufferp->dataVersion == -1)
+ memset(bufferp->datap, 0,
+ buf_bufferSize);
+ bufferp->dataVersion = scp->dataVersion;
+ }
+
+ if (cm_HaveBuffer(scp, bufferp, 1)) break;
+
+ /* otherwise, load the buffer and try again */
+ lock_ReleaseMutex(&bufferp->mx);
+ code = cm_GetBuffer(scp, bufferp, NULL, userp,
+ &req);
+ lock_ReleaseMutex(&scp->mx);
+ lock_ObtainMutex(&bufferp->mx);
+ lock_ObtainMutex(&scp->mx);
+ if (code) break;
+ }
+ if (code) {
+ lock_ReleaseMutex(&bufferp->mx);
+ buf_Release(bufferp);
+ bufferp = NULL;
+ goto done;
+ }
+ } /* if (wrong buffer) ... */
+
+ /* now we have the right buffer loaded. Copy out the
+ * data from here to the user's buffer.
+ */
+ bufIndex = offset.LowPart & (buf_bufferSize - 1);
+
+ /* and figure out how many bytes we want from this buffer */
+ nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
+ if (nbytes > count)
+ nbytes = count; /* don't go past end of request */
+
+ /* now copy the data */
+#ifdef DJGPP
+ if (dosflag)
+ dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
+ else
+#endif /* DJGPP */
+ memcpy(bufferp->datap + bufIndex, op, nbytes);
+ buf_SetDirty(bufferp);
+
+ /* and record the last writer */
+ if (bufferp->userp != userp) {
+ cm_HoldUser(userp);
+ if (bufferp->userp)
+ cm_ReleaseUser(bufferp->userp);
+ bufferp->userp = userp;
+ }
+
+ /* adjust counters, pointers, etc. */
+ op += nbytes;
+ count -= nbytes;
+ written += nbytes;
+ thyper.LowPart = nbytes;
+ thyper.HighPart = 0;
+ offset = LargeIntegerAdd(thyper, offset);
+ } /* while 1 */
+
+ done:
+ lock_ReleaseMutex(&scp->mx);
+ if (bufferp) {
+ lock_ReleaseMutex(&bufferp->mx);
+ buf_Release(bufferp);
+ }
+
+ if (code == 0 /* && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
+ && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)*/) {
+ /*smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
+ fidp->NTopen_dscp, fidp->NTopen_pathp,
+ NULL, TRUE);*/
+ }
+
+ if (code == 0 && doWriteBack) {
+ lock_ObtainMutex(&scp->mx);
+ cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
+ lock_ReleaseMutex(&scp->mx);
+ cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
+ writeBackOffset.HighPart, cm_chunkSize, 0, userp);
+ }
+
+ return code;
+}
+
+
--- /dev/null
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+/* versioning history
+ *
+ * 03-jun 2005 (eric williams) entered into versioning
+ */
+
+/* developer: eric williams,
+ * center for information technology integration,
+ * university of michigan, ann arbor
+ *
+ * comments: nativeafs@citi.umich.edu
+ */
+
+#define IRPMJFUNCDESC /* pull in text strings of the names of irp codes */
+#define RPC_SRV /* which half of the rpc library to use */
+
+#include <ntifs.h>
+#include <ntdddisk.h>
+#include <strsafe.h>
+#include <ksdebug.h>
+#include "ifs_rpc.h"
+#include "afsrdr.h"
+#include "kif.h"
+
+
+/*** notes ***/
+/* flag pooltag Io(sp)(sp) to check queryinfo requests for buffer overrun */
+
+NTKERNELAPI
+NTSTATUS
+IoAllocateDriverObjectExtension(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PVOID ClientIdentificationAddress,
+ IN ULONG DriverObjectExtensionSize,
+ OUT PVOID *DriverObjectExtension
+ );
+
+/*** local structs ***/
+/* represents a specific file */
+struct afs_fcb
+ {
+ FSRTL_COMMON_FCB_HEADER; /* needed to interface with cache manager, etc. */
+ SECTION_OBJECT_POINTERS sectionPtrs;
+ ERESOURCE _resource; /* pointed to by fcb_header->Resource */
+ ERESOURCE _pagingIoResource;
+ unsigned long fid; /* a courtesy from the userland daemon (a good hash function) */
+ UCHAR delPending; /* 3 types: FIX */
+ struct afs_ccb *ccb_list; /* list of open instances */
+ SHARE_ACCESS share_access; /* common access control */
+ };
+typedef struct afs_fcb afs_fcb_t;
+
+/* represents an open instance of a file */
+struct afs_ccb
+ {
+ struct afs_ccb *next; /* these are chained as siblings, non-circularly */
+ ULONG access; /* how this instance is opened */
+ wchar_t *name; /* ptr to name buffer */
+ UNICODE_STRING str; /* full name struct, for notification fns */
+ FILE_OBJECT *fo; /* can get parent fcb from this */
+ LARGE_INTEGER cookie; /* on enum ops, where we are */
+ wchar_t *filter; /* on enum ops, what we are filtering on */
+ PACCESS_TOKEN token; /* security data of opening app */
+ ULONG attribs; /* is dir, etc. */
+ };
+typedef struct afs_ccb afs_ccb_t;
+
+
+/*** globals ***/
+/* use wisely -- should be set by each thread in an arbitrary context */
+/* here mostly as a development convenience */
+DEVICE_OBJECT *RdrDevice, *ComDevice;
+struct AfsRdrExtension *rdrExt;
+struct ComExtension *comExt;
+
+
+/*** error and return handling ***/
+/* current code is stable without, but these should wrap all operations */
+/*#define TRY try{
+#define EXCEPT(x, y) } except(EXCEPTION_EXECUTE_HANDLER) \
+ { \
+ KdBreakPoint(); \
+ rpt4(("exception", "occurred")); \
+ Irp->IoStatus.Status = x; \
+ Irp->IoStatus.Information = y; \
+ }*/
+#define TRY
+#define EXCEPT(x, y)
+
+#define STATUS(st, in) Irp->IoStatus.Information = (in), Irp->IoStatus.Status = (st)
+#define SYNC_FAIL(st) \
+ { \
+ STATUS(st, 0); \
+ COMPLETE_NO_BOOST; \
+ return st; \
+ }
+#define SYNC_FAIL2(st, in) \
+ { \
+ STATUS(st, in); \
+ COMPLETE_NO_BOOST; \
+ return st; \
+ }
+#define SYNC_RET(st) \
+ { \
+ STATUS(st, 0); \
+ COMPLETE; \
+ return st; \
+ }
+#define SYNC_RET2(st, in) \
+ { \
+ STATUS(st, in); \
+ COMPLETE; \
+ return st; \
+ }
+#define SYNC_FAIL_RPC_TIMEOUT SYNC_FAIL(STATUS_NETWORK_BUSY)
+
+#define LOCK_FCB_LIST FsRtlEnterFileSystem(); ExAcquireFastMutex(&rdrExt->fcbLock);
+#define UNLOCK_FCB_LIST ExReleaseFastMutex(&rdrExt->fcbLock); FsRtlExitFileSystem();
+
+#define LOCK_FCB ExAcquireResourceExclusiveLite(fcb->Resource, TRUE)
+#define SLOCK_FCB ExAcquireResourceSharedLite(fcb->Resource, TRUE)
+#define UNLOCK_FCB if (fcb) ExReleaseResourceLite(fcb->Resource)
+
+#define LOCK_PAGING_FCB ExAcquireResourceExclusiveLite(fcb->PagingIoResource, TRUE)
+#define SLOCK_PAGING_FCB ExAcquireResourceSharedLite(fcb->PagingIoResource, TRUE)
+#define UNLOCK_PAGING_FCB if (fcb) ExReleaseResourceLite(fcb->PagingIoResource)
+
+/*** constants ***/
+#define AFS_RDR_TAG (0x73666440)//@dfs//0x482ac230//0x3029a4f2
+#define MAX_PATH 700
+#define AFS_FS_NAME L"Andrew File System"
+
+#define COMM_IOCTL (void*)0x01
+#define COMM_DOWNCALL (void*)0x02
+#define COMM_UPCALLHOOK (void*)0x03
+
+/*#define ACC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_LIST_DIRECTORY
+#define ACC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA)*
+
+
+/* dates from afs are time_t style -- seconds since 1970 */ /* 11644505691.6384 */
+#define AfsTimeToWindowsTime(x) (((x)+11644505692L)*10000000L) /*(1970L-1601L)*365.242199*24L*3600L)*/
+#define WindowsTimeToAfsTime(x) ((x)/10000000L-11644505692L) /*(1970L-1601L)*365.242199*24L*3600L)*/
+#define IsDeviceFile(fo) (!fo->FsContext)
+
+
+/*** auxiliary functions ***/
+#define COMPLETE_NO_BOOST IoCompleteRequest(Irp, IO_NO_INCREMENT)
+#define COMPLETE IoCompleteRequest(Irp, IO_NETWORK_INCREMENT)
+
+afs_fcb_t *FindFcb(FILE_OBJECT *fo)
+ {
+ if (fo)
+ return fo->FsContext;
+ return NULL;
+ }
+
+void *AfsFindBuffer(IRP *Irp)
+ {
+ void *outPtr;
+ if (Irp->MdlAddress)
+ {
+ outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ if (outPtr)
+ return outPtr;
+ }
+ outPtr = Irp->AssociatedIrp.SystemBuffer;
+ return outPtr;
+ }
+
+/* we do Resource locking because we don't want to figure out when to pull MainResource */
+BOOLEAN lazyWriteLock(PVOID context, BOOLEAN wait)
+{
+afs_fcb_t *fcb = context;
+ASSERT(fcb);
+return ExAcquireResourceExclusiveLite(fcb->Resource, wait);
+}
+
+void lazyWriteUnlock(PVOID context)
+{
+afs_fcb_t *fcb = context;
+ASSERT(fcb);
+ExReleaseResourceLite(fcb->Resource);
+}
+
+BOOLEAN readAheadLock(PVOID context, BOOLEAN wait)
+{
+afs_fcb_t *fcb = context;
+ASSERT(fcb);
+return ExAcquireResourceSharedLite(fcb->Resource, wait);
+}
+
+void readAheadUnlock(PVOID context)
+{
+afs_fcb_t *fcb = context;
+ASSERT(fcb);
+ExReleaseResourceLite(fcb->Resource);
+}
+
+afs_fcb_t *find_fcb(ULONG fid)
+{
+afs_fcb_t compare, *compare_ptr, **fcbp;
+
+compare.fid = fid;
+compare_ptr = &compare;
+fcbp = RtlLookupElementGenericTable(&rdrExt->fcbTable, (void*)&compare_ptr);
+
+if (fcbp)
+ return (*fcbp);
+return NULL;
+}
+
+
+/**********************************************************
+ * AfsRdrCreate
+ * - handle open and create requests
+ * - on success
+ * - FsContext of file object points to FCB
+ * - FsContext2 of file object is usermode handle of file instance
+ * - beginning failure codes and conditions came from ifstest
+ **********************************************************/
+NTSTATUS AfsRdrCreate(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *_fcb)
+{
+afs_fcb_t *pfcb, *fcb, **fcbp;
+afs_ccb_t *ccb, *pccb;
+ULONG len, x, y;
+wchar_t *str, *ptr;
+ULONG fid, access, granted, disp;
+LARGE_INTEGER size, creation, accesst, change, written, zero;
+ULONG attribs;
+ULONG share;
+CC_FILE_SIZES sizes;
+NTSTATUS status;
+char created;
+PACCESS_TOKEN acc_token;
+
+/* set rpc security context for current thread */
+acc_token = SeQuerySubjectContextToken(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+ASSERT(acc_token);
+rpc_set_context(acc_token);
+
+/* attempt to open afs volume directly */
+if (IrpSp->FileObject->FileName.Length == 0)
+ SYNC_FAIL(STATUS_SHARING_VIOLATION);
+
+if (IrpSp->FileObject->FileName.Length > MAX_PATH*sizeof(wchar_t))
+ SYNC_FAIL(STATUS_OBJECT_NAME_INVALID);
+
+if (IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY &&
+ IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE)
+ SYNC_FAIL(STATUS_INVALID_PARAMETER);
+
+/* relative opens cannot start with \ */
+if (IrpSp->FileObject->RelatedFileObject &&
+ IrpSp->FileObject->FileName.Length &&
+ IrpSp->FileObject->FileName.Buffer[0] == L'\\')
+ SYNC_FAIL(STATUS_INVALID_PARAMETER);/*STATUS_OBJECT_PATH_SYNTAX_BAD);*/
+
+/* a create request can be relative to a prior file. build filename here */
+pccb = NULL;
+if (IrpSp->FileObject->RelatedFileObject)
+ pccb = IrpSp->FileObject->RelatedFileObject->FsContext2;
+len = IrpSp->FileObject->FileName.Length + (pccb?wcslen(pccb->name):0)*sizeof(wchar_t) + 6;
+str = ExAllocatePoolWithTag(NonPagedPool, len, AFS_RDR_TAG);
+RtlZeroMemory(str, len);
+if (pccb)
+ {
+ StringCbCatN(str, len, IrpSp->FileObject->RelatedFileObject->FileName.Buffer, IrpSp->FileObject->RelatedFileObject->FileName.Length);
+ StringCbCat(str, len, L"\\");
+ }
+StringCbCatN(str, len, IrpSp->FileObject->FileName.Buffer, IrpSp->FileObject->FileName.Length);
+
+/* request to open heirarchical parent of specified path */
+/* remove last path component */
+if (IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY)
+ {
+ y = x = wcslen(str);
+ if (x)
+ x--, y--;
+ for (x; x >= 0; x--)
+ {
+ if (str[x] == L'\\')
+ {
+ if (y == x && x != 0)
+ str[x] = L'\0';
+ else if (x != 0)
+ {
+ str[x] = L'\0';
+ break;
+ }
+ else
+ {
+ str[x+1] = L'\0';
+ break;
+ }
+ }
+ }
+ }
+
+/* first two characters are \%01d . %d is number of path components immediately
+ following that should not be returned in file name queries.
+ EX: \3\mount\path\start\fname.ext is mapped to <driveletter>:\fname.ext */
+if (wcslen(str) <= 2)
+ {
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_OBJECT_NAME_INVALID);
+ }
+
+fid = 0;
+disp = (unsigned char)((IrpSp->Parameters.Create.Options >> 24) & 0xff);
+access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
+share = IrpSp->Parameters.Create.ShareAccess;
+size.QuadPart = 0;
+created = 0;
+
+/* check for file existance. we jump to creating it if needed */
+if (disp == FILE_OPEN || disp == FILE_OPEN_IF || disp == FILE_OVERWRITE ||
+ disp == FILE_OVERWRITE_IF || disp == FILE_SUPERSEDE)
+ {
+ /* chop our internal mount flagging from the beginning */
+ status = uc_namei(str+2, &fid);
+ if (status == IFSL_DOES_NOT_EXIST &&
+ (disp == FILE_OPEN_IF ||
+ disp == FILE_OVERWRITE_IF ||
+ disp == FILE_SUPERSEDE))
+ goto create;
+
+ if (status != IFSL_SUCCESS)
+ {
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ switch (status)
+ {
+ case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
+ case IFSL_NO_ACCESS: SYNC_FAIL(STATUS_ACCESS_DENIED);
+ case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
+ case IFSL_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_NAME_NOT_FOUND, FILE_DOES_NOT_EXIST);
+ case IFSL_PATH_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_PATH_NOT_FOUND, FILE_DOES_NOT_EXIST);
+ default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+ }
+
+ /* make upcall to get ACL in afs. we specify our requested level to
+ keep it from hitting the network on a public volume. */
+ status = uc_check_access(fid, access, &granted);
+ if (status != IFSL_SUCCESS)
+ {
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ switch (status)
+ {
+ case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
+ case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
+ default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+ }
+
+ /* make sure daemon approved access */
+ if ((access & granted) != access)
+ {
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_ACCESS_DENIED);
+ }
+
+ /* we depend on this information for caching, etc. */
+ status = uc_stat(fid, &attribs, &size, &creation, &accesst, &change, &written);
+ if (status != IFSL_SUCCESS)
+ {
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ switch (status)
+ {
+ case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
+ case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
+ default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+ }
+
+ /* afsd does not maintain instance-specific data, so we adjust here */
+ if (granted & FILE_READ_DATA && !(granted & FILE_WRITE_DATA))
+ attribs |= FILE_ATTRIBUTE_READONLY;
+
+ if (IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE &&
+ !(attribs & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_NOT_A_DIRECTORY);
+ }
+ if (IrpSp->Parameters.Create.Options & FILE_NON_DIRECTORY_FILE &&
+ attribs & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_FILE_IS_A_DIRECTORY);
+ }
+
+ /* check for previous open instance(s) of file. it will be in the fcb chain.
+ when we have this locked, we cannot make upcalls -- running at APC_LEVEL.
+ lock here (not later) to prevent possible truncation races. */
+ LOCK_FCB_LIST;
+ fcb = find_fcb(fid);
+ if (fcb)
+ {
+ LOCK_PAGING_FCB;
+ LOCK_FCB;
+ }
+
+ /* if we found it, check to make sure open disposition and sharing
+ are not in conflict with previous opens. then, make new file
+ instance entry and, if necessary, file entry. */
+ if (fcb)
+ {
+ /* file contents cannot be cached for a successful delete */
+ if (access & FILE_WRITE_DATA)
+ if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForWrite))
+ {
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_SHARING_VIOLATION);
+ }
+ if (access & DELETE)
+ if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForWrite))//Delete))
+ {
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_SHARING_VIOLATION);
+ }
+
+ /* check common sharing flags, but do not change */
+ if (IoCheckShareAccess(access, share, IrpSp->FileObject, &fcb->share_access, FALSE) != STATUS_SUCCESS)
+ {
+ rpt0(("create", "sharing violation for %ws", str));
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_SHARING_VIOLATION);
+ }
+
+ zero.QuadPart = 0;
+ if (access & DELETE)
+ if (!MmCanFileBeTruncated(&(fcb->sectionPtrs), &zero))
+ {
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_SHARING_VIOLATION);
+ }
+ }
+
+ /* do overwrite/supersede tasks */
+ if (disp == FILE_OVERWRITE ||
+ disp == FILE_OVERWRITE_IF ||
+ disp == FILE_SUPERSEDE)
+ {
+ zero.QuadPart = 0;
+ if (fcb && !MmCanFileBeTruncated(&(fcb->sectionPtrs), &zero))
+ {
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_SHARING_VIOLATION);
+ }
+ if (size.QuadPart != 0)
+ {
+ size.QuadPart = 0;
+ status = uc_trunc(fid, size);
+ if (status != IFSL_SUCCESS)
+ {
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_ACCESS_DENIED);
+ }
+ if (fcb)
+ {
+ fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size;
+ CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
+ }
+ }
+ if (Irp->Overlay.AllocationSize.QuadPart)
+ {
+ status = uc_trunc(fid, Irp->Overlay.AllocationSize);
+ size = Irp->Overlay.AllocationSize;
+ if (status != IFSL_SUCCESS)
+ {
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_DISK_FULL);
+ }
+ if (fcb)
+ {
+ fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size;
+ CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
+ }
+ }
+ }
+
+ if (fcb)
+ {
+ /* make actual change in common sharing flags */
+ IoUpdateShareAccess(IrpSp->FileObject, &fcb->share_access);
+ goto makeccb;
+ }
+
+ goto makefcb;
+ }
+
+
+/* if disposition was to create the file, or its non-existance necessitates this */
+create:
+if (disp == FILE_CREATE ||
+ status == IFSL_DOES_NOT_EXIST && (disp == FILE_OPEN_IF || disp == FILE_OVERWRITE_IF || disp == FILE_SUPERSEDE))
+ {
+ attribs = IrpSp->Parameters.Create.FileAttributes;
+ if (IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE)
+ attribs |= FILE_ATTRIBUTE_DIRECTORY;
+ if (IrpSp->Parameters.Create.Options & FILE_NON_DIRECTORY_FILE)
+ attribs &= ~FILE_ATTRIBUTE_DIRECTORY;
+ status = uc_create(str+2, attribs, Irp->Overlay.AllocationSize, access, &granted, &fid);
+ if (status != IFSL_SUCCESS)
+ {
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ switch (status)
+ {
+ case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
+ case IFSL_NO_ACCESS: SYNC_FAIL(STATUS_ACCESS_DENIED);
+ case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
+ case IFSL_PATH_DOES_NOT_EXIST: SYNC_FAIL2(STATUS_OBJECT_PATH_NOT_FOUND, FILE_DOES_NOT_EXIST);
+ case IFSL_OPEN_EXISTS: SYNC_FAIL2(STATUS_OBJECT_NAME_COLLISION, FILE_EXISTS);
+ case IFSL_OVERQUOTA: SYNC_FAIL(STATUS_DISK_FULL);//STATUS_QUOTA_EXCEEDED);
+ default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+ }
+
+ /* lock list like above. check again just to make sure it isn't in the list.
+ if it is, we should process like above. depending on how we follow symlinks
+ (same fid for multiple files), we cannot expect serialized create requests. */
+ LOCK_FCB_LIST;
+ fcb = find_fcb(fid);
+ if (fcb)
+ _asm int 3;
+
+ if (size.QuadPart != 0)
+ {
+ size.QuadPart = 0;
+ uc_trunc(fid, size);
+ if (status != IFSL_SUCCESS)
+ {
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_DISK_FULL);
+ }
+ }
+ if (Irp->Overlay.AllocationSize.QuadPart)
+ {
+ uc_trunc(fid, Irp->Overlay.AllocationSize);
+ size = Irp->Overlay.AllocationSize;
+ if (status != IFSL_SUCCESS)
+ {
+ UNLOCK_FCB_LIST;
+ ExFreePoolWithTag(str, AFS_RDR_TAG);
+ SYNC_FAIL(STATUS_ACCESS_DENIED);
+ }
+ }
+
+ created = 1;
+ goto makefcb;
+ }
+
+/* OS passed unexpected disposition */
+ExFreePoolWithTag(str, AFS_RDR_TAG);
+SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
+/*SYNC_FAIL2(STATUS_OBJECT_NAME_NOT_FOUND, FILE_DOES_NOT_EXIST);*/
+
+
+/* allocate nonpaged struct to track this file and all open instances */
+makefcb:
+ fcb = ExAllocateFromNPagedLookasideList(&rdrExt->fcbMemList);
+ ASSERT(fcb);
+ RtlZeroMemory(fcb, sizeof(afs_fcb_t));
+
+ fcb->fid = fid;
+ /*fcb->refs = 0;*/
+ fcb->ccb_list = NULL;
+ fcb->IsFastIoPossible = FastIoIsNotPossible;
+
+ ExInitializeResourceLite(&fcb->_resource);
+ ExInitializeResourceLite(&fcb->_pagingIoResource);
+ fcb->Resource = &fcb->_resource;
+ fcb->PagingIoResource = &fcb->_pagingIoResource;
+ LOCK_PAGING_FCB;
+ LOCK_FCB;
+
+ fcb->sectionPtrs.DataSectionObject = NULL;
+ fcb->sectionPtrs.SharedCacheMap = NULL;
+ fcb->sectionPtrs.ImageSectionObject = NULL;
+ fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = size;
+
+ IoSetShareAccess(access, share, IrpSp->FileObject, &fcb->share_access);
+
+ /* we store a pointer to the fcb. the table would want to store a copy otherwise. */
+ fcbp = &fcb;
+ RtlInsertElementGenericTable(&rdrExt->fcbTable, fcbp, sizeof(fcbp), NULL);
+
+ sizes.AllocationSize = sizes.FileSize = sizes.ValidDataLength = size;
+ rpt1(("create", "created size %d name %ws", size.LowPart, str));
+
+/* allocate nonpaged struct tracking information specific to (file, open instance) pair,
+ and link from parent. is put at head of parent's list. */
+makeccb:
+ /* there are two different types of pending deletes. we return different
+ errors in places depending on a) delete specified on call to open,
+ or b) file specifically deleted */
+ /* need to check for DELETE perms too? */
+ if (IrpSp->Parameters.Create.Options & FILE_DELETE_ON_CLOSE)
+ fcb->delPending = 2;
+
+ ccb = ExAllocateFromNPagedLookasideList(&rdrExt->ccbMemList);
+ ccb->name = str;
+ ccb->access = granted;
+ ccb->fo = IrpSp->FileObject;
+ ccb->cookie.QuadPart = 0;
+ ccb->filter = NULL;
+ ccb->attribs = attribs;
+
+ /* save security context information. we never change this ccb attribute. */
+ ObReferenceObjectByPointer(acc_token, TOKEN_QUERY, NULL, KernelMode);
+ ccb->token = acc_token;
+ /*ObOpenObjectByPointer(acc_token, OBJ_KERNEL_HANDLE, NULL, TOKEN_QUERY, NULL, KernelMode, &ccb->token);*/
+
+ /*fcb->refs++;*/
+ if (!fcb->ccb_list)
+ {
+ ccb->next = NULL;
+ fcb->ccb_list = ccb;
+ }
+ else
+ {
+ ccb->next = fcb->ccb_list;
+ fcb->ccb_list = ccb;
+ }
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ UNLOCK_FCB_LIST;
+
+ /* how we pack (as it is expected): a) fscontext same for all open instances of a file,
+ b) fscontext2 unique among each instance, c) private cache map pointer set by cache
+ manager upon caching, d) so pointers are per-file, as in (a). */
+ IrpSp->FileObject->FsContext = fcb;
+ IrpSp->FileObject->FsContext2 = ccb;
+ IrpSp->FileObject->PrivateCacheMap = NULL;
+ IrpSp->FileObject->SectionObjectPointer = &(fcb->sectionPtrs);
+
+ /* explicitly start caching on a data file. caching will still happen upon
+ paging i/o even if commented out below. the other option is to cache upon
+ the first read/write operation. that code is also in place. */
+ if (!(attribs & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ /*CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1);*/
+ /*CcSetAdditionalCacheAttributes(IrpSp->FileObject, TRUE, TRUE);*/
+ }
+
+ /* customize returns; semantics largely derived from output of ifstest.exe */
+ switch (disp)
+ {
+ case FILE_OPEN:
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_OPENED)
+
+ case FILE_OPEN_IF:
+ if (created)
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED)
+ else
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_OPENED)
+
+ case FILE_OVERWRITE:
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_OVERWRITTEN)
+
+ case FILE_OVERWRITE_IF:
+ if (created)
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED)
+ else
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_OVERWRITTEN)
+
+ case FILE_SUPERSEDE:
+ if (created)
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED)
+ else
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_SUPERSEDED)
+
+ case FILE_CREATE:
+ SYNC_FAIL2(STATUS_SUCCESS, FILE_CREATED)
+ }
+_asm int 3;
+return 0;
+}
+
+/* experimental; does not work. need to handle filesizes
+ and cache invalidation in more places. */
+#define EXPLICIT_CACHING
+
+/**********************************************************
+ * AfsRdrRead
+ * - handle reads
+ **********************************************************/
+NTSTATUS AfsRdrRead(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+struct ReadKOut *p;
+void *ptr;
+LARGE_INTEGER offset, curroff;
+ULONG length, read;
+void *outPtr;
+NTSTATUS status;
+afs_ccb_t *ccb;
+MDL m;
+ULONG currpos, ttlread, toread;
+
+ccb = IrpSp->FileObject->FsContext2;
+if (IsDeviceFile(IrpSp->FileObject) || (ccb->attribs & FILE_ATTRIBUTE_DIRECTORY))
+ SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
+
+/* the second line disables read ahead and write behind. since our data is
+ already cached in userland, and there are read-ahead parameters there,
+ we do not use this service. */
+#ifdef EXPLICIT_CACHING
+if (!IrpSp->FileObject->PrivateCacheMap)
+ {
+ CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1);
+ CcSetAdditionalCacheAttributes(IrpSp->FileObject, FALSE, TRUE);
+ //CcSetReadAheadGranularity
+ }
+#endif
+
+if (!(ccb->access & FILE_READ_DATA) && !(Irp->Flags & IRP_PAGING_IO))
+ SYNC_FAIL(STATUS_ACCESS_DENIED);
+
+if (!IrpSp->Parameters.Read.Length)
+ SYNC_FAIL(STATUS_SUCCESS);
+
+offset = IrpSp->Parameters.Read.ByteOffset;
+length = IrpSp->Parameters.Read.Length;
+
+/* FIX: lock here, before finding end-of-file */
+
+/* fast out for reads starting beyond eof */
+if (offset.QuadPart > fcb->ValidDataLength.QuadPart)
+ SYNC_FAIL(STATUS_END_OF_FILE);
+/* pre-truncate reads */
+if (offset.QuadPart + length > fcb->ValidDataLength.QuadPart)
+ length = (ULONG)(fcb->ValidDataLength.QuadPart - offset.QuadPart);
+
+outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+if (!outPtr)
+ SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
+
+#ifdef EXPLICIT_CACHING
+if (!(Irp->Flags & (IRP_NOCACHE | IRP_PAGING_IO)))
+ {
+ FsRtlEnterFileSystem();
+ SLOCK_PAGING_FCB;
+ ttlread = 0;
+ try
+ {
+ if (!CcCopyRead(IrpSp->FileObject, &offset, length, TRUE, outPtr, &Irp->IoStatus))
+ {
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+// KdPrint(("read %x at %x cache done %x\n", length, (ULONG)offset.QuadPart, Irp->IoStatus.Information));
+ ttlread = Irp->IoStatus.Information;
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ STATUS(STATUS_UNSUCCESSFUL, 0);
+ }
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ if (Irp->IoStatus.Status == STATUS_UNSUCCESSFUL)
+ SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+else
+#endif
+ {
+ FsRtlEnterFileSystem();
+ SLOCK_FCB;
+ for (currpos = ttlread = 0; ttlread < length; )
+ {
+ toread = length - currpos;
+ toread = (toread > TRANSFER_CHUNK_SIZE) ? TRANSFER_CHUNK_SIZE : toread;
+ curroff.QuadPart = offset.QuadPart + currpos;
+ status = uc_read(fcb->fid, curroff, toread, &read, outPtr);
+// KdPrint(("read %x at %x done %x\n", length, (ULONG)offset.QuadPart, read));
+ if (status == 0)
+ {
+ ttlread += read;
+ currpos += read;
+ if (read < toread)
+ goto end;
+ continue;
+ }
+ UNLOCK_FCB;
+ FsRtlExitFileSystem();
+ switch (status)
+ {
+ case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
+ case IFSL_IS_A_DIR: SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
+ case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
+ default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+ }
+end: ;
+ UNLOCK_FCB;
+ FsRtlExitFileSystem();
+ }
+
+/* update byteoffset when this is not a paging or async request */
+if (IoIsOperationSynchronous(Irp) && !(Irp->Flags & IRP_PAGING_IO))
+ IrpSp->FileObject->CurrentByteOffset.QuadPart += ttlread;
+
+if (ttlread == 0)//< length)
+ SYNC_FAIL2(STATUS_END_OF_FILE, ttlread)
+else
+ SYNC_FAIL2(STATUS_SUCCESS, ttlread)
+}
+
+
+
+/**********************************************************
+ * AfsRdrWrite
+ * - handle writes
+ **********************************************************/
+NTSTATUS AfsRdrWrite(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+struct WriteKOut *p;
+void *ptr, *outPtr;
+ULONG length, written;
+LARGE_INTEGER offset, end;
+NTSTATUS status;
+afs_ccb_t *ccb;
+CC_FILE_SIZES sizes, oldSizes;
+ULONG towrite, ttlwritten, currpos;
+LARGE_INTEGER curroff;
+BOOLEAN change, paging_lock;
+
+ccb = IrpSp->FileObject->FsContext2;
+if (IsDeviceFile(IrpSp->FileObject) || (ccb->attribs & FILE_ATTRIBUTE_DIRECTORY))
+ SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
+
+/* since we will be performing io on this instance, start caching. */
+#ifdef EXPLICIT_CACHING
+if (!IrpSp->FileObject->PrivateCacheMap)
+ {
+ CcInitializeCacheMap(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize, FALSE, &rdrExt->callbacks, IrpSp->FileObject->FsContext);//(PVOID)din->Context1);
+ CcSetAdditionalCacheAttributes(IrpSp->FileObject, FALSE, TRUE);
+ }
+#endif
+
+if (!(ccb->access & FILE_WRITE_DATA) && !(Irp->Flags & IRP_PAGING_IO))
+ SYNC_FAIL(STATUS_ACCESS_DENIED);
+
+/* fast-out for zero-length i/o */
+if (!IrpSp->Parameters.Write.Length)
+ SYNC_FAIL(STATUS_SUCCESS);
+
+if (IrpSp->Parameters.Write.ByteOffset.HighPart == 0xffffffff &&
+ IrpSp->Parameters.Write.ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE)
+ offset.QuadPart = fcb->FileSize.QuadPart;
+else
+ offset = IrpSp->Parameters.Write.ByteOffset;
+length = IrpSp->Parameters.Write.Length;
+
+if (!(outPtr = AfsFindBuffer(Irp)))
+ SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
+
+#ifdef EXPLICIT_CACHING
+if (!(Irp->Flags & (IRP_NOCACHE | IRP_PAGING_IO)))
+ {
+ /* extend file for cached writes */
+ FsRtlEnterFileSystem();
+ LOCK_PAGING_FCB;
+ if (offset.QuadPart + length > fcb->FileSize.QuadPart)
+ {
+ end.QuadPart = offset.QuadPart + length;
+ fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = end;
+ LOCK_FCB;
+ CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
+ UNLOCK_FCB;
+ /*ret = *//*CcZeroData(IrpSp->FileObject, &oldSizes.FileSize, &end, FALSE);*/ /* should wait? */
+ }
+ try
+ {
+ if (!CcCopyWrite(IrpSp->FileObject, &offset, length, TRUE, outPtr))
+ SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ STATUS(STATUS_UNSUCCESSFUL, 0);
+ }
+// KdPrint(("write %x at %x cache done\n", length, (ULONG)offset.QuadPart));
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ ttlwritten = written = length;
+ if (Irp->IoStatus.Status == STATUS_UNSUCCESSFUL)
+ SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+else
+#endif
+ {
+ FsRtlEnterFileSystem();
+ while (1)
+ {
+ if (offset.QuadPart + length > fcb->FileSize.QuadPart)
+ change = 1;
+ else
+ change = 0;
+ if (change && !(Irp->Flags & IRP_PAGING_IO))
+ paging_lock = 1;
+ else
+ paging_lock = 0;
+ if (paging_lock)
+ LOCK_PAGING_FCB;
+ LOCK_FCB;
+ if (offset.QuadPart + length > fcb->FileSize.QuadPart)
+ {
+ if (Irp->Flags & IRP_PAGING_IO)
+ {
+ /* the input buffer and length is for a full page. ignore this. */
+ if (offset.QuadPart > fcb->FileSize.QuadPart)
+ {
+ if (paging_lock)
+ {
+ _asm int 3;
+ UNLOCK_PAGING_FCB;
+ }
+ UNLOCK_FCB;
+ FsRtlExitFileSystem();
+ SYNC_FAIL2(STATUS_SUCCESS, length);
+ }
+ length = (ULONG)(fcb->FileSize.QuadPart - offset.QuadPart);
+ if (paging_lock)
+ {
+ _asm int 3;
+ UNLOCK_PAGING_FCB;
+ }
+ break;
+ }
+ else
+ {
+ if (!change)
+ {
+ if (paging_lock)
+ {
+ _asm int 3;
+ UNLOCK_PAGING_FCB;
+ }
+ UNLOCK_FCB;
+ continue;
+ }
+ end.QuadPart = offset.QuadPart + length;
+ fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = end;
+ CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
+ if (paging_lock)
+ UNLOCK_PAGING_FCB;
+ break;
+ }
+ }
+ else
+ {
+ //UNLOCK_FCB;
+ if (paging_lock)
+ UNLOCK_PAGING_FCB;
+ break;
+ }
+ }
+
+ for (currpos = ttlwritten = 0; ttlwritten < length; )
+ {
+ towrite = length - currpos;
+ towrite = (towrite > TRANSFER_CHUNK_SIZE) ? TRANSFER_CHUNK_SIZE : towrite;
+ curroff.QuadPart = offset.QuadPart + currpos;
+ status = uc_write(fcb->fid, curroff, towrite, &written, outPtr);
+// KdPrint(("write %x at %x done\n", length, (ULONG)offset.QuadPart));
+ if (status == 0)
+ {
+ ttlwritten += written;
+ currpos += written;
+ if (written < towrite)
+ goto end;
+ continue;
+ }
+ UNLOCK_FCB;
+ FsRtlExitFileSystem();
+ switch (status)
+ {
+ case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
+ case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
+ case IFSL_OVERQUOTA: SYNC_FAIL(STATUS_DISK_FULL);
+ default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+ }
+end: ;
+ UNLOCK_FCB;
+ FsRtlExitFileSystem();
+ }
+
+if (IoIsOperationSynchronous(Irp) && !(Irp->Flags & IRP_PAGING_IO))
+ IrpSp->FileObject->CurrentByteOffset.QuadPart += ttlwritten;
+
+/* if we failed a write, we would not be here. so, we must
+ tell the vmm that all data was written. */
+if (Irp->Flags & IRP_PAGING_IO)
+ SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.Write.Length)
+SYNC_FAIL2(STATUS_SUCCESS, ttlwritten)
+}
+
+
+wchar_t *SEARCH_MATCH_ALL = L"**";
+
+/**********************************************************
+ * AfsRdrDirCtrl
+ * - handle directory notification callbacks
+ * - handle directory enumeration
+ **********************************************************/
+NTSTATUS AfsRdrDirCtrl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+struct EnumDirKOut *p;
+LARGE_INTEGER size, creation, access, change, written;
+ULONG attribs, count;
+char buf[2048];
+afs_ccb_t *ccb;
+void *outPtr, *info, *pre_adj_info;
+FILE_BOTH_DIR_INFORMATION *info_both, *info_both_prev;
+FILE_DIRECTORY_INFORMATION *info_dir, *info_dir_prev;
+FILE_NAMES_INFORMATION *info_names, *info_names_prev;
+int info_size;
+readdir_data_t *ii;
+ULONG x, buf_size;
+LARGE_INTEGER last_cookie;
+BOOLEAN overflow;
+NTSTATUS status;
+FILE_NOTIFY_INFORMATION *notify;
+
+if (IsDeviceFile(IrpSp->FileObject))
+ SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
+
+if (IrpSp->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
+ {
+ ccb = IrpSp->FileObject->FsContext2;
+ ccb->str.Length = wcslen(ccb->name)*sizeof(wchar_t);
+ ccb->str.MaximumLength = ccb->str.Length + sizeof(wchar_t);
+ ccb->str.Buffer = ccb->name;
+
+ FsRtlEnterFileSystem();
+ LOCK_FCB; /* FIX: shared lock? */
+ FsRtlNotifyFullChangeDirectory(rdrExt->notifyList, &rdrExt->listHead,
+ ccb,
+ (STRING*)&ccb->str,
+ IrpSp->Flags & SL_WATCH_TREE,
+ FALSE,
+ /*FILE_NOTIFY_CHANGE_FILE_NAME,*/IrpSp->Parameters.NotifyDirectory.CompletionFilter,
+ Irp, NULL, NULL);
+ UNLOCK_FCB;
+ FsRtlExitFileSystem();
+ /* do NOT complete request; that will be done by fsrtlnotify functions */
+ return STATUS_PENDING;
+ }
+
+if (IrpSp->MinorFunction != IRP_MN_QUERY_DIRECTORY)
+ SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
+
+if (IrpSp->Parameters.QueryDirectory.FileInformationClass != FileBothDirectoryInformation &&
+ IrpSp->Parameters.QueryDirectory.FileInformationClass != FileDirectoryInformation &&
+ IrpSp->Parameters.QueryDirectory.FileInformationClass != FileNamesInformation)
+ {
+ _asm int 3;
+ rpt0(("enum", "enum class %d not supported", IrpSp->Parameters.QueryDirectory.FileInformationClass));
+ SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
+ }
+
+ccb = IrpSp->FileObject->FsContext2;
+
+if (!(outPtr = AfsFindBuffer(Irp)))
+ SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
+
+if (IrpSp->Flags & SL_INDEX_SPECIFIED)
+ {
+ /* we were told where to start our search; afsd should scrub this input */
+ ccb->cookie.QuadPart = IrpSp->Parameters.QueryDirectory.FileIndex;
+ if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL)
+ ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG);
+ ccb->filter = SEARCH_MATCH_ALL;
+ }
+else if (IrpSp->Flags & SL_RESTART_SCAN ||
+ ((IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) && ccb->cookie.QuadPart == 0))
+ {
+ /* copy new filter string into nonpaged memory */
+ ccb->cookie.QuadPart = 0;
+ if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL)
+ ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG);
+ buf_size = IrpSp->Parameters.QueryDirectory.FileName->Length+6;
+ ccb->filter = ExAllocatePoolWithTag(NonPagedPool, buf_size, AFS_RDR_TAG);
+ RtlCopyMemory(ccb->filter, IrpSp->Parameters.QueryDirectory.FileName->Buffer, buf_size);
+ ccb->filter[IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR)] = L'\0';
+ }
+
+if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY)
+ count = 1;
+buf_size = 2040;
+
+status = uc_readdir(fcb->fid, ccb->cookie, ccb->filter, &count, buf, &buf_size);
+
+switch (status)
+ {
+ case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
+ case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
+ default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ case 0: break;
+ }
+
+switch (IrpSp->Parameters.QueryDirectory.FileInformationClass)
+ {
+ case FileBothDirectoryInformation:
+ info_size = sizeof(FILE_BOTH_DIR_INFORMATION);
+ break;
+ case FileDirectoryInformation:
+ info_size = sizeof(FILE_DIRECTORY_INFORMATION);
+ break;
+ case FileNamesInformation:
+ info_size = sizeof(FILE_NAMES_INFORMATION);
+ break;
+ default:
+ KeBugCheckEx(0x12345, 0x98, 0x0, 0x0, 0x0);
+ }
+
+info = (FILE_BOTH_DIR_INFORMATION *)outPtr;
+ii = (readdir_data_t *)buf;
+Irp->IoStatus.Information = 0;
+if (!count)
+ {
+ if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY && ccb->cookie.QuadPart == 0)
+ SYNC_FAIL(STATUS_NO_SUCH_FILE);
+ SYNC_FAIL(STATUS_NO_MORE_FILES);
+ }
+
+info_both_prev = NULL;
+info_dir_prev = NULL;
+info_names_prev = NULL;
+if (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY)
+ count = 1;
+
+for (x = 0; x < count; x++)
+ {
+ pre_adj_info = info;
+
+ /* must explicitly align second and subsequent entries on 8-byte boundaries */
+ if (((ULONG)info & 0x7) && x)
+ info = (void*)(((ULONG)info) + (8-((ULONG)info & 0x7)));
+
+ overflow = ((long)info + info_size + (long)ii->name_length >
+ (long)outPtr + (long)IrpSp->Parameters.QueryDirectory.Length);
+ if (overflow && x != 0)
+ {
+ ccb->cookie = ii->cookie;
+ SYNC_FAIL2(STATUS_SUCCESS, (long)pre_adj_info - (long)outPtr);
+ }
+
+ memset(info, 0, info_size);
+ switch (IrpSp->Parameters.QueryDirectory.FileInformationClass)
+ {
+ case FileBothDirectoryInformation:
+ info_both = info;
+ if (info_both_prev)
+ info_both_prev->NextEntryOffset = (char*)info_both - (char*)info_both_prev;
+
+ info_both->NextEntryOffset = 0;
+ info_both->FileIndex = (ULONG)ii->cookie.QuadPart;
+ info_both->CreationTime.QuadPart = AfsTimeToWindowsTime(ii->creation.QuadPart);
+ info_both->LastAccessTime.QuadPart = AfsTimeToWindowsTime(ii->access.QuadPart);
+ info_both->LastWriteTime.QuadPart = AfsTimeToWindowsTime(ii->write.QuadPart);
+ info_both->ChangeTime.QuadPart = AfsTimeToWindowsTime(ii->change.QuadPart);
+ info_both->EndOfFile = info_both->AllocationSize = ii->size;
+ info_both->FileAttributes = ii->attribs;/*| FILE_ATTRIBUTE_READONLY*/;
+ info_both->EaSize = 0;
+ info_both->ShortNameLength = ii->short_name_length;
+ info_both->FileNameLength = ii->name_length;
+ RtlCopyMemory(info_both->ShortName, ii->short_name, ii->short_name_length*sizeof(WCHAR));
+
+ if (overflow)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ info_both->FileNameLength = 0;
+ info_both->FileName[0] = L'\0';
+ goto done;
+ }
+
+ RtlCopyMemory(info_both->FileName, ii->name, ii->name_length*sizeof(WCHAR));
+ info_both_prev = info_both;
+ break;
+
+ case FileDirectoryInformation:
+ info_dir = info;
+ if (info_dir_prev)
+ info_dir_prev->NextEntryOffset = (char*)info_dir - (char*)info_dir_prev;
+
+ info_dir->NextEntryOffset = 0;
+ info_dir->FileIndex = (ULONG)ii->cookie.QuadPart;
+ info_dir->CreationTime.QuadPart = AfsTimeToWindowsTime(ii->creation.QuadPart);
+ info_dir->LastAccessTime.QuadPart = AfsTimeToWindowsTime(ii->access.QuadPart);
+ info_dir->LastWriteTime.QuadPart = AfsTimeToWindowsTime(ii->write.QuadPart);
+ info_dir->ChangeTime.QuadPart = AfsTimeToWindowsTime(ii->change.QuadPart);
+ info_dir->EndOfFile = info_dir->AllocationSize = ii->size;
+ info_dir->FileAttributes = ii->attribs /*| FILE_ATTRIBUTE_READONLY*/;
+ info_dir->FileNameLength = ii->name_length;
+
+ if (overflow)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ info_dir->FileNameLength = 0;
+ info_dir->FileName[0] = L'\0';
+ goto done;
+ }
+
+ RtlCopyMemory(info_dir->FileName, ii->name, ii->name_length*sizeof(WCHAR));
+ info_dir_prev = info_dir;
+ break;
+
+ case FileNamesInformation:
+ info_names = info;
+ if (info_names_prev)
+ info_names_prev->NextEntryOffset = (char*)info_names - (char*)info_names_prev;
+
+ info_names->NextEntryOffset = 0;
+ info_names->FileIndex = (ULONG)ii->cookie.QuadPart;
+ info_names->FileNameLength = ii->name_length;
+
+ if (overflow)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ info_names->FileNameLength = 0;
+ info_names->FileName[0] = L'\0';
+ goto done;
+ }
+
+ RtlCopyMemory(info_names->FileName, ii->name, ii->name_length*sizeof(WCHAR));
+ info_names_prev = info_names;
+ break;
+ }
+
+ info = (void*)(((ULONG)info) + info_size + (ULONG)ii->name_length*sizeof(WCHAR));
+ ii = (readdir_data_t *)(((unsigned char *)ii) + sizeof(readdir_data_t) + ii->name_length);
+ last_cookie = ii->cookie;
+ }
+
+Irp->IoStatus.Status = STATUS_SUCCESS;
+done:
+ ccb->cookie = last_cookie;
+
+SYNC_FAIL2(Irp->IoStatus.Status, (long)info - (long)outPtr);
+}
+
+
+
+
+/**********************************************************
+ * AfsRdrQueryInfo
+ * - handle stat calls
+ **********************************************************/
+NTSTATUS AfsRdrQueryInfo(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+FILE_BASIC_INFORMATION *infoBasic;
+FILE_NAME_INFORMATION *infoName;
+FILE_STANDARD_INFORMATION *infoStandard;
+FILE_POSITION_INFORMATION *infoPosition;
+FILE_ALL_INFORMATION *infoAll;
+FILE_INTERNAL_INFORMATION *infoInternal;
+LARGE_INTEGER size, creation, access, change, written;
+ULONG attribs;
+long count;
+afs_ccb_t *ccb;
+char *outPtr;
+NTSTATUS status;
+wchar_t *start;
+
+if (IsDeviceFile(IrpSp->FileObject))
+ SYNC_FAIL(STATUS_UNSUCCESSFUL); // what should happen?
+
+if (!(outPtr = AfsFindBuffer(Irp)))
+ SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
+
+ccb = IrpSp->FileObject->FsContext2;
+
+status = uc_stat(fcb->fid, &attribs, &size, &creation, &access, &change, &written);
+switch (status)
+ {
+ case IFSL_RPC_TIMEOUT: SYNC_FAIL_RPC_TIMEOUT;
+ case IFSL_BAD_INPUT: SYNC_FAIL(STATUS_INVALID_PARAMETER);
+ default: SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ case 0: break;
+ }
+
+/* afsd does not maintain instance-specific data, so we adjust here */
+if (ccb->access & FILE_READ_DATA && !(ccb->access & FILE_WRITE_DATA))
+ attribs |= FILE_ATTRIBUTE_READONLY;
+
+(void*)infoBasic = (void*)infoName = (void*)infoPosition = (void*)infoStandard = (void*)infoInternal = NULL;
+switch (IrpSp->Parameters.QueryFile.FileInformationClass)
+ {
+ case FileBasicInformation:
+ infoBasic = (FILE_BASIC_INFORMATION*)outPtr;
+ break;
+ case FileNameInformation:
+ infoName = (FILE_NAME_INFORMATION*)outPtr;
+ break;
+ case FileStandardInformation:
+ infoStandard = (FILE_STANDARD_INFORMATION*)outPtr;
+ break;
+ case FilePositionInformation:
+ infoPosition = (FILE_POSITION_INFORMATION*)outPtr;
+ break;
+ case FileAllInformation:
+ infoAll = (FILE_ALL_INFORMATION*)outPtr;
+ infoBasic = &infoAll->BasicInformation;
+ infoName = &infoAll->NameInformation;
+ infoStandard = &infoAll->StandardInformation;
+ infoPosition = &infoAll->PositionInformation;
+ break;
+ case FileInternalInformation:
+ infoInternal = (FILE_INTERNAL_INFORMATION*)outPtr;
+ break;
+ default:
+ STATUS(STATUS_NOT_IMPLEMENTED, 0);
+ break;
+ }
+
+if (infoBasic)
+ {
+ memset(infoBasic, 0, sizeof(FILE_BASIC_INFORMATION));
+ infoBasic->FileAttributes = attribs;
+ infoBasic->CreationTime.QuadPart = AfsTimeToWindowsTime(creation.QuadPart);
+ infoBasic->LastAccessTime.QuadPart = AfsTimeToWindowsTime(access.QuadPart);
+ infoBasic->LastWriteTime.QuadPart = AfsTimeToWindowsTime(written.QuadPart);
+ infoBasic->ChangeTime.QuadPart = AfsTimeToWindowsTime(change.QuadPart);
+ STATUS(STATUS_SUCCESS, sizeof(FILE_BASIC_INFORMATION));
+ //KdPrint(("query basicinfo %d,%d %x,%I64d,%I64d\n", fcb->fid, (ULONG)IrpSp->FileObject->FsContext2, infoBasic->FileAttributes, infoBasic->CreationTime.QuadPart, infoBasic->ChangeTime.QuadPart));
+ }
+
+if (infoName)
+ {
+ memset(infoName, 0, sizeof(FILE_NAME_INFORMATION));
+ start = ccb->name;
+ count = (long)(*(start+1) - L'0');
+ if (count > 9 || count < 0)
+ SYNC_FAIL(STATUS_OBJECT_NAME_INVALID);
+ if (count || *start == L'0')
+ {
+ for ( ; count >= 0 && start; count--)
+ start = wcschr(start+1, L'\\');
+ if (!start)
+ SYNC_FAIL(STATUS_OBJECT_NAME_INVALID);
+ }
+ infoName->FileNameLength = wcslen(start)*sizeof(WCHAR);
+ if (((IrpSp->Parameters.QueryFile.FileInformationClass == FileAllInformation) ? sizeof(*infoAll) : sizeof(*infoName)) +
+ infoName->FileNameLength > IrpSp->Parameters.QueryFile.Length)
+ {
+ infoName->FileNameLength = 0;
+ infoName->FileName[0] = L'\0';
+ STATUS(STATUS_BUFFER_OVERFLOW, sizeof(FILE_NAME_INFORMATION));
+ //KdPrint(("query overflowing buffer %d\n", IrpSp->Parameters.QueryFile.Length));
+ }
+ else
+ { //TODO:check filename is correct/correct format
+ StringCbCopy(infoName->FileName, IrpSp->Parameters.QueryFile.Length - sizeof(*infoName), start);
+ STATUS(STATUS_SUCCESS, sizeof(FILE_NAME_INFORMATION) + (infoName->FileNameLength - sizeof(WCHAR)));
+ }
+ //KdPrint(("query nameinfo %ws from %ws\n", infoName->FileName, ccb->name));
+ }
+
+if (infoStandard)
+ {
+ memset(infoStandard, 0, sizeof(FILE_STANDARD_INFORMATION));
+ infoStandard->AllocationSize.QuadPart = size.QuadPart;
+ infoStandard->EndOfFile.QuadPart = size.QuadPart;
+ infoStandard->NumberOfLinks = 1;
+ infoStandard->DeletePending = (fcb->delPending == 1);
+ infoStandard->Directory = (attribs & FILE_ATTRIBUTE_DIRECTORY)?TRUE:FALSE; //TODO:check if flag is valid at this point
+ STATUS(STATUS_SUCCESS, sizeof(FILE_STANDARD_INFORMATION));
+ //KdPrint(("query stdinfo %d,%d %I64d,%s\n", fcb->fid, (ULONG)IrpSp->FileObject->FsContext2, infoStandard->EndOfFile.QuadPart, infoStandard->Directory?"dir":"file"));
+ }
+
+if (infoPosition)
+ {
+ infoPosition->CurrentByteOffset = IrpSp->FileObject->CurrentByteOffset;
+ STATUS(STATUS_SUCCESS, sizeof(FILE_POSITION_INFORMATION));
+ //KdPrint(("query position %d,%d %I64d\n", fcb, (ULONG)IrpSp->FileObject->FsContext2, infoPosition->CurrentByteOffset.QuadPart));
+ }
+
+if (IrpSp->Parameters.QueryFile.FileInformationClass == FileAllInformation)
+ {
+ if (!infoName->FileNameLength)
+ STATUS(STATUS_BUFFER_OVERFLOW, sizeof(FILE_ALL_INFORMATION));
+ else
+ STATUS(STATUS_SUCCESS, sizeof(FILE_ALL_INFORMATION) + (infoName->FileNameLength - sizeof(WCHAR)));
+ }
+
+if (infoInternal)
+ {
+ infoInternal->IndexNumber.QuadPart = fcb->fid;
+ STATUS(STATUS_SUCCESS, sizeof(FILE_INTERNAL_INFORMATION));
+ }
+
+status = Irp->IoStatus.Status;
+COMPLETE;
+return status;
+}
+
+
+
+
+/**********************************************************
+ * AfsRdrSetInfo
+ * - handle setting mod time
+ * - handle deleting
+ * - handle truncation/extension
+ * - handle renaming
+ **********************************************************/
+NTSTATUS AfsRdrSetInfo(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+struct SetInfoKOut *p;
+afs_fcb_t *fcbt;
+afs_ccb_t *ccb;
+FILE_DISPOSITION_INFORMATION *infoDisp;
+FILE_BASIC_INFORMATION *infoBasic;
+FILE_END_OF_FILE_INFORMATION *infoLength;
+FILE_RENAME_INFORMATION *infoRename;
+FILE_POSITION_INFORMATION *infoPosition;
+NTSTATUS ret;
+wchar_t *buf, *part, *ptr;
+ULONG size, new_fid;
+NTSTATUS status;
+
+if (IrpSp->FileObject->FileName.Length == 0)
+ SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
+
+ccb = IrpSp->FileObject->FsContext2;
+
+switch (IrpSp->Parameters.SetFile.FileInformationClass)
+ {
+ /* delete disposition */
+ case FileDispositionInformation:
+ infoDisp = Irp->AssociatedIrp.SystemBuffer;
+
+ FsRtlEnterFileSystem();
+ LOCK_FCB;
+
+ if (infoDisp->DeleteFile)
+ {
+ if (!MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForDelete))
+ SYNC_FAIL(STATUS_ACCESS_DENIED);
+ fcb->delPending |= 0x1;
+ }
+ else
+ fcb->delPending &= ~0x1;
+ UNLOCK_FCB;
+ FsRtlExitFileSystem();
+ SYNC_RET(STATUS_SUCCESS);
+
+ /*case FileAllocationInformation:*/
+ case FileEndOfFileInformation:
+ /* ignore extensions caused by paging requests*/
+ if (Irp->Flags & IRP_PAGING_IO)
+ SYNC_FAIL(STATUS_SUCCESS);
+
+ infoLength = Irp->AssociatedIrp.SystemBuffer;
+
+ FsRtlEnterFileSystem();
+ LOCK_PAGING_FCB;
+ LOCK_FCB;
+ if (IrpSp->Parameters.SetFile.AdvanceOnly && (infoLength->EndOfFile.QuadPart > fcb->FileSize.QuadPart) ||
+ !IrpSp->Parameters.SetFile.AdvanceOnly && (infoLength->EndOfFile.QuadPart < fcb->FileSize.QuadPart))
+ {
+ status = uc_trunc(fcb->fid, infoLength->EndOfFile);
+ /* because it is not written to the server immediately, this error will not always happen */
+ if (status == IFSL_OVERQUOTA)
+ {
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ SYNC_FAIL(STATUS_DISK_FULL);
+ }
+ }
+ fcb->FileSize = fcb->AllocationSize = fcb->ValidDataLength = infoLength->EndOfFile;
+ CcSetFileSizes(IrpSp->FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
+ //CcPurgeCacheSection(IrpSp->FileObject->SectionObjectPointer, &fcb->AllocationSize, 0, FALSE);
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ SYNC_FAIL(STATUS_SUCCESS);
+
+ case FileBasicInformation:
+ infoBasic = Irp->AssociatedIrp.SystemBuffer;
+ status = uc_setinfo(fcb->fid, infoBasic->FileAttributes, infoBasic->CreationTime, infoBasic->LastAccessTime, infoBasic->ChangeTime, infoBasic->LastWriteTime);
+ SYNC_FAIL(STATUS_SUCCESS);
+
+ case FileRenameInformation:
+ //KdPrint(("set rename %d\n", fcb->fid));
+ infoRename = Irp->AssociatedIrp.SystemBuffer;
+ new_fid = fcb->fid;
+ //rpt1(("setinfo", "rename %d,%d %d,%ws", ExtractFid(fcb), (ULONG)IrpSp->FileObject->FsContext2, infoRename->ReplaceIfExists, infoRename->FileName));
+
+ if (IrpSp->Parameters.SetFile.FileObject)
+ fcbt = FindFcb(IrpSp->Parameters.SetFile.FileObject);
+
+ //null-terminate all strings into uc_rename?
+ //FIX/one rename case not working
+
+ if (IrpSp->Parameters.SetFile.FileObject == NULL &&
+ infoRename->RootDirectory == NULL)
+ {
+ WCHAR fname[300]; /* FIX: uc_rename needs null-terminated string */
+ StringCchCopyNW(fname, 300-1, infoRename->FileName, infoRename->FileNameLength/sizeof(WCHAR));
+ uc_rename(fcb->fid, ccb->name+2, NULL, fname, &new_fid);
+ fcb->fid = new_fid;
+ }
+ else if (IrpSp->Parameters.SetFile.FileObject != NULL &&
+ infoRename->RootDirectory == NULL)
+ {
+ WCHAR fname[300];
+ StringCchCopyNW(fname, 300-1, infoRename->FileName, infoRename->FileNameLength/sizeof(WCHAR));
+ uc_rename(fcb->fid, ccb->name+2, fcbt->ccb_list->name+2, fname, &new_fid);
+ fcb->fid = new_fid;
+ }
+ else
+ {
+ _asm int 3;
+ /*fcbt = FindFcb(IrpSp->Parameters.SetFile.FileObject);
+
+ p->CurrNameOff = 0;
+ StringCbCopyW(buf, size, fcb->name);
+ p->NewNameOff = wcslen(buf)+1;
+ StringCbCopyNW(buf + p->NewNameOff,
+ size - p->NewNameOff,
+ infoRename->FileName,
+ infoRename->FileNameLength*sizeof(wchar_t));
+ buf[p->NewNameOff+infoRename->FileNameLength] = L'\0';
+ p->NewDirOff = p->NewNameOff + wcslen(buf + p->NewNameOff)+1;
+ StringCbCopyW(buf + p->NewDirOff,
+ size - p->NewDirOff,
+ fcbt->name);*/
+ }
+ SYNC_RET(STATUS_SUCCESS);
+ break;
+
+ case FilePositionInformation:
+ infoPosition = Irp->AssociatedIrp.SystemBuffer;
+ IrpSp->FileObject->CurrentByteOffset = infoPosition->CurrentByteOffset;
+ SYNC_FAIL(STATUS_SUCCESS);
+
+ default:
+ KdPrint(("set unsupp %d type %d\n", fcb->fid, IrpSp->Parameters.SetFile.FileInformationClass));
+ SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
+ }
+
+SYNC_FAIL(STATUS_UNSUCCESSFUL);
+}
+
+dc_break_callback(ULONG fid)
+{
+afs_fcb_t *fcb;
+int pos;
+USHORT len;
+UNICODE_STRING *s;
+
+LOCK_FCB_LIST;
+
+fcb = find_fcb(fid);
+if (!fcb)
+ {
+ UNLOCK_FCB_LIST;
+ return 1; /* we are done with this file */
+ }
+
+ASSERT(fcb->ccb_list);
+/*pos = wcslen(fcb->ccb_list->name);
+if (fcb->ccb_list->name[pos-1] == L'\\')
+ pos--;
+ASSERT(pos);
+while (pos > 0)
+ {
+ if (fcb->ccb_list->name[pos-1] == L'\\')
+ break;
+ pos--;
+ }*/
+
+len = (wcslen(fcb->ccb_list->name) + 10) * sizeof(wchar_t);
+s = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)+len+sizeof(wchar_t));
+s->Length = len;
+s->MaximumLength = len + sizeof(wchar_t);
+s->Buffer = (PWSTR)(s+1);
+
+StringCbCopyW((PWSTR)(s+1), len, fcb->ccb_list->name);
+if (s->Buffer[wcslen(s->Buffer) - 1] != L'\\')
+ StringCbCatW(s->Buffer, len, L"\\");
+pos = wcslen(s->Buffer);
+StringCbCatW(s->Buffer, len, L"jj"); /* FIX: make bogus change notification */
+
+KdPrint(("break callback on %d %ws %ws\n", fid, fcb->ccb_list->name, fcb->ccb_list->name+pos));
+
+FsRtlNotifyFullReportChange(rdrExt->notifyList, &rdrExt->listHead,
+ (PSTRING)s, (USHORT)pos*sizeof(wchar_t), NULL, NULL,
+ FILE_NOTIFY_CHANGE_FILE_NAME/*FILE_NOTIFY_VALID_MASK/*FILE_NOTIFY_CHANGE_FILE_NAME*/, FILE_ACTION_ADDED, NULL);
+
+ExFreePool(s);
+UNLOCK_FCB_LIST;
+return 0;
+}
+
+/**********************************************************
+ * AfsRdrDeviceControl
+ * - handle communication requests from fs, etc.
+ * - handle ioctls
+ **********************************************************/
+NTSTATUS AfsRdrDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+struct KOutEntry *entry;
+NTSTATUS ret;
+struct CbKIn *kin;
+USHORT offset;
+UNICODE_STRING nm;
+void *outPtr;
+ULONG key, code, length;
+
+/* utility ioctls */
+if (DeviceObject == ComDevice &&
+ IrpSp->FileObject->FsContext2 == COMM_IOCTL &&
+ IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_IOCTL)
+ {
+ outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ if (!outPtr)
+ _asm int 3;
+
+ rpc_set_context(IrpSp->FileObject->FsContext);
+ code = uc_ioctl_write(IrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ Irp->AssociatedIrp.SystemBuffer,
+ (ULONG*)&key);
+ length = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ if (!code)
+ code = uc_ioctl_read(key, &length, outPtr);
+ rpc_remove_context();
+
+ switch (code)
+ {
+ case IFSL_SUCCESS:
+ STATUS(STATUS_SUCCESS, length);
+ break;
+ default:
+ STATUS(STATUS_UNSUCCESSFUL, 0);
+ break;
+ }
+ }
+/* downcalls by afsd */
+else if (DeviceObject == ComDevice &&
+ IrpSp->FileObject->FsContext2 == COMM_DOWNCALL &&
+ IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_DOWNCALL)
+ {
+ outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ if (!outPtr)
+ _asm int 3;
+
+ rpc_set_context(IrpSp->FileObject->FsContext);
+ code = rpc_call(IrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ Irp->AssociatedIrp.SystemBuffer,
+ IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ outPtr,
+ &length);
+ rpc_remove_context();
+ switch (code)
+ {
+ case IFSL_SUCCESS:
+ STATUS(STATUS_SUCCESS, length);
+ break;
+ default:
+ STATUS(STATUS_UNSUCCESSFUL, 0);
+ break;
+ }
+ }
+else if (DeviceObject == RdrDevice &&
+ IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFSRDR_GET_PATH)
+ {
+ outPtr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ if (!outPtr)
+ _asm int 3;
+
+ StringCbCopyW(outPtr, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, fcb->ccb_list->name+2);
+
+ STATUS(STATUS_SUCCESS, (wcslen(outPtr)+1)*sizeof(wchar_t));
+ }
+else
+ {
+ rpt0(("devctl", "devctl %d rejected", IrpSp->Parameters.DeviceIoControl.IoControlCode));
+ SYNC_FAIL(STATUS_INVALID_DEVICE_REQUEST);
+ }
+
+ret = Irp->IoStatus.Status;
+COMPLETE;
+return ret;
+}
+
+
+
+/**********************************************************
+ * AfsRdrCleanup
+ * - called when usermode handle count reaches zero
+ **********************************************************/
+NTSTATUS AfsRdrCleanup(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+NTSTATUS ret;
+struct AfsRdrExtension *ext;
+
+//try {
+IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+if (IrpSp->FileObject->FileName.Length == 0)
+ SYNC_FAIL(STATUS_SUCCESS);
+
+ext = ((struct AfsRdrExtension*)RdrDevice->DeviceExtension);
+
+LOCK_FCB_LIST;
+LOCK_PAGING_FCB;
+LOCK_FCB;
+
+FsRtlNotifyCleanup(ext->notifyList, &ext->listHead, IrpSp->FileObject->FsContext2);
+
+CcFlushCache(IrpSp->FileObject->SectionObjectPointer, NULL, 0, NULL);
+
+if (fcb->delPending && !MmFlushImageSection(&(fcb->sectionPtrs), MmFlushForDelete))
+ /* yes, moot at this point */
+ STATUS(STATUS_ACCESS_DENIED, 0);
+else
+ STATUS(STATUS_SUCCESS, 0);
+
+MmFlushImageSection(IrpSp->FileObject->SectionObjectPointer, MmFlushForWrite);
+CcPurgeCacheSection(IrpSp->FileObject->SectionObjectPointer, NULL, 0, TRUE);
+CcUninitializeCacheMap(IrpSp->FileObject, NULL, NULL);
+
+UNLOCK_FCB;
+UNLOCK_PAGING_FCB;
+UNLOCK_FCB_LIST;
+
+/*} except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _asm int 3;
+ STATUS(STATUS_UNSUCCESSFUL, 0);
+ ExReleaseResourceLite(&ext->fcbLock);
+ FsRtlExitFileSystem();
+ }*/
+
+ret = Irp->IoStatus.Status;
+COMPLETE;
+return ret;
+}
+
+
+/**********************************************************
+ * AfsRdrClose
+ * - handle actual unlinking
+ * - handle closing
+ **********************************************************/
+NTSTATUS AfsRdrClose(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+ULONG length;
+wchar_t *name;
+char kill;
+KEVENT ev;
+LARGE_INTEGER timeout;
+afs_ccb_t *ccb, *curr;
+
+if (IrpSp->FileObject->FileName.Length == 0)
+ SYNC_FAIL(STATUS_SUCCESS);
+
+ccb = IrpSp->FileObject->FsContext2;
+LOCK_FCB_LIST;
+
+/* set share correctly so future opens can succeed */
+IoRemoveShareAccess(IrpSp->FileObject, &fcb->share_access);
+ObDereferenceObject(ccb->token);
+
+curr = fcb->ccb_list;
+if (fcb->ccb_list == ccb)
+ fcb->ccb_list = fcb->ccb_list->next;
+else
+ while (curr->next)
+ {
+ if (curr->next == ccb)
+ {
+ curr->next = curr->next->next;
+ break;
+ }
+ curr = curr->next;
+ }
+
+if (!fcb->ccb_list)
+ {
+ uc_close(fcb->fid);
+ if (fcb->delPending)
+ {
+ uc_unlink(ccb->name+2);
+ }
+ ExDeleteResourceLite(&fcb->_resource);
+ ExDeleteResourceLite(&fcb->_pagingIoResource);
+ RtlDeleteElementGenericTable(&rdrExt->fcbTable, &fcb);
+ ExFreeToNPagedLookasideList(&rdrExt->fcbMemList, fcb);
+ }
+
+ExFreePoolWithTag(ccb->name, AFS_RDR_TAG);
+if (ccb->filter && ccb->filter != SEARCH_MATCH_ALL)
+ ExFreePoolWithTag(ccb->filter, AFS_RDR_TAG);
+ExFreeToNPagedLookasideList(&rdrExt->ccbMemList, ccb);
+
+UNLOCK_FCB_LIST;
+
+SYNC_FAIL(STATUS_SUCCESS);
+}
+
+
+/**********************************************************
+ * AfsRdrShutdown
+ * - should flush all data
+ **********************************************************/
+NTSTATUS AfsRdrShutdown(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp)
+{
+_asm int 3;
+STATUS(STATUS_SUCCESS, 0);
+COMPLETE;
+}
+
+
+/**********************************************************
+ * AfsRdrFlushFile
+ * - flushes specified file to userspace and then disk
+ **********************************************************/
+NTSTATUS AfsRdrFlushFile(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+NTSTATUS ret;
+afs_ccb_t *ccb;
+
+/*TRY*/
+IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+if (IrpSp->FileObject->FileName.Length == 0)
+ SYNC_RET(STATUS_INVALID_DEVICE_REQUEST);
+
+ccb = IrpSp->FileObject->FsContext2;
+
+CcFlushCache(&fcb->sectionPtrs, NULL, 0, &Irp->IoStatus);
+
+//SYNC_FAIL2(/*STATUS_LOCK_NOT_GRANTED*//*STATUS_NOT_IMPLEMENTED*/STATUS_SUCCESS, 0);
+
+/*EXCEPT(STATUS_UNSUCCESSFUL, 0);*/
+COMPLETE;
+return Irp->IoStatus.Status;
+}
+
+
+/**********************************************************
+ * AfsRdrLockCtrl
+ * - should handle lock requests
+ **********************************************************/
+NTSTATUS AfsRdrLockCtrl(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp, afs_fcb_t *fcb)
+{
+NTSTATUS ret;
+
+/*TRY*/
+IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+/* complete lock on control device object without processing, as directed */
+if (IrpSp->FileObject->FileName.Length == 0)
+ {
+ rpt0(("lock", "lock granted on root device obj"));
+ SYNC_FAIL(STATUS_SUCCESS);
+ }
+
+SYNC_FAIL2(/*STATUS_LOCK_NOT_GRANTED*//*STATUS_NOT_IMPLEMENTED*/STATUS_SUCCESS, 0);
+
+/*EXCEPT(STATUS_UNSUCCESSFUL, 0);*/
+}
+
+
+/**********************************************************
+ * AfsRdrQueryVol
+ * - handle volume information requests
+ **********************************************************/
+NTSTATUS AfsRdrQueryVol(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp)
+{
+FILE_FS_ATTRIBUTE_INFORMATION *infoAttr;
+FILE_FS_DEVICE_INFORMATION *infoDevice;
+FILE_FS_SIZE_INFORMATION * infoSize;
+FILE_FS_VOLUME_INFORMATION *infoVolume;
+NTSTATUS ret;
+
+TRY
+
+switch (IrpSp->Parameters.QueryVolume.FsInformationClass)
+ {
+ case FileFsAttributeInformation:
+ infoAttr = (FILE_FS_ATTRIBUTE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
+ memset(infoAttr, 0, sizeof(FILE_FS_ATTRIBUTE_INFORMATION));
+ infoAttr->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH; //TODOTODO:?
+ infoAttr->MaximumComponentNameLength = 255; // should this be 255?
+ ///RtlCopyMemory(infoAttr->FileSystemName, L"AFS", 2);
+ ///infoAttr->FileSystemNameLength = 2;
+ //StringCbCopyLen(infoAttr->FileSystemName, IrpSp->Parameters.QueryVolume.Length-sizeof(*infoAttr)-2, L"AFS", &infoAttr->FileSystemNameLength);
+ //IrpSp->Parameters.QueryVolume.Length = 0;
+ //Irp->IoStatus.Information = sizeof(*infoAttr) + (infoAttr->FileSystemNameLength - sizeof(WCHAR));
+ if (sizeof(*infoAttr) + wcslen(AFS_FS_NAME)*sizeof(wchar_t) > IrpSp->Parameters.QueryVolume.Length)
+ {
+ infoAttr->FileSystemNameLength = 0;
+ rpt0(("vol", "overflowing attr buffer %d", IrpSp->Parameters.QueryVolume.Length));
+ SYNC_FAIL2(STATUS_BUFFER_OVERFLOW, sizeof(*infoAttr));
+ }
+ else
+ {
+ infoAttr->FileSystemNameLength = wcslen(AFS_FS_NAME)*sizeof(wchar_t);
+ StringCbCopyW(infoAttr->FileSystemName, IrpSp->Parameters.QueryVolume.Length - sizeof(*infoAttr) + sizeof(WCHAR), AFS_FS_NAME);
+ SYNC_FAIL2(STATUS_SUCCESS, sizeof(*infoAttr) + (infoAttr->FileSystemNameLength - sizeof(WCHAR)));
+ }
+ break;
+
+ case FileFsDeviceInformation:
+ infoDevice = (FILE_FS_DEVICE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
+ memset(infoDevice, 0, sizeof(FILE_FS_DEVICE_INFORMATION));
+ infoDevice->DeviceType = FILE_DEVICE_DISK;//DeviceObject->DeviceType;// FILE_DEVICE_NETWORK_FILE_SYSTEM;
+ infoDevice->Characteristics = DeviceObject->Characteristics;//FILE_DEVICE_IS_MOUNTED /*| FILE_REMOTE_DEVICE*/; // remote device?
+ IrpSp->Parameters.QueryVolume.Length = sizeof(*infoDevice);
+ SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.QueryVolume.Length);
+ break;
+
+ case FileFsSizeInformation:
+ infoSize = (FILE_FS_SIZE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
+ memset(infoSize, 0, sizeof(FILE_FS_SIZE_INFORMATION));
+ infoSize->TotalAllocationUnits.QuadPart = 0x00000000F0000000; //FIX
+ infoSize->AvailableAllocationUnits.QuadPart = 0x00000000E0000000;
+ infoSize->SectorsPerAllocationUnit = 1;
+ infoSize->BytesPerSector = 1;
+ IrpSp->Parameters.QueryVolume.Length = sizeof(*infoSize);
+ SYNC_FAIL2(STATUS_SUCCESS, IrpSp->Parameters.QueryVolume.Length);
+ break;
+
+ case FileFsVolumeInformation:
+ infoVolume = (FILE_FS_VOLUME_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
+ memset(infoVolume, 0, sizeof(FILE_FS_VOLUME_INFORMATION));
+ infoVolume->VolumeCreationTime.QuadPart = AfsTimeToWindowsTime(1080000000);//0x43218765); //TODO:fix
+ infoVolume->VolumeSerialNumber = 0x12345678; //TODO:fix
+ infoVolume->SupportsObjects = FALSE;
+ //StringCbCopyLen(infoVolume->VolumeLabel, IrpSp->Parameters.QueryVolume.Length-sizeof(*infoVolume)-2, L"AfsRed", &infoVolume->VolumeLabelLength);
+ //IrpSp->Parameters.QueryVolume.Length = 0;
+ if (sizeof(*infoVolume) + 12 > IrpSp->Parameters.QueryVolume.Length)
+ {
+ infoVolume->VolumeLabelLength = 0;
+ rpt0(("vol", "overflowing buffer %d", IrpSp->Parameters.QueryVolume.Length));
+ SYNC_FAIL2(STATUS_BUFFER_OVERFLOW, sizeof(*infoVolume));
+ }
+ else
+ {
+ infoVolume->VolumeLabelLength = 12;
+ RtlCopyMemory(infoVolume->VolumeLabel, L"AfsRed", 12);
+ SYNC_FAIL2(STATUS_SUCCESS, sizeof(*infoVolume) + (infoVolume->VolumeLabelLength - sizeof(WCHAR)));
+ }
+ break;
+ //case FileFsFullSizeInformation:
+ //TODO:
+ }
+
+EXCEPT(STATUS_UNSUCCESSFUL, 0);
+
+rpt0(("vol", "vol class %d unknown", IrpSp->Parameters.QueryVolume.FsInformationClass));
+SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
+}
+
+VOID AfsRdrUnload(DRIVER_OBJECT *DriverObject)
+{
+UNICODE_STRING userModeName;
+
+FsRtlNotifyUninitializeSync(&rdrExt->notifyList);
+
+RtlInitUnicodeString(&userModeName, L"\\DosDevices\\afscom");
+IoDeleteSymbolicLink(&userModeName);
+
+/*RtlInitUnicodeString(&userModeName, L"\\DosDevices\\T:");
+IoDeleteSymbolicLink(&userModeName);*/
+
+ExDeleteNPagedLookasideList(&rdrExt->fcbMemList);
+ExDeleteNPagedLookasideList(&rdrExt->ccbMemList);
+
+rpc_shutdown();
+
+IoDeleteDevice(ComDevice);
+IoDeleteDevice(RdrDevice);
+
+#ifdef RPT_ENA
+rptCliClose(REPORT);
+#endif
+
+KdPrint(("RdrUnload exiting.\n"));
+}
+
+
+// handles all non-handled irp's synchronously
+NTSTATUS AfsRdrNull(DEVICE_OBJECT *DeviceObject, IRP *Irp, IO_STACK_LOCATION *IrpSp)
+{
+NTSTATUS ret;
+
+/*TRY
+rpt0(("kunhand", IrpMjFuncDesc[IrpSp->MajorFunction]));*/
+
+SYNC_FAIL(STATUS_NOT_IMPLEMENTED);
+
+/*EXCEPT(STATUS_UNSUCCESSFUL, 0);
+
+ret = Irp->IoStatus.Status;
+COMPLETE_NO_BOOST;
+return ret;*/
+}
+
+NTSTATUS ComDispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp)
+{
+IO_STACK_LOCATION *IrpSp, *IrpSpClient;
+NTSTATUS ret;
+struct ComExtension *ext;
+void *ptr, *ptr2;
+rpc_t find, *find_ptr;
+LARGE_INTEGER timeout;
+struct afsFcb *fcb;
+rpc_t *rpc, **rpcp;
+ULONG len;
+ULONG code, read;
+PACCESS_TOKEN acc_token;
+
+ext = (struct ComExtension *)DeviceObject->DeviceExtension;
+IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+switch (IrpSp->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ IrpSp->FileObject->FsContext = 0;
+ IrpSp->FileObject->FsContext2 = 0;
+ if (IrpSp->FileObject->FileName.Length)
+ {
+ /* ioctls come from fs, vos, bos, etc. using a pre-existing interface */
+ /* downcalls come from afsd, using a new interface */
+ /* upcall hooks come from afsd */
+ if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\ioctl"))
+ IrpSp->FileObject->FsContext2 = COMM_IOCTL;
+ else if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\downcall"))
+ IrpSp->FileObject->FsContext2 = COMM_DOWNCALL;
+ else if (!wcscmp(IrpSp->FileObject->FileName.Buffer, L"\\upcallhook"))
+ IrpSp->FileObject->FsContext2 = COMM_UPCALLHOOK;
+ }
+ if (!IrpSp->FileObject->FsContext2)
+ SYNC_FAIL2(STATUS_INVALID_DEVICE_REQUEST, 0);
+
+ acc_token = SeQuerySubjectContextToken(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+ ASSERT(acc_token);
+ /* SeQueryAuthenticationIdToken */
+ IrpSp->FileObject->FsContext = acc_token;
+ STATUS(STATUS_SUCCESS, FILE_OPENED);
+ break;
+
+ case IRP_MJ_CLEANUP:
+ /* acc_token does not have to be released */
+ case IRP_MJ_CLOSE:
+ STATUS(STATUS_SUCCESS, 0);
+ break;
+
+ case IRP_MJ_WRITE:
+ /* we only process MDL writes */
+ //_asm int 3;
+ if (!Irp->MdlAddress ||
+ !(ptr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority))) /* should be LowPagePriority */
+ SYNC_FAIL(STATUS_INSUFFICIENT_RESOURCES);
+
+ if (!IrpSp->FileObject->FsContext ||
+ !IrpSp->FileObject->FsContext2)
+ SYNC_FAIL(STATUS_INVALID_HANDLE);
+
+ if (IrpSp->FileObject->FsContext2 == COMM_UPCALLHOOK)
+ {
+ rpc_recv(ptr, IrpSp->Parameters.Write.Length);
+ STATUS(STATUS_SUCCESS, IrpSp->Parameters.Write.Length);
+ }
+ else
+ STATUS(STATUS_INVALID_DEVICE_REQUEST, 0);
+ break;
+ case IRP_MJ_READ:
+ if (!Irp->MdlAddress || !(ptr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority))) // should be LowPagePriority
+ _asm int 3;
+
+ if (IrpSp->FileObject->FsContext2 == COMM_UPCALLHOOK)
+ {
+ /*timeout.QuadPart = -10000000L;*/
+ timeout.QuadPart = -100000000L;
+ KeWaitForSingleObject(&comExt->outEvent, Executive, KernelMode, FALSE, &timeout);
+
+ if (!rpc_send(ptr, IrpSp->Parameters.Read.Length, &read))
+ {
+ KeClearEvent(&comExt->outEvent);
+ KeWaitForSingleObject(&comExt->outEvent, Executive, KernelMode/*UserMode*/, FALSE, &timeout);
+ if (!rpc_send(ptr, IrpSp->Parameters.Read.Length, &read))
+ {
+ KeClearEvent(&comExt->outEvent);
+ SYNC_FAIL(STATUS_UNSUCCESSFUL);
+ }
+ }
+ SYNC_FAIL2(STATUS_SUCCESS, read);
+ }
+ else
+ STATUS(STATUS_INVALID_DEVICE_REQUEST, 0);
+ break;
+ case IRP_MJ_DEVICE_CONTROL:
+ return AfsRdrDeviceControl(DeviceObject, Irp, IrpSp, NULL);
+ default:
+ STATUS(STATUS_INVALID_DEVICE_REQUEST, 0);
+ break;
+ }
+
+ret = Irp->IoStatus.Status;
+COMPLETE;
+return ret;
+}
+
+
+// handles all irp's for primary (fs) device
+NTSTATUS Dispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp)
+{
+IO_STACK_LOCATION *IrpSp;
+NTSTATUS ret;
+afs_fcb_t *fcb;
+afs_ccb_t *ccb;
+
+if (DeviceObject->DeviceType == FILE_DEVICE_DATALINK)
+ return ComDispatch(DeviceObject, Irp);
+
+IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+rpt4(("irp", "%s min %d on %d (%ws) %x %x", IrpMjFuncDesc[IrpSp->MajorFunction], IrpSp->MinorFunction, 0/*ExtractFid(IrpSp->FileObject->FsContext)*/, IrpSp->FileObject->FileName.Buffer, IrpSp->Flags, IrpSp->Parameters.Create.Options));
+
+fcb = IrpSp->FileObject->FsContext;//FindFcb(IrpSp->FileObject);
+if (IrpSp->MajorFunction != IRP_MJ_CREATE)
+ ASSERT(fcb);
+
+if (IrpSp->FileObject && IrpSp->FileObject->FsContext2)
+ {
+ ccb = IrpSp->FileObject->FsContext2;
+ rpc_set_context(ccb->token);
+ }
+
+switch (IrpSp->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ ret = AfsRdrCreate(DeviceObject, Irp, IrpSp, NULL); break;
+ case IRP_MJ_DIRECTORY_CONTROL:
+ ret = AfsRdrDirCtrl(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_READ:
+ ret = AfsRdrRead(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_WRITE:
+ ret = AfsRdrWrite(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_CLOSE:
+ ret = AfsRdrClose(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_QUERY_INFORMATION:
+ ret = AfsRdrQueryInfo(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_DEVICE_CONTROL:
+ ret = AfsRdrDeviceControl(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_CLEANUP:
+ ret = AfsRdrCleanup(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_LOCK_CONTROL:
+ ret = AfsRdrLockCtrl(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_QUERY_VOLUME_INFORMATION:
+ ret = AfsRdrQueryVol(DeviceObject, Irp, IrpSp); break;
+ case IRP_MJ_SHUTDOWN:
+ ret = AfsRdrShutdown(DeviceObject, Irp, IrpSp); break;
+ case IRP_MJ_FILE_SYSTEM_CONTROL:
+ if (IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
+ (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1 ||
+ IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2 ||
+ IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK ||
+ IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK))
+ STATUS(STATUS_OPLOCK_NOT_GRANTED, 0);
+ else
+ STATUS(STATUS_INVALID_DEVICE_REQUEST/*STATUS_NOT_IMPLEMENTED*//*STATUS_INVALID_PARAMETER*/, 0);
+ ret = Irp->IoStatus.Status;
+ goto complete;
+ case IRP_MJ_SET_INFORMATION:
+ ret = AfsRdrSetInfo(DeviceObject, Irp, IrpSp, fcb); break;
+ case IRP_MJ_FLUSH_BUFFERS:
+ ret = AfsRdrFlushFile(DeviceObject, Irp, IrpSp, fcb); break;
+ default:
+ ret = AfsRdrNull(DeviceObject, Irp, IrpSp); break;
+ }
+rpc_remove_context();
+return ret;
+
+complete:
+rpc_remove_context();
+COMPLETE;
+return ret;
+}
+
+BOOLEAN
+fastIoRead (
+ IN struct _FILE_OBJECT *FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN ULONG LockKey,
+ OUT PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject
+ )
+{
+BOOLEAN ret;
+ULONG adj_len;
+afs_fcb_t *fcb;
+
+fcb = FileObject->FsContext;
+ASSERT(fcb);
+
+FsRtlEnterFileSystem();
+LOCK_PAGING_FCB;
+adj_len = Length;
+if (FileOffset->QuadPart > fcb->FileSize.QuadPart)
+ {
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ IoStatus->Status = STATUS_END_OF_FILE;
+ IoStatus->Information = 0;
+ return TRUE;
+ }
+if (FileOffset->QuadPart + Length > fcb->FileSize.QuadPart)
+ adj_len = (ULONG)(fcb->FileSize.QuadPart - FileOffset->QuadPart);
+
+try
+ {
+ ret = CcCopyRead(FileObject, FileOffset, adj_len, Wait, Buffer, IoStatus);
+ /*if (IoStatus->Status == STATUS_SUCCESS &&
+ (adj_len < Length))
+ IoStatus->Status = STATUS_END_OF_FILE;*/
+// KdPrint(("read %x at %x fast done %x\n", Length, (ULONG)FileOffset->QuadPart, IoStatus->Information));
+ FileObject->CurrentByteOffset.QuadPart += IoStatus->Information;
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ }
+except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ return FALSE;
+ }
+return ret;
+}
+
+BOOLEAN
+fastIoWrite (
+ IN struct _FILE_OBJECT *FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN ULONG LockKey,
+ OUT PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus,
+ IN struct _DEVICE_OBJECT *DeviceObject
+ )
+{
+BOOLEAN ret;
+LARGE_INTEGER adj_end;
+afs_fcb_t *fcb;
+
+fcb = FileObject->FsContext;
+ASSERT(fcb);
+
+FsRtlEnterFileSystem();
+LOCK_PAGING_FCB;
+
+if (FileOffset->QuadPart + Length > fcb->FileSize.QuadPart)
+ {
+ adj_end.QuadPart = fcb->FileSize.QuadPart + Length;
+ fcb->AllocationSize = fcb->FileSize = fcb->ValidDataLength = adj_end;
+ LOCK_FCB;
+ try
+ {
+ CcSetFileSizes(FileObject, (CC_FILE_SIZES*)&fcb->AllocationSize);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ UNLOCK_FCB;
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ return FALSE;
+ }
+ UNLOCK_FCB;
+ }
+
+try
+ {
+ ret = CcCopyWrite(FileObject, FileOffset, Length, Wait, Buffer);
+ IoStatus->Status = ret?STATUS_SUCCESS:STATUS_UNSUCCESSFUL;
+ IoStatus->Information = ret?Length:0;
+// KdPrint(("write %x at %x fast done\n", Length, (ULONG)FileOffset->QuadPart));
+ FileObject->CurrentByteOffset.QuadPart += IoStatus->Information;
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ }
+except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ UNLOCK_PAGING_FCB;
+ FsRtlExitFileSystem();
+ return FALSE;
+ }
+return ret;
+}
+
+RTL_GENERIC_COMPARE_RESULTS FcbCompareRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID FirstStruct, PVOID SecondStruct)
+ {
+ afs_fcb_t *p1, *p2;
+
+ p1 = (void*)*(afs_fcb_t**)FirstStruct; p2 = (void*)*(afs_fcb_t**)SecondStruct;
+ if (p1->fid < p2->fid)
+ return GenericLessThan;
+ if (p1->fid > p2->fid)
+ return GenericGreaterThan;
+ return GenericEqual;
+ }
+
+RTL_GENERIC_COMPARE_RESULTS ReqCompareRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID FirstStruct, PVOID SecondStruct)
+ {
+ rpc_t *p1, *p2;
+
+ p1 = *(rpc_t**)FirstStruct; p2 = *(rpc_t**)SecondStruct;
+ if (p1->key < p2->key)
+ return GenericLessThan;
+ if (p1->key > p2->key)
+ return GenericGreaterThan;
+ return GenericEqual;
+ }
+
+PVOID AllocateRoutine(struct _RTL_GENERIC_TABLE *Table, CLONG ByteSize)
+ {
+ PVOID ret;
+ ret = ExAllocatePoolWithTag(NonPagedPool, ByteSize, AFS_RDR_TAG);
+ ASSERT(ret);
+ RtlZeroMemory(ret, ByteSize);
+ return ret;
+ }
+
+VOID FreeRoutine(struct _RTL_GENERIC_TABLE *Table, PVOID Buffer)
+ {
+ ExFreePoolWithTag(Buffer, AFS_RDR_TAG);
+ }
+
+//KSPIN_LOCK rpc_lock;
+//KIRQL irql;
+FAST_MUTEX rpc_lock;
+
+void ifs_lock_rpcs()
+{
+ExAcquireFastMutex(&rpc_lock);
+//KeAcquireSpinLock(&rpc_lock, &irql);
+}
+
+void ifs_unlock_rpcs()
+{
+ExReleaseFastMutex(&rpc_lock);
+//KeReleaseSpinLock(&rpc_lock, irql);
+}
+
+NTSTATUS DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
+{
+NTSTATUS err;
+UNICODE_STRING rdrName, comName, userModeName, userModeCom;
+int x;
+IO_STATUS_BLOCK status;
+FAST_IO_DISPATCH *fastIoDispatch;
+
+//_asm int 3;
+
+//try {
+#ifdef RPT_ENA
+REPORT = rptOpen(NULL, "afskern");
+#endif
+rpt0(("init", "rpt initialized at %x", REPORT));
+
+RtlInitUnicodeString(&rdrName, L"\\Device\\afsrdr");
+RtlInitUnicodeString(&comName, L"\\Device\\afscom");
+
+rpt0(("init", "kern initializing"));
+//KeInitializeSpinLock(&rpc_lock);
+ExInitializeFastMutex(&rpc_lock);
+
+IoAllocateDriverObjectExtension(DriverObject, (void *)0x394389f7, sizeof(FAST_IO_DISPATCH), &fastIoDispatch);
+RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
+fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
+fastIoDispatch->FastIoRead = fastIoRead;
+fastIoDispatch->FastIoWrite = fastIoWrite;
+DriverObject->FastIoDispatch = fastIoDispatch;
+
+for (x = 0; x < IRP_MJ_MAXIMUM_FUNCTION; x++)
+ DriverObject->MajorFunction[x] = Dispatch;
+DriverObject->DriverUnload = AfsRdrUnload;
+
+err = IoCreateDevice(DriverObject, sizeof(struct AfsRdrExtension)*2, &rdrName, FILE_DEVICE_NETWORK_FILE_SYSTEM, /*FILE_REMOTE_DEVICE*/0, FALSE, &RdrDevice);
+if (!NT_SUCCESS(STATUS_SUCCESS))
+ return STATUS_UNSUCCESSFUL;
+err = IoCreateDevice(DriverObject, sizeof(struct ComExtension)*2, &comName, FILE_DEVICE_DATALINK, 0, FALSE, &ComDevice);
+if (!NT_SUCCESS(STATUS_SUCCESS))
+ return STATUS_UNSUCCESSFUL;
+
+RdrDevice->Flags |= DO_DIRECT_IO;
+RdrDevice->StackSize = 5; /* could this be zero? */
+rdrExt = ((struct AfsRdrExtension*)RdrDevice->DeviceExtension);
+RtlZeroMemory(rdrExt, sizeof(struct AfsRdrExtension));
+
+/* could raise exception */
+FsRtlNotifyInitializeSync(&rdrExt->notifyList);
+InitializeListHead(&rdrExt->listHead);
+
+rdrExt->callbacks.AcquireForLazyWrite = lazyWriteLock;
+rdrExt->callbacks.ReleaseFromLazyWrite = lazyWriteUnlock;
+rdrExt->callbacks.AcquireForReadAhead = readAheadLock;
+rdrExt->callbacks.ReleaseFromReadAhead = readAheadUnlock;
+ExInitializeNPagedLookasideList(&rdrExt->fcbMemList, NULL, NULL, 0, sizeof(afs_fcb_t), AFS_RDR_TAG, 0);
+ExInitializeNPagedLookasideList(&rdrExt->ccbMemList, NULL, NULL, 0, sizeof(afs_ccb_t), AFS_RDR_TAG, 0);
+ExInitializeFastMutex(&rdrExt->fcbLock);
+RtlInitializeGenericTable(&rdrExt->fcbTable, FcbCompareRoutine, AllocateRoutine, FreeRoutine, NULL);
+
+
+ComDevice->Flags |= DO_DIRECT_IO;
+ComDevice->StackSize = 5; // ??
+comExt = ((struct ComExtension*)ComDevice->DeviceExtension);
+RtlZeroMemory(comExt, sizeof(struct ComExtension));
+
+//ExInitializeNPagedLookasideList(&comExt->outMemList, NULL, NULL, 0, sizeof(struct KOutEntry)+100, AFS_RDR_TAG, 0);
+InitializeListHead(&comExt->outReqList);
+KeInitializeSpinLock(&comExt->outLock);
+ExInitializeFastMutex(&comExt->inLock);
+RtlInitializeGenericTable(&comExt->inTable, ReqCompareRoutine, AllocateRoutine, FreeRoutine, NULL);
+KeInitializeEvent(&comExt->outEvent, NotificationEvent, TRUE);
+KeInitializeEvent(&comExt->cancelEvent, NotificationEvent, TRUE);
+
+comExt->rdr = rdrExt;
+rdrExt->com = comExt;
+
+RtlInitUnicodeString(&userModeCom, L"\\DosDevices\\afscom");
+err = IoCreateSymbolicLink(&userModeCom, &comName);
+
+/*RtlInitUnicodeString(&rdrName, L"\\Device\\afsrdr\\1\\CITI.UMICH.EDU");
+RtlInitUnicodeString(&userModeName, L"\\DosDevices\\W:");
+err = IoCreateSymbolicLink(&userModeName, &rdrName);*/
+
+/*} except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _asm int 3;
+ //logerror();
+ return -1;
+ }*/
+
+KdPrint(("DriverEntry exiting.\n"));
+return STATUS_SUCCESS;
+}
--- /dev/null
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+/* versioning history
+ *
+ * 03-jun 2005 (eric williams) entered into versioning
+ */
+
+#include <ntifs.h>
+
+#define rpt0(args)
+#define rpt1(args)
+#define rpt2(args)
+#define rpt3(args)
+#define rpt4(args)
+#define rpt5(args)
+
+struct AfsRdrExtension
+{
+struct ComExtension *com;
+KMUTEX protectMutex;
+PNOTIFY_SYNC notifyList;
+LIST_ENTRY listHead;
+NPAGED_LOOKASIDE_LIST fcbMemList;
+FAST_MUTEX fcbLock;
+NPAGED_LOOKASIDE_LIST ccbMemList;
+RTL_GENERIC_TABLE fcbTable;
+CACHE_MANAGER_CALLBACKS callbacks;
+};
+
+struct ComExtension
+{
+struct AfsRdrExtension *rdr;
+LIST_ENTRY outReqList;
+KSPIN_LOCK outLock;
+RTL_GENERIC_TABLE inTable;
+FAST_MUTEX inLock;
+KEVENT outEvent, cancelEvent;
+};
+
+extern struct AfsRdrExtension *rdrExt;
+extern struct ComExtension *comExt;
+
+
+void ifs_lock_rpcs();
+void ifs_unlock_rpcs();
--- /dev/null
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+/* versioning history
+ *
+ * 03-jun 2005 (eric williams) entered into versioning
+ */
+
+#ifdef RPC_KERN
+#include <ntifs.h>
+#include "ifs_rpc.h"
+#include "afsrdr.h"
+#else
+#include "ifs_rpc.h"
+#endif
+#include "kif.h"
+
+/* general internal functions */
+rpc_t *rpc_create(int size_hint);
+void rpc_destroy(rpc_t *rpc);
+int rpc_marshal_long(rpc_t *rpc, ULONG data);
+int rpc_marshal_longlong(rpc_t *rpc, LARGE_INTEGER data);
+int rpc_marshal_wstr(rpc_t *rpc, WCHAR *str);
+int rpc_unmarshal_long(rpc_t *rpc, ULONG *data);
+int rpc_unmarshal_longlong(rpc_t *rpc, LARGE_INTEGER *data);
+int rpc_unmarshal_wstr(rpc_t *rpc, WCHAR *str);
+
+/* kernel-queue specific internal functions */
+#ifdef RPC_KERN
+int rpc_queue(rpc_t *rpc);
+rpc_queue_bulk(rpc_t *rpc, char *out_bulk, ULONG out_len, char *in_bulk, ULONG in_len);
+rpc_cancel(rpc_t *rpc);
+rpc_send_reg(rpc_t *rpc, char *out_buf);
+rpc_queue_bulk_mdl(rpc_t *rpc, MDL *mdl);
+rpc_t *rpc_find(int id);
+rpc_t *rpc_upgrade(rpc_t *rpc, int old_status, int new_status);
+rpc_wait(rpc_t *rpc, BOOLEAN long_op);
+rpc_send_mdl(rpc_t *rpc, char *out_buf);
+#endif
+
+/* internal timing functions (not used) */
+#ifdef RPC_KERN
+#define TIMING_START() LARGE_INTEGER start, stop; \
+ start.QuadPart = KeQueryInterruptTime();
+#define TIMING_END(name) stop.QuadPart = KeQueryInterruptTime(); \
+ rpt5((name, "%s %d", name, (ULONG)(stop.QuadPart - start.QuadPart)));
+#endif
+
+
+/* rpc security kernel functions */
+#ifdef RPC_KERN
+struct rpc_cred_map_entry
+ {
+ void *token;
+ PETHREAD thread;
+ };
+
+struct rpc_cred_map_entry cred_map[20];
+rpc_t *rpc_list_head = NULL;
+
+rpc_set_context(void *context)
+ {
+ int x, empty, ret;
+ PETHREAD thd;
+
+ thd = PsGetCurrentThread();
+ empty = -1;
+ ret = 0;
+
+ // LOCKLOCK
+ for (x = 0; x < 20; x++)
+ {
+ if (cred_map[x].thread == NULL)
+ empty = x;
+ if (cred_map[x].thread == thd)
+ {
+ cred_map[x].token = context;
+ goto done;
+ }
+ }
+ if (empty != -1)
+ {
+ cred_map[empty].thread = thd;
+ cred_map[empty].token = context;
+ }
+ else
+ ret = -1;
+
+ done:
+ // UNLOCKUNLOCK
+ return ret;
+ }
+
+void *rpc_get_context()
+ {
+ int x;
+ PETHREAD thd;
+
+ thd = PsGetCurrentThread();
+
+ // no lock
+ for (x = 0; x < 20; x++)
+ if (cred_map[x].thread == thd)
+ return cred_map[x].token;
+ // no unlock
+ return NULL;
+ }
+
+rpc_remove_context()
+ {
+ int x;
+ PETHREAD thd;
+
+ thd = PsGetCurrentThread();
+ // no lock
+ for (x = 0; x < 20; x++)
+ if (cred_map[x].thread == thd)
+ {
+ cred_map[x].token = NULL;
+ cred_map[x].thread = NULL;
+ return 0;
+ }
+
+ // no unlock
+ return -1;
+ }
+#endif
+
+
+/* rpc internal functions for kernel */
+#ifdef RPC_KERN
+rpc_t *rpc_create(int size_hint)
+ {
+ ULONG size;
+ rpc_t *rpc;
+ SECURITY_SUBJECT_CONTEXT subj_context;
+ PACCESS_TOKEN acc_token;
+ LUID auth_id;
+ LARGE_INTEGER user_id;
+ NTSTATUS status;
+ HANDLE token;
+
+ token = rpc_get_context();
+ ASSERT(token);
+ status = SeQueryAuthenticationIdToken(token, &auth_id);
+
+ user_id.LowPart = auth_id.LowPart;
+ user_id.HighPart = auth_id.HighPart;
+
+ ifs_lock_rpcs();
+
+ if (!(rpc = rpc_upgrade(NULL, 0, 1)))
+ {
+ size = sizeof(rpc_t) + 4096*10;
+ rpc = ExAllocatePoolWithTag(NonPagedPool, size, 0x1234);
+ if (!rpc)
+ _asm int 3;
+ memset(rpc, 0, size);
+ rpc->next = rpc_list_head;
+ rpc_list_head = rpc;
+ rpc_upgrade(rpc, 0, 1);
+ }
+
+ rpc->out_buf = rpc->out_pos = (char*)(rpc+1);
+ rpc->in_buf = rpc->in_pos = ((char*)(rpc+1))+2048*10;
+
+ rpc->key = rand() + 10;
+ rpc_marshal_long(rpc, rpc->key);
+ rpc->bulk_out_len = (ULONG*)rpc->out_pos;
+ rpc_marshal_long(rpc, 0);
+
+ /*SeCaptureSubjectContext(&subj_context);
+ acc_token = SeQuerySubjectContextToken(&subj_context);
+ status = SeQueryAuthenticationIdToken(acc_token, &auth_id);*/
+ /**token = rpc_get_context();
+ ASSERT(token);
+ status = SeQueryAuthenticationIdToken(token, &auth_id);
+
+ user_id.LowPart = auth_id.LowPart;
+ user_id.HighPart = auth_id.HighPart;
+ SeReleaseSubjectContext(&subj_context);*/
+
+ rpc_marshal_longlong(rpc, user_id);
+
+ ifs_unlock_rpcs();
+
+ return rpc;
+ }
+
+void rpc_destroy(rpc_t *rpc)
+ {
+ rpc_t *curr;
+ int count;
+
+ /*ExFreePoolWithTag(rpc, 0x1234);*/
+ ifs_lock_rpcs();
+
+ if (rpc_upgrade(rpc, -1, 0))
+ ;
+
+ ifs_unlock_rpcs();
+ }
+#endif
+
+
+/* rpc internal functions for usermode */
+#ifndef RPC_KERN
+rpc_t *rpc_create(int size_hint)
+ {
+ ULONG size;
+ rpc_t *rpc;
+ ULONG status;
+
+ size = sizeof(rpc_t) + 4096;
+ rpc = malloc(size);
+ if (!rpc)
+ _asm int 3;
+ memset(rpc, 0, size);
+
+ rpc->out_buf = rpc->out_pos = (char*)(rpc+1);
+ rpc->in_buf = rpc->in_pos = ((char*)(rpc+1))+2048;
+
+ rpc->key = rand() + 10;
+ rpc_marshal_long(rpc, rpc->key);
+
+ return rpc;
+ }
+
+void rpc_destroy(rpc_t *rpc)
+ {
+ if (!rpc)
+ return;
+ //_asm int 3;
+
+ free(rpc);
+ }
+
+rpc_transact(rpc_t *rpc)
+ {
+ HANDLE hf;
+ int ret;
+ ULONG header_len;
+ DWORD err, read = 0;
+
+ if (!rpc)
+ return IFSL_GENERIC_FAILURE;
+
+ header_len = rpc->out_pos - rpc->out_buf;
+
+ read = 2048;
+ return ifs_TransactRpc(rpc->out_buf, header_len, rpc->in_buf, &read);
+ }
+#endif
+
+
+/* upcall stubs */
+#ifdef RPC_KERN
+uc_namei(WCHAR *name, ULONG *fid)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ MDL *mdl;
+ TIMING_START();
+ /* put namei cache here */
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_NAMEI);
+ rpc_marshal_long(rpc, wcslen(name));
+
+ rpc_queue_bulk(rpc, (void*)name, (wcslen(name)+1)*sizeof(wchar_t), NULL, 0);
+
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel namei"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, fid);
+
+ rpc_destroy(rpc);
+ TIMING_END("namei");
+ return status;
+ }
+
+uc_check_access(ULONG fid, ULONG access, ULONG *granted)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_CHECK_ACCESS);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_long(rpc, access);
+
+ rpc_queue(rpc);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel access"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, granted);
+
+ rpc_destroy(rpc);
+ TIMING_END("access");
+ return status;
+ }
+
+uc_create(WCHAR *name, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_CREATE);
+ rpc_marshal_long(rpc, attribs);
+ rpc_marshal_longlong(rpc, alloc);
+ rpc_marshal_long(rpc, access);
+
+ rpc_queue_bulk(rpc, (void*)name, (wcslen(name)+1)*sizeof(wchar_t), NULL, 0);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel create"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, granted);
+ rpc_unmarshal_long(rpc, fid);
+
+ rpc_destroy(rpc);
+ TIMING_END("create");
+ return status;
+ }
+
+uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation, LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_STAT);
+ rpc_marshal_long(rpc, fid);
+
+ rpc_queue(rpc);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel stat"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, attribs);
+ rpc_unmarshal_longlong(rpc, size);
+ rpc_unmarshal_longlong(rpc, creation);
+ rpc_unmarshal_longlong(rpc, access);
+ rpc_unmarshal_longlong(rpc, change);
+ rpc_unmarshal_longlong(rpc, written);
+
+ rpc_destroy(rpc);
+ TIMING_END("stat");
+ return status;
+ }
+
+uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access, LARGE_INTEGER change, LARGE_INTEGER written)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_SETINFO);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_long(rpc, attribs);
+ rpc_marshal_longlong(rpc, creation);
+ rpc_marshal_longlong(rpc, access);
+ rpc_marshal_longlong(rpc, change);
+ rpc_marshal_longlong(rpc, written);
+
+
+ rpc_queue(rpc);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel setinfo"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+
+ rpc_destroy(rpc);
+ TIMING_END("setinfo");
+ return status;
+ }
+
+uc_trunc(ULONG fid, LARGE_INTEGER size)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_TRUNC);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_longlong(rpc, size);
+
+ rpc_queue(rpc);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel trunc"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+
+ rpc_destroy(rpc);
+ TIMING_END("trunc");
+ return status;
+ }
+
+uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_READ);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_longlong(rpc, offset);
+ rpc_marshal_long(rpc, length);
+
+ rpc_queue_bulk(rpc, NULL, 0, data, length);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel read"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, read);
+
+ rpc_destroy(rpc);
+ TIMING_END("read");
+ return status;
+ }
+
+/*uc_read_mdl(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, MDL *data)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_READ_BULK);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_longlong(rpc, offset);
+ rpc_marshal_long(rpc, length);
+
+ rpc_queue_bulk_mdl(rpc, data);
+ if (!rpc_wait(rpc, 1))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel read mdl"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, read);
+
+ rpc_destroy(rpc);
+ TIMING_END("read_mdl");
+ return status;
+ }*/
+
+uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_WRITE);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_longlong(rpc, offset);
+ rpc_marshal_long(rpc, length);
+
+ rpc_queue_bulk(rpc, data, length, NULL, 0);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel write"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, written);
+
+ rpc_destroy(rpc);
+ TIMING_END("write");
+ return status;
+ }
+
+/*uc_write_mdl(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, MDL *data)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_WRITE_BULK);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_longlong(rpc, offset);
+ rpc_marshal_long(rpc, length);
+
+ rpc_queue_bulk_mdl(rpc, data);
+ if (!rpc_wait(rpc, 1))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel write mdl"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, written);
+
+ rpc_destroy(rpc);
+ TIMING_END("write_mdl");
+ return status;
+ }*/
+
+uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_READDIR);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_longlong(rpc, cookie_in);
+ rpc_marshal_wstr(rpc, filter);
+ rpc_marshal_long(rpc, *len);
+
+ rpc_queue_bulk(rpc, NULL, 0, data, *len);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel readdir"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, count);
+ rpc_unmarshal_long(rpc, len);
+
+ rpc_destroy(rpc);
+ TIMING_END("readdir");
+ return status;
+ }
+
+uc_close(ULONG fid)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_CLOSE);
+ rpc_marshal_long(rpc, fid);
+
+ rpc_queue(rpc);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel close"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+
+ rpc_destroy(rpc);
+ TIMING_END("close");
+ return status;
+ }
+
+uc_unlink(WCHAR *name)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_UNLINK);
+ rpc_marshal_wstr(rpc, name);
+
+ rpc_queue(rpc);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel unlink"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+
+ rpc_destroy(rpc);
+ TIMING_END("unlink");
+ return status;
+ }
+
+uc_ioctl_write(ULONG length, char *data, ULONG *key)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_IOCTL_WRITE);
+ rpc_marshal_long(rpc, length);
+
+ rpc_queue_bulk(rpc, data, length, NULL, 0);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel ioctl write"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, key);
+
+ rpc_destroy(rpc);
+ TIMING_END("ioctl_write");
+ return status;
+ }
+
+uc_ioctl_read(ULONG key, ULONG *length, char *data)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_IOCTL_READ);
+ rpc_marshal_long(rpc, key);
+
+ rpc_queue_bulk(rpc, NULL, 0, data, *length);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel ioctl read"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, length);
+
+ rpc_destroy(rpc);
+ TIMING_END("ioctl_read");
+ return status;
+ }
+
+uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid)
+ {
+ rpc_t *rpc;
+ ULONG status;
+ TIMING_START();
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_RENAME);
+ rpc_marshal_long(rpc, fid);
+ rpc_marshal_wstr(rpc, curr);
+ rpc_marshal_wstr(rpc, new_dir);
+ rpc_marshal_wstr(rpc, new_name);
+
+ rpc_queue(rpc);
+ if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
+ {
+ rpc_cancel(rpc);
+ rpt0(("cancel", "cancel rename"));
+ return IFSL_RPC_TIMEOUT;
+ }
+
+ rpc_unmarshal_long(rpc, &status);
+ rpc_unmarshal_long(rpc, new_fid);
+
+ rpc_destroy(rpc);
+ TIMING_END("rename");
+ return status;
+ }
+#endif
+
+
+/* downcall stubs */
+#ifndef RPC_KERN
+dc_break_callback(ULONG fid)
+ {
+ rpc_t *rpc;
+ ULONG status;
+
+ rpc = rpc_create(0);
+
+ rpc_marshal_long(rpc, RPC_BREAK_CALLBACK);
+ rpc_marshal_long(rpc, fid);
+ if (!rpc_transact(rpc))
+ {
+ rpc_destroy(rpc);
+ return IFSL_GENERIC_FAILURE;
+ }
+ rpc_unmarshal_long(rpc, &status);
+ rpc_destroy(rpc);
+ return status;
+ }
+#endif
+
+
+/* rpc packing function */
+rpc_marshal_long(rpc_t *rpc, ULONG data)
+ {
+ memcpy(rpc->out_pos, &data, sizeof(ULONG));
+ rpc->out_pos += sizeof(ULONG);
+ return 0;
+ }
+
+rpc_marshal_longlong(rpc_t *rpc, LARGE_INTEGER data)
+ {
+ memcpy(rpc->out_pos, &data, sizeof(LARGE_INTEGER));
+ rpc->out_pos += sizeof(LARGE_INTEGER);
+ return 0;
+ }
+
+rpc_marshal_wstr(rpc_t *rpc, WCHAR *str)
+ {
+ long len;
+ len = wcslen(str);
+ rpc_marshal_long(rpc, len);
+ memcpy(rpc->out_pos, str, len*sizeof(WCHAR));
+ rpc->out_pos += len*sizeof(WCHAR);
+ return 0;
+ }
+
+
+rpc_unmarshal_long(rpc_t *rpc, ULONG *data)
+ {
+ memcpy(data, rpc->in_pos, sizeof(ULONG));
+ rpc->in_pos += sizeof(ULONG);
+ return 0;
+ }
+
+rpc_unmarshal_longlong(rpc_t *rpc, LARGE_INTEGER *data)
+ {
+ memcpy(data, rpc->in_pos, sizeof(LARGE_INTEGER));
+ rpc->in_pos += sizeof(LARGE_INTEGER);
+ return 0;
+ }
+
+rpc_unmarshal_wstr(rpc_t *rpc, WCHAR *str)//, int len)
+ {
+ long len;
+ rpc_unmarshal_long(rpc, &len);
+ memcpy(str, rpc->in_pos, len*sizeof(WCHAR));
+ rpc->in_pos += len*sizeof(WCHAR);
+ str[len] = L'\0';
+ return 0;
+ }
+
+
+/* kernel-queue management functions */
+#ifdef RPC_KERN
+rpc_t *rpc_find(int id)
+ {
+ rpc_t *curr;
+
+ curr = rpc_list_head;
+ while (curr)
+ {
+ if (curr->key == id && curr->status != 0)
+ return curr;
+ curr = curr->next;
+ }
+ return NULL;
+ }
+
+rpc_t *rpc_upgrade(rpc_t *rpc, int old_status, int new_status)
+ {
+ rpc_t *curr;
+
+ if (rpc)
+ {
+ ASSERT(!old_status || rpc_find(rpc->key));
+ if (old_status != -1 && rpc->status != old_status)
+ return NULL;
+ curr = rpc;
+ }
+ else
+ {
+ curr = rpc_list_head;
+ while (curr)
+ {
+ if (old_status == -1 || curr->status == old_status)
+ break;
+ curr = curr->next;
+ }
+ }
+
+ if (!curr)
+ return NULL;
+
+ ASSERT(old_status == -1 || curr->status == old_status);
+ curr->status = new_status;
+
+ return curr;
+ }
+
+rpc_queue(rpc_t *rpc)
+ {
+ int ret;
+
+ ifs_lock_rpcs();
+
+ KeInitializeEvent(&rpc->ev, NotificationEvent, FALSE);
+ ret = (rpc_upgrade(rpc, 1, 2) != NULL);
+ KeSetEvent(&comExt->outEvent, 0, FALSE);
+
+ ifs_unlock_rpcs();
+
+ return ret;
+ }
+
+rpc_cancel(rpc_t *rpc)
+ {
+ rpc_destroy(rpc);
+ //ExAcquireFastMutex(&ext->inLock);
+ /*ifs_lock_rpcs();
+ if (rpc_upgrade(rpc, -1, 0))
+ rpc_destroy(rpc);
+ ifs_unlock_rpcs();*/
+ //RtlDeleteElementGenericTable(&ext->inTable, (void*)&rpc);
+ //ExReleaseFastMutex(&ext->inLock);
+ }
+
+rpc_shutdown()
+ {
+ rpc_t *curr, *next;
+
+ ifs_lock_rpcs();
+
+ curr = rpc_list_head;
+ while (curr)
+ {
+ next = curr->next;
+ ExFreePoolWithTag(curr, 0x1234);
+ curr = next;
+ }
+ rpc_list_head = NULL;
+
+ ifs_unlock_rpcs();
+ }
+
+rpc_wait(rpc_t *rpc, BOOLEAN long_op)
+ {
+ NTSTATUS ret;
+ LARGE_INTEGER timeout;
+ //p->FsContext = (ULONG)&ev;
+
+ if (long_op)
+ timeout.QuadPart = -600000000L; /* 60 seconds 60L*1000000L */
+ else
+ timeout.QuadPart = -200000000L; /* 20 seconds 20L*1000000L */
+
+ do
+ ret = KeWaitForSingleObject(&rpc->ev, Executive, KernelMode, FALSE, &timeout);
+ while (ret != STATUS_SUCCESS);// && ret != STATUS_TIMEOUT);
+
+ /*if (KeReadStateEvent(&rpc->ev) == 0)
+ _asm int 3;*/
+ if (rpc->status == 5)
+ return 0;
+
+ if (ret == STATUS_SUCCESS)
+ return 1;
+ _asm int 3;
+ return 0;
+ }
+
+rpc_queue_bulk(rpc_t *rpc, char *out_bulk, ULONG out_len, char *in_bulk, ULONG in_len)
+ {
+ rpc->bulk_out = out_bulk;
+ *rpc->bulk_out_len = out_len;
+ rpc->bulk_in = in_bulk;
+ rpc->bulk_in_max = in_len;
+ return rpc_queue(rpc);
+ }
+
+/*rpc_queue_bulk_mdl(rpc_t *rpc, MDL *bulk)
+ {
+ rpc->bulk_mdl = bulk;
+ *rpc->bulk_out_len = 0xFFFFFFFC;
+ rpc->bulk_in = 0;
+ return rpc_queue(rpc);
+ }*/
+
+rpc_get_len(rpc_t *rpc)
+ {
+ if (*rpc->bulk_out_len != 0xFFFFFFFC)
+ return rpc->out_pos - rpc->out_buf + *rpc->bulk_out_len + sizeof(ULONG);
+ else
+ return rpc->out_pos - rpc->out_buf + sizeof(ULONG);
+ }
+
+rpc_send(char *out_buf, int out_len, int *out_written)
+ {
+ rpc_t *rpc;
+ int ret, mdl;
+ ULONG header_len;
+
+ restart:
+
+ ifs_lock_rpcs();
+ rpc = rpc_upgrade(NULL, 2, 3);
+
+ if (!rpc)
+ {
+ ifs_unlock_rpcs();
+ return 0;
+ }
+
+ if (rpc_get_len(rpc) > out_len)
+ {
+ //_asm int 3;
+ ifs_unlock_rpcs();
+ rpt0(("cancel", "cancel on send"));
+ rpc_upgrade(rpc, -1, 5);
+ KeSetEvent(&rpc->ev, IO_NO_INCREMENT, FALSE); /* move to rpc_ fn */
+ //rpc_cancel(rpc);
+ goto restart;//return 0;
+ }
+
+
+
+ /*mdl = (*rpc->bulk_out_len == 0xFFFFFFFC);
+
+ if (mdl)
+ *rpc->bulk_out_len = 0;*/
+
+ header_len = rpc->out_pos - rpc->out_buf;
+ RtlCopyMemory(out_buf, rpc->out_buf, header_len);
+
+ //if (!mdl)
+ {
+ if (*rpc->bulk_out_len && rpc->bulk_out)
+ RtlCopyMemory(out_buf + header_len, rpc->bulk_out, *rpc->bulk_out_len);
+ *out_written = header_len + *rpc->bulk_out_len;
+ }
+ #if 0
+ else
+ {
+ if (rpc->bulk_mdl)
+ {
+ void *ptr;
+ //_asm int 3;
+ #if 0
+ try
+ {
+ _asm int 3;
+ MmProbeAndLockPages(rpc->bulk_mdl, UserMode, IoModifyAccess);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ _asm int 3;
+ }
+ #endif
+ try
+ {
+ rpc->bulk_out = MmMapLockedPagesSpecifyCache(rpc->bulk_mdl, UserMode, MmNonCached, NULL, FALSE, NormalPagePriority);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ PMDL remap;
+ void *ptr;
+ _asm int 3;
+ ptr = ExAllocatePool(PagedPool, MmGetMdlByteCount(rpc->bulk_mdl));
+ remap = IoAllocateMdl(ptr, MmGetMdlByteCount(rpc->bulk_mdl), FALSE, TRUE, NULL);
+ MmProbeAndLockPages(remap, UserMode, IoModifyAccess);
+ rpc->bulk_out = MmMapLockedPagesSpecifyCache(remap, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
+ _asm int 3;
+ rpc->bulk_out = MmGetSystemAddressForMdlSafe(rpc->bulk_mdl, NormalPagePriority);
+ MmUnmapLockedPages(rpc->bulk_out, rpc->bulk_mdl);
+ rpc->bulk_out = MmMapLockedPagesSpecifyCache(rpc->bulk_mdl, UserMode, MmNonCached, NULL, FALSE, NormalPagePriority);
+
+ remap = IoAllocateMdl(rpc->bulk_out, MmGetMdlByteCount(rpc->bulk_mdl), FALSE, TRUE, NULL);
+ remap->Process = (void*)PsGetCurrentProcess();
+ MmBuildMdlForNonPagedPool(remap);
+ //MmProbeAndLockPages(remap, UserMode, IoModifyAccess);
+ rpc->bulk_out = MmMapLockedPagesSpecifyCache(remap, UserMode, MmNonCached, (void*)0x01111111, FALSE, NormalPagePriority);
+ /*ifs_unlock_rpcs();
+ rpc_upgrade(rpc, -1, 5);
+ KeSetEvent(&rpc->ev, IO_NO_INCREMENT, FALSE);
+ //rpc_cancel(rpc);
+ goto restart;//return 0;*/
+ }
+ ptr = rpc->bulk_out;
+ RtlCopyMemory(out_buf + header_len, &ptr, sizeof(ptr));
+ }
+
+ *rpc->bulk_out_len = 0xFFFFFFFC;
+ *out_written = header_len + sizeof(void*);
+ }
+ #endif
+
+ ifs_unlock_rpcs();
+ return (*out_written != 0);
+ }
+
+#if 0
+rpc_send_reg(rpc_t *rpc, char *out_buf)
+ {
+ ULONG header_len;
+
+ header_len = rpc->out_pos - rpc->out_buf;
+ RtlCopyMemory(out_buf, rpc->out_buf, header_len);
+
+ if (rpc->bulk_out_len && rpc->bulk_out)
+ RtlCopyMemory(out_buf + header_len, rpc->bulk_out, *rpc->bulk_out_len);
+ return header_len + *rpc->bulk_out_len;
+ }
+#endif
+#endif
+
+
+/* rpc library api */
+#ifdef RPC_KERN
+rpc_recv(char *in_buf, ULONG len)
+ {
+ ULONG key, header_size;
+ char *alloc;
+ rpc_t *rpc;
+
+ ifs_lock_rpcs();
+
+ rpc = rpc_find(*(ULONG*)in_buf);
+ if (!rpc)
+ {
+ //_asm int 3;
+ ifs_unlock_rpcs();
+ return -1;
+ }
+
+ //_asm int 3;
+ /*if (*rpc->bulk_out_len == 0xFFFFFFFC)
+ {
+ ASSERT(rpc->bulk_out);
+ MmUnmapLockedPages(rpc->bulk_out, rpc->bulk_mdl);
+ // MmUnlockPages(rpc->bulk_mdl);
+ }*/
+
+ alloc = rpc->in_buf;
+ rpc->in_buf = rpc->in_pos = in_buf;
+ rpc_unmarshal_long(rpc, &key);
+ ASSERT(key == rpc->key);
+ rpc_unmarshal_long(rpc, &rpc->bulk_in_len);
+
+ rpc->in_buf = rpc->in_pos = alloc;
+ header_size = len - rpc->bulk_in_len;
+ ASSERT(header_size < 4096);
+ RtlCopyMemory(rpc->in_buf, in_buf + 2*sizeof(ULONG), header_size - 2*sizeof(ULONG));
+ //if (*rpc->bulk_out_len != 0xFFFFFFFC)
+ {
+ if (rpc->bulk_in_len && rpc->bulk_in)
+ {
+ ASSERT(rpc->bulk_in_len <= rpc->bulk_in_max);
+ //_asm int 3;
+ RtlCopyMemory(rpc->bulk_in, in_buf + header_size, rpc->bulk_in_len);//len - header_size - 2*sizeof(ULONG));
+ }
+ }
+
+ KeSetEvent(&rpc->ev, IO_NO_INCREMENT, FALSE);
+ ifs_unlock_rpcs();
+ return 0;
+ }
+
+rpc_call(ULONG in_len, char *in_buf, ULONG out_max, char *out_buf, ULONG *out_len)
+ {
+ long rpc_code;
+ ULONG status;
+ WCHAR name[1024];
+ ULONG key, fid;
+ LARGE_INTEGER user_id;
+ rpc_t rpc;
+
+ rpc.in_buf = rpc.in_pos = in_buf;
+ rpc.out_buf = rpc.out_pos = out_buf;
+
+ rpc_unmarshal_long(&rpc, &key);
+ rpc_unmarshal_long(&rpc, &rpc_code);
+
+ switch (rpc_code)
+ {
+ case RPC_BREAK_CALLBACK:
+ rpc_unmarshal_long(&rpc, &fid);
+ status = dc_break_callback(fid);
+ rpc_marshal_long(&rpc, status);
+ break;
+ }
+ *out_len = rpc.out_pos - rpc.out_buf;
+ return 0;
+ //ifs_ImpersonateClient(user_id);
+ }
+#endif
+
+#ifndef RPC_KERN
+rpc_parse(rpc_t *rpc)
+ {
+ long rpc_code;
+ ULONG status;
+ WCHAR name[1024];
+ ULONG key;
+ LARGE_INTEGER user_id;
+
+ rpc_unmarshal_long(rpc, &key);
+ rpc_unmarshal_long(rpc, &rpc->bulk_in_len);
+ rpc_unmarshal_longlong(rpc, &user_id);
+ rpc_unmarshal_long(rpc, &rpc_code);
+
+ ifs_ImpersonateClient(user_id);
+
+ rpc_marshal_long(rpc, key);
+ rpc->bulk_out_len = (ULONG*)rpc->out_pos;
+ rpc_marshal_long(rpc, 0);
+
+ switch (rpc_code)
+ {
+ case RPC_NAMEI:
+ {
+ ULONG fid, length;
+ char *data;
+ //rpc_unmarshal_wstr(rpc, name);
+ rpc_unmarshal_long(rpc, &length);
+ //data = *((char**)rpc->in_pos);
+ data = rpc->in_pos;
+ status = uc_namei((WCHAR*)data, &fid);
+ //status = uc_namei(name, &fid);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, fid);
+ }
+ break;
+ case RPC_CHECK_ACCESS:
+ {
+ ULONG fid, access, granted;
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_long(rpc, &access);
+ status = uc_check_access(fid, access, &granted);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, granted);
+ }
+ break;
+ case RPC_CREATE:
+ {
+ LARGE_INTEGER alloc;
+ ULONG access, granted, fid, attribs;
+ char *data;
+
+ rpc_unmarshal_long(rpc, &attribs);
+ rpc_unmarshal_longlong(rpc, &alloc);
+ rpc_unmarshal_long(rpc, &access);
+ //rpc_unmarshal_wstr(rpc, name);
+ data = rpc->in_pos;
+ status = uc_create((WCHAR*)data, attribs, alloc, access, &granted, &fid);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, granted);
+ rpc_marshal_long(rpc, fid);
+ }
+ break;
+ case RPC_STAT:
+ {
+ ULONG fid, attribs;
+ LARGE_INTEGER size, creation, access, change, written;
+ rpc_unmarshal_long(rpc, &fid);
+ status = uc_stat(fid, &attribs, &size, &creation, &access, &change, &written);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, attribs);
+ rpc_marshal_longlong(rpc, size);
+ rpc_marshal_longlong(rpc, creation);
+ rpc_marshal_longlong(rpc, access);
+ rpc_marshal_longlong(rpc, change);
+ rpc_marshal_longlong(rpc, written);
+ }
+ break;
+ case RPC_READ:
+ {
+ ULONG fid, length, read;
+ LARGE_INTEGER offset;
+ char *data, *save;
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_longlong(rpc, &offset);
+ rpc_unmarshal_long(rpc, &length);
+ save = rpc->out_pos;
+ rpc_marshal_long(rpc, 0);
+ rpc_marshal_long(rpc, 0);
+ data = rpc->out_pos;
+ rpc->out_pos = save;
+ status = uc_read(fid, offset, length, &read, data);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, read);
+ rpc->out_pos += read;
+ *rpc->bulk_out_len = read;
+ }
+ break;
+ /* case RPC_READ_BULK:
+ {
+ ULONG fid, length, read;
+ LARGE_INTEGER offset;
+ char *data, *save;
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_longlong(rpc, &offset);
+ rpc_unmarshal_long(rpc, &length);
+ data = *((char**)rpc->in_pos);
+ status = uc_read(fid, offset, length, &read, data);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, read);
+ *rpc->bulk_out_len = 0;
+ }
+ break;*/
+ case RPC_WRITE:
+ {
+ ULONG fid, length, written;
+ LARGE_INTEGER offset;
+ char *data;
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_longlong(rpc, &offset);
+ rpc_unmarshal_long(rpc, &length);
+ data = rpc->in_pos;
+ status = uc_write(fid, offset, length, &written, data);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, written);
+ }
+ break;
+ /* case RPC_WRITE_BULK:
+ {
+ ULONG fid, length, written;
+ LARGE_INTEGER offset;
+ char *data;
+ //_asm int 3;
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_longlong(rpc, &offset);
+ rpc_unmarshal_long(rpc, &length);
+ data = *((char**)rpc->in_pos);
+ status = uc_write(fid, offset, length, &written, data);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, written);
+ }
+ break;*/
+ case RPC_TRUNC:
+ {
+ ULONG fid;
+ LARGE_INTEGER size;
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_longlong(rpc, &size);
+ status = uc_trunc(fid, size);
+ rpc_marshal_long(rpc, status);
+ }
+ break;
+ case RPC_SETINFO:
+ {
+ ULONG fid, attribs;
+ LARGE_INTEGER creation, access, change, written;
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_long(rpc, &attribs);
+ rpc_unmarshal_longlong(rpc, &creation);
+ rpc_unmarshal_longlong(rpc, &access);
+ rpc_unmarshal_longlong(rpc, &change);
+ rpc_unmarshal_longlong(rpc, &written);
+ status = uc_setinfo(fid, attribs, creation, access, change, written);
+ rpc_marshal_long(rpc, status);
+ }
+ break;
+ case RPC_READDIR:
+ {
+ ULONG fid, count, len;
+ LARGE_INTEGER cookie_in;
+ char *data, *save;
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_longlong(rpc, &cookie_in);
+ rpc_unmarshal_wstr(rpc, name);
+ rpc_unmarshal_long(rpc, &len);
+ save = rpc->out_pos;
+ rpc_marshal_long(rpc, 0);
+ rpc_marshal_long(rpc, 0);
+ rpc_marshal_long(rpc, 0);
+ data = rpc->out_pos;
+ rpc->out_pos = save;
+ status = uc_readdir(fid, cookie_in, name, &count, data, &len);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, count);
+ rpc_marshal_long(rpc, len);
+ rpc->out_pos += len;
+ *rpc->bulk_out_len = len;
+ }
+ break;
+ case RPC_CLOSE:
+ {
+ ULONG fid;
+ rpc_unmarshal_long(rpc, &fid);
+ status = uc_close(fid);
+ rpc_marshal_long(rpc, status);
+ }
+ break;
+ case RPC_UNLINK:
+ {
+ ULONG fid, unlink;
+ rpc_unmarshal_wstr(rpc, name);
+ status = uc_unlink(name);
+ rpc_marshal_long(rpc, status);
+ }
+ break;
+ case RPC_IOCTL_WRITE:
+ {
+ ULONG length, key;
+ rpc_unmarshal_long(rpc, &length);
+ status = uc_ioctl_write(length, rpc->in_pos, &key);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, key);
+ }
+ break;
+ case RPC_IOCTL_READ:
+ {
+ ULONG key, length;
+ char *save, *data;
+ rpc_unmarshal_long(rpc, &key);
+ save = rpc->out_pos;
+ rpc_marshal_long(rpc, 0);
+ rpc_marshal_long(rpc, 0);
+ data = rpc->out_pos;
+ rpc->out_pos = save;
+ status = uc_ioctl_read(key, &length, data);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, length);
+ rpc->out_pos += length;
+ *rpc->bulk_out_len = length;
+ }
+ break;
+ case RPC_RENAME:
+ {
+ ULONG fid, new_fid;
+ WCHAR curr[1024], new_dir[1024], new_name[1024];
+ rpc_unmarshal_long(rpc, &fid);
+ rpc_unmarshal_wstr(rpc, curr);
+ rpc_unmarshal_wstr(rpc, new_dir);
+ rpc_unmarshal_wstr(rpc, new_name);
+ status = uc_rename(fid, curr, new_dir, new_name, &new_fid);
+ rpc_marshal_long(rpc, status);
+ rpc_marshal_long(rpc, new_fid);
+ }
+ break;
+ }
+ }
+#endif
--- /dev/null
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+/* versioning history
+ *
+ * 03-jun 2005 (eric williams) entered into versioning
+ */
+
+#ifdef RPC_KERN
+#include <ntifs.h>
+#include <stdlib.h>
+#else
+#include <osi.h>
+#include <windows.h>
+#include <winioctl.h>
+#endif
+
+/* upcalls */
+#define RPC_NAMEI 0x10
+#define RPC_CHECK_ACCESS 0x11
+#define RPC_CREATE 0x12
+#define RPC_STAT 0x13
+#define RPC_READ 0x14
+#define RPC_WRITE 0x15
+#define RPC_TRUNC 0x16
+#define RPC_SETINFO 0x17
+#define RPC_READDIR 0x18
+#define RPC_CLOSE 0x19
+#define RPC_UNLINK 0x1A
+#define RPC_IOCTL_WRITE 0x1B
+#define RPC_IOCTL_READ 0x1C
+#define RPC_RENAME 0x1D
+#define RPC_READ_BULK 0x1E
+#define RPC_WRITE_BULK 0x1F
+
+/* downcalls */
+#define RPC_BREAK_CALLBACK 0x80
+
+#define TRANSFER_CHUNK_SIZE (1024*1024)
+#define RPC_TIMEOUT_SHORT 0
+#define RPC_TIMEOUT_LONG 1
+
+/* internal data struct for both client and server */
+struct rpc
+ {
+#ifdef RPC_KERN
+ struct rpc *next;
+ int size;
+ KEVENT ev;
+ MDL *bulk_mdl;
+#endif
+ char *bulk_out;
+ ULONG *bulk_out_len;
+ char *bulk_in;
+ ULONG bulk_in_len, bulk_in_max;
+ ULONG key;
+ char *out_buf, *out_pos;
+ char *in_buf, *in_pos;
+ int status;
+ };
+typedef struct rpc rpc_t;
+
+
+/* application interface into rpc library */
+#ifdef RPC_KERN
+rpc_call(ULONG in_len, char *in_buf, ULONG out_max, char *out_buf, ULONG *out_len);
+rpc_set_context(void *context);
+rpc_remove_context();
+rpc_get_len(rpc_t *rpc);
+rpc_send(char *out_buf, int out_len, int *out_written);
+rpc_recv(char *in_buf, ULONG len);
+rpc_shutdown();
+
+#else
+
+rpc_parse(rpc_t *rpc);
+#endif
+
+
+/* extended information */
+struct readdir_data
+ {
+ LARGE_INTEGER cookie;
+ long offset;
+ LARGE_INTEGER creation, access, write, change, size;
+ ULONG attribs, name_length; /* chars */
+ CCHAR short_name_length; /* chars */
+ WCHAR short_name[14];
+ WCHAR name[];
+ };
+typedef struct readdir_data readdir_data_t;
--- /dev/null
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+/* versioning history
+ *
+ * 03-jun 2005 (eric williams) entered into versioning
+ */
+
+/* error codes */
+#define IFSL_SUCCESS_BASE 0x00000000
+#define IFSL_FAIL_BASE 0x80000000
+
+#define IFSL_SUCCESS (IFSL_SUCCESS_BASE + 0)
+#define IFSL_DOES_NOT_EXIST (IFSL_FAIL_BASE + 1)
+#define IFSL_NOT_IMPLEMENTED (IFSL_FAIL_BASE + 2)
+#define IFSL_END_OF_ENUM (IFSL_SUCCESS_BASE + 3)
+#define IFSL_CANNOT_MAKE (IFSL_FAIL_BASE + 4)
+#define IFSL_END_OF_FILE (IFSL_SUCCESS_BASE + 5)
+#define IFSL_NO_ACCESS (IFSL_FAIL_BASE + 6)
+#define IFSL_BUFFER_TOO_SMALL (IFSL_FAIL_BASE + 7)
+#define IFSL_SHARING_VIOLATION (IFSL_FAIL_BASE + 8)
+#define IFSL_BAD_INPUT (IFSL_FAIL_BASE + 9)
+#define IFSL_GENERIC_FAILURE (IFSL_FAIL_BASE + 10)
+#define IFSL_OPEN_CREATED (IFSL_SUCCESS_BASE + 11)
+#define IFSL_OPEN_EXISTS (IFSL_FAIL_BASE + 12)
+#define IFSL_OPEN_OPENED (IFSL_SUCCESS_BASE + 13)
+#define IFSL_OPEN_OVERWRITTEN (IFSL_SUCCESS_BASE + 14)
+#define IFSL_OPEN_SUPERSCEDED (IFSL_SUCCESS_BASE + 15)
+#define IFSL_BADFILENAME (IFSL_FAIL_BASE + 16)
+#define IFSL_READONLY (IFSL_FAIL_BASE + 17)
+#define IFSL_IS_A_DIR (IFSL_FAIL_BASE + 18)
+#define IFSL_PATH_DOES_NOT_EXIST (IFSL_FAIL_BASE + 19)
+#define IFSL_IS_A_FILE (IFSL_FAIL_BASE + 20)
+#define IFSL_NO_FILE (IFSL_FAIL_BASE + 21)
+#define IFSL_NOT_EMPTY (IFSL_FAIL_BASE + 22)
+#define IFSL_RPC_TIMEOUT (IFSL_FAIL_BASE + 23)
+#define IFSL_OVERQUOTA (IFSL_FAIL_BASE + 24)
+#define IFSL_UNSPEC (IFSL_FAIL_BASE + 25)
+
+
+/* ioctl codes */
+#define IOCTL_AFSRDR_IOCTL CTL_CODE(IOCTL_DISK_BASE, 0x007, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+#define IOCTL_AFSRDR_DOWNCALL CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+#define IOCTL_AFSRDR_GET_PATH CTL_CODE(IOCTL_DISK_BASE, 0x009, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+
+/* upcalls */
+uc_namei(WCHAR *name, ULONG *fid);
+uc_check_access(ULONG fid, ULONG access, ULONG *granted);
+uc_create(WCHAR *str, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid);
+uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation, LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written);
+uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access, LARGE_INTEGER change, LARGE_INTEGER written);
+uc_trunc(ULONG fid, LARGE_INTEGER size);
+uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data);
+uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data);
+/*#ifdef RPC_KERN
+uc_read_mdl(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, MDL *data);
+uc_write_mdl(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, MDL *mdl);
+#endif*/
+uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len);
+uc_close(ULONG fid);
+uc_unlink(WCHAR *name);
+uc_ioctl_write(ULONG length, char *data, ULONG *key);
+uc_ioctl_read(ULONG key, ULONG *length, char *data);
+uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid);
+
+/* downcalls */
+dc_break_callback(ULONG fid);
--- /dev/null
+!INCLUDE $(NTMAKEENV)\makefile.def
--- /dev/null
+#/* copyright (c) 2005
+# * the regents of the university of michigan
+# * all rights reserved
+# *
+# * permission is granted to use, copy, create derivative works and
+# * redistribute this software and such derivative works for any purpose,
+# * so long as the name of the university of michigan is not used in
+# * any advertising or publicity pertaining to the use or distribution
+# * of this software without specific, written prior authorization. if
+# * the above copyright notice or any other identification of the
+# * university of michigan is included in any copy of any portion of
+# * this software, then the disclaimer below must also be included.
+# *
+# * this software is provided as is, without representation from the
+# * university of michigan as to its fitness for any purpose, and without
+# * warranty by the university of michigan of any kind, either express
+# * or implied, including without limitation the implied warranties of
+# * merchantability and fitness for a particular purpose. the regents
+# * of the university of michigan shall not be liable for any damages,
+# * including special, indirect, incidental, or consequential damages,
+# * with respect to any claim arising out or in connection with the use
+# * of the software, even if it has been or is hereafter advised of the
+# * possibility of such damages.
+# */
+
+SOURCES= afsrdr.c ifs_rpc.c
+TARGETNAME=afsrdr
+TARGETPATH=obj
+TARGETTYPE=DRIVER
+DRIVERTYPE=FS
+C_DEFINES=-DUNICODE -DRPT_CLI -DRPC_KERN
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
*/
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as no fee is charged, and so long as the copyright notice
+ * above, this grant of permission, and the disclaimer below appear
+ * in all copies made; and so long as the name of the university of
+ * michigan is not used in any advertising or publicity pertaining
+ * to the use or distribution of this software without specific, written
+ * prior authorization.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for nay damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to ant claim arising out of or in connection with the
+ * use of the software, even if it has been or is hereafter advised
+ * of the possibility of such damages.
+ */
extern "C" {
#include <afs/param.h>
// Otherwise, look up our list of submounts.
//
+#ifdef AFSIFS
+ AdjustAfsPath (pszPath, pszSubmount, TRUE, TRUE);
+#endif
for (size_t ii = 0; ii < pList->cSubmounts; ++ii)
{
+#ifndef AFSIFS
if (!lstrcmpi (pList->aSubmounts[ii].szSubmount, pszSubmount))
+#else
+ if (!lstrcmpi (pList->aSubmounts[ii].szMapping, pszPath))
+#endif
{
if (fMarkInUse)
pList->aSubmounts[ii].fInUse = TRUE;
}
// We now have a submount name and drive letter--map the network drive.
+#ifndef AFSIFS
DWORD rc=MountDOSDrive(chDrive,szSubmount,fPersistent,NULL);
+#else
+ DWORD rc=MountDOSDrive(chDrive,/*szSubmount*/pszMapping,fPersistent,NULL);
+#endif
if (rc == NO_ERROR)
return TRUE;
// <AuthID>: Authentication ID, 16 char hex.
// <netbiosname>: Netbios name of server
//
+#ifndef AFSIFS
if (_tcsnicmp(szMapping, cszLANMANDEVICE, _tcslen(cszLANMANDEVICE)))
+#else
+ const TCHAR ker_sub_path[] = "\\Device\\afsrdr\\";
+ if (_tcsnicmp(szMapping, ker_sub_path, _tcslen(ker_sub_path)))
+#endif
return FALSE;
+#ifndef AFSIFS
pszSubmount = &szMapping[ _tcslen(cszLANMANDEVICE) ];
+#else
+ pszSubmount = &szMapping[ _tcslen(ker_sub_path) ];
+#endif
+#ifdef AFSIFS
+ if (*(pszSubmount) < '0' ||
+ *(pszSubmount) > '9')
+ return FALSE;
+ ++pszSubmount;
+#else
if (IsWindows2000())
{
if (*(pszSubmount) != TEXT(';'))
return FALSE;
pszSubmount += _tcslen(szNetBiosName);
+#endif
}
else // (!IsWindowsNT())
{
if (!pszSubmount || !*pszSubmount)
return FALSE;
+#ifndef AFSIFS
lstrcpy (pszSubmountNow, pszSubmount);
+#else
+ lstrcpy (pszSubmountNow, "\\afs");
+ lstrcat (pszSubmountNow, pszSubmount);
+#endif
return TRUE;
}
DWORD MountDOSDrive(char chDrive,const char *szSubmount,BOOL bPersistent,const char * pUsername)
{
- TCHAR szPath[MAX_PATH];
+ DWORD err;
+ BOOL succ;
+ TCHAR szPath[MAX_PATH], szTokens[MAX_PATH], *tok;
TCHAR szClient[MAX_PATH];
TCHAR szDrive[3] = TEXT("?:");
+
+#ifdef AFSIFS
+ int pathCount, currPos, lastPos, x;
+
+ pathCount = 0;
+
+ pathCount = 0;
+ strcpy(szTokens, szSubmount);
+ tok = strtok(szTokens, "/\\");
+ strcpy(szPath, "");
+ while (tok)
+ {
+ if (pathCount || stricmp(tok, "afs"))
+ {
+ strcat(szPath, "\\");
+ strcat(szPath, tok);
+ pathCount++;
+ }
+ tok = strtok(NULL, "/\\");
+ }
+
+ sprintf(szDrive,"%c:",chDrive);
+ strcpy(szTokens, szPath);
+ sprintf(szPath,"\\Device\\afsrdr\\%d%s",pathCount,szTokens);
+ //succ = DefineDosDevice(DDD_RAW_TARGET_PATH, "J:", "\\Device\\afsrdr\\2\\ericjw\\test");
+ succ = DefineDosDevice(DDD_RAW_TARGET_PATH, szDrive, szPath);
+ err = GetLastError();
+
+ return succ ? NO_ERROR : ERROR_DEVICE_IN_USE;
+
+#else
+
sprintf(szDrive,"%c:",chDrive);
GetClientNetbiosName (szClient);
sprintf(szPath,"\\\\%s\\%s",szClient,szSubmount);
(bPersistent)?"Persistant" : "NonPresistant",
szDrive,szPath,pUsername?pUsername:"NULL",res);
return res;
+#endif
}
DWORD DisMountDOSDriveFull(const char *szPath,BOOL bForce)
{
+#ifndef AFSIFS
DWORD res=WNetCancelConnection(szPath,bForce);
+#else
+ DWORD res;
+ res = ERROR_DEVICE_IN_USE;
+ // must handle drive letters and afs paths
+ //DDD_REMOVE_DEFINITION
+#endif
DEBUG_EVENT3("AFS DriveMap","%sDismount Remote[%s]=%x",
bForce ? "Forced " : "",szPath,res);
return (res==ERROR_NOT_CONNECTED)?NO_ERROR:res;
DWORD DisMountDOSDrive(const char chDrive,BOOL bForce)
{
TCHAR szPath[MAX_PATH];
- sprintf(szPath,"%c:",chDrive);
+ DWORD succ;
+
+ sprintf(szPath,"%c:",chDrive);
+#ifdef AFSIFS
+ succ = DefineDosDevice(DDD_REMOVE_DEFINITION, szPath, NULL);
+ return (!succ) ? GetLastError() : 0;
+#else
return DisMountDOSDriveFull(szPath,bForce);
+#endif
}
!else if ("$(AFSVER_CL)" == "1300")
echo !define CL_1300 1 >> $(OUT)\nsi-includes.nsi
!endif
+!if ("$(AFSIFS)" == "TRUE")
+ echo !define AFSIFS 1 >> $(OUT)\nsi-includes.nsi
+!endif
!if ("$(AFSDEV_BUILDTYPE)" == "CHECKED")
echo !define DEBUG 1 >>$(OUT)\nsi-includes.nsi
!endif
VIAddVersionKey "ProductVersion" ${AFS_VERSION}
VIAddVersionKey "FileVersion" ${AFS_VERSION}
VIAddVersionKey "FileDescription" "OpenAFS for Windows Installer"
-VIAddVersionKey "LegalCopyright" "(C)2000-2004"
+VIAddVersionKey "LegalCopyright" "(C)2000-2005"
!ifdef DEBUG
VIAddVersionKey "PrivateBuild" "Checked/Debug"
!endif ; End DEBUG
!define REPLACEDLL_NOREGISTER
;General
+!ifndef AFSIFS
!ifndef DEBUG
OutFile "${AFS_DESTDIR}\WinInstall\OpenAFSforWindows.exe"
!else
OutFile "${AFS_DESTDIR}\WinInstall\OpenAFSforWindows-DEBUG.exe"
!endif
+!else
+!ifndef DEBUG
+ OutFile "${AFS_DESTDIR}\WinInstall\OpenAFSforWindows-IFS.exe"
+!else
+ OutFile "${AFS_DESTDIR}\WinInstall\OpenAFSforWindows-IFS-DEBUG.exe"
+!endif
+!endif
SilentInstall normal
SetCompressor lzma
!define MUI_ICON "..\..\client_config\afs_config.ico"
var REG_DATA_1
var REG_DATA_2
var REG_DATA_3
+var REG_DATA_4
;--------------------------------
SetOutPath "$SYSDIR"
!insertmacro ReplaceDLL "${AFS_CLIENT_BUILDDIR}\afslogon.dll" "$SYSDIR\afslogon.dll" "$INSTDIR"
File "${AFS_CLIENT_BUILDDIR}\afscpcc.exe"
+!ifdef AFSIFS
+!ifndef DEBUG
+ !insertmacro ReplaceDLL "..\..\afsrdr\objfre_w2K_x86\i386\afsrdr.sys" "$SYSDIR\DRIVERS\afsrdr.sys" "$INSTDIR"
+!else
+ !insertmacro ReplaceDLL "..\..\afsrdr\objchk_w2K_x86\i386\afsrdr.sys" "$SYSDIR\DRIVERS\afsrdr.sys" "$INSTDIR"
+!endif
+!endif
Call AFSLangFiles
SetOutPath "$INSTDIR\Common"
File "${AFS_WININSTALL_DIR}\Service.exe"
nsExec::Exec "net stop TransarcAFSDaemon"
+ nsExec::Exec "net stop AfsRdr"
;IMPORTANT! If we are not refreshing the config files, do NOT remove the service
;Don't re-install because it must be present or we wouldn't have passed the Reg check
StrCmp $R2 "" +1 skipremove
nsExec::Exec '$INSTDIR\Common\Service.exe u TransarcAFSDaemon'
nsExec::Exec '$INSTDIR\Common\Service.exe TransarcAFSDaemon "$INSTDIR\Client\Program\afsd_service.exe" "OpenAFS Client Service"'
+ nsExec::Exec '$INSTDIR\Common\Service.exe u AfsRdr'
+!ifdef AFSIFS
+ nsExec::Exec '$INSTDIR\Common\Service.exe AfsRdr "$SYSDIR\DRIVERS\afsrdr.sys" "AFS Redirector"'
+!endif
skipremove:
Delete "$INSTDIR\Common\service.exe"
strcpy $REG_DATA_1 "PNP_TDI"
strcpy $REG_DATA_2 ""
strcpy $REG_DATA_3 ""
+ strcpy $REG_DATA_4 ""
Call RegWriteMultiStr
strcpy $REG_SUB_KEY "SYSTEM\CurrentControlSet\Services\TransarcAFSDaemon"
strcpy $REG_VALUE "DependOnService"
strcpy $REG_DATA_1 "Tcpip"
strcpy $REG_DATA_2 "NETBIOS"
strcpy $REG_DATA_3 "RpcSs"
+!ifdef AFSIFS
+ strcpy $REG_DATA_4 "AfsRdr"
+!else
+ strcpy $REG_DATA_4 ""
+!endif
+ Call RegWriteMultiStr
+!ifdef AFSIFS
+ strcpy $REG_SUB_KEY "SYSTEM\CurrentControlSet\Services\AfsRdr"
+ strcpy $REG_VALUE "DependOnService"
+ strcpy $REG_DATA_1 "Tcpip"
+ strcpy $REG_DATA_2 ""
+ strcpy $REG_DATA_3 ""
+ strcpy $REG_DATA_4 ""
Call RegWriteMultiStr
+!endif
; WinLogon Event Notification
WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\AfsLogon" "Asynchronous" 0
System::Call "*$2(&t$9 '$REG_DATA_3')" ; Place the string
IntOp $2 $2 + $9 ; Advance to the next position
+ StrCmp '$REG_DATA_4' "" terminate
+ StrLen $9 '$REG_DATA_4' ; Length of third string
+ IntOp $9 $9 + 1 ; Plus null
+ System::Call "*$2(&t$9 '$REG_DATA_4')" ; Place the string
+ IntOp $2 $2 + $9 ; Advance to the next position
+
terminate:
System::Call "*$2(&t1 '')" ; Place the terminating null
IntOp $2 $2 + 1 ; Advance to the next position
int main(int argc, char *argv[])
{
+ DWORD type, start;
+
if(argc<3)
{
printf("Insufficient arguments: Service ServiceName ServicePath DisplayName.\n");
if(*argv[1]!='u' && *argv[1]!='U')
{
+ if (!stricmp(argv[2] + strlen(argv[2]) - 3, "sys"))
+ {
+ type = SERVICE_FILE_SYSTEM_DRIVER;
+ start = SERVICE_DEMAND_START;
+ }
+ else
+ {
+ type = SERVICE_WIN32_OWN_PROCESS;
+ start = SERVICE_AUTO_START;
+ }
hService = CreateService(hSCM, argv[1],
_T(argv[3]),
SERVICE_ALL_ACCESS,
- SERVICE_WIN32_OWN_PROCESS,
- SERVICE_AUTO_START,
+ type,
+ start,
SERVICE_ERROR_IGNORE,
argv[2],
NULL,NULL,NULL, NULL, NULL );
!ENDIF
!ENDIF
+!IF ("$(AFSIFS)" == "TRUE")
+dafsifs = "-DAFSIFS"
+!ELSE
+dafsifs = ""
+!ENDIF
+
!IF ("$(AFSDEV_BUILDTYPE)" == "FREE")
afscflags = $(afscflags) /Ox /Zi
afscflags = $(afscflags) /W$(AFSDEV_WARNLEVEL)
# C/C++ compilation macros
-C2OBJ = $(cc) /Fo$@ /Fd$*.pdb $(cflags) $(cdebug) $(cvarsdll) $(afscflags) $(afscdefs) /c
+C2OBJ = $(cc) /Fo$@ /Fd$*.pdb $(cflags) $(cdebug) $(dafsifs) $(cvarsdll) $(afscflags) $(afscdefs) /c
CPP2OBJ = $(C2OBJ)
# Inference rules for building and installing targets
# Compile .c files, from current directory to defined by OUT
:checked
set AFSBLD_TYPE=CHECKED
set AFSDEV_CRTDEBUG=1
-goto args_done
+goto ifs_arg
:free
set AFSBLD_TYPE=FREE
set AFSDEV_CRTDEBUG=0
+goto ifs_arg
+
+:ifs_arg
+
+set AFSIFS=
+if "%2"=="ifs" goto is_ifs
+if "%2"=="IFS" goto is_ifs
+
goto args_done
+:is_ifs
+
+set AFSIFS=TRUE
+
:args_done
REM #######################################################################
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
*/
+/* copyright (c) 2005
+ * the regents of the university of michigan
+ * all rights reserved
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose. the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
#include <afsconfig.h>
#include <afs/param.h>
#include <pioctl_nt.h>
#include <WINNT/afsreg.h>
#include <lanahelper.h>
+#include <WINNT/afsrdr/kif.h>
#include <loadfuncs-krb5.h>
#include <krb5.h>
DWORD gle;
DWORD dwSize = sizeof(szUser);
+#ifndef AFSIFS
if (fileNamep) {
drivep = strchr(fileNamep, ':');
if (drivep && (drivep - fileNamep) >= 1) {
lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
}
+#else
+ sprintf(tbuffer,"\\\\.\\afscom\\ioctl");
+#endif
fflush(stdout);
/* now open the file */
fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_WRITE_THROUGH, NULL);
- fflush(stdout);
- if (fh == INVALID_HANDLE_VALUE) {
+
+ fflush(stdout);
+
+#ifdef AFSIFS
+ if (fh == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+#endif
+
+ if (fh == INVALID_HANDLE_VALUE) {
int gonext = 0;
gle = GetLastError();
long rcount;
long ioCount;
DWORD gle;
+ char *data;
rcount = reqp->mp - reqp->data;
if (rcount <= 0) {
return EINVAL; /* not supposed to happen */
}
- if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
+#ifndef AFSIFS
+ if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
/* failed to write */
gle = GetLastError();
fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
return gle;
}
+#else
+ /* ioctl completes as one operation, so copy input to a new buffer, and use as output buffer */
+ data = malloc(rcount);
+ memcpy(data, reqp->data, rcount);
+ if (!DeviceIoControl(handle, IOCTL_AFSRDR_IOCTL, data, rcount, reqp->data, sizeof(reqp->data), &ioCount, NULL))
+ {
+ free(data);
+ return GetLastError();
+ }
+ free(data);
+#endif
reqp->nbytes = ioCount; /* set # of bytes available */
reqp->mp = reqp->data; /* restart marshalling */
int pathHasDrive;
int doSwitch;
char newPath[3];
+ HANDLE rootDir;
+ wchar_t *wpath;
+ unsigned long length;
+
+#ifdef AFSIFS
+ if (!pathp)
+ return CM_ERROR_NOSUCHPATH;
+
+ //sprintf(tpath, "%c:\\", pathp[0]);
+ rootDir = CreateFile(pathp, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (rootDir == INVALID_HANDLE_VALUE)
+ return CM_ERROR_NOSUCHPATH;
+
+ wpath = tpath;
+ length = 0;
+ if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, wpath, 1000, &length, NULL))
+ {
+ CloseHandle(rootDir);
+ return CM_ERROR_NOSUCHPATH;
+ }
+ CloseHandle(rootDir);
+
+ code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, wpath, length/sizeof(wchar_t), outPathp, outSize/sizeof(wchar_t), NULL, NULL);
+
+// strcpy(outPathp, tpath);
+ return 0;
+#endif
+
if (pathp[0] != 0 && pathp[1] == ':') {
/* there's a drive letter there */
/* now get the absolute path to the current wdir in this drive */
GetCurrentDirectory(sizeof(tpath), tpath);
if (tpath[1] == ':')
+#ifndef AFSIFS
strcpy(outPathp, tpath + 2); /* skip drive letter */
else if ( tpath[0] == '\\' && tpath[1] == '\\') {
/* UNC path - strip off the server and sharename */
} else {
strcpy(outPathp,&tpath[--i]);
}
+#else
+ {
+ HANDLE rootDir;
+
+ strcpy(outPathp, tpath);
+
+ sprintf(outPathp, "%c:\\", tpath[0]);
+ rootDir = CreateFile(outPathp, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (!DeviceIoControl(rootDir, IOCTL_AFSRDR_GET_PATH, NULL, 0, absRoot_w, 100*sizeof(wchar_t), &length, NULL))
+ {
+ CloseHandle(rootDir);
+ return CM_ERROR_NOSUCHPATH;
+ }
+ CloseHandle(rootDir);
+
+ ifs_ConvertFileName(absRoot_w, length/sizeof(wchar_t), absRoot, 100);
+
+ }
+#endif
} else {
/* this should never happen */
strcpy(outPathp, tpath);