<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Index: openafs/src/WINNT/afsd/afsd_flushvol.c
diff -c openafs/src/WINNT/afsd/afsd_flushvol.c:1.6 openafs/src/WINNT/afsd/afsd_flushvol.c:1.6.2.1
*** openafs/src/WINNT/afsd/afsd_flushvol.c:1.6	Fri Jun 18 00:52:25 2004
--- openafs/src/WINNT/afsd/afsd_flushvol.c	Sun Oct  3 09:35:15 2004
***************
*** 27,32 ****
--- 27,35 ----
  
  #include "afsd_flushvol.h"
  #include "afsd_eventlog.h"
+ #include "lanahelper.h"
+ 
+ extern void afsi_log(char *pattern, ...);
  
  static FLUSHVOLTHREADINFO	gThreadInfo   = {0};
  static HANDLE			gThreadHandle = NULL;
***************
*** 45,189 ****
  afs_int32
  afsd_ServicePerformFlushVolumeCmd(char *data)
  {
! 	register afs_int32 code;
! 	struct ViceIoctl blob;
  
! 	memset(&amp;blob, '\0', sizeof(blob));
! 	code = pioctl(data, VIOC_FLUSHVOLUME, &amp;blob, 0);
      
! 	return code;
  }
  
  BOOL
  afsd_ServicePerformFlushVolumes()
! {
! 	CONST CHAR	COLON = ':';
! 	CONST CHAR	SLASH = '\\';
! 	CONST DWORD	NETRESBUFSIZE = 16384;
! 	CHAR		bufMessage[1024];
! 	UINT		i;
! 	DWORD		dwServerSize;
! 	DWORD		dwRet;
! 	DWORD		dwCount;
! 	DWORD		dwNetResBufSize;
! 	DWORD		dwTotalVols = 0;
! 	DWORD		dwVolBegin, dwVolEnd;
! 	DWORD		dwFlushBegin, dwFlushEnd;
! 	HANDLE		hEnum;
! 	LPNETRESOURCE	lpNetResBuf, lpnr;
! 	PCHAR		pszShareName, pc;
! 	afs_int32	afsRet = 0;
! 	
! 	// Determine the root share name (\\AFS\ALL or \\&lt;machine&gt;-AFS\ALL),
! 	// and the length of the server name prefix.
! 	pszShareName = smb_GetSharename();
! 	if (pszShareName == NULL)
! 	{
! 		LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_NO_SHARE_NAME, NULL);
! 		return FALSE;
! 	}
! 	pc = strrchr(pszShareName, SLASH);
! 	if ((pc == NULL) || ((dwServerSize = pc - pszShareName) &lt; 3))
! 	{
! 		LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_BAD_SHARE_NAME,
! 			 pszShareName, NULL);
! 		free(pszShareName);
! 		return FALSE;
! 	}
! 
! 	// Allocate a buffer to hold network resources returned by
! 	// WNetEnumResource().
! 	lpNetResBuf = malloc(NETRESBUFSIZE);
! 	if (lpNetResBuf == NULL)
! 	{
! 		// Out of memory, give up now.
! 		LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_NO_MEMORY, NULL);
! 		free(pszShareName);
! 		return FALSE;
! 	}
! 
! 	// Initialize the flush timer.  Note that GetTickCount() returns
! 	// the number of milliseconds since the system started, in a DWORD,
! 	// so that the value wraps around every 49.7 days.  We do not bother
! 	// to handle the case where the flush elapsed time is greater than
! 	// that.
! 	dwFlushBegin = GetTickCount();
! 	
! 	dwRet = WNetOpenEnum(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL,
! 			     &amp;hEnum);
! 	if (dwRet != NO_ERROR)
! 	{
! 		LogEventMessage(EVENTLOG_ERROR_TYPE, MSG_FLUSH_OPEN_ENUM_ERROR,
! 				dwRet);
! 		free(pszShareName);
! 		return FALSE;
! 	}
! 
! 	// Loop to enumerate network resources, and flush those associated
! 	// with AFS volumes.
! 	while (1)
! 	{
! 		dwCount = -1;
! 		memset(lpNetResBuf, 0, NETRESBUFSIZE);
! 		dwNetResBufSize = NETRESBUFSIZE;
! 		dwRet = WNetEnumResource(hEnum, &amp;dwCount,
! 					 lpNetResBuf, &amp;dwNetResBufSize);
! 		if (dwRet != NO_ERROR)
! 			break;
! 		// Iterate over the returned network resources.
! 		for (i = 0, lpnr = lpNetResBuf; i &lt; dwCount; i++, lpnr++)
! 		{
! 			// Ensure resource has a remote name, and is connected.
! 			if ((lpnr-&gt;lpRemoteName == NULL) ||
! 			    (lpnr-&gt;dwScope != RESOURCE_CONNECTED))
! 				continue;
! 			if ((_strnicmp(lpnr-&gt;lpRemoteName, pszShareName,
! 				       dwServerSize) == 0) &amp;&amp;
! 			    (lpnr-&gt;lpRemoteName[dwServerSize] == SLASH))
! 			{
! 				// got one!
! 				// but we don't want to flush '\\[...]afs\all'
! 				if (_stricmp(lpnr-&gt;lpRemoteName,
! 					     pszShareName) == 0)
! 					continue;
! 				++dwTotalVols;
! 
! 				dwVolBegin = GetTickCount();
! 				afsRet = afsd_ServicePerformFlushVolumeCmd(lpnr-&gt;lpRemoteName);
! 				dwVolEnd = GetTickCount();
! 				if (afsRet == 0)
! 				{
! 					LogTimingEvent(MSG_TIME_FLUSH_PER_VOLUME,
! 						       lpnr-&gt;lpRemoteName,
! 						       dwVolEnd - dwVolBegin);
! 				}
! 				else
! 				{
! 					LogEvent(EVENTLOG_WARNING_TYPE,
! 						 MSG_FLUSH_FAILED,
! 						 lpnr-&gt;lpRemoteName, NULL);
! 				}
! 			}
! 		}
! 	}
! 	WNetCloseEnum(hEnum);
! 	free(lpNetResBuf);
! 	free(pszShareName);
! 	if (dwRet != ERROR_NO_MORE_ITEMS)
! 	{
! 		LogEventMessage(EVENTLOG_ERROR_TYPE, MSG_FLUSH_ENUM_ERROR,
! 				dwRet);
! 		return FALSE;
! 	}
  
! 	dwFlushEnd = GetTickCount();
  	
! 	// display total volume count in Event Logger
! 	sprintf(bufMessage, "%d", dwTotalVols);
! 	LogTimingEvent(MSG_TIME_FLUSH_TOTAL, bufMessage,
! 		       dwFlushEnd - dwFlushBegin);
  
! 	return TRUE;
  }
  
  // Report a timing event to the system event log.
--- 48,197 ----
  afs_int32
  afsd_ServicePerformFlushVolumeCmd(char *data)
  {
!     register afs_int32 code;
!     struct ViceIoctl blob;
  
!     afsi_log("Flushing Volume \"%s\"",data);
!     memset(&amp;blob, '\0', sizeof(blob));
!     code = pioctl(data, VIOC_FLUSHVOLUME, &amp;blob, 0);
      
!     return code;
  }
  
  BOOL
  afsd_ServicePerformFlushVolumes()
! {       
!     CONST CHAR	COLON = ':';
!     CONST CHAR	SLASH = '\\';
!     CONST DWORD	NETRESBUFSIZE = 16384;
!     CHAR		bufMessage[1024];
!     UINT		i;
!     DWORD		dwServerSize;
!     DWORD		dwRet;
!     DWORD		dwCount;
!     DWORD		dwNetResBufSize;
!     DWORD		dwTotalVols = 0;
!     DWORD		dwVolBegin, dwVolEnd;
!     DWORD		dwFlushBegin, dwFlushEnd;
!     HANDLE		hEnum;
!     LPNETRESOURCE	lpNetResBuf, lpnr;
!     PCHAR		pszShareName, pc;
!     afs_int32	afsRet = 0;
! 
!     if ( lana_OnlyLoopback() ) {
!         // Nothing to do if we only have a loopback interface
!         return TRUE;
!     }
! 
!     // Determine the root share name (\\AFS\ALL or \\&lt;machine&gt;-AFS\ALL),
!     // and the length of the server name prefix.
!     pszShareName = smb_GetSharename();
!     if (pszShareName == NULL)
!     {
!         LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_NO_SHARE_NAME, NULL);
!         return FALSE;
!     }
!     pc = strrchr(pszShareName, SLASH);
!     if ((pc == NULL) || ((dwServerSize = pc - pszShareName) &lt; 3))
!     {
!         LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_BAD_SHARE_NAME,
!                   pszShareName, NULL);
!         free(pszShareName);
!         return FALSE;
!     }
! 
!     // Allocate a buffer to hold network resources returned by
!     // WNetEnumResource().
!     lpNetResBuf = malloc(NETRESBUFSIZE);
!     if (lpNetResBuf == NULL)
!     {
!         // Out of memory, give up now.
!         LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_NO_MEMORY, NULL);
!         free(pszShareName);
!         return FALSE;
!     }
! 
!     // Initialize the flush timer.  Note that GetTickCount() returns
!     // the number of milliseconds since the system started, in a DWORD,
!     // so that the value wraps around every 49.7 days.  We do not bother
!     // to handle the case where the flush elapsed time is greater than
!     // that.
!     dwFlushBegin = GetTickCount();
! 
!     dwRet = WNetOpenEnum(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL,
!                           &amp;hEnum);
!     if (dwRet != NO_ERROR)
!     {
!         LogEventMessage(EVENTLOG_ERROR_TYPE, MSG_FLUSH_OPEN_ENUM_ERROR,
!                          dwRet);
!         free(pszShareName);
!         return FALSE;
!     }
! 
!     // Loop to enumerate network resources, and flush those associated
!     // with AFS volumes.
!     while (1)
!     {
!         dwCount = -1;
!         memset(lpNetResBuf, 0, NETRESBUFSIZE);
!         dwNetResBufSize = NETRESBUFSIZE;
!         dwRet = WNetEnumResource(hEnum, &amp;dwCount,
!                                   lpNetResBuf, &amp;dwNetResBufSize);
!         if (dwRet != NO_ERROR)
!             break;
!         // Iterate over the returned network resources.
!         for (i = 0, lpnr = lpNetResBuf; i &lt; dwCount; i++, lpnr++)
!         {
!             // Ensure resource has a remote name, and is connected.
!             if ((lpnr-&gt;lpRemoteName == NULL) ||
!                  (lpnr-&gt;dwScope != RESOURCE_CONNECTED))
!                 continue;
!             if ((_strnicmp(lpnr-&gt;lpRemoteName, pszShareName,
!                             dwServerSize) == 0) &amp;&amp;
!                  (lpnr-&gt;lpRemoteName[dwServerSize] == SLASH))
!             {
!                 // got one!
!                 // but we don't want to flush '\\[...]afs\all'
!                 if (_stricmp(lpnr-&gt;lpRemoteName, pszShareName) == 0)
!                     continue;
!                 ++dwTotalVols;
! 
!                 dwVolBegin = GetTickCount();
!                 afsRet = afsd_ServicePerformFlushVolumeCmd(lpnr-&gt;lpRemoteName);
!                 dwVolEnd = GetTickCount();
!                 if (afsRet == 0)
!                 {
!                     LogTimingEvent(MSG_TIME_FLUSH_PER_VOLUME,
!                                     lpnr-&gt;lpRemoteName,
!                                     dwVolEnd - dwVolBegin);
!                 }
!                 else
!                 {
!                     LogEvent(EVENTLOG_WARNING_TYPE,
!                               MSG_FLUSH_FAILED,
!                               lpnr-&gt;lpRemoteName, NULL);
!                 }
!             }
!         }
!     }
!     WNetCloseEnum(hEnum);
!     free(lpNetResBuf);
!     free(pszShareName);
!     if (dwRet != ERROR_NO_MORE_ITEMS)
!     {
!         LogEventMessage(EVENTLOG_ERROR_TYPE, MSG_FLUSH_ENUM_ERROR,
!                          dwRet);
!         return FALSE;
!     }
  
!     dwFlushEnd = GetTickCount();
  	
!     // display total volume count in Event Logger
!     sprintf(bufMessage, "%d", dwTotalVols);
!     LogTimingEvent(MSG_TIME_FLUSH_TOTAL, bufMessage,
!                     dwFlushEnd - dwFlushBegin);
  
!     return TRUE;
  }
  
  // Report a timing event to the system event log.
***************
*** 193,203 ****
  static VOID
  LogTimingEvent(DWORD dwEventID, LPTSTR lpString1, DWORD dwTime)
  {
! 	CHAR	szTime[16];
  	
! 	sprintf(szTime, "%lu", dwTime);
! 	LogEvent(EVENTLOG_INFORMATION_TYPE, dwEventID, lpString1, szTime,
! 		 NULL);
  }
  
  
--- 201,211 ----
  static VOID
  LogTimingEvent(DWORD dwEventID, LPTSTR lpString1, DWORD dwTime)
  {
!     CHAR	szTime[16];
  	
!     sprintf(szTime, "%lu", dwTime);
!     LogEvent(EVENTLOG_INFORMATION_TYPE, dwEventID, lpString1, szTime,
!               NULL);
  }
  
  
***************
*** 223,313 ****
  //
  HANDLE GetUserToken(DWORD access)
  {
! 	HANDLE hTok = NULL;
! 	DWORD pid = 0, tid = 0;
! 
! 	// Try it the easy way first - look for a window owned by the shell on
! 	// our current desktop.  If we find one, use that to get the process id.
! 	HWND shell = FindWindowEx(NULL, NULL, "Progman", NULL);
! 	if (shell != NULL)
! 	{
! 		tid = GetWindowThreadProcessId(shell, &amp;pid);
! 	}
! 
! 	// We are possibly running on a private window station and desktop: we must
! 	// switch to the default (which we suppose is where we will find the
! 	// running shell).
! 	else
! 	{
! 		HWINSTA saveWinSta = GetProcessWindowStation(); 
! 		HDESK saveDesk = GetThreadDesktop(GetCurrentThreadId()); 
! 		HWINSTA winSta = NULL;
! 		HDESK desk = NULL;
! 		BOOL changeFlag = FALSE;
! 		BOOL dummy = saveWinSta != NULL &amp;&amp;
! 					 saveDesk != NULL &amp;&amp;
! 					 (winSta = OpenWindowStation("WinSta0", FALSE,
! 									MAXIMUM_ALLOWED)) != NULL &amp;&amp;
! 					 (changeFlag = SetProcessWindowStation(winSta)) != 0 &amp;&amp;
! 					 (desk = OpenDesktop("Default", 0, FALSE,
! 									MAXIMUM_ALLOWED)) != NULL &amp;&amp;
! 					 SetThreadDesktop(desk) != 0;
! 
! 		// Now find the window and process on this desktop
! 		shell = FindWindowEx(NULL, NULL, "Progman", NULL);
! 		if (shell != NULL) 
! 		{
! 			tid = GetWindowThreadProcessId(shell, &amp;pid);
! 		}
! 
! 		// Restore our own window station and desktop
! 		if (changeFlag)
! 		{
! 			SetProcessWindowStation(saveWinSta);
! 			SetThreadDesktop(saveDesk);
! 		}
! 
! 		// Close temporary objects
! 		if (winSta != NULL)
! 			CloseWindowStation(winSta);
! 		if (desk != NULL) 
! 			CloseDesktop(desk);
! 	}
! 
! 	//
! 	// If we have a process id, use that to get the process handle and 
! 	// from there the process' access token.
! 	//
! 	if (pid != 0)
! 	{
! 		HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
! 		if (hProc != NULL)
! 		{
! 			OpenProcessToken(hProc, access, &amp;hTok) || (hTok = NULL);
! 			CloseHandle(hProc);
! 		}
! 	}
  
! 	// Return token if we got one
! 	return hTok;
! }
  
  // impersonate logged-on user as client
  BOOL
  ImpersonateClient()
  {
! 	DWORD	dwDesiredAccess = TOKEN_ALL_ACCESS;
! 	HANDLE	hUserToken = GetUserToken(dwDesiredAccess);
  	
! 	if (hUserToken == NULL)
! 		return FALSE;
! 	if (ImpersonateLoggedOnUser(hUserToken) == 0)
! 	{
! 		LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_IMPERSONATE_ERROR,
! 			 NULL);
! 		return FALSE;
! 	}
! 	return TRUE;
  }
  	
  /////////////////////////////////////////////////////////////////////
--- 231,321 ----
  //
  HANDLE GetUserToken(DWORD access)
  {
!     HANDLE hTok = NULL;
!     DWORD pid = 0, tid = 0;
  
!     // Try it the easy way first - look for a window owned by the shell on
!     // our current desktop.  If we find one, use that to get the process id.
!     HWND shell = FindWindowEx(NULL, NULL, "Progman", NULL);
!     if (shell != NULL)
!     {
!         tid = GetWindowThreadProcessId(shell, &amp;pid);
!     }
! 
!     // We are possibly running on a private window station and desktop: we must
!     // switch to the default (which we suppose is where we will find the
!     // running shell).
!     else
!     {
!         HWINSTA saveWinSta = GetProcessWindowStation(); 
!         HDESK saveDesk = GetThreadDesktop(GetCurrentThreadId()); 
!         HWINSTA winSta = NULL;
!         HDESK desk = NULL;
!         BOOL changeFlag = FALSE;
!         BOOL dummy = saveWinSta != NULL &amp;&amp;
!                      saveDesk != NULL &amp;&amp;
!                      (winSta = OpenWindowStation("WinSta0", FALSE,
!                                                  MAXIMUM_ALLOWED)) != NULL &amp;&amp;
!                      (changeFlag = SetProcessWindowStation(winSta)) != 0 &amp;&amp;
!                      (desk = OpenDesktop("Default", 0, FALSE,
!                                           MAXIMUM_ALLOWED)) != NULL &amp;&amp;
!                      SetThreadDesktop(desk) != 0;
! 
!         // Now find the window and process on this desktop
!         shell = FindWindowEx(NULL, NULL, "Progman", NULL);
!         if (shell != NULL) 
!         {
!             tid = GetWindowThreadProcessId(shell, &amp;pid);
!         }
! 
!         // Restore our own window station and desktop
!         if (changeFlag)
!         {
!             SetProcessWindowStation(saveWinSta);
!             SetThreadDesktop(saveDesk);
!         }
! 
!         // Close temporary objects
!         if (winSta != NULL)
!             CloseWindowStation(winSta);
!         if (desk != NULL) 
!             CloseDesktop(desk);
!     }
! 
!     //
!     // If we have a process id, use that to get the process handle and 
!     // from there the process' access token.
!     //
!     if (pid != 0)
!     {
!         HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
!         if (hProc != NULL)
!         {
!             OpenProcessToken(hProc, access, &amp;hTok) || (hTok = NULL);
!             CloseHandle(hProc);
!         }
!     }
! 
!     // Return token if we got one
!     return hTok;
! }       
  
  // impersonate logged-on user as client
  BOOL
  ImpersonateClient()
  {
!     DWORD	dwDesiredAccess = TOKEN_ALL_ACCESS;
!     HANDLE	hUserToken = GetUserToken(dwDesiredAccess);
  	
!     if (hUserToken == NULL)
!         return FALSE;
!     if (ImpersonateLoggedOnUser(hUserToken) == 0)
!     {
!         LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_IMPERSONATE_ERROR,
!                   NULL);
!         return FALSE;
!     }
!     return TRUE;
  }
  	
  /////////////////////////////////////////////////////////////////////
***************
*** 317,383 ****
  DWORD WINAPI 
  afsd_ServiceFlushVolumesThreadProc(LPVOID lpParam)
  {
! 	FLUSHVOLTHREADINFO ThreadInfo;
! 	PFLUSHVOLTHREADINFO pThreadInfo = (PFLUSHVOLTHREADINFO) lpParam; 
! 	HANDLE	arHandles[2] = {0};
! 	DWORD	dwWaitState = 0;
! 
! 	// thread running - get handles
! 	ThreadInfo.hEventPowerEvent = pThreadInfo-&gt;hEventPowerEvent;
! 	ThreadInfo.hEventResumeMain = pThreadInfo-&gt;hEventResumeMain;
! 	ThreadInfo.hEventTerminate  = pThreadInfo-&gt;hEventTerminate;
! 
! 	// setup to wait
! 	arHandles[0] = ThreadInfo.hEventTerminate;
! 	arHandles[1] = ThreadInfo.hEventPowerEvent;
! 
! 	// do stuff ..
! 	while (1)
! 	{
! 		// wait for an event to happen
! 		dwWaitState = WaitForMultipleObjectsEx(2, arHandles, FALSE, INFINITE, FALSE);
! 
! 		switch (dwWaitState)
! 		{
! 		case WAIT_OBJECT_0:
! 			// termination signaled
! 			RevertToSelf();
              CheckAndCloseHandle(ThreadInfo.hEventPowerEvent);
              CheckAndCloseHandle(ThreadInfo.hEventResumeMain);
              CheckAndCloseHandle(ThreadInfo.hEventTerminate);
! 			ExitThread(0);
! 			break;
  
! 		case WAIT_OBJECT_0+1:
! 			// Power event 
! 			// - flush 'em!
! 			if (ImpersonateClient())
! 			{
! 				afsd_ServicePerformFlushVolumes();
! 			}
! 			// acknowledge event
! 			ResetEvent(ThreadInfo.hEventPowerEvent);
! 			break;
! 
! 		case WAIT_ABANDONED_0:
! 		case WAIT_ABANDONED_0+1:
! 		case WAIT_IO_COMPLETION:
! 		case WAIT_TIMEOUT:
! 			// sno*
! 			LogEvent(EVENTLOG_WARNING_TYPE,
! 				 MSG_FLUSH_UNEXPECTED_EVENT, NULL);
! 			break;
! 		
! 		}	// end switch
! 
! 		// signal back to waiting mainline
! 		SetEvent(ThreadInfo.hEventResumeMain);
! 
! 	}	// end while
! 	
! 	// I suppose we never get here
! 	ExitThread(0);
! }
  
  /////////////////////////////////////////////////////////////////////
  //
--- 325,391 ----
  DWORD WINAPI 
  afsd_ServiceFlushVolumesThreadProc(LPVOID lpParam)
  {
!     FLUSHVOLTHREADINFO ThreadInfo;
!     PFLUSHVOLTHREADINFO pThreadInfo = (PFLUSHVOLTHREADINFO) lpParam; 
!     HANDLE	arHandles[2] = {0};
!     DWORD	dwWaitState = 0;
! 
!     // thread running - get handles
!     ThreadInfo.hEventPowerEvent = pThreadInfo-&gt;hEventPowerEvent;
!     ThreadInfo.hEventResumeMain = pThreadInfo-&gt;hEventResumeMain;
!     ThreadInfo.hEventTerminate  = pThreadInfo-&gt;hEventTerminate;
! 
!     // setup to wait
!     arHandles[0] = ThreadInfo.hEventTerminate;
!     arHandles[1] = ThreadInfo.hEventPowerEvent;
! 
!     // do stuff ..
!     while (1)
!     {
!         // wait for an event to happen
!         dwWaitState = WaitForMultipleObjectsEx(2, arHandles, FALSE, INFINITE, FALSE);
! 
!         switch (dwWaitState)
!         {
!         case WAIT_OBJECT_0:
!             // termination signaled
!             RevertToSelf();
              CheckAndCloseHandle(ThreadInfo.hEventPowerEvent);
              CheckAndCloseHandle(ThreadInfo.hEventResumeMain);
              CheckAndCloseHandle(ThreadInfo.hEventTerminate);
!             ExitThread(0);
!             break;
  
!         case WAIT_OBJECT_0+1:
!             // Power event 
!             // - flush 'em!
!             if (ImpersonateClient())
!             {
!                 afsd_ServicePerformFlushVolumes();
!             }
!             // acknowledge event
!             ResetEvent(ThreadInfo.hEventPowerEvent);
!             break;
! 
!         case WAIT_ABANDONED_0:
!         case WAIT_ABANDONED_0+1:
!         case WAIT_IO_COMPLETION:
!         case WAIT_TIMEOUT:
!             // sno*
!             LogEvent(EVENTLOG_WARNING_TYPE,
!                       MSG_FLUSH_UNEXPECTED_EVENT, NULL);
!             break;
! 
!         }	// end switch
! 
!         // signal back to waiting mainline
!         SetEvent(ThreadInfo.hEventResumeMain);
! 
!     }	// end while
! 
!     // I suppose we never get here
!     ExitThread(0);
! }       
  
  /////////////////////////////////////////////////////////////////////
  //
***************
*** 387,397 ****
  VOID	
  CheckAndCloseHandle(HANDLE thisHandle)
  {
! 	if (thisHandle != NULL)
! 	{
! 		CloseHandle(thisHandle);
! 		thisHandle = NULL;
! 	}
  }
  
  //
--- 395,405 ----
  VOID	
  CheckAndCloseHandle(HANDLE thisHandle)
  {
!     if (thisHandle != NULL)
!     {
!         CloseHandle(thisHandle);
!         thisHandle = NULL;
!     }
  }
  
  //
***************
*** 400,461 ****
  BOOL
  PowerNotificationThreadCreate()
  {
! 	BOOL	bSuccess = FALSE;
! 	DWORD	dwThreadId = 0;
      char    eventName[MAX_PATH];
  	
! 	do 
! 	{
! 		// create power event notification event
! 		// bManualReset=TRUE, bInitialState=FALSE
! 		gThreadInfo.hEventPowerEvent = CreateEvent(NULL, TRUE, FALSE, 
                                                     TEXT("afsd_flushvol_EventPowerEvent"));
          if ( GetLastError() == ERROR_ALREADY_EXISTS )
              afsi_log("Event Object Already Exists: %s", eventName);
! 		if (gThreadInfo.hEventPowerEvent == NULL)
! 			break;			
  
! 		// create mainline resume event
! 		// bManualReset=FALSE, bInitialState=FALSE
! 		gThreadInfo.hEventResumeMain = CreateEvent(NULL, FALSE, FALSE, 
                                                     TEXT("afsd_flushvol_EventResumeMain"));
          if ( GetLastError() == ERROR_ALREADY_EXISTS )
              afsi_log("Event Object Already Exists: %s", eventName);
! 		if (gThreadInfo.hEventResumeMain == NULL)
! 			break;			
  
! 		// create thread terminate event
! 		// bManualReset=FALSE, bInitialState=FALSE
! 		gThreadInfo.hEventTerminate = CreateEvent(NULL, FALSE, FALSE, 
                                                    TEXT("afsd_flushvol_EventTerminate"));
          if ( GetLastError() == ERROR_ALREADY_EXISTS )
              afsi_log("Event Object Already Exists: %s", eventName);
! 		if (gThreadInfo.hEventTerminate == NULL)
! 			break;			
  
! 		// good so far - create thread
! 		gThreadHandle = CreateThread(NULL, 0,
! 							afsd_ServiceFlushVolumesThreadProc,
! 							(LPVOID) &amp;gThreadInfo,
! 							0, &amp;dwThreadId);
  		
! 		if (!gThreadHandle)
! 			break;
  
! 		bSuccess = TRUE;
  
! 	} while (0);
  
  
! 	if (!bSuccess)
! 	{
! 		CheckAndCloseHandle(gThreadInfo.hEventPowerEvent);
! 		CheckAndCloseHandle(gThreadInfo.hEventResumeMain);
! 		CheckAndCloseHandle(gThreadInfo.hEventTerminate);
! 		CheckAndCloseHandle(gThreadHandle);
! 	}
  		
! 	return bSuccess;
  }
  
  //
--- 408,469 ----
  BOOL
  PowerNotificationThreadCreate()
  {
!     BOOL	bSuccess = FALSE;
!     DWORD	dwThreadId = 0;
      char    eventName[MAX_PATH];
  	
!     do 
!     {
!         // create power event notification event
!         // bManualReset=TRUE, bInitialState=FALSE
!         gThreadInfo.hEventPowerEvent = CreateEvent(NULL, TRUE, FALSE, 
                                                     TEXT("afsd_flushvol_EventPowerEvent"));
          if ( GetLastError() == ERROR_ALREADY_EXISTS )
              afsi_log("Event Object Already Exists: %s", eventName);
!         if (gThreadInfo.hEventPowerEvent == NULL)
!             break;			
  
!         // create mainline resume event
!         // bManualReset=FALSE, bInitialState=FALSE
!         gThreadInfo.hEventResumeMain = CreateEvent(NULL, FALSE, FALSE, 
                                                     TEXT("afsd_flushvol_EventResumeMain"));
          if ( GetLastError() == ERROR_ALREADY_EXISTS )
              afsi_log("Event Object Already Exists: %s", eventName);
!         if (gThreadInfo.hEventResumeMain == NULL)
!             break;			
  
!         // create thread terminate event
!         // bManualReset=FALSE, bInitialState=FALSE
!         gThreadInfo.hEventTerminate = CreateEvent(NULL, FALSE, FALSE, 
                                                    TEXT("afsd_flushvol_EventTerminate"));
          if ( GetLastError() == ERROR_ALREADY_EXISTS )
              afsi_log("Event Object Already Exists: %s", eventName);
!         if (gThreadInfo.hEventTerminate == NULL)
!             break;			
  
!         // good so far - create thread
!         gThreadHandle = CreateThread(NULL, 0,
!                                      afsd_ServiceFlushVolumesThreadProc,
!                                      (LPVOID) &amp;gThreadInfo,
!                                      0, &amp;dwThreadId);
  		
!         if (!gThreadHandle)
!             break;
  
!         bSuccess = TRUE;
  
!     } while (0);
  
  
!     if (!bSuccess)
!     {
!         CheckAndCloseHandle(gThreadInfo.hEventPowerEvent);
!         CheckAndCloseHandle(gThreadInfo.hEventResumeMain);
!         CheckAndCloseHandle(gThreadInfo.hEventTerminate);
!         CheckAndCloseHandle(gThreadHandle);
!     }
  		
!     return bSuccess;
  }
  
  //
***************
*** 464,484 ****
  BOOL
  PowerNotificationThreadNotify()
  {
! 	DWORD		dwRet = 0;
! 	BOOL		bRet  = FALSE;
  
! 	// Notify thread of power event, and wait for the HardDead timeout period
! 	dwRet = SignalObjectAndWait(
! 				gThreadInfo.hEventPowerEvent,	// object to signal
! 				gThreadInfo.hEventResumeMain,	// object to watch
! 				HardDeadtimeout*1000,			// timeout (ms)
! 				FALSE							// alertable
! 				);
  
! 	if (dwRet == WAIT_OBJECT_0)
! 		bRet = TRUE;
  
! 	return bRet;
  }
  
  //
--- 472,492 ----
  BOOL
  PowerNotificationThreadNotify()
  {
!     DWORD		dwRet = 0;
!     BOOL		bRet  = FALSE;
  
!     // Notify thread of power event, and wait for the HardDead timeout period
!     dwRet = SignalObjectAndWait(
!                 gThreadInfo.hEventPowerEvent,	// object to signal
!                 gThreadInfo.hEventResumeMain,	// object to watch
! 		HardDeadtimeout*1000,		// timeout (ms)
! 		FALSE				// alertable
! 		);
  
!     if (dwRet == WAIT_OBJECT_0)
!         bRet = TRUE;
  
!     return bRet;
  }
  
  //
***************
*** 487,498 ****
  VOID
  PowerNotificationThreadExit()
  {
! 	// ExitThread
! 	if (gThreadHandle)
! 	{
! 		SetEvent(gThreadInfo.hEventTerminate);
          WaitForSingleObject(gThreadHandle, INFINITE);
! 		CloseHandle(gThreadHandle);
! 	}
  }
  
--- 495,506 ----
  VOID
  PowerNotificationThreadExit()
  {
!     // ExitThread
!     if (gThreadHandle)
!     {
!         SetEvent(gThreadInfo.hEventTerminate);
          WaitForSingleObject(gThreadHandle, INFINITE);
!         CloseHandle(gThreadHandle);
!     }
  }
  
Index: openafs/src/WINNT/afsd/afsd_init.c
diff -c openafs/src/WINNT/afsd/afsd_init.c:1.40.2.2 openafs/src/WINNT/afsd/afsd_init.c:1.40.2.5
*** openafs/src/WINNT/afsd/afsd_init.c:1.40.2.2	Tue Aug 17 00:28:38 2004
--- openafs/src/WINNT/afsd/afsd_init.c	Mon Oct 18 00:09:25 2004
***************
*** 81,87 ****
  cm_initparams_v1 cm_initParams;
  
  char *cm_sysName = 0;
! int   cm_sysNameCount = 0;
  char *cm_sysNameList[MAXNUMSYSNAMES];
  
  DWORD TraceOption = 0;
--- 81,87 ----
  cm_initparams_v1 cm_initParams;
  
  char *cm_sysName = 0;
! unsigned int   cm_sysNameCount = 0;
  char *cm_sysNameList[MAXNUMSYSNAMES];
  
  DWORD TraceOption = 0;
***************
*** 358,429 ****
  
  int afsd_InitCM(char **reasonP)
  {
! 	osi_uid_t debugID;
! 	long cacheBlocks;
! 	long cacheSize;
! 	long logChunkSize;
! 	long stats;
! 	long traceBufSize;
      long maxcpus;
! 	long ltt, ltto;
      long rx_mtu, rx_nojumbo;
      long virtualCache;
! 	char rootCellName[256];
! 	struct rx_service *serverp;
! 	static struct rx_securityClass *nullServerSecurityClassp;
! 	struct hostent *thp;
! 	char *msgBuf;
! 	char buf[200];
! 	HKEY parmKey;
! 	DWORD dummyLen;
      DWORD regType;
! 	long code;
! 	/*int freelanceEnabled;*/
! 	WSADATA WSAjunk;
      lana_number_t lanaNum;
      int i;
  
! 	WSAStartup(0x0101, &amp;WSAjunk);
  
      afsd_initUpperCaseTable();
  
! 	/* setup osidebug server at RPC slot 1000 */
! 	osi_LongToUID(1000, &amp;debugID);
! 	code = osi_InitDebug(&amp;debugID);
! 	afsi_log("osi_InitDebug code %d", code);
  
      //	osi_LockTypeSetDefault("stat");	/* comment this out for speed *
! 	if (code != 0) {
! 		*reasonP = "unknown error";
! 		return -1;
! 	}
  
! 	/* who are we ? */
! 	gethostname(cm_HostName, sizeof(cm_HostName));
! 	afsi_log("gethostname %s", cm_HostName);
! 	thp = gethostbyname(cm_HostName);
! 	memcpy(&amp;cm_HostAddr, thp-&gt;h_addr_list[0], 4);
! 
! 	/* seed random number generator */
! 	srand(ntohl(cm_HostAddr));
! 
! 	/* Look up configuration parameters in Registry */
! 	code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
! 				0, KEY_QUERY_VALUE, &amp;parmKey);
! 	if (code != ERROR_SUCCESS) {
! 		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
! 				| FORMAT_MESSAGE_ALLOCATE_BUFFER,
! 			      NULL, code, 0, (LPTSTR)&amp;msgBuf, 0, NULL);
! 		StringCbPrintfA(buf, sizeof(buf),
! 			"Failure in configuration while opening Registry: %s",
! 			msgBuf);
! 		osi_panic(buf, __FILE__, __LINE__);
! 	}
  
      dummyLen = sizeof(maxcpus);
! 	code = RegQueryValueEx(parmKey, "MaxCPUs", NULL, NULL,
! 				(BYTE *) &amp;maxcpus, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS) {
          HANDLE hProcess;
          DWORD_PTR processAffinityMask, systemAffinityMask;
  
--- 358,429 ----
  
  int afsd_InitCM(char **reasonP)
  {
!     osi_uid_t debugID;
!     long cacheBlocks;
!     long cacheSize;
!     long logChunkSize;
!     long stats;
!     long traceBufSize;
      long maxcpus;
!     long ltt, ltto;
      long rx_mtu, rx_nojumbo;
      long virtualCache;
!     char rootCellName[256];
!     struct rx_service *serverp;
!     static struct rx_securityClass *nullServerSecurityClassp;
!     struct hostent *thp;
!     char *msgBuf;
!     char buf[1024];
!     HKEY parmKey;
!     DWORD dummyLen;
      DWORD regType;
!     long code;
!     /*int freelanceEnabled;*/
!     WSADATA WSAjunk;
      lana_number_t lanaNum;
      int i;
  
!     WSAStartup(0x0101, &amp;WSAjunk);
  
      afsd_initUpperCaseTable();
  
!     /* setup osidebug server at RPC slot 1000 */
!     osi_LongToUID(1000, &amp;debugID);
!     code = osi_InitDebug(&amp;debugID);
!     afsi_log("osi_InitDebug code %d", code);
  
      //	osi_LockTypeSetDefault("stat");	/* comment this out for speed *
!     if (code != 0) {
!         *reasonP = "unknown error";
!         return -1;
!     }
  
!     /* who are we ? */
!     gethostname(cm_HostName, sizeof(cm_HostName));
!     afsi_log("gethostname %s", cm_HostName);
!     thp = gethostbyname(cm_HostName);
!     memcpy(&amp;cm_HostAddr, thp-&gt;h_addr_list[0], 4);
! 
!     /* seed random number generator */
!     srand(ntohl(cm_HostAddr));
! 
!     /* Look up configuration parameters in Registry */
!     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
!                          0, KEY_QUERY_VALUE, &amp;parmKey);
!     if (code != ERROR_SUCCESS) {
!         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
!                        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
!                        NULL, code, 0, (LPTSTR)&amp;msgBuf, 0, NULL);
!         StringCbPrintfA(buf, sizeof(buf),
!                          "Failure in configuration while opening Registry: %s",
!                          msgBuf);
!         osi_panic(buf, __FILE__, __LINE__);
!     }
  
      dummyLen = sizeof(maxcpus);
!     code = RegQueryValueEx(parmKey, "MaxCPUs", NULL, NULL,
!                             (BYTE *) &amp;maxcpus, &amp;dummyLen);
!     if (code == ERROR_SUCCESS) {
          HANDLE hProcess;
          DWORD_PTR processAffinityMask, systemAffinityMask;
  
***************
*** 456,596 ****
          }
      }
  
! 	dummyLen = sizeof(TraceOption);
! 	code = RegQueryValueEx(parmKey, "TraceOption", NULL, NULL,
! 				(BYTE *) &amp;TraceOption, &amp;dummyLen);
      afsi_log("Event Log Tracing = %lX", TraceOption);
  
! 	dummyLen = sizeof(traceBufSize);
! 	code = RegQueryValueEx(parmKey, "TraceBufferSize", NULL, NULL,
! 				(BYTE *) &amp;traceBufSize, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("Trace Buffer size %d", traceBufSize);
! 	else {
! 		traceBufSize = CM_CONFIGDEFAULT_TRACEBUFSIZE;
! 		afsi_log("Default trace buffer size %d", traceBufSize);
! 	}
  
! 	/* setup and enable debug log */
! 	afsd_logp = osi_LogCreate("afsd", traceBufSize);
! 	afsi_log("osi_LogCreate log addr %x", (int)afsd_logp);
      osi_LogEnable(afsd_logp);
! 	logReady = 1;
  
      osi_Log0(afsd_logp, "Log init");
  
! 	dummyLen = sizeof(cacheSize);
! 	code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
! 				(BYTE *) &amp;cacheSize, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("Cache size %d", cacheSize);
! 	else {
! 		cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
! 		afsi_log("Default cache size %d", cacheSize);
! 	}
  
! 	dummyLen = sizeof(logChunkSize);
! 	code = RegQueryValueEx(parmKey, "ChunkSize", NULL, NULL,
! 				(BYTE *) &amp;logChunkSize, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS) {
! 		if (logChunkSize &lt; 12 || logChunkSize &gt; 30) {
! 			afsi_log("Invalid chunk size %d, using default",
! 				 logChunkSize);
! 			logChunkSize = CM_CONFIGDEFAULT_CHUNKSIZE;
! 		}
! 		afsi_log("Chunk size %d", logChunkSize);
! 	} else {
! 		logChunkSize = CM_CONFIGDEFAULT_CHUNKSIZE;
! 		afsi_log("Default chunk size %d", logChunkSize);
! 	}
! 	cm_logChunkSize = logChunkSize;
! 	cm_chunkSize = 1 &lt;&lt; logChunkSize;
  
! 	dummyLen = sizeof(numBkgD);
! 	code = RegQueryValueEx(parmKey, "Daemons", NULL, NULL,
! 				(BYTE *) &amp;numBkgD, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("%d background daemons", numBkgD);
! 	else {
! 		numBkgD = CM_CONFIGDEFAULT_DAEMONS;
! 		afsi_log("Defaulting to %d background daemons", numBkgD);
! 	}
  
! 	dummyLen = sizeof(numSvThreads);
! 	code = RegQueryValueEx(parmKey, "ServerThreads", NULL, NULL,
! 				(BYTE *) &amp;numSvThreads, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("%d server threads", numSvThreads);
! 	else {
! 		numSvThreads = CM_CONFIGDEFAULT_SVTHREADS;
! 		afsi_log("Defaulting to %d server threads", numSvThreads);
! 	}
  
! 	dummyLen = sizeof(stats);
! 	code = RegQueryValueEx(parmKey, "Stats", NULL, NULL,
! 				(BYTE *) &amp;stats, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("Status cache size %d", stats);
! 	else {
! 		stats = CM_CONFIGDEFAULT_STATS;
! 		afsi_log("Default status cache size %d", stats);
! 	}
  
! 	dummyLen = sizeof(ltt);
! 	code = RegQueryValueEx(parmKey, "LogoffTokenTransfer", NULL, NULL,
! 				(BYTE *) &amp;ltt, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("Logoff token transfer %s",  (ltt ? "on" : "off"));
! 	else {
! 		ltt = 1;
! 		afsi_log("Logoff token transfer on by default");
! 	}
      smb_LogoffTokenTransfer = ltt;
      afsi_log("Logoff token transfer is currently ignored");
  
! 	if (ltt) {
! 		dummyLen = sizeof(ltto);
! 		code = RegQueryValueEx(parmKey, "LogoffTokenTransferTimeout",
! 					NULL, NULL, (BYTE *) &amp;ltto, &amp;dummyLen);
! 		if (code == ERROR_SUCCESS)
              afsi_log("Logoff token tranfer timeout %d seconds", ltto);
! 		else {
! 			ltto = 10;
! 			afsi_log("Default logoff token transfer timeout 10 seconds");
! 		}
! 	} else {
          ltto = 0;
!     }
      smb_LogoffTransferTimeout = ltto;
      afsi_log("Default logoff token is currently ignored");
  
! 	dummyLen = sizeof(cm_rootVolumeName);
! 	code = RegQueryValueEx(parmKey, "RootVolume", NULL, NULL,
! 				cm_rootVolumeName, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("Root volume %s", cm_rootVolumeName);
! 	else {
! 		StringCbCopyA(cm_rootVolumeName, sizeof(cm_rootVolumeName), "root.afs");
! 		afsi_log("Default root volume name root.afs");
! 	}
  
! 	cm_mountRootLen = sizeof(cm_mountRoot);
! 	code = RegQueryValueEx(parmKey, "MountRoot", NULL, NULL,
! 				cm_mountRoot, &amp;cm_mountRootLen);
! 	if (code == ERROR_SUCCESS) {
! 		afsi_log("Mount root %s", cm_mountRoot);
! 		cm_mountRootLen = strlen(cm_mountRoot);
! 	} else {
! 		StringCbCopyA(cm_mountRoot, sizeof(cm_mountRoot), "/afs");
! 		cm_mountRootLen = 4;
! 		/* Don't log */
! 	}
  
! 	dummyLen = sizeof(buf);
! 	code = RegQueryValueEx(parmKey, "CachePath", NULL, &amp;regType,
! 				buf, &amp;dummyLen);
      if (code == ERROR_SUCCESS &amp;&amp; buf[0]) {
!         if(regType == REG_EXPAND_SZ) {
              dummyLen = ExpandEnvironmentStrings(buf, cm_CachePath, sizeof(cm_CachePath));
              if(dummyLen &gt; sizeof(cm_CachePath)) {
                  afsi_log("Cache path [%s] longer than %d after expanding env strings", buf, sizeof(cm_CachePath));
--- 456,596 ----
          }
      }
  
!     dummyLen = sizeof(TraceOption);
!     code = RegQueryValueEx(parmKey, "TraceOption", NULL, NULL,
!                             (BYTE *) &amp;TraceOption, &amp;dummyLen);
      afsi_log("Event Log Tracing = %lX", TraceOption);
  
!     dummyLen = sizeof(traceBufSize);
!     code = RegQueryValueEx(parmKey, "TraceBufferSize", NULL, NULL,
!                             (BYTE *) &amp;traceBufSize, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("Trace Buffer size %d", traceBufSize);
!     else {
!         traceBufSize = CM_CONFIGDEFAULT_TRACEBUFSIZE;
!         afsi_log("Default trace buffer size %d", traceBufSize);
!     }
  
!     /* setup and enable debug log */
!     afsd_logp = osi_LogCreate("afsd", traceBufSize);
!     afsi_log("osi_LogCreate log addr %x", (int)afsd_logp);
      osi_LogEnable(afsd_logp);
!     logReady = 1;
  
      osi_Log0(afsd_logp, "Log init");
  
!     dummyLen = sizeof(cacheSize);
!     code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
!                             (BYTE *) &amp;cacheSize, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("Cache size %d", cacheSize);
!     else {
!         cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
!         afsi_log("Default cache size %d", cacheSize);
!     }
  
!     dummyLen = sizeof(logChunkSize);
!     code = RegQueryValueEx(parmKey, "ChunkSize", NULL, NULL,
!                             (BYTE *) &amp;logChunkSize, &amp;dummyLen);
!     if (code == ERROR_SUCCESS) {
!         if (logChunkSize &lt; 12 || logChunkSize &gt; 30) {
!             afsi_log("Invalid chunk size %d, using default",
!                       logChunkSize);
!             logChunkSize = CM_CONFIGDEFAULT_CHUNKSIZE;
!         }
!         afsi_log("Chunk size %d", logChunkSize);
!     } else {
!         logChunkSize = CM_CONFIGDEFAULT_CHUNKSIZE;
!         afsi_log("Default chunk size %d", logChunkSize);
!     }
!     cm_logChunkSize = logChunkSize;
!     cm_chunkSize = 1 &lt;&lt; logChunkSize;
  
!     dummyLen = sizeof(numBkgD);
!     code = RegQueryValueEx(parmKey, "Daemons", NULL, NULL,
!                             (BYTE *) &amp;numBkgD, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("%d background daemons", numBkgD);
!     else {
!         numBkgD = CM_CONFIGDEFAULT_DAEMONS;
!         afsi_log("Defaulting to %d background daemons", numBkgD);
!     }
  
!     dummyLen = sizeof(numSvThreads);
!     code = RegQueryValueEx(parmKey, "ServerThreads", NULL, NULL,
!                             (BYTE *) &amp;numSvThreads, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("%d server threads", numSvThreads);
!     else {
!         numSvThreads = CM_CONFIGDEFAULT_SVTHREADS;
!         afsi_log("Defaulting to %d server threads", numSvThreads);
!     }
  
!     dummyLen = sizeof(stats);
!     code = RegQueryValueEx(parmKey, "Stats", NULL, NULL,
!                             (BYTE *) &amp;stats, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("Status cache size %d", stats);
!     else {
!         stats = CM_CONFIGDEFAULT_STATS;
!         afsi_log("Default status cache size %d", stats);
!     }
  
!     dummyLen = sizeof(ltt);
!     code = RegQueryValueEx(parmKey, "LogoffTokenTransfer", NULL, NULL,
!                             (BYTE *) &amp;ltt, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("Logoff token transfer %s",  (ltt ? "on" : "off"));
!     else {
!         ltt = 1;
!         afsi_log("Logoff token transfer on by default");
!     }
      smb_LogoffTokenTransfer = ltt;
      afsi_log("Logoff token transfer is currently ignored");
  
!     if (ltt) {
!         dummyLen = sizeof(ltto);
!         code = RegQueryValueEx(parmKey, "LogoffTokenTransferTimeout",
!                                 NULL, NULL, (BYTE *) &amp;ltto, &amp;dummyLen);
!         if (code == ERROR_SUCCESS)
              afsi_log("Logoff token tranfer timeout %d seconds", ltto);
!         else {
!             ltto = 10;
!             afsi_log("Default logoff token transfer timeout 10 seconds");
!         }
!     } else {
          ltto = 0;
!     }   
      smb_LogoffTransferTimeout = ltto;
      afsi_log("Default logoff token is currently ignored");
  
!     dummyLen = sizeof(cm_rootVolumeName);
!     code = RegQueryValueEx(parmKey, "RootVolume", NULL, NULL,
!                             cm_rootVolumeName, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("Root volume %s", cm_rootVolumeName);
!     else {
!         StringCbCopyA(cm_rootVolumeName, sizeof(cm_rootVolumeName), "root.afs");
!         afsi_log("Default root volume name root.afs");
!     }
  
!     cm_mountRootLen = sizeof(cm_mountRoot);
!     code = RegQueryValueEx(parmKey, "MountRoot", NULL, NULL,
!                             cm_mountRoot, &amp;cm_mountRootLen);
!     if (code == ERROR_SUCCESS) {
!         afsi_log("Mount root %s", cm_mountRoot);
!         cm_mountRootLen = strlen(cm_mountRoot);
!     } else {
!         StringCbCopyA(cm_mountRoot, sizeof(cm_mountRoot), "/afs");
!         cm_mountRootLen = 4;
!         /* Don't log */
!     }
  
!     dummyLen = sizeof(buf);
!     code = RegQueryValueEx(parmKey, "CachePath", NULL, &amp;regType,
!                             buf, &amp;dummyLen);
      if (code == ERROR_SUCCESS &amp;&amp; buf[0]) {
!         if (regType == REG_EXPAND_SZ) {
              dummyLen = ExpandEnvironmentStrings(buf, cm_CachePath, sizeof(cm_CachePath));
              if(dummyLen &gt; sizeof(cm_CachePath)) {
                  afsi_log("Cache path [%s] longer than %d after expanding env strings", buf, sizeof(cm_CachePath));
***************
*** 599,615 ****
          } else {
              StringCbCopyA(cm_CachePath, sizeof(cm_CachePath), buf);
          }
! 		afsi_log("Cache path %s", cm_CachePath);
      } else {
! 		GetWindowsDirectory(cm_CachePath, sizeof(cm_CachePath));
! 		cm_CachePath[2] = 0;	/* get drive letter only */
! 		StringCbCatA(cm_CachePath, sizeof(cm_CachePath), "\\AFSCache");
! 		afsi_log("Default cache path %s", cm_CachePath);
! 	}
  
      dummyLen = sizeof(virtualCache);
      code = RegQueryValueEx(parmKey, "NonPersistentCaching", NULL, NULL,
!         &amp;virtualCache, &amp;dummyLen);
      if (code == ERROR_SUCCESS &amp;&amp; virtualCache) {
          buf_cacheType = CM_BUF_CACHETYPE_VIRTUAL;
      } else {
--- 599,615 ----
          } else {
              StringCbCopyA(cm_CachePath, sizeof(cm_CachePath), buf);
          }
!         afsi_log("Cache path %s", cm_CachePath);
      } else {
!         GetWindowsDirectory(cm_CachePath, sizeof(cm_CachePath));
!         cm_CachePath[2] = 0;	/* get drive letter only */
!         StringCbCatA(cm_CachePath, sizeof(cm_CachePath), "\\AFSCache");
!         afsi_log("Default cache path %s", cm_CachePath);
!     }
  
      dummyLen = sizeof(virtualCache);
      code = RegQueryValueEx(parmKey, "NonPersistentCaching", NULL, NULL,
!                             &amp;virtualCache, &amp;dummyLen);
      if (code == ERROR_SUCCESS &amp;&amp; virtualCache) {
          buf_cacheType = CM_BUF_CACHETYPE_VIRTUAL;
      } else {
***************
*** 617,643 ****
      }
      afsi_log("Cache type is %s", ((buf_cacheType == CM_BUF_CACHETYPE_FILE)?"FILE":"VIRTUAL"));
  
! 	dummyLen = sizeof(traceOnPanic);
! 	code = RegQueryValueEx(parmKey, "TrapOnPanic", NULL, NULL,
! 				(BYTE *) &amp;traceOnPanic, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("Set to %s on panic",
! 			 traceOnPanic ? "trap" : "not trap");
! 	else {
! 		traceOnPanic = 0;
! 		/* Don't log */
! 	}
! 
! 	dummyLen = sizeof(reportSessionStartups);
! 	code = RegQueryValueEx(parmKey, "ReportSessionStartups", NULL, NULL,
! 				(BYTE *) &amp;reportSessionStartups, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("Session startups %s be recorded in the Event Log",
! 			 reportSessionStartups ? "will" : "will not");
! 	else {
! 		reportSessionStartups = 0;
! 		/* Don't log */
! 	}
  
      for ( i=0; i &lt; MAXNUMSYSNAMES; i++ ) {
          cm_sysNameList[i] = osi_Alloc(MAXSYSNAME);
--- 617,643 ----
      }
      afsi_log("Cache type is %s", ((buf_cacheType == CM_BUF_CACHETYPE_FILE)?"FILE":"VIRTUAL"));
  
!     dummyLen = sizeof(traceOnPanic);
!     code = RegQueryValueEx(parmKey, "TrapOnPanic", NULL, NULL,
!                             (BYTE *) &amp;traceOnPanic, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("Set to %s on panic",
!                   traceOnPanic ? "trap" : "not trap");
!     else {  
!         traceOnPanic = 0;
!         /* Don't log */
!     }
! 
!     dummyLen = sizeof(reportSessionStartups);
!     code = RegQueryValueEx(parmKey, "ReportSessionStartups", NULL, NULL,
!                             (BYTE *) &amp;reportSessionStartups, &amp;dummyLen);
!     if (code == ERROR_SUCCESS)
!         afsi_log("Session startups %s be recorded in the Event Log",
!                   reportSessionStartups ? "will" : "will not");
!     else {
!         reportSessionStartups = 0;
!         /* Don't log */
!     }
  
      for ( i=0; i &lt; MAXNUMSYSNAMES; i++ ) {
          cm_sysNameList[i] = osi_Alloc(MAXSYSNAME);
***************
*** 645,697 ****
      }
      cm_sysName = cm_sysNameList[0];
  
! 	dummyLen = MAXSYSNAME;
!     code = RegQueryValueEx(parmKey, "SysName", NULL, NULL, cm_sysName, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("Sys name %s", cm_sysName);
! 	else {
! 		StringCbCopyA(cm_sysName, MAXSYSNAME, "i386_nt40");
! 		afsi_log("Default sys name %s", cm_sysName);
! 	}
!     cm_sysNameCount = 1;
  
! 	dummyLen = sizeof(cryptall);
! 	code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
! 				(BYTE *) &amp;cryptall, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS)
! 		afsi_log("SecurityLevel is %s", cryptall?"crypt":"clear");
! 	else {
! 		cryptall = rxkad_clear;
! 		afsi_log("Default SecurityLevel is clear");
! 	}
  
  #ifdef AFS_AFSDB_ENV
! 	dummyLen = sizeof(cm_dnsEnabled);
! 	code = RegQueryValueEx(parmKey, "UseDNS", NULL, NULL,
! 				(BYTE *) &amp;cm_dnsEnabled, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS) {
! 		afsi_log("DNS %s be used to find AFS cell servers",
! 			 cm_dnsEnabled ? "will" : "will not");
! 	}
! 	else {
! 	  cm_dnsEnabled = 1;   /* default on */
! 	  afsi_log("Default to use DNS to find AFS cell servers");
! 	}
  #else /* AFS_AFSDB_ENV */
! 	afsi_log("AFS not built with DNS support to find AFS cell servers");
  #endif /* AFS_AFSDB_ENV */
  
  #ifdef AFS_FREELANCE_CLIENT
! 	dummyLen = sizeof(cm_freelanceEnabled);
! 	code = RegQueryValueEx(parmKey, "FreelanceClient", NULL, NULL,
! 				(BYTE *) &amp;cm_freelanceEnabled, &amp;dummyLen);
! 	if (code == ERROR_SUCCESS) {
! 		afsi_log("Freelance client feature %s activated",
! 			 cm_freelanceEnabled ? "is" : "is not");
! 	}
! 	else {
! 	  cm_freelanceEnabled = 0;  /* default off */
! 	}
  #endif /* AFS_FREELANCE_CLIENT */
  
  #ifdef COMMENT
--- 645,719 ----
      }
      cm_sysName = cm_sysNameList[0];
  
!     dummyLen = sizeof(buf);
!     code = RegQueryValueEx(parmKey, "SysName", NULL, NULL, buf, &amp;dummyLen);
!     if (code == ERROR_SUCCESS &amp;&amp; buf[0]) {
!         char * p, *q; 
!         afsi_log("Sys name %s", buf);
  
!         for (p = q = buf; p &lt; cm_sysName + dummyLen; p++)
!         {
!             if (*p == '\0' || isspace(*p)) {
!                 memcpy(cm_sysNameList[cm_sysNameCount],q,p-q);
!                 cm_sysNameList[cm_sysNameCount][p-q] = '\0';
!                 cm_sysNameCount++;
! 
!                 do {
!                     if (*p == '\0')
!                         goto done_sysname;
!                         
!                     p++;
!                 } while (*p == '\0' || isspace(*p));
!                 q = p;
!                 p--;
!             }
!         }
!       done_sysname:
!         StringCbCopyA(cm_sysName, MAXSYSNAME, cm_sysNameList[0]);
!     } else {
!         cm_sysNameCount = 1;
!         StringCbCopyA(cm_sysName, MAXSYSNAME, "i386_nt40");
!         StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, "i386_nt40");
!         afsi_log("Default sys name %s", cm_sysName);
!     }
! 
!     dummyLen = sizeof(cryptall);
!     code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
!                             (BYTE *) &amp;cryptall, &amp;dummyLen);
!     if (code == ERROR_SUCCESS) {
!         afsi_log("SecurityLevel is %s", cryptall?"crypt":"clear");
!     } else {
!         cryptall = 0;
!         afsi_log("Default SecurityLevel is clear");
!     }
  
  #ifdef AFS_AFSDB_ENV
!     dummyLen = sizeof(cm_dnsEnabled);
!     code = RegQueryValueEx(parmKey, "UseDNS", NULL, NULL,
!                             (BYTE *) &amp;cm_dnsEnabled, &amp;dummyLen);
!     if (code == ERROR_SUCCESS) {
!         afsi_log("DNS %s be used to find AFS cell servers",
!                   cm_dnsEnabled ? "will" : "will not");
!     }       
!     else {
!         cm_dnsEnabled = 1;   /* default on */
!         afsi_log("Default to use DNS to find AFS cell servers");
!     }
  #else /* AFS_AFSDB_ENV */
!     afsi_log("AFS not built with DNS support to find AFS cell servers");
  #endif /* AFS_AFSDB_ENV */
  
  #ifdef AFS_FREELANCE_CLIENT
!     dummyLen = sizeof(cm_freelanceEnabled);
!     code = RegQueryValueEx(parmKey, "FreelanceClient", NULL, NULL,
!                             (BYTE *) &amp;cm_freelanceEnabled, &amp;dummyLen);
!     if (code == ERROR_SUCCESS) {
!         afsi_log("Freelance client feature %s activated",
!                   cm_freelanceEnabled ? "is" : "is not");
!     }       
!     else {
!         cm_freelanceEnabled = 0;  /* default off */
!     }
  #endif /* AFS_FREELANCE_CLIENT */
  
  #ifdef COMMENT
***************
*** 738,752 ****
      }
      afsi_log("Maximum number of VCs per server is %d", smb_maxVCPerServer);
  
! 	dummyLen = sizeof(smb_authType);
! 	code = RegQueryValueEx(parmKey, "SMBAuthType", NULL, NULL,
! 		(BYTE *) &amp;smb_authType, &amp;dummyLen);
! 
! 	if (code != ERROR_SUCCESS || 
!         (smb_authType != SMB_AUTH_EXTENDED &amp;&amp; smb_authType != SMB_AUTH_NTLM &amp;&amp; smb_authType != SMB_AUTH_NONE)) {
! 		smb_authType = SMB_AUTH_EXTENDED; /* default is to use extended authentication */
! 	}
! 	afsi_log("SMB authentication type is %s", ((smb_authType == SMB_AUTH_NONE)?"NONE":((smb_authType == SMB_AUTH_EXTENDED)?"EXTENDED":"NTLM")));
  
      dummyLen = sizeof(rx_nojumbo);
      code = RegQueryValueEx(parmKey, "RxNoJumbo", NULL, NULL,
--- 760,774 ----
      }
      afsi_log("Maximum number of VCs per server is %d", smb_maxVCPerServer);
  
!     dummyLen = sizeof(smb_authType);
!     code = RegQueryValueEx(parmKey, "SMBAuthType", NULL, NULL,
!                             (BYTE *) &amp;smb_authType, &amp;dummyLen);
! 
!     if (code != ERROR_SUCCESS || 
!          (smb_authType != SMB_AUTH_EXTENDED &amp;&amp; smb_authType != SMB_AUTH_NTLM &amp;&amp; smb_authType != SMB_AUTH_NONE)) {
!         smb_authType = SMB_AUTH_EXTENDED; /* default is to use extended authentication */
!     }
!     afsi_log("SMB authentication type is %s", ((smb_authType == SMB_AUTH_NONE)?"NONE":((smb_authType == SMB_AUTH_EXTENDED)?"EXTENDED":"NTLM")));
  
      dummyLen = sizeof(rx_nojumbo);
      code = RegQueryValueEx(parmKey, "RxNoJumbo", NULL, NULL,
***************
*** 754,760 ****
      if (code != ERROR_SUCCESS) {
          rx_nojumbo = 0;
      }
!     if(rx_nojumbo)
          afsi_log("RX Jumbograms are disabled");
  
      dummyLen = sizeof(rx_mtu);
--- 776,782 ----
      if (code != ERROR_SUCCESS) {
          rx_nojumbo = 0;
      }
!     if (rx_nojumbo)
          afsi_log("RX Jumbograms are disabled");
  
      dummyLen = sizeof(rx_mtu);
***************
*** 763,769 ****
      if (code != ERROR_SUCCESS || !rx_mtu) {
          rx_mtu = -1;
      }
!     if(rx_mtu != -1)
          afsi_log("RX maximum MTU is %d", rx_mtu);
  
      dummyLen = sizeof(ConnDeadtimeout);
--- 785,791 ----
      if (code != ERROR_SUCCESS || !rx_mtu) {
          rx_mtu = -1;
      }
!     if (rx_mtu != -1)
          afsi_log("RX maximum MTU is %d", rx_mtu);
  
      dummyLen = sizeof(ConnDeadtimeout);
***************
*** 776,793 ****
                             (BYTE *) &amp;HardDeadtimeout, &amp;dummyLen);
      afsi_log("HardDeadTimeout is %d", HardDeadtimeout);
  
! 	RegCloseKey (parmKey);
  
      /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
      if(SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &amp;lanaNum, &amp;isGateway, LANA_NETBIOS_NAME_FULL))) {
          LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
  
!         if(LANadapter != -1)
              afsi_log("LAN adapter number %d", LANadapter);
          else
              afsi_log("LAN adapter number not determined");
  
!         if(isGateway)
              afsi_log("Set for gateway service");
  
          afsi_log("Using &gt;%s&lt; as SMB server name", cm_NetbiosName);
--- 798,815 ----
                             (BYTE *) &amp;HardDeadtimeout, &amp;dummyLen);
      afsi_log("HardDeadTimeout is %d", HardDeadtimeout);
  
!     RegCloseKey (parmKey);
  
      /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
      if(SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &amp;lanaNum, &amp;isGateway, LANA_NETBIOS_NAME_FULL))) {
          LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
  
!         if (LANadapter != -1)
              afsi_log("LAN adapter number %d", LANadapter);
          else
              afsi_log("LAN adapter number not determined");
  
!         if (isGateway)
              afsi_log("Set for gateway service");
  
          afsi_log("Using &gt;%s&lt; as SMB server name", cm_NetbiosName);
***************
*** 797,834 ****
          osi_panic(buf, __FILE__, __LINE__);
      }
  
! 	/* setup early variables */
! 	/* These both used to be configurable. */
! 	smb_UseV3 = 1;
      buf_bufferSize = CM_CONFIGDEFAULT_BLOCKSIZE;
  
! 	/* turn from 1024 byte units into memory blocks */
      cacheBlocks = (cacheSize * 1024) / buf_bufferSize;
          
! 	/* get network related info */
! 	cm_noIPAddr = CM_MAXINTERFACE_ADDR;
! 	code = syscfg_GetIFInfo(&amp;cm_noIPAddr,
!                             cm_IPAddr, cm_SubnetMask,
!                             cm_NetMtu, cm_NetFlags);
  
! 	if ( (cm_noIPAddr &lt;= 0) || (code &lt;= 0 ) )
! 	    afsi_log("syscfg_GetIFInfo error code %d", code);
! 	else
! 	    afsi_log("First Network address %x SubnetMask %x",
!                  cm_IPAddr[0], cm_SubnetMask[0]);
  
! 	/*
! 	 * Save client configuration for GetCacheConfig requests
! 	 */
! 	cm_initParams.nChunkFiles = 0;
! 	cm_initParams.nStatCaches = stats;
! 	cm_initParams.nDataCaches = 0;
! 	cm_initParams.nVolumeCaches = 0;
! 	cm_initParams.firstChunkSize = cm_chunkSize;
! 	cm_initParams.otherChunkSize = cm_chunkSize;
! 	cm_initParams.cacheSize = cacheSize;
! 	cm_initParams.setTime = 0;
! 	cm_initParams.memCache = 0;
  
      /* Set RX parameters before initializing RX */
      if ( rx_nojumbo ) {
--- 819,856 ----
          osi_panic(buf, __FILE__, __LINE__);
      }
  
!     /* setup early variables */
!     /* These both used to be configurable. */
!     smb_UseV3 = 1;
      buf_bufferSize = CM_CONFIGDEFAULT_BLOCKSIZE;
  
!     /* turn from 1024 byte units into memory blocks */
      cacheBlocks = (cacheSize * 1024) / buf_bufferSize;
          
!     /* get network related info */
!     cm_noIPAddr = CM_MAXINTERFACE_ADDR;
!     code = syscfg_GetIFInfo(&amp;cm_noIPAddr,
!                              cm_IPAddr, cm_SubnetMask,
!                              cm_NetMtu, cm_NetFlags);
  
!     if ( (cm_noIPAddr &lt;= 0) || (code &lt;= 0 ) )
!         afsi_log("syscfg_GetIFInfo error code %d", code);
!     else
!         afsi_log("First Network address %x SubnetMask %x",
!                   cm_IPAddr[0], cm_SubnetMask[0]);
  
!     /*
!      * Save client configuration for GetCacheConfig requests
!      */
!     cm_initParams.nChunkFiles = 0;
!     cm_initParams.nStatCaches = stats;
!     cm_initParams.nDataCaches = 0;
!     cm_initParams.nVolumeCaches = 0;
!     cm_initParams.firstChunkSize = cm_chunkSize;
!     cm_initParams.otherChunkSize = cm_chunkSize;
!     cm_initParams.cacheSize = cacheSize;
!     cm_initParams.setTime = 0;
!     cm_initParams.memCache = 0;
  
      /* Set RX parameters before initializing RX */
      if ( rx_nojumbo ) {
***************
*** 847,894 ****
      /* Ensure the AFS Netbios Name is registered to allow loopback access */
      configureBackConnectionHostNames();
  
! 	/* initialize RX, and tell it to listen to port 7001, which is used for
       * callback RPC messages.
       */
! 	code = rx_Init(htons(7001));
! 	afsi_log("rx_Init code %x", code);
! 	if (code != 0) {
! 		*reasonP = "afsd: failed to init rx client on port 7001";
! 		return -1;
! 	}
  
! 	/* Initialize the RPC server for session keys */
! 	RpcInit();
  
! 	/* create an unauthenticated service #1 for callbacks */
! 	nullServerSecurityClassp = rxnull_NewServerSecurityObject();
      serverp = rx_NewService(0, 1, "AFS", &amp;nullServerSecurityClassp, 1,
!                             RXAFSCB_ExecuteRequest);
! 	afsi_log("rx_NewService addr %x", (int)serverp);
! 	if (serverp == NULL) {
! 		*reasonP = "unknown error";
! 		return -1;
! 	}
  
! 	nullServerSecurityClassp = rxnull_NewServerSecurityObject();
      serverp = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats",
!                             &amp;nullServerSecurityClassp, 1, RXSTATS_ExecuteRequest);
! 	afsi_log("rx_NewService addr %x", (int)serverp);
! 	if (serverp == NULL) {
! 		*reasonP = "unknown error";
! 		return -1;
! 	}
          
      /* start server threads, *not* donating this one to the pool */
      rx_StartServer(0);
! 	afsi_log("rx_StartServer");
  
! 	/* init user daemon, and other packages */
! 	cm_InitUser();
  
! 	cm_InitACLCache(2*stats);
  
! 	cm_InitConn();
  
      cm_InitCell();
          
--- 869,916 ----
      /* Ensure the AFS Netbios Name is registered to allow loopback access */
      configureBackConnectionHostNames();
  
!     /* initialize RX, and tell it to listen to port 7001, which is used for
       * callback RPC messages.
       */
!     code = rx_Init(htons(7001));
!     afsi_log("rx_Init code %x", code);
!     if (code != 0) {
!         *reasonP = "afsd: failed to init rx client on port 7001";
!         return -1;
!     }
  
!     /* Initialize the RPC server for session keys */
!     RpcInit();
  
!     /* create an unauthenticated service #1 for callbacks */
!     nullServerSecurityClassp = rxnull_NewServerSecurityObject();
      serverp = rx_NewService(0, 1, "AFS", &amp;nullServerSecurityClassp, 1,
!                              RXAFSCB_ExecuteRequest);
!     afsi_log("rx_NewService addr %x", (int)serverp);
!     if (serverp == NULL) {
!         *reasonP = "unknown error";
!         return -1;
!     }
  
!     nullServerSecurityClassp = rxnull_NewServerSecurityObject();
      serverp = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats",
!                              &amp;nullServerSecurityClassp, 1, RXSTATS_ExecuteRequest);
!     afsi_log("rx_NewService addr %x", (int)serverp);
!     if (serverp == NULL) {
!         *reasonP = "unknown error";
!         return -1;
!     }
          
      /* start server threads, *not* donating this one to the pool */
      rx_StartServer(0);
!     afsi_log("rx_StartServer");
  
!     /* init user daemon, and other packages */
!     cm_InitUser();
  
!     cm_InitACLCache(2*stats);
  
!     cm_InitConn();
  
      cm_InitCell();
          
***************
*** 905,932 ****
      cm_InitSCache(stats);
          
      code = cm_InitDCache(0, cacheBlocks);
! 	afsi_log("cm_InitDCache code %x", code);
! 	if (code != 0) {
! 		*reasonP = "error initializing cache";
! 		return -1;
! 	}
  
  #ifdef AFS_AFSDB_ENV
  #if !defined(_WIN32_WINNT) || (_WIN32_WINNT &lt; 0x0500)
! 	if (cm_InitDNS(cm_dnsEnabled) == -1)
! 	  cm_dnsEnabled = 0;  /* init failed, so deactivate */
! 	afsi_log("cm_InitDNS %d", cm_dnsEnabled);
  #endif
  #endif
  
! 	code = cm_GetRootCellName(rootCellName);
! 	afsi_log("cm_GetRootCellName code %d, cm_freelanceEnabled= %d, rcn= %s", 
!              code, cm_freelanceEnabled, (code ? "&lt;none&gt;" : rootCellName));
! 	if (code != 0 &amp;&amp; !cm_freelanceEnabled) 
      {
! 	    *reasonP = "can't find root cell name in afsd.ini";
! 	    return -1;
!     }
      else if (cm_freelanceEnabled)
          cm_rootCellp = NULL;
  
--- 927,954 ----
      cm_InitSCache(stats);
          
      code = cm_InitDCache(0, cacheBlocks);
!     afsi_log("cm_InitDCache code %x", code);
!     if (code != 0) {
!         *reasonP = "error initializing cache";
!         return -1;
!     }
  
  #ifdef AFS_AFSDB_ENV
  #if !defined(_WIN32_WINNT) || (_WIN32_WINNT &lt; 0x0500)
!     if (cm_InitDNS(cm_dnsEnabled) == -1)
!         cm_dnsEnabled = 0;  /* init failed, so deactivate */
!     afsi_log("cm_InitDNS %d", cm_dnsEnabled);
  #endif
  #endif
  
!     code = cm_GetRootCellName(rootCellName);
!     afsi_log("cm_GetRootCellName code %d, cm_freelanceEnabled= %d, rcn= %s", 
!               code, cm_freelanceEnabled, (code ? "&lt;none&gt;" : rootCellName));
!     if (code != 0 &amp;&amp; !cm_freelanceEnabled) 
      {
!         *reasonP = "can't find root cell name in afsd.ini";
!         return -1;
!     }   
      else if (cm_freelanceEnabled)
          cm_rootCellp = NULL;
  
***************
*** 939,952 ****
              *reasonP = "can't find root cell in afsdcell.ini";
              return -1;
          }
! 	}
! 
  
  #ifdef AFS_FREELANCE_CLIENT
! 	if (cm_freelanceEnabled)
! 	  cm_InitFreelance();
  #endif
! 	return 0;
  }
  
  int afsd_InitDaemons(char **reasonP)
--- 961,973 ----
              *reasonP = "can't find root cell in afsdcell.ini";
              return -1;
          }
!     }
  
  #ifdef AFS_FREELANCE_CLIENT
!     if (cm_freelanceEnabled)
!         cm_InitFreelance();
  #endif
!     return 0;
  }
  
  int afsd_InitDaemons(char **reasonP)
Index: openafs/src/WINNT/afsd/afsd_service.c
diff -c openafs/src/WINNT/afsd/afsd_service.c:1.28 openafs/src/WINNT/afsd/afsd_service.c:1.28.2.2
*** openafs/src/WINNT/afsd/afsd_service.c:1.28	Sat Jul 24 11:25:35 2004
--- openafs/src/WINNT/afsd/afsd_service.c	Mon Oct 18 00:09:25 2004
***************
*** 32,38 ****
  // The following is defined if you want to receive Power notifications,
  // including Hibernation, and also subsequent flushing of AFS volumes
  //
! #define REGISTER_POWER_NOTIFICATIONS
  //
  // Check
  */
--- 32,39 ----
  // The following is defined if you want to receive Power notifications,
  // including Hibernation, and also subsequent flushing of AFS volumes
  //
! #define REGISTER_POWER_NOTIFICATIONS 1
! #define FLUSH_VOLUME                 1
  //
  // Check
  */
***************
*** 54,84 ****
  extern int traceOnPanic;
  extern HANDLE afsi_file;
  
  /*
   * Notifier function for use by osi_panic
   */
  static void afsd_notifier(char *msgp, char *filep, long line)
  {
! 	char tbuffer[512];
! 	char *ptbuf[1];
! 	HANDLE h;
! 
! 	if (filep)
! 		sprintf(tbuffer, "Error at file %s, line %d: %s",
! 			filep, line, msgp);
! 	else
! 		sprintf(tbuffer, "Error at unknown location: %s", msgp);
  
! 	h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 	ptbuf[0] = tbuffer;
! 	ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
! 	DeregisterEventSource(h);
  
! 	GlobalStatus = line;
  
! 	osi_LogEnable(afsd_logp);
  
! 	afsd_ForceTrace(TRUE);
  
      afsi_log("--- begin dump ---");
      cm_DumpSCache(afsi_file, "a");
--- 55,87 ----
  extern int traceOnPanic;
  extern HANDLE afsi_file;
  
+ int powerEventsRegistered = 0;
+ 
  /*
   * Notifier function for use by osi_panic
   */
  static void afsd_notifier(char *msgp, char *filep, long line)
  {
!     char tbuffer[512];
!     char *ptbuf[1];
!     HANDLE h;
! 
!     if (filep)
!         sprintf(tbuffer, "Error at file %s, line %d: %s",
!                  filep, line, msgp);
!     else
!         sprintf(tbuffer, "Error at unknown location: %s", msgp);
  
!     h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!     ptbuf[0] = tbuffer;
!     ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
!     DeregisterEventSource(h);
  
!     GlobalStatus = line;
  
!     osi_LogEnable(afsd_logp);
  
!     afsd_ForceTrace(TRUE);
  
      afsi_log("--- begin dump ---");
      cm_DumpSCache(afsi_file, "a");
***************
*** 91,104 ****
      
      DebugBreak();	
  
! 	SetEvent(WaitToTerminate);
  
  #ifdef JUMP
! 	if (GetCurrentThreadId() == MainThreadId)
! 		longjmp(notifier_jmp, 1);
! 	else
  #endif /* JUMP */
! 		ExitThread(1);
  }
  
  /*
--- 94,107 ----
      
      DebugBreak();	
  
!     SetEvent(WaitToTerminate);
  
  #ifdef JUMP
!     if (GetCurrentThreadId() == MainThreadId)
!         longjmp(notifier_jmp, 1);
!     else
  #endif /* JUMP */
!         ExitThread(1);
  }
  
  /*
***************
*** 106,112 ****
   */
  static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
  {
! 	return 0;
  }
  
  static SERVICE_STATUS		ServiceStatus;
--- 109,115 ----
   */
  static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
  {
!     return 0;
  }
  
  static SERVICE_STATUS		ServiceStatus;
***************
*** 130,136 ****
      {
          dwRet = NO_ERROR;
      }
- 
      else
      {
          /* flush was unsuccessful, or timeout - deny shutdown */
--- 133,138 ----
***************
*** 151,203 ****
  VOID WINAPI 
  afsd_ServiceControlHandler(DWORD ctrlCode)
  {
! 	HKEY parmKey;
! 	DWORD dummyLen, doTrace;
! 	long code;
! 
! 	switch (ctrlCode) {
! 		case SERVICE_CONTROL_STOP:
! 			/* Shutdown RPC */
! 			RpcMgmtStopServerListening(NULL);
! 
! 			/* Force trace if requested */
! 			code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
! 					    AFSConfigKeyName,
! 					    0, KEY_QUERY_VALUE, &amp;parmKey);
! 			if (code != ERROR_SUCCESS)
! 				goto doneTrace;
! 
! 			dummyLen = sizeof(doTrace);
! 			code = RegQueryValueEx(parmKey, "TraceOnShutdown",
! 						NULL, NULL,
! 						(BYTE *) &amp;doTrace, &amp;dummyLen);
! 			RegCloseKey (parmKey);
! 			if (code != ERROR_SUCCESS)
! 				doTrace = 0;
! 			if (doTrace)
! 				afsd_ForceTrace(FALSE);
! 
! doneTrace:
! 			ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
! 			ServiceStatus.dwWin32ExitCode = NO_ERROR;
! 			ServiceStatus.dwCheckPoint = 1;
! 			ServiceStatus.dwWaitHint = 10000;
! 			ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
! 			SetServiceStatus(StatusHandle, &amp;ServiceStatus);
! 			SetEvent(WaitToTerminate);
! 			break;
! 		case SERVICE_CONTROL_INTERROGATE:
! 			ServiceStatus.dwCurrentState = SERVICE_RUNNING;
! 			ServiceStatus.dwWin32ExitCode = NO_ERROR;
! 			ServiceStatus.dwCheckPoint = 0;
! 			ServiceStatus.dwWaitHint = 0;
! 			ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
! 			SetServiceStatus(StatusHandle, &amp;ServiceStatus);
! 			break;
! 		/* XXX handle system shutdown */
! 		/* XXX handle pause &amp; continue */
! 	}
! }
  
  
  /*
--- 153,205 ----
  VOID WINAPI 
  afsd_ServiceControlHandler(DWORD ctrlCode)
  {
!     HKEY parmKey;
!     DWORD dummyLen, doTrace;
!     long code;
! 
!     switch (ctrlCode) {
!     case SERVICE_CONTROL_STOP:
!         /* Shutdown RPC */
!         RpcMgmtStopServerListening(NULL);
! 
!         /* Force trace if requested */
!         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
!                              AFSConfigKeyName,
!                              0, KEY_QUERY_VALUE, &amp;parmKey);
!         if (code != ERROR_SUCCESS)
!             goto doneTrace;
! 
!         dummyLen = sizeof(doTrace);
!         code = RegQueryValueEx(parmKey, "TraceOnShutdown",
!                                 NULL, NULL,
!                                 (BYTE *) &amp;doTrace, &amp;dummyLen);
!         RegCloseKey (parmKey);
!         if (code != ERROR_SUCCESS)
!             doTrace = 0;
!         if (doTrace)
!             afsd_ForceTrace(FALSE);
! 
!       doneTrace:
!         ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
!         ServiceStatus.dwWin32ExitCode = NO_ERROR;
!         ServiceStatus.dwCheckPoint = 1;
!         ServiceStatus.dwWaitHint = 10000;
!         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
!         SetServiceStatus(StatusHandle, &amp;ServiceStatus);
!         SetEvent(WaitToTerminate);
!         break;
!     case SERVICE_CONTROL_INTERROGATE:
!         ServiceStatus.dwCurrentState = SERVICE_RUNNING;
!         ServiceStatus.dwWin32ExitCode = NO_ERROR;
!         ServiceStatus.dwCheckPoint = 0;
!         ServiceStatus.dwWaitHint = 0;
!         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
!         SetServiceStatus(StatusHandle, &amp;ServiceStatus);
!         break;
!         /* XXX handle system shutdown */
!         /* XXX handle pause &amp; continue */
!     }
! }       
  
  
  /*
***************
*** 212,223 ****
                LPVOID lpContext
                )
  {
! 	HKEY parmKey;
! 	DWORD dummyLen, doTrace;
! 	long code;
      DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
  
! 	switch (ctrlCode) 
      {
      case SERVICE_CONTROL_STOP:
          /* Shutdown RPC */
--- 214,225 ----
                LPVOID lpContext
                )
  {
!     HKEY parmKey;
!     DWORD dummyLen, doTrace;
!     long code;
      DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
  
!     switch (ctrlCode) 
      {
      case SERVICE_CONTROL_STOP:
          /* Shutdown RPC */
***************
*** 261,305 ****
          dwRet = NO_ERROR;
          break;
  
! 		/* XXX handle system shutdown */
! 		/* XXX handle pause &amp; continue */
! 		case SERVICE_CONTROL_POWEREVENT:                                              
! 		{                                                                                     
! 			/*                                                                                
              **	dwEventType of this notification == WPARAM of WM_POWERBROADCAST               
! 			**	Return NO_ERROR == return TRUE for that message, i.e. accept request          
! 			**	Return any error code to deny request,                                        
! 			**	i.e. as if returning BROADCAST_QUERY_DENY                                     
! 			*/                                                                                
! 			switch((int) dwEventType)                                                         
!             {                                                                               
! 			case PBT_APMQUERYSUSPEND:                                                         
! 			case PBT_APMQUERYSTANDBY:                                                         
!                                                                                             
! #ifdef	REGISTER_POWER_NOTIFICATIONS				                                      
! 				/* handle event */                                                            
! 				dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);                         
  #else                                                                                       
! 				dwRet = NO_ERROR;                                                             
  #endif                                                                                      
! 				break;                                                                        
  							                                                                  
!             /* allow remaining case PBT_WhatEver */                                           
! 			case PBT_APMSUSPEND:                                                              
! 			case PBT_APMSTANDBY:                                                              
! 			case PBT_APMRESUMECRITICAL:                                                       
! 			case PBT_APMRESUMESUSPEND:                                                        
! 			case PBT_APMRESUMESTANDBY:                                                        
! 			case PBT_APMBATTERYLOW:                                                           
! 			case PBT_APMPOWERSTATUSCHANGE:                                                    
! 			case PBT_APMOEMEVENT:                                                             
! 			case PBT_APMRESUMEAUTOMATIC:                                                      
! 			default:                                                                          
! 				dwRet = NO_ERROR;                                                             
              }
          }
      }		/* end switch(ctrlCode) */                                                        
! 	return dwRet;   
  }
  
  /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
--- 263,309 ----
          dwRet = NO_ERROR;
          break;
  
!         /* XXX handle system shutdown */
!         /* XXX handle pause &amp; continue */
!     case SERVICE_CONTROL_POWEREVENT:                                              
!         {                                                                                     
!             /*                                                                                
              **	dwEventType of this notification == WPARAM of WM_POWERBROADCAST               
!             **	Return NO_ERROR == return TRUE for that message, i.e. accept request          
!             **	Return any error code to deny request,                                        
!             **	i.e. as if returning BROADCAST_QUERY_DENY                                     
!             */                                                                                
!             if (powerEventsRegistered) {
!                 switch((int) dwEventType)                                                         
!                 {                                                                               
!                 case PBT_APMQUERYSUSPEND:                                                         
!                 case PBT_APMQUERYSTANDBY:                                                         
! 
! #ifdef	FLUSH_VOLUME
!                     /* handle event */                                                            
!                     dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);                         
  #else                                                                                       
!                     dwRet = NO_ERROR;                                                             
  #endif                                                                                      
!                     break;                                                                        
  							                                                                  
!                     /* allow remaining case PBT_WhatEver */                                           
!                 case PBT_APMSUSPEND:                                                              
!                 case PBT_APMSTANDBY:                                                              
!                 case PBT_APMRESUMECRITICAL:                                                       
!                 case PBT_APMRESUMESUSPEND:                                                        
!                 case PBT_APMRESUMESTANDBY:                                                        
!                 case PBT_APMBATTERYLOW:                                                           
!                 case PBT_APMPOWERSTATUSCHANGE:                                                    
!                 case PBT_APMOEMEVENT:                                                             
!                 case PBT_APMRESUMEAUTOMATIC:                                                      
!                 default:                                                                          
!                     dwRet = NO_ERROR;                                                             
!                 }   
              }
          }
      }		/* end switch(ctrlCode) */                                                        
!     return dwRet;   
  }
  
  /* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
***************
*** 308,314 ****
   */
  /* DEE Could check first if we are run as SYSTEM */
  #define MAX_RETRIES 30
! static void MountGlobalDrives()
  {
      char szAfsPath[_MAX_PATH];
      char szDriveToMapTo[5];
--- 312,318 ----
   */
  /* DEE Could check first if we are run as SYSTEM */
  #define MAX_RETRIES 30
! static void MountGlobalDrives(void)
  {
      char szAfsPath[_MAX_PATH];
      char szDriveToMapTo[5];
***************
*** 323,330 ****
  
      sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
  
! 	dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &amp;hKey);
! 	if (dwResult != ERROR_SUCCESS)
          return;
  
      while (dwRetry &lt; MAX_RETRIES) {
--- 327,334 ----
  
      sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
  
!     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &amp;hKey);
!     if (dwResult != ERROR_SUCCESS)
          return;
  
      while (dwRetry &lt; MAX_RETRIES) {
***************
*** 385,392 ****
  
      sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
  
! 	dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &amp;hKey);
! 	if (dwResult != ERROR_SUCCESS)
          return;
  
      while (1) {
--- 389,396 ----
  
      sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
  
!     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &amp;hKey);
!     if (dwResult != ERROR_SUCCESS)
          return;
  
      while (1) {
***************
*** 428,437 ****
  
  void afsd_Main(DWORD argc, LPTSTR *argv)
  {
! 	long code;
! 	char *reason;
  #ifdef JUMP
! 	int jmpret;
  #endif /* JUMP */
      HANDLE hInitHookDll;
      HANDLE hAdvApi32;
--- 432,441 ----
  
  void afsd_Main(DWORD argc, LPTSTR *argv)
  {
!     long code;
!     char *reason;
  #ifdef JUMP
!     int jmpret;
  #endif /* JUMP */
      HANDLE hInitHookDll;
      HANDLE hAdvApi32;
***************
*** 443,455 ****
  #endif 
  
      osi_InitPanic(afsd_notifier);
! 	osi_InitTraceOption();
  
! 	GlobalStatus = 0;
  
! 	afsi_start();
  
! 	WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
  
--- 447,459 ----
  #endif 
  
      osi_InitPanic(afsd_notifier);
!     osi_InitTraceOption();
  
!     GlobalStatus = 0;
  
!     afsi_start();
  
!     WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
  
***************
*** 472,486 ****
          StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
      }
  
! 	ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
! 	ServiceStatus.dwServiceSpecificExitCode = 0;
! 	ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
! 	ServiceStatus.dwWin32ExitCode = NO_ERROR;
! 	ServiceStatus.dwCheckPoint = 1;
! 	ServiceStatus.dwWaitHint = 30000;
      /* accept Power Events */
! 	ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
! 	SetServiceStatus(StatusHandle, &amp;ServiceStatus);
  #endif
  
      {       
--- 476,490 ----
          StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
      }
  
!     ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
!     ServiceStatus.dwServiceSpecificExitCode = 0;
!     ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
!     ServiceStatus.dwWin32ExitCode = NO_ERROR;
!     ServiceStatus.dwCheckPoint = 1;
!     ServiceStatus.dwWaitHint = 30000;
      /* accept Power Events */
!     ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
!     SetServiceStatus(StatusHandle, &amp;ServiceStatus);
  #endif
  
      {       
***************
*** 492,499 ****
      }
  
  #ifdef REGISTER_POWER_NOTIFICATIONS
!     /* create thread used to flush cache */
!     PowerNotificationThreadCreate();
  #endif
  
      /* allow an exit to be called prior to any initialization */
--- 496,525 ----
      }
  
  #ifdef REGISTER_POWER_NOTIFICATIONS
!     {
!         HKEY hkParm;
!         DWORD code;
!         DWORD dummyLen;
!         int bpower = TRUE;
! 
!         /* see if we should handle power notifications */
!         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0, KEY_QUERY_VALUE, &amp;hkParm);
!         if (code == ERROR_SUCCESS) {
!             dummyLen = sizeof(bpower);
!             code = RegQueryValueEx(hkParm, "FlushOnHibernate", NULL, NULL,
!                 (BYTE *) &amp;bpower, &amp;dummyLen);      
! 
!             if(code != ERROR_SUCCESS)
!                 bpower = TRUE;
! 
! 	    RegCloseKey(hkParm);
!         }
!         /* create thread used to flush cache */
!         if (bpower) {
!             PowerNotificationThreadCreate();
!             powerEventsRegistered = 1;
!         }
!     }
  #endif
  
      /* allow an exit to be called prior to any initialization */
***************
*** 538,552 ****
  
  #ifdef JUMP
      MainThreadId = GetCurrentThreadId();
! 	jmpret = setjmp(notifier_jmp);
  
! 	if (jmpret == 0) 
  #endif /* JUMP */
      {
! 		code = afsd_InitCM(&amp;reason);
! 		if (code != 0) {
              afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
! 			osi_panic(reason, __FILE__, __LINE__);
          }
  
  #ifndef NOTSERVICE
--- 564,578 ----
  
  #ifdef JUMP
      MainThreadId = GetCurrentThreadId();
!     jmpret = setjmp(notifier_jmp);
  
!     if (jmpret == 0) 
  #endif /* JUMP */
      {
!         code = afsd_InitCM(&amp;reason);
!         if (code != 0) {
              afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
!             osi_panic(reason, __FILE__, __LINE__);
          }
  
  #ifndef NOTSERVICE
***************
*** 554,561 ****
          ServiceStatus.dwWaitHint -= 5000;
          SetServiceStatus(StatusHandle, &amp;ServiceStatus);
  #endif
! 		code = afsd_InitDaemons(&amp;reason);
! 		if (code != 0) {
              afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
  			osi_panic(reason, __FILE__, __LINE__);
          }
--- 580,587 ----
          ServiceStatus.dwWaitHint -= 5000;
          SetServiceStatus(StatusHandle, &amp;ServiceStatus);
  #endif
!         code = afsd_InitDaemons(&amp;reason);
!         if (code != 0) {
              afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
  			osi_panic(reason, __FILE__, __LINE__);
          }
***************
*** 565,606 ****
          ServiceStatus.dwWaitHint -= 5000;
          SetServiceStatus(StatusHandle, &amp;ServiceStatus);
  #endif
! 		code = afsd_InitSMB(&amp;reason, MessageBox);
! 		if (code != 0) {
              afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
! 			osi_panic(reason, __FILE__, __LINE__);
          }
  
          MountGlobalDrives();
  
  #ifndef NOTSERVICE
! 		ServiceStatus.dwCurrentState = SERVICE_RUNNING;
! 		ServiceStatus.dwWin32ExitCode = NO_ERROR;
! 		ServiceStatus.dwCheckPoint = 0;
! 		ServiceStatus.dwWaitHint = 0;
  
          /* accept Power events */
! 		ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
! 		SetServiceStatus(StatusHandle, &amp;ServiceStatus);
! #endif
          {
  	    HANDLE h; char *ptbuf[1];
! 		h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 		ptbuf[0] = "AFS running";
! 		ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
! 		DeregisterEventSource(h);
          }
! 	}
  
! 	WaitForSingleObject(WaitToTerminate, INFINITE);
  
      {   
!     HANDLE h; char *ptbuf[1];
  	h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
  	ptbuf[0] = "AFS quitting";
  	ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
                  0, 0, NULL, 1, 0, ptbuf, NULL);
!     DeregisterEventSource(h);
      }
  
      DismountGlobalDrives();
--- 591,632 ----
          ServiceStatus.dwWaitHint -= 5000;
          SetServiceStatus(StatusHandle, &amp;ServiceStatus);
  #endif
!         code = afsd_InitSMB(&amp;reason, MessageBox);
!         if (code != 0) {
              afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
!             osi_panic(reason, __FILE__, __LINE__);
          }
  
          MountGlobalDrives();
  
  #ifndef NOTSERVICE
!         ServiceStatus.dwCurrentState = SERVICE_RUNNING;
!         ServiceStatus.dwWin32ExitCode = NO_ERROR;
!         ServiceStatus.dwCheckPoint = 0;
!         ServiceStatus.dwWaitHint = 0;
  
          /* accept Power events */
!         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
!         SetServiceStatus(StatusHandle, &amp;ServiceStatus);
! #endif  
          {
  	    HANDLE h; char *ptbuf[1];
!             h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!             ptbuf[0] = "AFS running";
!             ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
!             DeregisterEventSource(h);
          }
!     }
  
!     WaitForSingleObject(WaitToTerminate, INFINITE);
  
      {   
!         HANDLE h; char *ptbuf[1];
  	h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
  	ptbuf[0] = "AFS quitting";
  	ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
                  0, 0, NULL, 1, 0, ptbuf, NULL);
!         DeregisterEventSource(h);
      }
  
      DismountGlobalDrives();
***************
*** 608,627 ****
      rx_Finalize();
  
  #ifdef	REGISTER_POWER_NOTIFICATIONS
! 	/* terminate thread used to flush cache */
! 	PowerNotificationThreadExit();
  #endif
  
      /* Remove the ExceptionFilter */
      SetUnhandledExceptionFilter(NULL);
  
      ServiceStatus.dwCurrentState = SERVICE_STOPPED;
! 	ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
! 	ServiceStatus.dwCheckPoint = 0;
! 	ServiceStatus.dwWaitHint = 0;
! 	ServiceStatus.dwControlsAccepted = 0;
! 	SetServiceStatus(StatusHandle, &amp;ServiceStatus);
! }
  
  DWORD __stdcall afsdMain_thread(void* notUsed)
  {
--- 634,654 ----
      rx_Finalize();
  
  #ifdef	REGISTER_POWER_NOTIFICATIONS
!     /* terminate thread used to flush cache */
!     if (powerEventsRegistered)
!         PowerNotificationThreadExit();
  #endif
  
      /* Remove the ExceptionFilter */
      SetUnhandledExceptionFilter(NULL);
  
      ServiceStatus.dwCurrentState = SERVICE_STOPPED;
!     ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
!     ServiceStatus.dwCheckPoint = 0;
!     ServiceStatus.dwWaitHint = 0;
!     ServiceStatus.dwControlsAccepted = 0;
!     SetServiceStatus(StatusHandle, &amp;ServiceStatus);
! }       
  
  DWORD __stdcall afsdMain_thread(void* notUsed)
  {
***************
*** 633,647 ****
  int
  main(void)
  {
! 	static SERVICE_TABLE_ENTRY dispatchTable[] = {
! 		{AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
! 		{NULL, NULL}
! 	};
  
! 	if (!StartServiceCtrlDispatcher(dispatchTable))
      {
          LONG status = GetLastError();
! 	    if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
          {
              DWORD tid;
              hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &amp;tid);
--- 660,674 ----
  int
  main(void)
  {
!     static SERVICE_TABLE_ENTRY dispatchTable[] = {
!         {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
!         {NULL, NULL}
!     };
  
!     if (!StartServiceCtrlDispatcher(dispatchTable))
      {
          LONG status = GetLastError();
!         if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
          {
              DWORD tid;
              hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &amp;tid);
Index: openafs/src/WINNT/afsd/afskfw.c
diff -c openafs/src/WINNT/afsd/afskfw.c:1.8.2.1 openafs/src/WINNT/afsd/afskfw.c:1.8.2.4
*** openafs/src/WINNT/afsd/afskfw.c:1.8.2.1	Tue Aug 17 00:28:38 2004
--- openafs/src/WINNT/afsd/afskfw.c	Mon Oct 18 00:09:25 2004
***************
*** 444,471 ****
  
  static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
  
  int 
  KFW_is_available(void)
  {
      HKEY parmKey;
! 	DWORD code, len;
      DWORD enableKFW = 1;
  
      code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
                           0, KEY_QUERY_VALUE, &amp;parmKey);
!     if (code != ERROR_SUCCESS)
!         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
!                              0, KEY_QUERY_VALUE, &amp;parmKey);
! 	if (code == ERROR_SUCCESS) {
          len = sizeof(enableKFW);
          code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
                                  (BYTE *) &amp;enableKFW, &amp;len);
          if (code != ERROR_SUCCESS) {
!             enableKFW = 1;
          }
          RegCloseKey (parmKey);
! 	}
! 
      if ( !enableKFW )
          return FALSE;
  
--- 444,508 ----
  
  static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
  
+ int
+ KFW_use_krb524(void)
+ {
+     HKEY parmKey;
+     DWORD code, len;
+     DWORD use524 = 0;
+ 
+     code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
+                          0, KEY_QUERY_VALUE, &amp;parmKey);
+     if (code == ERROR_SUCCESS) {
+         len = sizeof(use524);
+         code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
+                                 (BYTE *) &amp;use524, &amp;len);
+         if (code != ERROR_SUCCESS) {
+             RegCloseKey(parmKey);
+ 
+             code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
+                                  0, KEY_QUERY_VALUE, &amp;parmKey);
+             if (code == ERROR_SUCCESS) {
+                 len = sizeof(use524);
+                 code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
+                                         (BYTE *) &amp;use524, &amp;len);
+                 if (code != ERROR_SUCCESS)
+                     use524 = 0;
+             }
+         }
+         RegCloseKey (parmKey);
+     }
+     return use524;
+ }
+ 
  int 
  KFW_is_available(void)
  {
      HKEY parmKey;
!     DWORD code, len;
      DWORD enableKFW = 1;
  
      code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
                           0, KEY_QUERY_VALUE, &amp;parmKey);
!     if (code == ERROR_SUCCESS) {
          len = sizeof(enableKFW);
          code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
                                  (BYTE *) &amp;enableKFW, &amp;len);
          if (code != ERROR_SUCCESS) {
!             RegCloseKey(parmKey);
! 
!             code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
!                                  0, KEY_QUERY_VALUE, &amp;parmKey);
!             if (code == ERROR_SUCCESS) {
!                 len = sizeof(enableKFW);
!                 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
!                                         (BYTE *) &amp;enableKFW, &amp;len);
!                 if (code != ERROR_SUCCESS)
!                     enableKFW = 1;
!             }
          }
          RegCloseKey (parmKey);
!     }
      if ( !enableKFW )
          return FALSE;
  
***************
*** 890,900 ****
  
      princ_realm = krb5_princ_realm(ctx, princ);
      for ( i=0; i&lt;princ_realm-&gt;length; i++ ) {
! 		realm[i] = princ_realm-&gt;data[i];
          cell[i] = tolower(princ_realm-&gt;data[i]);
      }
! 	cell[i] = '\0';
! 	realm[i] = '\0';
  
      code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
      if ( IsDebuggerPresent() ) {
--- 927,937 ----
  
      princ_realm = krb5_princ_realm(ctx, princ);
      for ( i=0; i&lt;princ_realm-&gt;length; i++ ) {
!         realm[i] = princ_realm-&gt;data[i];
          cell[i] = tolower(princ_realm-&gt;data[i]);
      }
!     cell[i] = '\0';
!     realm[i] = '\0';
  
      code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
      if ( IsDebuggerPresent() ) {
***************
*** 2546,2555 ****
      memset(ServiceName, '\0', sizeof(ServiceName));
      memset(realm_of_user, '\0', sizeof(realm_of_user));
      memset(realm_of_cell, '\0', sizeof(realm_of_cell));
! 	if (cell &amp;&amp; cell[0])
! 		strcpy(Dmycell, cell);
! 	else
! 		memset(Dmycell, '\0', sizeof(Dmycell));
  
      // NULL or empty cell returns information on local cell
      if (rc = KFW_AFS_get_cellconfig(Dmycell, &amp;ak_cellconfig, local_cell))
--- 2583,2592 ----
      memset(ServiceName, '\0', sizeof(ServiceName));
      memset(realm_of_user, '\0', sizeof(realm_of_user));
      memset(realm_of_cell, '\0', sizeof(realm_of_cell));
!     if (cell &amp;&amp; cell[0])
!         strcpy(Dmycell, cell);
!     else
!         memset(Dmycell, '\0', sizeof(Dmycell));
  
      // NULL or empty cell returns information on local cell
      if (rc = KFW_AFS_get_cellconfig(Dmycell, &amp;ak_cellconfig, local_cell))
***************
*** 2575,2587 ****
      memset((char *)&amp;increds, 0, sizeof(increds));
  
      code = pkrb5_cc_get_principal(ctx, cc, &amp;client_principal);
! 	if (code) {
          if ( code == KRB5_CC_NOTFOUND &amp;&amp; IsDebuggerPresent() ) 
          {
              OutputDebugString("Principal Not Found for ccache\n");
          }
          goto skip_krb5_init;
      }
      i = krb5_princ_realm(ctx, client_principal)-&gt;length;
      if (i &gt; REALM_SZ-1) 
          i = REALM_SZ-1;
--- 2612,2632 ----
      memset((char *)&amp;increds, 0, sizeof(increds));
  
      code = pkrb5_cc_get_principal(ctx, cc, &amp;client_principal);
!     if (code) {
          if ( code == KRB5_CC_NOTFOUND &amp;&amp; IsDebuggerPresent() ) 
          {
              OutputDebugString("Principal Not Found for ccache\n");
          }
          goto skip_krb5_init;
      }
+ 
+     if ( strchr(krb5_princ_component(ctx,client_principal,0),'.') != NULL )
+     {
+         OutputDebugString("Illegal Principal name contains dot in first component\n");
+         rc = KRB5KRB_ERR_GENERIC;
+         goto cleanup;
+     }
+ 
      i = krb5_princ_realm(ctx, client_principal)-&gt;length;
      if (i &gt; REALM_SZ-1) 
          i = REALM_SZ-1;
***************
*** 2761,2767 ****
           * No need to perform a krb524 translation which is 
           * commented out in the code below
           */
!         if (k5creds-&gt;ticket.length &gt; MAXKTCTICKETLEN)
              goto try_krb524d;
  
          memset(&amp;aserver, '\0', sizeof(aserver));
--- 2806,2813 ----
           * No need to perform a krb524 translation which is 
           * commented out in the code below
           */
!         if (KFW_use_krb524() ||
!             k5creds-&gt;ticket.length &gt; MAXKTCTICKETLEN)
              goto try_krb524d;
  
          memset(&amp;aserver, '\0', sizeof(aserver));
Index: openafs/src/WINNT/afsd/afsshare.c
diff -c openafs/src/WINNT/afsd/afsshare.c:1.5 openafs/src/WINNT/afsd/afsshare.c:1.5.2.1
*** openafs/src/WINNT/afsd/afsshare.c:1.5	Tue Jul 20 10:36:41 2004
--- openafs/src/WINNT/afsd/afsshare.c	Wed Sep  8 01:58:33 2004
***************
*** 65,71 ****
              else
                  mountstring = argv[2];
  
!             if (RegSetValueEx(hkSubmounts, argv[1], 0, REG_SZ, mountstring, strlen(mountstring)+1)) {
                  fprintf(stderr,"Submount Set failure for [%s]: %lX",
                           argv[1], GetLastError());
                  RegCloseKey(hkSubmounts);
--- 65,71 ----
              else
                  mountstring = argv[2];
  
!             if (RegSetValueEx(hkSubmounts, argv[1], 0, REG_EXPAND_SZ, mountstring, strlen(mountstring)+1)) {
                  fprintf(stderr,"Submount Set failure for [%s]: %lX",
                           argv[1], GetLastError());
                  RegCloseKey(hkSubmounts);
Index: openafs/src/WINNT/afsd/cm_buf.c
diff -c openafs/src/WINNT/afsd/cm_buf.c:1.13.2.1 openafs/src/WINNT/afsd/cm_buf.c:1.13.2.2
*** openafs/src/WINNT/afsd/cm_buf.c:1.13.2.1	Tue Aug 17 00:28:38 2004
--- openafs/src/WINNT/afsd/cm_buf.c	Sun Oct 10 19:52:04 2004
***************
*** 110,167 ****
  /* hold a reference to an already held buffer */
  void buf_Hold(cm_buf_t *bp)
  {
! 	lock_ObtainWrite(&amp;buf_globalLock);
! 	bp-&gt;refCount++;
! 	lock_ReleaseWrite(&amp;buf_globalLock);
  }
  
  /* incremental sync daemon.  Writes 1/10th of all the buffers every 5000 ms */
  void buf_IncrSyncer(long parm)
  {
! 	cm_buf_t *bp;			/* buffer we're hacking on; held */
!         long i;				/* counter */
!         long nAtOnce;			/* how many to do at once */
! 	cm_req_t req;
! 
! 	lock_ObtainWrite(&amp;buf_globalLock);
! 	bp = buf_allp;
!         bp-&gt;refCount++;
!         lock_ReleaseWrite(&amp;buf_globalLock);
!         nAtOnce = buf_nbuffers / 10;
! 	while (1) {
  #ifndef DJGPP
!                 i = SleepEx(5000, 1);
!                 if (i != 0) continue;
  #else
! 		thrd_Sleep(5000);
  #endif /* DJGPP */
                  
!                 /* now go through our percentage of the buffers */
!                 for(i=0; i&lt;nAtOnce; i++) {
! 			/* don't want its identity changing while we're
!                          * messing with it, so must do all of this with
!                          * bp held.
! 			 */
! 
! 			/* start cleaning the buffer; don't touch log pages since
!                          * the log code counts on knowing exactly who is writing
!                          * a log page at any given instant.
!                          */
! 			cm_InitReq(&amp;req);
! 			req.flags |= CM_REQ_NORETRY;
! 			buf_CleanAsync(bp, &amp;req);
! 
! 			/* now advance to the next buffer; the allp chain never changes,
!                          * and so can be followed even when holding no locks.
!                          */
! 			lock_ObtainWrite(&amp;buf_globalLock);
! 			buf_LockedRelease(bp);
!                         bp = bp-&gt;allp;
!                         if (!bp) bp = buf_allp;
!                         bp-&gt;refCount++;
! 			lock_ReleaseWrite(&amp;buf_globalLock);
!                 }	/* for loop over a bunch of buffers */
!         }		/* whole daemon's while loop */
  }
  
  #ifndef DJGPP
--- 110,167 ----
  /* hold a reference to an already held buffer */
  void buf_Hold(cm_buf_t *bp)
  {
!     lock_ObtainWrite(&amp;buf_globalLock);
!     bp-&gt;refCount++;
!     lock_ReleaseWrite(&amp;buf_globalLock);
  }
  
  /* incremental sync daemon.  Writes 1/10th of all the buffers every 5000 ms */
  void buf_IncrSyncer(long parm)
  {
!     cm_buf_t *bp;			/* buffer we're hacking on; held */
!     long i;				/* counter */
!     long nAtOnce;			/* how many to do at once */
!     cm_req_t req;
! 
!     lock_ObtainWrite(&amp;buf_globalLock);
!     bp = buf_allp;
!     bp-&gt;refCount++;
!     lock_ReleaseWrite(&amp;buf_globalLock);
!     nAtOnce = buf_nbuffers / 10;
!     while (1) {
  #ifndef DJGPP
!         i = SleepEx(5000, 1);
!         if (i != 0) continue;
  #else
!         thrd_Sleep(5000);
  #endif /* DJGPP */
                  
!         /* now go through our percentage of the buffers */
!         for(i=0; i&lt;nAtOnce; i++) {
!             /* don't want its identity changing while we're
!              * messing with it, so must do all of this with
!              * bp held.
!              */
! 
!             /* start cleaning the buffer; don't touch log pages since
!              * the log code counts on knowing exactly who is writing
!              * a log page at any given instant.
!              */
!             cm_InitReq(&amp;req);
!             req.flags |= CM_REQ_NORETRY;
!             buf_CleanAsync(bp, &amp;req);
! 
!             /* now advance to the next buffer; the allp chain never changes,
!              * and so can be followed even when holding no locks.
!              */
!             lock_ObtainWrite(&amp;buf_globalLock);
!             buf_LockedRelease(bp);
!             bp = bp-&gt;allp;
!             if (!bp) bp = buf_allp;
!             bp-&gt;refCount++;
!             lock_ReleaseWrite(&amp;buf_globalLock);
!         }	/* for loop over a bunch of buffers */
!     }		/* whole daemon's while loop */
  }
  
  #ifndef DJGPP
***************
*** 172,229 ****
   */
  PSECURITY_ATTRIBUTES CreateCacheFileSA()
  {
! 	PSECURITY_ATTRIBUTES psa;
! 	PSECURITY_DESCRIPTOR psd;
! 	SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
! 	PSID AdminSID;
! 	DWORD AdminSIDlength;
! 	PACL AdminOnlyACL;
! 	DWORD ACLlength;
! 
! 	/* Get Administrator SID */
! 	AllocateAndInitializeSid(&amp;authority, 2,
! 				 SECURITY_BUILTIN_DOMAIN_RID,
! 				 DOMAIN_ALIAS_RID_ADMINS,
! 				 0, 0, 0, 0, 0, 0,
! 				 &amp;AdminSID);
! 
! 	/* Create Administrator-only ACL */
! 	AdminSIDlength = GetLengthSid(AdminSID);
! 	ACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
! 			+ AdminSIDlength - sizeof(DWORD);
! 	AdminOnlyACL = GlobalAlloc(GMEM_FIXED, ACLlength);
! 	InitializeAcl(AdminOnlyACL, ACLlength, ACL_REVISION);
! 	AddAccessAllowedAce(AdminOnlyACL, ACL_REVISION,
! 			    STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
! 			    AdminSID);
! 
! 	/* Create security descriptor */
! 	psd = GlobalAlloc(GMEM_FIXED, sizeof(SECURITY_DESCRIPTOR));
! 	InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
! 	SetSecurityDescriptorDacl(psd, TRUE, AdminOnlyACL, FALSE);
! 
! 	/* Create security attributes structure */
! 	psa = GlobalAlloc(GMEM_FIXED, sizeof(SECURITY_ATTRIBUTES));
! 	psa-&gt;nLength = sizeof(SECURITY_ATTRIBUTES);
! 	psa-&gt;lpSecurityDescriptor = psd;
! 	psa-&gt;bInheritHandle = TRUE;
  
! 	return psa;
! }
  #endif /* !DJGPP */
  
  #ifndef DJGPP
  /* Free a security attribute structure created by CreateCacheFileSA() */
  VOID FreeCacheFileSA(PSECURITY_ATTRIBUTES psa)
  {
! 	BOOL b1, b2;
! 	PACL pAcl;
  
! 	GetSecurityDescriptorDacl(psa-&gt;lpSecurityDescriptor, &amp;b1, &amp;pAcl, &amp;b2);
! 	GlobalFree(pAcl);
! 	GlobalFree(psa-&gt;lpSecurityDescriptor);
! 	GlobalFree(psa);
! }
  #endif /* !DJGPP */
  	
  /* initialize the buffer package; called with no locks
--- 172,229 ----
   */
  PSECURITY_ATTRIBUTES CreateCacheFileSA()
  {
!     PSECURITY_ATTRIBUTES psa;
!     PSECURITY_DESCRIPTOR psd;
!     SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
!     PSID AdminSID;
!     DWORD AdminSIDlength;
!     PACL AdminOnlyACL;
!     DWORD ACLlength;
! 
!     /* Get Administrator SID */
!     AllocateAndInitializeSid(&amp;authority, 2,
!                               SECURITY_BUILTIN_DOMAIN_RID,
!                               DOMAIN_ALIAS_RID_ADMINS,
!                               0, 0, 0, 0, 0, 0,
!                               &amp;AdminSID);
! 
!     /* Create Administrator-only ACL */
!     AdminSIDlength = GetLengthSid(AdminSID);
!     ACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
!         + AdminSIDlength - sizeof(DWORD);
!     AdminOnlyACL = GlobalAlloc(GMEM_FIXED, ACLlength);
!     InitializeAcl(AdminOnlyACL, ACLlength, ACL_REVISION);
!     AddAccessAllowedAce(AdminOnlyACL, ACL_REVISION,
!                          STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
!                          AdminSID);
! 
!     /* Create security descriptor */
!     psd = GlobalAlloc(GMEM_FIXED, sizeof(SECURITY_DESCRIPTOR));
!     InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
!     SetSecurityDescriptorDacl(psd, TRUE, AdminOnlyACL, FALSE);
! 
!     /* Create security attributes structure */
!     psa = GlobalAlloc(GMEM_FIXED, sizeof(SECURITY_ATTRIBUTES));
!     psa-&gt;nLength = sizeof(SECURITY_ATTRIBUTES);
!     psa-&gt;lpSecurityDescriptor = psd;
!     psa-&gt;bInheritHandle = TRUE;
  
!     return psa;
! }       
  #endif /* !DJGPP */
  
  #ifndef DJGPP
  /* Free a security attribute structure created by CreateCacheFileSA() */
  VOID FreeCacheFileSA(PSECURITY_ATTRIBUTES psa)
  {
!     BOOL b1, b2;
!     PACL pAcl;
  
!     GetSecurityDescriptorDacl(psa-&gt;lpSecurityDescriptor, &amp;b1, &amp;pAcl, &amp;b2);
!     GlobalFree(pAcl);
!     GlobalFree(psa-&gt;lpSecurityDescriptor);
!     GlobalFree(psa);
! }       
  #endif /* !DJGPP */
  	
  /* initialize the buffer package; called with no locks
***************
*** 231,397 ****
   */
  long buf_Init(cm_buf_ops_t *opsp)
  {
! 	static osi_once_t once;
!         cm_buf_t *bp;
!         long sectorSize;
!         thread_t phandle;
  #ifndef DJGPP
! 	HANDLE hf, hm;
! 	PSECURITY_ATTRIBUTES psa;
  #endif /* !DJGPP */
! 	long i;
!         unsigned long pid;
! 	char *data;
! 	long cs;
  
  #ifndef DJGPP
! 	/* Get system info; all we really want is the allocation granularity */ 
! 	GetSystemInfo(&amp;sysInfo);
  #endif /* !DJGPP */
  
! 	/* Have to be able to reserve a whole chunk */
! 	if (((buf_nbuffers - 3) * buf_bufferSize) &lt; cm_chunkSize)
! 		return CM_ERROR_TOOFEWBUFS;
! 
! 	/* recall for callouts */
! 	cm_buf_opsp = opsp;
! 
!         if (osi_Once(&amp;once)) {
! 		/* initialize global locks */
! 		lock_InitializeRWLock(&amp;buf_globalLock, "Global buffer lock");
  
  #ifndef DJGPP
! 		/*
! 		 * Cache file mapping constrained by
! 		 * system allocation granularity;
! 		 * round up, assuming granularity is a power of two
! 		 */
! 		cs = buf_nbuffers * buf_bufferSize;
! 		cs = (cs + (sysInfo.dwAllocationGranularity - 1))
! 			&amp; ~(sysInfo.dwAllocationGranularity - 1);
! 		if (cs != buf_nbuffers * buf_bufferSize) {
! 			buf_nbuffers = cs / buf_bufferSize;
! 			afsi_log("Cache size rounded up to %d buffers",
! 				 buf_nbuffers);
! 		}
  #endif /* !DJGPP */
  
! 		/* remember this for those who want to reset it */
! 	        buf_nOrigBuffers = buf_nbuffers;
  
! 		/* lower hash size to a prime number */
!                 buf_hashSize = osi_PrimeLessThan(buf_hashSize);
  
! 		/* create hash table */
!                 buf_hashTablepp = malloc(buf_hashSize * sizeof(cm_buf_t *));
!                 memset((void *)buf_hashTablepp, 0,
! 			buf_hashSize * sizeof(cm_buf_t *));
! 
! 		/* another hash table */
!                 buf_fileHashTablepp = malloc(buf_hashSize * sizeof(cm_buf_t *));
!                 memset((void *)buf_fileHashTablepp, 0,
! 			buf_hashSize * sizeof(cm_buf_t *));
                  
! 		/* min value for which this works */
! 		sectorSize = 1;
  
  #ifndef DJGPP
!         if(buf_cacheType == CM_BUF_CACHETYPE_FILE) {
! 		/* Reserve buffer space by mapping cache file */
! 		psa = CreateCacheFileSA();
! 		hf = CreateFile(cm_CachePath,
! 			GENERIC_READ | GENERIC_WRITE,
! 			FILE_SHARE_READ | FILE_SHARE_WRITE,
! 			psa,
! 			OPEN_ALWAYS,
! 			FILE_ATTRIBUTE_NORMAL,
! 			NULL);
! 		if (hf == INVALID_HANDLE_VALUE) {
! 			afsi_log("create file error %d", GetLastError());
! 			return CM_ERROR_INVAL;
! 		}
! 		FreeCacheFileSA(psa);
          } else { /* buf_cacheType == CM_BUF_CACHETYPE_VIRTUAL */
              hf = INVALID_HANDLE_VALUE;
          }
! 		CacheHandle = hf;
! 		hm = CreateFileMapping(hf,
! 			NULL,
! 			PAGE_READWRITE,
! 			0, buf_nbuffers * buf_bufferSize,
! 			NULL);
! 		if (hm == NULL) {
! 			if (GetLastError() == ERROR_DISK_FULL) {
! 				afsi_log("Error creating cache file mapping: disk full");
! 				return CM_ERROR_TOOMANYBUFS;
! 			}
! 			return CM_ERROR_INVAL;
! 		}
! 		data = MapViewOfFile(hm,
! 			FILE_MAP_ALL_ACCESS,
! 			0, 0,
! 			buf_nbuffers * buf_bufferSize);
! 		if (data == NULL) {
! 			if(hf != INVALID_HANDLE_VALUE) CloseHandle(hf);
! 			CloseHandle(hm);
! 			return CM_ERROR_INVAL;
! 		}
! 		CloseHandle(hm);
! #else
!                 /* djgpp doesn't support memory mapped files */
!                 data = malloc(buf_nbuffers * buf_bufferSize);
  #endif /* !DJGPP */
  
!                 /* create buffer headers and put in free list */
! 		bp = malloc(buf_nbuffers * sizeof(cm_buf_t));
!                 buf_allp = NULL;
!                 for(i=0; i&lt;buf_nbuffers; i++) {
! 			/* allocate and zero some storage */
!                         memset(bp, 0, sizeof(cm_buf_t));
! 
! 			/* thread on list of all buffers */
!                         bp-&gt;allp = buf_allp;
!                         buf_allp = bp;
!                         
!                         osi_QAdd((osi_queue_t **)&amp;buf_freeListp, &amp;bp-&gt;q);
!                         bp-&gt;flags |= CM_BUF_INLRU;
!                         lock_InitializeMutex(&amp;bp-&gt;mx, "Buffer mutex");
! 
! 			/* grab appropriate number of bytes from aligned zone */
!                         bp-&gt;datap = data;
! 
! 			/* setup last buffer pointer */
! 	                if (i == 0)
!                         	buf_freeListEndp = bp;
! 
! 			/* next */
! 			bp++;
! 			data += buf_bufferSize;
!                 }
!                 
! 		/* none reserved at first */
!                 buf_reservedBufs = 0;
!                 
!                 /* just for safety's sake */
!                 buf_maxReservedBufs = buf_nbuffers - 3;
!                 
!                 /* init the buffer trace log */
!                 buf_logp = osi_LogCreate("buffer", 10);
  
! 		osi_EndOnce(&amp;once);
!                 
!                 /* and create the incr-syncer */
!                 phandle = thrd_Create(0, 0,
!                                       (ThreadFunc) buf_IncrSyncer, 0, 0, &amp;pid,
!                                       "buf_IncrSyncer");
  
! 		osi_assertx(phandle != NULL, "buf: can't create incremental sync proc");
  #ifndef DJGPP
! 		CloseHandle(phandle);
  #endif /* !DJGPP */
!         }
  
! 	return 0;
  }
  
  /* add nbuffers to the buffer pool, if possible.
--- 231,400 ----
   */
  long buf_Init(cm_buf_ops_t *opsp)
  {
!     static osi_once_t once;
!     cm_buf_t *bp;
!     long sectorSize;
!     thread_t phandle;
  #ifndef DJGPP
!     HANDLE hf, hm;
!     PSECURITY_ATTRIBUTES psa;
  #endif /* !DJGPP */
!     long i;
!     unsigned long pid;
!     char *data;
!     long cs;
  
  #ifndef DJGPP
!     /* Get system info; all we really want is the allocation granularity */ 
!     GetSystemInfo(&amp;sysInfo);
  #endif /* !DJGPP */
  
!     /* Have to be able to reserve a whole chunk */
!     if (((buf_nbuffers - 3) * buf_bufferSize) &lt; cm_chunkSize)
!         return CM_ERROR_TOOFEWBUFS;
! 
!     /* recall for callouts */
!     cm_buf_opsp = opsp;
! 
!     if (osi_Once(&amp;once)) {
!         /* initialize global locks */
!         lock_InitializeRWLock(&amp;buf_globalLock, "Global buffer lock");
  
  #ifndef DJGPP
!         /*
!         * Cache file mapping constrained by
!          * system allocation granularity;
!          * round up, assuming granularity is a power of two
!          */
!         cs = buf_nbuffers * buf_bufferSize;
!         cs = (cs + (sysInfo.dwAllocationGranularity - 1))
!             &amp; ~(sysInfo.dwAllocationGranularity - 1);
!         if (cs != buf_nbuffers * buf_bufferSize) {
!             buf_nbuffers = cs / buf_bufferSize;
!             afsi_log("Cache size rounded up to %d buffers",
!                       buf_nbuffers);
!         }
  #endif /* !DJGPP */
  
!         /* remember this for those who want to reset it */
!         buf_nOrigBuffers = buf_nbuffers;
  
!         /* lower hash size to a prime number */
!         buf_hashSize = osi_PrimeLessThan(buf_hashSize);
  
!         /* create hash table */
!         buf_hashTablepp = malloc(buf_hashSize * sizeof(cm_buf_t *));
!         memset((void *)buf_hashTablepp, 0,
!                 buf_hashSize * sizeof(cm_buf_t *));
! 
!         /* another hash table */
!         buf_fileHashTablepp = malloc(buf_hashSize * sizeof(cm_buf_t *));
!         memset((void *)buf_fileHashTablepp, 0,
!                 buf_hashSize * sizeof(cm_buf_t *));
                  
!         /* min value for which this works */
!         sectorSize = 1;
  
  #ifndef DJGPP
!         if (buf_cacheType == CM_BUF_CACHETYPE_FILE) {
!             /* Reserve buffer space by mapping cache file */
!             psa = CreateCacheFileSA();
!             hf = CreateFile(cm_CachePath,
!                              GENERIC_READ | GENERIC_WRITE,
!                              FILE_SHARE_READ | FILE_SHARE_WRITE,
!                              psa,
!                              OPEN_ALWAYS,
!                              FILE_ATTRIBUTE_NORMAL,
!                              NULL);
!             if (hf == INVALID_HANDLE_VALUE) {
!                 afsi_log("Error creating cache file \"%s\" error %d", 
!                           cm_CachePath, GetLastError());
!                 return CM_ERROR_INVAL;
!             }
!             FreeCacheFileSA(psa);
          } else { /* buf_cacheType == CM_BUF_CACHETYPE_VIRTUAL */
              hf = INVALID_HANDLE_VALUE;
          }
!         CacheHandle = hf;
!         hm = CreateFileMapping(hf,
!                                 NULL,
!                                 PAGE_READWRITE,
!                                 0, buf_nbuffers * buf_bufferSize,
!                                 NULL);
!         if (hm == NULL) {
!             if (GetLastError() == ERROR_DISK_FULL) {
!                 afsi_log("Error creating cache file \"%s\" mapping: disk full",
!                           cm_CachePath);
!                 return CM_ERROR_TOOMANYBUFS;
!             }
!             return CM_ERROR_INVAL;
!         }
!         data = MapViewOfFile(hm,
!                               FILE_MAP_ALL_ACCESS,
!                               0, 0,   
!                               buf_nbuffers * buf_bufferSize);
!         if (data == NULL) {
!             if (hf != INVALID_HANDLE_VALUE)
!                 CloseHandle(hf);
!             CloseHandle(hm);
!             return CM_ERROR_INVAL;
!         }
!         CloseHandle(hm);
! #else   
!         /* djgpp doesn't support memory mapped files */
!         data = malloc(buf_nbuffers * buf_bufferSize);
  #endif /* !DJGPP */
  
!         /* create buffer headers and put in free list */
!         bp = malloc(buf_nbuffers * sizeof(cm_buf_t));
!         buf_allp = NULL;
!         for(i=0; i&lt;buf_nbuffers; i++) {
!             /* allocate and zero some storage */
!             memset(bp, 0, sizeof(cm_buf_t));
! 
!             /* thread on list of all buffers */
!             bp-&gt;allp = buf_allp;
!             buf_allp = bp;
! 
!             osi_QAdd((osi_queue_t **)&amp;buf_freeListp, &amp;bp-&gt;q);
!             bp-&gt;flags |= CM_BUF_INLRU;
!             lock_InitializeMutex(&amp;bp-&gt;mx, "Buffer mutex");
! 
!             /* grab appropriate number of bytes from aligned zone */
!             bp-&gt;datap = data;
! 
!             /* setup last buffer pointer */
!             if (i == 0)
!                 buf_freeListEndp = bp;
! 
!             /* next */
!             bp++;
!             data += buf_bufferSize;
!         }
  
!         /* none reserved at first */
!         buf_reservedBufs = 0;
! 
!         /* just for safety's sake */
!         buf_maxReservedBufs = buf_nbuffers - 3;
! 
!         /* init the buffer trace log */
!         buf_logp = osi_LogCreate("buffer", 10);
! 
!         osi_EndOnce(&amp;once);
! 
!         /* and create the incr-syncer */
!         phandle = thrd_Create(0, 0,
!                                (ThreadFunc) buf_IncrSyncer, 0, 0, &amp;pid,
!                                "buf_IncrSyncer");
  
!         osi_assertx(phandle != NULL, "buf: can't create incremental sync proc");
  #ifndef DJGPP
!         CloseHandle(phandle);
  #endif /* !DJGPP */
!     }
  
!     return 0;
  }
  
  /* add nbuffers to the buffer pool, if possible.
***************
*** 399,410 ****
   */
  long buf_AddBuffers(long nbuffers)
  {
! 	cm_buf_t *bp;
!         int i;
! 	char *data;
  #ifndef DJGPP
! 	HANDLE hm;
! 	long cs;
  
      afsi_log("%d buffers being added to the existing cache of size %d",
                nbuffers, buf_nbuffers);
--- 402,413 ----
   */
  long buf_AddBuffers(long nbuffers)
  {
!     cm_buf_t *bp;
!     int i;
!     char *data;
  #ifndef DJGPP
!     HANDLE hm;
!     long cs;
  
      afsi_log("%d buffers being added to the existing cache of size %d",
                nbuffers, buf_nbuffers);
***************
*** 418,490 ****
          return CM_ERROR_INVAL;
      }
  
! 	/*
! 	 * Cache file mapping constrained by
! 	 * system allocation granularity;
! 	 * round up, assuming granularity is a power of two;
! 	 * assume existing cache size is already rounded
! 	 */
! 	cs = nbuffers * buf_bufferSize;
! 	cs = (cs + (sysInfo.dwAllocationGranularity - 1))
! 		&amp; ~(sysInfo.dwAllocationGranularity - 1);
! 	if (cs != nbuffers * buf_bufferSize) {
! 		nbuffers = cs / buf_bufferSize;
! 	}
! 
! 	/* Reserve additional buffer space by remapping cache file */
! 	hm = CreateFileMapping(CacheHandle,
! 		NULL,
! 		PAGE_READWRITE,
! 		0, (buf_nbuffers + nbuffers) * buf_bufferSize,
! 		NULL);
! 	if (hm == NULL) {
! 		if (GetLastError() == ERROR_DISK_FULL)
! 			return CM_ERROR_TOOMANYBUFS;
! 		else
! 			return CM_ERROR_INVAL;
! 	}
! 	data = MapViewOfFile(hm,
! 		FILE_MAP_ALL_ACCESS,
! 		0, buf_nbuffers * buf_bufferSize,
! 		nbuffers * buf_bufferSize);
! 	if (data == NULL) {
! 		CloseHandle(hm);
! 		return CM_ERROR_INVAL;
! 	}
! 	CloseHandle(hm);
  #else
!         data = malloc(buf_nbuffers * buf_bufferSize);
  #endif /* DJGPP */
  
! 	/* Create buffer headers and put in free list */
!         bp = malloc(nbuffers * sizeof(*bp));
  
! 	for(i=0; i&lt;nbuffers; i++) {
! 	        memset(bp, 0, sizeof(*bp));
          
! 	        lock_InitializeMutex(&amp;bp-&gt;mx, "cm_buf_t");
  
! 		/* grab appropriate number of bytes from aligned zone */
! 		bp-&gt;datap = data;
  
!                 bp-&gt;flags |= CM_BUF_INLRU;
!                 
!                 lock_ObtainWrite(&amp;buf_globalLock);
! 		/* note that buf_allp chain is covered by buf_globalLock now */
!                 bp-&gt;allp = buf_allp;
!                 buf_allp = bp;
!                 osi_QAdd((osi_queue_t **) &amp;buf_freeListp, &amp;bp-&gt;q);
!                 if (!buf_freeListEndp) buf_freeListEndp = bp;
!                 buf_nbuffers++;
!                 lock_ReleaseWrite(&amp;buf_globalLock);
  
! 		bp++;
! 		data += buf_bufferSize;
  	
!         }	 /* for loop over all buffers */
  
!         return 0;
! }
  
  /* interface to set the number of buffers to an exact figure.
   * Called with no locks held.
--- 421,493 ----
          return CM_ERROR_INVAL;
      }
  
!     /*
!      * Cache file mapping constrained by
!      * system allocation granularity;
!      * round up, assuming granularity is a power of two;
!      * assume existing cache size is already rounded
!      */
!     cs = nbuffers * buf_bufferSize;
!     cs = (cs + (sysInfo.dwAllocationGranularity - 1))
!         &amp; ~(sysInfo.dwAllocationGranularity - 1);
!     if (cs != nbuffers * buf_bufferSize) {
!         nbuffers = cs / buf_bufferSize;
!     }
! 
!     /* Reserve additional buffer space by remapping cache file */
!     hm = CreateFileMapping(CacheHandle,
!                             NULL,
!                             PAGE_READWRITE,
!                             0, (buf_nbuffers + nbuffers) * buf_bufferSize,
!                             NULL);
!     if (hm == NULL) {
!         if (GetLastError() == ERROR_DISK_FULL)
!             return CM_ERROR_TOOMANYBUFS;
!         else
!             return CM_ERROR_INVAL;
!     }
!     data = MapViewOfFile(hm,
!                           FILE_MAP_ALL_ACCESS,
!                           0, buf_nbuffers * buf_bufferSize,
!                           nbuffers * buf_bufferSize);
!     if (data == NULL) {
!         CloseHandle(hm);
!         return CM_ERROR_INVAL;
!     }
!     CloseHandle(hm);
  #else
!     data = malloc(buf_nbuffers * buf_bufferSize);
  #endif /* DJGPP */
  
!     /* Create buffer headers and put in free list */
!     bp = malloc(nbuffers * sizeof(*bp));
  
!     for(i=0; i&lt;nbuffers; i++) {
!         memset(bp, 0, sizeof(*bp));
          
!         lock_InitializeMutex(&amp;bp-&gt;mx, "cm_buf_t");
  
!         /* grab appropriate number of bytes from aligned zone */
!         bp-&gt;datap = data;
  
!         bp-&gt;flags |= CM_BUF_INLRU;
! 
!         lock_ObtainWrite(&amp;buf_globalLock);
!         /* note that buf_allp chain is covered by buf_globalLock now */
!         bp-&gt;allp = buf_allp;
!         buf_allp = bp;
!         osi_QAdd((osi_queue_t **) &amp;buf_freeListp, &amp;bp-&gt;q);
!         if (!buf_freeListEndp) buf_freeListEndp = bp;
!         buf_nbuffers++;
!         lock_ReleaseWrite(&amp;buf_globalLock);
  
!         bp++;
!         data += buf_bufferSize;
  	
!     }	 /* for loop over all buffers */
  
!     return 0;
! }       
  
  /* interface to set the number of buffers to an exact figure.
   * Called with no locks held.
***************
*** 495,502 ****
          return CM_ERROR_INVAL;
      if (nbuffers == buf_nbuffers) 
          return 0;
!         else if (nbuffers &gt; buf_nbuffers)
! 		return buf_AddBuffers(nbuffers - buf_nbuffers);
      else 
          return CM_ERROR_INVAL;
  }
--- 498,505 ----
          return CM_ERROR_INVAL;
      if (nbuffers == buf_nbuffers) 
          return 0;
!     else if (nbuffers &gt; buf_nbuffers)
!         return buf_AddBuffers(nbuffers - buf_nbuffers);
      else 
          return CM_ERROR_INVAL;
  }
***************
*** 504,512 ****
  /* release a buffer.  Buffer must be referenced, but unlocked. */
  void buf_Release(cm_buf_t *bp)
  {
! 	lock_ObtainWrite(&amp;buf_globalLock);
! 	buf_LockedRelease(bp);
! 	lock_ReleaseWrite(&amp;buf_globalLock);
  }
  
  /* wait for reading or writing to clear; called with write-locked
--- 507,515 ----
  /* release a buffer.  Buffer must be referenced, but unlocked. */
  void buf_Release(cm_buf_t *bp)
  {
!     lock_ObtainWrite(&amp;buf_globalLock);
!     buf_LockedRelease(bp);
!     lock_ReleaseWrite(&amp;buf_globalLock);
  }
  
  /* wait for reading or writing to clear; called with write-locked
***************
*** 514,523 ****
   */
  void buf_WaitIO(cm_buf_t *bp)
  {
! 	while (1) {
! 		/* if no IO is happening, we're done */
! 		if (!(bp-&gt;flags &amp; (CM_BUF_READING | CM_BUF_WRITING)))
! 			break;
  		
          /* otherwise I/O is happening, but some other thread is waiting for
           * the I/O already.  Wait for that guy to figure out what happened,
--- 517,526 ----
   */
  void buf_WaitIO(cm_buf_t *bp)
  {
!     while (1) {
!         /* if no IO is happening, we're done */
!         if (!(bp-&gt;flags &amp; (CM_BUF_READING | CM_BUF_WRITING)))
!             break;
  		
          /* otherwise I/O is happening, but some other thread is waiting for
           * the I/O already.  Wait for that guy to figure out what happened,
***************
*** 536,542 ****
       * the I/O to complete.  Do so.
       */
      if (bp-&gt;flags &amp; CM_BUF_WAITING) {
! 		bp-&gt;flags &amp;= ~CM_BUF_WAITING;
          osi_Wakeup((long) bp);
      }
      osi_Log1(buf_logp, "WaitIO finished wait for bp 0x%x", (long) bp);
--- 539,545 ----
       * the I/O to complete.  Do so.
       */
      if (bp-&gt;flags &amp; CM_BUF_WAITING) {
!         bp-&gt;flags &amp;= ~CM_BUF_WAITING;
          osi_Wakeup((long) bp);
      }
      osi_Log1(buf_logp, "WaitIO finished wait for bp 0x%x", (long) bp);
***************
*** 545,584 ****
  /* code to drop reference count while holding buf_globalLock */
  void buf_LockedRelease(cm_buf_t *bp)
  {
! 	/* ensure that we're in the LRU queue if our ref count is 0 */
! 	osi_assert(bp-&gt;refCount &gt; 0);
! 	if (--bp-&gt;refCount == 0) {
! 		if (!(bp-&gt;flags &amp; CM_BUF_INLRU)) {
! 			osi_QAdd((osi_queue_t **) &amp;buf_freeListp, &amp;bp-&gt;q);
! 
!       			/* watch for transition from empty to one element */
!                         if (!buf_freeListEndp)
!                         	buf_freeListEndp = buf_freeListp;
! 			bp-&gt;flags |= CM_BUF_INLRU;
!                 }
          }
! }
  
  /* find a buffer, if any, for a particular file ID and offset.  Assumes
   * that buf_globalLock is write locked when called.
   */
  cm_buf_t *buf_LockedFind(struct cm_scache *scp, osi_hyper_t *offsetp)
  {
! 	long i;
!         cm_buf_t *bp;
!         
!         i = BUF_HASH(&amp;scp-&gt;fid, offsetp);
!         for(bp = buf_hashTablepp[i]; bp; bp=bp-&gt;hashp) {
! 		if (cm_FidCmp(&amp;scp-&gt;fid, &amp;bp-&gt;fid) == 0
! 			&amp;&amp; offsetp-&gt;LowPart == bp-&gt;offset.LowPart
!                 	&amp;&amp; offsetp-&gt;HighPart == bp-&gt;offset.HighPart) {
! 			bp-&gt;refCount++;
! 			break;
!                 }
          }
          
! 	/* return whatever we found, if anything */
!         return bp;
  }
  
  /* find a buffer with offset *offsetp for vnode *scp.  Called
--- 548,587 ----
  /* code to drop reference count while holding buf_globalLock */
  void buf_LockedRelease(cm_buf_t *bp)
  {
!     /* ensure that we're in the LRU queue if our ref count is 0 */
!     osi_assert(bp-&gt;refCount &gt; 0);
!     if (--bp-&gt;refCount == 0) {
!         if (!(bp-&gt;flags &amp; CM_BUF_INLRU)) {
!             osi_QAdd((osi_queue_t **) &amp;buf_freeListp, &amp;bp-&gt;q);
! 
!             /* watch for transition from empty to one element */
!             if (!buf_freeListEndp)
!                 buf_freeListEndp = buf_freeListp;
!             bp-&gt;flags |= CM_BUF_INLRU;
          }
!     }
! }       
  
  /* find a buffer, if any, for a particular file ID and offset.  Assumes
   * that buf_globalLock is write locked when called.
   */
  cm_buf_t *buf_LockedFind(struct cm_scache *scp, osi_hyper_t *offsetp)
  {
!     long i;
!     cm_buf_t *bp;
! 
!     i = BUF_HASH(&amp;scp-&gt;fid, offsetp);
!     for(bp = buf_hashTablepp[i]; bp; bp=bp-&gt;hashp) {
!         if (cm_FidCmp(&amp;scp-&gt;fid, &amp;bp-&gt;fid) == 0
!              &amp;&amp; offsetp-&gt;LowPart == bp-&gt;offset.LowPart
!              &amp;&amp; offsetp-&gt;HighPart == bp-&gt;offset.HighPart) {
!             bp-&gt;refCount++;
!             break;
          }
+     }
          
!     /* return whatever we found, if anything */
!     return bp;
  }
  
  /* find a buffer with offset *offsetp for vnode *scp.  Called
***************
*** 586,599 ****
   */
  cm_buf_t *buf_Find(struct cm_scache *scp, osi_hyper_t *offsetp)
  {
! 	cm_buf_t *bp;
  
! 	lock_ObtainWrite(&amp;buf_globalLock);
! 	bp = buf_LockedFind(scp, offsetp);
! 	lock_ReleaseWrite(&amp;buf_globalLock);
  
! 	return bp;
! }
  
  /* start cleaning I/O on this buffer.  Buffer must be write locked, and is returned
   * write-locked.
--- 589,602 ----
   */
  cm_buf_t *buf_Find(struct cm_scache *scp, osi_hyper_t *offsetp)
  {
!     cm_buf_t *bp;
  
!     lock_ObtainWrite(&amp;buf_globalLock);
!     bp = buf_LockedFind(scp, offsetp);
!     lock_ReleaseWrite(&amp;buf_globalLock);
  
!     return bp;
! }       
  
  /* start cleaning I/O on this buffer.  Buffer must be write locked, and is returned
   * write-locked.
***************
*** 604,640 ****
   */
  void buf_LockedCleanAsync(cm_buf_t *bp, cm_req_t *reqp)
  {
! 	long code;
  
! 	code = 0;
! 	while ((bp-&gt;flags &amp; (CM_BUF_WRITING | CM_BUF_DIRTY)) == CM_BUF_DIRTY) {
!         	lock_ReleaseMutex(&amp;bp-&gt;mx);
! 
! 	        code = (*cm_buf_opsp-&gt;Writep)(&amp;bp-&gt;fid, &amp;bp-&gt;offset,
! 						buf_bufferSize, 0, bp-&gt;userp,
! 						reqp);
                  
!                 lock_ObtainMutex(&amp;bp-&gt;mx);
!                 if (code) break;
  
  #ifdef DISKCACHE95
!                 /* Disk cache support */
!                 /* write buffer to disk cache (synchronous for now) */
!                 diskcache_Update(bp-&gt;dcp, bp-&gt;datap, buf_bufferSize, bp-&gt;dataVersion);
  #endif /* DISKCACHE95 */
! 	};
  
!         /* do logging after call to GetLastError, or else */
! 	osi_Log2(buf_logp, "buf_CleanAsync starts I/O on 0x%x, done=%d", bp, code);
          
! 	/* if someone was waiting for the I/O that just completed or failed,
!          * wake them up.
!          */
!         if (bp-&gt;flags &amp; CM_BUF_WAITING) {
! 		/* turn off flags and wakeup users */
!                 bp-&gt;flags &amp;= ~CM_BUF_WAITING;
!                 osi_Wakeup((long) bp);
!         }
  }
  
  /* Called with a zero-ref count buffer and with the buf_globalLock write locked.
--- 607,644 ----
   */
  void buf_LockedCleanAsync(cm_buf_t *bp, cm_req_t *reqp)
  {
!     long code;
! 
!     code = 0;
!     while ((bp-&gt;flags &amp; (CM_BUF_WRITING | CM_BUF_DIRTY)) == CM_BUF_DIRTY) {
!         lock_ReleaseMutex(&amp;bp-&gt;mx);
  
!         code = (*cm_buf_opsp-&gt;Writep)(&amp;bp-&gt;fid, &amp;bp-&gt;offset,
!                                        buf_bufferSize, 0, bp-&gt;userp,
!                                        reqp);
                  
!         lock_ObtainMutex(&amp;bp-&gt;mx);
!         if (code) 
!             break;
  
  #ifdef DISKCACHE95
!         /* Disk cache support */
!         /* write buffer to disk cache (synchronous for now) */
!         diskcache_Update(bp-&gt;dcp, bp-&gt;datap, buf_bufferSize, bp-&gt;dataVersion);
  #endif /* DISKCACHE95 */
!     };
  
!     /* do logging after call to GetLastError, or else */
!     osi_Log2(buf_logp, "buf_CleanAsync starts I/O on 0x%x, done=%d", bp, code);
          
!     /* if someone was waiting for the I/O that just completed or failed,
!      * wake them up.
!      */
!     if (bp-&gt;flags &amp; CM_BUF_WAITING) {
!         /* turn off flags and wakeup users */
!         bp-&gt;flags &amp;= ~CM_BUF_WAITING;
!         osi_Wakeup((long) bp);
!     }
  }
  
  /* Called with a zero-ref count buffer and with the buf_globalLock write locked.
***************
*** 643,705 ****
   */
  void buf_Recycle(cm_buf_t *bp)
  {
! 	int i;
!         cm_buf_t **lbpp;
!         cm_buf_t *tbp;
! 	cm_buf_t *prevBp, *nextBp;
! 
! 	/* if we get here, we know that the buffer still has a 0 ref count,
! 	 * and that it is clean and has no currently pending I/O.  This is
! 	 * the dude to return.
! 	 * Remember that as long as the ref count is 0, we know that we won't
! 	 * have any lock conflicts, so we can grab the buffer lock out of
! 	 * order in the locking hierarchy.
! 	 */
      osi_Log2( buf_logp, "buf_Recycle recycles 0x%x, off 0x%x",
! 		bp, bp-&gt;offset.LowPart);
  
! 	osi_assert(bp-&gt;refCount == 0);
! 	osi_assert(!(bp-&gt;flags &amp; (CM_BUF_READING | CM_BUF_WRITING | CM_BUF_DIRTY)));
! 	lock_AssertWrite(&amp;buf_globalLock);
! 
! 	if (bp-&gt;flags &amp; CM_BUF_INHASH) {
! 		/* Remove from hash */
! 
! 		i = BUF_HASH(&amp;bp-&gt;fid, &amp;bp-&gt;offset);
! 		lbpp = &amp;(buf_hashTablepp[i]);
! 		for(tbp = *lbpp; tbp; lbpp = &amp;tbp-&gt;hashp, tbp = *lbpp) {
! 			if (tbp == bp) break;
! 		}
! 
! 		/* we better find it */
! 		osi_assertx(tbp != NULL, "buf_GetNewLocked: hash table screwup");
! 
! 		*lbpp = bp-&gt;hashp;	/* hash out */
! 
! 		/* Remove from file hash */
! 
! 		i = BUF_FILEHASH(&amp;bp-&gt;fid);
! 		prevBp = bp-&gt;fileHashBackp;
! 		nextBp = bp-&gt;fileHashp;
! 		if (prevBp)
! 			prevBp-&gt;fileHashp = nextBp;
! 		else
! 			buf_fileHashTablepp[i] = nextBp;
! 		if (nextBp)
! 			nextBp-&gt;fileHashBackp = prevBp;
  
! 		bp-&gt;flags &amp;= ~CM_BUF_INHASH;
! 	}
!                         
! 	/* bump the soft reference counter now, to invalidate softRefs; no
! 	 * wakeup is required since people don't sleep waiting for this
! 	 * counter to change.
! 	 */
! 	bp-&gt;idCounter++;
  
! 	/* make the fid unrecognizable */
!         memset(&amp;bp-&gt;fid, 0, sizeof(bp-&gt;fid));
! }
  
  /* recycle a buffer, removing it from the free list, hashing in its new identity
   * and returning it write-locked so that no one can use it.  Called without
--- 647,709 ----
   */
  void buf_Recycle(cm_buf_t *bp)
  {
!     int i;
!     cm_buf_t **lbpp;
!     cm_buf_t *tbp;
!     cm_buf_t *prevBp, *nextBp;
! 
!     /* if we get here, we know that the buffer still has a 0 ref count,
!      * and that it is clean and has no currently pending I/O.  This is
!      * the dude to return.
!      * Remember that as long as the ref count is 0, we know that we won't
!      * have any lock conflicts, so we can grab the buffer lock out of
!      * order in the locking hierarchy.
!      */
      osi_Log2( buf_logp, "buf_Recycle recycles 0x%x, off 0x%x",
!               bp, bp-&gt;offset.LowPart);
  
!     osi_assert(bp-&gt;refCount == 0);
!     osi_assert(!(bp-&gt;flags &amp; (CM_BUF_READING | CM_BUF_WRITING | CM_BUF_DIRTY)));
!     lock_AssertWrite(&amp;buf_globalLock);
! 
!     if (bp-&gt;flags &amp; CM_BUF_INHASH) {
!         /* Remove from hash */
! 
!         i = BUF_HASH(&amp;bp-&gt;fid, &amp;bp-&gt;offset);
!         lbpp = &amp;(buf_hashTablepp[i]);
!         for(tbp = *lbpp; tbp; lbpp = &amp;tbp-&gt;hashp, tbp = *lbpp) {
!             if (tbp == bp) break;
!         }
  
!         /* we better find it */
!         osi_assertx(tbp != NULL, "buf_GetNewLocked: hash table screwup");
  
!         *lbpp = bp-&gt;hashp;	/* hash out */
! 
!         /* Remove from file hash */
! 
!         i = BUF_FILEHASH(&amp;bp-&gt;fid);
!         prevBp = bp-&gt;fileHashBackp;
!         nextBp = bp-&gt;fileHashp;
!         if (prevBp)
!             prevBp-&gt;fileHashp = nextBp;
!         else
!             buf_fileHashTablepp[i] = nextBp;
!         if (nextBp)
!             nextBp-&gt;fileHashBackp = prevBp;
! 
!         bp-&gt;flags &amp;= ~CM_BUF_INHASH;
!     }
! 
!     /* bump the soft reference counter now, to invalidate softRefs; no
!      * wakeup is required since people don't sleep waiting for this
!      * counter to change.
!      */
!     bp-&gt;idCounter++;
! 
!     /* make the fid unrecognizable */
!     memset(&amp;bp-&gt;fid, 0, sizeof(bp-&gt;fid));
! }       
  
  /* recycle a buffer, removing it from the free list, hashing in its new identity
   * and returning it write-locked so that no one can use it.  Called without
***************
*** 714,866 ****
   */
  long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
  {
! 	cm_buf_t *bp;		/* buffer we're dealing with */
! 	cm_buf_t *nextBp;	/* next buffer in file hash chain */
!         long i;			/* temp */
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);	/* just in case */
! 
! 	while(1) {
! retry:
! 		lock_ObtainWrite(&amp;buf_globalLock);
! 		/* check to see if we lost the race */
! 		if (scp) {
! 			if (bp = buf_LockedFind(scp, offsetp)) {
! 				bp-&gt;refCount--;
! 				lock_ReleaseWrite(&amp;buf_globalLock);
! 	                	return CM_BUF_EXISTS;
! 	                }
! 		}
!                 
! 		/* for debugging, assert free list isn't empty, although we
! 		 * really should try waiting for a running tranasction to finish
! 		 * instead of this; or better, we should have a transaction
! 		 * throttler prevent us from entering this situation.
!                  */
!                 osi_assertx(buf_freeListEndp != NULL, "buf_GetNewLocked: no free buffers");
  
! 		/* look at all buffers in free list, some of which may temp.
! 		 * have high refcounts and which then should be skipped,
! 		 * starting cleaning I/O for those which are dirty.  If we find
! 		 * a clean buffer, we rehash it, lock it and return it.
!                  */
!                 for(bp = buf_freeListEndp; bp; bp=(cm_buf_t *) osi_QPrev(&amp;bp-&gt;q)) {
! 			/* check to see if it really has zero ref count.  This
! 			 * code can bump refcounts, at least, so it may not be
! 			 * zero.
!                          */
!                         if (bp-&gt;refCount &gt; 0) continue;
!                         
! 			/* we don't have to lock buffer itself, since the ref
! 			 * count is 0 and we know it will stay zero as long as
! 			 * we hold the global lock.
!                          */
! 
! 			/* don't recycle someone in our own chunk */
! 			if (!cm_FidCmp(&amp;bp-&gt;fid, &amp;scp-&gt;fid)
! 			    &amp;&amp; (bp-&gt;offset.LowPart &amp; (-cm_chunkSize))
! 				  == (offsetp-&gt;LowPart &amp; (-cm_chunkSize)))
! 				continue;
! 
! 			/* if this page is being filled (!) or cleaned, see if
! 			 * the I/O has completed.  If not, skip it, otherwise
! 			 * do the final processing for the I/O.
!                          */
!                         if (bp-&gt;flags &amp; (CM_BUF_READING | CM_BUF_WRITING)) {
! 				/* probably shouldn't do this much work while
! 				 * holding the big lock?  Watch for contention
! 				 * here.
!                                  */
!                                 continue;
!                         }
!                         
!                         if (bp-&gt;flags &amp; CM_BUF_DIRTY) {
! 				/* if the buffer is dirty, start cleaning it and
! 				 * move on to the next buffer.  We do this with
! 				 * just the lock required to minimize contention
! 				 * on the big lock.
!                                  */
! 				bp-&gt;refCount++;
!                                 lock_ReleaseWrite(&amp;buf_globalLock);
! 
! 				/* grab required lock and clean; this only
! 				 * starts the I/O.  By the time we're back,
! 				 * it'll still be marked dirty, but it will also
! 				 * have the WRITING flag set, so we won't get
! 				 * back here.
! 				 */
!                                	buf_CleanAsync(bp, &amp;req);
!                                 
!                                 /* now put it back and go around again */
! 				buf_Release(bp);
!                                 goto retry;
!                         }
!                         
!                         /* if we get here, we know that the buffer still has a 0
! 			 * ref count, and that it is clean and has no currently
! 			 * pending I/O.  This is the dude to return.
!                          * Remember that as long as the ref count is 0, we know
! 			 * that we won't have any lock conflicts, so we can grab
! 			 * the buffer lock out of order in the locking hierarchy.
!                          */
!                         buf_Recycle(bp);
! 
! 			/* clean up junk flags */
! 			bp-&gt;flags &amp;= ~(CM_BUF_EOF | CM_BUF_ERROR);
! 			bp-&gt;dataVersion = -1;	/* unknown so far */
! 
! 			/* now hash in as our new buffer, and give it the
! 			 * appropriate label, if requested.
!                          */
! 			if (scp) {
! 				bp-&gt;flags |= CM_BUF_INHASH;
! 				bp-&gt;fid = scp-&gt;fid;
! 				bp-&gt;offset = *offsetp;
! 				i = BUF_HASH(&amp;scp-&gt;fid, offsetp);
! 				bp-&gt;hashp = buf_hashTablepp[i];
! 				buf_hashTablepp[i] = bp;
! 				i = BUF_FILEHASH(&amp;scp-&gt;fid);
! 				nextBp = buf_fileHashTablepp[i];
! 				bp-&gt;fileHashp = nextBp;
! 				bp-&gt;fileHashBackp = NULL;
! 				if (nextBp)
! 					nextBp-&gt;fileHashBackp = bp;
! 				buf_fileHashTablepp[i] = bp;
! 			}
                          
! 			/* prepare to return it.  Start by giving it a good
! 			 * refcount */
! 			bp-&gt;refCount = 1;
                          
! 			/* and since it has a non-zero ref count, we should move
! 			 * it from the lru queue.  It better be still there,
! 			 * since we've held the global (big) lock since we found
! 			 * it there.
! 			 */
! 			osi_assertx(bp-&gt;flags &amp; CM_BUF_INLRU,
! 				    "buf_GetNewLocked: LRU screwup");
! 			if (buf_freeListEndp == bp) {
! 				/* we're the last guy in this queue, so maintain it */
! 				buf_freeListEndp = (cm_buf_t *) osi_QPrev(&amp;bp-&gt;q);
! 			}
! 			osi_QRemove((osi_queue_t **) &amp;buf_freeListp, &amp;bp-&gt;q);
! 			bp-&gt;flags &amp;= ~CM_BUF_INLRU;
                          
! 			/* finally, grab the mutex so that people don't use it
! 			 * before the caller fills it with data.  Again, no one	
! 			 * should have been able to get to this dude to lock it.
! 			 */
! 			osi_assertx(lock_TryMutex(&amp;bp-&gt;mx),
! 				    "buf_GetNewLocked: TryMutex failed");
! 
!                         lock_ReleaseWrite(&amp;buf_globalLock);
!                         *bufpp = bp;
!                         return 0;
!                 } /* for all buffers in lru queue */
! 		lock_ReleaseWrite(&amp;buf_globalLock);
!         }	/* while loop over everything */
!         /* not reached */
  } /* the proc */
  
  /* get a page, returning it held but unlocked.  Doesn't fill in the page
--- 718,871 ----
   */
  long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
  {
!     cm_buf_t *bp;		/* buffer we're dealing with */
!     cm_buf_t *nextBp;	/* next buffer in file hash chain */
!     long i;			/* temp */
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);	/* just in case */
! 
!     while(1) {
!       retry:
!         lock_ObtainWrite(&amp;buf_globalLock);
!         /* check to see if we lost the race */
!         if (scp) {
!             if (bp = buf_LockedFind(scp, offsetp)) {
!                 bp-&gt;refCount--;
!                 lock_ReleaseWrite(&amp;buf_globalLock);
!                 return CM_BUF_EXISTS;
!             }
!         }
! 
!         /* for debugging, assert free list isn't empty, although we
!          * really should try waiting for a running tranasction to finish
!          * instead of this; or better, we should have a transaction
!          * throttler prevent us from entering this situation.
!          */
!         osi_assertx(buf_freeListEndp != NULL, "buf_GetNewLocked: no free buffers");
! 
!         /* look at all buffers in free list, some of which may temp.
!          * have high refcounts and which then should be skipped,
!          * starting cleaning I/O for those which are dirty.  If we find
!          * a clean buffer, we rehash it, lock it and return it.
!          */
!         for(bp = buf_freeListEndp; bp; bp=(cm_buf_t *) osi_QPrev(&amp;bp-&gt;q)) {
!             /* check to see if it really has zero ref count.  This
!              * code can bump refcounts, at least, so it may not be
!              * zero.
!              */
!             if (bp-&gt;refCount &gt; 0) 
!                 continue;
                          
!             /* we don't have to lock buffer itself, since the ref
!              * count is 0 and we know it will stay zero as long as
!              * we hold the global lock.
!              */
! 
!             /* don't recycle someone in our own chunk */
!             if (!cm_FidCmp(&amp;bp-&gt;fid, &amp;scp-&gt;fid)
!                  &amp;&amp; (bp-&gt;offset.LowPart &amp; (-cm_chunkSize))
!                  == (offsetp-&gt;LowPart &amp; (-cm_chunkSize)))
!                 continue;
! 
!             /* if this page is being filled (!) or cleaned, see if
!              * the I/O has completed.  If not, skip it, otherwise
!              * do the final processing for the I/O.
!              */
!             if (bp-&gt;flags &amp; (CM_BUF_READING | CM_BUF_WRITING)) {
!                 /* probably shouldn't do this much work while
!                  * holding the big lock?  Watch for contention
!                  * here.
!                  */
!                 continue;
!             }
                          
!             if (bp-&gt;flags &amp; CM_BUF_DIRTY) {
!                 /* if the buffer is dirty, start cleaning it and
!                  * move on to the next buffer.  We do this with
!                  * just the lock required to minimize contention
!                  * on the big lock.
!                  */
!                 bp-&gt;refCount++;
!                 lock_ReleaseWrite(&amp;buf_globalLock);
! 
!                 /* grab required lock and clean; this only
!                  * starts the I/O.  By the time we're back,
!                  * it'll still be marked dirty, but it will also
!                  * have the WRITING flag set, so we won't get
!                  * back here.
!                  */
!                 buf_CleanAsync(bp, &amp;req);
! 
!                 /* now put it back and go around again */
!                 buf_Release(bp);
!                 goto retry;
!             }
! 
!             /* if we get here, we know that the buffer still has a 0
!              * ref count, and that it is clean and has no currently
!              * pending I/O.  This is the dude to return.
!              * Remember that as long as the ref count is 0, we know
!              * that we won't have any lock conflicts, so we can grab
!              * the buffer lock out of order in the locking hierarchy.
!              */
!             buf_Recycle(bp);
! 
!             /* clean up junk flags */
!             bp-&gt;flags &amp;= ~(CM_BUF_EOF | CM_BUF_ERROR);
!             bp-&gt;dataVersion = -1;	/* unknown so far */
! 
!             /* now hash in as our new buffer, and give it the
!              * appropriate label, if requested.
!              */
!             if (scp) {
!                 bp-&gt;flags |= CM_BUF_INHASH;
!                 bp-&gt;fid = scp-&gt;fid;
!                 bp-&gt;offset = *offsetp;
!                 i = BUF_HASH(&amp;scp-&gt;fid, offsetp);
!                 bp-&gt;hashp = buf_hashTablepp[i];
!                 buf_hashTablepp[i] = bp;
!                 i = BUF_FILEHASH(&amp;scp-&gt;fid);
!                 nextBp = buf_fileHashTablepp[i];
!                 bp-&gt;fileHashp = nextBp;
!                 bp-&gt;fileHashBackp = NULL;
!                 if (nextBp)
!                     nextBp-&gt;fileHashBackp = bp;
!                 buf_fileHashTablepp[i] = bp;
!             }
! 
!             /* prepare to return it.  Start by giving it a good
!              * refcount */
!             bp-&gt;refCount = 1;
                          
!             /* and since it has a non-zero ref count, we should move
!              * it from the lru queue.  It better be still there,
!              * since we've held the global (big) lock since we found
!              * it there.
!              */
!             osi_assertx(bp-&gt;flags &amp; CM_BUF_INLRU,
!                          "buf_GetNewLocked: LRU screwup");
!             if (buf_freeListEndp == bp) {
!                 /* we're the last guy in this queue, so maintain it */
!                 buf_freeListEndp = (cm_buf_t *) osi_QPrev(&amp;bp-&gt;q);
!             }
!             osi_QRemove((osi_queue_t **) &amp;buf_freeListp, &amp;bp-&gt;q);
!             bp-&gt;flags &amp;= ~CM_BUF_INLRU;
! 
!             /* finally, grab the mutex so that people don't use it
!              * before the caller fills it with data.  Again, no one	
!              * should have been able to get to this dude to lock it.
!              */
!             osi_assertx(lock_TryMutex(&amp;bp-&gt;mx),
!                          "buf_GetNewLocked: TryMutex failed");
! 
!             lock_ReleaseWrite(&amp;buf_globalLock);
!             *bufpp = bp;
!             return 0;
!         } /* for all buffers in lru queue */
!         lock_ReleaseWrite(&amp;buf_globalLock);
!     }	/* while loop over everything */
!     /* not reached */
  } /* the proc */
  
  /* get a page, returning it held but unlocked.  Doesn't fill in the page
***************
*** 868,1052 ****
   */
  long buf_GetNew(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
  {
! 	cm_buf_t *bp;
!         long code;
!         osi_hyper_t pageOffset;
!         int created;
! 
! 	created = 0;
!         pageOffset.HighPart = offsetp-&gt;HighPart;
!         pageOffset.LowPart = offsetp-&gt;LowPart &amp; ~(buf_bufferSize-1);
! 	while (1) {
! 		lock_ObtainWrite(&amp;buf_globalLock);
! 		bp = buf_LockedFind(scp, &amp;pageOffset);
! 		lock_ReleaseWrite(&amp;buf_globalLock);
!                 if (bp) {
! 			/* lock it and break out */
!                 	lock_ObtainMutex(&amp;bp-&gt;mx);
!                         break;
!                 }
!                 
!                 /* otherwise, we have to create a page */
!                 code = buf_GetNewLocked(scp, &amp;pageOffset, &amp;bp);
  
! 		/* check if the buffer was created in a race condition branch.
! 		 * If so, go around so we can hold a reference to it. 
!                  */
! 		if (code == CM_BUF_EXISTS) continue;
!                 
! 		/* something else went wrong */
!                 if (code != 0) return code;
!                 
!                 /* otherwise, we have a locked buffer that we just created */
!                 created = 1;
!                 break;
!         } /* big while loop */
!         
! 	/* wait for reads */
! 	if (bp-&gt;flags &amp; CM_BUF_READING)
!         	buf_WaitIO(bp);
  
!         /* once it has been read once, we can unlock it and return it, still
! 	 * with its refcount held.
           */
!         lock_ReleaseMutex(&amp;bp-&gt;mx);
!         *bufpp = bp;
!         osi_Log3(buf_logp, "buf_GetNew returning bp 0x%x for file 0x%x, offset 0x%x",
!         	bp, (long) scp, offsetp-&gt;LowPart);
!         return 0;
  }
  
  /* get a page, returning it held but unlocked.  Make sure it is complete */
  long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
  {
! 	cm_buf_t *bp;
!         long code;
!         osi_hyper_t pageOffset;
!         unsigned long tcount;
!         int created;
  #ifdef DISKCACHE95
!         cm_diskcache_t *dcp;
  #endif /* DISKCACHE95 */
  
! 	created = 0;
!         pageOffset.HighPart = offsetp-&gt;HighPart;
!         pageOffset.LowPart = offsetp-&gt;LowPart &amp; ~(buf_bufferSize-1);
! 	while (1) {
! 		lock_ObtainWrite(&amp;buf_globalLock);
! 		bp = buf_LockedFind(scp, &amp;pageOffset);
! 		lock_ReleaseWrite(&amp;buf_globalLock);
!                 if (bp) {
! 			/* lock it and break out */
!                 	lock_ObtainMutex(&amp;bp-&gt;mx);
!                         break;
  
  #ifdef DISKCACHE95
!                         /* touch disk chunk to update LRU info */
!                         diskcache_Touch(bp-&gt;dcp);
  #endif /* DISKCACHE95 */
!                 }
!                 
!                 /* otherwise, we have to create a page */
!                 code = buf_GetNewLocked(scp, &amp;pageOffset, &amp;bp);
  
! 		/* check if the buffer was created in a race condition branch.
! 		 * If so, go around so we can hold a reference to it. 
!                  */
! 		if (code == CM_BUF_EXISTS) continue;
!                 
! 		/* something else went wrong */
!                 if (code != 0) return code;
!                 
!                 /* otherwise, we have a locked buffer that we just created */
!                 created = 1;
!                 break;
!         } /* big while loop */
!         
!         /* if we get here, we have a locked buffer that may have just been
! 	 * created, in which case it needs to be filled with data.
           */
!         if (created) {
! 		/* load the page; freshly created pages should be idle */
! 		osi_assert(!(bp-&gt;flags &amp; (CM_BUF_READING | CM_BUF_WRITING)));
  
! 		/* setup offset, event */
  #ifndef DJGPP  /* doesn't seem to be used */
! 	        bp-&gt;over.Offset = bp-&gt;offset.LowPart;
! 	        bp-&gt;over.OffsetHigh = bp-&gt;offset.HighPart;
  #endif /* !DJGPP */
  
! 		/* start the I/O; may drop lock */
!                 bp-&gt;flags |= CM_BUF_READING;
!                	code = (*cm_buf_opsp-&gt;Readp)(bp, buf_bufferSize, &amp;tcount, NULL);
  
  #ifdef DISKCACHE95
!                 code = diskcache_Get(&amp;bp-&gt;fid, &amp;bp-&gt;offset, bp-&gt;datap, buf_bufferSize, &amp;bp-&gt;dataVersion, &amp;tcount, &amp;dcp);
!                 bp-&gt;dcp = dcp;    /* pointer to disk cache struct. */
  #endif /* DISKCACHE95 */
  
! 		if (code != 0) {
! 			/* failure or queued */
  #ifndef DJGPP   /* cm_bufRead always returns 0 */
!                         if (code != ERROR_IO_PENDING) {
  #endif
! 				bp-&gt;error = code;
!                                 bp-&gt;flags |= CM_BUF_ERROR;
!                                 bp-&gt;flags &amp;= ~CM_BUF_READING;
!                                 if (bp-&gt;flags &amp; CM_BUF_WAITING) {
! 					bp-&gt;flags &amp;= ~CM_BUF_WAITING;
!                                         osi_Wakeup((long) bp);
!                                 }
! 				lock_ReleaseMutex(&amp;bp-&gt;mx);
!                                 buf_Release(bp);
!                                 return code;
  #ifndef DJGPP
!                         }
  #endif
!                 } else {
! 	                /* otherwise, I/O completed instantly and we're done, except
!                          * for padding the xfr out with 0s and checking for EOF
!                          */
! 			if (tcount &lt; (unsigned long) buf_bufferSize) {
! 				memset(bp-&gt;datap+tcount, 0, buf_bufferSize - tcount);
!                                 if (tcount == 0)
!                                 	bp-&gt;flags |= CM_BUF_EOF;
!                         }
! 			bp-&gt;flags &amp;= ~CM_BUF_READING;
! 			if (bp-&gt;flags &amp; CM_BUF_WAITING) {
! 				bp-&gt;flags &amp;= ~CM_BUF_WAITING;
!                                 osi_Wakeup((long) bp);
!                         }
!                 }
!                         
!         } /* if created */
!         
! 	/* wait for reads, either that which we started above, or that someone
! 	 * else started.  We don't care if we return a buffer being cleaned.
!          */
! 	if (bp-&gt;flags &amp; CM_BUF_READING)
!         	buf_WaitIO(bp);
  
!         /* once it has been read once, we can unlock it and return it, still
! 	 * with its refcount held.
!          */
!         lock_ReleaseMutex(&amp;bp-&gt;mx);
!         *bufpp = bp;
  
! 	/* now remove from queue; will be put in at the head (farthest from
! 	 * being recycled) when we're done in buf_Release.
!          */
!         lock_ObtainWrite(&amp;buf_globalLock);
! 	if (bp-&gt;flags &amp; CM_BUF_INLRU) {
! 		if (buf_freeListEndp == bp)
!                 	buf_freeListEndp = (cm_buf_t *) osi_QPrev(&amp;bp-&gt;q);
! 		osi_QRemove((osi_queue_t **) &amp;buf_freeListp, &amp;bp-&gt;q);
!                 bp-&gt;flags &amp;= ~CM_BUF_INLRU;
!         }
!         lock_ReleaseWrite(&amp;buf_globalLock);
  
!         osi_Log3(buf_logp, "buf_Get returning bp 0x%x for file 0x%x, offset 0x%x",
!         	bp, (long) scp, offsetp-&gt;LowPart);
!         return 0;
  }
  
  /* count # of elements in the free list;
--- 873,1061 ----
   */
  long buf_GetNew(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
  {
!     cm_buf_t *bp;
!     long code;
!     osi_hyper_t pageOffset;
!     int created;
! 
!     created = 0;
!     pageOffset.HighPart = offsetp-&gt;HighPart;
!     pageOffset.LowPart = offsetp-&gt;LowPart &amp; ~(buf_bufferSize-1);
!     while (1) {
!         lock_ObtainWrite(&amp;buf_globalLock);
!         bp = buf_LockedFind(scp, &amp;pageOffset);
!         lock_ReleaseWrite(&amp;buf_globalLock);
!         if (bp) {
!             /* lock it and break out */
!             lock_ObtainMutex(&amp;bp-&gt;mx);
!             break;
!         }
  
!         /* otherwise, we have to create a page */
!         code = buf_GetNewLocked(scp, &amp;pageOffset, &amp;bp);
  
!         /* check if the buffer was created in a race condition branch.
!          * If so, go around so we can hold a reference to it. 
           */
!         if (code == CM_BUF_EXISTS) 
!             continue;
! 
!         /* something else went wrong */
!         if (code != 0) 
!             return code;
! 
!         /* otherwise, we have a locked buffer that we just created */
!         created = 1;
!         break;
!     } /* big while loop */
! 
!     /* wait for reads */
!     if (bp-&gt;flags &amp; CM_BUF_READING)
!         buf_WaitIO(bp);
! 
!     /* once it has been read once, we can unlock it and return it, still
!      * with its refcount held.
!      */
!     lock_ReleaseMutex(&amp;bp-&gt;mx);
!     *bufpp = bp;
!     osi_Log3(buf_logp, "buf_GetNew returning bp 0x%x for file 0x%x, offset 0x%x",
!               bp, (long) scp, offsetp-&gt;LowPart);
!     return 0;
  }
  
  /* get a page, returning it held but unlocked.  Make sure it is complete */
  long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
  {
!     cm_buf_t *bp;
!     long code;
!     osi_hyper_t pageOffset;
!     unsigned long tcount;
!     int created;
  #ifdef DISKCACHE95
!     cm_diskcache_t *dcp;
  #endif /* DISKCACHE95 */
  
!     created = 0;
!     pageOffset.HighPart = offsetp-&gt;HighPart;
!     pageOffset.LowPart = offsetp-&gt;LowPart &amp; ~(buf_bufferSize-1);
!     while (1) {
!         lock_ObtainWrite(&amp;buf_globalLock);
!         bp = buf_LockedFind(scp, &amp;pageOffset);
!         lock_ReleaseWrite(&amp;buf_globalLock);
!         if (bp) {
!             /* lock it and break out */
!             lock_ObtainMutex(&amp;bp-&gt;mx);
!             break;
  
  #ifdef DISKCACHE95
!             /* touch disk chunk to update LRU info */
!             diskcache_Touch(bp-&gt;dcp);
  #endif /* DISKCACHE95 */
!         }
  
!         /* otherwise, we have to create a page */
!         code = buf_GetNewLocked(scp, &amp;pageOffset, &amp;bp);
! 
!         /* check if the buffer was created in a race condition branch.
!          * If so, go around so we can hold a reference to it. 
           */
!         if (code == CM_BUF_EXISTS) 
!             continue;
! 
!         /* something else went wrong */
!         if (code != 0) 
!             return code;
!                 
!         /* otherwise, we have a locked buffer that we just created */
!         created = 1;
!         break;
!     } /* big while loop */
! 
!     /* if we get here, we have a locked buffer that may have just been
!      * created, in which case it needs to be filled with data.
!      */
!     if (created) {
!         /* load the page; freshly created pages should be idle */
!         osi_assert(!(bp-&gt;flags &amp; (CM_BUF_READING | CM_BUF_WRITING)));
  
!         /* setup offset, event */
  #ifndef DJGPP  /* doesn't seem to be used */
!         bp-&gt;over.Offset = bp-&gt;offset.LowPart;
!         bp-&gt;over.OffsetHigh = bp-&gt;offset.HighPart;
  #endif /* !DJGPP */
  
!         /* start the I/O; may drop lock */
!         bp-&gt;flags |= CM_BUF_READING;
!         code = (*cm_buf_opsp-&gt;Readp)(bp, buf_bufferSize, &amp;tcount, NULL);
  
  #ifdef DISKCACHE95
!         code = diskcache_Get(&amp;bp-&gt;fid, &amp;bp-&gt;offset, bp-&gt;datap, buf_bufferSize, &amp;bp-&gt;dataVersion, &amp;tcount, &amp;dcp);
!         bp-&gt;dcp = dcp;    /* pointer to disk cache struct. */
  #endif /* DISKCACHE95 */
  
!         if (code != 0) {
!             /* failure or queued */
  #ifndef DJGPP   /* cm_bufRead always returns 0 */
!             if (code != ERROR_IO_PENDING) {
  #endif
!                 bp-&gt;error = code;
!                 bp-&gt;flags |= CM_BUF_ERROR;
!                 bp-&gt;flags &amp;= ~CM_BUF_READING;
!                 if (bp-&gt;flags &amp; CM_BUF_WAITING) {
!                     bp-&gt;flags &amp;= ~CM_BUF_WAITING;
!                     osi_Wakeup((long) bp);
!                 }
!                 lock_ReleaseMutex(&amp;bp-&gt;mx);
!                 buf_Release(bp);
!                 return code;
  #ifndef DJGPP
!             }
  #endif
!         } else {
!             /* otherwise, I/O completed instantly and we're done, except
!              * for padding the xfr out with 0s and checking for EOF
!              */
!             if (tcount &lt; (unsigned long) buf_bufferSize) {
!                 memset(bp-&gt;datap+tcount, 0, buf_bufferSize - tcount);
!                 if (tcount == 0)
!                     bp-&gt;flags |= CM_BUF_EOF;
!             }
!             bp-&gt;flags &amp;= ~CM_BUF_READING;
!             if (bp-&gt;flags &amp; CM_BUF_WAITING) {
!                 bp-&gt;flags &amp;= ~CM_BUF_WAITING;
!                 osi_Wakeup((long) bp);
!             }
!         }
  
!     } /* if created */
  
!     /* wait for reads, either that which we started above, or that someone
!      * else started.  We don't care if we return a buffer being cleaned.
!      */
!     if (bp-&gt;flags &amp; CM_BUF_READING)
!         buf_WaitIO(bp);
  
!     /* once it has been read once, we can unlock it and return it, still
!      * with its refcount held.
!      */
!     lock_ReleaseMutex(&amp;bp-&gt;mx);
!     *bufpp = bp;
! 
!     /* now remove from queue; will be put in at the head (farthest from
!      * being recycled) when we're done in buf_Release.
!      */
!     lock_ObtainWrite(&amp;buf_globalLock);
!     if (bp-&gt;flags &amp; CM_BUF_INLRU) {
!         if (buf_freeListEndp == bp)
!             buf_freeListEndp = (cm_buf_t *) osi_QPrev(&amp;bp-&gt;q);
!         osi_QRemove((osi_queue_t **) &amp;buf_freeListp, &amp;bp-&gt;q);
!         bp-&gt;flags &amp;= ~CM_BUF_INLRU;
!     }
!     lock_ReleaseWrite(&amp;buf_globalLock);
! 
!     osi_Log3(buf_logp, "buf_Get returning bp 0x%x for file 0x%x, offset 0x%x",
!               bp, (long) scp, offsetp-&gt;LowPart);
!     return 0;
  }
  
  /* count # of elements in the free list;
***************
*** 1056,1095 ****
   */
  long buf_CountFreeList(void)
  {
! 	long count;
!         cm_buf_t *bufp;
  
! 	count = 0;
! 	lock_ObtainRead(&amp;buf_globalLock);
! 	for(bufp = buf_freeListp; bufp; bufp = (cm_buf_t *) osi_QNext(&amp;bufp-&gt;q)) {
! 		/* if the buffer doesn't have an identity, or if the buffer
!                  * has been invalidate (by having its DV stomped upon), then
!                  * count it as free, since it isn't really being utilized.
!                  */
! 		if (!(bufp-&gt;flags &amp; CM_BUF_INHASH) || bufp-&gt;dataVersion &lt;= 0)
!                 	count++;
!         }
! 	lock_ReleaseRead(&amp;buf_globalLock);
!         return count;
  }
  
  /* clean a buffer synchronously */
  void buf_CleanAsync(cm_buf_t *bp, cm_req_t *reqp)
  {
! 	lock_ObtainMutex(&amp;bp-&gt;mx);
! 	buf_LockedCleanAsync(bp, reqp);
! 	lock_ReleaseMutex(&amp;bp-&gt;mx);
! }
  
  /* wait for a buffer's cleaning to finish */
  void buf_CleanWait(cm_buf_t *bp)
  {
! 	lock_ObtainMutex(&amp;bp-&gt;mx);
! 	if (bp-&gt;flags &amp; CM_BUF_WRITING) {
! 		buf_WaitIO(bp);
!         }
! 	lock_ReleaseMutex(&amp;bp-&gt;mx);
! }
  
  /* set the dirty flag on a buffer, and set associated write-ahead log,
   * if there is one.  Allow one to be added to a buffer, but not changed.
--- 1065,1104 ----
   */
  long buf_CountFreeList(void)
  {
!     long count;
!     cm_buf_t *bufp;
  
!     count = 0;
!     lock_ObtainRead(&amp;buf_globalLock);
!     for(bufp = buf_freeListp; bufp; bufp = (cm_buf_t *) osi_QNext(&amp;bufp-&gt;q)) {
!         /* if the buffer doesn't have an identity, or if the buffer
!          * has been invalidate (by having its DV stomped upon), then
!          * count it as free, since it isn't really being utilized.
!          */
!         if (!(bufp-&gt;flags &amp; CM_BUF_INHASH) || bufp-&gt;dataVersion &lt;= 0)
!             count++;
!     }       
!     lock_ReleaseRead(&amp;buf_globalLock);
!     return count;
  }
  
  /* clean a buffer synchronously */
  void buf_CleanAsync(cm_buf_t *bp, cm_req_t *reqp)
  {
!     lock_ObtainMutex(&amp;bp-&gt;mx);
!     buf_LockedCleanAsync(bp, reqp);
!     lock_ReleaseMutex(&amp;bp-&gt;mx);
! }       
  
  /* wait for a buffer's cleaning to finish */
  void buf_CleanWait(cm_buf_t *bp)
  {
!     lock_ObtainMutex(&amp;bp-&gt;mx);
!     if (bp-&gt;flags &amp; CM_BUF_WRITING) {
!         buf_WaitIO(bp);
!     }
!     lock_ReleaseMutex(&amp;bp-&gt;mx);
! }       
  
  /* set the dirty flag on a buffer, and set associated write-ahead log,
   * if there is one.  Allow one to be added to a buffer, but not changed.
***************
*** 1098,1112 ****
   */
  void buf_SetDirty(cm_buf_t *bp)
  {
! 	osi_assert(bp-&gt;refCount &gt; 0);
  	
! 	osi_Log1(buf_logp, "buf_SetDirty 0x%x", bp);
  
!         /* set dirty bit */
! 	bp-&gt;flags |= CM_BUF_DIRTY;
  
! 	/* and turn off EOF flag, since it has associated data now */
!         bp-&gt;flags &amp;= ~CM_BUF_EOF;
  }
  
  /* clean all buffers, reset log pointers and invalidate all buffers.
--- 1107,1121 ----
   */
  void buf_SetDirty(cm_buf_t *bp)
  {
!     osi_assert(bp-&gt;refCount &gt; 0);
  	
!     osi_Log1(buf_logp, "buf_SetDirty 0x%x", bp);
  
!     /* set dirty bit */
!     bp-&gt;flags |= CM_BUF_DIRTY;
  
!     /* and turn off EOF flag, since it has associated data now */
!     bp-&gt;flags &amp;= ~CM_BUF_EOF;
  }
  
  /* clean all buffers, reset log pointers and invalidate all buffers.
***************
*** 1131,1214 ****
   */
  long buf_CleanAndReset(void)
  {
! 	long i;
!         cm_buf_t *bp;
! 	cm_req_t req;
! 
! 	lock_ObtainWrite(&amp;buf_globalLock);
!         for(i=0; i&lt;buf_hashSize; i++) {
!         	for(bp = buf_hashTablepp[i]; bp; bp = bp-&gt;hashp) {
! 			bp-&gt;refCount++;
!                         lock_ReleaseWrite(&amp;buf_globalLock);
! 			
!                         /* now no locks are held; clean buffer and go on */
! 			cm_InitReq(&amp;req);
!                         buf_CleanAsync(bp, &amp;req);
!                         buf_CleanWait(bp);
!                         
!                         /* relock and release buffer */
!                         lock_ObtainWrite(&amp;buf_globalLock);
!                         buf_LockedRelease(bp);
!                 } /* over one bucket */
! 	}	/* for loop over all hash buckets */
!         
!         /* release locks */
! 	lock_ReleaseWrite(&amp;buf_globalLock);
  
! 	/* and we're done */
!         return 0;
! }
  
  /* called without global lock being held, reserves buffers for callers
   * that need more than one held (not locked) at once.
   */
  void buf_ReserveBuffers(long nbuffers)
  {
! 	lock_ObtainWrite(&amp;buf_globalLock);
! 	while (1) {
! 		if (buf_reservedBufs + nbuffers &gt; buf_maxReservedBufs) {
! 			buf_reserveWaiting = 1;
!                         osi_Log1(buf_logp, "buf_ReserveBuffers waiting for %d bufs", nbuffers);
!                         osi_SleepW((long) &amp;buf_reservedBufs, &amp;buf_globalLock);
!                         lock_ObtainWrite(&amp;buf_globalLock);
!                 }
!                 else {
! 			buf_reservedBufs += nbuffers;
!                 	break;
!                 }
          }
! 	lock_ReleaseWrite(&amp;buf_globalLock);
  }
  
  int buf_TryReserveBuffers(long nbuffers)
  {
! 	int code;
  
! 	lock_ObtainWrite(&amp;buf_globalLock);
! 	if (buf_reservedBufs + nbuffers &gt; buf_maxReservedBufs) {
! 		code = 0;
! 	}
! 	else {
! 		buf_reservedBufs += nbuffers;
!                 code = 1;
! 	}
! 	lock_ReleaseWrite(&amp;buf_globalLock);
! 	return code;
! }
  
  /* called without global lock held, releases reservation held by
   * buf_ReserveBuffers.
   */
  void buf_UnreserveBuffers(long nbuffers)
  {
! 	lock_ObtainWrite(&amp;buf_globalLock);
! 	buf_reservedBufs -= nbuffers;
!         if (buf_reserveWaiting) {
! 		buf_reserveWaiting = 0;
!                 osi_Wakeup((long) &amp;buf_reservedBufs);
!         }
! 	lock_ReleaseWrite(&amp;buf_globalLock);
! }
  
  /* truncate the buffers past sizep, zeroing out the page, if we don't
   * end on a page boundary.
--- 1140,1223 ----
   */
  long buf_CleanAndReset(void)
  {
!     long i;
!     cm_buf_t *bp;
!     cm_req_t req;
  
!     lock_ObtainWrite(&amp;buf_globalLock);
!     for(i=0; i&lt;buf_hashSize; i++) {
!         for(bp = buf_hashTablepp[i]; bp; bp = bp-&gt;hashp) {
!             bp-&gt;refCount++;
!             lock_ReleaseWrite(&amp;buf_globalLock);
! 
!             /* now no locks are held; clean buffer and go on */
!             cm_InitReq(&amp;req);
!             buf_CleanAsync(bp, &amp;req);
!             buf_CleanWait(bp);
! 
!             /* relock and release buffer */
!             lock_ObtainWrite(&amp;buf_globalLock);
!             buf_LockedRelease(bp);
!         } /* over one bucket */
!     }	/* for loop over all hash buckets */
! 
!     /* release locks */
!     lock_ReleaseWrite(&amp;buf_globalLock);
! 
!     /* and we're done */
!     return 0;
! }       
  
  /* called without global lock being held, reserves buffers for callers
   * that need more than one held (not locked) at once.
   */
  void buf_ReserveBuffers(long nbuffers)
  {
!     lock_ObtainWrite(&amp;buf_globalLock);
!     while (1) {
!         if (buf_reservedBufs + nbuffers &gt; buf_maxReservedBufs) {
!             buf_reserveWaiting = 1;
!             osi_Log1(buf_logp, "buf_ReserveBuffers waiting for %d bufs", nbuffers);
!             osi_SleepW((long) &amp;buf_reservedBufs, &amp;buf_globalLock);
!             lock_ObtainWrite(&amp;buf_globalLock);
          }
!         else {
!             buf_reservedBufs += nbuffers;
!             break;
!         }
!     }
!     lock_ReleaseWrite(&amp;buf_globalLock);
  }
  
  int buf_TryReserveBuffers(long nbuffers)
  {
!     int code;
  
!     lock_ObtainWrite(&amp;buf_globalLock);
!     if (buf_reservedBufs + nbuffers &gt; buf_maxReservedBufs) {
!         code = 0;
!     }
!     else {
!         buf_reservedBufs += nbuffers;
!         code = 1;
!     }
!     lock_ReleaseWrite(&amp;buf_globalLock);
!     return code;
! }       
  
  /* called without global lock held, releases reservation held by
   * buf_ReserveBuffers.
   */
  void buf_UnreserveBuffers(long nbuffers)
  {
!     lock_ObtainWrite(&amp;buf_globalLock);
!     buf_reservedBufs -= nbuffers;
!     if (buf_reserveWaiting) {
!         buf_reserveWaiting = 0;
!         osi_Wakeup((long) &amp;buf_reservedBufs);
!     }
!     lock_ReleaseWrite(&amp;buf_globalLock);
! }       
  
  /* truncate the buffers past sizep, zeroing out the page, if we don't
   * end on a page boundary.
***************
*** 1216,1434 ****
   * Requires cm_bufCreateLock to be write locked.
   */
  long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
! 	osi_hyper_t *sizep)
  {
! 	cm_buf_t *bufp;
! 	cm_buf_t *nbufp;			/* next buffer, if didRelease */
!         osi_hyper_t bufEnd;
!         long code;
!         long bufferPos;
!         int didRelease;
! 	long i;
!         
! 	/* assert that cm_bufCreateLock is held in write mode */
!         lock_AssertWrite(&amp;scp-&gt;bufCreateLock);
! 
! 	i = BUF_FILEHASH(&amp;scp-&gt;fid);
  
! 	lock_ObtainWrite(&amp;buf_globalLock);
! 	bufp = buf_fileHashTablepp[i];
! 	if (bufp == NULL) {
! 		lock_ReleaseWrite(&amp;buf_globalLock);
! 		return 0;
! 	}
! 
!         bufp-&gt;refCount++;
! 	lock_ReleaseWrite(&amp;buf_globalLock);
!         for(; bufp; bufp = nbufp) {
!                 didRelease = 0;
! 		lock_ObtainMutex(&amp;bufp-&gt;mx);
! 
! 		bufEnd.HighPart = 0;
!                 bufEnd.LowPart = buf_bufferSize;
!                 bufEnd = LargeIntegerAdd(bufEnd, bufp-&gt;offset);
! 
! 		if (cm_FidCmp(&amp;bufp-&gt;fid, &amp;scp-&gt;fid) == 0 &amp;&amp;
!                 	LargeIntegerLessThan(*sizep, bufEnd)) {
! 	                buf_WaitIO(bufp);
! 		}
! 	        lock_ObtainMutex(&amp;scp-&gt;mx);
  	
! 		/* make sure we have a callback (so we have the right value for
! 		 * the length), and wait for it to be safe to do a truncate.
! 	         */
! 		code = cm_SyncOp(scp, bufp, userp, reqp, 0,
! 				 CM_SCACHESYNC_NEEDCALLBACK
!                 		 | CM_SCACHESYNC_GETSTATUS
!                 		 | CM_SCACHESYNC_SETSIZE
! 				 | CM_SCACHESYNC_BUFLOCKED);
! 		/* if we succeeded in our locking, and this applies to the right
! 		 * file, and the truncate request overlaps the buffer either
! 		 * totally or partially, then do something.
!                  */
! 		if (code == 0 &amp;&amp; cm_FidCmp(&amp;bufp-&gt;fid, &amp;scp-&gt;fid) == 0
!                 	&amp;&amp; LargeIntegerLessThan(*sizep, bufEnd)) {
!                         
!                         lock_ObtainWrite(&amp;buf_globalLock);
  
! 			/* destroy the buffer, turning off its dirty bit, if
! 			 * we're truncating the whole buffer.  Otherwise, set
! 			 * the dirty bit, and clear out the tail of the buffer
! 			 * if we just overlap some.
!                          */
!                         if (LargeIntegerLessThanOrEqualTo(*sizep, bufp-&gt;offset)) {
! 				/* truncating the entire page */
!                                 bufp-&gt;flags &amp;= ~CM_BUF_DIRTY;
!                                 bufp-&gt;dataVersion = -1;	/* known bad */
!                                 bufp-&gt;dirtyCounter++;
!                         }
! 			else {
! 				/* don't set dirty, since dirty implies
! 				 * currently up-to-date.  Don't need to do this,
! 				 * since we'll update the length anyway.
! 				 *
! 				 * Zero out remainder of the page, in case we
! 				 * seek and write past EOF, and make this data
! 				 * visible again.
!                                  */
!                                 bufferPos = sizep-&gt;LowPart &amp; (buf_bufferSize - 1);
!                                 osi_assert(bufferPos != 0);
!                                 memset(bufp-&gt;datap + bufferPos, 0,
! 					buf_bufferSize - bufferPos);
! 			}
  
!                         lock_ReleaseWrite(&amp;buf_globalLock);
!                 }
  		
!                 lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		lock_ReleaseMutex(&amp;bufp-&gt;mx);
! 		if (!didRelease) {
! 			lock_ObtainWrite(&amp;buf_globalLock);
! 			nbufp = bufp-&gt;fileHashp;
!                         if (nbufp) nbufp-&gt;refCount++;
!                         buf_LockedRelease(bufp);
! 			lock_ReleaseWrite(&amp;buf_globalLock);
! 		}
! 
! 		/* bail out early if we fail */
!                 if (code) {
! 			/* at this point, nbufp is held; bufp has already been
!                          * released.
!                          */
!                         if (nbufp) buf_Release(nbufp);
!                 	return code;
! 		}
! 	}
! 	
!         /* success */
!         return 0;
  }
  
  long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code;
! 	cm_buf_t *bp;		/* buffer we're hacking on */
!         cm_buf_t *nbp;
!         int didRelease;
! 	long i;
! 
! 	i = BUF_FILEHASH(&amp;scp-&gt;fid);
! 
! 	code = 0;
! 	lock_ObtainWrite(&amp;buf_globalLock);
!         bp = buf_fileHashTablepp[i];
!         if (bp) bp-&gt;refCount++;
!         lock_ReleaseWrite(&amp;buf_globalLock);
! 	for(; bp; bp = nbp) {
! 		didRelease = 0;	/* haven't released this buffer yet */
  
! 		/* clean buffer synchronously */
! 		if (cm_FidCmp(&amp;bp-&gt;fid, &amp;scp-&gt;fid) == 0) {
!                         lock_ObtainMutex(&amp;bp-&gt;mx);
! 
! 			/* start cleaning the buffer, and wait for it to finish */
! 			buf_LockedCleanAsync(bp, reqp);
!                         buf_WaitIO(bp);
!                         lock_ReleaseMutex(&amp;bp-&gt;mx);
! 
!                         code = (*cm_buf_opsp-&gt;Stabilizep)(scp, userp, reqp);
!                         if (code) goto skip;
! 
! 			lock_ObtainWrite(&amp;buf_globalLock);
! 			/* actually, we only know that buffer is clean if ref
! 			 * count is 1, since we don't have buffer itself locked.
!                          */
! 			if (!(bp-&gt;flags &amp; CM_BUF_DIRTY)) {
! 				if (bp-&gt;refCount == 1) {	/* bp is held above */
!                                 	buf_LockedRelease(bp);
!                                         nbp = bp-&gt;fileHashp;
!                                         if (nbp) nbp-&gt;refCount++;
!                                         didRelease = 1;
!                                 	buf_Recycle(bp);
! 				}
!                         }
! 			lock_ReleaseWrite(&amp;buf_globalLock);
! 
!                         (*cm_buf_opsp-&gt;Unstabilizep)(scp, userp);
! 		}
! 
! skip:
! 		if (!didRelease) {
! 			lock_ObtainWrite(&amp;buf_globalLock);
!                         if (nbp = bp-&gt;fileHashp) nbp-&gt;refCount++;
!                 	buf_LockedRelease(bp);
!                         lock_ReleaseWrite(&amp;buf_globalLock);
! 		}
! 	}	/* for loop over a bunch of buffers */
! 	
!         /* done */
! 	return code;
! }
  
  long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code;
! 	cm_buf_t *bp;		/* buffer we're hacking on */
      cm_buf_t *nbp;		/* next one */
! 	long i;
  
! 	i = BUF_FILEHASH(&amp;scp-&gt;fid);
  
! 	code = 0;
! 	lock_ObtainWrite(&amp;buf_globalLock);
      bp = buf_fileHashTablepp[i];
      if (bp) bp-&gt;refCount++;
      lock_ReleaseWrite(&amp;buf_globalLock);
! 	for(; bp; bp = nbp) {
! 		/* clean buffer synchronously */
! 		if (cm_FidCmp(&amp;bp-&gt;fid, &amp;scp-&gt;fid) == 0) {
! 			if (userp) {
                  cm_HoldUser(userp);
! 				lock_ObtainMutex(&amp;bp-&gt;mx);
! 				if (bp-&gt;userp) 
                      cm_ReleaseUser(bp-&gt;userp);
                  bp-&gt;userp = userp;
! 				lock_ReleaseMutex(&amp;bp-&gt;mx);
!             }
! 			buf_CleanAsync(bp, reqp);
              buf_CleanWait(bp);
              lock_ObtainMutex(&amp;bp-&gt;mx);
! 			if (bp-&gt;flags &amp; CM_BUF_ERROR) {
! 				if (code == 0 || code == -1) code = bp-&gt;error;
!                 if (code == 0) code = -1;
              }
              lock_ReleaseMutex(&amp;bp-&gt;mx);
! 		}
  
! 		lock_ObtainWrite(&amp;buf_globalLock);
! 		buf_LockedRelease(bp);
          nbp = bp-&gt;fileHashp;
          if (nbp) nbp-&gt;refCount++;
! 		lock_ReleaseWrite(&amp;buf_globalLock);
! 	}	/* for loop over a bunch of buffers */
! 	
      /* done */
! 	return code;
  }
  
  /* dump the contents of the buf_hashTablepp. */
--- 1225,1446 ----
   * Requires cm_bufCreateLock to be write locked.
   */
  long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
!                    osi_hyper_t *sizep)
  {
!     cm_buf_t *bufp;
!     cm_buf_t *nbufp;			/* next buffer, if didRelease */
!     osi_hyper_t bufEnd;
!     long code;
!     long bufferPos;
!     int didRelease;
!     long i;
! 
!     /* assert that cm_bufCreateLock is held in write mode */
!     lock_AssertWrite(&amp;scp-&gt;bufCreateLock);
! 
!     i = BUF_FILEHASH(&amp;scp-&gt;fid);
! 
!     lock_ObtainWrite(&amp;buf_globalLock);
!     bufp = buf_fileHashTablepp[i];
!     if (bufp == NULL) {
!         lock_ReleaseWrite(&amp;buf_globalLock);
!         return 0;
!     }
  
!     bufp-&gt;refCount++;
!     lock_ReleaseWrite(&amp;buf_globalLock);
!     for(; bufp; bufp = nbufp) {
!         didRelease = 0;
!         lock_ObtainMutex(&amp;bufp-&gt;mx);
! 
!         bufEnd.HighPart = 0;
!         bufEnd.LowPart = buf_bufferSize;
!         bufEnd = LargeIntegerAdd(bufEnd, bufp-&gt;offset);
! 
!         if (cm_FidCmp(&amp;bufp-&gt;fid, &amp;scp-&gt;fid) == 0 &amp;&amp;
!              LargeIntegerLessThan(*sizep, bufEnd)) {
!             buf_WaitIO(bufp);
!         }
!         lock_ObtainMutex(&amp;scp-&gt;mx);
  	
!         /* make sure we have a callback (so we have the right value for
!          * the length), and wait for it to be safe to do a truncate.
!          */
!         code = cm_SyncOp(scp, bufp, userp, reqp, 0,
!                           CM_SCACHESYNC_NEEDCALLBACK
!                           | CM_SCACHESYNC_GETSTATUS
!                           | CM_SCACHESYNC_SETSIZE
!                           | CM_SCACHESYNC_BUFLOCKED);
!         /* if we succeeded in our locking, and this applies to the right
!          * file, and the truncate request overlaps the buffer either
!          * totally or partially, then do something.
!          */
!         if (code == 0 &amp;&amp; cm_FidCmp(&amp;bufp-&gt;fid, &amp;scp-&gt;fid) == 0
!              &amp;&amp; LargeIntegerLessThan(*sizep, bufEnd)) {
  
!             lock_ObtainWrite(&amp;buf_globalLock);
  
!             /* destroy the buffer, turning off its dirty bit, if
!              * we're truncating the whole buffer.  Otherwise, set
!              * the dirty bit, and clear out the tail of the buffer
!              * if we just overlap some.
!              */
!             if (LargeIntegerLessThanOrEqualTo(*sizep, bufp-&gt;offset)) {
!                 /* truncating the entire page */
!                 bufp-&gt;flags &amp;= ~CM_BUF_DIRTY;
!                 bufp-&gt;dataVersion = -1;	/* known bad */
!                 bufp-&gt;dirtyCounter++;
!             }
!             else {
!                 /* don't set dirty, since dirty implies
!                  * currently up-to-date.  Don't need to do this,
!                  * since we'll update the length anyway.
!                  *
!                  * Zero out remainder of the page, in case we
!                  * seek and write past EOF, and make this data
!                  * visible again.
!                  */
!                 bufferPos = sizep-&gt;LowPart &amp; (buf_bufferSize - 1);
!                 osi_assert(bufferPos != 0);
!                 memset(bufp-&gt;datap + bufferPos, 0,
!                         buf_bufferSize - bufferPos);
!             }
! 
!             lock_ReleaseWrite(&amp;buf_globalLock);
!         }
  		
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         lock_ReleaseMutex(&amp;bufp-&gt;mx);
!         if (!didRelease) {
!             lock_ObtainWrite(&amp;buf_globalLock);
!             nbufp = bufp-&gt;fileHashp;
!             if (nbufp) nbufp-&gt;refCount++;
!             buf_LockedRelease(bufp);
!             lock_ReleaseWrite(&amp;buf_globalLock);
!         }
! 
!         /* bail out early if we fail */
!         if (code) {
!             /* at this point, nbufp is held; bufp has already been
!              * released.
!              */
!             if (nbufp) 
!                 buf_Release(nbufp);
!             return code;
!         }
!     }
! 
!     /* success */
!     return 0;
  }
  
  long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
!     cm_buf_t *bp;		/* buffer we're hacking on */
!     cm_buf_t *nbp;
!     int didRelease;
!     long i;
  
!     i = BUF_FILEHASH(&amp;scp-&gt;fid);
! 
!     code = 0;
!     lock_ObtainWrite(&amp;buf_globalLock);
!     bp = buf_fileHashTablepp[i];
!     if (bp) bp-&gt;refCount++;
!     lock_ReleaseWrite(&amp;buf_globalLock);
!     for(; bp; bp = nbp) {
!         didRelease = 0;	/* haven't released this buffer yet */
! 
!         /* clean buffer synchronously */
!         if (cm_FidCmp(&amp;bp-&gt;fid, &amp;scp-&gt;fid) == 0) {
!             lock_ObtainMutex(&amp;bp-&gt;mx);
! 
!             /* start cleaning the buffer, and wait for it to finish */
!             buf_LockedCleanAsync(bp, reqp);
!             buf_WaitIO(bp);
!             lock_ReleaseMutex(&amp;bp-&gt;mx);
! 
!             code = (*cm_buf_opsp-&gt;Stabilizep)(scp, userp, reqp);
!             if (code) goto skip;
! 
!             lock_ObtainWrite(&amp;buf_globalLock);
!             /* actually, we only know that buffer is clean if ref
!              * count is 1, since we don't have buffer itself locked.
!              */
!             if (!(bp-&gt;flags &amp; CM_BUF_DIRTY)) {
!                 if (bp-&gt;refCount == 1) {	/* bp is held above */
!                     buf_LockedRelease(bp);
!                     nbp = bp-&gt;fileHashp;
!                     if (nbp) nbp-&gt;refCount++;
!                     didRelease = 1;
!                     buf_Recycle(bp);
!                 }
!             }
!             lock_ReleaseWrite(&amp;buf_globalLock);
! 
!             (*cm_buf_opsp-&gt;Unstabilizep)(scp, userp);
!         }
! 
!       skip:
!         if (!didRelease) {
!             lock_ObtainWrite(&amp;buf_globalLock);
!             if (nbp = bp-&gt;fileHashp) nbp-&gt;refCount++;
!             buf_LockedRelease(bp);
!             lock_ReleaseWrite(&amp;buf_globalLock);
!         }
!     }	/* for loop over a bunch of buffers */
! 
!     /* done */
!     return code;
! }       
  
  long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
!     cm_buf_t *bp;		/* buffer we're hacking on */
      cm_buf_t *nbp;		/* next one */
!     long i;
  
!     i = BUF_FILEHASH(&amp;scp-&gt;fid);
  
!     code = 0;
!     lock_ObtainWrite(&amp;buf_globalLock);
      bp = buf_fileHashTablepp[i];
      if (bp) bp-&gt;refCount++;
      lock_ReleaseWrite(&amp;buf_globalLock);
!     for(; bp; bp = nbp) {
!         /* clean buffer synchronously */
!         if (cm_FidCmp(&amp;bp-&gt;fid, &amp;scp-&gt;fid) == 0) {
!             if (userp) {
                  cm_HoldUser(userp);
!                 lock_ObtainMutex(&amp;bp-&gt;mx);
!                 if (bp-&gt;userp) 
                      cm_ReleaseUser(bp-&gt;userp);
                  bp-&gt;userp = userp;
!                 lock_ReleaseMutex(&amp;bp-&gt;mx);
!             }   
!             buf_CleanAsync(bp, reqp);
              buf_CleanWait(bp);
              lock_ObtainMutex(&amp;bp-&gt;mx);
!             if (bp-&gt;flags &amp; CM_BUF_ERROR) {
!                 if (code == 0 || code == -1) 
!                     code = bp-&gt;error;
!                 if (code == 0) 
!                     code = -1;
              }
              lock_ReleaseMutex(&amp;bp-&gt;mx);
!         }
  
!         lock_ObtainWrite(&amp;buf_globalLock);
!         buf_LockedRelease(bp);
          nbp = bp-&gt;fileHashp;
          if (nbp) nbp-&gt;refCount++;
!         lock_ReleaseWrite(&amp;buf_globalLock);
!     }	/* for loop over a bunch of buffers */
! 
      /* done */
!     return code;
  }
  
  /* dump the contents of the buf_hashTablepp. */
***************
*** 1439,1446 ****
      char output[1024];
      int i;
    
! 	if (buf_hashTablepp == NULL)
! 		return -1;
  
      lock_ObtainRead(&amp;buf_globalLock);
    
--- 1451,1458 ----
      char output[1024];
      int i;
    
!     if (buf_hashTablepp == NULL)
!         return -1;
  
      lock_ObtainRead(&amp;buf_globalLock);
    
Index: openafs/src/WINNT/afsd/cm_buf.h
diff -c openafs/src/WINNT/afsd/cm_buf.h:1.4.2.1 openafs/src/WINNT/afsd/cm_buf.h:1.4.2.2
*** openafs/src/WINNT/afsd/cm_buf.h:1.4.2.1	Tue Aug 17 00:28:38 2004
--- openafs/src/WINNT/afsd/cm_buf.h	Mon Oct 18 00:09:25 2004
***************
*** 72,78 ****
  				 */
          struct cm_buf *allp;	/* next in all list */
  	osi_mutex_t mx;		/* mutex protecting structure except refcount */
!     int refCount;		/* reference count (buf_globalLock) */
          long idCounter;		/* counter for softrefs; bumped at each recycle */
          long dirtyCounter;	/* bumped at each dirty-&gt;clean transition */
  #ifdef notdef
--- 72,78 ----
  				 */
          struct cm_buf *allp;	/* next in all list */
  	osi_mutex_t mx;		/* mutex protecting structure except refcount */
!     unsigned long refCount;		/* reference count (buf_globalLock) */
          long idCounter;		/* counter for softrefs; bumped at each recycle */
          long dirtyCounter;	/* bumped at each dirty-&gt;clean transition */
  #ifdef notdef
Index: openafs/src/WINNT/afsd/cm_callback.c
diff -c openafs/src/WINNT/afsd/cm_callback.c:1.20.2.3 openafs/src/WINNT/afsd/cm_callback.c:1.20.2.5
*** openafs/src/WINNT/afsd/cm_callback.c:1.20.2.3	Thu Aug 19 15:51:23 2004
--- openafs/src/WINNT/afsd/cm_callback.c	Mon Oct 18 00:09:25 2004
***************
*** 70,91 ****
   */
  void cm_RecordRacingRevoke(cm_fid_t *fidp, long cancelFlags)
  {
! 	cm_racingRevokes_t *rp;
  
! 	lock_ObtainWrite(&amp;cm_callbackLock);
  
      osi_Log3(afsd_logp, "RecordRacingRevoke Volume %d Flags %lX activeCalls %d",
               fidp-&gt;volume, cancelFlags, cm_activeCallbackGrantingCalls);
  
! 	if (cm_activeCallbackGrantingCalls &gt; 0) {
! 		rp = malloc(sizeof(*rp));
! 	        memset(rp, 0, sizeof(*rp));
! 	        osi_QAdd((osi_queue_t **) &amp;cm_racingRevokesp, &amp;rp-&gt;q);
!                 rp-&gt;flags |= (cancelFlags &amp; CM_RACINGFLAG_ALL);
! 		if (fidp) rp-&gt;fid = *fidp;
!                 rp-&gt;callbackCount = ++cm_callbackCount;
! 	}
! 	lock_ReleaseWrite(&amp;cm_callbackLock);
  }
  
  /*
--- 70,91 ----
   */
  void cm_RecordRacingRevoke(cm_fid_t *fidp, long cancelFlags)
  {
!     cm_racingRevokes_t *rp;
  
!     lock_ObtainWrite(&amp;cm_callbackLock);
  
      osi_Log3(afsd_logp, "RecordRacingRevoke Volume %d Flags %lX activeCalls %d",
               fidp-&gt;volume, cancelFlags, cm_activeCallbackGrantingCalls);
  
!     if (cm_activeCallbackGrantingCalls &gt; 0) {
!         rp = malloc(sizeof(*rp));
!         memset(rp, 0, sizeof(*rp));
!         osi_QAdd((osi_queue_t **) &amp;cm_racingRevokesp, &amp;rp-&gt;q);
!         rp-&gt;flags |= (cancelFlags &amp; CM_RACINGFLAG_ALL);
!         if (fidp) rp-&gt;fid = *fidp;
!         rp-&gt;callbackCount = ++cm_callbackCount;
!     }
!     lock_ReleaseWrite(&amp;cm_callbackLock);
  }
  
  /*
***************
*** 128,177 ****
   */
  void cm_RevokeCallback(struct rx_call *callp, AFSFid *fidp)
  {
! 	cm_fid_t tfid;
!         cm_scache_t *scp;
!         long hash;
          
! 	/* don't bother setting cell, since we won't be checking it (to aid
!          * in working with multi-homed servers: we don't know the cell if we
!          * don't recognize the IP address).
!          */
! 	tfid.cell = 0;
!         tfid.volume = fidp-&gt;Volume;
!         tfid.vnode = fidp-&gt;Vnode;
!         tfid.unique = fidp-&gt;Unique;
!         hash = CM_SCACHE_HASH(&amp;tfid);
  
      osi_Log3(afsd_logp, "RevokeCallback vol %d vn %d un %d",
! 		 fidp-&gt;Volume, fidp-&gt;Vnode, fidp-&gt;Unique);
          
! 	/* do this first, so that if we're executing a callback granting call
!          * at this moment, we kill it before it can be merged in.  Otherwise,
!          * it could complete while we're doing the scan below, and get missed
!          * by both the scan and by this code.
!          */
! 	cm_RecordRacingRevoke(&amp;tfid, 0);
  
! 	lock_ObtainWrite(&amp;cm_scacheLock);
! 	/* do all in the hash bucket, since we don't know how many we'll find with
!          * varying cells.
!          */
!         for(scp = cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
! 		if (scp-&gt;fid.volume == tfid.volume &amp;&amp;
!                 	scp-&gt;fid.vnode == tfid.vnode &amp;&amp;
!                         scp-&gt;fid.unique == tfid.unique) {
! 			scp-&gt;refCount++;
! 			lock_ReleaseWrite(&amp;cm_scacheLock);
              osi_Log1(afsd_logp, "Discarding SCache scp %x", scp);
!                         lock_ObtainMutex(&amp;scp-&gt;mx);
! 			cm_DiscardSCache(scp);
!                         lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			cm_CallbackNotifyChange(scp);
!                         lock_ObtainWrite(&amp;cm_scacheLock);
!                         scp-&gt;refCount--;
! 		}
          }
! 	lock_ReleaseWrite(&amp;cm_scacheLock);
  }
  
  /* called to revoke a volume callback, which is typically issued when a volume
--- 128,177 ----
   */
  void cm_RevokeCallback(struct rx_call *callp, AFSFid *fidp)
  {
!     cm_fid_t tfid;
!     cm_scache_t *scp;
!     long hash;
          
!     /* don't bother setting cell, since we won't be checking it (to aid
!      * in working with multi-homed servers: we don't know the cell if we
!      * don't recognize the IP address).
!      */
!     tfid.cell = 0;
!     tfid.volume = fidp-&gt;Volume;
!     tfid.vnode = fidp-&gt;Vnode;
!     tfid.unique = fidp-&gt;Unique;
!     hash = CM_SCACHE_HASH(&amp;tfid);
  
      osi_Log3(afsd_logp, "RevokeCallback vol %d vn %d un %d",
!              fidp-&gt;Volume, fidp-&gt;Vnode, fidp-&gt;Unique);
          
!     /* do this first, so that if we're executing a callback granting call
!      * at this moment, we kill it before it can be merged in.  Otherwise,
!      * it could complete while we're doing the scan below, and get missed
!      * by both the scan and by this code.
!      */
!     cm_RecordRacingRevoke(&amp;tfid, 0);
  
!     lock_ObtainWrite(&amp;cm_scacheLock);
!     /* do all in the hash bucket, since we don't know how many we'll find with
!      * varying cells.
!      */
!     for (scp = cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
!         if (scp-&gt;fid.volume == tfid.volume &amp;&amp;
!              scp-&gt;fid.vnode == tfid.vnode &amp;&amp;
!              scp-&gt;fid.unique == tfid.unique) {
!             scp-&gt;refCount++;
!             lock_ReleaseWrite(&amp;cm_scacheLock);
              osi_Log1(afsd_logp, "Discarding SCache scp %x", scp);
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             cm_DiscardSCache(scp);
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             cm_CallbackNotifyChange(scp);
!             lock_ObtainWrite(&amp;cm_scacheLock);
!             scp-&gt;refCount--;
          }
!     }
!     lock_ReleaseWrite(&amp;cm_scacheLock);
  }
  
  /* called to revoke a volume callback, which is typically issued when a volume
***************
*** 181,220 ****
   */
  void cm_RevokeVolumeCallback(struct rx_call *callp, AFSFid *fidp)
  {
! 	long hash;
!         cm_scache_t *scp;
!         cm_fid_t tfid;
  
      osi_Log1(afsd_logp, "RevokeVolumeCallback %d", fidp-&gt;Volume);
  
! 	/* do this first, so that if we're executing a callback granting call
!          * at this moment, we kill it before it can be merged in.  Otherwise,
!          * it could complete while we're doing the scan below, and get missed
!          * by both the scan and by this code.
!          */
! 	tfid.cell = tfid.vnode = tfid.unique = 0;
!         tfid.volume = fidp-&gt;Volume;
!         cm_RecordRacingRevoke(&amp;tfid, CM_RACINGFLAG_CANCELVOL);
  
  
!         lock_ObtainWrite(&amp;cm_scacheLock);
! 	for(hash = 0; hash &lt; cm_hashTableSize; hash++) {
! 		for(scp=cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
! 			if (scp-&gt;fid.volume == fidp-&gt;Volume) {
! 				scp-&gt;refCount++;
! 	                        lock_ReleaseWrite(&amp;cm_scacheLock);
! 	                        lock_ObtainMutex(&amp;scp-&gt;mx);
                  osi_Log1(afsd_logp, "Discarding SCache scp %x", scp);
! 				cm_DiscardSCache(scp);
! 				lock_ReleaseMutex(&amp;scp-&gt;mx);
! 				cm_CallbackNotifyChange(scp);
! 	                        lock_ObtainWrite(&amp;cm_scacheLock);
! 	                        scp-&gt;refCount--;
! 	                }
! 		}	/* search one hash bucket */
! 	}	/* search all hash buckets */
!         
!         lock_ReleaseWrite(&amp;cm_scacheLock);
  }
  
  /* handle incoming RPC callback breaking message.
--- 181,220 ----
   */
  void cm_RevokeVolumeCallback(struct rx_call *callp, AFSFid *fidp)
  {
!     long hash;
!     cm_scache_t *scp;
!     cm_fid_t tfid;
  
      osi_Log1(afsd_logp, "RevokeVolumeCallback %d", fidp-&gt;Volume);
  
!     /* do this first, so that if we're executing a callback granting call
!      * at this moment, we kill it before it can be merged in.  Otherwise,
!      * it could complete while we're doing the scan below, and get missed
!      * by both the scan and by this code.
!      */
!     tfid.cell = tfid.vnode = tfid.unique = 0;
!     tfid.volume = fidp-&gt;Volume;
!     cm_RecordRacingRevoke(&amp;tfid, CM_RACINGFLAG_CANCELVOL);
  
  
!     lock_ObtainWrite(&amp;cm_scacheLock);
!     for (hash = 0; hash &lt; cm_hashTableSize; hash++) {
!         for(scp=cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
!             if (scp-&gt;fid.volume == fidp-&gt;Volume) {
!                 scp-&gt;refCount++;
!                 lock_ReleaseWrite(&amp;cm_scacheLock);
!                 lock_ObtainMutex(&amp;scp-&gt;mx);
                  osi_Log1(afsd_logp, "Discarding SCache scp %x", scp);
!                 cm_DiscardSCache(scp);
!                 lock_ReleaseMutex(&amp;scp-&gt;mx);
!                 cm_CallbackNotifyChange(scp);
!                 lock_ObtainWrite(&amp;cm_scacheLock);
!                 scp-&gt;refCount--;
!             }
!         }	/* search one hash bucket */
!     }	/* search all hash buckets */
! 
!     lock_ReleaseWrite(&amp;cm_scacheLock);
  }
  
  /* handle incoming RPC callback breaking message.
***************
*** 222,244 ****
   */
  SRXAFSCB_CallBack(struct rx_call *callp, AFSCBFids *fidsArrayp, AFSCBs *cbsArrayp)
  {
!         int i;
!         AFSFid *tfidp;
          
      osi_Log0(afsd_logp, "SRXAFSCB_CallBack");
  
!         for(i=0; i &lt; (long) fidsArrayp-&gt;AFSCBFids_len; i++) {
! 		tfidp = &amp;fidsArrayp-&gt;AFSCBFids_val[i];
                  
          if (tfidp-&gt;Volume == 0)
              continue;   /* means don't do anything */
!                 else if (tfidp-&gt;Vnode == 0)
!                 	cm_RevokeVolumeCallback(callp, tfidp);
          else
              cm_RevokeCallback(callp, tfidp);
!         }
  
! 	return 0;
  }
  
  /* called with no locks by RPC system when a server indicates that it has never
--- 222,244 ----
   */
  SRXAFSCB_CallBack(struct rx_call *callp, AFSCBFids *fidsArrayp, AFSCBs *cbsArrayp)
  {
!     int i;
!     AFSFid *tfidp;
          
      osi_Log0(afsd_logp, "SRXAFSCB_CallBack");
  
!     for (i=0; i &lt; (long) fidsArrayp-&gt;AFSCBFids_len; i++) {
!         tfidp = &amp;fidsArrayp-&gt;AFSCBFids_val[i];
                  
          if (tfidp-&gt;Volume == 0)
              continue;   /* means don't do anything */
!         else if (tfidp-&gt;Vnode == 0)
!             cm_RevokeVolumeCallback(callp, tfidp);
          else
              cm_RevokeCallback(callp, tfidp);
!     }
  
!     return 0;
  }
  
  /* called with no locks by RPC system when a server indicates that it has never
***************
*** 288,319 ****
  	 * are "rare," hopefully this won't be a problem.
  	 */
  	lock_ObtainWrite(&amp;cm_scacheLock);
! 	for(hash = 0; hash &lt; cm_hashTableSize; hash++) {
! 		for(scp=cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
! 			scp-&gt;refCount++;
!                         lock_ReleaseWrite(&amp;cm_scacheLock);
!                         lock_ObtainMutex(&amp;scp-&gt;mx);
! 			discarded = 0;
! 			if (scp-&gt;cbServerp != NULL) {
! 				/* we have a callback, now decide if we should clear it */
! 				if (scp-&gt;cbServerp == tsp || tsp == NULL) {
                          osi_Log1(afsd_logp, "Discarding SCache scp %x", scp);
! 					cm_DiscardSCache(scp);
! 					discarded = 1;
! 				}
! 			}
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			if (discarded)
! 				cm_CallbackNotifyChange(scp);
!                         lock_ObtainWrite(&amp;cm_scacheLock);
!                         scp-&gt;refCount--;
! 		}	/* search one hash bucket */
! 	}	/* search all hash buckets */
  	
  	lock_ReleaseWrite(&amp;cm_scacheLock);
  	
  	/* we're done with the server structure */
! 	if (tsp) cm_PutServer(tsp);
      }
  
      return 0;
--- 288,320 ----
  	 * are "rare," hopefully this won't be a problem.
  	 */
  	lock_ObtainWrite(&amp;cm_scacheLock);
! 	for (hash = 0; hash &lt; cm_hashTableSize; hash++) {
!             for (scp=cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
!                 scp-&gt;refCount++;
!                 lock_ReleaseWrite(&amp;cm_scacheLock);
!                 lock_ObtainMutex(&amp;scp-&gt;mx);
!                 discarded = 0;
!                 if (scp-&gt;cbServerp != NULL) {
!                     /* we have a callback, now decide if we should clear it */
!                     if (scp-&gt;cbServerp == tsp || tsp == NULL) {
                          osi_Log1(afsd_logp, "Discarding SCache scp %x", scp);
!                         cm_DiscardSCache(scp);
!                         discarded = 1;
!                     }
!                 }
!                 lock_ReleaseMutex(&amp;scp-&gt;mx);
!                 if (discarded)
!                     cm_CallbackNotifyChange(scp);
!                 lock_ObtainWrite(&amp;cm_scacheLock);
!                 scp-&gt;refCount--;
!             }	/* search one hash bucket */
! 	}      	/* search all hash buckets */
  	
  	lock_ReleaseWrite(&amp;cm_scacheLock);
  	
  	/* we're done with the server structure */
! 	if (tsp) 
!             cm_PutServer(tsp);
      }
  
      return 0;
***************
*** 323,329 ****
  SRXAFSCB_Probe(struct rx_call *callp)
  {
      osi_Log0(afsd_logp, "SRXAFSCB_Probe - not implemented");
! 	return 0;
  }
  
  /* debug interface: not implemented */
--- 324,330 ----
  SRXAFSCB_Probe(struct rx_call *callp)
  {
      osi_Log0(afsd_logp, "SRXAFSCB_Probe - not implemented");
!     return 0;
  }
  
  /* debug interface: not implemented */
***************
*** 337,403 ****
  /* debug interface: not implemented */
  SRXAFSCB_GetLock(struct rx_call *callp, long index, AFSDBLock *lockp)
  {
! 	/* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_GetLock - not implemented");
! 	return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_GetCE(struct rx_call *callp, long index, AFSDBCacheEntry *cep)
  {
! 	/* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_GetCE - not implemented");
! 	return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_XStatsVersion(struct rx_call *callp, long *vp)
  {
! 	/* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_XStatsVersion - not implemented");
! 	*vp = -1;
! 	return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_GetXStats(struct rx_call *callp, long cvn, long coln, long *srvp, long *timep,
  	AFSCB_CollData *datap)
  {
! 	/* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_GetXStats - not implemented");
! 	return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_InitCallBackState2(struct rx_call *callp, struct interfaceAddr* addr)
  {
! 	/* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_InitCallBackState2 - not implemented");
! 	return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_WhoAreYou(struct rx_call *callp, struct interfaceAddr* addr)
  {
! 	/* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_WhoAreYou - not implemented");
! 	return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid)
  {
! 	/* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_InitCallBackState3 - not implemented");
! 	return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_ProbeUuid(struct rx_call *callp, afsUUID* clientUuid)
  {
! 	/* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_ProbeUuid - not implemented");
! 	return RXGEN_OPCODE;
  }
  
  /*------------------------------------------------------------------------
--- 338,404 ----
  /* debug interface: not implemented */
  SRXAFSCB_GetLock(struct rx_call *callp, long index, AFSDBLock *lockp)
  {
!     /* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_GetLock - not implemented");
!     return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_GetCE(struct rx_call *callp, long index, AFSDBCacheEntry *cep)
  {
!     /* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_GetCE - not implemented");
!     return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_XStatsVersion(struct rx_call *callp, long *vp)
  {
!     /* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_XStatsVersion - not implemented");
!     *vp = -1;
!     return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_GetXStats(struct rx_call *callp, long cvn, long coln, long *srvp, long *timep,
  	AFSCB_CollData *datap)
  {
!     /* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_GetXStats - not implemented");
!     return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_InitCallBackState2(struct rx_call *callp, struct interfaceAddr* addr)
  {
!     /* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_InitCallBackState2 - not implemented");
!     return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_WhoAreYou(struct rx_call *callp, struct interfaceAddr* addr)
  {
!     /* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_WhoAreYou - not implemented");
!     return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid)
  {
!     /* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_InitCallBackState3 - not implemented");
!     return RXGEN_OPCODE;
  }
  
  /* debug interface: not implemented */
  SRXAFSCB_ProbeUuid(struct rx_call *callp, afsUUID* clientUuid)
  {
!     /* XXXX */
      osi_Log0(afsd_logp, "SRXAFSCB_ProbeUuid - not implemented");
!     return RXGEN_OPCODE;
  }
  
  /*------------------------------------------------------------------------
***************
*** 608,615 ****
  /* called by afsd without any locks to initialize this module */
  void cm_InitCallback(void)
  {
! 	lock_InitializeRWLock(&amp;cm_callbackLock, "cm_callbackLock");
!         cm_activeCallbackGrantingCalls = 0;
  }
  
  /* called with locked scp; tells us whether we've got a callback.
--- 609,616 ----
  /* called by afsd without any locks to initialize this module */
  void cm_InitCallback(void)
  {
!     lock_InitializeRWLock(&amp;cm_callbackLock, "cm_callbackLock");
!     cm_activeCallbackGrantingCalls = 0;
  }
  
  /* called with locked scp; tells us whether we've got a callback.
***************
*** 633,639 ****
      // to be called because cm_GetCallback has some initialization work to do.
      // If cm_fakeDirCallback is 2, then it means that the fake directory is in
      // good shape and we simply return true, provided no change is detected.
!   int fdc, fgc;
  
      if (cm_freelanceEnabled &amp;&amp; 
           scp-&gt;fid.cell==AFS_FAKE_ROOT_CELL_ID &amp;&amp; scp-&gt;fid.volume==AFS_FAKE_ROOT_VOL_ID) {
--- 634,640 ----
      // to be called because cm_GetCallback has some initialization work to do.
      // If cm_fakeDirCallback is 2, then it means that the fake directory is in
      // good shape and we simply return true, provided no change is detected.
!     int fdc, fgc;
  
      if (cm_freelanceEnabled &amp;&amp; 
           scp-&gt;fid.cell==AFS_FAKE_ROOT_CELL_ID &amp;&amp; scp-&gt;fid.volume==AFS_FAKE_ROOT_VOL_ID) {
***************
*** 691,702 ****
   */
  void cm_StartCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp)
  {
! 	lock_ObtainWrite(&amp;cm_callbackLock);
! 	cbrp-&gt;callbackCount = cm_callbackCount;
!         cm_activeCallbackGrantingCalls++;
!         cbrp-&gt;startTime = osi_Time();
!         cbrp-&gt;serverp = NULL;
! 	lock_ReleaseWrite(&amp;cm_callbackLock);
  }
  
  /* Called at the end of a callback-granting call, to remove the callback
--- 692,703 ----
   */
  void cm_StartCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp)
  {
!     lock_ObtainWrite(&amp;cm_callbackLock);
!     cbrp-&gt;callbackCount = cm_callbackCount;
!     cm_activeCallbackGrantingCalls++;
!     cbrp-&gt;startTime = osi_Time();
!     cbrp-&gt;serverp = NULL;
!     lock_ReleaseWrite(&amp;cm_callbackLock);
  }
  
  /* Called at the end of a callback-granting call, to remove the callback
***************
*** 706,788 ****
   * this locking hierarchy.
   */
  void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
! 	AFSCallBack *cbp, long flags)
  {
! 	cm_racingRevokes_t *revp;		/* where we are */
! 	cm_racingRevokes_t *nrevp;		/* where we'll be next */
!         int freeFlag;
      cm_server_t * serverp = 0;
  
! 	lock_ObtainWrite(&amp;cm_callbackLock);
! 	if (flags &amp; CM_CALLBACK_MAINTAINCOUNT) {
!         	osi_assert(cm_activeCallbackGrantingCalls &gt; 0);
! 	}
! 	else {
! 		osi_assert(cm_activeCallbackGrantingCalls-- &gt; 0);
! 	}
      if (cm_activeCallbackGrantingCalls == 0) 
          freeFlag = 1;
      else 
          freeFlag = 0;
  
! 	/* record the callback; we'll clear it below if we really lose it */
      if (cbrp) {
  	if (scp) {
              if (scp-&gt;cbServerp != cbrp-&gt;serverp) {
                  serverp = scp-&gt;cbServerp;
              }
! 	        scp-&gt;cbServerp = cbrp-&gt;serverp;
! 	        scp-&gt;cbExpires = cbrp-&gt;startTime + cbp-&gt;ExpirationTime;
          } else {
              serverp = cbrp-&gt;serverp;
          }
          cbrp-&gt;serverp = NULL;
! 	}
  
! 	/* a callback was actually revoked during our granting call, so
! 	 * run down the list of revoked fids, looking for ours.
! 	 * If activeCallbackGrantingCalls is zero, free the elements, too.
! 	 *
!          * May need to go through entire list just to do the freeing.
! 	 */
! 	for(revp = cm_racingRevokesp; revp; revp = nrevp) {
! 		nrevp = (cm_racingRevokes_t *) osi_QNext(&amp;revp-&gt;q);
! 		/* if this callback came in later than when we started the
!                  * callback-granting call, and if this fid is the right fid,
!                  * then clear the callback.
!                  */
          if (scp &amp;&amp; cbrp &amp;&amp; cbrp-&gt;callbackCount != cm_callbackCount
!                        	&amp;&amp; revp-&gt;callbackCount &gt; cbrp-&gt;callbackCount
               &amp;&amp; (( scp-&gt;fid.volume == revp-&gt;fid.volume &amp;&amp;
!                                  scp-&gt;fid.vnode == revp-&gt;fid.vnode &amp;&amp;
!                                  scp-&gt;fid.unique == revp-&gt;fid.unique)
!                             ||
!                                 ((revp-&gt;flags &amp; CM_RACINGFLAG_CANCELVOL) &amp;&amp;
!                                  scp-&gt;fid.volume == revp-&gt;fid.volume)
!                             ||
!                             	(revp-&gt;flags &amp; CM_RACINGFLAG_CANCELALL))) {
! 			/* this one matches */
! 			osi_Log4(afsd_logp,
! 			"Racing revoke scp %x old cbc %d rev cbc %d cur cbc %d",
! 				 scp,
! 				 cbrp-&gt;callbackCount, revp-&gt;callbackCount,
! 				 cm_callbackCount);
! 			cm_DiscardSCache(scp);
! 			/*
! 			 * Since we don't have a callback to preserve, it's
! 			 * OK to drop the lock and re-obtain it.
! 			 */
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			cm_CallbackNotifyChange(scp);
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
!                 }
!                 if (freeFlag) free(revp);
          }
  
! 	/* if we freed the list, zap the pointer to it */
! 	if (freeFlag) cm_racingRevokesp = NULL;
  
! 	lock_ReleaseWrite(&amp;cm_callbackLock);
  
      if ( serverp ) {
          lock_ObtainWrite(&amp;cm_serverLock);
--- 707,789 ----
   * this locking hierarchy.
   */
  void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
!                                 AFSCallBack *cbp, long flags)
  {
!     cm_racingRevokes_t *revp;		/* where we are */
!     cm_racingRevokes_t *nrevp;		/* where we'll be next */
!     int freeFlag;
      cm_server_t * serverp = 0;
  
!     lock_ObtainWrite(&amp;cm_callbackLock);
!     if (flags &amp; CM_CALLBACK_MAINTAINCOUNT) {
!         osi_assert(cm_activeCallbackGrantingCalls &gt; 0);
!     }
!     else {
!         osi_assert(cm_activeCallbackGrantingCalls-- &gt; 0);
!     }
      if (cm_activeCallbackGrantingCalls == 0) 
          freeFlag = 1;
      else 
          freeFlag = 0;
  
!     /* record the callback; we'll clear it below if we really lose it */
      if (cbrp) {
  	if (scp) {
              if (scp-&gt;cbServerp != cbrp-&gt;serverp) {
                  serverp = scp-&gt;cbServerp;
              }
!             scp-&gt;cbServerp = cbrp-&gt;serverp;
!             scp-&gt;cbExpires = cbrp-&gt;startTime + cbp-&gt;ExpirationTime;
          } else {
              serverp = cbrp-&gt;serverp;
          }
          cbrp-&gt;serverp = NULL;
!     }
  
!     /* a callback was actually revoked during our granting call, so
!      * run down the list of revoked fids, looking for ours.
!      * If activeCallbackGrantingCalls is zero, free the elements, too.
!      *
!      * May need to go through entire list just to do the freeing.
!      */
!     for (revp = cm_racingRevokesp; revp; revp = nrevp) {
!         nrevp = (cm_racingRevokes_t *) osi_QNext(&amp;revp-&gt;q);
!         /* if this callback came in later than when we started the
!          * callback-granting call, and if this fid is the right fid,
!          * then clear the callback.
!          */
          if (scp &amp;&amp; cbrp &amp;&amp; cbrp-&gt;callbackCount != cm_callbackCount
!              &amp;&amp; revp-&gt;callbackCount &gt; cbrp-&gt;callbackCount
               &amp;&amp; (( scp-&gt;fid.volume == revp-&gt;fid.volume &amp;&amp;
!                    scp-&gt;fid.vnode == revp-&gt;fid.vnode &amp;&amp;
!                    scp-&gt;fid.unique == revp-&gt;fid.unique)
!                   ||
!                   ((revp-&gt;flags &amp; CM_RACINGFLAG_CANCELVOL) &amp;&amp;
!                     scp-&gt;fid.volume == revp-&gt;fid.volume)
!                   ||
!                   (revp-&gt;flags &amp; CM_RACINGFLAG_CANCELALL))) {
!             /* this one matches */
!             osi_Log4(afsd_logp,
!                       "Racing revoke scp %x old cbc %d rev cbc %d cur cbc %d",
!                       scp,
!                       cbrp-&gt;callbackCount, revp-&gt;callbackCount,
!                       cm_callbackCount);
!             cm_DiscardSCache(scp);
!             /*
!              * Since we don't have a callback to preserve, it's
!              * OK to drop the lock and re-obtain it.
!              */
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             cm_CallbackNotifyChange(scp);
!             lock_ObtainMutex(&amp;scp-&gt;mx);
          }
+         if (freeFlag) free(revp);
+     }
  
!     /* if we freed the list, zap the pointer to it */
!     if (freeFlag) cm_racingRevokesp = NULL;
  
!     lock_ReleaseWrite(&amp;cm_callbackLock);
  
      if ( serverp ) {
          lock_ObtainWrite(&amp;cm_serverLock);
***************
*** 795,803 ****
   * called with locked scp; returns with same.
   */
  long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
! 	struct cm_req *reqp, long flags)
  {
! 	long code;
      cm_conn_t *connp;
      AFSFetchStatus afsStatus;
      AFSVolSync volSync;
--- 796,804 ----
   * called with locked scp; returns with same.
   */
  long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
!                     struct cm_req *reqp, long flags)
  {
!     long code;
      cm_conn_t *connp;
      AFSFetchStatus afsStatus;
      AFSVolSync volSync;
***************
*** 807,820 ****
      int mustCall;
      long sflags;
      cm_fid_t sfid;
  
      osi_Log2(afsd_logp, "GetCallback scp %x flags %lX", scp, flags);
  
  #ifdef AFS_FREELANCE_CLIENT
! 	// The case where a callback is needed on /afs is handled
! 	// specially. We need to fetch the status by calling
! 	// cm_MergeStatus and mark that cm_fakeDirCallback is 2
! 	if (cm_freelanceEnabled) {
          if (scp-&gt;fid.cell==AFS_FAKE_ROOT_CELL_ID &amp;&amp;
               scp-&gt;fid.volume==AFS_FAKE_ROOT_VOL_ID &amp;&amp;
               scp-&gt;fid.unique==0x1 &amp;&amp;
--- 808,822 ----
      int mustCall;
      long sflags;
      cm_fid_t sfid;
+     struct rx_connection * callp;
  
      osi_Log2(afsd_logp, "GetCallback scp %x flags %lX", scp, flags);
  
  #ifdef AFS_FREELANCE_CLIENT
!     // The case where a callback is needed on /afs is handled
!     // specially. We need to fetch the status by calling
!     // cm_MergeStatus and mark that cm_fakeDirCallback is 2
!     if (cm_freelanceEnabled) {
          if (scp-&gt;fid.cell==AFS_FAKE_ROOT_CELL_ID &amp;&amp;
               scp-&gt;fid.volume==AFS_FAKE_ROOT_VOL_ID &amp;&amp;
               scp-&gt;fid.unique==0x1 &amp;&amp;
***************
*** 849,889 ****
      }
  #endif /* AFS_FREELANCE_CLIENT */
  	
! 	mustCall = (flags &amp; 1);
! 	cm_AFSFidFromFid(&amp;tfid, &amp;scp-&gt;fid);
! 	while (1) {
! 		if (!mustCall &amp;&amp; cm_HaveCallback(scp)) return 0;
  
          /* turn off mustCall, since it has now forced us past the check above */
          mustCall = 0;
  
          /* otherwise, we have to make an RPC to get the status */
! 		sflags = CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK;
          cm_SyncOp(scp, NULL, NULL, NULL, 0, sflags);
          cm_StartCallbackGrantingCall(scp, &amp;cbr);
          sfid = scp-&gt;fid;
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
  		
! 		/* now make the RPC */
! 		osi_Log1(afsd_logp, "CALL FetchStatus vp %x", (long) scp);
          do {
! 			code = cm_Conn(&amp;sfid, userp, reqp, &amp;connp);
              if (code) continue;
! 		
!             code = RXAFS_FetchStatus(connp-&gt;callp, &amp;tfid,
                                       &amp;afsStatus, &amp;callback, &amp;volSync);
  
! 		} while (cm_Analyze(connp, userp, reqp, &amp;sfid, &amp;volSync, NULL,
                              &amp;cbr, code));
          code = cm_MapRPCError(code, reqp);
! 		osi_Log0(afsd_logp, "CALL FetchStatus DONE");
  
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
          cm_SyncOpDone(scp, NULL, sflags);
! 		if (code == 0) {
              cm_EndCallbackGrantingCall(scp, &amp;cbr, &amp;callback, 0);
              cm_MergeStatus(scp, &amp;afsStatus, &amp;volSync, userp, 0);
! 		}   
          else
              cm_EndCallbackGrantingCall(NULL, &amp;cbr, NULL, 0);
  
--- 851,893 ----
      }
  #endif /* AFS_FREELANCE_CLIENT */
  	
!     mustCall = (flags &amp; 1);
!     cm_AFSFidFromFid(&amp;tfid, &amp;scp-&gt;fid);
!     while (1) {
!         if (!mustCall &amp;&amp; cm_HaveCallback(scp)) return 0;
  
          /* turn off mustCall, since it has now forced us past the check above */
          mustCall = 0;
  
          /* otherwise, we have to make an RPC to get the status */
!         sflags = CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK;
          cm_SyncOp(scp, NULL, NULL, NULL, 0, sflags);
          cm_StartCallbackGrantingCall(scp, &amp;cbr);
          sfid = scp-&gt;fid;
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
  		
!         /* now make the RPC */
!         osi_Log1(afsd_logp, "CALL FetchStatus vp %x", (long) scp);
          do {
!             code = cm_Conn(&amp;sfid, userp, reqp, &amp;connp);
              if (code) continue;
! 
!             callp = cm_GetRxConn(connp);
!             code = RXAFS_FetchStatus(callp, &amp;tfid,
                                       &amp;afsStatus, &amp;callback, &amp;volSync);
+             rx_PutConnection(callp);
  
!         } while (cm_Analyze(connp, userp, reqp, &amp;sfid, &amp;volSync, NULL,
                              &amp;cbr, code));
          code = cm_MapRPCError(code, reqp);
!         osi_Log0(afsd_logp, "CALL FetchStatus DONE");
  
!         lock_ObtainMutex(&amp;scp-&gt;mx);
          cm_SyncOpDone(scp, NULL, sflags);
!         if (code == 0) {
              cm_EndCallbackGrantingCall(scp, &amp;cbr, &amp;callback, 0);
              cm_MergeStatus(scp, &amp;afsStatus, &amp;volSync, userp, 0);
!         }   
          else
              cm_EndCallbackGrantingCall(NULL, &amp;cbr, NULL, 0);
  
***************
*** 903,910 ****
  
      now = osi_Time();
      lock_ObtainWrite(&amp;cm_scacheLock);
!     for(i=0; i&lt;cm_hashTableSize; i++) {
!         for(scp = cm_hashTablep[i]; scp; scp=scp-&gt;nextp) {
              scp-&gt;refCount++;
              lock_ReleaseWrite(&amp;cm_scacheLock);
              if (scp-&gt;cbExpires &gt; 0 &amp;&amp; (scp-&gt;cbServerp == NULL || now &gt; scp-&gt;cbExpires)) {
--- 907,914 ----
  
      now = osi_Time();
      lock_ObtainWrite(&amp;cm_scacheLock);
!     for (i=0; i&lt;cm_hashTableSize; i++) {
!         for (scp = cm_hashTablep[i]; scp; scp=scp-&gt;nextp) {
              scp-&gt;refCount++;
              lock_ReleaseWrite(&amp;cm_scacheLock);
              if (scp-&gt;cbExpires &gt; 0 &amp;&amp; (scp-&gt;cbServerp == NULL || now &gt; scp-&gt;cbExpires)) {
Index: openafs/src/WINNT/afsd/cm_conn.c
diff -c openafs/src/WINNT/afsd/cm_conn.c:1.25.2.1 openafs/src/WINNT/afsd/cm_conn.c:1.25.2.3
*** openafs/src/WINNT/afsd/cm_conn.c:1.25.2.1	Tue Aug 17 00:28:38 2004
--- openafs/src/WINNT/afsd/cm_conn.c	Mon Oct 18 00:09:25 2004
***************
*** 463,491 ****
  /* called with a held server to GC all bad connections hanging off of the server */
  void cm_GCConnections(cm_server_t *serverp)
  {
! 	cm_conn_t *tcp;
      cm_conn_t **lcpp;
      cm_user_t *userp;
  
! 	lock_ObtainWrite(&amp;cm_connLock);
! 	lcpp = &amp;serverp-&gt;connsp;
! 	for(tcp = *lcpp; tcp; tcp = *lcpp) {
! 		userp = tcp-&gt;userp;
! 		if (userp &amp;&amp; tcp-&gt;refCount == 0 &amp;&amp; (userp-&gt;vcRefs == 0)) {
! 			/* do the deletion of this guy */
              cm_PutServer(tcp-&gt;serverp);
              cm_ReleaseUser(userp);
              *lcpp = tcp-&gt;nextp;
! 			rx_DestroyConnection(tcp-&gt;callp);
              lock_FinalizeMutex(&amp;tcp-&gt;mx);
              free(tcp);
          }
          else {
! 			/* just advance to the next */
              lcpp = &amp;tcp-&gt;nextp;
          }
      }
! 	lock_ReleaseWrite(&amp;cm_connLock);
  }
  
  static void cm_NewRXConnection(cm_conn_t *tcp, cm_ucell_t *ucellp,
--- 463,491 ----
  /* called with a held server to GC all bad connections hanging off of the server */
  void cm_GCConnections(cm_server_t *serverp)
  {
!     cm_conn_t *tcp;
      cm_conn_t **lcpp;
      cm_user_t *userp;
  
!     lock_ObtainWrite(&amp;cm_connLock);
!     lcpp = &amp;serverp-&gt;connsp;
!     for (tcp = *lcpp; tcp; tcp = *lcpp) {
!         userp = tcp-&gt;userp;
!         if (userp &amp;&amp; tcp-&gt;refCount == 0 &amp;&amp; (userp-&gt;vcRefs == 0)) {
!             /* do the deletion of this guy */
              cm_PutServer(tcp-&gt;serverp);
              cm_ReleaseUser(userp);
              *lcpp = tcp-&gt;nextp;
!             rx_DestroyConnection(tcp-&gt;callp);
              lock_FinalizeMutex(&amp;tcp-&gt;mx);
              free(tcp);
          }
          else {
!             /* just advance to the next */
              lcpp = &amp;tcp-&gt;nextp;
          }
      }
!     lock_ReleaseWrite(&amp;cm_connLock);
  }
  
  static void cm_NewRXConnection(cm_conn_t *tcp, cm_ucell_t *ucellp,
***************
*** 495,519 ****
      int serviceID;
      int secIndex;
      struct rx_securityClass *secObjp;
! 	afs_int32 level;
  
! 	if (serverp-&gt;type == CM_SERVER_VLDB) {
! 		port = htons(7003);
          serviceID = 52;
      }
      else {
! 		osi_assert(serverp-&gt;type == CM_SERVER_FILE);
          port = htons(7000);
          serviceID = 1;
      }
! 	if (ucellp-&gt;flags &amp; CM_UCELLFLAG_RXKAD) {
! 		secIndex = 2;
! 		if (cryptall) {
! 			level = rxkad_crypt;
! 			tcp-&gt;cryptlevel = rxkad_crypt;
! 		} else {
! 			level = rxkad_clear;
! 		}
          secObjp = rxkad_NewClientSecurityObject(level,
                                                  &amp;ucellp-&gt;sessionKey, ucellp-&gt;kvno,
                                                  ucellp-&gt;ticketLen, ucellp-&gt;ticketp);    
--- 495,518 ----
      int serviceID;
      int secIndex;
      struct rx_securityClass *secObjp;
!     afs_int32 level;
  
!     if (serverp-&gt;type == CM_SERVER_VLDB) {
!         port = htons(7003);
          serviceID = 52;
      }
      else {
!         osi_assert(serverp-&gt;type == CM_SERVER_FILE);
          port = htons(7000);
          serviceID = 1;
      }
!     if (ucellp-&gt;flags &amp; CM_UCELLFLAG_RXKAD) {
!         secIndex = 2;
!         if (cryptall) {
!             level = tcp-&gt;cryptlevel = rxkad_crypt;
!         } else {
!             level = tcp-&gt;cryptlevel = rxkad_clear;
!         }
          secObjp = rxkad_NewClientSecurityObject(level,
                                                  &amp;ucellp-&gt;sessionKey, ucellp-&gt;kvno,
                                                  ucellp-&gt;ticketLen, ucellp-&gt;ticketp);    
***************
*** 523,583 ****
          secIndex = 0;
          secObjp = rxnull_NewClientSecurityObject();
      }
! 	osi_assert(secObjp != NULL);
      tcp-&gt;callp = rx_NewConnection(serverp-&gt;addr.sin_addr.s_addr,
                                    port,
                                    serviceID,
                                    secObjp,
                                    secIndex);
! 	rx_SetConnDeadTime(tcp-&gt;callp, ConnDeadtimeout);
! 	rx_SetConnHardDeadTime(tcp-&gt;callp, HardDeadtimeout);
! 	tcp-&gt;ucgen = ucellp-&gt;gen;
      if (secObjp)
          rxs_Release(secObjp);   /* Decrement the initial refCount */
  }
  
  long cm_ConnByServer(cm_server_t *serverp, cm_user_t *userp, cm_conn_t **connpp)
  {
! 	cm_conn_t *tcp;
      cm_ucell_t *ucellp;
  
! 	lock_ObtainMutex(&amp;userp-&gt;mx);
! 	lock_ObtainWrite(&amp;cm_connLock);
! 	for(tcp = serverp-&gt;connsp; tcp; tcp=tcp-&gt;nextp) {
          if (tcp-&gt;userp == userp) 
              break;
      }
      
! 	/* find ucell structure */
      ucellp = cm_GetUCell(userp, serverp-&gt;cellp);
! 	if (!tcp) {
          cm_GetServer(serverp);
! 		tcp = malloc(sizeof(*tcp));
          memset(tcp, 0, sizeof(*tcp));
          tcp-&gt;nextp = serverp-&gt;connsp;
          serverp-&gt;connsp = tcp;
          cm_HoldUser(userp);
          tcp-&gt;userp = userp;
          lock_InitializeMutex(&amp;tcp-&gt;mx, "cm_conn_t mutex");
          tcp-&gt;serverp = serverp;
! 		tcp-&gt;cryptlevel = rxkad_clear;
! 		cm_NewRXConnection(tcp, ucellp, serverp);
! 		tcp-&gt;refCount = 1;
!     }
! 	else {
! 		if ((tcp-&gt;ucgen &lt; ucellp-&gt;gen) || (tcp-&gt;cryptlevel != cryptall))
! 		{
! 			rx_DestroyConnection(tcp-&gt;callp);
! 			cm_NewRXConnection(tcp, ucellp, serverp);
! 		}
          tcp-&gt;refCount++;
! 	}
! 	lock_ReleaseWrite(&amp;cm_connLock);
      lock_ReleaseMutex(&amp;userp-&gt;mx);
  
! 	/* return this pointer to our caller */
      osi_Log1(afsd_logp, "cm_ConnByServer returning conn 0x%x", (long) tcp);
! 	*connpp = tcp;
  
      return 0;
  }
--- 522,586 ----
          secIndex = 0;
          secObjp = rxnull_NewClientSecurityObject();
      }
!     osi_assert(secObjp != NULL);
      tcp-&gt;callp = rx_NewConnection(serverp-&gt;addr.sin_addr.s_addr,
                                    port,
                                    serviceID,
                                    secObjp,
                                    secIndex);
!     rx_SetConnDeadTime(tcp-&gt;callp, ConnDeadtimeout);
!     rx_SetConnHardDeadTime(tcp-&gt;callp, HardDeadtimeout);
!     tcp-&gt;ucgen = ucellp-&gt;gen;
      if (secObjp)
          rxs_Release(secObjp);   /* Decrement the initial refCount */
  }
  
  long cm_ConnByServer(cm_server_t *serverp, cm_user_t *userp, cm_conn_t **connpp)
  {
!     cm_conn_t *tcp;
      cm_ucell_t *ucellp;
  
!     lock_ObtainMutex(&amp;userp-&gt;mx);
!     lock_ObtainWrite(&amp;cm_connLock);
!     for (tcp = serverp-&gt;connsp; tcp; tcp=tcp-&gt;nextp) {
          if (tcp-&gt;userp == userp) 
              break;
      }
      
!     /* find ucell structure */
      ucellp = cm_GetUCell(userp, serverp-&gt;cellp);
!     if (!tcp) {
          cm_GetServer(serverp);
!         tcp = malloc(sizeof(*tcp));
          memset(tcp, 0, sizeof(*tcp));
          tcp-&gt;nextp = serverp-&gt;connsp;
          serverp-&gt;connsp = tcp;
          cm_HoldUser(userp);
          tcp-&gt;userp = userp;
          lock_InitializeMutex(&amp;tcp-&gt;mx, "cm_conn_t mutex");
+         lock_ObtainMutex(&amp;tcp-&gt;mx);
          tcp-&gt;serverp = serverp;
!         tcp-&gt;cryptlevel = rxkad_clear;
!         cm_NewRXConnection(tcp, ucellp, serverp);
!         tcp-&gt;refCount = 1;
!         lock_ReleaseMutex(&amp;tcp-&gt;mx);
!     } else {
!         if ((tcp-&gt;ucgen &lt; ucellp-&gt;gen) ||
!             (tcp-&gt;cryptlevel != (cryptall ? rxkad_crypt : rxkad_clear)))
!         {
!             lock_ObtainMutex(&amp;tcp-&gt;mx);
!             rx_DestroyConnection(tcp-&gt;callp);
!             cm_NewRXConnection(tcp, ucellp, serverp);
!             lock_ReleaseMutex(&amp;tcp-&gt;mx);
!         }
          tcp-&gt;refCount++;
!     }
!     lock_ReleaseWrite(&amp;cm_connLock);
      lock_ReleaseMutex(&amp;userp-&gt;mx);
  
!     /* return this pointer to our caller */
      osi_Log1(afsd_logp, "cm_ConnByServer returning conn 0x%x", (long) tcp);
!     *connpp = tcp;
  
      return 0;
  }
***************
*** 599,601 ****
--- 602,616 ----
      cm_FreeServerList(serverspp);
      return code;
  }
+ 
+ extern struct rx_connection * 
+ cm_GetRxConn(cm_conn_t *connp)
+ {
+     struct rx_connection * rxconn;
+     lock_ObtainMutex(&amp;connp-&gt;mx);
+     rxconn = connp-&gt;callp;
+     rx_GetConnection(rxconn);
+     lock_ReleaseMutex(&amp;connp-&gt;mx);
+     return rxconn;
+ }
+ 
Index: openafs/src/WINNT/afsd/cm_conn.h
diff -c openafs/src/WINNT/afsd/cm_conn.h:1.8 openafs/src/WINNT/afsd/cm_conn.h:1.8.2.1
*** openafs/src/WINNT/afsd/cm_conn.h:1.8	Sat Jul 31 20:16:37 2004
--- openafs/src/WINNT/afsd/cm_conn.h	Mon Oct 18 00:09:26 2004
***************
*** 23,29 ****
          struct rx_connection *callp;	/* locked by mx */
          struct cm_user *userp;		/* locked by mx; a held reference */
          osi_mutex_t mx;			/* mutex for some of these fields */
!         int refCount;			/* locked by cm_connLock */
  	int ucgen;			/* ucellp's generation number */
          long flags;			/* locked by mx */
  	int cryptlevel;			/* encrytion status */
--- 23,29 ----
          struct rx_connection *callp;	/* locked by mx */
          struct cm_user *userp;		/* locked by mx; a held reference */
          osi_mutex_t mx;			/* mutex for some of these fields */
!         unsigned long refCount;			/* locked by cm_connLock */
  	int ucgen;			/* ucellp's generation number */
          long flags;			/* locked by mx */
  	int cryptlevel;			/* encrytion status */
***************
*** 83,88 ****
--- 83,89 ----
  				   cache managers treat it as "server is down"*/
  
  #include "cm_server.h"
+ #include "rx.h"
  
  extern void cm_InitConn(void);
  
***************
*** 106,109 ****
--- 107,112 ----
  
  extern void cm_GCConnections(cm_server_t *serverp);
  
+ extern struct rx_connection * cm_GetRxConn(cm_conn_t *connp);
+ 
  #endif /*  __CM_CONN_H_ENV__ */
Index: openafs/src/WINNT/afsd/cm_dcache.c
diff -c openafs/src/WINNT/afsd/cm_dcache.c:1.11.2.1 openafs/src/WINNT/afsd/cm_dcache.c:1.11.2.3
*** openafs/src/WINNT/afsd/cm_dcache.c:1.11.2.1	Tue Aug 17 00:28:39 2004
--- openafs/src/WINNT/afsd/cm_dcache.c	Mon Oct 18 00:09:26 2004
***************
*** 37,52 ****
   * or when holding or releasing a vnode pointer.
   */
  long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
! 	cm_user_t *userp, cm_req_t *reqp)
  {
! 	/* store the data back from this buffer; the buffer is locked and held,
! 	 * but the vnode involved isn't locked, yet.  It is held by its
! 	 * reference from the buffer, which won't change until the buffer is
! 	 * released by our caller.  Thus, we don't have to worry about holding
! 	 * bufp-&gt;scp.
!          */
! 	long code;
! 	cm_fid_t *fidp = vfidp;
      cm_scache_t *scp;
      long nbytes;
      long temp;
--- 37,52 ----
   * or when holding or releasing a vnode pointer.
   */
  long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
!                  cm_user_t *userp, cm_req_t *reqp)
  {
!     /* store the data back from this buffer; the buffer is locked and held,
!      * but the vnode involved isn't locked, yet.  It is held by its
!      * reference from the buffer, which won't change until the buffer is
!      * released by our caller.  Thus, we don't have to worry about holding
!      * bufp-&gt;scp.
!      */
!     long code;
!     cm_fid_t *fidp = vfidp;
      cm_scache_t *scp;
      long nbytes;
      long temp;
***************
*** 70,104 ****
       * drops lots of locks, and may indeed return a properly initialized
       * buffer, although more likely it will just return a new, empty, buffer.
       */
! 	scp = cm_FindSCache(fidp);
! 	if (scp == NULL)
! 		return CM_ERROR_NOSUCHFILE;	/* shouldn't happen */
  
! 	cm_AFSFidFromFid(&amp;tfid, fidp);
  
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
          
      code = cm_SetupStoreBIOD(scp, offsetp, length, &amp;biod, userp, reqp);
      if (code) {
! 		osi_Log1(afsd_logp, "cm_SetupStoreBIOD code %x", code);
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		cm_ReleaseSCache(scp);
          return code;
      }
  
! 	if (biod.length == 0) {
! 		osi_Log0(afsd_logp, "cm_SetupStoreBIOD length 0");
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		cm_ReleaseBIOD(&amp;biod, 1);	/* should be a NOOP */
! 		cm_ReleaseSCache(scp);
          return 0;
! 	}   
  
! 	/* Serialize StoreData RPC's; for rationale see cm_scache.c */
! 	(void) cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA_EXCL);
  
! 	/* prepare the output status for the store */
! 	scp-&gt;mask |= CM_SCACHEMASK_CLIENTMODTIME;
      cm_StatusFromAttr(&amp;inStatus, scp, NULL);
      truncPos = scp-&gt;length.LowPart;
      if ((scp-&gt;mask &amp; CM_SCACHEMASK_TRUNCPOS)
--- 70,104 ----
       * drops lots of locks, and may indeed return a properly initialized
       * buffer, although more likely it will just return a new, empty, buffer.
       */
!     scp = cm_FindSCache(fidp);
!     if (scp == NULL)
!         return CM_ERROR_NOSUCHFILE;	/* shouldn't happen */
  
!     cm_AFSFidFromFid(&amp;tfid, fidp);
  
!     lock_ObtainMutex(&amp;scp-&gt;mx);
          
      code = cm_SetupStoreBIOD(scp, offsetp, length, &amp;biod, userp, reqp);
      if (code) {
!         osi_Log1(afsd_logp, "cm_SetupStoreBIOD code %x", code);
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         cm_ReleaseSCache(scp);
          return code;
      }
  
!     if (biod.length == 0) {
!         osi_Log0(afsd_logp, "cm_SetupStoreBIOD length 0");
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         cm_ReleaseBIOD(&amp;biod, 1);	/* should be a NOOP */
!         cm_ReleaseSCache(scp);
          return 0;
!     }   
  
!     /* Serialize StoreData RPC's; for rationale see cm_scache.c */
!     (void) cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA_EXCL);
  
!     /* prepare the output status for the store */
!     scp-&gt;mask |= CM_SCACHEMASK_CLIENTMODTIME;
      cm_StatusFromAttr(&amp;inStatus, scp, NULL);
      truncPos = scp-&gt;length.LowPart;
      if ((scp-&gt;mask &amp; CM_SCACHEMASK_TRUNCPOS)
***************
*** 106,151 ****
          truncPos = scp-&gt;truncPos.LowPart;
  	scp-&gt;mask &amp;= ~CM_SCACHEMASK_TRUNCPOS;
                  
! 	/* compute how many bytes to write from this buffer */
      thyper = LargeIntegerSubtract(scp-&gt;length, biod.offset);
      if (LargeIntegerLessThanZero(thyper)) {
! 		/* entire buffer is past EOF */
! 		nbytes = 0;
      }
      else {
! 		/* otherwise write out part of buffer before EOF, but not
           * more than bufferSize bytes.
           */
! 		nbytes = thyper.LowPart;
          if (nbytes &gt; biod.length) 
              nbytes = biod.length;
      }
  
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
          
      /* now we're ready to do the store operation */
      do {
! 		code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
          if (code) 
              continue;
  		
! 		callp = rx_NewCall(connp-&gt;callp);
  
! 		osi_Log3(afsd_logp, "CALL StoreData vp %x, off 0x%x, size 0x%x",
                   (long) scp, biod.offset.LowPart, nbytes);
  
          code = StartRXAFS_StoreData(callp, &amp;tfid, &amp;inStatus,
                                      biod.offset.LowPart, nbytes, truncPos);
  
! 		if (code == 0) {
              /* write the data from the the list of buffers */
              qdp = NULL;
! 			while(nbytes &gt; 0) {
! 				if (qdp == NULL)
! 		 			qdp = biod.bufListEndp;
! 				else
! 					qdp = (osi_queueData_t *) osi_QPrev(&amp;qdp-&gt;q);
! 				osi_assert(qdp != NULL);
                  bufp = osi_GetQData(qdp);
                  bufferp = bufp-&gt;datap;
                  wbytes = nbytes;
--- 106,153 ----
          truncPos = scp-&gt;truncPos.LowPart;
  	scp-&gt;mask &amp;= ~CM_SCACHEMASK_TRUNCPOS;
                  
!     /* compute how many bytes to write from this buffer */
      thyper = LargeIntegerSubtract(scp-&gt;length, biod.offset);
      if (LargeIntegerLessThanZero(thyper)) {
!         /* entire buffer is past EOF */
!         nbytes = 0;
      }
      else {
!         /* otherwise write out part of buffer before EOF, but not
           * more than bufferSize bytes.
           */
!         nbytes = thyper.LowPart;
          if (nbytes &gt; biod.length) 
              nbytes = biod.length;
      }
  
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
          
      /* now we're ready to do the store operation */
      do {
!         code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
          if (code) 
              continue;
  		
!         lock_ObtainMutex(&amp;connp-&gt;mx);
!         callp = rx_NewCall(connp-&gt;callp);
!         lock_ReleaseMutex(&amp;connp-&gt;mx);
  
!         osi_Log3(afsd_logp, "CALL StoreData vp %x, off 0x%x, size 0x%x",
                   (long) scp, biod.offset.LowPart, nbytes);
  
          code = StartRXAFS_StoreData(callp, &amp;tfid, &amp;inStatus,
                                      biod.offset.LowPart, nbytes, truncPos);
  
!         if (code == 0) {
              /* write the data from the the list of buffers */
              qdp = NULL;
!             while(nbytes &gt; 0) {
!                 if (qdp == NULL)
!                     qdp = biod.bufListEndp;
!                 else
!                     qdp = (osi_queueData_t *) osi_QPrev(&amp;qdp-&gt;q);
!                 osi_assert(qdp != NULL);
                  bufp = osi_GetQData(qdp);
                  bufferp = bufp-&gt;datap;
                  wbytes = nbytes;
***************
*** 157,219 ****
                  if (temp != wbytes) {
                      osi_Log2(afsd_logp, "rx_Write failed %d != %d",temp,wbytes);
                      code = -1;
! 					break;
! 				} else {
                      osi_Log1(afsd_logp, "rx_Write succeeded %d",temp);
!                 }
                  nbytes -= wbytes;
              }	/* while more bytes to write */
! 		}		/* if RPC started successfully */
          else {
              osi_Log1(afsd_logp, "StartRXAFS_StoreData failed (%lX)",code);
          }
! 		if (code == 0) {
! 			code = EndRXAFS_StoreData(callp, &amp;outStatus, &amp;volSync);
              if (code)
                  osi_Log1(afsd_logp, "EndRXAFS_StoreData failed (%lX)",code);
          }
          code = rx_EndCall(callp, code);
          osi_Log0(afsd_logp, "CALL StoreData DONE");
                  
! 	} while (cm_Analyze(connp, userp, reqp, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
      code = cm_MapRPCError(code, reqp);
          
      /* now, clean up our state */
      lock_ObtainMutex(&amp;scp-&gt;mx);
  
! 	cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
  
! 	if (code == 0) {
! 		/* now, here's something a little tricky: in AFS 3, a dirty
! 		 * length can't be directly stored, instead, a dirty chunk is
! 		 * stored that sets the file's size (by writing and by using
! 		 * the truncate-first option in the store call).
! 		 *
           * At this point, we've just finished a store, and so the trunc
! 		 * pos field is clean.  If the file's size at the server is at
! 		 * least as big as we think it should be, then we turn off the
! 		 * length dirty bit, since all the other dirty buffers must
! 		 * precede this one in the file.
           *
           * The file's desired size shouldn't be smaller than what's
! 		 * stored at the server now, since we just did the trunc pos
! 		 * store.
           *
           * We have to turn off the length dirty bit as soon as we can,
! 		 * so that we see updates made by other machines.
           */
! 		if (outStatus.Length &gt;= scp-&gt;length.LowPart)
              scp-&gt;mask &amp;= ~CM_SCACHEMASK_LENGTH;
! 		cm_MergeStatus(scp, &amp;outStatus, &amp;volSync, userp, 0);
! 	} else {
! 		if (code == CM_ERROR_SPACE)
! 			scp-&gt;flags |= CM_SCACHEFLAG_OUTOFSPACE;
! 		else if (code == CM_ERROR_QUOTA)
! 			scp-&gt;flags |= CM_SCACHEFLAG_OVERQUOTA;
! 	}
      lock_ReleaseMutex(&amp;scp-&gt;mx);
      cm_ReleaseBIOD(&amp;biod, 1);
! 	cm_ReleaseSCache(scp);
  
      return code;
  }
--- 159,221 ----
                  if (temp != wbytes) {
                      osi_Log2(afsd_logp, "rx_Write failed %d != %d",temp,wbytes);
                      code = -1;
!                     break;
!                 } else {
                      osi_Log1(afsd_logp, "rx_Write succeeded %d",temp);
!                 }       
                  nbytes -= wbytes;
              }	/* while more bytes to write */
!         }		/* if RPC started successfully */
          else {
              osi_Log1(afsd_logp, "StartRXAFS_StoreData failed (%lX)",code);
          }
!         if (code == 0) {
!             code = EndRXAFS_StoreData(callp, &amp;outStatus, &amp;volSync);
              if (code)
                  osi_Log1(afsd_logp, "EndRXAFS_StoreData failed (%lX)",code);
          }
          code = rx_EndCall(callp, code);
          osi_Log0(afsd_logp, "CALL StoreData DONE");
                  
!     } while (cm_Analyze(connp, userp, reqp, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
      code = cm_MapRPCError(code, reqp);
          
      /* now, clean up our state */
      lock_ObtainMutex(&amp;scp-&gt;mx);
  
!     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
  
!     if (code == 0) {
!         /* now, here's something a little tricky: in AFS 3, a dirty
!          * length can't be directly stored, instead, a dirty chunk is
!          * stored that sets the file's size (by writing and by using
!          * the truncate-first option in the store call).
!          *
           * At this point, we've just finished a store, and so the trunc
!          * pos field is clean.  If the file's size at the server is at
!          * least as big as we think it should be, then we turn off the
!          * length dirty bit, since all the other dirty buffers must
!          * precede this one in the file.
           *
           * The file's desired size shouldn't be smaller than what's
!          * stored at the server now, since we just did the trunc pos
!          * store.
           *
           * We have to turn off the length dirty bit as soon as we can,
!          * so that we see updates made by other machines.
           */
!         if (outStatus.Length &gt;= scp-&gt;length.LowPart)
              scp-&gt;mask &amp;= ~CM_SCACHEMASK_LENGTH;
!         cm_MergeStatus(scp, &amp;outStatus, &amp;volSync, userp, 0);
!     } else {
!         if (code == CM_ERROR_SPACE)
!             scp-&gt;flags |= CM_SCACHEFLAG_OUTOFSPACE;
!         else if (code == CM_ERROR_QUOTA)
!             scp-&gt;flags |= CM_SCACHEFLAG_OVERQUOTA;
!     }
      lock_ReleaseMutex(&amp;scp-&gt;mx);
      cm_ReleaseBIOD(&amp;biod, 1);
!     cm_ReleaseSCache(scp);
  
      return code;
  }
***************
*** 229,299 ****
      AFSStoreStatus inStatus;
      AFSVolSync volSync;
      AFSFid tfid;
! 	long code;
! 	long truncPos;
! 	cm_conn_t *connp;
      struct rx_call *callp;
  
! 	/* Serialize StoreData RPC's; for rationale see cm_scache.c */
! 	(void) cm_SyncOp(scp, NULL, userp, reqp, 0,
                       CM_SCACHESYNC_STOREDATA_EXCL);
  
! 	/* prepare the output status for the store */
! 	inStatus.Mask = AFS_SETMODTIME;
! 	inStatus.ClientModTime = scp-&gt;clientModTime;
! 	scp-&gt;mask &amp;= ~CM_SCACHEMASK_CLIENTMODTIME;
  
! 	/* calculate truncation position */
      truncPos = scp-&gt;length.LowPart;
      if ((scp-&gt;mask &amp; CM_SCACHEMASK_TRUNCPOS)
           &amp;&amp; scp-&gt;truncPos.LowPart &lt; (unsigned long) truncPos)
          truncPos = scp-&gt;truncPos.LowPart;
! 	scp-&gt;mask &amp;= ~CM_SCACHEMASK_TRUNCPOS;
!                 
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
  
! 	cm_AFSFidFromFid(&amp;tfid, &amp;scp-&gt;fid);
  
      /* now we're ready to do the store operation */
      do {
! 		code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
          if (code) 
              continue;
  		
! 		callp = rx_NewCall(connp-&gt;callp);
  
          code = StartRXAFS_StoreData(callp, &amp;tfid, &amp;inStatus,
                                      0, 0, truncPos);
  
! 		if (code == 0)
! 			code = EndRXAFS_StoreData(callp, &amp;outStatus, &amp;volSync);
          code = rx_EndCall(callp, code);
! 	} while (cm_Analyze(connp, userp, reqp, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
      code = cm_MapRPCError(code, reqp);
          
      /* now, clean up our state */
      lock_ObtainMutex(&amp;scp-&gt;mx);
  
! 	cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
  
! 	if (code == 0) {
! 		/*
! 		 * For explanation of handling of CM_SCACHEMASK_LENGTH,
! 		 * see cm_BufWrite().
! 		 */
! 		if (outStatus.Length &gt;= scp-&gt;length.LowPart)
              scp-&gt;mask &amp;= ~CM_SCACHEMASK_LENGTH;
! 		cm_MergeStatus(scp, &amp;outStatus, &amp;volSync, userp, 0);
! 	}
  
! 	return code;
  }
  
  long cm_BufRead(cm_buf_t *bufp, long nbytes, long *bytesReadp, cm_user_t *userp)
  {
! 	*bytesReadp = buf_bufferSize;
  
! 	/* now return a code that means that I/O is done */
      return 0;
  }
  
--- 231,304 ----
      AFSStoreStatus inStatus;
      AFSVolSync volSync;
      AFSFid tfid;
!     long code;
!     long truncPos;
!     cm_conn_t *connp;
      struct rx_call *callp;
  
!     /* Serialize StoreData RPC's; for rationale see cm_scache.c */
!     (void) cm_SyncOp(scp, NULL, userp, reqp, 0,
                       CM_SCACHESYNC_STOREDATA_EXCL);
  
!     /* prepare the output status for the store */
!     inStatus.Mask = AFS_SETMODTIME;
!     inStatus.ClientModTime = scp-&gt;clientModTime;
!     scp-&gt;mask &amp;= ~CM_SCACHEMASK_CLIENTMODTIME;
  
!     /* calculate truncation position */
      truncPos = scp-&gt;length.LowPart;
      if ((scp-&gt;mask &amp; CM_SCACHEMASK_TRUNCPOS)
           &amp;&amp; scp-&gt;truncPos.LowPart &lt; (unsigned long) truncPos)
          truncPos = scp-&gt;truncPos.LowPart;
!     scp-&gt;mask &amp;= ~CM_SCACHEMASK_TRUNCPOS;
  
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
!     cm_AFSFidFromFid(&amp;tfid, &amp;scp-&gt;fid);
  
      /* now we're ready to do the store operation */
      do {
!         code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
          if (code) 
              continue;
  		
!         lock_ObtainMutex(&amp;connp-&gt;mx);
!         callp = rx_NewCall(connp-&gt;callp);
!         lock_ReleaseMutex(&amp;connp-&gt;mx);
  
          code = StartRXAFS_StoreData(callp, &amp;tfid, &amp;inStatus,
                                      0, 0, truncPos);
  
!         if (code == 0)
!             code = EndRXAFS_StoreData(callp, &amp;outStatus, &amp;volSync);
          code = rx_EndCall(callp, code);
! 
!     } while (cm_Analyze(connp, userp, reqp, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
      code = cm_MapRPCError(code, reqp);
          
      /* now, clean up our state */
      lock_ObtainMutex(&amp;scp-&gt;mx);
  
!     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
  
!     if (code == 0) {
!         /*
!          * For explanation of handling of CM_SCACHEMASK_LENGTH,
!          * see cm_BufWrite().
!          */
!         if (outStatus.Length &gt;= scp-&gt;length.LowPart)
              scp-&gt;mask &amp;= ~CM_SCACHEMASK_LENGTH;
!         cm_MergeStatus(scp, &amp;outStatus, &amp;volSync, userp, 0);
!     }
  
!     return code;
  }
  
  long cm_BufRead(cm_buf_t *bufp, long nbytes, long *bytesReadp, cm_user_t *userp)
  {
!     *bytesReadp = buf_bufferSize;
  
!     /* now return a code that means that I/O is done */
      return 0;
  }
  
***************
*** 302,319 ****
   */
  long cm_BufStabilize(void *parmp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	cm_scache_t *scp;
      long code;
  
      scp = parmp;
          
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
      code = cm_SyncOp(scp, NULL, userp, reqp, 0, 
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_SETSIZE);
! 	if (code) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
          return code;
! 	}
          
      return 0;
  }
--- 307,324 ----
   */
  long cm_BufStabilize(void *parmp, cm_user_t *userp, cm_req_t *reqp)
  {
!     cm_scache_t *scp;
      long code;
  
      scp = parmp;
          
!     lock_ObtainMutex(&amp;scp-&gt;mx);
      code = cm_SyncOp(scp, NULL, userp, reqp, 0, 
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_SETSIZE);
!     if (code) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
          return code;
!     }
          
      return 0;
  }
***************
*** 321,338 ****
  /* undoes the work that cm_BufStabilize does: releases lock so things can change again */
  long cm_BufUnstabilize(void *parmp, cm_user_t *userp)
  {
! 	cm_scache_t *scp;
          
      scp = parmp;
          
      lock_ReleaseMutex(&amp;scp-&gt;mx);
          
! 	/* always succeeds */
      return 0;
  }
  
  cm_buf_ops_t cm_bufOps = {
! 	cm_BufWrite,
      cm_BufRead,
      cm_BufStabilize,
      cm_BufUnstabilize
--- 326,343 ----
  /* undoes the work that cm_BufStabilize does: releases lock so things can change again */
  long cm_BufUnstabilize(void *parmp, cm_user_t *userp)
  {
!     cm_scache_t *scp;
          
      scp = parmp;
          
      lock_ReleaseMutex(&amp;scp-&gt;mx);
          
!     /* always succeeds */
      return 0;
  }
  
  cm_buf_ops_t cm_bufOps = {
!     cm_BufWrite,
      cm_BufRead,
      cm_BufStabilize,
      cm_BufUnstabilize
***************
*** 340,349 ****
  
  int cm_InitDCache(long chunkSize, long nbuffers)
  {
! 	lock_InitializeMutex(&amp;cm_bufGetMutex, "buf_Get mutex");
! 	if (nbuffers) 
          buf_nbuffers = nbuffers;
! 	return buf_Init(&amp;cm_bufOps);
  }
  
  /* check to see if we have an up-to-date buffer.  The buffer must have
--- 345,354 ----
  
  int cm_InitDCache(long chunkSize, long nbuffers)
  {
!     lock_InitializeMutex(&amp;cm_bufGetMutex, "buf_Get mutex");
!     if (nbuffers) 
          buf_nbuffers = nbuffers;
!     return buf_Init(&amp;cm_bufOps);
  }
  
  /* check to see if we have an up-to-date buffer.  The buffer must have
***************
*** 357,400 ****
   */
  int cm_HaveBuffer(cm_scache_t *scp, cm_buf_t *bufp, int isBufLocked)
  {
! 	int code;
! 	if (!cm_HaveCallback(scp))
! 		return 0;
! 	if ((bufp-&gt;cmFlags
! 	     &amp; (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED))
! 		== (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED))
! 		return 1;
!        	if (bufp-&gt;dataVersion == scp-&gt;dataVersion)
!         	return 1;
! 	if (!isBufLocked) {
! 		code = lock_TryMutex(&amp;bufp-&gt;mx);
          if (code == 0) {
! 			/* don't have the lock, and can't lock it, then
               * return failure.
               */
              return 0;
          }
      }
  
! 	/* remember dirty flag for later */
! 	code = bufp-&gt;flags &amp; CM_BUF_DIRTY;
  
! 	/* release lock if we obtained it here */
! 	if (!isBufLocked) 
          lock_ReleaseMutex(&amp;bufp-&gt;mx);
  
! 	/* if buffer was dirty, buffer is acceptable for use */
!         if (code) 
!             return 1;
!         else 
!             return 0;
  }
  
  /* used when deciding whether to do a prefetch or not */
  long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, long length,
! 	cm_user_t *up, cm_req_t *reqp, osi_hyper_t *realBasep)
  {
! 	osi_hyper_t toffset;
      osi_hyper_t tbase;
      long code;
      cm_buf_t *bp;
--- 362,405 ----
   */
  int cm_HaveBuffer(cm_scache_t *scp, cm_buf_t *bufp, int isBufLocked)
  {
!     int code;
!     if (!cm_HaveCallback(scp))
!         return 0;
!     if ((bufp-&gt;cmFlags
!           &amp; (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED))
!          == (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED))
!         return 1;
!     if (bufp-&gt;dataVersion == scp-&gt;dataVersion)
!         return 1;
!     if (!isBufLocked) {
!         code = lock_TryMutex(&amp;bufp-&gt;mx);
          if (code == 0) {
!             /* don't have the lock, and can't lock it, then
               * return failure.
               */
              return 0;
          }
      }
  
!     /* remember dirty flag for later */
!     code = bufp-&gt;flags &amp; CM_BUF_DIRTY;
  
!     /* release lock if we obtained it here */
!     if (!isBufLocked) 
          lock_ReleaseMutex(&amp;bufp-&gt;mx);
  
!     /* if buffer was dirty, buffer is acceptable for use */
!     if (code) 
!         return 1;
!     else 
!         return 0;
  }
  
  /* used when deciding whether to do a prefetch or not */
  long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, long length,
!                         cm_user_t *up, cm_req_t *reqp, osi_hyper_t *realBasep)
  {
!     osi_hyper_t toffset;
      osi_hyper_t tbase;
      long code;
      cm_buf_t *bp;
***************
*** 403,439 ****
      /* now scan all buffers in the range, looking for any that look like
       * they need work.
       */
! 	tbase = *startBasep;
! 	stop = 0;
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
      while(length &gt; 0) {
! 		/* get callback so we can do a meaningful dataVersion comparison */
          code = cm_SyncOp(scp, NULL, up, reqp, 0,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 		if (code) {
! 			scp-&gt;flags &amp;= ~CM_SCACHEFLAG_PREFETCHING;
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
              return code;
          }
                  
          if (LargeIntegerGreaterThanOrEqualTo(tbase, scp-&gt;length)) {
! 			/* we're past the end of file */
              break;
          }
  
! 		bp = buf_Find(scp, &amp;tbase);
! 		/* We cheat slightly by not locking the bp mutex. */
          if (bp) {
              if ((bp-&gt;cmFlags
! 			      &amp; (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)) == 0
                   &amp;&amp; bp-&gt;dataVersion != scp-&gt;dataVersion)
                  stop = 1;
              buf_Release(bp);
! 		}
          else 
              stop = 1;
  
! 		/* if this buffer is essentially guaranteed to require a fetch,
           * break out here and return this position.
           */
          if (stop) 
--- 408,444 ----
      /* now scan all buffers in the range, looking for any that look like
       * they need work.
       */
!     tbase = *startBasep;
!     stop = 0;
!     lock_ObtainMutex(&amp;scp-&gt;mx);
      while(length &gt; 0) {
!         /* get callback so we can do a meaningful dataVersion comparison */
          code = cm_SyncOp(scp, NULL, up, reqp, 0,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!         if (code) {
!             scp-&gt;flags &amp;= ~CM_SCACHEFLAG_PREFETCHING;
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
              return code;
          }
                  
          if (LargeIntegerGreaterThanOrEqualTo(tbase, scp-&gt;length)) {
!             /* we're past the end of file */
              break;
          }
  
!         bp = buf_Find(scp, &amp;tbase);
!         /* We cheat slightly by not locking the bp mutex. */
          if (bp) {
              if ((bp-&gt;cmFlags
!                   &amp; (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)) == 0
                   &amp;&amp; bp-&gt;dataVersion != scp-&gt;dataVersion)
                  stop = 1;
              buf_Release(bp);
!         }
          else 
              stop = 1;
  
!         /* if this buffer is essentially guaranteed to require a fetch,
           * break out here and return this position.
           */
          if (stop) 
***************
*** 449,461 ****
       * particular buffer in the range that definitely needs to be fetched.
       */
      if (stop == 0) {
! 		/* return non-zero code since realBasep won't be valid */
! 		scp-&gt;flags &amp;= ~CM_SCACHEFLAG_PREFETCHING;
! 		code = -1;
!     }
      else {
! 		/* successfully found a page that will need fetching */
! 		*realBasep = tbase;
          code = 0;
      }
      lock_ReleaseMutex(&amp;scp-&gt;mx);
--- 454,466 ----
       * particular buffer in the range that definitely needs to be fetched.
       */
      if (stop == 0) {
!         /* return non-zero code since realBasep won't be valid */
!         scp-&gt;flags &amp;= ~CM_SCACHEFLAG_PREFETCHING;
!         code = -1;
!     }   
      else {
!         /* successfully found a page that will need fetching */
!         *realBasep = tbase;
          code = 0;
      }
      lock_ReleaseMutex(&amp;scp-&gt;mx);
***************
*** 463,541 ****
  }
  
  void cm_BkgStore(cm_scache_t *scp, long p1, long p2, long p3, long p4,
! 	cm_user_t *userp)
  {
! 	osi_hyper_t toffset;
      long length;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
! 	req.flags |= CM_REQ_NORETRY;
  
      toffset.LowPart = p1;
      toffset.HighPart = p2;
      length = p3;
  
! 	osi_Log2(afsd_logp, "Starting BKG store vp 0x%x, base 0x%x", scp, p1);
  
! 	cm_BufWrite(&amp;scp-&gt;fid, &amp;toffset, length, /* flags */ 0, userp, &amp;req);
  
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
      lock_ReleaseMutex(&amp;scp-&gt;mx);
  }
  
  void cm_ClearPrefetchFlag(long code, cm_scache_t *scp, osi_hyper_t *base)
  {
! 	osi_hyper_t thyper;
  
! 	if (code == 0) {
! 		thyper.LowPart = cm_chunkSize;
! 		thyper.HighPart = 0;
! 		thyper =  LargeIntegerAdd(*base, thyper);
! 		thyper.LowPart &amp;= (-cm_chunkSize);
! 		if (LargeIntegerGreaterThan(*base, scp-&gt;prefetch.base))
              scp-&gt;prefetch.base = *base;
! 		if (LargeIntegerGreaterThan(thyper, scp-&gt;prefetch.end))
              scp-&gt;prefetch.end = thyper;
! 	}
! 	scp-&gt;flags &amp;= ~CM_SCACHEFLAG_PREFETCHING;
  }
  
  /* do the prefetch */
  void cm_BkgPrefetch(cm_scache_t *scp, long p1, long p2, long p3, long p4,
! 	cm_user_t *userp)
  {
! 	long length;
      osi_hyper_t base;
      long code;
      cm_buf_t *bp;
! 	int cpff = 0;			/* cleared prefetch flag */
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
! 	req.flags |= CM_REQ_NORETRY;
          
! 	base.LowPart = p1;
      base.HighPart = p2;
      length = p3;
          
! 	osi_Log2(afsd_logp, "Starting BKG prefetch vp 0x%x, base 0x%x", scp, p1);
  
      code = buf_Get(scp, &amp;base, &amp;bp);
  
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
  
      if (code || (bp-&gt;cmFlags &amp; CM_BUF_CMFETCHING)) {
! 		scp-&gt;flags &amp;= ~CM_SCACHEFLAG_PREFETCHING;
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		return;
! 	}
  
      code = cm_GetBuffer(scp, bp, &amp;cpff, userp, &amp;req);
! 	if (!cpff) 
          cm_ClearPrefetchFlag(code, scp, &amp;base);
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
      buf_Release(bp);
      return;
  }
--- 468,546 ----
  }
  
  void cm_BkgStore(cm_scache_t *scp, long p1, long p2, long p3, long p4,
!                  cm_user_t *userp)
  {
!     osi_hyper_t toffset;
      long length;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
!     req.flags |= CM_REQ_NORETRY;
  
      toffset.LowPart = p1;
      toffset.HighPart = p2;
      length = p3;
  
!     osi_Log2(afsd_logp, "Starting BKG store vp 0x%x, base 0x%x", scp, p1);
  
!     cm_BufWrite(&amp;scp-&gt;fid, &amp;toffset, length, /* flags */ 0, userp, &amp;req);
  
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
      lock_ReleaseMutex(&amp;scp-&gt;mx);
  }
  
  void cm_ClearPrefetchFlag(long code, cm_scache_t *scp, osi_hyper_t *base)
  {
!     osi_hyper_t thyper;
  
!     if (code == 0) {
!         thyper.LowPart = cm_chunkSize;
!         thyper.HighPart = 0;
!         thyper =  LargeIntegerAdd(*base, thyper);
!         thyper.LowPart &amp;= (-cm_chunkSize);
!         if (LargeIntegerGreaterThan(*base, scp-&gt;prefetch.base))
              scp-&gt;prefetch.base = *base;
!         if (LargeIntegerGreaterThan(thyper, scp-&gt;prefetch.end))
              scp-&gt;prefetch.end = thyper;
!     }
!     scp-&gt;flags &amp;= ~CM_SCACHEFLAG_PREFETCHING;
  }
  
  /* do the prefetch */
  void cm_BkgPrefetch(cm_scache_t *scp, long p1, long p2, long p3, long p4,
!                     cm_user_t *userp)
  {
!     long length;
      osi_hyper_t base;
      long code;
      cm_buf_t *bp;
!     int cpff = 0;			/* cleared prefetch flag */
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
!     req.flags |= CM_REQ_NORETRY;
          
!     base.LowPart = p1;
      base.HighPart = p2;
      length = p3;
          
!     osi_Log2(afsd_logp, "Starting BKG prefetch vp 0x%x, base 0x%x", scp, p1);
  
      code = buf_Get(scp, &amp;base, &amp;bp);
  
!     lock_ObtainMutex(&amp;scp-&gt;mx);
  
      if (code || (bp-&gt;cmFlags &amp; CM_BUF_CMFETCHING)) {
!         scp-&gt;flags &amp;= ~CM_SCACHEFLAG_PREFETCHING;
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         return;
!     }
  
      code = cm_GetBuffer(scp, bp, &amp;cpff, userp, &amp;req);
!     if (!cpff) 
          cm_ClearPrefetchFlag(code, scp, &amp;base);
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
      buf_Release(bp);
      return;
  }
***************
*** 544,579 ****
   * do a prefetch.
   */
  void cm_ConsiderPrefetch(cm_scache_t *scp, osi_hyper_t *offsetp,
! 	cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code;
      osi_hyper_t realBase;
      osi_hyper_t readBase;
          
      readBase = *offsetp;
! 	/* round up to chunk boundary */
! 	readBase.LowPart += (cm_chunkSize-1);
! 	readBase.LowPart &amp;= (-cm_chunkSize);
  
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	if ((scp-&gt;flags &amp; CM_SCACHEFLAG_PREFETCHING)
           || LargeIntegerLessThanOrEqualTo(readBase, scp-&gt;prefetch.base)) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
          return;
! 	}
! 	scp-&gt;flags |= CM_SCACHEFLAG_PREFETCHING;
  
! 	/* start the scan at the latter of the end of this read or
       * the end of the last fetched region.
       */
! 	if (LargeIntegerGreaterThan(scp-&gt;prefetch.end, readBase))
          readBase = scp-&gt;prefetch.end;
  
      lock_ReleaseMutex(&amp;scp-&gt;mx);
  
      code = cm_CheckFetchRange(scp, &amp;readBase, cm_chunkSize, userp, reqp,
!                                   &amp;realBase);
! 	if (code) 
          return;	/* can't find something to prefetch */
  
      osi_Log2(afsd_logp, "BKG Prefetch request vp 0x%x, base 0x%x",
--- 549,584 ----
   * do a prefetch.
   */
  void cm_ConsiderPrefetch(cm_scache_t *scp, osi_hyper_t *offsetp,
!                          cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
      osi_hyper_t realBase;
      osi_hyper_t readBase;
          
      readBase = *offsetp;
!     /* round up to chunk boundary */
!     readBase.LowPart += (cm_chunkSize-1);
!     readBase.LowPart &amp;= (-cm_chunkSize);
  
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     if ((scp-&gt;flags &amp; CM_SCACHEFLAG_PREFETCHING)
           || LargeIntegerLessThanOrEqualTo(readBase, scp-&gt;prefetch.base)) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
          return;
!     }
!     scp-&gt;flags |= CM_SCACHEFLAG_PREFETCHING;
  
!     /* start the scan at the latter of the end of this read or
       * the end of the last fetched region.
       */
!     if (LargeIntegerGreaterThan(scp-&gt;prefetch.end, readBase))
          readBase = scp-&gt;prefetch.end;
  
      lock_ReleaseMutex(&amp;scp-&gt;mx);
  
      code = cm_CheckFetchRange(scp, &amp;readBase, cm_chunkSize, userp, reqp,
!                               &amp;realBase);
!     if (code) 
          return;	/* can't find something to prefetch */
  
      osi_Log2(afsd_logp, "BKG Prefetch request vp 0x%x, base 0x%x",
***************
*** 595,601 ****
   * is being written out.
   */
  long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
! 	cm_bulkIO_t *biop, cm_user_t *userp, cm_req_t *reqp)
  {
      cm_buf_t *bufp;
      osi_queueData_t *qdp;
--- 600,606 ----
   * is being written out.
   */
  long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
!                        cm_bulkIO_t *biop, cm_user_t *userp, cm_req_t *reqp)
  {
      cm_buf_t *bufp;
      osi_queueData_t *qdp;
***************
*** 608,682 ****
      long code;
      long flags;			/* flags to cm_SyncOp */
          
! 	/* clear things out */
! 	biop-&gt;scp = scp;		/* don't hold */
      biop-&gt;offset = *inOffsetp;
      biop-&gt;length = 0;
      biop-&gt;bufListp = NULL;
      biop-&gt;bufListEndp = NULL;
! 	biop-&gt;reserved = 0;
  
! 	/* reserve a chunk's worth of buffers */
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	buf_ReserveBuffers(cm_chunkSize / buf_bufferSize);
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
  
      bufp = NULL;
!     for(temp = 0; temp &lt; inSize; temp += buf_bufferSize, bufp = NULL) {
! 		thyper.HighPart = 0;
! 		thyper.LowPart = temp;
          tbase = LargeIntegerAdd(*inOffsetp, thyper);
  
          bufp = buf_Find(scp, &amp;tbase);
          if (bufp) {
! 			/* get buffer mutex and scp mutex safely */
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			lock_ObtainMutex(&amp;bufp-&gt;mx);
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 
! 			flags = CM_SCACHESYNC_NEEDCALLBACK
!                         	| CM_SCACHESYNC_GETSTATUS
!                                 | CM_SCACHESYNC_STOREDATA
!                                 | CM_SCACHESYNC_BUFLOCKED;
! 			code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags); 
              if (code) {
! 				lock_ReleaseMutex(&amp;bufp-&gt;mx);
                  buf_Release(bufp);
! 				buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
                  return code;
!             }
                          
! 			/* if the buffer is dirty, we're done */
              if (bufp-&gt;flags &amp; CM_BUF_DIRTY) {
                  osi_assertx(!(bufp-&gt;flags &amp; CM_BUF_WRITING),
                              "WRITING w/o CMSTORING in SetupStoreBIOD");
! 				bufp-&gt;flags |= CM_BUF_WRITING;
! 				break;
              }
  
! 			/* this buffer is clean, so there's no reason to process it */
! 			cm_SyncOpDone(scp, bufp, flags);
! 			lock_ReleaseMutex(&amp;bufp-&gt;mx);
! 			buf_Release(bufp);
!         }
      }
  
! 	biop-&gt;reserved = 1;
          
      /* if we get here, if bufp is null, we didn't find any dirty buffers
! 	 * that weren't already being stored back, so we just quit now.
       */
!         if (!bufp) {
!         	return 0;
! 	}
  
! 	/* don't need buffer mutex any more */
! 	lock_ReleaseMutex(&amp;bufp-&gt;mx);
          
! 	/* put this element in the list */
      qdp = osi_QDAlloc();
      osi_SetQData(qdp, bufp);
! 	/* don't have to hold bufp, since held by buf_Find above */
      osi_QAddH((osi_queue_t **) &amp;biop-&gt;bufListp,
                (osi_queue_t **) &amp;biop-&gt;bufListEndp,
                &amp;qdp-&gt;q);
--- 613,687 ----
      long code;
      long flags;			/* flags to cm_SyncOp */
          
!     /* clear things out */
!     biop-&gt;scp = scp;		/* don't hold */
      biop-&gt;offset = *inOffsetp;
      biop-&gt;length = 0;
      biop-&gt;bufListp = NULL;
      biop-&gt;bufListEndp = NULL;
!     biop-&gt;reserved = 0;
  
!     /* reserve a chunk's worth of buffers */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     buf_ReserveBuffers(cm_chunkSize / buf_bufferSize);
!     lock_ObtainMutex(&amp;scp-&gt;mx);
  
      bufp = NULL;
!     for (temp = 0; temp &lt; inSize; temp += buf_bufferSize, bufp = NULL) {
!         thyper.HighPart = 0;
!         thyper.LowPart = temp;
          tbase = LargeIntegerAdd(*inOffsetp, thyper);
  
          bufp = buf_Find(scp, &amp;tbase);
          if (bufp) {
!             /* get buffer mutex and scp mutex safely */
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             lock_ObtainMutex(&amp;bufp-&gt;mx);
!             lock_ObtainMutex(&amp;scp-&gt;mx);
! 
!             flags = CM_SCACHESYNC_NEEDCALLBACK
!                 | CM_SCACHESYNC_GETSTATUS
!                     | CM_SCACHESYNC_STOREDATA
!                         | CM_SCACHESYNC_BUFLOCKED;
!             code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags); 
              if (code) {
!                 lock_ReleaseMutex(&amp;bufp-&gt;mx);
                  buf_Release(bufp);
!                 buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
                  return code;
!             }   
                          
!             /* if the buffer is dirty, we're done */
              if (bufp-&gt;flags &amp; CM_BUF_DIRTY) {
                  osi_assertx(!(bufp-&gt;flags &amp; CM_BUF_WRITING),
                              "WRITING w/o CMSTORING in SetupStoreBIOD");
!                 bufp-&gt;flags |= CM_BUF_WRITING;
!                 break;
              }
  
!             /* this buffer is clean, so there's no reason to process it */
!             cm_SyncOpDone(scp, bufp, flags);
!             lock_ReleaseMutex(&amp;bufp-&gt;mx);
!             buf_Release(bufp);
!         }       
      }
  
!     biop-&gt;reserved = 1;
          
      /* if we get here, if bufp is null, we didn't find any dirty buffers
!      * that weren't already being stored back, so we just quit now.
       */
!     if (!bufp) {
!         return 0;
!     }
  
!     /* don't need buffer mutex any more */
!     lock_ReleaseMutex(&amp;bufp-&gt;mx);
          
!     /* put this element in the list */
      qdp = osi_QDAlloc();
      osi_SetQData(qdp, bufp);
!     /* don't have to hold bufp, since held by buf_Find above */
      osi_QAddH((osi_queue_t **) &amp;biop-&gt;bufListp,
                (osi_queue_t **) &amp;biop-&gt;bufListEndp,
                &amp;qdp-&gt;q);
***************
*** 684,749 ****
      firstModOffset = bufp-&gt;offset;
      biop-&gt;offset = firstModOffset;
  
! 	/* compute the window surrounding *inOffsetp of size cm_chunkSize */
! 	scanStart = *inOffsetp;
      scanStart.LowPart &amp;= (-cm_chunkSize);
! 	thyper.LowPart = cm_chunkSize;
      thyper.HighPart = 0;
! 	scanEnd = LargeIntegerAdd(scanStart, thyper);
  
! 	flags = CM_SCACHESYNC_NEEDCALLBACK
! 		| CM_SCACHESYNC_GETSTATUS
          | CM_SCACHESYNC_STOREDATA
          | CM_SCACHESYNC_BUFLOCKED
          | CM_SCACHESYNC_NOWAIT;
  
! 	/* start by looking backwards until scanStart */
! 	thyper.HighPart = 0;		/* hyper version of buf_bufferSize */
      thyper.LowPart = buf_bufferSize;
! 	tbase = LargeIntegerSubtract(firstModOffset, thyper);
      while(LargeIntegerGreaterThanOrEqualTo(tbase, scanStart)) {
          /* see if we can find the buffer */
! 		bufp = buf_Find(scp, &amp;tbase);
          if (!bufp) 
              break;
  
! 		/* try to lock it, and quit if we can't (simplifies locking) */
          code = lock_TryMutex(&amp;bufp-&gt;mx);
          if (code == 0) {
! 			buf_Release(bufp);
              break;
          }
                  
          code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags);
          if (code) {
! 			lock_ReleaseMutex(&amp;bufp-&gt;mx);
! 			buf_Release(bufp);
              break;
          }
                  
! 		if (!(bufp-&gt;flags &amp; CM_BUF_DIRTY)) {
! 			/* buffer is clean, so we shouldn't add it */
! 			cm_SyncOpDone(scp, bufp, flags);
! 			lock_ReleaseMutex(&amp;bufp-&gt;mx);
! 			buf_Release(bufp);
              break;
          }
  
! 		/* don't need buffer mutex any more */
! 		lock_ReleaseMutex(&amp;bufp-&gt;mx);
  
          /* we have a dirty buffer ready for storing.  Add it to the tail
           * of the list, since it immediately precedes all of the disk
           * addresses we've already collected.
           */
! 		qdp = osi_QDAlloc();
          osi_SetQData(qdp, bufp);
          /* no buf_hold necessary, since we have it held from buf_Find */
          osi_QAddT((osi_queue_t **) &amp;biop-&gt;bufListp,
                    (osi_queue_t **) &amp;biop-&gt;bufListEndp,
                    &amp;qdp-&gt;q);
  
! 		/* update biod info describing the transfer */
          biop-&gt;offset = LargeIntegerSubtract(biop-&gt;offset, thyper);
          biop-&gt;length += buf_bufferSize;
  
--- 689,754 ----
      firstModOffset = bufp-&gt;offset;
      biop-&gt;offset = firstModOffset;
  
!     /* compute the window surrounding *inOffsetp of size cm_chunkSize */
!     scanStart = *inOffsetp;
      scanStart.LowPart &amp;= (-cm_chunkSize);
!     thyper.LowPart = cm_chunkSize;
      thyper.HighPart = 0;
!     scanEnd = LargeIntegerAdd(scanStart, thyper);
  
!     flags = CM_SCACHESYNC_NEEDCALLBACK
!         | CM_SCACHESYNC_GETSTATUS
          | CM_SCACHESYNC_STOREDATA
          | CM_SCACHESYNC_BUFLOCKED
          | CM_SCACHESYNC_NOWAIT;
  
!     /* start by looking backwards until scanStart */
!     thyper.HighPart = 0;		/* hyper version of buf_bufferSize */
      thyper.LowPart = buf_bufferSize;
!     tbase = LargeIntegerSubtract(firstModOffset, thyper);
      while(LargeIntegerGreaterThanOrEqualTo(tbase, scanStart)) {
          /* see if we can find the buffer */
!         bufp = buf_Find(scp, &amp;tbase);
          if (!bufp) 
              break;
  
!         /* try to lock it, and quit if we can't (simplifies locking) */
          code = lock_TryMutex(&amp;bufp-&gt;mx);
          if (code == 0) {
!             buf_Release(bufp);
              break;
          }
                  
          code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags);
          if (code) {
!             lock_ReleaseMutex(&amp;bufp-&gt;mx);
!             buf_Release(bufp);
              break;
          }
                  
!         if (!(bufp-&gt;flags &amp; CM_BUF_DIRTY)) {
!             /* buffer is clean, so we shouldn't add it */
!             cm_SyncOpDone(scp, bufp, flags);
!             lock_ReleaseMutex(&amp;bufp-&gt;mx);
!             buf_Release(bufp);
              break;
          }
  
!         /* don't need buffer mutex any more */
!         lock_ReleaseMutex(&amp;bufp-&gt;mx);
  
          /* we have a dirty buffer ready for storing.  Add it to the tail
           * of the list, since it immediately precedes all of the disk
           * addresses we've already collected.
           */
!         qdp = osi_QDAlloc();
          osi_SetQData(qdp, bufp);
          /* no buf_hold necessary, since we have it held from buf_Find */
          osi_QAddT((osi_queue_t **) &amp;biop-&gt;bufListp,
                    (osi_queue_t **) &amp;biop-&gt;bufListEndp,
                    &amp;qdp-&gt;q);
  
!         /* update biod info describing the transfer */
          biop-&gt;offset = LargeIntegerSubtract(biop-&gt;offset, thyper);
          biop-&gt;length += buf_bufferSize;
  
***************
*** 751,803 ****
          tbase = LargeIntegerSubtract(tbase, thyper);
      }	/* while loop looking for pages preceding the one we found */
  
! 	/* now, find later dirty, contiguous pages, and add them to the list */
! 	thyper.HighPart = 0;		/* hyper version of buf_bufferSize */
      thyper.LowPart = buf_bufferSize;
! 	tbase = LargeIntegerAdd(firstModOffset, thyper);
      while(LargeIntegerLessThan(tbase, scanEnd)) {
! 		/* see if we can find the buffer */
! 		bufp = buf_Find(scp, &amp;tbase);
          if (!bufp) 
              break;
  
! 		/* try to lock it, and quit if we can't (simplifies locking) */
          code = lock_TryMutex(&amp;bufp-&gt;mx);
          if (code == 0) {
! 			buf_Release(bufp);
              break;
          }
  
          code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags);
          if (code) {
! 			lock_ReleaseMutex(&amp;bufp-&gt;mx);
! 			buf_Release(bufp);
              break;
          }
                  
! 		if (!(bufp-&gt;flags &amp; CM_BUF_DIRTY)) {
! 			/* buffer is clean, so we shouldn't add it */
! 			cm_SyncOpDone(scp, bufp, flags);
! 			lock_ReleaseMutex(&amp;bufp-&gt;mx);
! 			buf_Release(bufp);
              break;
          }
  
! 		/* don't need buffer mutex any more */
! 		lock_ReleaseMutex(&amp;bufp-&gt;mx);
  
          /* we have a dirty buffer ready for storing.  Add it to the head
           * of the list, since it immediately follows all of the disk
           * addresses we've already collected.
           */
! 		qdp = osi_QDAlloc();
          osi_SetQData(qdp, bufp);
          /* no buf_hold necessary, since we have it held from buf_Find */
          osi_QAddH((osi_queue_t **) &amp;biop-&gt;bufListp,
                    (osi_queue_t **) &amp;biop-&gt;bufListEndp,
                    &amp;qdp-&gt;q);
  
! 		/* update biod info describing the transfer */
          biop-&gt;length += buf_bufferSize;
                  
          /* update loop pointer */
--- 756,808 ----
          tbase = LargeIntegerSubtract(tbase, thyper);
      }	/* while loop looking for pages preceding the one we found */
  
!     /* now, find later dirty, contiguous pages, and add them to the list */
!     thyper.HighPart = 0;		/* hyper version of buf_bufferSize */
      thyper.LowPart = buf_bufferSize;
!     tbase = LargeIntegerAdd(firstModOffset, thyper);
      while(LargeIntegerLessThan(tbase, scanEnd)) {
!         /* see if we can find the buffer */
!         bufp = buf_Find(scp, &amp;tbase);
          if (!bufp) 
              break;
  
!         /* try to lock it, and quit if we can't (simplifies locking) */
          code = lock_TryMutex(&amp;bufp-&gt;mx);
          if (code == 0) {
!             buf_Release(bufp);
              break;
          }
  
          code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags);
          if (code) {
!             lock_ReleaseMutex(&amp;bufp-&gt;mx);
!             buf_Release(bufp);
              break;
          }
                  
!         if (!(bufp-&gt;flags &amp; CM_BUF_DIRTY)) {
!             /* buffer is clean, so we shouldn't add it */
!             cm_SyncOpDone(scp, bufp, flags);
!             lock_ReleaseMutex(&amp;bufp-&gt;mx);
!             buf_Release(bufp);
              break;
          }
  
!         /* don't need buffer mutex any more */
!         lock_ReleaseMutex(&amp;bufp-&gt;mx);
  
          /* we have a dirty buffer ready for storing.  Add it to the head
           * of the list, since it immediately follows all of the disk
           * addresses we've already collected.
           */
!         qdp = osi_QDAlloc();
          osi_SetQData(qdp, bufp);
          /* no buf_hold necessary, since we have it held from buf_Find */
          osi_QAddH((osi_queue_t **) &amp;biop-&gt;bufListp,
                    (osi_queue_t **) &amp;biop-&gt;bufListEndp,
                    &amp;qdp-&gt;q);
  
!         /* update biod info describing the transfer */
          biop-&gt;length += buf_bufferSize;
                  
          /* update loop pointer */
***************
*** 816,822 ****
  long cm_SetupFetchBIOD(cm_scache_t *scp, osi_hyper_t *offsetp,
  			cm_bulkIO_t *biop, cm_user_t *up, cm_req_t *reqp)
  {
! 	long code;
      cm_buf_t *tbp;
      osi_hyper_t toffset;		/* a long long temp variable */
      osi_hyper_t pageBase;		/* base offset we're looking at */
--- 821,827 ----
  long cm_SetupFetchBIOD(cm_scache_t *scp, osi_hyper_t *offsetp,
  			cm_bulkIO_t *biop, cm_user_t *up, cm_req_t *reqp)
  {
!     long code;
      cm_buf_t *tbp;
      osi_hyper_t toffset;		/* a long long temp variable */
      osi_hyper_t pageBase;		/* base offset we're looking at */
***************
*** 828,913 ****
      osi_hyper_t fileSize;		/* the # of bytes in the file */
      osi_queueData_t *heldBufListp;	/* we hold all buffers in this list */
      osi_queueData_t *heldBufListEndp;	/* first one */
! 	int reserving;
  
      biop-&gt;scp = scp;
      biop-&gt;offset = *offsetp;
! 	/* null out the list of buffers */
      biop-&gt;bufListp = biop-&gt;bufListEndp = NULL;
! 	biop-&gt;reserved = 0;
  
! 	/* first lookup the file's length, so we know when to stop */
      code = cm_SyncOp(scp, NULL, up, reqp, 0, 
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
      if (code) 
          return code;
          
! 	/* copy out size, since it may change */
      fileSize = scp-&gt;serverLength;
          
      lock_ReleaseMutex(&amp;scp-&gt;mx);
  
! 	pageBase = *offsetp;
      collected = pageBase.LowPart &amp; (cm_chunkSize - 1);
      heldBufListp = NULL;
      heldBufListEndp = NULL;
  
! 	/*
! 	 * Obtaining buffers can cause dirty buffers to be recycled, which
! 	 * can cause a storeback, so cannot be done while we have buffers
! 	 * reserved.
! 	 *
! 	 * To get around this, we get buffers twice.  Before reserving buffers,
! 	 * we obtain and release each one individually.  After reserving
! 	 * buffers, we try to obtain them again, but only by lookup, not by
! 	 * recycling.  If a buffer has gone away while we were waiting for
! 	 * the others, we just use whatever buffers we already have.
! 	 *
! 	 * On entry to this function, we are already holding a buffer, so we
! 	 * can't wait for reservation.  So we call buf_TryReserveBuffers()
! 	 * instead.  Not only that, we can't really even call buf_Get(), for
! 	 * the same reason.  We can't avoid that, though.  To avoid deadlock
! 	 * we allow only one thread to be executing the buf_Get()-buf_Release()
! 	 * sequence at a time.
! 	 */
  
! 	/* first hold all buffers, since we can't hold any locks in buf_Get */
      while (1) {
! 		/* stop at chunk boundary */
! 		if (collected &gt;= cm_chunkSize) break;
                  
          /* see if the next page would be past EOF */
          if (LargeIntegerGreaterThanOrEqualTo(pageBase, fileSize)) break;
  
! 		lock_ObtainMutex(&amp;cm_bufGetMutex);
  
! 		code = buf_Get(scp, &amp;pageBase, &amp;tbp);
          if (code) {
! 			lock_ReleaseMutex(&amp;cm_bufGetMutex);
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 			return code;
! 		}
                  
! 		buf_Release(tbp);
  
! 		lock_ReleaseMutex(&amp;cm_bufGetMutex);
  
          toffset.HighPart = 0;
          toffset.LowPart = buf_bufferSize;
          pageBase = LargeIntegerAdd(toffset, pageBase);
! 		collected += buf_bufferSize;
      }
  
      /* reserve a chunk's worth of buffers if possible */
! 	reserving = buf_TryReserveBuffers(cm_chunkSize / buf_bufferSize);
  
! 	pageBase = *offsetp;
      collected = pageBase.LowPart &amp; (cm_chunkSize - 1);
  
! 	/* now hold all buffers, if they are still there */
      while (1) {
! 		/* stop at chunk boundary */
! 		if (collected &gt;= cm_chunkSize) 
              break;
                  
          /* see if the next page would be past EOF */
--- 833,918 ----
      osi_hyper_t fileSize;		/* the # of bytes in the file */
      osi_queueData_t *heldBufListp;	/* we hold all buffers in this list */
      osi_queueData_t *heldBufListEndp;	/* first one */
!     int reserving;
  
      biop-&gt;scp = scp;
      biop-&gt;offset = *offsetp;
!     /* null out the list of buffers */
      biop-&gt;bufListp = biop-&gt;bufListEndp = NULL;
!     biop-&gt;reserved = 0;
  
!     /* first lookup the file's length, so we know when to stop */
      code = cm_SyncOp(scp, NULL, up, reqp, 0, 
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
      if (code) 
          return code;
          
!     /* copy out size, since it may change */
      fileSize = scp-&gt;serverLength;
          
      lock_ReleaseMutex(&amp;scp-&gt;mx);
  
!     pageBase = *offsetp;
      collected = pageBase.LowPart &amp; (cm_chunkSize - 1);
      heldBufListp = NULL;
      heldBufListEndp = NULL;
  
!     /*
!      * Obtaining buffers can cause dirty buffers to be recycled, which
!      * can cause a storeback, so cannot be done while we have buffers
!      * reserved.
!      *
!      * To get around this, we get buffers twice.  Before reserving buffers,
!      * we obtain and release each one individually.  After reserving
!      * buffers, we try to obtain them again, but only by lookup, not by
!      * recycling.  If a buffer has gone away while we were waiting for
!      * the others, we just use whatever buffers we already have.
!      *
!      * On entry to this function, we are already holding a buffer, so we
!      * can't wait for reservation.  So we call buf_TryReserveBuffers()
!      * instead.  Not only that, we can't really even call buf_Get(), for
!      * the same reason.  We can't avoid that, though.  To avoid deadlock
!      * we allow only one thread to be executing the buf_Get()-buf_Release()
!      * sequence at a time.
!      */
  
!     /* first hold all buffers, since we can't hold any locks in buf_Get */
      while (1) {
!         /* stop at chunk boundary */
!         if (collected &gt;= cm_chunkSize) break;
                  
          /* see if the next page would be past EOF */
          if (LargeIntegerGreaterThanOrEqualTo(pageBase, fileSize)) break;
  
!         lock_ObtainMutex(&amp;cm_bufGetMutex);
  
!         code = buf_Get(scp, &amp;pageBase, &amp;tbp);
          if (code) {
!             lock_ReleaseMutex(&amp;cm_bufGetMutex);
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             return code;
!         }
                  
!         buf_Release(tbp);
  
!         lock_ReleaseMutex(&amp;cm_bufGetMutex);
  
          toffset.HighPart = 0;
          toffset.LowPart = buf_bufferSize;
          pageBase = LargeIntegerAdd(toffset, pageBase);
!         collected += buf_bufferSize;
      }
  
      /* reserve a chunk's worth of buffers if possible */
!     reserving = buf_TryReserveBuffers(cm_chunkSize / buf_bufferSize);
  
!     pageBase = *offsetp;
      collected = pageBase.LowPart &amp; (cm_chunkSize - 1);
  
!     /* now hold all buffers, if they are still there */
      while (1) {
!         /* stop at chunk boundary */
!         if (collected &gt;= cm_chunkSize) 
              break;
                  
          /* see if the next page would be past EOF */
***************
*** 915,931 ****
              break;
  
          tbp = buf_Find(scp, &amp;pageBase);
! 		if (!tbp) 
              break;
  
          /* add the buffer to the list */
! 		qdp = osi_QDAlloc();
          osi_SetQData(qdp, tbp);
          osi_QAdd((osi_queue_t **)&amp;heldBufListp, &amp;qdp-&gt;q);
          if (!heldBufListEndp) heldBufListEndp = qdp;
! 		/* leave tbp held (from buf_Get) */
  
! 		if (!reserving) 
              break;
  
          collected += buf_bufferSize;
--- 920,936 ----
              break;
  
          tbp = buf_Find(scp, &amp;pageBase);
!         if (!tbp) 
              break;
  
          /* add the buffer to the list */
!         qdp = osi_QDAlloc();
          osi_SetQData(qdp, tbp);
          osi_QAdd((osi_queue_t **)&amp;heldBufListp, &amp;qdp-&gt;q);
          if (!heldBufListEndp) heldBufListEndp = qdp;
!         /* leave tbp held (from buf_Get) */
  
!         if (!reserving) 
              break;
  
          collected += buf_bufferSize;
***************
*** 935,1001 ****
      }
  
      /* look at each buffer, adding it into the list if it looks idle and
! 	 * filled with old data.  One special case: wait for idle if it is the
! 	 * first buffer since we really need that one for our caller to make
! 	 * any progress.
       */
      isFirst = 1;
      collected = 0;		/* now count how many we'll really use */
! 	for(tqdp = heldBufListEndp;
          tqdp;
! 	    tqdp = (osi_queueData_t *) osi_QPrev(&amp;tqdp-&gt;q)) {
! 		/* get a ptr to the held buffer */
! 		tbp = osi_GetQData(tqdp);
          pageBase = tbp-&gt;offset;
  
! 		/* now lock the buffer lock */
! 		lock_ObtainMutex(&amp;tbp-&gt;mx);
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
! 
! 		/* don't bother fetching over data that is already current */
! 		if (tbp-&gt;dataVersion == scp-&gt;dataVersion) {
! 			/* we don't need this buffer, since it is current */
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
              lock_ReleaseMutex(&amp;tbp-&gt;mx);
              break;
          }
  
! 		flags = CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_FETCHDATA
!                 	| CM_SCACHESYNC_BUFLOCKED;
! 		if (!isFirst) 
              flags |= CM_SCACHESYNC_NOWAIT;
  
! 		/* wait for the buffer to serialize, if required.  Doesn't
! 		 * release the scp or buffer lock(s) if NOWAIT is specified.
           */
! 		code = cm_SyncOp(scp, tbp, up, reqp, 0, flags);
          if (code) {
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			lock_ReleaseMutex(&amp;tbp-&gt;mx);
              break;
! 		}
                  
! 		/* don't fetch over dirty buffers */
          if (tbp-&gt;flags &amp; CM_BUF_DIRTY) {
! 			cm_SyncOpDone(scp, tbp, flags);
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
              lock_ReleaseMutex(&amp;tbp-&gt;mx);
              break;
! 		}
  
! 		/* Release locks */
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		lock_ReleaseMutex(&amp;tbp-&gt;mx);
  
          /* add the buffer to the list */
! 		qdp = osi_QDAlloc();
          osi_SetQData(qdp, tbp);
          osi_QAdd((osi_queue_t **)&amp;biop-&gt;bufListp, &amp;qdp-&gt;q);
          if (!biop-&gt;bufListEndp) 
              biop-&gt;bufListEndp = qdp;
! 		buf_Hold(tbp);
  
! 		/* from now on, a failure just stops our collection process, but
           * we still do the I/O to whatever we've already managed to collect.
           */
          isFirst = 0;
--- 940,1006 ----
      }
  
      /* look at each buffer, adding it into the list if it looks idle and
!      * filled with old data.  One special case: wait for idle if it is the
!      * first buffer since we really need that one for our caller to make
!      * any progress.
       */
      isFirst = 1;
      collected = 0;		/* now count how many we'll really use */
!     for (tqdp = heldBufListEndp;
          tqdp;
!           tqdp = (osi_queueData_t *) osi_QPrev(&amp;tqdp-&gt;q)) {
!         /* get a ptr to the held buffer */
!         tbp = osi_GetQData(tqdp);
          pageBase = tbp-&gt;offset;
  
!         /* now lock the buffer lock */
!         lock_ObtainMutex(&amp;tbp-&gt;mx);
!         lock_ObtainMutex(&amp;scp-&gt;mx);
! 
!         /* don't bother fetching over data that is already current */
!         if (tbp-&gt;dataVersion == scp-&gt;dataVersion) {
!             /* we don't need this buffer, since it is current */
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
              lock_ReleaseMutex(&amp;tbp-&gt;mx);
              break;
          }
  
!         flags = CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_FETCHDATA
!             | CM_SCACHESYNC_BUFLOCKED;
!         if (!isFirst) 
              flags |= CM_SCACHESYNC_NOWAIT;
  
!         /* wait for the buffer to serialize, if required.  Doesn't
!          * release the scp or buffer lock(s) if NOWAIT is specified.
           */
!         code = cm_SyncOp(scp, tbp, up, reqp, 0, flags);
          if (code) {
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             lock_ReleaseMutex(&amp;tbp-&gt;mx);
              break;
!         }
                  
!         /* don't fetch over dirty buffers */
          if (tbp-&gt;flags &amp; CM_BUF_DIRTY) {
!             cm_SyncOpDone(scp, tbp, flags);
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
              lock_ReleaseMutex(&amp;tbp-&gt;mx);
              break;
!         }
  
!         /* Release locks */
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         lock_ReleaseMutex(&amp;tbp-&gt;mx);
  
          /* add the buffer to the list */
!         qdp = osi_QDAlloc();
          osi_SetQData(qdp, tbp);
          osi_QAdd((osi_queue_t **)&amp;biop-&gt;bufListp, &amp;qdp-&gt;q);
          if (!biop-&gt;bufListEndp) 
              biop-&gt;bufListEndp = qdp;
!         buf_Hold(tbp);
  
!         /* from now on, a failure just stops our collection process, but
           * we still do the I/O to whatever we've already managed to collect.
           */
          isFirst = 0;
***************
*** 1003,1035 ****
      }
          
      /* now, we've held in biop-&gt;bufListp all the buffer's we're really
! 	 * interested in.  We also have holds left from heldBufListp, and we
! 	 * now release those holds on the buffers.
       */
! 	for(qdp = heldBufListp; qdp; qdp = tqdp) {
! 		tqdp = (osi_queueData_t *) osi_QNext(&amp;qdp-&gt;q);
! 		tbp = osi_GetQData(qdp);
          osi_QDFree(qdp);
          buf_Release(tbp);
      }
  
! 	/* Caller expects this */
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
   
! 	/* if we got a failure setting up the first buffer, then we don't have
       * any side effects yet, and we also have failed an operation that the
       * caller requires to make any progress.  Give up now.
       */
      if (code &amp;&amp; isFirst) {
! 		buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
! 		return code;
! 	}
          
      /* otherwise, we're still OK, and should just return the I/O setup we've
       * got.
       */
! 	biop-&gt;length = collected;
! 	biop-&gt;reserved = reserving;
      return 0;
  }
  
--- 1008,1040 ----
      }
          
      /* now, we've held in biop-&gt;bufListp all the buffer's we're really
!      * interested in.  We also have holds left from heldBufListp, and we
!      * now release those holds on the buffers.
       */
!     for (qdp = heldBufListp; qdp; qdp = tqdp) {
!         tqdp = (osi_queueData_t *) osi_QNext(&amp;qdp-&gt;q);
!         tbp = osi_GetQData(qdp);
          osi_QDFree(qdp);
          buf_Release(tbp);
      }
  
!     /* Caller expects this */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
   
!     /* if we got a failure setting up the first buffer, then we don't have
       * any side effects yet, and we also have failed an operation that the
       * caller requires to make any progress.  Give up now.
       */
      if (code &amp;&amp; isFirst) {
!         buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
!         return code;
!     }
          
      /* otherwise, we're still OK, and should just return the I/O setup we've
       * got.
       */
!     biop-&gt;length = collected;
!     biop-&gt;reserved = reserving;
      return 0;
  }
  
***************
*** 1038,1078 ****
   */
  void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore)
  {
! 	cm_scache_t *scp;
      cm_buf_t *bufp;
      osi_queueData_t *qdp;
      osi_queueData_t *nqdp;
      int flags;
  
! 	/* Give back reserved buffers */
! 	if (biop-&gt;reserved)
! 		buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
          
! 	flags = CM_SCACHESYNC_NEEDCALLBACK;
      if (isStore)
          flags |= CM_SCACHESYNC_STOREDATA;
! 	else
! 		flags |= CM_SCACHESYNC_FETCHDATA;
  
! 	scp = biop-&gt;scp;
      for(qdp = biop-&gt;bufListp; qdp; qdp = nqdp) {
! 		/* lookup next guy first, since we're going to free this one */
! 		nqdp = (osi_queueData_t *) osi_QNext(&amp;qdp-&gt;q);
                  
! 		/* extract buffer and free queue data */
          bufp = osi_GetQData(qdp);
          osi_QDFree(qdp);
  
          /* now, mark I/O as done, unlock the buffer and release it */
! 		lock_ObtainMutex(&amp;bufp-&gt;mx);
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
          cm_SyncOpDone(scp, bufp, flags);
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
                  
! 		/* turn off writing and wakeup users */
          if (isStore) {
              if (bufp-&gt;flags &amp; CM_BUF_WAITING) {
! 				osi_Wakeup((long) bufp);
              }
              bufp-&gt;flags &amp;= ~(CM_BUF_WAITING | CM_BUF_WRITING | CM_BUF_DIRTY);
          }
--- 1043,1083 ----
   */
  void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore)
  {
!     cm_scache_t *scp;
      cm_buf_t *bufp;
      osi_queueData_t *qdp;
      osi_queueData_t *nqdp;
      int flags;
  
!     /* Give back reserved buffers */
!     if (biop-&gt;reserved)
!         buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
          
!     flags = CM_SCACHESYNC_NEEDCALLBACK;
      if (isStore)
          flags |= CM_SCACHESYNC_STOREDATA;
!     else
!         flags |= CM_SCACHESYNC_FETCHDATA;
  
!     scp = biop-&gt;scp;
      for(qdp = biop-&gt;bufListp; qdp; qdp = nqdp) {
!         /* lookup next guy first, since we're going to free this one */
!         nqdp = (osi_queueData_t *) osi_QNext(&amp;qdp-&gt;q);
                  
!         /* extract buffer and free queue data */
          bufp = osi_GetQData(qdp);
          osi_QDFree(qdp);
  
          /* now, mark I/O as done, unlock the buffer and release it */
!         lock_ObtainMutex(&amp;bufp-&gt;mx);
!         lock_ObtainMutex(&amp;scp-&gt;mx);
          cm_SyncOpDone(scp, bufp, flags);
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
                  
!         /* turn off writing and wakeup users */
          if (isStore) {
              if (bufp-&gt;flags &amp; CM_BUF_WAITING) {
!                 osi_Wakeup((long) bufp);
              }
              bufp-&gt;flags &amp;= ~(CM_BUF_WAITING | CM_BUF_WRITING | CM_BUF_DIRTY);
          }
***************
*** 1090,1098 ****
   * The scp is locked on return.
   */
  long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
! 	cm_req_t *reqp)
  {
! 	long code;
      long nbytes;			/* bytes in transfer */
      long rbytes;			/* bytes in rx_Read call */
      long temp;
--- 1095,1103 ----
   * The scp is locked on return.
   */
  long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
!                   cm_req_t *reqp)
  {
!     long code;
      long nbytes;			/* bytes in transfer */
      long rbytes;			/* bytes in rx_Read call */
      long temp;
***************
*** 1106,1113 ****
      struct rx_call *callp;
      cm_bulkIO_t biod;		/* bulk IO descriptor */
      cm_conn_t *connp;
! 	int getroot;
! 	long t1, t2;
  
      /* now, the buffer may or may not be filled with good data (buf_GetNew
       * drops lots of locks, and may indeed return a properly initialized
--- 1111,1118 ----
      struct rx_call *callp;
      cm_bulkIO_t biod;		/* bulk IO descriptor */
      cm_conn_t *connp;
!     int getroot;
!     long t1, t2;
  
      /* now, the buffer may or may not be filled with good data (buf_GetNew
       * drops lots of locks, and may indeed return a properly initialized
***************
*** 1116,1160 ****
  
  #ifdef AFS_FREELANCE_CLIENT
  
! 	// yj: if they're trying to get the /afs directory, we need to
! 	// handle it differently, since it's local rather than on any
! 	// server
! 
! 	getroot = (scp==cm_rootSCachep);
! 	if (getroot)
! 		osi_Log1(afsd_logp,"GetBuffer returns cm_rootSCachep=%x",cm_rootSCachep);
  #endif
  
! 	cm_AFSFidFromFid(&amp;tfid, &amp;scp-&gt;fid);
  
! 	code = cm_SetupFetchBIOD(scp, &amp;bufp-&gt;offset, &amp;biod, up, reqp);
! 	if (code) {
! 		/* couldn't even get the first page setup properly */
! 		osi_Log1(afsd_logp, "SetupFetchBIOD failure code %d", code);
          return code;
! 	}
  
      /* once we get here, we have the callback in place, we know that no one
! 	 * is fetching the data now.  Check one last time that we still have
! 	 * the wrong data, and then fetch it if we're still wrong.
! 	 *
       * We can lose a race condition and end up with biod.length zero, in
! 	 * which case we just retry.
       */
      if (bufp-&gt;dataVersion == scp-&gt;dataVersion || biod.length == 0) {
! 		osi_Log3(afsd_logp, "Bad DVs %d, %d or length 0x%x",
                   bufp-&gt;dataVersion, scp-&gt;dataVersion, biod.length);
! 		if ((bufp-&gt;dataVersion == -1
! 		     || bufp-&gt;dataVersion &lt; scp-&gt;dataVersion)
               &amp;&amp; LargeIntegerGreaterThanOrEqualTo(bufp-&gt;offset,
                                                   scp-&gt;serverLength)) {
! 			if (bufp-&gt;dataVersion == -1)
! 				memset(bufp-&gt;datap, 0, buf_bufferSize);
! 			bufp-&gt;dataVersion = scp-&gt;dataVersion;
! 		}
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		cm_ReleaseBIOD(&amp;biod, 0);
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
          return 0;
      }
          
--- 1121,1165 ----
  
  #ifdef AFS_FREELANCE_CLIENT
  
!     // yj: if they're trying to get the /afs directory, we need to
!     // handle it differently, since it's local rather than on any
!     // server
! 
!     getroot = (scp==cm_rootSCachep);
!     if (getroot)
!         osi_Log1(afsd_logp,"GetBuffer returns cm_rootSCachep=%x",cm_rootSCachep);
  #endif
  
!     cm_AFSFidFromFid(&amp;tfid, &amp;scp-&gt;fid);
  
!     code = cm_SetupFetchBIOD(scp, &amp;bufp-&gt;offset, &amp;biod, up, reqp);
!     if (code) {
!         /* couldn't even get the first page setup properly */
!         osi_Log1(afsd_logp, "SetupFetchBIOD failure code %d", code);
          return code;
!     }
  
      /* once we get here, we have the callback in place, we know that no one
!      * is fetching the data now.  Check one last time that we still have
!      * the wrong data, and then fetch it if we're still wrong.
!      *
       * We can lose a race condition and end up with biod.length zero, in
!      * which case we just retry.
       */
      if (bufp-&gt;dataVersion == scp-&gt;dataVersion || biod.length == 0) {
!         osi_Log3(afsd_logp, "Bad DVs %d, %d or length 0x%x",
                   bufp-&gt;dataVersion, scp-&gt;dataVersion, biod.length);
!         if ((bufp-&gt;dataVersion == -1
!              || bufp-&gt;dataVersion &lt; scp-&gt;dataVersion)
               &amp;&amp; LargeIntegerGreaterThanOrEqualTo(bufp-&gt;offset,
                                                   scp-&gt;serverLength)) {
!             if (bufp-&gt;dataVersion == -1)
!                 memset(bufp-&gt;datap, 0, buf_bufferSize);
!             bufp-&gt;dataVersion = scp-&gt;dataVersion;
!         }
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         cm_ReleaseBIOD(&amp;biod, 0);
!         lock_ObtainMutex(&amp;scp-&gt;mx);
          return 0;
      }
          
***************
*** 1167,1366 ****
  
  #ifdef AFS_FREELANCE_CLIENT
  
! 	// yj code
! 	// if getroot then we don't need to make any calls
! 	// just return fake data
  	
! 	 if (cm_freelanceEnabled &amp;&amp; getroot) {
! 		// setup the fake status			
! 		afsStatus.InterfaceVersion = 0x1;
! 		afsStatus.FileType = 0x2;
! 		afsStatus.LinkCount = scp-&gt;linkCount;
! 		afsStatus.Length = cm_fakeDirSize;
! 		afsStatus.DataVersion = cm_fakeDirVersion;
! 		afsStatus.Author = 0x1;
! 		afsStatus.Owner = 0x0;
! 		afsStatus.CallerAccess = 0x9;
! 		afsStatus.AnonymousAccess = 0x9;
! 		afsStatus.UnixModeBits = 0x1ff;
! 		afsStatus.ParentVnode = 0x1;
! 		afsStatus.ParentUnique = 0x1;
! 		afsStatus.ResidencyMask = 0;
! 		afsStatus.ClientModTime = FakeFreelanceModTime;
! 		afsStatus.ServerModTime = FakeFreelanceModTime;
! 		afsStatus.Group = 0;
! 		afsStatus.SyncCounter = 0;
! 		afsStatus.dataVersionHigh = 0;
  	
! 		// once we're done setting up the status info,
! 		// we just fill the buffer pages with fakedata
! 		// from cm_FakeRootDir. Extra pages are set to
! 		// 0. 
  		
! 		lock_ObtainMutex(&amp;cm_Freelance_Lock);
! 		t1 = bufp-&gt;offset.LowPart;
! 		qdp = biod.bufListEndp;
! 		while (qdp) {
! 			tbufp = osi_GetQData(qdp);
! 			bufferp=tbufp-&gt;datap;
! 			memset(bufferp, 0, buf_bufferSize);
! 			t2 = cm_fakeDirSize - t1;
! 			if (t2&gt;buf_bufferSize) t2=buf_bufferSize;
! 			if (t2 &gt; 0) {
! 				memcpy(bufferp, cm_FakeRootDir+t1, t2);
! 			} else {
! 				t2 = 0;
! 			}
! 			t1+=t2;
! 			qdp = (osi_queueData_t *) osi_QPrev(&amp;qdp-&gt;q);
! 			
! 		}
! 		lock_ReleaseMutex(&amp;cm_Freelance_Lock);
  	
! 		// once we're done, we skip over the part of the
! 		// code that does the ACTUAL fetching of data for
! 		// real files
  
! 		goto fetchingcompleted;
! 	}
  
  #endif /* AFS_FREELANCE_CLIENT */
  
  	/* now make the call */
      do {
! 		code = cm_Conn(&amp;scp-&gt;fid, up, reqp, &amp;connp);
          if (code) 
              continue;
  		
! 		callp = rx_NewCall(connp-&gt;callp);
  
! 		osi_Log3(afsd_logp, "CALL FetchData vp %x, off 0x%x, size 0x%x",
!                  (long) scp, biod.offset.LowPart, biod.length);
  
          code = StartRXAFS_FetchData(callp, &amp;tfid, biod.offset.LowPart,
                                      biod.length);
  
! 		/* now copy the data out of the pipe and put it in the buffer */
! 		temp  = rx_Read(callp, (char *)&amp;nbytes, 4);
! 		if (temp == 4) {
! 			nbytes = ntohl(nbytes);
              if (nbytes &gt; biod.length) 
                  code = (callp-&gt;error &lt; 0) ? callp-&gt;error : -1;
          }
          else 
              code = (callp-&gt;error &lt; 0) ? callp-&gt;error : -1;
  
! 		if (code == 0) {
              qdp = biod.bufListEndp;
              if (qdp) {
! 				tbufp = osi_GetQData(qdp);
                  bufferp = tbufp-&gt;datap;
              }
              else 
                  bufferp = NULL;
! 			/* fill nbytes of data from the pipe into the pages.
! 			 * When we stop, qdp will point at the last page we're
! 			 * dealing with, and bufferp will tell us where we
! 			 * stopped.  We'll need this info below when we clear
! 			 * the remainder of the last page out (and potentially
               * clear later pages out, if we fetch past EOF).
               */
!             while(nbytes &gt; 0) {
! 				/* assert that there are still more buffers;
! 				 * our check above for nbytes being less than
! 				 * biod.length should ensure this.
                   */
! 				osi_assert(bufferp != NULL);
  
! 				/* read rbytes of data */
                  rbytes = (nbytes &gt; buf_bufferSize? buf_bufferSize : nbytes);
                  temp = rx_Read(callp, bufferp, rbytes);
                  if (temp &lt; rbytes) {
                      code = (callp-&gt;error &lt; 0) ? callp-&gt;error : -1;
                      break;
! 				}
  
! 				/* allow read-while-fetching.
! 				 * if this is the last buffer, clear the
! 				 * PREFETCHING flag, so the reader waiting for
! 				 * this buffer will start a prefetch.
! 				 */
! 				tbufp-&gt;cmFlags |= CM_BUF_CMFULLYFETCHED;
! 				lock_ObtainMutex(&amp;scp-&gt;mx);
! 				if (scp-&gt;flags &amp; CM_SCACHEFLAG_WAITING) {
! 					scp-&gt;flags &amp;= ~CM_SCACHEFLAG_WAITING;
! 					osi_Wakeup((long) &amp;scp-&gt;flags);
! 				}
! 				if (cpffp &amp;&amp; !*cpffp &amp;&amp; !osi_QPrev(&amp;qdp-&gt;q)) {
! 					*cpffp = 1;
! 					cm_ClearPrefetchFlag(0, scp, &amp;biod.offset);
! 				}
! 				lock_ReleaseMutex(&amp;scp-&gt;mx);
  
! 				/* and adjust counters */
                  nbytes -= temp;
!                                 
                  /* and move to the next buffer */
! 				if (nbytes != 0) {
                      qdp = (osi_queueData_t *) osi_QPrev(&amp;qdp-&gt;q);
                      if (qdp) {
! 						tbufp = osi_GetQData(qdp);
                          bufferp = tbufp-&gt;datap;
                      }
                      else 
                          bufferp = NULL;
! 				} else 
                      bufferp += temp;
              }
  
              /* zero out remainder of last pages, in case we are
! 			 * fetching past EOF.  We were fetching an integral #
! 			 * of pages, but stopped, potentially in the middle of
! 			 * a page.  Zero the remainder of that page, and then
! 			 * all of the rest of the pages.
               */
! 			/* bytes fetched */
              rbytes = bufferp - tbufp-&gt;datap;
! 			/* bytes left to zero */
              rbytes = buf_bufferSize - rbytes;
              while(qdp) {
                  if (rbytes != 0)
! 					memset(bufferp, 0, rbytes);
                  qdp = (osi_queueData_t *) osi_QPrev(&amp;qdp-&gt;q);
! 				if (qdp == NULL) 
                      break;
! 				tbufp = osi_GetQData(qdp);
                  bufferp = tbufp-&gt;datap;
! 				/* bytes to clear in this page */
! 				rbytes = buf_bufferSize;
!             }
! 		}
  
! 		if (code == 0)
! 			code = EndRXAFS_FetchData(callp, &amp;afsStatus, &amp;callback, &amp;volSync);
! 		else
! 			osi_Log0(afsd_logp, "CALL EndRXAFS_FetchData skipped due to error");
          code = rx_EndCall(callp, code);
          if (code == RXKADUNKNOWNKEY)
              osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY");
          osi_Log0(afsd_logp, "CALL FetchData DONE");
  
! 	} while (cm_Analyze(connp, up, reqp, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
  
    fetchingcompleted:
      code = cm_MapRPCError(code, reqp);
  
      lock_ObtainMutex(&amp;scp-&gt;mx);
! 	/* we know that no one else has changed the buffer, since we still have
! 	 * the fetching flag on the buffers, and we have the scp locked again.
! 	 * Copy in the version # into the buffer if we got code 0 back from the
! 	 * read.
       */
! 	if (code == 0) {
! 		for(qdp = biod.bufListp;
! 		    qdp;
! 		    qdp = (osi_queueData_t *) osi_QNext(&amp;qdp-&gt;q)) {
! 			tbufp = osi_GetQData(qdp);
              tbufp-&gt;dataVersion = afsStatus.DataVersion;
  
  #ifdef DISKCACHE95
--- 1172,1373 ----
  
  #ifdef AFS_FREELANCE_CLIENT
  
!     // yj code
!     // if getroot then we don't need to make any calls
!     // just return fake data
  	
!     if (cm_freelanceEnabled &amp;&amp; getroot) {
!         // setup the fake status			
!         afsStatus.InterfaceVersion = 0x1;
!         afsStatus.FileType = 0x2;
!         afsStatus.LinkCount = scp-&gt;linkCount;
!         afsStatus.Length = cm_fakeDirSize;
!         afsStatus.DataVersion = cm_fakeDirVersion;
!         afsStatus.Author = 0x1;
!         afsStatus.Owner = 0x0;
!         afsStatus.CallerAccess = 0x9;
!         afsStatus.AnonymousAccess = 0x9;
!         afsStatus.UnixModeBits = 0x1ff;
!         afsStatus.ParentVnode = 0x1;
!         afsStatus.ParentUnique = 0x1;
!         afsStatus.ResidencyMask = 0;
!         afsStatus.ClientModTime = FakeFreelanceModTime;
!         afsStatus.ServerModTime = FakeFreelanceModTime;
!         afsStatus.Group = 0;
!         afsStatus.SyncCounter = 0;
!         afsStatus.dataVersionHigh = 0;
  	
!         // once we're done setting up the status info,
!         // we just fill the buffer pages with fakedata
!         // from cm_FakeRootDir. Extra pages are set to
!         // 0. 
  		
!         lock_ObtainMutex(&amp;cm_Freelance_Lock);
!         t1 = bufp-&gt;offset.LowPart;
!         qdp = biod.bufListEndp;
!         while (qdp) {
!             tbufp = osi_GetQData(qdp);
!             bufferp=tbufp-&gt;datap;
!             memset(bufferp, 0, buf_bufferSize);
!             t2 = cm_fakeDirSize - t1;
!             if (t2&gt;buf_bufferSize) t2=buf_bufferSize;
!             if (t2 &gt; 0) {
!                 memcpy(bufferp, cm_FakeRootDir+t1, t2);
!             } else {
!                 t2 = 0;
!             }
!             t1+=t2;
!             qdp = (osi_queueData_t *) osi_QPrev(&amp;qdp-&gt;q);
! 
!         }
!         lock_ReleaseMutex(&amp;cm_Freelance_Lock);
  	
!         // once we're done, we skip over the part of the
!         // code that does the ACTUAL fetching of data for
!         // real files
  
!         goto fetchingcompleted;
!     }
  
  #endif /* AFS_FREELANCE_CLIENT */
  
  	/* now make the call */
      do {
!         code = cm_Conn(&amp;scp-&gt;fid, up, reqp, &amp;connp);
          if (code) 
              continue;
  		
!         lock_ObtainMutex(&amp;connp-&gt;mx);
!         callp = rx_NewCall(connp-&gt;callp);
!         lock_ReleaseMutex(&amp;connp-&gt;mx);
  
!         osi_Log3(afsd_logp, "CALL FetchData vp %x, off 0x%x, size 0x%x",
!                   (long) scp, biod.offset.LowPart, biod.length);
  
          code = StartRXAFS_FetchData(callp, &amp;tfid, biod.offset.LowPart,
                                      biod.length);
  
!         /* now copy the data out of the pipe and put it in the buffer */
!         temp  = rx_Read(callp, (char *)&amp;nbytes, 4);
!         if (temp == 4) {
!             nbytes = ntohl(nbytes);
              if (nbytes &gt; biod.length) 
                  code = (callp-&gt;error &lt; 0) ? callp-&gt;error : -1;
          }
          else 
              code = (callp-&gt;error &lt; 0) ? callp-&gt;error : -1;
  
!         if (code == 0) {
              qdp = biod.bufListEndp;
              if (qdp) {
!                 tbufp = osi_GetQData(qdp);
                  bufferp = tbufp-&gt;datap;
              }
              else 
                  bufferp = NULL;
!             /* fill nbytes of data from the pipe into the pages.
!              * When we stop, qdp will point at the last page we're
!              * dealing with, and bufferp will tell us where we
!              * stopped.  We'll need this info below when we clear
!              * the remainder of the last page out (and potentially
               * clear later pages out, if we fetch past EOF).
               */
!             while (nbytes &gt; 0) {
!                 /* assert that there are still more buffers;
!                  * our check above for nbytes being less than
!                  * biod.length should ensure this.
                   */
!                 osi_assert(bufferp != NULL);
  
!                 /* read rbytes of data */
                  rbytes = (nbytes &gt; buf_bufferSize? buf_bufferSize : nbytes);
                  temp = rx_Read(callp, bufferp, rbytes);
                  if (temp &lt; rbytes) {
                      code = (callp-&gt;error &lt; 0) ? callp-&gt;error : -1;
                      break;
!                 }
  
!                 /* allow read-while-fetching.
!                  * if this is the last buffer, clear the
!                  * PREFETCHING flag, so the reader waiting for
!                  * this buffer will start a prefetch.
!                  */
!                 tbufp-&gt;cmFlags |= CM_BUF_CMFULLYFETCHED;
!                 lock_ObtainMutex(&amp;scp-&gt;mx);
!                 if (scp-&gt;flags &amp; CM_SCACHEFLAG_WAITING) {
!                     scp-&gt;flags &amp;= ~CM_SCACHEFLAG_WAITING;
!                     osi_Wakeup((long) &amp;scp-&gt;flags);
!                 }
!                 if (cpffp &amp;&amp; !*cpffp &amp;&amp; !osi_QPrev(&amp;qdp-&gt;q)) {
!                     *cpffp = 1;
!                     cm_ClearPrefetchFlag(0, scp, &amp;biod.offset);
!                 }
!                 lock_ReleaseMutex(&amp;scp-&gt;mx);
  
!                 /* and adjust counters */
                  nbytes -= temp;
! 
                  /* and move to the next buffer */
!                 if (nbytes != 0) {
                      qdp = (osi_queueData_t *) osi_QPrev(&amp;qdp-&gt;q);
                      if (qdp) {
!                         tbufp = osi_GetQData(qdp);
                          bufferp = tbufp-&gt;datap;
                      }
                      else 
                          bufferp = NULL;
!                 } else 
                      bufferp += temp;
              }
  
              /* zero out remainder of last pages, in case we are
!              * fetching past EOF.  We were fetching an integral #
!              * of pages, but stopped, potentially in the middle of
!              * a page.  Zero the remainder of that page, and then
!              * all of the rest of the pages.
               */
!             /* bytes fetched */
              rbytes = bufferp - tbufp-&gt;datap;
!             /* bytes left to zero */
              rbytes = buf_bufferSize - rbytes;
              while(qdp) {
                  if (rbytes != 0)
!                     memset(bufferp, 0, rbytes);
                  qdp = (osi_queueData_t *) osi_QPrev(&amp;qdp-&gt;q);
!                 if (qdp == NULL) 
                      break;
!                 tbufp = osi_GetQData(qdp);
                  bufferp = tbufp-&gt;datap;
!                 /* bytes to clear in this page */
!                 rbytes = buf_bufferSize;
!             }   
!         }
  
!         if (code == 0)
!             code = EndRXAFS_FetchData(callp, &amp;afsStatus, &amp;callback, &amp;volSync);
!         else
!             osi_Log0(afsd_logp, "CALL EndRXAFS_FetchData skipped due to error");
          code = rx_EndCall(callp, code);
          if (code == RXKADUNKNOWNKEY)
              osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY");
          osi_Log0(afsd_logp, "CALL FetchData DONE");
  
!     } while (cm_Analyze(connp, up, reqp, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
  
    fetchingcompleted:
      code = cm_MapRPCError(code, reqp);
  
      lock_ObtainMutex(&amp;scp-&gt;mx);
!     /* we know that no one else has changed the buffer, since we still have
!      * the fetching flag on the buffers, and we have the scp locked again.
!      * Copy in the version # into the buffer if we got code 0 back from the
!      * read.
       */
!     if (code == 0) {
!         for(qdp = biod.bufListp;
!              qdp;
!              qdp = (osi_queueData_t *) osi_QNext(&amp;qdp-&gt;q)) {
!             tbufp = osi_GetQData(qdp);
              tbufp-&gt;dataVersion = afsStatus.DataVersion;
  
  #ifdef DISKCACHE95
***************
*** 1371,1382 ****
          }
      }
  
! 	/* release scatter/gather I/O structure (buffers, locks) */
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	cm_ReleaseBIOD(&amp;biod, 0);
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
  
      if (code == 0) 
          cm_MergeStatus(scp, &amp;afsStatus, &amp;volSync, up, 0);
! 	return code;
  }
--- 1378,1389 ----
          }
      }
  
!     /* release scatter/gather I/O structure (buffers, locks) */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     cm_ReleaseBIOD(&amp;biod, 0);
!     lock_ObtainMutex(&amp;scp-&gt;mx);
  
      if (code == 0) 
          cm_MergeStatus(scp, &amp;afsStatus, &amp;volSync, up, 0);
!     return code;
  }
Index: openafs/src/WINNT/afsd/cm_diskcache95.h
diff -c openafs/src/WINNT/afsd/cm_diskcache95.h:1.1 openafs/src/WINNT/afsd/cm_diskcache95.h:1.1.18.1
*** openafs/src/WINNT/afsd/cm_diskcache95.h:1.1	Mon Apr 30 02:48:04 2001
--- openafs/src/WINNT/afsd/cm_diskcache95.h	Mon Oct 18 00:09:26 2004
***************
*** 51,57 ****
    int openfd;      /* open file descriptor */
    struct cm_diskcache *hash_next;
    struct cm_diskcache *hash_prev;
!   int refCount;
    osi_mutex_t mx;
  } cm_diskcache_t;
  
--- 51,57 ----
    int openfd;      /* open file descriptor */
    struct cm_diskcache *hash_next;
    struct cm_diskcache *hash_prev;
!   unsigned long refCount;
    osi_mutex_t mx;
  } cm_diskcache_t;
  
Index: openafs/src/WINNT/afsd/cm_freelance.c
diff -c openafs/src/WINNT/afsd/cm_freelance.c:1.15.2.1 openafs/src/WINNT/afsd/cm_freelance.c:1.15.2.2
*** openafs/src/WINNT/afsd/cm_freelance.c:1.15.2.1	Tue Aug 17 00:28:39 2004
--- openafs/src/WINNT/afsd/cm_freelance.c	Mon Oct 18 00:09:26 2004
***************
*** 30,36 ****
  osi_mutex_t cm_Freelance_Lock;
  int cm_localMountPointChangeFlag = 0;
  int cm_freelanceEnabled = 0;
! afs_uint32    FakeFreelanceModTime = 0x3b49f6e2;
  
  void cm_InitFakeRootDir();
  
--- 30,36 ----
  osi_mutex_t cm_Freelance_Lock;
  int cm_localMountPointChangeFlag = 0;
  int cm_freelanceEnabled = 0;
! time_t FakeFreelanceModTime = 0x3b49f6e2;
  
  void cm_InitFakeRootDir();
  
***************
*** 81,103 ****
      int lpid;
  #endif
  
! 	lock_InitializeMutex(&amp;cm_Freelance_Lock, "Freelance Lock");
  
! 	// yj: first we make a call to cm_initLocalMountPoints
! 	// to read all the local mount points from an ini file
! 	cm_InitLocalMountPoints();
! 
! 	// then we make a call to InitFakeRootDir to create
! 	// a fake root directory based on the local mount points
! 	cm_InitFakeRootDir();
! 	// --- end of yj code
  
  #if !defined(DJGPP)
      /* Start the registry monitor */
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceChangeNotifier,
                            NULL, 0, &amp;lpid, "cm_FreelanceChangeNotifier");
! 	osi_assert(phandle != NULL);
! 	thrd_CloseHandle(phandle);
  #endif
  }
  
--- 81,103 ----
      int lpid;
  #endif
  
!     lock_InitializeMutex(&amp;cm_Freelance_Lock, "Freelance Lock");
  
!     // yj: first we make a call to cm_initLocalMountPoints
!     // to read all the local mount points from an ini file
!     cm_InitLocalMountPoints();
! 
!     // then we make a call to InitFakeRootDir to create
!     // a fake root directory based on the local mount points
!     cm_InitFakeRootDir();
!     // --- end of yj code
  
  #if !defined(DJGPP)
      /* Start the registry monitor */
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceChangeNotifier,
                            NULL, 0, &amp;lpid, "cm_FreelanceChangeNotifier");
!     osi_assert(phandle != NULL);
!     thrd_CloseHandle(phandle);
  #endif
  }
  
***************
*** 105,290 ****
  /* to be called while holding freelance lock unless during init. */
  void cm_InitFakeRootDir() {
  	
! 	int i, t1, t2;
! 	char* currentPos;
! 	int noChunks;
! 
! 	// allocate space for the fake info
! 	cm_dirHeader_t fakeDirHeader;
! 	cm_dirEntry_t fakeEntry;
! 	cm_pageHeader_t fakePageHeader;
! 
! 	// i'm going to calculate how much space is needed for
! 	// this fake root directory. we have these rules:
! 	// 1. there are cm_noLocalMountPoints number of entries
! 	// 2. each page is CM_DIR_PAGESIZE in size
! 	// 3. the first 13 chunks of the first page are used for
! 	//    some header stuff
! 	// 4. the first chunk of all subsequent pages are used
! 	//    for page header stuff
! 	// 5. a max of CM_DIR_EPP entries are allowed per page
! 	// 6. each entry takes 1 or more chunks, depending on 
! 	//    the size of the mount point string, as determined
! 	//    by cm_NameEntries
! 	// 7. each chunk is CM_DIR_CHUNKSIZE bytes
! 
! 	int CPP = CM_DIR_PAGESIZE / CM_DIR_CHUNKSIZE;
! 	int curChunk = 13;	// chunks 0 - 12 are used for header stuff
! 						// of the first page in the directory
! 	int curPage = 0;
! 	int curDirEntry = 0;
! 	int curDirEntryInPage = 0;
! 	int sizeOfCurEntry;
! 	int dirSize;
! 
! 	/* Reserve 2 directory chunks for "." and ".." */
! 	curChunk += 2;
! 
! 	while (curDirEntry!=cm_noLocalMountPoints) {
! 		sizeOfCurEntry = cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0);
! 		if ((curChunk + sizeOfCurEntry &gt;= CPP) ||
! 			(curDirEntryInPage + 1 &gt;= CM_DIR_EPP)) {
! 			curPage++;
! 			curDirEntryInPage = 0;
! 			curChunk = 1;
! 		}
! 		curChunk += sizeOfCurEntry;
! 		curDirEntry++;
! 		curDirEntryInPage++;
! 	}
! 
! 	dirSize = (curPage+1) *  CM_DIR_PAGESIZE;
! 	cm_FakeRootDir = malloc(dirSize);
! 	cm_fakeDirSize = dirSize;
! 
! 	// yj: when we get here, we've figured out how much memory we need and 
! 	// allocated the appropriate space for it. we now prceed to fill
! 	// it up with entries.
! 	curPage = 0;
! 	curDirEntry = 0;
! 	curDirEntryInPage = 0;
! 	curChunk = 0;
! 	
! 	// fields in the directory entry that are unused.
! 	fakeEntry.flag = 1;
! 	fakeEntry.length = 0;
! 	fakeEntry.next = 0;
! 	fakeEntry.fid.unique = htonl(1);
! 
! 	// the first page is special, it uses fakeDirHeader instead of fakePageHeader
! 	// we fill up the page with dirEntries that belong there and we make changes
! 	// to the fakeDirHeader.header.freeBitmap along the way. Then when we're done
! 	// filling up the dirEntries in this page, we copy the fakeDirHeader into 
! 	// the top of the page.
! 
! 	// init the freeBitmap array
! 	for (i=0; i&lt;8; i++) 
! 		fakeDirHeader.header.freeBitmap[i]=0;
  
! 	fakeDirHeader.header.freeBitmap[0] = 0xff;
! 	fakeDirHeader.header.freeBitmap[1] = 0x7f;
! 	
  
! 	// we start counting at 13 because the 0th to 12th chunks are used for header
! 	curChunk = 13;
  
! 	// stick the first 2 entries "." and ".." in
! 	fakeEntry.fid.unique = htonl(1);
! 	fakeEntry.fid.vnode = htonl(1);
! 	strcpy(fakeEntry.name, ".");
! 	currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
! 	memcpy(currentPos, &amp;fakeEntry, CM_DIR_CHUNKSIZE);
! 	curChunk++; curDirEntryInPage++;
! 	strcpy(fakeEntry.name, "..");
! 	currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
! 	memcpy(currentPos, &amp;fakeEntry, CM_DIR_CHUNKSIZE);
! 	curChunk++; curDirEntryInPage++;
! 
! 	// keep putting stuff into page 0 if
! 	// 1. we're not done with all entries
! 	// 2. we have less than CM_DIR_EPP entries in page 0
! 	// 3. we're not out of chunks in page 0
! 
! 	while( (curDirEntry!=cm_noLocalMountPoints) &amp;&amp; 
! 		   (curDirEntryInPage &lt; CM_DIR_EPP) &amp;&amp;
! 		   (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0) &lt;= CPP)) 
! 	{
! 
! 		noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0);
! 		fakeEntry.fid.vnode = htonl(curDirEntry + 2);
! 		currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
! 
! 		memcpy(currentPos, &amp;fakeEntry, CM_DIR_CHUNKSIZE);
! 		strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)-&gt;namep);
! 		curDirEntry++;
! 		curDirEntryInPage++;
! 		for (i=0; i&lt;noChunks; i++) {
! 			t1 = (curChunk + i) / 8;
! 			t2 = curChunk + i - (t1*8);
! 			fakeDirHeader.header.freeBitmap[t1] |= (1 &lt;&lt; t2);
! 		}
! 		curChunk+=noChunks;
! 	}
! 
! 	// when we get here, we're done with filling in the entries for page 0
! 	// copy in the header info
! 
! 	memcpy(cm_FakeRootDir, &amp;fakeDirHeader, 13 * CM_DIR_CHUNKSIZE);
! 
! 	curPage++;
! 
! 	// ok, page 0's done. Move on to the next page.
! 	while (curDirEntry!=cm_noLocalMountPoints) {
! 		// setup a new page
! 		curChunk = 1;			// the zeroth chunk is reserved for page header
! 		curDirEntryInPage = 0; 
! 		for (i=0; i&lt;8; i++) {
! 			fakePageHeader.freeBitmap[i]=0;
! 		}
! 		fakePageHeader.freeCount = 0;
! 		fakePageHeader.pgcount = 0;
! 		fakePageHeader.tag = htons(1234);
! 		
! 		// while we're on the same page...
! 		while ( (curDirEntry!=cm_noLocalMountPoints) &amp;&amp;
! 				(curDirEntryInPage &lt; CM_DIR_EPP) &amp;&amp;
! 			    (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0) &lt;= CPP))
! 		{
! 			// add an entry to this page
! 
! 			noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0);
! 			fakeEntry.fid.vnode=htonl(curDirEntry+2);
! 			currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
! 			memcpy(currentPos, &amp;fakeEntry, CM_DIR_CHUNKSIZE);
! 			strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)-&gt;namep);
! 			curDirEntry++;
! 			curDirEntryInPage++;
! 			for (i=0; i&lt;noChunks; i++) {
! 				t1 = (curChunk + i) / 8;
! 				t2 = curChunk + i - (t1*8);
! 				fakePageHeader.freeBitmap[t1] |= (1 &lt;&lt; t2);
! 			}
! 			curChunk+=noChunks;
! 		}
! 		memcpy(cm_FakeRootDir + curPage * CM_DIR_PAGESIZE, &amp;fakePageHeader, sizeof(fakePageHeader));
  
! 		curPage++;
! 	}
! 	
! 	// we know the fakeDir is setup properly, so we claim that we have callback
      osi_Log0(afsd_logp,"cm_InitFakeRootDir fakeDirCallback=1");
! 	cm_fakeDirCallback=1;
  
! 	// when we get here, we've set up everything! done!
  }
  
  int cm_FakeRootFid(cm_fid_t *fidp)
  {
!       fidp-&gt;cell = AFS_FAKE_ROOT_CELL_ID;            /* root cell */
!       fidp-&gt;volume = AFS_FAKE_ROOT_VOL_ID;   /* root.afs ? */
!       fidp-&gt;vnode = 0x1;
!       fidp-&gt;unique = 0x1;
!       return 0;
  }
    
  /* called directly from ioctl */
--- 105,290 ----
  /* to be called while holding freelance lock unless during init. */
  void cm_InitFakeRootDir() {
  	
!     int i, t1, t2;
!     char* currentPos;
!     int noChunks;
! 
!     // allocate space for the fake info
!     cm_dirHeader_t fakeDirHeader;
!     cm_dirEntry_t fakeEntry;
!     cm_pageHeader_t fakePageHeader;
! 
!     // i'm going to calculate how much space is needed for
!     // this fake root directory. we have these rules:
!     // 1. there are cm_noLocalMountPoints number of entries
!     // 2. each page is CM_DIR_PAGESIZE in size
!     // 3. the first 13 chunks of the first page are used for
!     //    some header stuff
!     // 4. the first chunk of all subsequent pages are used
!     //    for page header stuff
!     // 5. a max of CM_DIR_EPP entries are allowed per page
!     // 6. each entry takes 1 or more chunks, depending on 
!     //    the size of the mount point string, as determined
!     //    by cm_NameEntries
!     // 7. each chunk is CM_DIR_CHUNKSIZE bytes
! 
!     int CPP = CM_DIR_PAGESIZE / CM_DIR_CHUNKSIZE;
!     int curChunk = 13;	// chunks 0 - 12 are used for header stuff
!                         // of the first page in the directory
!     int curPage = 0;
!     int curDirEntry = 0;
!     int curDirEntryInPage = 0;
!     int sizeOfCurEntry;
!     int dirSize;
! 
!     /* Reserve 2 directory chunks for "." and ".." */
!     curChunk += 2;
! 
!     while (curDirEntry!=cm_noLocalMountPoints) {
!         sizeOfCurEntry = cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0);
!         if ((curChunk + sizeOfCurEntry &gt;= CPP) ||
!              (curDirEntryInPage + 1 &gt;= CM_DIR_EPP)) {
!             curPage++;
!             curDirEntryInPage = 0;
!             curChunk = 1;
!         }
!         curChunk += sizeOfCurEntry;
!         curDirEntry++;
!         curDirEntryInPage++;
!     }
  
!     dirSize = (curPage+1) *  CM_DIR_PAGESIZE;
!     cm_FakeRootDir = malloc(dirSize);
!     cm_fakeDirSize = dirSize;
! 
!     // yj: when we get here, we've figured out how much memory we need and 
!     // allocated the appropriate space for it. we now prceed to fill
!     // it up with entries.
!     curPage = 0;
!     curDirEntry = 0;
!     curDirEntryInPage = 0;
!     curChunk = 0;
! 
!     // fields in the directory entry that are unused.
!     fakeEntry.flag = 1;
!     fakeEntry.length = 0;
!     fakeEntry.next = 0;
!     fakeEntry.fid.unique = htonl(1);
! 
!     // the first page is special, it uses fakeDirHeader instead of fakePageHeader
!     // we fill up the page with dirEntries that belong there and we make changes
!     // to the fakeDirHeader.header.freeBitmap along the way. Then when we're done
!     // filling up the dirEntries in this page, we copy the fakeDirHeader into 
!     // the top of the page.
! 
!     // init the freeBitmap array
!     for (i=0; i&lt;8; i++) 
!         fakeDirHeader.header.freeBitmap[i]=0;
! 
!     fakeDirHeader.header.freeBitmap[0] = 0xff;
!     fakeDirHeader.header.freeBitmap[1] = 0x7f;
! 
! 
!     // we start counting at 13 because the 0th to 12th chunks are used for header
!     curChunk = 13;
! 
!     // stick the first 2 entries "." and ".." in
!     fakeEntry.fid.unique = htonl(1);
!     fakeEntry.fid.vnode = htonl(1);
!     strcpy(fakeEntry.name, ".");
!     currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
!     memcpy(currentPos, &amp;fakeEntry, CM_DIR_CHUNKSIZE);
!     curChunk++; curDirEntryInPage++;
!     strcpy(fakeEntry.name, "..");
!     currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
!     memcpy(currentPos, &amp;fakeEntry, CM_DIR_CHUNKSIZE);
!     curChunk++; curDirEntryInPage++;
! 
!     // keep putting stuff into page 0 if
!     // 1. we're not done with all entries
!     // 2. we have less than CM_DIR_EPP entries in page 0
!     // 3. we're not out of chunks in page 0
! 
!     while( (curDirEntry!=cm_noLocalMountPoints) &amp;&amp; 
!            (curDirEntryInPage &lt; CM_DIR_EPP) &amp;&amp;
!            (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0) &lt;= CPP)) 
!     {       
! 
!         noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0);
!         fakeEntry.fid.vnode = htonl(curDirEntry + 2);
!         currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
! 
!         memcpy(currentPos, &amp;fakeEntry, CM_DIR_CHUNKSIZE);
!         strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)-&gt;namep);
!         curDirEntry++;
!         curDirEntryInPage++;
!         for (i=0; i&lt;noChunks; i++) {
!             t1 = (curChunk + i) / 8;
!             t2 = curChunk + i - (t1*8);
!             fakeDirHeader.header.freeBitmap[t1] |= (1 &lt;&lt; t2);
!         }
!         curChunk+=noChunks;
!     }
  
!     // when we get here, we're done with filling in the entries for page 0
!     // copy in the header info
  
!     memcpy(cm_FakeRootDir, &amp;fakeDirHeader, 13 * CM_DIR_CHUNKSIZE);
  
!     curPage++;
! 
!     // ok, page 0's done. Move on to the next page.
!     while (curDirEntry!=cm_noLocalMountPoints) {
!         // setup a new page
!         curChunk = 1;			// the zeroth chunk is reserved for page header
!         curDirEntryInPage = 0; 
!         for (i=0; i&lt;8; i++) {
!             fakePageHeader.freeBitmap[i]=0;
!         }
!         fakePageHeader.freeCount = 0;
!         fakePageHeader.pgcount = 0;
!         fakePageHeader.tag = htons(1234);
! 
!         // while we're on the same page...
!         while ( (curDirEntry!=cm_noLocalMountPoints) &amp;&amp;
!                 (curDirEntryInPage &lt; CM_DIR_EPP) &amp;&amp;
!                 (curChunk + cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0) &lt;= CPP))
!         {
!             // add an entry to this page
! 
!             noChunks = cm_NameEntries((cm_localMountPoints+curDirEntry)-&gt;namep, 0);
!             fakeEntry.fid.vnode=htonl(curDirEntry+2);
!             currentPos = cm_FakeRootDir + curPage * CM_DIR_PAGESIZE + curChunk * CM_DIR_CHUNKSIZE;
!             memcpy(currentPos, &amp;fakeEntry, CM_DIR_CHUNKSIZE);
!             strcpy(currentPos + 12, (cm_localMountPoints+curDirEntry)-&gt;namep);
!             curDirEntry++;
!             curDirEntryInPage++;
!             for (i=0; i&lt;noChunks; i++) {
!                 t1 = (curChunk + i) / 8;
!                 t2 = curChunk + i - (t1*8);
!                 fakePageHeader.freeBitmap[t1] |= (1 &lt;&lt; t2);
!             }
!             curChunk+=noChunks;
!         }
!         memcpy(cm_FakeRootDir + curPage * CM_DIR_PAGESIZE, &amp;fakePageHeader, sizeof(fakePageHeader));
! 
!         curPage++;
!     }
! 
!     // we know the fakeDir is setup properly, so we claim that we have callback
      osi_Log0(afsd_logp,"cm_InitFakeRootDir fakeDirCallback=1");
!     cm_fakeDirCallback=1;
  
!     // when we get here, we've set up everything! done!
  }
  
  int cm_FakeRootFid(cm_fid_t *fidp)
  {
!     fidp-&gt;cell = AFS_FAKE_ROOT_CELL_ID;            /* root cell */
!     fidp-&gt;volume = AFS_FAKE_ROOT_VOL_ID;   /* root.afs ? */
!     fidp-&gt;vnode = 0x1;
!     fidp-&gt;unique = 0x1;
!     return 0;
  }
    
  /* called directly from ioctl */
***************
*** 307,389 ****
  }
  
  int cm_reInitLocalMountPoints() {
! 	cm_fid_t aFid;
! 	int i, hash;
! 	cm_scache_t *scp, **lscpp, *tscp;
  	
! 	osi_Log0(afsd_logp,"----- freelance reinitialization starts ----- ");
  
! 	// first we invalidate all the SCPs that were created
! 	// for the local mount points
  
! 	osi_Log0(afsd_logp,"Invalidating local mount point scp...  ");
  
! 	aFid.cell = AFS_FAKE_ROOT_CELL_ID;
! 	aFid.volume=AFS_FAKE_ROOT_VOL_ID;
! 	aFid.unique=0x1;
! 	aFid.vnode=0x2;
! 
! 	lock_ObtainWrite(&amp;cm_scacheLock);
! 	lock_ObtainMutex(&amp;cm_Freelance_Lock);  /* always scache then freelance lock */
! 	for (i=0; i&lt;cm_noLocalMountPoints; i++) {
! 		hash = CM_SCACHE_HASH(&amp;aFid);
! 		for (scp=cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
! 			if (scp-&gt;fid.volume == aFid.volume &amp;&amp;
! 				scp-&gt;fid.vnode == aFid.vnode &amp;&amp;
! 				scp-&gt;fid.unique == aFid.unique 
! 				) {
! 
! 				// mark the scp to be reused
! 				lock_ReleaseWrite(&amp;cm_scacheLock);
! 				lock_ObtainMutex(&amp;scp-&gt;mx);
! 				cm_DiscardSCache(scp);
! 				lock_ReleaseMutex(&amp;scp-&gt;mx);
! 				cm_CallbackNotifyChange(scp);
! 				lock_ObtainWrite(&amp;cm_scacheLock);
! 				scp-&gt;refCount--;
! 
! 				// take the scp out of the hash
! 				lscpp = &amp;cm_hashTablep[hash];
! 				for (tscp=*lscpp; tscp; lscpp = &amp;tscp-&gt;nextp, tscp = *lscpp) {
! 					if (tscp == scp) break;
! 				}
! 				*lscpp = scp-&gt;nextp;
! 				scp-&gt;flags &amp;= ~CM_SCACHEFLAG_INHASH;
! 
! 
! 			}
! 		}
! 		aFid.vnode = aFid.vnode + 1;
! 	}
! 	lock_ReleaseWrite(&amp;cm_scacheLock);
! 	osi_Log0(afsd_logp,"\tall old scp cleared!");
! 
! 	// we must free the memory that was allocated in the prev
! 	// cm_InitLocalMountPoints call
! 	osi_Log0(afsd_logp,"Removing old localmountpoints...  ");
! 	free(cm_localMountPoints);
! 	osi_Log0(afsd_logp,"\tall old localmountpoints cleared!");
! 
! 	// now re-init the localmountpoints
! 	osi_Log0(afsd_logp,"Creating new localmountpoints...  ");
! 	cm_InitLocalMountPoints();
! 	osi_Log0(afsd_logp,"\tcreated new set of localmountpoints!");
! 	
! 	
! 	// now we have to free the memory allocated in cm_initfakerootdir
! 	osi_Log0(afsd_logp,"Removing old fakedir...  ");
! 	free(cm_FakeRootDir);
! 	osi_Log0(afsd_logp,"\t\told fakedir removed!");
! 
! 	// then we re-create that dir
! 	osi_Log0(afsd_logp,"Creating new fakedir...  ");
! 	cm_InitFakeRootDir();
! 	osi_Log0(afsd_logp,"\t\tcreated new fakedir!");
  
! 	lock_ReleaseMutex(&amp;cm_Freelance_Lock);
  
! 	osi_Log0(afsd_logp,"----- freelance reinit complete -----");
! 	return 0;
  }
  
  
--- 307,386 ----
  }
  
  int cm_reInitLocalMountPoints() {
!     cm_fid_t aFid;
!     int i, hash;
!     cm_scache_t *scp, **lscpp, *tscp;
  	
!     osi_Log0(afsd_logp,"----- freelance reinitialization starts ----- ");
  
!     // first we invalidate all the SCPs that were created
!     // for the local mount points
  
!     osi_Log0(afsd_logp,"Invalidating local mount point scp...  ");
  
!     aFid.cell = AFS_FAKE_ROOT_CELL_ID;
!     aFid.volume=AFS_FAKE_ROOT_VOL_ID;
!     aFid.unique=0x1;
!     aFid.vnode=0x2;
! 
!     lock_ObtainWrite(&amp;cm_scacheLock);
!     lock_ObtainMutex(&amp;cm_Freelance_Lock);  /* always scache then freelance lock */
!     for (i=0; i&lt;cm_noLocalMountPoints; i++) {
!         hash = CM_SCACHE_HASH(&amp;aFid);
!         for (scp=cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
!             if (scp-&gt;fid.volume == aFid.volume &amp;&amp;
!                  scp-&gt;fid.vnode == aFid.vnode &amp;&amp;
!                  scp-&gt;fid.unique == aFid.unique 
!                  ) {
! 
!                 // mark the scp to be reused
!                 lock_ReleaseWrite(&amp;cm_scacheLock);
!                 lock_ObtainMutex(&amp;scp-&gt;mx);
!                 cm_DiscardSCache(scp);
!                 lock_ReleaseMutex(&amp;scp-&gt;mx);
!                 cm_CallbackNotifyChange(scp);
!                 lock_ObtainWrite(&amp;cm_scacheLock);
!                 scp-&gt;refCount--;
! 
!                 // take the scp out of the hash
!                 lscpp = &amp;cm_hashTablep[hash];
!                 for (tscp=*lscpp; tscp; lscpp = &amp;tscp-&gt;nextp, tscp = *lscpp) {
!                     if (tscp == scp) break;
!                 }
!                 *lscpp = scp-&gt;nextp;
!                 scp-&gt;flags &amp;= ~CM_SCACHEFLAG_INHASH;
!             }
!         }
!         aFid.vnode = aFid.vnode + 1;
!     }
!     lock_ReleaseWrite(&amp;cm_scacheLock);
!     osi_Log0(afsd_logp,"\tall old scp cleared!");
  
!     // we must free the memory that was allocated in the prev
!     // cm_InitLocalMountPoints call
!     osi_Log0(afsd_logp,"Removing old localmountpoints...  ");
!     free(cm_localMountPoints);
!     osi_Log0(afsd_logp,"\tall old localmountpoints cleared!");
! 
!     // now re-init the localmountpoints
!     osi_Log0(afsd_logp,"Creating new localmountpoints...  ");
!     cm_InitLocalMountPoints();
!     osi_Log0(afsd_logp,"\tcreated new set of localmountpoints!");
! 
!     // now we have to free the memory allocated in cm_initfakerootdir
!     osi_Log0(afsd_logp,"Removing old fakedir...  ");
!     free(cm_FakeRootDir);
!     osi_Log0(afsd_logp,"\t\told fakedir removed!");
! 
!     // then we re-create that dir
!     osi_Log0(afsd_logp,"Creating new fakedir...  ");
!     cm_InitFakeRootDir();
!     osi_Log0(afsd_logp,"\t\tcreated new fakedir!");
  
!     lock_ReleaseMutex(&amp;cm_Freelance_Lock);
! 
!     osi_Log0(afsd_logp,"----- freelance reinit complete -----");
!     return 0;
  }
  
  
***************
*** 392,403 ****
  // process for the freelance client.
  /* to be called while holding freelance lock unless during init. */
  long cm_InitLocalMountPoints() {
! 	FILE *fp;
      int i;
! 	char line[512];
! 	char* t;
! 	cm_localMountPoint_t* aLocalMountPoint;
! 	char hdir[120];
      long code;
      char rootCellName[256];
  #if !defined(DJGPP)
--- 389,400 ----
  // process for the freelance client.
  /* to be called while holding freelance lock unless during init. */
  long cm_InitLocalMountPoints() {
!     FILE *fp;
      int i;
!     char line[512];
!     char*t, *t2;
!     cm_localMountPoint_t* aLocalMountPoint;
!     char hdir[120];
      long code;
      char rootCellName[256];
  #if !defined(DJGPP)
***************
*** 465,470 ****
--- 462,472 ----
              RegEnumValue( hkFreelance, dwIndex, szValueName, &amp;dwValueSize, NULL,
                            &amp;dwType, line, &amp;dwSize);
  
+             /* find the trailing dot; null terminate after it */
+             t2 = strrchr(line, '.');
+             if (t2)
+                 *(t2+1) = '\0';
+ 
              // line is not empty, so let's parse it
              t = strchr(line, '#');
              if (!t)
***************
*** 477,488 ****
                  continue;
              }
              aLocalMountPoint-&gt;namep=malloc(t-line+1);
!             memcpy(aLocalMountPoint-&gt;namep, line, t-line);
!             *(aLocalMountPoint-&gt;namep + (t-line)) = 0;
  		
!             aLocalMountPoint-&gt;mountPointStringp=malloc(strlen(line) - (t-line) + 1);
!             memcpy(aLocalMountPoint-&gt;mountPointStringp, t, strlen(line)-(t-line)-2);
!             *(aLocalMountPoint-&gt;mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
      
              osi_Log2(afsd_logp,"found mount point: name %s, string %s",
                        osi_LogSaveString(afsd_logp,aLocalMountPoint-&gt;namep),
--- 479,491 ----
                  continue;
              }
              aLocalMountPoint-&gt;namep=malloc(t-line+1);
!             strncpy(aLocalMountPoint-&gt;namep, line, t-line);
!             aLocalMountPoint-&gt;namep[t-line] = '\0';
  		
!             /* copy the mount point string without the trailing dot */
!             aLocalMountPoint-&gt;mountPointStringp=malloc(strlen(t));
! 			strncpy(aLocalMountPoint-&gt;mountPointStringp, t, strlen(t)-1);
! 			aLocalMountPoint-&gt;mountPointStringp[strlen(t)-1] = '\0';
      
              osi_Log2(afsd_logp,"found mount point: name %s, string %s",
                        osi_LogSaveString(afsd_logp,aLocalMountPoint-&gt;namep),
***************
*** 499,511 ****
      /* What follows is the old code to read freelance mount points 
       * out of a text file modified to copy the data into the registry
       */
! 	cm_GetConfigDir(hdir);
! 	strcat(hdir, AFS_FREELANCE_INI);
! 	// open the ini file for reading
! 	fp = fopen(hdir, "r");
  
! 	// if we fail to open the file, create an empty one
! 	if (!fp) {
          fp = fopen(hdir, "w");
        	code = cm_GetRootCellName(rootCellName);
          if (code == 0) {
--- 502,514 ----
      /* What follows is the old code to read freelance mount points 
       * out of a text file modified to copy the data into the registry
       */
!     cm_GetConfigDir(hdir);
!     strcat(hdir, AFS_FREELANCE_INI);
!     // open the ini file for reading
!     fp = fopen(hdir, "r");
  
!     // if we fail to open the file, create an empty one
!     if (!fp) {
          fp = fopen(hdir, "w");
        	code = cm_GetRootCellName(rootCellName);
          if (code == 0) {
***************
*** 519,528 ****
              fclose(fp);
              return 0;  /* success */
          }
! 	}
  
! 	// we successfully opened the file
! 	osi_Log0(afsd_logp,"opened afs_freelance.ini");
  	
  #if !defined(DJGPP)
      RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
--- 522,531 ----
              fclose(fp);
              return 0;  /* success */
          }
!     }
  
!     // we successfully opened the file
!     osi_Log0(afsd_logp,"opened afs_freelance.ini");
  	
  #if !defined(DJGPP)
      RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
***************
*** 537,577 ****
      dwIndex = 0;
  #endif
  
! 	// now we read the first line to see how many entries
! 	// there are
! 	fgets(line, sizeof(line), fp);
! 
! 	// if the line is empty at any point when we're reading
! 	// we're screwed. report error and return.
! 	if (*line==0) {
! 		afsi_log("error occurred while reading afs_freelance.ini");
! 		fprintf(stderr, "error occurred while reading afs_freelance.ini");
! 		return -1;
! 	}
! 
! 	// get the number of entries there are from the first line
! 	// that we read
! 	cm_noLocalMountPoints = atoi(line);
! 
! 	// create space to store the local mount points
! 	cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
! 	aLocalMountPoint = cm_localMountPoints;
! 		
! 	// now we read n lines and parse them into local mount points
! 	// where n is the number of local mount points there are, as
! 	// determined above.
! 	// Each line in the ini file represents 1 local mount point and 
! 	// is in the format xxx#yyy:zzz, where xxx is the directory
! 	// entry name, yyy is the cell name and zzz is the volume name.
! 	// #yyy:zzz together make up the mount point.
! 	for (i=0; i&lt;cm_noLocalMountPoints; i++) {
! 		fgets(line, sizeof(line), fp);
! 		// check that the line is not empty
! 		if (line[0]==0) {
! 			afsi_log("error occurred while parsing entry in %s: empty line in line %d", AFS_FREELANCE_INI, i);
! 			fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: empty line in line %d", i);
! 			return -1;
! 		}
  
  #if !defined(DJGPP)
          if ( hkFreelance ) {
--- 540,580 ----
      dwIndex = 0;
  #endif
  
!     // now we read the first line to see how many entries
!     // there are
!     fgets(line, sizeof(line), fp);
! 
!     // if the line is empty at any point when we're reading
!     // we're screwed. report error and return.
!     if (*line==0) {
!         afsi_log("error occurred while reading afs_freelance.ini");
!         fprintf(stderr, "error occurred while reading afs_freelance.ini");
!         return -1;
!     }
! 
!     // get the number of entries there are from the first line
!     // that we read
!     cm_noLocalMountPoints = atoi(line);
! 
!     // create space to store the local mount points
!     cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints);
!     aLocalMountPoint = cm_localMountPoints;
! 
!     // now we read n lines and parse them into local mount points
!     // where n is the number of local mount points there are, as
!     // determined above.
!     // Each line in the ini file represents 1 local mount point and 
!     // is in the format xxx#yyy:zzz, where xxx is the directory
!     // entry name, yyy is the cell name and zzz is the volume name.
!     // #yyy:zzz together make up the mount point.
!     for (i=0; i&lt;cm_noLocalMountPoints; i++) {
!         fgets(line, sizeof(line), fp);
!         // check that the line is not empty
!         if (line[0]==0) {
!             afsi_log("error occurred while parsing entry in %s: empty line in line %d", AFS_FREELANCE_INI, i);
!             fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: empty line in line %d", i);
!             return -1;
!         }
  
  #if !defined(DJGPP)
          if ( hkFreelance ) {
***************
*** 584,629 ****
          }
  #endif 
  
! 		// line is not empty, so let's parse it
! 		t = strchr(line, '#');
          if (!t)
              t = strchr(line, '%');
! 		// make sure that there is a '#' or '%' separator in the line
! 		if (!t) {
! 			afsi_log("error occurred while parsing entry in %s: no # or %% separator in line %d", AFS_FREELANCE_INI, i);
! 			fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # or %% separator in line %d", i);
! 			return -1;
! 		}
! 		aLocalMountPoint-&gt;namep=malloc(t-line+1);
! 		memcpy(aLocalMountPoint-&gt;namep, line, t-line);
! 		*(aLocalMountPoint-&gt;namep + (t-line)) = 0;
! 		
          aLocalMountPoint-&gt;mountPointStringp=malloc(strlen(line) - (t-line) + 1);
! 		memcpy(aLocalMountPoint-&gt;mountPointStringp, t, strlen(line)-(t-line)-2);
! 		*(aLocalMountPoint-&gt;mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
!     
          osi_Log2(afsd_logp,"found mount point: name %s, string %s",
                    aLocalMountPoint-&gt;namep,
                    aLocalMountPoint-&gt;mountPointStringp);
  
          aLocalMountPoint++;
! 	}
! 	fclose(fp);
  #if !defined(DJGPP)
      if ( hkFreelance ) {
          RegCloseKey(hkFreelance);
          DeleteFile(hdir);
      }
  #endif
! 	return 0;
  }
  
  int cm_getNoLocalMountPoints() {
! 	return cm_noLocalMountPoints;
  }
  
  cm_localMountPoint_t* cm_getLocalMountPoint(int vnode) {
! 	return 0;
  }
  
  long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp)
--- 587,632 ----
          }
  #endif 
  
!         // line is not empty, so let's parse it
!         t = strchr(line, '#');
          if (!t)
              t = strchr(line, '%');
!         // make sure that there is a '#' or '%' separator in the line
!         if (!t) {
!             afsi_log("error occurred while parsing entry in %s: no # or %% separator in line %d", AFS_FREELANCE_INI, i);
!             fprintf(stderr, "error occurred while parsing entry in afs_freelance.ini: no # or %% separator in line %d", i);
!             return -1;
!         }
!         aLocalMountPoint-&gt;namep=malloc(t-line+1);
!         memcpy(aLocalMountPoint-&gt;namep, line, t-line);
!         *(aLocalMountPoint-&gt;namep + (t-line)) = 0;
! 
          aLocalMountPoint-&gt;mountPointStringp=malloc(strlen(line) - (t-line) + 1);
!         memcpy(aLocalMountPoint-&gt;mountPointStringp, t, strlen(line)-(t-line)-2);
!         *(aLocalMountPoint-&gt;mountPointStringp + (strlen(line)-(t-line)-2)) = 0;
! 
          osi_Log2(afsd_logp,"found mount point: name %s, string %s",
                    aLocalMountPoint-&gt;namep,
                    aLocalMountPoint-&gt;mountPointStringp);
  
          aLocalMountPoint++;
!     }
!     fclose(fp);
  #if !defined(DJGPP)
      if ( hkFreelance ) {
          RegCloseKey(hkFreelance);
          DeleteFile(hdir);
      }
  #endif
!     return 0;
  }
  
  int cm_getNoLocalMountPoints() {
!     return cm_noLocalMountPoints;
  }
  
  cm_localMountPoint_t* cm_getLocalMountPoint(int vnode) {
!     return 0;
  }
  
  long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp)
Index: openafs/src/WINNT/afsd/cm_freelance.h
diff -c openafs/src/WINNT/afsd/cm_freelance.h:1.6 openafs/src/WINNT/afsd/cm_freelance.h:1.6.2.1
*** openafs/src/WINNT/afsd/cm_freelance.h:1.6	Sat Aug  7 01:44:05 2004
--- openafs/src/WINNT/afsd/cm_freelance.h	Mon Oct 18 00:09:26 2004
***************
*** 17,27 ****
  extern long cm_FreelanceRemoveMount(char *toremove);
  extern long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp);
  extern int cm_clearLocalMountPointChange();
! 
  
  #define AFS_FREELANCE_INI "afs_freelance.ini"
  #define AFS_FAKE_ROOT_CELL_ID 0xFFFFFFFF
  #define AFS_FAKE_ROOT_VOL_ID  0xFFFFFFFF
  
! extern afs_uint32 FakeFreelanceModTime;
  #endif // _CM_FREELANCE_H
--- 17,27 ----
  extern long cm_FreelanceRemoveMount(char *toremove);
  extern long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp);
  extern int cm_clearLocalMountPointChange();
! extern int cm_FakeRootFid(cm_fid_t *fidp);
  
  #define AFS_FREELANCE_INI "afs_freelance.ini"
  #define AFS_FAKE_ROOT_CELL_ID 0xFFFFFFFF
  #define AFS_FAKE_ROOT_VOL_ID  0xFFFFFFFF
  
! extern time_t FakeFreelanceModTime;
  #endif // _CM_FREELANCE_H
Index: openafs/src/WINNT/afsd/cm_ioctl.c
diff -c openafs/src/WINNT/afsd/cm_ioctl.c:1.33.2.1 openafs/src/WINNT/afsd/cm_ioctl.c:1.33.2.4
*** openafs/src/WINNT/afsd/cm_ioctl.c:1.33.2.1	Tue Aug 17 00:28:39 2004
--- openafs/src/WINNT/afsd/cm_ioctl.c	Mon Oct 18 00:09:26 2004
***************
*** 39,44 ****
--- 39,45 ----
  #endif
  
  #include "cm_rpc.h"
+ #include &lt;strsafe.h&gt;
  
  #ifdef _DEBUG
  #include &lt;crtdbg.h&gt;
***************
*** 53,79 ****
  extern afs_int32 cryptall;
  extern char cm_NetbiosName[];
  
  void cm_InitIoctl(void)
  {
! 	lock_InitializeMutex(&amp;cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
  }
  
  long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code;
  
! 	lock_ObtainWrite(&amp;scp-&gt;bufCreateLock);
! 	code = buf_FlushCleanPages(scp, userp, reqp);
          
!         lock_ObtainMutex(&amp;scp-&gt;mx);
! 	scp-&gt;cbServerp = NULL;
!         scp-&gt;cbExpires = 0;
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
  
! 	lock_ReleaseWrite(&amp;scp-&gt;bufCreateLock);
! 	cm_dnlcPurgedp(scp);
  
!         return code;
  }
  
  /*
--- 54,82 ----
  extern afs_int32 cryptall;
  extern char cm_NetbiosName[];
  
+ extern void afsi_log(char *pattern, ...);
+ 
  void cm_InitIoctl(void)
  {
!     lock_InitializeMutex(&amp;cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
  }
  
  long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
  
!     lock_ObtainWrite(&amp;scp-&gt;bufCreateLock);
!     code = buf_FlushCleanPages(scp, userp, reqp);
          
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     scp-&gt;cbServerp = NULL;
!     scp-&gt;cbExpires = 0;
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
  
!     lock_ReleaseWrite(&amp;scp-&gt;bufCreateLock);
!     cm_dnlcPurgedp(scp);
  
!     return code;
  }
  
  /*
***************
*** 82,104 ****
   */
  void cm_ResetACLCache(cm_user_t *userp)
  {
! 	cm_scache_t *scp;
! 	int hash;
  
! 	lock_ObtainWrite(&amp;cm_scacheLock);
! 	for (hash=0; hash &lt; cm_hashTableSize; hash++) {
! 		for (scp=cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
! 			scp-&gt;refCount++;
! 			lock_ReleaseWrite(&amp;cm_scacheLock);
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 			cm_InvalidateACLUser(scp, userp);
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			lock_ObtainWrite(&amp;cm_scacheLock);
! 			scp-&gt;refCount--;
! 		}
! 	}
! 	lock_ReleaseWrite(&amp;cm_scacheLock);
! }
  
  /*
   *  TranslateExtendedChars - This is a fix for TR 54482.
--- 85,107 ----
   */
  void cm_ResetACLCache(cm_user_t *userp)
  {
!     cm_scache_t *scp;
!     int hash;
  
!     lock_ObtainWrite(&amp;cm_scacheLock);
!     for (hash=0; hash &lt; cm_hashTableSize; hash++) {
!         for (scp=cm_hashTablep[hash]; scp; scp=scp-&gt;nextp) {
!             scp-&gt;refCount++;
!             lock_ReleaseWrite(&amp;cm_scacheLock);
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             cm_InvalidateACLUser(scp, userp);
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             lock_ObtainWrite(&amp;cm_scacheLock);
!             scp-&gt;refCount--;
!         }
!     }
!     lock_ReleaseWrite(&amp;cm_scacheLock);
! }       
  
  /*
   *  TranslateExtendedChars - This is a fix for TR 54482.
***************
*** 136,143 ****
  long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
  	cm_scache_t **scpp)
  {
! 	long code;
! 	cm_scache_t *substRootp;
      char * relativePath = ioctlp-&gt;inDatap;
  
      /* This is usually the file name, but for StatMountPoint it is the path. */
--- 139,146 ----
  long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
  	cm_scache_t **scpp)
  {
!     long code;
!     cm_scache_t *substRootp;
      char * relativePath = ioctlp-&gt;inDatap;
  
      /* This is usually the file name, but for StatMountPoint it is the path. */
***************
*** 147,153 ****
       *    \\netbios-name\submount\path\.
       *    \\netbios-name\submount\path\file
       */
! 	TranslateExtendedChars(relativePath);
  
      if (relativePath[0] == relativePath[1] &amp;&amp;
           relativePath[1] == '\\' &amp;&amp; 
--- 150,156 ----
       *    \\netbios-name\submount\path\.
       *    \\netbios-name\submount\path\file
       */
!     TranslateExtendedChars(relativePath);
  
      if (relativePath[0] == relativePath[1] &amp;&amp;
           relativePath[1] == '\\' &amp;&amp; 
***************
*** 180,246 ****
                               CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                               userp, sharePath, reqp, &amp;substRootp);
              free(sharePath);
!             if (code) return code;
  
! 			code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                          userp, NULL, reqp, scpp);
! 			if (code) return code;
          } else {
              /* otherwise, treat the name as a cellname mounted off the afs root.
! 			 * This requires that we reconstruct the shareName string with 
! 			 * leading and trailing slashes.
! 			 */
              p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
! 			if ( !_strnicmp("all", p, 3) )
! 				p += 4;
  
- 			shareName[0] = '/';
- 			for (i = 1; *p &amp;&amp; *p != '\\'; i++,p++ ) {
- 				shareName[i] = *p;
- 			}
- 			p++;                    /* skip past trailing slash */
- 			shareName[i++] = '/';	/* add trailing slash */
- 			shareName[i] = 0;       /* terminate string */
  
! 			
! 			code = cm_NameI(cm_rootSCachep, ioctlp-&gt;prefix-&gt;data,
                               CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                               userp, shareName, reqp, &amp;substRootp);
!             if (code) return code;
  
! 			code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                          userp, NULL, reqp, scpp);
! 			if (code) return code;
          }
      } else {
          code = cm_NameI(cm_rootSCachep, ioctlp-&gt;prefix-&gt;data,
                           CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                           userp, ioctlp-&gt;tidPathp, reqp, &amp;substRootp);
!         if (code) return code;
          
          code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                           userp, NULL, reqp, scpp);
!         if (code) return code;
      }
  
! 	/* # of bytes of path */
      code = strlen(ioctlp-&gt;inDatap) + 1;
      ioctlp-&gt;inDatap += code;
  
      /* This is usually nothing, but for StatMountPoint it is the file name. */
      TranslateExtendedChars(ioctlp-&gt;inDatap);
  
! 	/* and return success */
      return 0;
  }
  
  void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
  {
! 	long temp;
          
!         temp = strlen(ioctlp-&gt;inDatap) + 1;
!         ioctlp-&gt;inDatap += temp;
! }
  
  
  /* format the specified path to look like "/afs/&lt;cellname&gt;/usr", by
--- 183,255 ----
                               CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                               userp, sharePath, reqp, &amp;substRootp);
              free(sharePath);
!             if (code) 
!                 return code;
  
!             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                              userp, NULL, reqp, scpp);
!             if (code) 
!                 return code;
          } else {
              /* otherwise, treat the name as a cellname mounted off the afs root.
!              * This requires that we reconstruct the shareName string with 
!              * leading and trailing slashes.
!              */
              p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
!             if ( !_strnicmp("all", p, 3) )
!                 p += 4;
! 
!             shareName[0] = '/';
!             for (i = 1; *p &amp;&amp; *p != '\\'; i++,p++ ) {
!                 shareName[i] = *p;
!             }
!             p++;                    /* skip past trailing slash */
!             shareName[i++] = '/';	/* add trailing slash */
!             shareName[i] = 0;       /* terminate string */
  
  
!             code = cm_NameI(cm_rootSCachep, ioctlp-&gt;prefix-&gt;data,
                               CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                               userp, shareName, reqp, &amp;substRootp);
!             if (code) 
!                 return code;
  
!             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                             userp, NULL, reqp, scpp);
!             if (code) 
!                 return code;
          }
      } else {
          code = cm_NameI(cm_rootSCachep, ioctlp-&gt;prefix-&gt;data,
                           CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                           userp, ioctlp-&gt;tidPathp, reqp, &amp;substRootp);
!         if (code) 
!             return code;
          
          code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                           userp, NULL, reqp, scpp);
!         if (code) 
!             return code;
      }
  
!     /* # of bytes of path */
      code = strlen(ioctlp-&gt;inDatap) + 1;
      ioctlp-&gt;inDatap += code;
  
      /* This is usually nothing, but for StatMountPoint it is the file name. */
      TranslateExtendedChars(ioctlp-&gt;inDatap);
  
!     /* and return success */
      return 0;
  }
  
  void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
  {
!     long temp;
          
!     temp = strlen(ioctlp-&gt;inDatap) + 1;
!     ioctlp-&gt;inDatap += temp;
! }       
  
  
  /* format the specified path to look like "/afs/&lt;cellname&gt;/usr", by
***************
*** 252,284 ****
   */
  void cm_NormalizeAfsPath (char *outpathp, char *inpathp)
  {
! 	char *cp;
      char bslash_mountRoot[256];
         
      strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
      bslash_mountRoot[0] = '\\';
         
      if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
! 		lstrcpy (outpathp, inpathp);
!        else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
! 		lstrcpy (outpathp, inpathp);
! 	else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
!                sprintf (outpathp, "%s%s", cm_mountRoot, inpathp);
! 	else // inpathp looks like "&lt;cell&gt;/usr"
!                sprintf (outpathp, "%s/%s", cm_mountRoot, inpathp);
! 
! 	for (cp = outpathp; *cp != 0; ++cp) {
! 		if (*cp == '\\')
! 			*cp = '/';
! 	}
! 
! 	if (strlen(outpathp) &amp;&amp; (outpathp[strlen(outpathp)-1] == '/')) {
!            outpathp[strlen(outpathp)-1] = 0;
! 	}
  
! 	if (!strcmpi (outpathp, cm_mountRoot)) {
          strcpy (outpathp, cm_mountRoot);
! 	}
  }
  
  /* parse the passed-in file name and do a namei on its parent.  If we fail,
--- 261,293 ----
   */
  void cm_NormalizeAfsPath (char *outpathp, char *inpathp)
  {
!     char *cp;
      char bslash_mountRoot[256];
         
      strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
      bslash_mountRoot[0] = '\\';
         
      if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
!         lstrcpy (outpathp, inpathp);
!     else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
!         lstrcpy (outpathp, inpathp);
!     else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
!         sprintf (outpathp, "%s%s", cm_mountRoot, inpathp);
!     else // inpathp looks like "&lt;cell&gt;/usr"
!         sprintf (outpathp, "%s/%s", cm_mountRoot, inpathp);
! 
!     for (cp = outpathp; *cp != 0; ++cp) {
!         if (*cp == '\\')
!             *cp = '/';
!     }       
  
!     if (strlen(outpathp) &amp;&amp; (outpathp[strlen(outpathp)-1] == '/')) {
!         outpathp[strlen(outpathp)-1] = 0;
!     }
! 
!     if (!strcmpi (outpathp, cm_mountRoot)) {
          strcpy (outpathp, cm_mountRoot);
!     }
  }
  
  /* parse the passed-in file name and do a namei on its parent.  If we fail,
***************
*** 287,314 ****
  long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
  			 cm_scache_t **scpp, char *leafp)
  {
! 	long code;
      char tbuffer[1024];
      char *tp, *jp;
! 	cm_scache_t *substRootp;
  
! 	strcpy(tbuffer, ioctlp-&gt;inDatap);
      tp = strrchr(tbuffer, '\\');
! 	jp = strrchr(tbuffer, '/');
! 	if (!tp)
! 		tp = jp;
! 	else if (jp &amp;&amp; (tp - tbuffer) &lt; (jp - tbuffer))
! 		tp = jp;
      if (!tp) {
          strcpy(tbuffer, "\\");
          if (leafp) 
              strcpy(leafp, ioctlp-&gt;inDatap);
! 	}
      else {
          *tp = 0;
          if (leafp) 
              strcpy(leafp, tp+1);
! 	}   
  
      if (tbuffer[0] == tbuffer[1] &amp;&amp;
          tbuffer[1] == '\\' &amp;&amp; 
--- 296,323 ----
  long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
  			 cm_scache_t **scpp, char *leafp)
  {
!     long code;
      char tbuffer[1024];
      char *tp, *jp;
!     cm_scache_t *substRootp;
  
!     strcpy(tbuffer, ioctlp-&gt;inDatap);
      tp = strrchr(tbuffer, '\\');
!     jp = strrchr(tbuffer, '/');
!     if (!tp)
!         tp = jp;
!     else if (jp &amp;&amp; (tp - tbuffer) &lt; (jp - tbuffer))
!         tp = jp;
      if (!tp) {
          strcpy(tbuffer, "\\");
          if (leafp) 
              strcpy(leafp, ioctlp-&gt;inDatap);
!     }
      else {
          *tp = 0;
          if (leafp) 
              strcpy(leafp, tp+1);
!     }   
  
      if (tbuffer[0] == tbuffer[1] &amp;&amp;
          tbuffer[1] == '\\' &amp;&amp; 
***************
*** 343,1064 ****
              free(sharePath);
              if (code) return code;
  
! 			code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                          userp, NULL, reqp, scpp);
! 			if (code) return code;
          } else {
              /* otherwise, treat the name as a cellname mounted off the afs root.
! 			 * This requires that we reconstruct the shareName string with 
! 			 * leading and trailing slashes.
! 			 */
              p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
! 			if ( !_strnicmp("all", p, 3) )
! 				p += 4;
  
! 			shareName[0] = '/';
! 			for (i = 1; *p &amp;&amp; *p != '\\'; i++,p++ ) {
! 				shareName[i] = *p;
! 			}
! 			p++;                    /* skip past trailing slash */
! 			shareName[i++] = '/';	/* add trailing slash */
! 			shareName[i] = 0;       /* terminate string */
! 			
! 			code = cm_NameI(cm_rootSCachep, ioctlp-&gt;prefix-&gt;data,
                               CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                               userp, shareName, reqp, &amp;substRootp);
              if (code) return code;
  
! 			code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                          userp, NULL, reqp, scpp);
! 			if (code) return code;
          }
      } else {
          code = cm_NameI(cm_rootSCachep, ioctlp-&gt;prefix-&gt;data,
!                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                     userp, ioctlp-&gt;tidPathp, reqp, &amp;substRootp);
          if (code) return code;
  
          code = cm_NameI(substRootp, tbuffer, CM_FLAG_FOLLOW,
!                     userp, NULL, reqp, scpp);
          if (code) return code;
      }
  
! 	/* # of bytes of path */
!         code = strlen(ioctlp-&gt;inDatap) + 1;
!         ioctlp-&gt;inDatap += code;
  
! 	/* and return success */
!         return 0;
  }
  
  long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
! 	cm_conn_t *connp;
!         cm_scache_t *scp;
!         AFSOpaque acl;
!         AFSFetchStatus fileStatus;
!         AFSVolSync volSync;
!         long code;
!         AFSFid fid;
!         int tlen;
! 	cm_req_t req;
  
!         cm_InitReq(&amp;req);
  
!         code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!         if (code) return code;
! 	
! 	/* now make the get acl call */
! 	fid.Volume = scp-&gt;fid.volume;
!         fid.Vnode = scp-&gt;fid.vnode;
!         fid.Unique = scp-&gt;fid.unique;
! 	do {
! 	        acl.AFSOpaque_val = ioctlp-&gt;outDatap;
! 	        acl.AFSOpaque_len = 0;
! 		code = cm_Conn(&amp;scp-&gt;fid, userp, &amp;req, &amp;connp);
!                 if (code) continue;
!                 
!                 code = RXAFS_FetchACL(connp-&gt;callp, &amp;fid, &amp;acl, &amp;fileStatus, &amp;volSync);
! 	} while (cm_Analyze(connp, userp, &amp;req, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
! 	code = cm_MapRPCError(code, &amp;req);
! 	cm_ReleaseSCache(scp);
!         
!         if (code) return code;
!         
! 	/* skip over return data */
!         tlen = strlen(ioctlp-&gt;outDatap) + 1;
!         ioctlp-&gt;outDatap += tlen;
  
! 	/* and return success */
!         return 0;
  }
  
  long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long code;
!         cm_scache_t *scp;
!         cm_cell_t *cellp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
!         code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!         if (code) return code;
!         
!         cellp = cm_FindCellByID(scp-&gt;fid.cell);
!         if (cellp) {
! 		strcpy(ioctlp-&gt;outDatap, cellp-&gt;namep);
!                 ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) + 1;
!                 code = 0;
!         }
!         else code = CM_ERROR_NOSUCHCELL;
!         
!         cm_ReleaseSCache(scp);
!         return code;
  }
  
  long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	cm_conn_t *connp;
!         cm_scache_t *scp;
!         AFSOpaque acl;
!         AFSFetchStatus fileStatus;
!         AFSVolSync volSync;
!         long code;
!         AFSFid fid;
! 	cm_req_t req;
  
!         cm_InitReq(&amp;req);
  
!         code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!         if (code) return code;
  	
! 	/* now make the get acl call */
! 	fid.Volume = scp-&gt;fid.volume;
!         fid.Vnode = scp-&gt;fid.vnode;
!         fid.Unique = scp-&gt;fid.unique;
! 	do {
! 	        acl.AFSOpaque_val = ioctlp-&gt;inDatap;
! 	        acl.AFSOpaque_len = strlen(ioctlp-&gt;inDatap)+1;
! 		code = cm_Conn(&amp;scp-&gt;fid, userp, &amp;req, &amp;connp);
!                 if (code) continue;
!                 
!                 code = RXAFS_StoreACL(connp-&gt;callp, &amp;fid, &amp;acl, &amp;fileStatus, &amp;volSync);
! 	} while (cm_Analyze(connp, userp, &amp;req, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
! 	code = cm_MapRPCError(code, &amp;req);
! 
! 	/* invalidate cache info, since we just trashed the ACL cache */
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
!         cm_DiscardSCache(scp);
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
  
! 	cm_ReleaseSCache(scp);
!         
!         return code;
  }
  
  long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long code;
!         cm_scache_t *scp;
!         unsigned long volume;
!         int i;
! 	cm_req_t req;
  
!         cm_InitReq(&amp;req);
  
!         code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!         if (code) return code;
          
! 	volume = scp-&gt;fid.volume;
!         cm_ReleaseSCache(scp);
  
! 	lock_ObtainWrite(&amp;cm_scacheLock);
! 	for(i=0; i&lt;cm_hashTableSize; i++) {
! 		for(scp = cm_hashTablep[i]; scp; scp = scp-&gt;nextp) {
! 			if (scp-&gt;fid.volume == volume) {
! 				scp-&gt;refCount++;
!                                 lock_ReleaseWrite(&amp;cm_scacheLock);
! 
! 				/* now flush the file */
! 				cm_FlushFile(scp, userp, &amp;req);
! 
!                                 lock_ObtainWrite(&amp;cm_scacheLock);
!                                 scp-&gt;refCount--;
!                         }
!                 }
          }
! 	lock_ReleaseWrite(&amp;cm_scacheLock);
  
!         return code;
  }
  
  long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long code;
!         cm_scache_t *scp;
! 	cm_req_t req;
  
!         cm_InitReq(&amp;req);
  
!         code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!         if (code) return code;
          
! 	cm_FlushFile(scp, userp, &amp;req);
!         cm_ReleaseSCache(scp);
  
!         return 0;
  }
  
  long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	cm_scache_t *scp;
! 	char volName[32];
! 	char offLineMsg[256];
! 	char motd[256];
! 	cm_conn_t *tcp;
! 	long code;
! 	AFSFetchVolumeStatus volStat;
! 	AFSStoreVolumeStatus storeStat;
! 	cm_volume_t *tvp;
! 	char *cp;
!         cm_cell_t *cellp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
! 	code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!         if (code) return code;
  
! 	cellp = cm_FindCellByID(scp-&gt;fid.cell);
!         osi_assert(cellp);
  
! 	if (scp-&gt;flags &amp; CM_SCACHEFLAG_RO) {
!         	cm_ReleaseSCache(scp);
!         	return CM_ERROR_READONLY;
! 	}
  
! 	code = cm_GetVolumeByID(cellp, scp-&gt;fid.volume, userp, &amp;req, &amp;tvp);
!         if (code) {
! 		cm_ReleaseSCache(scp);
!         	return code;
! 	}
! 
! 	/* Copy the junk out, using cp as a roving pointer. */
! 	cp = ioctlp-&gt;inDatap;
! 	memcpy((char *)&amp;volStat, cp, sizeof(AFSFetchVolumeStatus));
! 	cp += sizeof(AFSFetchVolumeStatus);
! 	strcpy(volName, cp);
! 	cp += strlen(volName)+1;
! 	strcpy(offLineMsg, cp);
! 	cp +=  strlen(offLineMsg)+1;
! 	strcpy(motd, cp);
! 	storeStat.Mask = 0;
! 	if (volStat.MinQuota != -1) {
! 		storeStat.MinQuota = volStat.MinQuota;
! 		storeStat.Mask |= AFS_SETMINQUOTA;
! 	}
! 	if (volStat.MaxQuota != -1) {
! 		storeStat.MaxQuota = volStat.MaxQuota;
! 		storeStat.Mask |= AFS_SETMAXQUOTA;
! 	}
! 
! 	do {
! 		code = cm_Conn(&amp;scp-&gt;fid, userp, &amp;req, &amp;tcp);
! 		if (code) continue;
! 
! 		code = RXAFS_SetVolumeStatus(tcp-&gt;callp, scp-&gt;fid.volume,
! 			&amp;storeStat, volName, offLineMsg, motd);
! 	} while (cm_Analyze(tcp, userp, &amp;req, &amp;scp-&gt;fid, NULL, NULL, NULL, code));
! 	code = cm_MapRPCError(code, &amp;req);
! 
! 	/* return on failure */
! 	cm_ReleaseSCache(scp);
! 	if (code) {
!         	return code;
! 	}
! 
! 	/* we are sending parms back to make compat. with prev system.  should
! 	 * change interface later to not ask for current status, just set
!          * new status
!          */
! 	cp = ioctlp-&gt;outDatap;
! 	memcpy(cp, (char *)&amp;volStat, sizeof(VolumeStatus));
! 	cp += sizeof(VolumeStatus);
! 	strcpy(cp, volName);
! 	cp += strlen(volName)+1;
! 	strcpy(cp, offLineMsg);
! 	cp += strlen(offLineMsg)+1;
! 	strcpy(cp, motd);
! 	cp += strlen(motd)+1;
  
! 	/* now return updated return data pointer */
! 	ioctlp-&gt;outDatap = cp;
  
! 	return 0;
! }
  
  long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	char volName[32];
!         cm_scache_t *scp;
! 	char offLineMsg[256];
! 	char motd[256];
! 	cm_conn_t *tcp;
! 	register long code;
! 	AFSFetchVolumeStatus volStat;
! 	register char *cp;
! 	char *Name;
!         char *OfflineMsg;
!         char *MOTD;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
! 	code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!         if (code) return code;
  
! 	Name = volName;
! 	OfflineMsg = offLineMsg;
! 	MOTD = motd;
! 	do {
! 		code = cm_Conn(&amp;scp-&gt;fid, userp, &amp;req, &amp;tcp);
!                 if (code) continue;
! 
! 		code = RXAFS_GetVolumeStatus(tcp-&gt;callp, scp-&gt;fid.volume,
! 			&amp;volStat, &amp;Name, &amp;OfflineMsg, &amp;MOTD);
! 	} while (cm_Analyze(tcp, userp, &amp;req, &amp;scp-&gt;fid, NULL, NULL, NULL, code));
! 	code = cm_MapRPCError(code, &amp;req);
! 
! 	cm_ReleaseSCache(scp);
! 	if (code) return code;
! 
!         /* Copy all this junk into msg-&gt;im_data, keeping track of the lengths. */
! 	cp = ioctlp-&gt;outDatap;
! 	memcpy(cp, (char *)&amp;volStat, sizeof(AFSFetchVolumeStatus));
! 	cp += sizeof(AFSFetchVolumeStatus);
! 	strcpy(cp, volName);
! 	cp += strlen(volName)+1;
! 	strcpy(cp, offLineMsg);
! 	cp += strlen(offLineMsg)+1;
! 	strcpy(cp, motd);
! 	cp += strlen(motd)+1;
  
! 	/* return new size */
! 	ioctlp-&gt;outDatap = cp;
  
! 	return 0;
  }
  
  long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long code;
      cm_scache_t *scp;
      cm_cell_t *cellp;
      cm_volume_t *tvp;
! 	cm_serverRef_t **tsrpp, *current;
      cm_server_t *tsp;
      unsigned long volume;
      char *cp;
      cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
      if (code) return code;
          
! 	volume = scp-&gt;fid.volume;
  
! 	cellp = cm_FindCellByID(scp-&gt;fid.cell);
      osi_assert(cellp);
  
      cm_ReleaseSCache(scp);
  
! 	code = cm_GetVolumeByID(cellp, volume, userp, &amp;req, &amp;tvp);
      if (code) return code;
  	
      cp = ioctlp-&gt;outDatap;
          
! 	lock_ObtainMutex(&amp;tvp-&gt;mx);
! 	tsrpp = cm_GetVolServers(tvp, volume);
! 	lock_ObtainRead(&amp;cm_serverLock);
! 	for (current = *tsrpp; current; current = current-&gt;next) {
! 		tsp = current-&gt;server;
! 		memcpy(cp, (char *)&amp;tsp-&gt;addr.sin_addr.s_addr, sizeof(long));
! 		cp += sizeof(long);
! 	}
! 	lock_ReleaseRead(&amp;cm_serverLock);
      cm_FreeServerList(tsrpp);
      lock_ReleaseMutex(&amp;tvp-&gt;mx);
  
! 	/* still room for terminating NULL, add it on */
! 	volume = 0;	/* reuse vbl */
! 	memcpy(cp, (char *)&amp;volume, sizeof(long));
! 	cp += sizeof(long);
! 
! 	ioctlp-&gt;outDatap = cp;
! 	cm_PutVolume(tvp);
! 	return 0;
! }
  
  long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long code;
!         cm_scache_t *dscp;
!         cm_scache_t *scp;
!         char *cp;
!         cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
!         code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
!         if (code) return code;
!         
! 	cp = ioctlp-&gt;inDatap;
  
! 	code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
! 	cm_ReleaseSCache(dscp);
!         if (code) return code;
          
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
  
!         /* now check that this is a real mount point */
!         if (scp-&gt;fileType != CM_SCACHETYPE_MOUNTPOINT) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
!         	cm_ReleaseSCache(scp);
!                 return CM_ERROR_INVAL;
!         }
! 	
!         code = cm_ReadMountPoint(scp, userp, &amp;req);
!         if (code == 0) {
! 		cp = ioctlp-&gt;outDatap;
!                 strcpy(cp, scp-&gt;mountPointStringp);
!                 cp += strlen(cp) + 1;
!                 ioctlp-&gt;outDatap = cp;
!         }
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
  
! 	return code;
! }
  
  long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long code;
!         cm_scache_t *dscp;
!         cm_scache_t *scp;
!         char *cp;
!         cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
!         code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
!         if (code) return code;
!         
! 	cp = ioctlp-&gt;inDatap;
  
! 	code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
          
! 	/* if something went wrong, bail out now */
!         if (code) {
! 		goto done;
! 	}
          
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
!         code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!         	CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!         if (code) {
!         	lock_ReleaseMutex(&amp;scp-&gt;mx);
!         	cm_ReleaseSCache(scp);
! 		goto done;
! 	}
! 	
!         /* now check that this is a real mount point */
!         if (scp-&gt;fileType != CM_SCACHETYPE_MOUNTPOINT) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
!         	cm_ReleaseSCache(scp);
!                 code = CM_ERROR_INVAL;
!                 goto done;
!         }
! 	
!         /* time to make the RPC, so drop the lock */
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
!         
! 	/* easier to do it this way */
!         code = cm_Unlink(dscp, cp, userp, &amp;req);
! 	if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 		smb_NotifyChange(FILE_ACTION_REMOVED,
! 				 FILE_NOTIFY_CHANGE_DIR_NAME,
! 				 dscp, cp, NULL, TRUE);
! 
! done:
! 	cm_ReleaseSCache(dscp);
! 	return code;
  }
  
  long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	cm_cell_t *cellp;
!         chservinfo_t csi;
!         char *tp;
!         char *cp;
!         long temp;
!         cm_server_t *tsp;
!         int haveCell;
!         
! 	cm_SkipIoctlPath(ioctlp);	/* we don't care about the path */
! 	tp = ioctlp-&gt;inDatap;
!         haveCell = 0;
! 
! 	memcpy(&amp;temp, tp, sizeof(temp));
! 	if (temp == 0x12345678) {	/* For afs3.3 version */
!                 memcpy(&amp;csi, tp, sizeof(csi));
! 		if (csi.tinterval &gt;= 0) {
! 			cp = ioctlp-&gt;outDatap;
! 			memcpy(cp, (char *)&amp;cm_daemonCheckInterval, sizeof(long));
! 			ioctlp-&gt;outDatap += sizeof(long);
! 			if (csi.tinterval &gt; 0) {
! 				if (!smb_SUser(userp))
! 					return CM_ERROR_NOACCESS;
! 				cm_daemonCheckInterval = csi.tinterval;
! 			}
! 			return 0;
! 		}
! 		if (csi.tsize)
! 			haveCell = 1;
! 		temp = csi.tflags;
! 		cp = csi.tbuffer;
! 	} else {	/* For pre afs3.3 versions */
! 		memcpy((char *)&amp;temp, ioctlp-&gt;inDatap, sizeof(long));
! 		ioctlp-&gt;inDatap = cp = ioctlp-&gt;inDatap + sizeof(long);
! 		if (cp - ioctlp-&gt;inAllocp &lt; ioctlp-&gt;inCopied)	/* still more data available */
! 			haveCell = 1;
! 	}
! 
! 	/* 
! 	 * 1: fast check, don't contact servers.
! 	 * 2: local cell only.
! 	 */
! 	if (haveCell) {
! 		/* have cell name, too */
! 		cellp = cm_GetCell(cp, 0);
! 		if (!cellp) return CM_ERROR_NOSUCHCELL;
! 	}
! 	else cellp = (cm_cell_t *) 0;
! 	if (!cellp &amp;&amp; (temp &amp; 2)) {
! 		/* use local cell */
! 		cellp = cm_FindCellByID(1);
! 	}
! 	if (!(temp &amp; 1)) {	/* if not fast, call server checker routine */
! 		/* check down servers */
! 		cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
!                 	cellp);
! 	}
! 
! 	/* now return the current down server list */
! 	cp = ioctlp-&gt;outDatap;
! 	lock_ObtainRead(&amp;cm_serverLock);
! 	for(tsp = cm_allServersp; tsp; tsp=tsp-&gt;allNextp) {
! 		if (cellp &amp;&amp; tsp-&gt;cellp != cellp) continue;	/* cell spec'd and wrong */
! 		if ((tsp-&gt;flags &amp; CM_SERVERFLAG_DOWN)
!                 	&amp;&amp; tsp-&gt;type == CM_SERVER_FILE) {
! 			memcpy(cp, (char *)&amp;tsp-&gt;addr.sin_addr.s_addr, sizeof(long));
! 			cp += sizeof(long);
! 		}
! 	}
! 	lock_ReleaseRead(&amp;cm_serverLock);
  
! 	ioctlp-&gt;outDatap = cp;
! 	return 0;
  }
  
  long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	/* we don't print anything superfluous, so we don't support the gag call */
! 	return CM_ERROR_INVAL;
  }
  
  long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	cm_CheckVolumes();
! 	return 0;
! }
  
  long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long temp;
!         long code;
!         
! 	cm_SkipIoctlPath(ioctlp);
  
!         memcpy(&amp;temp, ioctlp-&gt;inDatap, sizeof(temp));
!         if (temp == 0) temp = buf_nOrigBuffers;
!         else {
! 		/* temp is in 1K units, convert to # of buffers */
!                 temp = temp / (buf_bufferSize / 1024);
!         }
  
! 	/* now adjust the cache size */
!         code = buf_SetNBuffers(temp);
  
! 	return code;
  }
  
  long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!         long inValue;
          
!         cm_SkipIoctlPath(ioctlp);
          
!         memcpy(&amp;inValue, ioctlp-&gt;inDatap, sizeof(long));
  
! 	/* print trace */
! 	if (inValue &amp; 8) {
! 		afsd_ForceTrace(FALSE);
! 	}
!         
!         if (inValue &amp; 2) {
!         	/* set tracing value to low order bit */
!         	if ((inValue &amp; 1) == 0) {
! 			/* disable tracing */
! 	                osi_LogDisable(afsd_logp);
! 	        }
! 	        else {
! 			/* enable tracing */
! 	        	osi_LogEnable(afsd_logp);
! 		}
! 	}
! 
! 	/* see if we're supposed to do a reset, too */
!         if (inValue &amp; 4) {
!         	osi_LogReset(afsd_logp);
! 	}
! 
!         /* and copy out tracing flag */
!         inValue = afsd_logp-&gt;enabled;	/* use as a temp vbl */
!         memcpy(ioctlp-&gt;outDatap, &amp;inValue, sizeof(long));
!         ioctlp-&gt;outDatap += sizeof(long);
!         return 0;
! }
  
  long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	cm_cacheParms_t parms;
!         
!         memset(&amp;parms, 0, sizeof(parms));
  
! 	/* first we get, in 1K units, the cache size */
!         parms.parms[0] = buf_nbuffers * (buf_bufferSize / 1024);
!         
!         /* and then the actual # of buffers in use (not in the free list, I guess,
!          * will be what we do).
!          */
!         parms.parms[1] = (buf_nbuffers - buf_CountFreeList()) * (buf_bufferSize / 1024);
!         
!         memcpy(ioctlp-&gt;outDatap, &amp;parms, sizeof(parms));
!         ioctlp-&gt;outDatap += sizeof(parms);
  
! 	return 0;
  }
  
  long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long whichCell;
      long magic = 0;
! 	cm_cell_t *tcellp;
! 	cm_serverRef_t *serverRefp;
      cm_server_t *serverp;
! 	long i;
      char *cp;
      char *tp;
      char *basep;
  
! 	cm_SkipIoctlPath(ioctlp);
  
! 	tp = ioctlp-&gt;inDatap;
  
! 	memcpy((char *)&amp;whichCell, tp, sizeof(long));
! 	tp += sizeof(long);
! 	
! 	/* see if more than one long passed in, ignoring the null pathname (the -1) */
! 	if (ioctlp-&gt;inCopied-1 &gt; sizeof(long)) {
! 		memcpy((char *)&amp;magic, tp, sizeof(long));
! 	}
  
      lock_ObtainRead(&amp;cm_cellLock);
! 	for(tcellp = cm_allCellsp; tcellp; tcellp = tcellp-&gt;nextp) {
! 		if (whichCell == 0) break;
! 		whichCell--;
! 	}
! 	lock_ReleaseRead(&amp;cm_cellLock);
! 	if (tcellp) {
! 		int max = 8;
! 
! 		cp = ioctlp-&gt;outDatap;
! 
! 		if (magic == 0x12345678) {
! 			memcpy(cp, (char *)&amp;magic, sizeof(long));
! 			max = 13;
! 		}
! 		memset(cp, 0, max * sizeof(long));
          basep = cp;
! 		lock_ObtainRead(&amp;cm_serverLock);	/* for going down server list */
          /* jaltman - do the reference counts to serverRefp contents need to be increased? */
! 		serverRefp = tcellp-&gt;vlServersp;
! 		for(i=0; i&lt;max; i++) {
! 			if (!serverRefp) break;
! 			serverp = serverRefp-&gt;server;
! 			memcpy(cp, &amp;serverp-&gt;addr.sin_addr.s_addr, sizeof(long));
! 			cp += sizeof(long);
              serverRefp = serverRefp-&gt;next;
! 		}
! 		lock_ReleaseRead(&amp;cm_serverLock);
! 		cp = basep + max * sizeof(afs_int32);
! 		strcpy(cp, tcellp-&gt;namep);
! 		cp += strlen(tcellp-&gt;namep)+1;
! 		ioctlp-&gt;outDatap = cp;
! 	}
  
      if (tcellp) 
          return 0;
--- 352,1091 ----
              free(sharePath);
              if (code) return code;
  
!             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                              userp, NULL, reqp, scpp);
!             if (code) return code;
          } else {
              /* otherwise, treat the name as a cellname mounted off the afs root.
!              * This requires that we reconstruct the shareName string with 
!              * leading and trailing slashes.
!              */
              p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
!             if ( !_strnicmp("all", p, 3) )
!                 p += 4;
  
!             shareName[0] = '/';
!             for (i = 1; *p &amp;&amp; *p != '\\'; i++,p++ ) {
!                 shareName[i] = *p;
!             }
!             p++;                    /* skip past trailing slash */
!             shareName[i++] = '/';	/* add trailing slash */
!             shareName[i] = 0;       /* terminate string */
! 
!             code = cm_NameI(cm_rootSCachep, ioctlp-&gt;prefix-&gt;data,
                               CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                               userp, shareName, reqp, &amp;substRootp);
              if (code) return code;
  
!             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                             userp, NULL, reqp, scpp);
!             if (code) return code;
          }
      } else {
          code = cm_NameI(cm_rootSCachep, ioctlp-&gt;prefix-&gt;data,
!                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                         userp, ioctlp-&gt;tidPathp, reqp, &amp;substRootp);
          if (code) return code;
  
          code = cm_NameI(substRootp, tbuffer, CM_FLAG_FOLLOW,
!                         userp, NULL, reqp, scpp);
          if (code) return code;
      }
  
!     /* # of bytes of path */
!     code = strlen(ioctlp-&gt;inDatap) + 1;
!     ioctlp-&gt;inDatap += code;
  
!     /* and return success */
!     return 0;
  }
  
  long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     cm_conn_t *connp;
!     cm_scache_t *scp;
!     AFSOpaque acl;
!     AFSFetchStatus fileStatus;
!     AFSVolSync volSync;
!     long code;
!     AFSFid fid;
!     int tlen;
!     cm_req_t req;
!     struct rx_connection * callp;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!     if (code) return code;
  
!     /* now make the get acl call */
!     fid.Volume = scp-&gt;fid.volume;
!     fid.Vnode = scp-&gt;fid.vnode;
!     fid.Unique = scp-&gt;fid.unique;
!     do {
!         acl.AFSOpaque_val = ioctlp-&gt;outDatap;
!         acl.AFSOpaque_len = 0;
!         code = cm_Conn(&amp;scp-&gt;fid, userp, &amp;req, &amp;connp);
!         if (code) continue;
! 
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_FetchACL(callp, &amp;fid, &amp;acl, &amp;fileStatus, &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, &amp;req, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
!     code = cm_MapRPCError(code, &amp;req);
!     cm_ReleaseSCache(scp);
! 
!     if (code) return code;
! 
!     /* skip over return data */
!     tlen = strlen(ioctlp-&gt;outDatap) + 1;
!     ioctlp-&gt;outDatap += tlen;
! 
!     /* and return success */
!     return 0;
  }
  
  long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *scp;
!     cm_cell_t *cellp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!     if (code) return code;
! 
!     cellp = cm_FindCellByID(scp-&gt;fid.cell);
!     if (cellp) {
!         strcpy(ioctlp-&gt;outDatap, cellp-&gt;namep);
!         ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) + 1;
!         code = 0;
!     }
!     else code = CM_ERROR_NOSUCHCELL;
! 
!     cm_ReleaseSCache(scp);
!     return code;
  }
  
  long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_conn_t *connp;
!     cm_scache_t *scp;
!     AFSOpaque acl;
!     AFSFetchStatus fileStatus;
!     AFSVolSync volSync;
!     long code;
!     AFSFid fid;
!     cm_req_t req;
!     struct rx_connection * callp;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!     if (code) return code;
  	
!     /* now make the get acl call */
!     fid.Volume = scp-&gt;fid.volume;
!     fid.Vnode = scp-&gt;fid.vnode;
!     fid.Unique = scp-&gt;fid.unique;
!     do {
!         acl.AFSOpaque_val = ioctlp-&gt;inDatap;
!         acl.AFSOpaque_len = strlen(ioctlp-&gt;inDatap)+1;
!         code = cm_Conn(&amp;scp-&gt;fid, userp, &amp;req, &amp;connp);
!         if (code) continue;
! 
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_StoreACL(callp, &amp;fid, &amp;acl, &amp;fileStatus, &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, &amp;req, &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
!     code = cm_MapRPCError(code, &amp;req);
! 
!     /* invalidate cache info, since we just trashed the ACL cache */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     cm_DiscardSCache(scp);
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
  
!     cm_ReleaseSCache(scp);
! 
!     return code;
  }
  
  long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *scp;
!     unsigned long volume;
!     int i;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!     if (code) return code;
          
!     volume = scp-&gt;fid.volume;
!     cm_ReleaseSCache(scp);
  
!     lock_ObtainWrite(&amp;cm_scacheLock);
!     for (i=0; i&lt;cm_hashTableSize; i++) {
!         for (scp = cm_hashTablep[i]; scp; scp = scp-&gt;nextp) {
!             if (scp-&gt;fid.volume == volume) {
!                 scp-&gt;refCount++;
!                 lock_ReleaseWrite(&amp;cm_scacheLock);
! 
!                 /* now flush the file */
!                 code = cm_FlushFile(scp, userp, &amp;req);
!                 if ( code )
!                     afsi_log("cm_FlushFile returns error: [%x]",code);
!                 lock_ObtainWrite(&amp;cm_scacheLock);
!                 scp-&gt;refCount--;
!             }
          }
!     }
!     lock_ReleaseWrite(&amp;cm_scacheLock);
  
!     return code;
  }
  
  long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *scp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!     if (code) return code;
          
!     cm_FlushFile(scp, userp, &amp;req);
!     cm_ReleaseSCache(scp);
  
!     return 0;
  }
  
  long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_scache_t *scp;
!     char volName[32];
!     char offLineMsg[256];
!     char motd[256];
!     cm_conn_t *tcp;
!     long code;
!     AFSFetchVolumeStatus volStat;
!     AFSStoreVolumeStatus storeStat;
!     cm_volume_t *tvp;
!     char *cp;
!     cm_cell_t *cellp;
!     cm_req_t req;
!     struct rx_connection * callp;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!     if (code) return code;
  
!     cellp = cm_FindCellByID(scp-&gt;fid.cell);
!     osi_assert(cellp);
  
!     if (scp-&gt;flags &amp; CM_SCACHEFLAG_RO) {
!         cm_ReleaseSCache(scp);
!         return CM_ERROR_READONLY;
!     }
  
!     code = cm_GetVolumeByID(cellp, scp-&gt;fid.volume, userp, &amp;req, &amp;tvp);
!     if (code) {
!         cm_ReleaseSCache(scp);
!         return code;
!     }
  
!     /* Copy the junk out, using cp as a roving pointer. */
!     cp = ioctlp-&gt;inDatap;
!     memcpy((char *)&amp;volStat, cp, sizeof(AFSFetchVolumeStatus));
!     cp += sizeof(AFSFetchVolumeStatus);
!     strcpy(volName, cp);
!     cp += strlen(volName)+1;
!     strcpy(offLineMsg, cp);
!     cp +=  strlen(offLineMsg)+1;
!     strcpy(motd, cp);
!     storeStat.Mask = 0;
!     if (volStat.MinQuota != -1) {
!         storeStat.MinQuota = volStat.MinQuota;
!         storeStat.Mask |= AFS_SETMINQUOTA;
!     }
!     if (volStat.MaxQuota != -1) {
!         storeStat.MaxQuota = volStat.MaxQuota;
!         storeStat.Mask |= AFS_SETMAXQUOTA;
!     }
  
!     do {
!         code = cm_Conn(&amp;scp-&gt;fid, userp, &amp;req, &amp;tcp);
!         if (code) continue;
! 
!         callp = cm_GetRxConn(tcp);
!         code = RXAFS_SetVolumeStatus(callp, scp-&gt;fid.volume,
!                                       &amp;storeStat, volName, offLineMsg, motd);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(tcp, userp, &amp;req, &amp;scp-&gt;fid, NULL, NULL, NULL, code));
!     code = cm_MapRPCError(code, &amp;req);
! 
!     /* return on failure */
!     cm_ReleaseSCache(scp);
!     if (code) {
!         return code;
!     }
! 
!     /* we are sending parms back to make compat. with prev system.  should
!      * change interface later to not ask for current status, just set
!      * new status
!      */
!     cp = ioctlp-&gt;outDatap;
!     memcpy(cp, (char *)&amp;volStat, sizeof(VolumeStatus));
!     cp += sizeof(VolumeStatus);
!     strcpy(cp, volName);
!     cp += strlen(volName)+1;
!     strcpy(cp, offLineMsg);
!     cp += strlen(offLineMsg)+1;
!     strcpy(cp, motd);
!     cp += strlen(motd)+1;
! 
!     /* now return updated return data pointer */
!     ioctlp-&gt;outDatap = cp;
! 
!     return 0;
! }       
  
  long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     char volName[32];
!     cm_scache_t *scp;
!     char offLineMsg[256];
!     char motd[256];
!     cm_conn_t *tcp;
!     register long code;
!     AFSFetchVolumeStatus volStat;
!     register char *cp;
!     char *Name;
!     char *OfflineMsg;
!     char *MOTD;
!     cm_req_t req;
!     struct rx_connection * callp;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
!     if (code) return code;
! 
!     Name = volName;
!     OfflineMsg = offLineMsg;
!     MOTD = motd;
!     do {
!         code = cm_Conn(&amp;scp-&gt;fid, userp, &amp;req, &amp;tcp);
!         if (code) continue;
! 
!         callp = cm_GetRxConn(tcp);
!         code = RXAFS_GetVolumeStatus(callp, scp-&gt;fid.volume,
!                                       &amp;volStat, &amp;Name, &amp;OfflineMsg, &amp;MOTD);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(tcp, userp, &amp;req, &amp;scp-&gt;fid, NULL, NULL, NULL, code));
!     code = cm_MapRPCError(code, &amp;req);
  
!     cm_ReleaseSCache(scp);
!     if (code) return code;
! 
!     /* Copy all this junk into msg-&gt;im_data, keeping track of the lengths. */
!     cp = ioctlp-&gt;outDatap;
!     memcpy(cp, (char *)&amp;volStat, sizeof(AFSFetchVolumeStatus));
!     cp += sizeof(AFSFetchVolumeStatus);
!     strcpy(cp, volName);
!     cp += strlen(volName)+1;
!     strcpy(cp, offLineMsg);
!     cp += strlen(offLineMsg)+1;
!     strcpy(cp, motd);
!     cp += strlen(motd)+1;
  
!     /* return new size */
!     ioctlp-&gt;outDatap = cp;
  
!     return 0;
  }
  
  long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
      cm_scache_t *scp;
      cm_cell_t *cellp;
      cm_volume_t *tvp;
!     cm_serverRef_t **tsrpp, *current;
      cm_server_t *tsp;
      unsigned long volume;
      char *cp;
      cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;scp);
      if (code) return code;
          
!     volume = scp-&gt;fid.volume;
  
!     cellp = cm_FindCellByID(scp-&gt;fid.cell);
      osi_assert(cellp);
  
      cm_ReleaseSCache(scp);
  
!     code = cm_GetVolumeByID(cellp, volume, userp, &amp;req, &amp;tvp);
      if (code) return code;
  	
      cp = ioctlp-&gt;outDatap;
          
!     lock_ObtainMutex(&amp;tvp-&gt;mx);
!     tsrpp = cm_GetVolServers(tvp, volume);
!     lock_ObtainRead(&amp;cm_serverLock);
!     for (current = *tsrpp; current; current = current-&gt;next) {
!         tsp = current-&gt;server;
!         memcpy(cp, (char *)&amp;tsp-&gt;addr.sin_addr.s_addr, sizeof(long));
!         cp += sizeof(long);
!     }
!     lock_ReleaseRead(&amp;cm_serverLock);
      cm_FreeServerList(tsrpp);
      lock_ReleaseMutex(&amp;tvp-&gt;mx);
  
!     /* still room for terminating NULL, add it on */
!     volume = 0;	/* reuse vbl */
!     memcpy(cp, (char *)&amp;volume, sizeof(long));
!     cp += sizeof(long);
! 
!     ioctlp-&gt;outDatap = cp;
!     cm_PutVolume(tvp);
!     return 0;
! }       
  
  long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *dscp;
!     cm_scache_t *scp;
!     char *cp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
!     if (code) return code;
  
!     cp = ioctlp-&gt;inDatap;
! 
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
!     cm_ReleaseSCache(dscp);
!     if (code) return code;
          
!     lock_ObtainMutex(&amp;scp-&gt;mx);
  
!     /* now check that this is a real mount point */
!     if (scp-&gt;fileType != CM_SCACHETYPE_MOUNTPOINT) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
+         return CM_ERROR_INVAL;
+     }
  
!     code = cm_ReadMountPoint(scp, userp, &amp;req);
!     if (code == 0) {
!         cp = ioctlp-&gt;outDatap;
!         strcpy(cp, scp-&gt;mountPointStringp);
!         cp += strlen(cp) + 1;
!         ioctlp-&gt;outDatap = cp;
!     }
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     cm_ReleaseSCache(scp);
! 
!     return code;
! }       
  
  long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *dscp;
!     cm_scache_t *scp;
!     char *cp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
!     if (code) return code;
! 
!     cp = ioctlp-&gt;inDatap;
  
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
          
!     /* if something went wrong, bail out now */
!     if (code) {
!         goto done;
!     }
          
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) {     
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
!         goto done;
!     }
! 
!     /* now check that this is a real mount point */
!     if (scp-&gt;fileType != CM_SCACHETYPE_MOUNTPOINT) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         cm_ReleaseSCache(scp);
!         code = CM_ERROR_INVAL;
!         goto done;
!     }
! 
!     /* time to make the RPC, so drop the lock */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     cm_ReleaseSCache(scp);
! 
!     /* easier to do it this way */
!     code = cm_Unlink(dscp, cp, userp, &amp;req);
!     if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!         smb_NotifyChange(FILE_ACTION_REMOVED,
!                           FILE_NOTIFY_CHANGE_DIR_NAME,
!                           dscp, cp, NULL, TRUE);
! 
!   done:
!     cm_ReleaseSCache(dscp);
!     return code;
  }
  
  long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_cell_t *cellp;
!     chservinfo_t csi;
!     char *tp;
!     char *cp;
!     long temp;
!     cm_server_t *tsp;
!     int haveCell;
!         
!     cm_SkipIoctlPath(ioctlp);	/* we don't care about the path */
!     tp = ioctlp-&gt;inDatap;
!     haveCell = 0;
! 
!     memcpy(&amp;temp, tp, sizeof(temp));
!     if (temp == 0x12345678) {	/* For afs3.3 version */
!         memcpy(&amp;csi, tp, sizeof(csi));
!         if (csi.tinterval &gt;= 0) {
!             cp = ioctlp-&gt;outDatap;
!             memcpy(cp, (char *)&amp;cm_daemonCheckInterval, sizeof(long));
!             ioctlp-&gt;outDatap += sizeof(long);
!             if (csi.tinterval &gt; 0) {
!                 if (!smb_SUser(userp))
!                     return CM_ERROR_NOACCESS;
!                 cm_daemonCheckInterval = csi.tinterval;
!             }
!             return 0;
!         }
!         if (csi.tsize)
!             haveCell = 1;
!         temp = csi.tflags;
!         cp = csi.tbuffer;
!     } else {	/* For pre afs3.3 versions */
!         memcpy((char *)&amp;temp, ioctlp-&gt;inDatap, sizeof(long));
!         ioctlp-&gt;inDatap = cp = ioctlp-&gt;inDatap + sizeof(long);
!         if (cp - ioctlp-&gt;inAllocp &lt; ioctlp-&gt;inCopied)	/* still more data available */
!             haveCell = 1;
!     }       
! 
!     /* 
!      * 1: fast check, don't contact servers.
!      * 2: local cell only.
!      */
!     if (haveCell) {
!         /* have cell name, too */
!         cellp = cm_GetCell(cp, 0);
!         if (!cellp) return CM_ERROR_NOSUCHCELL;
!     }
!     else cellp = (cm_cell_t *) 0;
!     if (!cellp &amp;&amp; (temp &amp; 2)) {
!         /* use local cell */
!         cellp = cm_FindCellByID(1);
!     }
!     if (!(temp &amp; 1)) {	/* if not fast, call server checker routine */
!         /* check down servers */
!         cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
!                          cellp);
!     }       
! 
!     /* now return the current down server list */
!     cp = ioctlp-&gt;outDatap;
!     lock_ObtainRead(&amp;cm_serverLock);
!     for (tsp = cm_allServersp; tsp; tsp=tsp-&gt;allNextp) {
!         if (cellp &amp;&amp; tsp-&gt;cellp != cellp) continue;	/* cell spec'd and wrong */
!         if ((tsp-&gt;flags &amp; CM_SERVERFLAG_DOWN)
!              &amp;&amp; tsp-&gt;type == CM_SERVER_FILE) {
!             memcpy(cp, (char *)&amp;tsp-&gt;addr.sin_addr.s_addr, sizeof(long));
!             cp += sizeof(long);
!         }
!     }
!     lock_ReleaseRead(&amp;cm_serverLock);
  
!     ioctlp-&gt;outDatap = cp;
!     return 0;
  }
  
  long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     /* we don't print anything superfluous, so we don't support the gag call */
!     return CM_ERROR_INVAL;
  }
  
  long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_CheckVolumes();
!     return 0;
! }       
  
  long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long temp;
!     long code;
  
!     cm_SkipIoctlPath(ioctlp);
  
!     memcpy(&amp;temp, ioctlp-&gt;inDatap, sizeof(temp));
!     if (temp == 0) 
!         temp = buf_nOrigBuffers;
!     else {
!         /* temp is in 1K units, convert to # of buffers */
!         temp = temp / (buf_bufferSize / 1024);
!     }       
  
!     /* now adjust the cache size */
!     code = buf_SetNBuffers(temp);
! 
!     return code;
  }
  
  long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long inValue;
!         
!     cm_SkipIoctlPath(ioctlp);
          
!     memcpy(&amp;inValue, ioctlp-&gt;inDatap, sizeof(long));
! 
!     /* print trace */
!     if (inValue &amp; 8) {
!         afsd_ForceTrace(FALSE);
!     }
          
!     if (inValue &amp; 2) {
!         /* set tracing value to low order bit */
!         if ((inValue &amp; 1) == 0) {
!             /* disable tracing */
!             osi_LogDisable(afsd_logp);
!         }
!         else {
!             /* enable tracing */
!             osi_LogEnable(afsd_logp);
!         }
!     }
  
!     /* see if we're supposed to do a reset, too */
!     if (inValue &amp; 4) {
!         osi_LogReset(afsd_logp);
!     }
! 
!     /* and copy out tracing flag */
!     inValue = afsd_logp-&gt;enabled;	/* use as a temp vbl */
!     memcpy(ioctlp-&gt;outDatap, &amp;inValue, sizeof(long));
!     ioctlp-&gt;outDatap += sizeof(long);
!     return 0;
! }       
  
  long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_cacheParms_t parms;
  
!     memset(&amp;parms, 0, sizeof(parms));
! 
!     /* first we get, in 1K units, the cache size */
!     parms.parms[0] = buf_nbuffers * (buf_bufferSize / 1024);
! 
!     /* and then the actual # of buffers in use (not in the free list, I guess,
!      * will be what we do).
!      */
!     parms.parms[1] = (buf_nbuffers - buf_CountFreeList()) * (buf_bufferSize / 1024);
! 
!     memcpy(ioctlp-&gt;outDatap, &amp;parms, sizeof(parms));
!     ioctlp-&gt;outDatap += sizeof(parms);
  
!     return 0;
  }
  
  long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long whichCell;
      long magic = 0;
!     cm_cell_t *tcellp;
!     cm_serverRef_t *serverRefp;
      cm_server_t *serverp;
!     long i;
      char *cp;
      char *tp;
      char *basep;
  
!     cm_SkipIoctlPath(ioctlp);
  
!     tp = ioctlp-&gt;inDatap;
  
!     memcpy((char *)&amp;whichCell, tp, sizeof(long));
!     tp += sizeof(long);
! 
!     /* see if more than one long passed in, ignoring the null pathname (the -1) */
!     if (ioctlp-&gt;inCopied-1 &gt; sizeof(long)) {
!         memcpy((char *)&amp;magic, tp, sizeof(long));
!     }
  
      lock_ObtainRead(&amp;cm_cellLock);
!     for (tcellp = cm_allCellsp; tcellp; tcellp = tcellp-&gt;nextp) {
!         if (whichCell == 0) break;
!         whichCell--;
!     }
!     lock_ReleaseRead(&amp;cm_cellLock);
!     if (tcellp) {
!         int max = 8;
! 
!         cp = ioctlp-&gt;outDatap;
! 
!         if (magic == 0x12345678) {
!             memcpy(cp, (char *)&amp;magic, sizeof(long));
!             max = 13;
!         }
!         memset(cp, 0, max * sizeof(long));
          basep = cp;
!         lock_ObtainRead(&amp;cm_serverLock);	/* for going down server list */
          /* jaltman - do the reference counts to serverRefp contents need to be increased? */
!         serverRefp = tcellp-&gt;vlServersp;
!         for (i=0; i&lt;max; i++) {
!             if (!serverRefp) break;
!             serverp = serverRefp-&gt;server;
!             memcpy(cp, &amp;serverp-&gt;addr.sin_addr.s_addr, sizeof(long));
!             cp += sizeof(long);
              serverRefp = serverRefp-&gt;next;
!         }
!         lock_ReleaseRead(&amp;cm_serverLock);
!         cp = basep + max * sizeof(afs_int32);
!         strcpy(cp, tcellp-&gt;namep);
!         cp += strlen(tcellp-&gt;namep)+1;
!         ioctlp-&gt;outDatap = cp;
!     }
  
      if (tcellp) 
          return 0;
***************
*** 1077,1090 ****
       * are already loaded.
    
       * cell list will be cm_CellLock and cm_ServerLock will be held for write.
!     */  
    
      cm_cell_t *cp;
    
      cm_SkipIoctlPath(ioctlp);
      lock_ObtainWrite(&amp;cm_cellLock);
    
!     for(cp = cm_allCellsp; cp; cp=cp-&gt;nextp) 
      {
          long code;
          /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
--- 1104,1117 ----
       * are already loaded.
    
       * cell list will be cm_CellLock and cm_ServerLock will be held for write.
!      */  
    
      cm_cell_t *cp;
    
      cm_SkipIoctlPath(ioctlp);
      lock_ObtainWrite(&amp;cm_cellLock);
    
!     for (cp = cm_allCellsp; cp; cp=cp-&gt;nextp) 
      {
          long code;
          /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
***************
*** 1092,1098 ****
          cp-&gt;vlServersp = NULL;
          code = cm_SearchCellFile(cp-&gt;namep, cp-&gt;namep, cm_AddCellProc, cp);
  #ifdef AFS_AFSDB_ENV
! 		if (code) {
              if (cm_dnsEnabled) {
                  int ttl;
                  code = cm_SearchCellByDNS(cp-&gt;namep, cp-&gt;namep, &amp;ttl, cm_AddCellProc, cp);
--- 1119,1125 ----
          cp-&gt;vlServersp = NULL;
          code = cm_SearchCellFile(cp-&gt;namep, cp-&gt;namep, cm_AddCellProc, cp);
  #ifdef AFS_AFSDB_ENV
!         if (code) {
              if (cm_dnsEnabled) {
                  int ttl;
                  code = cm_SearchCellByDNS(cp-&gt;namep, cp-&gt;namep, &amp;ttl, cm_AddCellProc, cp);
***************
*** 1122,1148 ****
  
  long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
! 	/* if we don't know our default cell, return failure */
! 	if (cm_rootCellp == NULL) {
! 		return CM_ERROR_NOSUCHCELL;
! 	}
! 
! 	/* return the default cellname to the caller */
! 	strcpy(ioctlp-&gt;outDatap, cm_rootCellp-&gt;namep);
! 	ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
!         
! 	/* done: success */
!         return 0;
  }
  
  long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long setSysName, foundname = 0;
      char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
      int t, count, num = 0;
      char **sysnamelist[MAXSYSNAME];
          
! 	cm_SkipIoctlPath(ioctlp);
  
      memcpy(&amp;setSysName, ioctlp-&gt;inDatap, sizeof(long));
      ioctlp-&gt;inDatap += sizeof(long);
--- 1149,1175 ----
  
  long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     /* if we don't know our default cell, return failure */
!     if (cm_rootCellp == NULL) {
!         return CM_ERROR_NOSUCHCELL;
!     }
! 
!     /* return the default cellname to the caller */
!     strcpy(ioctlp-&gt;outDatap, cm_rootCellp-&gt;namep);
!     ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
! 
!     /* done: success */
!     return 0;
  }
  
  long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long setSysName, foundname = 0;
      char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
      int t, count, num = 0;
      char **sysnamelist[MAXSYSNAME];
          
!     cm_SkipIoctlPath(ioctlp);
  
      memcpy(&amp;setSysName, ioctlp-&gt;inDatap, sizeof(long));
      ioctlp-&gt;inDatap += sizeof(long);
***************
*** 1180,1186 ****
          strcpy(outname, cm_sysName);
          foundname = cm_sysNameCount;
          *sysnamelist = cm_sysNameList;
!     } else {                /* Local guy; only root can change sysname */
          /* clear @sys entries from the dnlc, once afs_lookup can
           * do lookups of @sys entries and thinks it can trust them */
          /* privs ok, store the entry, ... */
--- 1207,1214 ----
          strcpy(outname, cm_sysName);
          foundname = cm_sysNameCount;
          *sysnamelist = cm_sysNameList;
!     } else {        
!         /* Local guy; only root can change sysname */
          /* clear @sys entries from the dnlc, once afs_lookup can
           * do lookups of @sys entries and thinks it can trust them */
          /* privs ok, store the entry, ... */
***************
*** 1189,1197 ****
              cp = ioctlp-&gt;inDatap;
              for (count = 1; count &lt; setSysName; ++count) {
                  if (!cm_sysNameList[count])
!                     osi_panic
!                         ("cm_IoctlSysName: no cm_sysNameList entry to write\n"
!                           , __FILE__, __LINE__);
                  t = strlen(cp);
                  memcpy(cm_sysNameList[count], cp, t + 1);  /* include null */
                  cp += t + 1;
--- 1217,1224 ----
              cp = ioctlp-&gt;inDatap;
              for (count = 1; count &lt; setSysName; ++count) {
                  if (!cm_sysNameList[count])
!                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
!                                __FILE__, __LINE__);
                  t = strlen(cp);
                  memcpy(cm_sysNameList[count], cp, t + 1);  /* include null */
                  cp += t + 1;
***************
*** 1201,1208 ****
      }
  
      if (!setSysName) {
! 		/* return the sysname to the caller */
! 		cp = ioctlp-&gt;outDatap;
          memcpy(cp, (char *)&amp;foundname, sizeof(afs_int32));
          cp += sizeof(afs_int32);	/* skip found flag */
          if (foundname) {
--- 1228,1235 ----
      }
  
      if (!setSysName) {
!         /* return the sysname to the caller */
!         cp = ioctlp-&gt;outDatap;
          memcpy(cp, (char *)&amp;foundname, sizeof(afs_int32));
          cp += sizeof(afs_int32);	/* skip found flag */
          if (foundname) {
***************
*** 1210,1221 ****
              cp += strlen(outname) + 1;	/* skip name and terminating null char */
              for ( count=1; count &lt; foundname ; ++count) {   /* ... or list */
                  if ( !(*sysnamelist)[count] )
!                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n"
!                                , __FILE__, __LINE__);
                  t = strlen((*sysnamelist)[count]);
                  if (t &gt;= MAXSYSNAME)
!                     osi_panic("cm_IoctlSysName: sysname entry garbled\n"
!                                , __FILE__, __LINE__);
                  strcpy(cp, (*sysnamelist)[count]);
                  cp += t + 1;
              }
--- 1237,1248 ----
              cp += strlen(outname) + 1;	/* skip name and terminating null char */
              for ( count=1; count &lt; foundname ; ++count) {   /* ... or list */
                  if ( !(*sysnamelist)[count] )
!                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n", 
!                                __FILE__, __LINE__);
                  t = strlen((*sysnamelist)[count]);
                  if (t &gt;= MAXSYSNAME)
!                     osi_panic("cm_IoctlSysName: sysname entry garbled\n", 
!                                __FILE__, __LINE__);
                  strcpy(cp, (*sysnamelist)[count]);
                  cp += t + 1;
              }
***************
*** 1223,1400 ****
          ioctlp-&gt;outDatap = cp;
      }
          
! 	/* done: success */
      return 0;
  }
  
  long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long temp;
!         cm_cell_t *cellp;
! 
! 	cm_SkipIoctlPath(ioctlp);
  
! 	cellp = cm_GetCell(ioctlp-&gt;inDatap, 0);
! 	if (!cellp) return CM_ERROR_NOSUCHCELL;
  
! 	temp = 0;
! 	lock_ObtainMutex(&amp;cellp-&gt;mx);
!         if (cellp-&gt;flags &amp; CM_CELLFLAG_SUID)
! 		temp |= CM_SETCELLFLAG_SUID;
! 	lock_ReleaseMutex(&amp;cellp-&gt;mx);
          
!         /* now copy out parm */
!         memcpy(ioctlp-&gt;outDatap, &amp;temp, sizeof(long));
!         ioctlp-&gt;outDatap += sizeof(long);
  
! 	return 0;
  }
  
  long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long temp;
!         cm_cell_t *cellp;
! 
! 	cm_SkipIoctlPath(ioctlp);
! 
! 	cellp = cm_GetCell(ioctlp-&gt;inDatap + 2*sizeof(long), 0);
! 	if (!cellp) return CM_ERROR_NOSUCHCELL;
  
! 	memcpy((char *)&amp;temp, ioctlp-&gt;inDatap, sizeof(long));
  
! 	lock_ObtainMutex(&amp;cellp-&gt;mx);
!         if (temp &amp; CM_SETCELLFLAG_SUID)
!         	cellp-&gt;flags |= CM_CELLFLAG_SUID;
! 	else
!         	cellp-&gt;flags &amp;= ~CM_CELLFLAG_SUID;
! 	lock_ReleaseMutex(&amp;cellp-&gt;mx);
  
! 	return 0;
  }
  
  long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	cm_SSetPref_t 	  *spin; /* input */
! 	cm_SPref_t        *srvin;   /* one input component */
! 	cm_server_t       *tsp;
! 	int 		  i, vlonly, noServers, type;
! 	struct sockaddr_in	tmp;
! 	unsigned short	  rank;
! 
! 	cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
! 
! 	spin	   = (cm_SSetPref_t *)ioctlp-&gt;inDatap;
! 	noServers  = spin-&gt;num_servers;
! 	vlonly     = spin-&gt;flags;
! 	if ( vlonly )
! 		type = CM_SERVER_VLDB;
! 	else    
          type = CM_SERVER_FILE;
  
! 	for ( i=0; i &lt; noServers; i++) 
! 	{
! 		srvin          = &amp;(spin-&gt;servers[i]);
! 		rank           = srvin-&gt;rank + (rand() &amp; 0x000f);
! 		tmp.sin_addr   = srvin-&gt;host;
! 		tmp.sin_family = AF_INET;
! 
! 		tsp = cm_FindServer(&amp;tmp, type);
! 		if ( tsp )		/* an existing server - ref count increased */
! 		{
! 			tsp-&gt;ipRank = rank; /* no need to protect by mutex*/
! 
! 			if ( type == CM_SERVER_FILE) /* fileserver */
! 			{
! 			    /* find volumes which might have RO copy 
! 			    /* on server and change the ordering of 
! 			    ** their RO list */
! 			    cm_ChangeRankVolume(tsp);
! 			}
! 			else 	
! 			{
! 			    /* set preferences for an existing vlserver */
! 			    cm_ChangeRankCellVLServer(tsp);
! 			}
              cm_PutServer(tsp);  /* decrease refcount */
! 		}
! 		else	/* add a new server without a cell */
! 		{
! 			tsp = cm_NewServer(&amp;tmp, type, NULL); /* refcount = 1 */
! 			tsp-&gt;ipRank = rank;
! 		}
! 	}
! 	return 0;
  }
  
  long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	cm_SPrefRequest_t *spin; /* input */
!    	cm_SPrefInfo_t    *spout;   /* output */
! 	cm_SPref_t        *srvout;   /* one output component */
! 	cm_server_t       *tsp;
! 	int 		  i, vlonly, noServers;
! 
! 	cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
! 
! 	spin      = (cm_SPrefRequest_t *)ioctlp-&gt;inDatap;
! 	spout     = (cm_SPrefInfo_t *) ioctlp-&gt;outDatap;
! 	srvout    = spout-&gt;servers;
! 	noServers = spin-&gt;num_servers; 
! 	vlonly    = spin-&gt;flags &amp; CM_SPREF_VLONLY;
! 	spout-&gt;num_servers = 0;
! 
! 	lock_ObtainRead(&amp;cm_serverLock); /* get server lock */
! 
! 	for(tsp=cm_allServersp, i=0; tsp &amp;&amp; noServers; tsp=tsp-&gt;allNextp,i++){
! 		if (spin-&gt;offset &gt; i) {
! 			continue;    /* catch up to where we left off */
! 		}
! 
! 		if ( vlonly &amp;&amp; (tsp-&gt;type == CM_SERVER_FILE) )
! 			continue;   /* ignore fileserver for -vlserver option*/
! 		if ( !vlonly &amp;&amp; (tsp-&gt;type == CM_SERVER_VLDB) )
! 			continue;   /* ignore vlservers */
! 
! 		srvout-&gt;host = tsp-&gt;addr.sin_addr;
! 		srvout-&gt;rank = tsp-&gt;ipRank;
! 		srvout++;	
! 		spout-&gt;num_servers++;
! 		noServers--;
! 	}
! 	lock_ReleaseRead(&amp;cm_serverLock); /* release server lock */
! 
! 	if ( tsp ) 	/* we ran out of space in the output buffer */
! 		spout-&gt;next_offset = i;
! 	else    
! 		spout-&gt;next_offset = 0; 
! 	ioctlp-&gt;outDatap += sizeof(cm_SPrefInfo_t) + 
! 			(spout-&gt;num_servers -1 ) * sizeof(cm_SPref_t) ;
! 	return 0;
  }
  
  long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	/* we ignore default asynchrony since we only have one way
!          * of doing this today.
!          */
! 	return 0;
! }
  
  long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	char leaf[256];
      long code;
      cm_scache_t *dscp;
      cm_attr_t tattr;
      char *cp;
! 	cm_req_t req;
      char mpInfo[256];
      char fullCell[256];
! 	char volume[256];
! 	char cell[256];
! 	int ttl;
  
! 	cm_InitReq(&amp;req);
          
      code = cm_ParseIoctlParent(ioctlp, userp, &amp;req, &amp;dscp, leaf);
      if (code) return code;
--- 1250,1429 ----
          ioctlp-&gt;outDatap = cp;
      }
          
!     /* done: success */
      return 0;
  }
  
  long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long temp;
!     cm_cell_t *cellp;
  
!     cm_SkipIoctlPath(ioctlp);
  
!     cellp = cm_GetCell(ioctlp-&gt;inDatap, 0);
!     if (!cellp) 
!         return CM_ERROR_NOSUCHCELL;
! 
!     temp = 0;
!     lock_ObtainMutex(&amp;cellp-&gt;mx);
!     if (cellp-&gt;flags &amp; CM_CELLFLAG_SUID)
!         temp |= CM_SETCELLFLAG_SUID;
!     lock_ReleaseMutex(&amp;cellp-&gt;mx);
          
!     /* now copy out parm */
!     memcpy(ioctlp-&gt;outDatap, &amp;temp, sizeof(long));
!     ioctlp-&gt;outDatap += sizeof(long);
  
!     return 0;
  }
  
  long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long temp;
!     cm_cell_t *cellp;
  
!     cm_SkipIoctlPath(ioctlp);
  
!     cellp = cm_GetCell(ioctlp-&gt;inDatap + 2*sizeof(long), 0);
!     if (!cellp) 
!         return CM_ERROR_NOSUCHCELL;
! 
!     memcpy((char *)&amp;temp, ioctlp-&gt;inDatap, sizeof(long));
! 
!     lock_ObtainMutex(&amp;cellp-&gt;mx);
!     if (temp &amp; CM_SETCELLFLAG_SUID)
!         cellp-&gt;flags |= CM_CELLFLAG_SUID;
!     else
!         cellp-&gt;flags &amp;= ~CM_CELLFLAG_SUID;
!     lock_ReleaseMutex(&amp;cellp-&gt;mx);
  
!     return 0;
  }
  
  long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_SSetPref_t 	  *spin; /* input */
!     cm_SPref_t        *srvin;   /* one input component */
!     cm_server_t       *tsp;
!     int 		  i, vlonly, noServers, type;
!     struct sockaddr_in	tmp;
!     unsigned short	  rank;
! 
!     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
! 
!     spin	   = (cm_SSetPref_t *)ioctlp-&gt;inDatap;
!     noServers  = spin-&gt;num_servers;
!     vlonly     = spin-&gt;flags;
!     if ( vlonly )
!         type = CM_SERVER_VLDB;
!     else    
          type = CM_SERVER_FILE;
  
!     for ( i=0; i &lt; noServers; i++) 
!     {
!         srvin          = &amp;(spin-&gt;servers[i]);
!         rank           = srvin-&gt;rank + (rand() &amp; 0x000f);
!         tmp.sin_addr   = srvin-&gt;host;
!         tmp.sin_family = AF_INET;
! 
!         tsp = cm_FindServer(&amp;tmp, type);
!         if ( tsp )		/* an existing server - ref count increased */
!         {
!             tsp-&gt;ipRank = rank; /* no need to protect by mutex*/
! 
!             if ( type == CM_SERVER_FILE) /* fileserver */
!             {
!                 /* find volumes which might have RO copy 
!                 /* on server and change the ordering of 
!                 ** their RO list */
!                     cm_ChangeRankVolume(tsp);
!             }
!             else 	
!             {
!                 /* set preferences for an existing vlserver */
!                 cm_ChangeRankCellVLServer(tsp);
!             }
              cm_PutServer(tsp);  /* decrease refcount */
!         }
!         else	/* add a new server without a cell */
!         {
!             tsp = cm_NewServer(&amp;tmp, type, NULL); /* refcount = 1 */
!             tsp-&gt;ipRank = rank;
!         }
!     }
!     return 0;
  }
  
  long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_SPrefRequest_t *spin; /* input */
!     cm_SPrefInfo_t    *spout;   /* output */
!     cm_SPref_t        *srvout;   /* one output component */
!     cm_server_t       *tsp;
!     int 		  i, vlonly, noServers;
! 
!     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
! 
!     spin      = (cm_SPrefRequest_t *)ioctlp-&gt;inDatap;
!     spout     = (cm_SPrefInfo_t *) ioctlp-&gt;outDatap;
!     srvout    = spout-&gt;servers;
!     noServers = spin-&gt;num_servers; 
!     vlonly    = spin-&gt;flags &amp; CM_SPREF_VLONLY;
!     spout-&gt;num_servers = 0;
! 
!     lock_ObtainRead(&amp;cm_serverLock); /* get server lock */
! 
!     for (tsp=cm_allServersp, i=0; tsp &amp;&amp; noServers; tsp=tsp-&gt;allNextp,i++){
!         if (spin-&gt;offset &gt; i) {
!             continue;    /* catch up to where we left off */
!         }
! 
!         if ( vlonly &amp;&amp; (tsp-&gt;type == CM_SERVER_FILE) )
!             continue;   /* ignore fileserver for -vlserver option*/
!         if ( !vlonly &amp;&amp; (tsp-&gt;type == CM_SERVER_VLDB) )
!             continue;   /* ignore vlservers */
! 
!         srvout-&gt;host = tsp-&gt;addr.sin_addr;
!         srvout-&gt;rank = tsp-&gt;ipRank;
!         srvout++;	
!         spout-&gt;num_servers++;
!         noServers--;
!     }
!     lock_ReleaseRead(&amp;cm_serverLock); /* release server lock */
! 
!     if ( tsp ) 	/* we ran out of space in the output buffer */
!         spout-&gt;next_offset = i;
!     else    
!         spout-&gt;next_offset = 0; 
!     ioctlp-&gt;outDatap += sizeof(cm_SPrefInfo_t) + 
!         (spout-&gt;num_servers -1 ) * sizeof(cm_SPref_t) ;
!     return 0;
  }
  
  long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     /* we ignore default asynchrony since we only have one way
!      * of doing this today.
!      */
!     return 0;
! }       
  
  long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     char leaf[256];
      long code;
      cm_scache_t *dscp;
      cm_attr_t tattr;
      char *cp;
!     cm_req_t req;
      char mpInfo[256];
      char fullCell[256];
!     char volume[256];
!     char cell[256];
!     int ttl;
  
!     cm_InitReq(&amp;req);
          
      code = cm_ParseIoctlParent(ioctlp, userp, &amp;req, &amp;dscp, leaf);
      if (code) return code;
***************
*** 1408,1456 ****
       * work on UNIX clients.
       */
  
! 	/* Extract the possibly partial cell name */
! 	strcpy(cell, ioctlp-&gt;inDatap + 1);      /* Skip the mp type character */
          
      if (cp = strchr(cell, ':')) {
! 		/* Extract the volume name */
          *cp = 0;
! 		strcpy(volume,  cp + 1);
  	
          /* Get the full name for this cell */
          code = cm_SearchCellFile(cell, fullCell, 0, 0);
  #ifdef AFS_AFSDB_ENV
! 		if (code &amp;&amp; cm_dnsEnabled)
              code = cm_SearchCellByDNS(cell, fullCell, &amp;ttl, 0, 0);
  #endif
          if (code)
! 			return CM_ERROR_NOSUCHCELL;
  	
          sprintf(mpInfo, "%c%s:%s", *ioctlp-&gt;inDatap, fullCell, volume);
! 	} else {
          /* No cell name specified */
          strcpy(mpInfo, ioctlp-&gt;inDatap);
      }
  
  #ifdef AFS_FREELANCE_CLIENT
! 	if (cm_freelanceEnabled &amp;&amp; dscp == cm_rootSCachep) {
! 	  /* we are adding the mount point to the root dir., so call
! 	     the freelance code to do the add. */
! 	  osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
! 	  code = cm_FreelanceAddMount(leaf, fullCell, volume, 
!                                   *ioctlp-&gt;inDatap == '%', NULL);
! 	  return code;
! 	}
  #endif
! 	/* create the symlink with mode 644.  The lack of X bits tells
       * us that it is a mount point.
       */
! 	tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
      tattr.unixModeBits = 0644;
! 	tattr.clientModTime = time(NULL);
  
      code = cm_SymLink(dscp, leaf, mpInfo, 0, &amp;tattr, userp, &amp;req);
! 	if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 		smb_NotifyChange(FILE_ACTION_ADDED,
                           FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, leaf, NULL, TRUE);
  
--- 1437,1485 ----
       * work on UNIX clients.
       */
  
!     /* Extract the possibly partial cell name */
!     strcpy(cell, ioctlp-&gt;inDatap + 1);      /* Skip the mp type character */
          
      if (cp = strchr(cell, ':')) {
!         /* Extract the volume name */
          *cp = 0;
!         strcpy(volume,  cp + 1);
  	
          /* Get the full name for this cell */
          code = cm_SearchCellFile(cell, fullCell, 0, 0);
  #ifdef AFS_AFSDB_ENV
!         if (code &amp;&amp; cm_dnsEnabled)
              code = cm_SearchCellByDNS(cell, fullCell, &amp;ttl, 0, 0);
  #endif
          if (code)
!             return CM_ERROR_NOSUCHCELL;
  	
          sprintf(mpInfo, "%c%s:%s", *ioctlp-&gt;inDatap, fullCell, volume);
!     } else {
          /* No cell name specified */
          strcpy(mpInfo, ioctlp-&gt;inDatap);
      }
  
  #ifdef AFS_FREELANCE_CLIENT
!     if (cm_freelanceEnabled &amp;&amp; dscp == cm_rootSCachep) {
!         /* we are adding the mount point to the root dir., so call
!          * the freelance code to do the add. */
!         osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
!         code = cm_FreelanceAddMount(leaf, fullCell, volume, 
!                                     *ioctlp-&gt;inDatap == '%', NULL);
!         return code;
!     }
  #endif
!     /* create the symlink with mode 644.  The lack of X bits tells
       * us that it is a mount point.
       */
!     tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
      tattr.unixModeBits = 0644;
!     tattr.clientModTime = time(NULL);
  
      code = cm_SymLink(dscp, leaf, mpInfo, 0, &amp;tattr, userp, &amp;req);
!     if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!         smb_NotifyChange(FILE_ACTION_ADDED,
                           FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, leaf, NULL, TRUE);
  
***************
*** 1460,2022 ****
  
  long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	char leaf[256];
! 	long code;
! 	cm_scache_t *dscp;
! 	cm_attr_t tattr;
! 	char *cp;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
  
! 	code = cm_ParseIoctlParent(ioctlp, userp, &amp;req, &amp;dscp, leaf);
! 	if (code) return code;
  
!         /* Translate chars for the link name */
!         TranslateExtendedChars(leaf);
  
!         /* Translate chars for the linked to name */
!         TranslateExtendedChars(ioctlp-&gt;inDatap);
  
! 	cp = ioctlp-&gt;inDatap;		/* contents of link */
  
! 	/* Create symlink with mode 0755. */
! 	tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
! 	tattr.unixModeBits = 0755;
  
! 	code = cm_SymLink(dscp, leaf, cp, 0, &amp;tattr, userp, &amp;req);
! 	if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 		smb_NotifyChange(FILE_ACTION_ADDED,
! 				 FILE_NOTIFY_CHANGE_FILE_NAME
! 				   | FILE_NOTIFY_CHANGE_DIR_NAME,
! 				 dscp, leaf, NULL, TRUE);
  
! 	cm_ReleaseSCache(dscp);
  
! 	return code;
  }
  
  extern long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
! 	cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
! 	cm_user_t *userp, cm_req_t *reqp);
  
  long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long code;
! 	cm_scache_t *dscp;
! 	cm_scache_t *scp;
! 	char *cp;
! 	cm_space_t *spacep;
! 	cm_scache_t *newRootScp;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
! 
! 	code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
! 	if (code) return code;
! 
! 	cp = ioctlp-&gt;inDatap;
! 
! 	code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
! 	cm_ReleaseSCache(dscp);
! 	if (code) return code;
! 
! 	/* Check that it's a real symlink */
! 	if (scp-&gt;fileType != CM_SCACHETYPE_SYMLINK){
! 		cm_ReleaseSCache(scp);
! 		return CM_ERROR_INVAL;
! 	}
! 
! 	code = cm_AssembleLink(scp, "", &amp;newRootScp, &amp;spacep, userp, &amp;req);
! 	cm_ReleaseSCache(scp);
! 	if (code == 0) {
! 		cp = ioctlp-&gt;outDatap;
! 		if (newRootScp != NULL) {
              strcpy(cp, cm_mountRoot);
              strcat(cp, "/");
! 			cp += strlen(cp);
! 		}
! 		strcpy(cp, spacep-&gt;data);
! 		cp += strlen(cp) + 1;
! 		ioctlp-&gt;outDatap = cp;
! 		cm_FreeSpace(spacep);
! 		if (newRootScp != NULL)
! 			cm_ReleaseSCache(newRootScp);
! 	}
  
! 	return code;
  }
  
  long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {/*CHECK FOR VALID SYMLINK*/
! 	long code;
! 	cm_scache_t *dscp;
! 	cm_scache_t *scp;
! 	char *cp;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
! 
! 	code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
! 	if (code) return code;
! 
! 	cp = ioctlp-&gt;inDatap;
! 	osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
! 
! 	code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
! 	cm_ReleaseSCache(dscp);
! 	if (code) return code;
! 
! 	/* Check that it's a real symlink */
! 	if (scp-&gt;fileType != CM_SCACHETYPE_SYMLINK)
! 		code = CM_ERROR_INVAL;
! 	cm_ReleaseSCache(scp);
! 	return code;
  }
  
  long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	long code;
!         cm_scache_t *dscp;
!         cm_scache_t *scp;
! 	char *cp;
!         cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
!         code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
!         if (code) return code;
  
!         cp = ioctlp-&gt;inDatap;
  
! 	code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
          
! 	/* if something went wrong, bail out now */
!         if (code) {
! 		goto done;
! 	}
          
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
!         code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!         	CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!         if (code) {
!         	lock_ReleaseMutex(&amp;scp-&gt;mx);
!         	cm_ReleaseSCache(scp);
! 		goto done;
! 	}
! 	
!         /* now check that this is a real symlink */
!         if (scp-&gt;fileType != CM_SCACHETYPE_SYMLINK) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
!         	cm_ReleaseSCache(scp);
!                 code = CM_ERROR_INVAL;
!                 goto done;
!         }
  	
!         /* time to make the RPC, so drop the lock */
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
          
! 	/* easier to do it this way */
!         code = cm_Unlink(dscp, cp, userp, &amp;req);
! 	if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 		smb_NotifyChange(FILE_ACTION_REMOVED,
! 				 FILE_NOTIFY_CHANGE_FILE_NAME
! 				   | FILE_NOTIFY_CHANGE_DIR_NAME,
! 				 dscp, cp, NULL, TRUE);
! 
! done:
! 	cm_ReleaseSCache(dscp);
! 	return code;
  }
  
  long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	char *saveDataPtr;
! 	char *tp;
! 	int ticketLen;
! 	char *ticket;
! 	int ctSize;
! 	struct ClearToken ct;
! 	cm_cell_t *cellp;
! 	cm_ucell_t *ucellp;
! 	char *uname = NULL;
! 	afs_uuid_t uuid;
! 	int flags;
! 	char sessionKey[8];
! 	char *smbname;
! 
! 	saveDataPtr = ioctlp-&gt;inDatap;
! 
! 	cm_SkipIoctlPath(ioctlp);
! 
! 	tp = ioctlp-&gt;inDatap;
! 
! 	/* ticket length */
! 	memcpy(&amp;ticketLen, tp, sizeof(ticketLen));
! 	tp += sizeof(ticketLen);
! 	if (ticketLen &lt; MINKTCTICKETLEN || ticketLen &gt; MAXKTCTICKETLEN)
! 		return CM_ERROR_INVAL;
! 
! 	/* remember ticket and skip over it for now */
! 	ticket = tp;
! 	tp += ticketLen;
! 
! 	/* clear token size */
! 	memcpy(&amp;ctSize, tp, sizeof(ctSize));
! 	tp += sizeof(ctSize);
! 	if (ctSize != sizeof(struct ClearToken))
! 		return CM_ERROR_INVAL;
! 
! 	/* clear token */
! 	memcpy(&amp;ct, tp, ctSize);
! 	tp += ctSize;
! 	if (ct.AuthHandle == -1)
! 		ct.AuthHandle = 999;	/* more rxvab compat stuff */
! 
! 	/* more stuff, if any */
! 	if (ioctlp-&gt;inCopied &gt; tp - saveDataPtr) {
! 		/* flags:  logon flag */
! 		memcpy(&amp;flags, tp, sizeof(int));
! 		tp += sizeof(int);
! 
! 		/* cell name */
! 		cellp = cm_GetCell(tp, CM_FLAG_CREATE);
! 		if (!cellp) return CM_ERROR_NOSUCHCELL;
! 		tp += strlen(tp) + 1;
! 
! 		/* user name */
! 		uname = tp;
! 		tp += strlen(tp) + 1;
  
          if (flags &amp; PIOCTL_LOGON) {
! 		  /* SMB user name with which to associate tokens */
! 		  smbname = tp;
!           osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
!                     osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
!           fprintf(stderr, "SMB name = %s\n", smbname);
! 		  tp += strlen(tp) + 1;
          } else {
              osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
!                       osi_LogSaveString(smb_logp,uname));
          }
  
  #ifndef DJGPP   /* for win95, session key is back in pioctl */
  		/* uuid */
! 		memcpy(&amp;uuid, tp, sizeof(uuid));
! 		if (!cm_FindTokenEvent(uuid, sessionKey))
! 			return CM_ERROR_INVAL;
  #endif /* !DJGPP */
! 	} else {
! 		cellp = cm_rootCellp;
          osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
      }
  
! 	if (flags &amp; PIOCTL_LOGON) {
!           userp = smb_FindCMUserByName(smbname, ioctlp-&gt;fidp-&gt;vcp-&gt;rname);
! 	}
! 	
! 	/* store the token */
! 	lock_ObtainMutex(&amp;userp-&gt;mx);
! 	ucellp = cm_GetUCell(userp, cellp);
      osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
! 	ucellp-&gt;ticketLen = ticketLen;
! 	if (ucellp-&gt;ticketp)
! 		free(ucellp-&gt;ticketp);	/* Discard old token if any */
! 	ucellp-&gt;ticketp = malloc(ticketLen);
! 	memcpy(ucellp-&gt;ticketp, ticket, ticketLen);
  #ifndef DJGPP
! 	/*
! 	 * Get the session key from the RPC, rather than from the pioctl.
! 	 */
! 	/*
! 	memcpy(&amp;ucellp-&gt;sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
! 	 */
! 	memcpy(ucellp-&gt;sessionKey.data, sessionKey, sizeof(sessionKey));
  #else
!         /* for win95, we are getting the session key from the pioctl */
!         memcpy(&amp;ucellp-&gt;sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
  #endif /* !DJGPP */
! 	ucellp-&gt;kvno = ct.AuthHandle;
! 	ucellp-&gt;expirationTime = ct.EndTimestamp;
! 	ucellp-&gt;gen++;
! 	if (uname) strcpy(ucellp-&gt;userName, uname);
! 	ucellp-&gt;flags |= CM_UCELLFLAG_RXKAD;
! 	lock_ReleaseMutex(&amp;userp-&gt;mx);
! 
! 	if (flags &amp; PIOCTL_LOGON) {
! 		ioctlp-&gt;flags |= SMB_IOCTLFLAG_LOGON;
! 	}
  
! 	cm_ResetACLCache(userp);
  
! 	return 0;
  }
  
  long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	char *tp, *cp;
! 	int iterator;
! 	int temp;
! 	cm_ucell_t *ucellp;
! 	struct ClearToken ct;
! 
! 	cm_SkipIoctlPath(ioctlp);
! 
! 	tp = ioctlp-&gt;inDatap;
! 	cp = ioctlp-&gt;outDatap;
! 
! 	/* iterator */
! 	memcpy(&amp;iterator, tp, sizeof(iterator));
! 	tp += sizeof(iterator);
! 
! 	lock_ObtainMutex(&amp;userp-&gt;mx);
! 
! 	/* look for token */
! 	for (;;iterator++) {
! 		ucellp = cm_FindUCell(userp, iterator);
! 		if (!ucellp) {
! 			lock_ReleaseMutex(&amp;userp-&gt;mx);
! 			return CM_ERROR_NOMORETOKENS;
! 		}
! 		if (ucellp-&gt;flags &amp; CM_UCELLFLAG_RXKAD)
! 			break;
! 	}
! 
! 	/* new iterator */
! 	temp = ucellp-&gt;iterator + 1;
! 	memcpy(cp, &amp;temp, sizeof(temp));
! 	cp += sizeof(temp);
! 
! 	/* ticket length */
! 	memcpy(cp, &amp;ucellp-&gt;ticketLen, sizeof(ucellp-&gt;ticketLen));
! 	cp += sizeof(ucellp-&gt;ticketLen);
! 
! 	/* ticket */
! 	memcpy(cp, ucellp-&gt;ticketp, ucellp-&gt;ticketLen);
! 	cp += ucellp-&gt;ticketLen;
! 
! 	/* clear token size */
! 	temp = sizeof(ct);
! 	memcpy(cp, &amp;temp, sizeof(temp));
! 	cp += sizeof(temp);
  
! 	/* clear token */
! 	ct.AuthHandle = ucellp-&gt;kvno;
  #ifndef DJGPP
! 	/*
! 	 * Don't give out a real session key here
! 	 */
! 	/*
! 	memcpy(ct.HandShakeKey, &amp;ucellp-&gt;sessionKey, sizeof(ct.HandShakeKey));
! 	 */
! 	memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
  #else
! 	memcpy(ct.HandShakeKey, &amp;ucellp-&gt;sessionKey, sizeof(ct.HandShakeKey));
  #endif /* !DJGPP */
! 	ct.ViceId = 37;			/* XXX */
! 	ct.BeginTimestamp = 0;		/* XXX */
! 	ct.EndTimestamp = ucellp-&gt;expirationTime;
! 	memcpy(cp, &amp;ct, sizeof(ct));
! 	cp += sizeof(ct);
! 
! 	/* Primary flag (unused) */
! 	temp = 0;
! 	memcpy(cp, &amp;temp, sizeof(temp));
! 	cp += sizeof(temp);
! 
! 	/* cell name */
! 	strcpy(cp, ucellp-&gt;cellp-&gt;namep);
! 	cp += strlen(cp) + 1;
! 
! 	/* user name */
! 	strcpy(cp, ucellp-&gt;userName);
! 	cp += strlen(cp) + 1;
  
! 	ioctlp-&gt;outDatap = cp;
  
! 	lock_ReleaseMutex(&amp;userp-&gt;mx);
  
! 	return 0;
  }
  
  long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	char *cp;
! 	int temp;
! 	cm_cell_t *cellp;
! 	cm_ucell_t *ucellp;
! 	struct ClearToken ct;
! 	char *tp;
  #ifndef DJGPP
! 	afs_uuid_t uuid;
  #endif /* !DJGPP */
  
! 	cm_SkipIoctlPath(ioctlp);
  
! 	tp = ioctlp-&gt;inDatap;
  
! 	cp = ioctlp-&gt;outDatap;
  
! 	/* cell name is right here */
! 	cellp = cm_GetCell(tp, 0);
! 	if (!cellp) return CM_ERROR_NOSUCHCELL;
! 	tp += strlen(tp) + 1;
  
  #ifndef DJGPP
! 	/* uuid */
! 	memcpy(&amp;uuid, tp, sizeof(uuid));
  #endif /* !DJGPP */
  
! 	lock_ObtainMutex(&amp;userp-&gt;mx);
  
! 	ucellp = cm_GetUCell(userp, cellp);
! 	if (!ucellp || !(ucellp-&gt;flags &amp; CM_UCELLFLAG_RXKAD)) {
! 		lock_ReleaseMutex(&amp;userp-&gt;mx);
! 		return CM_ERROR_NOMORETOKENS;
! 	}
! 
! 	/* ticket length */
! 	memcpy(cp, &amp;ucellp-&gt;ticketLen, sizeof(ucellp-&gt;ticketLen));
! 	cp += sizeof(ucellp-&gt;ticketLen);
! 
! 	/* ticket */
! 	memcpy(cp, ucellp-&gt;ticketp, ucellp-&gt;ticketLen);
! 	cp += ucellp-&gt;ticketLen;
! 
! 	/* clear token size */
! 	temp = sizeof(ct);
! 	memcpy(cp, &amp;temp, sizeof(temp));
! 	cp += sizeof(temp);
  
! 	/* clear token */
! 	ct.AuthHandle = ucellp-&gt;kvno;
  #ifndef DJGPP
! 	/*
! 	 * Don't give out a real session key here
! 	 */
! 	/*
! 	memcpy(ct.HandShakeKey, &amp;ucellp-&gt;sessionKey, sizeof(ct.HandShakeKey));
! 	 */
! 	memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
  #else
!         memcpy(ct.HandShakeKey, &amp;ucellp-&gt;sessionKey, sizeof(ct.HandShakeKey));
  #endif /* !DJGPP */
! 	ct.ViceId = 37;			/* XXX */
! 	ct.BeginTimestamp = 0;		/* XXX */
! 	ct.EndTimestamp = ucellp-&gt;expirationTime;
! 	memcpy(cp, &amp;ct, sizeof(ct));
! 	cp += sizeof(ct);
! 
! 	/* Primary flag (unused) */
! 	temp = 0;
! 	memcpy(cp, &amp;temp, sizeof(temp));
! 	cp += sizeof(temp);
! 
! 	/* cell name */
! 	strcpy(cp, ucellp-&gt;cellp-&gt;namep);
! 	cp += strlen(cp) + 1;
! 
! 	/* user name */
! 	strcpy(cp, ucellp-&gt;userName);
! 	cp += strlen(cp) + 1;
  
! 	ioctlp-&gt;outDatap = cp;
  
! 	lock_ReleaseMutex(&amp;userp-&gt;mx);
  
  #ifndef DJGPP
! 	cm_RegisterNewTokenEvent(uuid, ucellp-&gt;sessionKey.data);
  #endif /* !DJGPP */
  
! 	return 0;
  }
  
  long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	char *cp;
! 	cm_cell_t *cellp;
! 	cm_ucell_t *ucellp;
! 
! 	cm_SkipIoctlPath(ioctlp);
! 
! 	cp = ioctlp-&gt;outDatap;
  
! 	/* cell name is right here */
! 	cellp = cm_GetCell(ioctlp-&gt;inDatap, 0);
! 	if (!cellp) return CM_ERROR_NOSUCHCELL;
  
! 	lock_ObtainMutex(&amp;userp-&gt;mx);
  
! 	ucellp = cm_GetUCell(userp, cellp);
! 	if (!ucellp) {
! 		lock_ReleaseMutex(&amp;userp-&gt;mx);
! 		return CM_ERROR_NOMORETOKENS;
! 	}
  
      osi_Log1(smb_logp,"cm_IoctlDelToken ucellp %lx", ucellp);
  
! 	if (ucellp-&gt;ticketp) {
! 		free(ucellp-&gt;ticketp);
! 		ucellp-&gt;ticketp = NULL;
! 	}
! 	ucellp-&gt;flags &amp;= ~CM_UCELLFLAG_RXKAD;
! 	ucellp-&gt;gen++;
  
! 	lock_ReleaseMutex(&amp;userp-&gt;mx);
  
! 	cm_ResetACLCache(userp);
  
! 	return 0;
  }
  
  long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
! 	cm_ucell_t *ucellp;
  
! 	lock_ObtainMutex(&amp;userp-&gt;mx);
  
      for (ucellp = userp-&gt;cellInfop; ucellp; ucellp = ucellp-&gt;nextp) {
          osi_Log1(smb_logp,"cm_IoctlDelAllToken ucellp %lx", ucellp);
! 		ucellp-&gt;flags &amp;= ~CM_UCELLFLAG_RXKAD;
! 		ucellp-&gt;gen++;
! 	}
  
! 	lock_ReleaseMutex(&amp;userp-&gt;mx);
  
! 	cm_ResetACLCache(userp);
  
! 	return 0;
  }
  
  long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
! 	char afspath[MAX_PATH];
! 	char *submountreqp;
! 	int nextAutoSubmount;
      HKEY hkSubmounts;
      DWORD dwType, dwSize;
      DWORD status;
      DWORD dwIndex;
      DWORD dwSubmounts;
  
! 	cm_SkipIoctlPath(ioctlp);
  
! 	/* Serialize this one, to prevent simultaneous mods
! 	 * to afsdsbmt.ini
! 	 */
! 	lock_ObtainMutex(&amp;cm_Afsdsbmt_Lock);
! 
! 	/* Parse the input parameters--first the required afs path,
! 	 * then the requested submount name (which may be "").
! 	 */
! 	cm_NormalizeAfsPath (afspath, ioctlp-&gt;inDatap);
! 	submountreqp = ioctlp-&gt;inDatap + (strlen(ioctlp-&gt;inDatap)+1);
! 
! 	/* If the caller supplied a suggested submount name, see if
! 	 * that submount name is in use... if so, the submount's path
! 	 * has to match our path.
! 	 */
  
      RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
                      "SOFTWARE\\OpenAFS\\Client\\Submounts",
--- 1489,2051 ----
  
  long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     char leaf[256];
!     long code;
!     cm_scache_t *dscp;
!     cm_attr_t tattr;
!     char *cp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlParent(ioctlp, userp, &amp;req, &amp;dscp, leaf);
!     if (code) return code;
  
!     /* Translate chars for the link name */
!     TranslateExtendedChars(leaf);
  
!     /* Translate chars for the linked to name */
!     TranslateExtendedChars(ioctlp-&gt;inDatap);
  
!     cp = ioctlp-&gt;inDatap;		/* contents of link */
  
!     /* Create symlink with mode 0755. */
!     tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
!     tattr.unixModeBits = 0755;
! 
!     code = cm_SymLink(dscp, leaf, cp, 0, &amp;tattr, userp, &amp;req);
!     if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!         smb_NotifyChange(FILE_ACTION_ADDED,
!                           FILE_NOTIFY_CHANGE_FILE_NAME
!                           | FILE_NOTIFY_CHANGE_DIR_NAME,
!                           dscp, leaf, NULL, TRUE);
  
!     cm_ReleaseSCache(dscp);
  
!     return code;
  }
  
  extern long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
!                             cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
!                             cm_user_t *userp, cm_req_t *reqp);
  
  long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *dscp;
!     cm_scache_t *scp;
!     char *cp;
!     cm_space_t *spacep;
!     cm_scache_t *newRootScp;
!     cm_req_t req;
! 
!     cm_InitReq(&amp;req);
! 
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
!     if (code) return code;
! 
!     cp = ioctlp-&gt;inDatap;
! 
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
!     cm_ReleaseSCache(dscp);
!     if (code) return code;
! 
!     /* Check that it's a real symlink */
!     if (scp-&gt;fileType != CM_SCACHETYPE_SYMLINK){
!         cm_ReleaseSCache(scp);
!         return CM_ERROR_INVAL;
!     }
! 
!     code = cm_AssembleLink(scp, "", &amp;newRootScp, &amp;spacep, userp, &amp;req);
!     cm_ReleaseSCache(scp);
!     if (code == 0) {
!         cp = ioctlp-&gt;outDatap;
!         if (newRootScp != NULL) {
              strcpy(cp, cm_mountRoot);
              strcat(cp, "/");
!             cp += strlen(cp);
!         }
!         strcpy(cp, spacep-&gt;data);
!         cp += strlen(cp) + 1;
!         ioctlp-&gt;outDatap = cp;
!         cm_FreeSpace(spacep);
!         if (newRootScp != NULL)
!             cm_ReleaseSCache(newRootScp);
!     }       
  
!     return code;
  }
  
  long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {/*CHECK FOR VALID SYMLINK*/
!     long code;
!     cm_scache_t *dscp;
!     cm_scache_t *scp;
!     char *cp;
!     cm_req_t req;
! 
!     cm_InitReq(&amp;req);
! 
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
!     if (code) return code;
! 
!     cp = ioctlp-&gt;inDatap;
!     osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
! 
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
!     cm_ReleaseSCache(dscp);
!     if (code) return code;
! 
!     /* Check that it's a real symlink */
!     if (scp-&gt;fileType != CM_SCACHETYPE_SYMLINK)
!         code = CM_ERROR_INVAL;
!     cm_ReleaseSCache(scp);
!     return code;
  }
  
  long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *dscp;
!     cm_scache_t *scp;
!     char *cp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &amp;req, &amp;dscp);
!     if (code) return code;
  
!     cp = ioctlp-&gt;inDatap;
  
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &amp;req, &amp;scp);
          
!     /* if something went wrong, bail out now */
!     if (code) {
!         goto done;
!     }
          
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) {     
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         cm_ReleaseSCache(scp);
!         goto done;
!     }
  	
!     /* now check that this is a real symlink */
!     if (scp-&gt;fileType != CM_SCACHETYPE_SYMLINK) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
+         code = CM_ERROR_INVAL;
+         goto done;
+     }
+ 	
+     /* time to make the RPC, so drop the lock */
+     lock_ReleaseMutex(&amp;scp-&gt;mx);
+     cm_ReleaseSCache(scp);
          
!     /* easier to do it this way */
!     code = cm_Unlink(dscp, cp, userp, &amp;req);
!     if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!         smb_NotifyChange(FILE_ACTION_REMOVED,
!                           FILE_NOTIFY_CHANGE_FILE_NAME
!                           | FILE_NOTIFY_CHANGE_DIR_NAME,
!                           dscp, cp, NULL, TRUE);
! 
!   done:
!     cm_ReleaseSCache(dscp);
!     return code;
  }
  
  long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     char *saveDataPtr;
!     char *tp;
!     int ticketLen;
!     char *ticket;
!     int ctSize;
!     struct ClearToken ct;
!     cm_cell_t *cellp;
!     cm_ucell_t *ucellp;
!     char *uname = NULL;
!     afs_uuid_t uuid;
!     int flags;
!     char sessionKey[8];
!     char *smbname;
! 
!     saveDataPtr = ioctlp-&gt;inDatap;
! 
!     cm_SkipIoctlPath(ioctlp);
! 
!     tp = ioctlp-&gt;inDatap;
! 
!     /* ticket length */
!     memcpy(&amp;ticketLen, tp, sizeof(ticketLen));
!     tp += sizeof(ticketLen);
!     if (ticketLen &lt; MINKTCTICKETLEN || ticketLen &gt; MAXKTCTICKETLEN)
!         return CM_ERROR_INVAL;
! 
!     /* remember ticket and skip over it for now */
!     ticket = tp;
!     tp += ticketLen;
! 
!     /* clear token size */
!     memcpy(&amp;ctSize, tp, sizeof(ctSize));
!     tp += sizeof(ctSize);
!     if (ctSize != sizeof(struct ClearToken))
!         return CM_ERROR_INVAL;
! 
!     /* clear token */
!     memcpy(&amp;ct, tp, ctSize);
!     tp += ctSize;
!     if (ct.AuthHandle == -1)
!         ct.AuthHandle = 999;	/* more rxvab compat stuff */
! 
!     /* more stuff, if any */
!     if (ioctlp-&gt;inCopied &gt; tp - saveDataPtr) {
!         /* flags:  logon flag */
!         memcpy(&amp;flags, tp, sizeof(int));
!         tp += sizeof(int);
! 
!         /* cell name */
!         cellp = cm_GetCell(tp, CM_FLAG_CREATE);
!         if (!cellp) return CM_ERROR_NOSUCHCELL;
!         tp += strlen(tp) + 1;
! 
!         /* user name */
!         uname = tp;
!         tp += strlen(tp) + 1;
  
          if (flags &amp; PIOCTL_LOGON) {
!             /* SMB user name with which to associate tokens */
!             smbname = tp;
!             osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
!                      osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
!             fprintf(stderr, "SMB name = %s\n", smbname);
!             tp += strlen(tp) + 1;
          } else {
              osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
!                      osi_LogSaveString(smb_logp,uname));
          }
  
  #ifndef DJGPP   /* for win95, session key is back in pioctl */
  		/* uuid */
!         memcpy(&amp;uuid, tp, sizeof(uuid));
!         if (!cm_FindTokenEvent(uuid, sessionKey))
!             return CM_ERROR_INVAL;
  #endif /* !DJGPP */
!     } else {
!         cellp = cm_rootCellp;
          osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
      }
  
!     if (flags &amp; PIOCTL_LOGON) {
!         userp = smb_FindCMUserByName(smbname, ioctlp-&gt;fidp-&gt;vcp-&gt;rname);
!     }
! 
!     /* store the token */
!     lock_ObtainMutex(&amp;userp-&gt;mx);
!     ucellp = cm_GetUCell(userp, cellp);
      osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
!     ucellp-&gt;ticketLen = ticketLen;
!     if (ucellp-&gt;ticketp)
!         free(ucellp-&gt;ticketp);	/* Discard old token if any */
!     ucellp-&gt;ticketp = malloc(ticketLen);
!     memcpy(ucellp-&gt;ticketp, ticket, ticketLen);
  #ifndef DJGPP
!     /*
!      * Get the session key from the RPC, rather than from the pioctl.
!      */
!     /*
!     memcpy(&amp;ucellp-&gt;sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
!     */
!     memcpy(ucellp-&gt;sessionKey.data, sessionKey, sizeof(sessionKey));
  #else
!     /* for win95, we are getting the session key from the pioctl */
!     memcpy(&amp;ucellp-&gt;sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
  #endif /* !DJGPP */
!     ucellp-&gt;kvno = ct.AuthHandle;
!     ucellp-&gt;expirationTime = ct.EndTimestamp;
!     ucellp-&gt;gen++;
!     if (uname) strcpy(ucellp-&gt;userName, uname);
!     ucellp-&gt;flags |= CM_UCELLFLAG_RXKAD;
!     lock_ReleaseMutex(&amp;userp-&gt;mx);
! 
!     if (flags &amp; PIOCTL_LOGON) {
!         ioctlp-&gt;flags |= SMB_IOCTLFLAG_LOGON;
!     }
  
!     cm_ResetACLCache(userp);
  
!     return 0;
  }
  
  long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     char *tp, *cp;
!     int iterator;
!     int temp;
!     cm_ucell_t *ucellp;
!     struct ClearToken ct;
! 
!     cm_SkipIoctlPath(ioctlp);
! 
!     tp = ioctlp-&gt;inDatap;
!     cp = ioctlp-&gt;outDatap;
! 
!     /* iterator */
!     memcpy(&amp;iterator, tp, sizeof(iterator));
!     tp += sizeof(iterator);
! 
!     lock_ObtainMutex(&amp;userp-&gt;mx);
! 
!     /* look for token */
!     for (;;iterator++) {
!         ucellp = cm_FindUCell(userp, iterator);
!         if (!ucellp) {
!             lock_ReleaseMutex(&amp;userp-&gt;mx);
!             return CM_ERROR_NOMORETOKENS;
!         }
!         if (ucellp-&gt;flags &amp; CM_UCELLFLAG_RXKAD)
!             break;
!     }       
! 
!     /* new iterator */
!     temp = ucellp-&gt;iterator + 1;
!     memcpy(cp, &amp;temp, sizeof(temp));
!     cp += sizeof(temp);
! 
!     /* ticket length */
!     memcpy(cp, &amp;ucellp-&gt;ticketLen, sizeof(ucellp-&gt;ticketLen));
!     cp += sizeof(ucellp-&gt;ticketLen);
! 
!     /* ticket */
!     memcpy(cp, ucellp-&gt;ticketp, ucellp-&gt;ticketLen);
!     cp += ucellp-&gt;ticketLen;
! 
!     /* clear token size */
!     temp = sizeof(ct);
!     memcpy(cp, &amp;temp, sizeof(temp));
!     cp += sizeof(temp);
  
!     /* clear token */
!     ct.AuthHandle = ucellp-&gt;kvno;
  #ifndef DJGPP
!     /*
!      * Don't give out a real session key here
!      */
!     /*
!     memcpy(ct.HandShakeKey, &amp;ucellp-&gt;sessionKey, sizeof(ct.HandShakeKey));
!     */
!     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
  #else
!     memcpy(ct.HandShakeKey, &amp;ucellp-&gt;sessionKey, sizeof(ct.HandShakeKey));
  #endif /* !DJGPP */
!     ct.ViceId = 37;			/* XXX */
!     ct.BeginTimestamp = 0;		/* XXX */
!     ct.EndTimestamp = ucellp-&gt;expirationTime;
!     memcpy(cp, &amp;ct, sizeof(ct));
!     cp += sizeof(ct);
! 
!     /* Primary flag (unused) */
!     temp = 0;
!     memcpy(cp, &amp;temp, sizeof(temp));
!     cp += sizeof(temp);
! 
!     /* cell name */
!     strcpy(cp, ucellp-&gt;cellp-&gt;namep);
!     cp += strlen(cp) + 1;
! 
!     /* user name */
!     strcpy(cp, ucellp-&gt;userName);
!     cp += strlen(cp) + 1;
  
!     ioctlp-&gt;outDatap = cp;
  
!     lock_ReleaseMutex(&amp;userp-&gt;mx);
  
!     return 0;
  }
  
  long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     char *cp;
!     int temp;
!     cm_cell_t *cellp;
!     cm_ucell_t *ucellp;
!     struct ClearToken ct;
!     char *tp;
  #ifndef DJGPP
!     afs_uuid_t uuid;
  #endif /* !DJGPP */
  
!     cm_SkipIoctlPath(ioctlp);
  
!     tp = ioctlp-&gt;inDatap;
  
!     cp = ioctlp-&gt;outDatap;
  
!     /* cell name is right here */
!     cellp = cm_GetCell(tp, 0);
!     if (!cellp) return CM_ERROR_NOSUCHCELL;
!     tp += strlen(tp) + 1;
  
  #ifndef DJGPP
!     /* uuid */
!     memcpy(&amp;uuid, tp, sizeof(uuid));
  #endif /* !DJGPP */
  
!     lock_ObtainMutex(&amp;userp-&gt;mx);
! 
!     ucellp = cm_GetUCell(userp, cellp);
!     if (!ucellp || !(ucellp-&gt;flags &amp; CM_UCELLFLAG_RXKAD)) {
!         lock_ReleaseMutex(&amp;userp-&gt;mx);
!         return CM_ERROR_NOMORETOKENS;
!     }
  
!     /* ticket length */
!     memcpy(cp, &amp;ucellp-&gt;ticketLen, sizeof(ucellp-&gt;ticketLen));
!     cp += sizeof(ucellp-&gt;ticketLen);
! 
!     /* ticket */
!     memcpy(cp, ucellp-&gt;ticketp, ucellp-&gt;ticketLen);
!     cp += ucellp-&gt;ticketLen;
! 
!     /* clear token size */
!     temp = sizeof(ct);
!     memcpy(cp, &amp;temp, sizeof(temp));
!     cp += sizeof(temp);
  
!     /* clear token */
!     ct.AuthHandle = ucellp-&gt;kvno;
  #ifndef DJGPP
!     /*
!      * Don't give out a real session key here
!      */
!     /*
!     memcpy(ct.HandShakeKey, &amp;ucellp-&gt;sessionKey, sizeof(ct.HandShakeKey));
!     */
!     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
  #else
!     memcpy(ct.HandShakeKey, &amp;ucellp-&gt;sessionKey, sizeof(ct.HandShakeKey));
  #endif /* !DJGPP */
!     ct.ViceId = 37;			/* XXX */
!     ct.BeginTimestamp = 0;		/* XXX */
!     ct.EndTimestamp = ucellp-&gt;expirationTime;
!     memcpy(cp, &amp;ct, sizeof(ct));
!     cp += sizeof(ct);
! 
!     /* Primary flag (unused) */
!     temp = 0;
!     memcpy(cp, &amp;temp, sizeof(temp));
!     cp += sizeof(temp);
! 
!     /* cell name */
!     strcpy(cp, ucellp-&gt;cellp-&gt;namep);
!     cp += strlen(cp) + 1;
! 
!     /* user name */
!     strcpy(cp, ucellp-&gt;userName);
!     cp += strlen(cp) + 1;
  
!     ioctlp-&gt;outDatap = cp;
  
!     lock_ReleaseMutex(&amp;userp-&gt;mx);
  
  #ifndef DJGPP
!     cm_RegisterNewTokenEvent(uuid, ucellp-&gt;sessionKey.data);
  #endif /* !DJGPP */
  
!     return 0;
  }
  
  long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     char *cp;
!     cm_cell_t *cellp;
!     cm_ucell_t *ucellp;
  
!     cm_SkipIoctlPath(ioctlp);
  
!     cp = ioctlp-&gt;outDatap;
  
!     /* cell name is right here */
!     cellp = cm_GetCell(ioctlp-&gt;inDatap, 0);
!     if (!cellp) return CM_ERROR_NOSUCHCELL;
! 
!     lock_ObtainMutex(&amp;userp-&gt;mx);
! 
!     ucellp = cm_GetUCell(userp, cellp);
!     if (!ucellp) {
!         lock_ReleaseMutex(&amp;userp-&gt;mx);
!         return CM_ERROR_NOMORETOKENS;
!     }
  
      osi_Log1(smb_logp,"cm_IoctlDelToken ucellp %lx", ucellp);
  
!     if (ucellp-&gt;ticketp) {
!         free(ucellp-&gt;ticketp);
!         ucellp-&gt;ticketp = NULL;
!     }
!     ucellp-&gt;flags &amp;= ~CM_UCELLFLAG_RXKAD;
!     ucellp-&gt;gen++;
  
!     lock_ReleaseMutex(&amp;userp-&gt;mx);
  
!     cm_ResetACLCache(userp);
  
!     return 0;
  }
  
  long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_ucell_t *ucellp;
  
!     lock_ObtainMutex(&amp;userp-&gt;mx);
  
      for (ucellp = userp-&gt;cellInfop; ucellp; ucellp = ucellp-&gt;nextp) {
          osi_Log1(smb_logp,"cm_IoctlDelAllToken ucellp %lx", ucellp);
!         ucellp-&gt;flags &amp;= ~CM_UCELLFLAG_RXKAD;
!         ucellp-&gt;gen++;
!     }
  
!     lock_ReleaseMutex(&amp;userp-&gt;mx);
  
!     cm_ResetACLCache(userp);
  
!     return 0;
  }
  
  long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     char afspath[MAX_PATH];
!     char *submountreqp;
!     int nextAutoSubmount;
      HKEY hkSubmounts;
      DWORD dwType, dwSize;
      DWORD status;
      DWORD dwIndex;
      DWORD dwSubmounts;
  
!     cm_SkipIoctlPath(ioctlp);
! 
!     /* Serialize this one, to prevent simultaneous mods
!      * to afsdsbmt.ini
!      */
!     lock_ObtainMutex(&amp;cm_Afsdsbmt_Lock);
! 
!     /* Parse the input parameters--first the required afs path,
!      * then the requested submount name (which may be "").
!      */
!     cm_NormalizeAfsPath (afspath, ioctlp-&gt;inDatap);
!     submountreqp = ioctlp-&gt;inDatap + (strlen(ioctlp-&gt;inDatap)+1);
  
!     /* If the caller supplied a suggested submount name, see if
!      * that submount name is in use... if so, the submount's path
!      * has to match our path.
!      */
  
      RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
                      "SOFTWARE\\OpenAFS\\Client\\Submounts",
***************
*** 2029,2050 ****
                      NULL );
  
      if (submountreqp &amp;&amp; *submountreqp) {
! 		char submountPathNormalized[MAX_PATH];
! 		char submountPath[MAX_PATH];
  
          dwSize = sizeof(submountPath);
          status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
!                          &amp;dwType, submountPath, &amp;dwSize);
  
! 		if (status != ERROR_SUCCESS) {
  
! 			/* The suggested submount name isn't in use now--
! 			 * so we can safely map the requested submount name
! 			 * to the supplied path. Remember not to write the
! 			 * leading "/afs" when writing out the submount.
! 			 */
              RegSetValueEx( hkSubmounts, submountreqp, 0,
!                            REG_SZ, 
                             (strlen(&amp;afspath[strlen(cm_mountRoot)])) ?
                             &amp;afspath[strlen(cm_mountRoot)]:"/",
                             (strlen(&amp;afspath[strlen(cm_mountRoot)])) ?
--- 2058,2079 ----
                      NULL );
  
      if (submountreqp &amp;&amp; *submountreqp) {
!         char submountPathNormalized[MAX_PATH];
!         char submountPath[MAX_PATH];
  
          dwSize = sizeof(submountPath);
          status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
!                                   &amp;dwType, submountPath, &amp;dwSize);
  
!         if (status != ERROR_SUCCESS) {
  
!             /* The suggested submount name isn't in use now--
!              * so we can safely map the requested submount name
!              * to the supplied path. Remember not to write the
!              * leading "/afs" when writing out the submount.
!              */
              RegSetValueEx( hkSubmounts, submountreqp, 0,
!                            REG_EXPAND_SZ, 
                             (strlen(&amp;afspath[strlen(cm_mountRoot)])) ?
                             &amp;afspath[strlen(cm_mountRoot)]:"/",
                             (strlen(&amp;afspath[strlen(cm_mountRoot)])) ?
***************
*** 2055,2177 ****
  			ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
  			lock_ReleaseMutex(&amp;cm_Afsdsbmt_Lock);
              return 0;
! 		}
  
! 		/* The suggested submount name is already in use--if the
! 		 * supplied path matches the submount's path, we can still
! 		 * use the suggested submount name.
! 		 */
! 		cm_NormalizeAfsPath (submountPathNormalized, submountPath);
! 		if (!strcmp (submountPathNormalized, afspath)) {
! 			strcpy(ioctlp-&gt;outDatap, submountreqp);
! 			ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
              RegCloseKey( hkSubmounts );
! 			lock_ReleaseMutex(&amp;cm_Afsdsbmt_Lock);
              return 0;
! 		}
! 	}
  
      RegQueryInfoKey( hkSubmounts,
!                  NULL,  /* lpClass */
!                  NULL,  /* lpcClass */
!                  NULL,  /* lpReserved */
!                  NULL,  /* lpcSubKeys */
!                  NULL,  /* lpcMaxSubKeyLen */
!                  NULL,  /* lpcMaxClassLen */
!                  &amp;dwSubmounts, /* lpcValues */
!                  NULL,  /* lpcMaxValueNameLen */
!                  NULL,  /* lpcMaxValueLen */
!                  NULL,  /* lpcbSecurityDescriptor */
!                  NULL   /* lpftLastWriteTime */
!                  );
! 
! 
! 	/* Having obtained a list of all available submounts, start
! 	 * searching that list for a path which matches the requested
! 	 * AFS path. We'll also keep track of the highest "auto15"/"auto47"
! 	 * submount, in case we need to add a new one later.
! 	 */
  
! 	nextAutoSubmount = 1;
  
      for ( dwIndex = 0; dwIndex &lt; dwSubmounts; dwIndex ++ ) {
! 		char submountPathNormalized[MAX_PATH];
! 		char submountPath[MAX_PATH] = "";
! 		DWORD submountPathLen = sizeof(submountPath);
!         char submountName[256];
          DWORD submountNameLen = sizeof(submountName);
  
          RegEnumValue( hkSubmounts, dwIndex, submountName, &amp;submountNameLen, NULL,
!               &amp;dwType, submountPath, &amp;submountPathLen);
  
! 		/* If this is an Auto### submount, remember its ### value */
  
! 		if ((!strnicmp (submountName, "auto", 4)) &amp;&amp;
! 		    (isdigit (submountName[strlen("auto")]))) {
! 			int thisAutoSubmount;
! 			thisAutoSubmount = atoi (&amp;submountName[strlen("auto")]);
! 			nextAutoSubmount = max (nextAutoSubmount,
! 						thisAutoSubmount+1);
! 		}
! 
! 		if ((submountPathLen == 0) ||
! 		    (submountPathLen == sizeof(submountPath) - 1)) {
! 			continue;
! 		}
! 
! 		/* See if the path for this submount matches the path
! 		 * that our caller specified. If so, we can return
! 		 * this submount.
! 		 */
! 		cm_NormalizeAfsPath (submountPathNormalized, submountPath);
! 		if (!strcmp (submountPathNormalized, afspath)) {
! 			strcpy(ioctlp-&gt;outDatap, submountName);
! 			ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
              RegCloseKey(hkSubmounts);
! 			lock_ReleaseMutex(&amp;cm_Afsdsbmt_Lock);
              return 0;
  
! 		}
! 	}
  
! 	/* We've been through the entire list of existing submounts, and
! 	 * didn't find any which matched the specified path. So, we'll
! 	 * just have to add one. Remember not to write the leading "/afs"
! 	 * when writing out the submount.
! 	 */
  
! 	sprintf(ioctlp-&gt;outDatap, "auto%ld", nextAutoSubmount);
  
      RegSetValueEx( hkSubmounts, 
                     ioctlp-&gt;outDatap,
                     0,
!                    REG_SZ, 
                     (strlen(&amp;afspath[strlen(cm_mountRoot)])) ?
                     &amp;afspath[strlen(cm_mountRoot)]:"/",
                     (strlen(&amp;afspath[strlen(cm_mountRoot)])) ?
                     strlen(&amp;afspath[strlen(cm_mountRoot)])+1:2);
  
! 	ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
      RegCloseKey(hkSubmounts);
! 	lock_ReleaseMutex(&amp;cm_Afsdsbmt_Lock);
! 	return 0;
  }
  
  long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
! 	memcpy(ioctlp-&gt;outDatap, &amp;cryptall, sizeof(cryptall));
!         ioctlp-&gt;outDatap += sizeof(cryptall);
  
! 	return 0;
  }
  
  long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
! 	cm_SkipIoctlPath(ioctlp);
  
! 	memcpy(&amp;cryptall, ioctlp-&gt;inDatap, sizeof(cryptall));
  
! 	return 0;
  }
  
  #ifdef DJGPP
--- 2084,2213 ----
  			ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
  			lock_ReleaseMutex(&amp;cm_Afsdsbmt_Lock);
              return 0;
!         }
  
!         /* The suggested submount name is already in use--if the
!          * supplied path matches the submount's path, we can still
!          * use the suggested submount name.
!          */
!         cm_NormalizeAfsPath (submountPathNormalized, submountPath);
!         if (!strcmp (submountPathNormalized, afspath)) {
!             strcpy(ioctlp-&gt;outDatap, submountreqp);
!             ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
              RegCloseKey( hkSubmounts );
!             lock_ReleaseMutex(&amp;cm_Afsdsbmt_Lock);
              return 0;
!         }
!     }
  
      RegQueryInfoKey( hkSubmounts,
!                      NULL,  /* lpClass */
!                      NULL,  /* lpcClass */
!                      NULL,  /* lpReserved */
!                      NULL,  /* lpcSubKeys */
!                      NULL,  /* lpcMaxSubKeyLen */
!                      NULL,  /* lpcMaxClassLen */
!                      &amp;dwSubmounts, /* lpcValues */
!                      NULL,  /* lpcMaxValueNameLen */
!                      NULL,  /* lpcMaxValueLen */
!                      NULL,  /* lpcbSecurityDescriptor */
!                      NULL   /* lpftLastWriteTime */
!                      );
! 
! 
!     /* Having obtained a list of all available submounts, start
!      * searching that list for a path which matches the requested
!      * AFS path. We'll also keep track of the highest "auto15"/"auto47"
!      * submount, in case we need to add a new one later.
!      */
  
!     nextAutoSubmount = 1;
  
      for ( dwIndex = 0; dwIndex &lt; dwSubmounts; dwIndex ++ ) {
!         char submountPathNormalized[MAX_PATH];
!         char submountPath[MAX_PATH] = "";
!         DWORD submountPathLen = sizeof(submountPath);
!         char submountName[MAX_PATH];
          DWORD submountNameLen = sizeof(submountName);
  
+         dwType = 0;
          RegEnumValue( hkSubmounts, dwIndex, submountName, &amp;submountNameLen, NULL,
!                       &amp;dwType, submountPath, &amp;submountPathLen);
!         if (dwType == REG_EXPAND_SZ) {
!             char buf[MAX_PATH];
!             StringCbCopyA(buf, MAX_PATH, submountPath);
!             submountPathLen = ExpandEnvironmentStrings(buf, submountPath, MAX_PATH);
!             if (submountPathLen &gt; MAX_PATH)
!                 continue;
!         }
  
!         /* If this is an Auto### submount, remember its ### value */
!         if ((!strnicmp (submountName, "auto", 4)) &amp;&amp;
!              (isdigit (submountName[strlen("auto")]))) {
!             int thisAutoSubmount;
!             thisAutoSubmount = atoi (&amp;submountName[strlen("auto")]);
!             nextAutoSubmount = max (nextAutoSubmount,
!                                      thisAutoSubmount+1);
!         }       
! 
!         if ((submountPathLen == 0) ||
!              (submountPathLen == sizeof(submountPath) - 1)) {
!             continue;
!         }
  
!         /* See if the path for this submount matches the path
!          * that our caller specified. If so, we can return
!          * this submount.
!          */
!         cm_NormalizeAfsPath (submountPathNormalized, submountPath);
!         if (!strcmp (submountPathNormalized, afspath)) {
!             strcpy(ioctlp-&gt;outDatap, submountName);
!             ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
              RegCloseKey(hkSubmounts);
!             lock_ReleaseMutex(&amp;cm_Afsdsbmt_Lock);
              return 0;
  
!         }
!     }
  
!     /* We've been through the entire list of existing submounts, and
!      * didn't find any which matched the specified path. So, we'll
!      * just have to add one. Remember not to write the leading "/afs"
!      * when writing out the submount.
!      */
  
!     sprintf(ioctlp-&gt;outDatap, "auto%ld", nextAutoSubmount);
  
      RegSetValueEx( hkSubmounts, 
                     ioctlp-&gt;outDatap,
                     0,
!                    REG_EXPAND_SZ, 
                     (strlen(&amp;afspath[strlen(cm_mountRoot)])) ?
                     &amp;afspath[strlen(cm_mountRoot)]:"/",
                     (strlen(&amp;afspath[strlen(cm_mountRoot)])) ?
                     strlen(&amp;afspath[strlen(cm_mountRoot)])+1:2);
  
!     ioctlp-&gt;outDatap += strlen(ioctlp-&gt;outDatap) +1;
      RegCloseKey(hkSubmounts);
!     lock_ReleaseMutex(&amp;cm_Afsdsbmt_Lock);
!     return 0;
  }
  
  long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     memcpy(ioctlp-&gt;outDatap, &amp;cryptall, sizeof(cryptall));
!     ioctlp-&gt;outDatap += sizeof(cryptall);
  
!     return 0;
  }
  
  long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     cm_SkipIoctlPath(ioctlp);
  
!     memcpy(&amp;cryptall, ioctlp-&gt;inDatap, sizeof(cryptall));
  
!     return 0;
  }
  
  #ifdef DJGPP
***************
*** 2191,2197 ****
    if (uidp &amp;&amp; uidp-&gt;unp) {
      memcpy(ioctlp-&gt;outDatap, uidp-&gt;unp-&gt;name, strlen(uidp-&gt;unp-&gt;name));
      ioctlp-&gt;outDatap += strlen(uidp-&gt;unp-&gt;name);
! 	}
  
    return 0;
  }
--- 2227,2233 ----
    if (uidp &amp;&amp; uidp-&gt;unp) {
      memcpy(ioctlp-&gt;outDatap, uidp-&gt;unp-&gt;name, strlen(uidp-&gt;unp-&gt;name));
      ioctlp-&gt;outDatap += strlen(uidp-&gt;unp-&gt;name);
!   }
  
    return 0;
  }
Index: openafs/src/WINNT/afsd/cm_ioctl.h
diff -c openafs/src/WINNT/afsd/cm_ioctl.h:1.8 openafs/src/WINNT/afsd/cm_ioctl.h:1.8.2.1
*** openafs/src/WINNT/afsd/cm_ioctl.h:1.8	Sat Jun 19 12:00:13 2004
--- openafs/src/WINNT/afsd/cm_ioctl.h	Sun Oct 10 19:52:05 2004
***************
*** 43,51 ****
  
  #define MAXNUMSYSNAMES    16      /* max that current constants allow */
  #define   MAXSYSNAME      128     /* max sysname (i.e. @sys) size */
! extern char *cm_sysName;
! extern int   cm_sysNameCount;
! extern char *cm_sysNameList[MAXNUMSYSNAMES];
  
  #ifndef __CM_IOCTL_INTERFACES_ONLY__
  
--- 43,51 ----
  
  #define MAXNUMSYSNAMES    16      /* max that current constants allow */
  #define   MAXSYSNAME      128     /* max sysname (i.e. @sys) size */
! extern char *         cm_sysName;
! extern unsigned int   cm_sysNameCount;
! extern char *         cm_sysNameList[MAXNUMSYSNAMES];
  
  #ifndef __CM_IOCTL_INTERFACES_ONLY__
  
Index: openafs/src/WINNT/afsd/cm_scache.h
diff -c openafs/src/WINNT/afsd/cm_scache.h:1.4.2.1 openafs/src/WINNT/afsd/cm_scache.h:1.4.2.2
*** openafs/src/WINNT/afsd/cm_scache.h:1.4.2.1	Wed Aug 18 13:11:22 2004
--- openafs/src/WINNT/afsd/cm_scache.h	Mon Oct 18 00:09:26 2004
***************
*** 58,64 ****
          				 * write-locked to prevent buffers from
                                           * being created during a truncate op, etc.
                                           */
!         int refCount;			/* reference count; cm_scacheLock */
          osi_queueData_t *bufReadsp;	/* queue of buffers being read */
          osi_queueData_t *bufWritesp;	/* queue of buffers being written */
  
--- 58,64 ----
          				 * write-locked to prevent buffers from
                                           * being created during a truncate op, etc.
                                           */
!         unsigned long refCount;			/* reference count; cm_scacheLock */
          osi_queueData_t *bufReadsp;	/* queue of buffers being read */
          osi_queueData_t *bufWritesp;	/* queue of buffers being written */
  
Index: openafs/src/WINNT/afsd/cm_server.c
diff -c openafs/src/WINNT/afsd/cm_server.c:1.13.2.2 openafs/src/WINNT/afsd/cm_server.c:1.13.2.4
*** openafs/src/WINNT/afsd/cm_server.c:1.13.2.2	Tue Aug 17 11:26:04 2004
--- openafs/src/WINNT/afsd/cm_server.c	Mon Oct 18 00:09:26 2004
***************
*** 37,138 ****
  
  void cm_CheckServers(long flags, cm_cell_t *cellp)
  {
! 	/* ping all file servers, up or down, with unauthenticated connection,
!          * to find out whether we have all our callbacks from the server still.
!          * Also, ping down VLDBs.
!          */
!         cm_server_t *tsp;
!         long code;
!         long secs;
!         long usecs;
! 	int doPing;
!         int serverType;
!         long now;
! 	int wasDown;
!         cm_conn_t *connp;
  
!         lock_ObtainWrite(&amp;cm_serverLock);
! 	for(tsp = cm_allServersp; tsp; tsp = tsp-&gt;allNextp) {
          cm_GetServerNoLock(tsp);
!                 lock_ReleaseWrite(&amp;cm_serverLock);
  
! 		/* now process the server */
!                 lock_ObtainMutex(&amp;tsp-&gt;mx);
  
! 		/* what time is it? */
!                 now = osi_Time();
  
! 		serverType = tsp-&gt;type;
! 		doPing = 0;
!                 wasDown = tsp-&gt;flags &amp; CM_SERVERFLAG_DOWN;
  
! 		/* only do the ping if the cell matches the requested cell, or we're
!                  * matching all cells (cellp == NULL), and if we've requested to ping
!                  * this type of {up, down} servers.
!                  */
! 		if ((cellp == NULL || cellp == tsp-&gt;cellp) &amp;&amp;
! 			((wasDown &amp;&amp; (flags &amp; CM_FLAG_CHECKDOWNSERVERS)) ||
!                 	 (!wasDown &amp;&amp; (flags &amp; CM_FLAG_CHECKUPSERVERS)))) {
! 
! 			doPing = 1;
! 		}	/* we're supposed to check this up/down server */
!                 lock_ReleaseMutex(&amp;tsp-&gt;mx);
!                         
!                 /* at this point, we've adjusted the server state, so do the ping and
!                  * adjust things.
                   */
!                 if (doPing) {
! 			code = cm_ConnByServer(tsp, cm_rootUserp, &amp;connp);
!                         if (code == 0) {
! 				/* now call the appropriate ping call.  Drop the timeout if
! 	                         * the server is known to be down, so that we don't waste a
! 	                         * lot of time retiming out down servers.
! 	                         */
! 				if (wasDown)
! 					rx_SetConnDeadTime(connp-&gt;callp, 10);
! 	                        if (serverType == CM_SERVER_VLDB) {
! 					code = VL_ProbeServer(connp-&gt;callp);
! 	                        }
! 	                        else {
! 					/* file server */
! 	                                code = RXAFS_GetTime(connp-&gt;callp, &amp;secs, &amp;usecs);
! 	                        }
! 				if (wasDown)
! 					rx_SetConnDeadTime(connp-&gt;callp, ConnDeadtimeout);
! 	                        cm_PutConn(connp);
! 			}	/* got an unauthenticated connection to this server */
! 
! 			lock_ObtainMutex(&amp;tsp-&gt;mx);
! 			if (code == 0) {
! 				/* mark server as up */
!                                 tsp-&gt;flags &amp;= ~CM_SERVERFLAG_DOWN;
!                         }
!                         else {
!                                	/* mark server as down */
!                                 tsp-&gt;flags |= CM_SERVERFLAG_DOWN;
! 			}
! 			lock_ReleaseMutex(&amp;tsp-&gt;mx);
                  }
!                         
!                 /* also, run the GC function for connections on all of the
!                  * server's connections.
!                  */
! 		cm_GCConnections(tsp);
  
!                 lock_ObtainWrite(&amp;cm_serverLock);
          cm_PutServerNoLock(tsp);
!         }
!         lock_ReleaseWrite(&amp;cm_serverLock);
! }
  
  void cm_InitServer(void)
  {
! 	static osi_once_t once;
          
!         if (osi_Once(&amp;once)) {
! 		lock_InitializeRWLock(&amp;cm_serverLock, "cm_serverLock");
! 		osi_EndOnce(&amp;once);
!         }
  }
  
  void cm_GetServer(cm_server_t *serverp)
--- 37,141 ----
  
  void cm_CheckServers(long flags, cm_cell_t *cellp)
  {
!     /* ping all file servers, up or down, with unauthenticated connection,
!      * to find out whether we have all our callbacks from the server still.
!      * Also, ping down VLDBs.
!      */
!     cm_server_t *tsp;
!     long code;
!     long secs;
!     long usecs;
!     int doPing;
!     int serverType;
!     long now;
!     int wasDown;
!     cm_conn_t *connp;
!     struct rx_connection * callp;
  
!     lock_ObtainWrite(&amp;cm_serverLock);
!     for (tsp = cm_allServersp; tsp; tsp = tsp-&gt;allNextp) {
          cm_GetServerNoLock(tsp);
!         lock_ReleaseWrite(&amp;cm_serverLock);
  
!         /* now process the server */
!         lock_ObtainMutex(&amp;tsp-&gt;mx);
  
!         /* what time is it? */
!         now = osi_Time();
  
!         serverType = tsp-&gt;type;
!         doPing = 0;
!         wasDown = tsp-&gt;flags &amp; CM_SERVERFLAG_DOWN;
! 
!         /* only do the ping if the cell matches the requested cell, or we're
!          * matching all cells (cellp == NULL), and if we've requested to ping
!          * this type of {up, down} servers.
!          */
!         if ((cellp == NULL || cellp == tsp-&gt;cellp) &amp;&amp;
!              ((wasDown &amp;&amp; (flags &amp; CM_FLAG_CHECKDOWNSERVERS)) ||
!                (!wasDown &amp;&amp; (flags &amp; CM_FLAG_CHECKUPSERVERS)))) {
! 
!             doPing = 1;
!         }	/* we're supposed to check this up/down server */
!         lock_ReleaseMutex(&amp;tsp-&gt;mx);
  
!         /* at this point, we've adjusted the server state, so do the ping and
!          * adjust things.
!          */
!         if (doPing) {
!             code = cm_ConnByServer(tsp, cm_rootUserp, &amp;connp);
!             if (code == 0) {
!                 /* now call the appropriate ping call.  Drop the timeout if
!                  * the server is known to be down, so that we don't waste a
!                  * lot of time retiming out down servers.
                   */
!                 if (wasDown)
!                     rx_SetConnDeadTime(connp-&gt;callp, 10);
!                 if (serverType == CM_SERVER_VLDB) {
!                     code = VL_ProbeServer(connp-&gt;callp);
                  }
!                 else {
!                     /* file server */
!                     callp = cm_GetRxConn(connp);
!                     code = RXAFS_GetTime(callp, &amp;secs, &amp;usecs);
!                     rx_PutConnection(callp);
!                 }
!                 if (wasDown)
!                     rx_SetConnDeadTime(connp-&gt;callp, ConnDeadtimeout);
!                 cm_PutConn(connp);
!             }	/* got an unauthenticated connection to this server */
! 
!             lock_ObtainMutex(&amp;tsp-&gt;mx);
!             if (code == 0) {
!                 /* mark server as up */
!                 tsp-&gt;flags &amp;= ~CM_SERVERFLAG_DOWN;
!             }
!             else {
!                 /* mark server as down */
!                 tsp-&gt;flags |= CM_SERVERFLAG_DOWN;
!             }
!             lock_ReleaseMutex(&amp;tsp-&gt;mx);
!         }
! 
!         /* also, run the GC function for connections on all of the
!          * server's connections.
!          */
!         cm_GCConnections(tsp);
  
!         lock_ObtainWrite(&amp;cm_serverLock);
          cm_PutServerNoLock(tsp);
!     }
!     lock_ReleaseWrite(&amp;cm_serverLock);
! }       
  
  void cm_InitServer(void)
  {
!     static osi_once_t once;
          
!     if (osi_Once(&amp;once)) {
!         lock_InitializeRWLock(&amp;cm_serverLock, "cm_serverLock");
!         osi_EndOnce(&amp;once);
!     }
  }
  
  void cm_GetServer(cm_server_t *serverp)
***************
*** 149,233 ****
  
  void cm_PutServer(cm_server_t *serverp)
  {
! 	lock_ObtainWrite(&amp;cm_serverLock);
! 	osi_assert(serverp-&gt;refCount-- &gt; 0);
! 	lock_ReleaseWrite(&amp;cm_serverLock);
  }
  
  void cm_PutServerNoLock(cm_server_t *serverp)
  {
! 	osi_assert(serverp-&gt;refCount-- &gt; 0);
  }
  
  void cm_SetServerPrefs(cm_server_t * serverp)
  {
! 	unsigned long	serverAddr; 	/* in host byte order */
! 	unsigned long	myAddr, myNet, mySubnet;/* in host byte order */
! 	unsigned long	netMask;
! 	int 		i;
! 
! 	/* implement server prefs for fileservers only */
! 	if ( serverp-&gt;type == CM_SERVER_FILE )
! 	{
! 	    serverAddr = ntohl(serverp-&gt;addr.sin_addr.s_addr);
! 	    serverp-&gt;ipRank  = CM_IPRANK_LOW;	/* default setings */
! 
! 	    for ( i=0; i &lt; cm_noIPAddr; i++)
! 	    {
! 		/* loop through all the client's IP address and compare
! 		** each of them against the server's IP address */
! 
! 		myAddr = cm_IPAddr[i];
! 		if ( IN_CLASSA(myAddr) )
! 		    netMask = IN_CLASSA_NET;
! 		else if ( IN_CLASSB(myAddr) )
! 		    netMask = IN_CLASSB_NET;
! 		else if ( IN_CLASSC(myAddr) )
! 		    netMask = IN_CLASSC_NET;
! 		else
! 		    netMask = 0;
! 
! 		myNet    =  myAddr &amp; netMask;
! 		mySubnet =  myAddr &amp; cm_SubnetMask[i];
! 
! 		if ( (serverAddr &amp; netMask) == myNet ) 
! 		{
! 		    if ( (serverAddr &amp; cm_SubnetMask[i]) == mySubnet)
! 		    {
! 			if ( serverAddr == myAddr ) 
! 			    serverp-&gt;ipRank = min(serverp-&gt;ipRank,
! 					      CM_IPRANK_TOP);/* same machine */
! 			else serverp-&gt;ipRank = min(serverp-&gt;ipRank,
! 					      CM_IPRANK_HI); /* same subnet */
! 		    }
! 		    else serverp-&gt;ipRank = min(serverp-&gt;ipRank,CM_IPRANK_MED);
! 							   /* same net */
! 		}	
! 						 /* random between 0..15*/
! 		serverp-&gt;ipRank += min(serverp-&gt;ipRank, rand() % 0x000f);
! 	    } /* and of for loop */
! 	}
      else 
          serverp-&gt;ipRank = 10000 + (rand() % 0x00ff); /* VL server */
  }
  
  cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp) {
! 	cm_server_t *tsp;
  
! 	osi_assert(socketp-&gt;sin_family == AF_INET);
  
! 	tsp = malloc(sizeof(*tsp));
      memset(tsp, 0, sizeof(*tsp));
! 	tsp-&gt;type = type;
      tsp-&gt;cellp = cellp;
      tsp-&gt;refCount = 1;
! 	lock_InitializeMutex(&amp;tsp-&gt;mx, "cm_server_t mutex");
! 	tsp-&gt;addr = *socketp;
  
! 	cm_SetServerPrefs(tsp); 
  
      lock_ObtainWrite(&amp;cm_serverLock); /* get server lock */
! 	tsp-&gt;allNextp = cm_allServersp;
      cm_allServersp = tsp;
      lock_ReleaseWrite(&amp;cm_serverLock); /* release server lock */
  
--- 152,236 ----
  
  void cm_PutServer(cm_server_t *serverp)
  {
!     lock_ObtainWrite(&amp;cm_serverLock);
!     osi_assert(serverp-&gt;refCount-- &gt; 0);
!     lock_ReleaseWrite(&amp;cm_serverLock);
  }
  
  void cm_PutServerNoLock(cm_server_t *serverp)
  {
!     osi_assert(serverp-&gt;refCount-- &gt; 0);
  }
  
  void cm_SetServerPrefs(cm_server_t * serverp)
  {
!     unsigned long	serverAddr; 	/* in host byte order */
!     unsigned long	myAddr, myNet, mySubnet;/* in host byte order */
!     unsigned long	netMask;
!     int 		i;
! 
!     /* implement server prefs for fileservers only */
!     if ( serverp-&gt;type == CM_SERVER_FILE )
!     {
!         serverAddr = ntohl(serverp-&gt;addr.sin_addr.s_addr);
!         serverp-&gt;ipRank  = CM_IPRANK_LOW;	/* default setings */
! 
!         for ( i=0; i &lt; cm_noIPAddr; i++)
!         {
!             /* loop through all the client's IP address and compare
!             ** each of them against the server's IP address */
! 
!             myAddr = cm_IPAddr[i];
!             if ( IN_CLASSA(myAddr) )
!                 netMask = IN_CLASSA_NET;
!             else if ( IN_CLASSB(myAddr) )
!                 netMask = IN_CLASSB_NET;
!             else if ( IN_CLASSC(myAddr) )
!                 netMask = IN_CLASSC_NET;
!             else
!                 netMask = 0;
! 
!             myNet    =  myAddr &amp; netMask;
!             mySubnet =  myAddr &amp; cm_SubnetMask[i];
! 
!             if ( (serverAddr &amp; netMask) == myNet ) 
!             {
!                 if ( (serverAddr &amp; cm_SubnetMask[i]) == mySubnet)
!                 {
!                     if ( serverAddr == myAddr ) 
!                         serverp-&gt;ipRank = min(serverp-&gt;ipRank,
!                                                CM_IPRANK_TOP);/* same machine */
!                     else serverp-&gt;ipRank = min(serverp-&gt;ipRank,
!                                                 CM_IPRANK_HI); /* same subnet */
!                 }
!                 else serverp-&gt;ipRank = min(serverp-&gt;ipRank,CM_IPRANK_MED);
!                 /* same net */
!             }	
!             /* random between 0..15*/
!             serverp-&gt;ipRank += min(serverp-&gt;ipRank, rand() % 0x000f);
!         } /* and of for loop */
!     }
      else 
          serverp-&gt;ipRank = 10000 + (rand() % 0x00ff); /* VL server */
  }
  
  cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp) {
!     cm_server_t *tsp;
  
!     osi_assert(socketp-&gt;sin_family == AF_INET);
  
!     tsp = malloc(sizeof(*tsp));
      memset(tsp, 0, sizeof(*tsp));
!     tsp-&gt;type = type;
      tsp-&gt;cellp = cellp;
      tsp-&gt;refCount = 1;
!     lock_InitializeMutex(&amp;tsp-&gt;mx, "cm_server_t mutex");
!     tsp-&gt;addr = *socketp;
  
!     cm_SetServerPrefs(tsp); 
  
      lock_ObtainWrite(&amp;cm_serverLock); /* get server lock */
!     tsp-&gt;allNextp = cm_allServersp;
      cm_allServersp = tsp;
      lock_ReleaseWrite(&amp;cm_serverLock); /* release server lock */
  
***************
*** 237,294 ****
  /* find a server based on its properties */
  cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type)
  {
! 	cm_server_t *tsp;
  
! 	osi_assert(addrp-&gt;sin_family == AF_INET);
          
!         lock_ObtainWrite(&amp;cm_serverLock);
! 	for(tsp = cm_allServersp; tsp; tsp=tsp-&gt;allNextp) {
! 		if (tsp-&gt;type == type &amp;&amp;
!                 	tsp-&gt;addr.sin_addr.s_addr == addrp-&gt;sin_addr.s_addr) break;
!         }
  
! 	/* bump ref count if we found the server */
      if (tsp) 
          cm_GetServerNoLock(tsp);
  
! 	/* drop big table lock */
!         lock_ReleaseWrite(&amp;cm_serverLock);
  	
! 	/* return what we found */
!         return tsp;
! }
  
  cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp)
  {
! 	cm_serverRef_t *tsrp;
  
      cm_GetServer(serverp);
! 	tsrp = malloc(sizeof(*tsrp));
! 	tsrp-&gt;server = serverp;
! 	tsrp-&gt;status = not_busy;
! 	tsrp-&gt;next = NULL;
      tsrp-&gt;refCount = 1;
  
! 	return tsrp;
  }
  
  long cm_ChecksumServerList(cm_serverRef_t *serversp)
  {
! 	long sum = 0;
! 	int first = 1;
! 	cm_serverRef_t *tsrp;
  
      lock_ObtainWrite(&amp;cm_serverLock);
! 	for (tsrp = serversp; tsrp; tsrp=tsrp-&gt;next) {
! 		if (first)
! 			first = 0;
! 		else
! 			sum &lt;&lt;= 1;
! 		sum ^= (long) tsrp-&gt;server;
! 	}
  
      lock_ReleaseWrite(&amp;cm_serverLock);
! 	return sum;
  }
  
  /*
--- 240,297 ----
  /* find a server based on its properties */
  cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type)
  {
!     cm_server_t *tsp;
  
!     osi_assert(addrp-&gt;sin_family == AF_INET);
          
!     lock_ObtainWrite(&amp;cm_serverLock);
!     for (tsp = cm_allServersp; tsp; tsp=tsp-&gt;allNextp) {
!         if (tsp-&gt;type == type &amp;&amp;
!              tsp-&gt;addr.sin_addr.s_addr == addrp-&gt;sin_addr.s_addr) break;
!     }       
  
!     /* bump ref count if we found the server */
      if (tsp) 
          cm_GetServerNoLock(tsp);
  
!     /* drop big table lock */
!     lock_ReleaseWrite(&amp;cm_serverLock);
  	
!     /* return what we found */
!     return tsp;
! }       
  
  cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp)
  {
!     cm_serverRef_t *tsrp;
  
      cm_GetServer(serverp);
!     tsrp = malloc(sizeof(*tsrp));
!     tsrp-&gt;server = serverp;
!     tsrp-&gt;status = not_busy;
!     tsrp-&gt;next = NULL;
      tsrp-&gt;refCount = 1;
  
!     return tsrp;
  }
  
  long cm_ChecksumServerList(cm_serverRef_t *serversp)
  {
!     long sum = 0;
!     int first = 1;
!     cm_serverRef_t *tsrp;
  
      lock_ObtainWrite(&amp;cm_serverLock);
!     for (tsrp = serversp; tsrp; tsrp=tsrp-&gt;next) {
!         if (first)
!             first = 0;
!         else
!             sum &lt;&lt;= 1;
!         sum ^= (long) tsrp-&gt;server;
!     }
  
      lock_ReleaseWrite(&amp;cm_serverLock);
!     return sum;
  }
  
  /*
***************
*** 299,329 ****
  */
  void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
  {
! 	cm_serverRef_t	*current=*list;
! 	unsigned short ipRank = element-&gt;server-&gt;ipRank;
  
      lock_ObtainWrite(&amp;cm_serverLock);
      element-&gt;refCount++;                /* increase refCount */
  
      /* insertion into empty list  or at the beginning of the list */
! 	if ( !current || (current-&gt;server-&gt;ipRank &gt; ipRank) )
! 	{
! 		element-&gt;next = *list;
! 		*list = element;
          lock_ReleaseWrite(&amp;cm_serverLock);
! 		return ;	
! 	}
  	
! 	while ( current-&gt;next ) /* find appropriate place to insert */
! 	{
! 		if ( current-&gt;next-&gt;server-&gt;ipRank &gt; ipRank )
! 			break;
! 		else current = current-&gt;next;
! 	}
! 	element-&gt;next = current-&gt;next;
! 	current-&gt;next = element;
      lock_ReleaseWrite(&amp;cm_serverLock);
! }
  /*
  ** Re-sort the server list with the modified rank
  ** returns 0 if element was changed successfully. 
--- 302,332 ----
  */
  void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
  {
!     cm_serverRef_t	*current=*list;
!     unsigned short ipRank = element-&gt;server-&gt;ipRank;
  
      lock_ObtainWrite(&amp;cm_serverLock);
      element-&gt;refCount++;                /* increase refCount */
  
      /* insertion into empty list  or at the beginning of the list */
!     if ( !current || (current-&gt;server-&gt;ipRank &gt; ipRank) )
!     {
!         element-&gt;next = *list;
!         *list = element;
          lock_ReleaseWrite(&amp;cm_serverLock);
!         return ;	
!     }
  	
!     while ( current-&gt;next ) /* find appropriate place to insert */
!     {
!         if ( current-&gt;next-&gt;server-&gt;ipRank &gt; ipRank )
!             break;
!         else current = current-&gt;next;
!     }
!     element-&gt;next = current-&gt;next;
!     current-&gt;next = element;
      lock_ReleaseWrite(&amp;cm_serverLock);
! }       
  /*
  ** Re-sort the server list with the modified rank
  ** returns 0 if element was changed successfully. 
***************
*** 331,369 ****
  */
  long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t*	server)
  {
! 	cm_serverRef_t  **current=list;
! 	cm_serverRef_t	*element=0;
  
! 	/* if there is max of one element in the list, nothing to sort */
! 	if ( (!*current) || !((*current)-&gt;next)  )
! 		return 1;		/* list unchanged: return success */
  
      lock_ObtainWrite(&amp;cm_serverLock);
! 	/* if the server is on the list, delete it from list */
! 	while ( *current )
! 	{
! 		if ( (*current)-&gt;server == server)
! 		{
! 			element = (*current);
! 			*current = (*current)-&gt;next; /* delete it */
! 			break;
! 		}
! 		current = &amp; ( (*current)-&gt;next);	
! 	}
      lock_ReleaseWrite(&amp;cm_serverLock);
  
      /* if this volume is not replicated on this server  */
! 	if (!element)
! 		return 1;	/* server is not on list */
  
! 	/* re-insert deleted element into the list with modified rank*/
! 	cm_InsertServerList(list, element);
  
      /* reduce refCount which was increased by cm_InsertServerList */
      lock_ObtainWrite(&amp;cm_serverLock);
      element-&gt;refCount--;
      lock_ReleaseWrite(&amp;cm_serverLock);
! 	return 0;
  }
  /*
  ** If there are more than one server on the list and the first n servers on 
--- 334,372 ----
  */
  long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t*	server)
  {
!     cm_serverRef_t  **current=list;
!     cm_serverRef_t	*element=0;
  
!     /* if there is max of one element in the list, nothing to sort */
!     if ( (!*current) || !((*current)-&gt;next)  )
!         return 1;		/* list unchanged: return success */
  
      lock_ObtainWrite(&amp;cm_serverLock);
!     /* if the server is on the list, delete it from list */
!     while ( *current )
!     {
!         if ( (*current)-&gt;server == server)
!         {
!             element = (*current);
!             *current = (*current)-&gt;next; /* delete it */
!             break;
!         }
!         current = &amp; ( (*current)-&gt;next);	
!     }
      lock_ReleaseWrite(&amp;cm_serverLock);
  
      /* if this volume is not replicated on this server  */
!     if (!element)
!         return 1;	/* server is not on list */
  
!     /* re-insert deleted element into the list with modified rank*/
!     cm_InsertServerList(list, element);
  
      /* reduce refCount which was increased by cm_InsertServerList */
      lock_ObtainWrite(&amp;cm_serverLock);
      element-&gt;refCount--;
      lock_ReleaseWrite(&amp;cm_serverLock);
!     return 0;
  }
  /*
  ** If there are more than one server on the list and the first n servers on 
***************
*** 371,419 ****
  */
  void cm_RandomizeServer(cm_serverRef_t** list)
  {
! 	int 		count, picked;
! 	cm_serverRef_t*	tsrp = *list, *lastTsrp;
! 	unsigned short	lowestRank;
! 
! 	/* an empty list or a list with only one element */
! 	if ( !tsrp || ! tsrp-&gt;next )
! 		return ; 
  
      lock_ObtainWrite(&amp;cm_serverLock);
  
! 	/* count the number of servers with the lowest rank */
! 	lowestRank = tsrp-&gt;server-&gt;ipRank;
! 	for ( count=1, tsrp=tsrp-&gt;next; tsrp; tsrp=tsrp-&gt;next)
! 	{
! 		if ( tsrp-&gt;server-&gt;ipRank != lowestRank)
! 			break;
! 		else
! 			count++;
! 	}	
  
! 	/* if there is only one server with the lowest rank, we are done */
! 	if ( count &lt;= 1 ) {
          lock_ReleaseWrite(&amp;cm_serverLock);
! 		return ;
!     }
  
! 	picked = rand() % count;
! 	if ( !picked ) {
          lock_ReleaseWrite(&amp;cm_serverLock);
! 		return ;
!     }
  
! 	tsrp = *list;
! 	while (--picked &gt;= 0)
! 	{
! 		lastTsrp = tsrp;
! 		tsrp = tsrp-&gt;next;
! 	}
! 	lastTsrp-&gt;next = tsrp-&gt;next;  /* delete random element from list*/
! 	tsrp-&gt;next     = *list; /* insert element at the beginning of list */
! 	*list          = tsrp;
      lock_ReleaseWrite(&amp;cm_serverLock);
! }
  
  /* call cm_FreeServer while holding a write lock on cm_serverLock */
  void cm_FreeServer(cm_server_t* serverp)
--- 374,422 ----
  */
  void cm_RandomizeServer(cm_serverRef_t** list)
  {
!     int 		count, picked;
!     cm_serverRef_t*	tsrp = *list, *lastTsrp;
!     unsigned short	lowestRank;
! 
!     /* an empty list or a list with only one element */
!     if ( !tsrp || ! tsrp-&gt;next )
!         return ; 
  
      lock_ObtainWrite(&amp;cm_serverLock);
  
!     /* count the number of servers with the lowest rank */
!     lowestRank = tsrp-&gt;server-&gt;ipRank;
!     for ( count=1, tsrp=tsrp-&gt;next; tsrp; tsrp=tsrp-&gt;next)
!     {
!         if ( tsrp-&gt;server-&gt;ipRank != lowestRank)
!             break;
!         else
!             count++;
!     }       	
  
!     /* if there is only one server with the lowest rank, we are done */
!     if ( count &lt;= 1 ) {
          lock_ReleaseWrite(&amp;cm_serverLock);
!         return ;
!     }   
  
!     picked = rand() % count;
!     if ( !picked ) {
          lock_ReleaseWrite(&amp;cm_serverLock);
!         return ;
!     }   
  
!     tsrp = *list;
!     while (--picked &gt;= 0)
!     {
!         lastTsrp = tsrp;
!         tsrp = tsrp-&gt;next;
!     }
!     lastTsrp-&gt;next = tsrp-&gt;next;  /* delete random element from list*/
!     tsrp-&gt;next     = *list; /* insert element at the beginning of list */
!     *list          = tsrp;
      lock_ReleaseWrite(&amp;cm_serverLock);
! }       
  
  /* call cm_FreeServer while holding a write lock on cm_serverLock */
  void cm_FreeServer(cm_server_t* serverp)
***************
*** 447,453 ****
  {
      cm_serverRef_t  **current = list;
      cm_serverRef_t  **nextp = 0;
! 	cm_serverRef_t  * next = 0;
  
      lock_ObtainWrite(&amp;cm_serverLock);
  
--- 450,456 ----
  {
      cm_serverRef_t  **current = list;
      cm_serverRef_t  **nextp = 0;
!     cm_serverRef_t  * next = 0;
  
      lock_ObtainWrite(&amp;cm_serverLock);
  
***************
*** 455,461 ****
      {
          nextp = &amp;(*current)-&gt;next;
          if (--((*current)-&gt;refCount) == 0) {
! 			next = *nextp;
              cm_FreeServer((*current)-&gt;server);
              free(*current);
              *current = next;
--- 458,464 ----
      {
          nextp = &amp;(*current)-&gt;next;
          if (--((*current)-&gt;refCount) == 0) {
!             next = *nextp;
              cm_FreeServer((*current)-&gt;server);
              free(*current);
              *current = next;
Index: openafs/src/WINNT/afsd/cm_server.h
diff -c openafs/src/WINNT/afsd/cm_server.h:1.5.2.1 openafs/src/WINNT/afsd/cm_server.h:1.5.2.2
*** openafs/src/WINNT/afsd/cm_server.h:1.5.2.1	Tue Aug 17 00:28:39 2004
--- openafs/src/WINNT/afsd/cm_server.h	Mon Oct 18 00:09:26 2004
***************
*** 27,33 ****
  	struct cm_conn *connsp;			/* locked by cm_connLock */
      long flags;				/* by mx */
      struct cm_cell *cellp;			/* cell containing this server */
! 	int refCount;				/* locked by cm_serverLock */
      osi_mutex_t mx;
  	unsigned short ipRank;			/* server priority */
  } cm_server_t;
--- 27,33 ----
  	struct cm_conn *connsp;			/* locked by cm_connLock */
      long flags;				/* by mx */
      struct cm_cell *cellp;			/* cell containing this server */
! 	unsigned long refCount;				/* locked by cm_serverLock */
      osi_mutex_t mx;
  	unsigned short ipRank;			/* server priority */
  } cm_server_t;
***************
*** 38,44 ****
  	struct cm_serverRef *next;      /* locked by cm_serverLock */
  	struct cm_server *server;       /* locked by cm_serverLock */
  	enum repstate status;           /* locked by cm_serverLock */
!     int refCount;                   /* locked by cm_serverLock */
  } cm_serverRef_t;
  
  /* types */
--- 38,44 ----
  	struct cm_serverRef *next;      /* locked by cm_serverLock */
  	struct cm_server *server;       /* locked by cm_serverLock */
  	enum repstate status;           /* locked by cm_serverLock */
!     unsigned long refCount;                   /* locked by cm_serverLock */
  } cm_serverRef_t;
  
  /* types */
Index: openafs/src/WINNT/afsd/cm_user.h
diff -c openafs/src/WINNT/afsd/cm_user.h:1.2 openafs/src/WINNT/afsd/cm_user.h:1.2.20.1
*** openafs/src/WINNT/afsd/cm_user.h:1.2	Sat Nov  4 05:01:40 2000
--- openafs/src/WINNT/afsd/cm_user.h	Mon Oct 18 00:09:26 2004
***************
*** 39,45 ****
  #define CM_UCELLFLAG_BADTIX	4	/* tickets are bad or expired */
  
  typedef struct cm_user {
! 	int refCount;			/* ref count */
  	cm_ucell_t *cellInfop;		/* list of cell info */
          osi_mutex_t mx;			/* mutex */
          int vcRefs;			/* count of references from virtual circuits */
--- 39,45 ----
  #define CM_UCELLFLAG_BADTIX	4	/* tickets are bad or expired */
  
  typedef struct cm_user {
! 	unsigned long refCount;			/* ref count */
  	cm_ucell_t *cellInfop;		/* list of cell info */
          osi_mutex_t mx;			/* mutex */
          int vcRefs;			/* count of references from virtual circuits */
Index: openafs/src/WINNT/afsd/cm_utils.c
diff -c openafs/src/WINNT/afsd/cm_utils.c:1.5 openafs/src/WINNT/afsd/cm_utils.c:1.5.14.1
*** openafs/src/WINNT/afsd/cm_utils.c:1.5	Sat Sep  8 00:31:22 2001
--- openafs/src/WINNT/afsd/cm_utils.c	Tue Sep 21 10:07:18 2004
***************
*** 30,70 ****
  
  long cm_MapRPCError(long error, cm_req_t *reqp)
  {
! 	if (error == 0) return 0;
! 
! 	/* If we had to stop retrying, report our saved error code. */
! 	if (reqp &amp;&amp; error == CM_ERROR_TIMEDOUT) {
! 		if (reqp-&gt;accessError)
! 			return reqp-&gt;accessError;
! 		if (reqp-&gt;volumeError)
! 			return reqp-&gt;volumeError;
! 		if (reqp-&gt;rpcError)
! 			return reqp-&gt;rpcError;
! 		return error;
! 	}
  
! 	if (error &lt; 0) error = CM_ERROR_TIMEDOUT;
! 	else if (error == 30) error = CM_ERROR_READONLY;
!         else if (error == 13) error = CM_ERROR_NOACCESS;
!         else if (error == 18) error = CM_ERROR_CROSSDEVLINK;
!         else if (error == 17) error = CM_ERROR_EXISTS;
! 	else if (error == 20) error = CM_ERROR_NOTDIR;
!         else if (error == 2) error = CM_ERROR_NOSUCHFILE;
! 	else if (error == 11		/* EAGAIN, most servers */
! 		 || error == 35)	/* EAGAIN, Digital UNIX */
! 			error = CM_ERROR_WOULDBLOCK;
! 	else if (error == VDISKFULL
! 		 || error == 28)        /* ENOSPC */ 
! 	                error = CM_ERROR_SPACE;
! 	else if (error == VOVERQUOTA
! 		 || error == 49         /* EDQUOT on Solaris */
! 		 || error == 88		/* EDQUOT on AIX */
! 		 || error == 69	        /* EDQUOT on Digital UNIX and HPUX */
! 		 || error == 122        /* EDQUOT on Linux */
! 		 || error == 1133)      /* EDQUOT on Irix  */
! 	                error = CM_ERROR_QUOTA;
!         else if (error == VNOVNODE) error = CM_ERROR_BADFD;
          return error;
  }
  
  long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
--- 30,81 ----
  
  long cm_MapRPCError(long error, cm_req_t *reqp)
  {
!     if (error == 0) 
!         return 0;
  
!     /* If we had to stop retrying, report our saved error code. */
!     if (reqp &amp;&amp; error == CM_ERROR_TIMEDOUT) {
!         if (reqp-&gt;accessError)
!             return reqp-&gt;accessError;
!         if (reqp-&gt;volumeError)
!             return reqp-&gt;volumeError;
!         if (reqp-&gt;rpcError)
!             return reqp-&gt;rpcError;
          return error;
+     }
+ 
+     if (error &lt; 0) 
+         error = CM_ERROR_TIMEDOUT;
+     else if (error == 30) 
+         error = CM_ERROR_READONLY;
+     else if (error == 13) 
+         error = CM_ERROR_NOACCESS;
+     else if (error == 18) 
+         error = CM_ERROR_CROSSDEVLINK;
+     else if (error == 17) 
+         error = CM_ERROR_EXISTS;
+     else if (error == 20) 
+         error = CM_ERROR_NOTDIR;
+     else if (error == 2) 
+         error = CM_ERROR_NOSUCHFILE;
+     else if (error == 11		/* EAGAIN, most servers */
+              || error == 35)	/* EAGAIN, Digital UNIX */
+         error = CM_ERROR_WOULDBLOCK;
+     else if (error == VDISKFULL
+               || error == 28)        /* ENOSPC */ 
+         error = CM_ERROR_SPACE;
+     else if (error == VOVERQUOTA
+               || error == 49         /* EDQUOT on Solaris */
+               || error == 88		/* EDQUOT on AIX */
+               || error == 69	        /* EDQUOT on Digital UNIX and HPUX */
+               || error == 122        /* EDQUOT on Linux */
+               || error == 1133)      /* EDQUOT on Irix  */
+         error = CM_ERROR_QUOTA;
+     else if (error == VNOVNODE) 
+         error = CM_ERROR_BADFD;
+     else if (error == 21)
+         return CM_ERROR_ISDIR;
+     return error;
  }
  
  long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
Index: openafs/src/WINNT/afsd/cm_vnodeops.c
diff -c openafs/src/WINNT/afsd/cm_vnodeops.c:1.19.2.1 openafs/src/WINNT/afsd/cm_vnodeops.c:1.19.2.4
*** openafs/src/WINNT/afsd/cm_vnodeops.c:1.19.2.1	Tue Aug 17 00:28:39 2004
--- openafs/src/WINNT/afsd/cm_vnodeops.c	Mon Oct 18 00:09:26 2004
***************
*** 80,102 ****
   */
  int cm_stricmp(const char *str1, const char *str2)
  {
! 	char c1, c2;
  
! 	while (1) {
! 		if (*str1 == 0)
! 			if (*str2 == 0)
! 				return 0;
! 			else
! 				return -1;
! 		if (*str2 == 0)
! 			return 1;
! 		c1 = (char) cm_foldUpper[(unsigned char)(*str1++)];
! 		c2 = (char) cm_foldUpper[(unsigned char)(*str2++)];
! 		if (c1 &lt; c2)
! 			return -1;
! 		if (c1 &gt; c2)
! 			return 1;
! 	}
  }
  
  /* characters that are legal in an 8.3 name */
--- 80,102 ----
   */
  int cm_stricmp(const char *str1, const char *str2)
  {
!     char c1, c2;
  
!     while (1) {
!         if (*str1 == 0)
!             if (*str2 == 0)
!                 return 0;
!             else
!                 return -1;
!         if (*str2 == 0)
!             return 1;
!         c1 = (char) cm_foldUpper[(unsigned char)(*str1++)];
!         c2 = (char) cm_foldUpper[(unsigned char)(*str2++)];
!         if (c1 &lt; c2)
!             return -1;
!         if (c1 &gt; c2)
!             return 1;
!     }
  }
  
  /* characters that are legal in an 8.3 name */
***************
*** 129,181 ****
  /* return true iff component is a valid 8.3 name */
  int cm_Is8Dot3(char *namep)
  {
! 	int sawDot = 0;
! 	int sawUpper = 0, sawLower = 0;
!         unsigned char tc;
!         int charCount = 0;
!         
! 	/*
! 	 * can't have a leading dot;
! 	 * special case for . and ..
! 	 */
! 	if (namep[0] == '.') {
! 		if (namep[1] == 0)
! 			return 1;
! 		if (namep[1] == '.' &amp;&amp; namep[2] == 0)
! 			return 1;
! 		return 0;
! 	}
!         while (tc = *namep++) {
! 		if (tc == '.') {
! 			/* saw another dot */
!                         if (sawDot) return 0;	/* second dot */
!                         sawDot = 1;
! 			charCount = 0;
!                         continue;
!                 }
! 		if (cm_LegalChars[tc] == 0)
! 			return 0;
! 		if (tc &gt;= 'A' &amp;&amp; tc &lt;= 'Z')
! 			sawUpper = 1;
! 		else if (tc &gt;= 'a' &amp;&amp; tc &lt;= 'z')
! 			sawLower = 1;
!                 charCount++;
!                 if (!sawDot &amp;&amp; charCount &gt; 8)
! 			/* more than 8 chars in name */
! 			return 0;
!                 if (sawDot &amp;&amp; charCount &gt; 3)
! 			/* more than 3 chars in extension */
! 			return 0;
!         }
! /*
!  * Used to check that all characters were the same case.
!  * This doesn't help 16-bit apps, and meanwhile it causes the
!  * MS-DOS Command Prompt to misbehave; see Sybase defect 10709.
!  *
! 	if (sawUpper &amp;&amp; sawLower)
! 		return 0;
!  */
!         return 1;
  }
  
  /*
--- 129,181 ----
  /* return true iff component is a valid 8.3 name */
  int cm_Is8Dot3(char *namep)
  {
!     int sawDot = 0;
!     int sawUpper = 0, sawLower = 0;
!     unsigned char tc;
!     int charCount = 0;
!         
!     /*
!      * can't have a leading dot;
!      * special case for . and ..
!      */
!     if (namep[0] == '.') {
!         if (namep[1] == 0)
!             return 1;
!         if (namep[1] == '.' &amp;&amp; namep[2] == 0)
!             return 1;
!         return 0;
!     }
!     while (tc = *namep++) {
!         if (tc == '.') {
!             /* saw another dot */
!             if (sawDot) return 0;	/* second dot */
!             sawDot = 1;
!             charCount = 0;
!             continue;
!         }
!         if (cm_LegalChars[tc] == 0)
!             return 0;
!         if (tc &gt;= 'A' &amp;&amp; tc &lt;= 'Z')
!             sawUpper = 1;
!         else if (tc &gt;= 'a' &amp;&amp; tc &lt;= 'z')
!             sawLower = 1;
!         charCount++;
!         if (!sawDot &amp;&amp; charCount &gt; 8)
!             /* more than 8 chars in name */
!             return 0;
!         if (sawDot &amp;&amp; charCount &gt; 3)
!             /* more than 3 chars in extension */
!             return 0;
!     }
!     /*
!      * Used to check that all characters were the same case.
!      * This doesn't help 16-bit apps, and meanwhile it causes the
!      * MS-DOS Command Prompt to misbehave; see Sybase defect 10709.
!      *
!      if (sawUpper &amp;&amp; sawLower)
!          return 0;
!      */
!     return 1;
  }
  
  /*
***************
*** 191,323 ****
  
  void cm_Gen8Dot3Name(cm_dirEntry_t *dep, char *shortName, char **shortNameEndp)
  {
! 	char number[12];
! 	int i, nsize = 0;
! 	int vnode = ntohl(dep-&gt;fid.vnode);
! 	char *lastDot;
! 	int validExtension = 0;
! 	char tc, *temp, *name;
! 
! 	/* Unparse the file's vnode number to get a "uniquifier" */
! 	do {
! 		number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
! 		nsize++;
! 		vnode /= cm_8Dot3MapSize;
! 	} while (vnode);
! 
! 	/*
! 	 * Look for valid extension.  There has to be a dot, and
! 	 * at least one of the characters following has to be legal.
! 	 */
! 	lastDot = strrchr(dep-&gt;name, '.');
! 	if (lastDot) {
! 		temp = lastDot; temp++;
! 		while (tc = *temp++)
! 			if (cm_LegalChars[tc])
! 				break;
! 		if (tc)
! 			validExtension = 1;
! 	}
! 
! 	/* Copy name characters */
! 	name = dep-&gt;name;
! 	for (i = 0, name = dep-&gt;name;
! 	     i &lt; (7 - nsize) &amp;&amp; name != lastDot; ) {
! 		tc = *name++;
! 
! 		if (tc == 0)
! 			break;
! 		if (!cm_LegalChars[tc])
! 			continue;
! 		i++;
! 		*shortName++ = toupper(tc);
! 	}
! 
! 	/* tilde */
! 	*shortName++ = '~';
! 
! 	/* Copy uniquifier characters */
! 	memcpy(shortName, number, nsize);
! 	shortName += nsize;
! 
! 	if (validExtension) {
! 		/* Copy extension characters */
! 		*shortName++ = *lastDot++;	/* copy dot */
! 		for (i = 0, tc = *lastDot++;
! 		     i &lt; 3 &amp;&amp; tc;
! 		     tc = *lastDot++) {
! 			if (cm_LegalChars[tc]) {
! 				i++;
! 				*shortName++ = toupper(tc);
! 			}
! 		}
! 	}
  
! 	/* Trailing null */
! 	*shortName = 0;
  
! 	if (shortNameEndp)
! 		*shortNameEndp = shortName;
! }
  
  /* return success if we can open this file in this mode */
  long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
! 	cm_req_t *reqp)
  {
! 	long rights;
!         long code;
! 
! 	rights = 0;
! 	if (openMode != 1) rights |= PRSFS_READ;
!         if (openMode == 1 || openMode == 2 || trunc) rights |= PRSFS_WRITE;
!         
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
  
!         code = cm_SyncOp(scp, NULL, userp, reqp, rights,
! 			 CM_SCACHESYNC_GETSTATUS
!         		 | CM_SCACHESYNC_NEEDCALLBACK);
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
  
! 	return code;
  }
  
  /* return success if we can open this file in this mode */
  long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
! 	unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	long rights;
!         long code;
! 
! 	/* Always allow delete; the RPC will tell us if it's OK */
! 	if (desiredAccess == DELETE)
! 		return 0;
  
! 	rights = 0;
  
! 	if (desiredAccess &amp; AFS_ACCESS_READ)
! 		rights |= PRSFS_READ;
  
!         if ((desiredAccess &amp; AFS_ACCESS_WRITE)
! 	    || createDisp == 4)
! 		rights |= PRSFS_WRITE;
!         
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
  
!         code = cm_SyncOp(scp, NULL, userp, reqp, rights,
! 			 CM_SCACHESYNC_GETSTATUS
!         		 | CM_SCACHESYNC_NEEDCALLBACK);
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
!         /*
!          * If the open will fail because the volume is readonly, then we will
!          * return an access denied error instead.  This is to help brain-dead
!          * apps run correctly on replicated volumes.
!          * See defect 10007 for more information.
!          */
!         if (code == CM_ERROR_READONLY)
!                 code = CM_ERROR_NOACCESS;
  
! 	return code;
  }
  
  /*
--- 191,323 ----
  
  void cm_Gen8Dot3Name(cm_dirEntry_t *dep, char *shortName, char **shortNameEndp)
  {
!     char number[12];
!     int i, nsize = 0;
!     int vnode = ntohl(dep-&gt;fid.vnode);
!     char *lastDot;
!     int validExtension = 0;
!     char tc, *temp, *name;
! 
!     /* Unparse the file's vnode number to get a "uniquifier" */
!     do {
!         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
!         nsize++;
!         vnode /= cm_8Dot3MapSize;
!     } while (vnode);
! 
!     /*
!      * Look for valid extension.  There has to be a dot, and
!      * at least one of the characters following has to be legal.
!      */
!     lastDot = strrchr(dep-&gt;name, '.');
!     if (lastDot) {
!         temp = lastDot; temp++;
!         while (tc = *temp++)
!             if (cm_LegalChars[tc])
!                 break;
!         if (tc)
!             validExtension = 1;
!     }       
! 
!     /* Copy name characters */
!     name = dep-&gt;name;
!     for (i = 0, name = dep-&gt;name;
!           i &lt; (7 - nsize) &amp;&amp; name != lastDot; ) {
!         tc = *name++;
! 
!         if (tc == 0)
!             break;
!         if (!cm_LegalChars[tc])
!             continue;
!         i++;
!         *shortName++ = toupper(tc);
!     }
  
!     /* tilde */
!     *shortName++ = '~';
  
!     /* Copy uniquifier characters */
!     memcpy(shortName, number, nsize);
!     shortName += nsize;
! 
!     if (validExtension) {
!         /* Copy extension characters */
!         *shortName++ = *lastDot++;	/* copy dot */
!         for (i = 0, tc = *lastDot++;
!               i &lt; 3 &amp;&amp; tc;
!               tc = *lastDot++) {
!             if (cm_LegalChars[tc]) {
!                 i++;
!                 *shortName++ = toupper(tc);
!             }
!         }
!     }
! 
!     /* Trailing null */
!     *shortName = 0;
! 
!     if (shortNameEndp)
!         *shortNameEndp = shortName;
! }       
  
  /* return success if we can open this file in this mode */
  long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
!                   cm_req_t *reqp)
  {
!     long rights;
!     long code;
  
!     rights = 0;
!     if (openMode != 1) rights |= PRSFS_READ;
!     if (openMode == 1 || openMode == 2 || trunc) rights |= PRSFS_WRITE;
!         
!     lock_ObtainMutex(&amp;scp-&gt;mx);
! 
!     code = cm_SyncOp(scp, NULL, userp, reqp, rights,
!                       CM_SCACHESYNC_GETSTATUS
!                       | CM_SCACHESYNC_NEEDCALLBACK);
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
  
!     return code;
  }
  
  /* return success if we can open this file in this mode */
  long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
!                     unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long rights;
!     long code;
  
!     /* Always allow delete; the RPC will tell us if it's OK */
!     if (desiredAccess == DELETE)
!         return 0;
  
!     rights = 0;
  
!     if (desiredAccess &amp; AFS_ACCESS_READ)
!         rights |= PRSFS_READ;
  
!     if ((desiredAccess &amp; AFS_ACCESS_WRITE)
!          || createDisp == 4)
!         rights |= PRSFS_WRITE;
! 
!     lock_ObtainMutex(&amp;scp-&gt;mx);
! 
!     code = cm_SyncOp(scp, NULL, userp, reqp, rights,
!                       CM_SCACHESYNC_GETSTATUS
!                       | CM_SCACHESYNC_NEEDCALLBACK);
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
!     /*
!      * If the open will fail because the volume is readonly, then we will
!      * return an access denied error instead.  This is to help brain-dead
!      * apps run correctly on replicated volumes.
!      * See defect 10007 for more information.
!      */
!     if (code == CM_ERROR_READONLY)
!         code = CM_ERROR_NOACCESS;
  
!     return code;
  }
  
  /*
***************
*** 336,427 ****
  long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
  	cm_req_t *reqp)
  {
! 	long code;
! 	osi_hyper_t thyper;
! 	cm_buf_t *bufferp;
! 	cm_dirEntry_t *dep;
! 	unsigned short *hashTable;
! 	unsigned int i, idx;
! 	int BeyondPage = 0, HaveDot = 0, HaveDotDot = 0;
! 
! 	/* First check permissions */
! 	lock_ObtainMutex(&amp;dscp-&gt;mx);
!         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_DELETE,
! 			 CM_SCACHESYNC_GETSTATUS
!         		 | CM_SCACHESYNC_NEEDCALLBACK);
! 	lock_ReleaseMutex(&amp;dscp-&gt;mx);
! 	if (code)
! 		return code;
! 
! 	/* If deleting directory, must be empty */
! 
! 	if (scp-&gt;fileType != CM_SCACHETYPE_DIRECTORY)
! 		return code;
! 
! 	thyper.HighPart = 0; thyper.LowPart = 0;
! 	lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
! 	code = buf_Get(scp, &amp;thyper, &amp;bufferp);
! 	lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
! 	if (code)
! 		return code;
! 
! 	lock_ObtainMutex(&amp;bufferp-&gt;mx);
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	while (1) {
! 		code = cm_SyncOp(scp, bufferp, userp, reqp, 0,
! 				 CM_SCACHESYNC_NEEDCALLBACK
! 				 | CM_SCACHESYNC_READ
! 				 | CM_SCACHESYNC_BUFLOCKED);
! 		if (code)
! 			break;
! 
! 		if (cm_HaveBuffer(scp, bufferp, 1))
! 			break;
! 
! 		/* otherwise, load the buffer and try again */
! 		lock_ReleaseMutex(&amp;bufferp-&gt;mx);
! 		code = cm_GetBuffer(scp, bufferp, NULL, userp, reqp);
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		lock_ObtainMutex(&amp;bufferp-&gt;mx);
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
! 		if (code)
! 			break;
! 	}
! 
! 	/* We try to determine emptiness without looking beyond the first page,
! 	 * and without assuming "." and ".." are present and are on the first
! 	 * page (though these assumptions might, after all, be reasonable).
! 	 */
! 	hashTable = (unsigned short *)(bufferp-&gt;datap + (32 * 5));
! 	for (i=0; i&lt;128; i++) {
! 		idx = ntohs(hashTable[i]);
! 		while (idx) {
! 			if (idx &gt;= 64) {
! 				BeyondPage = 1;
! 				break;
! 			}
! 			dep = (cm_dirEntry_t *)(bufferp-&gt;datap + (32 * idx));
! 			if (strcmp(dep-&gt;name, ".") == 0)
! 				HaveDot = 1;
! 			else if (strcmp(dep-&gt;name, "..") == 0)
! 				HaveDotDot = 1;
! 			else {
! 				code = CM_ERROR_NOTEMPTY;
! 				goto done;
! 			}
! 			idx = ntohs(dep-&gt;next);
! 		}
! 	}
! 	if (BeyondPage &amp;&amp; HaveDot &amp;&amp; HaveDotDot)
! 		code = CM_ERROR_NOTEMPTY;
! 	else
! 		code = 0;
! done:
! 	lock_ReleaseMutex(&amp;bufferp-&gt;mx);
! 	buf_Release(bufferp);
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	return code;
! }
  
  /*
   * Iterate through all entries in a directory.
--- 336,427 ----
  long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
  	cm_req_t *reqp)
  {
!     long code;
!     osi_hyper_t thyper;
!     cm_buf_t *bufferp;
!     cm_dirEntry_t *dep;
!     unsigned short *hashTable;
!     unsigned int i, idx;
!     int BeyondPage = 0, HaveDot = 0, HaveDotDot = 0;
! 
!     /* First check permissions */
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_DELETE,
!                       CM_SCACHESYNC_GETSTATUS
!                       | CM_SCACHESYNC_NEEDCALLBACK);
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
!     if (code)
!         return code;
! 
!     /* If deleting directory, must be empty */
! 
!     if (scp-&gt;fileType != CM_SCACHETYPE_DIRECTORY)
!         return code;
! 
!     thyper.HighPart = 0; thyper.LowPart = 0;
!     lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
!     code = buf_Get(scp, &amp;thyper, &amp;bufferp);
!     lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
!     if (code)
!         return code;
! 
!     lock_ObtainMutex(&amp;bufferp-&gt;mx);
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     while (1) {
!         code = cm_SyncOp(scp, bufferp, userp, reqp, 0,
!                           CM_SCACHESYNC_NEEDCALLBACK
!                           | CM_SCACHESYNC_READ
!                           | CM_SCACHESYNC_BUFLOCKED);
!         if (code)
!             break;
! 
!         if (cm_HaveBuffer(scp, bufferp, 1))
!             break;
! 
!         /* otherwise, load the buffer and try again */
!         lock_ReleaseMutex(&amp;bufferp-&gt;mx);
!         code = cm_GetBuffer(scp, bufferp, NULL, userp, reqp);
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         lock_ObtainMutex(&amp;bufferp-&gt;mx);
!         lock_ObtainMutex(&amp;scp-&gt;mx);
!         if (code)
!             break;
!     }
! 
!     /* We try to determine emptiness without looking beyond the first page,
!      * and without assuming "." and ".." are present and are on the first
!      * page (though these assumptions might, after all, be reasonable).
!      */
!     hashTable = (unsigned short *)(bufferp-&gt;datap + (32 * 5));
!     for (i=0; i&lt;128; i++) {
!         idx = ntohs(hashTable[i]);
!         while (idx) {
!             if (idx &gt;= 64) {
!                 BeyondPage = 1;
!                 break;
!             }
!             dep = (cm_dirEntry_t *)(bufferp-&gt;datap + (32 * idx));
!             if (strcmp(dep-&gt;name, ".") == 0)
!                 HaveDot = 1;
!             else if (strcmp(dep-&gt;name, "..") == 0)
!                 HaveDotDot = 1;
!             else {
!                 code = CM_ERROR_NOTEMPTY;
!                 goto done;
!             }
!             idx = ntohs(dep-&gt;next);
!         }
!     }
!     if (BeyondPage &amp;&amp; HaveDot &amp;&amp; HaveDotDot)
!         code = CM_ERROR_NOTEMPTY;
!     else
!         code = 0;
!   done:   
!     lock_ReleaseMutex(&amp;bufferp-&gt;mx);
!     buf_Release(bufferp);
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     return code;
! }       
  
  /*
   * Iterate through all entries in a directory.
***************
*** 429,436 ****
   * directory vnode is not.
   */
  long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
! 	osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
! 	cm_scache_t **retscp)
  {
      char *tp;
      long code;
--- 429,436 ----
   * directory vnode is not.
   */
  long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
!                   osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
!                   cm_scache_t **retscp)
  {
      char *tp;
      long code;
***************
*** 443,516 ****
      osi_hyper_t thyper;
      long entryInDir;
      long entryInBuffer;
! 	cm_pageHeader_t *pageHeaderp;
      int slotInPage;
      long nextEntryCookie;
      int numDirChunks;	/* # of 32 byte dir chunks in this entry */
          
      /* get the directory size */
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
      code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
!                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 	if (code) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
          return code;
      }
          
      if (scp-&gt;fileType != CM_SCACHETYPE_DIRECTORY) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		return CM_ERROR_NOTDIR;
!     }
  
! 	if (retscp) 			/* if this is a lookup call */
! 	{
! 		cm_lookupSearch_t*	sp = parmp;
          int casefold = sp-&gt;caseFold;
  
          sp-&gt;caseFold = 0; /* we have a strong preference for exact matches */
! 		if ( *retscp = cm_dnlcLookup(scp, sp))	/* dnlc hit */
! 		{
              sp-&gt;caseFold = casefold;
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			return 0;
! 		}
  
          sp-&gt;caseFold = casefold;
! 	}	
  
! 	/*
! 	 * XXX We only get the length once.  It might change when we drop the
! 	 * lock.
! 	 */
      dirLength = scp-&gt;length;
  
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
  
      bufferp = NULL;
      bufferOffset.LowPart = bufferOffset.HighPart = 0;
! 	if (startOffsetp)
          curOffset = *startOffsetp;
! 	else {
          curOffset.HighPart = 0;
          curOffset.LowPart = 0;
! 	}   
  
      while (1) {
! 		/* make sure that curOffset.LowPart doesn't point to the first
           * 32 bytes in the 2nd through last dir page, and that it
! 		 * doesn't point at the first 13 32-byte chunks in the first
! 		 * dir page, since those are dir and page headers, and don't
! 		 * contain useful information.
           */
! 		temp = curOffset.LowPart &amp; (2048-1);
          if (curOffset.HighPart == 0 &amp;&amp; curOffset.LowPart &lt; 2048) {
              /* we're in the first page */
              if (temp &lt; 13*32) temp = 13*32;
- 		}
- 		else {
- 			/* we're in a later dir page */
-             if (temp &lt; 32) temp = 32;
          }
  		
          /* make sure the low order 5 bits are zero */
          temp &amp;= ~(32-1);
--- 443,516 ----
      osi_hyper_t thyper;
      long entryInDir;
      long entryInBuffer;
!     cm_pageHeader_t *pageHeaderp;
      int slotInPage;
      long nextEntryCookie;
      int numDirChunks;	/* # of 32 byte dir chunks in this entry */
          
      /* get the directory size */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
      code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
          return code;
      }
          
      if (scp-&gt;fileType != CM_SCACHETYPE_DIRECTORY) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         return CM_ERROR_NOTDIR;
!     }   
  
!     if (retscp) 			/* if this is a lookup call */
!     {
!         cm_lookupSearch_t*	sp = parmp;
          int casefold = sp-&gt;caseFold;
  
          sp-&gt;caseFold = 0; /* we have a strong preference for exact matches */
!         if ( *retscp = cm_dnlcLookup(scp, sp))	/* dnlc hit */
!         {
              sp-&gt;caseFold = casefold;
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             return 0;
!         }
  
          sp-&gt;caseFold = casefold;
!     }	
  
!     /*
!      * XXX We only get the length once.  It might change when we drop the
!      * lock.
!      */
      dirLength = scp-&gt;length;
  
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
  
      bufferp = NULL;
      bufferOffset.LowPart = bufferOffset.HighPart = 0;
!     if (startOffsetp)
          curOffset = *startOffsetp;
!     else {
          curOffset.HighPart = 0;
          curOffset.LowPart = 0;
!     }   
  
      while (1) {
!         /* make sure that curOffset.LowPart doesn't point to the first
           * 32 bytes in the 2nd through last dir page, and that it
!          * doesn't point at the first 13 32-byte chunks in the first
!          * dir page, since those are dir and page headers, and don't
!          * contain useful information.
           */
!         temp = curOffset.LowPart &amp; (2048-1);
          if (curOffset.HighPart == 0 &amp;&amp; curOffset.LowPart &lt; 2048) {
              /* we're in the first page */
              if (temp &lt; 13*32) temp = 13*32;
          }
+         else {
+             /* we're in a later dir page */
+             if (temp &lt; 32) temp = 32;
+         }       
  		
          /* make sure the low order 5 bits are zero */
          temp &amp;= ~(32-1);
***************
*** 521,1007 ****
  
          /* check if we've passed the dir's EOF */
          if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength))
! 			break;
                  
          /* see if we can use the bufferp we have now; compute in which
           * page the current offset would be, and check whether that's
! 		 * the offset of the buffer we have.  If not, get the buffer.
! 		 */
          thyper.HighPart = curOffset.HighPart;
          thyper.LowPart = curOffset.LowPart &amp; ~(buf_bufferSize-1);
          if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
! 			/* wrong buffer */
              if (bufferp) {
! 				lock_ReleaseMutex(&amp;bufferp-&gt;mx);
                  buf_Release(bufferp);
                  bufferp = NULL;
! 			}
  
! 			lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
              code = buf_Get(scp, &amp;thyper, &amp;bufferp);
! 			lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
  
! 			lock_ObtainMutex(&amp;bufferp-&gt;mx);
!             if (code) break;
              bufferOffset = thyper;
  
              /* now get the data in the cache */
              while (1) {
                  lock_ObtainMutex(&amp;scp-&gt;mx);
! 				code = cm_SyncOp(scp, bufferp, userp, reqp,
!                                  PRSFS_LOOKUP,
!                                  CM_SCACHESYNC_NEEDCALLBACK
!                                  | CM_SCACHESYNC_READ
!                                  | CM_SCACHESYNC_BUFLOCKED);
! 				if (code) {
! 					lock_ReleaseMutex(&amp;scp-&gt;mx);
! 					break;
! 				}
                                  
                  if (cm_HaveBuffer(scp, bufferp, 1)) {
! 					lock_ReleaseMutex(&amp;scp-&gt;mx);
! 					break;
! 				}
!                                 
                  /* otherwise, load the buffer and try again */
                  lock_ReleaseMutex(&amp;bufferp-&gt;mx);
                  code = cm_GetBuffer(scp, bufferp, NULL, userp,
                                      reqp);
                  lock_ReleaseMutex(&amp;scp-&gt;mx);
                  lock_ObtainMutex(&amp;bufferp-&gt;mx);
!                 if (code) break;
              }
              if (code) {
! 				lock_ReleaseMutex(&amp;bufferp-&gt;mx);
! 				buf_Release(bufferp);
                  bufferp = NULL;
                  break;
! 			}
          }	/* if (wrong buffer) ... */
                  
          /* now we have the buffer containing the entry we're interested
           * in; copy it out if it represents a non-deleted entry.
           */
! 		entryInDir = curOffset.LowPart &amp; (2048-1);
          entryInBuffer = curOffset.LowPart &amp; (buf_bufferSize - 1);
  
! 		/* page header will help tell us which entries are free.  Page
! 		 * header can change more often than once per buffer, since
! 		 * AFS 3 dir page size may be less than (but not more than) a
! 		 * buffer package buffer.
           */
! 		/* only look intra-buffer */
! 		temp = curOffset.LowPart &amp; (buf_bufferSize - 1);
          temp &amp;= ~(2048 - 1);	/* turn off intra-page bits */
! 		pageHeaderp = (cm_pageHeader_t *) (bufferp-&gt;datap + temp);
  
! 		/* now determine which entry we're looking at in the page.  If
! 		 * it is free (there's a free bitmap at the start of the dir),
! 		 * we should skip these 32 bytes.
           */
          slotInPage = (entryInDir &amp; 0x7e0) &gt;&gt; 5;
          if (!(pageHeaderp-&gt;freeBitmap[slotInPage&gt;&gt;3]
                 &amp; (1 &lt;&lt; (slotInPage &amp; 0x7)))) {
! 			/* this entry is free */
              numDirChunks = 1;	/* only skip this guy */
              goto nextEntry;
          }
  
! 		tp = bufferp-&gt;datap + entryInBuffer;
          dep = (cm_dirEntry_t *) tp;	/* now points to AFS3 dir entry */
  
          /* while we're here, compute the next entry's location, too,
! 		 * since we'll need it when writing out the cookie into the
! 		 * dir listing stream.
           */
! 		numDirChunks = cm_NameEntries(dep-&gt;name, NULL);
  		
          /* compute the offset of the cookie representing the next entry */
          nextEntryCookie = curOffset.LowPart
! 			+ (CM_DIR_CHUNKSIZE * numDirChunks);
  
          if (dep-&gt;fid.vnode != 0) {
! 			/* this is one of the entries to use: it is not deleted */
! 			code = (*funcp)(scp, dep, parmp, &amp;curOffset);
!             if (code) break;
! 		}	/* if we're including this name */
                  
        nextEntry:
          /* and adjust curOffset to be where the new cookie is */
! 		thyper.HighPart = 0;
          thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
          curOffset = LargeIntegerAdd(thyper, curOffset);
      }		/* while copying data for dir listing */
  
! 	/* release the mutex */
      if (bufferp) {
! 		lock_ReleaseMutex(&amp;bufferp-&gt;mx);
          buf_Release(bufferp);
! 	}
      return code;
  }
  
  int cm_NoneUpper(char *s)
  {
! 	char c;
! 	while (c = *s++)
! 		if (c &gt;= 'A' &amp;&amp; c &lt;= 'Z')
! 			return 0;
! 	return 1;
  }
  
  int cm_NoneLower(char *s)
  {
! 	char c;
! 	while (c = *s++)
! 		if (c &gt;= 'a' &amp;&amp; c &lt;= 'z')
! 			return 0;
! 	return 1;
  }
  
  long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
! 	osi_hyper_t *offp)
  {
! 	cm_lookupSearch_t *sp;
      int match;
! 	char shortName[13];
! 	char *matchName;
!         
      sp = (cm_lookupSearch_t *) rockp;
  
! 	matchName = dep-&gt;name;
! 	if (sp-&gt;caseFold)
          match = cm_stricmp(matchName, sp-&gt;searchNamep);
! 	else
! 		match = strcmp(matchName, sp-&gt;searchNamep);
  
! 	if (match != 0
! 	    &amp;&amp; sp-&gt;hasTilde
! 	    &amp;&amp; !cm_Is8Dot3(dep-&gt;name)) {
! 		matchName = shortName;
! 		cm_Gen8Dot3Name(dep, shortName, NULL);
! 		if (sp-&gt;caseFold)
! 			match = cm_stricmp(matchName, sp-&gt;searchNamep);
! 		else
! 			match = strcmp(matchName, sp-&gt;searchNamep);
! 	}
! 
! 	if (match != 0)
! 		return 0;
! 
! 	sp-&gt;found = 1;
!     if(!sp-&gt;caseFold) sp-&gt;ExactFound = 1;
! 
! 	if (!sp-&gt;caseFold || matchName == shortName) {
! 		sp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
! 		sp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
          return CM_ERROR_STOPNOW;
      }
  
! 	/*
! 	 * If we get here, we are doing a case-insensitive search, and we
! 	 * have found a match.  Now we determine what kind of match it is:
! 	 * exact, lower-case, upper-case, or none of the above.  This is done
! 	 * in order to choose among matches, if there are more than one.
! 	 */
! 
! 	/* Exact matches are the best. */
! 	match = strcmp(matchName, sp-&gt;searchNamep);
! 	if (match == 0) {
          sp-&gt;ExactFound = 1;
! 		sp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
! 		sp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
          return CM_ERROR_STOPNOW;
      }
  
! 	/* Lower-case matches are next. */
! 	if (sp-&gt;LCfound)
! 		return 0;
! 	if (cm_NoneUpper(matchName)) {
! 		sp-&gt;LCfound = 1;
! 		goto inexact;
! 	}
! 
! 	/* Upper-case matches are next. */
! 	if (sp-&gt;UCfound)
! 		return 0;
! 	if (cm_NoneLower(matchName)) {
! 		sp-&gt;UCfound = 1;
! 		goto inexact;
! 	}
! 
! 	/* General matches are last. */
! 	if (sp-&gt;NCfound)
! 		return 0;
! 	sp-&gt;NCfound = 1;
! 
! inexact:
! 	sp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
! 	sp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
! 	return 0;
! }
  
  /* read the contents of a mount point into the appropriate string.
   * called with locked scp, and returns with locked scp.
   */
  long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code;
! 	cm_buf_t *bufp;
!         osi_hyper_t thyper;
!         int tlen;
  
! 	if (scp-&gt;mountPointStringp) return 0;
          
!         /* otherwise, we have to read it in */
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
  
! 	lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
!         thyper.LowPart = thyper.HighPart = 0;
! 	code = buf_Get(scp, &amp;thyper, &amp;bufp);
! 	lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
  
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
          if (code) {
!                 return code;
          }
! 	while (1) {
! 	        code = cm_SyncOp(scp, bufp, userp, reqp, 0,
!                 	CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
! 	        if (code) {
! 	                goto done;
! 	        }
!                 
!                 if (cm_HaveBuffer(scp, bufp, 0)) break;
!                 
!                 /* otherwise load buffer */
!                 code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
!                 if (code) {
! 			goto done;
! 		}
! 	}
!         /* locked, has callback, has valid data in buffer */
!         if ((tlen = scp-&gt;length.LowPart) &gt; 1000) return CM_ERROR_TOOBIG;
!         if (tlen &lt;= 0) {
!         	code = CM_ERROR_INVAL;
! 		goto done;
! 	}
!         
! 	/* someone else did the work while we were out */
!         if (scp-&gt;mountPointStringp) {
! 		code = 0;
!                 goto done;
          }
! 	
!         /* otherwise, copy out the link */
!         scp-&gt;mountPointStringp = malloc(tlen);
!         memcpy(scp-&gt;mountPointStringp, bufp-&gt;datap, tlen);
! 
! 	/* now make it null-terminated.  Note that the original contents of a
! 	 * link that is a mount point is "#volname." where "." is there just to
! 	 * be turned into a null.  That is, we can trash the last char of the
! 	 * link without damaging the vol name.  This is a stupid convention,
! 	 * but that's the protocol.
!          */
!         scp-&gt;mountPointStringp[tlen-1] = 0;
          code = 0;
  
! done:
! 	if (bufp) buf_Release(bufp);
!         return code;
  }
  
  /* called with a locked scp and chases the mount point, yielding outScpp.
   * scp remains locked, just for simplicity of describing the interface.
   */
  long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
! 	cm_req_t *reqp, cm_scache_t **outScpp)
  {
! 	char *cellNamep;
!         char *volNamep;
!         int tlen;
!         long code;
!         char *cp;
!         char *mpNamep;
! 	cm_volume_t *volp;
!         cm_cell_t *cellp;
!         char mtType;
!         cm_fid_t tfid;
! 	size_t vnLength;
! 	int type;
! 
! 	if (scp-&gt;mountRootFidp &amp;&amp; scp-&gt;mountRootGen &gt;= cm_mountRootGen) {
! 		tfid = *scp-&gt;mountRootFidp;
!                 lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		code = cm_GetSCache(&amp;tfid, outScpp, userp, reqp);
!                 lock_ObtainMutex(&amp;scp-&gt;mx);
!         	return code;
! 	}
! 
! 	/* parse the volume name */
! 	mpNamep = scp-&gt;mountPointStringp;
! 	osi_assert(mpNamep);
!         tlen = strlen(scp-&gt;mountPointStringp);
!         mtType = *scp-&gt;mountPointStringp;
!         cellNamep = malloc(tlen);
!         volNamep = malloc(tlen);
!         
! 	cp = strrchr(mpNamep, ':');
!         if (cp) {
! 		/* cellular mount point */
! 		memset(cellNamep, 0, tlen);
!                 strncpy(cellNamep, mpNamep+1, cp - mpNamep - 1);
!                 strcpy(volNamep, cp+1);
!                 /* now look up the cell */
!                 cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
!         }
! 	else {
! 		/* normal mt pt */
!                 strcpy(volNamep, mpNamep+1);
!                 
!                 cellp = cm_FindCellByID(scp-&gt;fid.cell);
!         }
!         
! 	if (!cellp) {
! 		code = CM_ERROR_NOSUCHCELL;
! 		goto done;
! 	}
! 
! 	vnLength = strlen(volNamep);
! 	if (vnLength &gt;= 8 &amp;&amp; strcmp(volNamep + vnLength - 7, ".backup") == 0)
! 		type = BACKVOL;
! 	else if (vnLength &gt;= 10
! 		  &amp;&amp; strcmp(volNamep + vnLength - 9, ".readonly") == 0)
! 		type = ROVOL;
! 	else
! 		type = RWVOL;
! 
! 	/* check for backups within backups */
! 	if (type == BACKVOL
! 	    &amp;&amp; (scp-&gt;flags &amp; (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
! 		  == CM_SCACHEFLAG_RO) {
! 		code = CM_ERROR_NOSUCHVOLUME;
! 		goto done;
! 	}
  
!         /* now we need to get the volume */
          lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	code = cm_GetVolumeByName(cellp, volNamep, userp, reqp, 0, &amp;volp);
          lock_ObtainMutex(&amp;scp-&gt;mx);
-         
-         if (code == 0) {
- 	        /* save the parent of the volume root for this is the 
- 		 * place where the volume is mounted and we must remember 
- 		 * this in the volume structure rather than just in the 
- 		 * scache entry lest the scache entry gets recycled 
- 		 * (defect 11489)
- 		 */
- 	        lock_ObtainMutex(&amp;volp-&gt;mx);
- 	        if(volp-&gt;dotdotFidp == (cm_fid_t *) NULL) 
- 		        volp-&gt;dotdotFidp = (cm_fid_t *) malloc(sizeof(cm_fid_t));
- 		*(volp-&gt;dotdotFidp) = dscp-&gt;fid;
- 		lock_ReleaseMutex(&amp;volp-&gt;mx);
- 
- 		if (scp-&gt;mountRootFidp == 0) {
- 			scp-&gt;mountRootFidp = malloc(sizeof(cm_fid_t));
-                 }
-                 scp-&gt;mountRootFidp-&gt;cell = cellp-&gt;cellID;
- 		/* if the mt pt is in a read-only volume (not just a
- 		 * backup), and if there is a read-only volume for the
- 		 * target, and if this is a type '#' mount point, use
- 		 * the read-only, otherwise use the one specified.
-                  */
-                 if (mtType == '#' &amp;&amp; (scp-&gt;flags &amp; CM_SCACHEFLAG_PURERO)
-                        	&amp;&amp; volp-&gt;roID != 0 &amp;&amp; type == RWVOL)
- 			type = ROVOL;
- 		if (type == ROVOL)
-                        	scp-&gt;mountRootFidp-&gt;volume = volp-&gt;roID;
- 		else if (type == BACKVOL)
- 			scp-&gt;mountRootFidp-&gt;volume = volp-&gt;bkID;
-                 else
- 			scp-&gt;mountRootFidp-&gt;volume = volp-&gt;rwID;
- 
- 		/* the rest of the fid is a magic number */
-                 scp-&gt;mountRootFidp-&gt;vnode = 1;
-                 scp-&gt;mountRootFidp-&gt;unique = 1;
- 		scp-&gt;mountRootGen = cm_mountRootGen;
-                
- 		tfid = *scp-&gt;mountRootFidp;
-                 lock_ReleaseMutex(&amp;scp-&gt;mx);
-                 code = cm_GetSCache(&amp;tfid, outScpp, userp, reqp);
-                 lock_ObtainMutex(&amp;scp-&gt;mx);
-         }
- 
- done:
- 	free(cellNamep);
-         free(volNamep);
          return code;
! }
  
! int cm_ExpandSysName(char *inp, char *outp, long outSize)
! {
! 	char *tp;
!     int prefixCount;
  
!     tp = strrchr(inp, '@');
!     if (tp == NULL) return 0;		/* no @sys */
  
!     if (strcmp(tp, "@sys") != 0) return 0;	/* no @sys */
  
! 	/* caller just wants to know if this is a valid @sys type of name */
! 	if (outp == NULL) return 1;
  
! 	/* otherwise generate the properly expanded @sys name */
!     prefixCount = tp - inp;
  
!     strncpy(outp, inp, prefixCount);	/* copy out "a." from "a.@sys" */
!     outp[prefixCount] = 0;			/* null terminate the "a." */
!     strcat(outp, cm_sysName);		/* append i386_nt40 */
!     return 1;
! }   
  
! long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
! 	cm_req_t *reqp, cm_scache_t **outpScpp)
  {
! 	long code;
! 	int dnlcHit = 1;	/* did we hit in the dnlc? yes, we did */
      cm_scache_t *tscp = NULL;
      cm_scache_t *mountedScp;
      cm_lookupSearch_t rock;
!     char tname[256];
! 	int getroot;
  
! 	if (dscp-&gt;fid.vnode == 1 &amp;&amp; dscp-&gt;fid.unique == 1
           &amp;&amp; strcmp(namep, "..") == 0) {
! 		if (dscp-&gt;dotdotFidp == (cm_fid_t *)NULL
               || dscp-&gt;dotdotFidp-&gt;volume == 0)
! 			return CM_ERROR_NOSUCHVOLUME;
! 		rock.fid = *dscp-&gt;dotdotFidp;
! 		goto haveFid;
! 	}
! 
! 	if (cm_ExpandSysName(namep, tname, sizeof(tname))) {
! 		namep = tname;
      }
! 	memset(&amp;rock, 0, sizeof(rock));
      rock.fid.cell = dscp-&gt;fid.cell;
      rock.fid.volume = dscp-&gt;fid.volume;
      rock.searchNamep = namep;
      rock.caseFold = (flags &amp; CM_FLAG_CASEFOLD);
! 	rock.hasTilde = ((strchr(namep, '~') != NULL) ? 1 : 0);
  
! 	/* If NOMOUNTCHASE, bypass DNLC by passing NULL scp pointer */
! 	code = cm_ApplyDir(dscp, cm_LookupSearchProc, &amp;rock, NULL, userp, reqp,
!                        (flags &amp; CM_FLAG_NOMOUNTCHASE) ? NULL : &amp;tscp);
  
! 	/* code == 0 means we fell off the end of the dir, while stopnow means
       * that we stopped early, probably because we found the entry we're
! 	 * looking for.  Any other non-zero code is an error.
       */
      if (code &amp;&amp; code != CM_ERROR_STOPNOW) 
          return code;
  
! 	getroot = (dscp==cm_rootSCachep) ;
      if (!rock.found) {
          if (!cm_freelanceEnabled || !getroot) {
              if (flags &amp; CM_FLAG_CHECKPATH)
--- 521,988 ----
  
          /* check if we've passed the dir's EOF */
          if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength))
!             break;
                  
          /* see if we can use the bufferp we have now; compute in which
           * page the current offset would be, and check whether that's
!          * the offset of the buffer we have.  If not, get the buffer.
!          */
          thyper.HighPart = curOffset.HighPart;
          thyper.LowPart = curOffset.LowPart &amp; ~(buf_bufferSize-1);
          if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
!             /* wrong buffer */
              if (bufferp) {
!                 lock_ReleaseMutex(&amp;bufferp-&gt;mx);
                  buf_Release(bufferp);
                  bufferp = NULL;
!             }
  
!             lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
              code = buf_Get(scp, &amp;thyper, &amp;bufferp);
!             lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
  
!             lock_ObtainMutex(&amp;bufferp-&gt;mx);
!             if (code) 
!                 break;
              bufferOffset = thyper;
  
              /* now get the data in the cache */
              while (1) {
                  lock_ObtainMutex(&amp;scp-&gt;mx);
!                 code = cm_SyncOp(scp, bufferp, userp, reqp,
!                                   PRSFS_LOOKUP,
!                                   CM_SCACHESYNC_NEEDCALLBACK
!                                   | CM_SCACHESYNC_READ
!                                   | CM_SCACHESYNC_BUFLOCKED);
!                 if (code) {
!                     lock_ReleaseMutex(&amp;scp-&gt;mx);
!                     break;
!                 }
                                  
                  if (cm_HaveBuffer(scp, bufferp, 1)) {
!                     lock_ReleaseMutex(&amp;scp-&gt;mx);
!                     break;
!                 }
! 
                  /* otherwise, load the buffer and try again */
                  lock_ReleaseMutex(&amp;bufferp-&gt;mx);
                  code = cm_GetBuffer(scp, bufferp, NULL, userp,
                                      reqp);
                  lock_ReleaseMutex(&amp;scp-&gt;mx);
                  lock_ObtainMutex(&amp;bufferp-&gt;mx);
!                 if (code) 
!                     break;
              }
              if (code) {
!                 lock_ReleaseMutex(&amp;bufferp-&gt;mx);
!                 buf_Release(bufferp);
                  bufferp = NULL;
                  break;
!             }
          }	/* if (wrong buffer) ... */
                  
          /* now we have the buffer containing the entry we're interested
           * in; copy it out if it represents a non-deleted entry.
           */
!         entryInDir = curOffset.LowPart &amp; (2048-1);
          entryInBuffer = curOffset.LowPart &amp; (buf_bufferSize - 1);
  
!         /* page header will help tell us which entries are free.  Page
!          * header can change more often than once per buffer, since
!          * AFS 3 dir page size may be less than (but not more than) a
!          * buffer package buffer.
           */
!         /* only look intra-buffer */
!         temp = curOffset.LowPart &amp; (buf_bufferSize - 1);
          temp &amp;= ~(2048 - 1);	/* turn off intra-page bits */
!         pageHeaderp = (cm_pageHeader_t *) (bufferp-&gt;datap + temp);
  
!         /* now determine which entry we're looking at in the page.  If
!          * it is free (there's a free bitmap at the start of the dir),
!          * we should skip these 32 bytes.
           */
          slotInPage = (entryInDir &amp; 0x7e0) &gt;&gt; 5;
          if (!(pageHeaderp-&gt;freeBitmap[slotInPage&gt;&gt;3]
                 &amp; (1 &lt;&lt; (slotInPage &amp; 0x7)))) {
!             /* this entry is free */
              numDirChunks = 1;	/* only skip this guy */
              goto nextEntry;
          }
  
!         tp = bufferp-&gt;datap + entryInBuffer;
          dep = (cm_dirEntry_t *) tp;	/* now points to AFS3 dir entry */
  
          /* while we're here, compute the next entry's location, too,
!          * since we'll need it when writing out the cookie into the
!          * dir listing stream.
           */
!         numDirChunks = cm_NameEntries(dep-&gt;name, NULL);
  		
          /* compute the offset of the cookie representing the next entry */
          nextEntryCookie = curOffset.LowPart
!             + (CM_DIR_CHUNKSIZE * numDirChunks);
  
          if (dep-&gt;fid.vnode != 0) {
!             /* this is one of the entries to use: it is not deleted */
!             code = (*funcp)(scp, dep, parmp, &amp;curOffset);
!             if (code) 
!                 break;
!         }	/* if we're including this name */
                  
        nextEntry:
          /* and adjust curOffset to be where the new cookie is */
!         thyper.HighPart = 0;
          thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
          curOffset = LargeIntegerAdd(thyper, curOffset);
      }		/* while copying data for dir listing */
  
!     /* release the mutex */
      if (bufferp) {
!         lock_ReleaseMutex(&amp;bufferp-&gt;mx);
          buf_Release(bufferp);
!     }
      return code;
  }
  
  int cm_NoneUpper(char *s)
  {
!     char c;
!     while (c = *s++)
!         if (c &gt;= 'A' &amp;&amp; c &lt;= 'Z')
!             return 0;
!     return 1;
  }
  
  int cm_NoneLower(char *s)
  {
!     char c;
!     while (c = *s++)
!         if (c &gt;= 'a' &amp;&amp; c &lt;= 'z')
!             return 0;
!     return 1;
  }
  
  long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
!                           osi_hyper_t *offp)
  {
!     cm_lookupSearch_t *sp;
      int match;
!     char shortName[13];
!     char *matchName;
! 
      sp = (cm_lookupSearch_t *) rockp;
  
!     matchName = dep-&gt;name;
!     if (sp-&gt;caseFold)
          match = cm_stricmp(matchName, sp-&gt;searchNamep);
!     else
!         match = strcmp(matchName, sp-&gt;searchNamep);
  
!     if (match != 0
!          &amp;&amp; sp-&gt;hasTilde
!          &amp;&amp; !cm_Is8Dot3(dep-&gt;name)) {
!         matchName = shortName;
!         cm_Gen8Dot3Name(dep, shortName, NULL);
!         if (sp-&gt;caseFold)
!             match = cm_stricmp(matchName, sp-&gt;searchNamep);
!         else
!             match = strcmp(matchName, sp-&gt;searchNamep);
!     }       
! 
!     if (match != 0)
!         return 0;
! 
!     sp-&gt;found = 1;
!     if(!sp-&gt;caseFold) 
!         sp-&gt;ExactFound = 1;
! 
!     if (!sp-&gt;caseFold || matchName == shortName) {
!         sp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
!         sp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
          return CM_ERROR_STOPNOW;
      }
  
!     /*
!      * If we get here, we are doing a case-insensitive search, and we
!      * have found a match.  Now we determine what kind of match it is:
!      * exact, lower-case, upper-case, or none of the above.  This is done
!      * in order to choose among matches, if there are more than one.
!      */
! 
!     /* Exact matches are the best. */
!     match = strcmp(matchName, sp-&gt;searchNamep);
!     if (match == 0) {
          sp-&gt;ExactFound = 1;
!         sp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
!         sp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
          return CM_ERROR_STOPNOW;
      }
  
!     /* Lower-case matches are next. */
!     if (sp-&gt;LCfound)
!         return 0;
!     if (cm_NoneUpper(matchName)) {
!         sp-&gt;LCfound = 1;
!         goto inexact;
!     }
! 
!     /* Upper-case matches are next. */
!     if (sp-&gt;UCfound)
!         return 0;
!     if (cm_NoneLower(matchName)) {
!         sp-&gt;UCfound = 1;
!         goto inexact;
!     }
! 
!     /* General matches are last. */
!     if (sp-&gt;NCfound)
!         return 0;
!     sp-&gt;NCfound = 1;
! 
!   inexact:
!     sp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
!     sp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
!     return 0;
! }       
  
  /* read the contents of a mount point into the appropriate string.
   * called with locked scp, and returns with locked scp.
   */
  long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
!     cm_buf_t *bufp;
!     osi_hyper_t thyper;
!     int tlen;
  
!     if (scp-&gt;mountPointStringp) 
!         return 0;
          
!     /* otherwise, we have to read it in */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
  
!     lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
!     thyper.LowPart = thyper.HighPart = 0;
!     code = buf_Get(scp, &amp;thyper, &amp;bufp);
!     lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
  
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     if (code) {
!         return code;
!     }
!     while (1) {
!         code = cm_SyncOp(scp, bufp, userp, reqp, 0,
!                           CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
          if (code) {
!             goto done;
          }
! 
!         if (cm_HaveBuffer(scp, bufp, 0)) 
!             break;
! 
!         /* otherwise load buffer */
!         code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
!         if (code) {
!             goto done;
          }
!     }
!     /* locked, has callback, has valid data in buffer */
!     if ((tlen = scp-&gt;length.LowPart) &gt; 1000) return CM_ERROR_TOOBIG;
!     if (tlen &lt;= 0) {
!         code = CM_ERROR_INVAL;
!         goto done;
!     }
! 
!     /* someone else did the work while we were out */
!     if (scp-&gt;mountPointStringp) {
          code = 0;
+         goto done;
+     }
  
!     /* otherwise, copy out the link */
!     scp-&gt;mountPointStringp = malloc(tlen);
!     memcpy(scp-&gt;mountPointStringp, bufp-&gt;datap, tlen);
! 
!     /* now make it null-terminated.  Note that the original contents of a
!      * link that is a mount point is "#volname." where "." is there just to
!      * be turned into a null.  That is, we can trash the last char of the
!      * link without damaging the vol name.  This is a stupid convention,
!      * but that's the protocol.
!      */
!     scp-&gt;mountPointStringp[tlen-1] = 0;
!     code = 0;
! 
!   done:
!     if (bufp) 
!         buf_Release(bufp);
!     return code;
  }
  
  /* called with a locked scp and chases the mount point, yielding outScpp.
   * scp remains locked, just for simplicity of describing the interface.
   */
  long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
!                           cm_req_t *reqp, cm_scache_t **outScpp)
  {
!     char *cellNamep;
!     char *volNamep;
!     int tlen;
!     long code;
!     char *cp;
!     char *mpNamep;
!     cm_volume_t *volp;
!     cm_cell_t *cellp;
!     char mtType;
!     cm_fid_t tfid;
!     size_t vnLength;
!     int type;
  
!     if (scp-&gt;mountRootFidp &amp;&amp; scp-&gt;mountRootGen &gt;= cm_mountRootGen) {
!         tfid = *scp-&gt;mountRootFidp;
          lock_ReleaseMutex(&amp;scp-&gt;mx);
!         code = cm_GetSCache(&amp;tfid, outScpp, userp, reqp);
          lock_ObtainMutex(&amp;scp-&gt;mx);
          return code;
!     }
  
!     /* parse the volume name */
!     mpNamep = scp-&gt;mountPointStringp;
!     osi_assert(mpNamep);
!     tlen = strlen(scp-&gt;mountPointStringp);
!     mtType = *scp-&gt;mountPointStringp;
!     cellNamep = malloc(tlen);
!     volNamep = malloc(tlen);
! 
!     cp = strrchr(mpNamep, ':');
!     if (cp) {
!         /* cellular mount point */
!         memset(cellNamep, 0, tlen);
!         strncpy(cellNamep, mpNamep+1, cp - mpNamep - 1);
!         strcpy(volNamep, cp+1);
!         /* now look up the cell */
!         cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
!     }
!     else {
!         /* normal mt pt */
!         strcpy(volNamep, mpNamep+1);
  
!         cellp = cm_FindCellByID(scp-&gt;fid.cell);
!     }
  
!     if (!cellp) {
!         code = CM_ERROR_NOSUCHCELL;
!         goto done;
!     }
  
!     vnLength = strlen(volNamep);
!     if (vnLength &gt;= 8 &amp;&amp; strcmp(volNamep + vnLength - 7, ".backup") == 0)
!         type = BACKVOL;
!     else if (vnLength &gt;= 10
!               &amp;&amp; strcmp(volNamep + vnLength - 9, ".readonly") == 0)
!         type = ROVOL;
!     else
!         type = RWVOL;
! 
!     /* check for backups within backups */
!     if (type == BACKVOL
!          &amp;&amp; (scp-&gt;flags &amp; (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
!          == CM_SCACHEFLAG_RO) {
!         code = CM_ERROR_NOSUCHVOLUME;
!         goto done;
!     }
  
!     /* now we need to get the volume */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     code = cm_GetVolumeByName(cellp, volNamep, userp, reqp, 0, &amp;volp);
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!         
!     if (code == 0) {
!         /* save the parent of the volume root for this is the 
!          * place where the volume is mounted and we must remember 
!          * this in the volume structure rather than just in the 
!          * scache entry lest the scache entry gets recycled 
!          * (defect 11489)
!          */
!         lock_ObtainMutex(&amp;volp-&gt;mx);
!         if(volp-&gt;dotdotFidp == (cm_fid_t *) NULL) 
!             volp-&gt;dotdotFidp = (cm_fid_t *) malloc(sizeof(cm_fid_t));
!         *(volp-&gt;dotdotFidp) = dscp-&gt;fid;
!         lock_ReleaseMutex(&amp;volp-&gt;mx);
! 
!         if (scp-&gt;mountRootFidp == 0) {
!             scp-&gt;mountRootFidp = malloc(sizeof(cm_fid_t));
!         }
!         scp-&gt;mountRootFidp-&gt;cell = cellp-&gt;cellID;
!         /* if the mt pt is in a read-only volume (not just a
!          * backup), and if there is a read-only volume for the
!          * target, and if this is a type '#' mount point, use
!          * the read-only, otherwise use the one specified.
!          */
!         if (mtType == '#' &amp;&amp; (scp-&gt;flags &amp; CM_SCACHEFLAG_PURERO)
!              &amp;&amp; volp-&gt;roID != 0 &amp;&amp; type == RWVOL)
!             type = ROVOL;
!         if (type == ROVOL)
!             scp-&gt;mountRootFidp-&gt;volume = volp-&gt;roID;
!         else if (type == BACKVOL)
!             scp-&gt;mountRootFidp-&gt;volume = volp-&gt;bkID;
!         else
!             scp-&gt;mountRootFidp-&gt;volume = volp-&gt;rwID;
! 
!         /* the rest of the fid is a magic number */
!         scp-&gt;mountRootFidp-&gt;vnode = 1;
!         scp-&gt;mountRootFidp-&gt;unique = 1;
!         scp-&gt;mountRootGen = cm_mountRootGen;
  
!         tfid = *scp-&gt;mountRootFidp;
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         code = cm_GetSCache(&amp;tfid, outScpp, userp, reqp);
!         lock_ObtainMutex(&amp;scp-&gt;mx);
!     }
  
!   done:
!     free(cellNamep);
!     free(volNamep);
!     return code;
! }       
! 
! long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
!                        cm_req_t *reqp, cm_scache_t **outpScpp)
  {
!     long code;
!     int dnlcHit = 1;	/* did we hit in the dnlc? yes, we did */
      cm_scache_t *tscp = NULL;
      cm_scache_t *mountedScp;
      cm_lookupSearch_t rock;
!     int getroot;
  
!     if (dscp-&gt;fid.vnode == 1 &amp;&amp; dscp-&gt;fid.unique == 1
           &amp;&amp; strcmp(namep, "..") == 0) {
!         if (dscp-&gt;dotdotFidp == (cm_fid_t *)NULL
               || dscp-&gt;dotdotFidp-&gt;volume == 0)
!             return CM_ERROR_NOSUCHVOLUME;
!         rock.fid = *dscp-&gt;dotdotFidp;
!         goto haveFid;
      }
! 
!     memset(&amp;rock, 0, sizeof(rock));
      rock.fid.cell = dscp-&gt;fid.cell;
      rock.fid.volume = dscp-&gt;fid.volume;
      rock.searchNamep = namep;
      rock.caseFold = (flags &amp; CM_FLAG_CASEFOLD);
!     rock.hasTilde = ((strchr(namep, '~') != NULL) ? 1 : 0);
  
!     /* If NOMOUNTCHASE, bypass DNLC by passing NULL scp pointer */
!     code = cm_ApplyDir(dscp, cm_LookupSearchProc, &amp;rock, NULL, userp, reqp,
!                         (flags &amp; CM_FLAG_NOMOUNTCHASE) ? NULL : &amp;tscp);
  
!     /* code == 0 means we fell off the end of the dir, while stopnow means
       * that we stopped early, probably because we found the entry we're
!      * looking for.  Any other non-zero code is an error.
       */
      if (code &amp;&amp; code != CM_ERROR_STOPNOW) 
          return code;
  
!     getroot = (dscp==cm_rootSCachep) ;
      if (!rock.found) {
          if (!cm_freelanceEnabled || !getroot) {
              if (flags &amp; CM_FLAG_CHECKPATH)
***************
*** 1010,1018 ****
                  return CM_ERROR_NOSUCHFILE;
          }
          else {  /* nonexistent dir on freelance root, so add it */
! 			osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s", 
!                      osi_LogSaveString(afsd_logp,namep));
! 			code = cm_FreelanceAddMount(namep, namep, "root.cell.", namep[0] == '.', &amp;rock.fid);
              if (code &lt; 0) {   /* add mount point failed, so give up */
                  if (flags &amp; CM_FLAG_CHECKPATH)
                      return CM_ERROR_NOSUCHPATH;
--- 991,999 ----
                  return CM_ERROR_NOSUCHFILE;
          }
          else {  /* nonexistent dir on freelance root, so add it */
!             osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s", 
!                       osi_LogSaveString(afsd_logp,namep));
!             code = cm_FreelanceAddMount(namep, namep, "root.cell.", namep[0] == '.', &amp;rock.fid);
              if (code &lt; 0) {   /* add mount point failed, so give up */
                  if (flags &amp; CM_FLAG_CHECKPATH)
                      return CM_ERROR_NOSUCHPATH;
***************
*** 1021,1129 ****
              }
              tscp = NULL;   /* to force call of cm_GetSCache */
          }
! 	}
  
! haveFid:       
! 	if ( !tscp )    /* we did not find it in the dnlc */
! 	{
! 		dnlcHit = 0;	
          code = cm_GetSCache(&amp;rock.fid, &amp;tscp, userp, reqp);
          if (code) 
              return code;
! 	}
      /* tscp is now held */
  
! 	lock_ObtainMutex(&amp;tscp-&gt;mx);
! 	code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
                        CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
      if (code) { 
! 		lock_ReleaseMutex(&amp;tscp-&gt;mx);
! 		cm_ReleaseSCache(tscp);
          return code;
! 	}
      /* tscp is now locked */
  
      if (!(flags &amp; CM_FLAG_NOMOUNTCHASE)
! 	      &amp;&amp; tscp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT) {
! 		/* mount points are funny: they have a volume name to mount
           * the root of.
           */
! 		code = cm_ReadMountPoint(tscp, userp, reqp);
          if (code == 0)
! 			code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
                                          &amp;mountedScp);
! 		lock_ReleaseMutex(&amp;tscp-&gt;mx);
! 		cm_ReleaseSCache(tscp);
! 		if (code) {
              return code;
          }
          tscp = mountedScp;
      }
! 	else {
! 		lock_ReleaseMutex(&amp;tscp-&gt;mx);
! 	}
  
! 	/* copy back pointer */
      *outpScpp = tscp;
  
! 	/* insert scache in dnlc */
! 	if ( !dnlcHit &amp;&amp; !(flags &amp; CM_FLAG_NOMOUNTCHASE) &amp;&amp; rock.ExactFound ) {
! 	    /* lock the directory entry to prevent racing callback revokes */
! 	    lock_ObtainMutex(&amp;dscp-&gt;mx);
! 	    if ( dscp-&gt;cbServerp &amp;&amp; dscp-&gt;cbExpires )
              cm_dnlcEnter(dscp, namep, tscp);
! 	    lock_ReleaseMutex(&amp;dscp-&gt;mx);
! 	}
  
! 	/* and return */
      return 0;
  }
  
  long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
  {
!         long code;
!         cm_conn_t *connp;
! 	AFSFid afsFid;
!         int sflags;
!         AFSFetchStatus newDirStatus;
!         AFSVolSync volSync;
  
  #ifdef AFS_FREELANCE_CLIENT
! 	if (cm_freelanceEnabled &amp;&amp; dscp == cm_rootSCachep) {
! 	  /* deleting a mount point from the root dir. */
! 	  code = cm_FreelanceRemoveMount(namep);
! 	  return code;
! 	}
! #endif
  
! 	/* make sure we don't screw up the dir status during the merge */
!         lock_ObtainMutex(&amp;dscp-&gt;mx);
! 	sflags = CM_SCACHESYNC_STOREDATA;
! 	code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags);
!         lock_ReleaseMutex(&amp;dscp-&gt;mx);
! 	if (code) return code;
  
! 	/* make the RPC */
! 	afsFid.Volume = dscp-&gt;fid.volume;
! 	afsFid.Vnode = dscp-&gt;fid.vnode;
! 	afsFid.Unique = dscp-&gt;fid.unique;
!         do {
! 		code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!                 if (code) continue;
!                 
!                 code = RXAFS_RemoveFile(connp-&gt;callp, &amp;afsFid, namep,
! 					&amp;newDirStatus, &amp;volSync);
! 		
! 	} while (cm_Analyze(connp, userp, reqp, &amp;dscp-&gt;fid, &amp;volSync, NULL, NULL, code));
!         code = cm_MapRPCError(code, reqp);
  
!         lock_ObtainMutex(&amp;dscp-&gt;mx);
! 	cm_dnlcRemove(dscp, namep);
! 	cm_SyncOpDone(dscp, NULL, sflags);
!         if (code == 0) cm_MergeStatus(dscp, &amp;newDirStatus, &amp;volSync, userp, 0);
!         lock_ReleaseMutex(&amp;dscp-&gt;mx);
  
!         return code;
  }
  
  /* called with a locked vnode, and fills in the link info.
--- 1002,1176 ----
              }
              tscp = NULL;   /* to force call of cm_GetSCache */
          }
!     }
  
!   haveFid:       
!     if ( !tscp )    /* we did not find it in the dnlc */
!     {
!         dnlcHit = 0;	
          code = cm_GetSCache(&amp;rock.fid, &amp;tscp, userp, reqp);
          if (code) 
              return code;
!     }       
      /* tscp is now held */
  
!     lock_ObtainMutex(&amp;tscp-&gt;mx);
!     code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
                        CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
      if (code) { 
!         lock_ReleaseMutex(&amp;tscp-&gt;mx);
!         cm_ReleaseSCache(tscp);
          return code;
!     }
      /* tscp is now locked */
  
      if (!(flags &amp; CM_FLAG_NOMOUNTCHASE)
!          &amp;&amp; tscp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT) {
!         /* mount points are funny: they have a volume name to mount
           * the root of.
           */
!         code = cm_ReadMountPoint(tscp, userp, reqp);
          if (code == 0)
!             code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
                                          &amp;mountedScp);
!         lock_ReleaseMutex(&amp;tscp-&gt;mx);
!         cm_ReleaseSCache(tscp);
!         if (code) {
              return code;
          }
          tscp = mountedScp;
      }
!     else {
!         lock_ReleaseMutex(&amp;tscp-&gt;mx);
!     }
  
!     /* copy back pointer */
      *outpScpp = tscp;
  
!     /* insert scache in dnlc */
!     if ( !dnlcHit &amp;&amp; !(flags &amp; CM_FLAG_NOMOUNTCHASE) &amp;&amp; rock.ExactFound ) {
!         /* lock the directory entry to prevent racing callback revokes */
!         lock_ObtainMutex(&amp;dscp-&gt;mx);
!         if ( dscp-&gt;cbServerp &amp;&amp; dscp-&gt;cbExpires )
              cm_dnlcEnter(dscp, namep, tscp);
!         lock_ReleaseMutex(&amp;dscp-&gt;mx);
!     }
  
!     /* and return */
      return 0;
  }
  
+ int cm_ExpandSysName(char *inp, char *outp, long outSize, unsigned int index)
+ {
+     char *tp;
+     int prefixCount;
+ 
+     tp = strrchr(inp, '@');
+     if (tp == NULL) 
+         return 0;		/* no @sys */
+ 
+     if (strcmp(tp, "@sys") != 0) 
+         return 0;	/* no @sys */
+ 
+     /* caller just wants to know if this is a valid @sys type of name */
+     if (outp == NULL) 
+         return 1;
+ 
+     if (index &gt;= MAXNUMSYSNAMES)
+         return -1;
+ 
+     /* otherwise generate the properly expanded @sys name */
+     prefixCount = tp - inp;
+ 
+     strncpy(outp, inp, prefixCount);	/* copy out "a." from "a.@sys" */
+     outp[prefixCount] = 0;		/* null terminate the "a." */
+     strcat(outp, cm_sysNameList[index]);/* append i386_nt40 */
+     return 1;
+ }   
+ 
+ long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
+                cm_req_t *reqp, cm_scache_t **outpScpp)
+ {
+     long code;
+     char tname[256];
+     int sysNameIndex = 0;
+     cm_scache_t *scp = 0;
+ 
+     for ( sysNameIndex = 0; sysNameIndex &lt; MAXNUMSYSNAMES; sysNameIndex++) {
+         code = cm_ExpandSysName(namep, tname, sizeof(tname), sysNameIndex);
+         if (code &gt; 0) {
+             code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &amp;scp);
+             if (code == 0) {
+                 *outpScpp = scp;
+                 return 0;
+             }
+ 			if (scp) {
+ 				cm_ReleaseSCache(scp);
+ 				scp = 0;
+ 			}
+         } else {
+             return cm_LookupInternal(dscp, namep, flags, userp, reqp, outpScpp);
+         }
+     }
+ 
+     /* None of the possible sysName expansions could be found */
+     if (flags &amp; CM_FLAG_CHECKPATH)
+         return CM_ERROR_NOSUCHPATH;
+     else
+         return CM_ERROR_NOSUCHFILE;
+ }
+ 
  long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
!     cm_conn_t *connp;
!     AFSFid afsFid;
!     int sflags;
!     AFSFetchStatus newDirStatus;
!     AFSVolSync volSync;
!     struct rx_connection * callp;
  
  #ifdef AFS_FREELANCE_CLIENT
!     if (cm_freelanceEnabled &amp;&amp; dscp == cm_rootSCachep) {
!         /* deleting a mount point from the root dir. */
!         code = cm_FreelanceRemoveMount(namep);
!         return code;
!     }
! #endif  
  
!     /* make sure we don't screw up the dir status during the merge */
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     sflags = CM_SCACHESYNC_STOREDATA;
!     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags);
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
!     if (code) 
!         return code;
  
!     /* make the RPC */
!     afsFid.Volume = dscp-&gt;fid.volume;
!     afsFid.Vnode = dscp-&gt;fid.vnode;
!     afsFid.Unique = dscp-&gt;fid.unique;
!     do {
!         code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!         if (code) 
!             continue;
  
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_RemoveFile(callp, &amp;afsFid, namep,
!                                  &amp;newDirStatus, &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, reqp, &amp;dscp-&gt;fid, &amp;volSync, NULL, NULL, code));
!     code = cm_MapRPCError(code, reqp);
! 
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     cm_dnlcRemove(dscp, namep);
!     cm_SyncOpDone(dscp, NULL, sflags);
!     if (code == 0) 
!         cm_MergeStatus(dscp, &amp;newDirStatus, &amp;volSync, userp, 0);
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
  
!     return code;
  }
  
  /* called with a locked vnode, and fills in the link info.
***************
*** 1131,1425 ****
   */
  long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code;
!         cm_buf_t *bufp;
!         long temp;
!         osi_hyper_t thyper;
! 
! 	lock_AssertMutex(&amp;linkScp-&gt;mx);
!         if (!linkScp-&gt;mountPointStringp) {
! 		/* read the link data */
! 		lock_ReleaseMutex(&amp;linkScp-&gt;mx);
! 		thyper.LowPart = thyper.HighPart = 0;
! 		code = buf_Get(linkScp, &amp;thyper, &amp;bufp);
!                 lock_ObtainMutex(&amp;linkScp-&gt;mx);
!                 if (code) return code;
! 		while (1) {
!         	        code = cm_SyncOp(linkScp, bufp, userp, reqp, 0,
! 	                	CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
! 			if (code) {
!                                 buf_Release(bufp);
! 	                        return code;
! 	                }
! 	                if (cm_HaveBuffer(linkScp, bufp, 0)) break;
!                         
!                         code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
!                         if (code) {
!                                 buf_Release(bufp);
!                                 return code;
!                         }
! 		} /* while loop to get the data */
!                 
!                 /* now if we still have no link read in,
! 		 * copy the data from the buffer */
!                 if ((temp = linkScp-&gt;length.LowPart) &gt;= 1024) {
!                         buf_Release(bufp);
!                         return CM_ERROR_TOOBIG;
!                 }
!                 
!                 /* otherwise, it fits; make sure it is still null (could have
! 		 * lost race with someone else referencing this link above),
! 		 * and if so, copy in the data.
!                  */
!                 if (linkScp-&gt;mountPointStringp == NULL) {
! 			linkScp-&gt;mountPointStringp = malloc(temp+1);
!                         strncpy(linkScp-&gt;mountPointStringp, bufp-&gt;datap, temp);
!                         linkScp-&gt;mountPointStringp[temp] = 0;	/* null terminate */
!                 }
!                 buf_Release(bufp);
!         }	/* don't have sym link contents cached */
!         
!         return 0;
! }
  
! /* called with a held vnode and a path suffix, with the held vnode being a
!  * symbolic link.  Our goal is to generate a new path to interpret, and return
!  * this new path in newSpaceBufferp.  If the new vnode is relative to a dir
!  * other than the directory containing the symbolic link, then the new root is
!  * returned in *newRootScpp, otherwise a null is returned there.
!  */
! long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
! 	cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
! 	cm_user_t *userp, cm_req_t *reqp)
! {
! 	long code;
!         char *linkp;
! 	cm_space_t *tsp;
! 
! 	lock_ObtainMutex(&amp;linkScp-&gt;mx);
! 	code = cm_HandleLink(linkScp, userp, reqp);
! 	if (code) goto done;
! 
! 	/* if we may overflow the buffer, bail out; buffer is signficantly
! 	 * bigger than max path length, so we don't really have to worry about
! 	 * being a little conservative here.
!          */
! 	if (strlen(linkScp-&gt;mountPointStringp) + strlen(pathSuffixp) + 2
! 	     &gt;= CM_UTILS_SPACESIZE)
! 	        return CM_ERROR_TOOBIG;
! 
!         tsp = cm_GetSpace();
!         linkp = linkScp-&gt;mountPointStringp;
!         if (strncmp(linkp, cm_mountRoot, cm_mountRootLen) == 0) {
! 		if (strlen(linkp) &gt; cm_mountRootLen)
! 			strcpy(tsp-&gt;data, linkp+cm_mountRootLen+1);
! 		else
! 			tsp-&gt;data[0] = 0;
!                 *newRootScpp = cm_rootSCachep;
!                 cm_HoldSCache(cm_rootSCachep);
!         } else if (*linkp == '\\' || *linkp == '/') {
! 	  /* formerly, this was considered to be from the AFS root,
! 	     but this seems to create problems.  instead, we will just
! 	     reject the link */
! #if 0
! 		strcpy(tsp-&gt;data, linkp+1);
!                 *newRootScpp = cm_rootSCachep;
!                 cm_HoldSCache(cm_rootSCachep);
! #else
! 		code = CM_ERROR_NOSUCHPATH;
! 		goto done;
! #endif
          }
!         else {
! 		/* a relative link */
! 		strcpy(tsp-&gt;data, linkp);
!                 *newRootScpp = NULL;
!         }
! 	if (pathSuffixp[0] != 0) {	/* if suffix string is non-null */
!         	strcat(tsp-&gt;data, "\\");
!         	strcat(tsp-&gt;data, pathSuffixp);
! 	}
! 	*newSpaceBufferp = tsp;
! 	code = 0;
  
! done:
!         lock_ReleaseMutex(&amp;linkScp-&gt;mx);
!         return code;
  }
  
  long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
! 	cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp)
  {
! 	long code;
!         char *tp;			/* ptr moving through input buffer */
!         char tc;			/* temp char */
!         int haveComponent;		/* has new component started? */
! 	char component[256];		/* this is the new component */
!         char *cp;			/* component name being assembled */
!         cm_scache_t *tscp;		/* current location in the hierarchy */
!         cm_scache_t *nscp;		/* next dude down */
!         cm_scache_t *dirScp;		/* last dir we searched */
!         cm_scache_t *linkScp;		/* new root for the symlink we just
! 					 * looked up */
!         cm_space_t *psp;		/* space for current path, if we've hit
! 					 * any symlinks */
!         cm_space_t *tempsp;		/* temp vbl */
!         char *restp;			/* rest of the pathname to interpret */
!         int symlinkCount;		/* count of # of symlinks traversed */
! 	int extraFlag;			/* avoid chasing mt pts for dir cmd */
! 	int phase = 1;			/* 1 = tidPathp, 2 = pathp */
! 
! 	tp = tidPathp;
! 	if (tp == NULL) {
!         	tp = pathp;
! 		phase = 2;
! 	}
! 	if (tp == NULL) {
! 		tp = "";
! 	}
! 	haveComponent = 0;
!         psp = NULL;
!         tscp = rootSCachep;
!         cm_HoldSCache(tscp);
!         symlinkCount = 0;
!         while (1) {
!             tc = *tp++;
! 		
!             /* map Unix slashes into DOS ones so we can interpret Unix
!              * symlinks properly
!              */
!             if (tc == '/') tc = '\\';
  
!             if (!haveComponent) {
! 			if (tc == '\\') continue;
              else if (tc == 0) {
! 				if (phase == 1) {
! 					phase = 2;
! 					tp = pathp;
! 					continue;
! 				}
                  code = 0;
                  break;
              }
              else {
! 				haveComponent = 1;
                  cp = component;
                  *cp++ = tc;
              }
!             }
!             else {
!                 /* we have a component here */
!                 if (tc == 0 || tc == '\\') {
!                     /* end of the component; we're at the last
!                      * component if tc == 0.  However, if the last
!                      * is a symlink, we have more to do.
!                      */
!                     *cp++ = 0;	/* add null termination */
!                     extraFlag = 0;
!                     if ((flags &amp; CM_FLAG_DIRSEARCH) &amp;&amp; tc == 0)
!                         extraFlag = CM_FLAG_NOMOUNTCHASE;
!                     code = cm_Lookup(tscp, component,
!                                       flags | extraFlag,
!                                       userp, reqp, &amp;nscp);
  
!                     if (code) {
                          cm_ReleaseSCache(tscp);
-                         if (psp) cm_FreeSpace(psp);
-                         return code;
-                     }
-                     haveComponent = 0;	/* component done */
-                     dirScp = tscp;		/* for some symlinks */
-                     tscp = nscp;	/* already held */
-                     if (tc == 0 &amp;&amp; !(flags &amp; CM_FLAG_FOLLOW) &amp;&amp; phase == 2) {
-                         code = 0;
                          cm_ReleaseSCache(dirScp);
!                         break;
                      }
! 
!                     /* now, if tscp is a symlink, we should follow
!                      * it and assemble the path again.
!                      */
!                     lock_ObtainMutex(&amp;tscp-&gt;mx);
!                     code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
!                                       CM_SCACHESYNC_GETSTATUS
!                                       | CM_SCACHESYNC_NEEDCALLBACK);
                      if (code) {
!                         lock_ReleaseMutex(&amp;tscp-&gt;mx);
                          cm_ReleaseSCache(tscp);
                          cm_ReleaseSCache(dirScp);
                          break;
                      }
-                     if (tscp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
-                         /* this is a symlink; assemble a new buffer */
-                         lock_ReleaseMutex(&amp;tscp-&gt;mx);
-                         if (symlinkCount++ &gt;= 16) {
-                             cm_ReleaseSCache(tscp);
-                             cm_ReleaseSCache(dirScp);
-                             if (psp) cm_FreeSpace(psp);
-                             return CM_ERROR_TOOBIG;
-                         }
-                         if (tc == 0) restp = "";
-                         else restp = tp;
-                         code = cm_AssembleLink(tscp, restp, &amp;linkScp, &amp;tempsp, userp, reqp);
-                         if (code) {
-                             /* something went wrong */
-                             cm_ReleaseSCache(tscp);
-                             cm_ReleaseSCache(dirScp);
-                             break;
-                         }
  
!                         /* otherwise, tempsp has the new path,
!                          * and linkScp is the new root from
!                          * which to interpret that path.
!                          * Continue with the namei processing,
!                          * also doing the bookkeeping for the
!                          * space allocation and tracking the
!                          * vnode reference counts.
!                          */
!                         if (psp) cm_FreeSpace(psp);
!                         psp = tempsp;
!                         tp = psp-&gt;data;
!                         cm_ReleaseSCache(tscp);
                      tscp = linkScp;	
                      /* already held
!                                          * by AssembleLink */
!                         /* now, if linkScp is null, that's
!                          * AssembleLink's way of telling us that
!                          * the sym link is relative to the dir
!                          * containing the link.  We have a ref
!                          * to it in dirScp, and we hold it now
!                          * and reuse it as the new spot in the
!                          * dir hierarchy.
!                          */
!                         if (tscp == NULL) {
!                             cm_HoldSCache(dirScp);
!                             tscp = dirScp;
!                         }
!                     }	/* if we have a sym link */
!                     else {
!                         /* not a symlink, we may be done */
!                         lock_ReleaseMutex(&amp;tscp-&gt;mx);
!                         if (tc == 0) {
!                             if (phase == 1) {
!                                 phase = 2;
!                                 tp = pathp;
!                                 continue;
!                             }
!                             cm_ReleaseSCache(dirScp);
!                             code = 0;
!                             break;
                          }
                      }
!                     cm_ReleaseSCache(dirScp);
!                 } /* end of a component */
!                 else *cp++ = tc;
!             } /* we have a component */
!         } /* big while loop over all components */
! 
! 	/* already held */
!     if (psp) cm_FreeSpace(psp);
! 	if (code == 0) *outScpp = tscp;
!         return code;
  }
  
  /* called with a dir, and a vnode within the dir that happens to be a symlink.
--- 1178,1484 ----
   */
  long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
!     cm_buf_t *bufp;
!     long temp;
!     osi_hyper_t thyper;
  
!     lock_AssertMutex(&amp;linkScp-&gt;mx);
!     if (!linkScp-&gt;mountPointStringp) {
!         /* read the link data */
!         lock_ReleaseMutex(&amp;linkScp-&gt;mx);
!         thyper.LowPart = thyper.HighPart = 0;
!         code = buf_Get(linkScp, &amp;thyper, &amp;bufp);
!         lock_ObtainMutex(&amp;linkScp-&gt;mx);
!         if (code) 
!             return code;
!         while (1) {
!             code = cm_SyncOp(linkScp, bufp, userp, reqp, 0,
!                               CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
!             if (code) {
!                 buf_Release(bufp);
!                 return code;
!             }
!             if (cm_HaveBuffer(linkScp, bufp, 0)) 
!                 break;
! 
!             code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
!             if (code) {
!                 buf_Release(bufp);
!                 return code;
!             }
!         } /* while loop to get the data */
!                 
!         /* now if we still have no link read in,
!          * copy the data from the buffer */
!         if ((temp = linkScp-&gt;length.LowPart) &gt;= 1024) {
!             buf_Release(bufp);
!             return CM_ERROR_TOOBIG;
!         }
! 
!         /* otherwise, it fits; make sure it is still null (could have
!          * lost race with someone else referencing this link above),
!          * and if so, copy in the data.
!          */
!         if (linkScp-&gt;mountPointStringp == NULL) {
!             linkScp-&gt;mountPointStringp = malloc(temp+1);
!             strncpy(linkScp-&gt;mountPointStringp, bufp-&gt;datap, temp);
!             linkScp-&gt;mountPointStringp[temp] = 0;	/* null terminate */
          }
!         buf_Release(bufp);
!     }	/* don't have sym link contents cached */
  
!     return 0;
! }       
! 
! /* called with a held vnode and a path suffix, with the held vnode being a
!  * symbolic link.  Our goal is to generate a new path to interpret, and return
!  * this new path in newSpaceBufferp.  If the new vnode is relative to a dir
!  * other than the directory containing the symbolic link, then the new root is
!  * returned in *newRootScpp, otherwise a null is returned there.
!  */
! long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
!                       cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
!                       cm_user_t *userp, cm_req_t *reqp)
! {
!     long code;
!     char *linkp;
!     cm_space_t *tsp;
! 
!     lock_ObtainMutex(&amp;linkScp-&gt;mx);
!     code = cm_HandleLink(linkScp, userp, reqp);
!     if (code) 
!         goto done;
! 
!     /* if we may overflow the buffer, bail out; buffer is signficantly
!      * bigger than max path length, so we don't really have to worry about
!      * being a little conservative here.
!      */
!     if (strlen(linkScp-&gt;mountPointStringp) + strlen(pathSuffixp) + 2
!          &gt;= CM_UTILS_SPACESIZE)
!         return CM_ERROR_TOOBIG;
! 
!     tsp = cm_GetSpace();
!     linkp = linkScp-&gt;mountPointStringp;
!     if (strncmp(linkp, cm_mountRoot, cm_mountRootLen) == 0) {
!         if (strlen(linkp) &gt; cm_mountRootLen)
!             strcpy(tsp-&gt;data, linkp+cm_mountRootLen+1);
!         else
!             tsp-&gt;data[0] = 0;
!         *newRootScpp = cm_rootSCachep;
!         cm_HoldSCache(cm_rootSCachep);
!     } else if (*linkp == '\\' || *linkp == '/') {
!         /* formerly, this was considered to be from the AFS root,
!          * but this seems to create problems.  instead, we will just
!          * reject the link */
! #if 0   
!         strcpy(tsp-&gt;data, linkp+1);
!         *newRootScpp = cm_rootSCachep;
!         cm_HoldSCache(cm_rootSCachep);
! #else
!         code = CM_ERROR_NOSUCHPATH;
!         goto done;
! #endif  
!     }
!     else {
!         /* a relative link */
!         strcpy(tsp-&gt;data, linkp);
!         *newRootScpp = NULL;
!     }
!     if (pathSuffixp[0] != 0) {	/* if suffix string is non-null */
!         strcat(tsp-&gt;data, "\\");
!         strcat(tsp-&gt;data, pathSuffixp);
!     }
!     *newSpaceBufferp = tsp;
!     code = 0;
! 
!   done:
!     lock_ReleaseMutex(&amp;linkScp-&gt;mx);
!     return code;
  }
  
  long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
!                cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp)
  {
!     long code;
!     char *tp;			/* ptr moving through input buffer */
!     char tc;			/* temp char */
!     int haveComponent;		/* has new component started? */
!     char component[256];		/* this is the new component */
!     char *cp;			/* component name being assembled */
!     cm_scache_t *tscp;		/* current location in the hierarchy */
!     cm_scache_t *nscp;		/* next dude down */
!     cm_scache_t *dirScp;		/* last dir we searched */
!     cm_scache_t *linkScp;		/* new root for the symlink we just
!     * looked up */
!     cm_space_t *psp;		/* space for current path, if we've hit
!     * any symlinks */
!     cm_space_t *tempsp;		/* temp vbl */
!     char *restp;			/* rest of the pathname to interpret */
!     int symlinkCount;		/* count of # of symlinks traversed */
!     int extraFlag;			/* avoid chasing mt pts for dir cmd */
!     int phase = 1;			/* 1 = tidPathp, 2 = pathp */
! 
!     tp = tidPathp;
!     if (tp == NULL) {
!         tp = pathp;
!         phase = 2;
!     }
!     if (tp == NULL) {
!         tp = "";
!     }
!     haveComponent = 0;
!     psp = NULL;
!     tscp = rootSCachep;
!     cm_HoldSCache(tscp);
!     symlinkCount = 0;
!     while (1) {
!         tc = *tp++;
! 
!         /* map Unix slashes into DOS ones so we can interpret Unix
!          * symlinks properly
!          */
!         if (tc == '/') 
!             tc = '\\';
  
!         if (!haveComponent) {
!             if (tc == '\\') 
!                 continue;
              else if (tc == 0) {
!                 if (phase == 1) {
!                     phase = 2;
!                     tp = pathp;
!                     continue;
!                 }
                  code = 0;
                  break;
              }
              else {
!                 haveComponent = 1;
                  cp = component;
                  *cp++ = tc;
              }
!         }
!         else {
!             /* we have a component here */
!             if (tc == 0 || tc == '\\') {
!                 /* end of the component; we're at the last
!                  * component if tc == 0.  However, if the last
!                  * is a symlink, we have more to do.
!                  */
!                 *cp++ = 0;	/* add null termination */
!                 extraFlag = 0;
!                 if ((flags &amp; CM_FLAG_DIRSEARCH) &amp;&amp; tc == 0)
!                     extraFlag = CM_FLAG_NOMOUNTCHASE;
!                 code = cm_Lookup(tscp, component,
!                                   flags | extraFlag,
!                                   userp, reqp, &amp;nscp);
  
!                 if (code) {
!                     cm_ReleaseSCache(tscp);
!                     if (psp) 
!                         cm_FreeSpace(psp);
!                     return code;
!                 }
!                 haveComponent = 0;	/* component done */
!                 dirScp = tscp;		/* for some symlinks */
!                 tscp = nscp;	/* already held */
!                 if (tc == 0 &amp;&amp; !(flags &amp; CM_FLAG_FOLLOW) &amp;&amp; phase == 2) {
!                     code = 0;
!                     cm_ReleaseSCache(dirScp);
!                     break;
!                 }
! 
!                 /* now, if tscp is a symlink, we should follow
!                  * it and assemble the path again.
!                  */
!                 lock_ObtainMutex(&amp;tscp-&gt;mx);
!                 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
!                                   CM_SCACHESYNC_GETSTATUS
!                                   | CM_SCACHESYNC_NEEDCALLBACK);
!                 if (code) {
!                     lock_ReleaseMutex(&amp;tscp-&gt;mx);
!                     cm_ReleaseSCache(tscp);
!                     cm_ReleaseSCache(dirScp);
!                     break;
!                 }
!                 if (tscp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!                     /* this is a symlink; assemble a new buffer */
!                     lock_ReleaseMutex(&amp;tscp-&gt;mx);
!                     if (symlinkCount++ &gt;= 16) {
                          cm_ReleaseSCache(tscp);
                          cm_ReleaseSCache(dirScp);
!                         if (psp) 
!                             cm_FreeSpace(psp);
!                         return CM_ERROR_TOOBIG;
                      }
!                     if (tc == 0) 
!                         restp = "";
!                     else 
!                         restp = tp;
!                     code = cm_AssembleLink(tscp, restp, &amp;linkScp, &amp;tempsp, userp, reqp);
                      if (code) {
!                         /* something went wrong */
                          cm_ReleaseSCache(tscp);
                          cm_ReleaseSCache(dirScp);
                          break;
                      }
  
!                     /* otherwise, tempsp has the new path,
!                      * and linkScp is the new root from
!                      * which to interpret that path.
!                      * Continue with the namei processing,
!                      * also doing the bookkeeping for the
!                      * space allocation and tracking the
!                      * vnode reference counts.
!                      */
!                     if (psp) 
!                         cm_FreeSpace(psp);
!                     psp = tempsp;
!                     tp = psp-&gt;data;
!                     cm_ReleaseSCache(tscp);
                      tscp = linkScp;	
                      /* already held
!                      * by AssembleLink
!                      * now, if linkScp is null, that's
!                      * AssembleLink's way of telling us that
!                      * the sym link is relative to the dir
!                      * containing the link.  We have a ref
!                      * to it in dirScp, and we hold it now
!                      * and reuse it as the new spot in the
!                      * dir hierarchy.
!                      */
!                     if (tscp == NULL) {
!                         cm_HoldSCache(dirScp);
!                         tscp = dirScp;
!                     }
!                 }	/* if we have a sym link */
!                 else {
!                     /* not a symlink, we may be done */
!                     lock_ReleaseMutex(&amp;tscp-&gt;mx);
!                     if (tc == 0) {
!                         if (phase == 1) {
!                             phase = 2;
!                             tp = pathp;
!                             continue;
                          }
+                         cm_ReleaseSCache(dirScp);
+                         code = 0;
+                         break;
                      }
!                 }
!                 cm_ReleaseSCache(dirScp);
!             } /* end of a component */
!             else *cp++ = tc;
!         } /* we have a component */
!     } /* big while loop over all components */
! 
!     /* already held */
!     if (psp) 
!         cm_FreeSpace(psp);
!     if (code == 0) 
!         *outScpp = tscp;
!     return code;
  }
  
  /* called with a dir, and a vnode within the dir that happens to be a symlink.
***************
*** 1438,1472 ****
   * The input vnode should not be locked when this function is called.
   */
  long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
! 	cm_scache_t **outScpp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code;
!         cm_space_t *spacep;
!         cm_scache_t *newRootScp;
  
! 	osi_Log1(afsd_logp, "Evaluating symlink vp %x", linkScp);
! 
!         code = cm_AssembleLink(linkScp, "", &amp;newRootScp, &amp;spacep, userp, reqp);
!         if (code) return code;
!         
!         /* now, if newRootScp is NULL, we're really being told that the symlink
! 	 * is relative to the current directory (dscp).
!          */
! 	if (newRootScp == NULL) {
! 		newRootScp = dscp;
! 		cm_HoldSCache(dscp);
!         }
!         
!         code = cm_NameI(newRootScp, spacep-&gt;data,
! 		CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
! 		userp, NULL, reqp, outScpp);
! 
! 	/* this stuff is allocated no matter what happened on the namei call,
! 	 * so free it */
! 	cm_FreeSpace(spacep);
!         cm_ReleaseSCache(newRootScp);
  
          return code;
  }
  
  /* make this big enough so that one buffer of dir pages won't overflow.  We'll
--- 1497,1532 ----
   * The input vnode should not be locked when this function is called.
   */
  long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
!                          cm_scache_t **outScpp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
!     cm_space_t *spacep;
!     cm_scache_t *newRootScp;
  
!     osi_Log1(afsd_logp, "Evaluating symlink vp %x", linkScp);
  
+     code = cm_AssembleLink(linkScp, "", &amp;newRootScp, &amp;spacep, userp, reqp);
+     if (code) 
          return code;
+ 
+     /* now, if newRootScp is NULL, we're really being told that the symlink
+      * is relative to the current directory (dscp).
+      */
+     if (newRootScp == NULL) {
+         newRootScp = dscp;
+         cm_HoldSCache(dscp);
+     }
+ 
+     code = cm_NameI(newRootScp, spacep-&gt;data,
+                      CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
+                      userp, NULL, reqp, outScpp);
+ 
+     /* this stuff is allocated no matter what happened on the namei call,
+      * so free it */
+     cm_FreeSpace(spacep);
+     cm_ReleaseSCache(newRootScp);
+ 
+     return code;
  }
  
  /* make this big enough so that one buffer of dir pages won't overflow.  We'll
***************
*** 1477,1489 ****
  
  /* rock for bulk stat calls */
  typedef struct cm_bulkStat {
! 	osi_hyper_t bufOffset;	/* only do it for things in this buffer page */
  
! 	/* info for the actual call */
!         int counter;			/* next free slot */
!         AFSFid fids[CM_BULKMAX];
!         AFSFetchStatus stats[CM_BULKMAX];
! 	AFSCallBack callbacks[CM_BULKMAX];
  } cm_bulkStat_t;
  
  /* for a given entry, make sure that it isn't in the stat cache, and then
--- 1537,1549 ----
  
  /* rock for bulk stat calls */
  typedef struct cm_bulkStat {
!     osi_hyper_t bufOffset;	/* only do it for things in this buffer page */
  
!     /* info for the actual call */
!     int counter;			/* next free slot */
!     AFSFid fids[CM_BULKMAX];
!     AFSFetchStatus stats[CM_BULKMAX];
!     AFSCallBack callbacks[CM_BULKMAX];
  } cm_bulkStat_t;
  
  /* for a given entry, make sure that it isn't in the stat cache, and then
***************
*** 1494,2626 ****
   * processing, to avoid deadlocks.
   */
  long cm_TryBulkProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
! 	osi_hyper_t *offp)
  {
! 	osi_hyper_t thyper;
!         cm_bulkStat_t *bsp;
!         int i;
!         cm_scache_t *tscp;
!         cm_fid_t tfid;
  
! 	bsp = rockp;
  
! 	/* Don't overflow bsp. */
! 	if (bsp-&gt;counter &gt;= CM_BULKMAX)
! 		return CM_ERROR_STOPNOW;
  
!         thyper.LowPart = buf_bufferSize;
!         thyper.HighPart = 0;
!         thyper = LargeIntegerAdd(thyper, bsp-&gt;bufOffset);
!         
!         /* thyper is now the first byte past the end of the record we're
! 	 * interested in, and bsp-&gt;bufOffset is the first byte of the record
! 	 * we're interested in.
!          * Skip data in the others.
!          * Skip '.' and '..'
!          */
!         if (LargeIntegerLessThan(*offp, bsp-&gt;bufOffset))
! 		return 0;
!         if (LargeIntegerGreaterThanOrEqualTo(*offp, thyper))
! 		return CM_ERROR_STOPNOW;
!         if (strcmp(dep-&gt;name, ".") == 0 || strcmp(dep-&gt;name, "..") == 0)
! 		return 0;
!         
! 	tfid.cell = scp-&gt;fid.cell;
! 	tfid.volume = scp-&gt;fid.volume;
!         tfid.vnode = ntohl(dep-&gt;fid.vnode);
!         tfid.unique = ntohl(dep-&gt;fid.unique);
!         tscp = cm_FindSCache(&amp;tfid);
!         if (tscp) {
!         	if (lock_TryMutex(&amp;tscp-&gt;mx)) {
! 			/* we have an entry that we can look at */
! 			if (cm_HaveCallback(tscp)) {
! 				/* we have a callback on it.  Don't bother
! 				 * fetching this stat entry, since we're happy
! 				 * with the info we have.
!                                  */
! 				lock_ReleaseMutex(&amp;tscp-&gt;mx);
!                                 cm_ReleaseSCache(tscp);
!                                 return 0;
!                         }
!                         lock_ReleaseMutex(&amp;tscp-&gt;mx);
! 		}	/* got lock */
                  cm_ReleaseSCache(tscp);
!         }	/* found entry */
  
  #ifdef AFS_FREELANCE_CLIENT
! 	// yj: if this is a mountpoint under root.afs then we don't want it
! 	// to be bulkstat-ed, instead, we call getSCache directly and under
! 	// getSCache, it is handled specially.
! 	if 	( cm_freelanceEnabled &amp;&amp;
            tfid.cell==AFS_FAKE_ROOT_CELL_ID &amp;&amp; 
            tfid.volume==AFS_FAKE_ROOT_VOL_ID &amp;&amp;
            !(tfid.vnode==0x1 &amp;&amp; tfid.unique==0x1) )
! 	{
          osi_Log0(afsd_logp, "cm_TryBulkProc Freelance calls cm_SCache on root.afs mountpoint");
! 		return cm_GetSCache(&amp;tfid, &amp;tscp, NULL, NULL);
! 	}
  #endif /* AFS_FREELANCE_CLIENT */
  
! 	i = bsp-&gt;counter++;
!         bsp-&gt;fids[i].Volume = scp-&gt;fid.volume;
!         bsp-&gt;fids[i].Vnode = tfid.vnode;
!         bsp-&gt;fids[i].Unique = tfid.unique;
!         return 0;
! }
  
  /* called with a locked scp and a pointer to a buffer.  Make bulk stat
   * calls on all undeleted files in the page of the directory specified.
   */
  void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
! 	cm_req_t *reqp)
  {
! 	long code;
!         cm_bulkStat_t bb;	/* this is *BIG*, probably 12K or so;
! 				 * watch for stack problems */
!         AFSCBFids fidStruct;
!         AFSBulkStats statStruct;
!         cm_conn_t *connp;
!         AFSCBs callbackStruct;
!         long filex;
! 	AFSVolSync volSync;
!         cm_callbackRequest_t cbReq;
!         long filesThisCall;
! 	long i;
!         long j;
!         cm_scache_t *scp;
!         cm_fid_t tfid;
! 
! 	osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%x", (long) dscp);
! 
! 	/* should be on a buffer boundary */
! 	osi_assert((offsetp-&gt;LowPart &amp; (buf_bufferSize - 1)) == 0);
! 
! 	bb.counter = 0;
!         bb.bufOffset = *offsetp;
! 
! 	/* first, assemble the file IDs we need to stat */
!         code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) &amp;bb, offsetp, userp,
! 			   reqp, NULL);
  
! 	/* if we failed, bail out early */
!         if (code &amp;&amp; code != CM_ERROR_STOPNOW) return;
!         
!         /* otherwise, we may have one or more bulk stat's worth of stuff in bb;
! 	 * make the calls to create the entries.  Handle AFSCBMAX files at a
! 	 * time.
           */
! 	filex = 0;
! 	while(filex &lt; bb.counter) {
! 		filesThisCall = bb.counter - filex;
!                 if (filesThisCall &gt; AFSCBMAX) filesThisCall = AFSCBMAX;
! 
! 		fidStruct.AFSCBFids_len = filesThisCall;
!                 fidStruct.AFSCBFids_val = &amp;bb.fids[filex];
!                 statStruct.AFSBulkStats_len = filesThisCall;
!                 statStruct.AFSBulkStats_val = &amp;bb.stats[filex];
!                 callbackStruct.AFSCBs_len = filesThisCall;
!                 callbackStruct.AFSCBs_val = &amp;bb.callbacks[filex];
!                 cm_StartCallbackGrantingCall(NULL, &amp;cbReq);
! 		osi_Log1(afsd_logp, "CALL BulkStatus, %d entries", filesThisCall);
! 		do {
! 			code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
! 	                if (code) continue;
! 		
! 	                code = RXAFS_BulkStatus(connp-&gt;callp, &amp;fidStruct,
!                         	&amp;statStruct, &amp;callbackStruct, &amp;volSync);
  
! 		} while (cm_Analyze(connp, userp, reqp, &amp;dscp-&gt;fid,
! 				    &amp;volSync, NULL, &amp;cbReq, code));
!                 code = cm_MapRPCError(code, reqp);
  
!                 osi_Log0(afsd_logp, "CALL BulkStatus DONE");
!                 
! 		/* may as well quit on an error, since we're not going to do
!                  * much better on the next immediate call, either.
!                  */
!                 if (code) break;
!                 
!                 /* otherwise, we should do the merges */
!                 for(i = 0; i&lt;filesThisCall; i++) {
! 			j = filex + i;
! 			tfid.cell = dscp-&gt;fid.cell;
!                         tfid.volume = bb.fids[j].Volume;
!                         tfid.vnode = bb.fids[j].Vnode;
!                         tfid.unique = bb.fids[j].Unique;
! 			code = cm_GetSCache(&amp;tfid, &amp;scp, userp, reqp);
!                         if (code != 0) continue;
!                         
!                         /* otherwise, if this entry has no callback info, 
!                          * merge in this.
!                          */
!                         lock_ObtainMutex(&amp;scp-&gt;mx);
! 			/* now, we have to be extra paranoid on merging in this
! 			 * information, since we didn't use cm_SyncOp before
! 			 * starting the fetch to make sure that no bad races
! 			 * were occurring.  Specifically, we need to make sure
! 			 * we don't obliterate any newer information in the
! 			 * vnode than have here.
!                          *
!                          * Right now, be pretty conservative: if there's a
! 			 * callback or a pending call, skip it.
!                          */
! 			if (scp-&gt;cbServerp == NULL
!                         	&amp;&amp; !(scp-&gt;flags &amp;
!                                 	(CM_SCACHEFLAG_FETCHING
! 					 | CM_SCACHEFLAG_STORING
!                                          | CM_SCACHEFLAG_SIZESTORING))) {
! 				cm_EndCallbackGrantingCall(scp, &amp;cbReq,
! 					&amp;bb.callbacks[j],
!                                 	CM_CALLBACK_MAINTAINCOUNT);
! 	                        cm_MergeStatus(scp, &amp;bb.stats[j], &amp;volSync,
! 					userp, 0);
! 			}
!                         lock_ReleaseMutex(&amp;scp-&gt;mx);
!                         cm_ReleaseSCache(scp);
!                 } /* all files in the response */
! 		/* now tell it to drop the count,
! 		 * after doing the vnode processing above */
          cm_EndCallbackGrantingCall(NULL, &amp;cbReq, NULL, 0);
!                 
!                 filex += filesThisCall;
!         }	/* while there are still more files to process */
!         osi_Log0(afsd_logp, "END cm_TryBulkStat");
! }
  
  void cm_StatusFromAttr(AFSStoreStatus *statusp, cm_scache_t *scp, cm_attr_t *attrp)
  {
! 	long mask;
  
! 	/* initialize store back mask as inexpensive local variable */
!         mask = 0;
! 	memset(statusp, 0, sizeof(AFSStoreStatus));
! 
! 	/* copy out queued info from scache first, if scp passed in */
!         if (scp) {
!         	if (scp-&gt;mask &amp; CM_SCACHEMASK_CLIENTMODTIME) {
! 			statusp-&gt;ClientModTime = scp-&gt;clientModTime;
! 	                mask |= AFS_SETMODTIME;
! 	                scp-&gt;mask &amp;= ~CM_SCACHEMASK_CLIENTMODTIME;
! 	        }
! 	}
! 
! 	if (attrp) {
! 		/* now add in our locally generated request */
! 	        if (attrp-&gt;mask &amp; CM_ATTRMASK_CLIENTMODTIME) {
! 	        	statusp-&gt;ClientModTime = attrp-&gt;clientModTime;
! 	                mask |= AFS_SETMODTIME;
! 		}
! 	        if (attrp-&gt;mask &amp; CM_ATTRMASK_UNIXMODEBITS) {
! 	        	statusp-&gt;UnixModeBits = attrp-&gt;unixModeBits;
! 	                mask |= AFS_SETMODE;
! 		}
! 	        if (attrp-&gt;mask &amp; CM_ATTRMASK_OWNER) {
! 	        	statusp-&gt;Owner = attrp-&gt;owner;
! 	                mask |= AFS_SETOWNER;
! 		}
! 	        if (attrp-&gt;mask &amp; CM_ATTRMASK_GROUP) {
! 	        	statusp-&gt;Group = attrp-&gt;group;
! 	                mask |= AFS_SETGROUP;
! 		}
! 	}
! 	statusp-&gt;Mask = mask;
! }
  
  /* set the file size, and make sure that all relevant buffers have been
   * truncated.  Ensure that any partially truncated buffers have been zeroed
   * to the end of the buffer.
   */
  long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
! 	cm_req_t *reqp)
  {
! 	long code;
! 	int shrinking;
  
! 	/* start by locking out buffer creation */
! 	lock_ObtainWrite(&amp;scp-&gt;bufCreateLock);
  
! 	/* verify that this is a file, not a dir or a symlink */
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	code = cm_SyncOp(scp, NULL, userp, reqp, 0,
!         	CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!         if (code) goto done;
!         
!         if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
! 		code = CM_ERROR_ISDIR;
!                 goto done;
!         }
  
! startover:
!         if (LargeIntegerLessThan(*sizep, scp-&gt;length))
! 		shrinking = 1;
! 	else
! 		shrinking = 0;
  
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
  
! 	/* can't hold scp-&gt;mx lock here, since we may wait for a storeback to
! 	 * finish if the buffer package is cleaning a buffer by storing it to
! 	 * the server.
!          */
! 	if (shrinking)
! 		buf_Truncate(scp, userp, reqp, sizep);
!         
!         /* now ensure that file length is short enough, and update truncPos */
!         lock_ObtainMutex(&amp;scp-&gt;mx);
! 	
! 	/* make sure we have a callback (so we have the right value for the
! 	 * length), and wait for it to be safe to do a truncate.
!          */
! 	code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_WRITE,
! 		CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
! 		| CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
! 	if (code) goto done;
! 
! 	if (LargeIntegerLessThan(*sizep, scp-&gt;length)) {
! 		/* a real truncation.  If truncPos is not set yet, or is bigger
! 		 * than where we're truncating the file, set truncPos to this
! 		 * new value.
! 		 */
! 		if (!shrinking)
! 			goto startover;
! 		if (!(scp-&gt;mask &amp; CM_SCACHEMASK_TRUNCPOS)
!                 	|| LargeIntegerLessThan(*sizep, scp-&gt;length)) {
! 			/* set trunc pos */
!                         scp-&gt;truncPos = *sizep;
!                         scp-&gt;mask |= CM_SCACHEMASK_TRUNCPOS;
! 		}
!                 /* in either case, the new file size has been changed */
!                 scp-&gt;length = *sizep;
!                 scp-&gt;mask |= CM_SCACHEMASK_LENGTH;
!         }
!         else if (LargeIntegerGreaterThan(*sizep, scp-&gt;length)) {
! 		/* really extending the file */
!                 scp-&gt;length = *sizep;
!                 scp-&gt;mask |= CM_SCACHEMASK_LENGTH;
! 	}
  
! 	/* done successfully */
!         code = 0;
  
! done:
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	lock_ReleaseWrite(&amp;scp-&gt;bufCreateLock);
  
!         return code;
  }
  
  /* set the file size or other attributes (but not both at once) */
  long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
! 	cm_req_t *reqp)
  {
! 	long code;
! 	int flags;
!         AFSFetchStatus afsOutStatus;
!         AFSVolSync volSync;
!         cm_conn_t *connp;
!         AFSFid tfid;
!         AFSStoreStatus afsInStatus;
! 
! 	/* handle file length setting */
! 	if (attrp-&gt;mask &amp; CM_ATTRMASK_LENGTH)
!         	return cm_SetLength(scp, &amp;attrp-&gt;length, userp, reqp);
  
! 	flags = CM_SCACHESYNC_STORESTATUS;
  
!         lock_ObtainMutex(&amp;scp-&gt;mx);
! 	/* otherwise, we have to make an RPC to get the status */
! 	code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
  
! 	/* make the attr structure */
!         cm_StatusFromAttr(&amp;afsInStatus, scp, attrp);
  
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
!         if (code) return code;
! 		
! 	/* now make the RPC */
! 	osi_Log1(afsd_logp, "CALL StoreStatus vp %x", (long) scp);
! 	tfid.Volume = scp-&gt;fid.volume;
!         tfid.Vnode = scp-&gt;fid.vnode;
!         tfid.Unique = scp-&gt;fid.unique;
!         do {
! 		code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
!                 if (code) continue;
! 		
!                 code = RXAFS_StoreStatus(connp-&gt;callp, &amp;tfid,
! 			&amp;afsInStatus, &amp;afsOutStatus, &amp;volSync);
  
! 	} while (cm_Analyze(connp, userp, reqp,
! 			    &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
!         code = cm_MapRPCError(code, reqp);
  
! 	osi_Log1(afsd_logp, "CALL StoreStatus DONE, code %d", code);
  
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
! 	if (code == 0)
! 		cm_MergeStatus(scp, &amp;afsOutStatus, &amp;volSync, userp,
! 				CM_MERGEFLAG_FORCE);
! 	
!         /* if we're changing the mode bits, discard the ACL cache, 
!          * since we changed the mode bits.
!          */
!         if (afsInStatus.Mask &amp; AFS_SETMODE) cm_FreeAllACLEnts(scp);
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
          return code;
! }
  
! long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
! 	cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp)
! {
! 	cm_conn_t *connp;
!         long code;
!         AFSFid dirAFSFid;
!         cm_callbackRequest_t cbReq;
!         AFSFid newAFSFid;
!         cm_fid_t newFid;
!         cm_scache_t *scp;
!         int didEnd;
! 	AFSStoreStatus inStatus;
!         AFSFetchStatus updatedDirStatus;
!         AFSFetchStatus newFileStatus;
!         AFSCallBack newFileCallback;
!         AFSVolSync volSync;
  
! 	/* can't create names with @sys in them; must expand it manually first.
!          * return "invalid request" if they try.
!          */
! 	if (cm_ExpandSysName(namep, NULL, 0)) {
! 		return CM_ERROR_ATSYS;
!         }
  
! 	/* before starting the RPC, mark that we're changing the file data, so
! 	 * that someone who does a chmod will know to wait until our call
! 	 * completes.
!          */
! 	lock_ObtainMutex(&amp;dscp-&gt;mx);
! 	code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
          if (code == 0) {
! 		cm_StartCallbackGrantingCall(NULL, &amp;cbReq);
          }
! 	lock_ReleaseMutex(&amp;dscp-&gt;mx);
!         if (code) {
!         	return code;
! 	}
!         didEnd = 0;
! 
! 	cm_StatusFromAttr(&amp;inStatus, NULL, attrp);
! 
! 	/* try the RPC now */
!         do {
! 		code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!                 if (code) continue;
!                 
! 		dirAFSFid.Volume = dscp-&gt;fid.volume;
!                 dirAFSFid.Vnode = dscp-&gt;fid.vnode;
!                 dirAFSFid.Unique = dscp-&gt;fid.unique;
!                 code = RXAFS_CreateFile(connp-&gt;callp, &amp;dirAFSFid, namep,
! 					&amp;inStatus, &amp;newAFSFid, &amp;newFileStatus,
! 					&amp;updatedDirStatus, &amp;newFileCallback,
! 					&amp;volSync);
! 	} while (cm_Analyze(connp, userp, reqp,
! 			    &amp;dscp-&gt;fid, &amp;volSync, NULL, &amp;cbReq, code));
!         code = cm_MapRPCError(code, reqp);
!         
!         lock_ObtainMutex(&amp;dscp-&gt;mx);
!         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
! 	if (code == 0) {
! 	        cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
! 	}
!         lock_ReleaseMutex(&amp;dscp-&gt;mx);
  
! 	/* now try to create the file's entry, too, but be careful to 
! 	 * make sure that we don't merge in old info.  Since we weren't locking
! 	 * out any requests during the file's creation, we may have pretty old
! 	 * info.
! 	 */
! 	if (code == 0) {
! 		newFid.cell = dscp-&gt;fid.cell;
!                 newFid.volume = dscp-&gt;fid.volume;
!                 newFid.vnode = newAFSFid.Vnode;
!                 newFid.unique = newAFSFid.Unique;
! 		code = cm_GetSCache(&amp;newFid, &amp;scp, userp, reqp);
!                 if (code == 0) {
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 			if (!cm_HaveCallback(scp)) {
! 				cm_MergeStatus(scp, &amp;newFileStatus, &amp;volSync,
! 						userp, 0);
! 				cm_EndCallbackGrantingCall(scp, &amp;cbReq,
! 							&amp;newFileCallback, 0);
!                                 didEnd = 1;
!                         }
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			*scpp = scp;
!                 }
!         }
! 	
!         /* make sure we end things properly */
!         if (!didEnd)
!         	cm_EndCallbackGrantingCall(NULL, &amp;cbReq, NULL, 0);
  
!         return code;
! }
  
  long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code;
  
! 	lock_ObtainWrite(&amp;scp-&gt;bufCreateLock);
! 	code = buf_CleanVnode(scp, userp, reqp);
! 	lock_ReleaseWrite(&amp;scp-&gt;bufCreateLock);
! 	if (code == 0) {
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
! 		scp-&gt;flags &amp;= ~(CM_SCACHEFLAG_OVERQUOTA
! 				 | CM_SCACHEFLAG_OUTOFSPACE);
! 		if (scp-&gt;mask &amp; (CM_SCACHEMASK_TRUNCPOS
! 				   | CM_SCACHEMASK_CLIENTMODTIME
! 				   | CM_SCACHEMASK_LENGTH))
! 			code = cm_StoreMini(scp, userp, reqp);
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	}
!         return code;
  }
  
  long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
! 	cm_user_t *userp, cm_req_t *reqp)
  {
! 	cm_conn_t *connp;
!         long code;
!         AFSFid dirAFSFid;
!         cm_callbackRequest_t cbReq;
!         AFSFid newAFSFid;
!         cm_fid_t newFid;
!         cm_scache_t *scp;
!         int didEnd;
! 	AFSStoreStatus inStatus;
!         AFSFetchStatus updatedDirStatus;
!         AFSFetchStatus newDirStatus;
!         AFSCallBack newDirCallback;
!         AFSVolSync volSync;
  
! 	/* can't create names with @sys in them; must expand it manually first.
!          * return "invalid request" if they try.
!          */
! 	if (cm_ExpandSysName(namep, NULL, 0)) {
! 		return CM_ERROR_ATSYS;
!         }
  
! 	/* before starting the RPC, mark that we're changing the directory
! 	 * data, so that someone who does a chmod on the dir will wait until
! 	 * our call completes.
!          */
! 	lock_ObtainMutex(&amp;dscp-&gt;mx);
! 	code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
          if (code == 0) {
! 		cm_StartCallbackGrantingCall(NULL, &amp;cbReq);
          }
! 	lock_ReleaseMutex(&amp;dscp-&gt;mx);
!         if (code) {
!         	return code;
! 	}
!         didEnd = 0;
  
! 	cm_StatusFromAttr(&amp;inStatus, NULL, attrp);
  
! 	/* try the RPC now */
!         do {
! 		code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!                 if (code) continue;
!                 
! 		dirAFSFid.Volume = dscp-&gt;fid.volume;
!                 dirAFSFid.Vnode = dscp-&gt;fid.vnode;
!                 dirAFSFid.Unique = dscp-&gt;fid.unique;
!                 code = RXAFS_MakeDir(connp-&gt;callp, &amp;dirAFSFid, namep,
! 				     &amp;inStatus, &amp;newAFSFid, &amp;newDirStatus,
! 				     &amp;updatedDirStatus, &amp;newDirCallback,
! 				     &amp;volSync);
! 	} while (cm_Analyze(connp, userp, reqp,
! 			    &amp;dscp-&gt;fid, &amp;volSync, NULL, &amp;cbReq, code));
!         code = cm_MapRPCError(code, reqp);
!         
!         lock_ObtainMutex(&amp;dscp-&gt;mx);
!         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
! 	if (code == 0) {
! 	        cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
! 	}
!         lock_ReleaseMutex(&amp;dscp-&gt;mx);
  
! 	/* now try to create the new dir's entry, too, but be careful to 
! 	 * make sure that we don't merge in old info.  Since we weren't locking
! 	 * out any requests during the file's creation, we may have pretty old
! 	 * info.
! 	 */
! 	if (code == 0) {
! 		newFid.cell = dscp-&gt;fid.cell;
!                 newFid.volume = dscp-&gt;fid.volume;
!                 newFid.vnode = newAFSFid.Vnode;
!                 newFid.unique = newAFSFid.Unique;
! 		code = cm_GetSCache(&amp;newFid, &amp;scp, userp, reqp);
!                 if (code == 0) {
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 			if (!cm_HaveCallback(scp)) {
! 				cm_MergeStatus(scp, &amp;newDirStatus, &amp;volSync,
! 						userp, 0);
! 				cm_EndCallbackGrantingCall(scp, &amp;cbReq,
! 							&amp;newDirCallback, 0);
!                                 didEnd = 1;
!                         }
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			cm_ReleaseSCache(scp);
!                 }
!         }
! 	
!         /* make sure we end things properly */
!         if (!didEnd)
!         	cm_EndCallbackGrantingCall(NULL, &amp;cbReq, NULL, 0);
! 	
!         /* and return error code */
          return code;
  }
  
  long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
! 	cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	cm_conn_t *connp;
!         long code;
!         AFSFid dirAFSFid;
!         AFSFid newAFSFid;
!         cm_fid_t newFid;
!         cm_scache_t *scp;
! 	AFSStoreStatus inStatus;
!         AFSFetchStatus updatedDirStatus;
!         AFSFetchStatus newLinkStatus;
!         AFSVolSync volSync;
! 
! 	/* before starting the RPC, mark that we're changing the directory data,
! 	 * so that someone who does a chmod on the dir will wait until our
! 	 * call completes.
!          */
! 	lock_ObtainMutex(&amp;dscp-&gt;mx);
! 	code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
! 	lock_ReleaseMutex(&amp;dscp-&gt;mx);
!         if (code) {
!         	return code;
! 	}
  
! 	cm_StatusFromAttr(&amp;inStatus, NULL, attrp);
  
! 	/* try the RPC now */
!         do {
! 		code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!                 if (code) continue;
!                 
! 		dirAFSFid.Volume = dscp-&gt;fid.volume;
!                 dirAFSFid.Vnode = dscp-&gt;fid.vnode;
!                 dirAFSFid.Unique = dscp-&gt;fid.unique;
!                 code = RXAFS_Symlink(connp-&gt;callp, &amp;dirAFSFid, namep, contentsp,
! 				     &amp;inStatus, &amp;newAFSFid, &amp;newLinkStatus,
! 				     &amp;updatedDirStatus, &amp;volSync);
! 	} while (cm_Analyze(connp, userp, reqp,
! 			    &amp;dscp-&gt;fid, &amp;volSync, NULL, NULL, code));
!         code = cm_MapRPCError(code, reqp);
!         
!         lock_ObtainMutex(&amp;dscp-&gt;mx);
!         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
! 	if (code == 0) {
! 	        cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
! 	}
!         lock_ReleaseMutex(&amp;dscp-&gt;mx);
  
! 	/* now try to create the new dir's entry, too, but be careful to 
! 	 * make sure that we don't merge in old info.  Since we weren't locking
! 	 * out any requests during the file's creation, we may have pretty old
! 	 * info.
! 	 */
! 	if (code == 0) {
! 		newFid.cell = dscp-&gt;fid.cell;
!                 newFid.volume = dscp-&gt;fid.volume;
!                 newFid.vnode = newAFSFid.Vnode;
!                 newFid.unique = newAFSFid.Unique;
! 		code = cm_GetSCache(&amp;newFid, &amp;scp, userp, reqp);
!                 if (code == 0) {
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 			if (!cm_HaveCallback(scp)) {
! 				cm_MergeStatus(scp, &amp;newLinkStatus, &amp;volSync,
! 						userp, 0);
!                         }
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			cm_ReleaseSCache(scp);
!                 }
          }
  	
!         /* and return error code */
!         return code;
  }
  
  long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
! 	cm_req_t *reqp)
  {
! 	cm_conn_t *connp;
!         long code;
!         AFSFid dirAFSFid;
!         int didEnd;
!         AFSFetchStatus updatedDirStatus;
!         AFSVolSync volSync;
! 
! 	/* before starting the RPC, mark that we're changing the directory data,
! 	 * so that someone who does a chmod on the dir will wait until our
! 	 * call completes.
!          */
! 	lock_ObtainMutex(&amp;dscp-&gt;mx);
! 	code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
! 	lock_ReleaseMutex(&amp;dscp-&gt;mx);
!         if (code) {
!         	return code;
! 	}
!         didEnd = 0;
  
! 	/* try the RPC now */
!         do {
! 		code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!                 if (code) continue;
!                 
! 		dirAFSFid.Volume = dscp-&gt;fid.volume;
!                 dirAFSFid.Vnode = dscp-&gt;fid.vnode;
!                 dirAFSFid.Unique = dscp-&gt;fid.unique;
!                 code = RXAFS_RemoveDir(connp-&gt;callp, &amp;dirAFSFid, namep,
! 					&amp;updatedDirStatus, &amp;volSync);
! 	} while (cm_Analyze(connp, userp, reqp,
! 			    &amp;dscp-&gt;fid, &amp;volSync, NULL, NULL, code));
!         code = cm_MapRPCErrorRmdir(code, reqp);
!         
!         lock_ObtainMutex(&amp;dscp-&gt;mx);
! 	cm_dnlcRemove(dscp, namep); 
!         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
! 	if (code == 0) {
! 	        cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
! 	}
!         lock_ReleaseMutex(&amp;dscp-&gt;mx);
  
!         /* and return error code */
!         return code;
  }
  
  long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
  {
! 	/* grab mutex on contents */
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
  
! 	/* reset the prefetch info */
! 	scp-&gt;prefetch.base.LowPart = 0;		/* base */
! 	scp-&gt;prefetch.base.HighPart = 0;
! 	scp-&gt;prefetch.end.LowPart = 0;		/* and end */
! 	scp-&gt;prefetch.end.HighPart = 0;
!         
!         /* release mutex on contents */
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	
!         /* we're done */
!         return 0;
! }
  
  long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
! 	char *newNamep, cm_user_t *userp, cm_req_t *reqp)
  {
! 	cm_conn_t *connp;
!         long code;
!         AFSFid oldDirAFSFid;
!         AFSFid newDirAFSFid;
!         int didEnd;
!         AFSFetchStatus updatedOldDirStatus;
!         AFSFetchStatus updatedNewDirStatus;
!         AFSVolSync volSync;
!         int oneDir;
! 
! 	/* before starting the RPC, mark that we're changing the directory data,
! 	 * so that someone who does a chmod on the dir will wait until our call
! 	 * completes.  We do this in vnode order so that we don't deadlock,
! 	 * which makes the code a little verbose.
!          */
! 	if (oldDscp == newDscp) {
!                 /* check for identical names */
!                 if (strcmp(oldNamep, newNamep) == 0)
!                         return CM_ERROR_RENAME_IDENTICAL;
! 
! 		oneDir = 1;
! 		lock_ObtainMutex(&amp;oldDscp-&gt;mx);
! 		cm_dnlcRemove(oldDscp, oldNamep);
! 		cm_dnlcRemove(oldDscp, newNamep);
! 		code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
! 				 CM_SCACHESYNC_STOREDATA);
! 		lock_ReleaseMutex(&amp;oldDscp-&gt;mx);
          }
          else {
!         	/* two distinct dir vnodes */
!                 oneDir = 0;
! 		if (oldDscp-&gt;fid.cell != newDscp-&gt;fid.cell ||
!                 	oldDscp-&gt;fid.volume != newDscp-&gt;fid.volume)
!                         	return CM_ERROR_CROSSDEVLINK;
! 
! 		/* shouldn't happen that we have distinct vnodes for two
! 		 * different files, but could due to deliberate attack, or
! 		 * stale info.  Avoid deadlocks and quit now.
!                  */
! 		if (oldDscp-&gt;fid.vnode == newDscp-&gt;fid.vnode)
!                 	return CM_ERROR_CROSSDEVLINK;
!                         
! 		if (oldDscp-&gt;fid.vnode &lt; newDscp-&gt;fid.vnode) {
! 			lock_ObtainMutex(&amp;oldDscp-&gt;mx);
! 			cm_dnlcRemove(oldDscp, oldNamep);
! 			code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
! 					 CM_SCACHESYNC_STOREDATA);
! 			lock_ReleaseMutex(&amp;oldDscp-&gt;mx);
!                         if (code == 0) {
! 				lock_ObtainMutex(&amp;newDscp-&gt;mx);
! 				cm_dnlcRemove(newDscp, newNamep);
! 				code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
! 						 CM_SCACHESYNC_STOREDATA);
! 				lock_ReleaseMutex(&amp;newDscp-&gt;mx);
!                                 if (code) {
! 					/* cleanup first one */
!                                         cm_SyncOpDone(oldDscp, NULL,
! 						      CM_SCACHESYNC_STOREDATA);
!                                 }
!                         }
! 		}
!                 else {
! 			/* lock the new vnode entry first */
! 			lock_ObtainMutex(&amp;newDscp-&gt;mx);
! 			cm_dnlcRemove(newDscp, newNamep);
! 			code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
! 					 CM_SCACHESYNC_STOREDATA);
! 			lock_ReleaseMutex(&amp;newDscp-&gt;mx);
!                         if (code == 0) {
! 				lock_ObtainMutex(&amp;oldDscp-&gt;mx);
! 				cm_dnlcRemove(oldDscp, oldNamep);
! 				code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
! 						 CM_SCACHESYNC_STOREDATA);
! 				lock_ReleaseMutex(&amp;oldDscp-&gt;mx);
!                                 if (code) {
! 					/* cleanup first one */
!                                         cm_SyncOpDone(newDscp, NULL,
! 						      CM_SCACHESYNC_STOREDATA);
!                                 }
!                         }
!                 }
!         }	/* two distinct vnodes */
  
!         if (code) {
!         	return code;
! 	}
!         didEnd = 0;
  
! 	/* try the RPC now */
!         do {
! 		code = cm_Conn(&amp;oldDscp-&gt;fid, userp, reqp, &amp;connp);
!                 if (code) continue;
!                 
! 		oldDirAFSFid.Volume = oldDscp-&gt;fid.volume;
!                 oldDirAFSFid.Vnode = oldDscp-&gt;fid.vnode;
!                 oldDirAFSFid.Unique = oldDscp-&gt;fid.unique;
! 		newDirAFSFid.Volume = newDscp-&gt;fid.volume;
!                 newDirAFSFid.Vnode = newDscp-&gt;fid.vnode;
!                 newDirAFSFid.Unique = newDscp-&gt;fid.unique;
!                 code = RXAFS_Rename(connp-&gt;callp, &amp;oldDirAFSFid, oldNamep,
!                 	&amp;newDirAFSFid, newNamep,
! 			&amp;updatedOldDirStatus, &amp;updatedNewDirStatus,
!                 	&amp;volSync);
! 	} while (cm_Analyze(connp, userp, reqp, &amp;oldDscp-&gt;fid,
! 			    &amp;volSync, NULL, NULL, code));
!         code = cm_MapRPCError(code, reqp);
!         
! 	/* update the individual stat cache entries for the directories */
!         lock_ObtainMutex(&amp;oldDscp-&gt;mx);
!         cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
! 	if (code == 0) {
! 	        cm_MergeStatus(oldDscp, &amp;updatedOldDirStatus, &amp;volSync,
! 				userp, 0);
! 	}
!         lock_ReleaseMutex(&amp;oldDscp-&gt;mx);
  
! 	/* and update it for the new one, too, if necessary */
! 	if (!oneDir) {
! 	        lock_ObtainMutex(&amp;newDscp-&gt;mx);
! 	        cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
! 		if (code == 0) {
! 		        cm_MergeStatus(newDscp, &amp;updatedNewDirStatus, &amp;volSync,
! 					userp, 0);
! 		}
! 	        lock_ReleaseMutex(&amp;newDscp-&gt;mx);
! 	}
  
!         /* and return error code */
!         return code;
  }
  
  long cm_Lock(cm_scache_t *scp, unsigned char LockType,
! 	LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
! 	u_long Timeout, cm_user_t *userp, cm_req_t *reqp,
! 	void **lockpp)
! {
! 	long code;
! 	int Which = ((LockType &amp; 0x1) ? LockRead : LockWrite);
! 	AFSFid tfid;
! 	AFSVolSync volSync;
! 	cm_conn_t *connp;
! 	cm_file_lock_t *fileLock;
! 	osi_queue_t *q;
! 	int found = 0;
! 
! 	/* Look for a conflict.  Also, if we are asking for a shared lock,
! 	 * look for another shared lock, so we don't have to do an RPC.
! 	 */
! 	q = scp-&gt;fileLocks;
! 	while (q) {
! 		fileLock = (cm_file_lock_t *)
! 				((char *) q - offsetof(cm_file_lock_t, fileq));
! 		if ((fileLock-&gt;flags &amp;
! 			(CM_FILELOCK_FLAG_INVALID | CM_FILELOCK_FLAG_WAITING))
! 		    == 0) {
! 			if ((LockType &amp; 0x1) == 0
! 			    || (fileLock-&gt;LockType &amp; 0x1) == 0)
! 				return CM_ERROR_WOULDBLOCK;
! 			found = 1;
! 		}
! 		q = osi_QNext(q);
! 	}
! 
! 	if (found)
! 		code = 0;
! 	else {
! 		tfid.Volume = scp-&gt;fid.volume;
! 		tfid.Vnode = scp-&gt;fid.vnode;
! 		tfid.Unique = scp-&gt;fid.unique;
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		do {
! 			code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
! 			if (code) break;
! 			code = RXAFS_SetLock(connp-&gt;callp, &amp;tfid, Which,
! 					     &amp;volSync);
! 		} while (cm_Analyze(connp, userp, reqp, &amp;scp-&gt;fid, &amp;volSync,
! 				    NULL, NULL, code));
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
! 		code = cm_MapRPCError(code, reqp);
! 	}
! 
! 	if (code == 0 || Timeout != 0) {
! 		fileLock = malloc(sizeof(cm_file_lock_t));
! 		fileLock-&gt;LockType = LockType;
! 		cm_HoldUser(userp);
! 		fileLock-&gt;userp = userp;
! 		fileLock-&gt;fid = scp-&gt;fid;
! 		fileLock-&gt;LOffset = LOffset;
! 		fileLock-&gt;LLength = LLength;
! 		fileLock-&gt;flags = (code == 0 ? 0 : CM_FILELOCK_FLAG_WAITING);
! 		osi_QAdd(&amp;scp-&gt;fileLocks, &amp;fileLock-&gt;fileq);
! 		lock_ObtainWrite(&amp;cm_scacheLock);
! 		osi_QAdd(&amp;cm_allFileLocks, &amp;fileLock-&gt;q);
! 		lock_ReleaseWrite(&amp;cm_scacheLock);
! 		if (code != 0) *lockpp = fileLock;
! 	}
! 	return code;
  }
  
  long cm_Unlock(cm_scache_t *scp, unsigned char LockType,
! 	LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
! 	cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code = 0;
! 	int Which = ((LockType &amp; 0x1) ? LockRead : LockWrite);
! 	AFSFid tfid;
! 	AFSVolSync volSync;
! 	cm_conn_t *connp;
! 	cm_file_lock_t *fileLock, *ourLock;
! 	osi_queue_t *q, *qq;
! 	int anotherReader = 0;
! 	int smallLock = 0;
! 	int found = 0;
! 
! 	if (LargeIntegerLessThan(LLength, scp-&gt;length))
! 		smallLock = 1;
! 
! 	/* Look for our own lock on the list, so as to remove it.
! 	 * Also, determine if we're the last reader; if not, avoid an RPC.
! 	 */
! 	q = scp-&gt;fileLocks;
! 	while (q) {
! 		fileLock = (cm_file_lock_t *)
              ((char *) q - offsetof(cm_file_lock_t, fileq));
! 		if (!found
! 		    &amp;&amp; fileLock-&gt;userp == userp
! 		    &amp;&amp; LargeIntegerEqualTo(fileLock-&gt;LOffset, LOffset)
! 		    &amp;&amp; LargeIntegerEqualTo(fileLock-&gt;LLength, LLength)) {
! 			found = 1;
! 			ourLock = fileLock;
! 			qq = q;
! 		}
! 		else if (fileLock-&gt;LockType &amp; 0x1)
! 			anotherReader = 1;
! 		q = osi_QNext(q);
! 	}
! 
! 	/* ignore byte ranges */
! 	if (smallLock &amp;&amp; !found)
! 		return 0;
! 
! 	/* don't try to unlock other people's locks */
! 	if (!found)
! 		return CM_ERROR_WOULDBLOCK;
! 
! 	/* discard lock record */
! 	osi_QRemove(&amp;scp-&gt;fileLocks, qq);
! 	/*
! 	 * Don't delete it here; let the daemon delete it, to simplify
! 	 * the daemon's traversal of the list.
! 	 */
! 	lock_ObtainWrite(&amp;cm_scacheLock);
! 	ourLock-&gt;flags |= CM_FILELOCK_FLAG_INVALID;
! 	cm_ReleaseUser(ourLock-&gt;userp);
! 	lock_ReleaseWrite(&amp;cm_scacheLock);
! 
! 	if (!anotherReader) {
! 		tfid.Volume = scp-&gt;fid.volume;
! 		tfid.Vnode = scp-&gt;fid.vnode;
! 		tfid.Unique = scp-&gt;fid.unique;
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		do {
! 			code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
! 			if (code) 
                  break;
- 			code = RXAFS_ReleaseLock(connp-&gt;callp, &amp;tfid, &amp;volSync);
- 		} while (cm_Analyze(connp, userp, reqp, &amp;scp-&gt;fid, &amp;volSync,
- 				    NULL, NULL, code));
- 		code = cm_MapRPCError(code, reqp);
- 		lock_ObtainMutex(&amp;scp-&gt;mx);
- 	}
  
! 	return code;
  }
  
  void cm_CheckLocks()
  {
! 	osi_queue_t *q, *nq;
! 	cm_file_lock_t *fileLock;
! 	cm_req_t req;
! 	AFSFid tfid;
! 	AFSVolSync volSync;
! 	cm_conn_t *connp;
! 	long code;
! 
! 	cm_InitReq(&amp;req);
! 
! 	lock_ObtainWrite(&amp;cm_scacheLock);
! 	q = cm_allFileLocks;
! 	while (q) {
! 		fileLock = (cm_file_lock_t *) q;
! 		nq = osi_QNext(q);
! 		if (fileLock-&gt;flags &amp; CM_FILELOCK_FLAG_INVALID) {
! 			osi_QRemove(&amp;cm_allFileLocks, q);
! 			free(fileLock);
! 		}
! 		else if (!(fileLock-&gt;flags &amp; CM_FILELOCK_FLAG_WAITING)) {
! 			tfid.Volume = fileLock-&gt;fid.volume;
! 			tfid.Vnode = fileLock-&gt;fid.vnode;
! 			tfid.Unique = fileLock-&gt;fid.unique;
! 			lock_ReleaseWrite(&amp;cm_scacheLock);
! 			do {
! 				code = cm_Conn(&amp;fileLock-&gt;fid, fileLock-&gt;userp,
! 						&amp;req, &amp;connp);
! 				if (code) break;
! 				code = RXAFS_ExtendLock(connp-&gt;callp, &amp;tfid,
! 							&amp;volSync);
! 			} while (cm_Analyze(connp, fileLock-&gt;userp, &amp;req,
! 					    &amp;fileLock-&gt;fid, &amp;volSync, NULL, NULL,
! 					    code));
! 			code = cm_MapRPCError(code, &amp;req);
! 			lock_ObtainWrite(&amp;cm_scacheLock);
! 		}
! 		q = nq;
! 	}
! 	lock_ReleaseWrite(&amp;cm_scacheLock);
! }
  
  long cm_RetryLock(cm_file_lock_t *oldFileLock, int vcp_is_dead)
  {
! 	long code;
! 	int Which = ((oldFileLock-&gt;LockType &amp; 0x1) ? LockRead : LockWrite);
! 	cm_scache_t *scp;
! 	AFSFid tfid;
! 	AFSVolSync volSync;
! 	cm_conn_t *connp;
! 	cm_file_lock_t *fileLock;
! 	osi_queue_t *q;
! 	cm_req_t req;
! 	int found = 0;
! 
! 	if (vcp_is_dead) {
! 		code = CM_ERROR_TIMEDOUT;
! 		goto handleCode;
! 	}
! 
! 	cm_InitReq(&amp;req);
! 
! 	/* Look for a conflict.  Also, if we are asking for a shared lock,
! 	 * look for another shared lock, so we don't have to do an RPC.
! 	 */
! 	code = cm_GetSCache(&amp;oldFileLock-&gt;fid, &amp;scp, oldFileLock-&gt;userp, &amp;req);
! 	if (code)
! 		return code;
! 
! 	q = scp-&gt;fileLocks;
! 	while (q) {
! 		fileLock = (cm_file_lock_t *)
! 				((char *) q - offsetof(cm_file_lock_t, fileq));
! 		if ((fileLock-&gt;flags &amp;
! 			(CM_FILELOCK_FLAG_INVALID | CM_FILELOCK_FLAG_WAITING))
! 		    == 0) {
! 			if ((oldFileLock-&gt;LockType &amp; 0x1) == 0
! 			    || (fileLock-&gt;LockType &amp; 0x1) == 0) {
! 				cm_ReleaseSCache(scp);
! 				return CM_ERROR_WOULDBLOCK;
! 			}
! 			found = 1;
! 		}
! 		q = osi_QNext(q);
! 	}
! 
! 	if (found)
! 		code = 0;
! 	else {
! 		tfid.Volume = oldFileLock-&gt;fid.volume;
! 		tfid.Vnode = oldFileLock-&gt;fid.vnode;
! 		tfid.Unique = oldFileLock-&gt;fid.unique;
! 		do {
! 			code = cm_Conn(&amp;oldFileLock-&gt;fid, oldFileLock-&gt;userp,
! 				       &amp;req, &amp;connp);
! 			if (code) break;
! 			code = RXAFS_SetLock(connp-&gt;callp, &amp;tfid, Which,
! 					     &amp;volSync);
! 		} while (cm_Analyze(connp, oldFileLock-&gt;userp, &amp;req,
! 				    &amp;oldFileLock-&gt;fid, &amp;volSync,
! 				    NULL, NULL, code));
! 		code = cm_MapRPCError(code, &amp;req);
! 	}
  
    handleCode:
! 	if (code != 0 &amp;&amp; code != CM_ERROR_WOULDBLOCK) {
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
! 		osi_QRemove(&amp;scp-&gt;fileLocks, &amp;oldFileLock-&gt;fileq);
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	}
! 	lock_ObtainWrite(&amp;cm_scacheLock);
! 	if (code == 0)
! 		oldFileLock-&gt;flags = 0;
! 	else if (code != CM_ERROR_WOULDBLOCK) {
! 		oldFileLock-&gt;flags |= CM_FILELOCK_FLAG_INVALID;
! 		cm_ReleaseUser(oldFileLock-&gt;userp);
          oldFileLock-&gt;userp = NULL;
! 	}
! 	lock_ReleaseWrite(&amp;cm_scacheLock);
  
! 	return code;
  }
--- 1554,2810 ----
   * processing, to avoid deadlocks.
   */
  long cm_TryBulkProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
!                      osi_hyper_t *offp)
  {
!     osi_hyper_t thyper;
!     cm_bulkStat_t *bsp;
!     int i;
!     cm_scache_t *tscp;
!     cm_fid_t tfid;
  
!     bsp = rockp;
  
!     /* Don't overflow bsp. */
!     if (bsp-&gt;counter &gt;= CM_BULKMAX)
!         return CM_ERROR_STOPNOW;
  
!     thyper.LowPart = buf_bufferSize;
!     thyper.HighPart = 0;
!     thyper = LargeIntegerAdd(thyper, bsp-&gt;bufOffset);
! 
!     /* thyper is now the first byte past the end of the record we're
!      * interested in, and bsp-&gt;bufOffset is the first byte of the record
!      * we're interested in.
!      * Skip data in the others.
!      * Skip '.' and '..'
!      */
!     if (LargeIntegerLessThan(*offp, bsp-&gt;bufOffset))
!         return 0;
!     if (LargeIntegerGreaterThanOrEqualTo(*offp, thyper))
!         return CM_ERROR_STOPNOW;
!     if (strcmp(dep-&gt;name, ".") == 0 || strcmp(dep-&gt;name, "..") == 0)
!         return 0;
! 
!     tfid.cell = scp-&gt;fid.cell;
!     tfid.volume = scp-&gt;fid.volume;
!     tfid.vnode = ntohl(dep-&gt;fid.vnode);
!     tfid.unique = ntohl(dep-&gt;fid.unique);
!     tscp = cm_FindSCache(&amp;tfid);
!     if (tscp) {
!         if (lock_TryMutex(&amp;tscp-&gt;mx)) {
!             /* we have an entry that we can look at */
!             if (cm_HaveCallback(tscp)) {
!                 /* we have a callback on it.  Don't bother
!                  * fetching this stat entry, since we're happy
!                  * with the info we have.
!                  */
!                 lock_ReleaseMutex(&amp;tscp-&gt;mx);
                  cm_ReleaseSCache(tscp);
!                 return 0;
!             }
!             lock_ReleaseMutex(&amp;tscp-&gt;mx);
!         }	/* got lock */
!         cm_ReleaseSCache(tscp);
!     }	/* found entry */
  
  #ifdef AFS_FREELANCE_CLIENT
!     // yj: if this is a mountpoint under root.afs then we don't want it
!     // to be bulkstat-ed, instead, we call getSCache directly and under
!     // getSCache, it is handled specially.
!     if 	( cm_freelanceEnabled &amp;&amp;
            tfid.cell==AFS_FAKE_ROOT_CELL_ID &amp;&amp; 
            tfid.volume==AFS_FAKE_ROOT_VOL_ID &amp;&amp;
            !(tfid.vnode==0x1 &amp;&amp; tfid.unique==0x1) )
!     {       
          osi_Log0(afsd_logp, "cm_TryBulkProc Freelance calls cm_SCache on root.afs mountpoint");
!         return cm_GetSCache(&amp;tfid, &amp;tscp, NULL, NULL);
!     }
  #endif /* AFS_FREELANCE_CLIENT */
  
!     i = bsp-&gt;counter++;
!     bsp-&gt;fids[i].Volume = scp-&gt;fid.volume;
!     bsp-&gt;fids[i].Vnode = tfid.vnode;
!     bsp-&gt;fids[i].Unique = tfid.unique;
!     return 0;
! }       
  
  /* called with a locked scp and a pointer to a buffer.  Make bulk stat
   * calls on all undeleted files in the page of the directory specified.
   */
  void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
!                      cm_req_t *reqp)
  {
!     long code;
!     cm_bulkStat_t bb;	/* this is *BIG*, probably 12K or so;
!                          * watch for stack problems */
!     AFSCBFids fidStruct;
!     AFSBulkStats statStruct;
!     cm_conn_t *connp;
!     AFSCBs callbackStruct;
!     long filex;
!     AFSVolSync volSync;
!     cm_callbackRequest_t cbReq;
!     long filesThisCall;
!     long i;
!     long j;
!     cm_scache_t *scp;
!     cm_fid_t tfid;
!     struct rx_connection * callp;
! 
!     osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%x", (long) dscp);
! 
!     /* should be on a buffer boundary */
!     osi_assert((offsetp-&gt;LowPart &amp; (buf_bufferSize - 1)) == 0);
! 
!     bb.counter = 0;
!     bb.bufOffset = *offsetp;
! 
!     /* first, assemble the file IDs we need to stat */
!     code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) &amp;bb, offsetp, userp,
!                         reqp, NULL);
! 
!     /* if we failed, bail out early */
!     if (code &amp;&amp; code != CM_ERROR_STOPNOW) return;
! 
!     /* otherwise, we may have one or more bulk stat's worth of stuff in bb;
!      * make the calls to create the entries.  Handle AFSCBMAX files at a
!      * time.
!      */
!     filex = 0;
!     while(filex &lt; bb.counter) {
!         filesThisCall = bb.counter - filex;
!         if (filesThisCall &gt; AFSCBMAX) filesThisCall = AFSCBMAX;
! 
!         fidStruct.AFSCBFids_len = filesThisCall;
!         fidStruct.AFSCBFids_val = &amp;bb.fids[filex];
!         statStruct.AFSBulkStats_len = filesThisCall;
!         statStruct.AFSBulkStats_val = &amp;bb.stats[filex];
!         callbackStruct.AFSCBs_len = filesThisCall;
!         callbackStruct.AFSCBs_val = &amp;bb.callbacks[filex];
!         cm_StartCallbackGrantingCall(NULL, &amp;cbReq);
!         osi_Log1(afsd_logp, "CALL BulkStatus, %d entries", filesThisCall);
!         do {
!             code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!             if (code) 
!                 continue;
! 
!             callp = cm_GetRxConn(connp);
!             code = RXAFS_BulkStatus(callp, &amp;fidStruct,
!                                      &amp;statStruct, &amp;callbackStruct, &amp;volSync);
!             rx_PutConnection(callp);
  
!         } while (cm_Analyze(connp, userp, reqp, &amp;dscp-&gt;fid,
!                              &amp;volSync, NULL, &amp;cbReq, code));
!         code = cm_MapRPCError(code, reqp);
! 
!         osi_Log0(afsd_logp, "CALL BulkStatus DONE");
! 
!         /* may as well quit on an error, since we're not going to do
!          * much better on the next immediate call, either.
           */
!         if (code) 
!             break;
  
!         /* otherwise, we should do the merges */
!         for(i = 0; i&lt;filesThisCall; i++) {
!             j = filex + i;
!             tfid.cell = dscp-&gt;fid.cell;
!             tfid.volume = bb.fids[j].Volume;
!             tfid.vnode = bb.fids[j].Vnode;
!             tfid.unique = bb.fids[j].Unique;
!             code = cm_GetSCache(&amp;tfid, &amp;scp, userp, reqp);
!             if (code != 0) 
!                 continue;
  
!             /* otherwise, if this entry has no callback info, 
!              * merge in this.
!              */
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             /* now, we have to be extra paranoid on merging in this
!              * information, since we didn't use cm_SyncOp before
!              * starting the fetch to make sure that no bad races
!              * were occurring.  Specifically, we need to make sure
!              * we don't obliterate any newer information in the
!              * vnode than have here.
!              *
!              * Right now, be pretty conservative: if there's a
!              * callback or a pending call, skip it.
!              */
!             if (scp-&gt;cbServerp == NULL
!                  &amp;&amp; !(scp-&gt;flags &amp;
!                        (CM_SCACHEFLAG_FETCHING
!                          | CM_SCACHEFLAG_STORING
!                          | CM_SCACHEFLAG_SIZESTORING))) {
!                 cm_EndCallbackGrantingCall(scp, &amp;cbReq,
!                                             &amp;bb.callbacks[j],
!                                             CM_CALLBACK_MAINTAINCOUNT);
!                 cm_MergeStatus(scp, &amp;bb.stats[j], &amp;volSync,
!                                 userp, 0);
!             }       
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             cm_ReleaseSCache(scp);
!         } /* all files in the response */
!         /* now tell it to drop the count,
!          * after doing the vnode processing above */
          cm_EndCallbackGrantingCall(NULL, &amp;cbReq, NULL, 0);
! 
!         filex += filesThisCall;
!     }	/* while there are still more files to process */
!     osi_Log0(afsd_logp, "END cm_TryBulkStat");
! }       
  
  void cm_StatusFromAttr(AFSStoreStatus *statusp, cm_scache_t *scp, cm_attr_t *attrp)
  {
!     long mask;
  
!     /* initialize store back mask as inexpensive local variable */
!     mask = 0;
!     memset(statusp, 0, sizeof(AFSStoreStatus));
! 
!     /* copy out queued info from scache first, if scp passed in */
!     if (scp) {
!         if (scp-&gt;mask &amp; CM_SCACHEMASK_CLIENTMODTIME) {
!             statusp-&gt;ClientModTime = scp-&gt;clientModTime;
!             mask |= AFS_SETMODTIME;
!             scp-&gt;mask &amp;= ~CM_SCACHEMASK_CLIENTMODTIME;
!         }
!     }
! 
!     if (attrp) {
!         /* now add in our locally generated request */
!         if (attrp-&gt;mask &amp; CM_ATTRMASK_CLIENTMODTIME) {
!             statusp-&gt;ClientModTime = attrp-&gt;clientModTime;
!             mask |= AFS_SETMODTIME;
!         }
!         if (attrp-&gt;mask &amp; CM_ATTRMASK_UNIXMODEBITS) {
!             statusp-&gt;UnixModeBits = attrp-&gt;unixModeBits;
!             mask |= AFS_SETMODE;
!         }
!         if (attrp-&gt;mask &amp; CM_ATTRMASK_OWNER) {
!             statusp-&gt;Owner = attrp-&gt;owner;
!             mask |= AFS_SETOWNER;
!         }
!         if (attrp-&gt;mask &amp; CM_ATTRMASK_GROUP) {
!             statusp-&gt;Group = attrp-&gt;group;
!             mask |= AFS_SETGROUP;
!         }
!     }
!     statusp-&gt;Mask = mask;
! }       
  
  /* set the file size, and make sure that all relevant buffers have been
   * truncated.  Ensure that any partially truncated buffers have been zeroed
   * to the end of the buffer.
   */
  long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
!                    cm_req_t *reqp)
  {
!     long code;
!     int shrinking;
  
!     /* start by locking out buffer creation */
!     lock_ObtainWrite(&amp;scp-&gt;bufCreateLock);
  
!     /* verify that this is a file, not a dir or a symlink */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) 
!         goto done;
!         
!     if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!         code = CM_ERROR_ISDIR;
!         goto done;
!     }
  
!   startover:
!     if (LargeIntegerLessThan(*sizep, scp-&gt;length))
!         shrinking = 1;
!     else
!         shrinking = 0;
! 
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
!     /* can't hold scp-&gt;mx lock here, since we may wait for a storeback to
!      * finish if the buffer package is cleaning a buffer by storing it to
!      * the server.
!      */
!     if (shrinking)
!         buf_Truncate(scp, userp, reqp, sizep);
  
!     /* now ensure that file length is short enough, and update truncPos */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
  
!     /* make sure we have a callback (so we have the right value for the
!      * length), and wait for it to be safe to do a truncate.
!      */
!     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_WRITE,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
!                       | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
!     if (code) 
!         goto done;
! 
!     if (LargeIntegerLessThan(*sizep, scp-&gt;length)) {
!         /* a real truncation.  If truncPos is not set yet, or is bigger
!          * than where we're truncating the file, set truncPos to this
!          * new value.
!          */
!         if (!shrinking)
!             goto startover;
!         if (!(scp-&gt;mask &amp; CM_SCACHEMASK_TRUNCPOS)
!              || LargeIntegerLessThan(*sizep, scp-&gt;length)) {
!             /* set trunc pos */
!             scp-&gt;truncPos = *sizep;
!             scp-&gt;mask |= CM_SCACHEMASK_TRUNCPOS;
!         }
!         /* in either case, the new file size has been changed */
!         scp-&gt;length = *sizep;
!         scp-&gt;mask |= CM_SCACHEMASK_LENGTH;
!     }
!     else if (LargeIntegerGreaterThan(*sizep, scp-&gt;length)) {
!         /* really extending the file */
!         scp-&gt;length = *sizep;
!         scp-&gt;mask |= CM_SCACHEMASK_LENGTH;
!     }
  
!     /* done successfully */
!     code = 0;
  
!   done:
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     lock_ReleaseWrite(&amp;scp-&gt;bufCreateLock);
  
!     return code;
  }
  
  /* set the file size or other attributes (but not both at once) */
  long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
!                 cm_req_t *reqp)
  {
!     long code;
!     int flags;
!     AFSFetchStatus afsOutStatus;
!     AFSVolSync volSync;
!     cm_conn_t *connp;
!     AFSFid tfid;
!     AFSStoreStatus afsInStatus;
!     struct rx_connection * callp;
! 
!     /* handle file length setting */
!     if (attrp-&gt;mask &amp; CM_ATTRMASK_LENGTH)
!         return cm_SetLength(scp, &amp;attrp-&gt;length, userp, reqp);
! 
!     flags = CM_SCACHESYNC_STORESTATUS;
! 
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     /* otherwise, we have to make an RPC to get the status */
!     code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
  
!     /* make the attr structure */
!     cm_StatusFromAttr(&amp;afsInStatus, scp, attrp);
  
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     if (code) 
!         return code;
  
!     /* now make the RPC */
!     osi_Log1(afsd_logp, "CALL StoreStatus vp %x", (long) scp);
!     tfid.Volume = scp-&gt;fid.volume;
!     tfid.Vnode = scp-&gt;fid.vnode;
!     tfid.Unique = scp-&gt;fid.unique;
!     do {
!         code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
!         if (code) 
!             continue;
  
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_StoreStatus(callp, &amp;tfid,
!                                   &amp;afsInStatus, &amp;afsOutStatus, &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, reqp,
!                          &amp;scp-&gt;fid, &amp;volSync, NULL, NULL, code));
!     code = cm_MapRPCError(code, reqp);
! 
!     osi_Log1(afsd_logp, "CALL StoreStatus DONE, code %d", code);
! 
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
!     if (code == 0)
!         cm_MergeStatus(scp, &amp;afsOutStatus, &amp;volSync, userp,
!                         CM_MERGEFLAG_FORCE);
! 	
!     /* if we're changing the mode bits, discard the ACL cache, 
!      * since we changed the mode bits.
!      */
!     if (afsInStatus.Mask &amp; AFS_SETMODE) cm_FreeAllACLEnts(scp);
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     return code;
! }       
  
! long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
!                cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp)
! {       
!     cm_conn_t *connp;
!     long code;
!     AFSFid dirAFSFid;
!     cm_callbackRequest_t cbReq;
!     AFSFid newAFSFid;
!     cm_fid_t newFid;
!     cm_scache_t *scp;
!     int didEnd;
!     AFSStoreStatus inStatus;
!     AFSFetchStatus updatedDirStatus;
!     AFSFetchStatus newFileStatus;
!     AFSCallBack newFileCallback;
!     AFSVolSync volSync;
!     struct rx_connection * callp;
  
!     /* can't create names with @sys in them; must expand it manually first.
!      * return "invalid request" if they try.
!      */
!     if (cm_ExpandSysName(namep, NULL, 0, 0)) {
!         return CM_ERROR_ATSYS;
!     }
  
!     /* before starting the RPC, mark that we're changing the file data, so
!      * that someone who does a chmod will know to wait until our call
!      * completes.
!      */
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
!     if (code == 0) {
!         cm_StartCallbackGrantingCall(NULL, &amp;cbReq);
!     }
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
!     if (code) {
          return code;
!     }
!     didEnd = 0;
  
!     cm_StatusFromAttr(&amp;inStatus, NULL, attrp);
  
!     /* try the RPC now */
!     do {
!         code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!         if (code) 
!             continue;
  
!         dirAFSFid.Volume = dscp-&gt;fid.volume;
!         dirAFSFid.Vnode = dscp-&gt;fid.vnode;
!         dirAFSFid.Unique = dscp-&gt;fid.unique;
! 
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_CreateFile(connp-&gt;callp, &amp;dirAFSFid, namep,
!                                  &amp;inStatus, &amp;newAFSFid, &amp;newFileStatus,
!                                  &amp;updatedDirStatus, &amp;newFileCallback,
!                                  &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, reqp,
!                          &amp;dscp-&gt;fid, &amp;volSync, NULL, &amp;cbReq, code));
!     code = cm_MapRPCError(code, reqp);
!         
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
!     if (code == 0) {
!         cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
!     }
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
! 
!     /* now try to create the file's entry, too, but be careful to 
!      * make sure that we don't merge in old info.  Since we weren't locking
!      * out any requests during the file's creation, we may have pretty old
!      * info.
!      */
!     if (code == 0) {
!         newFid.cell = dscp-&gt;fid.cell;
!         newFid.volume = dscp-&gt;fid.volume;
!         newFid.vnode = newAFSFid.Vnode;
!         newFid.unique = newAFSFid.Unique;
!         code = cm_GetSCache(&amp;newFid, &amp;scp, userp, reqp);
          if (code == 0) {
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             if (!cm_HaveCallback(scp)) {
!                 cm_MergeStatus(scp, &amp;newFileStatus, &amp;volSync,
!                                 userp, 0);
!                 cm_EndCallbackGrantingCall(scp, &amp;cbReq,
!                                             &amp;newFileCallback, 0);
!                 didEnd = 1;     
!             }       
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             *scpp = scp;
          }
!     }
  
!     /* make sure we end things properly */
!     if (!didEnd)
!         cm_EndCallbackGrantingCall(NULL, &amp;cbReq, NULL, 0);
  
!     return code;
! }       
  
  long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
  
!     lock_ObtainWrite(&amp;scp-&gt;bufCreateLock);
!     code = buf_CleanVnode(scp, userp, reqp);
!     lock_ReleaseWrite(&amp;scp-&gt;bufCreateLock);
!     if (code == 0) {
!         lock_ObtainMutex(&amp;scp-&gt;mx);
!         scp-&gt;flags &amp;= ~(CM_SCACHEFLAG_OVERQUOTA
!                          | CM_SCACHEFLAG_OUTOFSPACE);
!         if (scp-&gt;mask &amp; (CM_SCACHEMASK_TRUNCPOS
!                           | CM_SCACHEMASK_CLIENTMODTIME
!                           | CM_SCACHEMASK_LENGTH))
!             code = cm_StoreMini(scp, userp, reqp);
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!     }
!     return code;
  }
  
  long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
!                  cm_user_t *userp, cm_req_t *reqp)
  {
!     cm_conn_t *connp;
!     long code;
!     AFSFid dirAFSFid;
!     cm_callbackRequest_t cbReq;
!     AFSFid newAFSFid;
!     cm_fid_t newFid;
!     cm_scache_t *scp;
!     int didEnd;
!     AFSStoreStatus inStatus;
!     AFSFetchStatus updatedDirStatus;
!     AFSFetchStatus newDirStatus;
!     AFSCallBack newDirCallback;
!     AFSVolSync volSync;
!     struct rx_connection * callp;
  
!     /* can't create names with @sys in them; must expand it manually first.
!      * return "invalid request" if they try.
!      */
!     if (cm_ExpandSysName(namep, NULL, 0, 0)) {
!         return CM_ERROR_ATSYS;
!     }
  
!     /* before starting the RPC, mark that we're changing the directory
!      * data, so that someone who does a chmod on the dir will wait until
!      * our call completes.
!      */
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
!     if (code == 0) {
!         cm_StartCallbackGrantingCall(NULL, &amp;cbReq);
!     }
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
!     if (code) {
!         return code;
!     }
!     didEnd = 0;
! 
!     cm_StatusFromAttr(&amp;inStatus, NULL, attrp);
! 
!     /* try the RPC now */
!     do {
!         code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!         if (code) 
!             continue;
! 
!         dirAFSFid.Volume = dscp-&gt;fid.volume;
!         dirAFSFid.Vnode = dscp-&gt;fid.vnode;
!         dirAFSFid.Unique = dscp-&gt;fid.unique;
! 
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_MakeDir(connp-&gt;callp, &amp;dirAFSFid, namep,
!                               &amp;inStatus, &amp;newAFSFid, &amp;newDirStatus,
!                               &amp;updatedDirStatus, &amp;newDirCallback,
!                               &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, reqp,
!                          &amp;dscp-&gt;fid, &amp;volSync, NULL, &amp;cbReq, code));
!     code = cm_MapRPCError(code, reqp);
!         
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
!     if (code == 0) {
!         cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
!     }
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
! 
!     /* now try to create the new dir's entry, too, but be careful to 
!      * make sure that we don't merge in old info.  Since we weren't locking
!      * out any requests during the file's creation, we may have pretty old
!      * info.
!      */
!     if (code == 0) {
!         newFid.cell = dscp-&gt;fid.cell;
!         newFid.volume = dscp-&gt;fid.volume;
!         newFid.vnode = newAFSFid.Vnode;
!         newFid.unique = newAFSFid.Unique;
!         code = cm_GetSCache(&amp;newFid, &amp;scp, userp, reqp);
          if (code == 0) {
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             if (!cm_HaveCallback(scp)) {
!                 cm_MergeStatus(scp, &amp;newDirStatus, &amp;volSync,
!                                 userp, 0);
!                 cm_EndCallbackGrantingCall(scp, &amp;cbReq,
!                                             &amp;newDirCallback, 0);
!                 didEnd = 1;             
!             }
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             cm_ReleaseSCache(scp);
          }
!     }
  
!     /* make sure we end things properly */
!     if (!didEnd)
!         cm_EndCallbackGrantingCall(NULL, &amp;cbReq, NULL, 0);
  
!     /* and return error code */
!     return code;
! }       
  
! long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
!              cm_user_t *userp, cm_req_t *reqp)
! {
!     cm_conn_t *connp;
!     long code = 0;
!     AFSFid dirAFSFid;
!     AFSFid existingAFSFid;
!     AFSFetchStatus updatedDirStatus;
!     AFSFetchStatus newLinkStatus;
!     AFSVolSync volSync;
!     struct rx_connection * callp;
! 
!     if (dscp-&gt;fid.cell != sscp-&gt;fid.cell ||
!         dscp-&gt;fid.volume != sscp-&gt;fid.volume) {
!         return CM_ERROR_CROSSDEVLINK;
!     }
! 
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
! 
!     if (code)
          return code;
+ 
+     do {
+         code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
+         if (code) continue;
+ 
+         dirAFSFid.Volume = dscp-&gt;fid.volume;
+         dirAFSFid.Vnode = dscp-&gt;fid.vnode;
+         dirAFSFid.Unique = dscp-&gt;fid.unique;
+ 
+         existingAFSFid.Volume = sscp-&gt;fid.volume;
+         existingAFSFid.Vnode = sscp-&gt;fid.vnode;
+         existingAFSFid.Unique = sscp-&gt;fid.unique;
+ 
+         callp = cm_GetRxConn(connp);
+         code = RXAFS_Link(callp, &amp;dirAFSFid, namep, &amp;existingAFSFid,
+             &amp;newLinkStatus, &amp;updatedDirStatus, &amp;volSync);
+         rx_PutConnection(callp);
+         osi_Log1(smb_logp,"  RXAFS_Link returns %d", code);
+ 
+     } while (cm_Analyze(connp, userp, reqp,
+         &amp;dscp-&gt;fid, &amp;volSync, NULL, NULL, code));
+ 
+     code = cm_MapRPCError(code, reqp);
+ 
+     lock_ObtainMutex(&amp;dscp-&gt;mx);
+     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
+     if (code == 0) {
+         cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
+     }
+     lock_ReleaseMutex(&amp;dscp-&gt;mx);
+ 
+     return code;
  }
  
  long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
!                 cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp)
  {
!     cm_conn_t *connp;
!     long code;
!     AFSFid dirAFSFid;
!     AFSFid newAFSFid;
!     cm_fid_t newFid;
!     cm_scache_t *scp;
!     AFSStoreStatus inStatus;
!     AFSFetchStatus updatedDirStatus;
!     AFSFetchStatus newLinkStatus;
!     AFSVolSync volSync;
!     struct rx_connection * callp;
! 
!     /* before starting the RPC, mark that we're changing the directory data,
!      * so that someone who does a chmod on the dir will wait until our
!      * call completes.
!      */
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
!     if (code) {
!         return code;
!     }
  
!     cm_StatusFromAttr(&amp;inStatus, NULL, attrp);
  
!     /* try the RPC now */
!     do {
!         code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!         if (code) 
!             continue;
  
!         dirAFSFid.Volume = dscp-&gt;fid.volume;
!         dirAFSFid.Vnode = dscp-&gt;fid.vnode;
!         dirAFSFid.Unique = dscp-&gt;fid.unique;
! 
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_Symlink(callp, &amp;dirAFSFid, namep, contentsp,
!                               &amp;inStatus, &amp;newAFSFid, &amp;newLinkStatus,
!                               &amp;updatedDirStatus, &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, reqp,
!                          &amp;dscp-&gt;fid, &amp;volSync, NULL, NULL, code));
!     code = cm_MapRPCError(code, reqp);
!         
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
!     if (code == 0) {
!         cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
!     }
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
! 
!     /* now try to create the new dir's entry, too, but be careful to 
!      * make sure that we don't merge in old info.  Since we weren't locking
!      * out any requests during the file's creation, we may have pretty old
!      * info.
!      */
!     if (code == 0) {
!         newFid.cell = dscp-&gt;fid.cell;
!         newFid.volume = dscp-&gt;fid.volume;
!         newFid.vnode = newAFSFid.Vnode;
!         newFid.unique = newAFSFid.Unique;
!         code = cm_GetSCache(&amp;newFid, &amp;scp, userp, reqp);
!         if (code == 0) {
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             if (!cm_HaveCallback(scp)) {
!                 cm_MergeStatus(scp, &amp;newLinkStatus, &amp;volSync,
!                                 userp, 0);
!             }       
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             cm_ReleaseSCache(scp);
          }
+     }
  	
!     /* and return error code */
!     return code;
  }
  
  long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
!                    cm_req_t *reqp)
  {
!     cm_conn_t *connp;
!     long code;
!     AFSFid dirAFSFid;
!     int didEnd;
!     AFSFetchStatus updatedDirStatus;
!     AFSVolSync volSync;
!     struct rx_connection * callp;
! 
!     /* before starting the RPC, mark that we're changing the directory data,
!      * so that someone who does a chmod on the dir will wait until our
!      * call completes.
!      */
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
!     if (code) {
!         return code;
!     }
!     didEnd = 0;
  
!     /* try the RPC now */
!     do {
!         code = cm_Conn(&amp;dscp-&gt;fid, userp, reqp, &amp;connp);
!         if (code) 
!             continue;
  
!         dirAFSFid.Volume = dscp-&gt;fid.volume;
!         dirAFSFid.Vnode = dscp-&gt;fid.vnode;
!         dirAFSFid.Unique = dscp-&gt;fid.unique;
! 
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_RemoveDir(callp, &amp;dirAFSFid, namep,
!                                 &amp;updatedDirStatus, &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, reqp,
!                          &amp;dscp-&gt;fid, &amp;volSync, NULL, NULL, code));
!     code = cm_MapRPCErrorRmdir(code, reqp);
!         
!     lock_ObtainMutex(&amp;dscp-&gt;mx);
!     cm_dnlcRemove(dscp, namep); 
!     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
!     if (code == 0) {
!         cm_MergeStatus(dscp, &amp;updatedDirStatus, &amp;volSync, userp, 0);
!     }
!     lock_ReleaseMutex(&amp;dscp-&gt;mx);
! 
!     /* and return error code */
!     return code;
  }
  
  long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
  {
!     /* grab mutex on contents */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
  
!     /* reset the prefetch info */
!     scp-&gt;prefetch.base.LowPart = 0;		/* base */
!     scp-&gt;prefetch.base.HighPart = 0;
!     scp-&gt;prefetch.end.LowPart = 0;		/* and end */
!     scp-&gt;prefetch.end.HighPart = 0;
! 
!     /* release mutex on contents */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
!     /* we're done */
!     return 0;
! }       
  
  long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
!                 char *newNamep, cm_user_t *userp, cm_req_t *reqp)
  {
!     cm_conn_t *connp;
!     long code;
!     AFSFid oldDirAFSFid;
!     AFSFid newDirAFSFid;
!     int didEnd;
!     AFSFetchStatus updatedOldDirStatus;
!     AFSFetchStatus updatedNewDirStatus;
!     AFSVolSync volSync;
!     int oneDir;
!     struct rx_connection * callp;
! 
!     /* before starting the RPC, mark that we're changing the directory data,
!      * so that someone who does a chmod on the dir will wait until our call
!      * completes.  We do this in vnode order so that we don't deadlock,
!      * which makes the code a little verbose.
!      */
!     if (oldDscp == newDscp) {
!         /* check for identical names */
!         if (strcmp(oldNamep, newNamep) == 0)
!             return CM_ERROR_RENAME_IDENTICAL;
! 
!         oneDir = 1;
!         lock_ObtainMutex(&amp;oldDscp-&gt;mx);
!         cm_dnlcRemove(oldDscp, oldNamep);
!         cm_dnlcRemove(oldDscp, newNamep);
!         code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
!                           CM_SCACHESYNC_STOREDATA);
!         lock_ReleaseMutex(&amp;oldDscp-&gt;mx);
!     }
!     else {
!         /* two distinct dir vnodes */
!         oneDir = 0;
!         if (oldDscp-&gt;fid.cell != newDscp-&gt;fid.cell ||
!              oldDscp-&gt;fid.volume != newDscp-&gt;fid.volume)
!             return CM_ERROR_CROSSDEVLINK;
! 
!         /* shouldn't happen that we have distinct vnodes for two
!          * different files, but could due to deliberate attack, or
!          * stale info.  Avoid deadlocks and quit now.
!          */
!         if (oldDscp-&gt;fid.vnode == newDscp-&gt;fid.vnode)
!             return CM_ERROR_CROSSDEVLINK;
! 
!         if (oldDscp-&gt;fid.vnode &lt; newDscp-&gt;fid.vnode) {
!             lock_ObtainMutex(&amp;oldDscp-&gt;mx);
!             cm_dnlcRemove(oldDscp, oldNamep);
!             code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
!                               CM_SCACHESYNC_STOREDATA);
!             lock_ReleaseMutex(&amp;oldDscp-&gt;mx);
!             if (code == 0) {
!                 lock_ObtainMutex(&amp;newDscp-&gt;mx);
!                 cm_dnlcRemove(newDscp, newNamep);
!                 code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
!                                   CM_SCACHESYNC_STOREDATA);
!                 lock_ReleaseMutex(&amp;newDscp-&gt;mx);
!                 if (code) {
!                     /* cleanup first one */
!                     cm_SyncOpDone(oldDscp, NULL,
!                                    CM_SCACHESYNC_STOREDATA);
!                 }       
!             }
          }
          else {
!             /* lock the new vnode entry first */
!             lock_ObtainMutex(&amp;newDscp-&gt;mx);
!             cm_dnlcRemove(newDscp, newNamep);
!             code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
!                               CM_SCACHESYNC_STOREDATA);
!             lock_ReleaseMutex(&amp;newDscp-&gt;mx);
!             if (code == 0) {
!                 lock_ObtainMutex(&amp;oldDscp-&gt;mx);
!                 cm_dnlcRemove(oldDscp, oldNamep);
!                 code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
!                                   CM_SCACHESYNC_STOREDATA);
!                 lock_ReleaseMutex(&amp;oldDscp-&gt;mx);
!                 if (code) {
!                     /* cleanup first one */
!                     cm_SyncOpDone(newDscp, NULL,
!                                    CM_SCACHESYNC_STOREDATA);
!                 }       
!             }
!         }
!     }	/* two distinct vnodes */
  
!     if (code) {
!         return code;
!     }
!     didEnd = 0;
  
!     /* try the RPC now */
!     do {
!         code = cm_Conn(&amp;oldDscp-&gt;fid, userp, reqp, &amp;connp);
!         if (code) 
!             continue;
  
!         oldDirAFSFid.Volume = oldDscp-&gt;fid.volume;
!         oldDirAFSFid.Vnode = oldDscp-&gt;fid.vnode;
!         oldDirAFSFid.Unique = oldDscp-&gt;fid.unique;
!         newDirAFSFid.Volume = newDscp-&gt;fid.volume;
!         newDirAFSFid.Vnode = newDscp-&gt;fid.vnode;
!         newDirAFSFid.Unique = newDscp-&gt;fid.unique;
! 
!         callp = cm_GetRxConn(connp);
!         code = RXAFS_Rename(callp, &amp;oldDirAFSFid, oldNamep,
!                              &amp;newDirAFSFid, newNamep,
!                              &amp;updatedOldDirStatus, &amp;updatedNewDirStatus,
!                              &amp;volSync);
!         rx_PutConnection(callp);
! 
!     } while (cm_Analyze(connp, userp, reqp, &amp;oldDscp-&gt;fid,
!                          &amp;volSync, NULL, NULL, code));
!     code = cm_MapRPCError(code, reqp);
!         
!     /* update the individual stat cache entries for the directories */
!     lock_ObtainMutex(&amp;oldDscp-&gt;mx);
!     cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
!     if (code == 0) {
!         cm_MergeStatus(oldDscp, &amp;updatedOldDirStatus, &amp;volSync,
!                         userp, 0);
!     }
!     lock_ReleaseMutex(&amp;oldDscp-&gt;mx);
  
!     /* and update it for the new one, too, if necessary */
!     if (!oneDir) {
!         lock_ObtainMutex(&amp;newDscp-&gt;mx);
!         cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
!         if (code == 0) {
!             cm_MergeStatus(newDscp, &amp;updatedNewDirStatus, &amp;volSync,
!                             userp, 0);
!         }
!         lock_ReleaseMutex(&amp;newDscp-&gt;mx);
!     }
! 
!     /* and return error code */
!     return code;
  }
  
  long cm_Lock(cm_scache_t *scp, unsigned char LockType,
!               LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
!               u_long Timeout, cm_user_t *userp, cm_req_t *reqp,
!               void **lockpp)
! {
!     long code;
!     int Which = ((LockType &amp; 0x1) ? LockRead : LockWrite);
!     AFSFid tfid;
!     AFSVolSync volSync;
!     cm_conn_t *connp;
!     cm_file_lock_t *fileLock;
!     osi_queue_t *q;
!     int found = 0;
!     struct rx_connection * callp;
! 
!     /* Look for a conflict.  Also, if we are asking for a shared lock,
!      * look for another shared lock, so we don't have to do an RPC.
!      */
!     q = scp-&gt;fileLocks;
!     while (q) {
!         fileLock = (cm_file_lock_t *)
!             ((char *) q - offsetof(cm_file_lock_t, fileq));
!         if ((fileLock-&gt;flags &amp;
!               (CM_FILELOCK_FLAG_INVALID | CM_FILELOCK_FLAG_WAITING))
!              == 0) {
!             if ((LockType &amp; 0x1) == 0
!                  || (fileLock-&gt;LockType &amp; 0x1) == 0)
!                 return CM_ERROR_WOULDBLOCK;
!             found = 1;
!         }
!         q = osi_QNext(q);
!     }
! 
!     if (found)
!         code = 0;
!     else {
!         tfid.Volume = scp-&gt;fid.volume;
!         tfid.Vnode = scp-&gt;fid.vnode;
!         tfid.Unique = scp-&gt;fid.unique;
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         do {
!             code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
!             if (code) 
!                 break;
! 
!             callp = cm_GetRxConn(connp);
!             code = RXAFS_SetLock(callp, &amp;tfid, Which,
!                                   &amp;volSync);
!             rx_PutConnection(callp);
! 
!         } while (cm_Analyze(connp, userp, reqp, &amp;scp-&gt;fid, &amp;volSync,
!                              NULL, NULL, code));
!         lock_ObtainMutex(&amp;scp-&gt;mx);
!         code = cm_MapRPCError(code, reqp);
!     }
! 
!     if (code == 0 || Timeout != 0) {
!         fileLock = malloc(sizeof(cm_file_lock_t));
!         fileLock-&gt;LockType = LockType;
!         cm_HoldUser(userp);
!         fileLock-&gt;userp = userp;
!         fileLock-&gt;fid = scp-&gt;fid;
!         fileLock-&gt;LOffset = LOffset;
!         fileLock-&gt;LLength = LLength;
!         fileLock-&gt;flags = (code == 0 ? 0 : CM_FILELOCK_FLAG_WAITING);
!         osi_QAdd(&amp;scp-&gt;fileLocks, &amp;fileLock-&gt;fileq);
!         lock_ObtainWrite(&amp;cm_scacheLock);
!         osi_QAdd(&amp;cm_allFileLocks, &amp;fileLock-&gt;q);
!         lock_ReleaseWrite(&amp;cm_scacheLock);
!         if (code != 0) 
!             *lockpp = fileLock;
!     }
!     return code;
  }
  
  long cm_Unlock(cm_scache_t *scp, unsigned char LockType,
!                 LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
!                 cm_user_t *userp, cm_req_t *reqp)
  {
!     long code = 0;
!     int Which = ((LockType &amp; 0x1) ? LockRead : LockWrite);
!     AFSFid tfid;
!     AFSVolSync volSync;
!     cm_conn_t *connp;
!     cm_file_lock_t *fileLock, *ourLock;
!     osi_queue_t *q, *qq;
!     int anotherReader = 0;
!     int smallLock = 0;
!     int found = 0;
!     struct rx_connection * callp;
! 
!     if (LargeIntegerLessThan(LLength, scp-&gt;length))
!         smallLock = 1;
! 
!     /* Look for our own lock on the list, so as to remove it.
!      * Also, determine if we're the last reader; if not, avoid an RPC.
!      */
!     q = scp-&gt;fileLocks;
!     while (q) {
!         fileLock = (cm_file_lock_t *)
              ((char *) q - offsetof(cm_file_lock_t, fileq));
!         if (!found
!              &amp;&amp; fileLock-&gt;userp == userp
!              &amp;&amp; LargeIntegerEqualTo(fileLock-&gt;LOffset, LOffset)
!              &amp;&amp; LargeIntegerEqualTo(fileLock-&gt;LLength, LLength)) {
!             found = 1;
!             ourLock = fileLock;
!             qq = q;
!         }
!         else if (fileLock-&gt;LockType &amp; 0x1)
!             anotherReader = 1;
!         q = osi_QNext(q);
!     }
! 
!     /* ignore byte ranges */
!     if (smallLock &amp;&amp; !found)
!         return 0;
! 
!     /* don't try to unlock other people's locks */
!     if (!found)
!         return CM_ERROR_WOULDBLOCK;
! 
!     /* discard lock record */
!     osi_QRemove(&amp;scp-&gt;fileLocks, qq);
!     /*
!      * Don't delete it here; let the daemon delete it, to simplify
!      * the daemon's traversal of the list.
!      */
!     lock_ObtainWrite(&amp;cm_scacheLock);
!     ourLock-&gt;flags |= CM_FILELOCK_FLAG_INVALID;
!     cm_ReleaseUser(ourLock-&gt;userp);
!     lock_ReleaseWrite(&amp;cm_scacheLock);
! 
!     if (!anotherReader) {
!         tfid.Volume = scp-&gt;fid.volume;
!         tfid.Vnode = scp-&gt;fid.vnode;
!         tfid.Unique = scp-&gt;fid.unique;
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         do {
!             code = cm_Conn(&amp;scp-&gt;fid, userp, reqp, &amp;connp);
!             if (code) 
                  break;
  
!             callp = cm_GetRxConn(connp);
!             code = RXAFS_ReleaseLock(callp, &amp;tfid, &amp;volSync);
!             rx_PutConnection(callp);
! 
!         } while (cm_Analyze(connp, userp, reqp, &amp;scp-&gt;fid, &amp;volSync,
!                              NULL, NULL, code));
!         code = cm_MapRPCError(code, reqp);
!         lock_ObtainMutex(&amp;scp-&gt;mx);
!     }
! 
!     return code;
  }
  
  void cm_CheckLocks()
  {
!     osi_queue_t *q, *nq;
!     cm_file_lock_t *fileLock;
!     cm_req_t req;
!     AFSFid tfid;
!     AFSVolSync volSync;
!     cm_conn_t *connp;
!     long code;
!     struct rx_connection * callp;
! 
!     cm_InitReq(&amp;req);
! 
!     lock_ObtainWrite(&amp;cm_scacheLock);
!     q = cm_allFileLocks;
!     while (q) {
!         fileLock = (cm_file_lock_t *) q;
!         nq = osi_QNext(q);
!         if (fileLock-&gt;flags &amp; CM_FILELOCK_FLAG_INVALID) {
!             osi_QRemove(&amp;cm_allFileLocks, q);
!             free(fileLock);
!         }
!         else if (!(fileLock-&gt;flags &amp; CM_FILELOCK_FLAG_WAITING)) {
!             tfid.Volume = fileLock-&gt;fid.volume;
!             tfid.Vnode = fileLock-&gt;fid.vnode;
!             tfid.Unique = fileLock-&gt;fid.unique;
!             lock_ReleaseWrite(&amp;cm_scacheLock);
!             do {
!                 code = cm_Conn(&amp;fileLock-&gt;fid, fileLock-&gt;userp,
!                                 &amp;req, &amp;connp);
!                 if (code) 
!                     break;
! 
!                 callp = cm_GetRxConn(connp);
!                 code = RXAFS_ExtendLock(callp, &amp;tfid,
!                                          &amp;volSync);
!                 rx_PutConnection(callp);
! 
!             } while (cm_Analyze(connp, fileLock-&gt;userp, &amp;req,
!                                  &amp;fileLock-&gt;fid, &amp;volSync, NULL, NULL,
!                                  code));
!             code = cm_MapRPCError(code, &amp;req);
!             lock_ObtainWrite(&amp;cm_scacheLock);
!         }
!         q = nq;
!     }
!     lock_ReleaseWrite(&amp;cm_scacheLock);
! }       
  
  long cm_RetryLock(cm_file_lock_t *oldFileLock, int vcp_is_dead)
  {
!     long code;
!     int Which = ((oldFileLock-&gt;LockType &amp; 0x1) ? LockRead : LockWrite);
!     cm_scache_t *scp;
!     AFSFid tfid;
!     AFSVolSync volSync;
!     cm_conn_t *connp;
!     cm_file_lock_t *fileLock;
!     osi_queue_t *q;
!     cm_req_t req;
!     int found = 0;
!     struct rx_connection * callp;
! 
!     if (vcp_is_dead) {
!         code = CM_ERROR_TIMEDOUT;
!         goto handleCode;
!     }
! 
!     cm_InitReq(&amp;req);
! 
!     /* Look for a conflict.  Also, if we are asking for a shared lock,
!      * look for another shared lock, so we don't have to do an RPC.
!      */
!     code = cm_GetSCache(&amp;oldFileLock-&gt;fid, &amp;scp, oldFileLock-&gt;userp, &amp;req);
!     if (code)
!         return code;
! 
!     q = scp-&gt;fileLocks;
!     while (q) {
!         fileLock = (cm_file_lock_t *)
!             ((char *) q - offsetof(cm_file_lock_t, fileq));
!         if ((fileLock-&gt;flags &amp;
!               (CM_FILELOCK_FLAG_INVALID | CM_FILELOCK_FLAG_WAITING))
!              == 0) {
!             if ((oldFileLock-&gt;LockType &amp; 0x1) == 0
!                  || (fileLock-&gt;LockType &amp; 0x1) == 0) {
!                 cm_ReleaseSCache(scp);
!                 return CM_ERROR_WOULDBLOCK;
!             }
!             found = 1;
!         }
!         q = osi_QNext(q);
!     }
! 
!     if (found)
!         code = 0;
!     else {
!         tfid.Volume = oldFileLock-&gt;fid.volume;
!         tfid.Vnode = oldFileLock-&gt;fid.vnode;
!         tfid.Unique = oldFileLock-&gt;fid.unique;
!         do {
!             code = cm_Conn(&amp;oldFileLock-&gt;fid, oldFileLock-&gt;userp,
!                             &amp;req, &amp;connp);
!             if (code) 
!                 break;
! 
!             callp = cm_GetRxConn(connp);
!             code = RXAFS_SetLock(callp, &amp;tfid, Which,
!                                   &amp;volSync);
!             rx_PutConnection(callp);
! 
!         } while (cm_Analyze(connp, oldFileLock-&gt;userp, &amp;req,
!                              &amp;oldFileLock-&gt;fid, &amp;volSync,
!                              NULL, NULL, code));
!         code = cm_MapRPCError(code, &amp;req);
!     }
  
    handleCode:
!     if (code != 0 &amp;&amp; code != CM_ERROR_WOULDBLOCK) {
!         lock_ObtainMutex(&amp;scp-&gt;mx);
!         osi_QRemove(&amp;scp-&gt;fileLocks, &amp;oldFileLock-&gt;fileq);
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!     }
!     lock_ObtainWrite(&amp;cm_scacheLock);
!     if (code == 0)
!         oldFileLock-&gt;flags = 0;
!     else if (code != CM_ERROR_WOULDBLOCK) {
!         oldFileLock-&gt;flags |= CM_FILELOCK_FLAG_INVALID;
!         cm_ReleaseUser(oldFileLock-&gt;userp);
          oldFileLock-&gt;userp = NULL;
!     }
!     lock_ReleaseWrite(&amp;cm_scacheLock);
  
!     return code;
  }
Index: openafs/src/WINNT/afsd/cm_vnodeops.h
diff -c openafs/src/WINNT/afsd/cm_vnodeops.h:1.5 openafs/src/WINNT/afsd/cm_vnodeops.h:1.5.2.3
*** openafs/src/WINNT/afsd/cm_vnodeops.h:1.5	Mon Jun 21 13:25:35 2004
--- openafs/src/WINNT/afsd/cm_vnodeops.h	Mon Oct 18 00:09:26 2004
***************
*** 15,21 ****
  /* parms for attribute setting call */
  typedef struct cm_attr {
  	int mask;
! 	unsigned long clientModTime;
          osi_hyper_t length;
  	int unixModeBits;
          long owner;
--- 15,21 ----
  /* parms for attribute setting call */
  typedef struct cm_attr {
  	int mask;
! 	time_t clientModTime;
          osi_hyper_t length;
  	int unixModeBits;
          long owner;
***************
*** 70,75 ****
--- 70,79 ----
  extern long cm_Lookup(cm_scache_t *dscp, char *namep, long flags,
  	cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp);
  
+ extern long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags,
+                               cm_user_t *userp, cm_req_t *reqp, 
+                               cm_scache_t **outpScpp);
+ 
  extern void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp,
  	cm_user_t *userp, cm_req_t *reqp);
  
***************
*** 104,113 ****
  extern long cm_HandleLink(cm_scache_t *linkScp, struct cm_user *userp,
  	cm_req_t *reqp);
  
  extern long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp,
  	long flags, cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
  
! extern int cm_ExpandSysName(char *inp, char *outp, long outSize);
  
  extern long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp);
  
--- 108,121 ----
  extern long cm_HandleLink(cm_scache_t *linkScp, struct cm_user *userp,
  	cm_req_t *reqp);
  
+ extern long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp,
+     long flags, cm_user_t *userp, cm_req_t *reqp);
+ 
  extern long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp,
  	long flags, cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
  
! extern int cm_ExpandSysName(char *inp, char *outp, long outSize,
!                             unsigned int sysNameIndex);
  
  extern long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp);
  
Index: openafs/src/WINNT/afsd/cm_volume.h
diff -c openafs/src/WINNT/afsd/cm_volume.h:1.3 openafs/src/WINNT/afsd/cm_volume.h:1.3.2.1
*** openafs/src/WINNT/afsd/cm_volume.h:1.3	Wed Aug  4 11:52:56 2004
--- openafs/src/WINNT/afsd/cm_volume.h	Mon Oct 18 00:09:27 2004
***************
*** 20,26 ****
  	struct cm_fid *dotdotFidp;	/* parent of volume root */
      osi_mutex_t mx;
      long flags;			/* by mx */
!     int refCount;			/* by cm_volumeLock */
      cm_serverRef_t *rwServersp;	/* by mx */
      cm_serverRef_t *roServersp;	/* by mx */
      cm_serverRef_t *bkServersp;	/* by mx */
--- 20,26 ----
  	struct cm_fid *dotdotFidp;	/* parent of volume root */
      osi_mutex_t mx;
      long flags;			/* by mx */
!     unsigned long refCount;			/* by cm_volumeLock */
      cm_serverRef_t *rwServersp;	/* by mx */
      cm_serverRef_t *roServersp;	/* by mx */
      cm_serverRef_t *bkServersp;	/* by mx */
Index: openafs/src/WINNT/afsd/ctokens.c
diff -c openafs/src/WINNT/afsd/ctokens.c:1.2 openafs/src/WINNT/afsd/ctokens.c:1.2.20.1
*** openafs/src/WINNT/afsd/ctokens.c:1.2	Sat Nov  4 05:01:41 2000
--- openafs/src/WINNT/afsd/ctokens.c	Mon Oct 18 00:09:27 2004
***************
*** 88,94 ****
  			if (tokenExpireTime &lt;= current_time)
  				printf("[&gt;&gt; Expired &lt;&lt;]\n");
  			else {
! 				expireString = ctime(&amp;tokenExpireTime);
  				expireString += 4;	 /* Skip day of week */
  				expireString[12] = '\0'; /* Omit secs &amp; year */
  				printf("[Expires %s]\n", expireString);
--- 88,95 ----
  			if (tokenExpireTime &lt;= current_time)
  				printf("[&gt;&gt; Expired &lt;&lt;]\n");
  			else {
!                                 time_t t = tokenExpireTime;
! 				expireString = ctime(&amp;t);
  				expireString += 4;	 /* Skip day of week */
  				expireString[12] = '\0'; /* Omit secs &amp; year */
  				printf("[Expires %s]\n", expireString);
Index: openafs/src/WINNT/afsd/fs.c
diff -c openafs/src/WINNT/afsd/fs.c:1.16.2.1 openafs/src/WINNT/afsd/fs.c:1.16.2.3
*** openafs/src/WINNT/afsd/fs.c:1.16.2.1	Mon Aug 23 11:55:02 2004
--- openafs/src/WINNT/afsd/fs.c	Mon Oct 18 00:09:27 2004
***************
*** 609,616 ****
              return FALSE;
          }
  
-         fTested = TRUE;
- 
          dwSize = 0;
          dwSize2 = 0;
  
--- 609,614 ----
***************
*** 645,683 ****
  
              if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &amp;hToken))
              {
!                 /* We'll have to allocate a chunk of memory to store the list of
!                  * groups to which this user belongs; find out how much memory
!                  * we'll need.
!                  */
!                 DWORD dwSize = 0;
!                 PTOKEN_GROUPS pGroups;
!                 
!                 GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &amp;dwSize);
!             
!                 pGroups = (PTOKEN_GROUPS)malloc(dwSize);
!                 
!                 /* Allocate that buffer, and read in the list of groups. */
!                 if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &amp;dwSize))
!                 {
!                     /* Look through the list of group SIDs and see if any of them
!                      * matches the AFS Client Admin group SID.
                       */
!                     size_t iGroup = 0;
!                     for (; (!fAdmin) &amp;&amp; (iGroup &lt; pGroups-&gt;GroupCount); ++iGroup)
                      {
!                         if (EqualSid (psidAdmin, pGroups-&gt;Groups[ iGroup ].Sid)) {
!                             fAdmin = TRUE;
                          }
                      }
                  }
  
!                 if (pGroups)
!                     free(pGroups);
              }
          }
  
          free(psidAdmin);
          free(pszRefDomain);
      }
  
      return fAdmin;
--- 643,718 ----
  
              if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &amp;hToken))
              {
! 
!                 if (!CheckTokenMembership(hToken, psidAdmin, &amp;fAdmin)) {
!                     /* We'll have to allocate a chunk of memory to store the list of
!                      * groups to which this user belongs; find out how much memory
!                      * we'll need.
                       */
!                     DWORD dwSize = 0;
!                     PTOKEN_GROUPS pGroups;
! 
!                     GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &amp;dwSize);
! 
!                     pGroups = (PTOKEN_GROUPS)malloc(dwSize);
! 
!                     /* Allocate that buffer, and read in the list of groups. */
!                     if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &amp;dwSize))
                      {
!                         /* Look through the list of group SIDs and see if any of them
!                          * matches the AFS Client Admin group SID.
!                          */
!                         size_t iGroup = 0;
!                         for (; (!fAdmin) &amp;&amp; (iGroup &lt; pGroups-&gt;GroupCount); ++iGroup)
!                         {
!                             if (EqualSid (psidAdmin, pGroups-&gt;Groups[ iGroup ].Sid)) {
!                                 fAdmin = TRUE;
!                             }
                          }
                      }
+ 
+                     if (pGroups)
+                         free(pGroups);
                  }
  
!                 /* if do not have permission because we were not explicitly listed
!                  * in the Admin Client Group let's see if we are the SYSTEM account
!                  */
!                 if (!fAdmin) {
!                     PTOKEN_USER pTokenUser;
!                     SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
!                     PSID pSidLocalSystem = 0;
!                     DWORD gle;
! 
!                     GetTokenInformation(hToken, TokenUser, NULL, 0, &amp;dwSize);
! 
!                     pTokenUser = (PTOKEN_USER)malloc(dwSize);
! 
!                     if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &amp;dwSize))
!                         gle = GetLastError();
! 
!                     if (AllocateAndInitializeSid( &amp;SIDAuth, 1,
!                                                   SECURITY_LOCAL_SYSTEM_RID,
!                                                   0, 0, 0, 0, 0, 0, 0,
!                                                   &amp;pSidLocalSystem))
!                     {
!                         if (EqualSid(pTokenUser-&gt;User.Sid, pSidLocalSystem)) {
!                             fAdmin = TRUE;
!                         }
! 
!                         FreeSid(pSidLocalSystem);
!                     }
! 
!                     if ( pTokenUser )
!                         free(pTokenUser);
!                 }
              }
          }
  
          free(psidAdmin);
          free(pszRefDomain);
+ 
+         fTested = TRUE;
      }
  
      return fAdmin;
***************
*** 2181,2199 ****
          return 0;
      }
  
! 	input = space;
! 	memcpy(&amp;setp, input, sizeof(afs_int32));
! 	input += sizeof(afs_int32);
! 	if (!setp) {
! 	    fprintf(stderr,"No sysname name value was found\n");
          return 1;
! 	} 
      
      printf("Current sysname%s", setp &gt; 1 ? "s are" : " is");
      for (; setp &gt; 0; --setp ) {
          printf(" \'%s\'", input);
          input += strlen(input) + 1;
! 	}
      printf("\n");
      return 0;
  }
--- 2216,2234 ----
          return 0;
      }
  
!     input = space;
!     memcpy(&amp;setp, input, sizeof(afs_int32));
!     input += sizeof(afs_int32);
!     if (!setp) {
!         fprintf(stderr,"No sysname name value was found\n");
          return 1;
!     } 
      
      printf("Current sysname%s", setp &gt; 1 ? "s are" : " is");
      for (; setp &gt; 0; --setp ) {
          printf(" \'%s\'", input);
          input += strlen(input) + 1;
!     }
      printf("\n");
      return 0;
  }
***************
*** 2447,2453 ****
  	}
  	else {
  	    /* got a ticket */
! 	    if (ttoken.kvno &gt;= 0 &amp;&amp; ttoken.kvno	&lt;= 255)	scIndex	= 2;	/* kerberos */
  	    else {
  		fprintf (stderr, "fs: funny kvno (%d) in ticket, proceeding\n",
  			 ttoken.kvno);
--- 2482,2488 ----
  	}
  	else {
  	    /* got a ticket */
! 	    if (ttoken.kvno &gt;= 0 &amp;&amp; ttoken.kvno	&lt;= 256)	scIndex	= 2;	/* kerberos */
  	    else {
  		fprintf (stderr, "fs: funny kvno (%d) in ticket, proceeding\n",
  			 ttoken.kvno);
***************
*** 2943,2949 ****
  char **argv; {
      register afs_int32 code;
      register struct cmd_syndesc *ts;
!     
  #ifdef	AFS_AIX32_ENV
      /*
       * The following signal action for AIX is necessary so that in case of a 
--- 2978,2984 ----
  char **argv; {
      register afs_int32 code;
      register struct cmd_syndesc *ts;
! 
  #ifdef	AFS_AIX32_ENV
      /*
       * The following signal action for AIX is necessary so that in case of a 
***************
*** 3141,3147 ****
      cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
  
      ts = cmd_CreateSyntax("sysname", SysNameCmd, 0, "get/set sysname (i.e. @sys) value");
!     cmd_AddParm(ts, "-newsys", CMD_SINGLE, CMD_OPTIONAL, "new sysname");
  
      ts = cmd_CreateSyntax("exportafs", ExportAfsCmd, 0, "enable/disable translators to AFS");
      cmd_AddParm(ts, "-type", CMD_SINGLE, 0, "exporter name");
--- 3176,3182 ----
      cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
  
      ts = cmd_CreateSyntax("sysname", SysNameCmd, 0, "get/set sysname (i.e. @sys) value");
!     cmd_AddParm(ts, "-newsys", CMD_LIST, CMD_OPTIONAL, "new sysname");
  
      ts = cmd_CreateSyntax("exportafs", ExportAfsCmd, 0, "enable/disable translators to AFS");
      cmd_AddParm(ts, "-type", CMD_SINGLE, 0, "exporter name");
Index: openafs/src/WINNT/afsd/lanahelper.cpp
diff -c openafs/src/WINNT/afsd/lanahelper.cpp:1.8 openafs/src/WINNT/afsd/lanahelper.cpp:1.8.2.1
*** openafs/src/WINNT/afsd/lanahelper.cpp:1.8	Wed Jul 14 02:00:18 2004
--- openafs/src/WINNT/afsd/lanahelper.cpp	Sun Oct  3 09:35:15 2004
***************
*** 394,399 ****
--- 394,428 ----
      return LANA_INVALID;
  }
  
+ /* Returns TRUE if all adapters are loopback adapters */
+ extern "C" BOOL lana_OnlyLoopback(void)
+ {
+     NCB ncb;
+     LANA_ENUM lana_list;
+     int status;
+     int i;
+ 
+     memset(&amp;ncb, 0, sizeof(ncb));
+     ncb.ncb_command = NCBENUM;
+     ncb.ncb_buffer = (UCHAR *) &amp;lana_list;
+     ncb.ncb_length = sizeof(lana_list);
+     status = Netbios(&amp;ncb);
+     if (status != 0) {
+ #ifndef NOLOGGING
+         afsi_log("Netbios NCBENUM failed: status %ld", status);
+ #endif
+         return FALSE;
+     }
+     for (i = 0; i &lt; lana_list.length; i++) {
+ 	if (!lana_IsLoopback(lana_list.lana[i])) {
+ 	    // Found one non-Loopback adapter
+ 	    return FALSE;
+ 	}
+     }
+     // All adapters are loopback
+     return TRUE;
+ }
+ 
  // Is the given lana a Windows Loopback Adapter?
  // TODO: implement a better check for loopback
  // TODO: also check for proper bindings (IPv4)
Index: openafs/src/WINNT/afsd/lanahelper.h
diff -c openafs/src/WINNT/afsd/lanahelper.h:1.3 openafs/src/WINNT/afsd/lanahelper.h:1.3.2.1
*** openafs/src/WINNT/afsd/lanahelper.h:1.3	Wed Jul 14 02:00:18 2004
--- openafs/src/WINNT/afsd/lanahelper.h	Sun Oct  3 09:35:15 2004
***************
*** 59,64 ****
--- 59,66 ----
  
    lana_number_t lana_FindLoopback(void);
  
+   BOOL lana_OnlyLoopback(void);
+ 
    BOOL lana_IsLoopback(lana_number_t lana);
  
    long lana_GetUncServerNameEx(char *buffer, lana_number_t * pLana, int * pIsGateway, int flags);
Index: openafs/src/WINNT/afsd/smb.c
diff -c openafs/src/WINNT/afsd/smb.c:1.55.2.1 openafs/src/WINNT/afsd/smb.c:1.55.2.3
*** openafs/src/WINNT/afsd/smb.c:1.55.2.1	Wed Aug 18 13:11:22 2004
--- openafs/src/WINNT/afsd/smb.c	Mon Oct 18 00:09:27 2004
***************
*** 7,13 ****
   * directory or online at http://www.openafs.org/dl/license10.html
   */
  
! //#define NOSERVICE 1
  
  #include &lt;afs/param.h&gt;
  #include &lt;afs/stds.h&gt;
--- 7,14 ----
   * directory or online at http://www.openafs.org/dl/license10.html
   */
  
! //#define NOTSERVICE 1
! #define LOG_PACKET 1
  
  #include &lt;afs/param.h&gt;
  #include &lt;afs/stds.h&gt;
***************
*** 189,194 ****
--- 190,198 ----
         *(sizep) = strlen(cm_HostName)
  #endif /* DJGPP */
  
+ #ifdef LOG_PACKET
+ void smb_LogPacket(smb_packet_t *packet);
+ #endif /* LOG_PACKET */
  extern char AFSConfigKeyName[];
  
  char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
***************
*** 201,556 ****
  /* Faux server GUID. This is never checked. */
  GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
  
- /*
-  * Demo expiration
-  *
-  * To build an expiring version, comment out the definition of NOEXPIRE,
-  * and set the definition of EXPIREDATE to the desired value.
-  */
- #define NOEXPIRE 1
- #define EXPIREDATE 834000000		/* Wed Jun 5 1996 */
- 
- 
  char * myCrt_Dispatch(int i)
  {
! 	switch (i)
! 	{
! 	default:
! 		return "unknown SMB op";
! 	case 0x00:
! 		return "(00)ReceiveCoreMakeDir";
! 	case 0x01:
! 		return "(01)ReceiveCoreRemoveDir";
! 	case 0x02:
! 		return "(02)ReceiveCoreOpen";
! 	case 0x03:
! 		return "(03)ReceiveCoreCreate";
! 	case 0x04:
! 		return "(04)ReceiveCoreClose";
! 	case 0x05:
! 		return "(05)ReceiveCoreFlush";
! 	case 0x06:
! 		return "(06)ReceiveCoreUnlink";
! 	case 0x07:
! 		return "(07)ReceiveCoreRename";
! 	case 0x08:
! 		return "(08)ReceiveCoreGetFileAttributes";
! 	case 0x09:
! 		return "(09)ReceiveCoreSetFileAttributes";
! 	case 0x0a:
! 		return "(0a)ReceiveCoreRead";
! 	case 0x0b:
! 		return "(0b)ReceiveCoreWrite";
! 	case 0x0c:
! 		return "(0c)ReceiveCoreLockRecord";
! 	case 0x0d:
! 		return "(0d)ReceiveCoreUnlockRecord";
! 	case 0x0e:
! 		return "(0e)SendCoreBadOp";
! 	case 0x0f:
! 		return "(0f)ReceiveCoreCreate";
! 	case 0x10:
! 		return "(10)ReceiveCoreCheckPath";
! 	case 0x11:
! 		return "(11)SendCoreBadOp";
! 	case 0x12:
! 		return "(12)ReceiveCoreSeek";
! 	case 0x1a:
! 		return "(1a)ReceiveCoreReadRaw";
! 	case 0x1d:
! 		return "(1d)ReceiveCoreWriteRawDummy";
! 	case 0x22:
! 		return "(22)ReceiveV3SetAttributes";
! 	case 0x23:
! 		return "(23)ReceiveV3GetAttributes";
! 	case 0x24:
! 		return "(24)ReceiveV3LockingX";
! 	case 0x25:
! 		return "(25)ReceiveV3Trans";
! 	case 0x26:
! 		return "(26)ReceiveV3Trans[aux]";
! 	case 0x29:
! 		return "(29)SendCoreBadOp";
! 	case 0x2b:
! 		return "(2b)ReceiveCoreEcho";
! 	case 0x2d:
! 		return "(2d)ReceiveV3OpenX";
! 	case 0x2e:
! 		return "(2e)ReceiveV3ReadX";
! 	case 0x32:
! 		return "(32)ReceiveV3Tran2A";
! 	case 0x33:
! 		return "(33)ReceiveV3Tran2A[aux]";
! 	case 0x34:
! 		return "(34)ReceiveV3FindClose";
! 	case 0x35:
! 		return "(35)ReceiveV3FindNotifyClose";
! 	case 0x70:
! 		return "(70)ReceiveCoreTreeConnect";
! 	case 0x71:
! 		return "(71)ReceiveCoreTreeDisconnect";
! 	case 0x72:
! 		return "(72)ReceiveNegotiate";
! 	case 0x73:
! 		return "(73)ReceiveV3SessionSetupX";
! 	case 0x74:
! 		return "(74)ReceiveV3UserLogoffX";
! 	case 0x75:
! 		return "(75)ReceiveV3TreeConnectX";
! 	case 0x80:
! 		return "(80)ReceiveCoreGetDiskAttributes";
! 	case 0x81:
! 		return "(81)ReceiveCoreSearchDir";
! 	case 0xA0:
! 		return "(A0)ReceiveNTTransact";
! 	case 0xA2:
! 		return "(A2)ReceiveNTCreateX";
! 	case 0xA4:
! 		return "(A4)ReceiveNTCancel";
! 	case 0xc0:
! 		return "(c0)SendCoreBadOp";
! 	case 0xc1:
! 		return "(c1)SendCoreBadOp";
! 	case 0xc2:
! 		return "(c2)SendCoreBadOp";
! 	case 0xc3:
! 		return "(c3)SendCoreBadOp";
! 	}
! }
  
  char * myCrt_2Dispatch(int i)
  {
! 	switch (i)
! 	{
! 	default:
! 		return "unknown SMB op-2";
! 	case 0:
! 		return "S(00)CreateFile";
! 	case 1:
! 		return "S(01)FindFirst";
! 	case 2:
! 		return "S(02)FindNext";	/* FindNext */
! 	case 3:
! 		return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
! 	case 4:
! 		return "S(04)??";
! 	case 5:
! 		return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
! 	case 6:
! 		return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
! 	case 7:
! 		return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
! 	case 8:
! 		return "S(08)??_ReceiveTran2SetFileInfo";
! 	case 9:
! 		return "S(09)??_ReceiveTran2FSCTL";
! 	case 10:
! 		return "S(0a)_ReceiveTran2IOCTL";
! 	case 11:
! 		return "S(0b)_ReceiveTran2FindNotifyFirst";
! 	case 12:
! 		return "S(0c)_ReceiveTran2FindNotifyNext";
! 	case 13:
! 		return "S(0d)CreateDirectory_ReceiveTran2MKDir";
! 	}
! }
  
  char * myCrt_RapDispatch(int i)
  {
! 	switch(i)
! 	{
! 	default:
! 		return "unknown RAP OP";
! 	case 0:
! 		return "RAP(0)NetShareEnum";
! 	case 1:
! 		return "RAP(1)NetShareGetInfo";
! 	case 13:
! 		return "RAP(13)NetServerGetInfo";
! 	case 63:
! 		return "RAP(63)NetWkStaGetInfo";
! 	}
! }
  
  /* scache must be locked */
  unsigned int smb_Attributes(cm_scache_t *scp)
  {
! 	unsigned int attrs;
  
! 	if (scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY
! 		|| scp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT)
! 		attrs = SMB_ATTR_DIRECTORY;
! 	else
! 		attrs = 0;
! 
! 	/*
! 	 * We used to mark a file RO if it was in an RO volume, but that
! 	 * turns out to be impolitic in NT.  See defect 10007.
! 	 */
  #ifdef notdef
! 	if ((scp-&gt;unixModeBits &amp; 0222) == 0 || (scp-&gt;flags &amp; CM_SCACHEFLAG_RO))
  #endif
  	if ((scp-&gt;unixModeBits &amp; 0222) == 0)
! 		attrs |= SMB_ATTR_READONLY;	/* turn on read-only flag */
  
! 	return attrs;
  }
  
  /* Check if the named file/dir is a dotfile/dotdir */
  /* String pointed to by lastComp can have leading slashes, but otherwise should have
     no other patch components */
  unsigned int smb_IsDotFile(char *lastComp) {
! 	char *s;
! 	if(lastComp) {
! 		/* skip over slashes */
          for(s=lastComp;*s &amp;&amp; (*s == '\\' || *s == '/'); s++);
! 	}
! 	else
! 		return 0;
  
      /* nulls, curdir and parent dir doesn't count */
! 	if(!*s) return 0;
! 	if(*s == '.') {
! 		if(!*(s + 1)) return 0;
! 		if(*(s+1) == '.' &amp;&amp; !*(s + 2)) return 0;
! 		return 1;
! 	}
! 	return 0;
  }
  
  static int ExtractBits(WORD bits, short start, short len)
  {
! 	int end;
! 	WORD num;
  
! 	end = start + len;
          
! 	num = bits &lt;&lt; (16 - end);
! 	num = num &gt;&gt; ((16 - end) + start);
  
! 	return (int)num;
  }
  
  #ifndef DJGPP
  void ShowUnixTime(char *FuncName, time_t unixTime)
  {
! 	FILETIME ft;
! 	WORD wDate, wTime;
  
! 	smb_LargeSearchTimeFromUnixTime(&amp;ft, unixTime);
!                 
! 	if (!FileTimeToDosDateTime(&amp;ft, &amp;wDate, &amp;wTime))
! 		osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
! 	else {
! 		int day, month, year, sec, min, hour;
! 		char msg[256];
! 
! 		day = ExtractBits(wDate, 0, 5);
! 		month = ExtractBits(wDate, 5, 4);
! 		year = ExtractBits(wDate, 9, 7) + 1980;
! 
! 		sec = ExtractBits(wTime, 0, 5);
! 		min = ExtractBits(wTime, 5, 6);
! 		hour = ExtractBits(wTime, 11, 5);
! 
! 		sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
! 		osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
! 	}
! }
  #endif /* DJGPP */
  
  #ifndef DJGPP
  /* Determine if we are observing daylight savings time */
  void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
  {
! 	TIME_ZONE_INFORMATION timeZoneInformation;
! 	SYSTEMTIME utc, local, localDST;
  
! 	/* Get the time zone info. NT uses this to calc if we are in DST. */
! 	GetTimeZoneInformation(&amp;timeZoneInformation);
!  
! 	/* Return the daylight bias */
! 	*pDstBias = timeZoneInformation.DaylightBias;
  
! 	/* Return the bias */
! 	*pBias = timeZoneInformation.Bias;
  
! 	/* Now determine if DST is being observed */
  
! 	/* Get the UTC (GMT) time */
! 	GetSystemTime(&amp;utc);
! 
! 	/* Convert UTC time to local time using the time zone info.  If we are
! 	   observing DST, the calculated local time will include this. 
! 	*/
! 	SystemTimeToTzSpecificLocalTime(&amp;timeZoneInformation, &amp;utc, &amp;localDST);
! 
! 	/* Set the daylight bias to 0.  The daylight bias is the amount of change
! 	   in time that we use for daylight savings time.  By setting this to 0
! 	   we cause there to be no change in time during daylight savings time. 
! 	*/
! 	timeZoneInformation.DaylightBias = 0;
! 
! 	/* Convert the utc time to local time again, but this time without any
! 	   adjustment for daylight savings time. 
! 	*/
! 	SystemTimeToTzSpecificLocalTime(&amp;timeZoneInformation, &amp;utc, &amp;local);
! 
! 	/* If the two times are different, then it means that the localDST that
! 	   we calculated includes the daylight bias, and therefore we are
! 	   observing daylight savings time.
! 	*/
! 	*pDST = localDST.wHour != local.wHour;
! }
  #else
  /* Determine if we are observing daylight savings time */
  void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
  {
! 	struct timeb t;
  
! 	ftime(&amp;t);
! 	*pDST = t.dstflag;
! 	*pDstBias = -60;    /* where can this be different? */
! 	*pBias = t.timezone;
! }
  #endif /* DJGPP */
   
  
  void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
  {
! 	BOOL dst;       /* Will be TRUE if observing DST */
! 	LONG dstBias;   /* Offset from local time if observing DST */
! 	LONG bias;      /* Offset from GMT for local time */
! 
! 	/*
! 	 * This function will adjust the last write time to compensate
! 	 * for two bugs in the smb client:
! 	 *
! 	 *    1) During Daylight Savings Time, the LastWriteTime is ahead
! 	 *       in time by the DaylightBias (ignoring the sign - the
! 	 *       DaylightBias is always stored as a negative number).  If
! 	 *       the DaylightBias is -60, then the LastWriteTime will be
! 	 *       ahead by 60 minutes.
! 	 *
! 	 *    2) If the local time zone is a positive offset from GMT, then
! 	 *       the LastWriteTime will be the correct local time plus the
! 	 *       Bias (ignoring the sign - a positive offset from GMT is
! 	 *       always stored as a negative Bias).  If the Bias is -120,
! 	 *       then the LastWriteTime will be ahead by 120 minutes.
! 	 *
! 	 *    These bugs can occur at the same time.
! 	 */
! 
! 	GetTimeZoneInfo(&amp;dst, &amp;dstBias, &amp;bias);
! 
! 	/* First adjust for DST */
! 	if (dst)
! 		*pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
! 
! 	/* Now adjust for a positive offset from GMT (a negative bias). */
! 	if (bias &lt; 0)
! 		*pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
! }		
  
  /*
   * Calculate the difference (in seconds) between local time and GMT.
--- 205,569 ----
  /* Faux server GUID. This is never checked. */
  GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
  
  char * myCrt_Dispatch(int i)
  {
!     switch (i)
!     {
!     case 0x00:
!         return "(00)ReceiveCoreMakeDir";
!     case 0x01:
!         return "(01)ReceiveCoreRemoveDir";
!     case 0x02:
!         return "(02)ReceiveCoreOpen";
!     case 0x03:
!         return "(03)ReceiveCoreCreate";
!     case 0x04:
!         return "(04)ReceiveCoreClose";
!     case 0x05:
!         return "(05)ReceiveCoreFlush";
!     case 0x06:
!         return "(06)ReceiveCoreUnlink";
!     case 0x07:
!         return "(07)ReceiveCoreRename";
!     case 0x08:
!         return "(08)ReceiveCoreGetFileAttributes";
!     case 0x09:
!         return "(09)ReceiveCoreSetFileAttributes";
!     case 0x0a:
!         return "(0a)ReceiveCoreRead";
!     case 0x0b:
!         return "(0b)ReceiveCoreWrite";
!     case 0x0c:
!         return "(0c)ReceiveCoreLockRecord";
!     case 0x0d:
!         return "(0d)ReceiveCoreUnlockRecord";
!     case 0x0e:
!         return "(0e)SendCoreBadOp";
!     case 0x0f:
!         return "(0f)ReceiveCoreCreate";
!     case 0x10:
!         return "(10)ReceiveCoreCheckPath";
!     case 0x11:
!         return "(11)SendCoreBadOp";
!     case 0x12:
!         return "(12)ReceiveCoreSeek";
!     case 0x1a:
!         return "(1a)ReceiveCoreReadRaw";
!     case 0x1d:
!         return "(1d)ReceiveCoreWriteRawDummy";
!     case 0x22:
!         return "(22)ReceiveV3SetAttributes";
!     case 0x23:
!         return "(23)ReceiveV3GetAttributes";
!     case 0x24:
!         return "(24)ReceiveV3LockingX";
!     case 0x25:
!         return "(25)ReceiveV3Trans";
!     case 0x26:
!         return "(26)ReceiveV3Trans[aux]";
!     case 0x29:
!         return "(29)SendCoreBadOp";
!     case 0x2b:
!         return "(2b)ReceiveCoreEcho";
!     case 0x2d:
!         return "(2d)ReceiveV3OpenX";
!     case 0x2e:
!         return "(2e)ReceiveV3ReadX";
!     case 0x32:
!         return "(32)ReceiveV3Tran2A";
!     case 0x33:
!         return "(33)ReceiveV3Tran2A[aux]";
!     case 0x34:
!         return "(34)ReceiveV3FindClose";
!     case 0x35:
!         return "(35)ReceiveV3FindNotifyClose";
!     case 0x70:
!         return "(70)ReceiveCoreTreeConnect";
!     case 0x71:
!         return "(71)ReceiveCoreTreeDisconnect";
!     case 0x72:
!         return "(72)ReceiveNegotiate";
!     case 0x73:
!         return "(73)ReceiveV3SessionSetupX";
!     case 0x74:
!         return "(74)ReceiveV3UserLogoffX";
!     case 0x75:
!         return "(75)ReceiveV3TreeConnectX";
!     case 0x80:
!         return "(80)ReceiveCoreGetDiskAttributes";
!     case 0x81:
!         return "(81)ReceiveCoreSearchDir";
!     case 0x82:
!         return "(82)Find";
!     case 0x83:
!         return "(83)FindUnique";
!     case 0x84:
!         return "(84)FindClose";
!     case 0xA0:
!         return "(A0)ReceiveNTTransact";
!     case 0xA2:
!         return "(A2)ReceiveNTCreateX";
!     case 0xA4:
!         return "(A4)ReceiveNTCancel";
!     case 0xA5:
!         return "(A5)ReceiveNTRename";
!     case 0xc0:
!         return "(C0)OpenPrintFile";
!     case 0xc1:
!         return "(C1)WritePrintFile";
!     case 0xc2:
!         return "(C2)ClosePrintFile";
!     case 0xc3:
!         return "(C3)GetPrintQueue";
!     case 0xd8:
!         return "(D8)ReadBulk";
!     case 0xd9:
!         return "(D9)WriteBulk";
!     case 0xda:
!         return "(DA)WriteBulkData";
!     default:
!         return "unknown SMB op";
!     }
! }       
  
  char * myCrt_2Dispatch(int i)
  {
!     switch (i)
!     {
!     default:
!         return "unknown SMB op-2";
!     case 0:
!         return "S(00)CreateFile";
!     case 1:
!         return "S(01)FindFirst";
!     case 2:
!         return "S(02)FindNext";	/* FindNext */
!     case 3:
!         return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
!     case 4:
!         return "S(04)??";
!     case 5:
!         return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
!     case 6:
!         return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
!     case 7:
!         return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
!     case 8:
!         return "S(08)??_ReceiveTran2SetFileInfo";
!     case 9:
!         return "S(09)??_ReceiveTran2FSCTL";
!     case 10:
!         return "S(0a)_ReceiveTran2IOCTL";
!     case 11:
!         return "S(0b)_ReceiveTran2FindNotifyFirst";
!     case 12:
!         return "S(0c)_ReceiveTran2FindNotifyNext";
!     case 13:
!         return "S(0d)_ReceiveTran2CreateDirectory";
!     case 14:
!         return "S(0e)_ReceiveTran2SessionSetup";
!     }
! }       
  
  char * myCrt_RapDispatch(int i)
  {
!     switch(i)
!     {
!     default:
!         return "unknown RAP OP";
!     case 0:
!         return "RAP(0)NetShareEnum";
!     case 1:
!         return "RAP(1)NetShareGetInfo";
!     case 13:
!         return "RAP(13)NetServerGetInfo";
!     case 63:
!         return "RAP(63)NetWkStaGetInfo";
!     }
! }       
  
  /* scache must be locked */
  unsigned int smb_Attributes(cm_scache_t *scp)
  {
!     unsigned int attrs;
! 
!     if (scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY
!          || scp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT)
!         attrs = SMB_ATTR_DIRECTORY;
!     else
!         attrs = 0;
  
!     /*
!      * We used to mark a file RO if it was in an RO volume, but that
!      * turns out to be impolitic in NT.  See defect 10007.
!      */
  #ifdef notdef
!     if ((scp-&gt;unixModeBits &amp; 0222) == 0 || (scp-&gt;flags &amp; CM_SCACHEFLAG_RO))
  #endif
  	if ((scp-&gt;unixModeBits &amp; 0222) == 0)
!             attrs |= SMB_ATTR_READONLY;	/* turn on read-only flag */
  
!     return attrs;
  }
  
  /* Check if the named file/dir is a dotfile/dotdir */
  /* String pointed to by lastComp can have leading slashes, but otherwise should have
     no other patch components */
  unsigned int smb_IsDotFile(char *lastComp) {
!     char *s;
!     if(lastComp) {
!         /* skip over slashes */
          for(s=lastComp;*s &amp;&amp; (*s == '\\' || *s == '/'); s++);
!     }
!     else
!         return 0;
  
      /* nulls, curdir and parent dir doesn't count */
!     if (!*s) 
!         return 0;
!     if (*s == '.') {
!         if (!*(s + 1)) 
!             return 0;
!         if(*(s+1) == '.' &amp;&amp; !*(s + 2)) 
!             return 0;
!         return 1;
!     }
!     return 0;
  }
  
  static int ExtractBits(WORD bits, short start, short len)
  {
!     int end;
!     WORD num;
  
!     end = start + len;
          
!     num = bits &lt;&lt; (16 - end);
!     num = num &gt;&gt; ((16 - end) + start);
  
!     return (int)num;
  }
  
  #ifndef DJGPP
  void ShowUnixTime(char *FuncName, time_t unixTime)
  {
!     FILETIME ft;
!     WORD wDate, wTime;
  
!     smb_LargeSearchTimeFromUnixTime(&amp;ft, unixTime);
! 
!     if (!FileTimeToDosDateTime(&amp;ft, &amp;wDate, &amp;wTime))
!         osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
!     else {
!         int day, month, year, sec, min, hour;
!         char msg[256];
! 
!         day = ExtractBits(wDate, 0, 5);
!         month = ExtractBits(wDate, 5, 4);
!         year = ExtractBits(wDate, 9, 7) + 1980;
! 
!         sec = ExtractBits(wTime, 0, 5);
!         min = ExtractBits(wTime, 5, 6);
!         hour = ExtractBits(wTime, 11, 5);
! 
!         sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
!         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
!     }
! }       
  #endif /* DJGPP */
  
  #ifndef DJGPP
  /* Determine if we are observing daylight savings time */
  void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
  {
!     TIME_ZONE_INFORMATION timeZoneInformation;
!     SYSTEMTIME utc, local, localDST;
  
!     /* Get the time zone info. NT uses this to calc if we are in DST. */
!     GetTimeZoneInformation(&amp;timeZoneInformation);
  
!     /* Return the daylight bias */
!     *pDstBias = timeZoneInformation.DaylightBias;
  
!     /* Return the bias */
!     *pBias = timeZoneInformation.Bias;
  
!     /* Now determine if DST is being observed */
! 
!     /* Get the UTC (GMT) time */
!     GetSystemTime(&amp;utc);
! 
!     /* Convert UTC time to local time using the time zone info.  If we are
!        observing DST, the calculated local time will include this. 
!      */
!     SystemTimeToTzSpecificLocalTime(&amp;timeZoneInformation, &amp;utc, &amp;localDST);
! 
!     /* Set the daylight bias to 0.  The daylight bias is the amount of change
!      * in time that we use for daylight savings time.  By setting this to 0
!      * we cause there to be no change in time during daylight savings time. 
!      */
!     timeZoneInformation.DaylightBias = 0;
! 
!     /* Convert the utc time to local time again, but this time without any
!        adjustment for daylight savings time. 
!        */
!     SystemTimeToTzSpecificLocalTime(&amp;timeZoneInformation, &amp;utc, &amp;local);
! 
!     /* If the two times are different, then it means that the localDST that
!        we calculated includes the daylight bias, and therefore we are
!        observing daylight savings time.
!      */
!     *pDST = localDST.wHour != local.wHour;
! }       
  #else
  /* Determine if we are observing daylight savings time */
  void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
  {
!     struct timeb t;
  
!     ftime(&amp;t);
!     *pDST = t.dstflag;
!     *pDstBias = -60;    /* where can this be different? */
!     *pBias = t.timezone;
! }       
  #endif /* DJGPP */
   
  
  void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
  {
!     BOOL dst;       /* Will be TRUE if observing DST */
!     LONG dstBias;   /* Offset from local time if observing DST */
!     LONG bias;      /* Offset from GMT for local time */
! 
!     /*
!      * This function will adjust the last write time to compensate
!      * for two bugs in the smb client:
!      *
!      *    1) During Daylight Savings Time, the LastWriteTime is ahead
!      *       in time by the DaylightBias (ignoring the sign - the
!      *       DaylightBias is always stored as a negative number).  If
!      *       the DaylightBias is -60, then the LastWriteTime will be
!      *       ahead by 60 minutes.
!      *
!      *    2) If the local time zone is a positive offset from GMT, then
!      *       the LastWriteTime will be the correct local time plus the
!      *       Bias (ignoring the sign - a positive offset from GMT is
!      *       always stored as a negative Bias).  If the Bias is -120,
!      *       then the LastWriteTime will be ahead by 120 minutes.
!      *
!      *    These bugs can occur at the same time.
!      */
! 
!     GetTimeZoneInfo(&amp;dst, &amp;dstBias, &amp;bias);
! 
!     /* First adjust for DST */
!     if (dst)
!         *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
! 
!     /* Now adjust for a positive offset from GMT (a negative bias). */
!     if (bias &lt; 0)
!         *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
! }	        	
  
  /*
   * Calculate the difference (in seconds) between local time and GMT.
***************
*** 559,692 ****
  static void
  smb_CalculateNowTZ()
  {
! 	time_t t;
! 	struct tm gmt_tm, local_tm;
! 	int days, hours, minutes, seconds;
! 
! 	t = time(NULL);
! 	gmt_tm = *(gmtime(&amp;t));
! 	local_tm = *(localtime(&amp;t));
  
! 	days = local_tm.tm_yday - gmt_tm.tm_yday;
! 	hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
  #ifdef COMMENT
          /* There is a problem with DST immediately after the time change
!          * which may continue to exist until the machine is rebooted
           */
          - (local_tm.tm_isdst ? 1 : 0)
  #endif /* COMMENT */
!         ;
! 	minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
! 	seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
  
! 	smb_NowTZ = seconds;
  }
  
  #ifndef DJGPP
  void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
  {
! 	struct tm *ltp;
! 	SYSTEMTIME stm;
! 	struct tm localJunk;
! 	time_t ersatz_unixTime;
! 
! 	/*
! 	 * Must use kludge-GMT instead of real GMT.
! 	 * kludge-GMT is computed by adding time zone difference to localtime.
! 	 *
! 	 * real GMT would be:
! 	 * ltp = gmtime(&amp;unixTime);
! 	 */
! 	ersatz_unixTime = unixTime - smb_NowTZ;
! 	ltp = localtime(&amp;ersatz_unixTime);
! 
! 	/* if we fail, make up something */
! 	if (!ltp) {
! 		ltp = &amp;localJunk;
! 		localJunk.tm_year = 89 - 20;
! 		localJunk.tm_mon = 4;
! 		localJunk.tm_mday = 12;
! 		localJunk.tm_hour = 0;
! 		localJunk.tm_min = 0;
! 		localJunk.tm_sec = 0;
! 	}
! 
! 	stm.wYear = ltp-&gt;tm_year + 1900;
! 	stm.wMonth = ltp-&gt;tm_mon + 1;
! 	stm.wDayOfWeek = ltp-&gt;tm_wday;
! 	stm.wDay = ltp-&gt;tm_mday;
! 	stm.wHour = ltp-&gt;tm_hour;
! 	stm.wMinute = ltp-&gt;tm_min;
! 	stm.wSecond = ltp-&gt;tm_sec;
! 	stm.wMilliseconds = 0;
  
! 	SystemTimeToFileTime(&amp;stm, largeTimep);
  }
  #else /* DJGPP */
  void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
  {
! 	/* unixTime: seconds since 1/1/1970 00:00:00 GMT */
! 	/* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
! 	LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
! 	LARGE_INTEGER ut;
! 	int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
! 
! 	/* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
! 	*ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
!                                    * 24 * 60);
! 	*ft = LargeIntegerMultiplyByLong(*ft, 60);
! 	*ft = LargeIntegerMultiplyByLong(*ft, 10000000);
! 
! 	/* add unix time */
! 	ut = ConvertLongToLargeInteger(unixTime);
! 	ut = LargeIntegerMultiplyByLong(ut, 10000000);
! 	*ft = LargeIntegerAdd(*ft, ut);
! }
  #endif /* !DJGPP */
  
  #ifndef DJGPP
  void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
  {
! 	SYSTEMTIME stm;
! 	struct tm lt;
! 	long save_timezone;
! 
! 	FileTimeToSystemTime(largeTimep, &amp;stm);
! 
! 	lt.tm_year = stm.wYear - 1900;
! 	lt.tm_mon = stm.wMonth - 1;
! 	lt.tm_wday = stm.wDayOfWeek;
! 	lt.tm_mday = stm.wDay;
! 	lt.tm_hour = stm.wHour;
! 	lt.tm_min = stm.wMinute;
! 	lt.tm_sec = stm.wSecond;
! 	lt.tm_isdst = -1;
! 
! 	save_timezone = _timezone;
! 	_timezone += smb_NowTZ;
! 	*unixTimep = mktime(&amp;lt);
! 	_timezone = save_timezone;
! }
  #else /* DJGPP */
  void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
  {
! 	/* unixTime: seconds since 1/1/1970 00:00:00 GMT */
! 	/* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
! 	LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
! 	LARGE_INTEGER a;
! 	int leap_years = 89;
! 
! 	/* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
! 	a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
! 	a = LargeIntegerMultiplyByLong(a, 60);
! 	a = LargeIntegerMultiplyByLong(a, 10000000);
! 
! 	/* subtract it from ft */
! 	a = LargeIntegerSubtract(*ft, a);
! 
! 	/* divide down to seconds */
! 	*unixTimep = LargeIntegerDivideByLong(a, 10000000);
! }
  #endif /* !DJGPP */
  
  void smb_SearchTimeFromUnixTime(long *dosTimep, time_t unixTime)
--- 572,705 ----
  static void
  smb_CalculateNowTZ()
  {
!     time_t t;
!     struct tm gmt_tm, local_tm;
!     int days, hours, minutes, seconds;
! 
!     t = time(NULL);
!     gmt_tm = *(gmtime(&amp;t));
!     local_tm = *(localtime(&amp;t));
  
!     days = local_tm.tm_yday - gmt_tm.tm_yday;
!     hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
  #ifdef COMMENT
          /* There is a problem with DST immediately after the time change
!         * which may continue to exist until the machine is rebooted
           */
          - (local_tm.tm_isdst ? 1 : 0)
  #endif /* COMMENT */
!             ;
!     minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min; 
!     seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
  
!     smb_NowTZ = seconds;
  }
  
  #ifndef DJGPP
  void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
  {
!     struct tm *ltp;
!     SYSTEMTIME stm;
!     struct tm localJunk;
!     time_t ersatz_unixTime;
! 
!     /*
!      * Must use kludge-GMT instead of real GMT.
!      * kludge-GMT is computed by adding time zone difference to localtime.
!      *
!      * real GMT would be:
!      * ltp = gmtime(&amp;unixTime);
!      */
!     ersatz_unixTime = unixTime - smb_NowTZ;
!     ltp = localtime(&amp;ersatz_unixTime);
! 
!     /* if we fail, make up something */
!     if (!ltp) {
!         ltp = &amp;localJunk;
!         localJunk.tm_year = 89 - 20;
!         localJunk.tm_mon = 4;
!         localJunk.tm_mday = 12;
!         localJunk.tm_hour = 0;
!         localJunk.tm_min = 0;
!         localJunk.tm_sec = 0;
!     }
  
!     stm.wYear = ltp-&gt;tm_year + 1900;
!     stm.wMonth = ltp-&gt;tm_mon + 1;
!     stm.wDayOfWeek = ltp-&gt;tm_wday;
!     stm.wDay = ltp-&gt;tm_mday;
!     stm.wHour = ltp-&gt;tm_hour;
!     stm.wMinute = ltp-&gt;tm_min;
!     stm.wSecond = ltp-&gt;tm_sec;
!     stm.wMilliseconds = 0;
! 
!     SystemTimeToFileTime(&amp;stm, largeTimep);
  }
  #else /* DJGPP */
  void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
  {
!     /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
!     /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
!     LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
!     LARGE_INTEGER ut;
!     int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
! 
!     /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
!     *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
!                                      * 24 * 60);
!     *ft = LargeIntegerMultiplyByLong(*ft, 60);
!     *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
! 
!     /* add unix time */
!     ut = ConvertLongToLargeInteger(unixTime);
!     ut = LargeIntegerMultiplyByLong(ut, 10000000);
!     *ft = LargeIntegerAdd(*ft, ut);
! }       
  #endif /* !DJGPP */
  
  #ifndef DJGPP
  void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
  {
!     SYSTEMTIME stm;
!     struct tm lt;
!     long save_timezone;
! 
!     FileTimeToSystemTime(largeTimep, &amp;stm);
! 
!     lt.tm_year = stm.wYear - 1900;
!     lt.tm_mon = stm.wMonth - 1;
!     lt.tm_wday = stm.wDayOfWeek;
!     lt.tm_mday = stm.wDay;
!     lt.tm_hour = stm.wHour;
!     lt.tm_min = stm.wMinute;
!     lt.tm_sec = stm.wSecond;
!     lt.tm_isdst = -1;
! 
!     save_timezone = _timezone;
!     _timezone += smb_NowTZ;
!     *unixTimep = mktime(&amp;lt);
!     _timezone = save_timezone;
! }       
  #else /* DJGPP */
  void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
  {
!     /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
!     /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
!     LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
!     LARGE_INTEGER a;
!     int leap_years = 89;
! 
!     /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
!     a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
!     a = LargeIntegerMultiplyByLong(a, 60);
!     a = LargeIntegerMultiplyByLong(a, 10000000);
! 
!     /* subtract it from ft */
!     a = LargeIntegerSubtract(*ft, a);
! 
!     /* divide down to seconds */
!     *unixTimep = LargeIntegerDivideByLong(a, 10000000);
! }       
  #endif /* !DJGPP */
  
  void smb_SearchTimeFromUnixTime(long *dosTimep, time_t unixTime)
***************
*** 717,999 ****
  
  void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
  {
! 	unsigned short dosDate;
! 	unsigned short dosTime;
! 	struct tm localTm;
!         
! 	dosDate = searchTime &amp; 0xffff;
! 	dosTime = (searchTime &gt;&gt; 16) &amp; 0xffff;
!         
! 	localTm.tm_year = 80 + ((dosDate&gt;&gt;9) &amp; 0x3f);
! 	localTm.tm_mon = ((dosDate &gt;&gt; 5) &amp; 0xf) - 1;	/* January is 0 in localTm */
! 	localTm.tm_mday = (dosDate) &amp; 0x1f;
! 	localTm.tm_hour = (dosTime&gt;&gt;11) &amp; 0x1f;
! 	localTm.tm_min = (dosTime &gt;&gt; 5) &amp; 0x3f;
! 	localTm.tm_sec = (dosTime &amp; 0x1f) * 2;
! 	localTm.tm_isdst = -1;				/* compute whether DST in effect */
  
! 	*unixTimep = mktime(&amp;localTm);
  }
  
  void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
  {
! 	*dosUTimep = unixTime - smb_localZero;
  }
  
  void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
  {
  #ifndef DJGPP
! 	*unixTimep = dosTime + smb_localZero;
  #else /* DJGPP */
! 	/* dosTime seems to be already adjusted for GMT */
! 	*unixTimep = dosTime;
  #endif /* !DJGPP */
  }
  
  smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
  {
! 	smb_vc_t *vcp;
  
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	for(vcp = smb_allVCsp; vcp; vcp=vcp-&gt;nextp) {
! 		if (lsn == vcp-&gt;lsn &amp;&amp; lana == vcp-&gt;lana) {
! 			vcp-&gt;refCount++;
! 			break;
! 		}
! 	}
! 	if (!vcp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
! 		vcp = malloc(sizeof(*vcp));
! 		memset(vcp, 0, sizeof(*vcp));
          vcp-&gt;vcID = numVCs++;
! 		vcp-&gt;refCount = 1;
! 		vcp-&gt;tidCounter = 1;
! 		vcp-&gt;fidCounter = 1;
! 		vcp-&gt;uidCounter = 1;  /* UID 0 is reserved for blank user */
! 		vcp-&gt;nextp = smb_allVCsp;
! 		smb_allVCsp = vcp;
! 		lock_InitializeMutex(&amp;vcp-&gt;mx, "vc_t mutex");
! 		vcp-&gt;lsn = lsn;
! 		vcp-&gt;lana = lana;
          vcp-&gt;secCtx = NULL;
  
! 		if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
              /* We must obtain a challenge for extended auth 
               * in case the client negotiates smb v3 
               */
              NTSTATUS nts,ntsEx;
! 			MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
! 			PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
! 			ULONG lsaRespSize;
  
! 			lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
  
! 			nts = LsaCallAuthenticationPackage( smb_lsaHandle,
                                                  smb_lsaSecPackage,
                                                  &amp;lsaReq,
                                                  sizeof(lsaReq),
                                                  &amp;lsaResp,
                                                  &amp;lsaRespSize,
                                                  &amp;ntsEx);
! 			osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
  
! 			memcpy(vcp-&gt;encKey, lsaResp-&gt;ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
              LsaFreeReturnBuffer(lsaResp);
! 		}
! 		else
! 			memset(vcp-&gt;encKey, 0, MSV1_0_CHALLENGE_LENGTH);
! 	}
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! 	return vcp;
  }
  
  int smb_IsStarMask(char *maskp)
  {
! 	int i;
! 	char tc;
          
! 	for(i=0; i&lt;11; i++) {
! 		tc = *maskp++;
! 		if (tc == '?' || tc == '*' || tc == '&gt;') return 1;        
! 	}	
! 	return 0;
  }
  
  void smb_ReleaseVC(smb_vc_t *vcp)
  {
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	osi_assert(vcp-&gt;refCount-- &gt; 0);
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! }
  
  void smb_HoldVC(smb_vc_t *vcp)
  {
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	vcp-&gt;refCount++;
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! }
  
  smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
  {
! 	smb_tid_t *tidp;
  
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	for(tidp = vcp-&gt;tidsp; tidp; tidp = tidp-&gt;nextp) {
! 		if (tid == tidp-&gt;tid) {
! 			tidp-&gt;refCount++;
! 			break;
! 		}	
! 	}
! 	if (!tidp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
! 		tidp = malloc(sizeof(*tidp));
! 		memset(tidp, 0, sizeof(*tidp));
! 		tidp-&gt;nextp = vcp-&gt;tidsp;
! 		tidp-&gt;refCount = 1;
! 		tidp-&gt;vcp = vcp;
          vcp-&gt;refCount++;
! 		vcp-&gt;tidsp = tidp;
! 		lock_InitializeMutex(&amp;tidp-&gt;mx, "tid_t mutex");
! 		tidp-&gt;tid = tid;
! 	}
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! 	return tidp;
! }	
  
  void smb_ReleaseTID(smb_tid_t *tidp)
  {
! 	smb_tid_t *tp;
! 	smb_tid_t **ltpp;
! 	cm_user_t *userp;
      smb_vc_t  *vcp;
  
! 	userp = NULL;
      vcp = NULL;
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	osi_assert(tidp-&gt;refCount-- &gt; 0);
! 	if (tidp-&gt;refCount == 0 &amp;&amp; (tidp-&gt;flags &amp; SMB_TIDFLAG_DELETE)) {
! 		ltpp = &amp;tidp-&gt;vcp-&gt;tidsp;
! 		for(tp = *ltpp; tp; ltpp = &amp;tp-&gt;nextp, tp = *ltpp) {
! 			if (tp == tidp) break;
! 		}
! 		osi_assert(tp != NULL);
! 		*ltpp = tp-&gt;nextp;
! 		lock_FinalizeMutex(&amp;tidp-&gt;mx);
! 		userp = tidp-&gt;userp;	/* remember to drop ref later */
          vcp = tidp-&gt;vcp;
! 	}
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! 	if (userp) {
! 		cm_ReleaseUser(userp);
! 	}	
      if (vcp) {
          smb_ReleaseVC(vcp);
!     }
! }	
  
  smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
  {
! 	smb_user_t *uidp = NULL;
  
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	for(uidp = vcp-&gt;usersp; uidp; uidp = uidp-&gt;nextp) {
! 		if (uid == uidp-&gt;userID) {
! 			uidp-&gt;refCount++;
!                         osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
!                                       (int)vcp, uidp-&gt;userID, 
!                                       osi_LogSaveString(smb_logp, (uidp-&gt;unp) ? uidp-&gt;unp-&gt;name : ""));
!         	break;
! 		}
! 	}
! 	if (!uidp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
! 		uidp = malloc(sizeof(*uidp));
! 		memset(uidp, 0, sizeof(*uidp));
! 		uidp-&gt;nextp = vcp-&gt;usersp;
! 		uidp-&gt;refCount = 1;
! 		uidp-&gt;vcp = vcp;
          vcp-&gt;refCount++;
! 		vcp-&gt;usersp = uidp;
! 		lock_InitializeMutex(&amp;uidp-&gt;mx, "user_t mutex");
! 		uidp-&gt;userID = uid;
! 		osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp-&gt;userID,(uidp-&gt;unp ? uidp-&gt;unp-&gt;name : ""));
! 	}
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! 	return uidp;
! }	
  
  smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
  {
! 	smb_username_t *unp= NULL;
  
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	for(unp = usernamesp; unp; unp = unp-&gt;nextp) {
! 		if (stricmp(unp-&gt;name, usern) == 0 &amp;&amp;
! 			stricmp(unp-&gt;machine, machine) == 0) {
! 			unp-&gt;refCount++;
! 			break;
! 		}
! 	}
! 	if (!unp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
! 		unp = malloc(sizeof(*unp));
! 		memset(unp, 0, sizeof(*unp));
! 		unp-&gt;refCount = 1;
! 		unp-&gt;nextp = usernamesp;
! 		unp-&gt;name = strdup(usern);
! 		unp-&gt;machine = strdup(machine);
! 		usernamesp = unp;
! 		lock_InitializeMutex(&amp;unp-&gt;mx, "username_t mutex");
! 	}
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! 	return unp;
  }	
  
  smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
  {
! 	smb_user_t *uidp= NULL;
  
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	for(uidp = vcp-&gt;usersp; uidp; uidp = uidp-&gt;nextp) {
! 		if (!uidp-&gt;unp) 
              continue;
! 		if (stricmp(uidp-&gt;unp-&gt;name, usern) == 0) {
              uidp-&gt;refCount++;
! 			osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp-&gt;userID,usern);
              break;
! 		} else
              continue;
! 	}	
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! 	return uidp;
! }
  void smb_ReleaseUID(smb_user_t *uidp)
  {
! 	smb_user_t *up;
! 	smb_user_t **lupp;
! 	cm_user_t *userp;
      smb_vc_t  *vcp;
  
! 	userp = NULL;
      vcp = NULL;
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	osi_assert(uidp-&gt;refCount-- &gt; 0);
! 	if (uidp-&gt;refCount == 0 &amp;&amp; (uidp-&gt;flags &amp; SMB_USERFLAG_DELETE)) {
! 		lupp = &amp;uidp-&gt;vcp-&gt;usersp;
! 		for(up = *lupp; up; lupp = &amp;up-&gt;nextp, up = *lupp) {
! 			if (up == uidp) break;
! 		}
! 		osi_assert(up != NULL);
! 		*lupp = up-&gt;nextp;
! 		lock_FinalizeMutex(&amp;uidp-&gt;mx);
! 		if (uidp-&gt;unp) {
! 			userp = uidp-&gt;unp-&gt;userp;	/* remember to drop ref later */
              uidp-&gt;unp-&gt;userp = NULL;
!         }
          vcp = uidp-&gt;vcp;
          uidp-&gt;vcp = NULL;
! 	}		
! 	lock_ReleaseWrite(&amp;smb_rctLock);
! 	if (userp) {
! 		cm_ReleaseUserVCRef(userp);
! 		cm_ReleaseUser(userp);
! 	}	
      if (vcp) {
          smb_ReleaseVC(vcp);
      }
--- 730,1012 ----
  
  void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
  {
!     unsigned short dosDate;
!     unsigned short dosTime;
!     struct tm localTm;
!         
!     dosDate = searchTime &amp; 0xffff;
!     dosTime = (searchTime &gt;&gt; 16) &amp; 0xffff;
! 
!     localTm.tm_year = 80 + ((dosDate&gt;&gt;9) &amp; 0x3f);
!     localTm.tm_mon = ((dosDate &gt;&gt; 5) &amp; 0xf) - 1;	/* January is 0 in localTm */
!     localTm.tm_mday = (dosDate) &amp; 0x1f;
!     localTm.tm_hour = (dosTime&gt;&gt;11) &amp; 0x1f;
!     localTm.tm_min = (dosTime &gt;&gt; 5) &amp; 0x3f;
!     localTm.tm_sec = (dosTime &amp; 0x1f) * 2;
!     localTm.tm_isdst = -1;				/* compute whether DST in effect */
  
!     *unixTimep = mktime(&amp;localTm);
  }
  
  void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
  {
!     *dosUTimep = unixTime - smb_localZero;
  }
  
  void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
  {
  #ifndef DJGPP
!     *unixTimep = dosTime + smb_localZero;
  #else /* DJGPP */
!     /* dosTime seems to be already adjusted for GMT */
!     *unixTimep = dosTime;
  #endif /* !DJGPP */
  }
  
  smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
  {
!     smb_vc_t *vcp;
  
!     lock_ObtainWrite(&amp;smb_rctLock);
!     for(vcp = smb_allVCsp; vcp; vcp=vcp-&gt;nextp) {
!         if (lsn == vcp-&gt;lsn &amp;&amp; lana == vcp-&gt;lana) {
!             vcp-&gt;refCount++;
!             break;
!         }
!     }
!     if (!vcp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
!         vcp = malloc(sizeof(*vcp));
!         memset(vcp, 0, sizeof(*vcp));
          vcp-&gt;vcID = numVCs++;
!         vcp-&gt;refCount = 1;
!         vcp-&gt;tidCounter = 1;
!         vcp-&gt;fidCounter = 1;
!         vcp-&gt;uidCounter = 1;  /* UID 0 is reserved for blank user */
!         vcp-&gt;nextp = smb_allVCsp;
!         smb_allVCsp = vcp;
!         lock_InitializeMutex(&amp;vcp-&gt;mx, "vc_t mutex");
!         vcp-&gt;lsn = lsn;
!         vcp-&gt;lana = lana;
          vcp-&gt;secCtx = NULL;
  
!         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
              /* We must obtain a challenge for extended auth 
               * in case the client negotiates smb v3 
               */
              NTSTATUS nts,ntsEx;
!             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
!             PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
!             ULONG lsaRespSize;
  
!             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
  
!             nts = LsaCallAuthenticationPackage( smb_lsaHandle,
                                                  smb_lsaSecPackage,
                                                  &amp;lsaReq,
                                                  sizeof(lsaReq),
                                                  &amp;lsaResp,
                                                  &amp;lsaRespSize,
                                                  &amp;ntsEx);
!             osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
  
!             memcpy(vcp-&gt;encKey, lsaResp-&gt;ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
              LsaFreeReturnBuffer(lsaResp);
!         }
!         else
!             memset(vcp-&gt;encKey, 0, MSV1_0_CHALLENGE_LENGTH);
!     }
!     lock_ReleaseWrite(&amp;smb_rctLock);
!     return vcp;
  }
  
  int smb_IsStarMask(char *maskp)
  {
!     int i;
!     char tc;
          
!     for(i=0; i&lt;11; i++) {
!         tc = *maskp++;
!         if (tc == '?' || tc == '*' || tc == '&gt;') return 1;        
!     }	
!     return 0;
  }
  
  void smb_ReleaseVC(smb_vc_t *vcp)
  {
!     lock_ObtainWrite(&amp;smb_rctLock);
!     osi_assert(vcp-&gt;refCount-- &gt; 0);
!     lock_ReleaseWrite(&amp;smb_rctLock);
! }       
  
  void smb_HoldVC(smb_vc_t *vcp)
  {
!     lock_ObtainWrite(&amp;smb_rctLock);
!     vcp-&gt;refCount++;
!     lock_ReleaseWrite(&amp;smb_rctLock);
! }       
  
  smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
  {
!     smb_tid_t *tidp;
  
!     lock_ObtainWrite(&amp;smb_rctLock);
!     for (tidp = vcp-&gt;tidsp; tidp; tidp = tidp-&gt;nextp) {
!         if (tid == tidp-&gt;tid) {
!             tidp-&gt;refCount++;
!             break;
!         }	
!     }
!     if (!tidp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
!         tidp = malloc(sizeof(*tidp));
!         memset(tidp, 0, sizeof(*tidp));
!         tidp-&gt;nextp = vcp-&gt;tidsp;
!         tidp-&gt;refCount = 1;
!         tidp-&gt;vcp = vcp;
          vcp-&gt;refCount++;
!         vcp-&gt;tidsp = tidp;
!         lock_InitializeMutex(&amp;tidp-&gt;mx, "tid_t mutex");
!         tidp-&gt;tid = tid;
!     }
!     lock_ReleaseWrite(&amp;smb_rctLock);
!     return tidp;
! }       	
  
  void smb_ReleaseTID(smb_tid_t *tidp)
  {
!     smb_tid_t *tp;
!     smb_tid_t **ltpp;
!     cm_user_t *userp;
      smb_vc_t  *vcp;
  
!     userp = NULL;
      vcp = NULL;
!     lock_ObtainWrite(&amp;smb_rctLock);
!     osi_assert(tidp-&gt;refCount-- &gt; 0);
!     if (tidp-&gt;refCount == 0 &amp;&amp; (tidp-&gt;flags &amp; SMB_TIDFLAG_DELETE)) {
!         ltpp = &amp;tidp-&gt;vcp-&gt;tidsp;
!         for(tp = *ltpp; tp; ltpp = &amp;tp-&gt;nextp, tp = *ltpp) {
!             if (tp == tidp) break;
!         }
!         osi_assert(tp != NULL);
!         *ltpp = tp-&gt;nextp;
!         lock_FinalizeMutex(&amp;tidp-&gt;mx);
!         userp = tidp-&gt;userp;	/* remember to drop ref later */
          vcp = tidp-&gt;vcp;
!     }
!     lock_ReleaseWrite(&amp;smb_rctLock);
!     if (userp) {
!         cm_ReleaseUser(userp);
!     }	
      if (vcp) {
          smb_ReleaseVC(vcp);
!     }   
! }	        
  
  smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
  {
!     smb_user_t *uidp = NULL;
  
!     lock_ObtainWrite(&amp;smb_rctLock);
!     for(uidp = vcp-&gt;usersp; uidp; uidp = uidp-&gt;nextp) {
!         if (uid == uidp-&gt;userID) {
!             uidp-&gt;refCount++;
!             osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
!                           (int)vcp, uidp-&gt;userID, 
!                           osi_LogSaveString(smb_logp, (uidp-&gt;unp) ? uidp-&gt;unp-&gt;name : ""));
!             break;
!         }
!     }
!     if (!uidp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
!         uidp = malloc(sizeof(*uidp));
!         memset(uidp, 0, sizeof(*uidp));
!         uidp-&gt;nextp = vcp-&gt;usersp;
!         uidp-&gt;refCount = 1;
!         uidp-&gt;vcp = vcp;
          vcp-&gt;refCount++;
!         vcp-&gt;usersp = uidp;
!         lock_InitializeMutex(&amp;uidp-&gt;mx, "user_t mutex");
!         uidp-&gt;userID = uid;
!         osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp-&gt;userID,(uidp-&gt;unp ? uidp-&gt;unp-&gt;name : ""));
!     }
!     lock_ReleaseWrite(&amp;smb_rctLock);
!     return uidp;
! }       	
  
  smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
  {
!     smb_username_t *unp= NULL;
  
!     lock_ObtainWrite(&amp;smb_rctLock);
!     for(unp = usernamesp; unp; unp = unp-&gt;nextp) {
!         if (stricmp(unp-&gt;name, usern) == 0 &amp;&amp;
!              stricmp(unp-&gt;machine, machine) == 0) {
!             unp-&gt;refCount++;
!             break;
!         }
!     }
!     if (!unp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
!         unp = malloc(sizeof(*unp));
!         memset(unp, 0, sizeof(*unp));
!         unp-&gt;refCount = 1;
!         unp-&gt;nextp = usernamesp;
!         unp-&gt;name = strdup(usern);
!         unp-&gt;machine = strdup(machine);
!         usernamesp = unp;
!         lock_InitializeMutex(&amp;unp-&gt;mx, "username_t mutex");
!     }
!     lock_ReleaseWrite(&amp;smb_rctLock);
!     return unp;
  }	
  
  smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
  {
!     smb_user_t *uidp= NULL;
  
!     lock_ObtainWrite(&amp;smb_rctLock);
!     for(uidp = vcp-&gt;usersp; uidp; uidp = uidp-&gt;nextp) {
!         if (!uidp-&gt;unp) 
              continue;
!         if (stricmp(uidp-&gt;unp-&gt;name, usern) == 0) {
              uidp-&gt;refCount++;
!             osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp-&gt;userID,usern);
              break;
!         } else
              continue;
!     }       	
!     lock_ReleaseWrite(&amp;smb_rctLock);
!     return uidp;
! }       
  void smb_ReleaseUID(smb_user_t *uidp)
  {
!     smb_user_t *up;
!     smb_user_t **lupp;
!     cm_user_t *userp;
      smb_vc_t  *vcp;
  
!     userp = NULL;
      vcp = NULL;
!     lock_ObtainWrite(&amp;smb_rctLock);
!     osi_assert(uidp-&gt;refCount-- &gt; 0);
!     if (uidp-&gt;refCount == 0 &amp;&amp; (uidp-&gt;flags &amp; SMB_USERFLAG_DELETE)) {
!         lupp = &amp;uidp-&gt;vcp-&gt;usersp;
!         for(up = *lupp; up; lupp = &amp;up-&gt;nextp, up = *lupp) {
!             if (up == uidp) break;
!         }
!         osi_assert(up != NULL);
!         *lupp = up-&gt;nextp;
!         lock_FinalizeMutex(&amp;uidp-&gt;mx);
!         if (uidp-&gt;unp) {
!             userp = uidp-&gt;unp-&gt;userp;	/* remember to drop ref later */
              uidp-&gt;unp-&gt;userp = NULL;
!         }       
          vcp = uidp-&gt;vcp;
          uidp-&gt;vcp = NULL;
!     }		
!     lock_ReleaseWrite(&amp;smb_rctLock);
!     if (userp) {
!         cm_ReleaseUserVCRef(userp);
!         cm_ReleaseUser(userp);
!     }	
      if (vcp) {
          smb_ReleaseVC(vcp);
      }
***************
*** 1005,1027 ****
   */
  cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
  {
! 	smb_user_t *uidp;
! 	cm_user_t *up;
! 	smb_t *smbp;
! 
! 	smbp = (smb_t *) inp;
! 	uidp = smb_FindUID(vcp, smbp-&gt;uid, 0);
! 	if ((!uidp) ||  (!uidp-&gt;unp))
! 		return NULL;
!         
! 	lock_ObtainMutex(&amp;uidp-&gt;mx);
! 	up = uidp-&gt;unp-&gt;userp;
! 	cm_HoldUser(up);
! 	lock_ReleaseMutex(&amp;uidp-&gt;mx);
  
! 	smb_ReleaseUID(uidp);
!         
! 	return up;
  }
  
  /*
--- 1018,1040 ----
   */
  cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
  {
!     smb_user_t *uidp;
!     cm_user_t *up;
!     smb_t *smbp;
  
!     smbp = (smb_t *) inp;
!     uidp = smb_FindUID(vcp, smbp-&gt;uid, 0);
!     if ((!uidp) ||  (!uidp-&gt;unp))
!         return NULL;
! 
!     lock_ObtainMutex(&amp;uidp-&gt;mx);
!     up = uidp-&gt;unp-&gt;userp;
!     cm_HoldUser(up);
!     lock_ReleaseMutex(&amp;uidp-&gt;mx);
! 
!     smb_ReleaseUID(uidp);
! 
!     return up;
  }
  
  /*
***************
*** 1030,1039 ****
   */
  long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
  {
! 	smb_tid_t *tidp;
      long code = 0;
  
! 	tidp = smb_FindTID(vcp, tid, 0);
      if (!tidp) {
          *treepath = NULL;
      } else {
--- 1043,1052 ----
   */
  long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
  {
!     smb_tid_t *tidp;
      long code = 0;
  
!     tidp = smb_FindTID(vcp, tid, 0);
      if (!tidp) {
          *treepath = NULL;
      } else {
***************
*** 1054,1069 ****
   */
  int smb_ChainFID(int fid, smb_packet_t *inp)
  {
! 	if (inp-&gt;fid == 0 || inp-&gt;inCount == 0) 
! 		return fid;
! 	else 
! 		return inp-&gt;fid;
  }
  
  /* are we a priv'd user?  What does this mean on NT? */
  int smb_SUser(cm_user_t *userp)
  {
! 	return 1;
  }
  
  /* find a file ID.  If we pass in 0 we select an used File ID.
--- 1067,1082 ----
   */
  int smb_ChainFID(int fid, smb_packet_t *inp)
  {
!     if (inp-&gt;fid == 0 || inp-&gt;inCount == 0) 
!         return fid;
!     else 
!         return inp-&gt;fid;
  }
  
  /* are we a priv'd user?  What does this mean on NT? */
  int smb_SUser(cm_user_t *userp)
  {
!     return 1;
  }
  
  /* find a file ID.  If we pass in 0 we select an used File ID.
***************
*** 1072,1102 ****
   */
  smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
  {
! 	smb_fid_t *fidp;
! 	int newFid = 0;
          
      if (fid == 0 &amp;&amp; !(flags &amp; SMB_FLAG_CREATE))
          return NULL;
  
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	/* figure out if we need to allocate a new file ID */
! 	if (fid == 0) {
! 		newFid = 1;
! 		fid = vcp-&gt;fidCounter;
! 	}
! 
! retry:
! 	for(fidp = vcp-&gt;fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&amp;fidp-&gt;q)) {
! 		if (fid == fidp-&gt;fid) {
! 			if (newFid) {
! 				fid++;
                  if (fid == 0) 
! 					fid = 1;
                  goto retry;
              }
! 			fidp-&gt;refCount++;
              break;
! 		}
      }
      if (!fidp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
          char eventName[MAX_PATH];
--- 1085,1115 ----
   */
  smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
  {
!     smb_fid_t *fidp;
!     int newFid = 0;
          
      if (fid == 0 &amp;&amp; !(flags &amp; SMB_FLAG_CREATE))
          return NULL;
  
!     lock_ObtainWrite(&amp;smb_rctLock);
!     /* figure out if we need to allocate a new file ID */
!     if (fid == 0) {
!         newFid = 1;
!         fid = vcp-&gt;fidCounter;
!     }
! 
!   retry:
!     for(fidp = vcp-&gt;fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&amp;fidp-&gt;q)) {
!         if (fid == fidp-&gt;fid) {
!             if (newFid) {
!                 fid++;
                  if (fid == 0) 
!                     fid = 1;
                  goto retry;
              }
!             fidp-&gt;refCount++;
              break;
!         }
      }
      if (!fidp &amp;&amp; (flags &amp; SMB_FLAG_CREATE)) {
          char eventName[MAX_PATH];
***************
*** 1112,1127 ****
              goto retry;
          }
  
! 		fidp = malloc(sizeof(*fidp));
          memset(fidp, 0, sizeof(*fidp));
! 		osi_QAdd((osi_queue_t **)&amp;vcp-&gt;fidsp, &amp;fidp-&gt;q);
          fidp-&gt;refCount = 1;
          fidp-&gt;vcp = vcp;
          vcp-&gt;refCount++;
          lock_InitializeMutex(&amp;fidp-&gt;mx, "fid_t mutex");
          fidp-&gt;fid = fid;
! 		fidp-&gt;curr_chunk = fidp-&gt;prev_chunk = -2;
! 		fidp-&gt;raw_write_event = event;
          if (newFid) {
              vcp-&gt;fidCounter = fid+1;
              if (vcp-&gt;fidCounter == 0) 
--- 1125,1140 ----
              goto retry;
          }
  
!         fidp = malloc(sizeof(*fidp));
          memset(fidp, 0, sizeof(*fidp));
!         osi_QAdd((osi_queue_t **)&amp;vcp-&gt;fidsp, &amp;fidp-&gt;q);
          fidp-&gt;refCount = 1;
          fidp-&gt;vcp = vcp;
          vcp-&gt;refCount++;
          lock_InitializeMutex(&amp;fidp-&gt;mx, "fid_t mutex");
          fidp-&gt;fid = fid;
!         fidp-&gt;curr_chunk = fidp-&gt;prev_chunk = -2;
!         fidp-&gt;raw_write_event = event;
          if (newFid) {
              vcp-&gt;fidCounter = fid+1;
              if (vcp-&gt;fidCounter == 0) 
***************
*** 1134,1176 ****
  
  void smb_ReleaseFID(smb_fid_t *fidp)
  {
! 	cm_scache_t *scp;
      smb_vc_t *vcp = NULL;
      smb_ioctl_t *ioctlp;
  
      if (!fidp)
          return;
  
! 	scp = NULL;
! 	lock_ObtainWrite(&amp;smb_rctLock);
! 	osi_assert(fidp-&gt;refCount-- &gt; 0);
      if (fidp-&gt;refCount == 0 &amp;&amp; (fidp-&gt;flags &amp; SMB_FID_DELETE)) {
! 		vcp = fidp-&gt;vcp;
! 		if (!(fidp-&gt;flags &amp; SMB_FID_IOCTL))
! 			scp = fidp-&gt;scp;
! 		osi_QRemove((osi_queue_t **) &amp;vcp-&gt;fidsp, &amp;fidp-&gt;q);
! 		thrd_CloseHandle(fidp-&gt;raw_write_event);
  
! 		/* and see if there is ioctl stuff to free */
          ioctlp = fidp-&gt;ioctlp;
          if (ioctlp) {
! 			if (ioctlp-&gt;prefix) cm_FreeSpace(ioctlp-&gt;prefix);
! 			if (ioctlp-&gt;inAllocp) free(ioctlp-&gt;inAllocp);
! 			if (ioctlp-&gt;outAllocp) free(ioctlp-&gt;outAllocp);
! 			free(ioctlp);
!         }
  
          free(fidp);
  
          /* do not call smb_ReleaseVC() because we already have the lock */
          vcp-&gt;refCount--;
      }
! 	lock_ReleaseWrite(&amp;smb_rctLock);
  
! 	/* now release the scache structure */
! 	if (scp) 
! 		cm_ReleaseSCache(scp);
! }
  
  /*
   * Case-insensitive search for one string in another;
--- 1147,1189 ----
  
  void smb_ReleaseFID(smb_fid_t *fidp)
  {
!     cm_scache_t *scp;
      smb_vc_t *vcp = NULL;
      smb_ioctl_t *ioctlp;
  
      if (!fidp)
          return;
  
!     scp = NULL;
!     lock_ObtainWrite(&amp;smb_rctLock);
!     osi_assert(fidp-&gt;refCount-- &gt; 0);
      if (fidp-&gt;refCount == 0 &amp;&amp; (fidp-&gt;flags &amp; SMB_FID_DELETE)) {
!         vcp = fidp-&gt;vcp;
!         if (!(fidp-&gt;flags &amp; SMB_FID_IOCTL))
!             scp = fidp-&gt;scp;
!         osi_QRemove((osi_queue_t **) &amp;vcp-&gt;fidsp, &amp;fidp-&gt;q);
!         thrd_CloseHandle(fidp-&gt;raw_write_event);
  
!         /* and see if there is ioctl stuff to free */
          ioctlp = fidp-&gt;ioctlp;
          if (ioctlp) {
!             if (ioctlp-&gt;prefix) cm_FreeSpace(ioctlp-&gt;prefix);
!             if (ioctlp-&gt;inAllocp) free(ioctlp-&gt;inAllocp);
!             if (ioctlp-&gt;outAllocp) free(ioctlp-&gt;outAllocp);
!             free(ioctlp);
!         }       
  
          free(fidp);
  
          /* do not call smb_ReleaseVC() because we already have the lock */
          vcp-&gt;refCount--;
      }
!     lock_ReleaseWrite(&amp;smb_rctLock);
  
!     /* now release the scache structure */
!     if (scp) 
!         cm_ReleaseSCache(scp);
! }       
  
  /*
   * Case-insensitive search for one string in another;
***************
*** 1178,1190 ****
   */
  static char *smb_stristr(char *str1, char *str2)
  {
! 	char *cursor;
  
! 	for (cursor = str1; *cursor; cursor++)
! 		if (stricmp(cursor, str2) == 0)
! 			return cursor;
  
! 	return NULL;
  }
  
  /*
--- 1191,1203 ----
   */
  static char *smb_stristr(char *str1, char *str2)
  {
!     char *cursor;
  
!     for (cursor = str1; *cursor; cursor++)
!         if (stricmp(cursor, str2) == 0)
!             return cursor;
  
!     return NULL;
  }
  
  /*
***************
*** 1193,1206 ****
   * length (plus one) is in substr_size.  Variable value is in newstr.
   */
  static void smb_subst(char *str1, char *substr, unsigned int substr_size,
! 	char *newstr)
  {
! 	char temp[1024];
  
! 	strcpy(temp, substr + substr_size - 1);
! 	strcpy(substr, newstr);
! 	strcat(str1, temp);
! }
  
  char VNUserName[] = "%USERNAME%";
  char VNLCUserName[] = "%LCUSERNAME%";
--- 1206,1219 ----
   * length (plus one) is in substr_size.  Variable value is in newstr.
   */
  static void smb_subst(char *str1, char *substr, unsigned int substr_size,
!                       char *newstr)
  {
!     char temp[1024];
  
!     strcpy(temp, substr + substr_size - 1);
!     strcpy(substr, newstr);
!     strcat(str1, temp);
! }       
  
  char VNUserName[] = "%USERNAME%";
  char VNLCUserName[] = "%LCUSERNAME%";
***************
*** 1211,1275 ****
  /* List available shares */
  int smb_ListShares()
  {
! 	char sbmtpath[256];
! 	char pathName[256];
! 	char shareBuf[4096];
! 	int num_shares=0;
! 	char *this_share;
! 	int len;
! 	char *p;
! 	int print_afs = 0;
! 	int code;
! 
! 	/*strcpy(shareNameList[num_shares], "all");
! 	 strcpy(pathNameList[num_shares++], "/afs");*/
! 	fprintf(stderr, "The following shares are available:\n");
! 	fprintf(stderr, "Share Name (AFS Path)\n");
! 	fprintf(stderr, "---------------------\n");
! 	fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
  
  #ifndef DJGPP
! 	code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
! 	if (code == 0 || code &gt; sizeof(sbmtpath)) return -1;
  #else
! 	strcpy(sbmtpath, cm_confDir);
  #endif /* !DJGPP */
! 	strcat(sbmtpath, "/afsdsbmt.ini");
! 	len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
! 								   shareBuf, sizeof(shareBuf),
! 								   sbmtpath);
! 	if (len == 0) {
! 		return num_shares;
! 	}
! 
! 	this_share = shareBuf;
! 	do
! 	{
! 		print_afs = 0;
! 		/*strcpy(shareNameList[num_shares], this_share);*/
! 		len = GetPrivateProfileString("AFS Submounts", this_share,
! 									   NULL,
! 									   pathName, 256,
! 									   sbmtpath);
! 		if (!len) 
! 			return num_shares;
! 		p = pathName;
! 		if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
              print_afs = 1;
! 		while (*p) {
              if (*p == '\\') *p = '/';    /* change to / */
              p++;
! 		}
  
! 		fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
! 				 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
! 				 pathName);
! 		num_shares++;
! 		while (*this_share != 0) this_share++;  /* find next NUL */
! 		this_share++;   /* skip past the NUL */
! 	} while (*this_share != 0);  /* stop at final NUL */
  
! 	return num_shares;
  }
  #endif /* DJGPP */
  
--- 1224,1288 ----
  /* List available shares */
  int smb_ListShares()
  {
!     char sbmtpath[256];
!     char pathName[256];
!     char shareBuf[4096];
!     int num_shares=0;
!     char *this_share;
!     int len;
!     char *p;
!     int print_afs = 0;
!     int code;
! 
!     /*strcpy(shareNameList[num_shares], "all");
!       strcpy(pathNameList[num_shares++], "/afs");*/
!     fprintf(stderr, "The following shares are available:\n");
!     fprintf(stderr, "Share Name (AFS Path)\n");
!     fprintf(stderr, "---------------------\n");
!     fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
  
  #ifndef DJGPP
!     code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
!     if (code == 0 || code &gt; sizeof(sbmtpath)) return -1;
  #else
!     strcpy(sbmtpath, cm_confDir);
  #endif /* !DJGPP */
!     strcat(sbmtpath, "/afsdsbmt.ini");
!     len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
!                                    shareBuf, sizeof(shareBuf),
!                                    sbmtpath);
!     if (len == 0) {
!         return num_shares;
!     }
! 
!     this_share = shareBuf;
!     do
!     {
!         print_afs = 0;
!         /*strcpy(shareNameList[num_shares], this_share);*/
!         len = GetPrivateProfileString("AFS Submounts", this_share,
!                                        NULL,
!                                        pathName, 256,
!                                        sbmtpath);
!         if (!len) 
!             return num_shares;
!         p = pathName;
!         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
              print_afs = 1;
!         while (*p) {
              if (*p == '\\') *p = '/';    /* change to / */
              p++;
!         }
  
!         fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
!                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
!                  pathName);
!         num_shares++;
!         while (*this_share != 0) this_share++;  /* find next NUL */
!         this_share++;   /* skip past the NUL */
!     } while (*this_share != 0);  /* stop at final NUL */
  
!     return num_shares;
  }
  #endif /* DJGPP */
  
***************
*** 1283,1289 ****
  #define SMB_FINDSHARE_PARTIAL_MATCH 2
  
  long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
! 	osi_hyper_t *offp)
  {
      int matchType = 0;
      smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
--- 1296,1302 ----
  #define SMB_FINDSHARE_PARTIAL_MATCH 2
  
  long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
!                        osi_hyper_t *offp)
  {
      int matchType = 0;
      smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
***************
*** 1307,1323 ****
  int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
  	char **pathNamep)
  {
! 	DWORD len;
! 	char pathName[1024];
! 	char *var;
! 	char temp[1024];
! 	DWORD sizeTemp;
  #ifdef DJGPP
      char sbmtpath[MAX_PATH];
  #endif
      char *p, *q;
! 	HKEY parmKey;
! 	DWORD code;
      DWORD allSubmount = 1;
  
      /* if allSubmounts == 0, only return the //mountRoot/all share 
--- 1320,1336 ----
  int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
  	char **pathNamep)
  {
!     DWORD len;
!     char pathName[1024];
!     char *var;
!     char temp[1024];
!     DWORD sizeTemp;
  #ifdef DJGPP
      char sbmtpath[MAX_PATH];
  #endif
      char *p, *q;
!     HKEY parmKey;
!     DWORD code;
      DWORD allSubmount = 1;
  
      /* if allSubmounts == 0, only return the //mountRoot/all share 
***************
*** 1325,1333 ****
       * This is to allow sites that want to restrict access to the 
       * world to do so.
       */
! 	code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
! 						0, KEY_QUERY_VALUE, &amp;parmKey);
! 	if (code == ERROR_SUCCESS) {
          len = sizeof(allSubmount);
          code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
                                  (BYTE *) &amp;allSubmount, &amp;len);
--- 1338,1346 ----
       * This is to allow sites that want to restrict access to the 
       * world to do so.
       */
!     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
!                          0, KEY_QUERY_VALUE, &amp;parmKey);
!     if (code == ERROR_SUCCESS) {
          len = sizeof(allSubmount);
          code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
                                  (BYTE *) &amp;allSubmount, &amp;len);
***************
*** 1335,1383 ****
              allSubmount = 1;
          }
          RegCloseKey (parmKey);
! 	}
  
! 	if (allSubmount &amp;&amp; _stricmp(shareName, "all") == 0) {
! 		*pathNamep = NULL;
! 		return 1;
! 	}
  
      /* In case, the all share is disabled we need to still be able
       * to handle ioctl requests 
       */
! 	if (_stricmp(shareName, "ioctl$") == 0) {
! 		*pathNamep = strdup("/.__ioctl__");
! 		return 1;
! 	}
  
      if (_stricmp(shareName, "IPC$") == 0 ||
          _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
          _stricmp(shareName, "DESKTOP.INI") == 0
           ) {
! 		*pathNamep = NULL;
! 		return 0;
! 	}
  
  #ifndef DJGPP
! 	code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
! 						0, KEY_QUERY_VALUE, &amp;parmKey);
! 	if (code == ERROR_SUCCESS) {
          len = sizeof(pathName);
          code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
                                  (BYTE *) pathName, &amp;len);
! 		if (code != ERROR_SUCCESS)
! 			len = 0;
          RegCloseKey (parmKey);
! 	} else {
          len = 0;
      }   
  #else /* DJGPP */
      strcpy(sbmtpath, cm_confDir);
      strcat(sbmtpath, "/afsdsbmt.ini");
! 	len = GetPrivateProfileString("AFS Submounts", shareName, "",
!                                   pathName, sizeof(pathName), sbmtpath);
  #endif /* !DJGPP */
! 	if (len != 0 &amp;&amp; len != sizeof(pathName) - 1) {
          /* We can accept either unix or PC style AFS pathnames.  Convert
           * Unix-style to PC style here for internal use. 
           */
--- 1348,1396 ----
              allSubmount = 1;
          }
          RegCloseKey (parmKey);
!     }
  
!     if (allSubmount &amp;&amp; _stricmp(shareName, "all") == 0) {
!         *pathNamep = NULL;
!         return 1;
!     }
  
      /* In case, the all share is disabled we need to still be able
       * to handle ioctl requests 
       */
!     if (_stricmp(shareName, "ioctl$") == 0) {
!         *pathNamep = strdup("/.__ioctl__");
!         return 1;
!     }
  
      if (_stricmp(shareName, "IPC$") == 0 ||
          _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
          _stricmp(shareName, "DESKTOP.INI") == 0
           ) {
!         *pathNamep = NULL;
!         return 0;
!     }
  
  #ifndef DJGPP
!     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
!                          0, KEY_QUERY_VALUE, &amp;parmKey);
!     if (code == ERROR_SUCCESS) {
          len = sizeof(pathName);
          code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
                                  (BYTE *) pathName, &amp;len);
!         if (code != ERROR_SUCCESS)
!             len = 0;
          RegCloseKey (parmKey);
!     } else {
          len = 0;
      }   
  #else /* DJGPP */
      strcpy(sbmtpath, cm_confDir);
      strcat(sbmtpath, "/afsdsbmt.ini");
!     len = GetPrivateProfileString("AFS Submounts", shareName, "",
!                                    pathName, sizeof(pathName), sbmtpath);
  #endif /* !DJGPP */
!     if (len != 0 &amp;&amp; len != sizeof(pathName) - 1) {
          /* We can accept either unix or PC style AFS pathnames.  Convert
           * Unix-style to PC style here for internal use. 
           */
***************
*** 1478,1484 ****
              *pathNamep = strdup(strlwr(pathName));
              return 1;
          }
! 	}
      /* failure */
      *pathNamep = NULL;
      return 0;
--- 1491,1497 ----
              *pathNamep = strdup(strlwr(pathName));
              return 1;
          }
!     }
      /* failure */
      *pathNamep = NULL;
      return 0;
***************
*** 1492,1499 ****
  
  int smb_FindShareCSCPolicy(char *shareName)
  {
! 	DWORD len;
! 	char policy[1024];
      DWORD dwType;
      HKEY hkCSCPolicy;
      int  retval = CSC_POLICY_MANUAL;
--- 1505,1512 ----
  
  int smb_FindShareCSCPolicy(char *shareName)
  {
!     DWORD len;
!     char policy[1024];
      DWORD dwType;
      HKEY hkCSCPolicy;
      int  retval = CSC_POLICY_MANUAL;
***************
*** 1511,1533 ****
      len = sizeof(policy);
      if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &amp;dwType, policy, &amp;len ) ||
           len == 0) {
! 		retval = CSC_POLICY_MANUAL;
      }
- 	else if (stricmp(policy, "documents") == 0)
- 	{
- 		retval = CSC_POLICY_DOCUMENTS;
- 	}
- 	else if (stricmp(policy, "programs") == 0)
- 	{
- 		retval = CSC_POLICY_PROGRAMS;
- 	}
- 	else if (stricmp(policy, "disable") == 0)
- 	{
- 		retval = CSC_POLICY_DISABLE;
- 	}
  	
      RegCloseKey(hkCSCPolicy);
! 	return retval;
  }
  
  /* find a dir search structure by cookie value, and return it held.
--- 1524,1546 ----
      len = sizeof(policy);
      if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &amp;dwType, policy, &amp;len ) ||
           len == 0) {
!         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
!     }
!     else if (stricmp(policy, "documents") == 0)
!     {
!         retval = CSC_POLICY_DOCUMENTS;
!     }
!     else if (stricmp(policy, "programs") == 0)
!     {
!         retval = CSC_POLICY_PROGRAMS;
!     }
!     else if (stricmp(policy, "disable") == 0)
!     {
!         retval = CSC_POLICY_DISABLE;
      }
  	
      RegCloseKey(hkCSCPolicy);
!     return retval;
  }
  
  /* find a dir search structure by cookie value, and return it held.
***************
*** 1535,1610 ****
   */
  smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
  {
! 	smb_dirSearch_t *dsp;
          
! 	for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&amp;dsp-&gt;q)) {
! 		if (dsp-&gt;cookie == cookie) {
! 			if (dsp != smb_firstDirSearchp) {
! 				/* move to head of LRU queue, too, if we're not already there */
! 				if (smb_lastDirSearchp == (smb_dirSearch_t *) &amp;dsp-&gt;q)
! 					smb_lastDirSearchp = (smb_dirSearch_t *)
! 						osi_QPrev(&amp;dsp-&gt;q);
! 				osi_QRemove((osi_queue_t **) &amp;smb_firstDirSearchp, &amp;dsp-&gt;q);
! 				osi_QAdd((osi_queue_t **) &amp;smb_firstDirSearchp, &amp;dsp-&gt;q);
! 				if (!smb_lastDirSearchp)
! 					smb_lastDirSearchp = (smb_dirSearch_t *) &amp;dsp-&gt;q;
! 			}
! 			dsp-&gt;refCount++;
! 			break;
! 		}
! 	}
! 	return dsp;
! }
  
  void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
  {
! 	lock_ObtainWrite(&amp;smb_globalLock);
! 	dsp-&gt;flags |= SMB_DIRSEARCH_DELETE;
! 	lock_ReleaseWrite(&amp;smb_globalLock);
! 	lock_ObtainMutex(&amp;dsp-&gt;mx);
! 	if(dsp-&gt;scp != NULL) {
! 		lock_ObtainMutex(&amp;dsp-&gt;scp-&gt;mx);
! 		if (dsp-&gt;flags &amp; SMB_DIRSEARCH_BULKST) {
! 			dsp-&gt;flags &amp;= ~SMB_DIRSEARCH_BULKST;
! 		    dsp-&gt;scp-&gt;flags &amp;= ~CM_SCACHEFLAG_BULKSTATTING;
! 		    dsp-&gt;scp-&gt;bulkStatProgress = hones;
! 		}	
! 		lock_ReleaseMutex(&amp;dsp-&gt;scp-&gt;mx);
! 	}	
! 	lock_ReleaseMutex(&amp;dsp-&gt;mx);
! }
  
  void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
  {
! 	cm_scache_t *scp;
          
! 	scp = NULL;
  
! 	lock_ObtainWrite(&amp;smb_globalLock);
! 	osi_assert(dsp-&gt;refCount-- &gt; 0);
! 	if (dsp-&gt;refCount == 0 &amp;&amp; (dsp-&gt;flags &amp; SMB_DIRSEARCH_DELETE)) {
! 		if (&amp;dsp-&gt;q == (osi_queue_t *) smb_lastDirSearchp)
! 			smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&amp;smb_lastDirSearchp-&gt;q);
! 		osi_QRemove((osi_queue_t **) &amp;smb_firstDirSearchp, &amp;dsp-&gt;q);
! 		lock_FinalizeMutex(&amp;dsp-&gt;mx);
! 		scp = dsp-&gt;scp;
! 		free(dsp);
! 	}
! 	lock_ReleaseWrite(&amp;smb_globalLock);
  
! 	/* do this now to avoid spurious locking hierarchy creation */
! 	if (scp) cm_ReleaseSCache(scp);
! }
  
  /* find a dir search structure by cookie value, and return it held */
  smb_dirSearch_t *smb_FindDirSearch(long cookie)
  {
! 	smb_dirSearch_t *dsp;
  
! 	lock_ObtainWrite(&amp;smb_globalLock);
! 	dsp = smb_FindDirSearchNL(cookie);
! 	lock_ReleaseWrite(&amp;smb_globalLock);
! 	return dsp;
  }
  
  /* GC some dir search entries, in the address space expected by the specific protocol.
--- 1548,1623 ----
   */
  smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
  {
!     smb_dirSearch_t *dsp;
          
!     for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&amp;dsp-&gt;q)) {
!         if (dsp-&gt;cookie == cookie) {
!             if (dsp != smb_firstDirSearchp) {
!                 /* move to head of LRU queue, too, if we're not already there */
!                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &amp;dsp-&gt;q)
!                     smb_lastDirSearchp = (smb_dirSearch_t *)
!                         osi_QPrev(&amp;dsp-&gt;q);
!                 osi_QRemove((osi_queue_t **) &amp;smb_firstDirSearchp, &amp;dsp-&gt;q);
!                 osi_QAdd((osi_queue_t **) &amp;smb_firstDirSearchp, &amp;dsp-&gt;q);
!                 if (!smb_lastDirSearchp)
!                     smb_lastDirSearchp = (smb_dirSearch_t *) &amp;dsp-&gt;q;
!             }
!             dsp-&gt;refCount++;
!             break;
!         }
!     }
!     return dsp;
! }       
  
  void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
  {
!     lock_ObtainWrite(&amp;smb_globalLock);
!     dsp-&gt;flags |= SMB_DIRSEARCH_DELETE;
!     lock_ReleaseWrite(&amp;smb_globalLock);
!     lock_ObtainMutex(&amp;dsp-&gt;mx);
!     if(dsp-&gt;scp != NULL) {
!         lock_ObtainMutex(&amp;dsp-&gt;scp-&gt;mx);
!         if (dsp-&gt;flags &amp; SMB_DIRSEARCH_BULKST) {
!             dsp-&gt;flags &amp;= ~SMB_DIRSEARCH_BULKST;
!             dsp-&gt;scp-&gt;flags &amp;= ~CM_SCACHEFLAG_BULKSTATTING;
!             dsp-&gt;scp-&gt;bulkStatProgress = hones;
!         }	
!         lock_ReleaseMutex(&amp;dsp-&gt;scp-&gt;mx);
!     }	
!     lock_ReleaseMutex(&amp;dsp-&gt;mx);
! }               
  
  void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
  {
!     cm_scache_t *scp;
          
!     scp = NULL;
  
!     lock_ObtainWrite(&amp;smb_globalLock);
!     osi_assert(dsp-&gt;refCount-- &gt; 0);
!     if (dsp-&gt;refCount == 0 &amp;&amp; (dsp-&gt;flags &amp; SMB_DIRSEARCH_DELETE)) {
!         if (&amp;dsp-&gt;q == (osi_queue_t *) smb_lastDirSearchp)
!             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&amp;smb_lastDirSearchp-&gt;q);
!         osi_QRemove((osi_queue_t **) &amp;smb_firstDirSearchp, &amp;dsp-&gt;q);
!         lock_FinalizeMutex(&amp;dsp-&gt;mx);
!         scp = dsp-&gt;scp;
!         free(dsp);
!     }
!     lock_ReleaseWrite(&amp;smb_globalLock);
  
!     /* do this now to avoid spurious locking hierarchy creation */
!     if (scp) cm_ReleaseSCache(scp);
! }       
  
  /* find a dir search structure by cookie value, and return it held */
  smb_dirSearch_t *smb_FindDirSearch(long cookie)
  {
!     smb_dirSearch_t *dsp;
  
!     lock_ObtainWrite(&amp;smb_globalLock);
!     dsp = smb_FindDirSearchNL(cookie);
!     lock_ReleaseWrite(&amp;smb_globalLock);
!     return dsp;
  }
  
  /* GC some dir search entries, in the address space expected by the specific protocol.
***************
*** 1613,1651 ****
  #define SMB_DIRSEARCH_GCMAX	10	/* how many at once */
  void smb_GCDirSearches(int isV3)
  {
! 	smb_dirSearch_t *prevp;
! 	smb_dirSearch_t *tp;
! 	smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
! 	int victimCount;
! 	int i;
!         
! 	victimCount = 0;	/* how many have we got so far */
! 	for(tp = smb_lastDirSearchp; tp; tp=prevp) {
! 		/* we'll move tp from queue, so
! 		 * do this early.
! 		 */
! 		prevp = (smb_dirSearch_t *) osi_QPrev(&amp;tp-&gt;q);	
! 		/* if no one is using this guy, and we're either in the new protocol,
! 		 * or we're in the old one and this is a small enough ID to be useful
! 		 * to the old protocol, GC this guy.
! 		 */
! 		if (tp-&gt;refCount == 0 &amp;&amp; (isV3 || tp-&gt;cookie &lt;= 255)) {
! 			/* hold and delete */
! 			tp-&gt;flags |= SMB_DIRSEARCH_DELETE;
! 			victimsp[victimCount++] = tp;
! 			tp-&gt;refCount++;
! 		}
! 
! 		/* don't do more than this */
! 		if (victimCount &gt;= SMB_DIRSEARCH_GCMAX) break;
! 	}
  	
! 	/* now release them */
! 	lock_ReleaseWrite(&amp;smb_globalLock);
! 	for(i = 0; i &lt; victimCount; i++) {
! 		smb_ReleaseDirSearch(victimsp[i]);
! 	}
! 	lock_ObtainWrite(&amp;smb_globalLock);
  }
  
  /* function for allocating a dir search entry.  We need these to remember enough context
--- 1626,1664 ----
  #define SMB_DIRSEARCH_GCMAX	10	/* how many at once */
  void smb_GCDirSearches(int isV3)
  {
!     smb_dirSearch_t *prevp;
!     smb_dirSearch_t *tp;
!     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
!     int victimCount;
!     int i;
!         
!     victimCount = 0;	/* how many have we got so far */
!     for(tp = smb_lastDirSearchp; tp; tp=prevp) {
!         /* we'll move tp from queue, so
!          * do this early.
!          */
!         prevp = (smb_dirSearch_t *) osi_QPrev(&amp;tp-&gt;q);	
!         /* if no one is using this guy, and we're either in the new protocol,
!          * or we're in the old one and this is a small enough ID to be useful
!          * to the old protocol, GC this guy.
!          */
!         if (tp-&gt;refCount == 0 &amp;&amp; (isV3 || tp-&gt;cookie &lt;= 255)) {
!             /* hold and delete */
!             tp-&gt;flags |= SMB_DIRSEARCH_DELETE;
!             victimsp[victimCount++] = tp;
!             tp-&gt;refCount++;
!         }
! 
!         /* don't do more than this */
!         if (victimCount &gt;= SMB_DIRSEARCH_GCMAX) break;
!     }
  	
!     /* now release them */
!     lock_ReleaseWrite(&amp;smb_globalLock);
!     for(i = 0; i &lt; victimCount; i++) {
!         smb_ReleaseDirSearch(victimsp[i]);
!     }
!     lock_ObtainWrite(&amp;smb_globalLock);
  }
  
  /* function for allocating a dir search entry.  We need these to remember enough context
***************
*** 1656,1719 ****
   */
  smb_dirSearch_t *smb_NewDirSearch(int isV3)
  {
! 	smb_dirSearch_t *dsp;
! 	int counter;
! 	int maxAllowed;
! 
! 	lock_ObtainWrite(&amp;smb_globalLock);
! 	counter = 0;
! 
! 	/* what's the biggest ID allowed in this version of the protocol */
! 	if (isV3) maxAllowed = 65535;
! 	else maxAllowed = 255;
! 
! 	while(1) {
! 		/* twice so we have enough tries to find guys we GC after one pass;
! 		 * 10 extra is just in case I mis-counted.
! 		 */
! 		if (++counter &gt; 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
! 													__FILE__, __LINE__);
! 		if (smb_dirSearchCounter &gt; maxAllowed) {	
! 			smb_dirSearchCounter = 1;
! 			smb_GCDirSearches(isV3);	/* GC some (drops global lock) */
! 		}	
! 		dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
! 		if (dsp) {
! 			/* don't need to watch for refcount zero and deleted, since
! 			 * we haven't dropped the global lock.
! 			 */
! 			dsp-&gt;refCount--;
! 			++smb_dirSearchCounter;
! 			continue;
! 		}	
!                 
! 		dsp = malloc(sizeof(*dsp));
! 		memset(dsp, 0, sizeof(*dsp));
! 		osi_QAdd((osi_queue_t **) &amp;smb_firstDirSearchp, &amp;dsp-&gt;q);
! 		if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &amp;dsp-&gt;q;
! 		dsp-&gt;cookie = smb_dirSearchCounter;
! 		++smb_dirSearchCounter;
! 		dsp-&gt;refCount = 1;
! 		lock_InitializeMutex(&amp;dsp-&gt;mx, "cm_dirSearch_t");
! 		dsp-&gt;lastTime = osi_Time();
! 		break;
! 	}	
! 	lock_ReleaseWrite(&amp;smb_globalLock);
! 	return dsp;
  }
  
  static smb_packet_t *GetPacket(void)
  {
! 	smb_packet_t *tbp;
  #ifdef DJGPP
!         unsigned int npar, seg, tb_sel;
  #endif
  
! 	lock_ObtainWrite(&amp;smb_globalLock);
! 	tbp = smb_packetFreeListp;
      if (tbp) 
          smb_packetFreeListp = tbp-&gt;nextp;
! 	lock_ReleaseWrite(&amp;smb_globalLock);
      if (!tbp) {
  #ifndef DJGPP
          tbp = calloc(65540,1);
--- 1669,1732 ----
   */
  smb_dirSearch_t *smb_NewDirSearch(int isV3)
  {
!     smb_dirSearch_t *dsp;
!     int counter;
!     int maxAllowed;
! 
!     lock_ObtainWrite(&amp;smb_globalLock);
!     counter = 0;
! 
!     /* what's the biggest ID allowed in this version of the protocol */
!     if (isV3) maxAllowed = 65535;
!     else maxAllowed = 255;
! 
!     while(1) {
!         /* twice so we have enough tries to find guys we GC after one pass;
!          * 10 extra is just in case I mis-counted.
!          */
!         if (++counter &gt; 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
!                                                     __FILE__, __LINE__);
!         if (smb_dirSearchCounter &gt; maxAllowed) {	
!             smb_dirSearchCounter = 1;
!             smb_GCDirSearches(isV3);	/* GC some (drops global lock) */
!         }	
!         dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
!         if (dsp) {
!             /* don't need to watch for refcount zero and deleted, since
!             * we haven't dropped the global lock.
!             */
!             dsp-&gt;refCount--;
!             ++smb_dirSearchCounter;
!             continue;
!         }	
! 
!         dsp = malloc(sizeof(*dsp));
!         memset(dsp, 0, sizeof(*dsp));
!         osi_QAdd((osi_queue_t **) &amp;smb_firstDirSearchp, &amp;dsp-&gt;q);
!         if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &amp;dsp-&gt;q;
!         dsp-&gt;cookie = smb_dirSearchCounter;
!         ++smb_dirSearchCounter;
!         dsp-&gt;refCount = 1;
!         lock_InitializeMutex(&amp;dsp-&gt;mx, "cm_dirSearch_t");
!         dsp-&gt;lastTime = osi_Time();
!         break;
!     }	
!     lock_ReleaseWrite(&amp;smb_globalLock);
!     return dsp;
  }
  
  static smb_packet_t *GetPacket(void)
  {
!     smb_packet_t *tbp;
  #ifdef DJGPP
!     unsigned int npar, seg, tb_sel;
  #endif
  
!     lock_ObtainWrite(&amp;smb_globalLock);
!     tbp = smb_packetFreeListp;
      if (tbp) 
          smb_packetFreeListp = tbp-&gt;nextp;
!     lock_ReleaseWrite(&amp;smb_globalLock);
      if (!tbp) {
  #ifndef DJGPP
          tbp = calloc(65540,1);
***************
*** 1721,1736 ****
          tbp = malloc(sizeof(smb_packet_t));
  #endif /* !DJGPP */
          tbp-&gt;magic = SMB_PACKETMAGIC;
! 		tbp-&gt;ncbp = NULL;
! 		tbp-&gt;vcp = NULL;
! 		tbp-&gt;resumeCode = 0;
! 		tbp-&gt;inCount = 0;
! 		tbp-&gt;fid = 0;
! 		tbp-&gt;wctp = NULL;
! 		tbp-&gt;inCom = 0;
! 		tbp-&gt;oddByte = 0;
! 		tbp-&gt;ncb_length = 0;
! 		tbp-&gt;flags = 0;
          tbp-&gt;spacep = NULL;
          
  #ifdef DJGPP
--- 1734,1749 ----
          tbp = malloc(sizeof(smb_packet_t));
  #endif /* !DJGPP */
          tbp-&gt;magic = SMB_PACKETMAGIC;
!         tbp-&gt;ncbp = NULL;
!         tbp-&gt;vcp = NULL;
!         tbp-&gt;resumeCode = 0;
!         tbp-&gt;inCount = 0;
!         tbp-&gt;fid = 0;
!         tbp-&gt;wctp = NULL;
!         tbp-&gt;inCom = 0;
!         tbp-&gt;oddByte = 0;
!         tbp-&gt;ncb_length = 0;
!         tbp-&gt;flags = 0;
          tbp-&gt;spacep = NULL;
          
  #ifdef DJGPP
***************
*** 1752,1758 ****
          tbp-&gt;dos_pkt = (seg * 16) + 0;  /* DOS physical address */
          tbp-&gt;dos_pkt_sel = tb_sel;
  #endif /* DJGPP */
! 	}
      osi_assert(tbp-&gt;magic == SMB_PACKETMAGIC);
  
      return tbp;
--- 1765,1771 ----
          tbp-&gt;dos_pkt = (seg * 16) + 0;  /* DOS physical address */
          tbp-&gt;dos_pkt_sel = tb_sel;
  #endif /* DJGPP */
!     }
      osi_assert(tbp-&gt;magic == SMB_PACKETMAGIC);
  
      return tbp;
***************
*** 1760,1785 ****
  
  smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
  {
! 	smb_packet_t *tbp;
! 	tbp = GetPacket();
! 	memcpy(tbp, pkt, sizeof(smb_packet_t));
! 	tbp-&gt;wctp = tbp-&gt;data + ((unsigned int)pkt-&gt;wctp - (unsigned int)pkt-&gt;data);
! 	return tbp;
  }
  
  static NCB *GetNCB(void)
  {
! 	smb_ncb_t *tbp;
      NCB *ncbp;
  #ifdef DJGPP
      unsigned int npar, seg, tb_sel;
  #endif /* DJGPP */
  
! 	lock_ObtainWrite(&amp;smb_globalLock);
! 	tbp = smb_ncbFreeListp;
      if (tbp) 
          smb_ncbFreeListp = tbp-&gt;nextp;
! 	lock_ReleaseWrite(&amp;smb_globalLock);
      if (!tbp) {
  #ifndef DJGPP
          tbp = calloc(sizeof(*tbp),1);
--- 1773,1798 ----
  
  smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
  {
!     smb_packet_t *tbp;
!     tbp = GetPacket();
!     memcpy(tbp, pkt, sizeof(smb_packet_t));
!     tbp-&gt;wctp = tbp-&gt;data + ((unsigned int)pkt-&gt;wctp - (unsigned int)pkt-&gt;data);
!     return tbp;
  }
  
  static NCB *GetNCB(void)
  {
!     smb_ncb_t *tbp;
      NCB *ncbp;
  #ifdef DJGPP
      unsigned int npar, seg, tb_sel;
  #endif /* DJGPP */
  
!     lock_ObtainWrite(&amp;smb_globalLock);
!     tbp = smb_ncbFreeListp;
      if (tbp) 
          smb_ncbFreeListp = tbp-&gt;nextp;
!     lock_ReleaseWrite(&amp;smb_globalLock);
      if (!tbp) {
  #ifndef DJGPP
          tbp = calloc(sizeof(*tbp),1);
***************
*** 1803,1813 ****
          tbp-&gt;dos_ncb_sel = tb_sel;
  #endif /* !DJGPP */
          tbp-&gt;magic = SMB_NCBMAGIC;
! 	}
          
      osi_assert(tbp-&gt;magic == SMB_NCBMAGIC);
  
! 	memset(&amp;tbp-&gt;ncb, 0, sizeof(NCB));
      ncbp = &amp;tbp-&gt;ncb;
  #ifdef DJGPP
      dos_memset(tbp-&gt;dos_ncb, 0, sizeof(NCB));
--- 1816,1826 ----
          tbp-&gt;dos_ncb_sel = tb_sel;
  #endif /* !DJGPP */
          tbp-&gt;magic = SMB_NCBMAGIC;
!     }
          
      osi_assert(tbp-&gt;magic == SMB_NCBMAGIC);
  
!     memset(&amp;tbp-&gt;ncb, 0, sizeof(NCB));
      ncbp = &amp;tbp-&gt;ncb;
  #ifdef DJGPP
      dos_memset(tbp-&gt;dos_ncb, 0, sizeof(NCB));
***************
*** 1820,1851 ****
      osi_assert(tbp-&gt;magic == SMB_PACKETMAGIC);
          
      lock_ObtainWrite(&amp;smb_globalLock);
! 	tbp-&gt;nextp = smb_packetFreeListp;
! 	smb_packetFreeListp = tbp;
! 	tbp-&gt;magic = SMB_PACKETMAGIC;
! 	tbp-&gt;ncbp = NULL;
! 	tbp-&gt;vcp = NULL;
! 	tbp-&gt;resumeCode = 0;
! 	tbp-&gt;inCount = 0;
! 	tbp-&gt;fid = 0;
! 	tbp-&gt;wctp = NULL;
! 	tbp-&gt;inCom = 0;
! 	tbp-&gt;oddByte = 0;
! 	tbp-&gt;ncb_length = 0;
! 	tbp-&gt;flags = 0;
      lock_ReleaseWrite(&amp;smb_globalLock);
  }
  
  static void FreeNCB(NCB *bufferp)
  {
! 	smb_ncb_t *tbp;
          
      tbp = (smb_ncb_t *) bufferp;
      osi_assert(tbp-&gt;magic == SMB_NCBMAGIC);
          
      lock_ObtainWrite(&amp;smb_globalLock);
! 	tbp-&gt;nextp = smb_ncbFreeListp;
! 	smb_ncbFreeListp = tbp;
      lock_ReleaseWrite(&amp;smb_globalLock);
  }
  
--- 1833,1864 ----
      osi_assert(tbp-&gt;magic == SMB_PACKETMAGIC);
          
      lock_ObtainWrite(&amp;smb_globalLock);
!     tbp-&gt;nextp = smb_packetFreeListp;
!     smb_packetFreeListp = tbp;
!     tbp-&gt;magic = SMB_PACKETMAGIC;
!     tbp-&gt;ncbp = NULL;
!     tbp-&gt;vcp = NULL;
!     tbp-&gt;resumeCode = 0;
!     tbp-&gt;inCount = 0;
!     tbp-&gt;fid = 0;
!     tbp-&gt;wctp = NULL;
!     tbp-&gt;inCom = 0;
!     tbp-&gt;oddByte = 0;
!     tbp-&gt;ncb_length = 0;
!     tbp-&gt;flags = 0;
      lock_ReleaseWrite(&amp;smb_globalLock);
  }
  
  static void FreeNCB(NCB *bufferp)
  {
!     smb_ncb_t *tbp;
          
      tbp = (smb_ncb_t *) bufferp;
      osi_assert(tbp-&gt;magic == SMB_NCBMAGIC);
          
      lock_ObtainWrite(&amp;smb_globalLock);
!     tbp-&gt;nextp = smb_ncbFreeListp;
!     smb_ncbFreeListp = tbp;
      lock_ReleaseWrite(&amp;smb_globalLock);
  }
  
***************
*** 1857,1868 ****
      unsigned char *afterParmsp;
  
      parmBytes = *smbp-&gt;wctp &lt;&lt; 1;
! 	afterParmsp = smbp-&gt;wctp + parmBytes + 1;
          
      dataBytes = afterParmsp[0] + (afterParmsp[1]&lt;&lt;8);
      if (nbytesp) *nbytesp = dataBytes;
          
! 	/* don't forget to skip the data byte count, since it follows
       * the parameters; that's where the "2" comes from below.
       */
      return (unsigned char *) (afterParmsp + 2);
--- 1870,1881 ----
      unsigned char *afterParmsp;
  
      parmBytes = *smbp-&gt;wctp &lt;&lt; 1;
!     afterParmsp = smbp-&gt;wctp + parmBytes + 1;
          
      dataBytes = afterParmsp[0] + (afterParmsp[1]&lt;&lt;8);
      if (nbytesp) *nbytesp = dataBytes;
          
!     /* don't forget to skip the data byte count, since it follows
       * the parameters; that's where the "2" comes from below.
       */
      return (unsigned char *) (afterParmsp + 2);
***************
*** 1874,2454 ****
   */
  void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
  {
! 	unsigned char *afterParmsp;
  
! 	afterParmsp = smbp-&gt;wctp + ((*smbp-&gt;wctp)&lt;&lt;1) + 1;
          
! 	*afterParmsp++ = dsize &amp; 0xff;
! 	*afterParmsp = (dsize&gt;&gt;8) &amp; 0xff;
! }
  
  /* return the parm'th parameter in the smbp packet */
  unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
  {
! 	int parmCount;
! 	unsigned char *parmDatap;
  
! 	parmCount = *smbp-&gt;wctp;
  
! 	if (parm &gt;= parmCount) {
! 		char s[100];
  #ifndef DJGPP
          HANDLE h;
! 		char *ptbuf[1];
! 		h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! #endif
! 		sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
! 				parm, parmCount, smbp-&gt;ncb_length);
! #ifndef DJGPP
! 		ptbuf[0] = s;
! 		ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
! 					1, smbp-&gt;ncb_length, ptbuf, smbp);
! 		DeregisterEventSource(h);
  #endif
          osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
! 		osi_panic(s, __FILE__, __LINE__);
! 	}
! 	parmDatap = smbp-&gt;wctp + (2*parm) + 1;
          
! 	return parmDatap[0] + (parmDatap[1] &lt;&lt; 8);
  }
  
  /* return the parm'th parameter in the smbp packet */
  unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
  {
! 	int parmCount;
! 	unsigned char *parmDatap;
  
! 	parmCount = *smbp-&gt;wctp;
  
! 	if (parm * 2 + offset &gt;= parmCount * 2) {
! 		char s[100];
  #ifndef DJGPP
! 		HANDLE h;
! 		char *ptbuf[1];
! 		h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
  #endif
! 		sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
! 				parm, offset, parmCount, smbp-&gt;ncb_length);
  #ifndef DJGPP
          ptbuf[0] = s;
! 		ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
! 					1, smbp-&gt;ncb_length, ptbuf, smbp);
! 		DeregisterEventSource(h);
  #endif
          osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
! 		osi_panic(s, __FILE__, __LINE__);
! 	}
! 	parmDatap = smbp-&gt;wctp + (2*parm) + 1 + offset;
  	
! 	return parmDatap[0] + (parmDatap[1] &lt;&lt; 8);
  }
  
  void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
! 	char *parmDatap;
  
! 	/* make sure we have enough slots */
! 	if (*smbp-&gt;wctp &lt;= slot) *smbp-&gt;wctp = slot+1;
!         
! 	parmDatap = smbp-&gt;wctp + 2*slot + 1 + smbp-&gt;oddByte;
! 	*parmDatap++ = parmValue &amp; 0xff;
! 	*parmDatap = (parmValue&gt;&gt;8) &amp; 0xff;
! }
  
  void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
! 	char *parmDatap;
! 
! 	/* make sure we have enough slots */
! 	if (*smbp-&gt;wctp &lt;= slot) *smbp-&gt;wctp = slot+2;
  
! 	parmDatap = smbp-&gt;wctp + 2*slot + 1 + smbp-&gt;oddByte;
! 	*parmDatap++ = parmValue &amp; 0xff;
! 	*parmDatap++ = (parmValue&gt;&gt;8) &amp; 0xff;
! 	*parmDatap++ = (parmValue&gt;&gt;16) &amp; 0xff;
! 	*parmDatap++ = (parmValue&gt;&gt;24) &amp; 0xff;
  }
  
  void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
  {
! 	char *parmDatap;
! 	int i;
! 
! 	/* make sure we have enough slots */
! 	if (*smbp-&gt;wctp &lt;= slot) *smbp-&gt;wctp = slot+4;
  
! 	parmDatap = smbp-&gt;wctp + 2*slot + 1 + smbp-&gt;oddByte;
! 	for (i=0; i&lt;8; i++)
! 		*parmDatap++ = *parmValuep++;
! }
  
  void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
! 	char *parmDatap;
  
! 	/* make sure we have enough slots */
! 	if (*smbp-&gt;wctp &lt;= slot) {
! 		if (smbp-&gt;oddByte) {
! 			smbp-&gt;oddByte = 0;
! 			*smbp-&gt;wctp = slot+1;
! 		} else
! 			smbp-&gt;oddByte = 1;
! 	}
  
! 	parmDatap = smbp-&gt;wctp + 2*slot + 1 + (1 - smbp-&gt;oddByte);
! 	*parmDatap++ = parmValue &amp; 0xff;
  }
  
  void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
  {
! 	char *lastSlashp;
          
! 	lastSlashp = strrchr(inPathp, '\\');
! 	if (lastComponentp)
! 		*lastComponentp = lastSlashp;
! 	if (lastSlashp) {
! 		while (1) {
! 			if (inPathp == lastSlashp) 
! 				break;
! 			*outPathp++ = *inPathp++;
! 		}
! 		*outPathp++ = 0;
! 	}
! 	else {
! 		*outPathp++ = 0;
! 	}
  }
  
  unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
  {
! 	if (*inp++ != 0x4) 
! 		return NULL;
! 	if (chainpp) {
! 		*chainpp = inp + strlen(inp) + 1;	/* skip over null-terminated string */
! 	}
! 	return inp;
  }
  
  unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
  {
! 	int tlen;
  
! 	if (*inp++ != 0x5) 
! 		return NULL;
! 	tlen = inp[0] + (inp[1]&lt;&lt;8);
! 	inp += 2;		/* skip length field */
!         
! 	if (chainpp) {
! 		*chainpp = inp + tlen;
! 	}
          
! 	if (lengthp) 
! 		*lengthp = tlen;
          
! 	return inp;
  }	
  
  /* format a packet as a response */
  void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
  {
! 	smb_t *outp;
! 	smb_t *inSmbp;
  
! 	outp = (smb_t *) op;
  	
! 	/* zero the basic structure through the smb_wct field, and zero the data
! 	 * size field, assuming that wct stays zero; otherwise, you have to 
! 	 * explicitly set the data size field, too.
! 	 */
! 	inSmbp = (smb_t *) inp;
! 	memset(outp, 0, sizeof(smb_t)+2);
! 	outp-&gt;id[0] = 0xff;
! 	outp-&gt;id[1] = 'S';
! 	outp-&gt;id[2] = 'M';
! 	outp-&gt;id[3] = 'B';
! 	if (inp) {
! 		outp-&gt;com = inSmbp-&gt;com;
! 		outp-&gt;tid = inSmbp-&gt;tid;
! 		outp-&gt;pid = inSmbp-&gt;pid;
! 		outp-&gt;uid = inSmbp-&gt;uid;
! 		outp-&gt;mid = inSmbp-&gt;mid;
! 		outp-&gt;res[0] = inSmbp-&gt;res[0];
! 		outp-&gt;res[1] = inSmbp-&gt;res[1];
! 		op-&gt;inCom = inSmbp-&gt;com;
! 	}
! 	outp-&gt;reb = 0x80;	/* SERVER_RESP */
! 	outp-&gt;flg2 = 0x1;	/* KNOWS_LONG_NAMES */
! 
! 	/* copy fields in generic packet area */
! 	op-&gt;wctp = &amp;outp-&gt;wct;
! }
  
  /* send a (probably response) packet; vcp tells us to whom to send it.
   * we compute the length by looking at wct and bcc fields.
   */
  void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
  {
! 	NCB *ncbp;
! 	int extra;
! 	long code = 0;
! 	unsigned char *tp;
! 	int localNCB = 0;
  #ifdef DJGPP
! 	dos_ptr dos_ncb;
  #endif /* DJGPP */
          
! 	ncbp = inp-&gt;ncbp;
! 	if (ncbp == NULL) {
! 		ncbp = GetNCB();
! 		localNCB = 1;
! 	}
  #ifdef DJGPP
! 	dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
   
! 	memset((char *)ncbp, 0, sizeof(NCB));
  
! 	extra = 2 * (*inp-&gt;wctp);	/* space used by parms, in bytes */
! 	tp = inp-&gt;wctp + 1+ extra;	/* points to count of data bytes */
! 	extra += tp[0] + (tp[1]&lt;&lt;8);
! 	extra += ((unsigned int)inp-&gt;wctp - (unsigned int)inp-&gt;data);	/* distance to last wct field */
! 	extra += 3;			/* wct and length fields */
!         
! 	ncbp-&gt;ncb_length = extra;	/* bytes to send */
! 	ncbp-&gt;ncb_lsn = (unsigned char) vcp-&gt;lsn;	/* vc to use */
! 	ncbp-&gt;ncb_lana_num = vcp-&gt;lana;
! 	ncbp-&gt;ncb_command = NCBSEND;	/* op means send data */
  #ifndef DJGPP
! 	ncbp-&gt;ncb_buffer = (char *) inp;/* packet */
! 	code = Netbios(ncbp);
  #else /* DJGPP */
! 	ncbp-&gt;ncb_buffer = inp-&gt;dos_pkt;/* packet */
! 	((smb_ncb_t*)ncbp)-&gt;orig_pkt = inp;
  
! 	/* copy header information from virtual to DOS address space */
! 	dosmemput((char*)inp, SMB_PACKETSIZE, inp-&gt;dos_pkt);
! 	code = Netbios(ncbp, dos_ncb);
  #endif /* !DJGPP */
          
! 	if (code != 0)
! 		osi_Log1(smb_logp, "SendPacket failure code %d", code);
  
! 	if (localNCB)
! 		FreeNCB(ncbp);
  }
  
  void smb_MapNTError(long code, unsigned long *NTStatusp)
  {
! 	unsigned long NTStatus;
  
! 	/* map CM_ERROR_* errors to NT 32-bit status codes */
      /* NT Status codes are listed in ntstatus.h not winerror.h */
! 	if (code == CM_ERROR_NOSUCHCELL) {
! 		NTStatus = 0xC000000FL;	/* No such file */
! 	}
! 	else if (code == CM_ERROR_NOSUCHVOLUME) {
! 		NTStatus = 0xC000000FL;	/* No such file */
! 	}
! 	else if (code == CM_ERROR_TIMEDOUT) {
! 		NTStatus = 0xC00000CFL;	/* Sharing Paused */
! 	}
! 	else if (code == CM_ERROR_RETRY) {
! 		NTStatus = 0xC000022DL;	/* Retry */
! 	}
! 	else if (code == CM_ERROR_NOACCESS) {
! 		NTStatus = 0xC0000022L;	/* Access denied */
! 	}
! 	else if (code == CM_ERROR_READONLY) {
! 		NTStatus = 0xC00000A2L;	/* Write protected */
! 	}	
! 	else if (code == CM_ERROR_NOSUCHFILE) {
! 		NTStatus = 0xC000000FL;	/* No such file */
! 	}
! 	else if (code == CM_ERROR_NOSUCHPATH) {
! 		NTStatus = 0xC000003AL;	/* Object path not found */
! 	}		
! 	else if (code == CM_ERROR_TOOBIG) {
! 		NTStatus = 0xC000007BL;	/* Invalid image format */
! 	}
! 	else if (code == CM_ERROR_INVAL) {
! 		NTStatus = 0xC000000DL;	/* Invalid parameter */
! 	}
! 	else if (code == CM_ERROR_BADFD) {
! 		NTStatus = 0xC0000008L;	/* Invalid handle */
! 	}
! 	else if (code == CM_ERROR_BADFDOP) {
! 		NTStatus = 0xC0000022L;	/* Access denied */
! 	}
! 	else if (code == CM_ERROR_EXISTS) {
! 		NTStatus = 0xC0000035L;	/* Object name collision */
! 	}
! 	else if (code == CM_ERROR_NOTEMPTY) {
! 		NTStatus = 0xC0000101L;	/* Directory not empty */
! 	}	
! 	else if (code == CM_ERROR_CROSSDEVLINK) {
! 		NTStatus = 0xC00000D4L;	/* Not same device */
! 	}
! 	else if (code == CM_ERROR_NOTDIR) {
! 		NTStatus = 0xC0000103L;	/* Not a directory */
! 	}
! 	else if (code == CM_ERROR_ISDIR) {
! 		NTStatus = 0xC00000BAL;	/* File is a directory */
! 	}
! 	else if (code == CM_ERROR_BADOP) {
! 		NTStatus = 0xC09820FFL;	/* SMB no support */
! 	}
! 	else if (code == CM_ERROR_BADSHARENAME) {
! 		NTStatus = 0xC00000CCL;	/* Bad network name */
! 	}
! 	else if (code == CM_ERROR_NOIPC) {
  #ifdef COMMENT
! 		NTStatus = 0xC0000022L;	/* Access Denied */
  #else
!         NTStatus = 0xC000013DL; /* Remote Resources */
  #endif
! 	}
! 	else if (code == CM_ERROR_CLOCKSKEW) {
! 		NTStatus = 0xC0000133L;	/* Time difference at DC */
! 	}
! 	else if (code == CM_ERROR_BADTID) {
! 		NTStatus = 0xC0982005L;	/* SMB bad TID */
! 	}
! 	else if (code == CM_ERROR_USESTD) {
! 		NTStatus = 0xC09820FBL;	/* SMB use standard */
! 	}
! 	else if (code == CM_ERROR_QUOTA) {
! 		NTStatus = 0xC0000044L;	/* Quota exceeded */
! 	}
! 	else if (code == CM_ERROR_SPACE) {
! 		NTStatus = 0xC000007FL;	/* Disk full */
! 	}
! 	else if (code == CM_ERROR_ATSYS) {
! 		NTStatus = 0xC0000033L;	/* Object name invalid */
! 	}
! 	else if (code == CM_ERROR_BADNTFILENAME) {
! 		NTStatus = 0xC0000033L;	/* Object name invalid */
! 	}
! 	else if (code == CM_ERROR_WOULDBLOCK) {
! 		NTStatus = 0xC0000055L;	/* Lock not granted */
! 	}
! 	else if (code == CM_ERROR_PARTIALWRITE) {
! 		NTStatus = 0xC000007FL;	/* Disk full */
! 	}
! 	else if (code == CM_ERROR_BUFFERTOOSMALL) {
! 		NTStatus = 0xC0000023L;	/* Buffer too small */
! 	}
      else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
! 		NTStatus = 0xC0000035L;	/* Object name collision */
      }
- 	else if (code == CM_ERROR_BADPASSWORD) {
- 		NTStatus = 0xC000006DL; /* unknown username or bad password */
- 	}
- 	else if (code == CM_ERROR_BADLOGONTYPE) {
- 		NTStatus = 0xC000015BL; /* logon type not granted */
- 	}
- 	else if (code == CM_ERROR_GSSCONTINUE) {
- 		NTStatus = 0xC0000016L; /* more processing required */
- 	}
- 	else {
- 		NTStatus = 0xC0982001L;	/* SMB non-specific error */
- 	}
  
! 	*NTStatusp = NTStatus;
! 	osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
! }
  
  void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
! 	unsigned char *classp)
  {
! 	unsigned char class;
! 	unsigned short error;
  
! 	/* map CM_ERROR_* errors to SMB errors */
! 	if (code == CM_ERROR_NOSUCHCELL) {
! 		class = 1;
! 		error = 3;	/* bad path */
! 	}
! 	else if (code == CM_ERROR_NOSUCHVOLUME) {
! 		class = 1;
! 		error = 3;	/* bad path */
! 	}
! 	else if (code == CM_ERROR_TIMEDOUT) {
! 		class = 2;
! 		error = 81;	/* server is paused */
! 	}
! 	else if (code == CM_ERROR_RETRY) {
! 		class = 2;	/* shouldn't happen */
! 		error = 1;
! 	}
! 	else if (code == CM_ERROR_NOACCESS) {
! 		class = 2;
! 		error = 4;	/* bad access */
! 	}
! 	else if (code == CM_ERROR_READONLY) {
! 		class = 3;
! 		error = 19;	/* read only */
! 	}
! 	else if (code == CM_ERROR_NOSUCHFILE) {
! 		class = 1;
! 		error = 2;	/* ENOENT! */
! 	}
! 	else if (code == CM_ERROR_NOSUCHPATH) {
! 		class = 1;
! 		error = 3;	/* Bad path */
! 	}
! 	else if (code == CM_ERROR_TOOBIG) {
! 		class = 1;
! 		error = 11;	/* bad format */
! 	}
! 	else if (code == CM_ERROR_INVAL) {
! 		class = 2;	/* server non-specific error code */
! 		error = 1;
! 	}
! 	else if (code == CM_ERROR_BADFD) {
! 		class = 1;
! 		error = 6;	/* invalid file handle */
! 	}
! 	else if (code == CM_ERROR_BADFDOP) {
! 		class = 1;	/* invalid op on FD */
! 		error = 5;
! 	}
! 	else if (code == CM_ERROR_EXISTS) {
! 		class = 1;
! 		error = 80;	/* file already exists */
! 	}
! 	else if (code == CM_ERROR_NOTEMPTY) {
! 		class = 1;
! 		error = 5;	/* delete directory not empty */
! 	}
! 	else if (code == CM_ERROR_CROSSDEVLINK) {
! 		class = 1;
! 		error = 17;	/* EXDEV */
! 	}
! 	else if (code == CM_ERROR_NOTDIR) {
! 		class = 1;	/* bad path */
! 		error = 3;
! 	}
! 	else if (code == CM_ERROR_ISDIR) {
! 		class = 1;	/* access denied; DOS doesn't have a good match */
! 		error = 5;
! 	}
! 	else if (code == CM_ERROR_BADOP) {
! 		class = 2;
! 		error = 65535;
! 	}
! 	else if (code == CM_ERROR_BADSHARENAME) {
! 		class = 2;
! 		error = 6;
! 	}
! 	else if (code == CM_ERROR_NOIPC) {
! 		class = 2;
! 		error = 4; /* bad access */
! 	}
! 	else if (code == CM_ERROR_CLOCKSKEW) {
! 		class = 1;	/* invalid function */
! 		error = 1;
! 	}
! 	else if (code == CM_ERROR_BADTID) {
! 		class = 2;
! 		error = 5;
! 	}
! 	else if (code == CM_ERROR_USESTD) {
! 		class = 2;
! 		error = 251;
! 	}
! 	else if (code == CM_ERROR_REMOTECONN) {
! 		class = 2;
! 		error = 82;
! 	}
! 	else if (code == CM_ERROR_QUOTA) {
! 		if (vcp-&gt;flags &amp; SMB_VCFLAG_USEV3) {
! 			class = 3;
! 			error = 39;	/* disk full */
! 		}
! 		else {
! 			class = 1;
! 			error = 5;	/* access denied */
! 		}
! 	}
! 	else if (code == CM_ERROR_SPACE) {
! 		if (vcp-&gt;flags &amp; SMB_VCFLAG_USEV3) {
! 			class = 3;
! 			error = 39;	/* disk full */
! 		}
! 		else {
! 			class = 1;
! 			error = 5;	/* access denied */
! 		}
! 	}
! 	else if (code == CM_ERROR_PARTIALWRITE) {
! 		class = 3;
! 		error = 39;	/* disk full */
! 	}
! 	else if (code == CM_ERROR_ATSYS) {
! 		class = 1;
! 		error = 2;	/* ENOENT */
! 	}
! 	else if (code == CM_ERROR_WOULDBLOCK) {
! 		class = 1;
! 		error = 33;	/* lock conflict */
! 	}
! 	else if (code == CM_ERROR_NOFILES) {
! 		class = 1;
! 		error = 18;	/* no files in search */
! 	}
! 	else if (code == CM_ERROR_RENAME_IDENTICAL) {
! 		class = 1;
! 		error = 183;     /* Samba uses this */
! 	}
! 	else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
! 		/* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
! 		class = 2;
! 		error = 2; /* bad password */
! 	}
! 	else {
! 		class = 2;
! 		error = 1;
! 	}
! 
! 	*scodep = error;
! 	*classp = class;
! 	osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
! }
  
  long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	return CM_ERROR_BADOP;
  }
  
  long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	unsigned short EchoCount, i;
! 	char *data, *outdata;
! 	int dataSize;
! 
! 	EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
! 
! 	for (i=1; i&lt;=EchoCount; i++) {
! 	    data = smb_GetSMBData(inp, &amp;dataSize);
! 	    smb_SetSMBParm(outp, 0, i);
! 	    smb_SetSMBDataLength(outp, dataSize);
!             outdata = smb_GetSMBData(outp, NULL);
! 	    memcpy(outdata, data, dataSize);
! 	    smb_SendPacket(vcp, outp);
! 	}
  
! 	return 0;
  }
  
  long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	osi_hyper_t offset;
! 	long count, minCount, finalCount;
! 	unsigned short fd;
! 	smb_fid_t *fidp;
! 	long code = 0;
! 	cm_user_t *userp = NULL;
      NCB *ncbp;
      int rc;
  #ifndef DJGPP
--- 1887,2480 ----
   */
  void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
  {
!     unsigned char *afterParmsp;
  
!     afterParmsp = smbp-&gt;wctp + ((*smbp-&gt;wctp)&lt;&lt;1) + 1;
          
!     *afterParmsp++ = dsize &amp; 0xff;
!     *afterParmsp = (dsize&gt;&gt;8) &amp; 0xff;
! }       
  
  /* return the parm'th parameter in the smbp packet */
  unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
  {
!     int parmCount;
!     unsigned char *parmDatap;
  
!     parmCount = *smbp-&gt;wctp;
  
!     if (parm &gt;= parmCount) {
!         char s[100];
  #ifndef DJGPP
          HANDLE h;
!         char *ptbuf[1];
!         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! #endif  
!         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
!                  parm, parmCount, smbp-&gt;ncb_length);
! #ifndef DJGPP   
!         ptbuf[0] = s;
!         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
!                      1, smbp-&gt;ncb_length, ptbuf, smbp);
!         DeregisterEventSource(h);
  #endif
          osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
!         osi_panic(s, __FILE__, __LINE__);
!     }
!     parmDatap = smbp-&gt;wctp + (2*parm) + 1;
          
!     return parmDatap[0] + (parmDatap[1] &lt;&lt; 8);
  }
  
  /* return the parm'th parameter in the smbp packet */
  unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
  {
!     int parmCount;
!     unsigned char *parmDatap;
  
!     parmCount = *smbp-&gt;wctp;
  
!     if (parm * 2 + offset &gt;= parmCount * 2) {
!         char s[100];
  #ifndef DJGPP
!         HANDLE h;
!         char *ptbuf[1];
!         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
  #endif
!         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
!                 parm, offset, parmCount, smbp-&gt;ncb_length);
  #ifndef DJGPP
          ptbuf[0] = s;
!         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
!                     1, smbp-&gt;ncb_length, ptbuf, smbp);
!         DeregisterEventSource(h);
  #endif
          osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
!         osi_panic(s, __FILE__, __LINE__);
!     }
!     parmDatap = smbp-&gt;wctp + (2*parm) + 1 + offset;
  	
!     return parmDatap[0] + (parmDatap[1] &lt;&lt; 8);
  }
  
  void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     char *parmDatap;
  
!     /* make sure we have enough slots */
!     if (*smbp-&gt;wctp &lt;= slot) 
!         *smbp-&gt;wctp = slot+1;
!         
!     parmDatap = smbp-&gt;wctp + 2*slot + 1 + smbp-&gt;oddByte;
!     *parmDatap++ = parmValue &amp; 0xff;
!     *parmDatap = (parmValue&gt;&gt;8) &amp; 0xff;
! }       
  
  void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     char *parmDatap;
  
!     /* make sure we have enough slots */
!     if (*smbp-&gt;wctp &lt;= slot) 
!         *smbp-&gt;wctp = slot+2;
! 
!     parmDatap = smbp-&gt;wctp + 2*slot + 1 + smbp-&gt;oddByte;
!     *parmDatap++ = parmValue &amp; 0xff;
!     *parmDatap++ = (parmValue&gt;&gt;8) &amp; 0xff;
!     *parmDatap++ = (parmValue&gt;&gt;16) &amp; 0xff;
!     *parmDatap++ = (parmValue&gt;&gt;24) &amp; 0xff;
  }
  
  void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
  {
!     char *parmDatap;
!     int i;
  
!     /* make sure we have enough slots */
!     if (*smbp-&gt;wctp &lt;= slot) 
!         *smbp-&gt;wctp = slot+4;
! 
!     parmDatap = smbp-&gt;wctp + 2*slot + 1 + smbp-&gt;oddByte;
!     for (i=0; i&lt;8; i++)
!         *parmDatap++ = *parmValuep++;
! }       
  
  void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     char *parmDatap;
  
!     /* make sure we have enough slots */
!     if (*smbp-&gt;wctp &lt;= slot) {
!         if (smbp-&gt;oddByte) {
!             smbp-&gt;oddByte = 0;
!             *smbp-&gt;wctp = slot+1;
!         } else
!             smbp-&gt;oddByte = 1;
!     }
  
!     parmDatap = smbp-&gt;wctp + 2*slot + 1 + (1 - smbp-&gt;oddByte);
!     *parmDatap++ = parmValue &amp; 0xff;
  }
  
  void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
  {
!     char *lastSlashp;
          
!     lastSlashp = strrchr(inPathp, '\\');
!     if (lastComponentp)
!         *lastComponentp = lastSlashp;
!     if (lastSlashp) {
!         while (1) {
!             if (inPathp == lastSlashp) 
!                 break;
!             *outPathp++ = *inPathp++;
!         }
!         *outPathp++ = 0;
!     }
!     else {
!         *outPathp++ = 0;
!     }
  }
  
  unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
  {
!     if (*inp++ != 0x4) 
!         return NULL;
!     if (chainpp) {
!         *chainpp = inp + strlen(inp) + 1;	/* skip over null-terminated string */
!     }
!     return inp;
  }
  
  unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
  {
!     int tlen;
  
!     if (*inp++ != 0x5) 
!         return NULL;
!     tlen = inp[0] + (inp[1]&lt;&lt;8);
!     inp += 2;		/* skip length field */
! 
!     if (chainpp) {
!         *chainpp = inp + tlen;
!     }
          
!     if (lengthp) 
!         *lengthp = tlen;
          
!     return inp;
  }	
  
  /* format a packet as a response */
  void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
  {
!     smb_t *outp;
!     smb_t *inSmbp;
  
!     outp = (smb_t *) op;
  	
!     /* zero the basic structure through the smb_wct field, and zero the data
!      * size field, assuming that wct stays zero; otherwise, you have to 
!      * explicitly set the data size field, too.
!      */
!     inSmbp = (smb_t *) inp;
!     memset(outp, 0, sizeof(smb_t)+2);
!     outp-&gt;id[0] = 0xff;
!     outp-&gt;id[1] = 'S';
!     outp-&gt;id[2] = 'M';
!     outp-&gt;id[3] = 'B';
!     if (inp) {
!         outp-&gt;com = inSmbp-&gt;com;
!         outp-&gt;tid = inSmbp-&gt;tid;
!         outp-&gt;pid = inSmbp-&gt;pid;
!         outp-&gt;uid = inSmbp-&gt;uid;
!         outp-&gt;mid = inSmbp-&gt;mid;
!         outp-&gt;res[0] = inSmbp-&gt;res[0];
!         outp-&gt;res[1] = inSmbp-&gt;res[1];
!         op-&gt;inCom = inSmbp-&gt;com;
!     }
!     outp-&gt;reb = 0x80;	/* SERVER_RESP */
!     outp-&gt;flg2 = 0x1;	/* KNOWS_LONG_NAMES */
! 
!     /* copy fields in generic packet area */
!     op-&gt;wctp = &amp;outp-&gt;wct;
! }       
  
  /* send a (probably response) packet; vcp tells us to whom to send it.
   * we compute the length by looking at wct and bcc fields.
   */
  void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
  {
!     NCB *ncbp;
!     int extra;
!     long code = 0;
!     unsigned char *tp;
!     int localNCB = 0;
  #ifdef DJGPP
!     dos_ptr dos_ncb;
  #endif /* DJGPP */
          
!     ncbp = inp-&gt;ncbp;
!     if (ncbp == NULL) {
!         ncbp = GetNCB();
!         localNCB = 1;
!     }
  #ifdef DJGPP
!     dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
   
!     memset((char *)ncbp, 0, sizeof(NCB));
  
!     extra = 2 * (*inp-&gt;wctp);	/* space used by parms, in bytes */
!     tp = inp-&gt;wctp + 1+ extra;	/* points to count of data bytes */
!     extra += tp[0] + (tp[1]&lt;&lt;8);
!     extra += ((unsigned int)inp-&gt;wctp - (unsigned int)inp-&gt;data);	/* distance to last wct field */
!     extra += 3;			/* wct and length fields */
!         
!     ncbp-&gt;ncb_length = extra;	/* bytes to send */
!     ncbp-&gt;ncb_lsn = (unsigned char) vcp-&gt;lsn;	/* vc to use */
!     ncbp-&gt;ncb_lana_num = vcp-&gt;lana;
!     ncbp-&gt;ncb_command = NCBSEND;	/* op means send data */
  #ifndef DJGPP
!     ncbp-&gt;ncb_buffer = (char *) inp;/* packet */
!     code = Netbios(ncbp);
  #else /* DJGPP */
!     ncbp-&gt;ncb_buffer = inp-&gt;dos_pkt;/* packet */
!     ((smb_ncb_t*)ncbp)-&gt;orig_pkt = inp;
  
!     /* copy header information from virtual to DOS address space */
!     dosmemput((char*)inp, SMB_PACKETSIZE, inp-&gt;dos_pkt);
!     code = Netbios(ncbp, dos_ncb);
  #endif /* !DJGPP */
          
!     if (code != 0)
!         osi_Log1(smb_logp, "SendPacket failure code %d", code);
  
!     if (localNCB)
!         FreeNCB(ncbp);
  }
  
  void smb_MapNTError(long code, unsigned long *NTStatusp)
  {
!     unsigned long NTStatus;
  
!     /* map CM_ERROR_* errors to NT 32-bit status codes */
      /* NT Status codes are listed in ntstatus.h not winerror.h */
!     if (code == CM_ERROR_NOSUCHCELL) {
!         NTStatus = 0xC000000FL;	/* No such file */
!     }
!     else if (code == CM_ERROR_NOSUCHVOLUME) {
!         NTStatus = 0xC000000FL;	/* No such file */
!     }
!     else if (code == CM_ERROR_TIMEDOUT) {
!         NTStatus = 0xC00000CFL;	/* Sharing Paused */
!     }
!     else if (code == CM_ERROR_RETRY) {
!         NTStatus = 0xC000022DL;	/* Retry */
!     }
!     else if (code == CM_ERROR_NOACCESS) {
!         NTStatus = 0xC0000022L;	/* Access denied */
!     }
!     else if (code == CM_ERROR_READONLY) {
!         NTStatus = 0xC00000A2L;	/* Write protected */
!     }	
!     else if (code == CM_ERROR_NOSUCHFILE) {
!         NTStatus = 0xC000000FL;	/* No such file */
!     }
!     else if (code == CM_ERROR_NOSUCHPATH) {
!         NTStatus = 0xC000003AL;	/* Object path not found */
!     }		
!     else if (code == CM_ERROR_TOOBIG) {
!         NTStatus = 0xC000007BL;	/* Invalid image format */
!     }
!     else if (code == CM_ERROR_INVAL) {
!         NTStatus = 0xC000000DL;	/* Invalid parameter */
!     }
!     else if (code == CM_ERROR_BADFD) {
!         NTStatus = 0xC0000008L;	/* Invalid handle */
!     }
!     else if (code == CM_ERROR_BADFDOP) {
!         NTStatus = 0xC0000022L;	/* Access denied */
!     }
!     else if (code == CM_ERROR_EXISTS) {
!         NTStatus = 0xC0000035L;	/* Object name collision */
!     }
!     else if (code == CM_ERROR_NOTEMPTY) {
!         NTStatus = 0xC0000101L;	/* Directory not empty */
!     }	
!     else if (code == CM_ERROR_CROSSDEVLINK) {
!         NTStatus = 0xC00000D4L;	/* Not same device */
!     }
!     else if (code == CM_ERROR_NOTDIR) {
!         NTStatus = 0xC0000103L;	/* Not a directory */
!     }
!     else if (code == CM_ERROR_ISDIR) {
!         NTStatus = 0xC00000BAL;	/* File is a directory */
!     }
!     else if (code == CM_ERROR_BADOP) {
  #ifdef COMMENT
!         /* I have no idea where this comes from */
!         NTStatus = 0xC09820FFL;	/* SMB no support */
  #else
!         NTStatus = 0xC00000BBL;     /* Not supported */
! #endif /* COMMENT */
!     }
!     else if (code == CM_ERROR_BADSHARENAME) {
!         NTStatus = 0xC00000CCL;	/* Bad network name */
!     }
!     else if (code == CM_ERROR_NOIPC) {
! #ifdef COMMENT
!         NTStatus = 0xC0000022L;	/* Access Denied */
! #else   
!         NTStatus = 0xC000013DL; /* Remote Resources */
! #endif
!     }
!     else if (code == CM_ERROR_CLOCKSKEW) {
!         NTStatus = 0xC0000133L;	/* Time difference at DC */
!     }
!     else if (code == CM_ERROR_BADTID) {
!         NTStatus = 0xC0982005L;	/* SMB bad TID */
!     }
!     else if (code == CM_ERROR_USESTD) {
!         NTStatus = 0xC09820FBL;	/* SMB use standard */
!     }
!     else if (code == CM_ERROR_QUOTA) {
! #ifdef COMMENT
!         NTStatus = 0xC0000044L;	/* Quota exceeded */
! #else
!         NTStatus = 0xC000007FL;	/* Disk full */
  #endif
!     }
!     else if (code == CM_ERROR_SPACE) {
!         NTStatus = 0xC000007FL;	/* Disk full */
!     }
!     else if (code == CM_ERROR_ATSYS) {
!         NTStatus = 0xC0000033L;	/* Object name invalid */
!     }
!     else if (code == CM_ERROR_BADNTFILENAME) {
!         NTStatus = 0xC0000033L;	/* Object name invalid */
!     }
!     else if (code == CM_ERROR_WOULDBLOCK) {
!         NTStatus = 0xC0000055L;	/* Lock not granted */
!     }
!     else if (code == CM_ERROR_PARTIALWRITE) {
!         NTStatus = 0xC000007FL;	/* Disk full */
!     }
!     else if (code == CM_ERROR_BUFFERTOOSMALL) {
!         NTStatus = 0xC0000023L;	/* Buffer too small */
!     }
      else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
!         NTStatus = 0xC0000035L;	/* Object name collision */
!     }   
!     else if (code == CM_ERROR_BADPASSWORD) {
!         NTStatus = 0xC000006DL; /* unknown username or bad password */
!     }
!     else if (code == CM_ERROR_BADLOGONTYPE) {
!         NTStatus = 0xC000015BL; /* logon type not granted */
!     }
!     else if (code == CM_ERROR_GSSCONTINUE) {
!         NTStatus = 0xC0000016L; /* more processing required */
!     }
!     else {
!         NTStatus = 0xC0982001L;	/* SMB non-specific error */
      }
  
!     *NTStatusp = NTStatus;
!     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
! }       
  
  void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
!                       unsigned char *classp)
  {
!     unsigned char class;
!     unsigned short error;
  
!     /* map CM_ERROR_* errors to SMB errors */
!     if (code == CM_ERROR_NOSUCHCELL) {
!         class = 1;
!         error = 3;	/* bad path */
!     }
!     else if (code == CM_ERROR_NOSUCHVOLUME) {
!         class = 1;
!         error = 3;	/* bad path */
!     }
!     else if (code == CM_ERROR_TIMEDOUT) {
!         class = 2;
!         error = 81;	/* server is paused */
!     }
!     else if (code == CM_ERROR_RETRY) {
!         class = 2;	/* shouldn't happen */
!         error = 1;
!     }
!     else if (code == CM_ERROR_NOACCESS) {
!         class = 2;
!         error = 4;	/* bad access */
!     }
!     else if (code == CM_ERROR_READONLY) {
!         class = 3;
!         error = 19;	/* read only */
!     }
!     else if (code == CM_ERROR_NOSUCHFILE) {
!         class = 1;
!         error = 2;	/* ENOENT! */
!     }
!     else if (code == CM_ERROR_NOSUCHPATH) {
!         class = 1;
!         error = 3;	/* Bad path */
!     }
!     else if (code == CM_ERROR_TOOBIG) {
!         class = 1;
!         error = 11;	/* bad format */
!     }
!     else if (code == CM_ERROR_INVAL) {
!         class = 2;	/* server non-specific error code */
!         error = 1;
!     }
!     else if (code == CM_ERROR_BADFD) {
!         class = 1;
!         error = 6;	/* invalid file handle */
!     }
!     else if (code == CM_ERROR_BADFDOP) {
!         class = 1;	/* invalid op on FD */
!         error = 5;
!     }
!     else if (code == CM_ERROR_EXISTS) {
!         class = 1;
!         error = 80;	/* file already exists */
!     }
!     else if (code == CM_ERROR_NOTEMPTY) {
!         class = 1;
!         error = 5;	/* delete directory not empty */
!     }
!     else if (code == CM_ERROR_CROSSDEVLINK) {
!         class = 1;
!         error = 17;	/* EXDEV */
!     }
!     else if (code == CM_ERROR_NOTDIR) {
!         class = 1;	/* bad path */
!         error = 3;
!     }
!     else if (code == CM_ERROR_ISDIR) {
!         class = 1;	/* access denied; DOS doesn't have a good match */
!         error = 5;
!     }       
!     else if (code == CM_ERROR_BADOP) {
!         class = 2;
!         error = 65535;
!     }
!     else if (code == CM_ERROR_BADSHARENAME) {
!         class = 2;
!         error = 6;
!     }
!     else if (code == CM_ERROR_NOIPC) {
!         class = 2;
!         error = 4; /* bad access */
!     }
!     else if (code == CM_ERROR_CLOCKSKEW) {
!         class = 1;	/* invalid function */
!         error = 1;
!     }
!     else if (code == CM_ERROR_BADTID) {
!         class = 2;
!         error = 5;
!     }
!     else if (code == CM_ERROR_USESTD) {
!         class = 2;
!         error = 251;
!     }
!     else if (code == CM_ERROR_REMOTECONN) {
!         class = 2;
!         error = 82;
!     }
!     else if (code == CM_ERROR_QUOTA) {
!         if (vcp-&gt;flags &amp; SMB_VCFLAG_USEV3) {
!             class = 3;
!             error = 39;	/* disk full */
!         }
!         else {
!             class = 1;
!             error = 5;	/* access denied */
!         }
!     }
!     else if (code == CM_ERROR_SPACE) {
!         if (vcp-&gt;flags &amp; SMB_VCFLAG_USEV3) {
!             class = 3;
!             error = 39;	/* disk full */
!         }
!         else {
!             class = 1;
!             error = 5;	/* access denied */
!         }
!     }
!     else if (code == CM_ERROR_PARTIALWRITE) {
!         class = 3;
!         error = 39;	/* disk full */
!     }
!     else if (code == CM_ERROR_ATSYS) {
!         class = 1;
!         error = 2;	/* ENOENT */
!     }
!     else if (code == CM_ERROR_WOULDBLOCK) {
!         class = 1;
!         error = 33;	/* lock conflict */
!     }
!     else if (code == CM_ERROR_NOFILES) {
!         class = 1;
!         error = 18;	/* no files in search */
!     }
!     else if (code == CM_ERROR_RENAME_IDENTICAL) {
!         class = 1;
!         error = 183;     /* Samba uses this */
!     }
!     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
!         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
!         class = 2;
!         error = 2; /* bad password */
!     }
!     else {
!         class = 2;
!         error = 1;
!     }
! 
!     *scodep = error;
!     *classp = class;
!     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
! }       
  
  long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
!     return CM_ERROR_BADOP;
  }
  
  long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     unsigned short EchoCount, i;
!     char *data, *outdata;
!     int dataSize;
! 
!     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
! 
!     for (i=1; i&lt;=EchoCount; i++) {
!         data = smb_GetSMBData(inp, &amp;dataSize);
!         smb_SetSMBParm(outp, 0, i);
!         smb_SetSMBDataLength(outp, dataSize);
!         outdata = smb_GetSMBData(outp, NULL);
!         memcpy(outdata, data, dataSize);
!         smb_SendPacket(vcp, outp);
!     }
  
!     return 0;
  }
  
  long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     osi_hyper_t offset;
!     long count, minCount, finalCount;
!     unsigned short fd;
!     smb_fid_t *fidp;
!     long code = 0;
!     cm_user_t *userp = NULL;
      NCB *ncbp;
      int rc;
  #ifndef DJGPP
***************
*** 2458,2492 ****
      dos_ptr dos_ncb;
  #endif /* DJGPP */
  
! 	rawBuf = NULL;
! 	finalCount = 0;
  
! 	fd = smb_GetSMBParm(inp, 0);
! 	count = smb_GetSMBParm(inp, 3);
! 	minCount = smb_GetSMBParm(inp, 4);
! 	offset.HighPart = 0;	/* too bad */
! 	offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) &lt;&lt; 16);
  
! 	osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
               fd, offset.LowPart, count);
  
! 	fidp = smb_FindFID(vcp, fd, 0);
! 	if (!fidp)
! 		goto send1;
! 
! 	lock_ObtainMutex(&amp;smb_RawBufLock);
! 	if (smb_RawBufs) {
! 		/* Get a raw buf, from head of list */
! 		rawBuf = smb_RawBufs;
  #ifndef DJGPP
! 		smb_RawBufs = *(char **)smb_RawBufs;
  #else /* DJGPP */
          smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
  #endif /* !DJGPP */
! 	}
! 	lock_ReleaseMutex(&amp;smb_RawBufLock);
! 	if (!rawBuf)
! 		goto send1a;
  
      if (fidp-&gt;flags &amp; SMB_FID_IOCTL)
      {
--- 2484,2518 ----
      dos_ptr dos_ncb;
  #endif /* DJGPP */
  
!     rawBuf = NULL;
!     finalCount = 0;
  
!     fd = smb_GetSMBParm(inp, 0);
!     count = smb_GetSMBParm(inp, 3);
!     minCount = smb_GetSMBParm(inp, 4);
!     offset.HighPart = 0;	/* too bad */
!     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) &lt;&lt; 16);
  
!     osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
               fd, offset.LowPart, count);
  
!     fidp = smb_FindFID(vcp, fd, 0);
!     if (!fidp)
!         goto send1;
! 
!     lock_ObtainMutex(&amp;smb_RawBufLock);
!     if (smb_RawBufs) {
!         /* Get a raw buf, from head of list */
!         rawBuf = smb_RawBufs;
  #ifndef DJGPP
!         smb_RawBufs = *(char **)smb_RawBufs;
  #else /* DJGPP */
          smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
  #endif /* !DJGPP */
!     }
!     lock_ReleaseMutex(&amp;smb_RawBufLock);
!     if (!rawBuf)
!         goto send1a;
  
      if (fidp-&gt;flags &amp; SMB_FID_IOCTL)
      {
***************
*** 2515,2687 ****
      userp = smb_GetUser(vcp, inp);
  
  #ifndef DJGPP
! 	code = smb_ReadData(fidp, &amp;offset, count, rawBuf, userp, &amp;finalCount);
  #else /* DJGPP */
      /* have to give ReadData flag so it will treat buffer as DOS mem. */
      code = smb_ReadData(fidp, &amp;offset, count, (unsigned char *)rawBuf,
                          userp, &amp;finalCount, TRUE /* rawFlag */);
  #endif /* !DJGPP */
  
! 	if (code != 0)
! 		goto send;
  
    send:
      cm_ReleaseUser(userp);
  
    send1a:
! 	smb_ReleaseFID(fidp);
  
    send1:
! 	ncbp = outp-&gt;ncbp;
  #ifdef DJGPP
      dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
! 	memset((char *)ncbp, 0, sizeof(NCB));
  
! 	ncbp-&gt;ncb_length = (unsigned short) finalCount;
! 	ncbp-&gt;ncb_lsn = (unsigned char) vcp-&gt;lsn;
! 	ncbp-&gt;ncb_lana_num = vcp-&gt;lana;
! 	ncbp-&gt;ncb_command = NCBSEND;
! 	ncbp-&gt;ncb_buffer = rawBuf;
  
  #ifndef DJGPP
! 	code = Netbios(ncbp);
  #else /* DJGPP */
! 	code = Netbios(ncbp, dos_ncb);
  #endif /* !DJGPP */
! 	if (code != 0)
! 		osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
  
! 	if (rawBuf) {
! 		/* Give back raw buffer */
! 		lock_ObtainMutex(&amp;smb_RawBufLock);
  #ifndef DJGPP
! 		*((char **) rawBuf) = smb_RawBufs;
  #else /* DJGPP */
          _farpokel(_dos_ds, rawBuf, smb_RawBufs);
  #endif /* !DJGPP */
  
! 		smb_RawBufs = rawBuf;
! 		lock_ReleaseMutex(&amp;smb_RawBufLock);
! 	}
  
! 	return 0;
  }
  
  long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	return 0;
  }
  
  long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	return 0;
  }
  
  long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	char *namep;
      char *datap;
! 	int coreProtoIndex;
! 	int v3ProtoIndex;
! 	int NTProtoIndex;
! 	int protoIndex;			        /* index we're using */
! 	int namex;
! 	int dbytes;
! 	int entryLength;
! 	int tcounter;
! 	char protocol_array[10][1024];  /* protocol signature of the client */
      int caps;                       /* capabilities */
      time_t unixTime;
! 	time_t dosTime;
! 	TIME_ZONE_INFORMATION tzi;
  
      osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
  			 ongoingOps - 1);
! 	if (!isGateway) {
! 		if (active_vcp) {
! 			DWORD now = GetCurrentTime();
! 			if (now - last_msg_time &gt;= 30000
! 				&amp;&amp; now - last_msg_time &lt;= 90000) {
! 				osi_Log1(smb_logp,
! 						 "Setting dead_vcp %x", active_vcp);
                  if (dead_vcp) {
                      smb_ReleaseVC(dead_vcp);
                      osi_Log1(smb_logp,
!                               "Previous dead_vcp %x", dead_vcp);
                  }
                  smb_HoldVC(active_vcp);
! 				dead_vcp = active_vcp;
! 				dead_vcp-&gt;flags |= SMB_VCFLAG_ALREADYDEAD;
! 			}
! 		}
! 	}
! 
! 	inp-&gt;flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
! 
! 	namep = smb_GetSMBData(inp, &amp;dbytes);
! 	namex = 0;
! 	tcounter = 0;
! 	coreProtoIndex = -1;		/* not found */
! 	v3ProtoIndex = -1;
! 	NTProtoIndex = -1;
! 	while(namex &lt; dbytes) {
! 		osi_Log1(smb_logp, "Protocol %s",
! 				 osi_LogSaveString(smb_logp, namep+1));
! 		strcpy(protocol_array[tcounter], namep+1);
! 
! 		/* namep points at the first protocol, or really, a 0x02
! 		 * byte preceding the null-terminated ASCII name.
! 		 */
! 		if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
! 			coreProtoIndex = tcounter;
! 		}	
! 		else if (smb_useV3 &amp;&amp; strcmp("LM1.2X002", namep+1) == 0) {
! 			v3ProtoIndex = tcounter;
! 		}
! 		else if (smb_useV3 &amp;&amp; strcmp("NT LM 0.12", namep+1) == 0) {
! 			NTProtoIndex = tcounter;
! 		}
  
! 		/* compute size of protocol entry */
! 		entryLength = strlen(namep+1);
          entryLength += 2;	/* 0x02 bytes and null termination */
!                 
          /* advance over this protocol entry */
! 		namex += entryLength;
          namep += entryLength;
          tcounter++;		/* which proto entry we're looking at */
! 	}
  
! 	if (NTProtoIndex != -1) {
! 		protoIndex = NTProtoIndex;
! 		vcp-&gt;flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
! 	}
! 	else if (v3ProtoIndex != -1) {
! 		protoIndex = v3ProtoIndex;
! 		vcp-&gt;flags |= SMB_VCFLAG_USEV3;
! 	}	
! 	else if (coreProtoIndex != -1) {
! 		protoIndex = coreProtoIndex;
! 		vcp-&gt;flags |= SMB_VCFLAG_USECORE;
! 	}	
! 	else protoIndex = -1;
! 
! 	if (protoIndex == -1)
! 		return CM_ERROR_INVAL;
! 	else if (NTProtoIndex != -1) {
          smb_SetSMBParm(outp, 0, protoIndex);
! 		if (smb_authType != SMB_AUTH_NONE) {
! 			smb_SetSMBParmByte(outp, 1,
! 				NEGOTIATE_SECURITY_USER_LEVEL |
! 				NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);	/* user level security, challenge response */
! 		} else {
              smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
! 		}
          smb_SetSMBParm(outp, 1, smb_maxMpxRequests);	/* max multiplexed requests */
          smb_SetSMBParm(outp, 2, smb_maxVCPerServer);	/* max VCs per consumer/server connection */
          smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
! 		smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);	/* raw buffer size */
          /* The session key is not a well documented field however most clients
           * will echo back the session key to the server.  Currently we are using
           * the same value for all sessions.  We should generate a random value
--- 2541,2717 ----
      userp = smb_GetUser(vcp, inp);
  
  #ifndef DJGPP
!     code = smb_ReadData(fidp, &amp;offset, count, rawBuf, userp, &amp;finalCount);
  #else /* DJGPP */
      /* have to give ReadData flag so it will treat buffer as DOS mem. */
      code = smb_ReadData(fidp, &amp;offset, count, (unsigned char *)rawBuf,
                          userp, &amp;finalCount, TRUE /* rawFlag */);
  #endif /* !DJGPP */
  
!     if (code != 0)
!         goto send;
  
    send:
      cm_ReleaseUser(userp);
  
    send1a:
!     smb_ReleaseFID(fidp);
  
    send1:
!     ncbp = outp-&gt;ncbp;
  #ifdef DJGPP
      dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
!     memset((char *)ncbp, 0, sizeof(NCB));
  
!     ncbp-&gt;ncb_length = (unsigned short) finalCount;
!     ncbp-&gt;ncb_lsn = (unsigned char) vcp-&gt;lsn;
!     ncbp-&gt;ncb_lana_num = vcp-&gt;lana;
!     ncbp-&gt;ncb_command = NCBSEND;
!     ncbp-&gt;ncb_buffer = rawBuf;
  
  #ifndef DJGPP
!     code = Netbios(ncbp);
  #else /* DJGPP */
!     code = Netbios(ncbp, dos_ncb);
  #endif /* !DJGPP */
!     if (code != 0)
!         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
  
!     if (rawBuf) {
!         /* Give back raw buffer */
!         lock_ObtainMutex(&amp;smb_RawBufLock);
  #ifndef DJGPP
!         *((char **) rawBuf) = smb_RawBufs;
  #else /* DJGPP */
          _farpokel(_dos_ds, rawBuf, smb_RawBufs);
  #endif /* !DJGPP */
  
!         smb_RawBufs = rawBuf;
!         lock_ReleaseMutex(&amp;smb_RawBufLock);
!     }
  
!     return 0;
  }
  
  long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
! 			 ongoingOps - 1);
!     return 0;
  }
  
  long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
! 			 ongoingOps - 1);
!     return 0;
  }
  
  long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     char *namep;
      char *datap;
!     int coreProtoIndex;
!     int v3ProtoIndex;
!     int NTProtoIndex;
!     int protoIndex;			        /* index we're using */
!     int namex;
!     int dbytes;
!     int entryLength;
!     int tcounter;
!     char protocol_array[10][1024];  /* protocol signature of the client */
      int caps;                       /* capabilities */
      time_t unixTime;
!     time_t dosTime;
!     TIME_ZONE_INFORMATION tzi;
  
      osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
  			 ongoingOps - 1);
!     if (!isGateway) {
!         if (active_vcp) {
!             DWORD now = GetCurrentTime();
!             if (now - last_msg_time &gt;= 30000
!                  &amp;&amp; now - last_msg_time &lt;= 90000) {
!                 osi_Log1(smb_logp,
!                           "Setting dead_vcp %x", active_vcp);
                  if (dead_vcp) {
                      smb_ReleaseVC(dead_vcp);
                      osi_Log1(smb_logp,
!                              "Previous dead_vcp %x", dead_vcp);
                  }
                  smb_HoldVC(active_vcp);
!                 dead_vcp = active_vcp;
!                 dead_vcp-&gt;flags |= SMB_VCFLAG_ALREADYDEAD;
!             }
!         }
!     }
! 
!     inp-&gt;flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
! 
!     namep = smb_GetSMBData(inp, &amp;dbytes);
!     namex = 0;
!     tcounter = 0;
!     coreProtoIndex = -1;		/* not found */
!     v3ProtoIndex = -1;
!     NTProtoIndex = -1;
!     while(namex &lt; dbytes) {
!         osi_Log1(smb_logp, "Protocol %s",
!                   osi_LogSaveString(smb_logp, namep+1));
!         strcpy(protocol_array[tcounter], namep+1);
! 
!         /* namep points at the first protocol, or really, a 0x02
!          * byte preceding the null-terminated ASCII name.
!          */
!         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
!             coreProtoIndex = tcounter;
!         }	
!         else if (smb_useV3 &amp;&amp; strcmp("LM1.2X002", namep+1) == 0) {
!             v3ProtoIndex = tcounter;
!         }
!         else if (smb_useV3 &amp;&amp; strcmp("NT LM 0.12", namep+1) == 0) {
!             NTProtoIndex = tcounter;
!         }
  
!         /* compute size of protocol entry */
!         entryLength = strlen(namep+1);
          entryLength += 2;	/* 0x02 bytes and null termination */
! 
          /* advance over this protocol entry */
!         namex += entryLength;
          namep += entryLength;
          tcounter++;		/* which proto entry we're looking at */
!     }
! 
!     if (NTProtoIndex != -1) {
!         protoIndex = NTProtoIndex;
!         vcp-&gt;flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
!     }
!     else if (v3ProtoIndex != -1) {
!         protoIndex = v3ProtoIndex;
!         vcp-&gt;flags |= SMB_VCFLAG_USEV3;
!     }	
!     else if (coreProtoIndex != -1) {
!         protoIndex = coreProtoIndex;
!         vcp-&gt;flags |= SMB_VCFLAG_USECORE;
!     }	
!     else protoIndex = -1;
  
!     if (protoIndex == -1)
!         return CM_ERROR_INVAL;
!     else if (NTProtoIndex != -1) {
          smb_SetSMBParm(outp, 0, protoIndex);
!         if (smb_authType != SMB_AUTH_NONE) {
!             smb_SetSMBParmByte(outp, 1,
!                                NEGOTIATE_SECURITY_USER_LEVEL |
!                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);	/* user level security, challenge response */
!         } else {
              smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
!         }
          smb_SetSMBParm(outp, 1, smb_maxMpxRequests);	/* max multiplexed requests */
          smb_SetSMBParm(outp, 2, smb_maxVCPerServer);	/* max VCs per consumer/server connection */
          smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
!         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);	/* raw buffer size */
          /* The session key is not a well documented field however most clients
           * will echo back the session key to the server.  Currently we are using
           * the same value for all sessions.  We should generate a random value
***************
*** 2689,2817 ****
           */
          smb_SetSMBParm(outp, 7, 1);	/* next 2: session key */
          smb_SetSMBParm(outp, 8, 1);
! 		/* 
! 		 * Tried changing the capabilities to support for W2K - defect 117695
! 		 * Maybe something else needs to be changed here?
! 		 */
! 		/*
! 		  if (isWindows2000) 
! 		  smb_SetSMBParmLong(outp, 9, 0x43fd);
! 		  else 
! 		  smb_SetSMBParmLong(outp, 9, 0x251);
! 		  */
! 		/* Capabilities: *
! 		 * 32-bit error codes *
! 		 * and NT Find *
! 		 * and NT SMB's *
! 		 * and raw mode */
          caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
! 			   NTNEGOTIATE_CAPABILITY_NTFIND |
                 NTNEGOTIATE_CAPABILITY_RAWMODE |
! 			   NTNEGOTIATE_CAPABILITY_NTSMB;
  
          if ( smb_authType == SMB_AUTH_EXTENDED )
              caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
  
          smb_SetSMBParmLong(outp, 9, caps);
! 		time(&amp;unixTime);
! 		smb_SearchTimeFromUnixTime(&amp;dosTime, unixTime);
! 		smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
! 		smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
! 
! 		GetTimeZoneInformation(&amp;tzi);
! 		smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);	/* server tzone */
! 
! 		if (smb_authType == SMB_AUTH_NTLM) {
! 			smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
! 			smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
! 			/* paste in encryption key */
! 			datap = smb_GetSMBData(outp, NULL);
! 			memcpy(datap,vcp-&gt;encKey,MSV1_0_CHALLENGE_LENGTH);
! 			/* and the faux domain name */
! 			strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
! 		} else if ( smb_authType == SMB_AUTH_EXTENDED ) {
              void * secBlob;
! 			int secBlobLength;
  
! 			smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
  
! 			smb_NegotiateExtendedSecurity(&amp;secBlob, &amp;secBlobLength);
  
! 			smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
  			
! 			datap = smb_GetSMBData(outp, NULL);
! 			memcpy(datap, &amp;smb_ServerGUID, sizeof(smb_ServerGUID));
  
! 			if (secBlob) {
! 				datap += sizeof(smb_ServerGUID);
! 				memcpy(datap, secBlob, secBlobLength);
! 				free(secBlob);
! 			}
          } else {
! 			smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
! 			smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
! 		}
! 	}
! 	else if (v3ProtoIndex != -1) {
! 		smb_SetSMBParm(outp, 0, protoIndex);
  
          /* NOTE: Extended authentication cannot be negotiated with v3
           * therefore we fail over to NTLM 
           */
          if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
! 			smb_SetSMBParm(outp, 1,
! 				NEGOTIATE_SECURITY_USER_LEVEL |
! 				NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);	/* user level security, challenge response */
! 		} else {
! 			smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
! 		}
! 		smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
! 		smb_SetSMBParm(outp, 3, smb_maxMpxRequests);	/* max multiplexed requests */
! 		smb_SetSMBParm(outp, 4, smb_maxVCPerServer);	/* max VCs per consumer/server connection */
! 		smb_SetSMBParm(outp, 5, 0);	/* no support of block mode for read or write */
! 		smb_SetSMBParm(outp, 6, 1);	/* next 2: session key */
! 		smb_SetSMBParm(outp, 7, 1);
! 		time(&amp;unixTime);
! 		smb_SearchTimeFromUnixTime(&amp;dosTime, unixTime);
! 		smb_SetSMBParm(outp, 8, LOWORD(dosTime));	/* server time */
! 		smb_SetSMBParm(outp, 9, HIWORD(dosTime));	/* server date */
  
! 		GetTimeZoneInformation(&amp;tzi);
! 		smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);	/* server tzone */
  
          /* NOTE: Extended authentication cannot be negotiated with v3
           * therefore we fail over to NTLM 
           */
! 		if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
! 			smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);	/* encryption key length */
              smb_SetSMBParm(outp, 12, 0);	/* resvd */
! 			smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);	/* perhaps should specify 8 bytes anyway */
! 			datap = smb_GetSMBData(outp, NULL);
! 			/* paste in a new encryption key */
! 			memcpy(datap, vcp-&gt;encKey, MSV1_0_CHALLENGE_LENGTH);
! 			/* and the faux domain name */
! 			strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
! 		} else {
! 			smb_SetSMBParm(outp, 11, 0); /* encryption key length */
! 			smb_SetSMBParm(outp, 12, 0); /* resvd */
! 			smb_SetSMBDataLength(outp, 0);
! 		}
! 	}
! 	else if (coreProtoIndex != -1) {     /* not really supported anymore */
! 		smb_SetSMBParm(outp, 0, protoIndex);
! 		smb_SetSMBDataLength(outp, 0);
! 	}
! 	return 0;
  }
  
  void smb_Daemon(void *parmp)
  {
! 	afs_uint32 count = 0;
  
! 	while(1) {
! 		count++;
! 		thrd_Sleep(10000);
! 		if ((count % 72) == 0)	{	/* every five minutes */
              struct tm myTime;
              long old_localZero = smb_localZero;
  		 
--- 2719,2847 ----
           */
          smb_SetSMBParm(outp, 7, 1);	/* next 2: session key */
          smb_SetSMBParm(outp, 8, 1);
!         /* 
!          * Tried changing the capabilities to support for W2K - defect 117695
!          * Maybe something else needs to be changed here?
!          */
!         /*
!         if (isWindows2000) 
!         smb_SetSMBParmLong(outp, 9, 0x43fd);
!         else 
!         smb_SetSMBParmLong(outp, 9, 0x251);
!         */
!         /* Capabilities: *
!          * 32-bit error codes *
!          * and NT Find *
!          * and NT SMB's *
!          * and raw mode */
          caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
!                NTNEGOTIATE_CAPABILITY_NTFIND |
                 NTNEGOTIATE_CAPABILITY_RAWMODE |
!                NTNEGOTIATE_CAPABILITY_NTSMB;
  
          if ( smb_authType == SMB_AUTH_EXTENDED )
              caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
  
          smb_SetSMBParmLong(outp, 9, caps);
!         time(&amp;unixTime);
!         smb_SearchTimeFromUnixTime(&amp;dosTime, unixTime);
!         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
!         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
! 
!         GetTimeZoneInformation(&amp;tzi);
!         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);	/* server tzone */
! 
!         if (smb_authType == SMB_AUTH_NTLM) {
!             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
!             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
!             /* paste in encryption key */
!             datap = smb_GetSMBData(outp, NULL);
!             memcpy(datap,vcp-&gt;encKey,MSV1_0_CHALLENGE_LENGTH);
!             /* and the faux domain name */
!             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
!         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
              void * secBlob;
!             int secBlobLength;
  
!             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
  
!             smb_NegotiateExtendedSecurity(&amp;secBlob, &amp;secBlobLength);
  
!             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
  			
!             datap = smb_GetSMBData(outp, NULL);
!             memcpy(datap, &amp;smb_ServerGUID, sizeof(smb_ServerGUID));
  
!             if (secBlob) {
!                 datap += sizeof(smb_ServerGUID);
!                 memcpy(datap, secBlob, secBlobLength);
!                 free(secBlob);
!             }
          } else {
!             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
!             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
!         }
!     }
!     else if (v3ProtoIndex != -1) {
!         smb_SetSMBParm(outp, 0, protoIndex);
  
          /* NOTE: Extended authentication cannot be negotiated with v3
           * therefore we fail over to NTLM 
           */
          if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
!             smb_SetSMBParm(outp, 1,
!                            NEGOTIATE_SECURITY_USER_LEVEL |
!                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);	/* user level security, challenge response */
!         } else {
!             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
!         }
!         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
!         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);	/* max multiplexed requests */
!         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);	/* max VCs per consumer/server connection */
!         smb_SetSMBParm(outp, 5, 0);	/* no support of block mode for read or write */
!         smb_SetSMBParm(outp, 6, 1);	/* next 2: session key */
!         smb_SetSMBParm(outp, 7, 1);
!         time(&amp;unixTime);
!         smb_SearchTimeFromUnixTime(&amp;dosTime, unixTime);
!         smb_SetSMBParm(outp, 8, LOWORD(dosTime));	/* server time */
!         smb_SetSMBParm(outp, 9, HIWORD(dosTime));	/* server date */
  
!         GetTimeZoneInformation(&amp;tzi);
!         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);	/* server tzone */
  
          /* NOTE: Extended authentication cannot be negotiated with v3
           * therefore we fail over to NTLM 
           */
!         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
!             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);	/* encryption key length */
              smb_SetSMBParm(outp, 12, 0);	/* resvd */
!             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);	/* perhaps should specify 8 bytes anyway */
!             datap = smb_GetSMBData(outp, NULL);
!             /* paste in a new encryption key */
!             memcpy(datap, vcp-&gt;encKey, MSV1_0_CHALLENGE_LENGTH);
!             /* and the faux domain name */
!             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
!         } else {
!             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
!             smb_SetSMBParm(outp, 12, 0); /* resvd */
!             smb_SetSMBDataLength(outp, 0);
!         }
!     }
!     else if (coreProtoIndex != -1) {     /* not really supported anymore */
!         smb_SetSMBParm(outp, 0, protoIndex);
!         smb_SetSMBDataLength(outp, 0);
!     }
!     return 0;
  }
  
  void smb_Daemon(void *parmp)
  {
!     afs_uint32 count = 0;
  
!     while(1) {
!         count++;
!         thrd_Sleep(10000);
!         if ((count % 72) == 0)	{	/* every five minutes */
              struct tm myTime;
              long old_localZero = smb_localZero;
  		 
***************
*** 2832,2990 ****
                  cm_noteLocalMountPointChange();
  #endif
          }
! 		/* XXX GC dir search entries */
! 	}
  }
  
  void smb_WaitingLocksDaemon()
  {
! 	smb_waitingLock_t *wL, *nwL;
! 	int first;
! 	smb_vc_t *vcp;
! 	smb_packet_t *inp, *outp;
! 	NCB *ncbp;
! 	long code = 0;
! 
! 	while(1) {
! 		lock_ObtainWrite(&amp;smb_globalLock);
! 		nwL = smb_allWaitingLocks;
! 		if (nwL == NULL) {
! 			osi_SleepW((long)&amp;smb_allWaitingLocks, &amp;smb_globalLock);
! 			thrd_Sleep(1000);
! 			continue;
! 		}
! 		else first = 1;
! 		do {
! 			if (first)
! 				first = 0;
! 			else
! 				lock_ObtainWrite(&amp;smb_globalLock);
! 			wL = nwL;
! 			nwL = (smb_waitingLock_t *) osi_QNext(&amp;wL-&gt;q);
! 			lock_ReleaseWrite(&amp;smb_globalLock);
! 			code = cm_RetryLock((cm_file_lock_t *) wL-&gt;lockp,
! 								wL-&gt;vcp-&gt;flags &amp; SMB_VCFLAG_ALREADYDEAD);
! 			if (code == CM_ERROR_WOULDBLOCK) {
! 				/* no progress */
! 				if (wL-&gt;timeRemaining != 0xffffffff
! 				    &amp;&amp; (wL-&gt;timeRemaining -= 1000) &lt; 0)
! 					goto endWait;
! 				continue;
! 			}
! 		  endWait:
! 			vcp = wL-&gt;vcp;
! 			inp = wL-&gt;inp;
! 			outp = wL-&gt;outp;
! 			ncbp = GetNCB();
! 			ncbp-&gt;ncb_length = inp-&gt;ncb_length;
! 			inp-&gt;spacep = cm_GetSpace();
! 
! 			/* Remove waitingLock from list */
! 			lock_ObtainWrite(&amp;smb_globalLock);
! 			osi_QRemove((osi_queue_t **)&amp;smb_allWaitingLocks,
! 				    &amp;wL-&gt;q);
! 			lock_ReleaseWrite(&amp;smb_globalLock);
! 
! 			/* Resume packet processing */
! 			if (code == 0)
! 				smb_SetSMBDataLength(outp, 0);
! 			outp-&gt;flags |= SMB_PACKETFLAG_SUSPENDED;
! 			outp-&gt;resumeCode = code;
! 			outp-&gt;ncbp = ncbp;
! 			smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
! 
! 			/* Clean up */
! 			cm_FreeSpace(inp-&gt;spacep);
! 			smb_FreePacket(inp);
! 			smb_FreePacket(outp);
! 			FreeNCB(ncbp);
! 			free(wL);
! 		} while (nwL);
! 		thrd_Sleep(1000);
! 	}
  }
  
  long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	osi_Log0(smb_logp, "SMB receive get disk attributes");
  
! 	smb_SetSMBParm(outp, 0, 32000);
! 	smb_SetSMBParm(outp, 1, 64);
! 	smb_SetSMBParm(outp, 2, 1024);
! 	smb_SetSMBParm(outp, 3, 30000);
! 	smb_SetSMBParm(outp, 4, 0);
! 	smb_SetSMBDataLength(outp, 0);
! 	return 0;
  }
  
  long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
  {
! 	smb_tid_t *tidp;
      smb_user_t *uidp;
! 	unsigned short newTid;
! 	char shareName[256];
! 	char *sharePath;
! 	int shareFound;
! 	char *tp;
! 	char *pathp;
! 	char *passwordp;
! 	cm_user_t *userp;
! 
! 	osi_Log0(smb_logp, "SMB receive tree connect");
! 
! 	/* parse input parameters */
! 	tp = smb_GetSMBData(inp, NULL);
! 	pathp = smb_ParseASCIIBlock(tp, &amp;tp);
! 	passwordp = smb_ParseASCIIBlock(tp, &amp;tp);
! 	tp = strrchr(pathp, '\\');
! 	if (!tp)
! 		return CM_ERROR_BADSMB;
! 	strcpy(shareName, tp+1);
! 
! 	userp = smb_GetUser(vcp, inp);
! 
! 	lock_ObtainMutex(&amp;vcp-&gt;mx);
! 	newTid = vcp-&gt;tidCounter++;
! 	lock_ReleaseMutex(&amp;vcp-&gt;mx);
!         
! 	tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
      uidp = smb_FindUID(vcp, ((smb_t *)inp)-&gt;uid, 0);
! 	shareFound = smb_FindShare(vcp, uidp, shareName, &amp;sharePath);
      if (uidp)
          smb_ReleaseUID(uidp);
! 	if (!shareFound) {
! 		smb_ReleaseTID(tidp);
! 		return CM_ERROR_BADSHARENAME;
! 	}
! 	lock_ObtainMutex(&amp;tidp-&gt;mx);
! 	tidp-&gt;userp = userp;
! 	tidp-&gt;pathname = sharePath;
! 	lock_ReleaseMutex(&amp;tidp-&gt;mx);
! 	smb_ReleaseTID(tidp);
  
! 	smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
! 	smb_SetSMBParm(rsp, 1, newTid);
! 	smb_SetSMBDataLength(rsp, 0);
! 
! 	osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
! 	return 0;
  }
  
  unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
  {
! 	int tlen;
  
! 	if (*inp++ != 0x1) return NULL;
! 	tlen = inp[0] + (inp[1]&lt;&lt;8);
! 	inp += 2;		/* skip length field */
          
! 	if (chainpp) {
! 		*chainpp = inp + tlen;
! 	}	
!         
! 	if (lengthp) *lengthp = tlen;
          
! 	return inp;
  }
  
  /* set maskp to the mask part of the incoming path.
--- 2862,3020 ----
                  cm_noteLocalMountPointChange();
  #endif
          }
!         /* XXX GC dir search entries */
!     }
  }
  
  void smb_WaitingLocksDaemon()
  {
!     smb_waitingLock_t *wL, *nwL;
!     int first;
!     smb_vc_t *vcp;
!     smb_packet_t *inp, *outp;
!     NCB *ncbp;
!     long code = 0;
! 
!     while (1) {
!         lock_ObtainWrite(&amp;smb_globalLock);
!         nwL = smb_allWaitingLocks;
!         if (nwL == NULL) {
!             osi_SleepW((long)&amp;smb_allWaitingLocks, &amp;smb_globalLock);
!             thrd_Sleep(1000);
!             continue;
!         }
!         else first = 1;
!         do {
!             if (first)
!                 first = 0;
!             else
!                 lock_ObtainWrite(&amp;smb_globalLock);
!             wL = nwL;
!             nwL = (smb_waitingLock_t *) osi_QNext(&amp;wL-&gt;q);
!             lock_ReleaseWrite(&amp;smb_globalLock);
!             code = cm_RetryLock((cm_file_lock_t *) wL-&gt;lockp,
!                                  wL-&gt;vcp-&gt;flags &amp; SMB_VCFLAG_ALREADYDEAD);
!             if (code == CM_ERROR_WOULDBLOCK) {
!                 /* no progress */
!                 if (wL-&gt;timeRemaining != 0xffffffff
!                      &amp;&amp; (wL-&gt;timeRemaining -= 1000) &lt; 0)
!                     goto endWait;
!                 continue;
!             }
!           endWait:
!             vcp = wL-&gt;vcp;
!             inp = wL-&gt;inp;
!             outp = wL-&gt;outp;
!             ncbp = GetNCB();
!             ncbp-&gt;ncb_length = inp-&gt;ncb_length;
!             inp-&gt;spacep = cm_GetSpace();
! 
!             /* Remove waitingLock from list */
!             lock_ObtainWrite(&amp;smb_globalLock);
!             osi_QRemove((osi_queue_t **)&amp;smb_allWaitingLocks,
!                          &amp;wL-&gt;q);
!             lock_ReleaseWrite(&amp;smb_globalLock);
! 
!             /* Resume packet processing */
!             if (code == 0)
!                 smb_SetSMBDataLength(outp, 0);
!             outp-&gt;flags |= SMB_PACKETFLAG_SUSPENDED;
!             outp-&gt;resumeCode = code;
!             outp-&gt;ncbp = ncbp;
!             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
! 
!             /* Clean up */
!             cm_FreeSpace(inp-&gt;spacep);
!             smb_FreePacket(inp);
!             smb_FreePacket(outp);
!             FreeNCB(ncbp);
!             free(wL);
!         } while (nwL);
!         thrd_Sleep(1000);
!     }
  }
  
  long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     osi_Log0(smb_logp, "SMB receive get disk attributes");
  
!     smb_SetSMBParm(outp, 0, 32000);
!     smb_SetSMBParm(outp, 1, 64);
!     smb_SetSMBParm(outp, 2, 1024);
!     smb_SetSMBParm(outp, 3, 30000);
!     smb_SetSMBParm(outp, 4, 0);
!     smb_SetSMBDataLength(outp, 0);
!     return 0;
  }
  
  long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
  {
!     smb_tid_t *tidp;
      smb_user_t *uidp;
!     unsigned short newTid;
!     char shareName[256];
!     char *sharePath;
!     int shareFound;
!     char *tp;
!     char *pathp;
!     char *passwordp;
!     cm_user_t *userp;
! 
!     osi_Log0(smb_logp, "SMB receive tree connect");
! 
!     /* parse input parameters */
!     tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &amp;tp);
!     passwordp = smb_ParseASCIIBlock(tp, &amp;tp);
!     tp = strrchr(pathp, '\\');
!     if (!tp)
!         return CM_ERROR_BADSMB;
!     strcpy(shareName, tp+1);
! 
!     userp = smb_GetUser(vcp, inp);
! 
!     lock_ObtainMutex(&amp;vcp-&gt;mx);
!     newTid = vcp-&gt;tidCounter++;
!     lock_ReleaseMutex(&amp;vcp-&gt;mx);
! 
!     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
      uidp = smb_FindUID(vcp, ((smb_t *)inp)-&gt;uid, 0);
!     shareFound = smb_FindShare(vcp, uidp, shareName, &amp;sharePath);
      if (uidp)
          smb_ReleaseUID(uidp);
!     if (!shareFound) {
!         smb_ReleaseTID(tidp);
!         return CM_ERROR_BADSHARENAME;
!     }
!     lock_ObtainMutex(&amp;tidp-&gt;mx);
!     tidp-&gt;userp = userp;
!     tidp-&gt;pathname = sharePath;
!     lock_ReleaseMutex(&amp;tidp-&gt;mx);
!     smb_ReleaseTID(tidp);
! 
!     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
!     smb_SetSMBParm(rsp, 1, newTid);
!     smb_SetSMBDataLength(rsp, 0);
  
!     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
!     return 0;
  }
  
  unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
  {
!     int tlen;
  
!     if (*inp++ != 0x1) return NULL;
!     tlen = inp[0] + (inp[1]&lt;&lt;8);
!     inp += 2;		/* skip length field */
          
!     if (chainpp) {
!         *chainpp = inp + tlen;
!     }	
! 
!     if (lengthp) *lengthp = tlen;
          
!     return inp;
  }
  
  /* set maskp to the mask part of the incoming path.
***************
*** 2994,3023 ****
   */
  int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
  {
! 	char *tp;
! 	char *up;
! 	int i;
! 	int tc;
! 	int valid8Dot3;
! 
! 	/* starts off valid */
! 	valid8Dot3 = 1;
! 
! 	/* mask starts out all blanks */
! 	memset(maskp, ' ', 11);
! 
! 	/* find last backslash, or use whole thing if there is none */
! 	tp = strrchr(pathp, '\\');
! 	if (!tp) tp = pathp;
! 	else tp++;	/* skip slash */
          
! 	up = maskp;
  
! 	/* names starting with a dot are illegal */
! 	if (*tp == '.') valid8Dot3 = 0;
  
      for(i=0;; i++) {
! 		tc = *tp++;
          if (tc == 0) return valid8Dot3;
          if (tc == '.' || tc == '"') break;
          if (i &lt; 8) *up++ = tc;
--- 3024,3053 ----
   */
  int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
  {
!     char *tp;
!     char *up;
!     int i;
!     int tc;
!     int valid8Dot3;
! 
!     /* starts off valid */
!     valid8Dot3 = 1;
! 
!     /* mask starts out all blanks */
!     memset(maskp, ' ', 11);
! 
!     /* find last backslash, or use whole thing if there is none */
!     tp = strrchr(pathp, '\\');
!     if (!tp) tp = pathp;
!     else tp++;	/* skip slash */
          
!     up = maskp;
  
!     /* names starting with a dot are illegal */
!     if (*tp == '.') valid8Dot3 = 0;
  
      for(i=0;; i++) {
!         tc = *tp++;
          if (tc == 0) return valid8Dot3;
          if (tc == '.' || tc == '"') break;
          if (i &lt; 8) *up++ = tc;
***************
*** 3029,3045 ****
      for(i=0;;i++) {
          tc = *tp++;
          if (tc == 0) 
! 			return valid8Dot3;
  
          /* too many dots */
          if (tc == '.' || tc == '"') 
! 			valid8Dot3 = 0;
  
          /* copy extension if not too long */
          if (i &lt; 3) 
! 			*up++ = tc;
          else 
! 			valid8Dot3 = 0;
      }   
  
      /* unreachable */
--- 3059,3075 ----
      for(i=0;;i++) {
          tc = *tp++;
          if (tc == 0) 
!             return valid8Dot3;
  
          /* too many dots */
          if (tc == '.' || tc == '"') 
!             valid8Dot3 = 0;
  
          /* copy extension if not too long */
          if (i &lt; 3) 
!             *up++ = tc;
          else 
!             valid8Dot3 = 0;
      }   
  
      /* unreachable */
***************
*** 3047,3183 ****
  
  int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
  {
! 	char umask[11];
! 	int valid;
! 	int i;
! 	char tc1;
! 	char tc2;
! 	char *tp1;
! 	char *tp2;
! 
! 	/* XXX redo this, calling smb_V3MatchMask with a converted mask */
! 
! 	valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
! 	if (!valid) 
! 		return 0;
   
! 	/* otherwise, we have a valid 8.3 name; see if we have a match,
! 	 * treating '?' as a wildcard in maskp (but not in the file name).
! 	 */
! 	tp1 = umask;	/* real name, in mask format */
! 	tp2 = maskp;	/* mask, in mask format */
! 	for(i=0; i&lt;11; i++) {
! 		tc1 = *tp1++;	/* char from real name */
! 		tc2 = *tp2++;	/* char from mask */
! 		tc1 = (char) cm_foldUpper[(unsigned char)tc1];
! 		tc2 = (char) cm_foldUpper[(unsigned char)tc2];
! 		if (tc1 == tc2) 
! 			continue;
! 		if (tc2 == '?' &amp;&amp; tc1 != ' ') 
! 			continue;
! 		if (tc2 == '&gt;') 
! 			continue;
! 		return 0;
! 	}
  
! 	/* we got a match */
! 	return 1;
  }
  
  char *smb_FindMask(char *pathp)
  {
! 	char *tp;
          
! 	tp = strrchr(pathp, '\\');	/* find last slash */
  
! 	if (tp) 
! 		return tp+1;	/* skip the slash */
! 	else 
! 		return pathp;	/* no slash, return the entire path */
! }
  
  long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	unsigned char *pathp;
! 	unsigned char *tp;
! 	unsigned char mask[11];
! 	unsigned char *statBlockp;
! 	unsigned char initStatBlock[21];
! 	int statLen;
!         
! 	osi_Log0(smb_logp, "SMB receive search volume");
! 
! 	/* pull pathname and stat block out of request */
! 	tp = smb_GetSMBData(inp, NULL);
! 	pathp = smb_ParseASCIIBlock(tp, (char **) &amp;tp);
! 	osi_assert(pathp != NULL);
! 	statBlockp = smb_ParseVblBlock(tp, (char **) &amp;tp, &amp;statLen);
! 	osi_assert(statBlockp != NULL);
! 	if (statLen == 0) {
! 		statBlockp = initStatBlock;
! 		statBlockp[0] = 8;
! 	}
!         
! 	/* for returning to caller */
! 	smb_Get8Dot3MaskFromPath(mask, pathp);
!         
! 	smb_SetSMBParm(outp, 0, 1);		/* we're returning one entry */
! 	tp = smb_GetSMBData(outp, NULL);
! 	*tp++ = 5;
! 	*tp++ = 43;	/* bytes in a dir entry */
! 	*tp++ = 0;	/* high byte in counter */
! 
! 	/* now marshall the dir entry, starting with the search status */
! 	*tp++ = statBlockp[0];		/* Reserved */
! 	memcpy(tp, mask, 11); tp += 11;	/* FileName */
! 
! 	/* now pass back server use info, with 1st byte non-zero */
! 	*tp++ = 1;
! 	memset(tp, 0, 4); tp += 4;	/* reserved for server use */
! 
! 	memcpy(tp, statBlockp+17, 4); tp += 4;	/* reserved for consumer */
! 
! 	*tp++ = 0x8;		/* attribute: volume */
! 
! 	/* copy out time */
! 	*tp++ = 0;
! 	*tp++ = 0;
! 
! 	/* copy out date */
! 	*tp++ = 18;
! 	*tp++ = 178;
! 
! 	/* 4 byte file size */
! 	*tp++ = 0;
! 	*tp++ = 0;
! 	*tp++ = 0;
! 	*tp++ = 0;
! 
! 	/* finally, null-terminated 8.3 pathname, which we set to AFS */
! 	memset(tp, ' ', 13);
! 	strcpy(tp, "AFS");
! 
! 	/* set the length of the data part of the packet to 43 + 3, for the dir
! 	 * entry plus the 5 and the length fields.
! 	 */
! 	smb_SetSMBDataLength(outp, 46);
! 	return 0;
! }
  
  long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
! 	cm_user_t *userp, cm_req_t *reqp)
  {
! 	long code = 0;
! 	cm_scache_t *scp;
! 	char *dptr;
! 	time_t dosTime;
! 	u_short shortTemp;
! 	char attr;
! 	smb_dirListPatch_t *patchp;
! 	smb_dirListPatch_t *npatchp;
  
! 	for(patchp = *dirPatchespp; patchp; patchp =
! 		 (smb_dirListPatch_t *) osi_QNext(&amp;patchp-&gt;q)) {
  
          dptr = patchp-&gt;dptr;
  
--- 3077,3213 ----
  
  int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
  {
!     char umask[11];
!     int valid;
!     int i;
!     char tc1;
!     char tc2;
!     char *tp1;
!     char *tp2;
! 
!     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
! 
!     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
!     if (!valid) 
!         return 0;
   
!     /* otherwise, we have a valid 8.3 name; see if we have a match,
!      * treating '?' as a wildcard in maskp (but not in the file name).
!      */
!     tp1 = umask;	/* real name, in mask format */
!     tp2 = maskp;	/* mask, in mask format */
!     for(i=0; i&lt;11; i++) {
!         tc1 = *tp1++;	/* char from real name */
!         tc2 = *tp2++;	/* char from mask */
!         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
!         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
!         if (tc1 == tc2) 
!             continue;
!         if (tc2 == '?' &amp;&amp; tc1 != ' ') 
!             continue;
!         if (tc2 == '&gt;') 
!             continue;
!         return 0;
!     }
  
!     /* we got a match */
!     return 1;
  }
  
  char *smb_FindMask(char *pathp)
  {
!     char *tp;
          
!     tp = strrchr(pathp, '\\');	/* find last slash */
  
!     if (tp) 
!         return tp+1;	/* skip the slash */
!     else 
!         return pathp;	/* no slash, return the entire path */
! }       
  
  long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     unsigned char *pathp;
!     unsigned char *tp;
!     unsigned char mask[11];
!     unsigned char *statBlockp;
!     unsigned char initStatBlock[21];
!     int statLen;
!         
!     osi_Log0(smb_logp, "SMB receive search volume");
! 
!     /* pull pathname and stat block out of request */
!     tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, (char **) &amp;tp);
!     osi_assert(pathp != NULL);
!     statBlockp = smb_ParseVblBlock(tp, (char **) &amp;tp, &amp;statLen);
!     osi_assert(statBlockp != NULL);
!     if (statLen == 0) {
!         statBlockp = initStatBlock;
!         statBlockp[0] = 8;
!     }
!         
!     /* for returning to caller */
!     smb_Get8Dot3MaskFromPath(mask, pathp);
! 
!     smb_SetSMBParm(outp, 0, 1);		/* we're returning one entry */
!     tp = smb_GetSMBData(outp, NULL);
!     *tp++ = 5;
!     *tp++ = 43;	/* bytes in a dir entry */
!     *tp++ = 0;	/* high byte in counter */
! 
!     /* now marshall the dir entry, starting with the search status */
!     *tp++ = statBlockp[0];		/* Reserved */
!     memcpy(tp, mask, 11); tp += 11;	/* FileName */
! 
!     /* now pass back server use info, with 1st byte non-zero */
!     *tp++ = 1;
!     memset(tp, 0, 4); tp += 4;	/* reserved for server use */
! 
!     memcpy(tp, statBlockp+17, 4); tp += 4;	/* reserved for consumer */
! 
!     *tp++ = 0x8;		/* attribute: volume */
! 
!     /* copy out time */
!     *tp++ = 0;
!     *tp++ = 0;
! 
!     /* copy out date */
!     *tp++ = 18;
!     *tp++ = 178;
! 
!     /* 4 byte file size */
!     *tp++ = 0;
!     *tp++ = 0;
!     *tp++ = 0;
!     *tp++ = 0;
! 
!     /* finally, null-terminated 8.3 pathname, which we set to AFS */
!     memset(tp, ' ', 13);
!     strcpy(tp, "AFS");
! 
!     /* set the length of the data part of the packet to 43 + 3, for the dir
!      * entry plus the 5 and the length fields.
!      */
!     smb_SetSMBDataLength(outp, 46);
!     return 0;
! }       
  
  long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
!                              cm_user_t *userp, cm_req_t *reqp)
  {
!     long code = 0;
!     cm_scache_t *scp;
!     char *dptr;
!     time_t dosTime;
!     u_short shortTemp;
!     char attr;
!     smb_dirListPatch_t *patchp;
!     smb_dirListPatch_t *npatchp;
  
!     for (patchp = *dirPatchespp; patchp; patchp =
!          (smb_dirListPatch_t *) osi_QNext(&amp;patchp-&gt;q)) {
  
          dptr = patchp-&gt;dptr;
  
***************
*** 3187,4075 ****
                  *dptr++ = SMB_ATTR_HIDDEN;
              continue;
          }
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
! 		code = cm_SyncOp(scp, NULL, userp, reqp, 0,
! 						  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 		if (code) {	
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			cm_ReleaseSCache(scp);
!             if( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE )
                  *dptr++ = SMB_ATTR_HIDDEN;
! 			continue;
! 		}
  
! 		attr = smb_Attributes(scp);
          /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
!         if( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE )
              attr |= SMB_ATTR_HIDDEN;
          *dptr++ = attr;
  
          /* get dos time */
! 		smb_SearchTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
                  
! 		/* copy out time */
! 		shortTemp = dosTime &amp; 0xffff;
! 		*((u_short *)dptr) = shortTemp;
! 		dptr += 2;
! 
! 		/* and copy out date */
! 		shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
! 		*((u_short *)dptr) = shortTemp;
! 		dptr += 2;
                  
! 		/* copy out file length */
! 		*((u_long *)dptr) = scp-&gt;length.LowPart;
! 		dptr += 4;
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		cm_ReleaseSCache(scp);
! 	}
!         
! 	/* now free the patches */
! 	for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
! 		npatchp = (smb_dirListPatch_t *) osi_QNext(&amp;patchp-&gt;q);
! 		free(patchp);
! 	}	
          
! 	/* and mark the list as empty */
! 	*dirPatchespp = NULL;
  
! 	return code;
  }
  
  long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	int attribute;
! 	long nextCookie;
! 	char *tp;
! 	long code = 0;
! 	char *pathp;
! 	cm_dirEntry_t *dep;
! 	int maxCount;
! 	smb_dirListPatch_t *dirListPatchesp;
! 	smb_dirListPatch_t *curPatchp;
! 	int dataLength;
! 	cm_buf_t *bufferp;
! 	long temp;
! 	osi_hyper_t dirLength;
! 	osi_hyper_t bufferOffset;
! 	osi_hyper_t curOffset;
! 	osi_hyper_t thyper;
! 	unsigned char *inCookiep;
! 	smb_dirSearch_t *dsp;
! 	cm_scache_t *scp;
! 	long entryInDir;
! 	long entryInBuffer;
! 	unsigned long clientCookie;
! 	cm_pageHeader_t *pageHeaderp;
! 	cm_user_t *userp = NULL;
! 	int slotInPage;
! 	char shortName[13];
! 	char *actualName;
! 	char *shortNameEnd;
! 	char mask[11];
! 	int returnedNames;
! 	long nextEntryCookie;
! 	int numDirChunks;		/* # of 32 byte dir chunks in this entry */
! 	char resByte;			/* reserved byte from the cookie */
! 	char *op;			/* output data ptr */
! 	char *origOp;			/* original value of op */
! 	cm_space_t *spacep;		/* for pathname buffer */
! 	int starPattern;
! 	int rootPath = 0;
! 	int caseFold;
! 	char *tidPathp;
! 	cm_req_t req;
! 	cm_fid_t fid;
! 	int fileType;
! 
! 	cm_InitReq(&amp;req);
! 
! 	maxCount = smb_GetSMBParm(inp, 0);
! 
! 	dirListPatchesp = NULL;
!         
! 	caseFold = CM_FLAG_CASEFOLD;
! 
! 	tp = smb_GetSMBData(inp, NULL);
! 	pathp = smb_ParseASCIIBlock(tp, &amp;tp);
! 	inCookiep = smb_ParseVblBlock(tp, &amp;tp, &amp;dataLength);
! 
! 	/* bail out if request looks bad */
! 	if (!tp || !pathp) {
! 		return CM_ERROR_BADSMB;
! 	}
! 
! 	/* We can handle long names */
! 	if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
! 		((smb_t *)outp)-&gt;flg2 |= 0x40;	/* IS_LONG_NAME */
! 
! 	/* make sure we got a whole search status */
! 	if (dataLength &lt; 21) {
! 		nextCookie = 0;		/* start at the beginning of the dir */
! 		resByte = 0;
! 		clientCookie = 0;
! 		attribute = smb_GetSMBParm(inp, 1);
! 
! 		/* handle volume info in another function */
! 		if (attribute &amp; 0x8)
! 			return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
! 
! 		osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
! 				 maxCount, osi_LogSaveString(smb_logp, pathp));
! 
! 		if (*pathp == 0) {	/* null pathp, treat as root dir */
! 			if (!(attribute &amp; SMB_ATTR_DIRECTORY))	/* exclude dirs */
! 				return CM_ERROR_NOFILES;
! 			rootPath = 1;
! 		}
! 
! 		dsp = smb_NewDirSearch(0);
! 		dsp-&gt;attribute = attribute;
! 		smb_Get8Dot3MaskFromPath(mask, pathp);
! 		memcpy(dsp-&gt;mask, mask, 11);
! 
! 		/* track if this is likely to match a lot of entries */
! 		if (smb_IsStarMask(mask)) starPattern = 1;
! 		else starPattern = 0;
! 	}	
! 	else {
! 		/* pull the next cookie value out of the search status block */
! 		nextCookie = inCookiep[13] + (inCookiep[14]&lt;&lt;8) + (inCookiep[15]&lt;&lt;16)
! 			+ (inCookiep[16]&lt;&lt;24);
! 		dsp = smb_FindDirSearch(inCookiep[12]);
! 		if (!dsp) {
! 			/* can't find dir search status; fatal error */
! 			return CM_ERROR_BADFD;
! 		}
! 		attribute = dsp-&gt;attribute;
! 		resByte = inCookiep[0];
! 
! 		/* copy out client cookie, in host byte order.  Don't bother
! 		 * interpreting it, since we're just passing it through, anyway.
! 		 */
! 		memcpy(&amp;clientCookie, &amp;inCookiep[17], 4);
! 
! 		memcpy(mask, dsp-&gt;mask, 11);
! 
! 		/* assume we're doing a star match if it has continued for more
! 		 * than one call.
! 		 */
! 		starPattern = 1;
! 	}
! 
! 	osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
! 			 nextCookie, dsp-&gt;cookie, attribute);
! 
! 	userp = smb_GetUser(vcp, inp);
! 
! 	/* try to get the vnode for the path name next */
! 	lock_ObtainMutex(&amp;dsp-&gt;mx);
! 	if (dsp-&gt;scp) {
! 		scp = dsp-&gt;scp;
! 		cm_HoldSCache(scp);
! 		code = 0;
! 	}
! 	else {
! 		spacep = inp-&gt;spacep;
! 		smb_StripLastComponent(spacep-&gt;data, NULL, pathp);
! 		lock_ReleaseMutex(&amp;dsp-&gt;mx);
! 		code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!         if(code) {
!             lock_ReleaseMutex(&amp;dsp-&gt;mx);
!             cm_ReleaseUser(userp);
!             smb_DeleteDirSearch(dsp);
!             smb_ReleaseDirSearch(dsp);
!             return CM_ERROR_NOFILES;
!         }
! 		code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
! 						caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &amp;req, &amp;scp);
! 		lock_ObtainMutex(&amp;dsp-&gt;mx);
! 		if (code == 0) {
! 			if (dsp-&gt;scp != 0) cm_ReleaseSCache(dsp-&gt;scp);
! 			dsp-&gt;scp = scp;
! 			/* we need one hold for the entry we just stored into,
! 			 * and one for our own processing.  When we're done with this
! 			 * function, we'll drop the one for our own processing.
! 			 * We held it once from the namei call, and so we do another hold
! 			 * now.
! 			 */
! 			cm_HoldSCache(scp);
!    			lock_ObtainMutex(&amp;scp-&gt;mx);
!    			if ((scp-&gt;flags &amp; CM_SCACHEFLAG_BULKSTATTING) == 0
!    			    &amp;&amp; LargeIntegerGreaterOrEqualToZero(scp-&gt;bulkStatProgress)) {
!    				scp-&gt;flags |= CM_SCACHEFLAG_BULKSTATTING;
!    				dsp-&gt;flags |= SMB_DIRSEARCH_BULKST;
! 			}
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		}
! 	}
! 	lock_ReleaseMutex(&amp;dsp-&gt;mx);
! 	if (code) {
! 		cm_ReleaseUser(userp);
! 		smb_DeleteDirSearch(dsp);
! 		smb_ReleaseDirSearch(dsp);
! 		return code;
! 	}
! 
! 	/* reserves space for parameter; we'll adjust it again later to the
! 	 * real count of the # of entries we returned once we've actually
! 	 * assembled the directory listing.
! 	 */
! 	smb_SetSMBParm(outp, 0, 0);
! 	
! 	/* get the directory size */
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
! 					 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 	if (code) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		cm_ReleaseSCache(scp);
! 		cm_ReleaseUser(userp);
! 		smb_DeleteDirSearch(dsp);
! 		smb_ReleaseDirSearch(dsp);
! 		return code;
! 	}
!         
! 	dirLength = scp-&gt;length;
! 	bufferp = NULL;
! 	bufferOffset.LowPart = bufferOffset.HighPart = 0;
! 	curOffset.HighPart = 0;
! 	curOffset.LowPart = nextCookie;
! 	origOp = op = smb_GetSMBData(outp, NULL);
! 	/* and write out the basic header */
! 	*op++ = 5;		/* variable block */
! 	op += 2;		/* skip vbl block length; we'll fill it in later */
! 	code = 0;
! 	returnedNames = 0;
! 	while (1) {
! 		/* make sure that curOffset.LowPart doesn't point to the first
! 		 * 32 bytes in the 2nd through last dir page, and that it doesn't
! 		 * point at the first 13 32-byte chunks in the first dir page,
! 		 * since those are dir and page headers, and don't contain useful
! 		 * information.
! 		 */
! 		temp = curOffset.LowPart &amp; (2048-1);
! 		if (curOffset.HighPart == 0 &amp;&amp; curOffset.LowPart &lt; 2048) {
! 			/* we're in the first page */
! 			if (temp &lt; 13*32) temp = 13*32;
! 		}
! 		else {
! 			/* we're in a later dir page */
! 			if (temp &lt; 32) temp = 32;
! 		}
! 		
! 		/* make sure the low order 5 bits are zero */
! 		temp &amp;= ~(32-1);
! 
! 		/* now put temp bits back ito curOffset.LowPart */
! 		curOffset.LowPart &amp;= ~(2048-1);
! 		curOffset.LowPart |= temp;
! 
! 		/* check if we've returned all the names that will fit in the
! 		 * response packet.
! 		 */
! 		if (returnedNames &gt;= maxCount) 
! 			break;
!                 
! 		/* check if we've passed the dir's EOF */
! 		if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
! 
! 		/* see if we can use the bufferp we have now; compute in which page
! 		 * the current offset would be, and check whether that's the offset
! 		 * of the buffer we have.  If not, get the buffer.
! 		 */
! 		thyper.HighPart = curOffset.HighPart;
! 		thyper.LowPart = curOffset.LowPart &amp; ~(buf_bufferSize-1);
! 		if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
! 			/* wrong buffer */
! 			if (bufferp) {
! 				buf_Release(bufferp);
! 				bufferp = NULL;
! 			}	
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
! 			code = buf_Get(scp, &amp;thyper, &amp;bufferp);
! 			lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
! 
! 			/* now, if we're doing a star match, do bulk fetching of all of 
! 			 * the status info for files in the dir.
! 			 */
! 			if (starPattern) {
! 				smb_ApplyDirListPatches(&amp;dirListPatchesp, userp,
! 										&amp;req);
! 				if ((dsp-&gt;flags &amp; SMB_DIRSEARCH_BULKST)
!    				    &amp;&amp; LargeIntegerGreaterThanOrEqualTo(thyper, 
! 									scp-&gt;bulkStatProgress)) {
! 					/* Don't bulk stat if risking timeout */
! 					int now = GetCurrentTime();
! 					if (now - req.startTime &gt; 5000) {
! 						scp-&gt;bulkStatProgress = thyper;
! 						scp-&gt;flags &amp;= ~CM_SCACHEFLAG_BULKSTATTING;
! 						dsp-&gt;flags &amp;= ~SMB_DIRSEARCH_BULKST;
! 					} else
! 						cm_TryBulkStat(scp, &amp;thyper, userp, &amp;req);
!    				}
! 			}
! 
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 			if (code) 
! 				break;
! 			bufferOffset = thyper;
! 
! 			/* now get the data in the cache */
! 			while (1) {
! 				code = cm_SyncOp(scp, bufferp, userp, &amp;req,
! 								  PRSFS_LOOKUP,
! 								  CM_SCACHESYNC_NEEDCALLBACK
! 								  | CM_SCACHESYNC_READ);
! 				if (code) break;
!                                 
! 				if (cm_HaveBuffer(scp, bufferp, 0)) break;
  
! 				/* otherwise, load the buffer and try again */
! 				code = cm_GetBuffer(scp, bufferp, NULL, userp,
! 									&amp;req);
! 				if (code) break;
! 			}
! 			if (code) {
! 				buf_Release(bufferp);
! 				bufferp = NULL;
! 				break;
! 			}
! 		}	/* if (wrong buffer) ... */
! 
! 		/* now we have the buffer containing the entry we're interested in; copy
! 		 * it out if it represents a non-deleted entry.
! 		 */
! 		entryInDir = curOffset.LowPart &amp; (2048-1);
! 		entryInBuffer = curOffset.LowPart &amp; (buf_bufferSize - 1);
! 
! 		/* page header will help tell us which entries are free.  Page header
! 		 * can change more often than once per buffer, since AFS 3 dir page size
! 		 * may be less than (but not more than a buffer package buffer.
! 		 */
! 		temp = curOffset.LowPart &amp; (buf_bufferSize - 1);  /* only look intra-buffer */
! 		temp &amp;= ~(2048 - 1);	/* turn off intra-page bits */
! 		pageHeaderp = (cm_pageHeader_t *) (bufferp-&gt;datap + temp);
! 
! 		/* now determine which entry we're looking at in the page.  If it is
! 		 * free (there's a free bitmap at the start of the dir), we should
! 		 * skip these 32 bytes.
! 		 */
! 		slotInPage = (entryInDir &amp; 0x7e0) &gt;&gt; 5;
! 		if (!(pageHeaderp-&gt;freeBitmap[slotInPage&gt;&gt;3] &amp; (1 &lt;&lt; (slotInPage &amp; 0x7)))) {
! 			/* this entry is free */
! 			numDirChunks = 1;		/* only skip this guy */
! 			goto nextEntry;
! 		}
! 
! 		tp = bufferp-&gt;datap + entryInBuffer;
! 		dep = (cm_dirEntry_t *) tp;		/* now points to AFS3 dir entry */
! 
! 		/* while we're here, compute the next entry's location, too,
! 		 * since we'll need it when writing out the cookie into the dir
! 		 * listing stream.
! 		 *
! 		 * XXXX Probably should do more sanity checking.
! 		 */
! 		numDirChunks = cm_NameEntries(dep-&gt;name, NULL);
! 		
! 		/* compute the offset of the cookie representing the next entry */
! 		nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
  
! 		/* Compute 8.3 name if necessary */
! 		actualName = dep-&gt;name;
! 		if (dep-&gt;fid.vnode != 0 &amp;&amp; !cm_Is8Dot3(actualName)) {
! 			cm_Gen8Dot3Name(dep, shortName, &amp;shortNameEnd);
! 			actualName = shortName;
! 		}
! 
! 		if (dep-&gt;fid.vnode != 0 &amp;&amp; smb_Match8Dot3Mask(actualName, mask)) {
! 			/* this is one of the entries to use: it is not deleted
! 			 * and it matches the star pattern we're looking for.
! 			 */
! 
! 			/* Eliminate entries that don't match requested
! 			   attributes */
! 
! 			/* no hidden files */
! 			if(smb_hideDotFiles &amp;&amp; !(dsp-&gt;attribute &amp; SMB_ATTR_HIDDEN) &amp;&amp; smb_IsDotFile(actualName))
! 				goto nextEntry;
! 
! 			if (!(dsp-&gt;attribute &amp; SMB_ATTR_DIRECTORY))  /* no directories */
! 			{
! 				/* We have already done the cm_TryBulkStat above */
! 				fid.cell = scp-&gt;fid.cell;
! 				fid.volume = scp-&gt;fid.volume;
! 				fid.vnode = ntohl(dep-&gt;fid.vnode);
! 				fid.unique = ntohl(dep-&gt;fid.unique);
! 				fileType = cm_FindFileType(&amp;fid);
! 				osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
!                                                   "has filetype %d", osi_LogSaveString(smb_logp, dep-&gt;name),
! 						  fileType);
! 				if (fileType == CM_SCACHETYPE_DIRECTORY)
! 					goto nextEntry;
! 			}
! 
! 			*op++ = resByte;
! 			memcpy(op, mask, 11); op += 11;
! 			*op++ = (char) dsp-&gt;cookie;	/* they say it must be non-zero */
! 			*op++ = nextEntryCookie &amp; 0xff;
! 			*op++ = (nextEntryCookie&gt;&gt;8) &amp; 0xff;
! 			*op++ = (nextEntryCookie&gt;&gt;16) &amp; 0xff;
! 			*op++ = (nextEntryCookie&gt;&gt;24) &amp; 0xff;
! 			memcpy(op, &amp;clientCookie, 4); op += 4;
! 
! 			/* now we emit the attribute.  This is sort of tricky,
! 			 * since we need to really stat the file to find out
! 			 * what type of entry we've got.  Right now, we're
! 			 * copying out data from a buffer, while holding the
! 			 * scp locked, so it isn't really convenient to stat
! 			 * something now.  We'll put in a place holder now,
! 			 * and make a second pass before returning this to get
! 			 * the real attributes.  So, we just skip the data for
! 			 * now, and adjust it later.  We allocate a patch
! 			 * record to make it easy to find this point later.
! 			 * The replay will happen at a time when it is safe to
! 			 * unlock the directory.
! 			 */
! 			curPatchp = malloc(sizeof(*curPatchp));
! 			osi_QAdd((osi_queue_t **) &amp;dirListPatchesp, &amp;curPatchp-&gt;q);
! 			curPatchp-&gt;dptr = op;
! 			curPatchp-&gt;fid.cell = scp-&gt;fid.cell;
! 			curPatchp-&gt;fid.volume = scp-&gt;fid.volume;
! 			curPatchp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
! 			curPatchp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
! 
! 			/* do hidden attribute here since name won't be around when applying
! 			 * dir list patches
! 			 */
! 
! 			if ( smb_hideDotFiles &amp;&amp; smb_IsDotFile(actualName) )
! 				curPatchp-&gt;flags = SMB_DIRLISTPATCH_DOTFILE;
! 			else
! 				curPatchp-&gt;flags = 0;
! 
! 			op += 9;	/* skip attr, time, date and size */
! 
! 			/* zero out name area.  The spec says to pad with
! 			 * spaces, but Samba doesn't, and neither do we.
! 			 */
! 			memset(op, 0, 13);
! 
! 			/* finally, we get to copy out the name; we know that
! 			 * it fits in 8.3 or the pattern wouldn't match, but it
! 			 * never hurts to be sure.
! 			 */
! 			strncpy(op, actualName, 13);
! 
! 			/* Uppercase if requested by client */
! 			if ((((smb_t *)inp)-&gt;flg2 &amp; 1) == 0)
! 				_strupr(op);
! 
! 			op += 13;
! 
! 			/* now, adjust the # of entries copied */
! 			returnedNames++;
! 		}	/* if we're including this name */
!                 
! 	  nextEntry:
! 		/* and adjust curOffset to be where the new cookie is */
! 		thyper.HighPart = 0;
! 		thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
! 		curOffset = LargeIntegerAdd(thyper, curOffset);
! 	}		/* while copying data for dir listing */
! 
! 	/* release the mutex */
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	if (bufferp) buf_Release(bufferp);
! 
! 	/* apply and free last set of patches; if not doing a star match, this
! 	 * will be empty, but better safe (and freeing everything) than sorry.
! 	 */
! 	smb_ApplyDirListPatches(&amp;dirListPatchesp, userp, &amp;req);
! 
! 	/* special return code for unsuccessful search */
! 	if (code == 0 &amp;&amp; dataLength &lt; 21 &amp;&amp; returnedNames == 0)
! 		code = CM_ERROR_NOFILES;
! 
! 	osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
! 		 returnedNames, code);
! 
! 	if (code != 0) {
! 		smb_DeleteDirSearch(dsp);
! 		smb_ReleaseDirSearch(dsp);
! 		cm_ReleaseSCache(scp);
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
! 
! 	/* finalize the output buffer */
! 	smb_SetSMBParm(outp, 0, returnedNames);
! 	temp = (long) (op - origOp);
! 	smb_SetSMBDataLength(outp, temp);
! 
! 	/* the data area is a variable block, which has a 5 (already there)
! 	 * followed by the length of the # of data bytes.  We now know this to
! 	 * be "temp," although that includes the 3 bytes of vbl block header.
! 	 * Deduct for them and fill in the length field.
! 	 */
! 	temp -= 3;		/* deduct vbl block info */
! 	osi_assert(temp == (43 * returnedNames));
! 	origOp[1] = temp &amp; 0xff;
! 	origOp[2] = (temp&gt;&gt;8) &amp; 0xff;
! 	if (returnedNames == 0) smb_DeleteDirSearch(dsp);
! 	smb_ReleaseDirSearch(dsp);
! 	cm_ReleaseSCache(scp);
! 	cm_ReleaseUser(userp);
! 	return code;
! }	
  
! /* verify that this is a valid path to a directory.  I don't know why they
!  * don't use the get file attributes call.
!  */
! long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
! 	char *pathp;
! 	long code = 0;
! 	cm_scache_t *rootScp;
! 	cm_scache_t *newScp;
! 	cm_user_t *userp;
! 	unsigned int attrs;
! 	int caseFold;
! 	char *tidPathp;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
! 
! 	pathp = smb_GetSMBData(inp, NULL);
! 	pathp = smb_ParseASCIIBlock(pathp, NULL);
! 	osi_Log1(smb_logp, "SMB receive check path %s",
! 			  osi_LogSaveString(smb_logp, pathp));
! 
! 	if (!pathp) {
! 		return CM_ERROR_BADFD;
! 	}
!         
! 	rootScp = cm_rootSCachep;
          
! 	userp = smb_GetUser(vcp, inp);
  
! 	caseFold = CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
!         cm_ReleaseUser(userp);
!         return CM_ERROR_NOSUCHPATH;
      }
- 	code = cm_NameI(rootScp, pathp,
- 					 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
- 					 userp, tidPathp, &amp;req, &amp;newScp);
- 
- 	if (code) {
- 		cm_ReleaseUser(userp);
- 		return code;
- 	}
-         
- 	/* now lock the vnode with a callback; returns with newScp locked */
- 	lock_ObtainMutex(&amp;newScp-&gt;mx);
- 	code = cm_SyncOp(newScp, NULL, userp, &amp;req, PRSFS_LOOKUP,
- 					  CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
- 	if (code &amp;&amp; code != CM_ERROR_NOACCESS) {
- 		lock_ReleaseMutex(&amp;newScp-&gt;mx);
- 		cm_ReleaseSCache(newScp);
- 		cm_ReleaseUser(userp);
- 		return code;
- 	}
- 
- 	attrs = smb_Attributes(newScp);
- 
- 	if (!(attrs &amp; 0x10))
- 		code = CM_ERROR_NOTDIR;
- 
- 	lock_ReleaseMutex(&amp;newScp-&gt;mx);
- 
- 	cm_ReleaseSCache(newScp);
- 	cm_ReleaseUser(userp);
- 	return code;
- }	
  
! long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
! 	char *pathp;
! 	long code = 0;
! 	cm_scache_t *rootScp;
! 	unsigned short attribute;
! 	cm_attr_t attr;
! 	cm_scache_t *newScp;
! 	time_t dosTime;
! 	cm_user_t *userp;
! 	int caseFold;
! 	char *tidPathp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
! 	/* decode basic attributes we're passed */
! 	attribute = smb_GetSMBParm(inp, 0);
! 	dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) &lt;&lt; 16);
  
! 	pathp = smb_GetSMBData(inp, NULL);
! 	pathp = smb_ParseASCIIBlock(pathp, NULL);
!         
! 	if (!pathp) {
! 		return CM_ERROR_BADSMB;
! 	}
!         
! 	osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
! 			 dosTime, attribute);
  
! 	rootScp = cm_rootSCachep;
!         
! 	userp = smb_GetUser(vcp, inp);
  
! 	caseFold = CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
!         cm_ReleaseUser(userp);
!         return CM_ERROR_NOSUCHFILE;
!     }
! 	code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
! 					tidPathp, &amp;req, &amp;newScp);
  
! 	if (code) {
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
! 	
! 	/* now lock the vnode with a callback; returns with newScp locked; we
! 	 * need the current status to determine what the new status is, in some
! 	 * cases.
! 	 */
! 	lock_ObtainMutex(&amp;newScp-&gt;mx);
! 	code = cm_SyncOp(newScp, NULL, userp, &amp;req, 0,
! 					 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
! 	if (code) {
! 		lock_ReleaseMutex(&amp;newScp-&gt;mx);
! 		cm_ReleaseSCache(newScp);
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
! 
! 	/* Check for RO volume */
! 	if (newScp-&gt;flags &amp; CM_SCACHEFLAG_RO) {
! 		lock_ReleaseMutex(&amp;newScp-&gt;mx);
! 		cm_ReleaseSCache(newScp);
! 		cm_ReleaseUser(userp);
! 		return CM_ERROR_READONLY;
! 	}
! 
! 	/* prepare for setattr call */
! 	attr.mask = 0;
! 	if (dosTime != 0) {
! 		attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
! 		smb_UnixTimeFromDosUTime(&amp;attr.clientModTime, dosTime);
! 	}
! 	if ((newScp-&gt;unixModeBits &amp; 0222) &amp;&amp; (attribute &amp; 1) != 0) {
! 		/* we're told to make a writable file read-only */
! 		attr.unixModeBits = newScp-&gt;unixModeBits &amp; ~0222;
! 		attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
! 	}
! 	else if ((newScp-&gt;unixModeBits &amp; 0222) == 0 &amp;&amp; (attribute &amp; 1) == 0) {
! 		/* we're told to make a read-only file writable */
! 		attr.unixModeBits = newScp-&gt;unixModeBits | 0222;
! 		attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
! 	}
! 	lock_ReleaseMutex(&amp;newScp-&gt;mx);
! 
! 	/* now call setattr */
! 	if (attr.mask)
! 		code = cm_SetAttr(newScp, &amp;attr, userp, &amp;req);
! 	else
! 		code = 0;
!         
! 	cm_ReleaseSCache(newScp);
! 	cm_ReleaseUser(userp);
  
! 	return code;
! }
  
! long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
! 	char *pathp;
! 	long code = 0;
! 	cm_scache_t *rootScp;
! 	cm_scache_t *newScp, *dscp;
! 	time_t dosTime;
! 	int attrs;
! 	cm_user_t *userp;
! 	int caseFold;
! 	char *tidPathp;
! 	cm_space_t *spacep;
! 	char *lastComp;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
! 
! 	pathp = smb_GetSMBData(inp, NULL);
! 	pathp = smb_ParseASCIIBlock(pathp, NULL);
!         
! 	if (!pathp) {
! 		return CM_ERROR_BADSMB;
! 	}
!         
! 	if (*pathp == 0)		/* null path */
! 		pathp = "\\";
! 
! 	osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
! 			 osi_LogSaveString(smb_logp, pathp));
  
! 	rootScp = cm_rootSCachep;
!         
! 	userp = smb_GetUser(vcp, inp);
  
! 	/* we shouldn't need this for V3 requests, but we seem to */
! 	caseFold = CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
          cm_ReleaseUser(userp);
!         return CM_ERROR_NOSUCHFILE;
      }
  
! 	/*
! 	 * XXX Strange hack XXX
! 	 *
! 	 * As of Patch 5 (16 July 97), we are having the following problem:
! 	 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
! 	 * requests to look up "desktop.ini" in all the subdirectories.
! 	 * This can cause zillions of timeouts looking up non-existent cells
! 	 * and volumes, especially in the top-level directory.
! 	 *
! 	 * We have not found any way to avoid this or work around it except
! 	 * to explicitly ignore the requests for mount points that haven't
! 	 * yet been evaluated and for directories that haven't yet been
! 	 * fetched.
! 	 *
! 	 * We should modify this hack to provide a fake desktop.ini file
! 	 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
! 	 */
! 	spacep = inp-&gt;spacep;
! 	smb_StripLastComponent(spacep-&gt;data, &amp;lastComp, pathp);
! 	if (lastComp &amp;&amp; stricmp(lastComp, "\\desktop.ini") == 0) {
! 		code = cm_NameI(rootScp, spacep-&gt;data,
! 						caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
! 						userp, tidPathp, &amp;req, &amp;dscp);
! 		if (code == 0) {
! 			if (dscp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT
! 			    &amp;&amp; !dscp-&gt;mountRootFidp)
! 				code = CM_ERROR_NOSUCHFILE;
! 			else if (dscp-&gt;fileType == CM_SCACHETYPE_DIRECTORY) {
! 				cm_buf_t *bp = buf_Find(dscp, &amp;hzero);
! 				if (bp)
! 					buf_Release(bp);
! 				else
! 					code = CM_ERROR_NOSUCHFILE;
! 			}
! 			cm_ReleaseSCache(dscp);
! 			if (code) {
! 				cm_ReleaseUser(userp);
! 				return code;
! 			}
! 		}
! 	}
! 
! 	code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
! 					tidPathp, &amp;req, &amp;newScp);
! 
! 	if (code) {
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
!         
! 	/* now lock the vnode with a callback; returns with newScp locked */
! 	lock_ObtainMutex(&amp;newScp-&gt;mx);
! 	code = cm_SyncOp(newScp, NULL, userp, &amp;req, 0,
! 					 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
! 	if (code) {
! 		lock_ReleaseMutex(&amp;newScp-&gt;mx);
! 		cm_ReleaseSCache(newScp);
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
! 
! #ifdef undef
!     /* use smb_Attributes instead.   Also the fact that a file is 
! 	 * in a readonly volume doesn't mean it shojuld be marked as RO 
! 	 */
! 	if (newScp-&gt;fileType == CM_SCACHETYPE_DIRECTORY
! 		|| newScp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT)
! 		attrs = SMB_ATTR_DIRECTORY;
! 	else
! 		attrs = 0;
! 	if ((newScp-&gt;unixModeBits &amp; 0222) == 0 || (newScp-&gt;flags &amp; CM_SCACHEFLAG_RO))
! 		attrs |= SMB_ATTR_READONLY;	/* turn on read-only flag */
! #else
!     attrs = smb_Attributes(newScp);
! #endif
  
! 	smb_SetSMBParm(outp, 0, attrs);
          
! 	smb_DosUTimeFromUnixTime(&amp;dosTime, newScp-&gt;clientModTime);
! 	smb_SetSMBParm(outp, 1, dosTime &amp; 0xffff);
! 	smb_SetSMBParm(outp, 2, (dosTime&gt;&gt;16) &amp; 0xffff);
! 	smb_SetSMBParm(outp, 3, newScp-&gt;length.LowPart &amp; 0xffff);
! 	smb_SetSMBParm(outp, 4, (newScp-&gt;length.LowPart &gt;&gt; 16) &amp; 0xffff);
! 	smb_SetSMBParm(outp, 5, 0);
! 	smb_SetSMBParm(outp, 6, 0);
! 	smb_SetSMBParm(outp, 7, 0);
! 	smb_SetSMBParm(outp, 8, 0);
! 	smb_SetSMBParm(outp, 9, 0);
! 	smb_SetSMBDataLength(outp, 0);
! 	lock_ReleaseMutex(&amp;newScp-&gt;mx);
  
! 	cm_ReleaseSCache(newScp);
! 	cm_ReleaseUser(userp);
          
! 	return 0;
  }	
  
  long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	smb_tid_t *tidp;
          
! 	osi_Log0(smb_logp, "SMB receive tree disconnect");
  
! 	/* find the tree and free it */
! 	tidp = smb_FindTID(vcp, ((smb_t *)inp)-&gt;tid, 0);
! 	if (tidp) {
! 		lock_ObtainMutex(&amp;tidp-&gt;mx);
! 		tidp-&gt;flags |= SMB_TIDFLAG_DELETE;
! 		lock_ReleaseMutex(&amp;tidp-&gt;mx);
! 		smb_ReleaseTID(tidp);
! 	}
  
! 	return 0;
  }
  
  long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	smb_fid_t *fidp;
      char *pathp;
! 	char *lastNamep;
      int share;
      int attribute;
! 	long code = 0;
      cm_user_t *userp;
      cm_scache_t *scp;
      time_t dosTime;
      int caseFold;
! 	cm_space_t *spacep;
! 	char *tidPathp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      pathp = smb_GetSMBData(inp, NULL);
      pathp = smb_ParseASCIIBlock(pathp, NULL);
--- 3217,4104 ----
                  *dptr++ = SMB_ATTR_HIDDEN;
              continue;
          }
!         lock_ObtainMutex(&amp;scp-&gt;mx);
!         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
!                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!         if (code) {	
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             cm_ReleaseSCache(scp);
!             if (patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE)
                  *dptr++ = SMB_ATTR_HIDDEN;
!             continue;
!         }
  
!         attr = smb_Attributes(scp);
          /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
!         if (patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE)
              attr |= SMB_ATTR_HIDDEN;
          *dptr++ = attr;
  
          /* get dos time */
!         smb_SearchTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
                  
!         /* copy out time */
!         shortTemp = dosTime &amp; 0xffff;
!         *((u_short *)dptr) = shortTemp;
!         dptr += 2;
! 
!         /* and copy out date */
!         shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
!         *((u_short *)dptr) = shortTemp;
!         dptr += 2;
                  
!         /* copy out file length */
!         *((u_long *)dptr) = scp-&gt;length.LowPart;
!         dptr += 4;
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         cm_ReleaseSCache(scp);
!     }
!         
!     /* now free the patches */
!     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
!         npatchp = (smb_dirListPatch_t *) osi_QNext(&amp;patchp-&gt;q);
!         free(patchp);
!     }	
          
!     /* and mark the list as empty */
!     *dirPatchespp = NULL;
  
!     return code;
  }
  
  long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     int attribute;
!     long nextCookie;
!     char *tp;
!     long code = 0;
!     char *pathp;
!     cm_dirEntry_t *dep;
!     int maxCount;
!     smb_dirListPatch_t *dirListPatchesp;
!     smb_dirListPatch_t *curPatchp;
!     int dataLength;
!     cm_buf_t *bufferp;
!     long temp;
!     osi_hyper_t dirLength;
!     osi_hyper_t bufferOffset;
!     osi_hyper_t curOffset;
!     osi_hyper_t thyper;
!     unsigned char *inCookiep;
!     smb_dirSearch_t *dsp;
!     cm_scache_t *scp;
!     long entryInDir;
!     long entryInBuffer;
!     unsigned long clientCookie;
!     cm_pageHeader_t *pageHeaderp;
!     cm_user_t *userp = NULL;
!     int slotInPage;
!     char shortName[13];
!     char *actualName;
!     char *shortNameEnd;
!     char mask[11];
!     int returnedNames;
!     long nextEntryCookie;
!     int numDirChunks;		/* # of 32 byte dir chunks in this entry */
!     char resByte;			/* reserved byte from the cookie */
!     char *op;			/* output data ptr */
!     char *origOp;			/* original value of op */
!     cm_space_t *spacep;		/* for pathname buffer */
!     int starPattern;
!     int rootPath = 0;
!     int caseFold;
!     char *tidPathp;
!     cm_req_t req;
!     cm_fid_t fid;
!     int fileType;
  
!     cm_InitReq(&amp;req);
  
!     maxCount = smb_GetSMBParm(inp, 0);
  
!     dirListPatchesp = NULL;
          
!     caseFold = CM_FLAG_CASEFOLD;
  
!     tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &amp;tp);
!     inCookiep = smb_ParseVblBlock(tp, &amp;tp, &amp;dataLength);
  
!     /* bail out if request looks bad */
!     if (!tp || !pathp) {
!         return CM_ERROR_BADSMB;
      }
  
!     /* We can handle long names */
!     if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
!         ((smb_t *)outp)-&gt;flg2 |= 0x40;	/* IS_LONG_NAME */
  
!     /* make sure we got a whole search status */
!     if (dataLength &lt; 21) {
!         nextCookie = 0;		/* start at the beginning of the dir */
!         resByte = 0;
!         clientCookie = 0;
!         attribute = smb_GetSMBParm(inp, 1);
  
!         /* handle volume info in another function */
!         if (attribute &amp; 0x8)
!             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
  
!         osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
!                   maxCount, osi_LogSaveString(smb_logp, pathp));
  
!         if (*pathp == 0) {	/* null pathp, treat as root dir */
!             if (!(attribute &amp; SMB_ATTR_DIRECTORY))	/* exclude dirs */
!                 return CM_ERROR_NOFILES;
!             rootPath = 1;
!         }
  
!         dsp = smb_NewDirSearch(0);
!         dsp-&gt;attribute = attribute;
!         smb_Get8Dot3MaskFromPath(mask, pathp);
!         memcpy(dsp-&gt;mask, mask, 11);
  
!         /* track if this is likely to match a lot of entries */
!         if (smb_IsStarMask(mask)) starPattern = 1;
!         else starPattern = 0;
!     }	
!     else {
!         /* pull the next cookie value out of the search status block */
!         nextCookie = inCookiep[13] + (inCookiep[14]&lt;&lt;8) + (inCookiep[15]&lt;&lt;16)
!             + (inCookiep[16]&lt;&lt;24);
!         dsp = smb_FindDirSearch(inCookiep[12]);
!         if (!dsp) {
!             /* can't find dir search status; fatal error */
!             return CM_ERROR_BADFD;
!         }
!         attribute = dsp-&gt;attribute;
!         resByte = inCookiep[0];
  
!         /* copy out client cookie, in host byte order.  Don't bother
!          * interpreting it, since we're just passing it through, anyway.
!          */
!         memcpy(&amp;clientCookie, &amp;inCookiep[17], 4);
  
!         memcpy(mask, dsp-&gt;mask, 11);
  
!         /* assume we're doing a star match if it has continued for more
!          * than one call.
!          */
!         starPattern = 1;
!     }
  
!     osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
!              nextCookie, dsp-&gt;cookie, attribute);
  
!     userp = smb_GetUser(vcp, inp);
  
!     /* try to get the vnode for the path name next */
!     lock_ObtainMutex(&amp;dsp-&gt;mx);
!     if (dsp-&gt;scp) {
!         scp = dsp-&gt;scp;
!         cm_HoldSCache(scp);
!         code = 0;
!     }
!     else {
!         spacep = inp-&gt;spacep;
!         smb_StripLastComponent(spacep-&gt;data, NULL, pathp);
!         lock_ReleaseMutex(&amp;dsp-&gt;mx);
!         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!         if (code) {
!             lock_ReleaseMutex(&amp;dsp-&gt;mx);
!             cm_ReleaseUser(userp);
!             smb_DeleteDirSearch(dsp);
!             smb_ReleaseDirSearch(dsp);
!             return CM_ERROR_NOFILES;
!         }
!         code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
!                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &amp;req, &amp;scp);
!         lock_ObtainMutex(&amp;dsp-&gt;mx);
!         if (code == 0) {
!             if (dsp-&gt;scp != 0) cm_ReleaseSCache(dsp-&gt;scp);
!             dsp-&gt;scp = scp;
!             /* we need one hold for the entry we just stored into,
!              * and one for our own processing.  When we're done with this
!              * function, we'll drop the one for our own processing.
!              * We held it once from the namei call, and so we do another hold
!              * now.
!              */
!             cm_HoldSCache(scp);
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             if ((scp-&gt;flags &amp; CM_SCACHEFLAG_BULKSTATTING) == 0
!                  &amp;&amp; LargeIntegerGreaterOrEqualToZero(scp-&gt;bulkStatProgress)) {
!                 scp-&gt;flags |= CM_SCACHEFLAG_BULKSTATTING;
!                 dsp-&gt;flags |= SMB_DIRSEARCH_BULKST;
!             }
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!         }
!     }
!     lock_ReleaseMutex(&amp;dsp-&gt;mx);
!     if (code) {
          cm_ReleaseUser(userp);
!         smb_DeleteDirSearch(dsp);
!         smb_ReleaseDirSearch(dsp);
!         return code;
      }
  
!     /* reserves space for parameter; we'll adjust it again later to the
!      * real count of the # of entries we returned once we've actually
!      * assembled the directory listing.
!      */
!     smb_SetSMBParm(outp, 0, 0);
  
!     /* get the directory size */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         cm_ReleaseSCache(scp);
!         cm_ReleaseUser(userp);
!         smb_DeleteDirSearch(dsp);
!         smb_ReleaseDirSearch(dsp);
!         return code;
!     }
          
!     dirLength = scp-&gt;length;
!     bufferp = NULL;
!     bufferOffset.LowPart = bufferOffset.HighPart = 0;
!     curOffset.HighPart = 0;
!     curOffset.LowPart = nextCookie;
!     origOp = op = smb_GetSMBData(outp, NULL);
!     /* and write out the basic header */
!     *op++ = 5;		/* variable block */
!     op += 2;		/* skip vbl block length; we'll fill it in later */
!     code = 0;
!     returnedNames = 0;
!     while (1) {
!         /* make sure that curOffset.LowPart doesn't point to the first
!          * 32 bytes in the 2nd through last dir page, and that it doesn't
!          * point at the first 13 32-byte chunks in the first dir page,
!          * since those are dir and page headers, and don't contain useful
!          * information.
!          */
!         temp = curOffset.LowPart &amp; (2048-1);
!         if (curOffset.HighPart == 0 &amp;&amp; curOffset.LowPart &lt; 2048) {
!             /* we're in the first page */
!             if (temp &lt; 13*32) temp = 13*32;
!         }
!         else {
!             /* we're in a later dir page */
!             if (temp &lt; 32) temp = 32;
!         }
  
!         /* make sure the low order 5 bits are zero */
!         temp &amp;= ~(32-1);
! 
!         /* now put temp bits back ito curOffset.LowPart */
!         curOffset.LowPart &amp;= ~(2048-1);
!         curOffset.LowPart |= temp;
! 
!         /* check if we've returned all the names that will fit in the
!          * response packet.
!          */
!         if (returnedNames &gt;= maxCount) 
!             break;
!                 
!         /* check if we've passed the dir's EOF */
!         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
! 
!         /* see if we can use the bufferp we have now; compute in which page
!          * the current offset would be, and check whether that's the offset
!          * of the buffer we have.  If not, get the buffer.
!          */
!         thyper.HighPart = curOffset.HighPart;
!         thyper.LowPart = curOffset.LowPart &amp; ~(buf_bufferSize-1);
!         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
!             /* wrong buffer */
!             if (bufferp) {
!                 buf_Release(bufferp);
!                 bufferp = NULL;
!             }	
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
!             code = buf_Get(scp, &amp;thyper, &amp;bufferp);
!             lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
! 
!             /* now, if we're doing a star match, do bulk fetching of all of 
!              * the status info for files in the dir.
!              */
!             if (starPattern) {
!                 smb_ApplyDirListPatches(&amp;dirListPatchesp, userp,
!                                          &amp;req);
!                 if ((dsp-&gt;flags &amp; SMB_DIRSEARCH_BULKST) &amp;&amp;
!                      LargeIntegerGreaterThanOrEqualTo(thyper, 
!                                                       scp-&gt;bulkStatProgress)) {
!                     /* Don't bulk stat if risking timeout */
!                     int now = GetCurrentTime();
!                     if (now - req.startTime &gt; 5000) {
!                         scp-&gt;bulkStatProgress = thyper;
!                         scp-&gt;flags &amp;= ~CM_SCACHEFLAG_BULKSTATTING;
!                         dsp-&gt;flags &amp;= ~SMB_DIRSEARCH_BULKST;
!                     } else
!                         cm_TryBulkStat(scp, &amp;thyper, userp, &amp;req);
!                 }
!             }
! 
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             if (code) 
!                 break;
!             bufferOffset = thyper;
! 
!             /* now get the data in the cache */
!             while (1) {
!                 code = cm_SyncOp(scp, bufferp, userp, &amp;req,
!                                  PRSFS_LOOKUP,
!                                  CM_SCACHESYNC_NEEDCALLBACK |
!                                  CM_SCACHESYNC_READ);
!                 if (code) break;
!                                 
!                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
! 
!                 /* otherwise, load the buffer and try again */
!                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &amp;req);
!                 if (code) break;
!             }
!             if (code) {
!                 buf_Release(bufferp);
!                 bufferp = NULL;
!                 break;
!             }
!         }	/* if (wrong buffer) ... */
! 
!         /* now we have the buffer containing the entry we're interested in; copy
!          * it out if it represents a non-deleted entry.
!          */
!         entryInDir = curOffset.LowPart &amp; (2048-1);
!         entryInBuffer = curOffset.LowPart &amp; (buf_bufferSize - 1);
! 
!         /* page header will help tell us which entries are free.  Page header
!          * can change more often than once per buffer, since AFS 3 dir page size
!          * may be less than (but not more than a buffer package buffer.
!          */
!         temp = curOffset.LowPart &amp; (buf_bufferSize - 1);  /* only look intra-buffer */
!         temp &amp;= ~(2048 - 1);	/* turn off intra-page bits */
!         pageHeaderp = (cm_pageHeader_t *) (bufferp-&gt;datap + temp);
! 
!         /* now determine which entry we're looking at in the page.  If it is
!          * free (there's a free bitmap at the start of the dir), we should
!          * skip these 32 bytes.
!          */
!         slotInPage = (entryInDir &amp; 0x7e0) &gt;&gt; 5;
!         if (!(pageHeaderp-&gt;freeBitmap[slotInPage&gt;&gt;3] &amp; (1 &lt;&lt; (slotInPage &amp; 0x7)))) {
!             /* this entry is free */
!             numDirChunks = 1;		/* only skip this guy */
!             goto nextEntry;
!         }
! 
!         tp = bufferp-&gt;datap + entryInBuffer;
!         dep = (cm_dirEntry_t *) tp;		/* now points to AFS3 dir entry */
! 
!         /* while we're here, compute the next entry's location, too,
!          * since we'll need it when writing out the cookie into the dir
!          * listing stream.
!          *
!          * XXXX Probably should do more sanity checking.
!          */
!         numDirChunks = cm_NameEntries(dep-&gt;name, NULL);
! 
!         /* compute the offset of the cookie representing the next entry */
!         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
! 
!         /* Compute 8.3 name if necessary */
!         actualName = dep-&gt;name;
!         if (dep-&gt;fid.vnode != 0 &amp;&amp; !cm_Is8Dot3(actualName)) {
!             cm_Gen8Dot3Name(dep, shortName, &amp;shortNameEnd);
!             actualName = shortName;
!         }
! 
!         if (dep-&gt;fid.vnode != 0 &amp;&amp; smb_Match8Dot3Mask(actualName, mask)) {
!             /* this is one of the entries to use: it is not deleted
!              * and it matches the star pattern we're looking for.
!              */
! 
!             /* Eliminate entries that don't match requested
!              * attributes */
! 
!             /* no hidden files */
!             if(smb_hideDotFiles &amp;&amp; !(dsp-&gt;attribute &amp; SMB_ATTR_HIDDEN) &amp;&amp; smb_IsDotFile(actualName))
!                 goto nextEntry;
! 
!             if (!(dsp-&gt;attribute &amp; SMB_ATTR_DIRECTORY))  /* no directories */
!             {
!                 /* We have already done the cm_TryBulkStat above */
!                 fid.cell = scp-&gt;fid.cell;
!                 fid.volume = scp-&gt;fid.volume;
!                 fid.vnode = ntohl(dep-&gt;fid.vnode);
!                 fid.unique = ntohl(dep-&gt;fid.unique);
!                 fileType = cm_FindFileType(&amp;fid);
!                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
!                          "has filetype %d", osi_LogSaveString(smb_logp, dep-&gt;name),
!                           fileType);
!                 if (fileType == CM_SCACHETYPE_DIRECTORY)
!                     goto nextEntry;
!             }
! 
!             *op++ = resByte;
!             memcpy(op, mask, 11); op += 11;
!             *op++ = (char) dsp-&gt;cookie;	/* they say it must be non-zero */
!             *op++ = nextEntryCookie &amp; 0xff;
!             *op++ = (nextEntryCookie&gt;&gt;8) &amp; 0xff;
!             *op++ = (nextEntryCookie&gt;&gt;16) &amp; 0xff;
!             *op++ = (nextEntryCookie&gt;&gt;24) &amp; 0xff;
!             memcpy(op, &amp;clientCookie, 4); op += 4;
! 
!             /* now we emit the attribute.  This is sort of tricky,
!              * since we need to really stat the file to find out
!              * what type of entry we've got.  Right now, we're
!              * copying out data from a buffer, while holding the
!              * scp locked, so it isn't really convenient to stat
!              * something now.  We'll put in a place holder now,
!              * and make a second pass before returning this to get
!              * the real attributes.  So, we just skip the data for
!              * now, and adjust it later.  We allocate a patch
!              * record to make it easy to find this point later.
!              * The replay will happen at a time when it is safe to
!              * unlock the directory.
!              */
!             curPatchp = malloc(sizeof(*curPatchp));
!             osi_QAdd((osi_queue_t **) &amp;dirListPatchesp, &amp;curPatchp-&gt;q);
!             curPatchp-&gt;dptr = op;
!             curPatchp-&gt;fid.cell = scp-&gt;fid.cell;
!             curPatchp-&gt;fid.volume = scp-&gt;fid.volume;
!             curPatchp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
!             curPatchp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
! 
!             /* do hidden attribute here since name won't be around when applying
!              * dir list patches
!              */
! 
!             if ( smb_hideDotFiles &amp;&amp; smb_IsDotFile(actualName) )
!                 curPatchp-&gt;flags = SMB_DIRLISTPATCH_DOTFILE;
!             else
!                 curPatchp-&gt;flags = 0;
! 
!             op += 9;	/* skip attr, time, date and size */
! 
!             /* zero out name area.  The spec says to pad with
!              * spaces, but Samba doesn't, and neither do we.
!              */
!             memset(op, 0, 13);
! 
!             /* finally, we get to copy out the name; we know that
!              * it fits in 8.3 or the pattern wouldn't match, but it
!              * never hurts to be sure.
!              */
!             strncpy(op, actualName, 13);
! 
!             /* Uppercase if requested by client */
!             if ((((smb_t *)inp)-&gt;flg2 &amp; 1) == 0)
!                 _strupr(op);
! 
!             op += 13;
! 
!             /* now, adjust the # of entries copied */
!             returnedNames++;
!         }	/* if we're including this name */
! 
!       nextEntry:
!         /* and adjust curOffset to be where the new cookie is */
!         thyper.HighPart = 0;
!         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
!         curOffset = LargeIntegerAdd(thyper, curOffset);
!     }		/* while copying data for dir listing */
! 
!     /* release the mutex */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     if (bufferp) buf_Release(bufferp);
! 
!     /* apply and free last set of patches; if not doing a star match, this
!      * will be empty, but better safe (and freeing everything) than sorry.
!      */
!     smb_ApplyDirListPatches(&amp;dirListPatchesp, userp, &amp;req);
! 
!     /* special return code for unsuccessful search */
!     if (code == 0 &amp;&amp; dataLength &lt; 21 &amp;&amp; returnedNames == 0)
!         code = CM_ERROR_NOFILES;
! 
!     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
!              returnedNames, code);
! 
!     if (code != 0) {
!         smb_DeleteDirSearch(dsp);
!         smb_ReleaseDirSearch(dsp);
!         cm_ReleaseSCache(scp);
!         cm_ReleaseUser(userp);
!         return code;
!     }
! 
!     /* finalize the output buffer */
!     smb_SetSMBParm(outp, 0, returnedNames);
!     temp = (long) (op - origOp);
!     smb_SetSMBDataLength(outp, temp);
! 
!     /* the data area is a variable block, which has a 5 (already there)
!      * followed by the length of the # of data bytes.  We now know this to
!      * be "temp," although that includes the 3 bytes of vbl block header.
!      * Deduct for them and fill in the length field.
!      */
!     temp -= 3;		/* deduct vbl block info */
!     osi_assert(temp == (43 * returnedNames));
!     origOp[1] = temp &amp; 0xff;
!     origOp[2] = (temp&gt;&gt;8) &amp; 0xff;
!     if (returnedNames == 0) 
!         smb_DeleteDirSearch(dsp);
!     smb_ReleaseDirSearch(dsp);
!     cm_ReleaseSCache(scp);
!     cm_ReleaseUser(userp);
!     return code;
! }	
! 
! /* verify that this is a valid path to a directory.  I don't know why they
!  * don't use the get file attributes call.
!  */
! long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
!     char *pathp;
!     long code = 0;
!     cm_scache_t *rootScp;
!     cm_scache_t *newScp;
!     cm_user_t *userp;
!     unsigned int attrs;
!     int caseFold;
!     char *tidPathp;
!     cm_req_t req;
! 
!     cm_InitReq(&amp;req);
! 
!     pathp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(pathp, NULL);
!     osi_Log1(smb_logp, "SMB receive check path %s",
!              osi_LogSaveString(smb_logp, pathp));
! 
!     if (!pathp) {
!         return CM_ERROR_BADFD;
!     }
!         
!     rootScp = cm_rootSCachep;
!         
!     userp = smb_GetUser(vcp, inp);
! 
!     caseFold = CM_FLAG_CASEFOLD;
! 
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
!         cm_ReleaseUser(userp);
!         return CM_ERROR_NOSUCHPATH;
!     }
!     code = cm_NameI(rootScp, pathp,
!                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
!                     userp, tidPathp, &amp;req, &amp;newScp);
! 
!     if (code) {
!         cm_ReleaseUser(userp);
!         return code;
!     }
!         
!     /* now lock the vnode with a callback; returns with newScp locked */
!     lock_ObtainMutex(&amp;newScp-&gt;mx);
!     code = cm_SyncOp(newScp, NULL, userp, &amp;req, PRSFS_LOOKUP,
!                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
!     if (code &amp;&amp; code != CM_ERROR_NOACCESS) {
!         lock_ReleaseMutex(&amp;newScp-&gt;mx);
!         cm_ReleaseSCache(newScp);
!         cm_ReleaseUser(userp);
!         return code;
!     }
! 
!     attrs = smb_Attributes(newScp);
! 
!     if (!(attrs &amp; 0x10))
!         code = CM_ERROR_NOTDIR;
! 
!     lock_ReleaseMutex(&amp;newScp-&gt;mx);
! 
!     cm_ReleaseSCache(newScp);
!     cm_ReleaseUser(userp);
!     return code;
! }	
! 
! long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
!     char *pathp;
!     long code = 0;
!     cm_scache_t *rootScp;
!     unsigned short attribute;
!     cm_attr_t attr;
!     cm_scache_t *newScp;
!     time_t dosTime;
!     cm_user_t *userp;
!     int caseFold;
!     char *tidPathp;
!     cm_req_t req;
! 
!     cm_InitReq(&amp;req);
! 
!     /* decode basic attributes we're passed */
!     attribute = smb_GetSMBParm(inp, 0);
!     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) &lt;&lt; 16);
! 
!     pathp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(pathp, NULL);
! 
!     if (!pathp) {
!         return CM_ERROR_BADSMB;
!     }
!         
!     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
!              dosTime, attribute);
! 
!     rootScp = cm_rootSCachep;
!         
!     userp = smb_GetUser(vcp, inp);
! 
!     caseFold = CM_FLAG_CASEFOLD;
! 
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
!         cm_ReleaseUser(userp);
!         return CM_ERROR_NOSUCHFILE;
!     }
!     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
!                     tidPathp, &amp;req, &amp;newScp);
! 
!     if (code) {
!         cm_ReleaseUser(userp);
!         return code;
!     }
! 	
!     /* now lock the vnode with a callback; returns with newScp locked; we
!      * need the current status to determine what the new status is, in some
!      * cases.
!      */
!     lock_ObtainMutex(&amp;newScp-&gt;mx);
!     code = cm_SyncOp(newScp, NULL, userp, &amp;req, 0,
!                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
!     if (code) {
!         lock_ReleaseMutex(&amp;newScp-&gt;mx);
!         cm_ReleaseSCache(newScp);
!         cm_ReleaseUser(userp);
!         return code;
!     }
! 
!     /* Check for RO volume */
!     if (newScp-&gt;flags &amp; CM_SCACHEFLAG_RO) {
!         lock_ReleaseMutex(&amp;newScp-&gt;mx);
!         cm_ReleaseSCache(newScp);
!         cm_ReleaseUser(userp);
!         return CM_ERROR_READONLY;
!     }
! 
!     /* prepare for setattr call */
!     attr.mask = 0;
!     if (dosTime != 0) {
!         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
!         smb_UnixTimeFromDosUTime(&amp;attr.clientModTime, dosTime);
!     }
!     if ((newScp-&gt;unixModeBits &amp; 0222) &amp;&amp; (attribute &amp; 1) != 0) {
!         /* we're told to make a writable file read-only */
!         attr.unixModeBits = newScp-&gt;unixModeBits &amp; ~0222;
!         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
!     }
!     else if ((newScp-&gt;unixModeBits &amp; 0222) == 0 &amp;&amp; (attribute &amp; 1) == 0) {
!         /* we're told to make a read-only file writable */
!         attr.unixModeBits = newScp-&gt;unixModeBits | 0222;
!         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
!     }
!     lock_ReleaseMutex(&amp;newScp-&gt;mx);
! 
!     /* now call setattr */
!     if (attr.mask)
!         code = cm_SetAttr(newScp, &amp;attr, userp, &amp;req);
!     else
!         code = 0;
!         
!     cm_ReleaseSCache(newScp);
!     cm_ReleaseUser(userp);
! 
!     return code;
! }
! 
! long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
!     char *pathp;
!     long code = 0;
!     cm_scache_t *rootScp;
!     cm_scache_t *newScp, *dscp;
!     time_t dosTime;
!     int attrs;
!     cm_user_t *userp;
!     int caseFold;
!     char *tidPathp;
!     cm_space_t *spacep;
!     char *lastComp;
!     cm_req_t req;
! 
!     cm_InitReq(&amp;req);
! 
!     pathp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(pathp, NULL);
! 
!     if (!pathp) {
!         return CM_ERROR_BADSMB;
!     }
!         
!     if (*pathp == 0)		/* null path */
!         pathp = "\\";
! 
!     osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
!              osi_LogSaveString(smb_logp, pathp));
! 
!     rootScp = cm_rootSCachep;
!         
!     userp = smb_GetUser(vcp, inp);
! 
!     /* we shouldn't need this for V3 requests, but we seem to */
!     caseFold = CM_FLAG_CASEFOLD;
! 
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
!         cm_ReleaseUser(userp);
!         return CM_ERROR_NOSUCHFILE;
!     }
! 
!     /*
!      * XXX Strange hack XXX
!      *
!      * As of Patch 5 (16 July 97), we are having the following problem:
!      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
!      * requests to look up "desktop.ini" in all the subdirectories.
!      * This can cause zillions of timeouts looking up non-existent cells
!      * and volumes, especially in the top-level directory.
!      *
!      * We have not found any way to avoid this or work around it except
!      * to explicitly ignore the requests for mount points that haven't
!      * yet been evaluated and for directories that haven't yet been
!      * fetched.
!      *
!      * We should modify this hack to provide a fake desktop.ini file
!      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
!      */
!     spacep = inp-&gt;spacep;
!     smb_StripLastComponent(spacep-&gt;data, &amp;lastComp, pathp);
!     if (lastComp &amp;&amp; stricmp(lastComp, "\\desktop.ini") == 0) {
!         code = cm_NameI(rootScp, spacep-&gt;data,
!                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
!                         userp, tidPathp, &amp;req, &amp;dscp);
!         if (code == 0) {
!             if (dscp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT &amp;&amp;
!                 !dscp-&gt;mountRootFidp)
!                 code = CM_ERROR_NOSUCHFILE;
!             else if (dscp-&gt;fileType == CM_SCACHETYPE_DIRECTORY) {
!                 cm_buf_t *bp = buf_Find(dscp, &amp;hzero);
!                 if (bp)
!                     buf_Release(bp);
!                 else
!                     code = CM_ERROR_NOSUCHFILE;
!             }
!             cm_ReleaseSCache(dscp);
!             if (code) {
!                 cm_ReleaseUser(userp);
!                 return code;
!             }
!         }
!     }
! 
!     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
!                     tidPathp, &amp;req, &amp;newScp);
!     if (code) {
!         cm_ReleaseUser(userp);
!         return code;
!     }
!         
!     /* now lock the vnode with a callback; returns with newScp locked */
!     lock_ObtainMutex(&amp;newScp-&gt;mx);
!     code = cm_SyncOp(newScp, NULL, userp, &amp;req, 0,
!                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
!     if (code) {
!         lock_ReleaseMutex(&amp;newScp-&gt;mx);
!         cm_ReleaseSCache(newScp);
!         cm_ReleaseUser(userp);
!         return code;
!     }
! 
! #ifdef undef
!     /* use smb_Attributes instead.   Also the fact that a file is 
!      * in a readonly volume doesn't mean it shojuld be marked as RO 
!      */
!     if (newScp-&gt;fileType == CM_SCACHETYPE_DIRECTORY ||
!         newScp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT)
!         attrs = SMB_ATTR_DIRECTORY;
!     else
!         attrs = 0;
!     if ((newScp-&gt;unixModeBits &amp; 0222) == 0 || (newScp-&gt;flags &amp; CM_SCACHEFLAG_RO))
!         attrs |= SMB_ATTR_READONLY;	/* turn on read-only flag */
! #else
!     attrs = smb_Attributes(newScp);
! #endif
! 
!     smb_SetSMBParm(outp, 0, attrs);
          
!     smb_DosUTimeFromUnixTime(&amp;dosTime, newScp-&gt;clientModTime);
!     smb_SetSMBParm(outp, 1, dosTime &amp; 0xffff);
!     smb_SetSMBParm(outp, 2, (dosTime&gt;&gt;16) &amp; 0xffff);
!     smb_SetSMBParm(outp, 3, newScp-&gt;length.LowPart &amp; 0xffff);
!     smb_SetSMBParm(outp, 4, (newScp-&gt;length.LowPart &gt;&gt; 16) &amp; 0xffff);
!     smb_SetSMBParm(outp, 5, 0);
!     smb_SetSMBParm(outp, 6, 0);
!     smb_SetSMBParm(outp, 7, 0);
!     smb_SetSMBParm(outp, 8, 0);
!     smb_SetSMBParm(outp, 9, 0);
!     smb_SetSMBDataLength(outp, 0);
!     lock_ReleaseMutex(&amp;newScp-&gt;mx);
! 
!     cm_ReleaseSCache(newScp);
!     cm_ReleaseUser(userp);
! 
!     return 0;
  }	
  
  long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     smb_tid_t *tidp;
          
!     osi_Log0(smb_logp, "SMB receive tree disconnect");
  
!     /* find the tree and free it */
!     tidp = smb_FindTID(vcp, ((smb_t *)inp)-&gt;tid, 0);
!     if (tidp) {
!         lock_ObtainMutex(&amp;tidp-&gt;mx);
!         tidp-&gt;flags |= SMB_TIDFLAG_DELETE;
!         lock_ReleaseMutex(&amp;tidp-&gt;mx);
!         smb_ReleaseTID(tidp);
!     }
  
!     return 0;
  }
  
  long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     smb_fid_t *fidp;
      char *pathp;
!     char *lastNamep;
      int share;
      int attribute;
!     long code = 0;
      cm_user_t *userp;
      cm_scache_t *scp;
      time_t dosTime;
      int caseFold;
!     cm_space_t *spacep;
!     char *tidPathp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      pathp = smb_GetSMBData(inp, NULL);
      pathp = smb_ParseASCIIBlock(pathp, NULL);
***************
*** 4086,4121 ****
      }
  #endif
  
! 	share = smb_GetSMBParm(inp, 0);
      attribute = smb_GetSMBParm(inp, 1);
  
! 	spacep = inp-&gt;spacep;
! 	smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
! 	if (lastNamep &amp;&amp; strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
! 		/* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
          fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
! 		smb_SetupIoctlFid(fidp, spacep);
! 		smb_SetSMBParm(outp, 0, fidp-&gt;fid);
          smb_SetSMBParm(outp, 1, 0);	/* attrs */
          smb_SetSMBParm(outp, 2, 0);	/* next 2 are DOS time */
          smb_SetSMBParm(outp, 3, 0);
          smb_SetSMBParm(outp, 4, 0);	/* next 2 are length */
          smb_SetSMBParm(outp, 5, 0x7fff);
! 		/* pass the open mode back */
          smb_SetSMBParm(outp, 6, (share &amp; 0xf));
          smb_SetSMBDataLength(outp, 0);
          smb_ReleaseFID(fidp);
          return 0;
      }
  
! 	userp = smb_GetUser(vcp, inp);
  
! 	caseFold = CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
--- 4115,4150 ----
      }
  #endif
  
!     share = smb_GetSMBParm(inp, 0);
      attribute = smb_GetSMBParm(inp, 1);
  
!     spacep = inp-&gt;spacep;
!     smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
!     if (lastNamep &amp;&amp; strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
!         /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
          fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
!         smb_SetupIoctlFid(fidp, spacep);
!         smb_SetSMBParm(outp, 0, fidp-&gt;fid);
          smb_SetSMBParm(outp, 1, 0);	/* attrs */
          smb_SetSMBParm(outp, 2, 0);	/* next 2 are DOS time */
          smb_SetSMBParm(outp, 3, 0);
          smb_SetSMBParm(outp, 4, 0);	/* next 2 are length */
          smb_SetSMBParm(outp, 5, 0x7fff);
!         /* pass the open mode back */
          smb_SetSMBParm(outp, 6, (share &amp; 0xf));
          smb_SetSMBDataLength(outp, 0);
          smb_ReleaseFID(fidp);
          return 0;
      }
  
!     userp = smb_GetUser(vcp, inp);
  
!     caseFold = CM_FLAG_CASEFOLD;
  
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
***************
*** 4124,4145 ****
          
      if (code) {
          cm_ReleaseUser(userp);
! 		return code;
! 	}
!         
      code = cm_CheckOpen(scp, share &amp; 0x7, 0, userp, &amp;req);
! 	if (code) {
! 		cm_ReleaseSCache(scp);
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
! 
! 	/* don't need callback to check file type, since file types never
! 	 * change, and namei and cm_Lookup all stat the object at least once on
! 	 * a successful return.
       */
      if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
! 		cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          return CM_ERROR_ISDIR;
      }
--- 4153,4174 ----
          
      if (code) {
          cm_ReleaseUser(userp);
!         return code;
!     }
! 
      code = cm_CheckOpen(scp, share &amp; 0x7, 0, userp, &amp;req);
!     if (code) {
!         cm_ReleaseSCache(scp);
!         cm_ReleaseUser(userp);
!         return code;
!     }
! 
!     /* don't need callback to check file type, since file types never
!      * change, and namei and cm_Lookup all stat the object at least once on
!      * a successful return.
       */
      if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!         cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          return CM_ERROR_ISDIR;
      }
***************
*** 4147,4179 ****
      fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
      osi_assert(fidp);
  
! 	/* save a pointer to the vnode */
      fidp-&gt;scp = scp;
  
      if ((share &amp; 0xf) == 0)
          fidp-&gt;flags |= SMB_FID_OPENREAD;
! 	else if ((share &amp; 0xf) == 1)
          fidp-&gt;flags |= SMB_FID_OPENWRITE;
! 	else 
          fidp-&gt;flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
  
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	smb_SetSMBParm(outp, 0, fidp-&gt;fid);
      smb_SetSMBParm(outp, 1, smb_Attributes(scp));
! 	smb_DosUTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
      smb_SetSMBParm(outp, 2, dosTime &amp; 0xffff);
      smb_SetSMBParm(outp, 3, (dosTime &gt;&gt; 16) &amp; 0xffff);
      smb_SetSMBParm(outp, 4, scp-&gt;length.LowPart &amp; 0xffff);
      smb_SetSMBParm(outp, 5, (scp-&gt;length.LowPart &gt;&gt; 16) &amp; 0xffff);
! 	/* pass the open mode back; XXXX add access checks */
      smb_SetSMBParm(outp, 6, (share &amp; 0xf));
      smb_SetSMBDataLength(outp, 0);
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
          
! 	/* notify open */
      cm_Open(scp, 0, userp);
  
! 	/* send and free packet */
      smb_ReleaseFID(fidp);
      cm_ReleaseUser(userp);
      /* don't release scp, since we've squirreled away the pointer in the fid struct */
--- 4176,4208 ----
      fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
      osi_assert(fidp);
  
!     /* save a pointer to the vnode */
      fidp-&gt;scp = scp;
  
      if ((share &amp; 0xf) == 0)
          fidp-&gt;flags |= SMB_FID_OPENREAD;
!     else if ((share &amp; 0xf) == 1)
          fidp-&gt;flags |= SMB_FID_OPENWRITE;
!     else 
          fidp-&gt;flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
  
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     smb_SetSMBParm(outp, 0, fidp-&gt;fid);
      smb_SetSMBParm(outp, 1, smb_Attributes(scp));
!     smb_DosUTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
      smb_SetSMBParm(outp, 2, dosTime &amp; 0xffff);
      smb_SetSMBParm(outp, 3, (dosTime &gt;&gt; 16) &amp; 0xffff);
      smb_SetSMBParm(outp, 4, scp-&gt;length.LowPart &amp; 0xffff);
      smb_SetSMBParm(outp, 5, (scp-&gt;length.LowPart &gt;&gt; 16) &amp; 0xffff);
!     /* pass the open mode back; XXXX add access checks */
      smb_SetSMBParm(outp, 6, (share &amp; 0xf));
      smb_SetSMBDataLength(outp, 0);
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
          
!     /* notify open */
      cm_Open(scp, 0, userp);
  
!     /* send and free packet */
      smb_ReleaseFID(fidp);
      cm_ReleaseUser(userp);
      /* don't release scp, since we've squirreled away the pointer in the fid struct */
***************
*** 4181,4302 ****
  }
  
  typedef struct smb_unlinkRock {
! 	cm_scache_t *dscp;
! 	cm_user_t *userp;
! 	cm_req_t *reqp;
! 	smb_vc_t *vcp;
! 	char *maskp;		/* pointer to the star pattern */
! 	int flags;
! 	int any;
  } smb_unlinkRock_t;
  
  int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
  {
! 	long code = 0;
! 	smb_unlinkRock_t *rockp;
! 	int caseFold;
! 	int match;
! 	char shortName[13];
! 	char *matchName;
          
! 	rockp = vrockp;
  
      caseFold = ((rockp-&gt;flags &amp; SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
      if (!(rockp-&gt;vcp-&gt;flags &amp; SMB_VCFLAG_USEV3))
          caseFold |= CM_FLAG_8DOT3;
  
! 	matchName = dep-&gt;name;
! 	match = smb_V3MatchMask(matchName, rockp-&gt;maskp, caseFold);
! 	if (!match
! 	    &amp;&amp; (rockp-&gt;flags &amp; SMB_MASKFLAG_TILDE)
! 	    &amp;&amp; !cm_Is8Dot3(dep-&gt;name)) {
! 		cm_Gen8Dot3Name(dep, shortName, NULL);
! 		matchName = shortName;
          /* 8.3 matches are always case insensitive */
          match = smb_V3MatchMask(matchName, rockp-&gt;maskp, caseFold | CM_FLAG_CASEFOLD);
! 	}
! 	if (match) {
! 		osi_Log1(smb_logp, "Unlinking %s",
! 				 osi_LogSaveString(smb_logp, matchName));
! 		code = cm_Unlink(dscp, dep-&gt;name, rockp-&gt;userp, rockp-&gt;reqp);
! 		if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 			smb_NotifyChange(FILE_ACTION_REMOVED,
! 							 FILE_NOTIFY_CHANGE_FILE_NAME,
! 							 dscp, dep-&gt;name, NULL, TRUE);
! 		if (code == 0) {
! 			rockp-&gt;any = 1;
              /* If we made a case sensitive exact match, we might as well quit now. */
!             if(!(rockp-&gt;flags &amp; SMB_MASKFLAG_CASEFOLD) &amp;&amp; !strcmp(matchName, rockp-&gt;maskp))
                  code = CM_ERROR_STOPNOW;
          }
! 	}
! 	else code = 0;
  
! 	return code;
  }
  
  long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	int attribute;
! 	long code = 0;
! 	char *pathp;
! 	char *tp;
! 	cm_space_t *spacep;
! 	cm_scache_t *dscp;
! 	char *lastNamep;
! 	smb_unlinkRock_t rock;
! 	cm_user_t *userp;
! 	osi_hyper_t thyper;
! 	int caseFold;
! 	char *tidPathp;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
! 
! 	attribute = smb_GetSMBParm(inp, 0);
!         
! 	tp = smb_GetSMBData(inp, NULL);
! 	pathp = smb_ParseASCIIBlock(tp, &amp;tp);
! 
! 	osi_Log1(smb_logp, "SMB receive unlink %s",
! 			 osi_LogSaveString(smb_logp, pathp));
  
! 	spacep = inp-&gt;spacep;
! 	smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
! 	userp = smb_GetUser(vcp, inp);
  
! 	caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
! 	code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold, userp, tidPathp,
! 					&amp;req, &amp;dscp);
  
! 	if (code) {
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
!         
! 	/* otherwise, scp points to the parent directory. */
! 	if (!lastNamep) 
! 		lastNamep = pathp;
! 	else 
! 		lastNamep++;
! 
! 	rock.any = 0;
! 	rock.maskp = smb_FindMask(pathp);
! 	rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
!         
! 	thyper.LowPart = 0;
! 	thyper.HighPart = 0;
! 	rock.userp = userp;
! 	rock.reqp = &amp;req;
! 	rock.dscp = dscp;
! 	rock.vcp = vcp;
  
      /* Now, if we aren't dealing with a wildcard match, we first try an exact 
       * match.  If that fails, we do a case insensitve match. 
--- 4210,4332 ----
  }
  
  typedef struct smb_unlinkRock {
!     cm_scache_t *dscp;
!     cm_user_t *userp;
!     cm_req_t *reqp;
!     smb_vc_t *vcp;
!     char *maskp;		/* pointer to the star pattern */
!     int flags;
!     int any;
  } smb_unlinkRock_t;
  
  int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
  {
!     long code = 0;
!     smb_unlinkRock_t *rockp;
!     int caseFold;
!     int match;
!     char shortName[13];
!     char *matchName;
          
!     rockp = vrockp;
  
      caseFold = ((rockp-&gt;flags &amp; SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
      if (!(rockp-&gt;vcp-&gt;flags &amp; SMB_VCFLAG_USEV3))
          caseFold |= CM_FLAG_8DOT3;
  
!     matchName = dep-&gt;name;
!     match = smb_V3MatchMask(matchName, rockp-&gt;maskp, caseFold);
!     if (!match &amp;&amp;
!          (rockp-&gt;flags &amp; SMB_MASKFLAG_TILDE) &amp;&amp;
!          !cm_Is8Dot3(dep-&gt;name)) {
!         cm_Gen8Dot3Name(dep, shortName, NULL);
!         matchName = shortName;
          /* 8.3 matches are always case insensitive */
          match = smb_V3MatchMask(matchName, rockp-&gt;maskp, caseFold | CM_FLAG_CASEFOLD);
!     }
!     if (match) {
!         osi_Log1(smb_logp, "Unlinking %s",
!                  osi_LogSaveString(smb_logp, matchName));
!         code = cm_Unlink(dscp, dep-&gt;name, rockp-&gt;userp, rockp-&gt;reqp);
!         if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!             smb_NotifyChange(FILE_ACTION_REMOVED,
!                              FILE_NOTIFY_CHANGE_FILE_NAME,
!                              dscp, dep-&gt;name, NULL, TRUE);
!         if (code == 0) {
!             rockp-&gt;any = 1;
! 
              /* If we made a case sensitive exact match, we might as well quit now. */
!             if (!(rockp-&gt;flags &amp; SMB_MASKFLAG_CASEFOLD) &amp;&amp; !strcmp(matchName, rockp-&gt;maskp))
                  code = CM_ERROR_STOPNOW;
          }
!     }
!     else code = 0;
  
!     return code;
  }
  
  long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     int attribute;
!     long code = 0;
!     char *pathp;
!     char *tp;
!     cm_space_t *spacep;
!     cm_scache_t *dscp;
!     char *lastNamep;
!     smb_unlinkRock_t rock;
!     cm_user_t *userp;
!     osi_hyper_t thyper;
!     int caseFold;
!     char *tidPathp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     attribute = smb_GetSMBParm(inp, 0);
!         
!     tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &amp;tp);
  
!     osi_Log1(smb_logp, "SMB receive unlink %s",
!              osi_LogSaveString(smb_logp, pathp));
  
!     spacep = inp-&gt;spacep;
!     smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
! 
!     userp = smb_GetUser(vcp, inp);
! 
!     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
! 
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold, userp, tidPathp,
!                     &amp;req, &amp;dscp);
! 
!     if (code) {
!         cm_ReleaseUser(userp);
!         return code;
!     }
!         
!     /* otherwise, scp points to the parent directory. */
!     if (!lastNamep) 
!         lastNamep = pathp;
!     else 
!         lastNamep++;
  
!     rock.any = 0;
!     rock.maskp = smb_FindMask(pathp);
!     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
! 
!     thyper.LowPart = 0;
!     thyper.HighPart = 0;
!     rock.userp = userp;
!     rock.reqp = &amp;req;
!     rock.dscp = dscp;
!     rock.vcp = vcp;
  
      /* Now, if we aren't dealing with a wildcard match, we first try an exact 
       * match.  If that fails, we do a case insensitve match. 
***************
*** 4304,4310 ****
      if (!(rock.flags &amp; SMB_MASKFLAG_TILDE) &amp;&amp;
          !smb_IsStarMask(rock.maskp)) {
          code = cm_ApplyDir(dscp, smb_UnlinkProc, &amp;rock, &amp;thyper, userp, &amp;req, NULL);
!         if(!rock.any) {
              thyper.LowPart = 0;
              thyper.HighPart = 0;
              rock.flags |= SMB_MASKFLAG_CASEFOLD;
--- 4334,4340 ----
      if (!(rock.flags &amp; SMB_MASKFLAG_TILDE) &amp;&amp;
          !smb_IsStarMask(rock.maskp)) {
          code = cm_ApplyDir(dscp, smb_UnlinkProc, &amp;rock, &amp;thyper, userp, &amp;req, NULL);
!         if (!rock.any) {
              thyper.LowPart = 0;
              thyper.HighPart = 0;
              rock.flags |= SMB_MASKFLAG_CASEFOLD;
***************
*** 4317,4484 ****
      if (code == CM_ERROR_STOPNOW) 
          code = 0;
  
! 	cm_ReleaseUser(userp);
          
! 	cm_ReleaseSCache(dscp);
  
! 	if (code == 0 &amp;&amp; !rock.any)
! 		code = CM_ERROR_NOSUCHFILE;
! 	return code;
! }
  
  typedef struct smb_renameRock {
! 	cm_scache_t *odscp;	/* old dir */
! 	cm_scache_t *ndscp;	/* new dir */
! 	cm_user_t *userp;	/* user */
! 	cm_req_t *reqp;		/* request struct */
! 	smb_vc_t *vcp;		/* virtual circuit */
! 	char *maskp;		/* pointer to star pattern of old file name */
! 	int flags;		    /* tilde, casefold, etc */
! 	char *newNamep;		/* ptr to the new file's name */
  } smb_renameRock_t;
  
  int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
  {
! 	long code = 0;
! 	smb_renameRock_t *rockp;
! 	int caseFold;
! 	int match;
! 	char shortName[13];
!         
! 	rockp = (smb_renameRock_t *) vrockp;
  
      caseFold = ((rockp-&gt;flags &amp; SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
      if (!(rockp-&gt;vcp-&gt;flags &amp; SMB_VCFLAG_USEV3))
          caseFold |= CM_FLAG_8DOT3;
  
! 	match = smb_V3MatchMask(dep-&gt;name, rockp-&gt;maskp, caseFold);
! 	if (!match
! 	    &amp;&amp; (rockp-&gt;flags &amp; SMB_MASKFLAG_TILDE)
! 	    &amp;&amp; !cm_Is8Dot3(dep-&gt;name)) {
! 		cm_Gen8Dot3Name(dep, shortName, NULL);
! 		match = smb_V3MatchMask(shortName, rockp-&gt;maskp, caseFold);
! 	}
! 	if (match) {
! 		code = cm_Rename(rockp-&gt;odscp, dep-&gt;name,
! 						 rockp-&gt;ndscp, rockp-&gt;newNamep, rockp-&gt;userp,
! 						 rockp-&gt;reqp);	
! 		/* if the call worked, stop doing the search now, since we
! 		 * really only want to rename one file.
! 		 */
! 		if (code == 0) 
! 			code = CM_ERROR_STOPNOW;
! 	}
! 	else code = 0;
! 
! 	return code;
! }
! 
! long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
! 	long code = 0;
! 	char *oldPathp;
! 	char *newPathp;
! 	char *tp;
! 	cm_space_t *spacep = NULL;
! 	smb_renameRock_t rock;
! 	cm_scache_t *oldDscp = NULL;
! 	cm_scache_t *newDscp = NULL;
! 	cm_scache_t *tmpscp= NULL;
! 	cm_scache_t *tmpscp2 = NULL;
! 	char *oldLastNamep;
! 	char *newLastNamep;
! 	osi_hyper_t thyper;
! 	cm_user_t *userp;
! 	int caseFold;
! 	char *tidPathp;
! 	DWORD filter;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
!         
! 	tp = smb_GetSMBData(inp, NULL);
! 	oldPathp = smb_ParseASCIIBlock(tp, &amp;tp);
! 	newPathp = smb_ParseASCIIBlock(tp, &amp;tp);
! 
! 	osi_Log2(smb_logp, "smb rename [%s] to [%s]",
! 			 osi_LogSaveString(smb_logp, oldPathp),
! 			 osi_LogSaveString(smb_logp, newPathp));
! 
! 	spacep = inp-&gt;spacep;
! 	smb_StripLastComponent(spacep-&gt;data, &amp;oldLastNamep, oldPathp);
! 
! 	userp = smb_GetUser(vcp, inp);
! 
!  /*
!   * Changed to use CASEFOLD always.  This enables us to rename Foo/baz when
!   * what actually exists is foo/baz.  I don't know why the code used to be
!   * the way it was.  1/29/96
!   *
!   *     	caseFold = ((vcp-&gt;flags &amp; SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
!   *
!   * Changed to use CM_FLAG_FOLLOW.  7/24/96
!   *
!   *	caseFold = CM_FLAG_CASEFOLD;
!   */
! 	caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
- 	code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold,
- 					userp, tidPathp, &amp;req, &amp;oldDscp);
  
! 	if (code) {
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
!         
! 	smb_StripLastComponent(spacep-&gt;data, &amp;newLastNamep, newPathp);
! 	code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold,
! 					userp, tidPathp, &amp;req, &amp;newDscp);
! 
! 	if (code) {
! 		cm_ReleaseSCache(oldDscp);
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
!         
! 	/* otherwise, oldDscp and newDscp point to the corresponding directories.
! 	 * next, get the component names, and lower case them.
! 	 */
! 
! 	/* handle the old name first */
! 	if (!oldLastNamep) 
! 		oldLastNamep = oldPathp;
! 	else 
! 		oldLastNamep++;
! 
! 	/* and handle the new name, too */
! 	if (!newLastNamep) 
! 		newLastNamep = newPathp;
! 	else 
! 		newLastNamep++;
  
      /* TODO: The old name could be a wildcard.  The new name must not be */
! 	
! 	/* do the vnode call */
! 	rock.odscp = oldDscp;
! 	rock.ndscp = newDscp;
! 	rock.userp = userp;
! 	rock.reqp = &amp;req;
! 	rock.vcp = vcp;
! 	rock.maskp = oldLastNamep;
! 	rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
! 	rock.newNamep = newLastNamep;
  
      /* Check if the file already exists; if so return error */
! 	code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&amp;req,&amp;tmpscp);
! 	if ((code != CM_ERROR_NOSUCHFILE) &amp;&amp; (code != CM_ERROR_NOSUCHPATH) &amp;&amp; (code != CM_ERROR_NOSUCHVOLUME) ) {
          osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
                   osi_LogSaveString(afsd_logp, newLastNamep));
!  
          /* Check if the old and the new names differ only in case. If so return
           * success, else return CM_ERROR_EXISTS 
           */
--- 4347,4503 ----
      if (code == CM_ERROR_STOPNOW) 
          code = 0;
  
!     cm_ReleaseUser(userp);
          
!     cm_ReleaseSCache(dscp);
  
!     if (code == 0 &amp;&amp; !rock.any)
!         code = CM_ERROR_NOSUCHFILE;
!     return code;
! }       
  
  typedef struct smb_renameRock {
!     cm_scache_t *odscp;	/* old dir */
!     cm_scache_t *ndscp;	/* new dir */
!     cm_user_t *userp;	/* user */
!     cm_req_t *reqp;		/* request struct */
!     smb_vc_t *vcp;		/* virtual circuit */
!     char *maskp;		/* pointer to star pattern of old file name */
!     int flags;		    /* tilde, casefold, etc */
!     char *newNamep;		/* ptr to the new file's name */
  } smb_renameRock_t;
  
  int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
  {
!     long code = 0;
!     smb_renameRock_t *rockp;
!     int caseFold;
!     int match;
!     char shortName[13];
! 
!     rockp = (smb_renameRock_t *) vrockp;
  
      caseFold = ((rockp-&gt;flags &amp; SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
      if (!(rockp-&gt;vcp-&gt;flags &amp; SMB_VCFLAG_USEV3))
          caseFold |= CM_FLAG_8DOT3;
  
!     match = smb_V3MatchMask(dep-&gt;name, rockp-&gt;maskp, caseFold);
!     if (!match &amp;&amp;
!         (rockp-&gt;flags &amp; SMB_MASKFLAG_TILDE) &amp;&amp;
!          !cm_Is8Dot3(dep-&gt;name)) {
!         cm_Gen8Dot3Name(dep, shortName, NULL);
!         match = smb_V3MatchMask(shortName, rockp-&gt;maskp, caseFold);
!     }
!     if (match) {
!         code = cm_Rename(rockp-&gt;odscp, dep-&gt;name,
!                          rockp-&gt;ndscp, rockp-&gt;newNamep, rockp-&gt;userp,
!                          rockp-&gt;reqp);	
!         /* if the call worked, stop doing the search now, since we
!          * really only want to rename one file.
!          */
!         if (code == 0) 
!             code = CM_ERROR_STOPNOW;
!     }       
!     else code = 0;
! 
!     return code;
! }
! 
  
! long 
! smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
! {
!     long code = 0;
!     cm_space_t *spacep = NULL;
!     smb_renameRock_t rock;
!     cm_scache_t *oldDscp = NULL;
!     cm_scache_t *newDscp = NULL;
!     cm_scache_t *tmpscp= NULL;
!     cm_scache_t *tmpscp2 = NULL;
!     char *oldLastNamep;
!     char *newLastNamep;
!     osi_hyper_t thyper;
!     cm_user_t *userp;
!     int caseFold;
!     char *tidPathp;
!     DWORD filter;
!     cm_req_t req;
! 
!     userp = smb_GetUser(vcp, inp);
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
  
!     cm_InitReq(&amp;req);
!     spacep = inp-&gt;spacep;
!     smb_StripLastComponent(spacep-&gt;data, &amp;oldLastNamep, oldPathp);
! 
!     /*
!      * Changed to use CASEFOLD always.  This enables us to rename Foo/baz when
!      * what actually exists is foo/baz.  I don't know why the code used to be
!      * the way it was.  1/29/96
!      *
!      *     	caseFold = ((vcp-&gt;flags &amp; SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
!      *
!      * Changed to use CM_FLAG_FOLLOW.  7/24/96
!      *
!      *	caseFold = CM_FLAG_CASEFOLD;
!      */
!     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold,
!                     userp, tidPathp, &amp;req, &amp;oldDscp);
! 
!     if (code) {
!         cm_ReleaseUser(userp);
!         return code;
!     }
!         
!     smb_StripLastComponent(spacep-&gt;data, &amp;newLastNamep, newPathp);
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold,
!                     userp, tidPathp, &amp;req, &amp;newDscp);
! 
!     if (code) {
!         cm_ReleaseSCache(oldDscp);
!         cm_ReleaseUser(userp);
!         return code;
!     }
!         
!     /* otherwise, oldDscp and newDscp point to the corresponding directories.
!      * next, get the component names, and lower case them.
!      */
! 
!     /* handle the old name first */
!     if (!oldLastNamep) 
!         oldLastNamep = oldPathp;
!     else 
!         oldLastNamep++;
! 
!     /* and handle the new name, too */
!     if (!newLastNamep) 
!         newLastNamep = newPathp;
!     else 
!         newLastNamep++;
  
      /* TODO: The old name could be a wildcard.  The new name must not be */
! 
!     /* do the vnode call */
!     rock.odscp = oldDscp;
!     rock.ndscp = newDscp;
!     rock.userp = userp;
!     rock.reqp = &amp;req;
!     rock.vcp = vcp;
!     rock.maskp = oldLastNamep;
!     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
!     rock.newNamep = newLastNamep;
  
      /* Check if the file already exists; if so return error */
!     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&amp;req,&amp;tmpscp);
!     if ((code != CM_ERROR_NOSUCHFILE) &amp;&amp; (code != CM_ERROR_NOSUCHPATH) &amp;&amp; (code != CM_ERROR_NOSUCHVOLUME) ) {
          osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
                   osi_LogSaveString(afsd_logp, newLastNamep));
! 
          /* Check if the old and the new names differ only in case. If so return
           * success, else return CM_ERROR_EXISTS 
           */
***************
*** 4502,4658 ****
              code = CM_ERROR_EXISTS;
          }
  
! 		if(tmpscp != NULL)
              cm_ReleaseSCache(tmpscp);
          cm_ReleaseSCache(newDscp);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
! 	    return code; 
! 	}
  
      /* Now search the directory for the pattern, and do the appropriate rename when found */
! 	thyper.LowPart = 0;		/* search dir from here */
      thyper.HighPart = 0;
  
      code = cm_ApplyDir(oldDscp, smb_RenameProc, &amp;rock, &amp;thyper, userp, &amp;req, NULL);
  
      if (code == CM_ERROR_STOPNOW)
! 		code = 0;
! 	else if (code == 0)
! 		code = CM_ERROR_NOSUCHFILE;
! 
! 	/* Handle Change Notification */
! 	/*
! 	 * Being lazy, not distinguishing between files and dirs in this
! 	 * filter, since we'd have to do a lookup.
! 	 */
! 	filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
! 	if (oldDscp == newDscp) {
! 		if (oldDscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)
! 			smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
! 							 filter, oldDscp, oldLastNamep,
! 							 newLastNamep, TRUE);
! 	} else {
! 		if (oldDscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)
! 			smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
! 							 filter, oldDscp, oldLastNamep,
! 							 NULL, TRUE);
! 		if (newDscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)
! 			smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
! 							 filter, newDscp, newLastNamep,
! 							 NULL, TRUE);
! 	}
  
!     if(tmpscp != NULL) 
          cm_ReleaseSCache(tmpscp);
      cm_ReleaseUser(userp);
! 	cm_ReleaseSCache(oldDscp);
! 	cm_ReleaseSCache(newDscp);
! 	return code;
  }
  
  typedef struct smb_rmdirRock {
! 	cm_scache_t *dscp;
! 	cm_user_t *userp;
! 	cm_req_t *reqp;
! 	char *maskp;		/* pointer to the star pattern */
! 	int flags;
! 	int any;
  } smb_rmdirRock_t;
  
  int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
! {
! 	long code = 0;
! 	smb_rmdirRock_t *rockp;
! 	int match;
! 	char shortName[13];
! 	char *matchName;
          
! 	rockp = (smb_rmdirRock_t *) vrockp;
  
! 	matchName = dep-&gt;name;
      if (rockp-&gt;flags &amp; SMB_MASKFLAG_CASEFOLD)
          match = (cm_stricmp(matchName, rockp-&gt;maskp) == 0);
      else
          match = (strcmp(matchName, rockp-&gt;maskp) == 0);
! 	if (!match
! 	    &amp;&amp; (rockp-&gt;flags &amp; SMB_MASKFLAG_TILDE)
! 	    &amp;&amp; !cm_Is8Dot3(dep-&gt;name)) {
! 		cm_Gen8Dot3Name(dep, shortName, NULL);
! 		matchName = shortName;
! 		match = (cm_stricmp(matchName, rockp-&gt;maskp) == 0);
! 	}
! 	if (match) {
! 		osi_Log1(smb_logp, "Removing directory %s",
! 				 osi_LogSaveString(smb_logp, matchName));
! 		code = cm_RemoveDir(dscp, dep-&gt;name, rockp-&gt;userp, rockp-&gt;reqp);
! 		if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 			smb_NotifyChange(FILE_ACTION_REMOVED,
! 							 FILE_NOTIFY_CHANGE_DIR_NAME,
! 							 dscp, dep-&gt;name, NULL, TRUE);
! 		if (code == 0)
! 			rockp-&gt;any = 1;
! 	}
! 	else code = 0;
  
! 	return code;
  }
  
  long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	long code = 0;
! 	char *pathp;
! 	char *tp;
! 	cm_space_t *spacep;
! 	cm_scache_t *dscp;
! 	char *lastNamep;
! 	smb_rmdirRock_t rock;
! 	cm_user_t *userp;
! 	osi_hyper_t thyper;
! 	int caseFold;
! 	char *tidPathp;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
! 
! 	tp = smb_GetSMBData(inp, NULL);
! 	pathp = smb_ParseASCIIBlock(tp, &amp;tp);
  
! 	spacep = inp-&gt;spacep;
! 	smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
! 	userp = smb_GetUser(vcp, inp);
  
! 	caseFold = CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
! 	code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold | CM_FLAG_FOLLOW,
! 					userp, tidPathp, &amp;req, &amp;dscp);
  
! 	if (code) {
! 		cm_ReleaseUser(userp);
! 		return code;
! 	}
!         
! 	/* otherwise, scp points to the parent directory. */
! 	if (!lastNamep) 
! 		lastNamep = pathp;
! 	else 
! 		lastNamep++;
  	
! 	rock.any = 0;
! 	rock.maskp = lastNamep;
! 	rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
! 
! 	thyper.LowPart = 0;
! 	thyper.HighPart = 0;
! 	rock.userp = userp;
! 	rock.reqp = &amp;req;
! 	rock.dscp = dscp;
      /* First do a case sensitive match, and if that fails, do a case insensitive match */
      code = cm_ApplyDir(dscp, smb_RmdirProc, &amp;rock, &amp;thyper, userp, &amp;req, NULL);
      if (code == 0 &amp;&amp; !rock.any) {
--- 4521,4826 ----
              code = CM_ERROR_EXISTS;
          }
  
!         if (tmpscp != NULL)
              cm_ReleaseSCache(tmpscp);
          cm_ReleaseSCache(newDscp);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
!         return code; 
!     }
  
      /* Now search the directory for the pattern, and do the appropriate rename when found */
!     thyper.LowPart = 0;		/* search dir from here */
      thyper.HighPart = 0;
  
      code = cm_ApplyDir(oldDscp, smb_RenameProc, &amp;rock, &amp;thyper, userp, &amp;req, NULL);
  
      if (code == CM_ERROR_STOPNOW)
!         code = 0;
!     else if (code == 0)
!         code = CM_ERROR_NOSUCHFILE;
! 
!     /* Handle Change Notification */
!     /*
!     * Being lazy, not distinguishing between files and dirs in this
!     * filter, since we'd have to do a lookup.
!     */
!     filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
!     if (oldDscp == newDscp) {
!         if (oldDscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)
!             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
!                              filter, oldDscp, oldLastNamep,
!                              newLastNamep, TRUE);
!     } else {
!         if (oldDscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)
!             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
!                              filter, oldDscp, oldLastNamep,
!                              NULL, TRUE);
!         if (newDscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)
!             smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
!                              filter, newDscp, newLastNamep,
!                              NULL, TRUE);
!     }
! 
!     if (tmpscp != NULL) 
!         cm_ReleaseSCache(tmpscp);
!     cm_ReleaseUser(userp);
!     cm_ReleaseSCache(oldDscp);
!     cm_ReleaseSCache(newDscp);
!     return code;
! }       
! 
! long 
! smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp) 
! {
!     long code = 0;
!     cm_space_t *spacep = NULL;
!     cm_scache_t *oldDscp = NULL;
!     cm_scache_t *newDscp = NULL;
!     cm_scache_t *tmpscp= NULL;
!     cm_scache_t *tmpscp2 = NULL;
!     cm_scache_t *sscp = NULL;
!     char *oldLastNamep;
!     char *newLastNamep;
!     cm_user_t *userp;
!     int caseFold;
!     char *tidPathp;
!     DWORD filter;
!     cm_req_t req;
! 
!     userp = smb_GetUser(vcp, inp);
! 
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
!         cm_ReleaseUser(userp);
!         return CM_ERROR_NOSUCHPATH;
!     }
! 
!     cm_InitReq(&amp;req);
! 
!     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
! 
!     spacep = inp-&gt;spacep;
!     smb_StripLastComponent(spacep-&gt;data, &amp;oldLastNamep, oldPathp);
!     
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold,
!                     userp, tidPathp, &amp;req, &amp;oldDscp);
!     if (code) {
!         cm_ReleaseUser(userp);
!         return code;
!     }
!         
!     smb_StripLastComponent(spacep-&gt;data, &amp;newLastNamep, newPathp);
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold,
!                     userp, tidPathp, &amp;req, &amp;newDscp);
!     if (code) {
!         cm_ReleaseSCache(oldDscp);
!         cm_ReleaseUser(userp);
!         return code;
!     }
! 
!     /* Now, although we did two lookups for the two directories (because the same
!      * directory can be referenced through different paths), we only allow hard links
!      * within the same directory. */
!     if (oldDscp != newDscp) {
!         cm_ReleaseSCache(oldDscp);
!         cm_ReleaseSCache(newDscp);
!         cm_ReleaseUser(userp);
!         return CM_ERROR_CROSSDEVLINK;
!     }
! 
!     /* handle the old name first */
!     if (!oldLastNamep) 
!         oldLastNamep = oldPathp;
!     else 
!         oldLastNamep++;
  
!     /* and handle the new name, too */
!     if (!newLastNamep) 
!         newLastNamep = newPathp;
!     else 
!         newLastNamep++;
! 
!     /* now lookup the old name */
!     osi_Log1(smb_logp,"  looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
!     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &amp;req, &amp;sscp);
!     if (code) {
!         cm_ReleaseSCache(oldDscp);
!         cm_ReleaseSCache(newDscp);
!         cm_ReleaseUser(userp);
!         return code;
!     }
! 
!     /* Check if the file already exists; if so return error */
!     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&amp;req,&amp;tmpscp);
!     if ((code != CM_ERROR_NOSUCHFILE) &amp;&amp; (code != CM_ERROR_NOSUCHPATH) &amp;&amp; (code != CM_ERROR_NOSUCHVOLUME) ) {
!         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
!                  osi_LogSaveString(afsd_logp, newLastNamep));
! 
!         /* if the existing link is to the same file, then we return success */
!         if (!code) {
!             if(sscp == tmpscp) {
!                 code = 0;
!             } else {
!                 osi_Log0(smb_logp, "Can't create hardlink.  Target already exists");
!                 code = CM_ERROR_EXISTS;
!             }
!         }
! 
!         if (tmpscp != NULL)
!             cm_ReleaseSCache(tmpscp);
!         cm_ReleaseSCache(sscp);
!         cm_ReleaseSCache(newDscp);
!         cm_ReleaseSCache(oldDscp);
!         cm_ReleaseUser(userp);
!         return code; 
!     }
! 
!     /* now create the hardlink */
!     osi_Log1(smb_logp,"  Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
!     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &amp;req);
!     osi_Log1(smb_logp,"  Link returns %d", code);
! 
!     /* Handle Change Notification */
!     if (code == 0) {
!         filter = (sscp-&gt;fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
!         if (newDscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)
!             smb_NotifyChange(FILE_ACTION_ADDED,
!                              filter, newDscp, newLastNamep,
!                              NULL, TRUE);
!     }
! 
!     if (tmpscp != NULL) 
          cm_ReleaseSCache(tmpscp);
      cm_ReleaseUser(userp);
!     cm_ReleaseSCache(sscp);
!     cm_ReleaseSCache(oldDscp);
!     cm_ReleaseSCache(newDscp);
!     return code;
! }
! 
! long 
! smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
!     char *oldPathp;
!     char *newPathp;
!     char *tp;
! 
!     tp = smb_GetSMBData(inp, NULL);
!     oldPathp = smb_ParseASCIIBlock(tp, &amp;tp);
!     newPathp = smb_ParseASCIIBlock(tp, &amp;tp);
! 
!     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
!               osi_LogSaveString(smb_logp, oldPathp),
!               osi_LogSaveString(smb_logp, newPathp));
! 
!     return smb_Rename(vcp,inp,oldPathp,newPathp,0);
  }
  
+ 
+ 
  typedef struct smb_rmdirRock {
!     cm_scache_t *dscp;
!     cm_user_t *userp;
!     cm_req_t *reqp;
!     char *maskp;		/* pointer to the star pattern */
!     int flags;
!     int any;
  } smb_rmdirRock_t;
  
  int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
! {       
!     long code = 0;
!     smb_rmdirRock_t *rockp;
!     int match;
!     char shortName[13];
!     char *matchName;
          
!     rockp = (smb_rmdirRock_t *) vrockp;
  
!     matchName = dep-&gt;name;
      if (rockp-&gt;flags &amp; SMB_MASKFLAG_CASEFOLD)
          match = (cm_stricmp(matchName, rockp-&gt;maskp) == 0);
      else
          match = (strcmp(matchName, rockp-&gt;maskp) == 0);
!     if (!match &amp;&amp;
!          (rockp-&gt;flags &amp; SMB_MASKFLAG_TILDE) &amp;&amp;
!          !cm_Is8Dot3(dep-&gt;name)) {
!         cm_Gen8Dot3Name(dep, shortName, NULL);
!         matchName = shortName;
!         match = (cm_stricmp(matchName, rockp-&gt;maskp) == 0);
!     }       
!     if (match) {
!         osi_Log1(smb_logp, "Removing directory %s",
!                  osi_LogSaveString(smb_logp, matchName));
!         code = cm_RemoveDir(dscp, dep-&gt;name, rockp-&gt;userp, rockp-&gt;reqp);
!         if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!             smb_NotifyChange(FILE_ACTION_REMOVED,
!                              FILE_NOTIFY_CHANGE_DIR_NAME,
!                              dscp, dep-&gt;name, NULL, TRUE);
!         if (code == 0)
!             rockp-&gt;any = 1;
!     }
!     else code = 0;
  
!     return code;
  }
  
  long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     long code = 0;
!     char *pathp;
!     char *tp;
!     cm_space_t *spacep;
!     cm_scache_t *dscp;
!     char *lastNamep;
!     smb_rmdirRock_t rock;
!     cm_user_t *userp;
!     osi_hyper_t thyper;
!     int caseFold;
!     char *tidPathp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &amp;tp);
  
!     spacep = inp-&gt;spacep;
!     smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
!     userp = smb_GetUser(vcp, inp);
! 
!     caseFold = CM_FLAG_CASEFOLD;
! 
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold | CM_FLAG_FOLLOW,
!                     userp, tidPathp, &amp;req, &amp;dscp);
  
!     if (code) {
!         cm_ReleaseUser(userp);
!         return code;
!     }
!         
!     /* otherwise, scp points to the parent directory. */
!     if (!lastNamep) 
!         lastNamep = pathp;
!     else 
!         lastNamep++;
  	
!     rock.any = 0;
!     rock.maskp = lastNamep;
!     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
! 
!     thyper.LowPart = 0;
!     thyper.HighPart = 0;
!     rock.userp = userp;
!     rock.reqp = &amp;req;
!     rock.dscp = dscp;
      /* First do a case sensitive match, and if that fails, do a case insensitive match */
      code = cm_ApplyDir(dscp, smb_RmdirProc, &amp;rock, &amp;thyper, userp, &amp;req, NULL);
      if (code == 0 &amp;&amp; !rock.any) {
***************
*** 4662,4691 ****
          code = cm_ApplyDir(dscp, smb_RmdirProc, &amp;rock, &amp;thyper, userp, &amp;req, NULL);
      }
  
! 	cm_ReleaseUser(userp);
          
! 	cm_ReleaseSCache(dscp);
  
! 	if (code == 0 &amp;&amp; !rock.any)
! 		code = CM_ERROR_NOSUCHFILE;        
! 	return code;
  }
  
  long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	unsigned short fid;
      smb_fid_t *fidp;
      cm_user_t *userp;
      long code = 0;
      cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
! 	fid = smb_GetSMBParm(inp, 0);
!         
! 	osi_Log1(smb_logp, "SMB flush fid %d", fid);
  
! 	fid = smb_ChainFID(fid, inp);
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
          if (fidp)
--- 4830,4859 ----
          code = cm_ApplyDir(dscp, smb_RmdirProc, &amp;rock, &amp;thyper, userp, &amp;req, NULL);
      }
  
!     cm_ReleaseUser(userp);
          
!     cm_ReleaseSCache(dscp);
  
!     if (code == 0 &amp;&amp; !rock.any)
!         code = CM_ERROR_NOSUCHFILE;        
!     return code;
  }
  
  long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     unsigned short fid;
      smb_fid_t *fidp;
      cm_user_t *userp;
      long code = 0;
      cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     fid = smb_GetSMBParm(inp, 0);
! 
!     osi_Log1(smb_logp, "SMB flush fid %d", fid);
  
!     fid = smb_ChainFID(fid, inp);
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
          if (fidp)
***************
*** 4698,4705 ****
      lock_ObtainMutex(&amp;fidp-&gt;mx);
      if (fidp-&gt;flags &amp; SMB_FID_OPENWRITE)
          code = cm_FSync(fidp-&gt;scp, userp, &amp;req);
! 	else 
! 		code = 0;
      lock_ReleaseMutex(&amp;fidp-&gt;mx);
          
      smb_ReleaseFID(fidp);
--- 4866,4873 ----
      lock_ObtainMutex(&amp;fidp-&gt;mx);
      if (fidp-&gt;flags &amp; SMB_FID_OPENWRITE)
          code = cm_FSync(fidp-&gt;scp, userp, &amp;req);
!     else 
!         code = 0;
      lock_ReleaseMutex(&amp;fidp-&gt;mx);
          
      smb_ReleaseFID(fidp);
***************
*** 4710,4846 ****
  }
  
  struct smb_FullNameRock {
! 	char *name;
! 	cm_scache_t *vnode;
! 	char *fullName;
  };
  
  int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
! 	osi_hyper_t *offp)
  {
! 	char shortName[13];
! 	struct smb_FullNameRock *vrockp;
  
! 	vrockp = (struct smb_FullNameRock *)rockp;
  
! 	if (!cm_Is8Dot3(dep-&gt;name)) {
! 		cm_Gen8Dot3Name(dep, shortName, NULL);
! 
! 		if (cm_stricmp(shortName, vrockp-&gt;name) == 0) {
! 			vrockp-&gt;fullName = strdup(dep-&gt;name);
! 			return CM_ERROR_STOPNOW;
! 		}
! 	}
! 	if (cm_stricmp(dep-&gt;name, vrockp-&gt;name) == 0
! 	    &amp;&amp; ntohl(dep-&gt;fid.vnode) == vrockp-&gt;vnode-&gt;fid.vnode
! 	    &amp;&amp; ntohl(dep-&gt;fid.unique) == vrockp-&gt;vnode-&gt;fid.unique) {
! 		vrockp-&gt;fullName = strdup(dep-&gt;name);
! 		return CM_ERROR_STOPNOW;
! 	}
! 	return 0;
  }
  
  void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
! 	char **newPathp, cm_user_t *userp, cm_req_t *reqp)
  {
! 	struct smb_FullNameRock rock;
! 	long code = 0;
  
! 	rock.name = pathp;
! 	rock.vnode = scp;
  
! 	code = cm_ApplyDir(dscp, smb_FullNameProc, &amp;rock, NULL, 
! 				userp, reqp, NULL); 
! 	if (code == CM_ERROR_STOPNOW)
! 		*newPathp = rock.fullName;
! 	else
! 		*newPathp = strdup(pathp);
  }
  
  long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	unsigned short fid;
      smb_fid_t *fidp;
      cm_user_t *userp;
! 	long dosTime;
      long code = 0;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
! 	fid = smb_GetSMBParm(inp, 0);
! 	dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) &lt;&lt; 16);
!         
! 	osi_Log1(smb_logp, "SMB close fid %d", fid);
  
! 	fid = smb_ChainFID(fid, inp);
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp) {
          return CM_ERROR_BADFD;
      }
          
! 	userp = smb_GetUser(vcp, inp);
  
      lock_ObtainMutex(&amp;fidp-&gt;mx);
  
! 	/* Don't jump the gun on an async raw write */
! 	while (fidp-&gt;raw_writers) {
! 		lock_ReleaseMutex(&amp;fidp-&gt;mx);
! 		thrd_WaitForSingleObject_Event(fidp-&gt;raw_write_event, RAWTIMEOUT);
! 		lock_ObtainMutex(&amp;fidp-&gt;mx);
! 	}
! 
! 	fidp-&gt;flags |= SMB_FID_DELETE;
!         
! 	/* watch for ioctl closes, and read-only opens */
!     if (fidp-&gt;scp != NULL
!         &amp;&amp; (fidp-&gt;flags &amp; (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
           == SMB_FID_OPENWRITE) {
! 		if (dosTime != 0 &amp;&amp; dosTime != -1) {
! 			fidp-&gt;scp-&gt;mask |= CM_SCACHEMASK_CLIENTMODTIME;
              /* This fixes defect 10958 */
              CompensateForSmbClientLastWriteTimeBugs(&amp;dosTime);
! 			smb_UnixTimeFromDosUTime(&amp;fidp-&gt;scp-&gt;clientModTime, dosTime);
! 		}
          code = cm_FSync(fidp-&gt;scp, userp, &amp;req);
! 	}
! 	else 
          code = 0;
  
! 	if (fidp-&gt;flags &amp; SMB_FID_DELONCLOSE) {
! 		cm_scache_t *dscp = fidp-&gt;NTopen_dscp;
! 		char *pathp = fidp-&gt;NTopen_pathp;
! 		char *fullPathp;
! 
! 		smb_FullName(dscp, fidp-&gt;scp, pathp, &amp;fullPathp, userp, &amp;req);
! 		if (fidp-&gt;scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY) {
! 			code = cm_RemoveDir(dscp, fullPathp, userp, &amp;req);
! 			if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 				smb_NotifyChange(FILE_ACTION_REMOVED,
                                   FILE_NOTIFY_CHANGE_DIR_NAME,
                                   dscp, fullPathp, NULL, TRUE);
! 		}
! 		else 
          {
! 			code = cm_Unlink(dscp, fullPathp, userp, &amp;req);
! 			if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 				smb_NotifyChange(FILE_ACTION_REMOVED,
                                   FILE_NOTIFY_CHANGE_FILE_NAME,
                                   dscp, fullPathp, NULL, TRUE);
! 		}
! 		free(fullPathp);
! 	}
      lock_ReleaseMutex(&amp;fidp-&gt;mx);
  
      if (fidp-&gt;flags &amp; SMB_FID_NTOPEN) {
! 		cm_ReleaseSCache(fidp-&gt;NTopen_dscp);
! 		free(fidp-&gt;NTopen_pathp);
! 	}
! 	if (fidp-&gt;NTopen_wholepathp)
! 		free(fidp-&gt;NTopen_wholepathp);
      
      smb_ReleaseFID(fidp);
! 	cm_ReleaseUser(userp);
      return code;
  }
  
--- 4878,5014 ----
  }
  
  struct smb_FullNameRock {
!     char *name;
!     cm_scache_t *vnode;
!     char *fullName;
  };
  
  int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
!                      osi_hyper_t *offp)
  {
!     char shortName[13];
!     struct smb_FullNameRock *vrockp;
! 
!     vrockp = (struct smb_FullNameRock *)rockp;
  
!     if (!cm_Is8Dot3(dep-&gt;name)) {
!         cm_Gen8Dot3Name(dep, shortName, NULL);
  
!         if (cm_stricmp(shortName, vrockp-&gt;name) == 0) {
!             vrockp-&gt;fullName = strdup(dep-&gt;name);
!             return CM_ERROR_STOPNOW;
!         }
!     }
!     if (cm_stricmp(dep-&gt;name, vrockp-&gt;name) == 0 &amp;&amp;
!         ntohl(dep-&gt;fid.vnode) == vrockp-&gt;vnode-&gt;fid.vnode &amp;&amp;
!         ntohl(dep-&gt;fid.unique) == vrockp-&gt;vnode-&gt;fid.unique) {
!         vrockp-&gt;fullName = strdup(dep-&gt;name);
!         return CM_ERROR_STOPNOW;
!     }
!     return 0;
  }
  
  void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
!                   char **newPathp, cm_user_t *userp, cm_req_t *reqp)
  {
!     struct smb_FullNameRock rock;
!     long code = 0;
  
!     rock.name = pathp;
!     rock.vnode = scp;
  
!     code = cm_ApplyDir(dscp, smb_FullNameProc, &amp;rock, NULL, 
!                        userp, reqp, NULL); 
!     if (code == CM_ERROR_STOPNOW)
!         *newPathp = rock.fullName;
!     else
!         *newPathp = strdup(pathp);
  }
  
  long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     unsigned short fid;
      smb_fid_t *fidp;
      cm_user_t *userp;
!     long dosTime;
      long code = 0;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     fid = smb_GetSMBParm(inp, 0);
!     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) &lt;&lt; 16);
  
!     osi_Log1(smb_logp, "SMB close fid %d", fid);
! 
!     fid = smb_ChainFID(fid, inp);
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp) {
          return CM_ERROR_BADFD;
      }
          
!     userp = smb_GetUser(vcp, inp);
  
      lock_ObtainMutex(&amp;fidp-&gt;mx);
  
!     /* Don't jump the gun on an async raw write */
!     while (fidp-&gt;raw_writers) {
!         lock_ReleaseMutex(&amp;fidp-&gt;mx);
!         thrd_WaitForSingleObject_Event(fidp-&gt;raw_write_event, RAWTIMEOUT);
!         lock_ObtainMutex(&amp;fidp-&gt;mx);
!     }
! 
!     fidp-&gt;flags |= SMB_FID_DELETE;
!         
!     /* watch for ioctl closes, and read-only opens */
!     if (fidp-&gt;scp != NULL &amp;&amp;
!         (fidp-&gt;flags &amp; (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
           == SMB_FID_OPENWRITE) {
!         if (dosTime != 0 &amp;&amp; dosTime != -1) {
!             fidp-&gt;scp-&gt;mask |= CM_SCACHEMASK_CLIENTMODTIME;
              /* This fixes defect 10958 */
              CompensateForSmbClientLastWriteTimeBugs(&amp;dosTime);
!             smb_UnixTimeFromDosUTime(&amp;fidp-&gt;scp-&gt;clientModTime, dosTime);
!         }
          code = cm_FSync(fidp-&gt;scp, userp, &amp;req);
!     }
!     else 
          code = 0;
  
!     if (fidp-&gt;flags &amp; SMB_FID_DELONCLOSE) {
!         cm_scache_t *dscp = fidp-&gt;NTopen_dscp;
!         char *pathp = fidp-&gt;NTopen_pathp;
!         char *fullPathp;
! 
!         smb_FullName(dscp, fidp-&gt;scp, pathp, &amp;fullPathp, userp, &amp;req);
!         if (fidp-&gt;scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY) {
!             code = cm_RemoveDir(dscp, fullPathp, userp, &amp;req);
!             if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!                 smb_NotifyChange(FILE_ACTION_REMOVED,
                                   FILE_NOTIFY_CHANGE_DIR_NAME,
                                   dscp, fullPathp, NULL, TRUE);
!         }
!         else 
          {
!             code = cm_Unlink(dscp, fullPathp, userp, &amp;req);
!             if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!                 smb_NotifyChange(FILE_ACTION_REMOVED,
                                   FILE_NOTIFY_CHANGE_FILE_NAME,
                                   dscp, fullPathp, NULL, TRUE);
!         }
!         free(fullPathp);
!     }
      lock_ReleaseMutex(&amp;fidp-&gt;mx);
  
      if (fidp-&gt;flags &amp; SMB_FID_NTOPEN) {
!         cm_ReleaseSCache(fidp-&gt;NTopen_dscp);
!         free(fidp-&gt;NTopen_pathp);
!     }
!     if (fidp-&gt;NTopen_wholepathp)
!         free(fidp-&gt;NTopen_wholepathp);
      
      smb_ReleaseFID(fidp);
!     cm_ReleaseUser(userp);
      return code;
  }
  
***************
*** 4855,5001 ****
  	cm_user_t *userp, long *readp, int dosflag)
  #endif /* !DJGPP */
  {
! 	osi_hyper_t offset;
! 	long code = 0;
! 	cm_scache_t *scp;
! 	cm_buf_t *bufferp;
! 	osi_hyper_t fileLength;
! 	osi_hyper_t thyper;
! 	osi_hyper_t lastByte;
! 	osi_hyper_t bufferOffset;
! 	long bufIndex, nbytes;
! 	int chunk;
! 	int sequential = 0;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
! 
! 	bufferp = NULL;
! 	offset = *offsetp;
! 
! 	lock_ObtainMutex(&amp;fidp-&gt;mx);
! 	scp = fidp-&gt;scp;
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 
! 	if (offset.HighPart == 0) {
! 		chunk = offset.LowPart &gt;&gt; cm_logChunkSize;
! 		if (chunk != fidp-&gt;curr_chunk) {
! 			fidp-&gt;prev_chunk = fidp-&gt;curr_chunk;
! 			fidp-&gt;curr_chunk = chunk;
! 		}
! 		if (fidp-&gt;curr_chunk == fidp-&gt;prev_chunk + 1)
! 			sequential = 1;
! 	}
! 
! 	/* start by looking up the file's end */
! 	code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
! 					 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 	if (code) goto done;
! 
! 	/* now we have the entry locked, look up the length */
! 	fileLength = scp-&gt;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 &lt;= 0) break;
!                 
! 		/* otherwise, load up a buffer of data */
! 		thyper.HighPart = offset.HighPart;
! 		thyper.LowPart = offset.LowPart &amp; ~(buf_bufferSize-1);
! 		if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
! 			/* wrong buffer */
! 			if (bufferp) {
! 				buf_Release(bufferp);
! 				bufferp = NULL;
! 			}
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
! 			lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
! 			code = buf_Get(scp, &amp;thyper, &amp;bufferp);
! 			lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
! 
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 			if (code) goto done;
! 			bufferOffset = thyper;
! 
! 			/* now get the data in the cache */
! 			while (1) {
! 				code = cm_SyncOp(scp, bufferp, userp, &amp;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, &amp;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 &amp; (buf_bufferSize - 1);
! 
! 		/* and figure out how many bytes we want from this buffer */
! 		nbytes = buf_bufferSize - bufIndex;	/* what remains in buffer */
! 		if (nbytes &gt; count) nbytes = count;	/* don't go past EOF */
! 		
! 		/* now copy the data */
  #ifdef DJGPP
! 		if (dosflag)
! 			dosmemput(bufferp-&gt;datap + bufIndex, nbytes, (dos_ptr)op);
! 		else
  #endif /* DJGPP */
! 			memcpy(op, bufferp-&gt;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(&amp;scp-&gt;mx);
! 	lock_ReleaseMutex(&amp;fidp-&gt;mx);
! 	if (bufferp) 
! 		buf_Release(bufferp);
  
! 	if (code == 0 &amp;&amp; sequential)
! 		cm_ConsiderPrefetch(scp, &amp;lastByte, userp, &amp;req);
  
! 	return code;
  }
  
  /*
--- 5023,5169 ----
  	cm_user_t *userp, long *readp, int dosflag)
  #endif /* !DJGPP */
  {
!     osi_hyper_t offset;
!     long code = 0;
!     cm_scache_t *scp;
!     cm_buf_t *bufferp;
!     osi_hyper_t fileLength;
!     osi_hyper_t thyper;
!     osi_hyper_t lastByte;
!     osi_hyper_t bufferOffset;
!     long bufIndex, nbytes;
!     int chunk;
!     int sequential = 0;
!     cm_req_t req;
! 
!     cm_InitReq(&amp;req);
! 
!     bufferp = NULL;
!     offset = *offsetp;
! 
!     lock_ObtainMutex(&amp;fidp-&gt;mx);
!     scp = fidp-&gt;scp;
!     lock_ObtainMutex(&amp;scp-&gt;mx);
! 
!     if (offset.HighPart == 0) {
!         chunk = offset.LowPart &gt;&gt; cm_logChunkSize;
!         if (chunk != fidp-&gt;curr_chunk) {
!             fidp-&gt;prev_chunk = fidp-&gt;curr_chunk;
!             fidp-&gt;curr_chunk = chunk;
!         }
!         if (fidp-&gt;curr_chunk == fidp-&gt;prev_chunk + 1)
!             sequential = 1;
!     }       
! 
!     /* start by looking up the file's end */
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) goto done;
! 
!     /* now we have the entry locked, look up the length */
!     fileLength = scp-&gt;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 &lt;= 0) break;
! 
!         /* otherwise, load up a buffer of data */
!         thyper.HighPart = offset.HighPart;
!         thyper.LowPart = offset.LowPart &amp; ~(buf_bufferSize-1);
!         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
!             /* wrong buffer */
!             if (bufferp) {
!                 buf_Release(bufferp);
!                 bufferp = NULL;
!             }
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
!             lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
!             code = buf_Get(scp, &amp;thyper, &amp;bufferp);
!             lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
! 
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             if (code) goto done;
!             bufferOffset = thyper;
! 
!             /* now get the data in the cache */
!             while (1) {
!                 code = cm_SyncOp(scp, bufferp, userp, &amp;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, &amp;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 &amp; (buf_bufferSize - 1);
! 
!         /* and figure out how many bytes we want from this buffer */
!         nbytes = buf_bufferSize - bufIndex;	/* what remains in buffer */
!         if (nbytes &gt; count) nbytes = count;	/* don't go past EOF */
! 
!         /* now copy the data */
  #ifdef DJGPP
!         if (dosflag)
!             dosmemput(bufferp-&gt;datap + bufIndex, nbytes, (dos_ptr)op);
!         else
  #endif /* DJGPP */
!             memcpy(op, bufferp-&gt;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(&amp;scp-&gt;mx);
!     lock_ReleaseMutex(&amp;fidp-&gt;mx);
!     if (bufferp) 
!         buf_Release(bufferp);
  
!     if (code == 0 &amp;&amp; sequential)
!         cm_ConsiderPrefetch(scp, &amp;lastByte, userp, &amp;req);
  
!     return code;
  }
  
  /*
***************
*** 5009,5261 ****
  	cm_user_t *userp, long *writtenp, int dosflag)
  #endif /* !DJGPP */
  {
! 	osi_hyper_t offset;
! 	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;
  
      osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
                fidp-&gt;fid, offsetp-&gt;LowPart, count);
  
! 	cm_InitReq(&amp;req);
  
! 	bufferp = NULL;
! 	doWriteBack = 0;
! 	offset = *offsetp;
  
! 	lock_ObtainMutex(&amp;fidp-&gt;mx);
! 	scp = fidp-&gt;scp;
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
  
! 	/* start by looking up the file's end */
!     osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
!               fidp-&gt;fid);
! 	code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
! 					 CM_SCACHESYNC_NEEDCALLBACK
! 					 | CM_SCACHESYNC_SETSTATUS
! 					 | CM_SCACHESYNC_GETSTATUS);
!     osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
!               fidp-&gt;fid,code);
! 	if (code) 
! 		goto done;
!         
! 	/* make sure we have a writable FD */
! 	if (!(fidp-&gt;flags &amp; SMB_FID_OPENWRITE)) {
! 		code = CM_ERROR_BADFDOP;
! 		goto done;
! 	}
! 	
! 	/* now we have the entry locked, look up the length */
! 	fileLength = scp-&gt;length;
! 	minLength = fileLength;
! 	if (LargeIntegerGreaterThan(minLength, scp-&gt;serverLength))
! 		minLength = scp-&gt;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-&gt;mask |= CM_SCACHEMASK_LENGTH;
! 		scp-&gt;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 &amp; (-cm_chunkSize)) !=
! 		 (offset.LowPart &amp; (-cm_chunkSize))) {
! 		/* they're different */
! 		doWriteBack = 1;
! 		writeBackOffset.HighPart = offset.HighPart;
! 		writeBackOffset.LowPart = offset.LowPart &amp; (-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 &lt;= 0) break;
! 
! 		/* handle over quota or out of space */
! 		if (scp-&gt;flags &amp; (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
! 			*writtenp = written;
! 			break;
! 		}
!                 
! 		/* otherwise, load up a buffer of data */
! 		thyper.HighPart = offset.HighPart;
! 		thyper.LowPart = offset.LowPart &amp; ~(buf_bufferSize-1);
! 		if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
! 			/* wrong buffer */
! 			if (bufferp) {
! 				lock_ReleaseMutex(&amp;bufferp-&gt;mx);
! 				buf_Release(bufferp);
! 				bufferp = NULL;
! 			}	
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
! 			lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
! 			code = buf_Get(scp, &amp;thyper, &amp;bufferp);
! 			lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
! 
! 			lock_ObtainMutex(&amp;bufferp-&gt;mx);
! 			lock_ObtainMutex(&amp;scp-&gt;mx);
! 			if (code) goto done;
  
! 			bufferOffset = thyper;
  
! 			/* now get the data in the cache */
! 			while (1) {
                  osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
                            fidp-&gt;fid);
! 				code = cm_SyncOp(scp, bufferp, userp, &amp;req, 0,
! 								 CM_SCACHESYNC_NEEDCALLBACK
! 								 | CM_SCACHESYNC_WRITE
! 								 | CM_SCACHESYNC_BUFLOCKED);
                  osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
                            fidp-&gt;fid,code);
! 				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-&gt;length, since
! 				 * the latter has already been updated by this
! 				 * call.
! 				 */
! 				if (LargeIntegerGreaterThanOrEqualTo(
! 					bufferp-&gt;offset, minLength)
! 				    || LargeIntegerEqualTo(offset, bufferp-&gt;offset)
! 				       &amp;&amp; (count &gt;= buf_bufferSize
! 					   || LargeIntegerGreaterThanOrEqualTo(
! 					       LargeIntegerAdd(offset,
! 						   ConvertLongToLargeInteger(count)),
! 					       minLength))) {
! 					if (count &lt; buf_bufferSize
! 					    &amp;&amp; bufferp-&gt;dataVersion == -1)
! 					    memset(bufferp-&gt;datap, 0,
! 						   buf_bufferSize);
! 					bufferp-&gt;dataVersion = scp-&gt;dataVersion;
! 				}
! 
! 				if (cm_HaveBuffer(scp, bufferp, 1)) break;
! 
! 				/* otherwise, load the buffer and try again */
! 				lock_ReleaseMutex(&amp;bufferp-&gt;mx);
! 				code = cm_GetBuffer(scp, bufferp, NULL, userp,
! 									&amp;req);
! 				lock_ReleaseMutex(&amp;scp-&gt;mx);
! 				lock_ObtainMutex(&amp;bufferp-&gt;mx);
! 				lock_ObtainMutex(&amp;scp-&gt;mx);
! 				if (code) break;
! 			}
! 			if (code) {
! 				lock_ReleaseMutex(&amp;bufferp-&gt;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 &amp; (buf_bufferSize - 1);
! 
! 		/* and figure out how many bytes we want from this buffer */
! 		nbytes = buf_bufferSize - bufIndex;	/* what remains in buffer */
! 		if (nbytes &gt; count) 
! 			nbytes = count;	/* don't go past end of request */
! 		
! 		/* now copy the data */
  #ifdef DJGPP
! 		if (dosflag)
! 			dosmemget((dos_ptr)op, nbytes, bufferp-&gt;datap + bufIndex);
! 		else
  #endif /* DJGPP */
! 			memcpy(bufferp-&gt;datap + bufIndex, op, nbytes);
! 		buf_SetDirty(bufferp);
  
! 		/* and record the last writer */
! 		if (bufferp-&gt;userp != userp) {
! 			cm_HoldUser(userp);
! 			if (bufferp-&gt;userp) 
                  cm_ReleaseUser(bufferp-&gt;userp);
! 			bufferp-&gt;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(&amp;scp-&gt;mx);
! 	lock_ReleaseMutex(&amp;fidp-&gt;mx);
! 	if (bufferp) {
! 		lock_ReleaseMutex(&amp;bufferp-&gt;mx);
! 		buf_Release(bufferp);
! 	}
! 
! 	if (code == 0 &amp;&amp; filter != 0 &amp;&amp; (fidp-&gt;flags &amp; SMB_FID_NTOPEN)
! 	    &amp;&amp; (fidp-&gt;NTopen_dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)) {
! 		smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
! 						 fidp-&gt;NTopen_dscp, fidp-&gt;NTopen_pathp,
! 						 NULL, TRUE);
! 	}
  
! 	if (code == 0 &amp;&amp; doWriteBack) {
          long code2;
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
          osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
                    fidp-&gt;fid);
! 		code2 = cm_SyncOp(scp, NULL, userp, &amp;req, 0, CM_SCACHESYNC_ASYNCSTORE);
          osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
                    fidp-&gt;fid,code2);
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 		cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
! 						   writeBackOffset.HighPart, cm_chunkSize, 0, userp);
! 	}
! 
!     osi_Log2(smb_logp, "smb_WriteData fid %d returns %d",
!               fidp-&gt;fid, code);
! 	return code;
  }
  
  long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	osi_hyper_t offset;
!     long count, written = 0;
      unsigned short fd;
      smb_fid_t *fidp;
      long code = 0;
--- 5177,5431 ----
  	cm_user_t *userp, long *writtenp, int dosflag)
  #endif /* !DJGPP */
  {
!     osi_hyper_t offset;
!     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;
  
      osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
                fidp-&gt;fid, offsetp-&gt;LowPart, count);
  
!     *writtenp = 0;
! 
!     cm_InitReq(&amp;req);
! 
!     bufferp = NULL;
!     doWriteBack = 0;
!     offset = *offsetp;
! 
!     lock_ObtainMutex(&amp;fidp-&gt;mx);
!     scp = fidp-&gt;scp;
!     lock_ObtainMutex(&amp;scp-&gt;mx);
! 
!     /* start by looking up the file's end */
!     osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
!               fidp-&gt;fid);
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK
!                       | CM_SCACHESYNC_SETSTATUS
!                       | CM_SCACHESYNC_GETSTATUS);
!     osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
!               fidp-&gt;fid,code);
!     if (code) 
!         goto done;
!         
!     /* make sure we have a writable FD */
!     if (!(fidp-&gt;flags &amp; SMB_FID_OPENWRITE)) {
!         code = CM_ERROR_BADFDOP;
!         goto done;
!     }
! 
!     /* now we have the entry locked, look up the length */
!     fileLength = scp-&gt;length;
!     minLength = fileLength;
!     if (LargeIntegerGreaterThan(minLength, scp-&gt;serverLength))
!         minLength = scp-&gt;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-&gt;mask |= CM_SCACHEMASK_LENGTH;
!         scp-&gt;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 &amp; (-cm_chunkSize)) !=
!          (offset.LowPart &amp; (-cm_chunkSize))) {
!         /* they're different */
!         doWriteBack = 1;
!         writeBackOffset.HighPart = offset.HighPart;
!         writeBackOffset.LowPart = offset.LowPart &amp; (-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 &lt;= 0) 
!             break;
  
!         /* handle over quota or out of space */
!         if (scp-&gt;flags &amp; (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
!             *writtenp = written;
!             code = CM_ERROR_QUOTA;
!             break;
!         }
  
!         /* otherwise, load up a buffer of data */
!         thyper.HighPart = offset.HighPart;
!         thyper.LowPart = offset.LowPart &amp; ~(buf_bufferSize-1);
!         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
!             /* wrong buffer */
!             if (bufferp) {
!                 lock_ReleaseMutex(&amp;bufferp-&gt;mx);
!                 buf_Release(bufferp);
!                 bufferp = NULL;
!             }	
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
!             lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
!             code = buf_Get(scp, &amp;thyper, &amp;bufferp);
!             lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
! 
!             lock_ObtainMutex(&amp;bufferp-&gt;mx);
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             if (code) goto done;
  
!             bufferOffset = thyper;
  
!             /* now get the data in the cache */
!             while (1) {
                  osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
                            fidp-&gt;fid);
!                 code = cm_SyncOp(scp, bufferp, userp, &amp;req, 0,
!                                   CM_SCACHESYNC_NEEDCALLBACK
!                                   | CM_SCACHESYNC_WRITE
!                                   | CM_SCACHESYNC_BUFLOCKED);
                  osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
                            fidp-&gt;fid,code);
!                 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-&gt;length, since
!                  * the latter has already been updated by this
!                  * call.
!                  */
!                 if (LargeIntegerGreaterThanOrEqualTo(bufferp-&gt;offset, minLength)
!                      || LargeIntegerEqualTo(offset, bufferp-&gt;offset)
!                      &amp;&amp; (count &gt;= buf_bufferSize
!                           || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
!                                                                                ConvertLongToLargeInteger(count)),
!                                                                minLength))) {
!                     if (count &lt; buf_bufferSize
!                          &amp;&amp; bufferp-&gt;dataVersion == -1)
!                         memset(bufferp-&gt;datap, 0,
!                                 buf_bufferSize);
!                     bufferp-&gt;dataVersion = scp-&gt;dataVersion;
!                 }
! 
!                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
! 
!                 /* otherwise, load the buffer and try again */
!                 lock_ReleaseMutex(&amp;bufferp-&gt;mx);
!                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
!                                      &amp;req);
!                 lock_ReleaseMutex(&amp;scp-&gt;mx);
!                 lock_ObtainMutex(&amp;bufferp-&gt;mx);
!                 lock_ObtainMutex(&amp;scp-&gt;mx);
!                 if (code) break;
!             }
!             if (code) {
!                 lock_ReleaseMutex(&amp;bufferp-&gt;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 &amp; (buf_bufferSize - 1);
! 
!         /* and figure out how many bytes we want from this buffer */
!         nbytes = buf_bufferSize - bufIndex;	/* what remains in buffer */
!         if (nbytes &gt; count) 
!             nbytes = count;	/* don't go past end of request */
! 
!         /* now copy the data */
  #ifdef DJGPP
!         if (dosflag)
!             dosmemget((dos_ptr)op, nbytes, bufferp-&gt;datap + bufIndex);
!         else
  #endif /* DJGPP */
!             memcpy(bufferp-&gt;datap + bufIndex, op, nbytes);
!         buf_SetDirty(bufferp);
  
!         /* and record the last writer */
!         if (bufferp-&gt;userp != userp) {
!             cm_HoldUser(userp);
!             if (bufferp-&gt;userp) 
                  cm_ReleaseUser(bufferp-&gt;userp);
!             bufferp-&gt;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(&amp;scp-&gt;mx);
!     lock_ReleaseMutex(&amp;fidp-&gt;mx);
!     if (bufferp) {
!         lock_ReleaseMutex(&amp;bufferp-&gt;mx);
!         buf_Release(bufferp);
!     }
  
!     if (code == 0 &amp;&amp; filter != 0 &amp;&amp; (fidp-&gt;flags &amp; SMB_FID_NTOPEN)
!          &amp;&amp; (fidp-&gt;NTopen_dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH)) {
!         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
!                           fidp-&gt;NTopen_dscp, fidp-&gt;NTopen_pathp,
!                           NULL, TRUE);
!     }       
! 
!     if (code == 0 &amp;&amp; doWriteBack) {
          long code2;
!         lock_ObtainMutex(&amp;scp-&gt;mx);
          osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
                    fidp-&gt;fid);
!         code2 = cm_SyncOp(scp, NULL, userp, &amp;req, 0, CM_SCACHESYNC_ASYNCSTORE);
          osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
                    fidp-&gt;fid,code2);
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
!         cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
!                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
!     }
! 
!     osi_Log2(smb_logp, "smb_WriteData fid %d returns %d written %d",
!               fidp-&gt;fid, code, *writtenp);
!     return code;
  }
  
  long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     osi_hyper_t offset;
!     long count, written = 0, total_written = 0;
      unsigned short fd;
      smb_fid_t *fidp;
      long code = 0;
***************
*** 5270,5536 ****
      offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) &lt;&lt; 16);
  
      op = smb_GetSMBData(inp, NULL);
! 	op = smb_ParseDataBlock(op, NULL, &amp;inDataBlockCount);
  
      osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
               fd, offset.LowPart, count);
          
! 	fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp) {
! 		return CM_ERROR_BADFD;
      }
          
      if (fidp-&gt;flags &amp; SMB_FID_IOCTL)
          return smb_IoctlWrite(fidp, vcp, inp, outp);
          
! 	userp = smb_GetUser(vcp, inp);
  
  	/* special case: 0 bytes transferred means truncate to this position */
      if (count == 0) {
! 		cm_req_t req;
  
! 		cm_InitReq(&amp;req);
  
! 		truncAttr.mask = CM_ATTRMASK_LENGTH;
          truncAttr.length.LowPart = offset.LowPart;
          truncAttr.length.HighPart = 0;
! 		lock_ObtainMutex(&amp;fidp-&gt;mx);
          code = cm_SetAttr(fidp-&gt;scp, &amp;truncAttr, userp, &amp;req);
! 		lock_ReleaseMutex(&amp;fidp-&gt;mx);
! 		smb_SetSMBParm(outp, 0, /* count */ 0);
          smb_SetSMBDataLength(outp, 0);
! 		fidp-&gt;flags |= SMB_FID_LENGTHSETDONE;
          goto done;
      }
  
! 	/*
! 	 * Work around bug in NT client
! 	 *
! 	 * When copying a file, the NT client should first copy the data,
! 	 * then copy the last write time.  But sometimes the NT client does
! 	 * these in the wrong order, so the data copies would inadvertently
! 	 * cause the last write time to be overwritten.  We try to detect this,
! 	 * and don't set client mod time if we think that would go against the
! 	 * intention.
! 	 */
! 	if ((fidp-&gt;flags &amp; SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
! 		fidp-&gt;scp-&gt;mask |= CM_SCACHEMASK_CLIENTMODTIME;
! 		fidp-&gt;scp-&gt;clientModTime = time(NULL);
! 	}
  
  #ifndef DJGPP
  	code = smb_WriteData(fidp, &amp;offset, count, op, userp, &amp;written);
  #else /* DJGPP */
  	code = smb_WriteData(fidp, &amp;offset, count, op, userp, &amp;written, FALSE);
  #endif /* !DJGPP */
! 	if (code == 0 &amp;&amp; written &lt; count)
! 		code = CM_ERROR_PARTIALWRITE;
  
! 	/* set the packet data length to 3 bytes for the data block header,
       * plus the size of the data.
       */
! 	smb_SetSMBParm(outp, 0, written);
      smb_SetSMBDataLength(outp, 0);
  
    done:
      smb_ReleaseFID(fidp);
      cm_ReleaseUser(userp);
  
! 	return code;
  }
  
  void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
! 	NCB *ncbp, raw_write_cont_t *rwcp)
  {
! 	unsigned short fd;
! 	smb_fid_t *fidp;
! 	cm_user_t *userp;
  #ifndef DJGPP
! 	char *rawBuf;
  #else /* DJGPP */
! 	dos_ptr rawBuf;
  #endif /* !DJGPP */
! 	long written = 0;
! 	long code = 0;
  
! 	fd = smb_GetSMBParm(inp, 0);
! 	fidp = smb_FindFID(vcp, fd, 0);
  
! 	osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
! 	     	 rwcp-&gt;offset.LowPart, rwcp-&gt;count);
  
! 	userp = smb_GetUser(vcp, inp);
  
  #ifndef DJGPP
! 	rawBuf = rwcp-&gt;buf;
! 	code = smb_WriteData(fidp, &amp;rwcp-&gt;offset, rwcp-&gt;count, rawBuf, userp,
  						 &amp;written);
  #else /* DJGPP */
! 	rawBuf = (dos_ptr) rwcp-&gt;buf;
! 	code = smb_WriteData(fidp, &amp;rwcp-&gt;offset, rwcp-&gt;count,
                           (unsigned char *) rawBuf, userp,
                           &amp;written, TRUE);
  #endif /* !DJGPP */
  
! 	if (rwcp-&gt;writeMode &amp; 0x1) {	/* synchronous */
! 		smb_t *op;
  
! 		smb_FormatResponsePacket(vcp, inp, outp);
! 		op = (smb_t *) outp;
! 		op-&gt;com = 0x20;		/* SMB_COM_WRITE_COMPLETE */
! 		smb_SetSMBParm(outp, 0, written + rwcp-&gt;alreadyWritten);
! 		smb_SetSMBDataLength(outp,  0);
! 		smb_SendPacket(vcp, outp);
! 		smb_FreePacket(outp);
! 	}
! 	else {				/* asynchronous */
! 		lock_ObtainMutex(&amp;fidp-&gt;mx);
! 		fidp-&gt;raw_writers--;
! 		if (fidp-&gt;raw_writers == 0)
! 			thrd_SetEvent(fidp-&gt;raw_write_event);
! 		lock_ReleaseMutex(&amp;fidp-&gt;mx);
! 	}
  
! 	/* Give back raw buffer */
! 	lock_ObtainMutex(&amp;smb_RawBufLock);
  #ifndef DJGPP
! 	*((char **)rawBuf) = smb_RawBufs;
  #else /* DJGPP */
      _farpokel(_dos_ds, rawBuf, smb_RawBufs);
  #endif /* !DJGPP */
! 	smb_RawBufs = rawBuf;
! 	lock_ReleaseMutex(&amp;smb_RawBufLock);
  
! 	smb_ReleaseFID(fidp);
! 	cm_ReleaseUser(userp);
  }
  
  long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	return 0;
  }
  
  long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
  {
! 	osi_hyper_t offset;
!     long count, written = 0;
! 	long totalCount;
      unsigned short fd;
      smb_fid_t *fidp;
      long code = 0;
      cm_user_t *userp;
      char *op;
! 	unsigned short writeMode;
  #ifndef DJGPP
! 	char *rawBuf;
  #else /* DJGPP */
      dos_ptr rawBuf;
  #endif /* !DJGPP */
  
      fd = smb_GetSMBParm(inp, 0);
! 	totalCount = smb_GetSMBParm(inp, 1);
      count = smb_GetSMBParm(inp, 10);
      offset.HighPart = 0;	/* too bad */
      offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) &lt;&lt; 16);
! 	writeMode = smb_GetSMBParm(inp, 7);
  
! 	op = (char *) inp-&gt;data;
! 	op += smb_GetSMBParm(inp, 11);
  
      osi_Log4(smb_logp,
               "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
               fd, offset.LowPart, count, writeMode);
          
! 	fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp) {
! 		return CM_ERROR_BADFD;
      }
          
! 	userp = smb_GetUser(vcp, inp);
  
! 	/*
! 	 * Work around bug in NT client
! 	 *
! 	 * When copying a file, the NT client should first copy the data,
! 	 * then copy the last write time.  But sometimes the NT client does
! 	 * these in the wrong order, so the data copies would inadvertently
! 	 * cause the last write time to be overwritten.  We try to detect this,
! 	 * and don't set client mod time if we think that would go against the
! 	 * intention.
! 	 */
! 	if ((fidp-&gt;flags &amp; SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
! 		fidp-&gt;scp-&gt;mask |= CM_SCACHEMASK_CLIENTMODTIME;
! 		fidp-&gt;scp-&gt;clientModTime = time(NULL);
! 	}
  
  #ifndef DJGPP
  	code = smb_WriteData(fidp, &amp;offset, count, op, userp, &amp;written);
  #else /* DJGPP */
  	code = smb_WriteData(fidp, &amp;offset, count, op, userp, &amp;written, FALSE);
  #endif /* !DJGPP */
! 	if (code == 0 &amp;&amp; written &lt; count)
! 		code = CM_ERROR_PARTIALWRITE;
  
! 	/* Get a raw buffer */
! 	if (code == 0) {
! 		rawBuf = NULL;
! 		lock_ObtainMutex(&amp;smb_RawBufLock);
! 		if (smb_RawBufs) {
! 			/* Get a raw buf, from head of list */
! 			rawBuf = smb_RawBufs;
  #ifndef DJGPP
! 			smb_RawBufs = *(char **)smb_RawBufs;
  #else /* DJGPP */
              smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
  #endif /* !DJGPP */
! 		}
! 		else
! 			code = CM_ERROR_USESTD;
  		
          lock_ReleaseMutex(&amp;smb_RawBufLock);
! 	}
  
! 	/* Don't allow a premature Close */
! 	if (code == 0 &amp;&amp; (writeMode &amp; 1) == 0) {
! 		lock_ObtainMutex(&amp;fidp-&gt;mx);
! 		fidp-&gt;raw_writers++;
! 		thrd_ResetEvent(fidp-&gt;raw_write_event);
! 		lock_ReleaseMutex(&amp;fidp-&gt;mx);
! 	}
! 
! 	smb_ReleaseFID(fidp);
! 	cm_ReleaseUser(userp);
! 
! 	if (code) {
! 		smb_SetSMBParm(outp, 0, written);
! 		smb_SetSMBDataLength(outp, 0);
! 		((smb_t *)outp)-&gt;com = 0x20;	/* SMB_COM_WRITE_COMPLETE */
! 		rwcp-&gt;code = code;
! 		return code;
! 	}
! 
! 	rwcp-&gt;code = 0;
! 	rwcp-&gt;buf = rawBuf;
! 	rwcp-&gt;offset.HighPart = 0;
! 	rwcp-&gt;offset.LowPart = offset.LowPart + count;
! 	rwcp-&gt;count = totalCount - count;
! 	rwcp-&gt;writeMode = writeMode;
! 	rwcp-&gt;alreadyWritten = written;
  
! 	/* set the packet data length to 3 bytes for the data block header,
       * plus the size of the data.
       */
! 	smb_SetSMBParm(outp, 0, 0xffff);
      smb_SetSMBDataLength(outp, 0);
  
! 	return 0;
  }
  
  long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	osi_hyper_t offset;
      long count, finalCount;
      unsigned short fd;
      smb_fid_t *fidp;
--- 5440,5722 ----
      offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) &lt;&lt; 16);
  
      op = smb_GetSMBData(inp, NULL);
!     op = smb_ParseDataBlock(op, NULL, &amp;inDataBlockCount);
  
      osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
               fd, offset.LowPart, count);
          
!     fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp) {
!         return CM_ERROR_BADFD;
      }
          
      if (fidp-&gt;flags &amp; SMB_FID_IOCTL)
          return smb_IoctlWrite(fidp, vcp, inp, outp);
          
!     userp = smb_GetUser(vcp, inp);
  
  	/* special case: 0 bytes transferred means truncate to this position */
      if (count == 0) {
!         cm_req_t req;
  
!         cm_InitReq(&amp;req);
  
!         truncAttr.mask = CM_ATTRMASK_LENGTH;
          truncAttr.length.LowPart = offset.LowPart;
          truncAttr.length.HighPart = 0;
!         lock_ObtainMutex(&amp;fidp-&gt;mx);
          code = cm_SetAttr(fidp-&gt;scp, &amp;truncAttr, userp, &amp;req);
!         lock_ReleaseMutex(&amp;fidp-&gt;mx);
!         smb_SetSMBParm(outp, 0, /* count */ 0);
          smb_SetSMBDataLength(outp, 0);
!         fidp-&gt;flags |= SMB_FID_LENGTHSETDONE;
          goto done;
      }
  
!     /*
!      * Work around bug in NT client
!      *
!      * When copying a file, the NT client should first copy the data,
!      * then copy the last write time.  But sometimes the NT client does
!      * these in the wrong order, so the data copies would inadvertently
!      * cause the last write time to be overwritten.  We try to detect this,
!      * and don't set client mod time if we think that would go against the
!      * intention.
!      */
!     if ((fidp-&gt;flags &amp; SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
!         fidp-&gt;scp-&gt;mask |= CM_SCACHEMASK_CLIENTMODTIME;
!         fidp-&gt;scp-&gt;clientModTime = time(NULL);
!     }
  
+     code = 0;
+     while ( code == 0 &amp;&amp; count &gt; 0 ) {
  #ifndef DJGPP
  	code = smb_WriteData(fidp, &amp;offset, count, op, userp, &amp;written);
  #else /* DJGPP */
  	code = smb_WriteData(fidp, &amp;offset, count, op, userp, &amp;written, FALSE);
  #endif /* !DJGPP */
! 	if (code == 0 &amp;&amp; written == 0)
!             code = CM_ERROR_PARTIALWRITE;
  
!         offset.LowPart += written;
!         count -= written;
!         total_written += written;
!         written = 0;
!     }
!     
!     /* set the packet data length to 3 bytes for the data block header,
       * plus the size of the data.
       */
!     smb_SetSMBParm(outp, 0, total_written);
      smb_SetSMBDataLength(outp, 0);
  
    done:
      smb_ReleaseFID(fidp);
      cm_ReleaseUser(userp);
  
!     return code;
  }
  
  void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
!                           NCB *ncbp, raw_write_cont_t *rwcp)
  {
!     unsigned short fd;
!     smb_fid_t *fidp;
!     cm_user_t *userp;
  #ifndef DJGPP
!     char *rawBuf;
  #else /* DJGPP */
!     dos_ptr rawBuf;
  #endif /* !DJGPP */
!     long written = 0;
!     long code = 0;
  
!     fd = smb_GetSMBParm(inp, 0);
!     fidp = smb_FindFID(vcp, fd, 0);
  
!     osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
!              rwcp-&gt;offset.LowPart, rwcp-&gt;count);
  
!     userp = smb_GetUser(vcp, inp);
  
  #ifndef DJGPP
!     rawBuf = rwcp-&gt;buf;
!     code = smb_WriteData(fidp, &amp;rwcp-&gt;offset, rwcp-&gt;count, rawBuf, userp,
  						 &amp;written);
  #else /* DJGPP */
!     rawBuf = (dos_ptr) rwcp-&gt;buf;
!     code = smb_WriteData(fidp, &amp;rwcp-&gt;offset, rwcp-&gt;count,
                           (unsigned char *) rawBuf, userp,
                           &amp;written, TRUE);
  #endif /* !DJGPP */
  
!     if (rwcp-&gt;writeMode &amp; 0x1) {	/* synchronous */
!         smb_t *op;
  
!         smb_FormatResponsePacket(vcp, inp, outp);
!         op = (smb_t *) outp;
!         op-&gt;com = 0x20;		/* SMB_COM_WRITE_COMPLETE */
!         smb_SetSMBParm(outp, 0, written + rwcp-&gt;alreadyWritten);
!         smb_SetSMBDataLength(outp,  0);
!         smb_SendPacket(vcp, outp);
!         smb_FreePacket(outp);
!     }
!     else {				/* asynchronous */
!         lock_ObtainMutex(&amp;fidp-&gt;mx);
!         fidp-&gt;raw_writers--;
!         if (fidp-&gt;raw_writers == 0)
!             thrd_SetEvent(fidp-&gt;raw_write_event);
!         lock_ReleaseMutex(&amp;fidp-&gt;mx);
!     }
  
!     /* Give back raw buffer */
!     lock_ObtainMutex(&amp;smb_RawBufLock);
  #ifndef DJGPP
!     *((char **)rawBuf) = smb_RawBufs;
  #else /* DJGPP */
      _farpokel(_dos_ds, rawBuf, smb_RawBufs);
  #endif /* !DJGPP */
!     smb_RawBufs = rawBuf;
!     lock_ReleaseMutex(&amp;smb_RawBufLock);
  
!     smb_ReleaseFID(fidp);
!     cm_ReleaseUser(userp);
  }
  
  long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     return 0;
  }
  
  long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
  {
!     osi_hyper_t offset;
!     long count, written = 0, total_written = 0;
!     long totalCount;
      unsigned short fd;
      smb_fid_t *fidp;
      long code = 0;
      cm_user_t *userp;
      char *op;
!     unsigned short writeMode;
  #ifndef DJGPP
!     char *rawBuf;
  #else /* DJGPP */
      dos_ptr rawBuf;
  #endif /* !DJGPP */
  
      fd = smb_GetSMBParm(inp, 0);
!     totalCount = smb_GetSMBParm(inp, 1);
      count = smb_GetSMBParm(inp, 10);
      offset.HighPart = 0;	/* too bad */
      offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) &lt;&lt; 16);
!     writeMode = smb_GetSMBParm(inp, 7);
  
!     op = (char *) inp-&gt;data;
!     op += smb_GetSMBParm(inp, 11);
  
      osi_Log4(smb_logp,
               "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
               fd, offset.LowPart, count, writeMode);
          
!     fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp) {
!         return CM_ERROR_BADFD;
      }
          
!     userp = smb_GetUser(vcp, inp);
  
!     /*
!      * Work around bug in NT client
!      *
!      * When copying a file, the NT client should first copy the data,
!      * then copy the last write time.  But sometimes the NT client does
!      * these in the wrong order, so the data copies would inadvertently
!      * cause the last write time to be overwritten.  We try to detect this,
!      * and don't set client mod time if we think that would go against the
!      * intention.
!      */
!     if ((fidp-&gt;flags &amp; SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
!         fidp-&gt;scp-&gt;mask |= CM_SCACHEMASK_CLIENTMODTIME;
!         fidp-&gt;scp-&gt;clientModTime = time(NULL);
!     }
  
+     code = 0;
+     while ( code == 0 &amp;&amp; count &gt; 0 ) {
  #ifndef DJGPP
  	code = smb_WriteData(fidp, &amp;offset, count, op, userp, &amp;written);
  #else /* DJGPP */
  	code = smb_WriteData(fidp, &amp;offset, count, op, userp, &amp;written, FALSE);
  #endif /* !DJGPP */
! 	if (code == 0 &amp;&amp; written == 0)
!             code = CM_ERROR_PARTIALWRITE;
  
!         offset.LowPart += written;
!         count -= written;
!         total_written += written;
!         written = 0;
!     }
! 
!     /* Get a raw buffer */
!     if (code == 0) {
!         rawBuf = NULL;
!         lock_ObtainMutex(&amp;smb_RawBufLock);
!         if (smb_RawBufs) {
!             /* Get a raw buf, from head of list */
!             rawBuf = smb_RawBufs;
  #ifndef DJGPP
!             smb_RawBufs = *(char **)smb_RawBufs;
  #else /* DJGPP */
              smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
  #endif /* !DJGPP */
!         }
!         else
!             code = CM_ERROR_USESTD;
  		
          lock_ReleaseMutex(&amp;smb_RawBufLock);
!     }
! 
!     /* Don't allow a premature Close */
!     if (code == 0 &amp;&amp; (writeMode &amp; 1) == 0) {
!         lock_ObtainMutex(&amp;fidp-&gt;mx);
!         fidp-&gt;raw_writers++;
!         thrd_ResetEvent(fidp-&gt;raw_write_event);
!         lock_ReleaseMutex(&amp;fidp-&gt;mx);
!     }
! 
!     smb_ReleaseFID(fidp);
!     cm_ReleaseUser(userp);
  
!     if (code) {
!         smb_SetSMBParm(outp, 0, total_written);
!         smb_SetSMBDataLength(outp, 0);
!         ((smb_t *)outp)-&gt;com = 0x20;	/* SMB_COM_WRITE_COMPLETE */
!         rwcp-&gt;code = code;
!         return code;
!     }
  
!     rwcp-&gt;code = 0;
!     rwcp-&gt;buf = rawBuf;
!     rwcp-&gt;offset.HighPart = 0;
!     rwcp-&gt;offset.LowPart = offset.LowPart + count;
!     rwcp-&gt;count = totalCount - count;
!     rwcp-&gt;writeMode = writeMode;
!     rwcp-&gt;alreadyWritten = total_written;
! 
!     /* set the packet data length to 3 bytes for the data block header,
       * plus the size of the data.
       */
!     smb_SetSMBParm(outp, 0, 0xffff);
      smb_SetSMBDataLength(outp, 0);
  
!     return 0;
  }
  
  long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     osi_hyper_t offset;
      long count, finalCount;
      unsigned short fd;
      smb_fid_t *fidp;
***************
*** 5546,5594 ****
      osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
               fd, offset.LowPart, count);
          
! 	fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp) {
! 		return CM_ERROR_BADFD;
      }
          
      if (fidp-&gt;flags &amp; SMB_FID_IOCTL) {
! 		return smb_IoctlRead(fidp, vcp, inp, outp);
      }
          
! 	userp = smb_GetUser(vcp, inp);
  
! 	/* remember this for final results */
      smb_SetSMBParm(outp, 0, count);
      smb_SetSMBParm(outp, 1, 0);
      smb_SetSMBParm(outp, 2, 0);
      smb_SetSMBParm(outp, 3, 0);
      smb_SetSMBParm(outp, 4, 0);
  
! 	/* set the packet data length to 3 bytes for the data block header,
       * plus the size of the data.
       */
      smb_SetSMBDataLength(outp, count+3);
          
! 	/* get op ptr after putting in the parms, since otherwise we don't
       * know where the data really is.
       */
      op = smb_GetSMBData(outp, NULL);
  
! 	/* now emit the data block header: 1 byte of type and 2 bytes of length */
      *op++ = 1;	/* data block marker */
      *op++ = (unsigned char) (count &amp; 0xff);
      *op++ = (unsigned char) ((count &gt;&gt; 8) &amp; 0xff);
                  
  #ifndef DJGPP
! 	code = smb_ReadData(fidp, &amp;offset, count, op, userp, &amp;finalCount);
  #else /* DJGPP */
      code = smb_ReadData(fidp, &amp;offset, count, op, userp, &amp;finalCount, FALSE);
  #endif /* !DJGPP */
  
! 	/* fix some things up */
! 	smb_SetSMBParm(outp, 0, finalCount);
! 	smb_SetSMBDataLength(outp, finalCount+3);
  
      smb_ReleaseFID(fidp);
  	
--- 5732,5780 ----
      osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
               fd, offset.LowPart, count);
          
!     fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp) {
!         return CM_ERROR_BADFD;
      }
          
      if (fidp-&gt;flags &amp; SMB_FID_IOCTL) {
!         return smb_IoctlRead(fidp, vcp, inp, outp);
      }
          
!     userp = smb_GetUser(vcp, inp);
  
!     /* remember this for final results */
      smb_SetSMBParm(outp, 0, count);
      smb_SetSMBParm(outp, 1, 0);
      smb_SetSMBParm(outp, 2, 0);
      smb_SetSMBParm(outp, 3, 0);
      smb_SetSMBParm(outp, 4, 0);
  
!     /* set the packet data length to 3 bytes for the data block header,
       * plus the size of the data.
       */
      smb_SetSMBDataLength(outp, count+3);
          
!     /* get op ptr after putting in the parms, since otherwise we don't
       * know where the data really is.
       */
      op = smb_GetSMBData(outp, NULL);
  
!     /* now emit the data block header: 1 byte of type and 2 bytes of length */
      *op++ = 1;	/* data block marker */
      *op++ = (unsigned char) (count &amp; 0xff);
      *op++ = (unsigned char) ((count &gt;&gt; 8) &amp; 0xff);
                  
  #ifndef DJGPP
!     code = smb_ReadData(fidp, &amp;offset, count, op, userp, &amp;finalCount);
  #else /* DJGPP */
      code = smb_ReadData(fidp, &amp;offset, count, op, userp, &amp;finalCount, FALSE);
  #endif /* !DJGPP */
  
!     /* fix some things up */
!     smb_SetSMBParm(outp, 0, finalCount);
!     smb_SetSMBDataLength(outp, finalCount+3);
  
      smb_ReleaseFID(fidp);
  	
***************
*** 5598,5606 ****
  
  long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	char *pathp;
      long code = 0;
! 	cm_space_t *spacep;
      char *tp;
      cm_user_t *userp;
      cm_scache_t *dscp;			/* dir we're dealing with */
--- 5784,5792 ----
  
  long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     char *pathp;
      long code = 0;
!     cm_space_t *spacep;
      char *tp;
      cm_user_t *userp;
      cm_scache_t *dscp;			/* dir we're dealing with */
***************
*** 5609,5644 ****
      int initialModeBits;
      char *lastNamep;
      int caseFold;
! 	char *tidPathp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      scp = NULL;
          
! 	/* compute initial mode bits based on read-only flag in attributes */
      initialModeBits = 0777;
          
! 	tp = smb_GetSMBData(inp, NULL);
      pathp = smb_ParseASCIIBlock(tp, &amp;tp);
  
! 	if (strcmp(pathp, "\\") == 0)
! 		return CM_ERROR_EXISTS;
  
! 	spacep = inp-&gt;spacep;
      smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
! 	userp = smb_GetUser(vcp, inp);
  
      caseFold = CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
  
! 	code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
                      caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
                      userp, tidPathp, &amp;req, &amp;dscp);
  
--- 5795,5830 ----
      int initialModeBits;
      char *lastNamep;
      int caseFold;
!     char *tidPathp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      scp = NULL;
          
!     /* compute initial mode bits based on read-only flag in attributes */
      initialModeBits = 0777;
          
!     tp = smb_GetSMBData(inp, NULL);
      pathp = smb_ParseASCIIBlock(tp, &amp;tp);
  
!     if (strcmp(pathp, "\\") == 0)
!         return CM_ERROR_EXISTS;
  
!     spacep = inp-&gt;spacep;
      smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
!     userp = smb_GetUser(vcp, inp);
  
      caseFold = CM_FLAG_CASEFOLD;
  
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
  
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
                      caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
                      userp, tidPathp, &amp;req, &amp;dscp);
  
***************
*** 5648,5654 ****
      }
          
      /* otherwise, scp points to the parent directory.  Do a lookup, and
! 	 * fail if we find it.  Otherwise, we do the create.
       */
      if (!lastNamep) 
          lastNamep = pathp;
--- 5834,5840 ----
      }
          
      /* otherwise, scp points to the parent directory.  Do a lookup, and
!      * fail if we find it.  Otherwise, we do the create.
       */
      if (!lastNamep) 
          lastNamep = pathp;
***************
*** 5658,5686 ****
      if (scp) cm_ReleaseSCache(scp);
      if (code != CM_ERROR_NOSUCHFILE) {
          if (code == 0) code = CM_ERROR_EXISTS;
! 		cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          return code;
      }
          
! 	setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
! 	setAttr.clientModTime = time(NULL);
! 	code = cm_MakeDir(dscp, lastNamep, 0, &amp;setAttr, userp, &amp;req);
! 	if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 		smb_NotifyChange(FILE_ACTION_ADDED,
                           FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, lastNamep, NULL, TRUE);
          
! 	/* we don't need this any longer */
! 	cm_ReleaseSCache(dscp);
  
      if (code) {
! 		/* something went wrong creating or truncating the file */
          cm_ReleaseUser(userp);
          return code;
      }
          
! 	/* otherwise we succeeded */
      smb_SetSMBDataLength(outp, 0);
      cm_ReleaseUser(userp);
  
--- 5844,5872 ----
      if (scp) cm_ReleaseSCache(scp);
      if (code != CM_ERROR_NOSUCHFILE) {
          if (code == 0) code = CM_ERROR_EXISTS;
!         cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          return code;
      }
          
!     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
!     setAttr.clientModTime = time(NULL);
!     code = cm_MakeDir(dscp, lastNamep, 0, &amp;setAttr, userp, &amp;req);
!     if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!         smb_NotifyChange(FILE_ACTION_ADDED,
                           FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, lastNamep, NULL, TRUE);
          
!     /* we don't need this any longer */
!     cm_ReleaseSCache(dscp);
  
      if (code) {
!         /* something went wrong creating or truncating the file */
          cm_ReleaseUser(userp);
          return code;
      }
          
!     /* otherwise we succeeded */
      smb_SetSMBDataLength(outp, 0);
      cm_ReleaseUser(userp);
  
***************
*** 5703,5711 ****
  
  long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	char *pathp;
      long code = 0;
! 	cm_space_t *spacep;
      char *tp;
      int excl;
      cm_user_t *userp;
--- 5889,5897 ----
  
  long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     char *pathp;
      long code = 0;
!     cm_space_t *spacep;
      char *tp;
      int excl;
      cm_user_t *userp;
***************
*** 5718,5727 ****
      char *lastNamep;
      int caseFold;
      long dosTime;
! 	char *tidPathp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      scp = NULL;
      excl = (inp-&gt;inCom == 0x03)? 0 : 1;
--- 5904,5913 ----
      char *lastNamep;
      int caseFold;
      long dosTime;
!     char *tidPathp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      scp = NULL;
      excl = (inp-&gt;inCom == 0x03)? 0 : 1;
***************
*** 5729,5754 ****
      attributes = smb_GetSMBParm(inp, 0);
      dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) &lt;&lt; 16);
          
! 	/* compute initial mode bits based on read-only flag in attributes */
      initialModeBits = 0666;
      if (attributes &amp; 1) initialModeBits &amp;= ~0222;
          
! 	tp = smb_GetSMBData(inp, NULL);
      pathp = smb_ParseASCIIBlock(tp, &amp;tp);
  
! 	spacep = inp-&gt;spacep;
      smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
! 	userp = smb_GetUser(vcp, inp);
  
      caseFold = CM_FLAG_CASEFOLD;
  
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
! 	code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold | CM_FLAG_FOLLOW,
                      userp, tidPathp, &amp;req, &amp;dscp);
  
      if (code) {
--- 5915,5940 ----
      attributes = smb_GetSMBParm(inp, 0);
      dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) &lt;&lt; 16);
          
!     /* compute initial mode bits based on read-only flag in attributes */
      initialModeBits = 0666;
      if (attributes &amp; 1) initialModeBits &amp;= ~0222;
          
!     tp = smb_GetSMBData(inp, NULL);
      pathp = smb_ParseASCIIBlock(tp, &amp;tp);
  
!     spacep = inp-&gt;spacep;
      smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
!     userp = smb_GetUser(vcp, inp);
  
      caseFold = CM_FLAG_CASEFOLD;
  
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold | CM_FLAG_FOLLOW,
                      userp, tidPathp, &amp;req, &amp;dscp);
  
      if (code) {
***************
*** 5757,5763 ****
      }
          
      /* otherwise, scp points to the parent directory.  Do a lookup, and
! 	 * truncate the file if we find it, otherwise we create the file.
       */
      if (!lastNamep) lastNamep = pathp;
      else lastNamep++;
--- 5943,5949 ----
      }
          
      /* otherwise, scp points to the parent directory.  Do a lookup, and
!      * truncate the file if we find it, otherwise we create the file.
       */
      if (!lastNamep) lastNamep = pathp;
      else lastNamep++;
***************
*** 5777,5783 ****
  
      code = cm_Lookup(dscp, lastNamep, 0, userp, &amp;req, &amp;scp);
      if (code &amp;&amp; code != CM_ERROR_NOSUCHFILE) {
! 		cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          return code;
      }
--- 5963,5969 ----
  
      code = cm_Lookup(dscp, lastNamep, 0, userp, &amp;req, &amp;scp);
      if (code &amp;&amp; code != CM_ERROR_NOSUCHFILE) {
!         cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          return code;
      }
***************
*** 5785,5824 ****
      /* if we get here, if code is 0, the file exists and is represented by
       * scp.  Otherwise, we have to create it.
       */
! 	if (code == 0) {
! 		if (excl) {
! 			/* oops, file shouldn't be there */
              cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
              return CM_ERROR_EXISTS;
          }
  
! 		setAttr.mask = CM_ATTRMASK_LENGTH;
          setAttr.length.LowPart = 0;
          setAttr.length.HighPart = 0;
! 		code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
      }
      else {
! 		setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
! 		smb_UnixTimeFromDosUTime(&amp;setAttr.clientModTime, dosTime);
          code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
                           &amp;req);
! 		if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 			smb_NotifyChange(FILE_ACTION_ADDED,
                               FILE_NOTIFY_CHANGE_FILE_NAME,
                               dscp, lastNamep, NULL, TRUE);
          if (!excl &amp;&amp; code == CM_ERROR_EXISTS) {
! 			/* not an exclusive create, and someone else tried
! 			 * creating it already, then we open it anyway.  We
! 			 * don't bother retrying after this, since if this next
! 			 * fails, that means that the file was deleted after
! 			 * we started this call.
               */
              code = cm_Lookup(dscp, lastNamep, caseFold, userp,
                               &amp;req, &amp;scp);
              if (code == 0) {
! 				setAttr.mask = CM_ATTRMASK_LENGTH;
                  setAttr.length.LowPart = 0;
                  setAttr.length.HighPart = 0;
                  code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
--- 5971,6010 ----
      /* if we get here, if code is 0, the file exists and is represented by
       * scp.  Otherwise, we have to create it.
       */
!     if (code == 0) {
!         if (excl) {
!             /* oops, file shouldn't be there */
              cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
              return CM_ERROR_EXISTS;
          }
  
!         setAttr.mask = CM_ATTRMASK_LENGTH;
          setAttr.length.LowPart = 0;
          setAttr.length.HighPart = 0;
!         code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
      }
      else {
!         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
!         smb_UnixTimeFromDosUTime(&amp;setAttr.clientModTime, dosTime);
          code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
                           &amp;req);
!         if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!             smb_NotifyChange(FILE_ACTION_ADDED,
                               FILE_NOTIFY_CHANGE_FILE_NAME,
                               dscp, lastNamep, NULL, TRUE);
          if (!excl &amp;&amp; code == CM_ERROR_EXISTS) {
!             /* not an exclusive create, and someone else tried
!              * creating it already, then we open it anyway.  We
!              * don't bother retrying after this, since if this next
!              * fails, that means that the file was deleted after
!              * we started this call.
               */
              code = cm_Lookup(dscp, lastNamep, caseFold, userp,
                               &amp;req, &amp;scp);
              if (code == 0) {
!                 setAttr.mask = CM_ATTRMASK_LENGTH;
                  setAttr.length.LowPart = 0;
                  setAttr.length.HighPart = 0;
                  code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
***************
*** 5826,5864 ****
          }
      }
          
! 	/* we don't need this any longer */
! 	cm_ReleaseSCache(dscp);
  
      if (code) {
! 		/* something went wrong creating or truncating the file */
          if (scp) cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          return code;
      }
  
! 	/* make sure we only open files */
! 	if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
! 		cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          return CM_ERROR_ISDIR;
! 	}
  
      /* now all we have to do is open the file itself */
      fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
      osi_assert(fidp);
  	
! 	/* save a pointer to the vnode */
      fidp-&gt;scp = scp;
          
! 	/* always create it open for read/write */
! 	fidp-&gt;flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
  
! 	smb_ReleaseFID(fidp);
          
! 	smb_SetSMBParm(outp, 0, fidp-&gt;fid);
      smb_SetSMBDataLength(outp, 0);
  
! 	cm_Open(scp, 0, userp);
  
      cm_ReleaseUser(userp);
      /* leave scp held since we put it in fidp-&gt;scp */
--- 6012,6050 ----
          }
      }
          
!     /* we don't need this any longer */
!     cm_ReleaseSCache(dscp);
  
      if (code) {
!         /* something went wrong creating or truncating the file */
          if (scp) cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          return code;
      }
  
!     /* make sure we only open files */
!     if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!         cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          return CM_ERROR_ISDIR;
!     }
  
      /* now all we have to do is open the file itself */
      fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
      osi_assert(fidp);
  	
!     /* save a pointer to the vnode */
      fidp-&gt;scp = scp;
          
!     /* always create it open for read/write */
!     fidp-&gt;flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
  
!     smb_ReleaseFID(fidp);
          
!     smb_SetSMBParm(outp, 0, fidp-&gt;fid);
      smb_SetSMBDataLength(outp, 0);
  
!     cm_Open(scp, 0, userp);
  
      cm_ReleaseUser(userp);
      /* leave scp held since we put it in fidp-&gt;scp */
***************
*** 5874,5916 ****
      smb_fid_t *fidp;
      cm_scache_t *scp;
      cm_user_t *userp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
          
      fd = smb_GetSMBParm(inp, 0);
! 	whence = smb_GetSMBParm(inp, 1);
      offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) &lt;&lt; 16);
          
! 	/* try to find the file descriptor */
! 	fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
! 		return CM_ERROR_BADFD;
      }
  	
! 	userp = smb_GetUser(vcp, inp);
  
      lock_ObtainMutex(&amp;fidp-&gt;mx);
      scp = fidp-&gt;scp;
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 	if (code == 0) {
! 		if (whence == 1) {
              /* offset from current offset */
              offset += fidp-&gt;offset;
! 		}
! 		else if (whence == 2) {
              /* offset from current EOF */
              offset += scp-&gt;length.LowPart;
! 		}
          fidp-&gt;offset = offset;
          smb_SetSMBParm(outp, 0, offset &amp; 0xffff);
          smb_SetSMBParm(outp, 1, (offset&gt;&gt;16) &amp; 0xffff);
          smb_SetSMBDataLength(outp, 0);
      }
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
      lock_ReleaseMutex(&amp;fidp-&gt;mx);
      smb_ReleaseFID(fidp);
      cm_ReleaseUser(userp);
--- 6060,6102 ----
      smb_fid_t *fidp;
      cm_scache_t *scp;
      cm_user_t *userp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
          
      fd = smb_GetSMBParm(inp, 0);
!     whence = smb_GetSMBParm(inp, 1);
      offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) &lt;&lt; 16);
          
!     /* try to find the file descriptor */
!     fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
!         return CM_ERROR_BADFD;
      }
  	
!     userp = smb_GetUser(vcp, inp);
  
      lock_ObtainMutex(&amp;fidp-&gt;mx);
      scp = fidp-&gt;scp;
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code == 0) {
!         if (whence == 1) {
              /* offset from current offset */
              offset += fidp-&gt;offset;
!         }
!         else if (whence == 2) {
              /* offset from current EOF */
              offset += scp-&gt;length.LowPart;
!         }
          fidp-&gt;offset = offset;
          smb_SetSMBParm(outp, 0, offset &amp; 0xffff);
          smb_SetSMBParm(outp, 1, (offset&gt;&gt;16) &amp; 0xffff);
          smb_SetSMBDataLength(outp, 0);
      }
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
      lock_ReleaseMutex(&amp;fidp-&gt;mx);
      smb_ReleaseFID(fidp);
      cm_ReleaseUser(userp);
***************
*** 5921,5927 ****
   * be more than one request.
   */
  void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
! 	NCB *ncbp, raw_write_cont_t *rwcp)
  {
      smb_dispatch_t *dp;
      smb_t *smbp;
--- 6107,6113 ----
   * be more than one request.
   */
  void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
!                         NCB *ncbp, raw_write_cont_t *rwcp)
  {
      smb_dispatch_t *dp;
      smb_t *smbp;
***************
*** 5933,6157 ****
      int temp;
      unsigned char *tp;
      unsigned short errCode;
! 	unsigned long NTStatus;
      int noSend;
      unsigned char errClass;
! 	unsigned int oldGen;
! 	DWORD oldTime, newTime;
  
! 	/* get easy pointer to the data */
! 	smbp = (smb_t *) inp-&gt;data;
  
! 	if (!(outp-&gt;flags &amp; SMB_PACKETFLAG_SUSPENDED)) {
          /* setup the basic parms for the initial request in the packet */
! 		inp-&gt;inCom = smbp-&gt;com;
          inp-&gt;wctp = &amp;smbp-&gt;wct;
          inp-&gt;inCount = 0;
! 		inp-&gt;ncb_length = ncbp-&gt;ncb_length;
! 	}
      noSend = 0;
  
! 	/* Sanity check */
! 	if (ncbp-&gt;ncb_length &lt; offsetof(struct smb, vdata)) {
! 		/* log it and discard it */
! #ifndef DJGPP
! 		HANDLE h;
! 		char *ptbuf[1];
! 		char s[100];
! 		h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 		sprintf(s, "SMB message too short, len %d", ncbp-&gt;ncb_length);
! 		ptbuf[0] = s;
! 		ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
! 			1, ncbp-&gt;ncb_length, ptbuf, inp);
! 		DeregisterEventSource(h);
  #else /* DJGPP */
          osi_Log1(smb_logp, "SMB message too short, len %d", ncbp-&gt;ncb_length);
  #endif /* !DJGPP */
! 		return;
! 	}
  
! 	/* We are an ongoing op */
! 	thrd_Increment(&amp;ongoingOps);
  
      /* set up response packet for receiving output */
! 	if (!(outp-&gt;flags &amp; SMB_PACKETFLAG_SUSPENDED))
          smb_FormatResponsePacket(vcp, inp, outp);
      outWctp = outp-&gt;wctp;
  
! 	/* Remember session generation number and time */
! 	oldGen = sessionGen;
! 	oldTime = GetCurrentTime();
  
! 	while(inp-&gt;inCom != 0xff) {
          dp = &amp;smb_dispatchTable[inp-&gt;inCom];
  
! 		if (outp-&gt;flags &amp; SMB_PACKETFLAG_SUSPENDED) {
! 			outp-&gt;flags &amp;= ~SMB_PACKETFLAG_SUSPENDED;
! 			code = outp-&gt;resumeCode;
! 			goto resume;
! 		}
  
          /* process each request in the packet; inCom, wctp and inCount
           * are already set up.
           */
! 		osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp-&gt;inCom,
!                  ncbp-&gt;ncb_lsn);
  
! 		/* now do the dispatch */
! 		/* start by formatting the response record a little, as a default */
          if (dp-&gt;flags &amp; SMB_DISPATCHFLAG_CHAINED) {
! 			outWctp[0] = 2;
              outWctp[1] = 0xff;	/* no operation */
              outWctp[2] = 0;		/* padding */
              outWctp[3] = 0;
              outWctp[4] = 0;
          }
! 		else {
! 			/* not a chained request, this is a more reasonable default */
              outWctp[0] = 0;	/* wct of zero */
              outWctp[1] = 0;	/* and bcc (word) of zero */
              outWctp[2] = 0;
! 		}   
  
! 		/* once set, stays set.  Doesn't matter, since we never chain
           * "no response" calls.
           */
! 		if (dp-&gt;flags &amp; SMB_DISPATCHFLAG_NORESPONSE)
              noSend = 1;
  
          if (dp-&gt;procp) {
! 			/* we have a recognized operation */
  
! 			if (inp-&gt;inCom == 0x1d)
! 				/* Raw Write */
! 				code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
!                                                 rwcp);
! 			else {
! 					osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp-&gt;inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp-&gt;lana,vcp-&gt;lsn);
! 					osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp-&gt;inCom)),vcp,vcp-&gt;lana,vcp-&gt;lsn);
! 					code = (*(dp-&gt;procp)) (vcp, inp, outp);
! 					osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
! 					osi_Log1(smb_logp,"Dispatch return  code[%d]",(code==0)?0:code-CM_ERROR_BASE);
!             }
! 
! 			if (oldGen != sessionGen) {
! #ifndef DJGPP
! 				HANDLE h;
! 				char *ptbuf[1];
! 				char s[100];
! 				newTime = GetCurrentTime();
! 				h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 				sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
!                         newTime - oldTime, ncbp-&gt;ncb_length);
! 				ptbuf[0] = s;
! 				ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
!                             1005, NULL, 1, ncbp-&gt;ncb_length, ptbuf, smbp);
! 				DeregisterEventSource(h);
  #endif /* !DJGPP */
! 				osi_Log1(smb_logp, "Pkt straddled session startup, "
!                          "ncb length %d", ncbp-&gt;ncb_length);
! 			}
          }
          else {
! 			/* bad opcode, fail the request, after displaying it */
! #ifdef NOTSERVICE
              smb_LogPacket(inp);
! #endif  /* NOTSERVICE */
  
  #ifndef DJGPP
! 			if (showErrors) {
! 				sprintf(tbuffer, "Received bad SMB req 0x%x", inp-&gt;inCom);
                  code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
!                                      MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
!                 if (code == IDCANCEL) showErrors = 0;
! 			}
  #endif /* DJGPP */
              code = CM_ERROR_BADOP;
          }
  
! 		/* catastrophic failure:  log as much as possible */
! 		if (code == CM_ERROR_BADSMB) {
  #ifndef DJGPP
! 			HANDLE h;
! 			char *ptbuf[1];
! 			char s[100];
  
! 			osi_Log1(smb_logp,
                        "Invalid SMB, ncb_length %d",
                        ncbp-&gt;ncb_length);
  
! 			h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 			sprintf(s, "Invalid SMB message, length %d",
                       ncbp-&gt;ncb_length);
! 			ptbuf[0] = s;
! 			ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
                           1, ncbp-&gt;ncb_length, ptbuf, smbp);
! 			DeregisterEventSource(h);
! #ifdef NOTSERVICE
              smb_LogPacket(inp);
! #endif /* NOTSERVICE */
  #endif /* !DJGPP */
              osi_Log1(smb_logp, "Invalid SMB message, length %d",
                       ncbp-&gt;ncb_length);
  
! 			code = CM_ERROR_INVAL;
! 		}
  
! 		if (outp-&gt;flags &amp; SMB_PACKETFLAG_NOSEND) {
! 			thrd_Decrement(&amp;ongoingOps);
! 			return;
! 		}
  
        resume:
! 		/* now, if we failed, turn the current response into an empty
           * one, and fill in the response packet's error code.
           */
! 		if (code) {
! 			if (vcp-&gt;flags &amp; SMB_VCFLAG_STATUS32) {
! 				smb_MapNTError(code, &amp;NTStatus);
! 				outWctp = outp-&gt;wctp;
! 				smbp = (smb_t *) &amp;outp-&gt;data;
! 				if (code != CM_ERROR_PARTIALWRITE
! 				    &amp;&amp; code != CM_ERROR_BUFFERTOOSMALL 
!                     &amp;&amp; code != CM_ERROR_GSSCONTINUE) {
! 					/* nuke wct and bcc.  For a partial
! 					 * write or an in-process authentication handshake, 
                       * assume they're OK.
! 					 */
! 					*outWctp++ = 0;
! 					*outWctp++ = 0;
! 					*outWctp++ = 0;
! 				}
! 				smbp-&gt;rcls = (unsigned char) (NTStatus &amp; 0xff);
! 				smbp-&gt;reh = (unsigned char) ((NTStatus &gt;&gt; 8) &amp; 0xff);
! 				smbp-&gt;errLow = (unsigned char) ((NTStatus &gt;&gt; 16) &amp; 0xff);
! 				smbp-&gt;errHigh = (unsigned char) ((NTStatus &gt;&gt; 24) &amp; 0xff);
! 				smbp-&gt;flg2 |= 0x4000;
! 				break;
! 			}
! 			else {
                  smb_MapCoreError(code, vcp, &amp;errCode, &amp;errClass);
! 				outWctp = outp-&gt;wctp;
! 				smbp = (smb_t *) &amp;outp-&gt;data;
! 				if (code != CM_ERROR_PARTIALWRITE) {
! 					/* nuke wct and bcc.  For a partial
! 					 * write, assume they're OK.
! 					 */
! 					*outWctp++ = 0;
! 					*outWctp++ = 0;
! 					*outWctp++ = 0;
! 				}
! 				smbp-&gt;errLow = (unsigned char) (errCode &amp; 0xff);
! 				smbp-&gt;errHigh = (unsigned char) ((errCode &gt;&gt; 8) &amp; 0xff);
                  smbp-&gt;rcls = errClass;
! 				break;
! 			}
! 		}	/* error occurred */
!                 
          /* if we're here, we've finished one request.  Look to see if
! 		 * this is a chained opcode.  If it is, setup things to process
! 		 * the chained request, and setup the output buffer to hold the
! 		 * chained response.  Start by finding the next input record.
           */
          if (!(dp-&gt;flags &amp; SMB_DISPATCHFLAG_CHAINED))
              break;		/* not a chained req */
--- 6119,6350 ----
      int temp;
      unsigned char *tp;
      unsigned short errCode;
!     unsigned long NTStatus;
      int noSend;
      unsigned char errClass;
!     unsigned int oldGen;
!     DWORD oldTime, newTime;
  
!     /* get easy pointer to the data */
!     smbp = (smb_t *) inp-&gt;data;
  
!     if (!(outp-&gt;flags &amp; SMB_PACKETFLAG_SUSPENDED)) {
          /* setup the basic parms for the initial request in the packet */
!         inp-&gt;inCom = smbp-&gt;com;
          inp-&gt;wctp = &amp;smbp-&gt;wct;
          inp-&gt;inCount = 0;
!         inp-&gt;ncb_length = ncbp-&gt;ncb_length;
!     }
      noSend = 0;
  
!     /* Sanity check */
!     if (ncbp-&gt;ncb_length &lt; offsetof(struct smb, vdata)) {
!         /* log it and discard it */
! #ifndef DJGPP
!         HANDLE h;
!         char *ptbuf[1];
!         char s[100];
!         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!         sprintf(s, "SMB message too short, len %d", ncbp-&gt;ncb_length);
!         ptbuf[0] = s;
!         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
!                      1, ncbp-&gt;ncb_length, ptbuf, inp);
!         DeregisterEventSource(h);
  #else /* DJGPP */
          osi_Log1(smb_logp, "SMB message too short, len %d", ncbp-&gt;ncb_length);
  #endif /* !DJGPP */
!         return;
!     }
  
!     /* We are an ongoing op */
!     thrd_Increment(&amp;ongoingOps);
  
      /* set up response packet for receiving output */
!     if (!(outp-&gt;flags &amp; SMB_PACKETFLAG_SUSPENDED))
          smb_FormatResponsePacket(vcp, inp, outp);
      outWctp = outp-&gt;wctp;
  
!     /* Remember session generation number and time */
!     oldGen = sessionGen;
!     oldTime = GetCurrentTime();
  
!     while (inp-&gt;inCom != 0xff) {
          dp = &amp;smb_dispatchTable[inp-&gt;inCom];
  
!         if (outp-&gt;flags &amp; SMB_PACKETFLAG_SUSPENDED) {
!             outp-&gt;flags &amp;= ~SMB_PACKETFLAG_SUSPENDED;
!             code = outp-&gt;resumeCode;
!             goto resume;
!         }
  
          /* process each request in the packet; inCom, wctp and inCount
           * are already set up.
           */
!         osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp-&gt;inCom,
!                   ncbp-&gt;ncb_lsn);
  
!         /* now do the dispatch */
!         /* start by formatting the response record a little, as a default */
          if (dp-&gt;flags &amp; SMB_DISPATCHFLAG_CHAINED) {
!             outWctp[0] = 2;
              outWctp[1] = 0xff;	/* no operation */
              outWctp[2] = 0;		/* padding */
              outWctp[3] = 0;
              outWctp[4] = 0;
          }
!         else {
!             /* not a chained request, this is a more reasonable default */
              outWctp[0] = 0;	/* wct of zero */
              outWctp[1] = 0;	/* and bcc (word) of zero */
              outWctp[2] = 0;
!         }   
  
!         /* once set, stays set.  Doesn't matter, since we never chain
           * "no response" calls.
           */
!         if (dp-&gt;flags &amp; SMB_DISPATCHFLAG_NORESPONSE)
              noSend = 1;
  
          if (dp-&gt;procp) {
!             /* we have a recognized operation */
  
!             if (inp-&gt;inCom == 0x1d)
!                 /* Raw Write */
!                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
!                                                  rwcp);
!             else {
!                 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp-&gt;inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp-&gt;lana,vcp-&gt;lsn);
!                 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp-&gt;inCom)),vcp,vcp-&gt;lana,vcp-&gt;lsn);
!                 code = (*(dp-&gt;procp)) (vcp, inp, outp);
!                 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
!                 osi_Log1(smb_logp,"Dispatch return  code[%d]",(code==0)?0:code-CM_ERROR_BASE);
! #ifdef LOG_PACKET
!                 if ( code == CM_ERROR_BADSMB ||
!                      code == CM_ERROR_BADOP )
!                 smb_LogPacket(inp);
! #endif /* LOG_PACKET */
!             }   
! 
!             if (oldGen != sessionGen) {
! #ifndef DJGPP
!                 HANDLE h;
!                 char *ptbuf[1];
!                 char s[100];
!                 newTime = GetCurrentTime();
!                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!                 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
!                          newTime - oldTime, ncbp-&gt;ncb_length);
!                 ptbuf[0] = s;
!                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
!                              1005, NULL, 1, ncbp-&gt;ncb_length, ptbuf, smbp);
!                 DeregisterEventSource(h);
  #endif /* !DJGPP */
!                 osi_Log1(smb_logp, "Pkt straddled session startup, "
!                           "ncb length %d", ncbp-&gt;ncb_length);
!             }
          }
          else {
!             /* bad opcode, fail the request, after displaying it */
!             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp-&gt;inCom);
! #ifdef LOG_PACKET
              smb_LogPacket(inp);
! #endif  /* LOG_PACKET */
  
  #ifndef DJGPP
!             if (showErrors) {
!                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp-&gt;inCom);
                  code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
!                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
!                 if (code == IDCANCEL) 
!                     showErrors = 0;
!             }
  #endif /* DJGPP */
              code = CM_ERROR_BADOP;
          }
  
!         /* catastrophic failure:  log as much as possible */
!         if (code == CM_ERROR_BADSMB) {
  #ifndef DJGPP
!             HANDLE h;
!             char *ptbuf[1];
!             char s[100];
  
!             osi_Log1(smb_logp,
                        "Invalid SMB, ncb_length %d",
                        ncbp-&gt;ncb_length);
  
!             h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!             sprintf(s, "Invalid SMB message, length %d",
                       ncbp-&gt;ncb_length);
!             ptbuf[0] = s;
!             ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
                           1, ncbp-&gt;ncb_length, ptbuf, smbp);
!             DeregisterEventSource(h);
! #ifdef LOG_PACKET
              smb_LogPacket(inp);
! #endif /* LOG_PACKET */
  #endif /* !DJGPP */
              osi_Log1(smb_logp, "Invalid SMB message, length %d",
                       ncbp-&gt;ncb_length);
  
!             code = CM_ERROR_INVAL;
!         }
  
!         if (outp-&gt;flags &amp; SMB_PACKETFLAG_NOSEND) {
!             thrd_Decrement(&amp;ongoingOps);
!             return;
!         }
  
        resume:
!         /* now, if we failed, turn the current response into an empty
           * one, and fill in the response packet's error code.
           */
!         if (code) {
!             if (vcp-&gt;flags &amp; SMB_VCFLAG_STATUS32) {
!                 smb_MapNTError(code, &amp;NTStatus);
!                 outWctp = outp-&gt;wctp;
!                 smbp = (smb_t *) &amp;outp-&gt;data;
!                 if (code != CM_ERROR_PARTIALWRITE
!                      &amp;&amp; code != CM_ERROR_BUFFERTOOSMALL 
!                      &amp;&amp; code != CM_ERROR_GSSCONTINUE) {
!                     /* nuke wct and bcc.  For a partial
!                      * write or an in-process authentication handshake, 
                       * assume they're OK.
!                      */
!                     *outWctp++ = 0;
!                     *outWctp++ = 0;
!                     *outWctp++ = 0;
!                 }
!                 smbp-&gt;rcls = (unsigned char) (NTStatus &amp; 0xff);
!                 smbp-&gt;reh = (unsigned char) ((NTStatus &gt;&gt; 8) &amp; 0xff);
!                 smbp-&gt;errLow = (unsigned char) ((NTStatus &gt;&gt; 16) &amp; 0xff);
!                 smbp-&gt;errHigh = (unsigned char) ((NTStatus &gt;&gt; 24) &amp; 0xff);
!                 smbp-&gt;flg2 |= 0x4000;
!                 break;
!             }
!             else {
                  smb_MapCoreError(code, vcp, &amp;errCode, &amp;errClass);
!                 outWctp = outp-&gt;wctp;
!                 smbp = (smb_t *) &amp;outp-&gt;data;
!                 if (code != CM_ERROR_PARTIALWRITE) {
!                     /* nuke wct and bcc.  For a partial
!                      * write, assume they're OK.
!                      */
!                     *outWctp++ = 0;
!                     *outWctp++ = 0;
!                     *outWctp++ = 0;
!                 }
!                 smbp-&gt;errLow = (unsigned char) (errCode &amp; 0xff);
!                 smbp-&gt;errHigh = (unsigned char) ((errCode &gt;&gt; 8) &amp; 0xff);
                  smbp-&gt;rcls = errClass;
!                 break;
!             }
!         }	/* error occurred */
! 
          /* if we're here, we've finished one request.  Look to see if
!          * this is a chained opcode.  If it is, setup things to process
!          * the chained request, and setup the output buffer to hold the
!          * chained response.  Start by finding the next input record.
           */
          if (!(dp-&gt;flags &amp; SMB_DISPATCHFLAG_CHAINED))
              break;		/* not a chained req */
***************
*** 6168,6174 ****
  
          /* and now append the next output request to the end of this
           * last request.  Begin by finding out where the last response
! 		 * ends, since that's where we'll put our new response.
           */
          outWctp = outp-&gt;wctp;		/* ptr to out parameters */
          osi_assert (outWctp[0] &gt;= 2);	/* need this for all chained requests */
--- 6361,6367 ----
  
          /* and now append the next output request to the end of this
           * last request.  Begin by finding out where the last response
!          * ends, since that's where we'll put our new response.
           */
          outWctp = outp-&gt;wctp;		/* ptr to out parameters */
          osi_assert (outWctp[0] &gt;= 2);	/* need this for all chained requests */
***************
*** 6176,6210 ****
          tp = outWctp + nparms + 1;	/* now points to bcc field */
          nbytes = tp[0] + (tp[1] &lt;&lt; 8);	/* # of data bytes */
          tp += 2 /* for the count itself */ + nbytes;
! 		/* tp now points to the new output record; go back and patch the
           * second parameter (off2) to point to the new record.
           */
! 		temp = (unsigned int)tp - ((unsigned int) outp-&gt;data);
          outWctp[3] = (unsigned char) (temp &amp; 0xff);
          outWctp[4] = (unsigned char) ((temp &gt;&gt; 8) &amp; 0xff);
          outWctp[2] = 0;	/* padding */
          outWctp[1] = inp-&gt;inCom;	/* next opcode */
  
! 		/* finally, setup for the next iteration */
          outp-&gt;wctp = tp;
! 		outWctp = tp;
! 	}	/* while loop over all requests in the packet */
  
! 	/* done logging out, turn off logging-out flag */
! 	if (!(inp-&gt;flags &amp; SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
! 		vcp-&gt;justLoggedOut = NULL;
! 		if (loggedOut) {
! 			loggedOut = 0;
! 			free(loggedOutName);
! 			loggedOutName = NULL;
! 			smb_ReleaseUID(loggedOutUserp);
! 			loggedOutUserp = NULL;
! 		}
! 	}
   
      /* now send the output packet, and return */
      if (!noSend)
! 		smb_SendPacket(vcp, outp);
  	thrd_Decrement(&amp;ongoingOps);
  
  	if (!(vcp-&gt;flags &amp; SMB_VCFLAG_ALREADYDEAD)) {
--- 6369,6403 ----
          tp = outWctp + nparms + 1;	/* now points to bcc field */
          nbytes = tp[0] + (tp[1] &lt;&lt; 8);	/* # of data bytes */
          tp += 2 /* for the count itself */ + nbytes;
!         /* tp now points to the new output record; go back and patch the
           * second parameter (off2) to point to the new record.
           */
!         temp = (unsigned int)tp - ((unsigned int) outp-&gt;data);
          outWctp[3] = (unsigned char) (temp &amp; 0xff);
          outWctp[4] = (unsigned char) ((temp &gt;&gt; 8) &amp; 0xff);
          outWctp[2] = 0;	/* padding */
          outWctp[1] = inp-&gt;inCom;	/* next opcode */
  
!         /* finally, setup for the next iteration */
          outp-&gt;wctp = tp;
!         outWctp = tp;
!     }	/* while loop over all requests in the packet */
  
!     /* done logging out, turn off logging-out flag */
!     if (!(inp-&gt;flags &amp; SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
!         vcp-&gt;justLoggedOut = NULL;
!         if (loggedOut) {
!             loggedOut = 0;
!             free(loggedOutName);
!             loggedOutName = NULL;
!             smb_ReleaseUID(loggedOutUserp);
!             loggedOutUserp = NULL;
!         }
!     }
   
      /* now send the output packet, and return */
      if (!noSend)
!         smb_SendPacket(vcp, outp);
  	thrd_Decrement(&amp;ongoingOps);
  
  	if (!(vcp-&gt;flags &amp; SMB_VCFLAG_ALREADYDEAD)) {
***************
*** 6214,6225 ****
                        "Replacing active_vcp %x with %x", active_vcp, vcp);
          }
          smb_HoldVC(vcp);
! 		active_vcp = vcp;
! 		last_msg_time = GetCurrentTime();
! 	}
  	else if (active_vcp == vcp) {
!         smb_ReleaseVC(active_vcp);
! 		active_vcp = NULL;
      }
  
      return;
--- 6407,6418 ----
                        "Replacing active_vcp %x with %x", active_vcp, vcp);
          }
          smb_HoldVC(vcp);
!             active_vcp = vcp;
!             last_msg_time = GetCurrentTime();
! 	}       
  	else if (active_vcp == vcp) {
!             smb_ReleaseVC(active_vcp);
!             active_vcp = NULL;
      }
  
      return;
***************
*** 6233,6246 ****
   */
  void smb_ClientWaiter(void *parmp)
  {
! 	DWORD code;
      int   idx;
  
! 	while (1) {
! 		code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
! 					      FALSE, INFINITE);
! 		if (code == WAIT_OBJECT_0)
! 			continue;
  
          /* error checking */
          if (code &gt;= WAIT_ABANDONED_0 &amp;&amp; code &lt; (WAIT_ABANDONED_0 + numNCBs))
--- 6426,6439 ----
   */
  void smb_ClientWaiter(void *parmp)
  {
!     DWORD code;
      int   idx;
  
!     while (1) {
!         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
!                                                  FALSE, INFINITE);
!         if (code == WAIT_OBJECT_0)
!             continue;
  
          /* error checking */
          if (code &gt;= WAIT_ABANDONED_0 &amp;&amp; code &lt; (WAIT_ABANDONED_0 + numNCBs))
***************
*** 6275,6283 ****
              osi_assert(0);
          }
          
! 		thrd_ResetEvent(NCBevents[idx]);
! 		thrd_SetEvent(NCBreturns[0][idx]);
! 	}
  }
  #endif /* !DJGPP */
  
--- 6468,6476 ----
              osi_assert(0);
          }
          
!         thrd_ResetEvent(NCBevents[idx]);
!         thrd_SetEvent(NCBreturns[0][idx]);
!     }
  }
  #endif /* !DJGPP */
  
***************
*** 6287,6305 ****
   */
  void smb_ServerWaiter(void *parmp)
  {
! 	DWORD code;
      int idx_session, idx_NCB;
! 	NCB *ncbp;
  #ifdef DJGPP
      dos_ptr dos_ncb;
  #endif /* DJGPP */
  
! 	while (1) {
! 		/* Get a session */
! 		code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
!                                                    FALSE, INFINITE);
! 		if (code == WAIT_OBJECT_0)
! 			continue;
  
          if (code &gt;= WAIT_ABANDONED_0 &amp;&amp; code &lt; (WAIT_ABANDONED_0 + numSessions))
          {
--- 6480,6498 ----
   */
  void smb_ServerWaiter(void *parmp)
  {
!     DWORD code;
      int idx_session, idx_NCB;
!     NCB *ncbp;
  #ifdef DJGPP
      dos_ptr dos_ncb;
  #endif /* DJGPP */
  
!     while (1) {
!         /* Get a session */
!         code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
!                                                  FALSE, INFINITE);
!         if (code == WAIT_OBJECT_0)
!             continue;
  
          if (code &gt;= WAIT_ABANDONED_0 &amp;&amp; code &lt; (WAIT_ABANDONED_0 + numSessions))
          {
***************
*** 6335,6344 ****
  
  		/* Get an NCB */
        NCBretry:
! 		code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
!                                                    FALSE, INFINITE);
! 		if (code == WAIT_OBJECT_0)
! 			goto NCBretry;
  
          /* error checking */
          if (code &gt;= WAIT_ABANDONED_0 &amp;&amp; code &lt; (WAIT_ABANDONED_0 + numNCBs))
--- 6528,6537 ----
  
  		/* Get an NCB */
        NCBretry:
!         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
!                                                  FALSE, INFINITE);
!         if (code == WAIT_OBJECT_0)
!             goto NCBretry;
  
          /* error checking */
          if (code &gt;= WAIT_ABANDONED_0 &amp;&amp; code &lt; (WAIT_ABANDONED_0 + numNCBs))
***************
*** 6373,6402 ****
              osi_assert(0);
          }
  
! 		/* Link them together */
! 		NCBsessions[idx_NCB] = idx_session;
  
! 		/* Fire it up */
! 		ncbp = NCBs[idx_NCB];
  #ifdef DJGPP
          dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
! 		ncbp-&gt;ncb_lsn = (unsigned char) LSNs[idx_session];
! 		ncbp-&gt;ncb_command = NCBRECV | ASYNCH;
! 		ncbp-&gt;ncb_lana_num = lanas[idx_session];
! #ifndef DJGPP
! 		ncbp-&gt;ncb_buffer = (unsigned char *) bufs[idx_NCB];
! 		ncbp-&gt;ncb_event = NCBevents[idx_NCB];
! 		ncbp-&gt;ncb_length = SMB_PACKETSIZE;
! 		Netbios(ncbp);
  #else /* DJGPP */
! 		ncbp-&gt;ncb_buffer = bufs[idx_NCB]-&gt;dos_pkt;
!                 ((smb_ncb_t*)ncbp)-&gt;orig_pkt = bufs[idx_NCB];
! 		ncbp-&gt;ncb_event = NCBreturns[0][idx_NCB];
! 		ncbp-&gt;ncb_length = SMB_PACKETSIZE;
! 		Netbios(ncbp, dos_ncb);
  #endif /* !DJGPP */
! 	}
  }
  
  /*
--- 6566,6595 ----
              osi_assert(0);
          }
  
!         /* Link them together */
!         NCBsessions[idx_NCB] = idx_session;
  
!         /* Fire it up */
!         ncbp = NCBs[idx_NCB];
  #ifdef DJGPP
          dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
!         ncbp-&gt;ncb_lsn = (unsigned char) LSNs[idx_session];
!         ncbp-&gt;ncb_command = NCBRECV | ASYNCH;
!         ncbp-&gt;ncb_lana_num = lanas[idx_session];
! #ifndef DJGPP
!         ncbp-&gt;ncb_buffer = (unsigned char *) bufs[idx_NCB];
!         ncbp-&gt;ncb_event = NCBevents[idx_NCB];
!         ncbp-&gt;ncb_length = SMB_PACKETSIZE;
!         Netbios(ncbp);
  #else /* DJGPP */
!         ncbp-&gt;ncb_buffer = bufs[idx_NCB]-&gt;dos_pkt;
!         ((smb_ncb_t*)ncbp)-&gt;orig_pkt = bufs[idx_NCB];
!         ncbp-&gt;ncb_event = NCBreturns[0][idx_NCB];
!         ncbp-&gt;ncb_length = SMB_PACKETSIZE;
!         Netbios(ncbp, dos_ncb);
  #endif /* !DJGPP */
!     }
  }
  
  /*
***************
*** 6411,6452 ****
   */
  void smb_Server(VOID *parmp)
  {
! 	int myIdx = (int) parmp;
! 	NCB *ncbp;
! 	NCB *outncbp;
      smb_packet_t *bufp;
! 	smb_packet_t *outbufp;
      DWORD code, rcode;
      int idx_NCB, idx_session;
! 	UCHAR rc;
! 	smb_vc_t *vcp = NULL;
! 	smb_t *smbp;
  #ifdef DJGPP
      dos_ptr dos_ncb;
  #endif /* DJGPP */
  
! 	outncbp = GetNCB();
! 	outbufp = GetPacket();
! 	outbufp-&gt;ncbp = outncbp;
! 
! 	while (1) {
! #ifndef NOEXPIRE
! 		/* check for demo expiration */
! 		{
! 			unsigned long tod = time((void *) 0);
! 			if (tod &gt; EXPIREDATE) {
! 				(*smb_MBfunc)(NULL, "AFS demo expiration",
! 					   "afsd dispatcher",
! 					   MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
! 				trhd_Exit(1);
! 			}
! 		}
! #endif /* !NOEXPIRE */
! 
! 		code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
!                                                    FALSE, INFINITE);
! 		if (code == WAIT_OBJECT_0) {
! 			continue;
          }
  
          /* error checking */
--- 6604,6632 ----
   */
  void smb_Server(VOID *parmp)
  {
!     int myIdx = (int) parmp;
!     NCB *ncbp;
!     NCB *outncbp;
      smb_packet_t *bufp;
!     smb_packet_t *outbufp;
      DWORD code, rcode;
      int idx_NCB, idx_session;
!     UCHAR rc;
!     smb_vc_t *vcp = NULL;
!     smb_t *smbp;
  #ifdef DJGPP
      dos_ptr dos_ncb;
  #endif /* DJGPP */
  
!     outncbp = GetNCB();
!     outbufp = GetPacket();
!     outbufp-&gt;ncbp = outncbp;
! 
!     while (1) {
!         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
!                                                  FALSE, INFINITE);
!         if (code == WAIT_OBJECT_0) {
!             continue;
          }
  
          /* error checking */
***************
*** 6482,6664 ****
              osi_assert(0);
          }
  
! 		ncbp = NCBs[idx_NCB];
  #ifdef DJGPP
!                 dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
! 		idx_session = NCBsessions[idx_NCB];
! 		rc = ncbp-&gt;ncb_retcode;
  
! 		if (rc != NRC_PENDING &amp;&amp; rc != NRC_GOODRET)
! 			osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
  
! 		switch (rc) {
! 			case NRC_GOODRET: break;
  
! 			case NRC_PENDING:
! 				/* Can this happen? Or is it just my
! 				 * UNIX paranoia? 
!                  */
! 				continue;
  
! 			case NRC_SCLOSED:
! 			case NRC_SNUMOUT:
! 				/* Client closed session */
!                 if (reportSessionStartups) 
!                 {
!                     osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
                  }
! 				dead_sessions[idx_session] = TRUE;
!                 if (vcp)
!                     smb_ReleaseVC(vcp);
! 				vcp = smb_FindVC(ncbp-&gt;ncb_lsn, 0, lanas[idx_session]);
! 				/* Should also release vcp.  [done] 2004-05-11 jaltman
!                  * Also, should do
! 				 * sanity check that all TID's are gone. 
!                  *
!                  * TODO: check if we could use LSNs[idx_session] instead, 
!                  * also cleanup after dead vcp 
!                  */
!                 if (vcp) {
!                     if (dead_vcp)
!                         osi_Log1(smb_logp,
!                                   "dead_vcp already set, %x",
!                                   dead_vcp);
!                     if (!dead_vcp &amp;&amp; !(vcp-&gt;flags &amp; SMB_VCFLAG_ALREADYDEAD)) {
!                         osi_Log2(smb_logp,
!                                   "setting dead_vcp %x, user struct %x",
!                                   vcp, vcp-&gt;usersp);
!                         smb_HoldVC(vcp);
!                         dead_vcp = vcp;
!                         vcp-&gt;flags |= SMB_VCFLAG_ALREADYDEAD;
!                     }
!                     if (vcp-&gt;justLoggedOut) {
!                         loggedOut = 1;
!                         loggedOutTime = vcp-&gt;logoffTime;
!                         loggedOutName =
!                             strdup(vcp-&gt;justLoggedOut-&gt;unp-&gt;name);
!                         loggedOutUserp = vcp-&gt;justLoggedOut;
!                         lock_ObtainWrite(&amp;smb_rctLock);
!                         loggedOutUserp-&gt;refCount++;
!                         lock_ReleaseWrite(&amp;smb_rctLock);
!                     }
                  }
! 				goto doneWithNCB;
  
! 			case NRC_INCOMP:
! 				/* Treat as transient error */
! 				{
! #ifndef DJGPP
! 					EVENT_HANDLE h;
! 					char *ptbuf[1];
! 					char s[100];
! 
! 					h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 					sprintf(s, "SMB message incomplete, length %d",
!                             ncbp-&gt;ncb_length);
! 					ptbuf[0] = s;
! 					ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
!                                 1001, NULL, 1,
!                                 ncbp-&gt;ncb_length, ptbuf,
!                                 bufp);
! 					DeregisterEventSource(h);
  #endif /* !DJGPP */
! 					osi_Log1(smb_logp,
!                               "dispatch smb recv failed, message incomplete, ncb_length %d",
!                               ncbp-&gt;ncb_length);
!                     osi_Log1(smb_logp,
!                               "SMB message incomplete, "
!                               "length %d", ncbp-&gt;ncb_length);
  
! 					/*
! 					 * We used to discard the packet.
! 					 * Instead, try handling it normally.
! 					 *
!                      continue;
! 		 			 */
! 					break;
! 				}
! 
! 			default:
! 				/* A weird error code.  Log it, sleep, and
! 				 * continue. */
! 				if (vcp &amp;&amp; vcp-&gt;errorCount++ &gt; 3) {
!                     osi_Log2(smb_logp, "session [ %d ] closed, vcp-&gt;errorCount = %d", idx_session, vcp-&gt;errorCount);
! 					dead_sessions[idx_session] = TRUE;
!                 }
! 				else {
! 					thrd_Sleep(1000);
! 					thrd_SetEvent(SessionEvents[idx_session]);
! 				}
! 				continue;
! 		}
! 
! 		/* Success, so now dispatch on all the data in the packet */
! 
! 		smb_concurrentCalls++;
! 		if (smb_concurrentCalls &gt; smb_maxObsConcurrentCalls)
! 			smb_maxObsConcurrentCalls = smb_concurrentCalls;
  
          if (vcp)
              smb_ReleaseVC(vcp);
! 		vcp = smb_FindVC(ncbp-&gt;ncb_lsn, 0, ncbp-&gt;ncb_lana_num);
          /*
! 		* If at this point vcp is NULL (implies that packet was invalid)
! 		* then we are in big trouble. This means either :
! 		*   a) we have the wrong NCB.
! 		*   b) Netbios screwed up the call.
! 		* Obviously this implies that 
! 		*   ( LSNs[idx_session] != ncbp-&gt;ncb_lsn ||
! 		*   lanas[idx_session] != ncbp-&gt;ncb_lana_num )
! 		* Either way, we can't do anything with this packet.
! 		* Log, sleep and resume.
! 		*/
! 		if(!vcp) {
! 			HANDLE h;
! 			char buf[1000];
! 			char *ptbuf[1];
! 
! 			sprintf(buf,
! 				"Bad vcp!! : "
! 				"LSNs[idx_session]=[%d],"
! 				"lanas[idx_session]=[%d],"
! 				"ncbp-&gt;ncb_lsn=[%d],"
! 				"ncbp-&gt;ncb_lana_num=[%d]",
! 				LSNs[idx_session],
! 				lanas[idx_session],
! 				ncbp-&gt;ncb_lsn,
! 				ncbp-&gt;ncb_lana_num);
! 
! 			ptbuf[0] = buf;
! 
! 			h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
! 			if(h) {
! 				ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
! 				DeregisterEventSource(h);
! 			}
! 
! 			/* Also log in the trace log. */
! 			osi_Log4(smb_logp, "Server: BAD VCP!"
! 				"LSNs[idx_session]=[%d],"
! 				"lanas[idx_session]=[%d],"
! 				"ncbp-&gt;ncb_lsn=[%d],"
! 				"ncbp-&gt;ncb_lana_num=[%d]",
! 				LSNs[idx_session],
! 				lanas[idx_session],
! 				ncbp-&gt;ncb_lsn,
! 				ncbp-&gt;ncb_lana_num);
! 
! 			/* thrd_Sleep(1000); Don't bother sleeping */
! 			thrd_SetEvent(SessionEvents[idx_session]);
! 			smb_concurrentCalls--;
! 			continue;
! 		}
  
  
! 		vcp-&gt;errorCount = 0;
! 		bufp = (struct smb_packet *) ncbp-&gt;ncb_buffer;
  #ifdef DJGPP
! 		bufp = ((smb_ncb_t *) ncbp)-&gt;orig_pkt;
          /* copy whole packet to virtual memory */
          /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
          "bufp=0x%x\n",
--- 6662,6843 ----
              osi_assert(0);
          }
  
!         ncbp = NCBs[idx_NCB];
  #ifdef DJGPP
!         dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
!         idx_session = NCBsessions[idx_NCB];
!         rc = ncbp-&gt;ncb_retcode;
  
!         if (rc != NRC_PENDING &amp;&amp; rc != NRC_GOODRET)
!             osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
  
!         switch (rc) {
!         case NRC_GOODRET: break;
  
!         case NRC_PENDING:
!             /* Can this happen? Or is it just my
!              * UNIX paranoia? 
!              */
!             continue;
  
!         case NRC_SCLOSED:
!         case NRC_SNUMOUT:
!             /* Client closed session */
!             if (reportSessionStartups) 
!             {
!                 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
!             }
!             dead_sessions[idx_session] = TRUE;
!             if (vcp)
!                 smb_ReleaseVC(vcp);
!             vcp = smb_FindVC(ncbp-&gt;ncb_lsn, 0, lanas[idx_session]);
!             /* Should also release vcp.  [done] 2004-05-11 jaltman
!              * Also, should do
!              * sanity check that all TID's are gone. 
!              *
!              * TODO: check if we could use LSNs[idx_session] instead, 
!              * also cleanup after dead vcp 
!              */
!             if (vcp) {
!                 if (dead_vcp)
!                     osi_Log1(smb_logp,
!                              "dead_vcp already set, %x",
!                              dead_vcp);
!                 if (!dead_vcp &amp;&amp; !(vcp-&gt;flags &amp; SMB_VCFLAG_ALREADYDEAD)) {
!                     osi_Log2(smb_logp,
!                              "setting dead_vcp %x, user struct %x",
!                              vcp, vcp-&gt;usersp);
!                     smb_HoldVC(vcp);
!                     dead_vcp = vcp;
!                     vcp-&gt;flags |= SMB_VCFLAG_ALREADYDEAD;
                  }
!                 if (vcp-&gt;justLoggedOut) {
!                     loggedOut = 1;
!                     loggedOutTime = vcp-&gt;logoffTime;
!                     loggedOutName = strdup(vcp-&gt;justLoggedOut-&gt;unp-&gt;name);
!                     loggedOutUserp = vcp-&gt;justLoggedOut;
!                     lock_ObtainWrite(&amp;smb_rctLock);
!                     loggedOutUserp-&gt;refCount++;
!                     lock_ReleaseWrite(&amp;smb_rctLock);
                  }
!             }
!             goto doneWithNCB;
  
!         case NRC_INCOMP:
!             /* Treat as transient error */
!             {
! #ifndef DJGPP
!                 EVENT_HANDLE h;
!                 char *ptbuf[1];
!                 char s[100];
! 
!                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!                 sprintf(s, "SMB message incomplete, length %d",
!                          ncbp-&gt;ncb_length);
!                 ptbuf[0] = s;
!                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
!                              1001, NULL, 1,
!                              ncbp-&gt;ncb_length, ptbuf,
!                              bufp);
!                 DeregisterEventSource(h);
  #endif /* !DJGPP */
!                 osi_Log1(smb_logp,
!                           "dispatch smb recv failed, message incomplete, ncb_length %d",
!                           ncbp-&gt;ncb_length);
!                 osi_Log1(smb_logp,
!                           "SMB message incomplete, "
!                           "length %d", ncbp-&gt;ncb_length);
! 
!                 /*
!                  * We used to discard the packet.
!                  * Instead, try handling it normally.
!                  *
!                  continue;
!                  */
!                 break;
!             }
  
!         default:
!             /* A weird error code.  Log it, sleep, and
!             * continue. */
!             if (vcp &amp;&amp; vcp-&gt;errorCount++ &gt; 3) {
!                 osi_Log2(smb_logp, "session [ %d ] closed, vcp-&gt;errorCount = %d", idx_session, vcp-&gt;errorCount);
!                 dead_sessions[idx_session] = TRUE;
!             }
!             else {
!                 thrd_Sleep(1000);
!                 thrd_SetEvent(SessionEvents[idx_session]);
!             }
!             continue;
!         }
! 
!         /* Success, so now dispatch on all the data in the packet */
! 
!         smb_concurrentCalls++;
!         if (smb_concurrentCalls &gt; smb_maxObsConcurrentCalls)
!             smb_maxObsConcurrentCalls = smb_concurrentCalls;
  
          if (vcp)
              smb_ReleaseVC(vcp);
!         vcp = smb_FindVC(ncbp-&gt;ncb_lsn, 0, ncbp-&gt;ncb_lana_num);
          /*
!          * If at this point vcp is NULL (implies that packet was invalid)
!          * then we are in big trouble. This means either :
!          *   a) we have the wrong NCB.
!          *   b) Netbios screwed up the call.
!          * Obviously this implies that 
!          *   ( LSNs[idx_session] != ncbp-&gt;ncb_lsn ||
!          *   lanas[idx_session] != ncbp-&gt;ncb_lana_num )
!          * Either way, we can't do anything with this packet.
!          * Log, sleep and resume.
!          */
!         if(!vcp) {
!             HANDLE h;
!             char buf[1000];
!             char *ptbuf[1];
! 
!             sprintf(buf,
!                      "Bad vcp!! : "
!                      "LSNs[idx_session]=[%d],"
!                      "lanas[idx_session]=[%d],"
!                      "ncbp-&gt;ncb_lsn=[%d],"
!                      "ncbp-&gt;ncb_lana_num=[%d]",
!                      LSNs[idx_session],
!                      lanas[idx_session],
!                      ncbp-&gt;ncb_lsn,
!                      ncbp-&gt;ncb_lana_num);
! 
!             ptbuf[0] = buf;
! 
!             h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
!             if(h) {
!                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
!                 DeregisterEventSource(h);
!             }
  
+             /* Also log in the trace log. */
+             osi_Log4(smb_logp, "Server: BAD VCP!"
+                       "LSNs[idx_session]=[%d],"
+                       "lanas[idx_session]=[%d],"
+                       "ncbp-&gt;ncb_lsn=[%d],"
+                       "ncbp-&gt;ncb_lana_num=[%d]",
+                       LSNs[idx_session],
+                       lanas[idx_session],
+                       ncbp-&gt;ncb_lsn,
+                       ncbp-&gt;ncb_lana_num);
+ 
+             /* thrd_Sleep(1000); Don't bother sleeping */
+             thrd_SetEvent(SessionEvents[idx_session]);
+             smb_concurrentCalls--;
+             continue;
+         }
  
! 
!         vcp-&gt;errorCount = 0;
!         bufp = (struct smb_packet *) ncbp-&gt;ncb_buffer;
  #ifdef DJGPP
!         bufp = ((smb_ncb_t *) ncbp)-&gt;orig_pkt;
          /* copy whole packet to virtual memory */
          /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
          "bufp=0x%x\n",
***************
*** 6666,6729 ****
          fflush(stderr);
          dosmemget(bufp-&gt;dos_pkt, ncbp-&gt;ncb_length, bufp-&gt;data);
  #endif /* DJGPP */
! 		smbp = (smb_t *)bufp-&gt;data;
! 		outbufp-&gt;flags = 0;
  
  #if !defined(DJGPP) &amp;&amp; !defined(AFS_WIN32_ENV)
          __try
          {
  #endif
! 		if (smbp-&gt;com == 0x1d) {
! 			/* Special handling for Write Raw */
! 			raw_write_cont_t rwc;
! 			EVENT_HANDLE rwevent;
!             char eventName[MAX_PATH];
              
!             smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &amp;rwc);
! 			if (rwc.code == 0) {
! 				rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
!                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
!                     osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
! 				ncbp-&gt;ncb_command = NCBRECV | ASYNCH;
! 				ncbp-&gt;ncb_lsn = (unsigned char) vcp-&gt;lsn;
! 				ncbp-&gt;ncb_lana_num = vcp-&gt;lana;
! 				ncbp-&gt;ncb_buffer = rwc.buf;
! 				ncbp-&gt;ncb_length = 65535;
! 				ncbp-&gt;ncb_event = rwevent;
  #ifndef DJGPP
! 				Netbios(ncbp);
  #else
! 				Netbios(ncbp, dos_ncb);
  #endif /* !DJGPP */
! 				rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
! 				thrd_CloseHandle(rwevent);
! 			}
! 			thrd_SetEvent(SessionEvents[idx_session]);
! 			if (rwc.code == 0)
! 				smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &amp;rwc);
! 		} else if (smbp-&gt;com == 0xa0) { 
!             /* 
!              * Serialize the handling for NT Transact 
!              * (defect 11626)
!              */
!             smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
! 			thrd_SetEvent(SessionEvents[idx_session]);
!         } else {
! 			thrd_SetEvent(SessionEvents[idx_session]);
!             /* TODO: what else needs to be serialized? */
! 			smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
! 		}
  #if !defined(DJGPP) &amp;&amp; !defined(AFS_WIN95_ENV)
          }
          __except( smb_ServerExceptionFilter() ) {
          }
  #endif
  
! 		smb_concurrentCalls--;
  
  doneWithNCB:
! 		thrd_SetEvent(NCBavails[idx_NCB]);
! 	}
      if (vcp)
          smb_ReleaseVC(vcp);
  }
--- 6845,6909 ----
          fflush(stderr);
          dosmemget(bufp-&gt;dos_pkt, ncbp-&gt;ncb_length, bufp-&gt;data);
  #endif /* DJGPP */
!         smbp = (smb_t *)bufp-&gt;data;
!         outbufp-&gt;flags = 0;
  
  #if !defined(DJGPP) &amp;&amp; !defined(AFS_WIN32_ENV)
          __try
          {
  #endif
!             if (smbp-&gt;com == 0x1d) {
!                 /* Special handling for Write Raw */
!                 raw_write_cont_t rwc;
!                 EVENT_HANDLE rwevent;
!                 char eventName[MAX_PATH];
              
!                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &amp;rwc);
!                 if (rwc.code == 0) {
!                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
!                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
!                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
!                     ncbp-&gt;ncb_command = NCBRECV | ASYNCH;
!                     ncbp-&gt;ncb_lsn = (unsigned char) vcp-&gt;lsn;
!                     ncbp-&gt;ncb_lana_num = vcp-&gt;lana;
!                     ncbp-&gt;ncb_buffer = rwc.buf;
!                     ncbp-&gt;ncb_length = 65535;
!                     ncbp-&gt;ncb_event = rwevent;
  #ifndef DJGPP
!                     Netbios(ncbp);
  #else
!                     Netbios(ncbp, dos_ncb);
  #endif /* !DJGPP */
!                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
!                     thrd_CloseHandle(rwevent);
!                 }
!                 thrd_SetEvent(SessionEvents[idx_session]);
!                 if (rwc.code == 0)
!                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &amp;rwc);
!             } 
!             else if (smbp-&gt;com == 0xa0) {
!                 /* 
!                  * Serialize the handling for NT Transact 
!                  * (defect 11626)
!                  */
!                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
!                 thrd_SetEvent(SessionEvents[idx_session]);
!             } else {
!                 thrd_SetEvent(SessionEvents[idx_session]);
!                 /* TODO: what else needs to be serialized? */
!                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
!             }
  #if !defined(DJGPP) &amp;&amp; !defined(AFS_WIN95_ENV)
          }
          __except( smb_ServerExceptionFilter() ) {
          }
  #endif
  
!         smb_concurrentCalls--;
  
  doneWithNCB:
!         thrd_SetEvent(NCBavails[idx_NCB]);
!     }
      if (vcp)
          smb_ReleaseVC(vcp);
  }
***************
*** 6736,6759 ****
   */
  #if !defined(DJGPP) &amp;&amp; !defined(AFS_WIN95_ENV)
  DWORD smb_ServerExceptionFilter(void) {
! 	/* While this is not the best time to do a trace, if it succeeds, then
! 	 * we have a trace (assuming tracing was enabled). Otherwise, this should
! 	 * throw a second exception.
! 	 */
! 	HANDLE h;
! 	char *ptbuf[1];
! 
! 	ptbuf[0] = "Unhandled exception forcing trace";
! 
! 	h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
! 	if(h) {
! 		ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
! 		DeregisterEventSource(h);
! 	}
  
! 	afsd_ForceTrace(TRUE);
! 	return EXCEPTION_CONTINUE_SEARCH;
! }
  #endif
  
  /*
--- 6916,6939 ----
   */
  #if !defined(DJGPP) &amp;&amp; !defined(AFS_WIN95_ENV)
  DWORD smb_ServerExceptionFilter(void) {
!     /* While this is not the best time to do a trace, if it succeeds, then
!      * we have a trace (assuming tracing was enabled). Otherwise, this should
!      * throw a second exception.
!      */
!     HANDLE h;
!     char *ptbuf[1];
  
!     ptbuf[0] = "Unhandled exception forcing trace";
! 
!     h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
!     if(h) {
!         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
!         DeregisterEventSource(h);
!     }
! 
!     afsd_ForceTrace(TRUE);
!     return EXCEPTION_CONTINUE_SEARCH;
! }       
  #endif
  
  /*
***************
*** 6764,6817 ****
   */
  void InitNCBslot(int idx)
  {
! 	struct smb_packet *bufp;
! 	EVENT_HANDLE retHandle;
! 	int i;
      char eventName[MAX_PATH];
  
      osi_assert( idx &lt; (sizeof(NCBs) / sizeof(NCBs[0])) );
  
! 	NCBs[idx] = GetNCB();
      sprintf(eventName,"NCBavails[%d]", idx);
! 	NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
  #ifndef DJGPP
      sprintf(eventName,"NCBevents[%d]", idx);
! 	NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
  #endif /* !DJGPP */
      sprintf(eventName,"NCBReturns[0&lt;=i&lt;smb_NumServerThreads][%d]", idx);
! 	retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
! 	for (i=0; i&lt;smb_NumServerThreads; i++)
! 		NCBreturns[i][idx] = retHandle;
! 	bufp = GetPacket();
! 	bufp-&gt;spacep = cm_GetSpace();
! 	bufs[idx] = bufp;
  }
  
  /* listen for new connections */
  void smb_Listener(void *parmp)
  {
! 	NCB *ncbp;
      long code = 0;
      long len;
! 	long i, j;
      smb_vc_t *vcp;
! 	int flags = 0;
! 	char rname[NCBNAMSZ+1];
! 	char cname[MAX_COMPUTERNAME_LENGTH+1];
! 	int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
  #ifdef DJGPP
      dos_ptr dos_ncb;
      time_t now;
  #endif /* DJGPP */
! 	int lana = (int) parmp;
  
! 	ncbp = GetNCB();
  #ifdef DJGPP
      dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
--- 6944,6997 ----
   */
  void InitNCBslot(int idx)
  {
!     struct smb_packet *bufp;
!     EVENT_HANDLE retHandle;
!     int i;
      char eventName[MAX_PATH];
  
      osi_assert( idx &lt; (sizeof(NCBs) / sizeof(NCBs[0])) );
  
!     NCBs[idx] = GetNCB();
      sprintf(eventName,"NCBavails[%d]", idx);
!     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
  #ifndef DJGPP
      sprintf(eventName,"NCBevents[%d]", idx);
!     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
  #endif /* !DJGPP */
      sprintf(eventName,"NCBReturns[0&lt;=i&lt;smb_NumServerThreads][%d]", idx);
!     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
!     for (i=0; i&lt;smb_NumServerThreads; i++)
!         NCBreturns[i][idx] = retHandle;
!     bufp = GetPacket();
!     bufp-&gt;spacep = cm_GetSpace();
!     bufs[idx] = bufp;
  }
  
  /* listen for new connections */
  void smb_Listener(void *parmp)
  {
!     NCB *ncbp;
      long code = 0;
      long len;
!     long i, j;
      smb_vc_t *vcp;
!     int flags = 0;
!     char rname[NCBNAMSZ+1];
!     char cname[MAX_COMPUTERNAME_LENGTH+1];
!     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
  #ifdef DJGPP
      dos_ptr dos_ncb;
      time_t now;
  #endif /* DJGPP */
!     int lana = (int) parmp;
  
!     ncbp = GetNCB();
  #ifdef DJGPP
      dos_ncb = ((smb_ncb_t *)ncbp)-&gt;dos_ncb;
  #endif /* DJGPP */
***************
*** 6820,6859 ****
      GetComputerName(cname, &amp;cnamelen);
      _strupr(cname);
  
! 	while (1) {
! 		memset(ncbp, 0, sizeof(NCB));
! 		flags = 0;
! 
! #ifndef NOEXPIRE
! 		/* check for demo expiration */
! 		{
! 			unsigned long tod = time((void *) 0);
! 			if (tod &gt; EXPIREDATE) {
! 				(*smb_MBfunc)(NULL, "AFS demo expiration",
!                                "afsd listener",
!                                MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
! #ifndef DJGPP
!                 ExitThread(1);
! #else
!                 thrd_Exit(1);
! #endif
! 			}
! 		}
! #endif /* !NOEXPIRE */
  
          ncbp-&gt;ncb_command = NCBLISTEN;
          ncbp-&gt;ncb_rto = 0;	/* No receive timeout */
          ncbp-&gt;ncb_sto = 0;	/* No send timeout */
  
! 		/* pad out with spaces instead of null termination */
! 		len = strlen(smb_localNamep);
          strncpy(ncbp-&gt;ncb_name, smb_localNamep, NCBNAMSZ);
!         for(i=len; i&lt;NCBNAMSZ; i++) ncbp-&gt;ncb_name[i] = ' ';
          
          strcpy(ncbp-&gt;ncb_callname, "*");
!         for(i=1; i&lt;NCBNAMSZ; i++) ncbp-&gt;ncb_callname[i] = ' ';
          
! 		ncbp-&gt;ncb_lana_num = lana;
  
  #ifndef DJGPP
          code = Netbios(ncbp);
--- 7000,7022 ----
      GetComputerName(cname, &amp;cnamelen);
      _strupr(cname);
  
!     while (1) {
!         memset(ncbp, 0, sizeof(NCB));
!         flags = 0;
  
          ncbp-&gt;ncb_command = NCBLISTEN;
          ncbp-&gt;ncb_rto = 0;	/* No receive timeout */
          ncbp-&gt;ncb_sto = 0;	/* No send timeout */
  
!         /* pad out with spaces instead of null termination */
!         len = strlen(smb_localNamep);
          strncpy(ncbp-&gt;ncb_name, smb_localNamep, NCBNAMSZ);
!         for (i=len; i&lt;NCBNAMSZ; i++) ncbp-&gt;ncb_name[i] = ' ';
          
          strcpy(ncbp-&gt;ncb_callname, "*");
!         for (i=1; i&lt;NCBNAMSZ; i++) ncbp-&gt;ncb_callname[i] = ' ';
          
!         ncbp-&gt;ncb_lana_num = lana;
  
  #ifndef DJGPP
          code = Netbios(ncbp);
***************
*** 6868,6880 ****
  #endif
  
              /* terminate silently if shutdown flag is set */
! 	        if (smbShutdownFlag == 1) {
  #ifndef DJGPP
! 			    ExitThread(1);
  #else
! 				thrd_Exit(1);
  #endif
! 			}
  
              osi_Log2(smb_logp, 
                       "NCBLISTEN lana=%d failed with code %d",
--- 7031,7043 ----
  #endif
  
              /* terminate silently if shutdown flag is set */
!             if (smbShutdownFlag == 1) {
  #ifndef DJGPP
!                 ExitThread(1);
  #else
!                 thrd_Exit(1);
  #endif
!             }
  
              osi_Log2(smb_logp, 
                       "NCBLISTEN lana=%d failed with code %d",
***************
*** 6887,6895 ****
                       "Client exiting due to network failure.  Please restart client.\n"
                       "NCBLISTEN lana=%d failed with code %d",
                       ncbp-&gt;ncb_lana_num, code);
! 			if (showErrors)
                  code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
!                                      MB_OK|MB_SERVICE_NOTIFICATION);
              osi_assert(tbuffer);
              ExitThread(1);
  #else
--- 7050,7058 ----
                       "Client exiting due to network failure.  Please restart client.\n"
                       "NCBLISTEN lana=%d failed with code %d",
                       ncbp-&gt;ncb_lana_num, code);
!             if (showErrors)
                  code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
!                                       MB_OK|MB_SERVICE_NOTIFICATION);
              osi_assert(tbuffer);
              ExitThread(1);
  #else
***************
*** 6898,6976 ****
              fprintf(stderr, "\nClient exiting due to network failure "
                       "(possibly due to power-saving mode)\n");
              fprintf(stderr, "Please restart client.\n");
! 			afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
  #endif /* !DJGPP */
          }
  
! 		/* check for remote conns */
! 		/* first get remote name and insert null terminator */
! 		memcpy(rname, ncbp-&gt;ncb_callname, NCBNAMSZ);
! 		for (i=NCBNAMSZ; i&gt;0; i--) {
! 			if (rname[i-1] != ' ' &amp;&amp; rname[i-1] != 0) {
! 				rname[i] = 0;
! 				break;
! 			}
! 		}
  
          /* compare with local name */
! 		if (!isGateway)
! 			if (strncmp(rname, cname, NCBNAMSZ) != 0)
! 				flags |= SMB_VCFLAG_REMOTECONN;
! 
! 		osi_Log1(smb_logp, "New session lsn %d", ncbp-&gt;ncb_lsn);
! 		/* lock */
! 		lock_ObtainMutex(&amp;smb_ListenerLock);
  
! 		/* New generation */
! 		sessionGen++;
  
! 		/* Log session startup */
  #ifdef NOTSERVICE
          fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
! 				"%s\n",
!                 ncbp-&gt;ncb_lsn,ncbp-&gt;ncb_lana_num, rname);
! #endif
          osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
                    ncbp-&gt;ncb_lsn,ncbp-&gt;ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
  
          if (reportSessionStartups) {
  #ifndef DJGPP
! 			HANDLE h;
! 			char *ptbuf[1];
! 			char s[100];
! 
! 			h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 			sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
! 			ptbuf[0] = s;
! 			ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
!                         1, 0, ptbuf, NULL);
! 			DeregisterEventSource(h);
  #else /* DJGPP */
              time(&amp;now);
              fprintf(stderr, "%s: New session %d starting from host %s\n",
                      asctime(localtime(&amp;now)), ncbp-&gt;ncb_lsn, rname);
              fflush(stderr);
  #endif /* !DJGPP */
! 		}
!             osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
!             osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
!                      ongoingOps);
  
          /* now ncbp-&gt;ncb_lsn is the connection ID */
          vcp = smb_FindVC(ncbp-&gt;ncb_lsn, SMB_FLAG_CREATE, ncbp-&gt;ncb_lana_num);
! 		vcp-&gt;flags |= flags;
          strcpy(vcp-&gt;rname, rname);
  
! 		/* Allocate slot in session arrays */
! 		/* Re-use dead session if possible, otherwise add one more */
          /* But don't look at session[0], it is reserved */
! 		for (i = 1; i &lt; numSessions; i++) {
! 			if (dead_sessions[i]) {
                  osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
! 				dead_sessions[i] = FALSE;
! 				break;
! 			}
! 		}
  
          /* assert that we do not exceed the maximum number of sessions or NCBs.
           * we should probably want to wait for a session to be freed in case
--- 7061,7139 ----
              fprintf(stderr, "\nClient exiting due to network failure "
                       "(possibly due to power-saving mode)\n");
              fprintf(stderr, "Please restart client.\n");
!             afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
  #endif /* !DJGPP */
          }
  
!         /* check for remote conns */
!         /* first get remote name and insert null terminator */
!         memcpy(rname, ncbp-&gt;ncb_callname, NCBNAMSZ);
!         for (i=NCBNAMSZ; i&gt;0; i--) {
!             if (rname[i-1] != ' ' &amp;&amp; rname[i-1] != 0) {
!                 rname[i] = 0;
!                 break;
!             }
!         }
  
          /* compare with local name */
!         if (!isGateway)
!             if (strncmp(rname, cname, NCBNAMSZ) != 0)
!                 flags |= SMB_VCFLAG_REMOTECONN;
! 
!         osi_Log1(smb_logp, "New session lsn %d", ncbp-&gt;ncb_lsn);
!         /* lock */
!         lock_ObtainMutex(&amp;smb_ListenerLock);
  
!         /* New generation */
!         sessionGen++;
  
!         /* Log session startup */
  #ifdef NOTSERVICE
          fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
!                  "%s\n",
!                  ncbp-&gt;ncb_lsn,ncbp-&gt;ncb_lana_num, rname);
! #endif /* NOTSERVICE */
          osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
                    ncbp-&gt;ncb_lsn,ncbp-&gt;ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
  
          if (reportSessionStartups) {
  #ifndef DJGPP
!             HANDLE h;
!             char *ptbuf[1];
!             char s[100];
! 
!             h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!             sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
!             ptbuf[0] = s;
!             ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
!                          1, 0, ptbuf, NULL);
!             DeregisterEventSource(h);
  #else /* DJGPP */
              time(&amp;now);
              fprintf(stderr, "%s: New session %d starting from host %s\n",
                      asctime(localtime(&amp;now)), ncbp-&gt;ncb_lsn, rname);
              fflush(stderr);
  #endif /* !DJGPP */
!         }
!         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
!         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
!                   ongoingOps);
  
          /* now ncbp-&gt;ncb_lsn is the connection ID */
          vcp = smb_FindVC(ncbp-&gt;ncb_lsn, SMB_FLAG_CREATE, ncbp-&gt;ncb_lana_num);
!         vcp-&gt;flags |= flags;
          strcpy(vcp-&gt;rname, rname);
  
!         /* Allocate slot in session arrays */
!         /* Re-use dead session if possible, otherwise add one more */
          /* But don't look at session[0], it is reserved */
!         for (i = 1; i &lt; numSessions; i++) {
!             if (dead_sessions[i]) {
                  osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
!                 dead_sessions[i] = FALSE;
!                 break;
!             }
!         }
  
          /* assert that we do not exceed the maximum number of sessions or NCBs.
           * we should probably want to wait for a session to be freed in case
***************
*** 6980,7013 ****
          osi_assert(i &lt; Sessionmax - 1);
          osi_assert(numNCBs &lt; NCBmax - 1);   /* if we pass this test we can allocate one more */
  
! 		LSNs[i] = ncbp-&gt;ncb_lsn;
! 		lanas[i] = ncbp-&gt;ncb_lana_num;
  		
! 		if (i == numSessions) {
! 			/* Add new NCB for new session */
              char eventName[MAX_PATH];
  
              osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
  
! 			InitNCBslot(numNCBs);
! 			numNCBs++;
! 			thrd_SetEvent(NCBavails[0]);
! 			thrd_SetEvent(NCBevents[0]);
! 			for (j = 0; j &lt; smb_NumServerThreads; j++)
! 				thrd_SetEvent(NCBreturns[j][0]);
! 			/* Also add new session event */
              sprintf(eventName, "SessionEvents[%d]", i);
              SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
              if ( GetLastError() == ERROR_ALREADY_EXISTS )
                  osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
! 			numSessions++;
              osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
! 			thrd_SetEvent(SessionEvents[0]);
! 		} else {
! 			thrd_SetEvent(SessionEvents[i]);
! 		}
! 		/* unlock */
! 		lock_ReleaseMutex(&amp;smb_ListenerLock);
  
      }	/* dispatch while loop */
  }
--- 7143,7176 ----
          osi_assert(i &lt; Sessionmax - 1);
          osi_assert(numNCBs &lt; NCBmax - 1);   /* if we pass this test we can allocate one more */
  
!         LSNs[i] = ncbp-&gt;ncb_lsn;
!         lanas[i] = ncbp-&gt;ncb_lana_num;
  		
!         if (i == numSessions) {
!             /* Add new NCB for new session */
              char eventName[MAX_PATH];
  
              osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
  
!             InitNCBslot(numNCBs);
!             numNCBs++;
!             thrd_SetEvent(NCBavails[0]);
!             thrd_SetEvent(NCBevents[0]);
!             for (j = 0; j &lt; smb_NumServerThreads; j++)
!                 thrd_SetEvent(NCBreturns[j][0]);
!             /* Also add new session event */
              sprintf(eventName, "SessionEvents[%d]", i);
              SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
              if ( GetLastError() == ERROR_ALREADY_EXISTS )
                  osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
!             numSessions++;
              osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
!             thrd_SetEvent(SessionEvents[0]);
!         } else {
!             thrd_SetEvent(SessionEvents[i]);
!         }
!         /* unlock */
!         lock_ReleaseMutex(&amp;smb_ListenerLock);
  
      }	/* dispatch while loop */
  }
***************
*** 7149,7155 ****
  #else
                  code = Netbios(ncbp, dos_ncb);
  #endif /* DJGPP */
!                 if (code == 0) code = ncbp-&gt;ncb_retcode;
                  else {
                      sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
                      osi_Log0(smb_logp, s);
--- 7312,7319 ----
  #else
                  code = Netbios(ncbp, dos_ncb);
  #endif /* DJGPP */
!                 if (code == 0) 
!                     code = ncbp-&gt;ncb_retcode;
                  else {
                      sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
                      osi_Log0(smb_logp, s);
***************
*** 7198,7208 ****
    )
  
  {
! 	thread_t phandle;
      int lpid;
      int i;
      int len;
! 	struct tm myTime;
  #ifdef DJGPP
      int npar, seg, sel;
      dos_ptr rawBuf;
--- 7362,7372 ----
    )
  
  {
!     thread_t phandle;
      int lpid;
      int i;
      int len;
!     struct tm myTime;
  #ifdef DJGPP
      int npar, seg, sel;
      dos_ptr rawBuf;
***************
*** 7211,7284 ****
      char eventName[MAX_PATH];
  
  #ifndef DJGPP
! 	smb_MBfunc = aMBfunc;
  #endif /* DJGPP */
  
! #ifndef NOEXPIRE
! 	/* check for demo expiration */
! 	{
! 		unsigned long tod = time((void *) 0);
! 		if (tod &gt; EXPIREDATE) {
! #ifndef DJGPP
! 			(*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
!                           MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
! 			exit(1);
! #else /* DJGPP */
!             fprintf(stderr, "AFS demo expiration\n");
!             afs_exit(0);
! #endif /* !DJGPP */
! 		}
! 	}
! #endif /* !NOEXPIRE */
! 
! 	smb_useV3 = useV3;
! 	smb_LANadapter = LANadapt;
! 
! 	/* Initialize smb_localZero */
! 	myTime.tm_isdst = -1;		/* compute whether on DST or not */
! 	myTime.tm_year = 70;
! 	myTime.tm_mon = 0;
! 	myTime.tm_mday = 1;
! 	myTime.tm_hour = 0;
! 	myTime.tm_min = 0;
! 	myTime.tm_sec = 0;
! 	smb_localZero = mktime(&amp;myTime);
  
! 	/* Initialize kludge-GMT */
! 	smb_CalculateNowTZ();
  
  #ifdef AFS_FREELANCE_CLIENT
      /* Make sure the root.afs volume has the correct time */
      cm_noteLocalMountPointChange();
  #endif
  
! 	/* initialize the remote debugging log */
! 	smb_logp = logp;
          
      /* remember the name */
! 	len = strlen(snamep);
      smb_localNamep = malloc(len+1);
      strcpy(smb_localNamep, snamep);
      afsi_log("smb_localNamep is &gt;%s&lt;", smb_localNamep);
  
! 	/* and the global lock */
      lock_InitializeRWLock(&amp;smb_globalLock, "smb global lock");
      lock_InitializeRWLock(&amp;smb_rctLock, "smb refct and tree struct lock");
  
! 	/* Raw I/O data structures */
! 	lock_InitializeMutex(&amp;smb_RawBufLock, "smb raw buffer lock");
  
! 	lock_InitializeMutex(&amp;smb_ListenerLock, "smb listener lock");
  	
! 	/* 4 Raw I/O buffers */
  #ifndef DJGPP
! 	smb_RawBufs = calloc(65536,1);
! 	*((char **)smb_RawBufs) = NULL;
! 	for (i=0; i&lt;3; i++) {
! 		char *rawBuf = calloc(65536,1);
! 		*((char **)rawBuf) = smb_RawBufs;
! 		smb_RawBufs = rawBuf;
! 	}
  #else /* DJGPP */
      npar = 65536 &gt;&gt; 4;  /* number of paragraphs */
      seg = __dpmi_allocate_dos_memory(npar, &amp;smb_RawBufSel[0]);
--- 7375,7431 ----
      char eventName[MAX_PATH];
  
  #ifndef DJGPP
!     smb_MBfunc = aMBfunc;
  #endif /* DJGPP */
  
!     smb_useV3 = useV3;
!     smb_LANadapter = LANadapt;
! 
!     /* Initialize smb_localZero */
!     myTime.tm_isdst = -1;		/* compute whether on DST or not */
!     myTime.tm_year = 70;
!     myTime.tm_mon = 0;
!     myTime.tm_mday = 1;
!     myTime.tm_hour = 0;
!     myTime.tm_min = 0;
!     myTime.tm_sec = 0;
!     smb_localZero = mktime(&amp;myTime);
  
!     /* Initialize kludge-GMT */
!     smb_CalculateNowTZ();
  
  #ifdef AFS_FREELANCE_CLIENT
      /* Make sure the root.afs volume has the correct time */
      cm_noteLocalMountPointChange();
  #endif
  
!     /* initialize the remote debugging log */
!     smb_logp = logp;
          
      /* remember the name */
!     len = strlen(snamep);
      smb_localNamep = malloc(len+1);
      strcpy(smb_localNamep, snamep);
      afsi_log("smb_localNamep is &gt;%s&lt;", smb_localNamep);
  
!     /* and the global lock */
      lock_InitializeRWLock(&amp;smb_globalLock, "smb global lock");
      lock_InitializeRWLock(&amp;smb_rctLock, "smb refct and tree struct lock");
  
!     /* Raw I/O data structures */
!     lock_InitializeMutex(&amp;smb_RawBufLock, "smb raw buffer lock");
  
!     lock_InitializeMutex(&amp;smb_ListenerLock, "smb listener lock");
  	
!     /* 4 Raw I/O buffers */
  #ifndef DJGPP
!     smb_RawBufs = calloc(65536,1);
!     *((char **)smb_RawBufs) = NULL;
!     for (i=0; i&lt;3; i++) {
!         char *rawBuf = calloc(65536,1);
!         *((char **)rawBuf) = smb_RawBufs;
!         smb_RawBufs = rawBuf;
!     }
  #else /* DJGPP */
      npar = 65536 &gt;&gt; 4;  /* number of paragraphs */
      seg = __dpmi_allocate_dos_memory(npar, &amp;smb_RawBufSel[0]);
***************
*** 7313,7440 ****
      }
  #endif /* !DJGPP */
  
! 	/* global free lists */
! 	smb_ncbFreeListp = NULL;
      smb_packetFreeListp = NULL;
  
      smb_NetbiosInit();
  
! 	/* Initialize listener and server structures */
      numVCs = 0;
! 	memset(dead_sessions, 0, sizeof(dead_sessions));
      sprintf(eventName, "SessionEvents[0]");
! 	SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", eventName);
! 	numSessions = 1;
! 	smb_NumServerThreads = nThreads;
      sprintf(eventName, "NCBavails[0]");
! 	NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", eventName);
      sprintf(eventName, "NCBevents[0]");
! 	NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", eventName);
! 	NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
      sprintf(eventName, "NCBreturns[0&lt;=i&lt;smb_NumServerThreads][0]");
      retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", eventName);
! 	for (i = 0; i &lt; smb_NumServerThreads; i++) {
! 		NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
! 		NCBreturns[i][0] = retHandle;
! 	}
! 	for (i = 1; i &lt;= nThreads; i++)
! 		InitNCBslot(i);
! 	numNCBs = nThreads + 1;
! 
! 	/* Initialize dispatch table */
! 	memset(&amp;smb_dispatchTable, 0, sizeof(smb_dispatchTable));
! 	smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
! 	smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
! 	smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
! 	smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
! 	smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
! 	smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
! 	smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
! 	smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
! 	smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
! 	smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
! 	smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
! 	smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
! 	smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
! 	smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
! 	smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
! 	smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
! 	smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
! 	smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;	/* process exit */
! 	smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
! 	smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
! 	/* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
! 	smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
! 	smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
! 	smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
! 	smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
! 	smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
! 	smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
! 	smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
! 	smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
! 	smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
! 	smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
! 	smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;	/* copy file */
! 	smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
! 	/* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
! 	smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
      smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
      smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
      smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
      smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
! 	smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;	/* both are same */
      smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
      smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
      smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
      smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
      smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
! 	smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
! 	smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
! 	smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
! 	smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
      smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
      smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
      smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
      smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
      smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
! 	smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
! 	smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
! 	smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
! 	smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
! 	smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
! 	smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
! 	smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
! 	smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
! 	smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
! 	smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
! 	smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
! 	for(i=0xd0; i&lt;= 0xd7; i++) {
! 		smb_dispatchTable[i].procp = smb_SendCoreBadOp;
!     }
! 
! 	/* setup tran 2 dispatch table */
! 	smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
! 	smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;	/* FindFirst */
! 	smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;	/* FindNext */
! 	smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
! 	smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
! 	smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
! 	smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
! 	smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
! 	smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
! 	smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
! 	smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
! 	smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
! 	smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
! 	smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
  
      /* setup the rap dispatch table */
      memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
--- 7460,7599 ----
      }
  #endif /* !DJGPP */
  
!     /* global free lists */
!     smb_ncbFreeListp = NULL;
      smb_packetFreeListp = NULL;
  
      smb_NetbiosInit();
  
!     /* Initialize listener and server structures */
      numVCs = 0;
!     memset(dead_sessions, 0, sizeof(dead_sessions));
      sprintf(eventName, "SessionEvents[0]");
!     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", eventName);
!     numSessions = 1;
!     smb_NumServerThreads = nThreads;
      sprintf(eventName, "NCBavails[0]");
!     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", eventName);
      sprintf(eventName, "NCBevents[0]");
!     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", eventName);
!     NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
      sprintf(eventName, "NCBreturns[0&lt;=i&lt;smb_NumServerThreads][0]");
      retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          afsi_log("Event Object Already Exists: %s", eventName);
!     for (i = 0; i &lt; smb_NumServerThreads; i++) {
!         NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
!         NCBreturns[i][0] = retHandle;
!     }
!     for (i = 1; i &lt;= nThreads; i++)
!         InitNCBslot(i);
!     numNCBs = nThreads + 1;
! 
!     /* Initialize dispatch table */
!     memset(&amp;smb_dispatchTable, 0, sizeof(smb_dispatchTable));
!     /* Prepare the table for unknown operations */
!     for(i=0; i&lt;= SMB_NOPCODES; i++) {
!         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
!     }
!     /* Fill in the ones we do know */
!     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
!     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
!     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
!     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
!     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
!     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
!     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
!     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
!     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
!     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
!     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
!     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
!     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
!     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
!     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
!     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
!     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
!     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;	/* process exit */
!     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
!     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
!     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
!     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
!     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
!     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
!     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
!     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
!     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
!     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
!     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
!     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
!     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
!     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;	/* copy file */
!     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
!     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
!     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
      smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
      smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
      smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
      smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
!     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;	/* both are same */
      smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
      smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
      smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
      smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
      smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
!     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
!     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
!     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
!     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
      smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
      smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
      smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
      smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
      smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
!     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
!     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
!     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
!     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
!     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
!     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
!     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
!     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
!     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
!     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
!     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
!     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
!     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
!     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
!     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
!     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
!     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
!     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
! 
!     /* setup tran 2 dispatch table */
!     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
!     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;	/* FindFirst */
!     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;	/* FindNext */
!     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
!     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
!     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
!     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
!     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
!     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
!     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
!     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
!     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
!     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
!     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
!     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
!     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2GetDFSReferral;
!     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2ReportDFSInconsistency;
  
      /* setup the rap dispatch table */
      memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
***************
*** 7443,7487 ****
      smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
      smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
  
! 	smb3_Init();
  
! 	/* if we are doing SMB authentication we have register outselves as a logon process */
! 	if (smb_authType != SMB_AUTH_NONE) {
          NTSTATUS nts;
! 		LSA_STRING afsProcessName;
! 		LSA_OPERATIONAL_MODE dummy; /*junk*/
  
! 		afsProcessName.Buffer = "OpenAFSClientDaemon";
! 		afsProcessName.Length = strlen(afsProcessName.Buffer);
! 		afsProcessName.MaximumLength = afsProcessName.Length + 1;
! 
! 		nts = LsaRegisterLogonProcess(&amp;afsProcessName, &amp;smb_lsaHandle, &amp;dummy);
! 
! 		if (nts == STATUS_SUCCESS) {
! 			LSA_STRING packageName;
! 			/* we are registered. Find out the security package id */
! 			packageName.Buffer = MSV1_0_PACKAGE_NAME;
! 			packageName.Length = strlen(packageName.Buffer);
! 			packageName.MaximumLength = packageName.Length + 1;
! 			nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &amp;packageName , &amp;smb_lsaSecPackage);
! 			if (nts == STATUS_SUCCESS) {
! 				smb_lsaLogonOrigin.Buffer = "OpenAFS";
! 				smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
! 				smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
! 			} else {
! 				afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
! 			}
! 		} else {
! 			afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
! 		}
! 
! 		if (nts != STATUS_SUCCESS) {
! 			/* something went wrong. We report the error and revert back to no authentication
! 			   because we can't perform any auth requests without a successful lsa handle
! 			   or sec package id. */
! 			afsi_log("Reverting to NO SMB AUTH");
! 			smb_authType = SMB_AUTH_NONE;
! 		} 
  #ifdef COMMENT
          /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
           * time prevents the failure of authentication when logged into Windows with an
--- 7602,7646 ----
      smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
      smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
  
!     smb3_Init();
  
!     /* if we are doing SMB authentication we have register outselves as a logon process */
!     if (smb_authType != SMB_AUTH_NONE) {
          NTSTATUS nts;
!         LSA_STRING afsProcessName;
!         LSA_OPERATIONAL_MODE dummy; /*junk*/
! 
!         afsProcessName.Buffer = "OpenAFSClientDaemon";
!         afsProcessName.Length = strlen(afsProcessName.Buffer);
!         afsProcessName.MaximumLength = afsProcessName.Length + 1;
! 
!         nts = LsaRegisterLogonProcess(&amp;afsProcessName, &amp;smb_lsaHandle, &amp;dummy);
! 
!         if (nts == STATUS_SUCCESS) {
!             LSA_STRING packageName;
!             /* we are registered. Find out the security package id */
!             packageName.Buffer = MSV1_0_PACKAGE_NAME;
!             packageName.Length = strlen(packageName.Buffer);
!             packageName.MaximumLength = packageName.Length + 1;
!             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &amp;packageName , &amp;smb_lsaSecPackage);
!             if (nts == STATUS_SUCCESS) {
!                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
!                 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
!                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
!             } else {
!                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
!             }
!         } else {
!             afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
!         }
  
!         if (nts != STATUS_SUCCESS) {
!             /* something went wrong. We report the error and revert back to no authentication
!             because we can't perform any auth requests without a successful lsa handle
!             or sec package id. */
!             afsi_log("Reverting to NO SMB AUTH");
!             smb_authType = SMB_AUTH_NONE;
!         } 
  #ifdef COMMENT
          /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
           * time prevents the failure of authentication when logged into Windows with an
***************
*** 7489,7496 ****
           */
          else if ( smb_authType == SMB_AUTH_EXTENDED) {
              /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
!             * then the only option is NTLMSSP anyway; so just fallback. 
!             */
              void * secBlob;
              int secBlobLength;
  
--- 7648,7655 ----
           */
          else if ( smb_authType == SMB_AUTH_EXTENDED) {
              /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
!              * then the only option is NTLMSSP anyway; so just fallback. 
!              */
              void * secBlob;
              int secBlobLength;
  
***************
*** 7502,7566 ****
                  free(secBlob);
          }
  #endif
! 	}
  
! 	{
! 		DWORD bufsize;
! 		/* Now get ourselves a domain name. */
! 		/* For now we are using the local computer name as the domain name.
! 		* It is actually the domain for local logins, and we are acting as
! 		* a local SMB server. 
! 		*/
! 		bufsize = sizeof(smb_ServerDomainName) - 1;
! 		GetComputerName(smb_ServerDomainName, &amp;bufsize);
! 		smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
! 		afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
! 	}
! 
! 	/* Start listeners, waiters, servers, and daemons */
! 
! 	for (i = 0; i &lt; lana_list.length; i++) {
! 		if (lana_list.lana[i] == 255) continue;
! 		phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
! 			(void*)lana_list.lana[i], 0, &amp;lpid, "smb_Listener");
! 		osi_assert(phandle != NULL);
! 		thrd_CloseHandle(phandle);
! 	}
  
  #ifndef DJGPP
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
                            NULL, 0, &amp;lpid, "smb_ClientWaiter");
! 	osi_assert(phandle != NULL);
! 	thrd_CloseHandle(phandle);
  #endif /* !DJGPP */
  
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
                            NULL, 0, &amp;lpid, "smb_ServerWaiter");
! 	osi_assert(phandle != NULL);
! 	thrd_CloseHandle(phandle);
  
! 	for (i=0; i&lt;nThreads; i++) {
! 		phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
                                (void *) i, 0, &amp;lpid, "smb_Server");
! 		osi_assert(phandle != NULL);
! 		thrd_CloseHandle(phandle);
! 	}
  
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
                            NULL, 0, &amp;lpid, "smb_Daemon");
! 	osi_assert(phandle != NULL);
! 	thrd_CloseHandle(phandle);
  
! 	phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
                            NULL, 0, &amp;lpid, "smb_WaitingLocksDaemon");
! 	osi_assert(phandle != NULL);
! 	thrd_CloseHandle(phandle);
  
  #ifdef DJGPP
!         smb_ListShares();
  #endif
  
! 	return;
  }
  
  void smb_Shutdown(void)
--- 7661,7725 ----
                  free(secBlob);
          }
  #endif
!     }
! 
!     {
!         DWORD bufsize;
!         /* Now get ourselves a domain name. */
!         /* For now we are using the local computer name as the domain name.
!          * It is actually the domain for local logins, and we are acting as
!          * a local SMB server. 
!          */
!         bufsize = sizeof(smb_ServerDomainName) - 1;
!         GetComputerName(smb_ServerDomainName, &amp;bufsize);
!         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
!         afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
!     }
  
!     /* Start listeners, waiters, servers, and daemons */
! 
!     for (i = 0; i &lt; lana_list.length; i++) {
!         if (lana_list.lana[i] == 255) continue;
!         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
!                                (void*)lana_list.lana[i], 0, &amp;lpid, "smb_Listener");
!         osi_assert(phandle != NULL);
!         thrd_CloseHandle(phandle);
!     }
  
  #ifndef DJGPP
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
                            NULL, 0, &amp;lpid, "smb_ClientWaiter");
!     osi_assert(phandle != NULL);
!     thrd_CloseHandle(phandle);
  #endif /* !DJGPP */
  
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
                            NULL, 0, &amp;lpid, "smb_ServerWaiter");
!     osi_assert(phandle != NULL);
!     thrd_CloseHandle(phandle);
  
!     for (i=0; i&lt;nThreads; i++) {
!         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
                                (void *) i, 0, &amp;lpid, "smb_Server");
!         osi_assert(phandle != NULL);
!         thrd_CloseHandle(phandle);
!     }
  
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
                            NULL, 0, &amp;lpid, "smb_Daemon");
!     osi_assert(phandle != NULL);
!     thrd_CloseHandle(phandle);
  
!     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
                            NULL, 0, &amp;lpid, "smb_WaitingLocksDaemon");
!     osi_assert(phandle != NULL);
!     thrd_CloseHandle(phandle);
  
  #ifdef DJGPP
!     smb_ListShares();
  #endif
  
!     return;
  }
  
  void smb_Shutdown(void)
***************
*** 7609,7631 ****
  
      /* Delete Netbios name */
      memset((char *)ncbp, 0, sizeof(NCB));
! 	for (i = 0; i &lt; lana_list.length; i++) {
! 		if (lana_list.lana[i] == 255) continue;
! 		ncbp-&gt;ncb_command = NCBDELNAME;
! 		ncbp-&gt;ncb_lana_num = lana_list.lana[i];
! 		memcpy(ncbp-&gt;ncb_name,smb_sharename,NCBNAMSZ);
  #ifndef DJGPP
          code = Netbios(ncbp);
  #else
! 		code = Netbios(ncbp, dos_ncb);
  #endif
! 		if (code == 0) code = ncbp-&gt;ncb_retcode;
! 		if (code != 0) {
! 			fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
! 			ncbp-&gt;ncb_lana_num, code);
! 		}
! 		fflush(stderr);
! 	}
  }
  
  /* Get the UNC \\&lt;servername&gt;\&lt;sharename&gt; prefix. */
--- 7768,7791 ----
  
      /* Delete Netbios name */
      memset((char *)ncbp, 0, sizeof(NCB));
!     for (i = 0; i &lt; lana_list.length; i++) {
!         if (lana_list.lana[i] == 255) continue;
!         ncbp-&gt;ncb_command = NCBDELNAME;
!         ncbp-&gt;ncb_lana_num = lana_list.lana[i];
!         memcpy(ncbp-&gt;ncb_name,smb_sharename,NCBNAMSZ);
  #ifndef DJGPP
          code = Netbios(ncbp);
  #else
!         code = Netbios(ncbp, dos_ncb);
  #endif
!         if (code == 0) 
!             code = ncbp-&gt;ncb_retcode;
!         if (code != 0) {
!             fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
!                      ncbp-&gt;ncb_lana_num, code);
!         }       
!         fflush(stderr);
!     }
  }
  
  /* Get the UNC \\&lt;servername&gt;\&lt;sharename&gt; prefix. */
***************
*** 7633,7641 ****
  {
      char *name;
  
! 	/* Make sure we have been properly initialized. */
! 	if (smb_localNamep == NULL)
! 		return NULL;
  
      /* Allocate space for \\&lt;servername&gt;\&lt;sharename&gt;, plus the
       * terminator.
--- 7793,7801 ----
  {
      char *name;
  
!     /* Make sure we have been properly initialized. */
!     if (smb_localNamep == NULL)
!         return NULL;
  
      /* Allocate space for \\&lt;servername&gt;\&lt;sharename&gt;, plus the
       * terminator.
***************
*** 7645,7714 ****
      return name;
  }   
  
- #ifdef NOTSERVICE
  
  void smb_LogPacket(smb_packet_t *packet)
  {
! 	BYTE *vp, *cp;
! 	unsigned length, paramlen, datalen, i, j;
! 	char buf[81];
! 	char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
  
! 	if(!packet) return;
  
! 	osi_Log0(smb_logp, "*** SMB packet dump ***");
  
! 	vp = (BYTE *) packet-&gt;data;
  
! 	datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) &lt;&lt; 1)));
! 	length = paramlen + 2 + datalen;
  
  
! 	for(i=0;i &lt; length; i+=16)
! 	{
! 		memset( buf, ' ', 80 );
! 		buf[80] = 0;
! 
! 		itoa( i, buf, 16 );
  
! 		buf[strlen(buf)] = ' ';
  
! 		cp = (BYTE*) buf + 7;
  
! 		for(j=0;j &lt; 16 &amp;&amp; (i+j)&lt;length; j++)
! 		{
! 			*(cp++) = hex[vp[i+j] &gt;&gt; 4];
! 			*(cp++) = hex[vp[i+j] &amp; 0xf];
! 			*(cp++) = ' ';
  
! 			if(j==7)
! 			{
! 				*(cp++) = '-';
! 				*(cp++) = ' ';
! 			}
! 		}
  
! 		for(j=0;j &lt; 16 &amp;&amp; (i+j)&lt;length;j++)
! 		{
! 			*(cp++) = ( 32 &lt;= vp[i+j] &amp;&amp; 128 &gt; vp[i+j] )? vp[i+j]:'.';
! 			if(j==7)
! 			{
! 				*(cp++) = ' ';
! 				*(cp++) = '-';
! 				*(cp++) = ' ';
! 			}
! 		}
  
! 		*cp = 0;
  
! 		osi_Log0( smb_logp, buf );
! 	}
  
! 	osi_Log0(smb_logp, "*** End SMB packet dump ***");
  
  }
  
- #endif /* NOTSERVICE */
  
  int smb_DumpVCP(FILE *outputFile, char *cookie)
  {
--- 7805,7873 ----
      return name;
  }   
  
  
+ #ifdef LOG_PACKET
  void smb_LogPacket(smb_packet_t *packet)
  {
!     BYTE *vp, *cp;
!     unsigned length, paramlen, datalen, i, j;
!     char buf[81];
!     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
  
!     if (!packet) return;
  
!     osi_Log0(smb_logp, "*** SMB packet dump ***");
  
!     vp = (BYTE *) packet-&gt;data;
  
!     datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) &lt;&lt; 1)));
!     length = paramlen + 2 + datalen;
  
  
!     for (i=0;i &lt; length; i+=16)
!     {
!         memset( buf, ' ', 80 );
!         buf[80] = 0;
  
!         itoa( i, buf, 16 );
  
!         buf[strlen(buf)] = ' ';
  
!         cp = (BYTE*) buf + 7;
  
!         for (j=0;j &lt; 16 &amp;&amp; (i+j)&lt;length; j++)
!         {
!             *(cp++) = hex[vp[i+j] &gt;&gt; 4];
!             *(cp++) = hex[vp[i+j] &amp; 0xf];
!             *(cp++) = ' ';
  
!             if (j==7)
!             {
!                 *(cp++) = '-';
!                 *(cp++) = ' ';
!             }
!         }
  
!         for (j=0;j &lt; 16 &amp;&amp; (i+j)&lt;length;j++)
!         {
!             *(cp++) = ( 32 &lt;= vp[i+j] &amp;&amp; 128 &gt; vp[i+j] )? vp[i+j]:'.';
!             if (j==7)
!             {
!                 *(cp++) = ' ';
!                 *(cp++) = '-';
!                 *(cp++) = ' ';
!             }
!         }
  
!         *cp = 0;
  
!         osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
!     }
  
+     osi_Log0(smb_logp, "*** End SMB packet dump ***");
  }
+ #endif /* LOG_PACKET */
  
  
  int smb_DumpVCP(FILE *outputFile, char *cookie)
  {
Index: openafs/src/WINNT/afsd/smb.h
diff -c openafs/src/WINNT/afsd/smb.h:1.14.2.2 openafs/src/WINNT/afsd/smb.h:1.14.2.4
*** openafs/src/WINNT/afsd/smb.h:1.14.2.2	Wed Aug 18 13:11:22 2004
--- openafs/src/WINNT/afsd/smb.h	Mon Oct 18 00:09:28 2004
***************
*** 141,147 ****
  /* one per virtual circuit */
  typedef struct smb_vc {
  	struct smb_vc *nextp;		/* not used */
!     int refCount;			/* the reference count */
      long flags;			/* the flags, if any; locked by mx */
      osi_mutex_t mx;			/* the mutex */
  	long vcID;			/* VC id */
--- 141,147 ----
  /* one per virtual circuit */
  typedef struct smb_vc {
  	struct smb_vc *nextp;		/* not used */
!     unsigned long refCount;			/* the reference count */
      long flags;			/* the flags, if any; locked by mx */
      osi_mutex_t mx;			/* the mutex */
  	long vcID;			/* VC id */
***************
*** 177,183 ****
  /* one per user session */
  typedef struct smb_user {
  	struct smb_user *nextp;		/* next sibling */
!         long refCount;			/* ref count */
          long flags;			/* flags; locked by mx */
          osi_mutex_t mx;
          long userID;			/* the session identifier */
--- 177,183 ----
  /* one per user session */
  typedef struct smb_user {
  	struct smb_user *nextp;		/* next sibling */
!         unsigned long refCount;			/* ref count */
          long flags;			/* flags; locked by mx */
          osi_mutex_t mx;
          long userID;			/* the session identifier */
***************
*** 187,193 ****
  
  typedef struct smb_username {
  	struct smb_username *nextp;		/* next sibling */
!         long refCount;			/* ref count */
          long flags;			/* flags; locked by mx */
          osi_mutex_t mx;
  	struct cm_user *userp;		/* CM user structure */
--- 187,193 ----
  
  typedef struct smb_username {
  	struct smb_username *nextp;		/* next sibling */
!         unsigned long refCount;			/* ref count */
          long flags;			/* flags; locked by mx */
          osi_mutex_t mx;
  	struct cm_user *userp;		/* CM user structure */
***************
*** 202,208 ****
  /* one per tree-connect */
  typedef struct smb_tid {
  	struct smb_tid *nextp;		/* next sibling */
!         long refCount;
          long flags;
          osi_mutex_t mx;			/* for non-tree-related stuff */
          unsigned short tid;		/* the tid */
--- 202,208 ----
  /* one per tree-connect */
  typedef struct smb_tid {
  	struct smb_tid *nextp;		/* next sibling */
!         unsigned long refCount;
          long flags;
          osi_mutex_t mx;			/* for non-tree-related stuff */
          unsigned short tid;		/* the tid */
***************
*** 218,224 ****
  /* one per process ID */
  typedef struct smb_pid {
  	struct smb_pid *nextp;		/* next sibling */
!         long refCount;
          long flags;
          osi_mutex_t mx;			/* for non-tree-related stuff */
          unsigned short pid;		/* the pid */
--- 218,224 ----
  /* one per process ID */
  typedef struct smb_pid {
  	struct smb_pid *nextp;		/* next sibling */
!         unsigned long refCount;
          long flags;
          osi_mutex_t mx;			/* for non-tree-related stuff */
          unsigned short pid;		/* the pid */
***************
*** 260,267 ****
  /* one per file ID; these are really file descriptors */
  typedef struct smb_fid {
  	osi_queue_t q;
!         long refCount;
!         long flags;
          osi_mutex_t mx;			/* for non-tree-related stuff */
          unsigned short fid;		/* the file ID */
          struct smb_vc *vcp;		/* back ptr */
--- 260,267 ----
  /* one per file ID; these are really file descriptors */
  typedef struct smb_fid {
  	osi_queue_t q;
!         unsigned long refCount;
!         unsigned long flags;
          osi_mutex_t mx;			/* for non-tree-related stuff */
          unsigned short fid;		/* the file ID */
          struct smb_vc *vcp;		/* back ptr */
***************
*** 313,319 ****
  typedef struct smb_dirSearch {
  	osi_queue_t q;			/* queue of all outstanding cookies */
          osi_mutex_t mx;			/* just in case the caller screws up */
!         int refCount;			/* reference count */
          long cookie;			/* value returned to the caller */
          struct cm_scache *scp;		/* vnode of the dir we're searching */
          time_t lastTime;		/* last time we used this */
--- 313,319 ----
  typedef struct smb_dirSearch {
  	osi_queue_t q;			/* queue of all outstanding cookies */
          osi_mutex_t mx;			/* just in case the caller screws up */
!         unsigned long refCount;			/* reference count */
          long cookie;			/* value returned to the caller */
          struct cm_scache *scp;		/* vnode of the dir we're searching */
          time_t lastTime;		/* last time we used this */
***************
*** 561,566 ****
--- 561,570 ----
  	char *op, cm_user_t *userp, long *readp, int dosflag);
  #endif /* !DJGPP */
  
+ extern long smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char *oldPathp, char *newPathp, int attrs);
+ 
+ extern long smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char *oldPathp, char *newPathp);
+ 
  extern BOOL smb_IsLegalFilename(char *filename);
  
  extern char *smb_GetSharename(void);
Index: openafs/src/WINNT/afsd/smb3.c
diff -c openafs/src/WINNT/afsd/smb3.c:1.42.2.5 openafs/src/WINNT/afsd/smb3.c:1.42.2.9
*** openafs/src/WINNT/afsd/smb3.c:1.42.2.5	Thu Aug 19 15:51:23 2004
--- openafs/src/WINNT/afsd/smb3.c	Mon Oct 18 00:09:28 2004
***************
*** 44,61 ****
   * request */
  cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
  {
! 	smb_user_t *uidp;
      cm_user_t *up = NULL;
          
      uidp = smb_FindUID(vcp, inp-&gt;uid, 0);
      if (!uidp) return NULL;
          
! 	lock_ObtainMutex(&amp;uidp-&gt;mx);
      if (uidp-&gt;unp) {
          up = uidp-&gt;unp-&gt;userp;
          cm_HoldUser(up);
      }
! 	lock_ReleaseMutex(&amp;uidp-&gt;mx);
  
      smb_ReleaseUID(uidp);
  
--- 44,61 ----
   * request */
  cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
  {
!     smb_user_t *uidp;
      cm_user_t *up = NULL;
          
      uidp = smb_FindUID(vcp, inp-&gt;uid, 0);
      if (!uidp) return NULL;
          
!     lock_ObtainMutex(&amp;uidp-&gt;mx);
      if (uidp-&gt;unp) {
          up = uidp-&gt;unp-&gt;userp;
          cm_HoldUser(up);
      }
!     lock_ReleaseMutex(&amp;uidp-&gt;mx);
  
      smb_ReleaseUID(uidp);
  
***************
*** 69,112 ****
   */
  unsigned long smb_ExtAttributes(cm_scache_t *scp)
  {
! 	unsigned long attrs;
  
! 	if (scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY
! 	    || scp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT)
! 		attrs = SMB_ATTR_DIRECTORY;
! 	else
! 		attrs = 0;
! 	/*
! 	 * We used to mark a file RO if it was in an RO volume, but that
! 	 * turns out to be impolitic in NT.  See defect 10007.
! 	 */
  #ifdef notdef
! 	if ((scp-&gt;unixModeBits &amp; 0222) == 0 || (scp-&gt;flags &amp; CM_SCACHEFLAG_RO))
  #endif
  	if ((scp-&gt;unixModeBits &amp; 0222) == 0)
! 		attrs |= SMB_ATTR_READONLY;		/* Read-only */
  
! 	if (attrs == 0)
! 		attrs = SMB_ATTR_NORMAL;		/* FILE_ATTRIBUTE_NORMAL */
  
! 	return attrs;
  }
  
  int smb_V3IsStarMask(char *maskp)
  {
      char tc;
  
! 	while (tc = *maskp++)
          if (tc == '?' || tc == '*') 
              return 1;
! 	return 0;
  }
  
  unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
  {
      if (chainpp) {
! 		/* skip over null-terminated string */
! 		*chainpp = inp + strlen(inp) + 1;
      }
      return inp;
  }   
--- 69,112 ----
   */
  unsigned long smb_ExtAttributes(cm_scache_t *scp)
  {
!     unsigned long attrs;
  
!     if (scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY ||
!         scp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT)
!         attrs = SMB_ATTR_DIRECTORY;
!     else
!         attrs = 0;
!     /*
!      * We used to mark a file RO if it was in an RO volume, but that
!      * turns out to be impolitic in NT.  See defect 10007.
!      */
  #ifdef notdef
!     if ((scp-&gt;unixModeBits &amp; 0222) == 0 || (scp-&gt;flags &amp; CM_SCACHEFLAG_RO))
  #endif
  	if ((scp-&gt;unixModeBits &amp; 0222) == 0)
!             attrs |= SMB_ATTR_READONLY;		/* Read-only */
  
!     if (attrs == 0)
!         attrs = SMB_ATTR_NORMAL;		/* FILE_ATTRIBUTE_NORMAL */
  
!     return attrs;
  }
  
  int smb_V3IsStarMask(char *maskp)
  {
      char tc;
  
!     while (tc = *maskp++)
          if (tc == '?' || tc == '*') 
              return 1;
!     return 0;
  }
  
  unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
  {
      if (chainpp) {
!         /* skip over null-terminated string */
!         *chainpp = inp + strlen(inp) + 1;
      }
      return inp;
  }   
***************
*** 135,141 ****
  
      OutputDebugF("Hexdump length [%d]",len);
  
!     for(i=0;i&lt;len;i++) {
          if(!(i%16)) {
              if(i) {
                  osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
--- 135,141 ----
  
      OutputDebugF("Hexdump length [%d]",len);
  
!     for (i=0;i&lt;len;i++) {
          if(!(i%16)) {
              if(i) {
                  osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
***************
*** 162,239 ****
          osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
          strcat(buf,"\n");
          OutputDebugString(buf);
! }   
  }
  /**/
  
  #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
! void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength){
      SECURITY_STATUS status, istatus;
! 	CredHandle creds = {0,0};
! 	TimeStamp expiry;
! 	SecBufferDesc secOut;
! 	SecBuffer secTok;
! 	CtxtHandle ctx;
! 	ULONG flags;
  
! 	*secBlob = NULL;
! 	*secBlobLength = 0;
  
      OutputDebugF("Negotiating Extended Security");
  
! 	status = AcquireCredentialsHandle(
! 		NULL,
! 		SMB_EXT_SEC_PACKAGE_NAME,
! 		SECPKG_CRED_INBOUND,
! 		NULL,
! 		NULL,
! 		NULL,
! 		NULL,
! 		&amp;creds,
! 		&amp;expiry);
! 
! 	if (status != SEC_E_OK) {
! 		/* Really bad. We return an empty security blob */
! 		OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
! 		goto nes_0;
! 	}
! 
! 	secOut.cBuffers = 1;
! 	secOut.pBuffers = &amp;secTok;
! 	secOut.ulVersion = SECBUFFER_VERSION;
! 
! 	secTok.BufferType = SECBUFFER_TOKEN;
! 	secTok.cbBuffer = 0;
! 	secTok.pvBuffer = NULL;
! 
!         ctx.dwLower = ctx.dwUpper = 0;
! 
! 	status = AcceptSecurityContext(
! 		&amp;creds,
! 		NULL,
! 		NULL,
!         ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
! 		SECURITY_NETWORK_DREP,
! 		&amp;ctx,
! 		&amp;secOut,
! 		&amp;flags,
! 		&amp;expiry
! 		);
! 
! 	if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
! 		OutputDebugF("Completing token...");
! 		istatus = CompleteAuthToken(&amp;ctx, &amp;secOut);
          if ( istatus != SEC_E_OK )
              OutputDebugF("Token completion failed: %x", istatus);
! 	}
  
! 	if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
! 		if (secTok.pvBuffer) {
! 			*secBlobLength = secTok.cbBuffer;
! 			*secBlob = malloc( secTok.cbBuffer );
! 			memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
! 		}
! 	} else {
          if ( status != SEC_E_OK )
              OutputDebugF("AcceptSecurityContext status != CONTINUE  %lX", status);
      }
--- 162,237 ----
          osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
          strcat(buf,"\n");
          OutputDebugString(buf);
!     }   
  }
  /**/
  
  #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
! void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
      SECURITY_STATUS status, istatus;
!     CredHandle creds = {0,0};
!     TimeStamp expiry;
!     SecBufferDesc secOut;
!     SecBuffer secTok;
!     CtxtHandle ctx;
!     ULONG flags;
  
!     *secBlob = NULL;
!     *secBlobLength = 0;
  
      OutputDebugF("Negotiating Extended Security");
  
!     status = AcquireCredentialsHandle( NULL,
!                                        SMB_EXT_SEC_PACKAGE_NAME,
!                                        SECPKG_CRED_INBOUND,
!                                        NULL,
!                                        NULL,
!                                        NULL,
!                                        NULL,
!                                        &amp;creds,
!                                        &amp;expiry);
! 
!     if (status != SEC_E_OK) {       
!         /* Really bad. We return an empty security blob */
!         OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
!         goto nes_0;
!     }
! 
!     secOut.cBuffers = 1;
!     secOut.pBuffers = &amp;secTok;
!     secOut.ulVersion = SECBUFFER_VERSION;
! 
!     secTok.BufferType = SECBUFFER_TOKEN;
!     secTok.cbBuffer = 0;
!     secTok.pvBuffer = NULL;
! 
!     ctx.dwLower = ctx.dwUpper = 0;
! 
!     status = AcceptSecurityContext( &amp;creds,
!                                     NULL,
!                                     NULL,
!                                     ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
!                                     SECURITY_NETWORK_DREP,
!                                     &amp;ctx,
!                                     &amp;secOut,
!                                     &amp;flags,
!                                     &amp;expiry
!                                     );
! 
!     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
!         OutputDebugF("Completing token...");
!         istatus = CompleteAuthToken(&amp;ctx, &amp;secOut);
          if ( istatus != SEC_E_OK )
              OutputDebugF("Token completion failed: %x", istatus);
!     }
  
!     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
!         if (secTok.pvBuffer) {
!             *secBlobLength = secTok.cbBuffer;
!             *secBlob = malloc( secTok.cbBuffer );
!             memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
!         }
!     } else {
          if ( status != SEC_E_OK )
              OutputDebugF("AcceptSecurityContext status != CONTINUE  %lX", status);
      }
***************
*** 241,290 ****
      /* Discard partial security context */
      DeleteSecurityContext(&amp;ctx);
  
! 	if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
  
! 	/* Discard credentials handle.  We'll reacquire one when we get the session setup X */
! 	FreeCredentialsHandle(&amp;creds);
  
    nes_0:
! 	return;
  }
  
  struct smb_ext_context {
! 	CredHandle creds;
! 	CtxtHandle ctx;
! 	int partialTokenLen;
! 	void * partialToken;
! };
  
  long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
      SECURITY_STATUS status, istatus;
! 	CredHandle creds;
! 	TimeStamp expiry;
! 	long code = 0;
! 	SecBufferDesc secBufIn;
! 	SecBuffer secTokIn;
! 	SecBufferDesc secBufOut;
! 	SecBuffer secTokOut;
! 	CtxtHandle ctx;
! 	struct smb_ext_context * secCtx = NULL;
! 	struct smb_ext_context * newSecCtx = NULL;
! 	void * assembledBlob = NULL;
! 	int assembledBlobLength = 0;
! 	ULONG flags;
! 
! 	OutputDebugF("In smb_AuthenticateUserExt");
! 
! 	*secBlobOut = NULL;
! 	*secBlobOutLength = 0;
! 
! 	if (vcp-&gt;flags &amp; SMB_VCFLAG_AUTH_IN_PROGRESS) {
! 		secCtx = vcp-&gt;secCtx;
! 		lock_ObtainMutex(&amp;vcp-&gt;mx);
! 		vcp-&gt;flags &amp;= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
! 		vcp-&gt;secCtx = NULL;
! 		lock_ReleaseMutex(&amp;vcp-&gt;mx);
! 	}
  
      if (secBlobIn) {
          OutputDebugF("Received incoming token:");
--- 239,288 ----
      /* Discard partial security context */
      DeleteSecurityContext(&amp;ctx);
  
!     if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
  
!     /* Discard credentials handle.  We'll reacquire one when we get the session setup X */
!     FreeCredentialsHandle(&amp;creds);
  
    nes_0:
!     return;
  }
  
  struct smb_ext_context {
!     CredHandle creds;
!     CtxtHandle ctx;
!     int partialTokenLen;
!     void * partialToken;
! };      
  
  long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
      SECURITY_STATUS status, istatus;
!     CredHandle creds;
!     TimeStamp expiry;
!     long code = 0;
!     SecBufferDesc secBufIn;
!     SecBuffer secTokIn;
!     SecBufferDesc secBufOut;
!     SecBuffer secTokOut;
!     CtxtHandle ctx;
!     struct smb_ext_context * secCtx = NULL;
!     struct smb_ext_context * newSecCtx = NULL;
!     void * assembledBlob = NULL;
!     int assembledBlobLength = 0;
!     ULONG flags;
! 
!     OutputDebugF("In smb_AuthenticateUserExt");
! 
!     *secBlobOut = NULL;
!     *secBlobOutLength = 0;
! 
!     if (vcp-&gt;flags &amp; SMB_VCFLAG_AUTH_IN_PROGRESS) {
!         secCtx = vcp-&gt;secCtx;
!         lock_ObtainMutex(&amp;vcp-&gt;mx);
!         vcp-&gt;flags &amp;= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
!         vcp-&gt;secCtx = NULL;
!         lock_ReleaseMutex(&amp;vcp-&gt;mx);
!     }
  
      if (secBlobIn) {
          OutputDebugF("Received incoming token:");
***************
*** 296,425 ****
          creds = secCtx-&gt;creds;
          ctx = secCtx-&gt;ctx;
  
! 		if (secCtx-&gt;partialToken) {
! 			assembledBlobLength = secCtx-&gt;partialTokenLen + secBlobInLength;
! 			assembledBlob = malloc(assembledBlobLength);
              memcpy(assembledBlob,secCtx-&gt;partialToken, secCtx-&gt;partialTokenLen);
! 			memcpy(((BYTE *)assembledBlob) + secCtx-&gt;partialTokenLen, secBlobIn, secBlobInLength);
! 		}
! 	} else {
! 		status = AcquireCredentialsHandle(
! 			NULL,
! 			SMB_EXT_SEC_PACKAGE_NAME,
! 			SECPKG_CRED_INBOUND,
! 			NULL,
! 			NULL,
! 			NULL,
! 			NULL,
! 			&amp;creds,
! 			&amp;expiry);
! 
! 		if (status != SEC_E_OK) {
! 			OutputDebugF("Can't acquire Credentials handle [%lX]", status);
! 			code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
! 			goto aue_0;
! 		}
  
! 		ctx.dwLower = 0;
! 		ctx.dwUpper = 0;
! 	}
  
      secBufIn.cBuffers = 1;
! 	secBufIn.pBuffers = &amp;secTokIn;
! 	secBufIn.ulVersion = SECBUFFER_VERSION;
  
! 	secTokIn.BufferType = SECBUFFER_TOKEN;
! 	if (assembledBlob) {
! 		secTokIn.cbBuffer = assembledBlobLength;
! 		secTokIn.pvBuffer = assembledBlob;
! 	} else {
! 		secTokIn.cbBuffer = secBlobInLength;
! 		secTokIn.pvBuffer = secBlobIn;
! 	}
  
! 	secBufOut.cBuffers = 1;
! 	secBufOut.pBuffers = &amp;secTokOut;
! 	secBufOut.ulVersion = SECBUFFER_VERSION;
! 
! 	secTokOut.BufferType = SECBUFFER_TOKEN;
! 	secTokOut.cbBuffer = 0;
! 	secTokOut.pvBuffer = NULL;
! 
! 	status = AcceptSecurityContext(
! 		&amp;creds,
! 		((secCtx)?&amp;ctx:NULL),
! 		&amp;secBufIn,
! 		ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR	| ASC_REQ_ALLOCATE_MEMORY,
! 		SECURITY_NETWORK_DREP,
! 		&amp;ctx,
! 		&amp;secBufOut,
! 		&amp;flags,
! 		&amp;expiry
! 		);
! 
! 	if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
! 		OutputDebugF("Completing token...");
! 		istatus = CompleteAuthToken(&amp;ctx, &amp;secBufOut);
          if ( istatus != SEC_E_OK )
              OutputDebugF("Token completion failed: %lX", istatus);
! 	}
  
! 	if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
! 		OutputDebugF("Continue needed");
  
! 		newSecCtx = malloc(sizeof(*newSecCtx));
  
! 		newSecCtx-&gt;creds = creds;
! 		newSecCtx-&gt;ctx = ctx;
! 		newSecCtx-&gt;partialToken = NULL;
! 		newSecCtx-&gt;partialTokenLen = 0;
! 
! 		lock_ObtainMutex( &amp;vcp-&gt;mx );
! 		vcp-&gt;flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
! 		vcp-&gt;secCtx = newSecCtx;
! 		lock_ReleaseMutex( &amp;vcp-&gt;mx );
  
! 		code = CM_ERROR_GSSCONTINUE;
! 	}
  
! 	if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
!          status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &amp;&amp; 
!         secTokOut.pvBuffer) {
! 		OutputDebugF("Need to send token back to client");
! 
! 		*secBlobOutLength = secTokOut.cbBuffer;
! 		*secBlobOut = malloc(secTokOut.cbBuffer);
! 		memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
  
          OutputDebugF("Outgoing token:");
          OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
! 	} else if (status == SEC_E_INCOMPLETE_MESSAGE) {
! 		OutputDebugF("Incomplete message");
  
! 		newSecCtx = malloc(sizeof(*newSecCtx));
  
! 		newSecCtx-&gt;creds = creds;
! 		newSecCtx-&gt;ctx = ctx;
! 		newSecCtx-&gt;partialToken = malloc(secTokOut.cbBuffer);
! 		memcpy(newSecCtx-&gt;partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
! 		newSecCtx-&gt;partialTokenLen = secTokOut.cbBuffer;
! 
! 		lock_ObtainMutex( &amp;vcp-&gt;mx );
! 		vcp-&gt;flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
! 		vcp-&gt;secCtx = newSecCtx;
! 		lock_ReleaseMutex( &amp;vcp-&gt;mx );
  
! 		code = CM_ERROR_GSSCONTINUE;
! 	}
  
! 	if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
! 		/* woo hoo! */
! 		SecPkgContext_Names names;
  
! 		OutputDebugF("Authentication completed");
          OutputDebugF("Returned flags : [%lX]", flags);
  
! 		if (!QueryContextAttributes(&amp;ctx, SECPKG_ATTR_NAMES, &amp;names)) {
              OutputDebugF("Received name [%s]", names.sUserName);
              strcpy(usern, names.sUserName);
              strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
--- 294,421 ----
          creds = secCtx-&gt;creds;
          ctx = secCtx-&gt;ctx;
  
!         if (secCtx-&gt;partialToken) {
!             assembledBlobLength = secCtx-&gt;partialTokenLen + secBlobInLength;
!             assembledBlob = malloc(assembledBlobLength);
              memcpy(assembledBlob,secCtx-&gt;partialToken, secCtx-&gt;partialTokenLen);
!             memcpy(((BYTE *)assembledBlob) + secCtx-&gt;partialTokenLen, secBlobIn, secBlobInLength);
!         }
!     } else {
!         status = AcquireCredentialsHandle( NULL,
!                                            SMB_EXT_SEC_PACKAGE_NAME,
!                                            SECPKG_CRED_INBOUND,
!                                            NULL,
!                                            NULL,
!                                            NULL,
!                                            NULL,
!                                            &amp;creds,
!                                            &amp;expiry);
! 
!         if (status != SEC_E_OK) {
!             OutputDebugF("Can't acquire Credentials handle [%lX]", status);
!             code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
!             goto aue_0;
!         }
  
!         ctx.dwLower = 0;
!         ctx.dwUpper = 0;
!     }
  
      secBufIn.cBuffers = 1;
!     secBufIn.pBuffers = &amp;secTokIn;
!     secBufIn.ulVersion = SECBUFFER_VERSION;
  
!     secTokIn.BufferType = SECBUFFER_TOKEN;
!     if (assembledBlob) {
!         secTokIn.cbBuffer = assembledBlobLength;
!         secTokIn.pvBuffer = assembledBlob;
!     } else {
!         secTokIn.cbBuffer = secBlobInLength;
!         secTokIn.pvBuffer = secBlobIn;
!     }
  
!     secBufOut.cBuffers = 1;
!     secBufOut.pBuffers = &amp;secTokOut;
!     secBufOut.ulVersion = SECBUFFER_VERSION;
! 
!     secTokOut.BufferType = SECBUFFER_TOKEN;
!     secTokOut.cbBuffer = 0;
!     secTokOut.pvBuffer = NULL;
! 
!     status = AcceptSecurityContext( &amp;creds,
!                                     ((secCtx)?&amp;ctx:NULL),
!                                     &amp;secBufIn,
!                                     ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR	| ASC_REQ_ALLOCATE_MEMORY,
!                                     SECURITY_NETWORK_DREP,
!                                     &amp;ctx,
!                                     &amp;secBufOut,
!                                     &amp;flags,
!                                     &amp;expiry
!                                     );
! 
!     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
!         OutputDebugF("Completing token...");
!         istatus = CompleteAuthToken(&amp;ctx, &amp;secBufOut);
          if ( istatus != SEC_E_OK )
              OutputDebugF("Token completion failed: %lX", istatus);
!     }
  
!     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
!         OutputDebugF("Continue needed");
  
!         newSecCtx = malloc(sizeof(*newSecCtx));
  
!         newSecCtx-&gt;creds = creds;
!         newSecCtx-&gt;ctx = ctx;
!         newSecCtx-&gt;partialToken = NULL;
!         newSecCtx-&gt;partialTokenLen = 0;
  
!         lock_ObtainMutex( &amp;vcp-&gt;mx );
!         vcp-&gt;flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
!         vcp-&gt;secCtx = newSecCtx;
!         lock_ReleaseMutex( &amp;vcp-&gt;mx );
! 
!         code = CM_ERROR_GSSCONTINUE;
!     }
! 
!     if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
!           status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &amp;&amp; 
!          secTokOut.pvBuffer) {
!         OutputDebugF("Need to send token back to client");
  
!         *secBlobOutLength = secTokOut.cbBuffer;
!         *secBlobOut = malloc(secTokOut.cbBuffer);
!         memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
  
          OutputDebugF("Outgoing token:");
          OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
!     } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
!         OutputDebugF("Incomplete message");
  
!         newSecCtx = malloc(sizeof(*newSecCtx));
  
!         newSecCtx-&gt;creds = creds;
!         newSecCtx-&gt;ctx = ctx;
!         newSecCtx-&gt;partialToken = malloc(secTokOut.cbBuffer);
!         memcpy(newSecCtx-&gt;partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
!         newSecCtx-&gt;partialTokenLen = secTokOut.cbBuffer;
  
!         lock_ObtainMutex( &amp;vcp-&gt;mx );
!         vcp-&gt;flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
!         vcp-&gt;secCtx = newSecCtx;
!         lock_ReleaseMutex( &amp;vcp-&gt;mx );
! 
!         code = CM_ERROR_GSSCONTINUE;
!     }
  
!     if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
!         /* woo hoo! */
!         SecPkgContext_Names names;
  
!         OutputDebugF("Authentication completed");
          OutputDebugF("Returned flags : [%lX]", flags);
  
!         if (!QueryContextAttributes(&amp;ctx, SECPKG_ATTR_NAMES, &amp;names)) {
              OutputDebugF("Received name [%s]", names.sUserName);
              strcpy(usern, names.sUserName);
              strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
***************
*** 429,435 ****
              OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
              code = CM_ERROR_BADPASSWORD; 
          }
! 	} else if (!code) {
          switch ( status ) {
          case SEC_E_INVALID_TOKEN:
              OutputDebugF("Returning bad password :: INVALID_TOKEN");
--- 425,431 ----
              OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
              code = CM_ERROR_BADPASSWORD; 
          }
!     } else if (!code) {
          switch ( status ) {
          case SEC_E_INVALID_TOKEN:
              OutputDebugF("Returning bad password :: INVALID_TOKEN");
***************
*** 461,488 ****
          default:
              OutputDebugF("Returning bad password :: Status == %lX", status);
          }
! 		code = CM_ERROR_BADPASSWORD;
! 	}
  
! 	if (secCtx) {
! 		if (secCtx-&gt;partialToken) free(secCtx-&gt;partialToken);
! 		free(secCtx);
! 	}
  
! 	if (assembledBlob) {
! 		free(assembledBlob);
! 	}
  
! 	if (secTokOut.pvBuffer)
! 		FreeContextBuffer(secTokOut.pvBuffer);
  
! 	if (code != CM_ERROR_GSSCONTINUE) {
! 		DeleteSecurityContext(&amp;ctx);
! 		FreeCredentialsHandle(&amp;creds);
! 	}
  
    aue_0:
! 	return code;
  }
  
  #define P_LEN 256
--- 457,484 ----
          default:
              OutputDebugF("Returning bad password :: Status == %lX", status);
          }
!         code = CM_ERROR_BADPASSWORD;
!     }
  
!     if (secCtx) {
!         if (secCtx-&gt;partialToken) free(secCtx-&gt;partialToken);
!         free(secCtx);
!     }
  
!     if (assembledBlob) {
!         free(assembledBlob);
!     }
  
!     if (secTokOut.pvBuffer)
!         FreeContextBuffer(secTokOut.pvBuffer);
  
!     if (code != CM_ERROR_GSSCONTINUE) {
!         DeleteSecurityContext(&amp;ctx);
!         FreeCredentialsHandle(&amp;creds);
!     }
  
    aue_0:
!     return code;
  }
  
  #define P_LEN 256
***************
*** 491,643 ****
  /* LsaLogonUser expects input parameters to be in a contiguous block of memory. 
     So put stuff in a struct. */
  struct Lm20AuthBlob {
! 	MSV1_0_LM20_LOGON lmlogon;
! 	BYTE ciResponse[P_RESP_LEN];    /* Unicode representation */
! 	BYTE csResponse[P_RESP_LEN];    /* ANSI representation */
! 	WCHAR accountNameW[P_LEN];
! 	WCHAR primaryDomainW[P_LEN];
! 	WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
! 	TOKEN_GROUPS tgroups;
! 	TOKEN_SOURCE tsource;
  };
  
! long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) {
  
! 	NTSTATUS nts, ntsEx;
! 	struct Lm20AuthBlob lmAuth;
! 	PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
! 	QUOTA_LIMITS quotaLimits;
! 	DWORD size;
! 	ULONG lmprofilepSize;
! 	LUID lmSession;
! 	HANDLE lmToken;
! 
! 	OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
! 	OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
! 
! 	if (ciPwdLength &gt; P_RESP_LEN || csPwdLength &gt; P_RESP_LEN) {
! 		OutputDebugF("ciPwdLength or csPwdLength is too long");
! 		return CM_ERROR_BADPASSWORD;
! 	}
  
! 	memset(&amp;lmAuth,0,sizeof(lmAuth));
  
! 	lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
  	
! 	lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
! 	mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
! 	lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
! 	lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
! 
! 	lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
! 	mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
! 	lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
! 	lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
! 
! 	lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
! 	lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
! 	size = MAX_COMPUTERNAME_LENGTH + 1;
! 	GetComputerNameW(lmAuth.workstationW, &amp;size);
      lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
  
! 	memcpy(lmAuth.lmlogon.ChallengeToClient, vcp-&gt;encKey, MSV1_0_CHALLENGE_LENGTH);
  
! 	lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
! 	lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
! 	lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
! 	memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
! 
! 	lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
! 	lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
! 	lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
! 	memcpy(lmAuth.csResponse, csPwd, csPwdLength);
! 
! 	lmAuth.lmlogon.ParameterControl = 0;
! 
! 	lmAuth.tgroups.GroupCount = 0;
! 	lmAuth.tgroups.Groups[0].Sid = NULL;
! 	lmAuth.tgroups.Groups[0].Attributes = 0;
! 
! 	lmAuth.tsource.SourceIdentifier.HighPart = 0;
! 	lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
! 	strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
! 
! 	nts = LsaLogonUser(
! 		smb_lsaHandle,
! 		&amp;smb_lsaLogonOrigin,
! 		Network, /*3*/
!         smb_lsaSecPackage,
! 		&amp;lmAuth,
! 		sizeof(lmAuth),
!         &amp;lmAuth.tgroups,
! 		&amp;lmAuth.tsource,
! 		&amp;lmprofilep,
! 		&amp;lmprofilepSize,
! 		&amp;lmSession,
! 		&amp;lmToken,
! 		&amp;quotaLimits,
! 		&amp;ntsEx);
! 
! 	OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
! 	OutputDebugF("Extended status is 0x%lX", ntsEx);
! 
! 	if (nts == ERROR_SUCCESS) {
! 		/* free the token */
! 		LsaFreeReturnBuffer(lmprofilep);
          CloseHandle(lmToken);
! 		return 0;
! 	} else {
! 		/* No AFS for you */
! 		if (nts == 0xC000015BL)
! 			return CM_ERROR_BADLOGONTYPE;
! 		else /* our catchall is a bad password though we could be more specific */
! 			return CM_ERROR_BADPASSWORD;
! 	}
  }
  
  /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
! long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) {
  
! 	char * atsign;
! 	const char * domain;
  
! 	/* check if we have sane input */
! 	if ((strlen(accountName) + strlen(domainName) + 1) &gt; SMB_MAX_USERNAME_LENGTH)
! 		return 1;
! 
! 	/* we could get : [accountName][domainName]
! 	   [user][domain]
! 	   [user@domain][]
! 	   [user][]/[user][?]
! 	   [][]/[][?] */
! 
! 	atsign = strchr(accountName, '@');
! 
! 	if (atsign) /* [user@domain][] -&gt; [user@domain][domain] */
! 		domain = atsign + 1;
! 	else
! 		domain = domainName;
! 
! 	/* if for some reason the client doesn't know what domain to use,
! 		   it will either return an empty string or a '?' */
! 	if (!domain[0] || domain[0] == '?')
! 		/* Empty domains and empty usernames are usually sent from tokenless contexts.
! 		   This way such logins will get an empty username (easy to check).  I don't know 
! 		   when a non-empty username would be supplied with an anonymous domain, but *shrug* */
! 		strcpy(usern,accountName);
! 	else {
! 		/* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
! 		strcpy(usern,domain);
! 		strcat(usern,"\\");
! 		if (atsign)
! 			strncat(usern,accountName,atsign - accountName);
! 		else
! 			strcat(usern,accountName);
! 	}
  
! 	strlwr(usern);
  
! 	return 0;
  }
  
  /* When using SMB auth, all SMB sessions have to pass through here first to
--- 487,638 ----
  /* LsaLogonUser expects input parameters to be in a contiguous block of memory. 
     So put stuff in a struct. */
  struct Lm20AuthBlob {
!     MSV1_0_LM20_LOGON lmlogon;
!     BYTE ciResponse[P_RESP_LEN];    /* Unicode representation */
!     BYTE csResponse[P_RESP_LEN];    /* ANSI representation */
!     WCHAR accountNameW[P_LEN];
!     WCHAR primaryDomainW[P_LEN];
!     WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
!     TOKEN_GROUPS tgroups;
!     TOKEN_SOURCE tsource;
  };
  
! long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) 
! {
!     NTSTATUS nts, ntsEx;
!     struct Lm20AuthBlob lmAuth;
!     PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
!     QUOTA_LIMITS quotaLimits;
!     DWORD size;
!     ULONG lmprofilepSize;
!     LUID lmSession;
!     HANDLE lmToken;
! 
!     OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
!     OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
  
!     if (ciPwdLength &gt; P_RESP_LEN || csPwdLength &gt; P_RESP_LEN) {
!         OutputDebugF("ciPwdLength or csPwdLength is too long");
!         return CM_ERROR_BADPASSWORD;
!     }
  
!     memset(&amp;lmAuth,0,sizeof(lmAuth));
  
!     lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
  	
!     lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
!     mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
!     lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
!     lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
! 
!     lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
!     mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
!     lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
!     lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
! 
!     lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
!     lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
!     size = MAX_COMPUTERNAME_LENGTH + 1;
!     GetComputerNameW(lmAuth.workstationW, &amp;size);
      lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
  
!     memcpy(lmAuth.lmlogon.ChallengeToClient, vcp-&gt;encKey, MSV1_0_CHALLENGE_LENGTH);
  
!     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
!     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
!     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
!     memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
! 
!     lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
!     lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
!     lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
!     memcpy(lmAuth.csResponse, csPwd, csPwdLength);
! 
!     lmAuth.lmlogon.ParameterControl = 0;
! 
!     lmAuth.tgroups.GroupCount = 0;
!     lmAuth.tgroups.Groups[0].Sid = NULL;
!     lmAuth.tgroups.Groups[0].Attributes = 0;
! 
!     lmAuth.tsource.SourceIdentifier.HighPart = 0;
!     lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
!     strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
! 
!     nts = LsaLogonUser( smb_lsaHandle,
!                         &amp;smb_lsaLogonOrigin,
!                         Network, /*3*/
!                         smb_lsaSecPackage,
!                         &amp;lmAuth,
!                         sizeof(lmAuth),
!                         &amp;lmAuth.tgroups,
!                         &amp;lmAuth.tsource,
!                         &amp;lmprofilep,
!                         &amp;lmprofilepSize,
!                         &amp;lmSession,
!                         &amp;lmToken,
!                         &amp;quotaLimits,
!                         &amp;ntsEx);
! 
!     OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
!     OutputDebugF("Extended status is 0x%lX", ntsEx);
! 
!     if (nts == ERROR_SUCCESS) {
!         /* free the token */
!         LsaFreeReturnBuffer(lmprofilep);
          CloseHandle(lmToken);
!         return 0;
!     } else {
!         /* No AFS for you */
!         if (nts == 0xC000015BL)
!             return CM_ERROR_BADLOGONTYPE;
!         else /* our catchall is a bad password though we could be more specific */
!             return CM_ERROR_BADPASSWORD;
!     }       
  }
  
  /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
! long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) 
! {
!     char * atsign;
!     const char * domain;
  
!     /* check if we have sane input */
!     if ((strlen(accountName) + strlen(domainName) + 1) &gt; SMB_MAX_USERNAME_LENGTH)
!         return 1;
  
!     /* we could get : [accountName][domainName]
!        [user][domain]
!        [user@domain][]
!        [user][]/[user][?]
!        [][]/[][?] */
! 
!     atsign = strchr(accountName, '@');
! 
!     if (atsign) /* [user@domain][] -&gt; [user@domain][domain] */
!         domain = atsign + 1;
!     else
!         domain = domainName;
! 
!     /* if for some reason the client doesn't know what domain to use,
!        it will either return an empty string or a '?' */
!     if (!domain[0] || domain[0] == '?')
!         /* Empty domains and empty usernames are usually sent from tokenless contexts.
!            This way such logins will get an empty username (easy to check).  I don't know 
!            when a non-empty username would be supplied with an anonymous domain, but *shrug* */
!         strcpy(usern,accountName);
!     else {
!         /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
!         strcpy(usern,domain);
!         strcat(usern,"\\");
!         if (atsign)
!             strncat(usern,accountName,atsign - accountName);
!         else
!             strcat(usern,accountName);
!     }       
  
!     strlwr(usern);
  
!     return 0;
  }
  
  /* When using SMB auth, all SMB sessions have to pass through here first to
***************
*** 739,790 ****
      }  else { /* V3 */
          unsigned ciPwdLength;
          char *ciPwd;
! 		char *accountName;
! 		char *primaryDomain;
  
! 		ciPwdLength = smb_GetSMBParm(inp, 7);
          tp = smb_GetSMBData(inp, NULL);
! 		ciPwd = tp;
! 		tp += ciPwdLength;
  
! 		accountName = smb_ParseString(tp, &amp;tp);
! 		primaryDomain = smb_ParseString(tp, NULL);
  
! 		if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
! 			/* shouldn't happen */
! 			code = CM_ERROR_BADSMB;
              goto after_read_packet;
! 		}
  
          /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
           * to NTLM.
           */
! 		if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
! 			code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
! 		}
! 	}
  
    after_read_packet:
! 	/* note down that we received a session setup X and set the capabilities flag */
! 	if (!(vcp-&gt;flags &amp; SMB_VCFLAG_SESSX_RCVD)) {
! 		lock_ObtainMutex(&amp;vcp-&gt;mx);
! 		vcp-&gt;flags |= SMB_VCFLAG_SESSX_RCVD;
          /* for the moment we can only deal with NTSTATUS */
          if (caps &amp; NTNEGOTIATE_CAPABILITY_NTSTATUS) {
              vcp-&gt;flags |= SMB_VCFLAG_STATUS32;
!         }
! 		lock_ReleaseMutex(&amp;vcp-&gt;mx);
! 	}
  
! 	/* code would be non-zero if there was an authentication failure.
! 	   Ideally we would like to invalidate the uid for this session or break
! 	   early to avoid accidently stealing someone else's tokens. */
  
! 	if (code) {
! 		return code;
! 	}
  
! 	OutputDebugF("Received username=[%s]", usern);
  
      /* On Windows 2000, this function appears to be called more often than
         it is expected to be called. This resulted in multiple smb_user_t
--- 734,785 ----
      }  else { /* V3 */
          unsigned ciPwdLength;
          char *ciPwd;
!         char *accountName;
!         char *primaryDomain;
  
!         ciPwdLength = smb_GetSMBParm(inp, 7);
          tp = smb_GetSMBData(inp, NULL);
!         ciPwd = tp;
!         tp += ciPwdLength;
  
!         accountName = smb_ParseString(tp, &amp;tp);
!         primaryDomain = smb_ParseString(tp, NULL);
  
!         if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
!             /* shouldn't happen */
!             code = CM_ERROR_BADSMB;
              goto after_read_packet;
!         }
  
          /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
           * to NTLM.
           */
!         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
!             code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
!         }
!     }
  
    after_read_packet:
!     /* note down that we received a session setup X and set the capabilities flag */
!     if (!(vcp-&gt;flags &amp; SMB_VCFLAG_SESSX_RCVD)) {
!         lock_ObtainMutex(&amp;vcp-&gt;mx);
!         vcp-&gt;flags |= SMB_VCFLAG_SESSX_RCVD;
          /* for the moment we can only deal with NTSTATUS */
          if (caps &amp; NTNEGOTIATE_CAPABILITY_NTSTATUS) {
              vcp-&gt;flags |= SMB_VCFLAG_STATUS32;
!         }       
!         lock_ReleaseMutex(&amp;vcp-&gt;mx);
!     }
  
!     /* code would be non-zero if there was an authentication failure.
!        Ideally we would like to invalidate the uid for this session or break
!        early to avoid accidently stealing someone else's tokens. */
  
!     if (code) {
!         return code;
!     }
  
!     OutputDebugF("Received username=[%s]", usern);
  
      /* On Windows 2000, this function appears to be called more often than
         it is expected to be called. This resulted in multiple smb_user_t
***************
*** 800,807 ****
          unp = uidp-&gt;unp;
          userp = unp-&gt;userp;
          newUid = (unsigned short)uidp-&gt;userID;  /* For some reason these are different types!*/
!                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp-&gt;lana,vcp-&gt;lsn,newUid,osi_LogSaveString(smb_logp, usern));
! 		osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp-&gt;lana,vcp-&gt;lsn,newUid);
          smb_ReleaseUID(uidp);
      }
      else {
--- 795,802 ----
          unp = uidp-&gt;unp;
          userp = unp-&gt;userp;
          newUid = (unsigned short)uidp-&gt;userID;  /* For some reason these are different types!*/
!         osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp-&gt;lana,vcp-&gt;lsn,newUid,osi_LogSaveString(smb_logp, usern));
!         osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp-&gt;lana,vcp-&gt;lsn,newUid);
          smb_ReleaseUID(uidp);
      }
      else {
***************
*** 826,833 ****
          uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
          lock_ObtainMutex(&amp;uidp-&gt;mx);
          uidp-&gt;unp = unp;
!                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp-&gt;lana,vcp-&gt;lsn,newUid,osi_LogSaveString(smb_logp, usern));
! 		osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp-&gt;lana,vcp-&gt;lsn,newUid);
          lock_ReleaseMutex(&amp;uidp-&gt;mx);
          smb_ReleaseUID(uidp);
      }
--- 821,828 ----
          uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
          lock_ObtainMutex(&amp;uidp-&gt;mx);
          uidp-&gt;unp = unp;
!         osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp-&gt;lana,vcp-&gt;lsn,newUid,osi_LogSaveString(smb_logp, usern));
!         osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp-&gt;lana,vcp-&gt;lsn,newUid);
          lock_ReleaseMutex(&amp;uidp-&gt;mx);
          smb_ReleaseUID(uidp);
      }
***************
*** 881,915 ****
  
  long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	smb_user_t *uidp;
  
! 	/* don't get tokens from this VC */
! 	vcp-&gt;flags |= SMB_VCFLAG_ALREADYDEAD;
  
! 	inp-&gt;flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
  
! 	/* find the tree and free it */
      uidp = smb_FindUID(vcp, ((smb_t *)inp)-&gt;uid, 0);
      /* TODO: smb_ReleaseUID() ? */
      if (uidp) {
! 		char *s1 = NULL, *s2 = NULL;
  
! 		if (s2 == NULL) s2 = " ";
! 		if (s1 == NULL) {s1 = s2; s2 = " ";}
  
! 		osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp-&gt;userID,
!                  osi_LogSaveString(smb_logp, (uidp-&gt;unp) ? uidp-&gt;unp-&gt;name: " "), s1, s2);
  
! 		lock_ObtainMutex(&amp;uidp-&gt;mx);
! 		uidp-&gt;flags |= SMB_USERFLAG_DELETE;
! 		/*
! 		 * it doesn't get deleted right away
! 		 * because the vcp points to it
! 		 */
          lock_ReleaseMutex(&amp;uidp-&gt;mx);
      }
! 	else    
! 		osi_Log0(smb_logp, "SMB3 user logoffX");
  
      smb_SetSMBDataLength(outp, 0);
      return 0;
--- 876,910 ----
  
  long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     smb_user_t *uidp;
  
!     /* don't get tokens from this VC */
!     vcp-&gt;flags |= SMB_VCFLAG_ALREADYDEAD;
  
!     inp-&gt;flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
  
!     /* find the tree and free it */
      uidp = smb_FindUID(vcp, ((smb_t *)inp)-&gt;uid, 0);
      /* TODO: smb_ReleaseUID() ? */
      if (uidp) {
!         char *s1 = NULL, *s2 = NULL;
  
!         if (s2 == NULL) s2 = " ";
!         if (s1 == NULL) {s1 = s2; s2 = " ";}
  
!         osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp-&gt;userID,
!                   osi_LogSaveString(smb_logp, (uidp-&gt;unp) ? uidp-&gt;unp-&gt;name: " "), s1, s2);
  
!         lock_ObtainMutex(&amp;uidp-&gt;mx);
!         uidp-&gt;flags |= SMB_USERFLAG_DELETE;
!         /*
!          * it doesn't get deleted right away
!          * because the vcp points to it
!          */
          lock_ReleaseMutex(&amp;uidp-&gt;mx);
      }
!     else    
!         osi_Log0(smb_logp, "SMB3 user logoffX");
  
      smb_SetSMBDataLength(outp, 0);
      return 0;
***************
*** 923,1011 ****
      smb_user_t *uidp;
      unsigned short newTid;
      char shareName[256];
! 	char *sharePath;
! 	int shareFound;
      char *tp;
      char *pathp;
      char *passwordp;
! 	char *servicep;
      cm_user_t *userp;
! 	int ipc = 0;
          
! 	osi_Log0(smb_logp, "SMB3 receive tree connect");
  
! 	/* parse input parameters */
! 	tp = smb_GetSMBData(inp, NULL);
      passwordp = smb_ParseString(tp, &amp;tp);
! 	pathp = smb_ParseString(tp, &amp;tp);
! 	servicep = smb_ParseString(tp, &amp;tp);
  
! 	tp = strrchr(pathp, '\\');
      if (!tp) {
          return CM_ERROR_BADSMB;
      }
      strcpy(shareName, tp+1);
  
      osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
!         osi_LogSaveString(smb_logp, pathp),
!         osi_LogSaveString(smb_logp, shareName));
  
! 	if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
  #ifndef NO_IPC
! 		osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
! 		ipc = 1;
  #else
! 		return CM_ERROR_NOIPC;
  #endif
! 	}
  
      userp = smb_GetUser(vcp, inp);
  
! 	lock_ObtainMutex(&amp;vcp-&gt;mx);
      newTid = vcp-&gt;tidCounter++;
! 	lock_ReleaseMutex(&amp;vcp-&gt;mx);
          
! 	tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
  
! 	if(!ipc) {
!     uidp = smb_FindUID(vcp, ((smb_t *)inp)-&gt;uid, 0);
  	shareFound = smb_FindShare(vcp, uidp, shareName, &amp;sharePath);
!     if (uidp)
!         smb_ReleaseUID(uidp);
  	if (!shareFound) {
! 		smb_ReleaseTID(tidp);
! 		return CM_ERROR_BADSHARENAME;
  	}
  
  	if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
!     {
!         int policy = smb_FindShareCSCPolicy(shareName);
!         smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy &lt;&lt; 2));
      }
- 	} else {
- 		smb_SetSMBParm(outp, 2, 0);
- 		sharePath = NULL;
- 	}
  
      lock_ObtainMutex(&amp;tidp-&gt;mx);
      tidp-&gt;userp = userp;
! 	tidp-&gt;pathname = sharePath;
! 	if(ipc) tidp-&gt;flags |= SMB_TIDFLAG_IPC;
      lock_ReleaseMutex(&amp;tidp-&gt;mx);
      smb_ReleaseTID(tidp);
  
! 	((smb_t *)outp)-&gt;tid = newTid;
! 	((smb_t *)inp)-&gt;tid = newTid;
! 	tp = smb_GetSMBData(outp, NULL);
! 	if(!ipc) {
!     *tp++ = 'A';
!     *tp++ = ':';
!     *tp++ = 0;
!     smb_SetSMBDataLength(outp, 3);
! 	} else {
! 		strcpy(tp, "IPC");
! 		smb_SetSMBDataLength(outp, 4);
! 	}
  
      osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
      return 0;
--- 918,1006 ----
      smb_user_t *uidp;
      unsigned short newTid;
      char shareName[256];
!     char *sharePath;
!     int shareFound;
      char *tp;
      char *pathp;
      char *passwordp;
!     char *servicep;
      cm_user_t *userp;
!     int ipc = 0;
          
!     osi_Log0(smb_logp, "SMB3 receive tree connect");
  
!     /* parse input parameters */
!     tp = smb_GetSMBData(inp, NULL);
      passwordp = smb_ParseString(tp, &amp;tp);
!     pathp = smb_ParseString(tp, &amp;tp);
!     servicep = smb_ParseString(tp, &amp;tp);
  
!     tp = strrchr(pathp, '\\');
      if (!tp) {
          return CM_ERROR_BADSMB;
      }
      strcpy(shareName, tp+1);
  
      osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
!              osi_LogSaveString(smb_logp, pathp),
!              osi_LogSaveString(smb_logp, shareName));
  
!     if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
  #ifndef NO_IPC
!         osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
!         ipc = 1;
  #else
!         return CM_ERROR_NOIPC;
  #endif
!     }
  
      userp = smb_GetUser(vcp, inp);
  
!     lock_ObtainMutex(&amp;vcp-&gt;mx);
      newTid = vcp-&gt;tidCounter++;
!     lock_ReleaseMutex(&amp;vcp-&gt;mx);
          
!     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
  
!     if(!ipc) {
!         uidp = smb_FindUID(vcp, ((smb_t *)inp)-&gt;uid, 0);
  	shareFound = smb_FindShare(vcp, uidp, shareName, &amp;sharePath);
!         if (uidp)
!             smb_ReleaseUID(uidp);
  	if (!shareFound) {
!             smb_ReleaseTID(tidp);
!             return CM_ERROR_BADSHARENAME;
  	}
  
  	if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
!         {
!             int policy = smb_FindShareCSCPolicy(shareName);
!             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy &lt;&lt; 2));
!         }
!     } else {
!         smb_SetSMBParm(outp, 2, 0);
!         sharePath = NULL;
      }
  
      lock_ObtainMutex(&amp;tidp-&gt;mx);
      tidp-&gt;userp = userp;
!     tidp-&gt;pathname = sharePath;
!     if(ipc) tidp-&gt;flags |= SMB_TIDFLAG_IPC;
      lock_ReleaseMutex(&amp;tidp-&gt;mx);
      smb_ReleaseTID(tidp);
  
!     ((smb_t *)outp)-&gt;tid = newTid;
!     ((smb_t *)inp)-&gt;tid = newTid;
!     tp = smb_GetSMBData(outp, NULL);
!     if (!ipc) {
!         *tp++ = 'A';
!         *tp++ = ':';
!         *tp++ = 0;
!         smb_SetSMBDataLength(outp, 3);
!     } else {
!         strcpy(tp, "IPC");
!         smb_SetSMBDataLength(outp, 4);
!     }
  
      osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
      return 0;
***************
*** 1014,1025 ****
  /* must be called with global tran lock held */
  smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
  {
! 	smb_tran2Packet_t *tp;
      smb_t *smbp;
          
      smbp = (smb_t *) inp-&gt;data;
! 	for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&amp;tp-&gt;q)) {
! 		if (tp-&gt;vcp == vcp &amp;&amp; tp-&gt;mid == smbp-&gt;mid &amp;&amp; tp-&gt;tid == smbp-&gt;tid)
              return tp;
      }
      return NULL;
--- 1009,1020 ----
  /* must be called with global tran lock held */
  smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
  {
!     smb_tran2Packet_t *tp;
      smb_t *smbp;
          
      smbp = (smb_t *) inp-&gt;data;
!     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&amp;tp-&gt;q)) {
!         if (tp-&gt;vcp == vcp &amp;&amp; tp-&gt;mid == smbp-&gt;mid &amp;&amp; tp-&gt;tid == smbp-&gt;tid)
              return tp;
      }
      return NULL;
***************
*** 1028,1038 ****
  smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
  	int totalParms, int totalData)
  {
! 	smb_tran2Packet_t *tp;
      smb_t *smbp;
          
      smbp = (smb_t *) inp-&gt;data;
! 	tp = malloc(sizeof(*tp));
      memset(tp, 0, sizeof(*tp));
      tp-&gt;vcp = vcp;
      smb_HoldVC(vcp);
--- 1023,1033 ----
  smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
  	int totalParms, int totalData)
  {
!     smb_tran2Packet_t *tp;
      smb_t *smbp;
          
      smbp = (smb_t *) inp-&gt;data;
!     tp = malloc(sizeof(*tp));
      memset(tp, 0, sizeof(*tp));
      tp-&gt;vcp = vcp;
      smb_HoldVC(vcp);
***************
*** 1043,1116 ****
      tp-&gt;mid = smbp-&gt;mid;
      tp-&gt;uid = smbp-&gt;uid;
      tp-&gt;pid = smbp-&gt;pid;
! 	tp-&gt;res[0] = smbp-&gt;res[0];
! 	osi_QAdd((osi_queue_t **)&amp;smb_tran2AssemblyQueuep, &amp;tp-&gt;q);
! 	if (totalParms != 0)
          tp-&gt;parmsp = malloc(totalParms);
! 	if (totalData != 0)
          tp-&gt;datap = malloc(totalData);
! 	if (smbp-&gt;com == 0x25 || smbp-&gt;com == 0x26)
! 		tp-&gt;com = 0x25;
! 	else {
! 	    tp-&gt;opcode = smb_GetSMBParm(inp, 14);
! 		tp-&gt;com = 0x32;
! 	}
! 	tp-&gt;flags |= SMB_TRAN2PFLAG_ALLOC;
      return tp;
  }
  
  smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
! 	smb_tran2Packet_t *inp, smb_packet_t *outp,
! 	int totalParms, int totalData)
  {
! 	smb_tran2Packet_t *tp;
! 	unsigned short parmOffset;
! 	unsigned short dataOffset;
! 	unsigned short dataAlign;
          
! 	tp = malloc(sizeof(*tp));
      memset(tp, 0, sizeof(*tp));
      tp-&gt;vcp = NULL;
      tp-&gt;curData = tp-&gt;curParms = 0;
      tp-&gt;totalData = totalData;
      tp-&gt;totalParms = totalParms;
! 	tp-&gt;oldTotalParms = totalParms;
      tp-&gt;tid = inp-&gt;tid;
      tp-&gt;mid = inp-&gt;mid;
      tp-&gt;uid = inp-&gt;uid;
      tp-&gt;pid = inp-&gt;pid;
! 	tp-&gt;res[0] = inp-&gt;res[0];
      tp-&gt;opcode = inp-&gt;opcode;
! 	tp-&gt;com = inp-&gt;com;
  
! 	/*
! 	 * We calculate where the parameters and data will start.
! 	 * This calculation must parallel the calculation in
! 	 * smb_SendTran2Packet.
! 	 */
  
! 	parmOffset = 10*2 + 35;
! 	parmOffset++;			/* round to even */
! 	tp-&gt;parmsp = (unsigned short *) (outp-&gt;data + parmOffset);
! 
! 	dataOffset = parmOffset + totalParms;
! 	dataAlign = dataOffset &amp; 2;	/* quad-align */
! 	dataOffset += dataAlign;
! 	tp-&gt;datap = outp-&gt;data + dataOffset;
  
      return tp;
! }
  
  /* free a tran2 packet; must be called with smb_globalLock held */
  void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
  {
      if (t2p-&gt;vcp) smb_ReleaseVC(t2p-&gt;vcp);
! 	if (t2p-&gt;flags &amp; SMB_TRAN2PFLAG_ALLOC) {
! 		if (t2p-&gt;parmsp)
! 			free(t2p-&gt;parmsp);
! 		if (t2p-&gt;datap)
! 			free(t2p-&gt;datap);
! 	}
      free(t2p);
  }
  
--- 1038,1111 ----
      tp-&gt;mid = smbp-&gt;mid;
      tp-&gt;uid = smbp-&gt;uid;
      tp-&gt;pid = smbp-&gt;pid;
!     tp-&gt;res[0] = smbp-&gt;res[0];
!     osi_QAdd((osi_queue_t **)&amp;smb_tran2AssemblyQueuep, &amp;tp-&gt;q);
!     if (totalParms != 0)
          tp-&gt;parmsp = malloc(totalParms);
!     if (totalData != 0)
          tp-&gt;datap = malloc(totalData);
!     if (smbp-&gt;com == 0x25 || smbp-&gt;com == 0x26)
!         tp-&gt;com = 0x25;
!     else {
!         tp-&gt;opcode = smb_GetSMBParm(inp, 14);
!         tp-&gt;com = 0x32;
!     }
!     tp-&gt;flags |= SMB_TRAN2PFLAG_ALLOC;
      return tp;
  }
  
  smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
!                                                smb_tran2Packet_t *inp, smb_packet_t *outp,
!                                                int totalParms, int totalData)  
  {
!     smb_tran2Packet_t *tp;
!     unsigned short parmOffset;
!     unsigned short dataOffset;
!     unsigned short dataAlign;
          
!     tp = malloc(sizeof(*tp));
      memset(tp, 0, sizeof(*tp));
      tp-&gt;vcp = NULL;
      tp-&gt;curData = tp-&gt;curParms = 0;
      tp-&gt;totalData = totalData;
      tp-&gt;totalParms = totalParms;
!     tp-&gt;oldTotalParms = totalParms;
      tp-&gt;tid = inp-&gt;tid;
      tp-&gt;mid = inp-&gt;mid;
      tp-&gt;uid = inp-&gt;uid;
      tp-&gt;pid = inp-&gt;pid;
!     tp-&gt;res[0] = inp-&gt;res[0];
      tp-&gt;opcode = inp-&gt;opcode;
!     tp-&gt;com = inp-&gt;com;
  
!     /*
!      * We calculate where the parameters and data will start.
!      * This calculation must parallel the calculation in
!      * smb_SendTran2Packet.
!      */
  
!     parmOffset = 10*2 + 35;
!     parmOffset++;			/* round to even */
!     tp-&gt;parmsp = (unsigned short *) (outp-&gt;data + parmOffset);
! 
!     dataOffset = parmOffset + totalParms;
!     dataAlign = dataOffset &amp; 2;	/* quad-align */
!     dataOffset += dataAlign;
!     tp-&gt;datap = outp-&gt;data + dataOffset;
  
      return tp;
! }       
  
  /* free a tran2 packet; must be called with smb_globalLock held */
  void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
  {
      if (t2p-&gt;vcp) smb_ReleaseVC(t2p-&gt;vcp);
!     if (t2p-&gt;flags &amp; SMB_TRAN2PFLAG_ALLOC) {
!         if (t2p-&gt;parmsp)
!             free(t2p-&gt;parmsp);
!         if (t2p-&gt;datap)
!             free(t2p-&gt;datap);
!     }       
      free(t2p);
  }
  
***************
*** 1123,1141 ****
      smb_t *smbp;
      unsigned short errCode;
      unsigned char errClass;
! 	unsigned long NTStatus;
  
      if (vcp-&gt;flags &amp; SMB_VCFLAG_STATUS32)
! 		smb_MapNTError(code, &amp;NTStatus);
! 	else
! 		smb_MapCoreError(code, vcp, &amp;errCode, &amp;errClass);
  
      smb_FormatResponsePacket(vcp, NULL, tp);
      smbp = (smb_t *) tp;
  
! 	/* We can handle long names */
! 	if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
! 		smbp-&gt;flg2 |= 0x40;	/* IS_LONG_NAME */
          
      /* now copy important fields from the tran 2 packet */
      smbp-&gt;com = t2p-&gt;com;
--- 1118,1136 ----
      smb_t *smbp;
      unsigned short errCode;
      unsigned char errClass;
!     unsigned long NTStatus;
  
      if (vcp-&gt;flags &amp; SMB_VCFLAG_STATUS32)
!         smb_MapNTError(code, &amp;NTStatus);
!     else
!         smb_MapCoreError(code, vcp, &amp;errCode, &amp;errClass);
  
      smb_FormatResponsePacket(vcp, NULL, tp);
      smbp = (smb_t *) tp;
  
!     /* We can handle long names */
!     if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
!         smbp-&gt;flg2 |= 0x40;	/* IS_LONG_NAME */
          
      /* now copy important fields from the tran 2 packet */
      smbp-&gt;com = t2p-&gt;com;
***************
*** 1143,1161 ****
      smbp-&gt;mid = t2p-&gt;mid;
      smbp-&gt;pid = t2p-&gt;pid;
      smbp-&gt;uid = t2p-&gt;uid;
! 	smbp-&gt;res[0] = t2p-&gt;res[0];
! 	if (vcp-&gt;flags &amp; SMB_VCFLAG_STATUS32) {
! 		smbp-&gt;rcls = (unsigned char) (NTStatus &amp; 0xff);
! 		smbp-&gt;reh = (unsigned char) ((NTStatus &gt;&gt; 8) &amp; 0xff);
! 		smbp-&gt;errLow = (unsigned char) ((NTStatus &gt;&gt; 16) &amp; 0xff);
! 		smbp-&gt;errHigh = (unsigned char) ((NTStatus &gt;&gt; 24) &amp; 0xff);
! 		smbp-&gt;flg2 |= 0x4000;
! 	}
! 	else {
          smbp-&gt;rcls = errClass;
! 		smbp-&gt;errLow = (unsigned char) (errCode &amp; 0xff);
! 		smbp-&gt;errHigh = (unsigned char) ((errCode &gt;&gt; 8) &amp; 0xff);
! 	}
          
      /* send packet */
      smb_SendPacket(vcp, tp);
--- 1138,1156 ----
      smbp-&gt;mid = t2p-&gt;mid;
      smbp-&gt;pid = t2p-&gt;pid;
      smbp-&gt;uid = t2p-&gt;uid;
!     smbp-&gt;res[0] = t2p-&gt;res[0];
!     if (vcp-&gt;flags &amp; SMB_VCFLAG_STATUS32) {
!         smbp-&gt;rcls = (unsigned char) (NTStatus &amp; 0xff);
!         smbp-&gt;reh = (unsigned char) ((NTStatus &gt;&gt; 8) &amp; 0xff);
!         smbp-&gt;errLow = (unsigned char) ((NTStatus &gt;&gt; 16) &amp; 0xff);
!         smbp-&gt;errHigh = (unsigned char) ((NTStatus &gt;&gt; 24) &amp; 0xff);
!         smbp-&gt;flg2 |= 0x4000;
!     }
!     else {
          smbp-&gt;rcls = errClass;
!         smbp-&gt;errLow = (unsigned char) (errCode &amp; 0xff);
!         smbp-&gt;errHigh = (unsigned char) ((errCode &gt;&gt; 8) &amp; 0xff);
!     }
          
      /* send packet */
      smb_SendPacket(vcp, tp);
***************
*** 1165,1181 ****
  {
      smb_t *smbp;
      unsigned short parmOffset;
! 	unsigned short dataOffset;
! 	unsigned short totalLength;
! 	unsigned short dataAlign;
      char *datap;
!         
      smb_FormatResponsePacket(vcp, NULL, tp);
      smbp = (smb_t *) tp;
  
! 	/* We can handle long names */
! 	if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
! 		smbp-&gt;flg2 |= 0x40;	/* IS_LONG_NAME */
  
      /* now copy important fields from the tran 2 packet */
      smbp-&gt;com = t2p-&gt;com;
--- 1160,1176 ----
  {
      smb_t *smbp;
      unsigned short parmOffset;
!     unsigned short dataOffset;
!     unsigned short totalLength;
!     unsigned short dataAlign;
      char *datap;
! 
      smb_FormatResponsePacket(vcp, NULL, tp);
      smbp = (smb_t *) tp;
  
!     /* We can handle long names */
!     if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
!         smbp-&gt;flg2 |= 0x40;	/* IS_LONG_NAME */
  
      /* now copy important fields from the tran 2 packet */
      smbp-&gt;com = t2p-&gt;com;
***************
*** 1183,1189 ****
      smbp-&gt;mid = t2p-&gt;mid;
      smbp-&gt;pid = t2p-&gt;pid;
      smbp-&gt;uid = t2p-&gt;uid;
! 	smbp-&gt;res[0] = t2p-&gt;res[0];
  
      totalLength = 1 + t2p-&gt;totalData + t2p-&gt;totalParms;
  
--- 1178,1184 ----
      smbp-&gt;mid = t2p-&gt;mid;
      smbp-&gt;pid = t2p-&gt;pid;
      smbp-&gt;uid = t2p-&gt;uid;
!     smbp-&gt;res[0] = t2p-&gt;res[0];
  
      totalLength = 1 + t2p-&gt;totalData + t2p-&gt;totalParms;
  
***************
*** 1192,1215 ****
      smb_SetSMBParm(tp, 1, t2p-&gt;totalData);	/* data bytes */
      smb_SetSMBParm(tp, 2, 0);		/* reserved */
      smb_SetSMBParm(tp, 3, t2p-&gt;totalParms);	/* parm bytes in this packet */
! 	parmOffset = 10*2 + 35;			/* parm offset in packet */
! 	parmOffset++;				/* round to even */
      smb_SetSMBParm(tp, 4, parmOffset);	/* 11 parm words plus *
      * hdr, bcc and wct */
      smb_SetSMBParm(tp, 5, 0);		/* parm displacement */
      smb_SetSMBParm(tp, 6, t2p-&gt;totalData);	/* data in this packet */
! 	dataOffset = parmOffset + t2p-&gt;oldTotalParms;
! 	dataAlign = dataOffset &amp; 2;		/* quad-align */
! 	dataOffset += dataAlign;
      smb_SetSMBParm(tp, 7, dataOffset);	/* offset of data */
      smb_SetSMBParm(tp, 8, 0);		/* data displacement */
      smb_SetSMBParm(tp, 9, 0);		/* low: setup word count *
      * high: resvd */
  
      datap = smb_GetSMBData(tp, NULL);
! 	*datap++ = 0;				/* we rounded to even */
  
! 	totalLength += dataAlign;
      smb_SetSMBDataLength(tp, totalLength);
          
      /* next, send the datagram */
--- 1187,1210 ----
      smb_SetSMBParm(tp, 1, t2p-&gt;totalData);	/* data bytes */
      smb_SetSMBParm(tp, 2, 0);		/* reserved */
      smb_SetSMBParm(tp, 3, t2p-&gt;totalParms);	/* parm bytes in this packet */
!     parmOffset = 10*2 + 35;			/* parm offset in packet */
!     parmOffset++;				/* round to even */
      smb_SetSMBParm(tp, 4, parmOffset);	/* 11 parm words plus *
      * hdr, bcc and wct */
      smb_SetSMBParm(tp, 5, 0);		/* parm displacement */
      smb_SetSMBParm(tp, 6, t2p-&gt;totalData);	/* data in this packet */
!     dataOffset = parmOffset + t2p-&gt;oldTotalParms;
!     dataAlign = dataOffset &amp; 2;		/* quad-align */
!     dataOffset += dataAlign;
      smb_SetSMBParm(tp, 7, dataOffset);	/* offset of data */
      smb_SetSMBParm(tp, 8, 0);		/* data displacement */
      smb_SetSMBParm(tp, 9, 0);		/* low: setup word count *
      * high: resvd */
  
      datap = smb_GetSMBData(tp, NULL);
!     *datap++ = 0;				/* we rounded to even */
  
!     totalLength += dataAlign;
      smb_SetSMBDataLength(tp, totalLength);
          
      /* next, send the datagram */
***************
*** 1228,1283 ****
      int parmCount;
      int dataCount;
      int firstPacket;
! 	int rapOp;
      long code = 0;
  
! 	/* We sometimes see 0 word count.  What to do? */
! 	if (*inp-&gt;wctp == 0) {
  #ifndef DJGPP
! 		HANDLE h;
! 		char *ptbuf[1];
  
! 		osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
  
! 		h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 		ptbuf[0] = "Transaction2 word count = 0";
! 		ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
! 			    1, inp-&gt;ncb_length, ptbuf, inp);
! 		DeregisterEventSource(h);
  #else /* DJGPP */
! 		osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
  #endif /* !DJGPP */
  
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
! 		return 0;
! 	}
  
      totalParms = smb_GetSMBParm(inp, 0);
      totalData = smb_GetSMBParm(inp, 1);
          
      firstPacket = (inp-&gt;inCom == 0x25);
          
! 	/* find the packet we're reassembling */
! 	lock_ObtainWrite(&amp;smb_globalLock);
      asp = smb_FindTran2Packet(vcp, inp);
      if (!asp) {
          asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
! 	}
      lock_ReleaseWrite(&amp;smb_globalLock);
          
      /* now merge in this latest packet; start by looking up offsets */
! 	if (firstPacket) {
! 		parmDisp = dataDisp = 0;
          parmOffset = smb_GetSMBParm(inp, 10);
          dataOffset = smb_GetSMBParm(inp, 12);
          parmCount = smb_GetSMBParm(inp, 9);
          dataCount = smb_GetSMBParm(inp, 11);
! 		asp-&gt;maxReturnParms = smb_GetSMBParm(inp, 2);
          asp-&gt;maxReturnData = smb_GetSMBParm(inp, 3);
  
! 		osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
!                  totalData, dataCount, asp-&gt;maxReturnData);
      }
      else {
          parmDisp = smb_GetSMBParm(inp, 4);
--- 1223,1278 ----
      int parmCount;
      int dataCount;
      int firstPacket;
!     int rapOp;
      long code = 0;
  
!     /* We sometimes see 0 word count.  What to do? */
!     if (*inp-&gt;wctp == 0) {
  #ifndef DJGPP
!         HANDLE h;
!         char *ptbuf[1];
  
!         osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
  
!         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!         ptbuf[0] = "Transaction2 word count = 0";
!         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
!                     1, inp-&gt;ncb_length, ptbuf, inp);
!         DeregisterEventSource(h);
  #else /* DJGPP */
!         osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
  #endif /* !DJGPP */
  
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
!         return 0;
!     }
  
      totalParms = smb_GetSMBParm(inp, 0);
      totalData = smb_GetSMBParm(inp, 1);
          
      firstPacket = (inp-&gt;inCom == 0x25);
          
!     /* find the packet we're reassembling */
!     lock_ObtainWrite(&amp;smb_globalLock);
      asp = smb_FindTran2Packet(vcp, inp);
      if (!asp) {
          asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
!     }
      lock_ReleaseWrite(&amp;smb_globalLock);
          
      /* now merge in this latest packet; start by looking up offsets */
!     if (firstPacket) {
!         parmDisp = dataDisp = 0;
          parmOffset = smb_GetSMBParm(inp, 10);
          dataOffset = smb_GetSMBParm(inp, 12);
          parmCount = smb_GetSMBParm(inp, 9);
          dataCount = smb_GetSMBParm(inp, 11);
!         asp-&gt;maxReturnParms = smb_GetSMBParm(inp, 2);
          asp-&gt;maxReturnData = smb_GetSMBParm(inp, 3);
  
!         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
!                   totalData, dataCount, asp-&gt;maxReturnData);
      }
      else {
          parmDisp = smb_GetSMBParm(inp, 4);
***************
*** 1309,1321 ****
          asp-&gt;curParms &gt; 0 &amp;&amp;
          asp-&gt;totalData &lt;= asp-&gt;curData &amp;&amp;
          asp-&gt;totalParms &lt;= asp-&gt;curParms) {
! 		/* we've received it all */
          lock_ObtainWrite(&amp;smb_globalLock);
! 		osi_QRemove((osi_queue_t **) &amp;smb_tran2AssemblyQueuep, &amp;asp-&gt;q);
          lock_ReleaseWrite(&amp;smb_globalLock);
  
          /* now dispatch it */
! 		rapOp = asp-&gt;parmsp[0];
  
          if ( rapOp &gt;= 0 &amp;&amp; rapOp &lt; SMB_RAP_NOPCODES &amp;&amp; smb_rapDispatchTable[rapOp].procp) {
              osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp-&gt;lana,vcp-&gt;lsn);
--- 1304,1316 ----
          asp-&gt;curParms &gt; 0 &amp;&amp;
          asp-&gt;totalData &lt;= asp-&gt;curData &amp;&amp;
          asp-&gt;totalParms &lt;= asp-&gt;curParms) {
!         /* we've received it all */
          lock_ObtainWrite(&amp;smb_globalLock);
!         osi_QRemove((osi_queue_t **) &amp;smb_tran2AssemblyQueuep, &amp;asp-&gt;q);
          lock_ReleaseWrite(&amp;smb_globalLock);
  
          /* now dispatch it */
!         rapOp = asp-&gt;parmsp[0];
  
          if ( rapOp &gt;= 0 &amp;&amp; rapOp &lt; SMB_RAP_NOPCODES &amp;&amp; smb_rapDispatchTable[rapOp].procp) {
              osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp-&gt;lana,vcp-&gt;lsn);
***************
*** 1328,1334 ****
              code = CM_ERROR_BADOP;
          }
  
! 		/* if an error is returned, we're supposed to send an error packet,
           * otherwise the dispatched function already did the data sending.
           * We give dispatched proc the responsibility since it knows how much
           * space to allocate.
--- 1323,1329 ----
              code = CM_ERROR_BADOP;
          }
  
!         /* if an error is returned, we're supposed to send an error packet,
           * otherwise the dispatched function already did the data sending.
           * We give dispatched proc the responsibility since it knows how much
           * space to allocate.
***************
*** 1337,1772 ****
              smb_SendTran2Error(vcp, asp, outp, code);
          }
  
! 		/* free the input tran 2 packet */
! 		lock_ObtainWrite(&amp;smb_globalLock);
          smb_FreeTran2Packet(asp);
! 		lock_ReleaseWrite(&amp;smb_globalLock);
      }
      else if (firstPacket) {
! 		/* the first packet in a multi-packet request, we need to send an
           * ack to get more data.
           */
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
      }
  
! 	return 0;
  }
  
  /* ANSI versions.  The unicode versions support arbitrary length
     share names, but we don't support unicode yet. */
  
  typedef struct smb_rap_share_info_0 {
! 	char			shi0_netname[13];
  } smb_rap_share_info_0_t;
  
  typedef struct smb_rap_share_info_1 {
! 	char			shi1_netname[13];
! 	char			shi1_pad;
! 	WORD			shi1_type;
! 	DWORD			shi1_remark; /* char *shi1_remark; data offset */
  } smb_rap_share_info_1_t;
  
  typedef struct smb_rap_share_info_2 {
! 	char				shi2_netname[13];
! 	char				shi2_pad;
! 	unsigned short		shi2_type;
! 	DWORD				shi2_remark; /* char *shi2_remark; data offset */
! 	unsigned short		shi2_permissions;
! 	unsigned short		shi2_max_uses;
! 	unsigned short		shi2_current_uses;
! 	DWORD				shi2_path;  /* char *shi2_path; data offset */
! 	unsigned short		shi2_passwd[9];
! 	unsigned short		shi2_pad2;
  } smb_rap_share_info_2_t;
  
  #define SMB_RAP_MAX_SHARES 512
  
  typedef struct smb_rap_share_list {
! 	int cShare;
! 	int maxShares;
! 	smb_rap_share_info_0_t * shares;
  } smb_rap_share_list_t;
  
  int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
! 	smb_rap_share_list_t * sp;
! 	char * name;
  
! 	name = dep-&gt;name;
  
! 	if(name[0] == '.' &amp;&amp; (!name[1] || (name[1] == '.' &amp;&amp; !name[2])))
! 		return 0; /* skip over '.' and '..' */
  
! 	sp = (smb_rap_share_list_t *) vrockp;
  
! 	strncpy(sp-&gt;shares[sp-&gt;cShare].shi0_netname, name, 12);
! 	sp-&gt;shares[sp-&gt;cShare].shi0_netname[12] = 0;
  
! 	sp-&gt;cShare++;
  
! 	if(sp-&gt;cShare &gt;= sp-&gt;maxShares)
! 		return CM_ERROR_STOPNOW;
! 	else
! 		return 0;
! }
  
  long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
! 	smb_tran2Packet_t *outp;
! 	unsigned short * tp;
! 	int len;
! 	int infoLevel;
! 	int bufsize;
! 	int outParmsTotal;	/* total parameter bytes */
! 	int outDataTotal;	/* total data bytes */
! 	int code = 0;
! 	DWORD rv;
! 	DWORD allSubmount;
! 	USHORT nShares;
! 	DWORD nRegShares;
! 	DWORD nSharesRet;
! 	HKEY hkParam;
! 	HKEY hkSubmount = NULL;
! 	smb_rap_share_info_1_t * shares;
! 	USHORT cshare = 0;
! 	char * cstrp;
! 	char thisShare[256];
! 	int i,j;
! 	int nonrootShares;
! 	smb_rap_share_list_t rootShares;
! 	cm_req_t req;
! 	cm_user_t * userp;
! 	osi_hyper_t thyper;
! 
! 	tp = p-&gt;parmsp + 1; /* skip over function number (always 0) */
! 	(void) smb_ParseString((char *) tp, (char **) &amp;tp); /* skip over parm descriptor */
! 	(void) smb_ParseString((char *) tp, (char **) &amp;tp); /* skip over data descriptor */
! 	infoLevel = tp[0];
      bufsize = tp[1];
  
! 	if(infoLevel != 1) {
! 		return CM_ERROR_INVAL;
! 	}
  
! 	/* first figure out how many shares there are */
      rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
! 		KEY_QUERY_VALUE, &amp;hkParam);
! 	if (rv == ERROR_SUCCESS) {
          len = sizeof(allSubmount);
          rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
!                                 (BYTE *) &amp;allSubmount, &amp;len);
! 		if (rv != ERROR_SUCCESS || allSubmount != 0) {
! 			allSubmount = 1;
! 		}
          RegCloseKey (hkParam);
! 	}
  
! 	rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
! 		0, KEY_QUERY_VALUE, &amp;hkSubmount);
! 	if (rv == ERROR_SUCCESS) {
          rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
! 			NULL, NULL, &amp;nRegShares, NULL, NULL, NULL, NULL);
! 		if (rv != ERROR_SUCCESS)
! 			nRegShares = 0;
! 	} else {
! 		hkSubmount = NULL;
! 	}
  
! 	/* fetch the root shares */
! 	rootShares.maxShares = SMB_RAP_MAX_SHARES;
! 	rootShares.cShare = 0;
! 	rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
  
! 	cm_InitReq(&amp;req);
  
! 	userp = smb_GetTran2User(vcp,p);
  
! 	thyper.HighPart = 0;
! 	thyper.LowPart = 0;
  
! 	cm_HoldSCache(cm_rootSCachep);
! 	cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &amp;rootShares, &amp;thyper, userp, &amp;req, NULL);
! 	cm_ReleaseSCache(cm_rootSCachep);
  
! 	cm_ReleaseUser(userp);
  
! 	nShares = rootShares.cShare + nRegShares + allSubmount;
  
  #define REMARK_LEN 1
! 	outParmsTotal = 8; /* 4 dwords */
! 	outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
! 	if(outDataTotal &gt; bufsize) {
! 		nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
! 		outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
! 	}
! 	else {
! 		nSharesRet = nShares;
! 	}
      
! 	outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
  
! 	/* now for the submounts */
      shares = (smb_rap_share_info_1_t *) outp-&gt;datap;
! 	cstrp = outp-&gt;datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
  
! 	memset(outp-&gt;datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
  
! 	if(allSubmount) {
! 		strcpy( shares[cshare].shi1_netname, "all" );
! 		shares[cshare].shi1_remark = cstrp - outp-&gt;datap;
! 		/* type and pad are zero already */
! 		cshare++;
! 		cstrp+=REMARK_LEN;
! 	}
  
! 	if(hkSubmount) {
! 		for(i=0; i &lt; nRegShares &amp;&amp; cshare &lt; nSharesRet; i++) {
! 			len = sizeof(thisShare);
              rv = RegEnumValue(hkSubmount, i, thisShare, &amp;len, NULL, NULL, NULL, NULL);
! 			if(rv == ERROR_SUCCESS &amp;&amp; strlen(thisShare) &amp;&amp; (!allSubmount || stricmp(thisShare,"all"))) {
! 				strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares-&gt;shi1_netname)-1);
! 				shares[cshare].shi1_netname[sizeof(shares-&gt;shi1_netname)-1] = 0; /* unfortunate truncation */
! 				shares[cshare].shi1_remark = cstrp - outp-&gt;datap;
! 				cshare++;
! 				cstrp+=REMARK_LEN;
! 			}
! 			else
! 				nShares--; /* uncount key */
! 		}
  
! 		RegCloseKey(hkSubmount);
! 	}
  
! 	nonrootShares = cshare;
  
! 	for(i=0; i &lt; rootShares.cShare &amp;&amp; cshare &lt; nSharesRet; i++) {
          /* in case there are collisions with submounts, submounts have higher priority */		
! 		for(j=0; j &lt; nonrootShares; j++)
! 			if(!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
! 				break;
  		
! 		if(j &lt; nonrootShares) {
! 			nShares--; /* uncount */
! 			continue;
! 		}
! 
! 		strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
! 		shares[cshare].shi1_remark = cstrp - outp-&gt;datap;
! 		cshare++;
! 		cstrp+=REMARK_LEN;
! 	}
  
! 	outp-&gt;parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
! 	outp-&gt;parmsp[1] = 0;
! 	outp-&gt;parmsp[2] = cshare;
! 	outp-&gt;parmsp[3] = nShares;
  
! 	outp-&gt;totalData = cstrp - outp-&gt;datap;
! 	outp-&gt;totalParms = outParmsTotal;
  
! 	smb_SendTran2Packet(vcp, outp, op);
! 	smb_FreeTran2Packet(outp);
  
! 	free(rootShares.shares);
  
! 	return code;
  }
  
  long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
! 	smb_tran2Packet_t *outp;
! 	unsigned short * tp;
! 	char * shareName;
! 	BOOL shareFound = FALSE;
! 	unsigned short infoLevel;
! 	unsigned short bufsize;
! 	int totalData;
! 	int totalParam;
! 	DWORD len;
! 	HKEY hkParam;
! 	HKEY hkSubmount;
! 	DWORD allSubmount;
! 	LONG rv;
! 	long code = 0;
! 
! 	tp = p-&gt;parmsp + 1; /* skip over function number (always 1) */
! 	(void) smb_ParseString( (char *) tp, (char **) &amp;tp); /* skip over param descriptor */
! 	(void) smb_ParseString( (char *) tp, (char **) &amp;tp); /* skip over data descriptor */
! 	shareName = smb_ParseString( (char *) tp, (char **) &amp;tp);
      infoLevel = *tp++;
      bufsize = *tp++;
      
! 	totalParam = 6;
  
! 	if(infoLevel == 0)
! 		totalData = sizeof(smb_rap_share_info_0_t);
! 	else if(infoLevel == 1)
! 		totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
! 	else if(infoLevel == 2)
! 		totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
! 	else
! 		return CM_ERROR_INVAL;
! 
! 	outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
! 
! 	if(!stricmp(shareName,"all")) {
! 		rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
! 			KEY_QUERY_VALUE, &amp;hkParam);
! 		if (rv == ERROR_SUCCESS) {
! 			len = sizeof(allSubmount);
! 			rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
! 									(BYTE *) &amp;allSubmount, &amp;len);
! 			if (rv != ERROR_SUCCESS || allSubmount != 0) {
! 				allSubmount = 1;
! 			}
! 			RegCloseKey (hkParam);
! 		}
! 
! 		if(allSubmount)
! 			shareFound = TRUE;
! 
! 	} else {
! 		rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
! 			KEY_QUERY_VALUE, &amp;hkSubmount);
! 		if(rv == ERROR_SUCCESS) {
              rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
! 			if(rv == ERROR_SUCCESS) {
! 				shareFound = TRUE;
! 			}
! 			RegCloseKey(hkSubmount);
! 		}
! 	}
  
! 	if(!shareFound) {
! 		smb_FreeTran2Packet(outp);
! 		return CM_ERROR_BADSHARENAME;
! 	}
  
! 	memset(outp-&gt;datap, 0, totalData);
  
! 	outp-&gt;parmsp[0] = 0;
! 	outp-&gt;parmsp[1] = 0;
! 	outp-&gt;parmsp[2] = totalData;
! 
! 	if(infoLevel == 0) {
! 		smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp-&gt;datap;
! 		strncpy(info-&gt;shi0_netname, shareName, sizeof(info-&gt;shi0_netname)-1);
! 		info-&gt;shi0_netname[sizeof(info-&gt;shi0_netname)-1] = 0;
! 	} else if(infoLevel == 1) {
! 		smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp-&gt;datap;
          strncpy(info-&gt;shi1_netname, shareName, sizeof(info-&gt;shi1_netname)-1);
! 		info-&gt;shi1_netname[sizeof(info-&gt;shi1_netname)-1] = 0;
! 		info-&gt;shi1_remark = ((unsigned char *) (info + 1)) - outp-&gt;datap;
! 		/* type and pad are already zero */
! 	} else { /* infoLevel==2 */
! 		smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp-&gt;datap;
! 		strncpy(info-&gt;shi2_netname, shareName, sizeof(info-&gt;shi2_netname)-1);
! 		info-&gt;shi2_netname[sizeof(info-&gt;shi2_netname)-1] = 0;
! 		info-&gt;shi2_remark = ((unsigned char *) (info + 1)) - outp-&gt;datap;
          info-&gt;shi2_permissions = ACCESS_ALL;
! 		info-&gt;shi2_max_uses = (unsigned short) -1;
          info-&gt;shi2_path = 1 + (((unsigned char *) (info + 1)) - outp-&gt;datap);
! 	}
  
! 	outp-&gt;totalData = totalData;
! 	outp-&gt;totalParms = totalParam;
  
! 	smb_SendTran2Packet(vcp, outp, op);
! 	smb_FreeTran2Packet(outp);
  
! 	return code;
  }
  
  typedef struct smb_rap_wksta_info_10 {
! 	DWORD	wki10_computername;	/*char *wki10_computername;*/
! 	DWORD	wki10_username; /* char *wki10_username; */
! 	DWORD  	wki10_langroup;	/* char *wki10_langroup;*/
! 	unsigned char  	wki10_ver_major;
! 	unsigned char	wki10_ver_minor;
! 	DWORD	wki10_logon_domain;	/*char *wki10_logon_domain;*/
! 	DWORD	wki10_oth_domains; /* char *wki10_oth_domains;*/
  } smb_rap_wksta_info_10_t;
  
  
  long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
! 	smb_tran2Packet_t *outp;
      long code = 0;
! 	int infoLevel;
! 	int bufsize;
! 	unsigned short * tp;
! 	int totalData;
! 	int totalParams;
! 	smb_rap_wksta_info_10_t * info;
! 	char * cstrp;
! 	smb_user_t *uidp;
! 
! 	tp = p-&gt;parmsp + 1; /* Skip over function number */
! 	(void) smb_ParseString((unsigned char*) tp, (char **) &amp;tp); /* skip over param descriptor */
! 	(void) smb_ParseString((unsigned char*) tp, (char **) &amp;tp); /* skip over data descriptor */
! 	infoLevel = *tp++;
! 	bufsize = *tp++;
  
! 	if(infoLevel != 10) {
! 		return CM_ERROR_INVAL;
! 	}
  
! 	totalParams = 6;
  	
! 	/* infolevel 10 */
! 	totalData = sizeof(*info) +		/* info */
! 		MAX_COMPUTERNAME_LENGTH +	/* wki10_computername */
! 		SMB_MAX_USERNAME_LENGTH +	/* wki10_username */
! 		MAX_COMPUTERNAME_LENGTH +	/* wki10_langroup */
! 		MAX_COMPUTERNAME_LENGTH +	/* wki10_logon_domain */
! 		1;							/* wki10_oth_domains (null)*/
  
! 	outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
  
! 	memset(outp-&gt;parmsp,0,totalParams);
! 	memset(outp-&gt;datap,0,totalData);
  
      info = (smb_rap_wksta_info_10_t *) outp-&gt;datap;
! 	cstrp = (char *) (info + 1);
  
! 	info-&gt;wki10_computername = (DWORD) (cstrp - outp-&gt;datap);
! 	strcpy(cstrp, smb_localNamep);
! 	cstrp += strlen(cstrp) + 1;
! 
! 	info-&gt;wki10_username = (DWORD) (cstrp - outp-&gt;datap);
! 	uidp = smb_FindUID(vcp, p-&gt;uid, 0);
! 	if(uidp) {
! 		lock_ObtainMutex(&amp;uidp-&gt;mx);
! 		if(uidp-&gt;unp &amp;&amp; uidp-&gt;unp-&gt;name)
! 			strcpy(cstrp, uidp-&gt;unp-&gt;name);
! 		lock_ReleaseMutex(&amp;uidp-&gt;mx);
! 		smb_ReleaseUID(uidp);
! 	}
! 	cstrp += strlen(cstrp) + 1;
  
! 	info-&gt;wki10_langroup = (DWORD) (cstrp - outp-&gt;datap);
! 	strcpy(cstrp, "WORKGROUP");
! 	cstrp += strlen(cstrp) + 1;
  
! 	/* TODO: Not sure what values these should take, but these work */
! 	info-&gt;wki10_ver_major = 5;
! 	info-&gt;wki10_ver_minor = 1;
  
! 	info-&gt;wki10_logon_domain = (DWORD) (cstrp - outp-&gt;datap);
! 	strcpy(cstrp, smb_ServerDomainName);
! 	cstrp += strlen(cstrp) + 1;
  
! 	info-&gt;wki10_oth_domains = (DWORD) (cstrp - outp-&gt;datap);
! 	cstrp ++; /* no other domains */
  
! 	outp-&gt;totalData = (unsigned short) (cstrp - outp-&gt;datap); /* actual data size */
! 	outp-&gt;parmsp[2] = outp-&gt;totalData;
! 	outp-&gt;totalParms = totalParams;
  
! 	smb_SendTran2Packet(vcp,outp,op);
! 	smb_FreeTran2Packet(outp);
  
! 	return code;
  }
  
  typedef struct smb_rap_server_info_0 {
--- 1332,1767 ----
              smb_SendTran2Error(vcp, asp, outp, code);
          }
  
!         /* free the input tran 2 packet */
!         lock_ObtainWrite(&amp;smb_globalLock);
          smb_FreeTran2Packet(asp);
!         lock_ReleaseWrite(&amp;smb_globalLock);
      }
      else if (firstPacket) {
!         /* the first packet in a multi-packet request, we need to send an
           * ack to get more data.
           */
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
      }
  
!     return 0;
  }
  
  /* ANSI versions.  The unicode versions support arbitrary length
     share names, but we don't support unicode yet. */
  
  typedef struct smb_rap_share_info_0 {
!     char        shi0_netname[13];
  } smb_rap_share_info_0_t;
  
  typedef struct smb_rap_share_info_1 {
!     char			shi1_netname[13];
!     char			shi1_pad;
!     WORD			shi1_type;
!     DWORD			shi1_remark; /* char *shi1_remark; data offset */
  } smb_rap_share_info_1_t;
  
  typedef struct smb_rap_share_info_2 {
!     char				shi2_netname[13];
!     char				shi2_pad;
!     unsigned short		shi2_type;
!     DWORD				shi2_remark; /* char *shi2_remark; data offset */
!     unsigned short		shi2_permissions;
!     unsigned short		shi2_max_uses;
!     unsigned short		shi2_current_uses;
!     DWORD				shi2_path;  /* char *shi2_path; data offset */
!     unsigned short		shi2_passwd[9];
!     unsigned short		shi2_pad2;
  } smb_rap_share_info_2_t;
  
  #define SMB_RAP_MAX_SHARES 512
  
  typedef struct smb_rap_share_list {
!     int cShare;
!     int maxShares;
!     smb_rap_share_info_0_t * shares;
  } smb_rap_share_list_t;
  
  int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
!     smb_rap_share_list_t * sp;
!     char * name;
  
!     name = dep-&gt;name;
  
!     if (name[0] == '.' &amp;&amp; (!name[1] || (name[1] == '.' &amp;&amp; !name[2])))
!         return 0; /* skip over '.' and '..' */
  
!     sp = (smb_rap_share_list_t *) vrockp;
  
!     strncpy(sp-&gt;shares[sp-&gt;cShare].shi0_netname, name, 12);
!     sp-&gt;shares[sp-&gt;cShare].shi0_netname[12] = 0;
  
!     sp-&gt;cShare++;
  
!     if (sp-&gt;cShare &gt;= sp-&gt;maxShares)
!         return CM_ERROR_STOPNOW;
!     else
!         return 0;
! }       
  
  long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
!     smb_tran2Packet_t *outp;
!     unsigned short * tp;
!     int len;
!     int infoLevel;
!     int bufsize;
!     int outParmsTotal;	/* total parameter bytes */
!     int outDataTotal;	/* total data bytes */
!     int code = 0;
!     DWORD rv;
!     DWORD allSubmount;
!     USHORT nShares;
!     DWORD nRegShares;
!     DWORD nSharesRet;
!     HKEY hkParam;
!     HKEY hkSubmount = NULL;
!     smb_rap_share_info_1_t * shares;
!     USHORT cshare = 0;
!     char * cstrp;
!     char thisShare[256];
!     int i,j;
!     int nonrootShares;
!     smb_rap_share_list_t rootShares;
!     cm_req_t req;
!     cm_user_t * userp;
!     osi_hyper_t thyper;
! 
!     tp = p-&gt;parmsp + 1; /* skip over function number (always 0) */
!     (void) smb_ParseString((char *) tp, (char **) &amp;tp); /* skip over parm descriptor */
!     (void) smb_ParseString((char *) tp, (char **) &amp;tp); /* skip over data descriptor */
!     infoLevel = tp[0];
      bufsize = tp[1];
  
!     if (infoLevel != 1) {
!         return CM_ERROR_INVAL;
!     }
  
!     /* first figure out how many shares there are */
      rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
!                       KEY_QUERY_VALUE, &amp;hkParam);
!     if (rv == ERROR_SUCCESS) {
          len = sizeof(allSubmount);
          rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
!                              (BYTE *) &amp;allSubmount, &amp;len);
!         if (rv != ERROR_SUCCESS || allSubmount != 0) {
!             allSubmount = 1;
!         }
          RegCloseKey (hkParam);
!     }
  
!     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
!                       0, KEY_QUERY_VALUE, &amp;hkSubmount);
!     if (rv == ERROR_SUCCESS) {
          rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
!                              NULL, NULL, &amp;nRegShares, NULL, NULL, NULL, NULL);
!         if (rv != ERROR_SUCCESS)
!             nRegShares = 0;
!     } else {
!         hkSubmount = NULL;
!     }
  
!     /* fetch the root shares */
!     rootShares.maxShares = SMB_RAP_MAX_SHARES;
!     rootShares.cShare = 0;
!     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
  
!     cm_InitReq(&amp;req);
  
!     userp = smb_GetTran2User(vcp,p);
  
!     thyper.HighPart = 0;
!     thyper.LowPart = 0;
  
!     cm_HoldSCache(cm_rootSCachep);
!     cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &amp;rootShares, &amp;thyper, userp, &amp;req, NULL);
!     cm_ReleaseSCache(cm_rootSCachep);
  
!     cm_ReleaseUser(userp);
  
!     nShares = rootShares.cShare + nRegShares + allSubmount;
  
  #define REMARK_LEN 1
!     outParmsTotal = 8; /* 4 dwords */
!     outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
!     if(outDataTotal &gt; bufsize) {
!         nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
!         outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
!     }
!     else {
!         nSharesRet = nShares;
!     }
      
!     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
  
!     /* now for the submounts */
      shares = (smb_rap_share_info_1_t *) outp-&gt;datap;
!     cstrp = outp-&gt;datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
  
!     memset(outp-&gt;datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
  
!     if (allSubmount) {
!         strcpy( shares[cshare].shi1_netname, "all" );
!         shares[cshare].shi1_remark = cstrp - outp-&gt;datap;
!         /* type and pad are zero already */
!         cshare++;
!         cstrp+=REMARK_LEN;
!     }
  
!     if (hkSubmount) {
!         for (i=0; i &lt; nRegShares &amp;&amp; cshare &lt; nSharesRet; i++) {
!             len = sizeof(thisShare);
              rv = RegEnumValue(hkSubmount, i, thisShare, &amp;len, NULL, NULL, NULL, NULL);
!             if (rv == ERROR_SUCCESS &amp;&amp; strlen(thisShare) &amp;&amp; (!allSubmount || stricmp(thisShare,"all"))) {
!                 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares-&gt;shi1_netname)-1);
!                 shares[cshare].shi1_netname[sizeof(shares-&gt;shi1_netname)-1] = 0; /* unfortunate truncation */
!                 shares[cshare].shi1_remark = cstrp - outp-&gt;datap;
!                 cshare++;
!                 cstrp+=REMARK_LEN;
!             }
!             else
!                 nShares--; /* uncount key */
!         }
  
!         RegCloseKey(hkSubmount);
!     }
  
!     nonrootShares = cshare;
  
!     for (i=0; i &lt; rootShares.cShare &amp;&amp; cshare &lt; nSharesRet; i++) {
          /* in case there are collisions with submounts, submounts have higher priority */		
!         for (j=0; j &lt; nonrootShares; j++)
!             if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
!                 break;
  		
!         if (j &lt; nonrootShares) {
!             nShares--; /* uncount */
!             continue;
!         }
  
!         strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
!         shares[cshare].shi1_remark = cstrp - outp-&gt;datap;
!         cshare++;
!         cstrp+=REMARK_LEN;
!     }
! 
!     outp-&gt;parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
!     outp-&gt;parmsp[1] = 0;
!     outp-&gt;parmsp[2] = cshare;
!     outp-&gt;parmsp[3] = nShares;
  
!     outp-&gt;totalData = cstrp - outp-&gt;datap;
!     outp-&gt;totalParms = outParmsTotal;
  
!     smb_SendTran2Packet(vcp, outp, op);
!     smb_FreeTran2Packet(outp);
  
!     free(rootShares.shares);
  
!     return code;
  }
  
  long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
!     smb_tran2Packet_t *outp;
!     unsigned short * tp;
!     char * shareName;
!     BOOL shareFound = FALSE;
!     unsigned short infoLevel;
!     unsigned short bufsize;
!     int totalData;
!     int totalParam;
!     DWORD len;
!     HKEY hkParam;
!     HKEY hkSubmount;
!     DWORD allSubmount;
!     LONG rv;
!     long code = 0;
! 
!     tp = p-&gt;parmsp + 1; /* skip over function number (always 1) */
!     (void) smb_ParseString( (char *) tp, (char **) &amp;tp); /* skip over param descriptor */
!     (void) smb_ParseString( (char *) tp, (char **) &amp;tp); /* skip over data descriptor */
!     shareName = smb_ParseString( (char *) tp, (char **) &amp;tp);
      infoLevel = *tp++;
      bufsize = *tp++;
      
!     totalParam = 6;
! 
!     if (infoLevel == 0)
!         totalData = sizeof(smb_rap_share_info_0_t);
!     else if(infoLevel == 1)
!         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
!     else if(infoLevel == 2)
!         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
!     else
!         return CM_ERROR_INVAL;
  
!     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
! 
!     if(!stricmp(shareName,"all")) {
!         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
!                           KEY_QUERY_VALUE, &amp;hkParam);
!         if (rv == ERROR_SUCCESS) {
!             len = sizeof(allSubmount);
!             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
!                                   (BYTE *) &amp;allSubmount, &amp;len);
!             if (rv != ERROR_SUCCESS || allSubmount != 0) {
!                 allSubmount = 1;
!             }
!             RegCloseKey (hkParam);
!         }
! 
!         if (allSubmount)
!             shareFound = TRUE;
! 
!     } else {
!         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
!                           KEY_QUERY_VALUE, &amp;hkSubmount);
!         if (rv == ERROR_SUCCESS) {
              rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
!             if (rv == ERROR_SUCCESS) {
!                 shareFound = TRUE;
!             }
!             RegCloseKey(hkSubmount);
!         }
!     }
  
!     if (!shareFound) {
!         smb_FreeTran2Packet(outp);
!         return CM_ERROR_BADSHARENAME;
!     }
! 
!     memset(outp-&gt;datap, 0, totalData);
  
!     outp-&gt;parmsp[0] = 0;
!     outp-&gt;parmsp[1] = 0;
!     outp-&gt;parmsp[2] = totalData;
  
!     if (infoLevel == 0) {
!         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp-&gt;datap;
!         strncpy(info-&gt;shi0_netname, shareName, sizeof(info-&gt;shi0_netname)-1);
!         info-&gt;shi0_netname[sizeof(info-&gt;shi0_netname)-1] = 0;
!     } else if(infoLevel == 1) {
!         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp-&gt;datap;
          strncpy(info-&gt;shi1_netname, shareName, sizeof(info-&gt;shi1_netname)-1);
!         info-&gt;shi1_netname[sizeof(info-&gt;shi1_netname)-1] = 0;
!         info-&gt;shi1_remark = ((unsigned char *) (info + 1)) - outp-&gt;datap;
!         /* type and pad are already zero */
!     } else { /* infoLevel==2 */
!         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp-&gt;datap;
!         strncpy(info-&gt;shi2_netname, shareName, sizeof(info-&gt;shi2_netname)-1);
!         info-&gt;shi2_netname[sizeof(info-&gt;shi2_netname)-1] = 0;
!         info-&gt;shi2_remark = ((unsigned char *) (info + 1)) - outp-&gt;datap;
          info-&gt;shi2_permissions = ACCESS_ALL;
!         info-&gt;shi2_max_uses = (unsigned short) -1;
          info-&gt;shi2_path = 1 + (((unsigned char *) (info + 1)) - outp-&gt;datap);
!     }
  
!     outp-&gt;totalData = totalData;
!     outp-&gt;totalParms = totalParam;
  
!     smb_SendTran2Packet(vcp, outp, op);
!     smb_FreeTran2Packet(outp);
  
!     return code;
  }
  
  typedef struct smb_rap_wksta_info_10 {
!     DWORD	wki10_computername;	/*char *wki10_computername;*/
!     DWORD	wki10_username; /* char *wki10_username; */
!     DWORD  	wki10_langroup;	/* char *wki10_langroup;*/
!     unsigned char  	wki10_ver_major;
!     unsigned char	wki10_ver_minor;
!     DWORD	wki10_logon_domain;	/*char *wki10_logon_domain;*/
!     DWORD	wki10_oth_domains; /* char *wki10_oth_domains;*/
  } smb_rap_wksta_info_10_t;
  
  
  long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
!     smb_tran2Packet_t *outp;
      long code = 0;
!     int infoLevel;
!     int bufsize;
!     unsigned short * tp;
!     int totalData;
!     int totalParams;
!     smb_rap_wksta_info_10_t * info;
!     char * cstrp;
!     smb_user_t *uidp;
  
!     tp = p-&gt;parmsp + 1; /* Skip over function number */
!     (void) smb_ParseString((unsigned char*) tp, (char **) &amp;tp); /* skip over param descriptor */
!     (void) smb_ParseString((unsigned char*) tp, (char **) &amp;tp); /* skip over data descriptor */
!     infoLevel = *tp++;
!     bufsize = *tp++;
! 
!     if (infoLevel != 10) {
!         return CM_ERROR_INVAL;
!     }
  
!     totalParams = 6;
  	
!     /* infolevel 10 */
!     totalData = sizeof(*info) +		/* info */
!         MAX_COMPUTERNAME_LENGTH +	/* wki10_computername */
!         SMB_MAX_USERNAME_LENGTH +	/* wki10_username */
!         MAX_COMPUTERNAME_LENGTH +	/* wki10_langroup */
!         MAX_COMPUTERNAME_LENGTH +	/* wki10_logon_domain */
!         1;				/* wki10_oth_domains (null)*/
  
!     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
  
!     memset(outp-&gt;parmsp,0,totalParams);
!     memset(outp-&gt;datap,0,totalData);
  
      info = (smb_rap_wksta_info_10_t *) outp-&gt;datap;
!     cstrp = (char *) (info + 1);
  
!     info-&gt;wki10_computername = (DWORD) (cstrp - outp-&gt;datap);
!     strcpy(cstrp, smb_localNamep);
!     cstrp += strlen(cstrp) + 1;
! 
!     info-&gt;wki10_username = (DWORD) (cstrp - outp-&gt;datap);
!     uidp = smb_FindUID(vcp, p-&gt;uid, 0);
!     if (uidp) {
!         lock_ObtainMutex(&amp;uidp-&gt;mx);
!         if(uidp-&gt;unp &amp;&amp; uidp-&gt;unp-&gt;name)
!             strcpy(cstrp, uidp-&gt;unp-&gt;name);
!         lock_ReleaseMutex(&amp;uidp-&gt;mx);
!         smb_ReleaseUID(uidp);
!     }
!     cstrp += strlen(cstrp) + 1;
  
!     info-&gt;wki10_langroup = (DWORD) (cstrp - outp-&gt;datap);
!     strcpy(cstrp, "WORKGROUP");
!     cstrp += strlen(cstrp) + 1;
  
!     /* TODO: Not sure what values these should take, but these work */
!     info-&gt;wki10_ver_major = 5;
!     info-&gt;wki10_ver_minor = 1;
  
!     info-&gt;wki10_logon_domain = (DWORD) (cstrp - outp-&gt;datap);
!     strcpy(cstrp, smb_ServerDomainName);
!     cstrp += strlen(cstrp) + 1;
  
!     info-&gt;wki10_oth_domains = (DWORD) (cstrp - outp-&gt;datap);
!     cstrp ++; /* no other domains */
  
!     outp-&gt;totalData = (unsigned short) (cstrp - outp-&gt;datap); /* actual data size */
!     outp-&gt;parmsp[2] = outp-&gt;totalData;
!     outp-&gt;totalParms = totalParams;
  
!     smb_SendTran2Packet(vcp,outp,op);
!     smb_FreeTran2Packet(outp);
  
!     return code;
  }
  
  typedef struct smb_rap_server_info_0 {
***************
*** 1790,1828 ****
  
  long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
! 	smb_tran2Packet_t *outp;
      long code = 0;
! 	int infoLevel;
! 	int bufsize;
! 	unsigned short * tp;
! 	int totalData;
! 	int totalParams;
      smb_rap_server_info_0_t * info0;
      smb_rap_server_info_1_t * info1;
      char * cstrp;
  
! 	tp = p-&gt;parmsp + 1; /* Skip over function number */
! 	(void) smb_ParseString((unsigned char*) tp, (char **) &amp;tp); /* skip over param descriptor */
! 	(void) smb_ParseString((unsigned char*) tp, (char **) &amp;tp); /* skip over data descriptor */
! 	infoLevel = *tp++;
! 	bufsize = *tp++;
  
!     if(infoLevel != 0 &amp;&amp; infoLevel != 1) {
          return CM_ERROR_INVAL;
      }
  
! 	totalParams = 6;
! 	
! 	totalData = 
          (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
          : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
  
! 	outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
  
! 	memset(outp-&gt;parmsp,0,totalParams);
! 	memset(outp-&gt;datap,0,totalData);
  
!     if(infoLevel == 0) {
          info0 = (smb_rap_server_info_0_t *) outp-&gt;datap;
          cstrp = (char *) (info0 + 1);
          strcpy(info0-&gt;sv0_name, "AFS");
--- 1785,1823 ----
  
  long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
!     smb_tran2Packet_t *outp;
      long code = 0;
!     int infoLevel;
!     int bufsize;
!     unsigned short * tp;
!     int totalData;
!     int totalParams;
      smb_rap_server_info_0_t * info0;
      smb_rap_server_info_1_t * info1;
      char * cstrp;
  
!     tp = p-&gt;parmsp + 1; /* Skip over function number */
!     (void) smb_ParseString((unsigned char*) tp, (char **) &amp;tp); /* skip over param descriptor */
!     (void) smb_ParseString((unsigned char*) tp, (char **) &amp;tp); /* skip over data descriptor */
!     infoLevel = *tp++;
!     bufsize = *tp++;
  
!     if (infoLevel != 0 &amp;&amp; infoLevel != 1) {
          return CM_ERROR_INVAL;
      }
  
!     totalParams = 6;
! 
!     totalData = 
          (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
          : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
  
!     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
  
!     memset(outp-&gt;parmsp,0,totalParams);
!     memset(outp-&gt;datap,0,totalData);
  
!     if (infoLevel == 0) {
          info0 = (smb_rap_server_info_0_t *) outp-&gt;datap;
          cstrp = (char *) (info0 + 1);
          strcpy(info0-&gt;sv0_name, "AFS");
***************
*** 1846,1858 ****
      }
  
      totalData = cstrp - outp-&gt;datap;
! 	outp-&gt;totalData = min(bufsize,totalData); /* actual data size */
      outp-&gt;parmsp[0] = (outp-&gt;totalData == totalData)? 0 : ERROR_MORE_DATA;
! 	outp-&gt;parmsp[2] = totalData;
! 	outp-&gt;totalParms = totalParams;
  
! 	smb_SendTran2Packet(vcp,outp,op);
! 	smb_FreeTran2Packet(outp);
  
      return code;
  }
--- 1841,1853 ----
      }
  
      totalData = cstrp - outp-&gt;datap;
!     outp-&gt;totalData = min(bufsize,totalData); /* actual data size */
      outp-&gt;parmsp[0] = (outp-&gt;totalData == totalData)? 0 : ERROR_MORE_DATA;
!     outp-&gt;parmsp[2] = totalData;
!     outp-&gt;totalParms = totalParams;
  
!     smb_SendTran2Packet(vcp,outp,op);
!     smb_FreeTran2Packet(outp);
  
      return code;
  }
***************
*** 1871,1922 ****
      int firstPacket;
      long code = 0;
  
! 	/* We sometimes see 0 word count.  What to do? */
! 	if (*inp-&gt;wctp == 0) {
  #ifndef DJGPP
! 		HANDLE h;
! 		char *ptbuf[1];
  
! 		osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
  
! 		h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
! 		ptbuf[0] = "Transaction2 word count = 0";
! 		ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
! 			    1, inp-&gt;ncb_length, ptbuf, inp);
! 		DeregisterEventSource(h);
  #else /* DJGPP */
! 		osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
  #endif /* !DJGPP */
  
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
! 		return 0;
! 	}
  
      totalParms = smb_GetSMBParm(inp, 0);
      totalData = smb_GetSMBParm(inp, 1);
          
      firstPacket = (inp-&gt;inCom == 0x32);
          
! 	/* find the packet we're reassembling */
! 	lock_ObtainWrite(&amp;smb_globalLock);
      asp = smb_FindTran2Packet(vcp, inp);
      if (!asp) {
          asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
! 	}
      lock_ReleaseWrite(&amp;smb_globalLock);
          
      /* now merge in this latest packet; start by looking up offsets */
! 	if (firstPacket) {
! 		parmDisp = dataDisp = 0;
          parmOffset = smb_GetSMBParm(inp, 10);
          dataOffset = smb_GetSMBParm(inp, 12);
          parmCount = smb_GetSMBParm(inp, 9);
          dataCount = smb_GetSMBParm(inp, 11);
! 		asp-&gt;maxReturnParms = smb_GetSMBParm(inp, 2);
          asp-&gt;maxReturnData = smb_GetSMBParm(inp, 3);
  
! 		osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
                   totalData, dataCount, asp-&gt;maxReturnData);
      }
      else {
--- 1866,1917 ----
      int firstPacket;
      long code = 0;
  
!     /* We sometimes see 0 word count.  What to do? */
!     if (*inp-&gt;wctp == 0) {
  #ifndef DJGPP
!         HANDLE h;
!         char *ptbuf[1];
  
!         osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
  
!         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
!         ptbuf[0] = "Transaction2 word count = 0";
!         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
!                     1, inp-&gt;ncb_length, ptbuf, inp);
!         DeregisterEventSource(h);
  #else /* DJGPP */
!         osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
  #endif /* !DJGPP */
  
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
!         return 0;
!     }
  
      totalParms = smb_GetSMBParm(inp, 0);
      totalData = smb_GetSMBParm(inp, 1);
          
      firstPacket = (inp-&gt;inCom == 0x32);
          
!     /* find the packet we're reassembling */
!     lock_ObtainWrite(&amp;smb_globalLock);
      asp = smb_FindTran2Packet(vcp, inp);
      if (!asp) {
          asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
!     }
      lock_ReleaseWrite(&amp;smb_globalLock);
          
      /* now merge in this latest packet; start by looking up offsets */
!     if (firstPacket) {
!         parmDisp = dataDisp = 0;
          parmOffset = smb_GetSMBParm(inp, 10);
          dataOffset = smb_GetSMBParm(inp, 12);
          parmCount = smb_GetSMBParm(inp, 9);
          dataCount = smb_GetSMBParm(inp, 11);
!         asp-&gt;maxReturnParms = smb_GetSMBParm(inp, 2);
          asp-&gt;maxReturnData = smb_GetSMBParm(inp, 3);
  
!         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
                   totalData, dataCount, asp-&gt;maxReturnData);
      }
      else {
***************
*** 1949,1957 ****
          asp-&gt;curParms &gt; 0 &amp;&amp;
          asp-&gt;totalData &lt;= asp-&gt;curData &amp;&amp;
          asp-&gt;totalParms &lt;= asp-&gt;curParms) {
! 		/* we've received it all */
          lock_ObtainWrite(&amp;smb_globalLock);
! 		osi_QRemove((osi_queue_t **) &amp;smb_tran2AssemblyQueuep, &amp;asp-&gt;q);
          lock_ReleaseWrite(&amp;smb_globalLock);
  
          /* now dispatch it */
--- 1944,1952 ----
          asp-&gt;curParms &gt; 0 &amp;&amp;
          asp-&gt;totalData &lt;= asp-&gt;curData &amp;&amp;
          asp-&gt;totalParms &lt;= asp-&gt;curParms) {
!         /* we've received it all */
          lock_ObtainWrite(&amp;smb_globalLock);
!         osi_QRemove((osi_queue_t **) &amp;smb_tran2AssemblyQueuep, &amp;asp-&gt;q);
          lock_ReleaseWrite(&amp;smb_globalLock);
  
          /* now dispatch it */
***************
*** 1966,1972 ****
              code = CM_ERROR_BADOP;
          }
  
! 		/* if an error is returned, we're supposed to send an error packet,
           * otherwise the dispatched function already did the data sending.
           * We give dispatched proc the responsibility since it knows how much
           * space to allocate.
--- 1961,1967 ----
              code = CM_ERROR_BADOP;
          }
  
!         /* if an error is returned, we're supposed to send an error packet,
           * otherwise the dispatched function already did the data sending.
           * We give dispatched proc the responsibility since it knows how much
           * space to allocate.
***************
*** 1975,2002 ****
              smb_SendTran2Error(vcp, asp, outp, code);
          }
  
! 		/* free the input tran 2 packet */
! 		lock_ObtainWrite(&amp;smb_globalLock);
          smb_FreeTran2Packet(asp);
! 		lock_ReleaseWrite(&amp;smb_globalLock);
      }
      else if (firstPacket) {
! 		/* the first packet in a multi-packet request, we need to send an
           * ack to get more data.
           */
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
      }
  
! 	return 0;
  }
  
  long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
! 	char *pathp;
      smb_tran2Packet_t *outp;
      long code = 0;
! 	cm_space_t *spacep;
      int excl;
      cm_user_t *userp;
      cm_scache_t *dscp;		/* dir we're dealing with */
--- 1970,1997 ----
              smb_SendTran2Error(vcp, asp, outp, code);
          }
  
!         /* free the input tran 2 packet */
!         lock_ObtainWrite(&amp;smb_globalLock);
          smb_FreeTran2Packet(asp);
!         lock_ReleaseWrite(&amp;smb_globalLock);
      }
      else if (firstPacket) {
!         /* the first packet in a multi-packet request, we need to send an
           * ack to get more data.
           */
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
      }
  
!     return 0;
  }
  
  long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
!     char *pathp;
      smb_tran2Packet_t *outp;
      long code = 0;
!     cm_space_t *spacep;
      int excl;
      cm_user_t *userp;
      cm_scache_t *dscp;		/* dir we're dealing with */
***************
*** 2006,2012 ****
      smb_fid_t *fidp;
      int attributes;
      char *lastNamep;
!     long dosTime;
      int openFun;
      int trunc;
      int openMode;
--- 2001,2007 ----
      smb_fid_t *fidp;
      int attributes;
      char *lastNamep;
!     time_t dosTime;
      int openFun;
      int trunc;
      int openMode;
***************
*** 2014,2039 ****
      int openAction;
      int parmSlot;			/* which parm we're dealing with */
      long returnEALength;
! 	char *tidPathp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      scp = NULL;
          
! 	extraInfo = (p-&gt;parmsp[0] &amp; 1);	/* return extra info */
      returnEALength = (p-&gt;parmsp[0] &amp; 8);	/* return extended attr length */
  
! 	openFun = p-&gt;parmsp[6];		/* open function */
      excl = ((openFun &amp; 3) == 0);
      trunc = ((openFun &amp; 3) == 2);	/* truncate it */
! 	openMode = (p-&gt;parmsp[1] &amp; 0x7);
      openAction = 0;			/* tracks what we did */
  
      attributes = p-&gt;parmsp[3];
      dosTime = p-&gt;parmsp[4] | (p-&gt;parmsp[5] &lt;&lt; 16);
          
! 	/* compute initial mode bits based on read-only flag in attributes */
      initialModeBits = 0666;
      if (attributes &amp; 1) initialModeBits &amp;= ~0222;
          
--- 2009,2034 ----
      int openAction;
      int parmSlot;			/* which parm we're dealing with */
      long returnEALength;
!     char *tidPathp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      scp = NULL;
          
!     extraInfo = (p-&gt;parmsp[0] &amp; 1);	/* return extra info */
      returnEALength = (p-&gt;parmsp[0] &amp; 8);	/* return extended attr length */
  
!     openFun = p-&gt;parmsp[6];		/* open function */
      excl = ((openFun &amp; 3) == 0);
      trunc = ((openFun &amp; 3) == 2);	/* truncate it */
!     openMode = (p-&gt;parmsp[1] &amp; 0x7);
      openAction = 0;			/* tracks what we did */
  
      attributes = p-&gt;parmsp[3];
      dosTime = p-&gt;parmsp[4] | (p-&gt;parmsp[5] &lt;&lt; 16);
          
!     /* compute initial mode bits based on read-only flag in attributes */
      initialModeBits = 0666;
      if (attributes &amp; 1) initialModeBits &amp;= ~0222;
          
***************
*** 2041,2060 ****
          
      outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
  
! 	spacep = cm_GetSpace();
      smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
! 	if (lastNamep &amp;&amp; strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
! 		/* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
          fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
          smb_SetupIoctlFid(fidp, spacep);
  
          /* copy out remainder of the parms */
! 		parmSlot = 0;
! 		outp-&gt;parmsp[parmSlot] = fidp-&gt;fid; parmSlot++;
! 		if (extraInfo) {
              outp-&gt;parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
              outp-&gt;parmsp[parmSlot] = 0; parmSlot++;	/* mod time */
              outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
--- 2036,2055 ----
          
      outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
  
!     spacep = cm_GetSpace();
      smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
!     if (lastNamep &amp;&amp; strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
!         /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
          fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
          smb_SetupIoctlFid(fidp, spacep);
  
          /* copy out remainder of the parms */
!         parmSlot = 0;
!         outp-&gt;parmsp[parmSlot] = fidp-&gt;fid; parmSlot++;
!         if (extraInfo) {
              outp-&gt;parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
              outp-&gt;parmsp[parmSlot] = 0; parmSlot++;	/* mod time */
              outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
***************
*** 2063,2079 ****
              outp-&gt;parmsp[parmSlot] = openMode; parmSlot++;
              outp-&gt;parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==&gt; normal file or dir */
              outp-&gt;parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
! 		}   
! 		/* and the final "always present" stuff */
          outp-&gt;parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
! 		/* next write out the "unique" ID */
! 		outp-&gt;parmsp[parmSlot] = 0x1234; parmSlot++;
! 		outp-&gt;parmsp[parmSlot] = 0x5678; parmSlot++;
          outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
! 		if (returnEALength) {
! 			outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
! 			outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
!         }
                  
          outp-&gt;totalData = 0;
          outp-&gt;totalParms = parmSlot * 2;
--- 2058,2074 ----
              outp-&gt;parmsp[parmSlot] = openMode; parmSlot++;
              outp-&gt;parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==&gt; normal file or dir */
              outp-&gt;parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
!         }   
!         /* and the final "always present" stuff */
          outp-&gt;parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
!         /* next write out the "unique" ID */
!         outp-&gt;parmsp[parmSlot] = 0x1234; parmSlot++;
!         outp-&gt;parmsp[parmSlot] = 0x5678; parmSlot++;
          outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
!         if (returnEALength) {
!             outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
!             outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
!         }       
                  
          outp-&gt;totalData = 0;
          outp-&gt;totalParms = parmSlot * 2;
***************
*** 2082,2103 ****
                  
          smb_FreeTran2Packet(outp);
  
! 		/* and clean up fid reference */
          smb_ReleaseFID(fidp);
          return 0;
      }
  
  #ifdef DEBUG_VERBOSE
! 	{
! 		char *hexp, *asciip;
! 		asciip = (lastNamep ? lastNamep : pathp);
! 		hexp = osi_HexifyString( asciip );
! 		DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
! 		free(hexp);
! 	}
  #endif
  
! 	userp = smb_GetTran2User(vcp, p);
      /* In the off chance that userp is NULL, we log and abandon */
      if (!userp) {
          osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p-&gt;uid);
--- 2077,2098 ----
                  
          smb_FreeTran2Packet(outp);
  
!         /* and clean up fid reference */
          smb_ReleaseFID(fidp);
          return 0;
      }
  
  #ifdef DEBUG_VERBOSE
!     {
!         char *hexp, *asciip;
!         asciip = (lastNamep ? lastNamep : pathp);
!         hexp = osi_HexifyString( asciip );
!         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
!         free(hexp);
!     }       
  #endif
  
!     userp = smb_GetTran2User(vcp, p);
      /* In the off chance that userp is NULL, we log and abandon */
      if (!userp) {
          osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p-&gt;uid);
***************
*** 2105,2112 ****
          return CM_ERROR_BADSMB;
      }
  
! 	code = smb_LookupTIDPath(vcp, p-&gt;tid, &amp;tidPathp);
!     if(code == CM_ERROR_TIDIPC) {
          /* Attempt to use TID allocated for IPC.  The client is
             probably trying to locate DCE RPC end points, which
             we don't support. */
--- 2100,2107 ----
          return CM_ERROR_BADSMB;
      }
  
!     code = smb_LookupTIDPath(vcp, p-&gt;tid, &amp;tidPathp);
!     if (code == CM_ERROR_TIDIPC) {
          /* Attempt to use TID allocated for IPC.  The client is
             probably trying to locate DCE RPC end points, which
             we don't support. */
***************
*** 2116,2269 ****
          return CM_ERROR_NOSUCHPATH;
      }
  
! 	dscp = NULL;
! 	code = cm_NameI(cm_rootSCachep, pathp,
!                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
!                     userp, tidPathp, &amp;req, &amp;scp);
! 	if (code != 0) {
! 		code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
!                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
!                         userp, tidPathp, &amp;req, &amp;dscp);
! 		cm_FreeSpace(spacep);
  
          if (code) {
              cm_ReleaseUser(userp);
! 			smb_FreeTran2Packet(outp);
              return code;
          }
          
          /* otherwise, scp points to the parent directory.  Do a lookup,
! 		 * and truncate the file if we find it, otherwise we create the
! 		 * file.
           */
!         if (!lastNamep) lastNamep = pathp;
!         else lastNamep++;
          code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                           &amp;req, &amp;scp);
          if (code &amp;&amp; code != CM_ERROR_NOSUCHFILE) {
! 			cm_ReleaseSCache(dscp);
              cm_ReleaseUser(userp);
! 			smb_FreeTran2Packet(outp);
              return code;
          }
! 	}
      else {
          cm_FreeSpace(spacep);
! 	}
          
      /* if we get here, if code is 0, the file exists and is represented by
       * scp.  Otherwise, we have to create it.
       */
! 	if (code == 0) {
          code = cm_CheckOpen(scp, openMode, trunc, userp, &amp;req);
          if (code) {
              if (dscp) cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
! 			smb_FreeTran2Packet(outp);
              return code;
          }
  
! 		if (excl) {
! 			/* oops, file shouldn't be there */
              if (dscp) cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
! 			smb_FreeTran2Packet(outp);
              return CM_ERROR_EXISTS;
          }
  
! 		if (trunc) {
! 			setAttr.mask = CM_ATTRMASK_LENGTH;
              setAttr.length.LowPart = 0;
              setAttr.length.HighPart = 0;
! 			code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
              openAction = 3;	/* truncated existing file */
! 		}   
!         else openAction = 1;	/* found existing file */
      }
! 	else if (!(openFun &amp; SMB_ATTR_DIRECTORY)) {
! 		/* don't create if not found */
          if (dscp) cm_ReleaseSCache(dscp);
          osi_assert(scp == NULL);
          cm_ReleaseUser(userp);
! 		smb_FreeTran2Packet(outp);
          return CM_ERROR_NOSUCHFILE;
      }
      else {
! 		osi_assert(dscp != NULL &amp;&amp; scp == NULL);
! 		openAction = 2;	/* created file */
! 		setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
! 		smb_UnixTimeFromSearchTime(&amp;setAttr.clientModTime, dosTime);
          code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
!                          &amp;req);
! 		if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 			smb_NotifyChange(FILE_ACTION_ADDED,
                               FILE_NOTIFY_CHANGE_FILE_NAME,  
                               dscp, lastNamep, NULL, TRUE);
          if (!excl &amp;&amp; code == CM_ERROR_EXISTS) {
! 			/* not an exclusive create, and someone else tried
! 			 * creating it already, then we open it anyway.  We
! 			 * don't bother retrying after this, since if this next
! 			 * fails, that means that the file was deleted after we
! 			 * started this call.
               */
              code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
!                              userp, &amp;req, &amp;scp);
              if (code == 0) {
                  if (trunc) {
! 					setAttr.mask = CM_ATTRMASK_LENGTH;
                      setAttr.length.LowPart = 0;
                      setAttr.length.HighPart = 0;
                      code = cm_SetAttr(scp, &amp;setAttr, userp,
!                                       &amp;req);
                  }   
! 			}	/* lookup succeeded */
          }
      }
          
! 	/* we don't need this any longer */
! 	if (dscp) cm_ReleaseSCache(dscp);
  
      if (code) {
! 		/* something went wrong creating or truncating the file */
          if (scp) cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
! 		smb_FreeTran2Packet(outp);
          return code;
      }
          
! 	/* make sure we're about to open a file */
! 	if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
! 		cm_ReleaseSCache(scp);
! 		cm_ReleaseUser(userp);
! 		smb_FreeTran2Packet(outp);
! 		return CM_ERROR_ISDIR;
! 	}
  
      /* now all we have to do is open the file itself */
      fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
      osi_assert(fidp);
  	
! 	/* save a pointer to the vnode */
      fidp-&gt;scp = scp;
          
! 	/* compute open mode */
      if (openMode != 1) fidp-&gt;flags |= SMB_FID_OPENREAD;
      if (openMode == 1 || openMode == 2)
          fidp-&gt;flags |= SMB_FID_OPENWRITE;
  
! 	smb_ReleaseFID(fidp);
          
! 	cm_Open(scp, 0, userp);
  
      /* copy out remainder of the parms */
! 	parmSlot = 0;
! 	outp-&gt;parmsp[parmSlot] = fidp-&gt;fid; parmSlot++;
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	if (extraInfo) {
          outp-&gt;parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
! 		smb_SearchTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
          outp-&gt;parmsp[parmSlot] = (unsigned short)(dosTime &amp; 0xffff); parmSlot++;
          outp-&gt;parmsp[parmSlot] = (unsigned short)((dosTime&gt;&gt;16) &amp; 0xffff); parmSlot++;
          outp-&gt;parmsp[parmSlot] = (unsigned short) (scp-&gt;length.LowPart &amp; 0xffff);
--- 2111,2284 ----
          return CM_ERROR_NOSUCHPATH;
      }
  
!     dscp = NULL;
!     code = cm_NameI(cm_rootSCachep, pathp,
!                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
!                      userp, tidPathp, &amp;req, &amp;scp);
!     if (code != 0) {
!         code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
!                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
!                          userp, tidPathp, &amp;req, &amp;dscp);
!         cm_FreeSpace(spacep);
  
          if (code) {
              cm_ReleaseUser(userp);
!             smb_FreeTran2Packet(outp);
              return code;
          }
          
          /* otherwise, scp points to the parent directory.  Do a lookup,
!          * and truncate the file if we find it, otherwise we create the
!          * file.
           */
!         if (!lastNamep) 
!             lastNamep = pathp;
!         else 
!             lastNamep++;
          code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                           &amp;req, &amp;scp);
          if (code &amp;&amp; code != CM_ERROR_NOSUCHFILE) {
!             cm_ReleaseSCache(dscp);
              cm_ReleaseUser(userp);
!             smb_FreeTran2Packet(outp);
              return code;
          }
!     }
      else {
          cm_FreeSpace(spacep);
!     }
          
      /* if we get here, if code is 0, the file exists and is represented by
       * scp.  Otherwise, we have to create it.
       */
!     if (code == 0) {
          code = cm_CheckOpen(scp, openMode, trunc, userp, &amp;req);
          if (code) {
              if (dscp) cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
!             smb_FreeTran2Packet(outp);
              return code;
          }
  
!         if (excl) {
!             /* oops, file shouldn't be there */
              if (dscp) cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
!             smb_FreeTran2Packet(outp);
              return CM_ERROR_EXISTS;
          }
  
!         if (trunc) {
!             setAttr.mask = CM_ATTRMASK_LENGTH;
              setAttr.length.LowPart = 0;
              setAttr.length.HighPart = 0;
!             code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
              openAction = 3;	/* truncated existing file */
!         }   
!         else 
!             openAction = 1;	/* found existing file */
      }
!     else if (!(openFun &amp; SMB_ATTR_DIRECTORY)) {
!         /* don't create if not found */
          if (dscp) cm_ReleaseSCache(dscp);
          osi_assert(scp == NULL);
          cm_ReleaseUser(userp);
!         smb_FreeTran2Packet(outp);
          return CM_ERROR_NOSUCHFILE;
      }
      else {
!         osi_assert(dscp != NULL &amp;&amp; scp == NULL);
!         openAction = 2;	/* created file */
!         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
!         smb_UnixTimeFromSearchTime(&amp;setAttr.clientModTime, dosTime);
          code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
!                           &amp;req);
!         if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!             smb_NotifyChange(FILE_ACTION_ADDED,
                               FILE_NOTIFY_CHANGE_FILE_NAME,  
                               dscp, lastNamep, NULL, TRUE);
          if (!excl &amp;&amp; code == CM_ERROR_EXISTS) {
!             /* not an exclusive create, and someone else tried
!              * creating it already, then we open it anyway.  We
!              * don't bother retrying after this, since if this next
!              * fails, that means that the file was deleted after we
!              * started this call.
               */
              code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
!                               userp, &amp;req, &amp;scp);
              if (code == 0) {
                  if (trunc) {
!                     setAttr.mask = CM_ATTRMASK_LENGTH;
                      setAttr.length.LowPart = 0;
                      setAttr.length.HighPart = 0;
                      code = cm_SetAttr(scp, &amp;setAttr, userp,
!                                        &amp;req);
                  }   
!             }	/* lookup succeeded */
          }
      }
          
!     /* we don't need this any longer */
!     if (dscp) cm_ReleaseSCache(dscp);
  
      if (code) {
!         /* something went wrong creating or truncating the file */
          if (scp) cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
!         smb_FreeTran2Packet(outp);
          return code;
      }
          
!     /* make sure we're about to open a file */
!     if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!         code = 0;
!         while (code == 0 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!             cm_scache_t * targetScp = 0;
!             code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, &amp;req);
!             if (code == 0) {
!                 /* we have a more accurate file to use (the
!                 * target of the symbolic link).  Otherwise,
!                 * we'll just use the symlink anyway.
!                 */
!                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                           scp, targetScp);
!                 cm_ReleaseSCache(scp);
!                 scp = targetScp;
!             }
!         }
!         if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!             cm_ReleaseSCache(scp);
!             cm_ReleaseUser(userp);
!             smb_FreeTran2Packet(outp);
!             return CM_ERROR_ISDIR;
!         }
!     }
  
      /* now all we have to do is open the file itself */
      fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
      osi_assert(fidp);
  	
!     /* save a pointer to the vnode */
      fidp-&gt;scp = scp;
          
!     /* compute open mode */
      if (openMode != 1) fidp-&gt;flags |= SMB_FID_OPENREAD;
      if (openMode == 1 || openMode == 2)
          fidp-&gt;flags |= SMB_FID_OPENWRITE;
  
!     smb_ReleaseFID(fidp);
          
!     cm_Open(scp, 0, userp);
  
      /* copy out remainder of the parms */
!     parmSlot = 0;
!     outp-&gt;parmsp[parmSlot] = fidp-&gt;fid; parmSlot++;
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     if (extraInfo) {
          outp-&gt;parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
!         smb_SearchTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
          outp-&gt;parmsp[parmSlot] = (unsigned short)(dosTime &amp; 0xffff); parmSlot++;
          outp-&gt;parmsp[parmSlot] = (unsigned short)((dosTime&gt;&gt;16) &amp; 0xffff); parmSlot++;
          outp-&gt;parmsp[parmSlot] = (unsigned short) (scp-&gt;length.LowPart &amp; 0xffff);
***************
*** 2273,2295 ****
          outp-&gt;parmsp[parmSlot] = openMode; parmSlot++;
          outp-&gt;parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==&gt; normal file or dir */
          outp-&gt;parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
! 	}   
! 	/* and the final "always present" stuff */
      outp-&gt;parmsp[parmSlot] = openAction; parmSlot++;
! 	/* next write out the "unique" ID */
! 	outp-&gt;parmsp[parmSlot] = (unsigned short) (scp-&gt;fid.vnode &amp; 0xffff); parmSlot++;
! 	outp-&gt;parmsp[parmSlot] = (unsigned short) (scp-&gt;fid.volume &amp; 0xffff); parmSlot++;
      outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
      if (returnEALength) {
! 		outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
! 		outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
!     }
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	outp-&gt;totalData = 0;		/* total # of data bytes */
      outp-&gt;totalParms = parmSlot * 2;	/* shorts are two bytes */
  
! 	smb_SendTran2Packet(vcp, outp, op);
!         
      smb_FreeTran2Packet(outp);
  
      cm_ReleaseUser(userp);
--- 2288,2310 ----
          outp-&gt;parmsp[parmSlot] = openMode; parmSlot++;
          outp-&gt;parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==&gt; normal file or dir */
          outp-&gt;parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
!     }   
!     /* and the final "always present" stuff */
      outp-&gt;parmsp[parmSlot] = openAction; parmSlot++;
!     /* next write out the "unique" ID */
!     outp-&gt;parmsp[parmSlot] = (unsigned short) (scp-&gt;fid.vnode &amp; 0xffff); parmSlot++;
!     outp-&gt;parmsp[parmSlot] = (unsigned short) (scp-&gt;fid.volume &amp; 0xffff); parmSlot++;
      outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
      if (returnEALength) {
!         outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
!         outp-&gt;parmsp[parmSlot] = 0; parmSlot++;
!     }   
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     outp-&gt;totalData = 0;		/* total # of data bytes */
      outp-&gt;totalParms = parmSlot * 2;	/* shorts are two bytes */
  
!     smb_SendTran2Packet(vcp, outp, op);
! 
      smb_FreeTran2Packet(outp);
  
      cm_ReleaseUser(userp);
***************
*** 2299,2401 ****
  
  long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
  long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
  long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
! 	smb_tran2Packet_t *outp;
      smb_tran2QFSInfo_t qi;
! 	int responseSize;
! 	osi_hyper_t temp;
! 	static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
!         
! 	osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p-&gt;parmsp[0]);
! 
! 	switch (p-&gt;parmsp[0]) {
! 	case 1: responseSize = sizeof(qi.u.allocInfo); break;
! 	case 2: responseSize = sizeof(qi.u.volumeInfo); break;
! 	case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
! 	case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
! 	case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
! 	case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
! 	default: return CM_ERROR_INVAL;
! 	}
  
      outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
! 	switch (p-&gt;parmsp[0]) {
! 	case 1:
! 		/* alloc info */
          qi.u.allocInfo.FSID = 0;
          qi.u.allocInfo.sectorsPerAllocUnit = 1;
          qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
          qi.u.allocInfo.availAllocUnits = 0x3fffffff;
          qi.u.allocInfo.bytesPerSector = 1024;
! 		break;
  
      case 2:
! 		/* volume info */
          qi.u.volumeInfo.vsn = 1234;
          qi.u.volumeInfo.vnCount = 4;
! 		/* we're supposed to pad it out with zeroes to the end */
! 		memset(&amp;qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
          memcpy(qi.u.volumeInfo.label, "AFS", 4);
! 		break;
  
! 	case 0x102:
! 		/* FS volume info */
! 		memset((char *)&amp;qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
! 		qi.u.FSvolumeInfo.vsn = 1234;
! 		qi.u.FSvolumeInfo.vnCount = 8;
! 		memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
! 		break;
! 
! 	case 0x103:
! 		/* FS size info */
! 		temp.HighPart = 0;
! 		temp.LowPart = 0x7fffffff;
! 		qi.u.FSsizeInfo.totalAllocUnits = temp;
! 		temp.LowPart = 0x3fffffff;
! 		qi.u.FSsizeInfo.availAllocUnits = temp;
! 		qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
! 		qi.u.FSsizeInfo.bytesPerSector = 1024;
! 		break;
! 
! 	case 0x104:
! 		/* FS device info */
! 		qi.u.FSdeviceInfo.devType = 0;	/* don't have a number */
! 		qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
! 		break;
  
  	case 0x105:
! 		/* FS attribute info */
! 		/* attributes, defined in WINNT.H:
! 		 *	FILE_CASE_SENSITIVE_SEARCH	0x1
! 		 *	FILE_CASE_PRESERVED_NAMES	0x2
! 		 *	&lt;no name defined&gt;		0x4000
! 		 *	   If bit 0x4000 is not set, Windows 95 thinks
! 		 *	   we can't handle long (non-8.3) names,
! 		 *	   despite our protestations to the contrary.
! 		 */
! 		qi.u.FSattributeInfo.attributes = 0x4003;
! 		qi.u.FSattributeInfo.maxCompLength = 255;
! 		qi.u.FSattributeInfo.FSnameLength = 6;
! 		memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
! 		break;
!     }
          
! 	/* copy out return data, and set corresponding sizes */
! 	outp-&gt;totalParms = 0;
      outp-&gt;totalData = responseSize;
      memcpy(outp-&gt;datap, &amp;qi, responseSize);
  
! 	/* send and free the packets */
! 	smb_SendTran2Packet(vcp, outp, op);
      smb_FreeTran2Packet(outp);
  
      return 0;
--- 2314,2418 ----
  
  long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
  long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
  long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
!     smb_tran2Packet_t *outp;
      smb_tran2QFSInfo_t qi;
!     int responseSize;
!     osi_hyper_t temp;
!     static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
!         
!     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p-&gt;parmsp[0]);
! 
!     switch (p-&gt;parmsp[0]) {
!     case 1: responseSize = sizeof(qi.u.allocInfo); break;
!     case 2: responseSize = sizeof(qi.u.volumeInfo); break;
!     case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
!     case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
!     case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
!     case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
!     default: return CM_ERROR_INVAL;
!     }
  
      outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
!     switch (p-&gt;parmsp[0]) {
!     case 1:
!         /* alloc info */
          qi.u.allocInfo.FSID = 0;
          qi.u.allocInfo.sectorsPerAllocUnit = 1;
          qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
          qi.u.allocInfo.availAllocUnits = 0x3fffffff;
          qi.u.allocInfo.bytesPerSector = 1024;
!         break;
  
      case 2:
!         /* volume info */
          qi.u.volumeInfo.vsn = 1234;
          qi.u.volumeInfo.vnCount = 4;
!         /* we're supposed to pad it out with zeroes to the end */
!         memset(&amp;qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
          memcpy(qi.u.volumeInfo.label, "AFS", 4);
!         break;
  
!     case 0x102:
!         /* FS volume info */
!         memset((char *)&amp;qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
!         qi.u.FSvolumeInfo.vsn = 1234;
!         qi.u.FSvolumeInfo.vnCount = 8;
!         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
!         break;
! 
!     case 0x103:
!         /* FS size info */
!         temp.HighPart = 0;
!         temp.LowPart = 0x7fffffff;
!         qi.u.FSsizeInfo.totalAllocUnits = temp;
!         temp.LowPart = 0x3fffffff;
!         qi.u.FSsizeInfo.availAllocUnits = temp;
!         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
!         qi.u.FSsizeInfo.bytesPerSector = 1024;
!         break;
! 
!     case 0x104:
!         /* FS device info */
!         qi.u.FSdeviceInfo.devType = 0;	/* don't have a number */
!         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
!         break;
  
  	case 0x105:
!         /* FS attribute info */
!         /* attributes, defined in WINNT.H:
!          *	FILE_CASE_SENSITIVE_SEARCH	0x1
!          *	FILE_CASE_PRESERVED_NAMES	0x2
!          *	&lt;no name defined&gt;		0x4000
!          *	   If bit 0x4000 is not set, Windows 95 thinks
!          *	   we can't handle long (non-8.3) names,
!          *	   despite our protestations to the contrary.
!          */
!         qi.u.FSattributeInfo.attributes = 0x4003;
!         qi.u.FSattributeInfo.maxCompLength = 255;
!         qi.u.FSattributeInfo.FSnameLength = 6;
!         memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
!         break;
!     }   
          
!     /* copy out return data, and set corresponding sizes */
!     outp-&gt;totalParms = 0;
      outp-&gt;totalData = responseSize;
      memcpy(outp-&gt;datap, &amp;qi, responseSize);
  
!     /* send and free the packets */
!     smb_SendTran2Packet(vcp, outp, op);
      smb_FreeTran2Packet(outp);
  
      return 0;
***************
*** 2403,2534 ****
  
  long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
  struct smb_ShortNameRock {
! 	char *maskp;
! 	unsigned int vnode;
! 	char *shortName;
! 	size_t shortNameLen;
! };
  
  int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
! 	osi_hyper_t *offp)
! {
! 	struct smb_ShortNameRock *rockp;
! 	char *shortNameEnd;
! 
! 	rockp = vrockp;
! 	/* compare both names and vnodes, though probably just comparing vnodes
! 	 * would be safe enough.
! 	 */
! 	if (cm_stricmp(dep-&gt;name, rockp-&gt;maskp) != 0)
! 		return 0;
! 	if (ntohl(dep-&gt;fid.vnode) != rockp-&gt;vnode)
! 		return 0;
! 	/* This is the entry */
! 	cm_Gen8Dot3Name(dep, rockp-&gt;shortName, &amp;shortNameEnd);
! 	rockp-&gt;shortNameLen = shortNameEnd - rockp-&gt;shortName;
! 	return CM_ERROR_STOPNOW;
! }
  
  long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
  	char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
  {
! 	struct smb_ShortNameRock rock;
! 	char *lastNamep;
! 	cm_space_t *spacep;
! 	cm_scache_t *dscp;
! 	int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
! 	long code = 0;
! 	osi_hyper_t thyper;
  
! 	spacep = cm_GetSpace();
! 	smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
! 	code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold, userp, tidPathp,
                       reqp, &amp;dscp);
! 	cm_FreeSpace(spacep);
! 	if (code) return code;
  
! 	if (!lastNamep) lastNamep = pathp;
! 	else lastNamep++;
! 	thyper.LowPart = 0;
! 	thyper.HighPart = 0;
! 	rock.shortName = shortName;
! 	rock.vnode = vnode;
! 	rock.maskp = lastNamep;
! 	code = cm_ApplyDir(dscp, cm_GetShortNameProc, &amp;rock, &amp;thyper, userp,
                          reqp, NULL);
  
! 	cm_ReleaseSCache(dscp);
  
! 	if (code == 0)
! 		return CM_ERROR_NOSUCHFILE;
! 	if (code == CM_ERROR_STOPNOW) {
! 		*shortNameLenp = rock.shortNameLen;
! 		return 0;
! 	}
! 	return code;
  }
  
  long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
! 	smb_tran2Packet_t *outp;
!     unsigned long dosTime;
! 	FILETIME ft;
      unsigned short infoLevel;
      int nbytesRequired;
      unsigned short attributes;
! 	unsigned long extAttributes;
! 	char shortName[13];
! 	unsigned int len;
      cm_user_t *userp;
! 	cm_space_t *spacep;
      cm_scache_t *scp, *dscp;
      long code = 0;
      char *op;
! 	char *tidPathp;
! 	char *lastComp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
! 	infoLevel = p-&gt;parmsp[0];
      if (infoLevel == 6) nbytesRequired = 0;
      else if (infoLevel == 1) nbytesRequired = 22;
      else if (infoLevel == 2) nbytesRequired = 26;
! 	else if (infoLevel == 0x101) nbytesRequired = 40;
! 	else if (infoLevel == 0x102) nbytesRequired = 24;
! 	else if (infoLevel == 0x103) nbytesRequired = 4;
! 	else if (infoLevel == 0x108) nbytesRequired = 30;
      else {
! 		osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
                    p-&gt;opcode, infoLevel);
! 		smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
          return 0;
      }
! 	osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
!              osi_LogSaveString(smb_logp, (char *)(&amp;p-&gt;parmsp[3])));
  
      outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
  
! 	if (infoLevel &gt; 0x100)
! 		outp-&gt;totalParms = 2;
! 	else
! 		outp-&gt;totalParms = 0;
!         outp-&gt;totalData = nbytesRequired;
          
      /* now, if we're at infoLevel 6, we're only being asked to check
       * the syntax, so we just OK things now.  In particular, we're *not*
       * being asked to verify anything about the state of any parent dirs.
       */
! 	if (infoLevel == 6) {
! 		smb_SendTran2Packet(vcp, outp, opx);
          smb_FreeTran2Packet(outp);
! 		return 0;
!     }
          
      userp = smb_GetTran2User(vcp, p);
      if (!userp) {
--- 2420,2552 ----
  
  long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
  struct smb_ShortNameRock {
!     char *maskp;
!     unsigned int vnode;
!     char *shortName;
!     size_t shortNameLen;
! };      
  
  int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
!                          osi_hyper_t *offp)
! {       
!     struct smb_ShortNameRock *rockp;
!     char *shortNameEnd;
! 
!     rockp = vrockp;
!     /* compare both names and vnodes, though probably just comparing vnodes
!      * would be safe enough.
!      */
!     if (cm_stricmp(dep-&gt;name, rockp-&gt;maskp) != 0)
!         return 0;
!     if (ntohl(dep-&gt;fid.vnode) != rockp-&gt;vnode)
!         return 0;
!     /* This is the entry */
!     cm_Gen8Dot3Name(dep, rockp-&gt;shortName, &amp;shortNameEnd);
!     rockp-&gt;shortNameLen = shortNameEnd - rockp-&gt;shortName;
!     return CM_ERROR_STOPNOW;
! }       
  
  long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
  	char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
  {
!     struct smb_ShortNameRock rock;
!     char *lastNamep;
!     cm_space_t *spacep;
!     cm_scache_t *dscp;
!     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
!     long code = 0;
!     osi_hyper_t thyper;
  
!     spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
!     code = cm_NameI(cm_rootSCachep, spacep-&gt;data, caseFold, userp, tidPathp,
                       reqp, &amp;dscp);
!     cm_FreeSpace(spacep);
!     if (code) return code;
  
!     if (!lastNamep) lastNamep = pathp;
!     else lastNamep++;
!     thyper.LowPart = 0;
!     thyper.HighPart = 0;
!     rock.shortName = shortName;
!     rock.vnode = vnode;
!     rock.maskp = lastNamep;
!     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &amp;rock, &amp;thyper, userp,
                          reqp, NULL);
  
!     cm_ReleaseSCache(dscp);
  
!     if (code == 0)
!         return CM_ERROR_NOSUCHFILE;
!     if (code == CM_ERROR_STOPNOW) {
!         *shortNameLenp = rock.shortNameLen;
!         return 0;
!     }
!     return code;
  }
  
  long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
!     smb_tran2Packet_t *outp;
!     time_t dosTime;
!     FILETIME ft;
      unsigned short infoLevel;
      int nbytesRequired;
      unsigned short attributes;
!     unsigned long extAttributes;
!     char shortName[13];
!     unsigned int len;
      cm_user_t *userp;
!     cm_space_t *spacep;
      cm_scache_t *scp, *dscp;
      long code = 0;
      char *op;
!     char *tidPathp;
!     char *lastComp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     infoLevel = p-&gt;parmsp[0];
      if (infoLevel == 6) nbytesRequired = 0;
      else if (infoLevel == 1) nbytesRequired = 22;
      else if (infoLevel == 2) nbytesRequired = 26;
!     else if (infoLevel == 0x101) nbytesRequired = 40;
!     else if (infoLevel == 0x102) nbytesRequired = 24;
!     else if (infoLevel == 0x103) nbytesRequired = 4;
!     else if (infoLevel == 0x108) nbytesRequired = 30;
      else {
!         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
                    p-&gt;opcode, infoLevel);
!         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
          return 0;
      }
!     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
!               osi_LogSaveString(smb_logp, (char *)(&amp;p-&gt;parmsp[3])));
  
      outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
  
!     if (infoLevel &gt; 0x100)
!         outp-&gt;totalParms = 2;
!     else
!         outp-&gt;totalParms = 0;
!     outp-&gt;totalData = nbytesRequired;
          
      /* now, if we're at infoLevel 6, we're only being asked to check
       * the syntax, so we just OK things now.  In particular, we're *not*
       * being asked to verify anything about the state of any parent dirs.
       */
!     if (infoLevel == 6) {
!         smb_SendTran2Packet(vcp, outp, opx);
          smb_FreeTran2Packet(outp);
!         return 0;
!     }   
          
      userp = smb_GetTran2User(vcp, p);
      if (!userp) {
***************
*** 2537,2543 ****
          return CM_ERROR_BADSMB;
      }
  
! 	code = smb_LookupTIDPath(vcp, p-&gt;tid, &amp;tidPathp);
      if(code) {
          cm_ReleaseUser(userp);
          smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
--- 2555,2561 ----
          return CM_ERROR_BADSMB;
      }
  
!     code = smb_LookupTIDPath(vcp, p-&gt;tid, &amp;tidPathp);
      if(code) {
          cm_ReleaseUser(userp);
          smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
***************
*** 2545,2576 ****
          return 0;
      }
  
! 	/*
! 	 * XXX Strange hack XXX
! 	 *
! 	 * As of Patch 7 (13 January 98), we are having the following problem:
! 	 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
! 	 * requests to look up "desktop.ini" in all the subdirectories.
! 	 * This can cause zillions of timeouts looking up non-existent cells
! 	 * and volumes, especially in the top-level directory.
! 	 *
! 	 * We have not found any way to avoid this or work around it except
! 	 * to explicitly ignore the requests for mount points that haven't
! 	 * yet been evaluated and for directories that haven't yet been
! 	 * fetched.
! 	 */
! 	if (infoLevel == 0x101) {
! 		spacep = cm_GetSpace();
! 		smb_StripLastComponent(spacep-&gt;data, &amp;lastComp,
! 					(char *)(&amp;p-&gt;parmsp[3]));
! 		/* Make sure that lastComp is not NULL */
! 		if (lastComp) {
! 		    if (strcmp(lastComp, "\\desktop.ini") == 0) {
                  code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
!                                 CM_FLAG_CASEFOLD
!                                 | CM_FLAG_DIRSEARCH
!                                 | CM_FLAG_FOLLOW,
!                                 userp, tidPathp, &amp;req, &amp;dscp);
                  if (code == 0) {
                      if (dscp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT
                           &amp;&amp; !dscp-&gt;mountRootFidp)
--- 2563,2594 ----
          return 0;
      }
  
!     /*
!      * XXX Strange hack XXX
!      *
!      * As of Patch 7 (13 January 98), we are having the following problem:
!      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
!      * requests to look up "desktop.ini" in all the subdirectories.
!      * This can cause zillions of timeouts looking up non-existent cells
!      * and volumes, especially in the top-level directory.
!      *
!      * We have not found any way to avoid this or work around it except
!      * to explicitly ignore the requests for mount points that haven't
!      * yet been evaluated and for directories that haven't yet been
!      * fetched.
!      */
!     if (infoLevel == 0x101) {
!         spacep = cm_GetSpace();
!         smb_StripLastComponent(spacep-&gt;data, &amp;lastComp,
!                                 (char *)(&amp;p-&gt;parmsp[3]));
!         /* Make sure that lastComp is not NULL */
!         if (lastComp) {
!             if (strcmp(lastComp, "\\desktop.ini") == 0) {
                  code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
!                                  CM_FLAG_CASEFOLD
!                                  | CM_FLAG_DIRSEARCH
!                                  | CM_FLAG_FOLLOW,
!                                  userp, tidPathp, &amp;req, &amp;dscp);
                  if (code == 0) {
                      if (dscp-&gt;fileType == CM_SCACHETYPE_MOUNTPOINT
                           &amp;&amp; !dscp-&gt;mountRootFidp)
***************
*** 2593,2682 ****
                  }
              }
          }
! 		cm_FreeSpace(spacep);
! 	}
  
! 	/* now do namei and stat, and copy out the info */
      code = cm_NameI(cm_rootSCachep, (char *)(&amp;p-&gt;parmsp[3]),
!                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &amp;req, &amp;scp);
  
! 	if (code) {
! 		cm_ReleaseUser(userp);
          smb_SendTran2Error(vcp, p, opx, code);
          smb_FreeTran2Packet(outp);
          return 0;
      }
  
      lock_ObtainMutex(&amp;scp-&gt;mx);
!         code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 	if (code) goto done;
          
      /* now we have the status in the cache entry, and everything is locked.
! 	 * Marshall the output data.
       */
! 	op = outp-&gt;datap;
! 	/* for info level 108, figure out short name */
! 	if (infoLevel == 0x108) {
! 		code = cm_GetShortName((char *)(&amp;p-&gt;parmsp[3]), userp, &amp;req,
                                  tidPathp, scp-&gt;fid.vnode, shortName,
                                  (size_t *) &amp;len);
! 		if (code) {
! 			goto done;
! 		}
! 
! 		op = outp-&gt;datap;
! 		*((u_long *)op) = len * 2; op += 4;
! 		mbstowcs((unsigned short *)op, shortName, len);
! 		op += (len * 2);
  
! 		goto done;
! 	}
! 	if (infoLevel == 1 || infoLevel == 2) {
! 		smb_SearchTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
          *((u_long *)op) = dosTime; op += 4;	/* creation time */
          *((u_long *)op) = dosTime; op += 4;	/* access time */
          *((u_long *)op) = dosTime; op += 4;	/* write time */
          *((u_long *)op) = scp-&gt;length.LowPart; op += 4;	/* length */
          *((u_long *)op) = scp-&gt;length.LowPart; op += 4;	/* alloc size */
! 		attributes = smb_Attributes(scp);
! 		*((u_short *)op) = attributes; op += 2;	/* attributes */
! 	}
! 	else if (infoLevel == 0x101) {
! 		smb_LargeSearchTimeFromUnixTime(&amp;ft, scp-&gt;clientModTime);
! 		*((FILETIME *)op) = ft; op += 8;	/* creation time */
! 		*((FILETIME *)op) = ft; op += 8;	/* last access time */
! 		*((FILETIME *)op) = ft; op += 8;	/* last write time */
! 		*((FILETIME *)op) = ft; op += 8;	/* last change time */
! 		extAttributes = smb_ExtAttributes(scp);
! 		*((u_long *)op) = extAttributes; op += 4; /* extended attribs */
! 		*((u_long *)op) = 0; op += 4;	/* don't know what this is */
! 	}
! 	else if (infoLevel == 0x102) {
! 		*((LARGE_INTEGER *)op) = scp-&gt;length; op += 8;	/* alloc size */
! 		*((LARGE_INTEGER *)op) = scp-&gt;length; op += 8;	/* EOF */
! 		*((u_long *)op) = scp-&gt;linkCount; op += 4;
! 		*op++ = 0;
! 		*op++ = 0;
! 		*op++ = (scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
! 		*op++ = 0;
! 	}
! 	else if (infoLevel == 0x103) {
!    		memset(op, 0, 4); op += 4;	/* EA size */
! 	}
  
-         /* now, if we are being asked about extended attrs, return a 0 size */
- 	if (infoLevel == 2) {
- 		*((u_long *)op) = 0; op += 4;
- 	}
-         
  
! 	/* send and free the packets */
    done:
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
      cm_ReleaseSCache(scp);
      cm_ReleaseUser(userp);
! 	if (code == 0) 
          smb_SendTran2Packet(vcp, outp, opx);
      else 
          smb_SendTran2Error(vcp, p, opx, code);
--- 2611,2700 ----
                  }
              }
          }
!         cm_FreeSpace(spacep);
!     }
  
!     /* now do namei and stat, and copy out the info */
      code = cm_NameI(cm_rootSCachep, (char *)(&amp;p-&gt;parmsp[3]),
!                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &amp;req, &amp;scp);
  
!     if (code) {
!         cm_ReleaseUser(userp);
          smb_SendTran2Error(vcp, p, opx, code);
          smb_FreeTran2Packet(outp);
          return 0;
      }
  
      lock_ObtainMutex(&amp;scp-&gt;mx);
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) goto done;
          
      /* now we have the status in the cache entry, and everything is locked.
!      * Marshall the output data.
       */
!     op = outp-&gt;datap;
!     /* for info level 108, figure out short name */
!     if (infoLevel == 0x108) {
!         code = cm_GetShortName((char *)(&amp;p-&gt;parmsp[3]), userp, &amp;req,
                                  tidPathp, scp-&gt;fid.vnode, shortName,
                                  (size_t *) &amp;len);
!         if (code) {
!             goto done;
!         }
  
!         op = outp-&gt;datap;
!         *((u_long *)op) = len * 2; op += 4;
!         mbstowcs((unsigned short *)op, shortName, len);
!         op += (len * 2);
! 
!         goto done;
!     }
!     if (infoLevel == 1 || infoLevel == 2) {
!         smb_SearchTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
          *((u_long *)op) = dosTime; op += 4;	/* creation time */
          *((u_long *)op) = dosTime; op += 4;	/* access time */
          *((u_long *)op) = dosTime; op += 4;	/* write time */
          *((u_long *)op) = scp-&gt;length.LowPart; op += 4;	/* length */
          *((u_long *)op) = scp-&gt;length.LowPart; op += 4;	/* alloc size */
!         attributes = smb_Attributes(scp);
!         *((u_short *)op) = attributes; op += 2;	/* attributes */
!     }
!     else if (infoLevel == 0x101) {
!         smb_LargeSearchTimeFromUnixTime(&amp;ft, scp-&gt;clientModTime);
!         *((FILETIME *)op) = ft; op += 8;	/* creation time */
!         *((FILETIME *)op) = ft; op += 8;	/* last access time */
!         *((FILETIME *)op) = ft; op += 8;	/* last write time */
!         *((FILETIME *)op) = ft; op += 8;	/* last change time */
!         extAttributes = smb_ExtAttributes(scp);
!         *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
!         *((u_long *)op) = 0; op += 4;	/* don't know what this is */
!     }
!     else if (infoLevel == 0x102) {
!         *((LARGE_INTEGER *)op) = scp-&gt;length; op += 8;	/* alloc size */
!         *((LARGE_INTEGER *)op) = scp-&gt;length; op += 8;	/* EOF */
!         *((u_long *)op) = scp-&gt;linkCount; op += 4;
!         *op++ = 0;
!         *op++ = 0;
!         *op++ = (scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
!         *op++ = 0;
!     }
!     else if (infoLevel == 0x103) {
!         memset(op, 0, 4); op += 4;	/* EA size */
!     }
! 
!     /* now, if we are being asked about extended attrs, return a 0 size */
!     if (infoLevel == 2) {
!         *((u_long *)op) = 0; op += 4;
!     }
  
  
!     /* send and free the packets */
    done:
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
      cm_ReleaseSCache(scp);
      cm_ReleaseUser(userp);
!     if (code == 0) 
          smb_SendTran2Packet(vcp, outp, opx);
      else 
          smb_SendTran2Error(vcp, p, opx, code);
***************
*** 2687,2990 ****
  
  long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
  long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
! 	smb_tran2Packet_t *outp;
! 	FILETIME ft;
! 	unsigned long attributes;
! 	unsigned short infoLevel;
! 	int nbytesRequired;
! 	unsigned short fid;
! 	cm_user_t *userp;
      smb_fid_t *fidp;
! 	cm_scache_t *scp;
! 	char *op;
! 	long code = 0;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      fid = p-&gt;parmsp[0];
      fidp = smb_FindFID(vcp, fid, 0);
  
! 	if (fidp == NULL) {
! 		smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
! 		return 0;
! 	}
  
! 	infoLevel = p-&gt;parmsp[1];
! 	if (infoLevel == 0x101) nbytesRequired = 40;
! 	else if (infoLevel == 0x102) nbytesRequired = 24;
! 	else if (infoLevel == 0x103) nbytesRequired = 4;
! 	else if (infoLevel == 0x104) nbytesRequired = 6;
! 	else {
! 		osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
!                  p-&gt;opcode, infoLevel);
! 		smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
          smb_ReleaseFID(fidp);
! 		return 0;
! 	}
! 	osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
  
! 	outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
  
! 	if (infoLevel &gt; 0x100)
! 		outp-&gt;totalParms = 2;
! 	else
! 		outp-&gt;totalParms = 0;
! 	outp-&gt;totalData = nbytesRequired;
  
! 	userp = smb_GetTran2User(vcp, p);
      if (!userp) {
      	osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p-&gt;uid);
      	code = CM_ERROR_BADSMB;
      	goto done;
!     }
  
! 	scp = fidp-&gt;scp;
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 	if (code) goto done;
  
! 	/* now we have the status in the cache entry, and everything is locked.
! 	 * Marshall the output data.
! 	 */
! 	op = outp-&gt;datap;
! 	if (infoLevel == 0x101) {
! 		smb_LargeSearchTimeFromUnixTime(&amp;ft, scp-&gt;clientModTime);
! 		*((FILETIME *)op) = ft; op += 8;	/* creation time */
! 		*((FILETIME *)op) = ft; op += 8;	/* last access time */
! 		*((FILETIME *)op) = ft; op += 8;	/* last write time */
! 		*((FILETIME *)op) = ft; op += 8;	/* last change time */
! 		attributes = smb_ExtAttributes(scp);
! 		*((u_long *)op) = attributes; op += 4;
! 		*((u_long *)op) = 0; op += 4;
! 	}
! 	else if (infoLevel == 0x102) {
! 		*((LARGE_INTEGER *)op) = scp-&gt;length; op += 8;	/* alloc size */
! 		*((LARGE_INTEGER *)op) = scp-&gt;length; op += 8;	/* EOF */
! 		*((u_long *)op) = scp-&gt;linkCount; op += 4;
! 		*op++ = ((fidp-&gt;flags &amp; SMB_FID_DELONCLOSE) ? 1 : 0);
! 		*op++ = (scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
! 		*op++ = 0;
! 		*op++ = 0;
! 	}
! 	else if (infoLevel == 0x103) {
! 		*((u_long *)op) = 0; op += 4;
! 	}
! 	else if (infoLevel == 0x104) {
! 		unsigned long len;
! 		char *name;
! 
! 		if (fidp-&gt;NTopen_wholepathp)
! 			name = fidp-&gt;NTopen_wholepathp;
! 		else
! 			name = "\\";	/* probably can't happen */
! 		len = strlen(name);
! 		outp-&gt;totalData = (len*2) + 4;	/* this is actually what we want to return */
! 		*((u_long *)op) = len * 2; op += 4;
! 		mbstowcs((unsigned short *)op, name, len); op += (len * 2);
! 	}
  
! 	/* send and free the packets */
    done:
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	cm_ReleaseUser(userp);
! 	smb_ReleaseFID(fidp);
! 	if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
! 	else smb_SendTran2Error(vcp, p, opx, code);
! 	smb_FreeTran2Packet(outp);
  
! 	return 0;
! }
  
  long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
! 	long code = 0;
! 	unsigned short fid;
! 	smb_fid_t *fidp;
! 	unsigned short infoLevel;
! 	smb_tran2Packet_t *outp;
! 	cm_user_t *userp;
! 	cm_scache_t *scp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      fid = p-&gt;parmsp[0];
! 	fidp = smb_FindFID(vcp, fid, 0);
  
! 	if (fidp == NULL) {
! 		smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
! 		return 0;
! 	}
  
! 	infoLevel = p-&gt;parmsp[1];
! 	if (infoLevel &gt; 0x104 || infoLevel &lt; 0x101) {
! 		osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
! 			 p-&gt;opcode, infoLevel);
! 		smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
          smb_ReleaseFID(fidp);
! 		return 0;
! 	}
  
! 	if (infoLevel == 0x102 &amp;&amp; !(fidp-&gt;flags &amp; SMB_FID_OPENDELETE)) {
! 		smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
          smb_ReleaseFID(fidp);
! 		return 0;
! 	}
! 	if ((infoLevel == 0x103 || infoLevel == 0x104)
! 	    &amp;&amp; !(fidp-&gt;flags &amp; SMB_FID_OPENWRITE)) {
! 		smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
          smb_ReleaseFID(fidp);
! 		return 0;
! 	}
  
! 	osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
  
! 	outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
  
! 	outp-&gt;totalParms = 2;
! 	outp-&gt;totalData = 0;
  
! 	userp = smb_GetTran2User(vcp, p);
      if (!userp) {
      	osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p-&gt;uid);
      	code = CM_ERROR_BADSMB;
      	goto done;
!     }
  
! 	scp = fidp-&gt;scp;
  
! 	if (infoLevel == 0x101) {
! 		FILETIME lastMod;
! 		unsigned int attribute;
! 		cm_attr_t attr;
! 
! 		/* lock the vnode with a callback; we need the current status
! 		 * to determine what the new status is, in some cases.
! 		 */
! 		lock_ObtainMutex(&amp;scp-&gt;mx);
! 		code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                          CM_SCACHESYNC_GETSTATUS
                           | CM_SCACHESYNC_NEEDCALLBACK);
! 		if (code) {
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			goto done;
! 		}
  
! 		/* prepare for setattr call */
! 		attr.mask = 0;
! 		
! 		lastMod = *((FILETIME *)(p-&gt;datap + 16));
! 		/* when called as result of move a b, lastMod is (-1, -1). 
           * If the check for -1 is not present, timestamp
! 		 * of the resulting file will be 1969 (-1)
! 		 */
! 		if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&amp;lastMod)) &amp;&amp; 
!             lastMod.dwLowDateTime != -1 &amp;&amp; lastMod.dwHighDateTime != -1) {
! 			attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
! 			smb_UnixTimeFromLargeSearchTime(&amp;attr.clientModTime,
! 							&amp;lastMod);
! 			fidp-&gt;flags |= SMB_FID_MTIMESETDONE;
! 		}
  		
! 		attribute = *((u_long *)(p-&gt;datap + 32));
! 		if (attribute != 0) {
! 			if ((scp-&gt;unixModeBits &amp; 0222)
! 			    &amp;&amp; (attribute &amp; 1) != 0) {
! 				/* make a writable file read-only */
! 				attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
! 				attr.unixModeBits = scp-&gt;unixModeBits &amp; ~0222;
! 			}
! 			else if ((scp-&gt;unixModeBits &amp; 0222) == 0
! 				 &amp;&amp; (attribute &amp; 1) == 0) {
! 				/* make a read-only file writable */
! 				attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
! 				attr.unixModeBits = scp-&gt;unixModeBits | 0222;
! 			}
! 		}
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
! 		/* call setattr */
! 		if (attr.mask)
! 			code = cm_SetAttr(scp, &amp;attr, userp, &amp;req);
! 		else
! 			code = 0;
! 	}
! 	else if (infoLevel == 0x103 || infoLevel == 0x104) {
! 		LARGE_INTEGER size = *((LARGE_INTEGER *)(p-&gt;datap));
! 		cm_attr_t attr;
! 
! 		attr.mask = CM_ATTRMASK_LENGTH;
! 		attr.length.LowPart = size.LowPart;
! 		attr.length.HighPart = size.HighPart;
! 		code = cm_SetAttr(scp, &amp;attr, userp, &amp;req);
! 	}
! 	else if (infoLevel == 0x102) {
! 		if (*((char *)(p-&gt;datap))) {
! 			code = cm_CheckNTDelete(fidp-&gt;NTopen_dscp, scp, userp,
! 						&amp;req);
! 			if (code == 0)
! 				fidp-&gt;flags |= SMB_FID_DELONCLOSE;
! 		}
! 		else {
! 			code = 0;
! 			fidp-&gt;flags &amp;= ~SMB_FID_DELONCLOSE;
! 		}
! 	}
    done:
! 	cm_ReleaseUser(userp);
! 	smb_ReleaseFID(fidp);
! 	if (code == 0) smb_SendTran2Packet(vcp, outp, op);
! 	else smb_SendTran2Error(vcp, p, op, code);
! 	smb_FreeTran2Packet(outp);
  
! 	return 0;
  }
  
! long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
! long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
! long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
! long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
! long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
      return CM_ERROR_BADOP;
  }
  
! long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
  	smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
  	cm_req_t *reqp)
  {
! 	long code = 0;
      cm_scache_t *scp;
      cm_scache_t *targetScp;			/* target if scp is a symlink */
      char *dptr;
!     long dosTime;
! 	FILETIME ft;
      int shortTemp;
      unsigned short attr;
! 	unsigned long lattr;
      smb_dirListPatch_t *patchp;
      smb_dirListPatch_t *npatchp;
          
--- 2705,3048 ----
  
  long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
  long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
!     smb_tran2Packet_t *outp;
!     FILETIME ft;
!     unsigned long attributes;
!     unsigned short infoLevel;
!     int nbytesRequired;
!     unsigned short fid;
!     cm_user_t *userp;
      smb_fid_t *fidp;
!     cm_scache_t *scp;
!     char *op;
!     long code = 0;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      fid = p-&gt;parmsp[0];
      fidp = smb_FindFID(vcp, fid, 0);
  
!     if (fidp == NULL) {
!         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
!         return 0;
!     }
  
!     infoLevel = p-&gt;parmsp[1];
!     if (infoLevel == 0x101) nbytesRequired = 40;
!     else if (infoLevel == 0x102) nbytesRequired = 24;
!     else if (infoLevel == 0x103) nbytesRequired = 4;
!     else if (infoLevel == 0x104) nbytesRequired = 6;
!     else {
!         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
!                   p-&gt;opcode, infoLevel);
!         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
          smb_ReleaseFID(fidp);
!         return 0;
!     }
!     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
  
!     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
  
!     if (infoLevel &gt; 0x100)
!         outp-&gt;totalParms = 2;
!     else
!         outp-&gt;totalParms = 0;
!     outp-&gt;totalData = nbytesRequired;
  
!     userp = smb_GetTran2User(vcp, p);
      if (!userp) {
      	osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p-&gt;uid);
      	code = CM_ERROR_BADSMB;
      	goto done;
!     }   
  
!     scp = fidp-&gt;scp;
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) 
!         goto done;
  
!     /* now we have the status in the cache entry, and everything is locked.
!      * Marshall the output data.
!      */
!     op = outp-&gt;datap;
!     if (infoLevel == 0x101) {
!         smb_LargeSearchTimeFromUnixTime(&amp;ft, scp-&gt;clientModTime);
!         *((FILETIME *)op) = ft; op += 8;	/* creation time */
!         *((FILETIME *)op) = ft; op += 8;	/* last access time */
!         *((FILETIME *)op) = ft; op += 8;	/* last write time */
!         *((FILETIME *)op) = ft; op += 8;	/* last change time */
!         attributes = smb_ExtAttributes(scp);
!         *((u_long *)op) = attributes; op += 4;
!         *((u_long *)op) = 0; op += 4;
!     }
!     else if (infoLevel == 0x102) {
!         *((LARGE_INTEGER *)op) = scp-&gt;length; op += 8;	/* alloc size */
!         *((LARGE_INTEGER *)op) = scp-&gt;length; op += 8;	/* EOF */
!         *((u_long *)op) = scp-&gt;linkCount; op += 4;
!         *op++ = ((fidp-&gt;flags &amp; SMB_FID_DELONCLOSE) ? 1 : 0);
!         *op++ = (scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
!         *op++ = 0;
!         *op++ = 0;
!     }
!     else if (infoLevel == 0x103) {
!         *((u_long *)op) = 0; op += 4;
!     }
!     else if (infoLevel == 0x104) {
!         unsigned long len;
!         char *name;
! 
!         if (fidp-&gt;NTopen_wholepathp)
!             name = fidp-&gt;NTopen_wholepathp;
!         else
!             name = "\\";	/* probably can't happen */
!         len = strlen(name);
!         outp-&gt;totalData = (len*2) + 4;	/* this is actually what we want to return */
!         *((u_long *)op) = len * 2; op += 4;
!         mbstowcs((unsigned short *)op, name, len); op += (len * 2);
!     }
  
!     /* send and free the packets */
    done:
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     cm_ReleaseUser(userp);
!     smb_ReleaseFID(fidp);
!     if (code == 0) 
!         smb_SendTran2Packet(vcp, outp, opx);
!     else 
!         smb_SendTran2Error(vcp, p, opx, code);
!     smb_FreeTran2Packet(outp);
  
!     return 0;
! }       
  
  long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
!     long code = 0;
!     unsigned short fid;
!     smb_fid_t *fidp;
!     unsigned short infoLevel;
!     smb_tran2Packet_t *outp;
!     cm_user_t *userp;
!     cm_scache_t *scp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      fid = p-&gt;parmsp[0];
!     fidp = smb_FindFID(vcp, fid, 0);
  
!     if (fidp == NULL) {
!         smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
!         return 0;
!     }
  
!     infoLevel = p-&gt;parmsp[1];
!     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
!     if (infoLevel &gt; 0x104 || infoLevel &lt; 0x101) {
!         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
!                   p-&gt;opcode, infoLevel);
!         smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
          smb_ReleaseFID(fidp);
!         return 0;
!     }
  
!     if (infoLevel == 0x102 &amp;&amp; !(fidp-&gt;flags &amp; SMB_FID_OPENDELETE)) {
!         smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
          smb_ReleaseFID(fidp);
!         return 0;
!     }
!     if ((infoLevel == 0x103 || infoLevel == 0x104)
!          &amp;&amp; !(fidp-&gt;flags &amp; SMB_FID_OPENWRITE)) {
!         smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
          smb_ReleaseFID(fidp);
!         return 0;
!     }
  
!     osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
  
!     outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
  
!     outp-&gt;totalParms = 2;
!     outp-&gt;totalData = 0;
  
!     userp = smb_GetTran2User(vcp, p);
      if (!userp) {
      	osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p-&gt;uid);
      	code = CM_ERROR_BADSMB;
      	goto done;
!     }   
! 
!     scp = fidp-&gt;scp;
  
!     if (infoLevel == 0x101) {
!         FILETIME lastMod;
!         unsigned int attribute;
!         cm_attr_t attr;
  
!         /* lock the vnode with a callback; we need the current status
!          * to determine what the new status is, in some cases.
!          */
!         lock_ObtainMutex(&amp;scp-&gt;mx);
!         code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                           CM_SCACHESYNC_GETSTATUS
                           | CM_SCACHESYNC_NEEDCALLBACK);
!         if (code) {
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             goto done;
!         }
  
!         /* prepare for setattr call */
!         attr.mask = 0;
! 
!         lastMod = *((FILETIME *)(p-&gt;datap + 16));
!         /* when called as result of move a b, lastMod is (-1, -1). 
           * If the check for -1 is not present, timestamp
!          * of the resulting file will be 1969 (-1)
!          */
!         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&amp;lastMod)) &amp;&amp; 
!              lastMod.dwLowDateTime != -1 &amp;&amp; lastMod.dwHighDateTime != -1) {
!             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
!             smb_UnixTimeFromLargeSearchTime(&amp;attr.clientModTime,
!                                              &amp;lastMod);
!             fidp-&gt;flags |= SMB_FID_MTIMESETDONE;
!         }
  		
!         attribute = *((u_long *)(p-&gt;datap + 32));
!         if (attribute != 0) {
!             if ((scp-&gt;unixModeBits &amp; 0222)
!                  &amp;&amp; (attribute &amp; 1) != 0) {
!                 /* make a writable file read-only */
!                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
!                 attr.unixModeBits = scp-&gt;unixModeBits &amp; ~0222;
!             }
!             else if ((scp-&gt;unixModeBits &amp; 0222) == 0
!                       &amp;&amp; (attribute &amp; 1) == 0) {
!                 /* make a read-only file writable */
!                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
!                 attr.unixModeBits = scp-&gt;unixModeBits | 0222;
!             }
!         }
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
! 
!         /* call setattr */
!         if (attr.mask)
!             code = cm_SetAttr(scp, &amp;attr, userp, &amp;req);
!         else
!             code = 0;
!     }               
!     else if (infoLevel == 0x103 || infoLevel == 0x104) {
!         LARGE_INTEGER size = *((LARGE_INTEGER *)(p-&gt;datap));
!         cm_attr_t attr;
! 
!         attr.mask = CM_ATTRMASK_LENGTH;
!         attr.length.LowPart = size.LowPart;
!         attr.length.HighPart = size.HighPart;
!         code = cm_SetAttr(scp, &amp;attr, userp, &amp;req);
!     }       
!     else if (infoLevel == 0x102) {
!         if (*((char *)(p-&gt;datap))) {
!             code = cm_CheckNTDelete(fidp-&gt;NTopen_dscp, scp, userp,
!                                      &amp;req);
!             if (code == 0)          
!                 fidp-&gt;flags |= SMB_FID_DELONCLOSE;
!         }               
!         else {  
!             code = 0;
!             fidp-&gt;flags &amp;= ~SMB_FID_DELONCLOSE;
!         }
!     }       
! 
    done:
!     cm_ReleaseUser(userp);
!     smb_ReleaseFID(fidp);
!     if (code == 0) 
!         smb_SendTran2Packet(vcp, outp, op);
!     else 
!         smb_SendTran2Error(vcp, p, op, code);
!     smb_FreeTran2Packet(outp);
! 
!     return 0;
! }
! 
! long 
! smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
! {
!     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
!     return CM_ERROR_BADOP;
! }
  
! long 
! smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
! {
!     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
!     return CM_ERROR_BADOP;
  }
  
! long 
! smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
! long 
! smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
! long 
! smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
! long 
! smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
! long 
! smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
+     osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
      return CM_ERROR_BADOP;
  }
  
! long 
! smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
! {
!     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
!     return CM_ERROR_BADOP;
! }
! 
! long 
! smb_ApplyV3DirListPatches(cm_scache_t *dscp,
  	smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
  	cm_req_t *reqp)
  {
!     long code = 0;
      cm_scache_t *scp;
      cm_scache_t *targetScp;			/* target if scp is a symlink */
      char *dptr;
!     time_t dosTime;
!     FILETIME ft;
      int shortTemp;
      unsigned short attr;
!     unsigned long lattr;
      smb_dirListPatch_t *patchp;
      smb_dirListPatch_t *npatchp;
          
***************
*** 2995,3003 ****
          lock_ObtainMutex(&amp;scp-&gt;mx);
          code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                            CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 		if (code) { 
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			cm_ReleaseSCache(scp);
  
              dptr = patchp-&gt;dptr;
  
--- 3053,3061 ----
          lock_ObtainMutex(&amp;scp-&gt;mx);
          code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                            CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!         if (code) { 
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             cm_ReleaseSCache(scp);
  
              dptr = patchp-&gt;dptr;
  
***************
*** 3008,3191 ****
                  ft.dwHighDateTime = 0x19DB200;
                  ft.dwLowDateTime = 0x5BB78980;
  
! 			    /* copy to Creation Time */
! 			    *((FILETIME *)dptr) = ft;
! 			    dptr += 8;
! 
! 			    /* copy to Last Access Time */
! 			    *((FILETIME *)dptr) = ft;
! 			    dptr += 8;
! 
! 			    /* copy to Last Write Time */
! 			    *((FILETIME *)dptr) = ft;
! 			    dptr += 8;
  
! 			    /* copy to Change Time */
! 			    *((FILETIME *)dptr) = ft;
                  dptr += 24;
  
                  /* merge in hidden attribute */
                  if ( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE ) {
! 			        *((u_long *)dptr) = SMB_ATTR_HIDDEN;
                  }
! 			    dptr += 4;
              } else {
                  /* 1969-12-31 23:59:58 +00*/
                  dosTime = 0xEBBFBF7D;
  
! 			    /* and copy out date */
! 			    shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
! 			    *((u_short *)dptr) = shortTemp;
! 			    dptr += 2;
! 
! 			    /* copy out creation time */
! 			    shortTemp = dosTime &amp; 0xffff;
! 			    *((u_short *)dptr) = shortTemp;
! 			    dptr += 2;
! 
! 			    /* and copy out date */
! 			    shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
! 			    *((u_short *)dptr) = shortTemp;
! 			    dptr += 2;
      			
! 			    /* copy out access time */
! 			    shortTemp = dosTime &amp; 0xffff;
! 			    *((u_short *)dptr) = shortTemp;
! 			    dptr += 2;
! 
! 			    /* and copy out date */
! 			    shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
! 			    *((u_short *)dptr) = shortTemp;
! 			    dptr += 2;
      			
! 			    /* copy out mod time */
! 			    shortTemp = dosTime &amp; 0xffff;
! 			    *((u_short *)dptr) = shortTemp;
! 			    dptr += 10;
  
                  /* merge in hidden (dot file) attribute */
                  if ( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE ) {
                      attr = SMB_ATTR_HIDDEN;
! 			        *dptr++ = attr &amp; 0xff;
! 			        *dptr++ = (attr &gt;&gt; 8) &amp; 0xff;
!                 }
              }
! 			continue;
          }
                  
          /* now watch for a symlink */
!         if (scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
              code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, reqp);
              if (code == 0) {
! 				/* we have a more accurate file to use (the
! 				 * target of the symbolic link).  Otherwise,
! 				 * we'll just use the symlink anyway.
                   */
! 				osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                          scp, targetScp);
! 				cm_ReleaseSCache(scp);
                  scp = targetScp;
              }
              lock_ObtainMutex(&amp;scp-&gt;mx);
          }
  
! 		dptr = patchp-&gt;dptr;
  
! 		if (infoLevel &gt;= 0x101) {
! 			/* get filetime */
! 			smb_LargeSearchTimeFromUnixTime(&amp;ft, scp-&gt;clientModTime);
! 
! 			/* copy to Creation Time */
! 			*((FILETIME *)dptr) = ft;
! 			dptr += 8;
! 
! 			/* copy to Last Access Time */
! 			*((FILETIME *)dptr) = ft;
! 			dptr += 8;
! 
! 			/* copy to Last Write Time */
! 			*((FILETIME *)dptr) = ft;
! 			dptr += 8;
! 
! 			/* copy to Change Time */
! 			*((FILETIME *)dptr) = ft;
! 			dptr += 8;
! 
! 			/* Use length for both file length and alloc length */
! 			*((LARGE_INTEGER *)dptr) = scp-&gt;length;
! 			dptr += 8;
! 			*((LARGE_INTEGER *)dptr) = scp-&gt;length;
! 			dptr += 8;
  
! 			/* Copy attributes */
! 			lattr = smb_ExtAttributes(scp);
              /* merge in hidden (dot file) attribute */
!  			if ( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE )
!  				lattr |= SMB_ATTR_HIDDEN;
! 			*((u_long *)dptr) = lattr;
! 			dptr += 4;
! 		}
! 		else {
! 			/* get dos time */
! 			smb_SearchTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
! 
! 			/* and copy out date */
! 			shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
! 			*((u_short *)dptr) = shortTemp;
! 			dptr += 2;
! 
! 			/* copy out creation time */
! 			shortTemp = dosTime &amp; 0xffff;
! 			*((u_short *)dptr) = shortTemp;
! 			dptr += 2;
! 
! 			/* and copy out date */
! 			shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
! 			*((u_short *)dptr) = shortTemp;
! 			dptr += 2;
! 			
! 			/* copy out access time */
! 			shortTemp = dosTime &amp; 0xffff;
! 			*((u_short *)dptr) = shortTemp;
! 			dptr += 2;
! 
! 			/* and copy out date */
! 			shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
! 			*((u_short *)dptr) = shortTemp;
! 			dptr += 2;
! 			
! 			/* copy out mod time */
! 			shortTemp = dosTime &amp; 0xffff;
! 			*((u_short *)dptr) = shortTemp;
! 			dptr += 2;
! 
! 			/* copy out file length and alloc length,
! 			 * using the same for both
! 			 */
! 			*((u_long *)dptr) = scp-&gt;length.LowPart;
! 			dptr += 4;
! 			*((u_long *)dptr) = scp-&gt;length.LowPart;
! 			dptr += 4;
  
! 			/* finally copy out attributes as short */
! 			attr = smb_Attributes(scp);
              /* merge in hidden (dot file) attribute */
              if ( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE )
                  attr |= SMB_ATTR_HIDDEN;
! 			*dptr++ = attr &amp; 0xff;
! 			*dptr++ = (attr &gt;&gt; 8) &amp; 0xff;
! 		}
  
          lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
! 	}
          
      /* now free the patches */
!     for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
! 		npatchp = (smb_dirListPatch_t *) osi_QNext(&amp;patchp-&gt;q);
          free(patchp);
! 	}
          
      /* and mark the list as empty */
      *dirPatchespp = NULL;
--- 3066,3250 ----
                  ft.dwHighDateTime = 0x19DB200;
                  ft.dwLowDateTime = 0x5BB78980;
  
!                 /* copy to Creation Time */
!                 *((FILETIME *)dptr) = ft;
!                 dptr += 8;
! 
!                 /* copy to Last Access Time */
!                 *((FILETIME *)dptr) = ft;
!                 dptr += 8;
! 
!                 /* copy to Last Write Time */
!                 *((FILETIME *)dptr) = ft;
!                 dptr += 8;
  
!                 /* copy to Change Time */
!                 *((FILETIME *)dptr) = ft;
                  dptr += 24;
  
                  /* merge in hidden attribute */
                  if ( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE ) {
!                     *((u_long *)dptr) = SMB_ATTR_HIDDEN;
                  }
!                 dptr += 4;
              } else {
                  /* 1969-12-31 23:59:58 +00*/
                  dosTime = 0xEBBFBF7D;
  
!                 /* and copy out date */
!                 shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
! 
!                 /* copy out creation time */
!                 shortTemp = dosTime &amp; 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
! 
!                 /* and copy out date */
!                 shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
      			
!                 /* copy out access time */
!                 shortTemp = dosTime &amp; 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
! 
!                 /* and copy out date */
!                 shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
      			
!                 /* copy out mod time */
!                 shortTemp = dosTime &amp; 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 10;
  
                  /* merge in hidden (dot file) attribute */
                  if ( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE ) {
                      attr = SMB_ATTR_HIDDEN;
!                     *dptr++ = attr &amp; 0xff;
!                     *dptr++ = (attr &gt;&gt; 8) &amp; 0xff;
!                 }       
              }
!             continue;
          }
                  
          /* now watch for a symlink */
!         code = 0;
!         while (code == 0 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
              code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, reqp);
              if (code == 0) {
!                 /* we have a more accurate file to use (the
!                  * target of the symbolic link).  Otherwise,
!                  * we'll just use the symlink anyway.
                   */
!                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                           scp, targetScp);
!                 cm_ReleaseSCache(scp);
                  scp = targetScp;
              }
              lock_ObtainMutex(&amp;scp-&gt;mx);
          }
  
!         dptr = patchp-&gt;dptr;
  
!         if (infoLevel &gt;= 0x101) {
!             /* get filetime */
!             smb_LargeSearchTimeFromUnixTime(&amp;ft, scp-&gt;clientModTime);
! 
!             /* copy to Creation Time */
!             *((FILETIME *)dptr) = ft;
!             dptr += 8;
! 
!             /* copy to Last Access Time */
!             *((FILETIME *)dptr) = ft;
!             dptr += 8;
! 
!             /* copy to Last Write Time */
!             *((FILETIME *)dptr) = ft;
!             dptr += 8;
! 
!             /* copy to Change Time */
!             *((FILETIME *)dptr) = ft;
!             dptr += 8;
! 
!             /* Use length for both file length and alloc length */
!             *((LARGE_INTEGER *)dptr) = scp-&gt;length;
!             dptr += 8;
!             *((LARGE_INTEGER *)dptr) = scp-&gt;length;
!             dptr += 8;
  
!             /* Copy attributes */
!             lattr = smb_ExtAttributes(scp);
              /* merge in hidden (dot file) attribute */
!             if ( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE )
!                 lattr |= SMB_ATTR_HIDDEN;
!             *((u_long *)dptr) = lattr;
!             dptr += 4;
!         }
!         else {
!             /* get dos time */
!             smb_SearchTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
  
!             /* and copy out date */
!             shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* copy out creation time */
!             shortTemp = dosTime &amp; 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* and copy out date */
!             shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* copy out access time */
!             shortTemp = dosTime &amp; 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* and copy out date */
!             shortTemp = (dosTime&gt;&gt;16) &amp; 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* copy out mod time */
!             shortTemp = dosTime &amp; 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* copy out file length and alloc length,
!              * using the same for both
!              */
!             *((u_long *)dptr) = scp-&gt;length.LowPart;
!             dptr += 4;
!             *((u_long *)dptr) = scp-&gt;length.LowPart;
!             dptr += 4;
! 
!             /* finally copy out attributes as short */
!             attr = smb_Attributes(scp);
              /* merge in hidden (dot file) attribute */
              if ( patchp-&gt;flags &amp; SMB_DIRLISTPATCH_DOTFILE )
                  attr |= SMB_ATTR_HIDDEN;
!             *dptr++ = attr &amp; 0xff;
!             *dptr++ = (attr &gt;&gt; 8) &amp; 0xff;
!         }
  
          lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
!     }
          
      /* now free the patches */
!     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
!         npatchp = (smb_dirListPatch_t *) osi_QNext(&amp;patchp-&gt;q);
          free(patchp);
!     }
          
      /* and mark the list as empty */
      *dirPatchespp = NULL;
***************
*** 3219,3258 ****
  // Return value
  // BOOL : TRUE/FALSE (match/mistmatch)
  
! BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
!    PSZ pename;         // points to the last 'name' character
!    PSZ p;
!    pename = name + strlen(name) - 1;
!    while (*name) {
!       switch (*pattern) {
!          case '?':
!          case '&gt;':
!             if (*(++pattern) != '&lt;' || *(++pattern) != '*') {
!                if (*name == '.') 
!                    return FALSE;
!                ++name;
!                break;
!             } /* endif */
!          case '&lt;':
           case '*':
!             while ((*pattern == '&lt;') || (*pattern == '*') || (*pattern == '?') || (*pattern == '&gt;')) 
!                 ++pattern;
!             if (!*pattern) 
                  return TRUE;
              for (p = pename; p &gt;= name; --p) {
!                if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &amp;&amp;
!                    szWildCardMatchFileName(pattern + 1, p + 1))
!                   return TRUE;
              } /* endfor */
              return FALSE;
!          default:
              if (mapCaseTable[*name] != mapCaseTable[*pattern]) 
                  return FALSE;
              ++pattern, ++name;
              break;
!       } /* endswitch */
!    } /* endwhile */ 
!    return !*pattern;
  }
  
  /* do a case-folding search of the star name mask with the name in namep.
--- 3278,3318 ----
  // Return value
  // BOOL : TRUE/FALSE (match/mistmatch)
  
! BOOL 
! szWildCardMatchFileName(PSZ pattern, PSZ name) 
! {
!     PSZ pename;         // points to the last 'name' character
!     PSZ p;
!     pename = name + strlen(name) - 1;
!     while (*name) {
!         switch (*pattern) {
!         case '?':
!             if (*name == '.') 
!                 return FALSE;
!             ++pattern, ++name;
!             break;
           case '*':
!             ++pattern;
!             if (*pattern == '\0')
                  return TRUE;
              for (p = pename; p &gt;= name; --p) {
!                 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &amp;&amp;
!                      szWildCardMatchFileName(pattern + 1, p + 1))
!                     return TRUE;
              } /* endfor */
              return FALSE;
!         default:
              if (mapCaseTable[*name] != mapCaseTable[*pattern]) 
                  return FALSE;
              ++pattern, ++name;
              break;
!         } /* endswitch */
!     } /* endwhile */ 
! 
!     if (*pattern == '\0' || *pattern == '*' &amp;&amp; *(pattern+1) == '\0')
!         return TRUE;
!     else 
!         return FALSE;
  }
  
  /* do a case-folding search of the star name mask with the name in namep.
***************
*** 3260,3270 ****
   */
  int smb_V3MatchMask(char *namep, char *maskp, int flags) 
  {
! 	/* make sure we only match 8.3 names, if requested */
! 	if ((flags &amp; CM_FLAG_8DOT3) &amp;&amp; !cm_Is8Dot3(namep)) 
          return 0;
! 	
! 	return szWildCardMatchFileName(maskp, namep) ? 1:0;
  }
  
  #else /* USE_OLD_MATCHING */
--- 3320,3372 ----
   */
  int smb_V3MatchMask(char *namep, char *maskp, int flags) 
  {
!     char * newmask;
!     int    i, j, star, qmark, retval;
! 
!     /* make sure we only match 8.3 names, if requested */
!     if ((flags &amp; CM_FLAG_8DOT3) &amp;&amp; !cm_Is8Dot3(namep)) 
          return 0;
!     
!     /* optimize the pattern:
!      * if there is a mixture of '?' and '*',
!      * for example  the sequence "*?*?*?*"
!      * must be turned into the form "*"
!      */
!     newmask = (char *)malloc(strlen(maskp)+1);
!     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
!         switch ( maskp[i] ) {
!         case '?':
!         case '&gt;':
!             qmark++;
!             break;
!         case '&lt;':
!         case '*':
!             star++;
!             break;
!         default:
!             if ( star ) {
!                 newmask[j++] = '*';
!             } else if ( qmark ) {
!                 while ( qmark-- )
!                     newmask[j++] = '?';
!             }
!             newmask[j++] = maskp[i];
!             star = 0;
!             qmark = 0;
!         }
!     }
!     if ( star ) {
!         newmask[j++] = '*';
!     } else if ( qmark ) {
!         while ( qmark-- )
!             newmask[j++] = '?';
!     }
!     newmask[j++] = '\0';
! 
!     retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
! 
!     free(newmask);
!     return retval;
  }
  
  #else /* USE_OLD_MATCHING */
***************
*** 3273,3415 ****
   */
  int smb_V3MatchMask(char *namep, char *maskp, int flags)
  {
! 	unsigned char tcp1, tcp2;	/* Pattern characters */
      unsigned char tcn1;		/* Name characters */
! 	int sawDot = 0, sawStar = 0, req8dot3 = 0;
! 	char *starNamep, *starMaskp;
! 	static char nullCharp[] = {0};
      int casefold = flags &amp; CM_FLAG_CASEFOLD;
  
! 	/* make sure we only match 8.3 names, if requested */
      req8dot3 = (flags &amp; CM_FLAG_8DOT3);
! 	if (req8dot3 &amp;&amp; !cm_Is8Dot3(namep)) 
          return 0;
  
! 	/* loop */
! 	while (1) {
! 		/* Next pattern character */
! 		tcp1 = *maskp++;
! 
! 		/* Next name character */
! 		tcn1 = *namep;
! 
! 		if (tcp1 == 0) {
! 			/* 0 - end of pattern */
! 			if (tcn1 == 0)
! 				return 1;
! 			else
! 				return 0;
! 		}
! 		else if (tcp1 == '.' || tcp1 == '"') {
! 			if (sawDot) {
! 				if (tcn1 == '.') {
! 					namep++;
! 					continue;
! 				} else
! 					return 0;
! 			}
! 			else {
! 				/*
! 				 * first dot in pattern;
! 				 * must match dot or end of name
! 				 */
! 				sawDot = 1;
! 				if (tcn1 == 0)
! 					continue;
! 				else if (tcn1 == '.') {
! 					sawStar = 0;
! 					namep++;
! 					continue;
! 				}
! 				else
! 					return 0;
! 			}
! 		}
! 		else if (tcp1 == '?') {
! 			if (tcn1 == 0 || tcn1 == '.')
! 				return 0;
! 			namep++;
! 			continue;
! 		}
! 		else if (tcp1 == '&gt;') {
! 			if (tcn1 != 0 &amp;&amp; tcn1 != '.')
! 				namep++;
! 			continue;
! 		}
! 		else if (tcp1 == '*' || tcp1 == '&lt;') {
! 			tcp2 = *maskp++;
! 			if (tcp2 == 0)
! 				return 1;
! 			else if ((req8dot3 &amp;&amp; tcp2 == '.') || tcp2 == '"') {
! 				while (req8dot3 &amp;&amp; tcn1 != '.' &amp;&amp; tcn1 != 0)
! 					tcn1 = *++namep;
! 				if (tcn1 == 0) {
! 					if (sawDot)
! 						return 0;
! 					else
! 						continue;
! 				}
! 				else {
! 					namep++;
! 					continue;
! 				}
! 			}
! 			else {
! 				/*
! 				 * pattern character after '*' is not null or
! 				 * period.  If it is '?' or '&gt;', we are not
! 				 * going to understand it.  If it is '*' or
! 				 * '&lt;', we are going to skip over it.  None of
! 				 * these are likely, I hope.
! 				 */
! 				/* skip over '*' and '&lt;' */
! 				while (tcp2 == '*' || tcp2 == '&lt;')
! 					tcp2 = *maskp++;
! 
! 				/* skip over characters that don't match tcp2 */
! 				while (req8dot3 &amp;&amp; tcn1 != '.' &amp;&amp; tcn1 != 0 &amp;&amp; 
!                        ((casefold &amp;&amp; cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
!                          (!casefold &amp;&amp; tcn1 != tcp2)))
! 					tcn1 = *++namep;
! 
! 				/* No match */
! 				if ((req8dot3 &amp;&amp; tcn1 == '.') || tcn1 == 0)
! 					return 0;
! 
! 				/* Remember where we are */
! 				sawStar = 1;
! 				starMaskp = maskp;
! 				starNamep = namep;
! 
! 				namep++;
! 				continue;
! 			}
! 		}
! 		else {
! 			/* tcp1 is not a wildcard */
              if ((casefold &amp;&amp; cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
!                 (!casefold &amp;&amp; tcn1 == tcp1)) {
! 				/* they match */
! 				namep++;
! 				continue;
! 			}
! 			/* if trying to match a star pattern, go back */
! 			if (sawStar) {
! 				maskp = starMaskp - 2;
! 				namep = starNamep + 1;
! 				sawStar = 0;
! 				continue;
! 			}
! 			/* that's all */
! 			return 0;
! 		}
! 	}
  }
  #endif /* USE_OLD_MATCHING */
  
  long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
! 	int attribute;
      long nextCookie;
      char *tp;
      long code = 0;
--- 3375,3517 ----
   */
  int smb_V3MatchMask(char *namep, char *maskp, int flags)
  {
!     unsigned char tcp1, tcp2;	/* Pattern characters */
      unsigned char tcn1;		/* Name characters */
!     int sawDot = 0, sawStar = 0, req8dot3 = 0;
!     char *starNamep, *starMaskp;
!     static char nullCharp[] = {0};
      int casefold = flags &amp; CM_FLAG_CASEFOLD;
  
!     /* make sure we only match 8.3 names, if requested */
      req8dot3 = (flags &amp; CM_FLAG_8DOT3);
!     if (req8dot3 &amp;&amp; !cm_Is8Dot3(namep)) 
          return 0;
  
!     /* loop */
!     while (1) {
!         /* Next pattern character */
!         tcp1 = *maskp++;
! 
!         /* Next name character */
!         tcn1 = *namep;
! 
!         if (tcp1 == 0) {
!             /* 0 - end of pattern */
!             if (tcn1 == 0)
!                 return 1;
!             else
!                 return 0;
!         }
!         else if (tcp1 == '.' || tcp1 == '"') {
!             if (sawDot) {
!                 if (tcn1 == '.') {
!                     namep++;
!                     continue;
!                 } else
!                     return 0;
!             }
!             else {
!                 /*
!                  * first dot in pattern;
!                  * must match dot or end of name
!                  */
!                 sawDot = 1;
!                 if (tcn1 == 0)
!                     continue;
!                 else if (tcn1 == '.') {
!                     sawStar = 0;
!                     namep++;
!                     continue;
!                 }
!                 else
!                     return 0;
!             }
!         }
!         else if (tcp1 == '?') {
!             if (tcn1 == 0 || tcn1 == '.')
!                 return 0;
!             namep++;
!             continue;
!         }
!         else if (tcp1 == '&gt;') {
!             if (tcn1 != 0 &amp;&amp; tcn1 != '.')
!                 namep++;
!             continue;
!         }
!         else if (tcp1 == '*' || tcp1 == '&lt;') {
!             tcp2 = *maskp++;
!             if (tcp2 == 0)
!                 return 1;
!             else if ((req8dot3 &amp;&amp; tcp2 == '.') || tcp2 == '"') {
!                 while (req8dot3 &amp;&amp; tcn1 != '.' &amp;&amp; tcn1 != 0)
!                     tcn1 = *++namep;
!                 if (tcn1 == 0) {
!                     if (sawDot)
!                         return 0;
!                     else
!                         continue;
!                 }
!                 else {
!                     namep++;
!                     continue;
!                 }
!             }
!             else {
!                 /*
!                  * pattern character after '*' is not null or
!                  * period.  If it is '?' or '&gt;', we are not
!                  * going to understand it.  If it is '*' or
!                  * '&lt;', we are going to skip over it.  None of
!                  * these are likely, I hope.
!                  */
!                 /* skip over '*' and '&lt;' */
!                 while (tcp2 == '*' || tcp2 == '&lt;')
!                     tcp2 = *maskp++;
! 
!                 /* skip over characters that don't match tcp2 */
!                 while (req8dot3 &amp;&amp; tcn1 != '.' &amp;&amp; tcn1 != 0 &amp;&amp; 
!                         ((casefold &amp;&amp; cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
!                           (!casefold &amp;&amp; tcn1 != tcp2)))
!                     tcn1 = *++namep;
! 
!                 /* No match */
!                 if ((req8dot3 &amp;&amp; tcn1 == '.') || tcn1 == 0)
!                     return 0;
! 
!                 /* Remember where we are */
!                 sawStar = 1;
!                 starMaskp = maskp;
!                 starNamep = namep;
! 
!                 namep++;
!                 continue;
!             }
!         }
!         else {
!             /* tcp1 is not a wildcard */
              if ((casefold &amp;&amp; cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
!                  (!casefold &amp;&amp; tcn1 == tcp1)) {
!                 /* they match */
!                 namep++;
!                 continue;
!             }
!             /* if trying to match a star pattern, go back */
!             if (sawStar) {
!                 maskp = starMaskp - 2;
!                 namep = starNamep + 1;
!                 sawStar = 0;
!                 continue;
!             }
!             /* that's all */
!             return 0;
!         }
!     }
  }
  #endif /* USE_OLD_MATCHING */
  
  long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
!     int attribute;
      long nextCookie;
      char *tp;
      long code = 0;
***************
*** 3431,3444 ****
      cm_scache_t *scp;
      long entryInDir;
      long entryInBuffer;
! 	cm_pageHeader_t *pageHeaderp;
      cm_user_t *userp = NULL;
      int slotInPage;
      int returnedNames;
      long nextEntryCookie;
      int numDirChunks;		/* # of 32 byte dir chunks in this entry */
      char *op;			/* output data ptr */
! 	char *origOp;			/* original value of op */
      cm_space_t *spacep;		/* for pathname buffer */
      long maxReturnData;		/* max # of return data */
      long maxReturnParms;		/* max # of return parms */
--- 3533,3546 ----
      cm_scache_t *scp;
      long entryInDir;
      long entryInBuffer;
!     cm_pageHeader_t *pageHeaderp;
      cm_user_t *userp = NULL;
      int slotInPage;
      int returnedNames;
      long nextEntryCookie;
      int numDirChunks;		/* # of 32 byte dir chunks in this entry */
      char *op;			/* output data ptr */
!     char *origOp;			/* original value of op */
      cm_space_t *spacep;		/* for pathname buffer */
      long maxReturnData;		/* max # of return data */
      long maxReturnParms;		/* max # of return parms */
***************
*** 3449,3470 ****
      int searchFlags;
      int eos;
      smb_tran2Packet_t *outp;	/* response packet */
! 	char *tidPathp;
! 	int align;
! 	char shortName[13];		/* 8.3 name if needed */
! 	int NeedShortName;
      int foundInexact;
! 	char *shortNameEnd;
      int fileType;
      cm_fid_t fid;
- 
      cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
! 	eos = 0;
! 	if (p-&gt;opcode == 1) {
! 		/* find first; obtain basic parameters from request */
          attribute = p-&gt;parmsp[0];
          maxCount = p-&gt;parmsp[1];
          infoLevel = p-&gt;parmsp[3];
--- 3551,3571 ----
      int searchFlags;
      int eos;
      smb_tran2Packet_t *outp;	/* response packet */
!     char *tidPathp;
!     int align;
!     char shortName[13];		/* 8.3 name if needed */
!     int NeedShortName;
      int foundInexact;
!     char *shortNameEnd;
      int fileType;
      cm_fid_t fid;
      cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
!     eos = 0;
!     if (p-&gt;opcode == 1) {
!         /* find first; obtain basic parameters from request */
          attribute = p-&gt;parmsp[0];
          maxCount = p-&gt;parmsp[1];
          infoLevel = p-&gt;parmsp[3];
***************
*** 3475,3487 ****
          nextCookie = 0;
          maskp = strrchr(pathp, '\\');
          if (maskp == NULL) maskp = pathp;
! 		else maskp++;	/* skip over backslash */
          strcpy(dsp-&gt;mask, maskp);	/* and save mask */
!    		/* track if this is likely to match a lot of entries */
          starPattern = smb_V3IsStarMask(maskp);
!         }
      else {
! 		osi_assert(p-&gt;opcode == 2);
          /* find next; obtain basic parameters from request or open dir file */
          dsp = smb_FindDirSearch(p-&gt;parmsp[0]);
          if (!dsp) return CM_ERROR_BADFD;
--- 3576,3588 ----
          nextCookie = 0;
          maskp = strrchr(pathp, '\\');
          if (maskp == NULL) maskp = pathp;
!         else maskp++;	/* skip over backslash */
          strcpy(dsp-&gt;mask, maskp);	/* and save mask */
!         /* track if this is likely to match a lot of entries */
          starPattern = smb_V3IsStarMask(maskp);
!     }
      else {
!         osi_assert(p-&gt;opcode == 2);
          /* find next; obtain basic parameters from request or open dir file */
          dsp = smb_FindDirSearch(p-&gt;parmsp[0]);
          if (!dsp) return CM_ERROR_BADFD;
***************
*** 3492,3516 ****
          pathp = NULL;
          nextCookie = p-&gt;parmsp[3] | (p-&gt;parmsp[4] &lt;&lt; 16);
          maskp = dsp-&gt;mask;
! 		starPattern = 1;	/* assume, since required a Find Next */
      }
  
! 	osi_Log4(smb_logp,
                "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
                attribute, infoLevel, maxCount, searchFlags);
  
! 	osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
                p-&gt;opcode, nextCookie);
  
! 	if (infoLevel &gt;= 0x101)
! 		searchFlags &amp;= ~4;	/* no resume keys */
  
      dirListPatchesp = NULL;
  
! 	maxReturnData = p-&gt;maxReturnData;
      if (p-&gt;opcode == 1)	/* find first */
          maxReturnParms = 10;	/* bytes */
! 	else    
          maxReturnParms = 8;	/* bytes */
  
  #ifndef CM_CONFIG_MULTITRAN2RESPONSES
--- 3593,3617 ----
          pathp = NULL;
          nextCookie = p-&gt;parmsp[3] | (p-&gt;parmsp[4] &lt;&lt; 16);
          maskp = dsp-&gt;mask;
!         starPattern = 1;	/* assume, since required a Find Next */
      }
  
!     osi_Log4(smb_logp,
                "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
                attribute, infoLevel, maxCount, searchFlags);
  
!     osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
                p-&gt;opcode, nextCookie);
  
!     if (infoLevel &gt;= 0x101)
!         searchFlags &amp;= ~4;	/* no resume keys */
  
      dirListPatchesp = NULL;
  
!     maxReturnData = p-&gt;maxReturnData;
      if (p-&gt;opcode == 1)	/* find first */
          maxReturnParms = 10;	/* bytes */
!     else    
          maxReturnParms = 8;	/* bytes */
  
  #ifndef CM_CONFIG_MULTITRAN2RESPONSES
***************
*** 3518,3524 ****
          maxReturnData = 6000;
  #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
  
! 	outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                        maxReturnData);
  
      osi_Log1(smb_logp, "T2 receive search dir %s",
--- 3619,3625 ----
          maxReturnData = 6000;
  #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
  
!     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                        maxReturnData);
  
      osi_Log1(smb_logp, "T2 receive search dir %s",
***************
*** 3531,3540 ****
          return CM_ERROR_BADSMB;
      }
          
! 	osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
               nextCookie, dsp-&gt;cookie);
  
!  	userp = smb_GetTran2User(vcp, p);
      if (!userp) {
      	osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p-&gt;uid);
      	smb_ReleaseDirSearch(dsp);
--- 3632,3641 ----
          return CM_ERROR_BADSMB;
      }
          
!     osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
               nextCookie, dsp-&gt;cookie);
  
!     userp = smb_GetTran2User(vcp, p);
      if (!userp) {
      	osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p-&gt;uid);
      	smb_ReleaseDirSearch(dsp);
***************
*** 3542,3566 ****
      	return CM_ERROR_BADSMB;
      }
  
! 	/* try to get the vnode for the path name next */
! 	lock_ObtainMutex(&amp;dsp-&gt;mx);
! 	if (dsp-&gt;scp) {
! 		scp = dsp-&gt;scp;
          cm_HoldSCache(scp);
          code = 0;
      }
      else {
! 		spacep = cm_GetSpace();
          smb_StripLastComponent(spacep-&gt;data, NULL, pathp);
          lock_ReleaseMutex(&amp;dsp-&gt;mx);
  
! 		code = smb_LookupTIDPath(vcp, p-&gt;tid, &amp;tidPathp);
!         if(code) {
! 		    cm_ReleaseUser(userp);
              smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
              smb_FreeTran2Packet(outp);
! 		    smb_DeleteDirSearch(dsp);
! 		    smb_ReleaseDirSearch(dsp);
              return 0;
          }
          code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
--- 3643,3667 ----
      	return CM_ERROR_BADSMB;
      }
  
!     /* try to get the vnode for the path name next */
!     lock_ObtainMutex(&amp;dsp-&gt;mx);
!     if (dsp-&gt;scp) {
!         scp = dsp-&gt;scp;
          cm_HoldSCache(scp);
          code = 0;
      }
      else {
!         spacep = cm_GetSpace();
          smb_StripLastComponent(spacep-&gt;data, NULL, pathp);
          lock_ReleaseMutex(&amp;dsp-&gt;mx);
  
!         code = smb_LookupTIDPath(vcp, p-&gt;tid, &amp;tidPathp);
!         if (code) {
!             cm_ReleaseUser(userp);
              smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
              smb_FreeTran2Packet(outp);
!             smb_DeleteDirSearch(dsp);
!             smb_ReleaseDirSearch(dsp);
              return 0;
          }
          code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
***************
*** 3569,3613 ****
          cm_FreeSpace(spacep);
  
          lock_ObtainMutex(&amp;dsp-&gt;mx);
! 		if (code == 0) {
              if (dsp-&gt;scp != 0) cm_ReleaseSCache(dsp-&gt;scp);
! 			dsp-&gt;scp = scp;
! 			/* we need one hold for the entry we just stored into,
               * and one for our own processing.  When we're done
! 			 * with this function, we'll drop the one for our own
! 			 * processing.  We held it once from the namei call,
! 			 * and so we do another hold now.
               */
              cm_HoldSCache(scp);
!    			lock_ObtainMutex(&amp;scp-&gt;mx);
!    			if ((scp-&gt;flags &amp; CM_SCACHEFLAG_BULKSTATTING) == 0
!    			    &amp;&amp; LargeIntegerGreaterOrEqualToZero(scp-&gt;bulkStatProgress)) {
                  scp-&gt;flags |= CM_SCACHEFLAG_BULKSTATTING;
! 				dsp-&gt;flags |= SMB_DIRSEARCH_BULKST;
!    			}
!    			lock_ReleaseMutex(&amp;scp-&gt;mx);
!         }
      }
! 	lock_ReleaseMutex(&amp;dsp-&gt;mx);
      if (code) {
! 		cm_ReleaseUser(userp);
          smb_FreeTran2Packet(outp);
! 		smb_DeleteDirSearch(dsp);
! 		smb_ReleaseDirSearch(dsp);
          return code;
!         }
  
      /* get the directory size */
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
      code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 	if (code) {
! 		lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          smb_FreeTran2Packet(outp);
! 		smb_DeleteDirSearch(dsp);
! 		smb_ReleaseDirSearch(dsp);
          return code;
      }
  
--- 3670,3714 ----
          cm_FreeSpace(spacep);
  
          lock_ObtainMutex(&amp;dsp-&gt;mx);
!         if (code == 0) {
              if (dsp-&gt;scp != 0) cm_ReleaseSCache(dsp-&gt;scp);
!             dsp-&gt;scp = scp;
!             /* we need one hold for the entry we just stored into,
               * and one for our own processing.  When we're done
!              * with this function, we'll drop the one for our own
!              * processing.  We held it once from the namei call,
!              * and so we do another hold now.
               */
              cm_HoldSCache(scp);
!             lock_ObtainMutex(&amp;scp-&gt;mx);
!             if ((scp-&gt;flags &amp; CM_SCACHEFLAG_BULKSTATTING) == 0 &amp;&amp;
!                  LargeIntegerGreaterOrEqualToZero(scp-&gt;bulkStatProgress)) {
                  scp-&gt;flags |= CM_SCACHEFLAG_BULKSTATTING;
!                 dsp-&gt;flags |= SMB_DIRSEARCH_BULKST;
!             }
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!         }       
      }
!     lock_ReleaseMutex(&amp;dsp-&gt;mx);
      if (code) {
!         cm_ReleaseUser(userp);
          smb_FreeTran2Packet(outp);
!         smb_DeleteDirSearch(dsp);
!         smb_ReleaseDirSearch(dsp);
          return code;
!     }
  
      /* get the directory size */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
      code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) {
!         lock_ReleaseMutex(&amp;scp-&gt;mx);
          cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          smb_FreeTran2Packet(outp);
!         smb_DeleteDirSearch(dsp);
!         smb_ReleaseDirSearch(dsp);
          return code;
      }
  
***************
*** 3617,3647 ****
      bufferOffset.LowPart = bufferOffset.HighPart = 0;
      curOffset.HighPart = 0;
      curOffset.LowPart = nextCookie;
! 	origOp = outp-&gt;datap;
  
      foundInexact = 0;
      code = 0;
      returnedNames = 0;
      bytesInBuffer = 0;
      while (1) {
! 		op = origOp;
! 		if (searchFlags &amp; 4)
! 			/* skip over resume key */
! 			op += 4;
  
! 		/* make sure that curOffset.LowPart doesn't point to the first
           * 32 bytes in the 2nd through last dir page, and that it doesn't
           * point at the first 13 32-byte chunks in the first dir page,
           * since those are dir and page headers, and don't contain useful
           * information.
           */
! 		temp = curOffset.LowPart &amp; (2048-1);
          if (curOffset.HighPart == 0 &amp;&amp; curOffset.LowPart &lt; 2048) {
! 			/* we're in the first page */
              if (temp &lt; 13*32) temp = 13*32;
! 		}
! 		else {
! 			/* we're in a later dir page */
              if (temp &lt; 32) temp = 32;
          }
  		
--- 3718,3748 ----
      bufferOffset.LowPart = bufferOffset.HighPart = 0;
      curOffset.HighPart = 0;
      curOffset.LowPart = nextCookie;
!     origOp = outp-&gt;datap;
  
      foundInexact = 0;
      code = 0;
      returnedNames = 0;
      bytesInBuffer = 0;
      while (1) {
!         op = origOp;
!         if (searchFlags &amp; 4)
!             /* skip over resume key */
!             op += 4;
  
!         /* make sure that curOffset.LowPart doesn't point to the first
           * 32 bytes in the 2nd through last dir page, and that it doesn't
           * point at the first 13 32-byte chunks in the first dir page,
           * since those are dir and page headers, and don't contain useful
           * information.
           */
!         temp = curOffset.LowPart &amp; (2048-1);
          if (curOffset.HighPart == 0 &amp;&amp; curOffset.LowPart &lt; 2048) {
!             /* we're in the first page */
              if (temp &lt; 13*32) temp = 13*32;
!         }
!         else {
!             /* we're in a later dir page */
              if (temp &lt; 32) temp = 32;
          }
  		
***************
*** 3674,3708 ****
          thyper.HighPart = curOffset.HighPart;
          thyper.LowPart = curOffset.LowPart &amp; ~(buf_bufferSize-1);
          if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
! 			/* wrong buffer */
              if (bufferp) {
                  buf_Release(bufferp);
                  bufferp = NULL;
! 			}       
! 			lock_ReleaseMutex(&amp;scp-&gt;mx);
! 			lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
              code = buf_Get(scp, &amp;thyper, &amp;bufferp);
! 			lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
  
! 			/* now, if we're doing a star match, do bulk fetching
! 			 * of all of the status info for files in the dir.
               */
              if (starPattern) {
! 				smb_ApplyV3DirListPatches(scp, &amp;dirListPatchesp,
!                                           infoLevel, userp,
!                                           &amp;req);
!    				if ((dsp-&gt;flags &amp; SMB_DIRSEARCH_BULKST)
!                     &amp;&amp; LargeIntegerGreaterThanOrEqualTo(thyper, scp-&gt;bulkStatProgress)) {
!    					/* Don't bulk stat if risking timeout */
!    					int now = GetCurrentTime();
!    					if (now - req.startTime &gt; 5000) {
!    						scp-&gt;bulkStatProgress = thyper;
!    						scp-&gt;flags &amp;= ~CM_SCACHEFLAG_BULKSTATTING;
!    						dsp-&gt;flags &amp;= ~SMB_DIRSEARCH_BULKST;
!    					} else
                          cm_TryBulkStat(scp, &amp;thyper, userp, &amp;req);
!    				}
! 			}
  
              lock_ObtainMutex(&amp;scp-&gt;mx);
              if (code) break;
--- 3775,3809 ----
          thyper.HighPart = curOffset.HighPart;
          thyper.LowPart = curOffset.LowPart &amp; ~(buf_bufferSize-1);
          if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
!             /* wrong buffer */
              if (bufferp) {
                  buf_Release(bufferp);
                  bufferp = NULL;
!             }       
!             lock_ReleaseMutex(&amp;scp-&gt;mx);
!             lock_ObtainRead(&amp;scp-&gt;bufCreateLock);
              code = buf_Get(scp, &amp;thyper, &amp;bufferp);
!             lock_ReleaseRead(&amp;scp-&gt;bufCreateLock);
  
!             /* now, if we're doing a star match, do bulk fetching
!              * of all of the status info for files in the dir.
               */
              if (starPattern) {
!                 smb_ApplyV3DirListPatches(scp, &amp;dirListPatchesp,
!                                            infoLevel, userp,
!                                            &amp;req);
!                 if ((dsp-&gt;flags &amp; SMB_DIRSEARCH_BULKST) &amp;&amp;
!                     LargeIntegerGreaterThanOrEqualTo(thyper, scp-&gt;bulkStatProgress)) {
!                     /* Don't bulk stat if risking timeout */
!                     int now = GetCurrentTime();
!                     if (now - req.startTime &gt; 5000) {
!                         scp-&gt;bulkStatProgress = thyper;
!                         scp-&gt;flags &amp;= ~CM_SCACHEFLAG_BULKSTATTING;
!                         dsp-&gt;flags &amp;= ~SMB_DIRSEARCH_BULKST;
!                     } else
                          cm_TryBulkStat(scp, &amp;thyper, userp, &amp;req);
!                 }
!             }
  
              lock_ObtainMutex(&amp;scp-&gt;mx);
              if (code) break;
***************
*** 3710,3720 ****
  
              /* now get the data in the cache */
              while (1) {
! 				code = cm_SyncOp(scp, bufferp, userp, &amp;req,
                                   PRSFS_LOOKUP,
                                   CM_SCACHESYNC_NEEDCALLBACK
                                   | CM_SCACHESYNC_READ);
! 				if (code) break;
                                  
                  if (cm_HaveBuffer(scp, bufferp, 0)) break;
  
--- 3811,3821 ----
  
              /* now get the data in the cache */
              while (1) {
!                 code = cm_SyncOp(scp, bufferp, userp, &amp;req,
                                   PRSFS_LOOKUP,
                                   CM_SCACHESYNC_NEEDCALLBACK
                                   | CM_SCACHESYNC_READ);
!                 if (code) break;
                                  
                  if (cm_HaveBuffer(scp, bufferp, 0)) break;
  
***************
*** 3724,3793 ****
                  if (code) break;
              }
              if (code) {
! 				buf_Release(bufferp);
                  bufferp = NULL;
                  break;
! 			}
          }	/* if (wrong buffer) ... */
                  
          /* now we have the buffer containing the entry we're interested
           * in; copy it out if it represents a non-deleted entry.
           */
! 		entryInDir = curOffset.LowPart &amp; (2048-1);
          entryInBuffer = curOffset.LowPart &amp; (buf_bufferSize - 1);
  
! 		/* page header will help tell us which entries are free.  Page
! 		 * header can change more often than once per buffer, since
! 		 * AFS 3 dir page size may be less than (but not more than)
! 		 * a buffer package buffer.
           */
! 		/* only look intra-buffer */
! 		temp = curOffset.LowPart &amp; (buf_bufferSize - 1);
          temp &amp;= ~(2048 - 1);	/* turn off intra-page bits */
! 		pageHeaderp = (cm_pageHeader_t *) (bufferp-&gt;datap + temp);
  
! 		/* now determine which entry we're looking at in the page.
! 		 * If it is free (there's a free bitmap at the start of the
! 		 * dir), we should skip these 32 bytes.
           */
          slotInPage = (entryInDir &amp; 0x7e0) &gt;&gt; 5;
!         if (!(pageHeaderp-&gt;freeBitmap[slotInPage&gt;&gt;3]
!                &amp; (1 &lt;&lt; (slotInPage &amp; 0x7)))) {
! 			/* this entry is free */
              numDirChunks = 1;	/* only skip this guy */
              goto nextEntry;
          }
  
! 		tp = bufferp-&gt;datap + entryInBuffer;
          dep = (cm_dirEntry_t *) tp;	/* now points to AFS3 dir entry */
  
          /* while we're here, compute the next entry's location, too,
! 		 * since we'll need it when writing out the cookie into the dir
! 		 * listing stream.
           *
           * XXXX Probably should do more sanity checking.
           */
! 		numDirChunks = cm_NameEntries(dep-&gt;name, &amp;onbytes);
  		
          /* compute offset of cookie representing next entry */
          nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
  
! 		/* Need 8.3 name? */
! 		NeedShortName = 0;
! 		if (infoLevel == 0x104
! 		    &amp;&amp; dep-&gt;fid.vnode != 0
! 		    &amp;&amp; !cm_Is8Dot3(dep-&gt;name)) {
! 			cm_Gen8Dot3Name(dep, shortName, &amp;shortNameEnd);
! 			NeedShortName = 1;
! 		}
  
          /* When matching, we are using doing a case fold if we have a wildcard mask.
           * If we get a non-wildcard match, it's a lookup for a specific file. 
           */
          if (dep-&gt;fid.vnode != 0 &amp;&amp; 
!             (smb_V3MatchMask(dep-&gt;name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
!               || (NeedShortName
!                    &amp;&amp; smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
  
              /* Eliminate entries that don't match requested attributes */
              if (smb_hideDotFiles &amp;&amp; !(dsp-&gt;attribute &amp; SMB_ATTR_HIDDEN) &amp;&amp; 
--- 3825,3894 ----
                  if (code) break;
              }
              if (code) {
!                 buf_Release(bufferp);
                  bufferp = NULL;
                  break;
!             }
          }	/* if (wrong buffer) ... */
                  
          /* now we have the buffer containing the entry we're interested
           * in; copy it out if it represents a non-deleted entry.
           */
!         entryInDir = curOffset.LowPart &amp; (2048-1);
          entryInBuffer = curOffset.LowPart &amp; (buf_bufferSize - 1);
  
!         /* page header will help tell us which entries are free.  Page
!          * header can change more often than once per buffer, since
!          * AFS 3 dir page size may be less than (but not more than)
!          * a buffer package buffer.
           */
!         /* only look intra-buffer */
!         temp = curOffset.LowPart &amp; (buf_bufferSize - 1);
          temp &amp;= ~(2048 - 1);	/* turn off intra-page bits */
!         pageHeaderp = (cm_pageHeader_t *) (bufferp-&gt;datap + temp);
  
!         /* now determine which entry we're looking at in the page.
!          * If it is free (there's a free bitmap at the start of the
!          * dir), we should skip these 32 bytes.
           */
          slotInPage = (entryInDir &amp; 0x7e0) &gt;&gt; 5;
!         if (!(pageHeaderp-&gt;freeBitmap[slotInPage&gt;&gt;3] &amp;
!             (1 &lt;&lt; (slotInPage &amp; 0x7)))) {
!             /* this entry is free */
              numDirChunks = 1;	/* only skip this guy */
              goto nextEntry;
          }
  
!         tp = bufferp-&gt;datap + entryInBuffer;
          dep = (cm_dirEntry_t *) tp;	/* now points to AFS3 dir entry */
  
          /* while we're here, compute the next entry's location, too,
!          * since we'll need it when writing out the cookie into the dir
!          * listing stream.
           *
           * XXXX Probably should do more sanity checking.
           */
!         numDirChunks = cm_NameEntries(dep-&gt;name, &amp;onbytes);
  		
          /* compute offset of cookie representing next entry */
          nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
  
!         /* Need 8.3 name? */
!         NeedShortName = 0;
!         if (infoLevel == 0x104
!              &amp;&amp; dep-&gt;fid.vnode != 0
!              &amp;&amp; !cm_Is8Dot3(dep-&gt;name)) {
!             cm_Gen8Dot3Name(dep, shortName, &amp;shortNameEnd);
!             NeedShortName = 1;
!         }
  
          /* When matching, we are using doing a case fold if we have a wildcard mask.
           * If we get a non-wildcard match, it's a lookup for a specific file. 
           */
          if (dep-&gt;fid.vnode != 0 &amp;&amp; 
!             (smb_V3MatchMask(dep-&gt;name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
!              (NeedShortName &amp;&amp;
!               smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
  
              /* Eliminate entries that don't match requested attributes */
              if (smb_hideDotFiles &amp;&amp; !(dsp-&gt;attribute &amp; SMB_ATTR_HIDDEN) &amp;&amp; 
***************
*** 3809,3940 ****
                      goto nextEntry;
              }
  
! 			/* finally check if this name will fit */
  
! 			/* standard dir entry stuff */
! 			if (infoLevel &lt; 0x101)
! 				ohbytes = 23;	/* pre-NT */
! 			else if (infoLevel == 0x103)
! 				ohbytes = 12;	/* NT names only */
! 			else
! 				ohbytes = 64;	/* NT */
  
! 			if (infoLevel == 0x104)
! 				ohbytes += 26;	/* Short name &amp; length */
  
              if (searchFlags &amp; 4) {
                  ohbytes += 4;	/* if resume key required */
! 			}   
  
              if (infoLevel != 1
                   &amp;&amp; infoLevel != 0x101
                   &amp;&amp; infoLevel != 0x103)
! 				ohbytes += 4;	/* EASIZE */
  
! 			/* add header to name &amp; term. null */
! 			orbytes = onbytes + ohbytes + 1;
  
! 			/* now, we round up the record to a 4 byte alignment,
! 			 * and we make sure that we have enough room here for
! 			 * even the aligned version (so we don't have to worry
! 			 * about an * overflow when we pad things out below).
! 			 * That's the reason for the alignment arithmetic below.
               */
! 			if (infoLevel &gt;= 0x101)
! 				align = (4 - (orbytes &amp; 3)) &amp; 3;
! 			else
! 				align = 0;
! 			if (orbytes + bytesInBuffer + align &gt; maxReturnData)
                  break;
  
! 			/* this is one of the entries to use: it is not deleted
! 			 * and it matches the star pattern we're looking for.
! 			 * Put out the name, preceded by its length.
               */
! 			/* First zero everything else */
! 			memset(origOp, 0, ohbytes);
  
! 			if (infoLevel &lt;= 0x101)
                  *(origOp + ohbytes - 1) = (unsigned char) onbytes;
! 			else if (infoLevel == 0x103)
! 				*((u_long *)(op + 8)) = onbytes;
! 			else
! 				*((u_long *)(op + 60)) = onbytes;
              strcpy(origOp+ohbytes, dep-&gt;name);
  
! 			/* Short name if requested and needed */
              if (infoLevel == 0x104) {
! 				if (NeedShortName) {
! 					strcpy(op + 70, shortName);
! 					*(op + 68) = shortNameEnd - shortName;
! 				}
! 			}
  
              /* now, adjust the # of entries copied */
              returnedNames++;
  
! 			/* NextEntryOffset and FileIndex */
! 			if (infoLevel &gt;= 101) {
! 				int entryOffset = orbytes + align;
! 				*((u_long *)op) = entryOffset;
! 				*((u_long *)(op+4)) = nextEntryCookie;
! 			}
  
              /* now we emit the attribute.  This is tricky, since
               * we need to really stat the file to find out what
! 			 * type of entry we've got.  Right now, we're copying
! 			 * out data from * a buffer, while holding the scp
! 			 * locked, so it isn't really convenient to stat
! 			 * something now.  We'll put in a place holder
               * now, and make a second pass before returning this
! 			 * to get the real attributes.  So, we just skip the
! 			 * data for now, and adjust it later.  We allocate a
! 			 * patch record to make it easy to find this point
! 			 * later.  The replay will happen at a time when it is
! 			 * safe to unlock the directory.
               */
! 			if (infoLevel != 0x103) {
! 				curPatchp = malloc(sizeof(*curPatchp));
                  osi_QAdd((osi_queue_t **) &amp;dirListPatchesp,
                            &amp;curPatchp-&gt;q);
! 				curPatchp-&gt;dptr = op;
! 				if (infoLevel &gt;= 0x101)
! 					curPatchp-&gt;dptr += 8;
  
                  if (smb_hideDotFiles &amp;&amp; smb_IsDotFile(dep-&gt;name)) {
                      curPatchp-&gt;flags = SMB_DIRLISTPATCH_DOTFILE;
!                 }
!                 else
                      curPatchp-&gt;flags = 0;
  
! 				curPatchp-&gt;fid.cell = scp-&gt;fid.cell;
! 				curPatchp-&gt;fid.volume = scp-&gt;fid.volume;
! 				curPatchp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
! 				curPatchp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
  
                  /* temp */
                  curPatchp-&gt;dep = dep;
! 			}   
  
! 			if (searchFlags &amp; 4)
! 				/* put out resume key */
! 				*((u_long *)origOp) = nextEntryCookie;
  
! 			/* Adjust byte ptr and count */
! 			origOp += orbytes;	/* skip entire record */
              bytesInBuffer += orbytes;
  
! 			/* and pad the record out */
              while (--align &gt;= 0) {
! 				*origOp++ = 0;
                  bytesInBuffer++;
              }
! 
! 		}	/* if we're including this name */
          else if (!NeedShortName &amp;&amp;
                   !starPattern &amp;&amp;
                   !foundInexact &amp;&amp;
!                  					dep-&gt;fid.vnode != 0 &amp;&amp;
                   smb_V3MatchMask(dep-&gt;name, maskp, CM_FLAG_CASEFOLD)) {
              /* We were looking for exact matches, but here's an inexact one*/
              foundInexact = 1;
--- 3910,4040 ----
                      goto nextEntry;
              }
  
!             /* finally check if this name will fit */
  
!             /* standard dir entry stuff */
!             if (infoLevel &lt; 0x101)
!                 ohbytes = 23;	/* pre-NT */
!             else if (infoLevel == 0x103)
!                 ohbytes = 12;	/* NT names only */
!             else
!                 ohbytes = 64;	/* NT */
  
!             if (infoLevel == 0x104)
!                 ohbytes += 26;	/* Short name &amp; length */
  
              if (searchFlags &amp; 4) {
                  ohbytes += 4;	/* if resume key required */
!             }   
  
              if (infoLevel != 1
                   &amp;&amp; infoLevel != 0x101
                   &amp;&amp; infoLevel != 0x103)
!                 ohbytes += 4;	/* EASIZE */
  
!             /* add header to name &amp; term. null */
!             orbytes = onbytes + ohbytes + 1;
  
!             /* now, we round up the record to a 4 byte alignment,
!              * and we make sure that we have enough room here for
!              * even the aligned version (so we don't have to worry
!              * about an * overflow when we pad things out below).
!              * That's the reason for the alignment arithmetic below.
               */
!             if (infoLevel &gt;= 0x101)
!                 align = (4 - (orbytes &amp; 3)) &amp; 3;
!             else
!                 align = 0;
!             if (orbytes + bytesInBuffer + align &gt; maxReturnData)
                  break;
  
!             /* this is one of the entries to use: it is not deleted
!              * and it matches the star pattern we're looking for.
!              * Put out the name, preceded by its length.
               */
!             /* First zero everything else */
!             memset(origOp, 0, ohbytes);
  
!             if (infoLevel &lt;= 0x101)
                  *(origOp + ohbytes - 1) = (unsigned char) onbytes;
!             else if (infoLevel == 0x103)
!                 *((u_long *)(op + 8)) = onbytes;
!             else
!                 *((u_long *)(op + 60)) = onbytes;
              strcpy(origOp+ohbytes, dep-&gt;name);
  
!             /* Short name if requested and needed */
              if (infoLevel == 0x104) {
!                 if (NeedShortName) {
!                     strcpy(op + 70, shortName);
!                     *(op + 68) = shortNameEnd - shortName;
!                 }
!             }
  
              /* now, adjust the # of entries copied */
              returnedNames++;
  
!             /* NextEntryOffset and FileIndex */
!             if (infoLevel &gt;= 101) {
!                 int entryOffset = orbytes + align;
!                 *((u_long *)op) = entryOffset;
!                 *((u_long *)(op+4)) = nextEntryCookie;
!             }
  
              /* now we emit the attribute.  This is tricky, since
               * we need to really stat the file to find out what
!              * type of entry we've got.  Right now, we're copying
!              * out data from * a buffer, while holding the scp
!              * locked, so it isn't really convenient to stat
!              * something now.  We'll put in a place holder
               * now, and make a second pass before returning this
!              * to get the real attributes.  So, we just skip the
!              * data for now, and adjust it later.  We allocate a
!              * patch record to make it easy to find this point
!              * later.  The replay will happen at a time when it is
!              * safe to unlock the directory.
               */
!             if (infoLevel != 0x103) {
!                 curPatchp = malloc(sizeof(*curPatchp));
                  osi_QAdd((osi_queue_t **) &amp;dirListPatchesp,
                            &amp;curPatchp-&gt;q);
!                 curPatchp-&gt;dptr = op;
!                 if (infoLevel &gt;= 0x101)
!                     curPatchp-&gt;dptr += 8;
  
                  if (smb_hideDotFiles &amp;&amp; smb_IsDotFile(dep-&gt;name)) {
                      curPatchp-&gt;flags = SMB_DIRLISTPATCH_DOTFILE;
!                 }       
!                 else    
                      curPatchp-&gt;flags = 0;
  
!                 curPatchp-&gt;fid.cell = scp-&gt;fid.cell;
!                 curPatchp-&gt;fid.volume = scp-&gt;fid.volume;
!                 curPatchp-&gt;fid.vnode = ntohl(dep-&gt;fid.vnode);
!                 curPatchp-&gt;fid.unique = ntohl(dep-&gt;fid.unique);
  
                  /* temp */
                  curPatchp-&gt;dep = dep;
!             }   
  
!             if (searchFlags &amp; 4)
!                 /* put out resume key */
!                 *((u_long *)origOp) = nextEntryCookie;
  
!             /* Adjust byte ptr and count */
!             origOp += orbytes;	/* skip entire record */
              bytesInBuffer += orbytes;
  
!             /* and pad the record out */
              while (--align &gt;= 0) {
!                 *origOp++ = 0;
                  bytesInBuffer++;
              }
!         }	/* if we're including this name */
          else if (!NeedShortName &amp;&amp;
                   !starPattern &amp;&amp;
                   !foundInexact &amp;&amp;
!                  dep-&gt;fid.vnode != 0 &amp;&amp;
                   smb_V3MatchMask(dep-&gt;name, maskp, CM_FLAG_CASEFOLD)) {
              /* We were looking for exact matches, but here's an inexact one*/
              foundInexact = 1;
***************
*** 3942,3951 ****
                  
        nextEntry:
          /* and adjust curOffset to be where the new cookie is */
! 		thyper.HighPart = 0;
          thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
          curOffset = LargeIntegerAdd(thyper, curOffset);
!     }		/* while copying data for dir listing */
  
      /* If we didn't get a star pattern, we did an exact match during the first pass. 
       * If there were no exact matches found, we fail over to inexact matches by
--- 4042,4051 ----
                  
        nextEntry:
          /* and adjust curOffset to be where the new cookie is */
!         thyper.HighPart = 0;
          thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
          curOffset = LargeIntegerAdd(thyper, curOffset);
!     } /* while copying data for dir listing */
  
      /* If we didn't get a star pattern, we did an exact match during the first pass. 
       * If there were no exact matches found, we fail over to inexact matches by
***************
*** 3958,3977 ****
          goto startsearch;
      }
  
! 	/* release the mutex */
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
      if (bufferp) buf_Release(bufferp);
  
! 	/* apply and free last set of patches; if not doing a star match, this
! 	 * will be empty, but better safe (and freeing everything) than sorry.
       */
      smb_ApplyV3DirListPatches(scp, &amp;dirListPatchesp, infoLevel, userp,
                                &amp;req);
          
      /* now put out the final parameters */
! 	if (returnedNames == 0) eos = 1;
      if (p-&gt;opcode == 1) {
! 		/* find first */
          outp-&gt;parmsp[0] = (unsigned short) dsp-&gt;cookie;
          outp-&gt;parmsp[1] = returnedNames;
          outp-&gt;parmsp[2] = eos;
--- 4058,4077 ----
          goto startsearch;
      }
  
!     /* release the mutex */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
      if (bufferp) buf_Release(bufferp);
  
!     /* apply and free last set of patches; if not doing a star match, this
!      * will be empty, but better safe (and freeing everything) than sorry.
       */
      smb_ApplyV3DirListPatches(scp, &amp;dirListPatchesp, infoLevel, userp,
                                &amp;req);
          
      /* now put out the final parameters */
!     if (returnedNames == 0) eos = 1;
      if (p-&gt;opcode == 1) {
!         /* find first */
          outp-&gt;parmsp[0] = (unsigned short) dsp-&gt;cookie;
          outp-&gt;parmsp[1] = returnedNames;
          outp-&gt;parmsp[2] = eos;
***************
*** 3993,4022 ****
          outp-&gt;totalParms = 8;	/* in bytes */
      }   
  
! 	/* return # of bytes in the buffer */
      outp-&gt;totalData = bytesInBuffer;
  
! 	osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
!               returnedNames, code);
  
! 	/* Return error code if unsuccessful on first request */
! 	if (code == 0 &amp;&amp; p-&gt;opcode == 1 &amp;&amp; returnedNames == 0)
! 		code = CM_ERROR_NOSUCHFILE;
  
! 	/* if we're supposed to close the search after this request, or if
       * we're supposed to close the search if we're done, and we're done,
       * or if something went wrong, close the search.
       */
      /* ((searchFlags &amp; 1) || ((searchFlags &amp; 2) &amp;&amp; eos) */
! 	if ((searchFlags &amp; 1) || (returnedNames == 0) || 
           ((searchFlags &amp; 2) &amp;&amp; eos) || code != 0)
! 	    smb_DeleteDirSearch(dsp);
! 	if (code)
          smb_SendTran2Error(vcp, p, opx, code);
! 	else {
          smb_SendTran2Packet(vcp, outp, opx);
! 	}
! 	smb_FreeTran2Packet(outp);
      smb_ReleaseDirSearch(dsp);
      cm_ReleaseSCache(scp);
      cm_ReleaseUser(userp);
--- 4093,4122 ----
          outp-&gt;totalParms = 8;	/* in bytes */
      }   
  
!     /* return # of bytes in the buffer */
      outp-&gt;totalData = bytesInBuffer;
  
!     osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
!              returnedNames, code);
  
!     /* Return error code if unsuccessful on first request */
!     if (code == 0 &amp;&amp; p-&gt;opcode == 1 &amp;&amp; returnedNames == 0)
!         code = CM_ERROR_NOSUCHFILE;
  
!     /* if we're supposed to close the search after this request, or if
       * we're supposed to close the search if we're done, and we're done,
       * or if something went wrong, close the search.
       */
      /* ((searchFlags &amp; 1) || ((searchFlags &amp; 2) &amp;&amp; eos) */
!     if ((searchFlags &amp; 1) || (returnedNames == 0) || 
           ((searchFlags &amp; 2) &amp;&amp; eos) || code != 0)
!         smb_DeleteDirSearch(dsp);
!     if (code)
          smb_SendTran2Error(vcp, p, opx, code);
!     else {
          smb_SendTran2Packet(vcp, outp, opx);
!     }
!     smb_FreeTran2Packet(outp);
      smb_ReleaseDirSearch(dsp);
      cm_ReleaseSCache(scp);
      cm_ReleaseUser(userp);
***************
*** 4035,4063 ****
      dsp = smb_FindDirSearch(dirHandle);
          
      if (!dsp)
! 		return CM_ERROR_BADFD;
  	
      /* otherwise, we have an FD to destroy */
      smb_DeleteDirSearch(dsp);
      smb_ReleaseDirSearch(dsp);
          
! 	/* and return results */
! 	smb_SetSMBDataLength(outp, 0);
  
      return 0;
  }
  
  long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	smb_SetSMBDataLength(outp, 0);
      return 0;
  }
  
  long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	char *pathp;
      long code = 0;
! 	cm_space_t *spacep;
      int excl;
      cm_user_t *userp;
      cm_scache_t *dscp;		/* dir we're dealing with */
--- 4135,4163 ----
      dsp = smb_FindDirSearch(dirHandle);
          
      if (!dsp)
!         return CM_ERROR_BADFD;
  	
      /* otherwise, we have an FD to destroy */
      smb_DeleteDirSearch(dsp);
      smb_ReleaseDirSearch(dsp);
          
!     /* and return results */
!     smb_SetSMBDataLength(outp, 0);
  
      return 0;
  }
  
  long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     smb_SetSMBDataLength(outp, 0);
      return 0;
  }
  
  long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     char *pathp;
      long code = 0;
!     cm_space_t *spacep;
      int excl;
      cm_user_t *userp;
      cm_scache_t *dscp;		/* dir we're dealing with */
***************
*** 4067,4091 ****
      smb_fid_t *fidp;
      int attributes;
      char *lastNamep;
!     long dosTime;
      int openFun;
      int trunc;
      int openMode;
      int extraInfo;
      int openAction;
      int parmSlot;			/* which parm we're dealing with */
! 	char *tidPathp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      scp = NULL;
          
! 	extraInfo = (smb_GetSMBParm(inp, 2) &amp; 1);	/* return extra info */
! 	openFun = smb_GetSMBParm(inp, 8);	/* open function */
      excl = ((openFun &amp; 3) == 0);
      trunc = ((openFun &amp; 3) == 2);		/* truncate it */
! 	openMode = (smb_GetSMBParm(inp, 3) &amp; 0x7);
      openAction = 0;			/* tracks what we did */
  
      attributes = smb_GetSMBParm(inp, 5);
--- 4167,4191 ----
      smb_fid_t *fidp;
      int attributes;
      char *lastNamep;
!     time_t dosTime;
      int openFun;
      int trunc;
      int openMode;
      int extraInfo;
      int openAction;
      int parmSlot;			/* which parm we're dealing with */
!     char *tidPathp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      scp = NULL;
          
!     extraInfo = (smb_GetSMBParm(inp, 2) &amp; 1);	/* return extra info */
!     openFun = smb_GetSMBParm(inp, 8);	/* open function */
      excl = ((openFun &amp; 3) == 0);
      trunc = ((openFun &amp; 3) == 2);		/* truncate it */
!     openMode = (smb_GetSMBParm(inp, 3) &amp; 0x7);
      openAction = 0;			/* tracks what we did */
  
      attributes = smb_GetSMBParm(inp, 5);
***************
*** 4097,4107 ****
          
      pathp = smb_GetSMBData(inp, NULL);
  
! 	spacep = inp-&gt;spacep;
      smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
! 	if (lastNamep &amp;&amp; strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
! 		/* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
  #ifdef NOTSERVICE
--- 4197,4207 ----
          
      pathp = smb_GetSMBData(inp, NULL);
  
!     spacep = inp-&gt;spacep;
      smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, pathp);
  
!     if (lastNamep &amp;&amp; strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
!         /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
  #ifdef NOTSERVICE
***************
*** 4111,4123 ****
          fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
          smb_SetupIoctlFid(fidp, spacep);
  
! 		/* set inp-&gt;fid so that later read calls in same msg can find fid */
          inp-&gt;fid = fidp-&gt;fid;
          
          /* copy out remainder of the parms */
! 		parmSlot = 2;
! 		smb_SetSMBParm(outp, parmSlot, fidp-&gt;fid); parmSlot++;
! 		if (extraInfo) {
              smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
              smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* mod time */
              smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
--- 4211,4223 ----
          fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
          smb_SetupIoctlFid(fidp, spacep);
  
!         /* set inp-&gt;fid so that later read calls in same msg can find fid */
          inp-&gt;fid = fidp-&gt;fid;
          
          /* copy out remainder of the parms */
!         parmSlot = 2;
!         smb_SetSMBParm(outp, parmSlot, fidp-&gt;fid); parmSlot++;
!         if (extraInfo) {
              smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
              smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* mod time */
              smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
***************
*** 4126,4141 ****
              smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
              smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==&gt; normal file or dir */
              smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
! 		}   
! 		/* and the final "always present" stuff */
          smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
! 		/* next write out the "unique" ID */
! 		smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
! 		smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
          smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
          smb_SetSMBDataLength(outp, 0);
  
! 		/* and clean up fid reference */
          smb_ReleaseFID(fidp);
          return 0;
      }
--- 4226,4241 ----
              smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
              smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==&gt; normal file or dir */
              smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
!         }   
!         /* and the final "always present" stuff */
          smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
!         /* next write out the "unique" ID */
!         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
!         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
          smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
          smb_SetSMBDataLength(outp, 0);
  
!         /* and clean up fid reference */
          smb_ReleaseFID(fidp);
          return 0;
      }
***************
*** 4151,4167 ****
  #endif
      userp = smb_GetUser(vcp, inp);
  
! 	dscp = NULL;
! 	code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
! 	code = cm_NameI(cm_rootSCachep, pathp,
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                      userp, tidPathp, &amp;req, &amp;scp);
! 	if (code != 0) {
! 		code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &amp;req, &amp;dscp);
  
--- 4251,4267 ----
  #endif
      userp = smb_GetUser(vcp, inp);
  
!     dscp = NULL;
!     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!     if (code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_rootSCachep, pathp,
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                      userp, tidPathp, &amp;req, &amp;scp);
!     if (code != 0) {
!         code = cm_NameI(cm_rootSCachep, spacep-&gt;data,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &amp;req, &amp;dscp);
  
***************
*** 4183,4196 ****
              cm_ReleaseUser(userp);
              return code;
          }
! 	}
          
      /* if we get here, if code is 0, the file exists and is represented by
       * scp.  Otherwise, we have to create it.  The dir may be represented
       * by dscp, or we may have found the file directly.  If code is non-zero,
       * scp is NULL.
       */
! 	if (code == 0) {
          code = cm_CheckOpen(scp, openMode, trunc, userp, &amp;req);
          if (code) {
              if (dscp) cm_ReleaseSCache(dscp);
--- 4283,4296 ----
              cm_ReleaseUser(userp);
              return code;
          }
!     }
          
      /* if we get here, if code is 0, the file exists and is represented by
       * scp.  Otherwise, we have to create it.  The dir may be represented
       * by dscp, or we may have found the file directly.  If code is non-zero,
       * scp is NULL.
       */
!     if (code == 0) {
          code = cm_CheckOpen(scp, openMode, trunc, userp, &amp;req);
          if (code) {
              if (dscp) cm_ReleaseSCache(dscp);
***************
*** 4199,4303 ****
              return code;
          }
  
! 		if (excl) {
! 			/* oops, file shouldn't be there */
              if (dscp) cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
              return CM_ERROR_EXISTS;
          }
  
! 		if (trunc) {
! 			setAttr.mask = CM_ATTRMASK_LENGTH;
              setAttr.length.LowPart = 0;
              setAttr.length.HighPart = 0;
! 			code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
              openAction = 3;	/* truncated existing file */
! 		}
          else openAction = 1;	/* found existing file */
      }
! 	else if (!(openFun &amp; 0x10)) {
! 		/* don't create if not found */
          if (dscp) cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHFILE;
      }
      else {
! 		osi_assert(dscp != NULL);
! 		osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
                   osi_LogSaveString(smb_logp, lastNamep));
! 		openAction = 2;	/* created file */
! 		setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
! 		smb_UnixTimeFromDosUTime(&amp;setAttr.clientModTime, dosTime);
          code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
                           &amp;req);
! 		if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 			smb_NotifyChange(FILE_ACTION_ADDED,
                               FILE_NOTIFY_CHANGE_FILE_NAME,
                               dscp, lastNamep, NULL, TRUE);
          if (!excl &amp;&amp; code == CM_ERROR_EXISTS) {
! 			/* not an exclusive create, and someone else tried
! 			 * creating it already, then we open it anyway.  We
! 			 * don't bother retrying after this, since if this next
! 			 * fails, that means that the file was deleted after we
! 			 * started this call.
               */
              code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
                               userp, &amp;req, &amp;scp);
              if (code == 0) {
                  if (trunc) {
! 					setAttr.mask = CM_ATTRMASK_LENGTH;
                      setAttr.length.LowPart = 0;
                      setAttr.length.HighPart = 0;
                      code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
                  }   
! 			}	/* lookup succeeded */
          }
      }
          
! 	/* we don't need this any longer */
! 	if (dscp) cm_ReleaseSCache(dscp);
  
      if (code) {
! 		/* something went wrong creating or truncating the file */
          if (scp) cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          return code;
      }
          
! 	/* make sure we're about to open a file */
! 	if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
! 		cm_ReleaseSCache(scp);
! 		cm_ReleaseUser(userp);
! 		return CM_ERROR_ISDIR;
! 	}
  
      /* now all we have to do is open the file itself */
      fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
      osi_assert(fidp);
  	
! 	/* save a pointer to the vnode */
      fidp-&gt;scp = scp;
          
! 	/* compute open mode */
      if (openMode != 1) fidp-&gt;flags |= SMB_FID_OPENREAD;
      if (openMode == 1 || openMode == 2)
          fidp-&gt;flags |= SMB_FID_OPENWRITE;
  
! 	smb_ReleaseFID(fidp);
          
! 	cm_Open(scp, 0, userp);
  
! 	/* set inp-&gt;fid so that later read calls in same msg can find fid */
      inp-&gt;fid = fidp-&gt;fid;
          
      /* copy out remainder of the parms */
! 	parmSlot = 2;
! 	smb_SetSMBParm(outp, parmSlot, fidp-&gt;fid); parmSlot++;
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	if (extraInfo) {
          smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
! 		smb_DosUTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
          smb_SetSMBParm(outp, parmSlot, dosTime &amp; 0xffff); parmSlot++;
          smb_SetSMBParm(outp, parmSlot, (dosTime&gt;&gt;16) &amp; 0xffff); parmSlot++;
          smb_SetSMBParm(outp, parmSlot, scp-&gt;length.LowPart &amp; 0xffff); parmSlot++;
--- 4299,4403 ----
              return code;
          }
  
!         if (excl) {
!             /* oops, file shouldn't be there */
              if (dscp) cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
              return CM_ERROR_EXISTS;
          }
  
!         if (trunc) {
!             setAttr.mask = CM_ATTRMASK_LENGTH;
              setAttr.length.LowPart = 0;
              setAttr.length.HighPart = 0;
!             code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
              openAction = 3;	/* truncated existing file */
!         }
          else openAction = 1;	/* found existing file */
      }
!     else if (!(openFun &amp; 0x10)) {
!         /* don't create if not found */
          if (dscp) cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHFILE;
      }
      else {
!         osi_assert(dscp != NULL);
!         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
                   osi_LogSaveString(smb_logp, lastNamep));
!         openAction = 2;	/* created file */
!         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
!         smb_UnixTimeFromDosUTime(&amp;setAttr.clientModTime, dosTime);
          code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
                           &amp;req);
!         if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!             smb_NotifyChange(FILE_ACTION_ADDED,
                               FILE_NOTIFY_CHANGE_FILE_NAME,
                               dscp, lastNamep, NULL, TRUE);
          if (!excl &amp;&amp; code == CM_ERROR_EXISTS) {
!             /* not an exclusive create, and someone else tried
!              * creating it already, then we open it anyway.  We
!              * don't bother retrying after this, since if this next
!              * fails, that means that the file was deleted after we
!              * started this call.
               */
              code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
                               userp, &amp;req, &amp;scp);
              if (code == 0) {
                  if (trunc) {
!                     setAttr.mask = CM_ATTRMASK_LENGTH;
                      setAttr.length.LowPart = 0;
                      setAttr.length.HighPart = 0;
                      code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
                  }   
!             }	/* lookup succeeded */
          }
      }
          
!     /* we don't need this any longer */
!     if (dscp) cm_ReleaseSCache(dscp);
  
      if (code) {
!         /* something went wrong creating or truncating the file */
          if (scp) cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
          return code;
      }
          
!     /* make sure we're about to open a file */
!     if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!         cm_ReleaseSCache(scp);
!         cm_ReleaseUser(userp);
!         return CM_ERROR_ISDIR;
!     }
  
      /* now all we have to do is open the file itself */
      fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
      osi_assert(fidp);
  	
!     /* save a pointer to the vnode */
      fidp-&gt;scp = scp;
          
!     /* compute open mode */
      if (openMode != 1) fidp-&gt;flags |= SMB_FID_OPENREAD;
      if (openMode == 1 || openMode == 2)
          fidp-&gt;flags |= SMB_FID_OPENWRITE;
  
!     smb_ReleaseFID(fidp);
          
!     cm_Open(scp, 0, userp);
  
!     /* set inp-&gt;fid so that later read calls in same msg can find fid */
      inp-&gt;fid = fidp-&gt;fid;
          
      /* copy out remainder of the parms */
!     parmSlot = 2;
!     smb_SetSMBParm(outp, parmSlot, fidp-&gt;fid); parmSlot++;
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     if (extraInfo) {
          smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
!         smb_DosUTimeFromUnixTime(&amp;dosTime, scp-&gt;clientModTime);
          smb_SetSMBParm(outp, parmSlot, dosTime &amp; 0xffff); parmSlot++;
          smb_SetSMBParm(outp, parmSlot, (dosTime&gt;&gt;16) &amp; 0xffff); parmSlot++;
          smb_SetSMBParm(outp, parmSlot, scp-&gt;length.LowPart &amp; 0xffff); parmSlot++;
***************
*** 4305,4363 ****
          smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
          smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==&gt; normal file or dir */
          smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
! 	}
! 	/* and the final "always present" stuff */
      smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
! 	/* next write out the "unique" ID */
! 	smb_SetSMBParm(outp, parmSlot, scp-&gt;fid.vnode &amp; 0xffff); parmSlot++;
! 	smb_SetSMBParm(outp, parmSlot, scp-&gt;fid.volume &amp; 0xffff); parmSlot++;
      smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
      smb_SetSMBDataLength(outp, 0);
  
! 	osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp-&gt;fid);
  
      cm_ReleaseUser(userp);
      /* leave scp held since we put it in fidp-&gt;scp */
      return 0;
! }   
  
  long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	cm_req_t req;
! 	cm_user_t *userp;
! 	unsigned short fid;
! 	smb_fid_t *fidp;
! 	cm_scache_t *scp;
! 	unsigned char LockType;
! 	unsigned short NumberOfUnlocks, NumberOfLocks;
! 	unsigned long Timeout;
! 	char *op;
! 	LARGE_INTEGER LOffset, LLength;
! 	smb_waitingLock_t *waitingLock;
! 	void *lockp;
! 	long code = 0;
! 	int i;
! 
! 	cm_InitReq(&amp;req);
! 
! 	fid = smb_GetSMBParm(inp, 2);
! 	fid = smb_ChainFID(fid, inp);
! 
! 	fidp = smb_FindFID(vcp, fid, 0);
! 	if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
! 		return CM_ERROR_BADFD;
! 	}
! 	/* set inp-&gt;fid so that later read calls in same msg can find fid */
      inp-&gt;fid = fid;
  
! 	userp = smb_GetUser(vcp, inp);
  
! 	scp = fidp-&gt;scp;
  
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
! 			 CM_SCACHESYNC_NEEDCALLBACK
  			 | CM_SCACHESYNC_GETSTATUS
  			 | CM_SCACHESYNC_LOCK);
  	if (code) goto doneSync;
--- 4405,4463 ----
          smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
          smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==&gt; normal file or dir */
          smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
!     }
!     /* and the final "always present" stuff */
      smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
!     /* next write out the "unique" ID */
!     smb_SetSMBParm(outp, parmSlot, scp-&gt;fid.vnode &amp; 0xffff); parmSlot++;
!     smb_SetSMBParm(outp, parmSlot, scp-&gt;fid.volume &amp; 0xffff); parmSlot++;
      smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
      smb_SetSMBDataLength(outp, 0);
  
!     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp-&gt;fid);
  
      cm_ReleaseUser(userp);
      /* leave scp held since we put it in fidp-&gt;scp */
      return 0;
! }       
  
  long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     cm_req_t req;
!     cm_user_t *userp;
!     unsigned short fid;
!     smb_fid_t *fidp;
!     cm_scache_t *scp;
!     unsigned char LockType;
!     unsigned short NumberOfUnlocks, NumberOfLocks;
!     unsigned long Timeout;
!     char *op;
!     LARGE_INTEGER LOffset, LLength;
!     smb_waitingLock_t *waitingLock;
!     void *lockp;
!     long code = 0;
!     int i;
! 
!     cm_InitReq(&amp;req);
! 
!     fid = smb_GetSMBParm(inp, 2);
!     fid = smb_ChainFID(fid, inp);
! 
!     fidp = smb_FindFID(vcp, fid, 0);
!     if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
!         return CM_ERROR_BADFD;
!     }
!     /* set inp-&gt;fid so that later read calls in same msg can find fid */
      inp-&gt;fid = fid;
  
!     userp = smb_GetUser(vcp, inp);
  
!     scp = fidp-&gt;scp;
  
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK
  			 | CM_SCACHESYNC_GETSTATUS
  			 | CM_SCACHESYNC_LOCK);
  	if (code) goto doneSync;
***************
*** 4370,4475 ****
  	op = smb_GetSMBData(inp, NULL);
  
  	for (i=0; i&lt;NumberOfUnlocks; i++) {
! 		if (LockType &amp; 0x10) {
! 			/* Large Files */
! 			LOffset.HighPart = *((LONG *)(op + 4));
! 			LOffset.LowPart = *((DWORD *)(op + 8));
! 			LLength.HighPart = *((LONG *)(op + 12));
! 			LLength.LowPart = *((DWORD *)(op + 16));
! 			op += 20;
! 		}
! 		else {
! 			/* Not Large Files */
! 			LOffset.HighPart = 0;
! 			LOffset.LowPart = *((DWORD *)(op + 2));
! 			LLength.HighPart = 0;
! 			LLength.LowPart = *((DWORD *)(op + 6));
! 			op += 10;
! 		}
! 		if (LargeIntegerNotEqualToZero(LOffset))
! 			continue;
! 		/* Do not check length -- length check done in cm_Unlock */
! 
! 		code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &amp;req);
! 		if (code) goto done;
! 	}
  
  	for (i=0; i&lt;NumberOfLocks; i++) {
! 		if (LockType &amp; 0x10) {
! 			/* Large Files */
! 			LOffset.HighPart = *((LONG *)(op + 4));
! 			LOffset.LowPart = *((DWORD *)(op + 8));
! 			LLength.HighPart = *((LONG *)(op + 12));
! 			LLength.LowPart = *((DWORD *)(op + 16));
! 			op += 20;
! 		}
! 		else {
! 			/* Not Large Files */
! 			LOffset.HighPart = 0;
! 			LOffset.LowPart = *((DWORD *)(op + 2));
! 			LLength.HighPart = 0;
! 			LLength.LowPart = *((DWORD *)(op + 6));
! 			op += 10;
! 		}
! 		if (LargeIntegerNotEqualToZero(LOffset))
! 			continue;
! 		if (LargeIntegerLessThan(LOffset, scp-&gt;length))
! 			continue;
! 
! 		code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
! 				userp, &amp;req, &amp;lockp);
! 		if (code == CM_ERROR_WOULDBLOCK &amp;&amp; Timeout != 0) {
! 			/* Put on waiting list */
! 			waitingLock = malloc(sizeof(smb_waitingLock_t));
! 			waitingLock-&gt;vcp = vcp;
! 			waitingLock-&gt;inp = smb_CopyPacket(inp);
! 			waitingLock-&gt;outp = smb_CopyPacket(outp);
! 			waitingLock-&gt;timeRemaining = Timeout;
! 			waitingLock-&gt;lockp = lockp;
! 			lock_ObtainWrite(&amp;smb_globalLock);
! 			osi_QAdd((osi_queue_t **)&amp;smb_allWaitingLocks,
! 				 &amp;waitingLock-&gt;q);
! 			osi_Wakeup((long) &amp;smb_allWaitingLocks);
! 			lock_ReleaseWrite(&amp;smb_globalLock);
! 			/* don't send reply immediately */
! 			outp-&gt;flags |= SMB_PACKETFLAG_NOSEND;
! 		}
! 		if (code) break;
! 	}
  
! 	if (code) {
! 		/* release any locks acquired before the failure */
! 	}
! 	else
! 		smb_SetSMBDataLength(outp, 0);
! done:
! 	cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
! doneSync:
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	cm_ReleaseUser(userp);
! 	smb_ReleaseFID(fidp);
  
! 	return code;
  }
  
  long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	unsigned short fid;
      smb_fid_t *fidp;
      cm_scache_t *scp;
      long code = 0;
!     long searchTime;
      cm_user_t *userp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      fid = smb_GetSMBParm(inp, 0);
      fid = smb_ChainFID(fid, inp);
          
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
! 		return CM_ERROR_BADFD;
      }
          
      userp = smb_GetUser(vcp, inp);
--- 4470,4575 ----
  	op = smb_GetSMBData(inp, NULL);
  
  	for (i=0; i&lt;NumberOfUnlocks; i++) {
!             if (LockType &amp; 0x10) {
!                 /* Large Files */
!                 LOffset.HighPart = *((LONG *)(op + 4));
!                 LOffset.LowPart = *((DWORD *)(op + 8));
!                 LLength.HighPart = *((LONG *)(op + 12));
!                 LLength.LowPart = *((DWORD *)(op + 16));
!                 op += 20;
!             }
!             else {
!                 /* Not Large Files */
!                 LOffset.HighPart = 0;
!                 LOffset.LowPart = *((DWORD *)(op + 2));
!                 LLength.HighPart = 0;
!                 LLength.LowPart = *((DWORD *)(op + 6));
!                 op += 10;
!             }
!             if (LargeIntegerNotEqualToZero(LOffset))
!                 continue;
!             /* Do not check length -- length check done in cm_Unlock */
! 
!             code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &amp;req);
!             if (code) goto done;
! 	}       
  
  	for (i=0; i&lt;NumberOfLocks; i++) {
!             if (LockType &amp; 0x10) {
!                 /* Large Files */
!                 LOffset.HighPart = *((LONG *)(op + 4));
!                 LOffset.LowPart = *((DWORD *)(op + 8));
!                 LLength.HighPart = *((LONG *)(op + 12));
!                 LLength.LowPart = *((DWORD *)(op + 16));
!                 op += 20;
!             }
!             else {
!                 /* Not Large Files */
!                 LOffset.HighPart = 0;
!                 LOffset.LowPart = *((DWORD *)(op + 2));
!                 LLength.HighPart = 0;
!                 LLength.LowPart = *((DWORD *)(op + 6));
!                 op += 10;
!             }
!             if (LargeIntegerNotEqualToZero(LOffset))
!                 continue;
!             if (LargeIntegerLessThan(LOffset, scp-&gt;length))
!                 continue;
! 
!             code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
!                             userp, &amp;req, &amp;lockp);
!             if (code == CM_ERROR_WOULDBLOCK &amp;&amp; Timeout != 0) {
!                 /* Put on waiting list */
!                 waitingLock = malloc(sizeof(smb_waitingLock_t));
!                 waitingLock-&gt;vcp = vcp;
!                 waitingLock-&gt;inp = smb_CopyPacket(inp);
!                 waitingLock-&gt;outp = smb_CopyPacket(outp);
!                 waitingLock-&gt;timeRemaining = Timeout;
!                 waitingLock-&gt;lockp = lockp;
!                 lock_ObtainWrite(&amp;smb_globalLock);
!                 osi_QAdd((osi_queue_t **)&amp;smb_allWaitingLocks,
!                           &amp;waitingLock-&gt;q);
!                 osi_Wakeup((long) &amp;smb_allWaitingLocks);
!                 lock_ReleaseWrite(&amp;smb_globalLock);
!                 /* don't send reply immediately */
!                 outp-&gt;flags |= SMB_PACKETFLAG_NOSEND;
!             }
!             if (code) break;
! 	}       
  
!     if (code) {
!         /* release any locks acquired before the failure */
!     }
!     else
!         smb_SetSMBDataLength(outp, 0);
!   done:   
!     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
!   doneSync:
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     cm_ReleaseUser(userp);
!     smb_ReleaseFID(fidp);
  
!     return code;
  }
  
  long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     unsigned short fid;
      smb_fid_t *fidp;
      cm_scache_t *scp;
      long code = 0;
!     time_t searchTime;
      cm_user_t *userp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      fid = smb_GetSMBParm(inp, 0);
      fid = smb_ChainFID(fid, inp);
          
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
!         return CM_ERROR_BADFD;
      }
          
      userp = smb_GetUser(vcp, inp);
***************
*** 4477,4492 ****
      scp = fidp-&gt;scp;
          
      /* otherwise, stat the file */
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
      code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! 	if (code) goto done;
  
! 	/* decode times.  We need a search time, but the response to this
       * call provides the date first, not the time, as returned in the
       * searchTime variable.  So we take the high-order bits first.
       */
! 	smb_SearchTimeFromUnixTime(&amp;searchTime, scp-&gt;clientModTime);
      smb_SetSMBParm(outp, 0, (searchTime &gt;&gt; 16) &amp; 0xffff);	/* ctime */
      smb_SetSMBParm(outp, 1, searchTime &amp; 0xffff);
      smb_SetSMBParm(outp, 2, (searchTime &gt;&gt; 16) &amp; 0xffff);	/* atime */
--- 4577,4592 ----
      scp = fidp-&gt;scp;
          
      /* otherwise, stat the file */
!     lock_ObtainMutex(&amp;scp-&gt;mx);
      code = cm_SyncOp(scp, NULL, userp, &amp;req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code) goto done;
  
!     /* decode times.  We need a search time, but the response to this
       * call provides the date first, not the time, as returned in the
       * searchTime variable.  So we take the high-order bits first.
       */
!     smb_SearchTimeFromUnixTime(&amp;searchTime, scp-&gt;clientModTime);
      smb_SetSMBParm(outp, 0, (searchTime &gt;&gt; 16) &amp; 0xffff);	/* ctime */
      smb_SetSMBParm(outp, 1, searchTime &amp; 0xffff);
      smb_SetSMBParm(outp, 2, (searchTime &gt;&gt; 16) &amp; 0xffff);	/* atime */
***************
*** 4500,4506 ****
      smb_SetSMBParm(outp, 8, scp-&gt;length.LowPart &amp; 0xffff);		/* alloc size */
      smb_SetSMBParm(outp, 9, (scp-&gt;length.LowPart &gt;&gt; 16) &amp; 0xffff);
  
! 	/* file attribute */
      smb_SetSMBParm(outp, 10, smb_Attributes(scp));
          
      /* and finalize stuff */
--- 4600,4606 ----
      smb_SetSMBParm(outp, 8, scp-&gt;length.LowPart &amp; 0xffff);		/* alloc size */
      smb_SetSMBParm(outp, 9, (scp-&gt;length.LowPart &gt;&gt; 16) &amp; 0xffff);
  
!     /* file attribute */
      smb_SetSMBParm(outp, 10, smb_Attributes(scp));
          
      /* and finalize stuff */
***************
*** 4508,4553 ****
      code = 0;
  
    done:
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	cm_ReleaseUser(userp);
! 	smb_ReleaseFID(fidp);
! 	return code;
! }
  
  long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	unsigned short fid;
      smb_fid_t *fidp;
      cm_scache_t *scp;
      long code = 0;
! 	long searchTime;
!     long unixTime;
      cm_user_t *userp;
      cm_attr_t attrs;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      fid = smb_GetSMBParm(inp, 0);
      fid = smb_ChainFID(fid, inp);
          
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
! 		return CM_ERROR_BADFD;
      }
          
      userp = smb_GetUser(vcp, inp);
          
      scp = fidp-&gt;scp;
          
! 	/* now prepare to call cm_setattr.  This message only sets various times,
       * and AFS only implements mtime, and we'll set the mtime if that's
       * requested.  The others we'll ignore.
       */
! 	searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) &lt;&lt; 16);
          
      if (searchTime != 0) {
! 		smb_UnixTimeFromSearchTime(&amp;unixTime, searchTime);
  
          if ( unixTime != -1 ) {
              attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
--- 4608,4653 ----
      code = 0;
  
    done:
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     cm_ReleaseUser(userp);
!     smb_ReleaseFID(fidp);
!     return code;
! }       
  
  long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     unsigned short fid;
      smb_fid_t *fidp;
      cm_scache_t *scp;
      long code = 0;
!     time_t searchTime;
!     time_t unixTime;
      cm_user_t *userp;
      cm_attr_t attrs;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      fid = smb_GetSMBParm(inp, 0);
      fid = smb_ChainFID(fid, inp);
          
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp || (fidp-&gt;flags &amp; SMB_FID_IOCTL)) {
!         return CM_ERROR_BADFD;
      }
          
      userp = smb_GetUser(vcp, inp);
          
      scp = fidp-&gt;scp;
          
!     /* now prepare to call cm_setattr.  This message only sets various times,
       * and AFS only implements mtime, and we'll set the mtime if that's
       * requested.  The others we'll ignore.
       */
!     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) &lt;&lt; 16);
          
      if (searchTime != 0) {
!         smb_UnixTimeFromSearchTime(&amp;unixTime, searchTime);
  
          if ( unixTime != -1 ) {
              attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
***************
*** 4561,4575 ****
      }
      else code = 0;
  
! 	cm_ReleaseUser(userp);
! 	smb_ReleaseFID(fidp);
! 	return code;
  }
  
  
  long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	osi_hyper_t offset;
      long count, finalCount;
      unsigned short fd;
      smb_fid_t *fidp;
--- 4661,4675 ----
      }
      else code = 0;
  
!     cm_ReleaseUser(userp);
!     smb_ReleaseFID(fidp);
!     return code;
  }
  
  
  long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     osi_hyper_t offset;
      long count, finalCount;
      unsigned short fd;
      smb_fid_t *fidp;
***************
*** 4585,4619 ****
      osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
               fd, offset.LowPart, count);
          
! 	fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp) {
! 		return CM_ERROR_BADFD;
      }
! 	/* set inp-&gt;fid so that later read calls in same msg can find fid */
      inp-&gt;fid = fd;
  
      if (fidp-&gt;flags &amp; SMB_FID_IOCTL) {
! 		return smb_IoctlV3Read(fidp, vcp, inp, outp);
      }
          
! 	userp = smb_GetUser(vcp, inp);
  
! 	/* 0 and 1 are reserved for request chaining, were setup by our caller,
       * and will be further filled in after we return.
       */
      smb_SetSMBParm(outp, 2, 0);	/* remaining bytes, for pipes */
      smb_SetSMBParm(outp, 3, 0);	/* resvd */
      smb_SetSMBParm(outp, 4, 0);	/* resvd */
! 	smb_SetSMBParm(outp, 5, count);	/* # of bytes we're going to read */
      /* fill in #6 when we have all the parameters' space reserved */
      smb_SetSMBParm(outp, 7, 0);	/* resv'd */
      smb_SetSMBParm(outp, 8, 0);	/* resv'd */
      smb_SetSMBParm(outp, 9, 0);	/* resv'd */
      smb_SetSMBParm(outp, 10, 0);	/* resv'd */
! 	smb_SetSMBParm(outp, 11, 0);	/* reserved */
  
! 	/* get op ptr after putting in the parms, since otherwise we don't
       * know where the data really is.
       */
      op = smb_GetSMBData(outp, NULL);
--- 4685,4719 ----
      osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
               fd, offset.LowPart, count);
          
!     fd = smb_ChainFID(fd, inp);
      fidp = smb_FindFID(vcp, fd, 0);
      if (!fidp) {
!         return CM_ERROR_BADFD;
      }
!     /* set inp-&gt;fid so that later read calls in same msg can find fid */
      inp-&gt;fid = fd;
  
      if (fidp-&gt;flags &amp; SMB_FID_IOCTL) {
!         return smb_IoctlV3Read(fidp, vcp, inp, outp);
      }
          
!     userp = smb_GetUser(vcp, inp);
  
!     /* 0 and 1 are reserved for request chaining, were setup by our caller,
       * and will be further filled in after we return.
       */
      smb_SetSMBParm(outp, 2, 0);	/* remaining bytes, for pipes */
      smb_SetSMBParm(outp, 3, 0);	/* resvd */
      smb_SetSMBParm(outp, 4, 0);	/* resvd */
!     smb_SetSMBParm(outp, 5, count);	/* # of bytes we're going to read */
      /* fill in #6 when we have all the parameters' space reserved */
      smb_SetSMBParm(outp, 7, 0);	/* resv'd */
      smb_SetSMBParm(outp, 8, 0);	/* resv'd */
      smb_SetSMBParm(outp, 9, 0);	/* resv'd */
      smb_SetSMBParm(outp, 10, 0);	/* resv'd */
!     smb_SetSMBParm(outp, 11, 0);	/* reserved */
  
!     /* get op ptr after putting in the parms, since otherwise we don't
       * know where the data really is.
       */
      op = smb_GetSMBData(outp, NULL);
***************
*** 4621,4638 ****
      /* now fill in offset from start of SMB header to first data byte (to op) */
      smb_SetSMBParm(outp, 6, ((int) (op - outp-&gt;data)));
  
! 	/* set the packet data length the count of the # of bytes */
      smb_SetSMBDataLength(outp, count);
  
  #ifndef DJGPP
! 	code = smb_ReadData(fidp, &amp;offset, count, op, userp, &amp;finalCount);
  #else /* DJGPP */
! 	code = smb_ReadData(fidp, &amp;offset, count, op, userp, &amp;finalCount, FALSE);
  #endif /* !DJGPP */
  
! 	/* fix some things up */
! 	smb_SetSMBParm(outp, 5, finalCount);
! 	smb_SetSMBDataLength(outp, finalCount);
  
      smb_ReleaseFID(fidp);
  
--- 4721,4738 ----
      /* now fill in offset from start of SMB header to first data byte (to op) */
      smb_SetSMBParm(outp, 6, ((int) (op - outp-&gt;data)));
  
!     /* set the packet data length the count of the # of bytes */
      smb_SetSMBDataLength(outp, count);
  
  #ifndef DJGPP
!     code = smb_ReadData(fidp, &amp;offset, count, op, userp, &amp;finalCount);
  #else /* DJGPP */
!     code = smb_ReadData(fidp, &amp;offset, count, op, userp, &amp;finalCount, FALSE);
  #endif /* !DJGPP */
  
!     /* fix some things up */
!     smb_SetSMBParm(outp, 5, finalCount);
!     smb_SetSMBDataLength(outp, finalCount);
  
      smb_ReleaseFID(fidp);
  
***************
*** 4642,4787 ****
          
  /*
   * Values for createDisp, copied from NTDDK.H
-  *
-  *  FILE_SUPERSEDE	0	(???)
-  *  FILE_OPEN		1	(open)
-  *  FILE_CREATE		2	(exclusive)
-  *  FILE_OPEN_IF	3	(non-exclusive)
-  *  FILE_OVERWRITE	4	(open &amp; truncate, but do not create)
-  *  FILE_OVERWRITE_IF	5	(open &amp; truncate, or create)
   */
  
  long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	char *pathp, *realPathp;
! 	long code = 0;
! 	cm_space_t *spacep;
! 	cm_user_t *userp;
! 	cm_scache_t *dscp;		/* parent dir */
! 	cm_scache_t *scp;		/* file to create or open */
! 	cm_attr_t setAttr;
! 	char *lastNamep;
      char *treeStartp;
! 	unsigned short nameLength;
! 	unsigned int flags;
! 	unsigned int requestOpLock;
! 	unsigned int requestBatchOpLock;
! 	unsigned int mustBeDir;
      unsigned int treeCreate;
! 	int realDirFlag;
! 	unsigned int desiredAccess;
! 	unsigned int extAttributes;
! 	unsigned int createDisp;
! 	unsigned int createOptions;
! 	int initialModeBits;
! 	unsigned short baseFid;
! 	smb_fid_t *baseFidp;
! 	smb_fid_t *fidp;
! 	cm_scache_t *baseDirp;
! 	unsigned short openAction;
! 	int parmSlot;
! 	long fidflags;
! 	FILETIME ft;
! 	LARGE_INTEGER sz;
! 	char *tidPathp;
! 	BOOL foundscp;
! 	cm_req_t req;
  
! 	cm_InitReq(&amp;req);
  
      treeCreate = FALSE;
! 	foundscp = FALSE;
! 	scp = NULL;
  
! 	nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
! 	flags = smb_GetSMBOffsetParm(inp, 3, 1)
! 		  | (smb_GetSMBOffsetParm(inp, 4, 1) &lt;&lt; 16);
! 	requestOpLock = flags &amp; 0x02;
! 	requestBatchOpLock = flags &amp; 0x04;
! 	mustBeDir = flags &amp; 0x08;
! 
! 	/*
! 	 * Why all of a sudden 32-bit FID?
! 	 * We will reject all bits higher than 16.
! 	 */
! 	if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
! 		return CM_ERROR_INVAL;
! 	baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
! 	desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
! 			  | (smb_GetSMBOffsetParm(inp, 8, 1) &lt;&lt; 16);
! 	extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
! 			  | (smb_GetSMBOffsetParm(inp, 14, 1) &lt;&lt; 16);
! 	createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
! 			| (smb_GetSMBOffsetParm(inp, 18, 1) &lt;&lt; 16);
! 	createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
! 			  | (smb_GetSMBOffsetParm(inp, 20, 1) &lt;&lt; 16);
  
! 	/* mustBeDir is never set; createOptions directory bit seems to be
       * more important
! 	 */
! 	if (createOptions &amp; 1)
! 		realDirFlag = 1;
! 	else if (createOptions &amp; 0x40)
! 		realDirFlag = 0;
! 	else
! 		realDirFlag = -1;
! 
! 	/*
! 	 * compute initial mode bits based on read-only flag in
! 	 * extended attributes
! 	 */
! 	initialModeBits = 0666;
! 	if (extAttributes &amp; 1) initialModeBits &amp;= ~0222;
  
! 	pathp = smb_GetSMBData(inp, NULL);
! 	/* Sometimes path is not null-terminated, so we make a copy. */
! 	realPathp = malloc(nameLength+1);
! 	memcpy(realPathp, pathp, nameLength);
! 	realPathp[nameLength] = 0;
  
! 	spacep = inp-&gt;spacep;
! 	smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, realPathp);
  
      osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
!     osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
!     osi_Log1(smb_logp,"NTCreateX lastNamep=[%s]",osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
  
! 	if (lastNamep &amp;&amp; strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
! 		/* special case magic file name for receiving IOCTL requests
! 		 * (since IOCTL calls themselves aren't getting through).
! 		 */
! 		fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
! 		smb_SetupIoctlFid(fidp, spacep);
! 		osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp-&gt;fid);
! 
! 		/* set inp-&gt;fid so that later read calls in same msg can find fid */
! 		inp-&gt;fid = fidp-&gt;fid;
! 
! 		/* out parms */
! 		parmSlot = 2;
! 		smb_SetSMBParmByte(outp, parmSlot, 0);	/* oplock */
! 		smb_SetSMBParm(outp, parmSlot, fidp-&gt;fid); parmSlot++;
! 		smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
! 		/* times */
! 		memset(&amp;ft, 0, sizeof(ft));
! 		smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
! 		smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
! 		smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
! 		smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
! 		smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
! 		sz.HighPart = 0x7fff; sz.LowPart = 0;
! 		smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;sz); parmSlot += 4; /* alen */
! 		smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;sz); parmSlot += 4; /* len */
! 		smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* filetype */
! 		smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* dev state */
! 		smb_SetSMBParmByte(outp, parmSlot, 0);	/* is a dir? */
! 		smb_SetSMBDataLength(outp, 0);
! 
! 		/* clean up fid reference */
! 		smb_ReleaseFID(fidp);
! 		free(realPathp);
! 		return 0;
! 	}
  
  #ifdef DEBUG_VERBOSE
      {
--- 4742,4888 ----
          
  /*
   * Values for createDisp, copied from NTDDK.H
   */
+ #define  FILE_SUPERSEDE	0	// (???)
+ #define  FILE_OPEN     	1	// (open)
+ #define  FILE_CREATE	2	// (exclusive)
+ #define  FILE_OPEN_IF	3	// (non-exclusive)
+ #define  FILE_OVERWRITE	4	// (open &amp; truncate, but do not create)
+ #define  FILE_OVERWRITE_IF 5	// (open &amp; truncate, or create)
  
  long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     char *pathp, *realPathp;
!     long code = 0;
!     cm_space_t *spacep;
!     cm_user_t *userp;
!     cm_scache_t *dscp;		/* parent dir */
!     cm_scache_t *scp;		/* file to create or open */
!     cm_scache_t *targetScp;	/* if scp is a symlink */
!     cm_attr_t setAttr;
!     char *lastNamep;
      char *treeStartp;
!     unsigned short nameLength;
!     unsigned int flags;
!     unsigned int requestOpLock;
!     unsigned int requestBatchOpLock;
!     unsigned int mustBeDir;
      unsigned int treeCreate;
!     int realDirFlag;
!     unsigned int desiredAccess;
!     unsigned int extAttributes;
!     unsigned int createDisp;
!     unsigned int createOptions;
!     int initialModeBits;
!     unsigned short baseFid;
!     smb_fid_t *baseFidp;
!     smb_fid_t *fidp;
!     cm_scache_t *baseDirp;
!     unsigned short openAction;
!     int parmSlot;
!     long fidflags;
!     FILETIME ft;
!     LARGE_INTEGER sz;
!     char *tidPathp;
!     BOOL foundscp;
!     cm_req_t req;
  
!     cm_InitReq(&amp;req);
  
      treeCreate = FALSE;
!     foundscp = FALSE;
!     scp = NULL;
  
!     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
!     flags = smb_GetSMBOffsetParm(inp, 3, 1)
!         | (smb_GetSMBOffsetParm(inp, 4, 1) &lt;&lt; 16);
!     requestOpLock = flags &amp; 0x02;
!     requestBatchOpLock = flags &amp; 0x04;
!     mustBeDir = flags &amp; 0x08;
! 
!     /*
!      * Why all of a sudden 32-bit FID?
!      * We will reject all bits higher than 16.
!      */
!     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
!         return CM_ERROR_INVAL;
!     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
!     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
!         | (smb_GetSMBOffsetParm(inp, 8, 1) &lt;&lt; 16);
!     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
!         | (smb_GetSMBOffsetParm(inp, 14, 1) &lt;&lt; 16);
!     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
!         | (smb_GetSMBOffsetParm(inp, 18, 1) &lt;&lt; 16);
!     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
!         | (smb_GetSMBOffsetParm(inp, 20, 1) &lt;&lt; 16);
  
!     /* mustBeDir is never set; createOptions directory bit seems to be
       * more important
!      */
!     if (createOptions &amp; 1)
!         realDirFlag = 1;
!     else if (createOptions &amp; 0x40)
!         realDirFlag = 0;
!     else
!         realDirFlag = -1;
  
!     /*
!      * compute initial mode bits based on read-only flag in
!      * extended attributes
!      */
!     initialModeBits = 0666;
!     if (extAttributes &amp; 1) 
!         initialModeBits &amp;= ~0222;
  
!     pathp = smb_GetSMBData(inp, NULL);
!     /* Sometimes path is not null-terminated, so we make a copy. */
!     realPathp = malloc(nameLength+1);
!     memcpy(realPathp, pathp, nameLength);
!     realPathp[nameLength] = 0;
! 
!     spacep = inp-&gt;spacep;
!     smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, realPathp);
  
      osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
!     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
!     osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
  
!     if (lastNamep &amp;&amp; strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
!         /* special case magic file name for receiving IOCTL requests
!          * (since IOCTL calls themselves aren't getting through).
!          */
!         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
!         smb_SetupIoctlFid(fidp, spacep);
!         osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp-&gt;fid);
! 
!         /* set inp-&gt;fid so that later read calls in same msg can find fid */
!         inp-&gt;fid = fidp-&gt;fid;
! 
!         /* out parms */
!         parmSlot = 2;
!         smb_SetSMBParmByte(outp, parmSlot, 0);	/* oplock */
!         smb_SetSMBParm(outp, parmSlot, fidp-&gt;fid); parmSlot++;
!         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
!         /* times */
!         memset(&amp;ft, 0, sizeof(ft));
!         smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
!         smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
!         smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
!         smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
!         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
!         sz.HighPart = 0x7fff; sz.LowPart = 0;
!         smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;sz); parmSlot += 4; /* alen */
!         smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;sz); parmSlot += 4; /* len */
!         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* filetype */
!         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* dev state */
!         smb_SetSMBParmByte(outp, parmSlot, 0);	/* is a dir? */
!         smb_SetSMBDataLength(outp, 0);
! 
!         /* clean up fid reference */
!         smb_ReleaseFID(fidp);
!         free(realPathp);
!         return 0;
!     }
  
  #ifdef DEBUG_VERBOSE
      {
***************
*** 4799,4844 ****
      	return CM_ERROR_INVAL;
      }
  
! 	if (baseFid == 0) {
! 		baseDirp = cm_rootSCachep;
! 		code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!         if(code == CM_ERROR_TIDIPC) {
              /* Attempt to use a TID allocated for IPC.  The client
!                is probably looking for DCE RPC end points which we
!                don't support. */
              osi_Log0(smb_logp, "NTCreateX received IPC TID");
              free(realPathp);
              cm_ReleaseUser(userp);
              return CM_ERROR_NOSUCHFILE;
          }
! 	}
! 	else {
          baseFidp = smb_FindFID(vcp, baseFid, 0);
          if (!baseFidp) {
!         	osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
!         	free(realPathp);
!         	cm_ReleaseUser(userp);
!         	return CM_ERROR_INVAL;
!         }
! 		baseDirp = baseFidp-&gt;scp;
! 		tidPathp = NULL;
! 	}
  
      osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
! 	
      /* compute open mode */
! 	fidflags = 0;
! 	if (desiredAccess &amp; DELETE)
! 		fidflags |= SMB_FID_OPENDELETE;
! 	if (desiredAccess &amp; AFS_ACCESS_READ)
! 		fidflags |= SMB_FID_OPENREAD;
! 	if (desiredAccess &amp; AFS_ACCESS_WRITE)
! 		fidflags |= SMB_FID_OPENWRITE;
  
! 	dscp = NULL;
! 	code = 0;
      /* For an exclusive create, we want to do a case sensitive match for the last component. */
!     if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
          code = cm_NameI(baseDirp, spacep-&gt;data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &amp;req, &amp;dscp);
          if (code == 0) {
--- 4900,4947 ----
      	return CM_ERROR_INVAL;
      }
  
!     if (baseFid == 0) {
!         baseDirp = cm_rootSCachep;
!         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
!         if (code == CM_ERROR_TIDIPC) {
              /* Attempt to use a TID allocated for IPC.  The client
!              * is probably looking for DCE RPC end points which we
!              * don't support. */
              osi_Log0(smb_logp, "NTCreateX received IPC TID");
              free(realPathp);
              cm_ReleaseUser(userp);
              return CM_ERROR_NOSUCHFILE;
          }
!     }
!     else {
          baseFidp = smb_FindFID(vcp, baseFid, 0);
          if (!baseFidp) {
!             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
!             free(realPathp);
!             cm_ReleaseUser(userp);
!             return CM_ERROR_INVAL;
!         }       
!         baseDirp = baseFidp-&gt;scp;
!         tidPathp = NULL;
!     }
  
      osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
! 
      /* compute open mode */
!     fidflags = 0;
!     if (desiredAccess &amp; DELETE)
!         fidflags |= SMB_FID_OPENDELETE;
!     if (desiredAccess &amp; AFS_ACCESS_READ)
!         fidflags |= SMB_FID_OPENREAD;
!     if (desiredAccess &amp; AFS_ACCESS_WRITE)
!         fidflags |= SMB_FID_OPENWRITE;
  
!     dscp = NULL;
!     code = 0;
      /* For an exclusive create, we want to do a case sensitive match for the last component. */
!     if ( createDisp == FILE_CREATE || 
!          createDisp == FILE_OVERWRITE ||
!          createDisp == FILE_OVERWRITE_IF) {
          code = cm_NameI(baseDirp, spacep-&gt;data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &amp;req, &amp;dscp);
          if (code == 0) {
***************
*** 4848,4854 ****
                  code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
                                   CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &amp;req, &amp;scp);
                  if (code == 0 &amp;&amp; realDirFlag == 1) {
! 					cm_ReleaseSCache(scp);
                      cm_ReleaseSCache(dscp);
                      cm_ReleaseUser(userp);
                      free(realPathp);
--- 4951,4957 ----
                  code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
                                   CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &amp;req, &amp;scp);
                  if (code == 0 &amp;&amp; realDirFlag == 1) {
!                     cm_ReleaseSCache(scp);
                      cm_ReleaseSCache(dscp);
                      cm_ReleaseUser(userp);
                      free(realPathp);
***************
*** 4862,4871 ****
                          userp, tidPathp, &amp;req, &amp;scp);
      }
      if (code == 0) 
! 		foundscp = TRUE;
  
! 	if (!foundscp || (fidflags &amp; (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
! 		/* look up parent directory */
          /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
           * the immediate parent.  We have to work our way up realPathp until we hit something that we
           * recognize.
--- 4965,4974 ----
                          userp, tidPathp, &amp;req, &amp;scp);
      }
      if (code == 0) 
!         foundscp = TRUE;
  
!     if (!foundscp || (fidflags &amp; (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
!         /* look up parent directory */
          /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
           * the immediate parent.  We have to work our way up realPathp until we hit something that we
           * recognize.
***************
*** 4881,4887 ****
  
                  if (code &amp;&amp; 
                       (tp = strrchr(spacep-&gt;data,'\\')) &amp;&amp;
!                      (createDisp == 2) &amp;&amp;
                       (realDirFlag == 1)) {
                      *tp++ = 0;
                      treeCreate = TRUE;
--- 4984,4990 ----
  
                  if (code &amp;&amp; 
                       (tp = strrchr(spacep-&gt;data,'\\')) &amp;&amp;
!                      (createDisp == FILE_CREATE) &amp;&amp;
                       (realDirFlag == 1)) {
                      *tp++ = 0;
                      treeCreate = TRUE;
***************
*** 4902,4908 ****
              code = 0;
  
          if (baseFid != 0) 
! 			smb_ReleaseFID(baseFidp);
  
          if (code) {
              osi_Log0(smb_logp,"NTCreateX parent not found");
--- 5005,5011 ----
              code = 0;
  
          if (baseFid != 0) 
!             smb_ReleaseFID(baseFidp);
  
          if (code) {
              osi_Log0(smb_logp,"NTCreateX parent not found");
***************
*** 4932,4956 ****
          }
  
          if (!foundscp &amp;&amp; !treeCreate) {
!             if (createDisp == 2 || createDisp == 4)
                  code = cm_Lookup(dscp, lastNamep,
                                    CM_FLAG_FOLLOW, userp, &amp;req, &amp;scp);
!             else
                  code = cm_Lookup(dscp, lastNamep,
                                   CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                                   userp, &amp;req, &amp;scp);
! 			if (code &amp;&amp; code != CM_ERROR_NOSUCHFILE) {
! 				cm_ReleaseSCache(dscp);
! 				cm_ReleaseUser(userp);
! 				free(realPathp);
! 				return code;
! 			}
! 		}
! 	}
! 	else {
! 		if (baseFid != 0) 
! 			smb_ReleaseFID(baseFidp);
! 	}
  
  	/* if we get here, if code is 0, the file exists and is represented by
  	 * scp.  Otherwise, we have to create it.  The dir may be represented
--- 5035,5063 ----
          }
  
          if (!foundscp &amp;&amp; !treeCreate) {
!             if ( createDisp == FILE_CREATE || 
!                  createDisp == FILE_OVERWRITE ||
!                  createDisp == FILE_OVERWRITE_IF) 
!             {
                  code = cm_Lookup(dscp, lastNamep,
                                    CM_FLAG_FOLLOW, userp, &amp;req, &amp;scp);
!             } else {
                  code = cm_Lookup(dscp, lastNamep,
                                   CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                                   userp, &amp;req, &amp;scp);
!             }
!             if (code &amp;&amp; code != CM_ERROR_NOSUCHFILE) {
!                 cm_ReleaseSCache(dscp);
!                 cm_ReleaseUser(userp);
!                 free(realPathp);
!                 return code;
!             }
!         }
!     }
!     else {
!         if (baseFid != 0) 
!             smb_ReleaseFID(baseFidp);
! 	}       
  
  	/* if we get here, if code is 0, the file exists and is represented by
  	 * scp.  Otherwise, we have to create it.  The dir may be represented
***************
*** 4958,5186 ****
  	 * scp is NULL.
  	 */
  	if (code == 0 &amp;&amp; !treeCreate) {
! 		code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
! 				      &amp;req);
! 		if (code) {
! 			if (dscp) cm_ReleaseSCache(dscp);
! 			cm_ReleaseSCache(scp);
! 			cm_ReleaseUser(userp);
! 			free(realPathp);
! 			return code;
! 		}
! 
! 		if (createDisp == 2) {
! 			/* oops, file shouldn't be there */
! 			if (dscp) cm_ReleaseSCache(dscp);
! 			cm_ReleaseSCache(scp);
! 			cm_ReleaseUser(userp);
! 			free(realPathp);
! 			return CM_ERROR_EXISTS;
! 		}
! 
! 		if (createDisp == 4
! 		    || createDisp == 5) {
! 			setAttr.mask = CM_ATTRMASK_LENGTH;
! 			setAttr.length.LowPart = 0;
! 			setAttr.length.HighPart = 0;
! 			code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
! 			openAction = 3;	/* truncated existing file */
! 		}
! 		else openAction = 1;	/* found existing file */
! 	}
! 	else if (createDisp == 1 || createDisp == 4) {
! 		/* don't create if not found */
! 		if (dscp) cm_ReleaseSCache(dscp);
! 		cm_ReleaseUser(userp);
! 		free(realPathp);
! 		return CM_ERROR_NOSUCHFILE;
! 	}
  	else if (realDirFlag == 0 || realDirFlag == -1) {
! 		osi_assert(dscp != NULL);
! 		osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
! 				osi_LogSaveString(smb_logp, lastNamep));
! 		openAction = 2;		/* created file */
! 		setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
! 		setAttr.clientModTime = time(NULL);
! 		code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
! 				 &amp;req);
! 		if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 			smb_NotifyChange(FILE_ACTION_ADDED,
! 					 FILE_NOTIFY_CHANGE_FILE_NAME,
! 					 dscp, lastNamep, NULL, TRUE);
! 		if (code == CM_ERROR_EXISTS &amp;&amp; createDisp != 2) {
! 			/* Not an exclusive create, and someone else tried
! 			 * creating it already, then we open it anyway.  We
! 			 * don't bother retrying after this, since if this next
! 			 * fails, that means that the file was deleted after we
! 			 * started this call.
! 			 */
! 			code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
! 					 userp, &amp;req, &amp;scp);
! 			if (code == 0) {
! 				if (createDisp == 5) {
! 					setAttr.mask = CM_ATTRMASK_LENGTH;
! 					setAttr.length.LowPart = 0;
! 					setAttr.length.HighPart = 0;
! 					code = cm_SetAttr(scp, &amp;setAttr, userp,
! 							  &amp;req);
! 				}
! 			}	/* lookup succeeded */
! 		}
! 	}
  	else {
!         char *tp, *pp;
!         char *cp; /* This component */
!         int clen = 0; /* length of component */
!         cm_scache_t *tscp;
!         int isLast = 0;
  		
!         /* create directory */
! 		if ( !treeCreate ) treeStartp = lastNamep;
!         osi_assert(dscp != NULL);
!         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
! 				osi_LogSaveString(smb_logp, treeStartp));
! 		openAction = 2;		/* created directory */
  
! 		setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
! 		setAttr.clientModTime = time(NULL);
  		
! 		pp = treeStartp;
! 		cp = spacep-&gt;data;
! 		tscp = dscp;
! 
! 		while (pp &amp;&amp; *pp) {
! 			tp = strchr(pp, '\\');
! 			if (!tp) {
! 				strcpy(cp,pp);
!                 clen = strlen(cp);
! 				isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
! 			}
! 			else {
! 				clen = tp - pp;
! 				strncpy(cp,pp,clen);
! 				*(cp + clen) = 0;
! 				tp++;
! 			}
! 			pp = tp;
! 
! 			if (clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
! 
! 			/* cp is the next component to be created. */
! 			code = cm_MakeDir(tscp, cp, 0, &amp;setAttr, userp, &amp;req);
! 			if (code == 0 &amp;&amp; (tscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 				smb_NotifyChange(FILE_ACTION_ADDED,
! 				FILE_NOTIFY_CHANGE_DIR_NAME,
! 				tscp, cp, NULL, TRUE);
! 			if (code == 0 || 
! 				(code == CM_ERROR_EXISTS &amp;&amp; createDisp != 2)) {
! 					/* Not an exclusive create, and someone else tried
! 					* creating it already, then we open it anyway.  We
! 					* don't bother retrying after this, since if this next
! 					* fails, that means that the file was deleted after we
! 					* started this call.
! 					*/
! 					code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
! 						userp, &amp;req, &amp;scp);
! 				}
! 			if (code) break;
! 
! 			if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
! 				cm_ReleaseSCache(tscp);
! 				tscp = scp; /* Newly created directory will be next parent */
! 			}
! 		}
! 
! 		/* 
! 		if we get here and code == 0, then scp is the last directory created, and tscp is the
! 		parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
! 		*/
! 		dscp = tscp;
! 	}
  
! 	if (code) {
! 		/* something went wrong creating or truncating the file */
! 		if (scp) cm_ReleaseSCache(scp);
!         if (dscp) cm_ReleaseSCache(dscp);
! 		cm_ReleaseUser(userp);
! 		free(realPathp);
! 		return code;
  	}
  
! 	/* make sure we have file vs. dir right (only applies for single component case) */
! 	if (realDirFlag == 0 &amp;&amp; scp-&gt;fileType != CM_SCACHETYPE_FILE) {
! 		cm_ReleaseSCache(scp);
          if (dscp) cm_ReleaseSCache(dscp);
! 		cm_ReleaseUser(userp);
! 		free(realPathp);
! 		return CM_ERROR_ISDIR;
! 	}
      /* (only applies to single component case) */
! 	if (realDirFlag == 1 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_FILE) {
! 		cm_ReleaseSCache(scp);
          if (dscp) cm_ReleaseSCache(dscp);
! 		cm_ReleaseUser(userp);
! 		free(realPathp);
! 		return CM_ERROR_NOTDIR;
! 	}
  
! 	/* open the file itself */
! 	fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
! 	osi_assert(fidp);
! 	/* save a pointer to the vnode */
! 	fidp-&gt;scp = scp;
! 
! 	fidp-&gt;flags = fidflags;
! 
! 	/* save parent dir and pathname for delete or change notification */
! 	if (fidflags &amp; (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
! 		fidp-&gt;flags |= SMB_FID_NTOPEN;
! 		fidp-&gt;NTopen_dscp = dscp;
! 		cm_HoldSCache(dscp);
! 		fidp-&gt;NTopen_pathp = strdup(lastNamep);
! 	}
! 	fidp-&gt;NTopen_wholepathp = realPathp;
  
! 	/* we don't need this any longer */
! 	if (dscp) cm_ReleaseSCache(dscp);
! 	cm_Open(scp, 0, userp);
! 
! 	/* set inp-&gt;fid so that later read calls in same msg can find fid */
! 	inp-&gt;fid = fidp-&gt;fid;
! 
! 	/* out parms */
! 	parmSlot = 2;
! 	lock_ObtainMutex(&amp;scp-&gt;mx);
! 	smb_SetSMBParmByte(outp, parmSlot, 0);	/* oplock */
! 	smb_SetSMBParm(outp, parmSlot, fidp-&gt;fid); parmSlot++;
! 	smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
! 	smb_LargeSearchTimeFromUnixTime(&amp;ft, scp-&gt;clientModTime);
! 	smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
! 	smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
! 	smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
! 	smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
! 	smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
! 						parmSlot += 2;
! 	smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;scp-&gt;length); parmSlot += 4;
! 	smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;scp-&gt;length); parmSlot += 4;
! 	smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* filetype */
! 	smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* dev state */
! 	smb_SetSMBParmByte(outp, parmSlot,
! 		scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
! 	lock_ReleaseMutex(&amp;scp-&gt;mx);
! 	smb_SetSMBDataLength(outp, 0);
  
! 	osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp-&gt;fid,
! 		 osi_LogSaveString(smb_logp, realPathp));
  
! 	smb_ReleaseFID(fidp);
  
! 	cm_ReleaseUser(userp);
  
      /* Can't free realPathp if we get here since fidp-&gt;NTopen_wholepathp is pointing there */
  
! 	/* leave scp held since we put it in fidp-&gt;scp */
! 	return 0;
! }
  
  /*
   * A lot of stuff copied verbatim from NT Create&amp;X to NT Tran Create.
--- 5065,5347 ----
  	 * scp is NULL.
  	 */
  	if (code == 0 &amp;&amp; !treeCreate) {
!             if (createDisp == FILE_CREATE) {
!                 /* oops, file shouldn't be there */
!                 if (dscp) cm_ReleaseSCache(dscp);
!                 cm_ReleaseSCache(scp);
!                 cm_ReleaseUser(userp);
!                 free(realPathp);
!                 return CM_ERROR_EXISTS;
!             }
! 
!             if ( createDisp == FILE_OVERWRITE || 
!                  createDisp == FILE_OVERWRITE_IF) {
!                 setAttr.mask = CM_ATTRMASK_LENGTH;
!                 setAttr.length.LowPart = 0;
!                 setAttr.length.HighPart = 0;
!                 /* now watch for a symlink */
!                 code = 0;
!                 while (code == 0 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!                     targetScp = 0;
!                     code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, &amp;req);
!                     if (code == 0) {
!                         /* we have a more accurate file to use (the
!                         * target of the symbolic link).  Otherwise,
!                         * we'll just use the symlink anyway.
!                         */
!                         osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                                   scp, targetScp);
!                         cm_ReleaseSCache(scp);
!                         scp = targetScp;
!                     }
!                 }
!                 code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
!                 openAction = 3;	/* truncated existing file */
!             }
!             else 
!                 openAction = 1;	/* found existing file */
! 
!             code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
!                                   &amp;req);
!             if (code) {
!                 if (dscp) cm_ReleaseSCache(dscp);
!                 cm_ReleaseSCache(scp);
!                 cm_ReleaseUser(userp);
!                 free(realPathp);
!                 return code;
!             }
! 	}       
! 	else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
!             /* don't create if not found */
!             if (dscp) cm_ReleaseSCache(dscp);
!             cm_ReleaseUser(userp);
!             free(realPathp);
!             return CM_ERROR_NOSUCHFILE;
! 	}       
  	else if (realDirFlag == 0 || realDirFlag == -1) {
!             osi_assert(dscp != NULL);
!             osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
!                       osi_LogSaveString(smb_logp, lastNamep));
!             openAction = 2;		/* created file */
!             setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
!             setAttr.clientModTime = time(NULL);
!             code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
!                               &amp;req);
!             if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!                 smb_NotifyChange(FILE_ACTION_ADDED,
!                                   FILE_NOTIFY_CHANGE_FILE_NAME,
!                                   dscp, lastNamep, NULL, TRUE);
!             if (code == CM_ERROR_EXISTS &amp;&amp; createDisp != FILE_CREATE) {
!                 /* Not an exclusive create, and someone else tried
!                  * creating it already, then we open it anyway.  We
!                  * don't bother retrying after this, since if this next
!                  * fails, that means that the file was deleted after we
!                  * started this call.
!                  */
!                 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
!                                   userp, &amp;req, &amp;scp);
!                 if (code == 0) {
!                     if (createDisp == FILE_OVERWRITE_IF) {
!                         setAttr.mask = CM_ATTRMASK_LENGTH;
!                         setAttr.length.LowPart = 0;
!                         setAttr.length.HighPart = 0;
! 
!                         /* now watch for a symlink */
!                         code = 0;
!                         while (code == 0 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!                             targetScp = 0;
!                             code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, &amp;req);
!                             if (code == 0) {
!                                 /* we have a more accurate file to use (the
!                                 * target of the symbolic link).  Otherwise,
!                                 * we'll just use the symlink anyway.
!                                 */
!                                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                                           scp, targetScp);
!                                 cm_ReleaseSCache(scp);
!                                 scp = targetScp;
!                             }
!                         }
!                         code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
!                     }
!                 }	/* lookup succeeded */
!             }
! 	}       
  	else {
!             char *tp, *pp;
!             char *cp; /* This component */
!             int clen = 0; /* length of component */
!             cm_scache_t *tscp;
!             int isLast = 0;
  		
!             /* create directory */
!             if ( !treeCreate ) 
!                 treeStartp = lastNamep;
!             osi_assert(dscp != NULL);
!             osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
!                       osi_LogSaveString(smb_logp, treeStartp));
!             openAction = 2;		/* created directory */
  
!             setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
!             setAttr.clientModTime = time(NULL);
  		
!             pp = treeStartp;
!             cp = spacep-&gt;data;
!             tscp = dscp;
! 
!             while (pp &amp;&amp; *pp) {
!                 tp = strchr(pp, '\\');
!                 if (!tp) {
!                     strcpy(cp,pp);
!                     clen = strlen(cp);
!                     isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
!                 }
!                 else {
!                     clen = tp - pp;
!                     strncpy(cp,pp,clen);
!                     *(cp + clen) = 0;
!                     tp++;
!                 }
!                 pp = tp;
  
!                 if (clen == 0) 
!                     continue; /* the supplied path can't have consecutive slashes either , but */
! 
!                 /* cp is the next component to be created. */
!                 code = cm_MakeDir(tscp, cp, 0, &amp;setAttr, userp, &amp;req);
!                 if (code == 0 &amp;&amp; (tscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!                     smb_NotifyChange(FILE_ACTION_ADDED,
!                                       FILE_NOTIFY_CHANGE_DIR_NAME,
!                                       tscp, cp, NULL, TRUE);
!                 if (code == 0 || 
!                      (code == CM_ERROR_EXISTS &amp;&amp; createDisp != FILE_CREATE)) {
!                     /* Not an exclusive create, and someone else tried
!                      * creating it already, then we open it anyway.  We
!                      * don't bother retrying after this, since if this next
!                      * fails, that means that the file was deleted after we
!                      * started this call.
!                      */
!                     code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
!                                       userp, &amp;req, &amp;scp);
!                 }
!                 if (code) break;
! 
!                 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
!                     cm_ReleaseSCache(tscp);
!                     tscp = scp; /* Newly created directory will be next parent */
!                 }
!             }
! 
!             /* 
!              * if we get here and code == 0, then scp is the last directory created, and tscp is the
!              * parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
!              */
!             dscp = tscp;
  	}
  
!     if (code) {
!         /* something went wrong creating or truncating the file */
!         if (scp) cm_ReleaseSCache(scp);
          if (dscp) cm_ReleaseSCache(dscp);
!         cm_ReleaseUser(userp);
!         free(realPathp);
!         return code;
!     }
! 
!     /* make sure we have file vs. dir right (only applies for single component case) */
!     if (realDirFlag == 0 &amp;&amp; scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!         /* now watch for a symlink */
!         code = 0;
!         while (code == 0 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!             cm_scache_t * targetScp = 0;
!             code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, &amp;req);
!             if (code == 0) {
!                 /* we have a more accurate file to use (the
!                 * target of the symbolic link).  Otherwise,
!                 * we'll just use the symlink anyway.
!                 */
!                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                           scp, targetScp);
!                 cm_ReleaseSCache(scp);
!                 scp = targetScp;
!             }
!         }
! 
!         if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!             cm_ReleaseSCache(scp);
!             cm_ReleaseUser(userp);
!             free(realPathp);
!             return CM_ERROR_ISDIR;
!         }
!     }
! 
      /* (only applies to single component case) */
!     if (realDirFlag == 1 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_FILE) {
!         cm_ReleaseSCache(scp);
          if (dscp) cm_ReleaseSCache(dscp);
!         cm_ReleaseUser(userp);
!         free(realPathp);
!         return CM_ERROR_NOTDIR;
!     }
  
!     /* open the file itself */
!     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
!     osi_assert(fidp);
!     /* save a pointer to the vnode */
!     fidp-&gt;scp = scp;
! 
!     fidp-&gt;flags = fidflags;
  
!     /* save parent dir and pathname for delete or change notification */
!     if (fidflags &amp; (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
!         fidp-&gt;flags |= SMB_FID_NTOPEN;
!         fidp-&gt;NTopen_dscp = dscp;
!         cm_HoldSCache(dscp);
!         fidp-&gt;NTopen_pathp = strdup(lastNamep);
!     }
!     fidp-&gt;NTopen_wholepathp = realPathp;
! 
!     /* we don't need this any longer */
!     if (dscp) cm_ReleaseSCache(dscp);
!     cm_Open(scp, 0, userp);
! 
!     /* set inp-&gt;fid so that later read calls in same msg can find fid */
!     inp-&gt;fid = fidp-&gt;fid;
! 
!     /* out parms */
!     parmSlot = 2;
!     lock_ObtainMutex(&amp;scp-&gt;mx);
!     smb_SetSMBParmByte(outp, parmSlot, 0);	/* oplock */
!     smb_SetSMBParm(outp, parmSlot, fidp-&gt;fid); parmSlot++;
!     smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
!     smb_LargeSearchTimeFromUnixTime(&amp;ft, scp-&gt;clientModTime);
!     smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
!     smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
!     smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
!     smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;ft); parmSlot += 4;
!     smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
!     parmSlot += 2;
!     smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;scp-&gt;length); parmSlot += 4;
!     smb_SetSMBParmDouble(outp, parmSlot, (char *)&amp;scp-&gt;length); parmSlot += 4;
!     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* filetype */
!     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;	/* dev state */
!     smb_SetSMBParmByte(outp, parmSlot,
!                         scp-&gt;fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
!     lock_ReleaseMutex(&amp;scp-&gt;mx);
!     smb_SetSMBDataLength(outp, 0);
  
!     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp-&gt;fid,
!               osi_LogSaveString(smb_logp, realPathp));
  
!     smb_ReleaseFID(fidp);
  
!     cm_ReleaseUser(userp);
  
      /* Can't free realPathp if we get here since fidp-&gt;NTopen_wholepathp is pointing there */
  
!     /* leave scp held since we put it in fidp-&gt;scp */
!     return 0;
! }       
  
  /*
   * A lot of stuff copied verbatim from NT Create&amp;X to NT Tran Create.
***************
*** 5188,5352 ****
   */
  long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	char *pathp, *realPathp;
! 	long code = 0;
! 	cm_space_t *spacep;
! 	cm_user_t *userp;
! 	cm_scache_t *dscp;		/* parent dir */
! 	cm_scache_t *scp;		/* file to create or open */
! 	cm_attr_t setAttr;
! 	char *lastNamep;
! 	unsigned long nameLength;
! 	unsigned int flags;
! 	unsigned int requestOpLock;
! 	unsigned int requestBatchOpLock;
! 	unsigned int mustBeDir;
      unsigned int extendedRespRequired;
! 	int realDirFlag;
! 	unsigned int desiredAccess;
  #ifdef DEBUG_VERBOSE    
      unsigned int allocSize;
      unsigned int shareAccess;
  #endif
! 	unsigned int extAttributes;
! 	unsigned int createDisp;
  #ifdef DEBUG_VERBOSE
      unsigned int sdLen;
  #endif
! 	unsigned int createOptions;
! 	int initialModeBits;
! 	unsigned short baseFid;
! 	smb_fid_t *baseFidp;
! 	smb_fid_t *fidp;
! 	cm_scache_t *baseDirp;
! 	unsigned short openAction;
! 	int parmSlot;
! 	long fidflags;
! 	FILETIME ft;
! 	char *tidPathp;
! 	BOOL foundscp;
! 	int parmOffset, dataOffset;
! 	char *parmp;
! 	ULONG *lparmp;
! 	char *outData;
! 	cm_req_t req;
! 
! 	cm_InitReq(&amp;req);
! 
! 	foundscp = FALSE;
! 	scp = NULL;
! 
! 	parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
! 			| (smb_GetSMBOffsetParm(inp, 12, 1) &lt;&lt; 16);
! 	parmp = inp-&gt;data + parmOffset;
! 	lparmp = (ULONG *) parmp;
! 
! 	flags = lparmp[0];
! 	requestOpLock = flags &amp; 0x02;
! 	requestBatchOpLock = flags &amp; 0x04;
! 	mustBeDir = flags &amp; 0x08;
      extendedRespRequired = flags &amp; 0x10;
  
! 	/*
! 	 * Why all of a sudden 32-bit FID?
! 	 * We will reject all bits higher than 16.
! 	 */
! 	if (lparmp[1] &amp; 0xFFFF0000)
! 		return CM_ERROR_INVAL;
! 	baseFid = (unsigned short)lparmp[1];
! 	desiredAccess = lparmp[2];
  #ifdef DEBUG_VERBOSE
      allocSize = lparmp[3];
  #endif /* DEBUG_VERSOSE */
! 	extAttributes = lparmp[5];
  #ifdef DEBUG_VEROSE
      shareAccess = lparmp[6];
  #endif
! 	createDisp = lparmp[7];
! 	createOptions = lparmp[8];
  #ifdef DEBUG_VERBOSE
      sdLen = lparmp[9];
  #endif
! 	nameLength = lparmp[11];
  
  #ifdef DEBUG_VERBOSE
! 	osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
! 	osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
! 	osi_Log1(smb_logp,"... flags[%x]",flags);
  #endif
  
! 	/* mustBeDir is never set; createOptions directory bit seems to be
!          * more important
! 	 */
! 	if (createOptions &amp; 1)
! 		realDirFlag = 1;
! 	else if (createOptions &amp; 0x40)
! 		realDirFlag = 0;
! 	else
! 		realDirFlag = -1;
! 
! 	/*
! 	 * compute initial mode bits based on read-only flag in
! 	 * extended attributes
! 	 */
! 	initialModeBits = 0666;
! 	if (extAttributes &amp; 1) initialModeBits &amp;= ~0222;
  
! 	pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
! 	/* Sometimes path is not null-terminated, so we make a copy. */
! 	realPathp = malloc(nameLength+1);
! 	memcpy(realPathp, pathp, nameLength);
! 	realPathp[nameLength] = 0;
! 
! 	spacep = cm_GetSpace();
! 	smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, realPathp);
! 
! 	/*
! 	 * Nothing here to handle SMB_IOCTL_FILENAME.
! 	 * Will add it if necessary.
! 	 */
  
  #ifdef DEBUG_VERBOSE
! 	{
! 		char *hexp, *asciip;
! 		asciip = (lastNamep? lastNamep : realPathp);
! 		hexp = osi_HexifyString( asciip );
! 		DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
! 		free(hexp);
! 	}
  #endif
  
! 	userp = smb_GetUser(vcp, inp);
      if (!userp) {
      	osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)-&gt;uid);
      	free(realPathp);
      	return CM_ERROR_INVAL;
      }
  
! 	if (baseFid == 0) {
! 		baseDirp = cm_rootSCachep;
! 		code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
          if(code == CM_ERROR_TIDIPC) {
              /* Attempt to use TID allocated for IPC.  The client is
!                probably trying to locate DCE RPC endpoints, which we
!                don't support. */
              osi_Log0(smb_logp, "NTTranCreate received IPC TID");
              free(realPathp);
              cm_ReleaseUser(userp);
              return CM_ERROR_NOSUCHPATH;
          }
! 	}
! 	else {
          baseFidp = smb_FindFID(vcp, baseFid, 0);
          if (!baseFidp) {
          	osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
!         	free(realPathp);
!         	cm_ReleaseUser(userp);
!         	return CM_ERROR_INVAL;
!         }
! 		baseDirp = baseFidp-&gt;scp;
! 		tidPathp = NULL;
! 	}
  
      /* compute open mode */
      fidflags = 0;
--- 5349,5515 ----
   */
  long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     char *pathp, *realPathp;
!     long code = 0;
!     cm_space_t *spacep;
!     cm_user_t *userp;
!     cm_scache_t *dscp;		/* parent dir */
!     cm_scache_t *scp;		/* file to create or open */
!     cm_scache_t *targetScp;     /* if scp is a symlink */
!     cm_attr_t setAttr;
!     char *lastNamep;
!     unsigned long nameLength;
!     unsigned int flags;
!     unsigned int requestOpLock;
!     unsigned int requestBatchOpLock;
!     unsigned int mustBeDir;
      unsigned int extendedRespRequired;
!     int realDirFlag;
!     unsigned int desiredAccess;
  #ifdef DEBUG_VERBOSE    
      unsigned int allocSize;
      unsigned int shareAccess;
  #endif
!     unsigned int extAttributes;
!     unsigned int createDisp;
  #ifdef DEBUG_VERBOSE
      unsigned int sdLen;
  #endif
!     unsigned int createOptions;
!     int initialModeBits;
!     unsigned short baseFid;
!     smb_fid_t *baseFidp;
!     smb_fid_t *fidp;
!     cm_scache_t *baseDirp;
!     unsigned short openAction;
!     int parmSlot;
!     long fidflags;
!     FILETIME ft;
!     char *tidPathp;
!     BOOL foundscp;
!     int parmOffset, dataOffset;
!     char *parmp;
!     ULONG *lparmp;
!     char *outData;
!     cm_req_t req;
! 
!     cm_InitReq(&amp;req);
! 
!     foundscp = FALSE;
!     scp = NULL;
! 
!     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
!         | (smb_GetSMBOffsetParm(inp, 12, 1) &lt;&lt; 16);
!     parmp = inp-&gt;data + parmOffset;
!     lparmp = (ULONG *) parmp;
! 
!     flags = lparmp[0];
!     requestOpLock = flags &amp; 0x02;
!     requestBatchOpLock = flags &amp; 0x04;
!     mustBeDir = flags &amp; 0x08;
      extendedRespRequired = flags &amp; 0x10;
  
!     /*
!      * Why all of a sudden 32-bit FID?
!      * We will reject all bits higher than 16.
!      */
!     if (lparmp[1] &amp; 0xFFFF0000)
!         return CM_ERROR_INVAL;
!     baseFid = (unsigned short)lparmp[1];
!     desiredAccess = lparmp[2];
  #ifdef DEBUG_VERBOSE
      allocSize = lparmp[3];
  #endif /* DEBUG_VERSOSE */
!     extAttributes = lparmp[5];
  #ifdef DEBUG_VEROSE
      shareAccess = lparmp[6];
  #endif
!     createDisp = lparmp[7];
!     createOptions = lparmp[8];
  #ifdef DEBUG_VERBOSE
      sdLen = lparmp[9];
  #endif
!     nameLength = lparmp[11];
  
  #ifdef DEBUG_VERBOSE
!     osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
!     osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
!     osi_Log1(smb_logp,"... flags[%x]",flags);
  #endif
  
!     /* mustBeDir is never set; createOptions directory bit seems to be
!      * more important
!      */
!     if (createOptions &amp; 1)
!         realDirFlag = 1;
!     else if (createOptions &amp; 0x40)
!         realDirFlag = 0;
!     else
!         realDirFlag = -1;
  
!     /*
!      * compute initial mode bits based on read-only flag in
!      * extended attributes
!      */
!     initialModeBits = 0666;
!     if (extAttributes &amp; 1) 
!         initialModeBits &amp;= ~0222;
! 
!     pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
!     /* Sometimes path is not null-terminated, so we make a copy. */
!     realPathp = malloc(nameLength+1);
!     memcpy(realPathp, pathp, nameLength);
!     realPathp[nameLength] = 0;
! 
!     spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep-&gt;data, &amp;lastNamep, realPathp);
! 
!     /*
!      * Nothing here to handle SMB_IOCTL_FILENAME.
!      * Will add it if necessary.
!      */
  
  #ifdef DEBUG_VERBOSE
!     {
!         char *hexp, *asciip;
!         asciip = (lastNamep? lastNamep : realPathp);
!         hexp = osi_HexifyString( asciip );
!         DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
!         free(hexp);
!     }
  #endif
  
!     userp = smb_GetUser(vcp, inp);
      if (!userp) {
      	osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)-&gt;uid);
      	free(realPathp);
      	return CM_ERROR_INVAL;
      }
  
!     if (baseFid == 0) {
!         baseDirp = cm_rootSCachep;
!         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)-&gt;tid, &amp;tidPathp);
          if(code == CM_ERROR_TIDIPC) {
              /* Attempt to use TID allocated for IPC.  The client is
!              * probably trying to locate DCE RPC endpoints, which we
!              * don't support. */
              osi_Log0(smb_logp, "NTTranCreate received IPC TID");
              free(realPathp);
              cm_ReleaseUser(userp);
              return CM_ERROR_NOSUCHPATH;
          }
!     }
!     else {
          baseFidp = smb_FindFID(vcp, baseFid, 0);
          if (!baseFidp) {
          	osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
!             free(realPathp);
!             cm_ReleaseUser(userp);
!             return CM_ERROR_INVAL;
!         }       
!         baseDirp = baseFidp-&gt;scp;
!         tidPathp = NULL;
!     }
  
      /* compute open mode */
      fidflags = 0;
***************
*** 5357,5365 ****
      if (desiredAccess &amp; AFS_ACCESS_WRITE)
          fidflags |= SMB_FID_OPENWRITE;
  
! 	dscp = NULL;
! 	code = 0;
!     if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
          code = cm_NameI(baseDirp, spacep-&gt;data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &amp;req, &amp;dscp);
          if (code == 0) {
--- 5520,5530 ----
      if (desiredAccess &amp; AFS_ACCESS_WRITE)
          fidflags |= SMB_FID_OPENWRITE;
  
!     dscp = NULL;
!     code = 0;
!     if ( createDisp == FILE_OPEN || 
!          createDisp == FILE_OVERWRITE ||
!          createDisp == FILE_OVERWRITE_IF) {
          code = cm_NameI(baseDirp, spacep-&gt;data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &amp;req, &amp;dscp);
          if (code == 0) {
***************
*** 5369,5375 ****
                  code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
                                   CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &amp;req, &amp;scp);
                  if (code == 0 &amp;&amp; realDirFlag == 1) {
! 					cm_ReleaseSCache(scp);
                      cm_ReleaseSCache(dscp);
                      cm_ReleaseUser(userp);
                      free(realPathp);
--- 5534,5540 ----
                  code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
                                   CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &amp;req, &amp;scp);
                  if (code == 0 &amp;&amp; realDirFlag == 1) {
!                     cm_ReleaseSCache(scp);
                      cm_ReleaseSCache(dscp);
                      cm_ReleaseUser(userp);
                      free(realPathp);
***************
*** 5383,5392 ****
                          userp, tidPathp, &amp;req, &amp;scp);
      }
  
! 	if (code == 0) foundscp = TRUE;
! 	if (code != 0
! 	    || (fidflags &amp; (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
! 		/* look up parent directory */
          if ( !dscp ) {
              code = cm_NameI(baseDirp, spacep-&gt;data,
                               CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
--- 5548,5558 ----
                          userp, tidPathp, &amp;req, &amp;scp);
      }
  
!     if (code == 0) 
!         foundscp = TRUE;
!     if (code != 0
!          || (fidflags &amp; (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
!         /* look up parent directory */
          if ( !dscp ) {
              code = cm_NameI(baseDirp, spacep-&gt;data,
                               CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
***************
*** 5396,5574 ****
          
          cm_FreeSpace(spacep);
  
! 		if (baseFid != 0) {
!            smb_ReleaseFID(baseFidp);
!            baseFidp = 0;
          }
  
! 		if (code) {
! 			cm_ReleaseUser(userp);
! 			free(realPathp);
! 			return code;
! 		}
  
! 		if (!lastNamep) lastNamep = realPathp;
! 		else lastNamep++;
  
          if (!smb_IsLegalFilename(lastNamep))
              return CM_ERROR_BADNTFILENAME;
  
! 		if (!foundscp) {
!             if (createDisp == 2 || createDisp == 4)
                  code = cm_Lookup(dscp, lastNamep,
!                                  CM_FLAG_FOLLOW, userp, &amp;req, &amp;scp);
!             else
                  code = cm_Lookup(dscp, lastNamep,
                                   CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                                   userp, &amp;req, &amp;scp);
! 			if (code &amp;&amp; code != CM_ERROR_NOSUCHFILE) {
! 				cm_ReleaseSCache(dscp);
! 				cm_ReleaseUser(userp);
! 				free(realPathp);
! 				return code;
! 			}
! 		}
! 	}
! 	else {
! 		if (baseFid != 0) {
              smb_ReleaseFID(baseFidp);
              baseFidp = 0;
          }
! 		cm_FreeSpace(spacep);
! 	}
  
! 	/* if we get here, if code is 0, the file exists and is represented by
! 	 * scp.  Otherwise, we have to create it.  The dir may be represented
! 	 * by dscp, or we may have found the file directly.  If code is non-zero,
! 	 * scp is NULL.
! 	 */
! 	if (code == 0) {
! 		code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
! 				      &amp;req);
! 		if (code) {
! 			if (dscp) cm_ReleaseSCache(dscp);
! 			cm_ReleaseSCache(scp);
! 			cm_ReleaseUser(userp);
! 			free(realPathp);
! 			return code;
! 		}
! 
! 		if (createDisp == 2) {
! 			/* oops, file shouldn't be there */
! 			if (dscp) cm_ReleaseSCache(dscp);
! 			cm_ReleaseSCache(scp);
! 			cm_ReleaseUser(userp);
! 			free(realPathp);
! 			return CM_ERROR_EXISTS;
! 		}
! 
! 		if (createDisp == 4
! 		    || createDisp == 5) {
! 			setAttr.mask = CM_ATTRMASK_LENGTH;
! 			setAttr.length.LowPart = 0;
! 			setAttr.length.HighPart = 0;
! 			code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
! 			openAction = 3;	/* truncated existing file */
! 		}
! 		else openAction = 1;	/* found existing file */
! 	}
! 	else if (createDisp == 1 || createDisp == 4) {
! 		/* don't create if not found */
! 		if (dscp) cm_ReleaseSCache(dscp);
! 		cm_ReleaseUser(userp);
! 		free(realPathp);
! 		return CM_ERROR_NOSUCHFILE;
! 	}
! 	else if (realDirFlag == 0 || realDirFlag == -1) {
! 		osi_assert(dscp != NULL);
! 		osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
!                  osi_LogSaveString(smb_logp, lastNamep));
! 		openAction = 2;		/* created file */
! 		setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
! 		setAttr.clientModTime = time(NULL);
! 		code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
! 				 &amp;req);
! 		if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 			smb_NotifyChange(FILE_ACTION_ADDED,
! 					 FILE_NOTIFY_CHANGE_FILE_NAME,
! 					 dscp, lastNamep, NULL, TRUE);
! 		if (code == CM_ERROR_EXISTS &amp;&amp; createDisp != 2) {
! 			/* Not an exclusive create, and someone else tried
! 			 * creating it already, then we open it anyway.  We
! 			 * don't bother retrying after this, since if this next
! 			 * fails, that means that the file was deleted after we
! 			 * started this call.
! 			 */
! 			code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
! 					 userp, &amp;req, &amp;scp);
! 			if (code == 0) {
! 				if (createDisp == 5) {
! 					setAttr.mask = CM_ATTRMASK_LENGTH;
! 					setAttr.length.LowPart = 0;
! 					setAttr.length.HighPart = 0;
! 					code = cm_SetAttr(scp, &amp;setAttr, userp,
! 							  &amp;req);
! 				}
! 			}	/* lookup succeeded */
! 		}
! 	}
! 	else {
! 		/* create directory */
! 		osi_assert(dscp != NULL);
! 		osi_Log1(smb_logp,
! 				"smb_ReceiveNTTranCreate creating directory %s",
! 				osi_LogSaveString(smb_logp, lastNamep));
! 		openAction = 2;		/* created directory */
! 		setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
! 		setAttr.clientModTime = time(NULL);
! 		code = cm_MakeDir(dscp, lastNamep, 0, &amp;setAttr, userp, &amp;req);
! 		if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
! 			smb_NotifyChange(FILE_ACTION_ADDED,
! 					 FILE_NOTIFY_CHANGE_DIR_NAME,
! 					 dscp, lastNamep, NULL, TRUE);
! 		if (code == 0
! 		    || (code == CM_ERROR_EXISTS &amp;&amp; createDisp != 2)) {
! 			/* Not an exclusive create, and someone else tried
! 			 * creating it already, then we open it anyway.  We
! 			 * don't bother retrying after this, since if this next
! 			 * fails, that means that the file was deleted after we
! 			 * started this call.
! 			 */
! 			code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
! 					 userp, &amp;req, &amp;scp);
! 		}
! 	}
  
! 	if (code) {
! 		/* something went wrong creating or truncating the file */
! 		if (scp) cm_ReleaseSCache(scp);
! 		cm_ReleaseUser(userp);
! 		free(realPathp);
! 		return code;
! 	}
  
! 	/* make sure we have file vs. dir right */
! 	if (realDirFlag == 0 &amp;&amp; scp-&gt;fileType != CM_SCACHETYPE_FILE) {
! 		cm_ReleaseSCache(scp);
! 		cm_ReleaseUser(userp);
! 		free(realPathp);
! 		return CM_ERROR_ISDIR;
! 	}
! 	if (realDirFlag == 1 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_FILE) {
! 		cm_ReleaseSCache(scp);
! 		cm_ReleaseUser(userp);
! 		free(realPathp);
! 		return CM_ERROR_NOTDIR;
! 	}
  
! 	/* open the file itself */
! 	fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
! 	osi_assert(fidp);
  
! 	/* save a pointer to the vnode */
! 	fidp-&gt;scp = scp;
  
! 	fidp-&gt;flags = fidflags;
  
      /* save parent dir and pathname for deletion or change notification */
      if (fidflags &amp; (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
--- 5562,5794 ----
          
          cm_FreeSpace(spacep);
  
!         if (baseFid != 0) {
!             smb_ReleaseFID(baseFidp);
!             baseFidp = 0;
          }
  
!         if (code) {
!             cm_ReleaseUser(userp);
!             free(realPathp);
!             return code;
!         }
  
!         if (!lastNamep) lastNamep = realPathp;
!         else lastNamep++;
  
          if (!smb_IsLegalFilename(lastNamep))
              return CM_ERROR_BADNTFILENAME;
  
!         if (!foundscp) {
!             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
                  code = cm_Lookup(dscp, lastNamep,
!                                   CM_FLAG_FOLLOW, userp, &amp;req, &amp;scp);
!             } else {
                  code = cm_Lookup(dscp, lastNamep,
                                   CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                                   userp, &amp;req, &amp;scp);
!             }
!             if (code &amp;&amp; code != CM_ERROR_NOSUCHFILE) {
!                 cm_ReleaseSCache(dscp);
!                 cm_ReleaseUser(userp);
!                 free(realPathp);
!                 return code;
!             }
!         }
!     }
!     else {
!         if (baseFid != 0) {
              smb_ReleaseFID(baseFidp);
              baseFidp = 0;
          }
!         cm_FreeSpace(spacep);
!     }
  
!     /* if we get here, if code is 0, the file exists and is represented by
!      * scp.  Otherwise, we have to create it.  The dir may be represented
!      * by dscp, or we may have found the file directly.  If code is non-zero,
!      * scp is NULL.
!      */
!     if (code == 0) {
!         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
!                                &amp;req);
!         if (code) {     
!             if (dscp) cm_ReleaseSCache(dscp);
!             cm_ReleaseSCache(scp);
!             cm_ReleaseUser(userp);
!             free(realPathp);
!             return code;
!         }
  
!         if (createDisp == FILE_CREATE) {
!             /* oops, file shouldn't be there */
!             if (dscp) cm_ReleaseSCache(dscp);
!             cm_ReleaseSCache(scp);
!             cm_ReleaseUser(userp);
!             free(realPathp);
!             return CM_ERROR_EXISTS;
!         }
  
!         if (createDisp == FILE_OVERWRITE ||
!             createDisp == FILE_OVERWRITE_IF) {
!             setAttr.mask = CM_ATTRMASK_LENGTH;
!             setAttr.length.LowPart = 0;
!             setAttr.length.HighPart = 0;
! 
!             /* now watch for a symlink */
!             code = 0;
!             while (code == 0 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!                 targetScp = 0;
!                 code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, &amp;req);
!                 if (code == 0) {
!                     /* we have a more accurate file to use (the
!                     * target of the symbolic link).  Otherwise,
!                     * we'll just use the symlink anyway.
!                     */
!                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                               scp, targetScp);
!                     cm_ReleaseSCache(scp);
!                     scp = targetScp;
!                 }
!             }
!             code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
!             openAction = 3;	/* truncated existing file */
!         }
!         else openAction = 1;	/* found existing file */
!     }
!     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
!         /* don't create if not found */
!         if (dscp) cm_ReleaseSCache(dscp);
!         cm_ReleaseUser(userp);
!         free(realPathp);
!         return CM_ERROR_NOSUCHFILE;
!     }
!     else if (realDirFlag == 0 || realDirFlag == -1) {
!         osi_assert(dscp != NULL);
!         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
!                   osi_LogSaveString(smb_logp, lastNamep));
!         openAction = 2;		/* created file */
!         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
!         setAttr.clientModTime = time(NULL);
!         code = cm_Create(dscp, lastNamep, 0, &amp;setAttr, &amp;scp, userp,
!                           &amp;req);
!         if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!             smb_NotifyChange(FILE_ACTION_ADDED,
!                               FILE_NOTIFY_CHANGE_FILE_NAME,
!                               dscp, lastNamep, NULL, TRUE);
!         if (code == CM_ERROR_EXISTS &amp;&amp; createDisp != FILE_CREATE) {
!             /* Not an exclusive create, and someone else tried
!              * creating it already, then we open it anyway.  We
!              * don't bother retrying after this, since if this next
!              * fails, that means that the file was deleted after we
!              * started this call.
!              */
!             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
!                               userp, &amp;req, &amp;scp);
!             if (code == 0) {
!                 if (createDisp == FILE_OVERWRITE_IF) {
!                     setAttr.mask = CM_ATTRMASK_LENGTH;
!                     setAttr.length.LowPart = 0;
!                     setAttr.length.HighPart = 0;
! 
!                     /* now watch for a symlink */
!                     code = 0;
!                     while (code == 0 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!                         targetScp = 0;
!                         code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, &amp;req);
!                         if (code == 0) {
!                             /* we have a more accurate file to use (the
!                             * target of the symbolic link).  Otherwise,
!                             * we'll just use the symlink anyway.
!                             */
!                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                                       scp, targetScp);
!                             cm_ReleaseSCache(scp);
!                             scp = targetScp;
!                         }
!                     }
!                     code = cm_SetAttr(scp, &amp;setAttr, userp, &amp;req);
!                 }       
!             }	/* lookup succeeded */
!         }
!     }
!     else {
!         /* create directory */
!         osi_assert(dscp != NULL);
!         osi_Log1(smb_logp,
!                   "smb_ReceiveNTTranCreate creating directory %s",
!                   osi_LogSaveString(smb_logp, lastNamep));
!         openAction = 2;		/* created directory */
!         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
!         setAttr.clientModTime = time(NULL);
!         code = cm_MakeDir(dscp, lastNamep, 0, &amp;setAttr, userp, &amp;req);
!         if (code == 0 &amp;&amp; (dscp-&gt;flags &amp; CM_SCACHEFLAG_ANYWATCH))
!             smb_NotifyChange(FILE_ACTION_ADDED,
!                               FILE_NOTIFY_CHANGE_DIR_NAME,
!                               dscp, lastNamep, NULL, TRUE);
!         if (code == 0 ||
!             (code == CM_ERROR_EXISTS &amp;&amp; createDisp != FILE_CREATE)) {
!             /* Not an exclusive create, and someone else tried
!              * creating it already, then we open it anyway.  We
!              * don't bother retrying after this, since if this next
!              * fails, that means that the file was deleted after we
!              * started this call.
!              */
!             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
!                               userp, &amp;req, &amp;scp);
!         }       
!     }
! 
!     if (code) {
!         /* something went wrong creating or truncating the file */
!         if (scp) cm_ReleaseSCache(scp);
!         cm_ReleaseUser(userp);
!         free(realPathp);
!         return code;
!     }
! 
!     /* make sure we have file vs. dir right */
!     if (realDirFlag == 0 &amp;&amp; scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!         /* now watch for a symlink */
!         code = 0;
!         while (code == 0 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_SYMLINK) {
!             targetScp = 0;
!             code = cm_EvaluateSymLink(dscp, scp, &amp;targetScp, userp, &amp;req);
!             if (code == 0) {
!                 /* we have a more accurate file to use (the
!                 * target of the symbolic link).  Otherwise,
!                 * we'll just use the symlink anyway.
!                 */
!                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
!                           scp, targetScp);
!                 cm_ReleaseSCache(scp);
!                 scp = targetScp;
!             }
!         }
! 
!         if (scp-&gt;fileType != CM_SCACHETYPE_FILE) {
!             cm_ReleaseSCache(scp);
!             cm_ReleaseUser(userp);
!             free(realPathp);
!             return CM_ERROR_ISDIR;
!         }
!     }
! 
!     if (realDirFlag == 1 &amp;&amp; scp-&gt;fileType == CM_SCACHETYPE_FILE) {
!         cm_ReleaseSCache(scp);
!         cm_ReleaseUser(userp);
!         free(realPathp);
!         return CM_ERROR_NOTDIR;
!     }
  
!     /* open the file itself */
!     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
!     osi_assert(fidp);
  
!     /* save a pointer to the vnode */
!     fidp-&gt;scp = scp;
  
!     fidp-&gt;flags = fidflags;
  
      /* save parent dir and pathname for deletion or change notification */
      if (fidflags &amp; (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
***************
*** 5577,5591 ****
          cm_HoldSCache(dscp);
          fidp-&gt;NTopen_pathp = strdup(lastNamep);
      }
! 	fidp-&gt;NTopen_wholepathp = realPathp;
  
! 	/* we don't need this any longer */
! 	if (dscp) cm_ReleaseSCache(dscp);
  
! 	cm_Open(scp, 0, userp);
  
! 	/* set inp-&gt;fid so that later read calls in same msg can find fid */
! 	inp-&gt;fid = fidp-&gt;fid;
  
      /* check whether we are required to send an extended response */
      if (!extendedRespRequired) {
--- 5797,5811 ----
          cm_HoldSCache(dscp);
          fidp-&gt;NTopen_pathp = strdup(lastNamep);
      }
!     fidp-&gt;NTopen_wholepathp = realPathp;
  
!     /* we don't need this any longer */
!     if (dscp) cm_ReleaseSCache(dscp);
  
!     cm_Open(scp, 0, userp);
  
!     /* set inp-&gt;fid so that later read calls in same msg can find fid */
!     inp-&gt;fid = fidp-&gt;fid;
  
      /* check whether we are required to send an extended response */
      if (!extendedRespRequired) {
***************
*** 5689,5717 ****
          lock_ReleaseMutex(&amp;scp-&gt;mx);
      }
  
! 	osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp-&gt;fid);
  
! 	smb_ReleaseFID(fidp);
  
! 	cm_ReleaseUser(userp);
  
!    	/* free(realPathp); Can't free realPathp here because fidp-&gt;NTopen_wholepathp points there */
! 	/* leave scp held since we put it in fidp-&gt;scp */
! 	return 0;
  }
  
  long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
  	smb_packet_t *outp)
  {
! 	smb_packet_t *savedPacketp;
! 	ULONG filter; USHORT fid, watchtree;
! 	smb_fid_t *fidp;
! 	cm_scache_t *scp;
!         
! 	filter = smb_GetSMBParm(inp, 19)
! 			| (smb_GetSMBParm(inp, 20) &lt;&lt; 16);
! 	fid = smb_GetSMBParm(inp, 21);
! 	watchtree = smb_GetSMBParm(inp, 22) &amp;&amp; 0xffff;  /* TODO: should this be 0xff ? */
  
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp) {
--- 5909,5937 ----
          lock_ReleaseMutex(&amp;scp-&gt;mx);
      }
  
!     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp-&gt;fid);
  
!     smb_ReleaseFID(fidp);
  
!     cm_ReleaseUser(userp);
  
!     /* free(realPathp); Can't free realPathp here because fidp-&gt;NTopen_wholepathp points there */
!     /* leave scp held since we put it in fidp-&gt;scp */
!     return 0;
  }
  
  long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
  	smb_packet_t *outp)
  {
!     smb_packet_t *savedPacketp;
!     ULONG filter; USHORT fid, watchtree;
!     smb_fid_t *fidp;
!     cm_scache_t *scp;
!         
!     filter = smb_GetSMBParm(inp, 19) |
!              (smb_GetSMBParm(inp, 20) &lt;&lt; 16);
!     fid = smb_GetSMBParm(inp, 21);
!     watchtree = smb_GetSMBParm(inp, 22) &amp;&amp; 0xffff;  /* TODO: should this be 0xff ? */
  
      fidp = smb_FindFID(vcp, fid, 0);
      if (!fidp) {
***************
*** 5719,5731 ****
          return CM_ERROR_BADFD;
      }
  
! 	savedPacketp = smb_CopyPacket(inp);
      smb_HoldVC(vcp);
! 	savedPacketp-&gt;vcp = vcp;
! 	lock_ObtainMutex(&amp;smb_Dir_Watch_Lock);
! 	savedPacketp-&gt;nextp = smb_Directory_Watches;
! 	smb_Directory_Watches = savedPacketp;
! 	lock_ReleaseMutex(&amp;smb_Dir_Watch_Lock);
  
      osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
               filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp-&gt;NTopen_wholepathp));
--- 5939,5951 ----
          return CM_ERROR_BADFD;
      }
  
!     savedPacketp = smb_CopyPacket(inp);
      smb_HoldVC(vcp);
!     savedPacketp-&gt;vcp = vcp;
!     lock_ObtainMutex(&amp;smb_Dir_Watch_Lock);
!     savedPacketp-&gt;nextp = smb_Directory_Watches;
!     smb_Directory_Watches = savedPacketp;
!     lock_ReleaseMutex(&amp;smb_Dir_Watch_Lock);
  
      osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
               filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp-&gt;NTopen_wholepathp));
***************
*** 5739,5853 ****
      lock_ReleaseMutex(&amp;scp-&gt;mx);
      smb_ReleaseFID(fidp);
  
! 	outp-&gt;flags |= SMB_PACKETFLAG_NOSEND;
! 	return 0;
  }
  
  unsigned char nullSecurityDesc[36] = {
! 	0x01,				/* security descriptor revision */
! 	0x00,				/* reserved, should be zero */
! 	0x00, 0x80,			/* security descriptor control;
! 					 * 0x8000 : self-relative format */
! 	0x14, 0x00, 0x00, 0x00,		/* offset of owner SID */
! 	0x1c, 0x00, 0x00, 0x00,		/* offset of group SID */
! 	0x00, 0x00, 0x00, 0x00,		/* offset of DACL would go here */
! 	0x00, 0x00, 0x00, 0x00,		/* offset of SACL would go here */
! 	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 					/* "null SID" owner SID */
! 	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
! 					/* "null SID" group SID */
! };
  
  long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	int parmOffset, parmCount, dataOffset, dataCount;
! 	int parmSlot;
! 	int maxData;
! 	char *outData;
! 	char *parmp;
! 	USHORT *sparmp;
! 	ULONG *lparmp;
! 	USHORT fid;
! 	ULONG securityInformation;
! 
! 	parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
! 			| (smb_GetSMBOffsetParm(inp, 12, 1) &lt;&lt; 16);
! 	parmp = inp-&gt;data + parmOffset;
! 	sparmp = (USHORT *) parmp;
! 	lparmp = (ULONG *) parmp;
! 
! 	fid = sparmp[0];
! 	securityInformation = lparmp[1];
! 
! 	maxData = smb_GetSMBOffsetParm(inp, 7, 1)
! 			| (smb_GetSMBOffsetParm(inp, 8, 1) &lt;&lt; 16);
! 
! 	if (maxData &lt; 36)
! 		dataCount = 0;
! 	else
! 		dataCount = 36;
! 
! 	/* out parms */
! 	parmOffset = 8*4 + 39;
! 	parmOffset += 1;	/* pad to 4 */
! 	parmCount = 4;
! 	dataOffset = parmOffset + parmCount;
! 
! 	parmSlot = 1;
! 	outp-&gt;oddByte = 1;
! 	/* Total Parameter Count */
! 	smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
! 	/* Total Data Count */
! 	smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
! 	/* Parameter Count */
! 	smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
! 	/* Parameter Offset */
! 	smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
! 	/* Parameter Displacement */
! 	smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
! 	/* Data Count */
! 	smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
! 	/* Data Offset */
! 	smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
! 	/* Data Displacement */
! 	smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
! 	smb_SetSMBParmByte(outp, parmSlot, 0);	/* Setup Count */
! 	smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
! 
! 	outData = smb_GetSMBData(outp, NULL);
! 	outData++;			/* round to get to parmOffset */
! 	*((ULONG *)outData) = 36; outData += 4;	/* length */
! 
! 	if (maxData &gt;= 36) {
! 		memcpy(outData, nullSecurityDesc, 36);
! 		outData += 36;
! 		return 0;
! 	} else
! 		return CM_ERROR_BUFFERTOOSMALL;
! }
  
! long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
! 	unsigned short function;
  
! 	function = smb_GetSMBParm(inp, 18);
  
! 	osi_Log1(smb_logp, "SMB NT Transact function %d", function);
  
! 	/* We can handle long names */
! 	if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
! 		((smb_t *)outp)-&gt;flg2 |= 0x40;	/* IS_LONG_NAME */
!         
! 	switch (function) {
  
! 		case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
  
! 		case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
  
! 		case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
  
! 		default: return CM_ERROR_INVAL;
! 	}
  }
  
  /*
--- 5959,6073 ----
      lock_ReleaseMutex(&amp;scp-&gt;mx);
      smb_ReleaseFID(fidp);
  
!     outp-&gt;flags |= SMB_PACKETFLAG_NOSEND;
!     return 0;
  }
  
  unsigned char nullSecurityDesc[36] = {
!     0x01,				/* security descriptor revision */
!     0x00,				/* reserved, should be zero */
!     0x00, 0x80,			/* security descriptor control;
!     * 0x8000 : self-relative format */
!     0x14, 0x00, 0x00, 0x00,		/* offset of owner SID */
!     0x1c, 0x00, 0x00, 0x00,		/* offset of group SID */
!     0x00, 0x00, 0x00, 0x00,		/* offset of DACL would go here */
!     0x00, 0x00, 0x00, 0x00,		/* offset of SACL would go here */
!     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
!     /* "null SID" owner SID */
!     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
!     /* "null SID" group SID */
! };      
  
  long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     int parmOffset, parmCount, dataOffset, dataCount;
!     int parmSlot;
!     int maxData;
!     char *outData;
!     char *parmp;
!     USHORT *sparmp;
!     ULONG *lparmp;
!     USHORT fid;
!     ULONG securityInformation;
! 
!     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
!         | (smb_GetSMBOffsetParm(inp, 12, 1) &lt;&lt; 16);
!     parmp = inp-&gt;data + parmOffset;
!     sparmp = (USHORT *) parmp;
!     lparmp = (ULONG *) parmp;
  
!     fid = sparmp[0];
!     securityInformation = lparmp[1];
  
!     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
!         | (smb_GetSMBOffsetParm(inp, 8, 1) &lt;&lt; 16);
  
!     if (maxData &lt; 36)
!         dataCount = 0;
!     else
!         dataCount = 36;
  
!     /* out parms */
!     parmOffset = 8*4 + 39;
!     parmOffset += 1;	/* pad to 4 */
!     parmCount = 4;
!     dataOffset = parmOffset + parmCount;
! 
!     parmSlot = 1;
!     outp-&gt;oddByte = 1;
!     /* Total Parameter Count */
!     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
!     /* Total Data Count */
!     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
!     /* Parameter Count */
!     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
!     /* Parameter Offset */
!     smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
!     /* Parameter Displacement */
!     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
!     /* Data Count */
!     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
!     /* Data Offset */
!     smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
!     /* Data Displacement */
!     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
!     smb_SetSMBParmByte(outp, parmSlot, 0);	/* Setup Count */
!     smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
! 
!     outData = smb_GetSMBData(outp, NULL);
!     outData++;			/* round to get to parmOffset */
!     *((ULONG *)outData) = 36; outData += 4;	/* length */
! 
!     if (maxData &gt;= 36) {
!         memcpy(outData, nullSecurityDesc, 36);
!         outData += 36;
!         return 0;
!     } else
!         return CM_ERROR_BUFFERTOOSMALL;
! }
  
! long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
! {
!     unsigned short function;
  
!     function = smb_GetSMBParm(inp, 18);
  
!     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
  
!     /* We can handle long names */
!     if (vcp-&gt;flags &amp; SMB_VCFLAG_USENT)
!         ((smb_t *)outp)-&gt;flg2 |= 0x40;	/* IS_LONG_NAME */
!         
!     switch (function) {
!     case 6: 
!         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
!     case 4: 
!         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
!     case 1: 
!         return smb_ReceiveNTTranCreate(vcp, inp, outp);
!     default: 
!         return CM_ERROR_INVAL;
!     }
  }
  
  /*
***************
*** 6103,6111 ****
      return 0;
  }
  
  void smb3_Init()
  {
! 	lock_InitializeMutex(&amp;smb_Dir_Watch_Lock, "Directory Watch List Lock");
  }
  
  cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
--- 6323,6374 ----
      return 0;
  }
  
+ /*
+  * NT rename also does hard links.
+  */
+ 
+ #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
+ #define RENAME_FLAG_HARD_LINK                0x103
+ #define RENAME_FLAG_RENAME                   0x104
+ #define RENAME_FLAG_COPY                     0x105
+ 
+ long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+ {
+     char *oldname, *newname;
+     long code = 0;
+     cm_user_t *userp;
+     char * tp;
+     int attrs;
+     int rename_type;
+ 
+     attrs = smb_GetSMBParm(inp, 0);
+     rename_type = smb_GetSMBParm(inp, 1);
+ 
+     if (rename_type != RENAME_FLAG_RENAME &amp;&amp; rename_type != RENAME_FLAG_HARD_LINK) {
+         osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
+         return CM_ERROR_NOACCESS;
+     }
+ 
+     tp = smb_GetSMBData(inp, NULL);
+     oldname = smb_ParseASCIIBlock(tp, &amp;tp);
+     newname = smb_ParseASCIIBlock(tp, &amp;tp);
+ 
+     osi_Log3(smb_logp, "NTRename for [%s]-&gt;[%s] type [%s]",
+              osi_LogSaveString(smb_logp, oldname),
+              osi_LogSaveString(smb_logp, newname),
+              ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
+ 
+     if (rename_type == RENAME_FLAG_RENAME) {
+         code = smb_Rename(vcp,inp,oldname,newname,attrs);
+     } else { /* RENAME_FLAG_HARD_LINK */
+         code = smb_Link(vcp,inp,oldname,newname);
+     }
+     return code;
+ }
+ 
  void smb3_Init()
  {
!     lock_InitializeMutex(&amp;smb_Dir_Watch_Lock, "Directory Watch List Lock");
  }
  
  cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
Index: openafs/src/WINNT/afsd/smb3.h
diff -c openafs/src/WINNT/afsd/smb3.h:1.7 openafs/src/WINNT/afsd/smb3.h:1.7.2.1
*** openafs/src/WINNT/afsd/smb3.h:1.7	Wed Jul 21 00:43:07 2004
--- openafs/src/WINNT/afsd/smb3.h	Tue Sep 21 10:07:19 2004
***************
*** 149,155 ****
  extern long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p,
  	smb_packet_t *outp);
  
! extern long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p,
  	smb_packet_t *outp);
  
  extern long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
--- 149,164 ----
  extern long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p,
  	smb_packet_t *outp);
  
! extern long smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p,
! 	smb_packet_t *outp);
! 
! extern long smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p,
! 	smb_packet_t *outp);
! 
! extern long smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p,
! 	smb_packet_t *outp);
! 
! extern long smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p,
  	smb_packet_t *outp);
  
  extern long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
***************
*** 178,183 ****
--- 187,194 ----
  
  extern long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
  
+ extern long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
+ 
  extern int smb_V3MatchMask(char *namep, char *maskp, int flags);
  
  extern void smb3_Init();
Index: openafs/src/WINNT/aklog/aklog.c
diff -c openafs/src/WINNT/aklog/aklog.c:1.5.2.1 openafs/src/WINNT/aklog/aklog.c:1.5.2.3
*** openafs/src/WINNT/aklog/aklog.c:1.5.2.1	Tue Aug 17 00:28:41 2004
--- openafs/src/WINNT/aklog/aklog.c	Mon Oct 18 00:09:34 2004
***************
*** 134,141 ****
  #define VOLMARKERSTRING ":"	/* String form of above */
  
  typedef struct {
! 	char cell[BUFSIZ];
! 	char realm[REALM_SZ];
  } cellinfo_t;
  
  
--- 134,141 ----
  #define VOLMARKERSTRING ":"	/* String form of above */
  
  typedef struct {
!     char cell[BUFSIZ];
!     char realm[REALM_SZ];
  } cellinfo_t;
  
  
***************
*** 148,176 ****
  static linked_list authedcells;	/* List of cells already logged to */
  
  static int usev5 = TRUE;   /* use kerberos 5? */
  static krb5_ccache _krb425_ccache;
  
  long GetLocalCell(struct afsconf_dir **pconfigdir, char *local_cell)
  {
! 	if (!(*pconfigdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH)))
! 	{
! 		fprintf(stderr, "%s: can't get afs configuration (afsconf_Open(%s))\n",
! 			progname, AFSDIR_CLIENT_ETC_DIRPATH);
! 		exit(AKLOG_AFS);
! 	}
  
! 	return afsconf_GetLocalCell(*pconfigdir, local_cell, MAXCELLCHARS);
  }
  
  long GetCellInfo(struct afsconf_dir **pconfigdir, char* cell, 
  struct afsconf_cell **pcellconfig)
  {
! 	return afsconf_GetCellInfo(*pconfigdir, cell, NULL, *pcellconfig);
  }
  
  void CloseConf(struct afsconf_dir **pconfigdir)
! {
! 	(void) afsconf_Close(*pconfigdir);
  }
  
  #define ALLOW_REGISTER 1
--- 148,177 ----
  static linked_list authedcells;	/* List of cells already logged to */
  
  static int usev5 = TRUE;   /* use kerberos 5? */
+ static int use524 = FALSE;  /* use krb524? */
  static krb5_ccache _krb425_ccache;
  
  long GetLocalCell(struct afsconf_dir **pconfigdir, char *local_cell)
  {
!     if (!(*pconfigdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH)))
!     {
!         fprintf(stderr, "%s: can't get afs configuration (afsconf_Open(%s))\n",
!                  progname, AFSDIR_CLIENT_ETC_DIRPATH);
!         exit(AKLOG_AFS);
!     }
  
!     return afsconf_GetLocalCell(*pconfigdir, local_cell, MAXCELLCHARS);
  }
  
  long GetCellInfo(struct afsconf_dir **pconfigdir, char* cell, 
  struct afsconf_cell **pcellconfig)
  {
!     return afsconf_GetCellInfo(*pconfigdir, cell, NULL, *pcellconfig);
  }
  
  void CloseConf(struct afsconf_dir **pconfigdir)
! {       
!     (void) afsconf_Close(*pconfigdir);
  }
  
  #define ALLOW_REGISTER 1
***************
*** 182,188 ****
      static char lastcell[MAXCELLCHARS+1] = { 0 };
      static char confname[512] = { 0 };
      char username_copy[BUFSIZ];
! 	long viceId;			/* AFS uid of user */
  #ifdef ALLOW_REGISTER
      afs_int32 id;
  #endif /* ALLOW_REGISTER */
--- 183,189 ----
      static char lastcell[MAXCELLCHARS+1] = { 0 };
      static char confname[512] = { 0 };
      char username_copy[BUFSIZ];
!     long viceId;			/* AFS uid of user */
  #ifdef ALLOW_REGISTER
      afs_int32 id;
  #endif /* ALLOW_REGISTER */
***************
*** 192,199 ****
          confname[sizeof(confname) - 2] = '\0';
      }
  
! 	if (dflag)
! 		printf("About to resolve name %s to id\n", username);
  
      /*
      * Talk about DUMB!  It turns out that there is a bug in
--- 193,200 ----
          confname[sizeof(confname) - 2] = '\0';
      }
  
!     if (dflag)
!         printf("About to resolve name %s to id\n", username);
  
      /*
      * Talk about DUMB!  It turns out that there is a bug in
***************
*** 217,247 ****
  
      strcpy(lastcell, aserver-&gt;cell);
  
! 	if (!pr_Initialize (0, confname, aserver-&gt;cell))
! 		*status = pr_SNameToId (username, &amp;viceId);
  
! 	if (dflag)
! 	{
! 		if (*status)
! 			printf("Error %d\n", *status);
! 		else
! 			printf("Id %d\n", viceId);
! 	}
  
! 	/*
! 	* This is a crock, but it is Transarc's crock, so
! 	* we have to play along in order to get the
! 	* functionality.  The way the afs id is stored is
! 	* as a string in the username field of the token.
! 	* Contrary to what you may think by looking at
! 	* the code for tokens, this hack (AFS ID %d) will
! 	* not work if you change %d to something else.
! 	*/
  
      /*
!     * This code is taken from cklog -- it lets people
!     * automatically register with the ptserver in foreign cells
!     */
  
  #ifdef ALLOW_REGISTER
      if (*status == 0) {
--- 218,248 ----
  
      strcpy(lastcell, aserver-&gt;cell);
  
!     if (!pr_Initialize (0, confname, aserver-&gt;cell))
!         *status = pr_SNameToId (username, &amp;viceId);
  
!     if (dflag)
!     {
!         if (*status)
!             printf("Error %d\n", *status);
!         else
!             printf("Id %d\n", viceId);
!     }       
  
!     /*
!      * This is a crock, but it is Transarc's crock, so
!      * we have to play along in order to get the
!      * functionality.  The way the afs id is stored is
!      * as a string in the username field of the token.
!      * Contrary to what you may think by looking at
!      * the code for tokens, this hack (AFS ID %d) will
!      * not work if you change %d to something else.
!      */
  
      /*
!      * This code is taken from cklog -- it lets people
!      * automatically register with the ptserver in foreign cells
!      */
  
  #ifdef ALLOW_REGISTER
      if (*status == 0) {
***************
*** 256,346 ****
  #endif /* AFS_ID_TO_NAME */
              }
  #ifdef ALLOW_REGISTER
!             } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
!                 if (dflag) {
!                     printf("doing first-time registration of %s "
!                             "at %s\n", username, cell_to_use);
!                 }
!                 id = 0;
!                 strncpy(aclient-&gt;name, username, MAXKTCNAMELEN - 1);
!                 strcpy(aclient-&gt;instance, "");
!                 strncpy(aclient-&gt;cell, c-&gt;realm, MAXKTCREALMLEN - 1);
!                 if ((*status = ktc_SetToken(aserver, atoken, aclient, 0))) {
!                     printf("%s: unable to obtain tokens for cell %s "
!                             "(status: %d).\n", progname, cell_to_use, status);
!                     *status = AKLOG_TOKEN;
                  return ;
!                 }
  
!                 /*
!                  * In case you're wondering, we don't need to change the
!                  * filename here because we're still connecting to the
!                  * same cell -- we're just using a different authentication
!                  * level
!                  */
  
!                 if ((*status = pr_Initialize(1L, confname, aserver-&gt;cell, 0))) {
!                     printf("Error %d\n", status);
                  return;
!                 }
  
!                 if ((*status = pr_CreateUser(username, &amp;id))) {
!                     printf("%s: unable to create remote PTS "
!                             "user %s in cell %s (status: %d).\n", progname,
!                             username, cell_to_use, *status);
!                 } else {
!                     printf("created cross-cell entry for %s at %s\n",
!                             username, cell_to_use);
  #ifdef AFS_ID_TO_NAME
                  strncpy(username_copy, username, BUFSIZ);
                  snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
  #endif /* AFS_ID_TO_NAME */
-                 }
              }
          }
  #endif /* ALLOW_REGISTER */
  }
  
  char *LastComponent(char *str)
  {
! 	char *ret = strrchr(str, DIR);
  
  #ifdef WIN32
! 	if (!ret)
! 		ret = strrchr(str, BDIR);
  #endif
! 	return ret;
  }
  
  int FirstComponent(char *str)
  {
! 	return (int)(
  #ifdef WIN32
! 		strchr(str, BDIR) ||
  #endif
! 		strchr(str, DIR));
  }
  
  void CopyPathColon(char *origpath, char *path, char *pathtocheck)
  {
  #ifdef WIN32
! 	if (origpath[1] == DRIVECOLON)
! 	{
! 		strncpy(pathtocheck, origpath, 2);
! 		strcpy(path, origpath+2);
! 	}
! 	else
  #endif
! 		strcpy(path, origpath);
  }
  
  int BeginsWithDir(char *str, int colon)
  {
! 	return (str[0] == DIR) ||
  #ifdef WIN32
! 		((str[0] == BDIR) || (colon &amp;&amp; str[1] == DRIVECOLON));
  #else
! 		FALSE;
  #endif
  }
  
--- 257,347 ----
  #endif /* AFS_ID_TO_NAME */
              }
  #ifdef ALLOW_REGISTER
!         } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
!             if (dflag) {
!                 printf("doing first-time registration of %s "
!                         "at %s\n", username, cell_to_use);
!             }
!             id = 0;
!             strncpy(aclient-&gt;name, username, MAXKTCNAMELEN - 1);
!             strcpy(aclient-&gt;instance, "");
!             strncpy(aclient-&gt;cell, c-&gt;realm, MAXKTCREALMLEN - 1);
!             if ((*status = ktc_SetToken(aserver, atoken, aclient, 0))) {
!                 printf("%s: unable to obtain tokens for cell %s "
!                         "(status: %d).\n", progname, cell_to_use, status);
!                 *status = AKLOG_TOKEN;
                  return ;
!             }
  
!             /*
!              * In case you're wondering, we don't need to change the
!              * filename here because we're still connecting to the
!              * same cell -- we're just using a different authentication
!              * level
!              */
  
!             if ((*status = pr_Initialize(1L, confname, aserver-&gt;cell, 0))) {
!                 printf("Error %d\n", status);
                  return;
!             }
  
!             if ((*status = pr_CreateUser(username, &amp;id))) {
!                 printf("%s: unable to create remote PTS "
!                         "user %s in cell %s (status: %d).\n", progname,
!                         username, cell_to_use, *status);
!             } else {
!                 printf("created cross-cell entry for %s at %s\n",
!                         username, cell_to_use);
  #ifdef AFS_ID_TO_NAME
                  strncpy(username_copy, username, BUFSIZ);
                  snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
  #endif /* AFS_ID_TO_NAME */
              }
          }
+     }
  #endif /* ALLOW_REGISTER */
  }
  
  char *LastComponent(char *str)
  {
!     char *ret = strrchr(str, DIR);
  
  #ifdef WIN32
!     if (!ret)
!         ret = strrchr(str, BDIR);
  #endif
!     return ret;
  }
  
  int FirstComponent(char *str)
  {
!     return (int)(
  #ifdef WIN32
!                 strchr(str, BDIR) ||
  #endif
!                 strchr(str, DIR));
  }
  
  void CopyPathColon(char *origpath, char *path, char *pathtocheck)
  {
  #ifdef WIN32
!     if (origpath[1] == DRIVECOLON)
!     {
!         strncpy(pathtocheck, origpath, 2);
!         strcpy(path, origpath+2);
!     }
!     else
  #endif
!         strcpy(path, origpath);
  }
  
  int BeginsWithDir(char *str, int colon)
  {
!     return (str[0] == DIR) ||
  #ifdef WIN32
!         ((str[0] == BDIR) || (colon &amp;&amp; str[1] == DRIVECOLON));
  #else
!     FALSE;
  #endif
  }
  
***************
*** 356,387 ****
  */
  int des_pcbc_init()
  {
! 	abort();
  }
  
  static int get_cred(char *name, char *inst, char *realm, CREDENTIALS *c)
  {
! 	int status;
  
! 	status = krb_get_cred(name, inst, realm, c);
! 	if (status != KSUCCESS)
! 	{
  #ifdef DONT_HAVE_GET_AD_TKT
! 		KTEXT_ST ticket;
! 		status = krb_mk_req(&amp;ticket, name, inst, realm, 0);
  #else
! 		status = get_ad_tkt(name, inst, realm, 255);
  #endif
! 		if (status == KSUCCESS)
! 			status = krb_get_cred(name, inst, realm, c);
! 	}
  
! 	return (status);
  }
  
  static int get_v5cred(krb5_context context, 
! 			char *name, char *inst, char *realm, CREDENTIALS *c,
! 			krb5_creds **creds)
  {
      krb5_creds increds;
      krb5_error_code r;
--- 357,388 ----
  */
  int des_pcbc_init()
  {
!     abort();
  }
  
  static int get_cred(char *name, char *inst, char *realm, CREDENTIALS *c)
  {
!     int status;
  
!     status = krb_get_cred(name, inst, realm, c);
!     if (status != KSUCCESS)
!     {
  #ifdef DONT_HAVE_GET_AD_TKT
!         KTEXT_ST ticket;
!         status = krb_mk_req(&amp;ticket, name, inst, realm, 0);
  #else
!         status = get_ad_tkt(name, inst, realm, 255);
  #endif
!         if (status == KSUCCESS)
!             status = krb_get_cred(name, inst, realm, c);
!     }       
  
!     return (status);
  }
  
  static int get_v5cred(krb5_context context, 
!                       char *name, char *inst, char *realm, CREDENTIALS *c,
!                       krb5_creds **creds)
  {
      krb5_creds increds;
      krb5_error_code r;
***************
*** 389,399 ****
  
      memset((char *)&amp;increds, 0, sizeof(increds));
  
! 	if ((r = krb5_build_principal(context, &amp;increds.server,
!                      strlen(realm), realm,
!                      name,
!            (inst &amp;&amp; strlen(inst)) ? inst : 0,
!                      0))) {
          return((int)r);
      }
  
--- 390,400 ----
  
      memset((char *)&amp;increds, 0, sizeof(increds));
  
!     if ((r = krb5_build_principal(context, &amp;increds.server,
!                                   strlen(realm), realm,
!                                   name,
!                                   (inst &amp;&amp; strlen(inst)) ? inst : 0,
!                                   0))) {
          return((int)r);
      }
  
***************
*** 547,683 ****
  * to.  */
  static int auth_to_cell(krb5_context context, char *cell, char *realm)
  {
! 	int status = AKLOG_SUCCESS;
! 	char username[BUFSIZ];	/* To hold client username structure */
  
! 	char name[ANAME_SZ];		/* Name of afs key */
! 	char instance[INST_SZ];	/* Instance of afs key */
! 	char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
! 	char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
! 	char local_cell[MAXCELLCHARS+1];
! 	char cell_to_use[MAXCELLCHARS+1]; /* Cell to authenticate to */
! 
! 	krb5_creds *v5cred = NULL;
! 	CREDENTIALS c;
! 	struct ktc_principal aserver;
! 	struct ktc_principal aclient;
! 	struct ktc_token atoken, btoken;
! 
! 
! 	/* try to avoid an expensive call to get_cellconfig */
! 	if (cell &amp;&amp; ll_string_check(&amp;authedcells, cell))
! 	{
! 		if (dflag)
! 			printf("Already authenticated to %s (or tried to)\n", cell);
! 		return(AKLOG_SUCCESS);
! 	}
! 
! 	memset(name, 0, sizeof(name));
! 	memset(instance, 0, sizeof(instance));
! 	memset(realm_of_user, 0, sizeof(realm_of_user));
! 	memset(realm_of_cell, 0, sizeof(realm_of_cell));
! 
! 	/* NULL or empty cell returns information on local cell */
! 	if (status = get_cellconfig(cell, &amp;ak_cellconfig, local_cell))
! 		return(status);
  
! 	strncpy(cell_to_use, ak_cellconfig.name, MAXCELLCHARS);
! 	cell_to_use[MAXCELLCHARS] = 0;
  
! 	if (ll_string_check(&amp;authedcells, cell_to_use))
! 	{
! 		if (dflag)
! 			printf("Already authenticated to %s (or tried to)\n", cell_to_use);
! 		return(AKLOG_SUCCESS);
! 	}
  
! 	/*
! 	* Record that we have attempted to log to this cell.  We do this
! 	* before we try rather than after so that we will not try
! 	* and fail repeatedly for one cell.
! 	*/
! 	(void)ll_add_string(&amp;authedcells, cell_to_use);
! 
! 	if (dflag)
! 		printf("Authenticating to cell %s.\n", cell_to_use);
! 
! 	if (realm &amp;&amp; realm[0])
! 		strcpy(realm_of_cell, realm);
! 	else
! 		strcpy(realm_of_cell,
! 			(usev5)? 
! 				afs_realm_of_cell5(context, &amp;ak_cellconfig) : 
! 				afs_realm_of_cell(&amp;ak_cellconfig));
! 
! 	/* We use the afs.&lt;cellname&gt; convention here... */
! 	strcpy(name, AFSKEY);
! 	strncpy(instance, cell_to_use, sizeof(instance));
! 	instance[sizeof(instance)-1] = '\0';
! 
! 	/*
! 	* Extract the session key from the ticket file and hand-frob an
! 	* afs style authenticator.
! 	*/
  
! 	if (usev5) 
! 	{ /* using krb5 */
          int retry = 1;
  
        try_v5:
! 		if (dflag)
! 			printf("Getting v5 tickets: %s/%s@%s\n", name, instance, realm_of_cell);
! 		status = get_v5cred(context, name, instance, realm_of_cell, NULL, &amp;v5cred);
! 		if (status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
! 			if (dflag)
! 				printf("Getting v5 tickets: %s@%s\n", name, realm_of_cell);
! 			status = get_v5cred(context, name, "", realm_of_cell, NULL, &amp;v5cred);
! 		}
          if ( status == KRB5KRB_AP_ERR_MSG_TYPE &amp;&amp; retry ) {
              retry = 0;
              goto try_v5;
          }
! 	}
! 	else 
! 	{
! 		/*
! 		* Try to obtain AFS tickets.  Because there are two valid service
! 		* names, we will try both, but trying the more specific first.
! 		*
! 		* 	afs.&lt;cell&gt;@&lt;realm&gt;
! 		* 	afs@&lt;realm&gt;
! 		*/
! 		if (dflag)
! 			printf("Getting tickets: %s.%s@%s\n", name, instance, realm_of_cell);
! 		status = get_cred(name, instance, realm_of_cell, &amp;c);
! 		if (status == KDC_PR_UNKNOWN)
! 		{
! 			if (dflag)
! 				printf("Getting tickets: %s@%s\n", name, realm_of_cell);
! 			status = get_cred(name, "", realm_of_cell, &amp;c);
! 		}
! 	} 
  
! 	/* TODO: get k5 error text */
! 	if (status != KSUCCESS)
! 	{
! 		if (dflag)
! 			printf("Kerberos error code returned by get_cred: %d\n", status);
! 		fprintf(stderr, "%s: Couldn't get %s AFS tickets: %s\n",
! 			progname, cell_to_use, 
! 			(usev5)?"":
! 			krb_err_text(status));
! 		return(AKLOG_KERBEROS);
! 	}
  
! 	strncpy(aserver.name, AFSKEY, MAXKTCNAMELEN - 1);
! 	strncpy(aserver.instance, AFSINST, MAXKTCNAMELEN - 1);
! 	strncpy(aserver.cell, cell_to_use, MAXKTCREALMLEN - 1);
  
!     if (usev5) {
          /* This code inserts the entire K5 ticket into the token
!         * No need to perform a krb524 translation which is
!         * commented out in the code below
!         */
          char * p;
          int len;
          
--- 548,692 ----
  * to.  */
  static int auth_to_cell(krb5_context context, char *cell, char *realm)
  {
!     int status = AKLOG_SUCCESS;
!     char username[BUFSIZ];	/* To hold client username structure */
  
!     char name[ANAME_SZ];		/* Name of afs key */
!     char instance[INST_SZ];	/* Instance of afs key */
!     char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
!     char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
!     char local_cell[MAXCELLCHARS+1];
!     char cell_to_use[MAXCELLCHARS+1]; /* Cell to authenticate to */
! 
!     krb5_creds *v5cred = NULL;
!     CREDENTIALS c;
!     struct ktc_principal aserver;
!     struct ktc_principal aclient;
!     struct ktc_token atoken, btoken;
! 
! 
!     /* try to avoid an expensive call to get_cellconfig */
!     if (cell &amp;&amp; ll_string_check(&amp;authedcells, cell))
!     {
!         if (dflag)
!             printf("Already authenticated to %s (or tried to)\n", cell);
!         return(AKLOG_SUCCESS);
!     }
  
!     memset(name, 0, sizeof(name));
!     memset(instance, 0, sizeof(instance));
!     memset(realm_of_user, 0, sizeof(realm_of_user));
!     memset(realm_of_cell, 0, sizeof(realm_of_cell));
! 
!     /* NULL or empty cell returns information on local cell */
!     if (status = get_cellconfig(cell, &amp;ak_cellconfig, local_cell))
!         return(status);
! 
!     strncpy(cell_to_use, ak_cellconfig.name, MAXCELLCHARS);
!     cell_to_use[MAXCELLCHARS] = 0;
! 
!     if (ll_string_check(&amp;authedcells, cell_to_use))
!     {
!         if (dflag)
!             printf("Already authenticated to %s (or tried to)\n", cell_to_use);
!         return(AKLOG_SUCCESS);
!     }
  
!     /*
!      * Record that we have attempted to log to this cell.  We do this
!      * before we try rather than after so that we will not try
!      * and fail repeatedly for one cell.
!      */
!     (void)ll_add_string(&amp;authedcells, cell_to_use);
! 
!     if (dflag)
!         printf("Authenticating to cell %s.\n", cell_to_use);
! 
!     if (realm &amp;&amp; realm[0])
!         strcpy(realm_of_cell, realm);
!     else
!         strcpy(realm_of_cell,
!                 (usev5)? 
!                 afs_realm_of_cell5(context, &amp;ak_cellconfig) : 
!                 afs_realm_of_cell(&amp;ak_cellconfig));
! 
!     /* We use the afs.&lt;cellname&gt; convention here... */
!     strcpy(name, AFSKEY);
!     strncpy(instance, cell_to_use, sizeof(instance));
!     instance[sizeof(instance)-1] = '\0';
  
!     /*
!      * Extract the session key from the ticket file and hand-frob an
!      * afs style authenticator.
!      */
  
!     if (usev5) 
!     { /* using krb5 */
          int retry = 1;
  
+         if ( strchr(name,'.') != NULL ) {
+             fprintf(stderr, "%s: Can't support principal names including a dot.\n",
+                     progname);
+             return(AKLOG_MISC);
+         }
+ 
        try_v5:
!         if (dflag)
!             printf("Getting v5 tickets: %s/%s@%s\n", name, instance, realm_of_cell);
!         status = get_v5cred(context, name, instance, realm_of_cell, 
!                             use524 ? &amp;c : NULL, &amp;v5cred);
!         if (status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
!             if (dflag)
!                 printf("Getting v5 tickets: %s@%s\n", name, realm_of_cell);
!             status = get_v5cred(context, name, "", realm_of_cell, 
!                                 use524 ? &amp;c : NULL, &amp;v5cred);
!         }
          if ( status == KRB5KRB_AP_ERR_MSG_TYPE &amp;&amp; retry ) {
              retry = 0;
              goto try_v5;
+         }       
+     }       
+     else 
+     {
+         /*
+          * Try to obtain AFS tickets.  Because there are two valid service
+          * names, we will try both, but trying the more specific first.
+          *
+          * 	afs.&lt;cell&gt;@&lt;realm&gt;
+          * 	afs@&lt;realm&gt;
+          */
+         if (dflag)
+             printf("Getting tickets: %s.%s@%s\n", name, instance, realm_of_cell);
+         status = get_cred(name, instance, realm_of_cell, &amp;c);
+         if (status == KDC_PR_UNKNOWN)
+         {
+             if (dflag)
+                 printf("Getting tickets: %s@%s\n", name, realm_of_cell);
+             status = get_cred(name, "", realm_of_cell, &amp;c);
          }
!     } 
  
!     /* TODO: get k5 error text */
!     if (status != KSUCCESS)
!     {
!         if (dflag)
!             printf("Kerberos error code returned by get_cred: %d\n", status);
!         fprintf(stderr, "%s: Couldn't get %s AFS tickets: %s\n",
!                  progname, cell_to_use, 
!                  (usev5)?"":
!                  krb_err_text(status));
!         return(AKLOG_KERBEROS);
!     }
  
!     strncpy(aserver.name, AFSKEY, MAXKTCNAMELEN - 1);
!     strncpy(aserver.instance, AFSINST, MAXKTCNAMELEN - 1);
!     strncpy(aserver.cell, cell_to_use, MAXKTCREALMLEN - 1);
  
!     if (usev5 &amp;&amp; !use524) {
          /* This code inserts the entire K5 ticket into the token
!          * No need to perform a krb524 translation which is
!          * commented out in the code below
!          */
          char * p;
          int len;
          
***************
*** 718,848 ****
          memcpy(atoken.ticket, c.ticket_st.dat, atoken.ticketLen);
      }
  
! 	if (!force &amp;&amp;
! 		!ktc_GetToken(&amp;aserver, &amp;btoken, sizeof(btoken), &amp;aclient) &amp;&amp;
! 		atoken.kvno == btoken.kvno &amp;&amp;
! 		atoken.ticketLen == btoken.ticketLen &amp;&amp;
! 		!memcmp(&amp;atoken.sessionKey, &amp;btoken.sessionKey, sizeof(atoken.sessionKey)) &amp;&amp;
! 		!memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
! 	{
! 		if (dflag)
! 			printf("Identical tokens already exist; skipping.\n");
! 		return 0;
! 	}
  
! 	if (noprdb)
! 	{
! 		if (dflag)
! 			printf("Not resolving name %s to id (-noprdb set)\n", username);
! 	}
! 	else
! 	{
! 		if(usev5) {
! 			if((status = get_v5_user_realm(context, realm_of_user)) != KSUCCESS) {
! 				fprintf(stderr, "%s: Couldn't determine realm of user: %d\n",
! 					progname, status);
! 				return(AKLOG_KERBEROS);
! 			}
          } else {
! 			if ((status = krb_get_tf_realm(TKT_FILE, realm_of_user)) != KSUCCESS)
! 			{
! 				fprintf(stderr, "%s: Couldn't determine realm of user: %s)",
! 					progname, krb_err_text(status));
! 				return(AKLOG_KERBEROS);
! 			}
! 		}
  
! 		if (strcmp(realm_of_user, realm_of_cell))
! 		{
! 			strcat(username, "@");
! 			strcat(username, realm_of_user);
! 		}
  
! 		ViceIDToUsername(username, realm_of_user, realm_of_cell, cell_to_use, &amp;c, &amp;status, &amp;aclient, &amp;aserver, &amp;atoken);
! 	}
  
! 	if (dflag)
! 		printf("Set username to %s\n", username);
  
! 	/* Reset the "aclient" structure before we call ktc_SetToken.
! 	* This structure was first set by the ktc_GetToken call when
! 	* we were comparing whether identical tokens already existed.
! 	*/
! 	strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
! 	strcpy(aclient.instance, "");
      
!     if (usev5) {
          int len = min(v5cred-&gt;client-&gt;realm.length,MAXKTCNAMELEN - 1);
          strncpy(aclient.cell, v5cred-&gt;client-&gt;realm.data, len);
          aclient.cell[len] = '\0';
      } else
  	strncpy(aclient.cell, c.realm, MAXKTCREALMLEN - 1);
  
! 	if (dflag)
! 		printf("Getting tokens.\n");
! 	if (status = ktc_SetToken(&amp;aserver, &amp;atoken, &amp;aclient, 0))
! 	{
! 		fprintf(stderr,
! 			"%s: unable to obtain tokens for cell %s (status: %d).\n",
! 			progname, cell_to_use, status);
! 		status = AKLOG_TOKEN;
! 	}
  
! 	return(status);
  }
  
  static int get_afs_mountpoint(char *file, char *mountpoint, int size)
  {
! 	char our_file[MAXPATHLEN + 1];
! 	char *parent_dir;
! 	char *last_component;
! 	struct ViceIoctl vio;
! 	char cellname[BUFSIZ];
! 
! 	memset(our_file, 0, sizeof(our_file));
! 	strcpy(our_file, file);
! 
! 	if (last_component = LastComponent(our_file))
! 	{
! 		*last_component++ = 0;
! 		parent_dir = our_file;
! 	}
! 	else
! 	{
! 		last_component = our_file;
! 		parent_dir = ".";
! 	}
  
! 	memset(cellname, 0, sizeof(cellname));
  
! 	vio.in = last_component;
! 	vio.in_size = strlen(last_component)+1;
! 	vio.out_size = size;
! 	vio.out = mountpoint;
  
! 	if (!pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &amp;vio, 0))
! 	{
! 		if (strchr(mountpoint, VOLMARKER) == NULL)
! 		{
! 			vio.in = file;
! 			vio.in_size = strlen(file) + 1;
! 			vio.out_size = sizeof(cellname);
! 			vio.out = cellname;
! 
! 			if (!pioctl(file, VIOC_FILE_CELL_NAME, &amp;vio, 1))
! 			{
! 				strcat(cellname, VOLMARKERSTRING);
! 				strcat(cellname, mountpoint + 1);
! 				memset(mountpoint + 1, 0, size - 1);
! 				strcpy(mountpoint + 1, cellname);
! 			}
! 		}
! 		return(TRUE);
! 	}
! 	else {
! 		return(FALSE);
! 	}
! }
  
  /*
  * This routine each time it is called returns the next directory
--- 727,857 ----
          memcpy(atoken.ticket, c.ticket_st.dat, atoken.ticketLen);
      }
  
!     if (!force &amp;&amp;
!          !ktc_GetToken(&amp;aserver, &amp;btoken, sizeof(btoken), &amp;aclient) &amp;&amp;
!          atoken.kvno == btoken.kvno &amp;&amp;
!          atoken.ticketLen == btoken.ticketLen &amp;&amp;
!          !memcmp(&amp;atoken.sessionKey, &amp;btoken.sessionKey, sizeof(atoken.sessionKey)) &amp;&amp;
!          !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
!     {       
!         if (dflag)
!             printf("Identical tokens already exist; skipping.\n");
!         return 0;
!     }
  
!     if (noprdb)
!     {
!         if (dflag)
!             printf("Not resolving name %s to id (-noprdb set)\n", username);
!     }       
!     else    
!     {
!         if (usev5) {
!             if((status = get_v5_user_realm(context, realm_of_user)) != KSUCCESS) {
!                 fprintf(stderr, "%s: Couldn't determine realm of user: %d\n",
!                          progname, status);
!                 return(AKLOG_KERBEROS);
!             }
          } else {
!             if ((status = krb_get_tf_realm(TKT_FILE, realm_of_user)) != KSUCCESS)
!             {
!                 fprintf(stderr, "%s: Couldn't determine realm of user: %s)",
!                          progname, krb_err_text(status));
!                 return(AKLOG_KERBEROS);
!             }
!         }
  
!         if (strcmp(realm_of_user, realm_of_cell))
!         {
!             strcat(username, "@");
!             strcat(username, realm_of_user);
!         }
  
!         ViceIDToUsername(username, realm_of_user, realm_of_cell, cell_to_use, &amp;c, &amp;status, &amp;aclient, &amp;aserver, &amp;atoken);
!     }
  
!     if (dflag)
!         printf("Set username to %s\n", username);
  
!     /* Reset the "aclient" structure before we call ktc_SetToken.
!      * This structure was first set by the ktc_GetToken call when
!      * we were comparing whether identical tokens already existed.
!      */
!     strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
!     strcpy(aclient.instance, "");
      
!     if (usev5 &amp;&amp; !use524) {
          int len = min(v5cred-&gt;client-&gt;realm.length,MAXKTCNAMELEN - 1);
          strncpy(aclient.cell, v5cred-&gt;client-&gt;realm.data, len);
          aclient.cell[len] = '\0';
      } else
  	strncpy(aclient.cell, c.realm, MAXKTCREALMLEN - 1);
  
!     if (dflag)
!         printf("Getting tokens.\n");
!     if (status = ktc_SetToken(&amp;aserver, &amp;atoken, &amp;aclient, 0))
!     {
!         fprintf(stderr,
!                  "%s: unable to obtain tokens for cell %s (status: %d).\n",
!                  progname, cell_to_use, status);
!         status = AKLOG_TOKEN;
!     }
  
!     return(status);
  }
  
  static int get_afs_mountpoint(char *file, char *mountpoint, int size)
  {
!     char our_file[MAXPATHLEN + 1];
!     char *parent_dir;
!     char *last_component;
!     struct ViceIoctl vio;
!     char cellname[BUFSIZ];
! 
!     memset(our_file, 0, sizeof(our_file));
!     strcpy(our_file, file);
! 
!     if (last_component = LastComponent(our_file))
!     {
!         *last_component++ = 0;
!         parent_dir = our_file;
!     }
!     else
!     {
!         last_component = our_file;
!         parent_dir = ".";
!     }
  
!     memset(cellname, 0, sizeof(cellname));
  
!     vio.in = last_component;
!     vio.in_size = strlen(last_component)+1;
!     vio.out_size = size;
!     vio.out = mountpoint;
! 
!     if (!pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &amp;vio, 0))
!     {
!         if (strchr(mountpoint, VOLMARKER) == NULL)
!         {
!             vio.in = file;
!             vio.in_size = strlen(file) + 1;
!             vio.out_size = sizeof(cellname);
!             vio.out = cellname;
  
!             if (!pioctl(file, VIOC_FILE_CELL_NAME, &amp;vio, 1))
!             {
!                 strcat(cellname, VOLMARKERSTRING);
!                 strcat(cellname, mountpoint + 1);
!                 memset(mountpoint + 1, 0, size - 1);
!                 strcpy(mountpoint + 1, cellname);
!             }
!         }
!         return(TRUE);
!     }
!     else {
!         return(FALSE);
!     }
! }       
  
  /*
  * This routine each time it is called returns the next directory
***************
*** 853,944 ****
  */
  static char *next_path(char *origpath)
  {
! 	static char path[MAXPATHLEN + 1];
! 	static char pathtocheck[MAXPATHLEN + 1];
! 
! 	int link = FALSE;		/* Is this a symbolic link? */
! 	char linkbuf[MAXPATHLEN + 1];
! 	char tmpbuf[MAXPATHLEN + 1];
! 
! 	static char *last_comp;	/* last component of directory name */
! 	static char *elast_comp;	/* End of last component */
! 	char *t;
! 	int len;
! 
! 	static int symlinkcount = 0;	/* We can't exceed MAXSYMLINKS */
  
! 	/* If we are given something for origpath, we are initializing only. */
! 	if (origpath)
! 	{
! 		memset(path, 0, sizeof(path));
! 		memset(pathtocheck, 0, sizeof(pathtocheck));
! 		CopyPathColon(origpath, path, pathtocheck);
! 		last_comp = path;
! 		symlinkcount = 0;
! 		return(NULL);
! 	}
! 
! 	/* We were not given origpath; find then next path to check */
  
! 	/* If we've gotten all the way through already, return NULL */
! 	if (last_comp == NULL)
! 		return(NULL);
  
! 	do
! 	{
! 		while (BeginsWithDir(last_comp, FALSE))
! 			strncat(pathtocheck, last_comp++, 1);
! 		len = (elast_comp = LastComponent(last_comp))
! 			? elast_comp - last_comp : strlen(last_comp);
! 		strncat(pathtocheck, last_comp, len);
! 		memset(linkbuf, 0, sizeof(linkbuf));
! 		if (link = (readlink(pathtocheck, linkbuf, sizeof(linkbuf)) &gt; 0))
! 		{
! 			if (++symlinkcount &gt; MAXSYMLINKS)
! 			{
! 				fprintf(stderr, "%s: %s\n", progname, strerror(ELOOP));
! 				exit(AKLOG_BADPATH);
! 			}
! 			memset(tmpbuf, 0, sizeof(tmpbuf));
! 			if (elast_comp)
! 				strcpy(tmpbuf, elast_comp);
! 			if (BeginsWithDir(linkbuf, FALSE))
! 			{
! 				/*
! 				* If this is a symbolic link to an absolute path,
! 				* replace what we have by the absolute path.
! 				*/
! 				memset(path, 0, strlen(path));
! 				memcpy(path, linkbuf, sizeof(linkbuf));
! 				strcat(path, tmpbuf);
! 				last_comp = path;
! 				elast_comp = NULL;
! 				memset(pathtocheck, 0, sizeof(pathtocheck));
! 			}
! 			else
! 			{
! 				/*
! 				* If this is a symbolic link to a relative path,
! 				* replace only the last component with the link name.
! 				*/
! 				strncpy(last_comp, linkbuf, strlen(linkbuf) + 1);
! 				strcat(path, tmpbuf);
! 				elast_comp = NULL;
! 				if (t = LastComponent(pathtocheck))
! 				{
! 					t++;
! 					memset(t, 0, strlen(t));
! 				}
! 				else
! 					memset(pathtocheck, 0, sizeof(pathtocheck));
! 			}
! 		}
! 		else
! 			last_comp = elast_comp;
! 	}
! 	while(link);
  
! 	return(pathtocheck);
  }
  
  /*
--- 862,953 ----
  */
  static char *next_path(char *origpath)
  {
!     static char path[MAXPATHLEN + 1];
!     static char pathtocheck[MAXPATHLEN + 1];
  
!     int link = FALSE;		/* Is this a symbolic link? */
!     char linkbuf[MAXPATHLEN + 1];
!     char tmpbuf[MAXPATHLEN + 1];
! 
!     static char *last_comp;	/* last component of directory name */
!     static char *elast_comp;	/* End of last component */
!     char *t;
!     int len;
! 
!     static int symlinkcount = 0;	/* We can't exceed MAXSYMLINKS */
! 
!     /* If we are given something for origpath, we are initializing only. */
!     if (origpath)
!     {
!         memset(path, 0, sizeof(path));
!         memset(pathtocheck, 0, sizeof(pathtocheck));
!         CopyPathColon(origpath, path, pathtocheck);
!         last_comp = path;
!         symlinkcount = 0;
!         return(NULL);
!     }
  
!     /* We were not given origpath; find then next path to check */
  
!     /* If we've gotten all the way through already, return NULL */
!     if (last_comp == NULL)
!         return(NULL);
! 
!     do
!     {
!         while (BeginsWithDir(last_comp, FALSE))
!             strncat(pathtocheck, last_comp++, 1);
!         len = (elast_comp = LastComponent(last_comp))
!             ? elast_comp - last_comp : strlen(last_comp);
!         strncat(pathtocheck, last_comp, len);
!         memset(linkbuf, 0, sizeof(linkbuf));
!         if (link = (readlink(pathtocheck, linkbuf, sizeof(linkbuf)) &gt; 0))
!         {
!             if (++symlinkcount &gt; MAXSYMLINKS)
!             {
!                 fprintf(stderr, "%s: %s\n", progname, strerror(ELOOP));
!                 exit(AKLOG_BADPATH);
!             }
!             memset(tmpbuf, 0, sizeof(tmpbuf));
!             if (elast_comp)
!                 strcpy(tmpbuf, elast_comp);
!             if (BeginsWithDir(linkbuf, FALSE))
!             {
!                 /*
!                 * If this is a symbolic link to an absolute path,
!                 * replace what we have by the absolute path.
!                 */
!                 memset(path, 0, strlen(path));
!                 memcpy(path, linkbuf, sizeof(linkbuf));
!                 strcat(path, tmpbuf);
!                 last_comp = path;
!                 elast_comp = NULL;
!                 memset(pathtocheck, 0, sizeof(pathtocheck));
!             }
!             else
!             {
!                 /*
!                 * If this is a symbolic link to a relative path,
!                 * replace only the last component with the link name.
!                 */
!                 strncpy(last_comp, linkbuf, strlen(linkbuf) + 1);
!                 strcat(path, tmpbuf);
!                 elast_comp = NULL;
!                 if (t = LastComponent(pathtocheck))
!                 {
!                     t++;
!                     memset(t, 0, strlen(t));
!                 }
!                 else
!                     memset(pathtocheck, 0, sizeof(pathtocheck));
!             }
!         }
!         else
!             last_comp = elast_comp;
!     }       
!     while(link);
  
!     return(pathtocheck);
  }
  
  /*
***************
*** 947,1260 ****
  */
  static int auth_to_path(krb5_context context, char *path)
  {
! 	int status = AKLOG_SUCCESS;
! 	int auth_to_cell_status = AKLOG_SUCCESS;
  
! 	char *nextpath;
! 	char pathtocheck[MAXPATHLEN + 1];
! 	char mountpoint[MAXPATHLEN + 1];
! 
! 	char *cell;
! 	char *endofcell;
! 
! 	/* Initialize */
! 	if (BeginsWithDir(path, TRUE))
! 		strcpy(pathtocheck, path);
! 	else
! 	{
! 		if (getcwd(pathtocheck, sizeof(pathtocheck)) == NULL)
! 		{
! 			fprintf(stderr, "Unable to find current working directory:\n");
! 			fprintf(stderr, "%s\n", pathtocheck);
! 			fprintf(stderr, "Try an absolute pathname.\n");
! 			exit(AKLOG_BADPATH);
! 		}
! 		else
! 		{
! 			/* in WIN32, if getcwd returns a root dir (eg: c:\), the returned string
! 			* will already have a trailing slash ('\'). Otherwise, the string will
! 			* end in the last directory name */
! #ifdef WIN32
! 			if(pathtocheck[strlen(pathtocheck) - 1] != BDIR)
! #endif
! 				strcat(pathtocheck, DIRSTRING);
! 			strcat(pathtocheck, path);
! 		}
! 	}
! 	next_path(pathtocheck);
  
! 	/* Go on to the next level down the path */
! 	while (nextpath = next_path(NULL))
! 	{
! 		strcpy(pathtocheck, nextpath);
! 		if (dflag)
! 			printf("Checking directory [%s]\n", pathtocheck);
! 		/*
! 		* If this is an afs mountpoint, determine what cell from
! 		* the mountpoint name which is of the form
! 		* #cellname:volumename or %cellname:volumename.
! 		*/
! 		if (get_afs_mountpoint(pathtocheck, mountpoint, sizeof(mountpoint)))
! 		{
! 			if(dflag)
! 				printf("Found mount point [%s]\n", mountpoint);
! 			/* skip over the '#' or '%' */
! 			cell = mountpoint + 1;
! 			if (endofcell = strchr(mountpoint, VOLMARKER))
! 			{
! 				*endofcell = '\0';
! 				if (auth_to_cell_status = auth_to_cell(context, cell, NULL))
! 				{
! 					if (status == AKLOG_SUCCESS)
! 						status = auth_to_cell_status;
! 					else if (status != auth_to_cell_status)
! 						status = AKLOG_SOMETHINGSWRONG;
! 				}
! 			}
! 		}
! 		else
! 		{
! 			struct stat st;
  
! 			if (lstat(pathtocheck, &amp;st) &lt; 0)
! 			{
! 				/*
! 				* If we've logged and still can't stat, there's
! 				* a problem...
! 				*/
! 				fprintf(stderr, "%s: stat(%s): %s\n", progname,
! 					pathtocheck, strerror(errno));
! 				return(AKLOG_BADPATH);
! 			}
! 			else if (!S_ISDIR(st.st_mode))
! 			{
! 				/* Allow only directories */
! 				fprintf(stderr, "%s: %s: %s\n", progname, pathtocheck,
! 					strerror(ENOTDIR));
! 				return(AKLOG_BADPATH);
! 			}
! 		}
! 	}
  
! 	return(status);
  }
  
  /* Print usage message and exit */
  static void usage(void)
  {
! 	fprintf(stderr, "\nUsage: %s %s%s%s%s\n", progname,
! 		"[-d] [[-cell | -c] cell [-k krb_realm]] ",
! 		"[[-p | -path] pathname]\n",
! 		"    [-noprdb] [-force]\n",
! 		"    [-5 | -4]\n"
! 		);
! 	fprintf(stderr, "    -d gives debugging information.\n");
! 	fprintf(stderr, "    krb_realm is the kerberos realm of a cell.\n");
! 	fprintf(stderr, "    pathname is the name of a directory to which ");
! 	fprintf(stderr, "you wish to authenticate.\n");
! 	fprintf(stderr, "    -noprdb means don't try to determine AFS ID.\n");
! 	fprintf(stderr, "    -5 or -4 selects whether to use Kerberos V or Kerberos IV.\n"
! 					"       (default is Kerberos V)\n");
! 	fprintf(stderr, "    No commandline arguments means ");
! 	fprintf(stderr, "authenticate to the local cell.\n");
! 	fprintf(stderr, "\n");
! 	exit(AKLOG_USAGE);
  }
  
  int main(int argc, char *argv[])
  {
! 	int status = AKLOG_SUCCESS;
! 	int i;
! 	int somethingswrong = FALSE;
! 
! 	cellinfo_t cellinfo;
! 
! 	extern char *progname;	/* Name of this program */
! 
! 	extern int dflag;		/* Debug mode */
! 
! 	int cmode = FALSE;		/* Cellname mode */
! 	int pmode = FALSE;		/* Path name mode */
! 
! 	char realm[REALM_SZ];		/* Kerberos realm of afs server */
! 	char cell[BUFSIZ];		/* Cell to which we are authenticating */
! 	char path[MAXPATHLEN + 1];	/* Path length for path mode */
! 
! 	linked_list cells;		/* List of cells to log to */
! 	linked_list paths;		/* List of paths to log to */
! 	ll_node *cur_node;
! 
! 	krb5_context context = 0;
! 
! 	memset(&amp;cellinfo, 0, sizeof(cellinfo));
! 
! 	memset(realm, 0, sizeof(realm));
! 	memset(cell, 0, sizeof(cell));
! 	memset(path, 0, sizeof(path));
  
! 	ll_init(&amp;cells);
! 	ll_init(&amp;paths);
  
! 	/* Store the program name here for error messages */
! 	if (progname = LastComponent(argv[0]))
! 		progname++;
! 	else
! 		progname = argv[0];
  
! 	/* Initialize list of cells to which we have authenticated */
! 	(void)ll_init(&amp;authedcells);
  
! 	/* Parse commandline arguments and make list of what to do. */
! 	for (i = 1; i &lt; argc; i++)
! 	{
! 		if (strcmp(argv[i], "-d") == 0)
! 			dflag++;
! 		else if (strcmp(argv[i], "-5") == 0)
! 			usev5++;
! 		else if (strcmp(argv[i], "-4") == 0)
! 			usev5 = 0;
! 		else if (strcmp(argv[i], "-noprdb") == 0)
! 			noprdb++;
! 		else if (strcmp(argv[i], "-force") == 0)
! 			force++;
! 		else if (((strcmp(argv[i], "-cell") == 0) ||
! 			(strcmp(argv[i], "-c") == 0)) &amp;&amp; !pmode)
! 		{
! 			if (++i &lt; argc)
! 			{
! 				cmode++;
! 				strcpy(cell, argv[i]);
! 			}
! 			else
! 				usage();
! 		}
! 		else if (((strcmp(argv[i], "-path") == 0) ||
! 			(strcmp(argv[i], "-p") == 0)) &amp;&amp; !cmode)
! 		{
! 			if (++i &lt; argc)
! 			{
! 				pmode++;
! 				strcpy(path, argv[i]);
! 			}
! 			else
! 				usage();
! 		}
! 		else if (argv[i][0] == '-')
! 			usage();
! 		else if (!pmode &amp;&amp; !cmode)
! 		{
! 			if (FirstComponent(argv[i]) || (strcmp(argv[i], ".") == 0) ||
! 				(strcmp(argv[i], "..") == 0))
! 			{
! 				pmode++;
! 				strcpy(path, argv[i]);
! 			}
! 			else
! 			{
! 				cmode++;
! 				strcpy(cell, argv[i]);
! 			}
! 		}
! 		else
! 			usage();
  
! 		if (cmode)
! 		{
! 			if (((i + 1) &lt; argc) &amp;&amp; (strcmp(argv[i + 1], "-k") == 0))
! 			{
! 				i += 2;
! 				if (i &lt; argc)
! 					strcpy(realm, argv[i]);
! 				else
! 					usage();
! 			}
! 			/* Add this cell to list of cells */
! 			strcpy(cellinfo.cell, cell);
! 			strcpy(cellinfo.realm, realm);
! 			if (cur_node = ll_add_node(&amp;cells, ll_tail))
! 			{
! 				char *new_cellinfo;
! 				if (new_cellinfo = copy_cellinfo(&amp;cellinfo))
! 					ll_add_data(cur_node, new_cellinfo);
! 				else
! 				{
! 					fprintf(stderr, "%s: failure copying cellinfo.\n", progname);
! 					exit(AKLOG_MISC);
! 				}
! 			}
! 			else
! 			{
! 				fprintf(stderr, "%s: failure adding cell to cells list.\n",
! 					progname);
! 				exit(AKLOG_MISC);
! 			}
! 			memset(&amp;cellinfo, 0, sizeof(cellinfo));
! 			cmode = FALSE;
! 			memset(cell, 0, sizeof(cell));
! 			memset(realm, 0, sizeof(realm));
! 		}
! 		else if (pmode)
! 		{
! 			/* Add this path to list of paths */
! 			if (cur_node = ll_add_node(&amp;paths, ll_tail))
! 			{
! 				char *new_path;
! 				if (new_path = copy_string(path))
! 					ll_add_data(cur_node, new_path);
! 				else
! 				{
! 					fprintf(stderr, "%s: failure copying path name.\n",
! 						progname);
! 					exit(AKLOG_MISC);
! 				}
! 			}
! 			else
! 			{
! 				fprintf(stderr, "%s: failure adding path to paths list.\n",
! 					progname);
! 				exit(AKLOG_MISC);
! 			}
! 			pmode = FALSE;
! 			memset(path, 0, sizeof(path));
! 		}
! 	}
  
! 	if(usev5)
! 		krb5_init_context(&amp;context);
  
! 	/* If nothing was given, log to the local cell. */
! 	if ((cells.nelements + paths.nelements) == 0)
! 		status = auth_to_cell(context, NULL, NULL);
! 	else
! 	{
! 		/* Log to all cells in the cells list first */
! 		for (cur_node = cells.first; cur_node; cur_node = cur_node-&gt;next)
! 		{
! 			memcpy(&amp;cellinfo, cur_node-&gt;data, sizeof(cellinfo));
              if (status = auth_to_cell(context, 
! 				cellinfo.cell, cellinfo.realm))
! 				somethingswrong++;
! 		}
  
! 		/* Then, log to all paths in the paths list */
! 		for (cur_node = paths.first; cur_node; cur_node = cur_node-&gt;next)
! 		{
              if (status = auth_to_path(context, 
! 				cur_node-&gt;data))
! 				somethingswrong++;
! 		}
  
! 		/*
! 		* If only one thing was logged to, we'll return the status
! 		* of the single call.  Otherwise, we'll return a generic
! 		* something failed status.
! 		*/
! 		if (somethingswrong &amp;&amp; ((cells.nelements + paths.nelements) &gt; 1))
! 			status = AKLOG_SOMETHINGSWRONG;
! 	}
  
! 	if(usev5)
! 		krb5_free_context(context);
  
! 	exit(status);
! }
--- 956,1272 ----
  */
  static int auth_to_path(krb5_context context, char *path)
  {
!     int status = AKLOG_SUCCESS;
!     int auth_to_cell_status = AKLOG_SUCCESS;
  
!     char *nextpath;
!     char pathtocheck[MAXPATHLEN + 1];
!     char mountpoint[MAXPATHLEN + 1];
! 
!     char *cell;
!     char *endofcell;
! 
!     /* Initialize */
!     if (BeginsWithDir(path, TRUE))
!         strcpy(pathtocheck, path);
!     else
!     {
!         if (getcwd(pathtocheck, sizeof(pathtocheck)) == NULL)
!         {
!             fprintf(stderr, "Unable to find current working directory:\n");
!             fprintf(stderr, "%s\n", pathtocheck);
!             fprintf(stderr, "Try an absolute pathname.\n");
!             exit(AKLOG_BADPATH);
!         }
!         else
!         {
!             /* in WIN32, if getcwd returns a root dir (eg: c:\), the returned string
!             * will already have a trailing slash ('\'). Otherwise, the string will
!             * end in the last directory name */
! #ifdef WIN32    
!             if(pathtocheck[strlen(pathtocheck) - 1] != BDIR)
! #endif  
!                 strcat(pathtocheck, DIRSTRING);
!             strcat(pathtocheck, path);
!         }
!     }
!     next_path(pathtocheck);
  
!     /* Go on to the next level down the path */
!     while (nextpath = next_path(NULL))
!     {
!         strcpy(pathtocheck, nextpath);
!         if (dflag)
!             printf("Checking directory [%s]\n", pathtocheck);
!         /*
!         * If this is an afs mountpoint, determine what cell from
!         * the mountpoint name which is of the form
!         * #cellname:volumename or %cellname:volumename.
!         */
!         if (get_afs_mountpoint(pathtocheck, mountpoint, sizeof(mountpoint)))
!         {
!             if(dflag)
!                 printf("Found mount point [%s]\n", mountpoint);
!             /* skip over the '#' or '%' */
!             cell = mountpoint + 1;
!             if (endofcell = strchr(mountpoint, VOLMARKER))
!             {
!                 *endofcell = '\0';
!                 if (auth_to_cell_status = auth_to_cell(context, cell, NULL))
!                 {
!                     if (status == AKLOG_SUCCESS)
!                         status = auth_to_cell_status;
!                     else if (status != auth_to_cell_status)
!                         status = AKLOG_SOMETHINGSWRONG;
!                 }
!             }
!         }
!         else
!         {
!             struct stat st;
  
!             if (lstat(pathtocheck, &amp;st) &lt; 0)
!             {
!                 /*
!                 * If we've logged and still can't stat, there's
!                 * a problem...
!                 */
!                 fprintf(stderr, "%s: stat(%s): %s\n", progname,
!                          pathtocheck, strerror(errno));
!                 return(AKLOG_BADPATH);
!             }
!             else if (!S_ISDIR(st.st_mode))
!             {
!                 /* Allow only directories */
!                 fprintf(stderr, "%s: %s: %s\n", progname, pathtocheck,
!                          strerror(ENOTDIR));
!                 return(AKLOG_BADPATH);
!             }
!         }
!     }
  
!     return(status);
  }
  
  /* Print usage message and exit */
  static void usage(void)
  {
!     fprintf(stderr, "\nUsage: %s %s%s%s%s\n", progname,
!              "[-d] [[-cell | -c] cell [-k krb_realm]] ",
!              "[[-p | -path] pathname]\n",
!              "    [-noprdb] [-force]\n",
!              "    [-5 [-m]| -4]\n"
!              );
!     fprintf(stderr, "    -d gives debugging information.\n");
!     fprintf(stderr, "    krb_realm is the kerberos realm of a cell.\n");
!     fprintf(stderr, "    pathname is the name of a directory to which ");
!     fprintf(stderr, "you wish to authenticate.\n");
!     fprintf(stderr, "    -noprdb means don't try to determine AFS ID.\n");
!     fprintf(stderr, "    -5 or -4 selects whether to use Kerberos V or Kerberos IV.\n"
!                     "       (default is Kerberos V)\n");
!     fprintf(stderr, "       -m means use krb524d to convert Kerberos V tickets.\n");
!     fprintf(stderr, "    No commandline arguments means ");
!     fprintf(stderr, "authenticate to the local cell.\n");
!     fprintf(stderr, "\n");
!     exit(AKLOG_USAGE);
  }
  
  int main(int argc, char *argv[])
  {
!     int status = AKLOG_SUCCESS;
!     int i;
!     int somethingswrong = FALSE;
  
!     cellinfo_t cellinfo;
  
!     extern char *progname;	/* Name of this program */
  
!     extern int dflag;		/* Debug mode */
  
!     int cmode = FALSE;		/* Cellname mode */
!     int pmode = FALSE;		/* Path name mode */
! 
!     char realm[REALM_SZ];		/* Kerberos realm of afs server */
!     char cell[BUFSIZ];		/* Cell to which we are authenticating */
!     char path[MAXPATHLEN + 1];	/* Path length for path mode */
! 
!     linked_list cells;		/* List of cells to log to */
!     linked_list paths;		/* List of paths to log to */
!     ll_node *cur_node;
! 
!     krb5_context context = 0;
! 
!     memset(&amp;cellinfo, 0, sizeof(cellinfo));
! 
!     memset(realm, 0, sizeof(realm));
!     memset(cell, 0, sizeof(cell));
!     memset(path, 0, sizeof(path));
! 
!     ll_init(&amp;cells);
!     ll_init(&amp;paths);
! 
!     /* Store the program name here for error messages */
!     if (progname = LastComponent(argv[0]))
!         progname++;
!     else
!         progname = argv[0];
! 
!     /* Initialize list of cells to which we have authenticated */
!     (void)ll_init(&amp;authedcells);
! 
!     /* Parse commandline arguments and make list of what to do. */
!     for (i = 1; i &lt; argc; i++)
!     {
!         if (strcmp(argv[i], "-d") == 0)
!             dflag++;
!         else if (strcmp(argv[i], "-5") == 0)
!             usev5++;
!         else if (strcmp(argv[i], "-m") == 0)
!             use524++;
!         else if (strcmp(argv[i], "-4") == 0)
!             usev5 = 0;
!         else if (strcmp(argv[i], "-noprdb") == 0)
!             noprdb++;
!         else if (strcmp(argv[i], "-force") == 0)
!             force++;
!         else if (((strcmp(argv[i], "-cell") == 0) ||
!                    (strcmp(argv[i], "-c") == 0)) &amp;&amp; !pmode)
!         {       
!             if (++i &lt; argc)
!             {
!                 cmode++;
!                 strcpy(cell, argv[i]);
!             }
!             else
!                 usage();
!         }
!         else if (((strcmp(argv[i], "-path") == 0) ||
!                    (strcmp(argv[i], "-p") == 0)) &amp;&amp; !cmode)
!         {       
!             if (++i &lt; argc)
!             {
!                 pmode++;
!                 strcpy(path, argv[i]);
!             }
!             else
!                 usage();
!         }
!         else if (argv[i][0] == '-')
!             usage();
!         else if (!pmode &amp;&amp; !cmode)
!         {
!             if (FirstComponent(argv[i]) || (strcmp(argv[i], ".") == 0) ||
!                  (strcmp(argv[i], "..") == 0))
!             {
!                 pmode++;
!                 strcpy(path, argv[i]);
!             }
!             else
!             {
!                 cmode++;
!                 strcpy(cell, argv[i]);
!             }
!         }
!         else
!             usage();
  
!         if (cmode)
!         {
!             if (((i + 1) &lt; argc) &amp;&amp; (strcmp(argv[i + 1], "-k") == 0))
!             {
!                 i += 2;
!                 if (i &lt; argc)
!                     strcpy(realm, argv[i]);
!                 else
!                     usage();
!             }
!             /* Add this cell to list of cells */
!             strcpy(cellinfo.cell, cell);
!             strcpy(cellinfo.realm, realm);
!             if (cur_node = ll_add_node(&amp;cells, ll_tail))
!             {
!                 char *new_cellinfo;
!                 if (new_cellinfo = copy_cellinfo(&amp;cellinfo))
!                     ll_add_data(cur_node, new_cellinfo);
!                 else
!                 {
!                     fprintf(stderr, "%s: failure copying cellinfo.\n", progname);
!                     exit(AKLOG_MISC);
!                 }
!             }
!             else
!             {
!                 fprintf(stderr, "%s: failure adding cell to cells list.\n",
!                          progname);
!                 exit(AKLOG_MISC);
!             }
!             memset(&amp;cellinfo, 0, sizeof(cellinfo));
!             cmode = FALSE;
!             memset(cell, 0, sizeof(cell));
!             memset(realm, 0, sizeof(realm));
!         }
!         else if (pmode)
!         {
!             /* Add this path to list of paths */
!             if (cur_node = ll_add_node(&amp;paths, ll_tail))
!             {
!                 char *new_path;
!                 if (new_path = copy_string(path))
!                     ll_add_data(cur_node, new_path);
!                 else
!                 {
!                     fprintf(stderr, "%s: failure copying path name.\n",
!                              progname);
!                     exit(AKLOG_MISC);
!                 }
!             }
!             else
!             {
!                 fprintf(stderr, "%s: failure adding path to paths list.\n",
!                          progname);
!                 exit(AKLOG_MISC);
!             }
!             pmode = FALSE;
!             memset(path, 0, sizeof(path));
!         }
!     }
  
!     if(usev5)
!         krb5_init_context(&amp;context);
  
!     /* If nothing was given, log to the local cell. */
!     if ((cells.nelements + paths.nelements) == 0)
!         status = auth_to_cell(context, NULL, NULL);
!     else
!     {
!         /* Log to all cells in the cells list first */
!         for (cur_node = cells.first; cur_node; cur_node = cur_node-&gt;next)
!         {
!             memcpy(&amp;cellinfo, cur_node-&gt;data, sizeof(cellinfo));
              if (status = auth_to_cell(context, 
!                                        cellinfo.cell, cellinfo.realm))
!                 somethingswrong++;
!         }       
  
!         /* Then, log to all paths in the paths list */
!         for (cur_node = paths.first; cur_node; cur_node = cur_node-&gt;next)
!         {
              if (status = auth_to_path(context, 
!                                        cur_node-&gt;data))
!                 somethingswrong++;
!         }
  
!         /*
!         * If only one thing was logged to, we'll return the status
!         * of the single call.  Otherwise, we'll return a generic
!         * something failed status.
!         */
!         if (somethingswrong &amp;&amp; ((cells.nelements + paths.nelements) &gt; 1))
!             status = AKLOG_SOMETHINGSWRONG;
!     }       
  
!     if(usev5)
!         krb5_free_context(context);
  
!     exit(status);
! }       
Index: openafs/src/WINNT/client_config/drivemap.cpp
diff -c openafs/src/WINNT/client_config/drivemap.cpp:1.27.2.1 openafs/src/WINNT/client_config/drivemap.cpp:1.27.2.3
*** openafs/src/WINNT/client_config/drivemap.cpp:1.27.2.1	Mon Aug 23 15:38:36 2004
--- openafs/src/WINNT/client_config/drivemap.cpp	Mon Oct 18 00:09:34 2004
***************
*** 26,31 ****
--- 26,32 ----
  #endif
  #include &lt;osilog.h&gt;
  #include &lt;lanahelper.h&gt;
+ #include &lt;strsafe.h&gt;
  
  extern void Config_GetLanAdapter (ULONG *pnLanAdapter);
  
***************
*** 76,81 ****
--- 77,104 ----
  }
  
  static BOOL 
+ WriteExpandedRegistryString(HKEY key, TCHAR * subkey, LPTSTR lhs, LPTSTR rhs)
+ {
+     HKEY hkSub = NULL;
+     RegCreateKeyEx( key,
+                     subkey,
+                     0,
+                     NULL,
+                     REG_OPTION_NON_VOLATILE,
+                     KEY_WRITE,
+                     NULL,
+                     &amp;hkSub,
+                     NULL);
+ 
+     DWORD status = RegSetValueEx( hkSub, lhs, 0, REG_EXPAND_SZ, (const BYTE *)rhs, strlen(rhs)+1 );
+ 
+     if ( hkSub )
+         RegCloseKey( hkSub );
+ 
+     return (status == ERROR_SUCCESS);
+ }
+ 
+ static BOOL 
  ReadRegistryString(HKEY key, TCHAR * subkey, LPTSTR lhs, LPTSTR rhs, DWORD * size)
  {
      HKEY hkSub = NULL;
***************
*** 89,96 ****
                      &amp;hkSub,
                      NULL);
  
!     DWORD dwType;
!     DWORD status = RegQueryValueEx( hkSub, lhs, 0, &amp;dwType, (LPBYTE)rhs, size );
  
      if ( hkSub )
          RegCloseKey( hkSub );
--- 112,130 ----
                      &amp;hkSub,
                      NULL);
  
!     DWORD dwType = 0;
!     DWORD localSize = *size;
! 
!     DWORD status = RegQueryValueEx( hkSub, lhs, 0, &amp;dwType, (LPBYTE)rhs, &amp;localSize);
!     if (status == 0 &amp;&amp; dwType == REG_EXPAND_SZ) {
!         TCHAR * buf = (TCHAR *)malloc((*size) * sizeof(TCHAR));
!         memcpy(buf, rhs, (*size) * sizeof(TCHAR));
!         localSize = ExpandEnvironmentStrings(buf, rhs, *size);
!         free(buf);
!         if ( localSize &gt; *size )
!             status = !ERROR_SUCCESS;
!     }
!     *size = localSize;
  
      if ( hkSub )
          RegCloseKey( hkSub );
***************
*** 112,118 ****
                      &amp;hkSub,
                      NULL);
  
-     DWORD dwType;
      DWORD status = RegDeleteValue( hkSub, lhs );
  
      if ( hkSub )
--- 146,151 ----
***************
*** 385,391 ****
          HKEY hkSubmounts;
  
          RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
!                         "SOFTWARE\\OpenAFS\\Client\\Submounts",
                          0, 
                          "AFS", 
                          REG_OPTION_NON_VOLATILE,
--- 418,424 ----
          HKEY hkSubmounts;
  
          RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
!                         cszSECTION_SUBMOUNTS,
                          0, 
                          "AFS", 
                          REG_OPTION_NON_VOLATILE,
***************
*** 414,424 ****
              DWORD submountPathLen = MAX_PATH;
              TCHAR submountName[MAX_PATH];
              DWORD submountNameLen = MAX_PATH;
!             DWORD dwType;
  
              RegEnumValue( hkSubmounts, dwIndex, submountName, &amp;submountNameLen, NULL,
                            &amp;dwType, (LPBYTE)submountPath, &amp;submountPathLen);
  
              SUBMOUNT Submount;
              memset (&amp;Submount, 0x00, sizeof(SUBMOUNT));
              lstrcpy (Submount.szSubmount, submountName);
--- 447,465 ----
              DWORD submountPathLen = MAX_PATH;
              TCHAR submountName[MAX_PATH];
              DWORD submountNameLen = MAX_PATH;
!             DWORD dwType = 0;
  
              RegEnumValue( hkSubmounts, dwIndex, submountName, &amp;submountNameLen, NULL,
                            &amp;dwType, (LPBYTE)submountPath, &amp;submountPathLen);
  
+             if (dwType == REG_EXPAND_SZ) {
+                 char buf[MAX_PATH];
+                 StringCbCopyA(buf, MAX_PATH, submountPath);
+                 submountPathLen = ExpandEnvironmentStrings(buf, submountPath, MAX_PATH);
+                 if (submountPathLen &gt; MAX_PATH)
+                     continue;
+             }
+ 
              SUBMOUNT Submount;
              memset (&amp;Submount, 0x00, sizeof(SUBMOUNT));
              lstrcpy (Submount.szSubmount, submountName);
***************
*** 482,488 ****
                        &amp;dwType, (LPBYTE)mapping, &amp;mappingLen);
          if ( dwType == REG_EXPAND_SZ ) {
              TCHAR buf[MAX_PATH];
!             DWORD dummyLen = ExpandEnvironmentStrings(buf, mapping, MAX_PATH);
              if (dummyLen &gt; MAX_PATH)
                  continue;
              _tcsncpy(mapping, buf, MAX_PATH);
--- 523,529 ----
                        &amp;dwType, (LPBYTE)mapping, &amp;mappingLen);
          if ( dwType == REG_EXPAND_SZ ) {
              TCHAR buf[MAX_PATH];
!             DWORD dummyLen = ExpandEnvironmentStrings(mapping, buf, MAX_PATH);
              if (dummyLen &gt; MAX_PATH)
                  continue;
              _tcsncpy(mapping, buf, MAX_PATH);
***************
*** 805,811 ****
      if (!szRHS[0])
          lstrcpy (szRHS, TEXT("/"));
  
!     WriteRegistryString(HKEY_LOCAL_MACHINE, cszSECTION_SUBMOUNTS, pszSubmount, szRHS);
  }
  
  
--- 846,852 ----
      if (!szRHS[0])
          lstrcpy (szRHS, TEXT("/"));
  
!     WriteExpandedRegistryString(HKEY_LOCAL_MACHINE, cszSECTION_SUBMOUNTS, pszSubmount, szRHS);
  }
  
  
Index: openafs/src/WINNT/client_config/isadmin.cpp
diff -c openafs/src/WINNT/client_config/isadmin.cpp:1.2.20.1 openafs/src/WINNT/client_config/isadmin.cpp:1.2.20.2
*** openafs/src/WINNT/client_config/isadmin.cpp:1.2.20.1	Mon Aug 23 11:55:06 2004
--- openafs/src/WINNT/client_config/isadmin.cpp	Mon Oct 18 00:09:35 2004
***************
*** 76,83 ****
              return FALSE;
          }
  
-         fTested = TRUE;
- 
          dwSize = 0;
          dwSize2 = 0;
  
--- 76,81 ----
***************
*** 99,105 ****
              return TRUE;
          }
  
!         psidAdmin = (PSID) malloc(dwSize); memset(psidAdmin,0,dwSize);
          pszRefDomain = (char *)malloc(dwSize2);
  
          if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &amp;dwSize, pszRefDomain, &amp;dwSize2, &amp;snu)) {
--- 97,103 ----
              return TRUE;
          }
  
!         psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
          pszRefDomain = (char *)malloc(dwSize2);
  
          if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &amp;dwSize, pszRefDomain, &amp;dwSize2, &amp;snu)) {
***************
*** 112,150 ****
  
              if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &amp;hToken))
              {
!                 /* We'll have to allocate a chunk of memory to store the list of
!                  * groups to which this user belongs; find out how much memory
!                  * we'll need.
!                  */
!                 DWORD dwSize = 0;
!                 PTOKEN_GROUPS pGroups;
!                 
!                 GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &amp;dwSize);
!             
!                 pGroups = (PTOKEN_GROUPS)malloc(dwSize);
!                 
!                 /* Allocate that buffer, and read in the list of groups. */
!                 if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &amp;dwSize))
!                 {
!                     /* Look through the list of group SIDs and see if any of them
!                      * matches the AFS Client Admin group SID.
                       */
!                     size_t iGroup = 0;
!                     for (; (!fAdmin) &amp;&amp; (iGroup &lt; pGroups-&gt;GroupCount); ++iGroup)
                      {
!                         if (EqualSid (psidAdmin, pGroups-&gt;Groups[ iGroup ].Sid)) {
!                             fAdmin = TRUE;
                          }
                      }
                  }
  
!                 if (pGroups)
!                     free(pGroups);
              }
          }
  
          free(psidAdmin);
          free(pszRefDomain);
      }
  
      return fAdmin;
--- 110,185 ----
  
              if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &amp;hToken))
              {
! 
!                 if (!CheckTokenMembership(hToken, psidAdmin, &amp;fAdmin)) {
!                     /* We'll have to allocate a chunk of memory to store the list of
!                      * groups to which this user belongs; find out how much memory
!                      * we'll need.
                       */
!                     DWORD dwSize = 0;
!                     PTOKEN_GROUPS pGroups;
! 
!                     GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &amp;dwSize);
! 
!                     pGroups = (PTOKEN_GROUPS)malloc(dwSize);
! 
!                     /* Allocate that buffer, and read in the list of groups. */
!                     if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &amp;dwSize))
                      {
!                         /* Look through the list of group SIDs and see if any of them
!                          * matches the AFS Client Admin group SID.
!                          */
!                         size_t iGroup = 0;
!                         for (; (!fAdmin) &amp;&amp; (iGroup &lt; pGroups-&gt;GroupCount); ++iGroup)
!                         {
!                             if (EqualSid (psidAdmin, pGroups-&gt;Groups[ iGroup ].Sid)) {
!                                 fAdmin = TRUE;
!                             }
                          }
                      }
+ 
+                     if (pGroups)
+                         free(pGroups);
                  }
  
!                 /* if do not have permission because we were not explicitly listed
!                  * in the Admin Client Group let's see if we are the SYSTEM account
!                  */
!                 if (!fAdmin) {
!                     PTOKEN_USER pTokenUser;
!                     SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
!                     PSID pSidLocalSystem = 0;
!                     DWORD gle;
! 
!                     GetTokenInformation(hToken, TokenUser, NULL, 0, &amp;dwSize);
! 
!                     pTokenUser = (PTOKEN_USER)malloc(dwSize);
! 
!                     if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &amp;dwSize))
!                         gle = GetLastError();
! 
!                     if (AllocateAndInitializeSid( &amp;SIDAuth, 1,
!                                                   SECURITY_LOCAL_SYSTEM_RID,
!                                                   0, 0, 0, 0, 0, 0, 0,
!                                                   &amp;pSidLocalSystem))
!                     {
!                         if (EqualSid(pTokenUser-&gt;User.Sid, pSidLocalSystem)) {
!                             fAdmin = TRUE;
!                         }
! 
!                         FreeSid(pSidLocalSystem);
!                     }
! 
!                     if ( pTokenUser )
!                         free(pTokenUser);
!                 }
              }
          }
  
          free(psidAdmin);
          free(pszRefDomain);
+ 
+         fTested = TRUE;
      }
  
      return fAdmin;
Index: openafs/src/WINNT/client_creds/ipaddrchg.c
diff -c openafs/src/WINNT/client_creds/ipaddrchg.c:1.1.2.1 openafs/src/WINNT/client_creds/ipaddrchg.c:1.1.2.2
*** openafs/src/WINNT/client_creds/ipaddrchg.c:1.1.2.1	Wed Aug 18 13:11:25 2004
--- openafs/src/WINNT/client_creds/ipaddrchg.c	Wed Sep  8 01:59:01 2004
***************
*** 304,316 ****
      strcpy(aserver.name, "afs");
      strcpy(aserver.cell, rootcell);
  
      rc = ktc_GetToken(&amp;aserver, &amp;atoken, sizeof(atoken), &amp;aclient);
      if ( rc == 0 ) {
-         GetLocalTime (&amp;stNow);
-         SystemTimeToFileTime (&amp;stNow, &amp;ftNow);
-         llNow = (((LONGLONG)ftNow.dwHighDateTime) &lt;&lt; 32) + (LONGLONG)(ftNow.dwLowDateTime);
-         llNow /= c100ns1SECOND;
- 
          TimeToSystemTime (&amp;stExpires, atoken.endTime);
          SystemTimeToFileTime (&amp;stExpires, &amp;ftExpires);
          llExpires = (((LONGLONG)ftExpires.dwHighDateTime) &lt;&lt; 32) + (LONGLONG)(ftExpires.dwLowDateTime);
--- 304,316 ----
      strcpy(aserver.name, "afs");
      strcpy(aserver.cell, rootcell);
  
+     GetLocalTime (&amp;stNow);
+     SystemTimeToFileTime (&amp;stNow, &amp;ftNow);
+     llNow = (((LONGLONG)ftNow.dwHighDateTime) &lt;&lt; 32) + (LONGLONG)(ftNow.dwLowDateTime);
+     llNow /= c100ns1SECOND;
+ 
      rc = ktc_GetToken(&amp;aserver, &amp;atoken, sizeof(atoken), &amp;aclient);
      if ( rc == 0 ) {
          TimeToSystemTime (&amp;stExpires, atoken.endTime);
          SystemTimeToFileTime (&amp;stExpires, &amp;ftExpires);
          llExpires = (((LONGLONG)ftExpires.dwHighDateTime) &lt;&lt; 32) + (LONGLONG)(ftExpires.dwLowDateTime);
***************
*** 371,384 ****
          KFW_AFS_renew_token_for_cell(rootcell);
  
          rc = ktc_GetToken(&amp;aserver, &amp;atoken, sizeof(atoken), &amp;aclient);
! 
!         TimeToSystemTime (&amp;stExpires, atoken.endTime);
!         SystemTimeToFileTime (&amp;stExpires, &amp;ftExpires);
!         llExpires = (((LONGLONG)ftExpires.dwHighDateTime) &lt;&lt; 32) + (LONGLONG)(ftExpires.dwLowDateTime);
!         llExpires /= c100ns1SECOND;
          
!         if (!rc &amp;&amp; (llNow &lt; llExpires))
!             goto cleanup;
      }
  
      SendMessage(hWnd, WM_OBTAIN_TOKENS, FALSE, (long)rootcell);
--- 371,385 ----
          KFW_AFS_renew_token_for_cell(rootcell);
  
          rc = ktc_GetToken(&amp;aserver, &amp;atoken, sizeof(atoken), &amp;aclient);
!         if ( rc == 0 ) {
!             TimeToSystemTime (&amp;stExpires, atoken.endTime);
!             SystemTimeToFileTime (&amp;stExpires, &amp;ftExpires);
!             llExpires = (((LONGLONG)ftExpires.dwHighDateTime) &lt;&lt; 32) + (LONGLONG)(ftExpires.dwLowDateTime);
!             llExpires /= c100ns1SECOND;
          
!             if (llNow &lt; llExpires)
!                 goto cleanup;
!         }
      }
  
      SendMessage(hWnd, WM_OBTAIN_TOKENS, FALSE, (long)rootcell);
Index: openafs/src/WINNT/client_osi/osisleep.h
diff -c openafs/src/WINNT/client_osi/osisleep.h:1.4 openafs/src/WINNT/client_osi/osisleep.h:1.4.2.1
*** openafs/src/WINNT/client_osi/osisleep.h:1.4	Sun Mar  9 20:59:15 2003
--- openafs/src/WINNT/client_osi/osisleep.h	Mon Oct 18 00:09:36 2004
***************
*** 35,41 ****
  	unsigned short states;	/* states bits */
  	unsigned short idx;	/* sleep hash table we're in, if in hash */
          unsigned short waitFor;	/* what are we waiting for; used for bulk wakeups */
! 	unsigned short refCount;/* reference count from FDs */
  } osi_sleepInfo_t;
  
  /* first guy is the most recently added process */
--- 35,41 ----
  	unsigned short states;	/* states bits */
  	unsigned short idx;	/* sleep hash table we're in, if in hash */
          unsigned short waitFor;	/* what are we waiting for; used for bulk wakeups */
! 	unsigned long refCount;/* reference count from FDs */
  } osi_sleepInfo_t;
  
  /* first guy is the most recently added process */
Index: openafs/src/WINNT/client_osi/osistatl.h
diff -c openafs/src/WINNT/client_osi/osistatl.h:1.4 openafs/src/WINNT/client_osi/osistatl.h:1.4.2.1
*** openafs/src/WINNT/client_osi/osistatl.h:1.4	Thu Feb 26 14:22:49 2004
--- openafs/src/WINNT/client_osi/osistatl.h	Mon Oct 18 00:09:36 2004
***************
*** 56,63 ****
   */
  typedef struct osi_mutexStat {
  	osi_queue_t q;		/* queue of all mutexes */
! 	osi_turnstile_t turn;		/* the real turnstile */
! 	short refCount;			/* so we can iterate cleanly */
  	short states;
  
  	/* track # of lock calls and blocks */
--- 56,63 ----
   */
  typedef struct osi_mutexStat {
  	osi_queue_t q;		/* queue of all mutexes */
! 	osi_turnstile_t turn;  	/* the real turnstile */
! 	unsigned long refCount;	/* so we can iterate cleanly */
  	short states;
  
  	/* track # of lock calls and blocks */
***************
*** 79,85 ****
  typedef struct osi_rwlockStat {
  	osi_queue_t q;			/* queue of all mutexes */
  	osi_turnstile_t turn;		/* the real turnstile */
! 	short refCount;			/* so we can iterate cleanly */
  	short states;
  
  	/* statistics */
--- 79,85 ----
  typedef struct osi_rwlockStat {
  	osi_queue_t q;			/* queue of all mutexes */
  	osi_turnstile_t turn;		/* the real turnstile */
! 	unsigned long refCount;		/* so we can iterate cleanly */
  	short states;
  
  	/* statistics */
Index: openafs/src/WINNT/install/NSIS/AdminGroup.cpp
diff -c openafs/src/WINNT/install/NSIS/AdminGroup.cpp:1.1.2.1 openafs/src/WINNT/install/NSIS/AdminGroup.cpp:1.1.2.2
*** openafs/src/WINNT/install/NSIS/AdminGroup.cpp:1.1.2.1	Mon Aug 23 11:55:07 2004
--- openafs/src/WINNT/install/NSIS/AdminGroup.cpp	Mon Oct  4 03:35:38 2004
***************
*** 62,68 ****
          return 1;
      }
  
!     if(stricmp(argv[1], "-create")) {
          rv = createAfsAdminGroup();
          if(rv) {
              if(rv != ERROR_ALIAS_EXISTS) {
--- 62,68 ----
          return 1;
      }
  
!     if(!stricmp(argv[1], "-create")) {
          rv = createAfsAdminGroup();
          if(rv) {
              if(rv != ERROR_ALIAS_EXISTS) {
***************
*** 77,83 ****
              if(rv)
                  fprintf(stderr, "%s: Can't populate AFS Client Admin group. NetApi error %u\n", rv);
          }
!     } else if(stricmp(argv[1], "-remove")) {
          removeAfsAdminGroup();
          rv = 0;
      } else {
--- 77,83 ----
              if(rv)
                  fprintf(stderr, "%s: Can't populate AFS Client Admin group. NetApi error %u\n", rv);
          }
!     } else if(!stricmp(argv[1], "-remove")) {
          removeAfsAdminGroup();
          rv = 0;
      } else {
Index: openafs/src/WINNT/install/NSIS/NTMakefile
diff -c openafs/src/WINNT/install/NSIS/NTMakefile:1.13.2.1 openafs/src/WINNT/install/NSIS/NTMakefile:1.13.2.3
*** openafs/src/WINNT/install/NSIS/NTMakefile:1.13.2.1	Mon Aug 23 11:55:07 2004
--- openafs/src/WINNT/install/NSIS/NTMakefile	Thu Sep  9 16:19:51 2004
***************
*** 30,38 ****
  
  prebuild:
  !IF ("$(AFSDEV_BUILDTYPE)" == "FREE")
! !IF ("$(AFSVER_CL)"=="1310")
     $(COPY) %SystemRoot%\System32\Msvcr71.dll $(EXEDIR)
-    $(COPY) %SystemRoot%\System32\MSVCRT.DLL $(EXEDIR)
     $(COPY) %SystemRoot%\System32\MFC71.DLL $(EXEDIR)
  !ELSE IF ("$(AFSVER_CL)"=="1300")
     $(COPY) %SystemRoot%\System32\Msvcp70.dll $(EXEDIR)
--- 30,40 ----
  
  prebuild:
  !IF ("$(AFSDEV_BUILDTYPE)" == "FREE")
! !IF ("$(AFSVER_CL)"=="1400")
!    $(COPY) %SystemRoot%\System32\Msvcr80.dll $(EXEDIR)
!    $(COPY) %SystemRoot%\System32\MFC80.DLL $(EXEDIR)
! !ELSE IF ("$(AFSVER_CL)"=="1310")
     $(COPY) %SystemRoot%\System32\Msvcr71.dll $(EXEDIR)
     $(COPY) %SystemRoot%\System32\MFC71.DLL $(EXEDIR)
  !ELSE IF ("$(AFSVER_CL)"=="1300")
     $(COPY) %SystemRoot%\System32\Msvcp70.dll $(EXEDIR)
***************
*** 45,51 ****
  !ERROR Unknown Compiler Version
  !ENDIF
  !ELSE # NOT FREE - CHECKED
! !IF ("$(AFSVER_CL)"=="1310")
     $(COPY) %SystemRoot%\System32\Msvcr71d.dll $(EXEDIR)
     $(COPY) %SystemRoot%\System32\Msvcr71d.pdb $(EXEDIR)
     $(COPY) %SystemRoot%\System32\MFC71D.DLL $(EXEDIR)
--- 47,58 ----
  !ERROR Unknown Compiler Version
  !ENDIF
  !ELSE # NOT FREE - CHECKED
! !IF ("$(AFSVER_CL)"=="1400")
!    $(COPY) %SystemRoot%\System32\Msvcr80d.dll $(EXEDIR)
!    $(COPY) %SystemRoot%\System32\Msvcr80d.pdb $(EXEDIR)
!    $(COPY) %SystemRoot%\System32\MFC80D.DLL $(EXEDIR)
!    $(COPY) %SystemRoot%\System32\MFC80D.pdb $(EXEDIR)
! !ELSE IF ("$(AFSVER_CL)"=="1310")
     $(COPY) %SystemRoot%\System32\Msvcr71d.dll $(EXEDIR)
     $(COPY) %SystemRoot%\System32\Msvcr71d.pdb $(EXEDIR)
     $(COPY) %SystemRoot%\System32\MFC71D.DLL $(EXEDIR)
***************
*** 75,81 ****
     $(DESTDIR)\bin\util_cr.exe _echo "!define " &gt;&gt;$(OUT)\nsi-includes.nsi 
     "$(NSISDIR)\makensis.exe" /VERSION &gt;&gt;$(OUT)\nsi-includes.nsi          
     echo. &gt;&gt;$(OUT)\nsi-includes.nsi                                       
! !if ("$(AFSVER_CL)" == "1310")
     echo !define CL_1310 1 &gt;&gt; $(OUT)\nsi-includes.nsi
  !else if ("$(AFSVER_CL)" == "1300")
     echo !define CL_1300 1 &gt;&gt; $(OUT)\nsi-includes.nsi
--- 82,90 ----
     $(DESTDIR)\bin\util_cr.exe _echo "!define " &gt;&gt;$(OUT)\nsi-includes.nsi 
     "$(NSISDIR)\makensis.exe" /VERSION &gt;&gt;$(OUT)\nsi-includes.nsi          
     echo. &gt;&gt;$(OUT)\nsi-includes.nsi                                       
! !if ("$(AFSVER_CL)" == "1400")
!    echo !define CL_1310 1 &gt;&gt; $(OUT)\nsi-includes.nsi
! !else if ("$(AFSVER_CL)" == "1310")
     echo !define CL_1310 1 &gt;&gt; $(OUT)\nsi-includes.nsi
  !else if ("$(AFSVER_CL)" == "1300")
     echo !define CL_1300 1 &gt;&gt; $(OUT)\nsi-includes.nsi
Index: openafs/src/WINNT/install/NSIS/OpenAFS.nsi
diff -c openafs/src/WINNT/install/NSIS/OpenAFS.nsi:1.69.2.3 openafs/src/WINNT/install/NSIS/OpenAFS.nsi:1.69.2.4
*** openafs/src/WINNT/install/NSIS/OpenAFS.nsi:1.69.2.3	Mon Aug 23 11:55:07 2004
--- openafs/src/WINNT/install/NSIS/OpenAFS.nsi	Thu Sep  9 16:13:14 2004
***************
*** 1177,1182 ****
--- 1177,1187 ----
  
  DoCommon:
    SetOutPath "$INSTDIR\Common"
+ !IFDEF CL_1400
+    File "${SYSTEMDIR}\msvcr80d.pdb"
+    File "${SYSTEMDIR}\msvcp80d.pdb"
+    File "${SYSTEMDIR}\mfc80d.pdb"
+ !ELSE
  !IFDEF CL_1310
     File "${SYSTEMDIR}\msvcr71d.pdb"
     File "${SYSTEMDIR}\msvcp71d.pdb"
***************
*** 1192,1197 ****
--- 1197,1203 ----
     File "${SYSTEMDIR}\msvcrtd.pdb"
  !ENDIF
  !ENDIF
+ !ENDIF
    
  ; Common Areas
     SetOutPath "$INSTDIR\Common"
***************
*** 1631,1636 ****
--- 1637,1650 ----
     Delete /REBOOTOK "$INSTDIR\Common\afskasadmin.pdb"
     Delete /REBOOTOK "$INSTDIR\Common\afsptsadmin.pdb"
  !IFDEF DEBUG
+ !IFDEF CL_1400
+    Delete /REBOOTOK "$INSTDIR\bin\msvcr80d.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcr80d.pdb"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcp80d.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcp80d.pdb"
+    Delete /REBOOTOK "$INSTDIR\bin\mfc80d.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\mfc80d.pdb"
+ !ELSE
  !IFDEF CL_1310
     Delete /REBOOTOK "$INSTDIR\bin\msvcr71d.dll"
     Delete /REBOOTOK "$INSTDIR\bin\msvcr71d.pdb"
***************
*** 1655,1660 ****
--- 1669,1689 ----
     Delete /REBOOTOK "$INSTDIR\bin\msvcrtd.pdb"
  !ENDIF
  !ENDIF
+ !ENDIF
+ !ELSE
+ !IFDEF CL_1400
+    Delete /REBOOTOK "$INSTDIR\bin\mfc80.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcr80.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcp80.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80CHS.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80CHT.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80DEU.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80ENU.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80ESP.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80FRA.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80ITA.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80JPN.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80KOR.DLL"
  !ELSE
  !IFDEF CL_1310
     Delete /REBOOTOK "$INSTDIR\bin\mfc71.dll"
***************
*** 1690,1695 ****
--- 1719,1725 ----
  !ENDIF
  !ENDIF
  !ENDIF
+ !ENDIF
    
     IfSilent SkipDel
  ;  IfFileExists "$INSTDIR\Client\CellServDB" CellExists SkipDelAsk
***************
*** 1790,1795 ****
--- 1820,1833 ----
    RMDir  "$INSTDIR\Client"
  
  !IFDEF DEBUG  
+ !IFDEF CL_1400
+    Delete /REBOOTOK "$INSTDIR\bin\msvcr80d.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcr80d.pdb"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcp80d.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcp80d.pdb"
+    Delete /REBOOTOK "$INSTDIR\bin\mfc80d.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\mfc80d.pdb"
+ !ELSE
  !IFDEF CL_1310
     Delete /REBOOTOK "$INSTDIR\bin\msvcr71d.dll"
     Delete /REBOOTOK "$INSTDIR\bin\msvcr71d.pdb"
***************
*** 1814,1819 ****
--- 1852,1872 ----
     Delete /REBOOTOK "$INSTDIR\bin\msvcrtd.pdb"
  !ENDIF
  !ENDIF
+ !ENDIF
+ !ELSE
+ !IFDEF CL_1400
+    Delete /REBOOTOK "$INSTDIR\bin\mfc80.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcr80.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\msvcp80.dll"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80CHS.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80CHT.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80DEU.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80ENU.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80ESP.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80FRA.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80ITA.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80JPN.DLL"
+    Delete /REBOOTOK "$INSTDIR\bin\MFC80KOR.DLL"
  !ELSE
  !IFDEF CL_1310
     Delete /REBOOTOK "$INSTDIR\bin\mfc71.dll"
***************
*** 1849,1854 ****
--- 1902,1908 ----
  !ENDIF
  !ENDIF
  !ENDIF
+ !ENDIF
  
    Delete /REBOOTOK "$INSTDIR\Common\*"
    RMDir "$INSTDIR\Common"
***************
*** 2597,2602 ****
--- 2651,2670 ----
   SetOutPath "$INSTDIR\Common"
  
  !IFDEF DEBUG
+ !IFDEF CL_1400
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr80d.dll" "$INSTDIR\Common\msvcr80d.dll" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp80d.dll" "$INSTDIR\Common\msvcp80d.dll" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc80d.dll" "$INSTDIR\Common\mfc80d.dll" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80CHS.DLL" "$INSTDIR\Common\MFC80CHS.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80CHT.DLL" "$INSTDIR\Common\MFC80CHT.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80DEU.DLL" "$INSTDIR\Common\MFC80DEU.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ENU.DLL" "$INSTDIR\Common\MFC80ENU.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ESP.DLL" "$INSTDIR\Common\MFC80ESP.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80FRA.DLL" "$INSTDIR\Common\MFC80FRA.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ITA.DLL" "$INSTDIR\Common\MFC80ITA.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80JPN.DLL" "$INSTDIR\Common\MFC80JPN.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80KOR.DLL" "$INSTDIR\Common\MFC80KOR.DLL" "$INSTDIR"
+ !ELSE
  !IFDEF CL_1310
     !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr71d.dll" "$INSTDIR\Common\msvcr71d.dll" "$INSTDIR"
     !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp71d.dll" "$INSTDIR\Common\msvcp71d.dll" "$INSTDIR"
***************
*** 2630,2635 ****
--- 2698,2718 ----
     !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcrtd.dll" "$INSTDIR\Common\msvcrtd.dll" "$INSTDIR"
  !ENDIF
  !ENDIF
+ !ENDIF
+ !ELSE
+ !IFDEF CL_1400
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc80.dll" "$INSTDIR\Common\mfc80.dll" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr80.dll" "$INSTDIR\Common\msvcr80.dll" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp80.dll" "$INSTDIR\Common\msvcp80.dll" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80CHS.DLL" "$INSTDIR\Common\MFC80CHS.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80CHT.DLL" "$INSTDIR\Common\MFC80CHT.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80DEU.DLL" "$INSTDIR\Common\MFC80DEU.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ENU.DLL" "$INSTDIR\Common\MFC80ENU.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ESP.DLL" "$INSTDIR\Common\MFC80ESP.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80FRA.DLL" "$INSTDIR\Common\MFC80FRA.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ITA.DLL" "$INSTDIR\Common\MFC80ITA.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80JPN.DLL" "$INSTDIR\Common\MFC80JPN.DLL" "$INSTDIR"
+    !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80KOR.DLL" "$INSTDIR\Common\MFC80KOR.DLL" "$INSTDIR"
  !ELSE
  !IFDEF CL_1310
     !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc71.dll" "$INSTDIR\Common\mfc71.dll" "$INSTDIR"
***************
*** 2665,2670 ****
--- 2748,2754 ----
  !ENDIF
  !ENDIF
  !ENDIF   
+ !ENDIF
  
     StrCmp $LANGUAGE ${LANG_ENGLISH} DoEnglish
     StrCmp $LANGUAGE ${LANG_GERMAN} DoGerman
Index: openafs/src/WINNT/install/wix/NTMakefile
diff -c openafs/src/WINNT/install/wix/NTMakefile:1.2.2.1 openafs/src/WINNT/install/wix/NTMakefile:1.2.2.2
*** openafs/src/WINNT/install/wix/NTMakefile:1.2.2.1	Fri Aug 20 16:15:19 2004
--- openafs/src/WINNT/install/wix/NTMakefile	Tue Sep 21 10:07:24 2004
***************
*** 30,36 ****
  #	)
  	$(MAKE) /f NTMakefile /nologo LANG=en_US lang
  
! lang:: $(MSIFILE)
  
  customactions:
  	$(CD) custom
--- 30,36 ----
  #	)
  	$(MAKE) /f NTMakefile /nologo LANG=en_US lang
  
! lang:: lang_clean $(MSIFILE)
  
  customactions:
  	$(CD) custom
Index: openafs/src/afs/afs.h
diff -c openafs/src/afs/afs.h:1.48.2.1 openafs/src/afs/afs.h:1.48.2.2
*** openafs/src/afs/afs.h:1.48.2.1	Wed Aug 25 03:03:35 2004
--- openafs/src/afs/afs.h	Mon Oct 18 13:43:49 2004
***************
*** 43,49 ****
  #if     defined(AFS_HPUX102_ENV)
  #define AFS_FLOCK       k_flock
  #else
! #if     defined(AFS_SUN56_ENV) || defined(AFS_LINUX24_ENV)
  #define AFS_FLOCK       flock64
  #else
  #define AFS_FLOCK       flock
--- 43,49 ----
  #if     defined(AFS_HPUX102_ENV)
  #define AFS_FLOCK       k_flock
  #else
! #if     defined(AFS_SUN56_ENV) || (defined(AFS_LINUX24_ENV) &amp;&amp; !defined(AFS_PPC64_LINUX26_ENV) &amp;&amp; !defined(AFS_AMD64_LINUX26_ENV))
  #define AFS_FLOCK       flock64
  #else
  #define AFS_FLOCK       flock
***************
*** 1195,1201 ****
  extern int afs_fakestat_enable;
  
  struct buffer {
!     ino_t fid[1];		/* Unique cache key + i/o addressing */
      afs_int32 page;
      afs_int32 accesstime;
      struct buffer *hashNext;
--- 1195,1201 ----
  extern int afs_fakestat_enable;
  
  struct buffer {
!     struct fcache *fid;
      afs_int32 page;
      afs_int32 accesstime;
      struct buffer *hashNext;
Index: openafs/src/afs/afs_buffer.c
diff -c openafs/src/afs/afs_buffer.c:1.16 openafs/src/afs/afs_buffer.c:1.16.2.1
*** openafs/src/afs/afs_buffer.c:1.16	Fri Jan 23 11:53:35 2004
--- openafs/src/afs/afs_buffer.c	Mon Oct 18 03:11:45 2004
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_buffer.c,v 1.16 2004/01/23 16:53:35 rees Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_buffer.c,v 1.16.2.1 2004/10/18 07:11:45 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
***************
*** 63,69 ****
  /* page hash table size - this is pretty intertwined with pHash */
  #define PHSIZE (PHPAGEMASK + PHFIDMASK + 1)
  /* the pHash macro */
! #define pHash(fid,page) ((((afs_int32)((fid)[0])) &amp; PHFIDMASK) \
  			 | (page &amp; PHPAGEMASK))
  
  #ifdef	dirty
--- 63,69 ----
  /* page hash table size - this is pretty intertwined with pHash */
  #define PHSIZE (PHPAGEMASK + PHFIDMASK + 1)
  /* the pHash macro */
! #define pHash(fid,page) ((((afs_int32)((fid)-&gt;inode)) &amp; PHFIDMASK) \
  			 | (page &amp; PHPAGEMASK))
  
  #ifdef	dirty
***************
*** 88,94 ****
  static afs_int32 timecounter;
  
  /* Prototypes for static routines */
! static struct buffer *afs_newslot(afs_inode_t * afid, afs_int32 apage,
  				  register struct buffer *lp);
  
  static int dinit_flag = 0;
--- 88,94 ----
  static afs_int32 timecounter;
  
  /* Prototypes for static routines */
! static struct buffer *afs_newslot(struct fcache * afid, afs_int32 apage,
  				  register struct buffer *lp);
  
  static int dinit_flag = 0;
***************
*** 150,156 ****
  }
  
  void *
! DRead(register afs_inode_t * fid, register int page)
  {
      /* Read a page from the disk. */
      register struct buffer *tb, *tb2;
--- 150,156 ----
  }
  
  void *
! DRead(register struct fcache * fid, register int page)
  {
      /* Read a page from the disk. */
      register struct buffer *tb, *tb2;
***************
*** 224,237 ****
      MObtainWriteLock(&amp;tb-&gt;lock, 260);
      MReleaseWriteLock(&amp;afs_bufferLock);
      tb-&gt;lockers++;
!     tfile = afs_CFileOpen(fid[0]);
!     if (page * AFS_BUFFER_PAGESIZE &gt;= tfile-&gt;size) {
  	dirp_Zap(tb-&gt;fid);
  	tb-&gt;lockers--;
  	MReleaseWriteLock(&amp;tb-&gt;lock);
- 	afs_CFileClose(tfile);
  	return NULL;
      }
      code =
  	afs_CFileRead(tfile, tb-&gt;page * AFS_BUFFER_PAGESIZE, tb-&gt;data,
  		      AFS_BUFFER_PAGESIZE);
--- 224,236 ----
      MObtainWriteLock(&amp;tb-&gt;lock, 260);
      MReleaseWriteLock(&amp;afs_bufferLock);
      tb-&gt;lockers++;
!     if (page * AFS_BUFFER_PAGESIZE &gt;= fid-&gt;chunkBytes) {
  	dirp_Zap(tb-&gt;fid);
  	tb-&gt;lockers--;
  	MReleaseWriteLock(&amp;tb-&gt;lock);
  	return NULL;
      }
+     tfile = afs_CFileOpen(fid-&gt;inode);
      code =
  	afs_CFileRead(tfile, tb-&gt;page * AFS_BUFFER_PAGESIZE, tb-&gt;data,
  		      AFS_BUFFER_PAGESIZE);
***************
*** 274,280 ****
  
  /* lp is pointer to a fairly-old buffer */
  static struct buffer *
! afs_newslot(afs_inode_t * afid, afs_int32 apage, register struct buffer *lp)
  {
      /* Find a usable buffer slot */
      register afs_int32 i;
--- 273,279 ----
  
  /* lp is pointer to a fairly-old buffer */
  static struct buffer *
! afs_newslot(struct fcache * afid, afs_int32 apage, register struct buffer *lp)
  {
      /* Find a usable buffer slot */
      register afs_int32 i;
***************
*** 341,347 ****
      }
  
      if (lp-&gt;dirty) {
! 	tfile = afs_CFileOpen(lp-&gt;fid[0]);
  	afs_CFileWrite(tfile, lp-&gt;page * AFS_BUFFER_PAGESIZE, lp-&gt;data,
  		       AFS_BUFFER_PAGESIZE);
  	lp-&gt;dirty = 0;
--- 340,346 ----
      }
  
      if (lp-&gt;dirty) {
! 	tfile = afs_CFileOpen(lp-&gt;fid-&gt;inode);
  	afs_CFileWrite(tfile, lp-&gt;page * AFS_BUFFER_PAGESIZE, lp-&gt;data,
  		       AFS_BUFFER_PAGESIZE);
  	lp-&gt;dirty = 0;
***************
*** 433,439 ****
   * method of DRead...
   */
  void
! DZap(afs_inode_t * fid)
  {
      register int i;
      /* Destroy all buffers pertaining to a particular fid. */
--- 432,438 ----
   * method of DRead...
   */
  void
! DZap(struct fcache * fid)
  {
      register int i;
      /* Destroy all buffers pertaining to a particular fid. */
***************
*** 470,476 ****
  	    tb-&gt;lockers++;
  	    MReleaseReadLock(&amp;afs_bufferLock);
  	    if (tb-&gt;dirty) {
! 		tfile = afs_CFileOpen(tb-&gt;fid[0]);
  		afs_CFileWrite(tfile, tb-&gt;page * AFS_BUFFER_PAGESIZE,
  			       tb-&gt;data, AFS_BUFFER_PAGESIZE);
  		tb-&gt;dirty = 0;	/* Clear the dirty flag */
--- 469,475 ----
  	    tb-&gt;lockers++;
  	    MReleaseReadLock(&amp;afs_bufferLock);
  	    if (tb-&gt;dirty) {
! 		tfile = afs_CFileOpen(tb-&gt;fid-&gt;inode);
  		afs_CFileWrite(tfile, tb-&gt;page * AFS_BUFFER_PAGESIZE,
  			       tb-&gt;data, AFS_BUFFER_PAGESIZE);
  		tb-&gt;dirty = 0;	/* Clear the dirty flag */
***************
*** 485,491 ****
  }
  
  void *
! DNew(register afs_inode_t * fid, register int page)
  {
      /* Same as read, only do *not* even try to read the page, since it probably doesn't exist. */
      register struct buffer *tb;
--- 484,490 ----
  }
  
  void *
! DNew(register struct fcache * fid, register int page)
  {
      /* Same as read, only do *not* even try to read the page, since it probably doesn't exist. */
      register struct buffer *tb;
Index: openafs/src/afs/afs_dcache.c
diff -c openafs/src/afs/afs_dcache.c:1.42.2.1 openafs/src/afs/afs_dcache.c:1.42.2.2
*** openafs/src/afs/afs_dcache.c:1.42.2.1	Wed Aug 25 03:09:32 2004
--- openafs/src/afs/afs_dcache.c	Mon Oct 18 13:43:49 2004
***************
*** 14,20 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_dcache.c,v 1.42.2.1 2004/08/25 07:09:32 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 14,20 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_dcache.c,v 1.42.2.2 2004/10/18 17:43:49 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 686,692 ****
      AFS_STATCNT(afs_glink);
  #endif
      /* we know this guy's in the LRUQ.  We'll move dude into DCQ below */
!     DZap(&amp;adc-&gt;f.inode);
      /* if this guy is in the hash table, pull him out */
      if (adc-&gt;f.fid.Fid.Volume != 0) {
  	/* remove entry from first hash chains */
--- 686,692 ----
      AFS_STATCNT(afs_glink);
  #endif
      /* we know this guy's in the LRUQ.  We'll move dude into DCQ below */
!     DZap(&amp;adc-&gt;f);
      /* if this guy is in the hash table, pull him out */
      if (adc-&gt;f.fid.Fid.Volume != 0) {
  	/* remove entry from first hash chains */
***************
*** 2038,2044 ****
  	 * Right now, we only have one tool, and it's a hammer.  So, we
  	 * fetch the whole file.
  	 */
! 	DZap(&amp;tdc-&gt;f.inode);	/* pages in cache may be old */
  #ifdef  IHINT
  	if (file = tdc-&gt;ihint) {
  	    if (tdc-&gt;f.inode == file-&gt;inum)
--- 2038,2044 ----
  	 * Right now, we only have one tool, and it's a hammer.  So, we
  	 * fetch the whole file.
  	 */
! 	DZap(&amp;tdc-&gt;f);	/* pages in cache may be old */
  #ifdef  IHINT
  	if (file = tdc-&gt;ihint) {
  	    if (tdc-&gt;f.inode == file-&gt;inum)
***************
*** 2415,2421 ****
  	    afs_CFileClose(file);
  	    ZapDCE(tdc);	/* sets DFEntryMod */
  	    if (vType(avc) == VDIR) {
! 		DZap(&amp;tdc-&gt;f.inode);
  	    }
  	    ReleaseWriteLock(&amp;tdc-&gt;lock);
  	    afs_PutDCache(tdc);
--- 2415,2421 ----
  	    afs_CFileClose(file);
  	    ZapDCE(tdc);	/* sets DFEntryMod */
  	    if (vType(avc) == VDIR) {
! 		DZap(&amp;tdc-&gt;f);
  	    }
  	    ReleaseWriteLock(&amp;tdc-&gt;lock);
  	    afs_PutDCache(tdc);
Index: openafs/src/afs/afs_osi.h
diff -c openafs/src/afs/afs_osi.h:1.22 openafs/src/afs/afs_osi.h:1.22.2.1
*** openafs/src/afs/afs_osi.h:1.22	Thu Jun 24 13:38:23 2004
--- openafs/src/afs/afs_osi.h	Mon Oct 18 03:11:45 2004
***************
*** 187,195 ****
   * The following three routines provide the fid routines used by the buffer
   * and directory packages.
   */
! #define dirp_Zap(afid)    (*(afid) = -1)
! #define dirp_Eq(afid, bfid) (*(afid) == *(bfid))
! #define dirp_Cpy(dfid,sfid) (*(dfid) = *(sfid))
  
  
  /*
--- 187,195 ----
   * The following three routines provide the fid routines used by the buffer
   * and directory packages.
   */
! #define dirp_Zap(afid)    ((afid) = 0)
! #define dirp_Eq(afid, bfid) ((afid) == (bfid))
! #define dirp_Cpy(dfid,sfid) ((dfid) = (sfid))
  
  
  /*
Index: openafs/src/afs/afs_osi_pag.c
diff -c openafs/src/afs/afs_osi_pag.c:1.21 openafs/src/afs/afs_osi_pag.c:1.21.2.1
*** openafs/src/afs/afs_osi_pag.c:1.21	Wed Jul 28 23:13:37 2004
--- openafs/src/afs/afs_osi_pag.c	Mon Oct 18 03:11:45 2004
***************
*** 23,29 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi_pag.c,v 1.21 2004/07/29 03:13:37 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 23,29 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi_pag.c,v 1.21.2.1 2004/10/18 07:11:45 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 139,144 ****
--- 139,181 ----
   * activates tokens repeatedly) for that entire period.
   */
  
+ static int afs_pag_sleepcnt = 0;
+ 
+ static int 
+ afs_pag_sleep(struct AFS_UCRED **acred) 
+ {
+   int rv = 0;
+   if(!afs_suser(acred)) {
+     if(osi_Time() - pag_epoch &lt; pagCounter) {
+       rv = 1;
+     }
+   }
+ 
+   return rv;
+ }
+ 
+ static int 
+ afs_pag_wait(struct AFS_UCRED **acred)
+ {
+   if(afs_pag_sleep(acred)) {
+     if(!afs_pag_sleepcnt) {
+       printf("%s() PAG throttling triggered, pid %d... sleeping.  sleepcnt %d\n",
+ 	     __func__, getpid(), afs_pag_sleepcnt);
+     }
+     
+     afs_pag_sleepcnt++;
+     
+     do {
+       /* XXX spins on EINTR */
+       afs_osi_Wait(1000, (struct afs_osi_WaitHandle *)0, 0);
+     } while(afs_pag_sleep(acred));
+     
+     afs_pag_sleepcnt--;
+   }
+ 
+   return 0;
+ }
+ 
  int
  #if	defined(AFS_SUN5_ENV)
  afs_setpag(struct AFS_UCRED **credpp)
***************
*** 148,153 ****
--- 185,199 ----
  afs_setpag(void)
  #endif
  {
+ 
+ #if     defined(AFS_SUN5_ENV)
+     struct AFS_UCRED **acred = *credpp;
+ #elif  defined(AFS_OBSD_ENV)
+     struct AFS_UCRED **acred = p-&gt;p_ucred;
+ #else
+     struct AFS_UCRED **acred = NULL;
+ #endif
+ 
      int code = 0;
  
  #if defined(AFS_SGI53_ENV) &amp;&amp; defined(MP)
***************
*** 156,173 ****
  #endif /* defined(AFS_SGI53_ENV) &amp;&amp; defined(MP) */
  
      AFS_STATCNT(afs_setpag);
! #if	defined(AFS_SUN5_ENV)
!     if (!afs_suser(*credpp))
! #elif  defined(AFS_OBSD_ENV)
!     if (!afs_osi_suser(p-&gt;p_ucred))
! #else
!     if (!afs_suser(NULL))
! #endif
!     {
! 	while (osi_Time() - pag_epoch &lt; pagCounter) {
! 	    afs_osi_Wait(1000, (struct afs_osi_WaitHandle *)0, 0);
! 	}
!     }
  #if	defined(AFS_SUN5_ENV)
      code = AddPag(genpag(), credpp);
  #elif	defined(AFS_OSF_ENV) || defined(AFS_XBSD_ENV)
--- 202,211 ----
  #endif /* defined(AFS_SGI53_ENV) &amp;&amp; defined(MP) */
  
      AFS_STATCNT(afs_setpag);
! 
!     afs_pag_wait(acred);
! 
! 
  #if	defined(AFS_SUN5_ENV)
      code = AddPag(genpag(), credpp);
  #elif	defined(AFS_OSF_ENV) || defined(AFS_XBSD_ENV)
***************
*** 213,225 ****
--- 251,266 ----
  #endif
  
      afs_Trace1(afs_iclSetp, CM_TRACE_SETPAG, ICL_TYPE_INT32, code);
+ 
  #if defined(KERNEL_HAVE_UERROR)
      if (!getuerror())
  	setuerror(code);
  #endif
+ 
  #if defined(AFS_SGI53_ENV) &amp;&amp; defined(MP)
      AFS_GUNLOCK();
  #endif /* defined(AFS_SGI53_ENV) &amp;&amp; defined(MP) */
+ 
      return (code);
  }
  
***************
*** 240,245 ****
--- 281,295 ----
  afs_setpag_val(int pagval)
  #endif
  {
+ 
+ #if     defined(AFS_SUN5_ENV)
+     struct AFS_UCRED **acred = *credp;
+ #elif  defined(AFS_OBSD_ENV)
+     struct AFS_UCRED **acred = p-&gt;p_ucred;
+ #else
+     struct AFS_UCRED **acred = NULL;
+ #endif
+ 
      int code = 0;
  
  #if defined(AFS_SGI53_ENV) &amp;&amp; defined(MP)
***************
*** 248,263 ****
  #endif /* defined(AFS_SGI53_ENV) &amp;&amp; defined(MP) */
  
      AFS_STATCNT(afs_setpag);
! #ifdef AFS_SUN5_ENV
!     if (!afs_suser(*credpp))
! #else
!     if (!afs_suser(NULL))
! #endif
!     {
! 	while (osi_Time() - pag_epoch &lt; pagCounter) {
! 	    afs_osi_Wait(1000, (struct afs_osi_WaitHandle *)0, 0);
! 	}
!     }
  #if	defined(AFS_SUN5_ENV)
      code = AddPag(pagval, credpp);
  #elif	defined(AFS_OSF_ENV) || defined(AFS_XBSD_ENV)
--- 298,306 ----
  #endif /* defined(AFS_SGI53_ENV) &amp;&amp; defined(MP) */
  
      AFS_STATCNT(afs_setpag);
! 
!     afs_pag_wait(acred);
! 
  #if	defined(AFS_SUN5_ENV)
      code = AddPag(pagval, credpp);
  #elif	defined(AFS_OSF_ENV) || defined(AFS_XBSD_ENV)
Index: openafs/src/afs/afs_pioctl.c
diff -c openafs/src/afs/afs_pioctl.c:1.81.2.1 openafs/src/afs/afs_pioctl.c:1.81.2.2
*** openafs/src/afs/afs_pioctl.c:1.81.2.1	Wed Aug 25 03:03:35 2004
--- openafs/src/afs/afs_pioctl.c	Mon Oct 18 13:43:49 2004
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_pioctl.c,v 1.81.2.1 2004/08/25 07:03:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #ifdef AFS_OBSD_ENV
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_pioctl.c,v 1.81.2.2 2004/10/18 17:43:49 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #ifdef AFS_OBSD_ENV
***************
*** 268,274 ****
  #elif defined(AFS_AMD64_LINUX20_ENV)
      if (current-&gt;thread.flags &amp; THREAD_IA32)
  #elif defined(AFS_PPC64_LINUX20_ENV)
!     if (current-&gt;thread.flags &amp; PPC_FLAG_32BIT)
  #elif defined(AFS_S390X_LINUX20_ENV)
      if (current-&gt;thread.flags &amp; S390_FLAG_31BIT)
  #else
--- 268,278 ----
  #elif defined(AFS_AMD64_LINUX20_ENV)
      if (current-&gt;thread.flags &amp; THREAD_IA32)
  #elif defined(AFS_PPC64_LINUX20_ENV)
! #ifdef AFS_PPC64_LINUX26_ENV
!       if (current-&gt;thread_info-&gt;flags &amp; _TIF_32BIT)
! #else /*Linux 2.6*/
!     if (current-&gt;thread.flags &amp; PPC_FLAG_32BIT) 
! #endif
  #elif defined(AFS_S390X_LINUX20_ENV)
      if (current-&gt;thread.flags &amp; S390_FLAG_31BIT)
  #else
***************
*** 488,494 ****
      unsigned int com;
      unsigned long arg;
  };
! asmlinkage int
  afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
  	   unsigned long arg)
  {
--- 492,498 ----
      unsigned int com;
      unsigned long arg;
  };
! int
  afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
  	   unsigned long arg)
  {
***************
*** 1713,1719 ****
      Check_AtSys(avc, ain, &amp;sysState, areq);
      ObtainReadLock(&amp;tdc-&gt;lock);
      do {
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f.inode, sysState.name, &amp;tfid.Fid);
      } while (code == ENOENT &amp;&amp; Next_AtSys(avc, areq, &amp;sysState));
      ReleaseReadLock(&amp;tdc-&gt;lock);
      afs_PutDCache(tdc);		/* we're done with the data */
--- 1717,1723 ----
      Check_AtSys(avc, ain, &amp;sysState, areq);
      ObtainReadLock(&amp;tdc-&gt;lock);
      do {
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f, sysState.name, &amp;tfid.Fid);
      } while (code == ENOENT &amp;&amp; Next_AtSys(avc, areq, &amp;sysState));
      ReleaseReadLock(&amp;tdc-&gt;lock);
      afs_PutDCache(tdc);		/* we're done with the data */
***************
*** 2393,2399 ****
      Check_AtSys(avc, ain, &amp;sysState, areq);
      ObtainReadLock(&amp;tdc-&gt;lock);
      do {
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f.inode, sysState.name, &amp;tfid.Fid);
      } while (code == ENOENT &amp;&amp; Next_AtSys(avc, areq, &amp;sysState));
      ReleaseReadLock(&amp;tdc-&gt;lock);
      bufp = sysState.name;
--- 2397,2403 ----
      Check_AtSys(avc, ain, &amp;sysState, areq);
      ObtainReadLock(&amp;tdc-&gt;lock);
      do {
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f, sysState.name, &amp;tfid.Fid);
      } while (code == ENOENT &amp;&amp; Next_AtSys(avc, areq, &amp;sysState));
      ReleaseReadLock(&amp;tdc-&gt;lock);
      bufp = sysState.name;
***************
*** 2464,2473 ****
  	ObtainWriteLock(&amp;tdc-&gt;lock, 661);
  	if (afs_LocalHero(avc, tdc, &amp;OutDirStatus, 1)) {
  	    /* we can do it locally */
! 	    code = afs_dir_Delete(&amp;tdc-&gt;f.inode, bufp);
  	    if (code) {
  		ZapDCE(tdc);	/* surprise error -- invalid value */
! 		DZap(&amp;tdc-&gt;f.inode);
  	    }
  	}
  	ReleaseWriteLock(&amp;tdc-&gt;lock);
--- 2468,2477 ----
  	ObtainWriteLock(&amp;tdc-&gt;lock, 661);
  	if (afs_LocalHero(avc, tdc, &amp;OutDirStatus, 1)) {
  	    /* we can do it locally */
! 	    code = afs_dir_Delete(&amp;tdc-&gt;f, bufp);
  	    if (code) {
  		ZapDCE(tdc);	/* surprise error -- invalid value */
! 		DZap(&amp;tdc-&gt;f);
  	    }
  	}
  	ReleaseWriteLock(&amp;tdc-&gt;lock);
***************
*** 3499,3505 ****
      Check_AtSys(avc, ain, &amp;sysState, areq);
      ObtainReadLock(&amp;tdc-&gt;lock);
      do {
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f.inode, sysState.name, &amp;tfid.Fid);
      } while (code == ENOENT &amp;&amp; Next_AtSys(avc, areq, &amp;sysState));
      ReleaseReadLock(&amp;tdc-&gt;lock);
      afs_PutDCache(tdc);		/* we're done with the data */
--- 3503,3509 ----
      Check_AtSys(avc, ain, &amp;sysState, areq);
      ObtainReadLock(&amp;tdc-&gt;lock);
      do {
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f, sysState.name, &amp;tfid.Fid);
      } while (code == ENOENT &amp;&amp; Next_AtSys(avc, areq, &amp;sysState));
      ReleaseReadLock(&amp;tdc-&gt;lock);
      afs_PutDCache(tdc);		/* we're done with the data */
Index: openafs/src/afs/afs_prototypes.h
diff -c openafs/src/afs/afs_prototypes.h:1.53 openafs/src/afs/afs_prototypes.h:1.53.2.1
*** openafs/src/afs/afs_prototypes.h:1.53	Sun Aug  8 20:24:57 2004
--- openafs/src/afs/afs_prototypes.h	Mon Oct 18 03:11:45 2004
***************
*** 31,42 ****
  
  /* afs_buffer.c */
  extern void DInit(int abuffers);
! extern void *DRead(register afs_inode_t * fid, register int page);
  extern void DRelease(register struct buffer *bp, int flag);
  extern int DVOffset(register void *ap);
! extern void DZap(afs_inode_t * fid);
  extern void DFlush(void);
! extern void *DNew(register afs_inode_t * fid, register int page);
  extern void shutdown_bufferpackage(void);
  
  /* afs_call.c */
--- 31,42 ----
  
  /* afs_buffer.c */
  extern void DInit(int abuffers);
! extern void *DRead(register struct fcache * fid, register int page);
  extern void DRelease(register struct buffer *bp, int flag);
  extern int DVOffset(register void *ap);
! extern void DZap(struct fcache * fid);
  extern void DFlush(void);
! extern void *DNew(register struct fcache * fid, register int page);
  extern void shutdown_bufferpackage(void);
  
  /* afs_call.c */
Index: openafs/src/afs/afs_segments.c
diff -c openafs/src/afs/afs_segments.c:1.16.2.1 openafs/src/afs/afs_segments.c:1.16.2.2
*** openafs/src/afs/afs_segments.c:1.16.2.1	Wed Aug 25 03:09:32 2004
--- openafs/src/afs/afs_segments.c	Mon Oct 18 13:43:50 2004
***************
*** 14,20 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_segments.c,v 1.16.2.1 2004/08/25 07:09:32 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 14,20 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_segments.c,v 1.16.2.2 2004/10/18 17:43:50 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 898,904 ****
  	ObtainWriteLock(&amp;tdc-&gt;lock, 679);
  	ZapDCE(tdc);
  	if (vType(avc) == VDIR)
! 	    DZap(&amp;tdc-&gt;f.inode);
  	ReleaseWriteLock(&amp;tdc-&gt;lock);
  	afs_PutDCache(tdc);
      }
--- 898,904 ----
  	ObtainWriteLock(&amp;tdc-&gt;lock, 679);
  	ZapDCE(tdc);
  	if (vType(avc) == VDIR)
! 	    DZap(&amp;tdc-&gt;f);
  	ReleaseWriteLock(&amp;tdc-&gt;lock);
  	afs_PutDCache(tdc);
      }
***************
*** 1041,1046 ****
--- 1041,1052 ----
  	    afs_CFileTruncate(tfile, newSize);
  	    afs_CFileClose(tfile);
  	    afs_AdjustSize(tdc, newSize);
+ 	    if (alen &lt; tdc-&gt;validPos) {
+                 if (alen &lt; AFS_CHUNKTOBASE(tdc-&gt;f.chunk))
+                     tdc-&gt;validPos = 0;
+                 else
+                     tdc-&gt;validPos = alen;
+             }
  	    ConvertWToSLock(&amp;tdc-&gt;lock);
  	}
  	ReleaseSharedLock(&amp;tdc-&gt;lock);
Index: openafs/src/afs/afs_stats.h
diff -c openafs/src/afs/afs_stats.h:1.11 openafs/src/afs/afs_stats.h:1.11.2.1
*** openafs/src/afs/afs_stats.h:1.11	Tue Jul 15 19:14:13 2003
--- openafs/src/afs/afs_stats.h	Sat Aug 28 21:18:56 2004
***************
*** 46,52 ****
  #endif /* !KERNEL */
  
  #define XSTATS_DECLS struct afs_stats_opTimingData *opP; \
!     osi_timeval_t opStartTime, opStopTime, elapsedTime;
  
  #define XSTATS_START_TIME(arg) \
    opP = &amp;(afs_stats_cmfullperf.rpc.fsRPCTimes[arg]); \
--- 46,52 ----
  #endif /* !KERNEL */
  
  #define XSTATS_DECLS struct afs_stats_opTimingData *opP; \
!     osi_timeval_t opStartTime, opStopTime, elapsedTime
  
  #define XSTATS_START_TIME(arg) \
    opP = &amp;(afs_stats_cmfullperf.rpc.fsRPCTimes[arg]); \
Index: openafs/src/afs/afs_vcache.c
diff -c openafs/src/afs/afs_vcache.c:1.65.2.3 openafs/src/afs/afs_vcache.c:1.65.2.4
*** openafs/src/afs/afs_vcache.c:1.65.2.3	Wed Aug 25 03:16:11 2004
--- openafs/src/afs/afs_vcache.c	Mon Oct 18 13:43:50 2004
***************
*** 39,45 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_vcache.c,v 1.65.2.3 2004/08/25 07:16:11 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 39,45 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_vcache.c,v 1.65.2.4 2004/10/18 17:43:50 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 840,848 ****
  #elif defined(AFS_LINUX22_ENV)
  	    if (tvc != afs_globalVp &amp;&amp; VREFCOUNT(tvc) &amp;&amp; tvc-&gt;opens == 0) {
  #if defined(AFS_LINUX26_ENV)
! 		AFS_GUNLOCK();
! 		d_prune_aliases(AFSTOI(tvc));
! 		AFS_GLOCK();
  #else
  		afs_TryFlushDcacheChildren(tvc);
  #endif
--- 840,857 ----
  #elif defined(AFS_LINUX22_ENV)
  	    if (tvc != afs_globalVp &amp;&amp; VREFCOUNT(tvc) &amp;&amp; tvc-&gt;opens == 0) {
  #if defined(AFS_LINUX26_ENV)
!                 struct dentry *dentry;
!                 struct list_head *cur, *head = &amp;(AFSTOI(tvc))-&gt;i_dentry;
!                 AFS_GUNLOCK();
!                 cur=head;
!                 while ((cur = cur-&gt;next) != head) {
!                     dentry = list_entry(cur, struct dentry, d_alias);
!                     if (!d_unhashed(dentry) &amp;&amp;
!                         !list_empty(&amp;dentry-&gt;d_subdirs))
! 			shrink_dcache_parent(dentry);
!                 }
!                 d_prune_aliases(AFSTOI(tvc));
!                 AFS_GLOCK();
  #else
  		afs_TryFlushDcacheChildren(tvc);
  #endif
Index: openafs/src/afs/LINUX/osi_groups.c
diff -c openafs/src/afs/LINUX/osi_groups.c:1.25 openafs/src/afs/LINUX/osi_groups.c:1.25.2.1
*** openafs/src/afs/LINUX/osi_groups.c:1.25	Wed Jul 14 00:09:12 2004
--- openafs/src/afs/LINUX/osi_groups.c	Mon Oct 18 03:11:46 2004
***************
*** 17,23 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_groups.c,v 1.25 2004/07/14 04:09:12 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
--- 17,23 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_groups.c,v 1.25.2.1 2004/10/18 07:11:46 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
***************
*** 222,228 ****
  
  
  /* Intercept the standard system call. */
! extern long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
  asmlinkage long
  afs_xsetgroups(int gidsetsize, gid_t * grouplist)
  {
--- 222,228 ----
  
  
  /* Intercept the standard system call. */
! extern asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
  asmlinkage long
  afs_xsetgroups(int gidsetsize, gid_t * grouplist)
  {
***************
*** 256,262 ****
  
  #if defined(AFS_LINUX24_ENV)
  /* Intercept the standard uid32 system call. */
! extern long (*sys_setgroups32p) (int gidsetsize, gid_t * grouplist);
  asmlinkage long
  afs_xsetgroups32(int gidsetsize, gid_t * grouplist)
  {
--- 256,262 ----
  
  #if defined(AFS_LINUX24_ENV)
  /* Intercept the standard uid32 system call. */
! extern asmlinkage long (*sys_setgroups32p) (int gidsetsize, gid_t * grouplist);
  asmlinkage long
  afs_xsetgroups32(int gidsetsize, gid_t * grouplist)
  {
Index: openafs/src/afs/LINUX/osi_module.c
diff -c openafs/src/afs/LINUX/osi_module.c:1.52.2.1 openafs/src/afs/LINUX/osi_module.c:1.52.2.2
*** openafs/src/afs/LINUX/osi_module.c:1.52.2.1	Wed Aug 25 03:03:36 2004
--- openafs/src/afs/LINUX/osi_module.c	Mon Oct 18 13:43:51 2004
***************
*** 15,21 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_module.c,v 1.52.2.1 2004/08/25 07:03:36 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
--- 15,21 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_module.c,v 1.52.2.2 2004/10/18 17:43:51 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
***************
*** 223,233 ****
  #define SYSCALL2POINTER (void *)
  #endif
  
- #ifdef AFS_PPC64_LINUX20_ENV
- extern void *set_afs_syscall(void*);
- extern void *set_afs_xsetgroups_syscall(void*);
- extern void *set_afs_xsetgroups_syscall32(void*);
- #endif
  
  #if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,4,0)
  int __init
--- 223,228 ----
***************
*** 525,535 ****
  #endif /* AFS_AMD64_LINUX20_ENV */
  #endif /* AFS_IA64_LINUX20_ENV */
  
- #ifdef AFS_PPC64_LINUX20_ENV
-     afs_ni_syscall = set_afs_syscall(afs_syscall);
-     sys_setgroupsp = set_afs_xsetgroups_syscall(afs_xsetgroups);
-     sys32_setgroupsp = set_afs_xsetgroups_syscall32(afs32_xsetgroups);
- #endif
      }
  
      osi_sysctl_init();
--- 520,525 ----
***************
*** 582,592 ****
      }
  #endif
      }
- #ifdef AFS_PPC64_LINUX20_ENV
-     set_afs_syscall(afs_ni_syscall);
-     set_afs_xsetgroups_syscall(sys_setgroupsp);
-     set_afs_xsetgroups_syscall32(sys32_setgroupsp);
- #endif
      unregister_filesystem(&amp;afs_fs_type);
  
      osi_linux_free_inode_pages();	/* Invalidate all pages using AFS inodes. */
--- 572,577 ----
Index: openafs/src/afs/LINUX/osi_prototypes.h
diff -c openafs/src/afs/LINUX/osi_prototypes.h:1.6 openafs/src/afs/LINUX/osi_prototypes.h:1.6.2.1
*** openafs/src/afs/LINUX/osi_prototypes.h:1.6	Tue Jul 15 19:14:24 2003
--- openafs/src/afs/LINUX/osi_prototypes.h	Mon Oct 18 03:11:46 2004
***************
*** 36,44 ****
  extern int osi_InitCacheInfo(char *aname);
  extern int osi_rdwr(int rw, struct osi_file *file, caddr_t addrp,
  		    size_t asize, size_t * resid);
- extern void inline setup_uio(uio_t * uiop, struct iovec *iovecp, char *buf,
- 			     afs_offs_t pos, int count, uio_flag_t flag,
- 			     uio_seg_t seg);
  extern int osi_file_uio_rdwr(struct osi_file *osifile, uio_t * uiop, int rw);
  extern void afs_osi_SetTime(osi_timeval_t * tvp);
  extern void osi_linux_free_inode_pages(void);
--- 36,41 ----
Index: openafs/src/afs/LINUX/osi_vnodeops.c
diff -c openafs/src/afs/LINUX/osi_vnodeops.c:1.81.2.2 openafs/src/afs/LINUX/osi_vnodeops.c:1.81.2.3
*** openafs/src/afs/LINUX/osi_vnodeops.c:1.81.2.2	Wed Aug 25 03:10:39 2004
--- openafs/src/afs/LINUX/osi_vnodeops.c	Mon Oct 18 13:43:51 2004
***************
*** 22,28 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_vnodeops.c,v 1.81.2.2 2004/08/25 07:10:39 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
--- 22,28 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_vnodeops.c,v 1.81.2.3 2004/10/18 17:43:51 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
***************
*** 333,343 ****
      code = 0;
      offset = (int) fp-&gt;f_pos;
      while (1) {
! 	dirpos = BlobScan(&amp;tdc-&gt;f.inode, offset);
  	if (!dirpos)
  	    break;
  
! 	de = afs_dir_GetBlob(&amp;tdc-&gt;f.inode, dirpos);
  	if (!de)
  	    break;
  
--- 333,343 ----
      code = 0;
      offset = (int) fp-&gt;f_pos;
      while (1) {
! 	dirpos = BlobScan(&amp;tdc-&gt;f, offset);
  	if (!dirpos)
  	    break;
  
! 	de = afs_dir_GetBlob(&amp;tdc-&gt;f, dirpos);
  	if (!de)
  	    break;
  
***************
*** 649,660 ****
      int code = 0;
      struct vcache *vcp = ITOAFS(FILE_INODE(fp));
      cred_t *credp = crref();
! #ifdef AFS_LINUX24_ENV
!     struct flock64 flock;
! #else
!     struct flock flock;
! #endif
! 
      /* Convert to a lock format afs_lockctl understands. */
      memset((char *)&amp;flock, 0, sizeof(flock));
      flock.l_type = flp-&gt;fl_type;
--- 649,655 ----
      int code = 0;
      struct vcache *vcp = ITOAFS(FILE_INODE(fp));
      cred_t *credp = crref();
!     struct AFS_FLOCK flock;
      /* Convert to a lock format afs_lockctl understands. */
      memset((char *)&amp;flock, 0, sizeof(flock));
      flock.l_type = flp-&gt;fl_type;
***************
*** 1485,1490 ****
--- 1480,1491 ----
      unsigned offset = PAGE_CACHE_SIZE;
      long status;
  
+ #ifdef PageLaunder
+     if (PageLaunder(pp)) {
+ 	return(fail_writepage(pp));
+     }
+ #endif
+ 
      inode = (struct inode *)mapping-&gt;host;
      end_index = inode-&gt;i_size &gt;&gt; PAGE_CACHE_SHIFT;
  
Index: openafs/src/afs/SOLARIS/osi_vnodeops.c
diff -c openafs/src/afs/SOLARIS/osi_vnodeops.c:1.20 openafs/src/afs/SOLARIS/osi_vnodeops.c:1.20.2.1
*** openafs/src/afs/SOLARIS/osi_vnodeops.c:1.20	Thu Jun 24 13:38:24 2004
--- openafs/src/afs/SOLARIS/osi_vnodeops.c	Mon Oct 18 03:11:47 2004
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/SOLARIS/osi_vnodeops.c,v 1.20 2004/06/24 17:38:24 shadow Exp $");
  
  #if	defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
  /*
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/SOLARIS/osi_vnodeops.c,v 1.20.2.1 2004/10/18 07:11:47 shadow Exp $");
  
  #if	defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
  /*
***************
*** 1069,1075 ****
  	/* do ulimit processing; shrink resid or fail */
  #if	defined(AFS_SUN56_ENV)
  	if (auio-&gt;uio_loffset + auio-&gt;afsio_resid &gt; auio-&gt;uio_llimit) {
! 	    if (auio-&gt;uio_llimit &gt;= auio-&gt;uio_llimit) {
  		ReleaseWriteLock(&amp;avc-&gt;lock);
  		afs_BozonUnlock(&amp;avc-&gt;pvnLock, avc);
  		return EFBIG;
--- 1069,1075 ----
  	/* do ulimit processing; shrink resid or fail */
  #if	defined(AFS_SUN56_ENV)
  	if (auio-&gt;uio_loffset + auio-&gt;afsio_resid &gt; auio-&gt;uio_llimit) {
! 	    if (auio-&gt;uio_loffset &gt;= auio-&gt;uio_llimit) {
  		ReleaseWriteLock(&amp;avc-&gt;lock);
  		afs_BozonUnlock(&amp;avc-&gt;pvnLock, avc);
  		return EFBIG;
Index: openafs/src/afs/VNOPS/afs_vnop_create.c
diff -c openafs/src/afs/VNOPS/afs_vnop_create.c:1.16.2.1 openafs/src/afs/VNOPS/afs_vnop_create.c:1.16.2.2
*** openafs/src/afs/VNOPS/afs_vnop_create.c:1.16.2.1	Wed Aug 25 03:09:35 2004
--- openafs/src/afs/VNOPS/afs_vnop_create.c	Mon Oct 18 13:43:51 2004
***************
*** 17,23 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_create.c,v 1.16.2.1 2004/08/25 07:09:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 17,23 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_create.c,v 1.16.2.2 2004/10/18 17:43:51 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 154,160 ****
      if (tdc) {
  	/* see if file already exists.  If it does, we only set 
  	 * the size attributes (to handle O_TRUNC) */
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f.inode, aname, &amp;newFid.Fid);	/* use dnlc first xxx */
  	if (code == 0) {
  	    ReleaseSharedLock(&amp;tdc-&gt;lock);
  	    afs_PutDCache(tdc);
--- 154,160 ----
      if (tdc) {
  	/* see if file already exists.  If it does, we only set 
  	 * the size attributes (to handle O_TRUNC) */
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f, aname, &amp;newFid.Fid);	/* use dnlc first xxx */
  	if (code == 0) {
  	    ReleaseSharedLock(&amp;tdc-&gt;lock);
  	    afs_PutDCache(tdc);
***************
*** 368,377 ****
  	UpgradeSToWLock(&amp;tdc-&gt;lock, 631);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Create(&amp;tdc-&gt;f.inode, aname, &amp;newFid.Fid);
  	if (code) {
  	    ZapDCE(tdc);
! 	    DZap(&amp;tdc-&gt;f.inode);
  	}
      }
      if (tdc) {
--- 368,377 ----
  	UpgradeSToWLock(&amp;tdc-&gt;lock, 631);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Create(&amp;tdc-&gt;f, aname, &amp;newFid.Fid);
  	if (code) {
  	    ZapDCE(tdc);
! 	    DZap(&amp;tdc-&gt;f);
  	}
      }
      if (tdc) {
***************
*** 531,537 ****
      } else {
  	if (adc) {
  	    ZapDCE(adc);
! 	    DZap(&amp;adc-&gt;f.inode);
  	}
  	if (avc-&gt;states &amp; CStatd) {
  	    osi_dnlc_purgedp(avc);
--- 531,537 ----
      } else {
  	if (adc) {
  	    ZapDCE(adc);
! 	    DZap(&amp;adc-&gt;f);
  	}
  	if (avc-&gt;states &amp; CStatd) {
  	    osi_dnlc_purgedp(avc);
Index: openafs/src/afs/VNOPS/afs_vnop_dirops.c
diff -c openafs/src/afs/VNOPS/afs_vnop_dirops.c:1.14.2.1 openafs/src/afs/VNOPS/afs_vnop_dirops.c:1.14.2.2
*** openafs/src/afs/VNOPS/afs_vnop_dirops.c:1.14.2.1	Wed Aug 25 03:09:35 2004
--- openafs/src/afs/VNOPS/afs_vnop_dirops.c	Mon Oct 18 13:43:51 2004
***************
*** 21,27 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_dirops.c,v 1.14.2.1 2004/08/25 07:09:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 21,27 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_dirops.c,v 1.14.2.2 2004/10/18 17:43:51 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 147,156 ****
  	ObtainWriteLock(&amp;tdc-&gt;lock, 632);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Create(&amp;tdc-&gt;f.inode, aname, &amp;newFid.Fid);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- use invalid value */
! 	    DZap(&amp;tdc-&gt;f.inode);
  	}
      }
      if (tdc) {
--- 147,156 ----
  	ObtainWriteLock(&amp;tdc-&gt;lock, 632);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Create(&amp;tdc-&gt;f, aname, &amp;newFid.Fid);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- use invalid value */
! 	    DZap(&amp;tdc-&gt;f);
  	}
      }
      if (tdc) {
***************
*** 250,256 ****
  	struct VenusFid unlinkFid;
  
  	unlinkFid.Fid.Vnode = 0;
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f.inode, aname, &amp;unlinkFid.Fid);
  	if (code == 0) {
  	    afs_int32 cached = 0;
  
--- 250,256 ----
  	struct VenusFid unlinkFid;
  
  	unlinkFid.Fid.Vnode = 0;
! 	code = afs_dir_Lookup(&amp;tdc-&gt;f, aname, &amp;unlinkFid.Fid);
  	if (code == 0) {
  	    afs_int32 cached = 0;
  
***************
*** 304,313 ****
  	UpgradeSToWLock(&amp;tdc-&gt;lock, 634);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Delete(&amp;tdc-&gt;f.inode, aname);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- invalid value */
! 	    DZap(&amp;tdc-&gt;f.inode);
  	}
      }
      if (tdc) {
--- 304,313 ----
  	UpgradeSToWLock(&amp;tdc-&gt;lock, 634);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Delete(&amp;tdc-&gt;f, aname);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- invalid value */
! 	    DZap(&amp;tdc-&gt;f);
  	}
      }
      if (tdc) {
Index: openafs/src/afs/VNOPS/afs_vnop_link.c
diff -c openafs/src/afs/VNOPS/afs_vnop_link.c:1.15.2.1 openafs/src/afs/VNOPS/afs_vnop_link.c:1.15.2.2
*** openafs/src/afs/VNOPS/afs_vnop_link.c:1.15.2.1	Wed Aug 25 03:09:35 2004
--- openafs/src/afs/VNOPS/afs_vnop_link.c	Mon Oct 18 13:43:51 2004
***************
*** 17,23 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_link.c,v 1.15.2.1 2004/08/25 07:09:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 17,23 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_link.c,v 1.15.2.2 2004/10/18 17:43:51 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 137,146 ****
  	ObtainWriteLock(&amp;tdc-&gt;lock, 635);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Create(&amp;tdc-&gt;f.inode, aname, &amp;avc-&gt;fid.Fid);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- invalid value */
! 	    DZap(&amp;tdc-&gt;f.inode);
  	}
      }
      if (tdc) {
--- 137,146 ----
  	ObtainWriteLock(&amp;tdc-&gt;lock, 635);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Create(&amp;tdc-&gt;f, aname, &amp;avc-&gt;fid.Fid);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- invalid value */
! 	    DZap(&amp;tdc-&gt;f);
  	}
      }
      if (tdc) {
Index: openafs/src/afs/VNOPS/afs_vnop_lookup.c
diff -c openafs/src/afs/VNOPS/afs_vnop_lookup.c:1.50.2.1 openafs/src/afs/VNOPS/afs_vnop_lookup.c:1.50.2.3
*** openafs/src/afs/VNOPS/afs_vnop_lookup.c:1.50.2.1	Wed Aug 25 03:09:35 2004
--- openafs/src/afs/VNOPS/afs_vnop_lookup.c	Mon Oct 18 13:43:51 2004
***************
*** 18,24 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_lookup.c,v 1.50.2.1 2004/08/25 07:09:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 18,24 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_lookup.c,v 1.50.2.3 2004/10/18 17:43:51 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 674,680 ****
  	/* look for first safe entry to examine in the directory.  BlobScan
  	 * looks for a the 1st allocated dir after the dirCookie slot.
  	 */
! 	newIndex = BlobScan(&amp;dcp-&gt;f.inode, (dirCookie &gt;&gt; 5));
  	if (newIndex == 0)
  	    break;
  
--- 674,680 ----
  	/* look for first safe entry to examine in the directory.  BlobScan
  	 * looks for a the 1st allocated dir after the dirCookie slot.
  	 */
! 	newIndex = BlobScan(&amp;dcp-&gt;f, (dirCookie &gt;&gt; 5));
  	if (newIndex == 0)
  	    break;
  
***************
*** 683,689 ****
  
  	/* get a ptr to the dir entry */
  	dirEntryp =
! 	    (struct DirEntry *)afs_dir_GetBlob(&amp;dcp-&gt;f.inode, newIndex);
  	if (!dirEntryp)
  	    break;
  
--- 683,689 ----
  
  	/* get a ptr to the dir entry */
  	dirEntryp =
! 	    (struct DirEntry *)afs_dir_GetBlob(&amp;dcp-&gt;f, newIndex);
  	if (!dirEntryp)
  	    break;
  
***************
*** 1128,1140 ****
      int pass = 0, hit = 0;
      long dirCookie;
      extern afs_int32 afs_mariner;	/*Writing activity to log? */
-     OSI_VC_CONVERT(adp);
      afs_hyper_t versionNo;
      int no_read_access = 0;
      struct sysname_info sysState;	/* used only for @sys checking */
      int dynrootRetry = 1;
      struct afs_fakestat_state fakestate;
      int tryEvalOnly = 0;
  
      AFS_STATCNT(afs_lookup);
      afs_InitFakeStat(&amp;fakestate);
--- 1128,1140 ----
      int pass = 0, hit = 0;
      long dirCookie;
      extern afs_int32 afs_mariner;	/*Writing activity to log? */
      afs_hyper_t versionNo;
      int no_read_access = 0;
      struct sysname_info sysState;	/* used only for @sys checking */
      int dynrootRetry = 1;
      struct afs_fakestat_state fakestate;
      int tryEvalOnly = 0;
+     OSI_VC_CONVERT(adp);
  
      AFS_STATCNT(afs_lookup);
      afs_InitFakeStat(&amp;fakestate);
***************
*** 1293,1299 ****
      {				/* sub-block just to reduce stack usage */
  	register struct dcache *tdc;
  	afs_size_t dirOffset, dirLen;
! 	ino_t theDir;
  	struct VenusFid tfid;
  
  	/* now we have to lookup the next fid */
--- 1293,1299 ----
      {				/* sub-block just to reduce stack usage */
  	register struct dcache *tdc;
  	afs_size_t dirOffset, dirLen;
! 	struct fcache *theDir;
  	struct VenusFid tfid;
  
  	/* now we have to lookup the next fid */
***************
*** 1351,1365 ****
  
  	/* lookup the name in the appropriate dir, and return a cache entry
  	 * on the resulting fid */
! 	theDir = tdc-&gt;f.inode;
  	code =
! 	    afs_dir_LookupOffset(&amp;theDir, sysState.name, &amp;tfid.Fid,
  				 &amp;dirCookie);
  
  	/* If the first lookup doesn't succeed, maybe it's got @sys in the name */
  	while (code == ENOENT &amp;&amp; Next_AtSys(adp, &amp;treq, &amp;sysState))
  	    code =
! 		afs_dir_LookupOffset(&amp;theDir, sysState.name, &amp;tfid.Fid,
  				     &amp;dirCookie);
  	tname = sysState.name;
  
--- 1351,1365 ----
  
  	/* lookup the name in the appropriate dir, and return a cache entry
  	 * on the resulting fid */
! 	theDir = &amp;tdc-&gt;f;
  	code =
! 	    afs_dir_LookupOffset(theDir, sysState.name, &amp;tfid.Fid,
  				 &amp;dirCookie);
  
  	/* If the first lookup doesn't succeed, maybe it's got @sys in the name */
  	while (code == ENOENT &amp;&amp; Next_AtSys(adp, &amp;treq, &amp;sysState))
  	    code =
! 		afs_dir_LookupOffset(theDir, sysState.name, &amp;tfid.Fid,
  				     &amp;dirCookie);
  	tname = sysState.name;
  
Index: openafs/src/afs/VNOPS/afs_vnop_readdir.c
diff -c openafs/src/afs/VNOPS/afs_vnop_readdir.c:1.24.2.1 openafs/src/afs/VNOPS/afs_vnop_readdir.c:1.24.2.2
*** openafs/src/afs/VNOPS/afs_vnop_readdir.c:1.24.2.1	Wed Aug 25 03:09:35 2004
--- openafs/src/afs/VNOPS/afs_vnop_readdir.c	Mon Oct 18 13:43:53 2004
***************
*** 23,29 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_readdir.c,v 1.24.2.1 2004/08/25 07:09:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 23,29 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_readdir.c,v 1.24.2.2 2004/10/18 17:43:53 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 66,89 ****
      BlobScan is used by the Linux port in a separate file, so it should not
      become static.
  */
- #if defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV)
  int
! BlobScan(ino64_t * afile, afs_int32 ablob)
! #else
! #if defined(AFS_HPUX1123_ENV)
! /*DEE should use afs_inode_t for all */
! int
! BlobScan(ino_t * afile, afs_int32 ablob)
! #else
! #ifdef AFS_LINUX_64BIT_KERNEL
! int
! BlobScan(long *afile, afs_int32 ablob)
! #else
! int
! BlobScan(afs_int32 * afile, afs_int32 ablob)
! #endif
! #endif
! #endif
  {
      register afs_int32 relativeBlob;
      afs_int32 pageBlob;
--- 66,73 ----
      BlobScan is used by the Linux port in a separate file, so it should not
      become static.
  */
  int
! BlobScan(struct fcache * afile, afs_int32 ablob)
  {
      register afs_int32 relativeBlob;
      afs_int32 pageBlob;
***************
*** 657,664 ****
  	origOffset = auio-&gt;afsio_offset;
  	/* scan for the next interesting entry scan for in-use blob otherwise up point at
  	 * this blob note that ode, if non-zero, also represents a held dir page */
! 	if (!(us = BlobScan(&amp;tdc-&gt;f.inode, (origOffset &gt;&gt; 5)))
! 	    || !(nde = (struct DirEntry *)afs_dir_GetBlob(&amp;tdc-&gt;f.inode, us))) {
  	    /* failed to setup nde, return what we've got, and release ode */
  	    if (len) {
  		/* something to hand over. */
--- 641,648 ----
  	origOffset = auio-&gt;afsio_offset;
  	/* scan for the next interesting entry scan for in-use blob otherwise up point at
  	 * this blob note that ode, if non-zero, also represents a held dir page */
! 	if (!(us = BlobScan(&amp;tdc-&gt;f, (origOffset &gt;&gt; 5)))
! 	    || !(nde = (struct DirEntry *)afs_dir_GetBlob(&amp;tdc-&gt;f, us))) {
  	    /* failed to setup nde, return what we've got, and release ode */
  	    if (len) {
  		/* something to hand over. */
***************
*** 948,955 ****
  
  	/* scan for the next interesting entry scan for in-use blob otherwise up point at
  	 * this blob note that ode, if non-zero, also represents a held dir page */
! 	if (!(us = BlobScan(&amp;tdc-&gt;f.inode, (origOffset &gt;&gt; 5)))
! 	    || !(nde = (struct DirEntry *)afs_dir_GetBlob(&amp;tdc-&gt;f.inode, us))) {
  	    /* failed to setup nde, return what we've got, and release ode */
  	    if (len) {
  		/* something to hand over. */
--- 932,939 ----
  
  	/* scan for the next interesting entry scan for in-use blob otherwise up point at
  	 * this blob note that ode, if non-zero, also represents a held dir page */
! 	if (!(us = BlobScan(&amp;tdc-&gt;f, (origOffset &gt;&gt; 5)))
! 	    || !(nde = (struct DirEntry *)afs_dir_GetBlob(&amp;tdc-&gt;f, us))) {
  	    /* failed to setup nde, return what we've got, and release ode */
  	    if (len) {
  		/* something to hand over. */
Index: openafs/src/afs/VNOPS/afs_vnop_remove.c
diff -c openafs/src/afs/VNOPS/afs_vnop_remove.c:1.31.2.1 openafs/src/afs/VNOPS/afs_vnop_remove.c:1.31.2.2
*** openafs/src/afs/VNOPS/afs_vnop_remove.c:1.31.2.1	Wed Aug 25 03:09:35 2004
--- openafs/src/afs/VNOPS/afs_vnop_remove.c	Mon Oct 18 13:43:53 2004
***************
*** 23,29 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_remove.c,v 1.31.2.1 2004/08/25 07:09:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 23,29 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_remove.c,v 1.31.2.2 2004/10/18 17:43:53 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 154,163 ****
  	UpgradeSToWLock(&amp;tdc-&gt;lock, 637);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Delete(&amp;tdc-&gt;f.inode, aname);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- invalid value */
! 	    DZap(&amp;tdc-&gt;f.inode);
  	}
      }
      if (tdc) {
--- 154,163 ----
  	UpgradeSToWLock(&amp;tdc-&gt;lock, 637);
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Delete(&amp;tdc-&gt;f, aname);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- invalid value */
! 	    DZap(&amp;tdc-&gt;f);
  	}
      }
      if (tdc) {
***************
*** 357,363 ****
       * done the work */
      if (!tvc)
  	if (tdc) {
! 	    code = afs_dir_Lookup(&amp;tdc-&gt;f.inode, aname, &amp;unlinkFid.Fid);
  	    if (code == 0) {
  		afs_int32 cached = 0;
  
--- 357,363 ----
       * done the work */
      if (!tvc)
  	if (tdc) {
! 	    code = afs_dir_Lookup(&amp;tdc-&gt;f, aname, &amp;unlinkFid.Fid);
  	    if (code == 0) {
  		afs_int32 cached = 0;
  
Index: openafs/src/afs/VNOPS/afs_vnop_rename.c
diff -c openafs/src/afs/VNOPS/afs_vnop_rename.c:1.16.2.1 openafs/src/afs/VNOPS/afs_vnop_rename.c:1.16.2.2
*** openafs/src/afs/VNOPS/afs_vnop_rename.c:1.16.2.1	Wed Aug 25 03:09:35 2004
--- openafs/src/afs/VNOPS/afs_vnop_rename.c	Mon Oct 18 13:43:53 2004
***************
*** 18,24 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_rename.c,v 1.16.2.1 2004/08/25 07:09:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 18,24 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_rename.c,v 1.16.2.2 2004/10/18 17:43:53 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 146,152 ****
      }
  
      if (code == 0)
! 	code = afs_dir_Lookup(&amp;tdc1-&gt;f.inode, aname1, &amp;fileFid.Fid);
      if (code) {
  	if (tdc1) {
  	    ReleaseWriteLock(&amp;tdc1-&gt;lock);
--- 146,152 ----
      }
  
      if (code == 0)
! 	code = afs_dir_Lookup(&amp;tdc1-&gt;f, aname1, &amp;fileFid.Fid);
      if (code) {
  	if (tdc1) {
  	    ReleaseWriteLock(&amp;tdc1-&gt;lock);
***************
*** 205,242 ****
  	    if (!doLocally) {
  		if (tdc1) {
  		    ZapDCE(tdc1);
! 		    DZap(&amp;tdc1-&gt;f.inode);
  		}
  		if (tdc2) {
  		    ZapDCE(tdc2);
! 		    DZap(&amp;tdc2-&gt;f.inode);
  		}
  	    }
  	}
  	/* now really do the work */
  	if (doLocally) {
  	    /* first lookup the fid of the dude we're moving */
! 	    code = afs_dir_Lookup(&amp;tdc1-&gt;f.inode, aname1, &amp;fileFid.Fid);
  	    if (code == 0) {
  		/* delete the source */
! 		code = afs_dir_Delete(&amp;tdc1-&gt;f.inode, aname1);
  	    }
  	    /* first see if target is there */
  	    if (code == 0
! 		&amp;&amp; afs_dir_Lookup(&amp;tdc2-&gt;f.inode, aname2,
  				  &amp;unlinkFid.Fid) == 0) {
  		/* target already exists, and will be unlinked by server */
! 		code = afs_dir_Delete(&amp;tdc2-&gt;f.inode, aname2);
  	    }
  	    if (code == 0) {
! 		code = afs_dir_Create(&amp;tdc2-&gt;f.inode, aname2, &amp;fileFid.Fid);
  	    }
  	    if (code != 0) {
  		ZapDCE(tdc1);
! 		DZap(&amp;tdc1-&gt;f.inode);
  		if (!oneDir) {
  		    ZapDCE(tdc2);
! 		    DZap(&amp;tdc2-&gt;f.inode);
  		}
  	    }
  	}
--- 205,242 ----
  	    if (!doLocally) {
  		if (tdc1) {
  		    ZapDCE(tdc1);
! 		    DZap(&amp;tdc1-&gt;f);
  		}
  		if (tdc2) {
  		    ZapDCE(tdc2);
! 		    DZap(&amp;tdc2-&gt;f);
  		}
  	    }
  	}
  	/* now really do the work */
  	if (doLocally) {
  	    /* first lookup the fid of the dude we're moving */
! 	    code = afs_dir_Lookup(&amp;tdc1-&gt;f, aname1, &amp;fileFid.Fid);
  	    if (code == 0) {
  		/* delete the source */
! 		code = afs_dir_Delete(&amp;tdc1-&gt;f, aname1);
  	    }
  	    /* first see if target is there */
  	    if (code == 0
! 		&amp;&amp; afs_dir_Lookup(&amp;tdc2-&gt;f, aname2,
  				  &amp;unlinkFid.Fid) == 0) {
  		/* target already exists, and will be unlinked by server */
! 		code = afs_dir_Delete(&amp;tdc2-&gt;f, aname2);
  	    }
  	    if (code == 0) {
! 		code = afs_dir_Create(&amp;tdc2-&gt;f, aname2, &amp;fileFid.Fid);
  	    }
  	    if (code != 0) {
  		ZapDCE(tdc1);
! 		DZap(&amp;tdc1-&gt;f);
  		if (!oneDir) {
  		    ZapDCE(tdc2);
! 		    DZap(&amp;tdc2-&gt;f);
  		}
  	    }
  	}
***************
*** 339,345 ****
  	    if (tdc1) {
  		ObtainWriteLock(&amp;tdc1-&gt;lock, 648);
  		ZapDCE(tdc1);	/* mark as unknown */
! 		DZap(&amp;tdc1-&gt;f.inode);
  		ReleaseWriteLock(&amp;tdc1-&gt;lock);
  		afs_PutDCache(tdc1);	/* put it back */
  	    }
--- 339,345 ----
  	    if (tdc1) {
  		ObtainWriteLock(&amp;tdc1-&gt;lock, 648);
  		ZapDCE(tdc1);	/* mark as unknown */
! 		DZap(&amp;tdc1-&gt;f);
  		ReleaseWriteLock(&amp;tdc1-&gt;lock);
  		afs_PutDCache(tdc1);	/* put it back */
  	    }
Index: openafs/src/afs/VNOPS/afs_vnop_symlink.c
diff -c openafs/src/afs/VNOPS/afs_vnop_symlink.c:1.19.2.1 openafs/src/afs/VNOPS/afs_vnop_symlink.c:1.19.2.2
*** openafs/src/afs/VNOPS/afs_vnop_symlink.c:1.19.2.1	Wed Aug 25 03:09:35 2004
--- openafs/src/afs/VNOPS/afs_vnop_symlink.c	Mon Oct 18 13:43:53 2004
***************
*** 22,28 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_symlink.c,v 1.19.2.1 2004/08/25 07:09:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 22,28 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_symlink.c,v 1.19.2.2 2004/10/18 17:43:53 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 184,193 ****
      /* otherwise, we should see if we can make the change to the dir locally */
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Create(&amp;tdc-&gt;f.inode, aname, &amp;newFid.Fid);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- use invalid value */
! 	    DZap(&amp;tdc-&gt;f.inode);
  	}
      }
      if (tdc) {
--- 184,193 ----
      /* otherwise, we should see if we can make the change to the dir locally */
      if (afs_LocalHero(adp, tdc, &amp;OutDirStatus, 1)) {
  	/* we can do it locally */
! 	code = afs_dir_Create(&amp;tdc-&gt;f, aname, &amp;newFid.Fid);
  	if (code) {
  	    ZapDCE(tdc);	/* surprise error -- use invalid value */
! 	    DZap(&amp;tdc-&gt;f);
  	}
      }
      if (tdc) {
Index: openafs/src/auth/Makefile.in
diff -c openafs/src/auth/Makefile.in:1.12 openafs/src/auth/Makefile.in:1.12.2.1
*** openafs/src/auth/Makefile.in:1.12	Sat Jan 11 02:33:55 2003
--- openafs/src/auth/Makefile.in	Mon Oct 18 03:11:49 2004
***************
*** 36,42 ****
  setkey.o: setkey.c ${INCLS} AFS_component_version_number.o
  
  ktc.krb.o: ktc.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
! 	${CC} ${CFLAGS} -DAFS_KERBEROS_ENV -c ${srcdir}/ktc.c -o ktc.krb.o
  
  libauth.a: $(OBJS) AFS_component_version_number.o
  	-$(RM) -f libauth.a
--- 36,42 ----
  setkey.o: setkey.c ${INCLS} AFS_component_version_number.o
  
  ktc.krb.o: ktc.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
! 	${CCOBJ} ${CFLAGS} -DAFS_KERBEROS_ENV -c ${srcdir}/ktc.c -o ktc.krb.o
  
  libauth.a: $(OBJS) AFS_component_version_number.o
  	-$(RM) -f libauth.a
Index: openafs/src/bozo/bos.c
diff -c openafs/src/bozo/bos.c:1.20.2.1 openafs/src/bozo/bos.c:1.20.2.2
*** openafs/src/bozo/bos.c:1.20.2.1	Wed Aug 25 03:03:36 2004
--- openafs/src/bozo/bos.c	Mon Oct 18 13:43:53 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/bozo/bos.c,v 1.20.2.1 2004/08/25 07:03:36 shadow Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;stdlib.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/bozo/bos.c,v 1.20.2.2 2004/10/18 17:43:53 shadow Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;stdlib.h&gt;
***************
*** 239,245 ****
  	    code = ktc_GetToken(&amp;sname, &amp;ttoken, sizeof(ttoken), NULL);
  	    if (code == 0) {
  		/* have tickets, will travel */
! 		if (ttoken.kvno &gt;= 0 &amp;&amp; ttoken.kvno &lt;= 255);
  		else {
  		    fprintf(stderr,
  			    "bos: funny kvno (%d) in ticket, proceeding\n",
--- 239,245 ----
  	    code = ktc_GetToken(&amp;sname, &amp;ttoken, sizeof(ttoken), NULL);
  	    if (code == 0) {
  		/* have tickets, will travel */
! 		if (ttoken.kvno &gt;= 0 &amp;&amp; ttoken.kvno &lt;= 256);
  		else {
  		    fprintf(stderr,
  			    "bos: funny kvno (%d) in ticket, proceeding\n",
Index: openafs/src/bucoord/commands.c
diff -c openafs/src/bucoord/commands.c:1.14 openafs/src/bucoord/commands.c:1.14.2.1
*** openafs/src/bucoord/commands.c:1.14	Sun Dec  7 20:45:28 2003
--- openafs/src/bucoord/commands.c	Mon Oct 18 03:11:50 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/bucoord/commands.c,v 1.14 2003/12/08 01:45:28 jaltman Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;sys/types.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/bucoord/commands.c,v 1.14.2.1 2004/10/18 07:11:50 shadow Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;sys/types.h&gt;
***************
*** 626,632 ****
      if (*date_long == NEVERDATE) {
  	sprintf(string, "NEVER");
      } else {
! 	ltime = localtime(date_long);
  	/* prints date in U.S. format of mm/dd/yyyy */
  	strftime(string, size, "%m/%d/%Y %H:%M", ltime);
      }
--- 626,633 ----
      if (*date_long == NEVERDATE) {
  	sprintf(string, "NEVER");
      } else {
!         time_t t = *date_long;
! 	ltime = localtime(&amp;t);
  	/* prints date in U.S. format of mm/dd/yyyy */
  	strftime(string, size, "%m/%d/%Y %H:%M", ltime);
      }
***************
*** 2902,2914 ****
  	printf("----\n");
  	printDumpEntry(&amp;dumpEntry);
      } else {
  	if (dbDump)
  	    printf("Dump: id %u, created: %s\n", dumpEntry.id,
! 		   ctime(&amp;dumpEntry.created));
! 	else
  	    printf("Dump: id %u, level %d, volumes %d, created: %s\n",
  		   dumpEntry.id, dumpEntry.level, dumpEntry.nVolumes,
! 		   ctime(&amp;dumpEntry.created));
      }
  
      if (!detailFlag &amp;&amp; (strlen(dumpEntry.tapes.tapeServer) &gt; 0)
--- 2903,2916 ----
  	printf("----\n");
  	printDumpEntry(&amp;dumpEntry);
      } else {
+         time_t t = dumpEntry.created;
  	if (dbDump)
  	    printf("Dump: id %u, created: %s\n", dumpEntry.id,
! 		   ctime(&amp;t));
!  	else
  	    printf("Dump: id %u, level %d, volumes %d, created: %s\n",
  		   dumpEntry.id, dumpEntry.level, dumpEntry.nVolumes,
! 		   ctime(&amp;t));
      }
  
      if (!detailFlag &amp;&amp; (strlen(dumpEntry.tapes.tapeServer) &gt; 0)
Index: openafs/src/bucoord/dump_sched.c
diff -c openafs/src/bucoord/dump_sched.c:1.7 openafs/src/bucoord/dump_sched.c:1.7.2.1
*** openafs/src/bucoord/dump_sched.c:1.7	Sat Nov 22 23:53:30 2003
--- openafs/src/bucoord/dump_sched.c	Mon Oct 18 03:11:50 2004
***************
*** 17,23 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/bucoord/dump_sched.c,v 1.7 2003/11/23 04:53:30 jaltman Exp $");
  
  #ifdef AFS_NT40_ENV
  #include &lt;winsock2.h&gt;
--- 17,23 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/bucoord/dump_sched.c,v 1.7.2.1 2004/10/18 07:11:50 shadow Exp $");
  
  #ifdef AFS_NT40_ENV
  #include &lt;winsock2.h&gt;
***************
*** 581,587 ****
      case BC_ABS_EXPDATE:
  	/* absolute expiration date. Never expires if date is 0 */
  	if (adump-&gt;expDate) {
! 	    printf("expires at %.24s", cTIME(&amp;adump-&gt;expDate));
  	}
  	break;
  
--- 581,588 ----
      case BC_ABS_EXPDATE:
  	/* absolute expiration date. Never expires if date is 0 */
  	if (adump-&gt;expDate) {
!             time_t t = adump-&gt;expDate;
! 	    printf("expires at %.24s", cTIME(&amp;t));
  	}
  	break;
  
Index: openafs/src/bucoord/restore.c
diff -c openafs/src/bucoord/restore.c:1.8 openafs/src/bucoord/restore.c:1.8.2.1
*** openafs/src/bucoord/restore.c:1.8	Sun Dec  7 17:49:19 2003
--- openafs/src/bucoord/restore.c	Mon Oct 18 03:11:50 2004
***************
*** 15,21 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/bucoord/restore.c,v 1.8 2003/12/07 22:49:19 jaltman Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;sys/types.h&gt;
--- 15,21 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/bucoord/restore.c,v 1.8.2.1 2004/10/18 07:11:50 shadow Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;sys/types.h&gt;
***************
*** 195,201 ****
      afs_int32 partitionAll;	/* Likewise for partition */
      struct hostent *hostPtr;
      long haddr;
!     u_long did;
      int foundtape, c;
  
      extern statusP createStatusNode();
--- 195,201 ----
      afs_int32 partitionAll;	/* Likewise for partition */
      struct hostent *hostPtr;
      long haddr;
!     time_t did;
      int foundtape, c;
  
      extern statusP createStatusNode();
Index: openafs/src/butc/lwps.c
diff -c openafs/src/butc/lwps.c:1.12 openafs/src/butc/lwps.c:1.12.2.1
*** openafs/src/butc/lwps.c:1.12	Sun Dec  7 20:45:29 2003
--- openafs/src/butc/lwps.c	Mon Oct 18 03:11:51 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/butc/lwps.c,v 1.12 2003/12/08 01:45:29 jaltman Exp $");
  
  #include &lt;sys/types.h&gt;
  #ifdef AFS_NT40_ENV
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/butc/lwps.c,v 1.12.2.1 2004/10/18 07:11:51 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #ifdef AFS_NT40_ENV
***************
*** 2287,2292 ****
--- 2287,2293 ----
       struct butm_tapeLabel *labelptr;
  {
      char tapeName[BU_MAXTAPELEN + 32];
+     time_t t;
  
      printf("Tape label\n");
      printf("----------\n");
***************
*** 2294,2302 ****
      printf("permanent tape name = %s\n", tapeName);
      TAPENAME(tapeName, labelptr-&gt;AFSName, labelptr-&gt;dumpid);
      printf("AFS tape name = %s\n", tapeName);
!     printf("creationTime = %s", ctime(&amp;labelptr-&gt;creationTime));
!     if (labelptr-&gt;expirationDate)
! 	printf("expirationDate = %s", cTIME(&amp;labelptr-&gt;expirationDate));
      printf("cell = %s\n", labelptr-&gt;cell);
      printf("size = %u Kbytes\n", labelptr-&gt;size);
      printf("dump path = %s\n", labelptr-&gt;dumpPath);
--- 2295,2306 ----
      printf("permanent tape name = %s\n", tapeName);
      TAPENAME(tapeName, labelptr-&gt;AFSName, labelptr-&gt;dumpid);
      printf("AFS tape name = %s\n", tapeName);
!     t = labelptr-&gt;creationTime;
!     printf("creationTime = %s", ctime(&amp;t));
!     if (labelptr-&gt;expirationDate) {
!         t = labelptr-&gt;expirationDate;
! 	printf("expirationDate = %s", cTIME(&amp;t));
!     }
      printf("cell = %s\n", labelptr-&gt;cell);
      printf("size = %u Kbytes\n", labelptr-&gt;size);
      printf("dump path = %s\n", labelptr-&gt;dumpPath);
Index: openafs/src/butc/recoverDb.c
diff -c openafs/src/butc/recoverDb.c:1.10 openafs/src/butc/recoverDb.c:1.10.2.1
*** openafs/src/butc/recoverDb.c:1.10	Sun Dec  7 17:49:23 2003
--- openafs/src/butc/recoverDb.c	Mon Oct 18 03:11:51 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/butc/recoverDb.c,v 1.10 2003/12/07 22:49:23 jaltman Exp $");
  
  #include &lt;stdio.h&gt;
  #ifdef AFS_NT40_ENV
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/butc/recoverDb.c,v 1.10.2.1 2004/10/18 07:11:51 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #ifdef AFS_NT40_ENV
***************
*** 59,64 ****
--- 59,65 ----
       struct butm_tapeLabel *labelptr;
  {
      char tapeName[BU_MAXTAPELEN + 32];
+     time_t t;
  
      printf("Dump label\n");
      printf("----------\n");
***************
*** 66,74 ****
      printf("permanent tape name = %s\n", tapeName);
      TAPENAME(tapeName, labelptr-&gt;AFSName, labelptr-&gt;dumpid);
      printf("AFS tape name = %s\n", tapeName);
!     printf("creationTime = %s", ctime(&amp;labelptr-&gt;creationTime));
!     if (labelptr-&gt;expirationDate)
! 	printf("expirationDate = %s", cTIME(&amp;labelptr-&gt;expirationDate));
      printf("cell = %s\n", labelptr-&gt;cell);
      printf("size = %u Kbytes\n", labelptr-&gt;size);
      printf("dump path = %s\n", labelptr-&gt;dumpPath);
--- 67,78 ----
      printf("permanent tape name = %s\n", tapeName);
      TAPENAME(tapeName, labelptr-&gt;AFSName, labelptr-&gt;dumpid);
      printf("AFS tape name = %s\n", tapeName);
!     t = labelptr-&gt;creationTime;
!     printf("creationTime = %s", ctime(&amp;t));
!     if (labelptr-&gt;expirationDate) {
!         t = labelptr-&gt;expirationDate;
! 	printf("expirationDate = %s", cTIME(&amp;t));
!     }
      printf("cell = %s\n", labelptr-&gt;cell);
      printf("size = %u Kbytes\n", labelptr-&gt;size);
      printf("dump path = %s\n", labelptr-&gt;dumpPath);
***************
*** 87,92 ****
--- 91,98 ----
  PrintVolumeHeader(volHeader)
       struct volumeHeader *volHeader;
  {
+     time_t t;
+ 
      printf("-- volume --\n");
      printf("volume name: %s\n", volHeader-&gt;volumeName);
      printf("volume ID %d\n", volHeader-&gt;volumeID);
***************
*** 97,103 ****
      printf("parentID %d\n", volHeader-&gt;parentID);
      printf("endTime %d\n", volHeader-&gt;endTime);
      /* printf("versionflags %d\n", volHeader-&gt;versionflags); */
!     printf("clonedate %s\n", ctime(&amp;volHeader-&gt;cloneDate));
  }
  
  /* Ask
--- 103,110 ----
      printf("parentID %d\n", volHeader-&gt;parentID);
      printf("endTime %d\n", volHeader-&gt;endTime);
      /* printf("versionflags %d\n", volHeader-&gt;versionflags); */
!     t = volHeader-&gt;cloneDate;
!     printf("clonedate %s\n", ctime(&amp;t));
  }
  
  /* Ask
Index: openafs/src/butc/tcmain.c
diff -c openafs/src/butc/tcmain.c:1.14.2.1 openafs/src/butc/tcmain.c:1.14.2.2
*** openafs/src/butc/tcmain.c:1.14.2.1	Wed Aug 25 03:12:37 2004
--- openafs/src/butc/tcmain.c	Mon Oct 18 13:43:54 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/butc/tcmain.c,v 1.14.2.1 2004/08/25 07:12:37 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;sys/stat.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/butc/tcmain.c,v 1.14.2.2 2004/10/18 17:43:54 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;sys/stat.h&gt;
***************
*** 856,861 ****
--- 856,862 ----
  #else
      PROCESS dbWatcherPid;
  #endif
+     time_t t;
  
      debugLevel = 0;
  
***************
*** 1131,1137 ****
  
      TLog(0, "Starting Tape Coordinator: Port offset %u   Debug level %u\n",
  	 portOffset, debugLevel);
!     TLog(0, "Token expires: %s\n", cTIME(&amp;ttoken.endTime));
  
      rx_StartServer(1);		/* Donate this process to the server process pool */
      TLog(0, "Error: StartServer returned");
--- 1132,1139 ----
  
      TLog(0, "Starting Tape Coordinator: Port offset %u   Debug level %u\n",
  	 portOffset, debugLevel);
!     t = ttoken.endTime;
!     TLog(0, "Token expires: %s\n", cTIME(&amp;t));
  
      rx_StartServer(1);		/* Donate this process to the server process pool */
      TLog(0, "Error: StartServer returned");
Index: openafs/src/butm/test_ftm.c
diff -c openafs/src/butm/test_ftm.c:1.10 openafs/src/butm/test_ftm.c:1.10.2.1
*** openafs/src/butm/test_ftm.c:1.10	Sat Nov 29 16:37:57 2003
--- openafs/src/butm/test_ftm.c	Mon Oct 18 03:11:52 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/butm/test_ftm.c,v 1.10 2003/11/29 21:37:57 jaltman Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;fcntl.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/butm/test_ftm.c,v 1.10.2.1 2004/10/18 07:11:52 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;fcntl.h&gt;
***************
*** 324,331 ****
      }
      past = time(0) - label.creationTime;
      if ((past &lt; 0) || (past &gt; 5 * 60)) {
! 	printf("label creation time is long ago: %s\n",
! 	       ctime(&amp;label.creationTime));
  	ERROR_EXIT(5);
      }
      if (strcmp(label.AFSName, tip-&gt;tapeName) != 0) {
--- 324,331 ----
      }
      past = time(0) - label.creationTime;
      if ((past &lt; 0) || (past &gt; 5 * 60)) {
!         time_t t = label.creationTime;
! 	printf("label creation time is long ago: %s\n", ctime(&amp;t));
  	ERROR_EXIT(5);
      }
      if (strcmp(label.AFSName, tip-&gt;tapeName) != 0) {
Index: openafs/src/cf/linux-test3.m4
diff -c openafs/src/cf/linux-test3.m4:1.8 openafs/src/cf/linux-test3.m4:1.8.2.2
*** openafs/src/cf/linux-test3.m4:1.8	Mon Jun 21 16:06:21 2004
--- openafs/src/cf/linux-test3.m4	Sat Oct  9 01:05:06 2004
***************
*** 94,96 ****
--- 94,113 ----
    ac_cv_linux_kernel_is_selinux=no)])
  AC_MSG_RESULT($ac_cv_linux_kernel_is_selinux)
  CPPFLAGS="$save_CPPFLAGS"])
+ 
+ AC_DEFUN([LINUX_KERNEL_SOCK_CREATE],[
+ AC_MSG_CHECKING(for 5th argument in sock_create found in some SELinux kernels)
+ save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-I${LINUX_KERNEL_PATH}/include -D__KERNEL__ $CPPFLAGS"
+ AC_CACHE_VAL(ac_cv_linux_kernel_sock_create_v,
+ [
+ AC_TRY_COMPILE(
+   [#include &lt;linux/net.h&gt;],
+   [
+   sock_create(0,0,0,0,0)
+   ],
+   ac_cv_linux_kernel_sock_create_v=yes,
+   ac_cv_linux_kernel_sock_create_v=no)])
+ AC_MSG_RESULT($ac_cv_linux_kernel_sock_create_v)
+ CPPFLAGS="$save_CPPFLAGS"])
+ 
Index: openafs/src/cf/osconf.m4
diff -c openafs/src/cf/osconf.m4:1.51.2.3 openafs/src/cf/osconf.m4:1.51.2.4
*** openafs/src/cf/osconf.m4:1.51.2.3	Wed Aug 25 03:15:37 2004
--- openafs/src/cf/osconf.m4	Mon Oct 18 13:43:54 2004
***************
*** 229,240 ****
  		SHLIB_LINKER="${MT_CC} -shared"
  		;;
  
! 	amd64_linux24)
  		KERN_OPTMZ=-O2
  		LEX="flex -l"
  		MT_CFLAGS='-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}'
  		MT_LIBS="-lpthread"
  		PAM_CFLAGS="-g -O2 -Dlinux -DLINUX_PAM -fPIC"
  		SHLIB_LDFLAGS="-shared -Xlinker -x"
  		TXLIBS="-lncurses"
  		XCFLAGS="-g -O2 -D_LARGEFILE64_SOURCE"
--- 229,242 ----
  		SHLIB_LINKER="${MT_CC} -shared"
  		;;
  
! 	amd64_linux*)
! 		CCOBJ="${CC} -fPIC"
  		KERN_OPTMZ=-O2
  		LEX="flex -l"
  		MT_CFLAGS='-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}'
  		MT_LIBS="-lpthread"
  		PAM_CFLAGS="-g -O2 -Dlinux -DLINUX_PAM -fPIC"
+ 		SHLIB_CFLAGS="-fPIC"
  		SHLIB_LDFLAGS="-shared -Xlinker -x"
  		TXLIBS="-lncurses"
  		XCFLAGS="-g -O2 -D_LARGEFILE64_SOURCE"
Index: openafs/src/config/NTMakefile.i386_nt40
diff -c openafs/src/config/NTMakefile.i386_nt40:1.46.2.5 openafs/src/config/NTMakefile.i386_nt40:1.46.2.7
*** openafs/src/config/NTMakefile.i386_nt40:1.46.2.5	Tue Aug 24 03:10:19 2004
--- openafs/src/config/NTMakefile.i386_nt40	Mon Oct 18 00:21:25 2004
***************
*** 80,86 ****
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=3
! AFSPRODUCT_VER_PATCH=7100
  AFSPRODUCT_VER_BUILD=0
  
  # For MSI installer, each major release should have a different GUID
--- 80,86 ----
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=3
! AFSPRODUCT_VER_PATCH=7200
  AFSPRODUCT_VER_BUILD=0
  
  # For MSI installer, each major release should have a different GUID
Index: openafs/src/config/afs_sysnames.h
diff -c openafs/src/config/afs_sysnames.h:1.50.2.1 openafs/src/config/afs_sysnames.h:1.50.2.2
*** openafs/src/config/afs_sysnames.h:1.50.2.1	Wed Aug 25 03:03:38 2004
--- openafs/src/config/afs_sysnames.h	Mon Oct 18 13:43:55 2004
***************
*** 206,211 ****
--- 206,212 ----
  #define SYS_NAME_ID_amd64_linux2        2700
  #define SYS_NAME_ID_amd64_linux22       2701
  #define SYS_NAME_ID_amd64_linux24       2702
+ #define SYS_NAME_ID_amd64_linux26       2703
  
  #define SYS_NAME_ID_i386_umlinux2	2800
  #define SYS_NAME_ID_i386_umlinux22	2801
***************
*** 214,219 ****
--- 215,221 ----
  #define SYS_NAME_ID_ppc64_linux2	2900
  #define SYS_NAME_ID_ppc64_linux22	2901
  #define SYS_NAME_ID_ppc64_linux24	2902
+ #define SYS_NAME_ID_ppc64_linux26	2903
  
  /*
   * Placeholder to keep system-wide standard flags since this file is included by all 
Index: openafs/src/config/param.amd64_linux26.h
diff -c /dev/null openafs/src/config/param.amd64_linux26.h:1.1.2.1
*** /dev/null	Mon Oct 18 13:53:42 2004
--- openafs/src/config/param.amd64_linux26.h	Mon Oct 18 03:11:54 2004
***************
*** 0 ****
--- 1,147 ----
+ #ifndef UKERNEL
+ /* This section for kernel libafs compiles only */
+ 
+ #ifndef AFS_PARAM_H
+ #define AFS_PARAM_H
+ 
+ /* In user space the AFS_LINUX20_ENV should be sufficient. In the kernel,
+  * it's a judgment call. If something is obviously amd64 specific, use that
+  * #define instead. Note that "20" refers to the linux 2.0 kernel. The "2"
+  * in the sysname is the current version of the client. This takes into
+  * account the perferred OS user space configuration as well as the kernel.
+  */
+ 
+ #define AFS_LINUX20_ENV        1
+ #define AFS_LINUX22_ENV        1
+ #define AFS_LINUX24_ENV        1
+ #define AFS_LINUX26_ENV        1
+ #define AFS_AMD64_LINUX20_ENV   1
+ #define AFS_AMD64_LINUX22_ENV   1
+ #define AFS_AMD64_LINUX24_ENV   1
+ #define AFS_AMD64_LINUX26_ENV   1
+ #define AFS_NONFSTRANS 1
+ 
+ #define AFS_MOUNT_AFS "afs"	/* The name of the filesystem type. */
+ #define AFS_SYSCALL 183
+ #define AFS_64BIT_IOPS_ENV  1
+ #define AFS_NAMEI_ENV     1	/* User space interface to file system */
+ #define AFS_64BIT_ENV		1
+ #define AFS_64BIT_CLIENT	1
+ #define AFS_64BITPOINTER_ENV	1	/* pointers are 64 bits */
+ 
+ #if defined(__KERNEL__) &amp;&amp; !defined(KDUMP_KERNEL)
+ #include &lt;linux/threads.h&gt;
+ 
+ #include &lt;linux/config.h&gt;
+ #ifdef CONFIG_SMP
+ #ifndef AFS_SMP
+ #define AFS_SMP 1
+ #endif
+ #endif
+ /* Using "AFS_SMP" to map to however many #define's are required to get
+  * MP to compile for Linux
+  */
+ #ifdef AFS_SMP
+ #ifndef CONFIG_SMP
+ #define CONFIG_SMP 1
+ #endif
+ #ifndef __SMP__
+ #define __SMP__
+ #endif
+ #define AFS_GLOBAL_SUNLOCK
+ #endif
+ 
+ #endif /* __KERNEL__  &amp;&amp; !DUMP_KERNEL */
+ 
+ #include &lt;afs/afs_sysnames.h&gt;
+ #define AFS_USERSPACE_IP_ADDR 1
+ #define RXK_LISTENER_ENV 1
+ #define AFS_GCPAGS       2	/* Set to Userdisabled, allow sysctl to override */
+ 
+ #define AFSLITTLE_ENDIAN    1
+ #define AFS_HAVE_FFS        1	/* Use system's ffs. */
+ #define AFS_HAVE_STATVFS    0	/* System doesn't support statvfs */
+ #define AFS_VM_RDWR_ENV            1	/* read/write implemented via VM */
+ 
+ #ifdef KERNEL
+ #ifndef MIN
+ #define MIN(A,B) ((A) &lt; (B) ? (A) : (B))
+ #endif
+ #ifndef MAX
+ #define MAX(A,B) ((A) &gt; (B) ? (A) : (B))
+ #endif
+ #endif /* KERNEL */
+ 
+ /* Machine / Operating system information */
+ #define SYS_NAME       "amd64_linux26"
+ #define SYS_NAME_ID    SYS_NAME_ID_amd64_linux26
+ 
+ #define USE_UCONTEXT
+ 
+ #endif /* AFS_PARAM_H */
+ 
+ 
+ 
+ #else /* !defined(UKERNEL) */
+ 
+ /* This section for user space compiles only */
+ 
+ #ifndef AFS_PARAM_H
+ #define AFS_PARAM_H
+ 
+ /* In user space the AFS_LINUX20_ENV should be sufficient. In the kernel,
+  * it's a judgment call. If something is obviously amd64 specific, use that
+  * #define instead. Note that "20" refers to the linux 2.0 kernel. The "2"
+  * in the sysname is the current version of the client. This takes into
+  * account the perferred OS user space configuration as well as the kernel.
+  */
+ 
+ #define UKERNEL                        1	/* user space kernel */
+ #define AFS_ENV                        1
+ #define AFS_USR_LINUX20_ENV    1
+ #define AFS_USR_LINUX22_ENV    1
+ #define AFS_USR_LINUX24_ENV    1
+ #define AFS_USR_LINUX26_ENV    1
+ #define AFS_NONFSTRANS 1
+ 
+ #define AFS_MOUNT_AFS "afs"	/* The name of the filesystem type. */
+ #define AFS_SYSCALL 183
+ #define AFS_64BIT_IOPS_ENV  1
+ #define AFS_NAMEI_ENV     1	/* User space interface to file system */
+ #include &lt;afs/afs_sysnames.h&gt;
+ 
+ #define AFS_USERSPACE_IP_ADDR 1
+ #define RXK_LISTENER_ENV 1
+ #define AFS_GCPAGS             0	/* if nonzero, garbage collect PAGs */
+ 
+ 
+ /* Machine / Operating system information */
+ #define SYS_NAME       "amd64_linux26"
+ #define SYS_NAME_ID    SYS_NAME_ID_amd64_linux26
+ #define AFSLITTLE_ENDIAN    1
+ #define AFS_HAVE_FFS        1	/* Use system's ffs. */
+ #define AFS_HAVE_STATVFS    0	/* System doesn't support statvfs */
+ #define AFS_VM_RDWR_ENV            1	/* read/write implemented via VM */
+ 
+ #define        afsio_iov       uio_iov
+ #define        afsio_iovcnt    uio_iovcnt
+ #define        afsio_offset    uio_offset
+ #define        afsio_seg       uio_segflg
+ #define        afsio_fmode     uio_fmode
+ #define        afsio_resid     uio_resid
+ #define        AFS_UIOSYS      1
+ #define        AFS_UIOUSER     UIO_USERSPACE
+ #define        AFS_CLBYTES     MCLBYTES
+ #define        AFS_MINCHANGE   2
+ #define        VATTR_NULL      usr_vattr_null
+ 
+ #define AFS_DIRENT
+ #ifndef CMSERVERPREF
+ #define CMSERVERPREF
+ #endif
+ 
+ #define USE_UCONTEXT
+ 
+ #endif /* AFS_PARAM_H */
+ 
+ #endif /* !defined(UKERNEL) */
Index: openafs/src/des/Makefile.in
diff -c openafs/src/des/Makefile.in:1.11.2.1 openafs/src/des/Makefile.in:1.11.2.2
*** openafs/src/des/Makefile.in:1.11.2.1	Wed Aug 25 03:15:37 2004
--- openafs/src/des/Makefile.in	Mon Oct 18 13:43:56 2004
***************
*** 88,96 ****
  crypt.o: crypt.c
  	case ${SYS_NAME} in \
  	rs_aix*)\
! 		${CC} -c ${COMMON_INCL} -o crypt.o crypt.c ;;\
  	*)\
! 		${CC} -c ${CFLAGS} -o crypt.o crypt.c ;;\
  	esac
  #
  # Table/code generation targets
--- 88,96 ----
  crypt.o: crypt.c
  	case ${SYS_NAME} in \
  	rs_aix*)\
! 		${CCOBJ} -c ${COMMON_INCL} -o crypt.o crypt.c ;;\
  	*)\
! 		${CCOBJ} -c ${CFLAGS} -o crypt.o crypt.c ;;\
  	esac
  #
  # Table/code generation targets
Index: openafs/src/des/cbc_encrypt.c
diff -c openafs/src/des/cbc_encrypt.c:1.9 openafs/src/des/cbc_encrypt.c:1.9.2.1
*** openafs/src/des/cbc_encrypt.c:1.9	Tue Jul 15 19:14:59 2003
--- openafs/src/des/cbc_encrypt.c	Mon Oct 18 03:11:56 2004
***************
*** 29,35 ****
  #include "des_prototypes.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/des/cbc_encrypt.c,v 1.9 2003/07/15 23:14:59 shadow Exp $");
  
  
  #define XPRT_CBC_ENCRYPT
--- 29,35 ----
  #include "des_prototypes.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/des/cbc_encrypt.c,v 1.9.2.1 2004/10/18 07:11:56 shadow Exp $");
  
  
  #define XPRT_CBC_ENCRYPT
***************
*** 61,67 ****
      des_cblock *iv;		* 8 bytes of ivec *
  */
  afs_int32
! des_cbc_encrypt(des_cblock * in, des_cblock * out, register afs_int32 length,
  		des_key_schedule key, des_cblock * iv, int encrypt)
  {
      register afs_uint32 *input = (afs_uint32 *) in;
--- 61,67 ----
      des_cblock *iv;		* 8 bytes of ivec *
  */
  afs_int32
! des_cbc_encrypt(void * in, void * out, register afs_int32 length,
  		des_key_schedule key, des_cblock * iv, int encrypt)
  {
      register afs_uint32 *input = (afs_uint32 *) in;
Index: openafs/src/des/des.c
diff -c openafs/src/des/des.c:1.11.2.1 openafs/src/des/des.c:1.11.2.2
*** openafs/src/des/des.c:1.11.2.1	Wed Aug 25 03:09:37 2004
--- openafs/src/des/des.c	Mon Oct 18 13:43:56 2004
***************
*** 37,43 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/des/des.c,v 1.11.2.1 2004/08/25 07:09:37 shadow Exp $");
  
  #ifndef KERNEL
  #include &lt;stdio.h&gt;
--- 37,43 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/des/des.c,v 1.11.2.2 2004/10/18 17:43:56 shadow Exp $");
  
  #ifndef KERNEL
  #include &lt;stdio.h&gt;
***************
*** 72,83 ****
  /* encrypt == 0  ==&gt; decrypt, else encrypt */
  
  afs_int32
! des_ecb_encrypt(afs_uint32 * clear, afs_uint32 * cipher,
  		register des_key_schedule schedule, int encrypt)
  {
      /* better pass 8 bytes, length not checked here */
  
!     register afs_uint32 R1 = 0, L1 = 0;	/* R1 = r10, L1 = r9 */
      register afs_uint32 R2 = 0, L2 = 0;	/* R2 = r8, L2 = r7 */
      afs_int32 i;
      /* one more registers left on VAX, see below P_temp_p */
--- 72,84 ----
  /* encrypt == 0  ==&gt; decrypt, else encrypt */
  
  afs_int32
! des_ecb_encrypt(void * clear, void * cipher,
  		register des_key_schedule schedule, int encrypt)
  {
      /* better pass 8 bytes, length not checked here */
  
!     register afs_uint32 R1 = 0;
!     register afs_uint32 L1 = 0;	/* R1 = r10, L1 = r9 */
      register afs_uint32 R2 = 0, L2 = 0;	/* R2 = r8, L2 = r7 */
      afs_int32 i;
      /* one more registers left on VAX, see below P_temp_p */
***************
*** 128,147 ****
  	abort();
      }
  #endif
!     if ((afs_int32) clear &amp; 3) {
! 	memcpy((char *)&amp;L_save, (char *)clear++, sizeof(L_save));
! 	memcpy((char *)&amp;R_save, (char *)clear, sizeof(R_save));
  	L1 = L_save;
  	R1 = R_save;
      } else
  #endif
      {
! 	if (clear)
! 	    L1 = *clear++;
! 	else
  	    L1 = 0;
  	if (clear)
! 	    R1 = *clear;
  	else
  	    R1 = 0;
      }
--- 129,150 ----
  	abort();
      }
  #endif
!     if ((afs_uint32) clear &amp; 3) {
! 	memcpy((char *)(&amp;L_save), (char *)clear, sizeof(L_save));
! 	clear=((afs_uint32*)clear)+1;
! 	memcpy((char *)(&amp;R_save), (char *)clear, sizeof(R_save));
  	L1 = L_save;
  	R1 = R_save;
      } else
  #endif
      {
! 	if (clear) {
! 	    L1 = *((afs_uint32 *)clear);
!             clear=((afs_uint32*)clear)+1;
! 	} else
  	    L1 = 0;
  	if (clear)
! 	    R1 = *((afs_uint32 *)clear);
  	else
  	    R1 = 0;
      }
***************
*** 441,453 ****
      if ((afs_int32) cipher &amp; 3) {
  	L_save = L2;		/* cant bcopy a reg */
  	R_save = R2;
! 	memcpy((char *)cipher++, (char *)&amp;L_save, sizeof(L_save));
  	memcpy((char *)cipher, (char *)&amp;R_save, sizeof(R_save));
      } else
  #endif
      {
! 	*cipher++ = L2;
! 	*cipher = R2;
      }
  
  #ifdef DEBUG
--- 444,458 ----
      if ((afs_int32) cipher &amp; 3) {
  	L_save = L2;		/* cant bcopy a reg */
  	R_save = R2;
! 	memcpy((char *)cipher, (char *)&amp;L_save, sizeof(L_save));
! 	cipher=((afs_uint32*)cipher)+1;
  	memcpy((char *)cipher, (char *)&amp;R_save, sizeof(R_save));
      } else
  #endif
      {
!         *((afs_uint32*)cipher)= L2;	
! 	cipher = ((afs_int32 *)cipher)+1;
! 	*((afs_uint32 *)cipher) = R2;
      }
  
  #ifdef DEBUG
Index: openafs/src/des/des_prototypes.h
diff -c openafs/src/des/des_prototypes.h:1.3 openafs/src/des/des_prototypes.h:1.3.2.1
*** openafs/src/des/des_prototypes.h:1.3	Tue Jul 15 19:15:00 2003
--- openafs/src/des/des_prototypes.h	Mon Oct 18 03:11:56 2004
***************
*** 18,36 ****
  extern int des_debug;
  
  /* cbc_encrypt.c */
! extern afs_int32 des_cbc_encrypt(des_cblock * in, des_cblock * out,
  				 register afs_int32 length,
  				 des_key_schedule key, des_cblock * iv,
  				 int encrypt);
  
  /* pcbc_encrypt.c */
! extern afs_int32 des_pcbc_encrypt(des_cblock * in, des_cblock * out,
  				  register afs_int32 length,
  				  des_key_schedule key, des_cblock * iv,
  				  int encrypt);
  
  /* des.c */
! extern afs_int32 des_ecb_encrypt(afs_uint32 * clear, afs_uint32 * cipher,
  				 register des_key_schedule schedule,
  				 int encrypt);
  
--- 18,36 ----
  extern int des_debug;
  
  /* cbc_encrypt.c */
! extern afs_int32 des_cbc_encrypt(void * in, void * out,
  				 register afs_int32 length,
  				 des_key_schedule key, des_cblock * iv,
  				 int encrypt);
  
  /* pcbc_encrypt.c */
! extern afs_int32 des_pcbc_encrypt(void * in, void * out,
  				  register afs_int32 length,
  				  des_key_schedule key, des_cblock * iv,
  				  int encrypt);
  
  /* des.c */
! extern afs_int32 des_ecb_encrypt(void * clear, void * cipher,
  				 register des_key_schedule schedule,
  				 int encrypt);
  
Index: openafs/src/des/pcbc_encrypt.c
diff -c openafs/src/des/pcbc_encrypt.c:1.9 openafs/src/des/pcbc_encrypt.c:1.9.2.1
*** openafs/src/des/pcbc_encrypt.c:1.9	Tue Jul 15 19:15:00 2003
--- openafs/src/des/pcbc_encrypt.c	Mon Oct 18 03:11:56 2004
***************
*** 30,36 ****
  #include "des_prototypes.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/des/pcbc_encrypt.c,v 1.9 2003/07/15 23:15:00 shadow Exp $");
  
  #include "des_internal.h"
  
--- 30,36 ----
  #include "des_prototypes.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/des/pcbc_encrypt.c,v 1.9.2.1 2004/10/18 07:11:56 shadow Exp $");
  
  #include "des_internal.h"
  
***************
*** 74,80 ****
      des_cblock *iv;             * 8 bytes of ivec *
  */
  afs_int32
! des_pcbc_encrypt(des_cblock * in, des_cblock * out, register afs_int32 length,
  		 des_key_schedule key, des_cblock * iv, int encrypt)
  {
      register afs_uint32 *input = (afs_uint32 *) in;
--- 74,80 ----
      des_cblock *iv;             * 8 bytes of ivec *
  */
  afs_int32
! des_pcbc_encrypt(void * in, void * out, register afs_int32 length,
  		 des_key_schedule key, des_cblock * iv, int encrypt)
  {
      register afs_uint32 *input = (afs_uint32 *) in;
Index: openafs/src/kauth/Makefile.in
diff -c openafs/src/kauth/Makefile.in:1.11 openafs/src/kauth/Makefile.in:1.11.2.1
*** openafs/src/kauth/Makefile.in:1.11	Sat Jan 11 02:34:24 2003
--- openafs/src/kauth/Makefile.in	Mon Oct 18 03:11:57 2004
***************
*** 185,194 ****
  	${CC} ${LDFLAGS} -o kpwvalid kpwvalid.o ${LIBS} ${XLIBS}
  
  user.krb.o: user.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
! 	${CC} ${CFLAGS} -DAFS_KERBEROS_ENV -c ${srcdir}/user.c -o user.krb.o
  
  user.o: user.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
! 	${CC} ${CFLAGS} -c ${srcdir}/user.c
  
  kdb: kdb.o ${INCLS} ${LIBS} libkauth.a
  	${CC} ${LDFLAGS} -o kdb kdb.o libkauth.a ${LIBS} ${XLIBS}
--- 185,194 ----
  	${CC} ${LDFLAGS} -o kpwvalid kpwvalid.o ${LIBS} ${XLIBS}
  
  user.krb.o: user.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
! 	${CCOBJ} ${CFLAGS} -DAFS_KERBEROS_ENV -c ${srcdir}/user.c -o user.krb.o
  
  user.o: user.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
! 	${CCOBJ} ${CFLAGS} -c ${srcdir}/user.c
  
  kdb: kdb.o ${INCLS} ${LIBS} libkauth.a
  	${CC} ${LDFLAGS} -o kdb kdb.o libkauth.a ${LIBS} ${XLIBS}
Index: openafs/src/libafs/MakefileProto.LINUX.in
diff -c openafs/src/libafs/MakefileProto.LINUX.in:1.40.2.1 openafs/src/libafs/MakefileProto.LINUX.in:1.40.2.2
*** openafs/src/libafs/MakefileProto.LINUX.in:1.40.2.1	Wed Aug 25 03:03:39 2004
--- openafs/src/libafs/MakefileProto.LINUX.in	Mon Oct 18 13:43:56 2004
***************
*** 144,172 ****
  	$(RM) -f asm-generic
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-generic asm-generic
  	$(RM) -f asm
! &lt;parisc_linux22 parisc_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-parisc asm
! &lt;alpha_linux_22 alpha_linux_24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-alpha asm
! &lt;i386_linux22 i386_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-i386 asm
! &lt;i386_umlinux22 i386_umlinux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-um asm
! &lt;amd64_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-x86_64 asm
! &lt;s390_linux22 s390_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-s390 asm
! &lt;s390x_linux22 s390x_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-s390x asm
! &lt;ppc_linux22 ppc_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-ppc asm 
! &lt;ppc64_linux24&gt;
  	ln -s ${LINUX_KERNEL_PATH}/include/asm-ppc64 asm 
! &lt;sparc_linux22 sparc_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-sparc asm
! &lt;sparc64_linux22 sparc64_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-sparc64 asm
! &lt;ia64_linux24&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-ia64 asm
  &lt;all&gt;
  	for m in ${MPS} ; do \
--- 144,172 ----
  	$(RM) -f asm-generic
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-generic asm-generic
  	$(RM) -f asm
! &lt;parisc_linux22 parisc_linux24 parisc_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-parisc asm
! &lt;alpha_linux_22 alpha_linux_24 alpha_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-alpha asm
! &lt;i386_linux22 i386_linux24 i386_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-i386 asm
! &lt;i386_umlinux22 i386_umlinux24 i386_umlinux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-um asm
! &lt;amd64_linux24 amd64_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-x86_64 asm
! &lt;s390_linux22 s390_linux24 s390_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-s390 asm
! &lt;s390x_linux22 s390x_linux24 s390x_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-s390x asm
! &lt;ppc_linux22 ppc_linux24 ppc_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-ppc asm 
! &lt;ppc64_linux24 ppc64_linux26&gt;
  	ln -s ${LINUX_KERNEL_PATH}/include/asm-ppc64 asm 
! &lt;sparc_linux22 sparc_linux24 sparc_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-sparc asm
! &lt;sparc64_linux22 sparc64_linux24 sparc64_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-sparc64 asm
! &lt;ia64_linux24 ia64_linux26&gt;
  	ln -fs ${LINUX_KERNEL_PATH}/include/asm-ia64 asm
  &lt;all&gt;
  	for m in ${MPS} ; do \
Index: openafs/src/libafsauthent/Makefile.in
diff -c openafs/src/libafsauthent/Makefile.in:1.9 openafs/src/libafsauthent/Makefile.in:1.9.2.1
*** openafs/src/libafsauthent/Makefile.in:1.9	Sat Jan 11 02:34:42 2003
--- openafs/src/libafsauthent/Makefile.in	Mon Oct 18 03:11:59 2004
***************
*** 48,53 ****
--- 48,54 ----
  	read_passwd.o
  
  UBIKOBJS = \
+ 	uinit.o \
  	ubikclient.o \
  	uerrors.o \
  	ubik_int.cs.o \
***************
*** 160,165 ****
--- 161,169 ----
  ubikclient.o: ${UBIK}/ubikclient.c
  	${CCRULE}
  
+ uinit.o: ${UBIK}/uinit.c
+ 	${CCRULE}
+ 
  uerrors.o: ${UBIK}/uerrors.c
  	${CCRULE}
  
Index: openafs/src/libafsauthent/NTMakefile
diff -c openafs/src/libafsauthent/NTMakefile:1.10 openafs/src/libafsauthent/NTMakefile:1.10.2.1
*** openafs/src/libafsauthent/NTMakefile:1.10	Thu Aug  5 12:31:40 2004
--- openafs/src/libafsauthent/NTMakefile	Mon Oct 18 03:11:59 2004
***************
*** 53,58 ****
--- 53,59 ----
  	$(OUT)\user_nt.obj
  
  UBIKOBJS = \
+ 	$(OUT)\uinit.obj \
  	$(OUT)\ubikclient.obj \
  	$(OUT)\uerrors.obj \
  	$(OUT)\ubik_int.cs.obj \
Index: openafs/src/libafsrpc/Makefile.in
diff -c openafs/src/libafsrpc/Makefile.in:1.29 openafs/src/libafsrpc/Makefile.in:1.29.2.1
*** openafs/src/libafsrpc/Makefile.in:1.29	Fri Apr  9 02:03:09 2004
--- openafs/src/libafsrpc/Makefile.in	Mon Oct 18 03:12:01 2004
***************
*** 202,212 ****
  md5.o: ${RXKAD}/md5.c
  	${CCRULE} ${RXKAD}/md5.c
  
! fcrypt.o: ${TOP_OBJDIR}/src/rxkad/fcrypt.c
! 	${CCRULE} ${TOP_OBJDIR}/src/rxkad/fcrypt.c
  
! crypt_conn.o: ${TOP_OBJDIR}/src/rxkad/crypt_conn.c
! 	${CCRULE} ${TOP_OBJDIR}/src/rxkad/crypt_conn.c
  
  AFS_component_version_number.o: ${TOP_OBJDIR}/src/rx/AFS_component_version_number.c
  	${CCRULE} ${TOP_OBJDIR}/src/rx/AFS_component_version_number.c
--- 202,212 ----
  md5.o: ${RXKAD}/md5.c
  	${CCRULE} ${RXKAD}/md5.c
  
! fcrypt.o: ${TOP_OBJDIR}/src/rxkad/domestic/fcrypt.c
! 	${CCRULE} ${TOP_OBJDIR}/src/rxkad/domestic/fcrypt.c
  
! crypt_conn.o: ${TOP_OBJDIR}/src/rxkad/domestic/crypt_conn.c
! 	${CCRULE} ${TOP_OBJDIR}/src/rxkad/domestic/crypt_conn.c
  
  AFS_component_version_number.o: ${TOP_OBJDIR}/src/rx/AFS_component_version_number.c
  	${CCRULE} ${TOP_OBJDIR}/src/rx/AFS_component_version_number.c
***************
*** 266,272 ****
  #
  #   $ what /opt/langtools/bin/pxdb32
  #   /opt/langtools/bin/pxdb32:
! #           HP92453-02 A.10.0A HP-UX SYMBOLIC DEBUGGER (PXDB) $Revision: 1.29 $
  #
  # The problem occurs when -g and -O are both used when compiling des.c.
  # The simplest way to work around the problem is to leave out either -g or -O.
--- 266,272 ----
  #
  #   $ what /opt/langtools/bin/pxdb32
  #   /opt/langtools/bin/pxdb32:
! #           HP92453-02 A.10.0A HP-UX SYMBOLIC DEBUGGER (PXDB) $Revision: 1.29.2.1 $
  #
  # The problem occurs when -g and -O are both used when compiling des.c.
  # The simplest way to work around the problem is to leave out either -g or -O.
Index: openafs/src/libafsrpc/afsrpc.def
diff -c openafs/src/libafsrpc/afsrpc.def:1.3 openafs/src/libafsrpc/afsrpc.def:1.3.2.1
*** openafs/src/libafsrpc/afsrpc.def:1.3	Thu Feb 26 14:23:01 2004
--- openafs/src/libafsrpc/afsrpc.def	Mon Oct 18 03:12:01 2004
***************
*** 198,201 ****
  	rx_enable_hot_thread			@203 DATA
  	xdr_int64				@204
  	xdr_uint64				@205
!     rx_SetMaxMTU            @206
--- 198,202 ----
  	rx_enable_hot_thread			@203 DATA
  	xdr_int64				@204
  	xdr_uint64				@205
! 	rx_SetMaxMTU				@206
! 	rx_GetConnection			@207
Index: openafs/src/libafsrpc/mapfile
diff -c openafs/src/libafsrpc/mapfile:1.2 openafs/src/libafsrpc/mapfile:removed
*** openafs/src/libafsrpc/mapfile:1.2	Sat Nov  4 05:05:06 2000
--- openafs/src/libafsrpc/mapfile	Mon Oct 18 13:53:42 2004
***************
*** 1,117 ****
- # 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
- 
- {
-     global:
- 	des_cbc_init;
- 	des_check_key_parity;
- 	des_cksum_init;
- 	des_des_init;
- 	des_fixup_key_parity;
- 	des_init_random_number_generator;
- 	des_is_weak_key;
- 	des_key_sched;
- 	des_random_key;
- 	des_string_to_key;
- 	ktohl;
- 	life_to_time;
- 	rx_DestroyConnection;
- 	rx_EndCall;
- 	rx_Finalize;
- 	rx_GetCachedConnection;
- 	rx_GetCall;
- 	rx_GetIFInfo;
- 	rx_GetSpecific;
- 	rx_Init;
- 	rx_KeyCreate;
- 	rx_NewCall;
- 	rx_NewConnection;
- 	rx_NewService;
- 	rx_PrintPeerStats;
- 	rx_PrintStats;
- 	rx_PrintTheseStats;
- 	rx_ReadProc;
- 	rx_ReleaseCachedConnection;
- 	rx_ServerProc;
- 	rx_SetSpecific;
- 	rx_StartServer;
- 	rx_WriteProc;
- 	rxevent_Init;
- 	rxevent_Post;
- 	rxkad_GetServerInfo;
- 	rxkad_NewClientSecurityObject;
- 	rxkad_NewServerSecurityObject;
- 	rxkad_client_init;
- 	rxkad_crypt_init;
- 	rxnull_NewClientSecurityObject;
- 	rxnull_NewServerSecurityObject;
- 	rxs_Release;
- 	time_to_life;
- 	tkt_CheckTimes;
- 	tkt_DecodeTicket;
- 	tkt_MakeTicket;
- 	xdrrx_create;
- 	hton_syserr_conv;
- 	rxkad_stats;
- 	com_err;
- 	error_message;
- 	rx_socket;
- 	des_pcbc_init;
- 	rxevent_debugFile;
- 	rx_debugFile;
- 	rx_connDeadTime;
- 	rx_maxReceiveSize;
- 	rx_UdpBufSize;
- 	rx_extraQuota;
- 	rx_extraPackets;
- 	rx_tranquil;
- 	rx_getAllAddr;
- 	rx_nWaiting;
- 	rx_stats;
- 	rx_SetNoJumbo;
- 	rx_SetConnDeadTime;
- 	rx_FlushWrite;
- 	rx_thread_id_key;
- 	multi_Finalize;
- 	multi_Select;
- 	multi_Init;
- 	multi_Finalize_Ignore;
- 	add_to_error_table;
- 	xdr_afsUUID;
- 	rx_IncrementTimeAndCount;
- 	rx_enable_stats;
- 	rx_GetServerDebug;
- 	rx_GetServerStats;
- 	rx_GetServerVersion;
- 	rx_GetServerConnections;
- 	rx_stats_mutex;
- 	rx_GetServerPeers;
- 	rx_RetrieveProcessRPCStats;
- 	rx_RetrievePeerRPCStats;
- 	rx_FreeRPCStats;
- 	rx_queryProcessRPCStats;
- 	rx_queryPeerRPCStats;
- 	rx_enableProcessRPCStats;
- 	rx_enablePeerRPCStats;
- 	rx_disableProcessRPCStats;
- 	rx_disablePeerRPCStats;
- 	RXSTATS_ExecuteRequest;
- 	RXSTATS_RetrieveProcessRPCStats;
- 	RXSTATS_RetrievePeerRPCStats;
- 	RXSTATS_QueryProcessRPCStats;
- 	RXSTATS_QueryPeerRPCStats;
- 	RXSTATS_EnableProcessRPCStats;
- 	RXSTATS_EnablePeerRPCStats;
- 	RXSTATS_DisableProcessRPCStats;
- 	RXSTATS_DisablePeerRPCStats;
- 	RXSTATS_QueryRPCStatsVersion;
- 	RXSTATS_ClearProcessRPCStats;
- 	RXSTATS_ClearPeerRPCStats;
- 
-     local:
- 	*;
- };
--- 0 ----
Index: openafs/src/ptserver/pts.c
diff -c openafs/src/ptserver/pts.c:1.13 openafs/src/ptserver/pts.c:1.13.2.1
*** openafs/src/ptserver/pts.c:1.13	Wed Jun 23 10:27:42 2004
--- openafs/src/ptserver/pts.c	Mon Oct 18 03:12:04 2004
***************
*** 23,29 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/pts.c,v 1.13 2004/06/23 14:27:42 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;string.h&gt;
--- 23,29 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/pts.c,v 1.13.2.1 2004/10/18 07:12:04 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;string.h&gt;
***************
*** 853,859 ****
      idlist ids;
      namelist names;
      int i;
!     afs_int32 mask, flags, ngroups, nusers;
  
      if (GetNameOrId(as, &amp;ids, &amp;names))
  	return PRBADARG;
--- 853,859 ----
      idlist ids;
      namelist names;
      int i;
!     afs_int32 mask, flags=0, ngroups, nusers;
  
      if (GetNameOrId(as, &amp;ids, &amp;names))
  	return PRBADARG;
Index: openafs/src/ptserver/ptuser.c
diff -c openafs/src/ptserver/ptuser.c:1.16 openafs/src/ptserver/ptuser.c:1.16.2.1
*** openafs/src/ptserver/ptuser.c:1.16	Wed Jun 23 10:27:42 2004
--- openafs/src/ptserver/ptuser.c	Mon Oct 18 03:12:04 2004
***************
*** 15,21 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/ptuser.c,v 1.16 2004/06/23 14:27:42 shadow Exp $");
  
  #if defined(UKERNEL)
  #include "afs/sysincludes.h"
--- 15,21 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/ptuser.c,v 1.16.2.1 2004/10/18 07:12:04 shadow Exp $");
  
  #if defined(UKERNEL)
  #include "afs/sysincludes.h"
***************
*** 86,91 ****
--- 86,93 ----
  	/*
  	 * Different conf dir; force re-evaluation.
  	 */
+ 	if (tdir) 
+ 	    afsconf_Close(tdir);
  	tdir = (struct afsconf_dir *)0;
  	pruclient = (struct ubik_client *)0;
      }
***************
*** 168,174 ****
  	if (code)
  	    scIndex = 0;
  	else {
! 	    if (ttoken.kvno &gt;= 0 &amp;&amp; ttoken.kvno &lt;= 255)
  		/* this is a kerberos ticket, set scIndex accordingly */
  		scIndex = 2;
  	    else {
--- 170,176 ----
  	if (code)
  	    scIndex = 0;
  	else {
! 	    if (ttoken.kvno &gt;= 0 &amp;&amp; ttoken.kvno &lt;= 256)
  		/* this is a kerberos ticket, set scIndex accordingly */
  		scIndex = 2;
  	    else {
***************
*** 178,184 ****
  		scIndex = 2;
  	    }
  	    sc[2] =
! 		rxkad_NewClientSecurityObject(secLevel, &amp;ttoken.sessionKey,
  					      ttoken.kvno, ttoken.ticketLen,
  					      ttoken.ticket);
  	}
--- 180,186 ----
  		scIndex = 2;
  	    }
  	    sc[2] =
! 		rxkad_NewClientSecurityObject(rxkad_clear, &amp;ttoken.sessionKey,
  					      ttoken.kvno, ttoken.ticketLen,
  					      ttoken.ticket);
  	}
Index: openafs/src/rx/rx.c
diff -c openafs/src/rx/rx.c:1.58.2.2 openafs/src/rx/rx.c:1.58.2.3
*** openafs/src/rx/rx.c:1.58.2.2	Wed Aug 25 03:13:09 2004
--- openafs/src/rx/rx.c	Mon Oct 18 13:43:57 2004
***************
*** 17,23 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx.c,v 1.58.2.2 2004/08/25 07:13:09 shadow Exp $");
  
  #ifdef KERNEL
  #include "afs/sysincludes.h"
--- 17,23 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx.c,v 1.58.2.3 2004/10/18 17:43:57 shadow Exp $");
  
  #ifdef KERNEL
  #include "afs/sysincludes.h"
***************
*** 662,668 ****
  rx_StartServer(int donateMe)
  {
      register struct rx_service *service;
!     register int i, nProcs = 0;
      SPLVAR;
      clock_NewTime();
  
--- 662,668 ----
  rx_StartServer(int donateMe)
  {
      register struct rx_service *service;
!     register int i;
      SPLVAR;
      clock_NewTime();
  
***************
*** 701,706 ****
--- 701,707 ----
  #ifndef AFS_NT40_ENV
  #ifndef KERNEL
  	char name[32];
+ 	static int nProcs;
  #ifdef AFS_PTHREAD_ENV
  	pid_t pid;
  	pid = (pid_t) pthread_self();
***************
*** 816,830 ****
       * idle (refCount == 0) after rx_idlePeerTime (60 seconds) have passed.
       */
      MUTEX_ENTER(&amp;rx_peerHashTable_lock);
!     if (--conn-&gt;peer-&gt;refCount &lt;= 0) {
  	conn-&gt;peer-&gt;idleWhen = clock_Sec();
! 	if (conn-&gt;peer-&gt;refCount &lt; 0) {
! 	    conn-&gt;peer-&gt;refCount = 0;
  	    MUTEX_ENTER(&amp;rx_stats_mutex);
  	    rxi_lowPeerRefCount++;
  	    MUTEX_EXIT(&amp;rx_stats_mutex);
  	}
      }
      MUTEX_EXIT(&amp;rx_peerHashTable_lock);
  
      MUTEX_ENTER(&amp;rx_stats_mutex);
--- 817,832 ----
       * idle (refCount == 0) after rx_idlePeerTime (60 seconds) have passed.
       */
      MUTEX_ENTER(&amp;rx_peerHashTable_lock);
!     if (conn-&gt;peer-&gt;refCount &lt; 2) {
  	conn-&gt;peer-&gt;idleWhen = clock_Sec();
! 	if (conn-&gt;peer-&gt;refCount &lt; 1) {
! 	    conn-&gt;peer-&gt;refCount = 1;
  	    MUTEX_ENTER(&amp;rx_stats_mutex);
  	    rxi_lowPeerRefCount++;
  	    MUTEX_EXIT(&amp;rx_stats_mutex);
  	}
      }
+     conn-&gt;peer-&gt;refCount--;
      MUTEX_EXIT(&amp;rx_peerHashTable_lock);
  
      MUTEX_ENTER(&amp;rx_stats_mutex);
***************
*** 1014,1019 ****
--- 1016,1035 ----
      USERPRI;
  }
  
+ void
+ rx_GetConnection(register struct rx_connection *conn)
+ {
+     SPLVAR;
+ 
+     NETPRI;
+     AFS_RXGLOCK();
+     MUTEX_ENTER(&amp;conn-&gt;conn_data_lock);
+     conn-&gt;refCount++;
+     MUTEX_EXIT(&amp;conn-&gt;conn_data_lock);
+     AFS_RXGUNLOCK();
+     USERPRI;
+ }
+ 
  /* Start a new rx remote procedure call, on the specified connection.
   * If wait is set to 1, wait for a free call channel; otherwise return
   * 0.  Maxtime gives the maximum number of seconds this call may take,
***************
*** 3984,3989 ****
--- 4000,4006 ----
  	    call-&gt;flags |= RX_CALL_WAIT_PROC;
  	    MUTEX_ENTER(&amp;rx_stats_mutex);
  	    rx_nWaiting++;
+ 	    rx_nWaited++;
  	    MUTEX_EXIT(&amp;rx_stats_mutex);
  	    rxi_calltrace(RX_CALL_ARRIVAL, call);
  	    SET_CALL_QUEUE_LOCK(call, &amp;rx_serverPool_lock);
***************
*** 5747,5753 ****
  		    MUTEX_ENTER(&amp;rx_stats_mutex);
  		    rx_stats.nPeerStructs--;
  		    MUTEX_EXIT(&amp;rx_stats_mutex);
! 		    if (prev == *peer_ptr) {
  			*peer_ptr = next;
  			prev = next;
  		    } else
--- 5764,5770 ----
  		    MUTEX_ENTER(&amp;rx_stats_mutex);
  		    rx_stats.nPeerStructs--;
  		    MUTEX_EXIT(&amp;rx_stats_mutex);
! 		    if (peer == *peer_ptr) {
  			*peer_ptr = next;
  			prev = next;
  		    } else
***************
*** 6218,6223 ****
--- 6235,6243 ----
  	if (stat-&gt;version &gt;= RX_DEBUGI_VERSION_W_GETPEER) {
  	    *supportedValues |= RX_SERVER_DEBUG_ALL_PEER;
  	}
+ 	if (stat-&gt;version &gt;= RX_DEBUGI_VERSION_W_WAITED) {
+ 	    *supportedValues |= RX_SERVER_DEBUG_WAITED_CNT;
+ 	}
  
  	stat-&gt;nFreePackets = ntohl(stat-&gt;nFreePackets);
  	stat-&gt;packetReclaims = ntohl(stat-&gt;packetReclaims);
Index: openafs/src/rx/rx.h
diff -c openafs/src/rx/rx.h:1.22 openafs/src/rx/rx.h:1.22.2.1
*** openafs/src/rx/rx.h:1.22	Wed Jul 28 18:33:54 2004
--- openafs/src/rx/rx.h	Mon Oct 18 03:12:06 2004
***************
*** 211,216 ****
--- 211,218 ----
  #define rx_EnableHotThread()		(rx_enable_hot_thread = 1)
  #define rx_DisableHotThread()		(rx_enable_hot_thread = 0)
  
+ #define rx_PutConnection(conn) rx_DestroyConnection(conn)
+ 
  /* A connection is an authenticated communication path, allowing 
     limited multiple asynchronous conversations. */
  #ifdef KDUMP_RX_LOCK
***************
*** 248,254 ****
      /* client-- to retransmit the challenge */
      struct rx_service *service;	/* used by servers only */
      u_short serviceId;		/* To stamp on requests (clients only) */
!     u_short refCount;		/* Reference count */
      u_char flags;		/* Defined below */
      u_char type;		/* Type of connection, defined below */
      u_char secondsUntilPing;	/* how often to ping for each active call */
--- 250,256 ----
      /* client-- to retransmit the challenge */
      struct rx_service *service;	/* used by servers only */
      u_short serviceId;		/* To stamp on requests (clients only) */
!     afs_uint32 refCount;		/* Reference count */
      u_char flags;		/* Defined below */
      u_char type;		/* Type of connection, defined below */
      u_char secondsUntilPing;	/* how often to ping for each active call */
***************
*** 363,369 ****
  
      /* For garbage collection */
      afs_uint32 idleWhen;	/* When the refcountwent to zero */
!     short refCount;		/* Reference count for this structure */
  
      /* Congestion control parameters */
      u_char burstSize;		/* Reinitialization size for the burst parameter */
--- 365,371 ----
  
      /* For garbage collection */
      afs_uint32 idleWhen;	/* When the refcountwent to zero */
!     afs_uint32 refCount;		/* Reference count for this structure */
  
      /* Congestion control parameters */
      u_char burstSize;		/* Reinitialization size for the burst parameter */
***************
*** 817,823 ****
  #define RX_DEBUGI_BADTYPE     (-8)
  
  #define RX_DEBUGI_VERSION_MINIMUM ('L')	/* earliest real version */
! #define RX_DEBUGI_VERSION     ('Q')	/* Latest version */
      /* first version w/ secStats */
  #define RX_DEBUGI_VERSION_W_SECSTATS ('L')
      /* version M is first supporting GETALLCONN and RXSTATS type */
--- 819,825 ----
  #define RX_DEBUGI_BADTYPE     (-8)
  
  #define RX_DEBUGI_VERSION_MINIMUM ('L')	/* earliest real version */
! #define RX_DEBUGI_VERSION     ('R')	/* Latest version */
      /* first version w/ secStats */
  #define RX_DEBUGI_VERSION_W_SECSTATS ('L')
      /* version M is first supporting GETALLCONN and RXSTATS type */
***************
*** 829,834 ****
--- 831,837 ----
  #define RX_DEBUGI_VERSION_W_IDLETHREADS ('O')
  #define RX_DEBUGI_VERSION_W_NEWPACKETTYPES ('P')
  #define RX_DEBUGI_VERSION_W_GETPEER ('Q')
+ #define RX_DEBUGI_VERSION_W_WAITED ('R')
  
  #define	RX_DEBUGI_GETSTATS	1	/* get basic rx stats */
  #define	RX_DEBUGI_GETCONN	2	/* get connection info */
***************
*** 846,852 ****
      char spare1;
      afs_int32 nWaiting;
      afs_int32 idleThreads;	/* Number of server threads that are idle */
!     afs_int32 spare2[8];
  };
  
  struct rx_debugConn_vL {
--- 849,856 ----
      char spare1;
      afs_int32 nWaiting;
      afs_int32 idleThreads;	/* Number of server threads that are idle */
!     afs_int32 nWaited;
!     afs_int32 spare2[7];
  };
  
  struct rx_debugConn_vL {
***************
*** 971,976 ****
--- 975,981 ----
  #define RX_SERVER_DEBUG_OLD_CONN		0x20
  #define RX_SERVER_DEBUG_NEW_PACKETS		0x40
  #define RX_SERVER_DEBUG_ALL_PEER		0x80
+ #define RX_SERVER_DEBUG_WAITED_CNT              0x100
  
  #define AFS_RX_STATS_CLEAR_ALL			0xffffffff
  #define AFS_RX_STATS_CLEAR_INVOCATIONS		0x1
Index: openafs/src/rx/rx_getaddr.c
diff -c openafs/src/rx/rx_getaddr.c:1.15 openafs/src/rx/rx_getaddr.c:1.15.2.1
*** openafs/src/rx/rx_getaddr.c:1.15	Tue Jul 15 19:16:09 2003
--- openafs/src/rx/rx_getaddr.c	Mon Oct 18 03:12:06 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_getaddr.c,v 1.15 2003/07/15 23:16:09 shadow Exp $");
  
  #ifndef AFS_DJGPP_ENV
  #ifndef KERNEL
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_getaddr.c,v 1.15.2.1 2004/10/18 07:12:06 shadow Exp $");
  
  #ifndef AFS_DJGPP_ENV
  #ifndef KERNEL
***************
*** 118,126 ****
  #define ADVANCE(x, n) (x += ROUNDUP((n)-&gt;sa_len))
  
  static void
! rt_xaddrs(cp, cplim, rtinfo)
!      caddr_t cp, cplim;
!      struct rt_addrinfo *rtinfo;
  {
      struct sockaddr *sa;
      int i;
--- 118,124 ----
  #define ADVANCE(x, n) (x += ROUNDUP((n)-&gt;sa_len))
  
  static void
! rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
  {
      struct sockaddr *sa;
      int i;
***************
*** 141,149 ****
  */
  #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
  int
! rx_getAllAddr(buffer, maxSize)
!      afs_int32 buffer[];
!      int maxSize;		/* sizeof of buffer in afs_int32 units */
  {
      size_t needed;
      int mib[6];
--- 139,145 ----
  */
  #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
  int
! rx_getAllAddr(afs_int32 buffer[], int maxSize)
  {
      size_t needed;
      int mib[6];
***************
*** 221,231 ****
  }
  
  int
! rxi_getAllAddrMaskMtu(addrBuffer, maskBuffer, mtuBuffer, maxSize)
!      afs_int32 addrBuffer[];	/* the network addrs in net byte order */
!      afs_int32 maskBuffer[];	/* the subnet masks */
!      afs_int32 mtuBuffer[];	/* the MTU sizes */
!      int maxSize;		/* sizeof of buffer in afs_int32 units */
  {
      int s;
  
--- 217,224 ----
  }
  
  int
! rxi_getAllAddrMaskMtu(afs_int32 addrBuffer[], afs_int32 maskBuffer[],
! 		      afs_int32 mtuBuffer[], int maxSize)
  {
      int s;
  
***************
*** 279,287 ****
  	}
  	if ((ifm-&gt;ifm_flags &amp; IFF_UP) == 0)
  	    continue;		/* not up */
- 	if (ifm-&gt;ifm_flags &amp; IFF_LOOPBACK) {
- 	    continue;		/* skip aliased loopbacks as well. */
- 	}
  	while (addrcount &gt; 0) {
  	    struct sockaddr_in *a;
  
--- 272,277 ----
***************
*** 322,334 ****
      free(buf);
      return count;
  }
- 
- 
  #else
! int
! rx_getAllAddr(buffer, maxSize)
!      afs_int32 buffer[];
!      int maxSize;		/* sizeof of buffer in afs_int32 units */
  {
      int s;
      int i, len, count = 0;
--- 312,320 ----
      free(buf);
      return count;
  }
  #else
! static int
! rx_getAllAddr_internal(afs_int32 buffer[], int maxSize, int loopbacks)
  {
      int s;
      int i, len, count = 0;
***************
*** 381,387 ****
  	    continue;		/* ignore this address */
  	}
  	if (a-&gt;sin_addr.s_addr != 0) {
! 	    if (ifr-&gt;ifr_flags &amp; IFF_LOOPBACK) {
  		continue;	/* skip aliased loopbacks as well. */
  	    }
  	    if (count &gt;= maxSize)	/* no more space */
--- 367,373 ----
  	    continue;		/* ignore this address */
  	}
  	if (a-&gt;sin_addr.s_addr != 0) {
! 	    if (!loopbacks &amp;&amp; (ifr-&gt;ifr_flags &amp; IFF_LOOPBACK)) {
  		continue;	/* skip aliased loopbacks as well. */
  	    }
  	    if (count &gt;= maxSize)	/* no more space */
***************
*** 395,400 ****
--- 381,392 ----
      return count;
  }
  
+ int
+ rx_getAllAddr(afs_int32 buffer[], int maxSize)
+ {
+     return rx_getAllAddr_internal(buffer, maxSize, 0);
+ }
+ 
  /* this function returns the total number of interface addresses
   * the buffer has to be passed in by the caller. It also returns
   * the interface mask. If AFS_USERSPACE_IP_ADDR is defined, it
***************
*** 402,412 ****
   * by afsi_SetServerIPRank().
   */
  int
! rxi_getAllAddrMaskMtu(addrBuffer, maskBuffer, mtuBuffer, maxSize)
!      afs_int32 addrBuffer[];	/* the network addrs in net byte order */
!      afs_int32 maskBuffer[];	/* the subnet masks */
!      afs_int32 mtuBuffer[];	/* the MTU sizes */
!      int maxSize;		/* sizeof of buffer in afs_int32 units */
  {
      int s;
      int i, len, count = 0;
--- 394,401 ----
   * by afsi_SetServerIPRank().
   */
  int
! rxi_getAllAddrMaskMtu(afs_int32 addrBuffer[], afs_int32 maskBuffer[],
! 		      afs_int32 mtuBuffer[], int maxSize)
  {
      int s;
      int i, len, count = 0;
***************
*** 418,424 ****
  #endif
  
  #if !defined(AFS_USERSPACE_IP_ADDR)
!     count = rx_getAllAddr(addrBuffer, 1024);
      for (i = 0; i &lt; count; i++) {
  	maskBuffer[i] = htonl(0xffffffff);
  	mtuBuffer[i] = htonl(1500);
--- 407,413 ----
  #endif
  
  #if !defined(AFS_USERSPACE_IP_ADDR)
!     count = rx_getAllAddr_internal(addrBuffer, 1024, 1);
      for (i = 0; i &lt; count; i++) {
  	maskBuffer[i] = htonl(0xffffffff);
  	mtuBuffer[i] = htonl(1500);
***************
*** 458,466 ****
  		perror("SIOCGIFFLAGS");
  		continue;	/* ignore this address */
  	    }
- 	    if (ifr-&gt;ifr_flags &amp; IFF_LOOPBACK) {
- 		continue;	/* skip aliased loopbacks as well. */
- 	    }
  
  	    if (count &gt;= maxSize) {	/* no more space */
  		printf("Too many interfaces..ignoring 0x%x\n",
--- 447,452 ----
Index: openafs/src/rx/rx_globals.h
diff -c openafs/src/rx/rx_globals.h:1.9 openafs/src/rx/rx_globals.h:1.9.2.1
*** openafs/src/rx/rx_globals.h:1.9	Tue Jul 15 19:16:09 2003
--- openafs/src/rx/rx_globals.h	Mon Oct 18 03:12:06 2004
***************
*** 151,156 ****
--- 151,157 ----
  EXT int rx_nFreePackets INIT(0);
  EXT int rxi_NeedMorePackets INIT(0);
  EXT int rx_nWaiting INIT(0);
+ EXT int rx_nWaited INIT(0);
  EXT int rx_packetReclaims INIT(0);
  
  /* largest packet which we can safely receive, initialized to AFS 3.2 value
Index: openafs/src/rx/rx_packet.c
diff -c openafs/src/rx/rx_packet.c:1.35.2.1 openafs/src/rx/rx_packet.c:1.35.2.2
*** openafs/src/rx/rx_packet.c:1.35.2.1	Wed Aug 25 03:09:42 2004
--- openafs/src/rx/rx_packet.c	Mon Oct 18 13:43:58 2004
***************
*** 15,21 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_packet.c,v 1.35.2.1 2004/08/25 07:09:42 shadow Exp $");
  
  #ifdef KERNEL
  #if defined(UKERNEL)
--- 15,21 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_packet.c,v 1.35.2.2 2004/10/18 17:43:58 shadow Exp $");
  
  #ifdef KERNEL
  #if defined(UKERNEL)
***************
*** 865,871 ****
  	     * never be cleaned up.
  	     */
  	    peer = rxi_FindPeer(*host, *port, 0, 0);
! 	    if (peer) {
  		MUTEX_ENTER(&amp;peer-&gt;peer_lock);
  		hadd32(peer-&gt;bytesReceived, p-&gt;length);
  		MUTEX_EXIT(&amp;peer-&gt;peer_lock);
--- 865,875 ----
  	     * never be cleaned up.
  	     */
  	    peer = rxi_FindPeer(*host, *port, 0, 0);
! 	    /* Since this may not be associated with a connection,
! 	     * it may have no refCount, meaning we could race with
! 	     * ReapConnections
! 	     */
! 	    if (peer &amp;&amp; (peer-&gt;refCount &gt; 0)) {
  		MUTEX_ENTER(&amp;peer-&gt;peer_lock);
  		hadd32(peer-&gt;bytesReceived, p-&gt;length);
  		MUTEX_EXIT(&amp;peer-&gt;peer_lock);
***************
*** 1160,1165 ****
--- 1164,1170 ----
  	    tstat.packetReclaims = htonl(rx_packetReclaims);
  	    tstat.usedFDs = CountFDs(64);
  	    tstat.nWaiting = htonl(rx_nWaiting);
+ 	    tstat.nWaited = htonl(rx_nWaited);
  	    queue_Count(&amp;rx_idleServerQueue, np, nqe, rx_serverQueueEntry,
  			tstat.idleThreads);
  	    MUTEX_EXIT(&amp;rx_serverPool_lock);
Index: openafs/src/rx/rx_prototypes.h
diff -c openafs/src/rx/rx_prototypes.h:1.14 openafs/src/rx/rx_prototypes.h:1.14.2.1
*** openafs/src/rx/rx_prototypes.h:1.14	Wed Jul 28 18:33:54 2004
--- openafs/src/rx/rx_prototypes.h	Mon Oct 18 03:12:06 2004
***************
*** 26,31 ****
--- 26,32 ----
  			       register int seconds);
  extern void rxi_CleanupConnection(struct rx_connection *conn);
  extern void rxi_DestroyConnection(register struct rx_connection *conn);
+ extern void rx_GetConnection(register struct rx_connection *conn);
  extern void rx_DestroyConnection(register struct rx_connection *conn);
  extern struct rx_call *rx_NewCall(register struct rx_connection *conn);
  extern int rxi_HasActiveCalls(register struct rx_connection *aconn);
Index: openafs/src/rx/rx_rdwr.c
diff -c openafs/src/rx/rx_rdwr.c:1.21 openafs/src/rx/rx_rdwr.c:1.21.2.1
*** openafs/src/rx/rx_rdwr.c:1.21	Tue Jul 15 19:16:10 2003
--- openafs/src/rx/rx_rdwr.c	Mon Oct 18 03:12:06 2004
***************
*** 15,21 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_rdwr.c,v 1.21 2003/07/15 23:16:10 shadow Exp $");
  
  #ifdef KERNEL
  #ifndef UKERNEL
--- 15,21 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_rdwr.c,v 1.21.2.1 2004/10/18 07:12:06 shadow Exp $");
  
  #ifdef KERNEL
  #ifndef UKERNEL
***************
*** 1301,1307 ****
  		return;
  	    }
  	    cp-&gt;length = 0;
! 	    cp-&gt;niovecs = 1;	/* just the header */
  	    call-&gt;nFree = 0;
  	}
  
--- 1301,1307 ----
  		return;
  	    }
  	    cp-&gt;length = 0;
! 	    cp-&gt;niovecs = 2;	/* header + space for rxkad stuff */
  	    call-&gt;nFree = 0;
  	}
  
Index: openafs/src/rx/rx_user.c
diff -c openafs/src/rx/rx_user.c:1.18.2.1 openafs/src/rx/rx_user.c:1.18.2.2
*** openafs/src/rx/rx_user.c:1.18.2.1	Wed Aug 25 03:09:42 2004
--- openafs/src/rx/rx_user.c	Mon Oct 18 13:43:58 2004
***************
*** 13,19 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_user.c,v 1.18.2.1 2004/08/25 07:09:42 shadow Exp $");
  
  # include &lt;sys/types.h&gt;
  # include &lt;errno.h&gt;
--- 13,19 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_user.c,v 1.18.2.2 2004/10/18 17:43:58 shadow Exp $");
  
  # include &lt;sys/types.h&gt;
  # include &lt;errno.h&gt;
***************
*** 100,106 ****
      osi_socket socketFd = OSI_NULLSOCKET;
      struct sockaddr_in taddr;
      char *name = "rxi_GetUDPSocket: ";
!     int greedy = 0;
  
  #if !defined(AFS_NT40_ENV) &amp;&amp; !defined(AFS_DJGPP_ENV)
      if (ntohs(port) &gt;= IPPORT_RESERVED &amp;&amp; ntohs(port) &lt; IPPORT_USERRESERVED) {
--- 100,108 ----
      osi_socket socketFd = OSI_NULLSOCKET;
      struct sockaddr_in taddr;
      char *name = "rxi_GetUDPSocket: ";
! #ifdef AFS_LINUX22_ENV
!     int pmtu=IP_PMTUDISC_DONT;
! #endif
  
  #if !defined(AFS_NT40_ENV) &amp;&amp; !defined(AFS_DJGPP_ENV)
      if (ntohs(port) &gt;= IPPORT_RESERVED &amp;&amp; ntohs(port) &lt; IPPORT_USERRESERVED) {
***************
*** 147,161 ****
      fcntl(socketFd, F_SETFD, 1);
  #endif
  
      /* Use one of three different ways of getting a socket buffer expanded to
       * a reasonable size.
       */
      {
  	int len1, len2;
  
  	len1 = 32766;
  	len2 = rx_UdpBufSize;
- #ifndef AFS_DJGPP_ENV
  	greedy =
  	    (setsockopt
  	     (socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&amp;len2,
--- 149,164 ----
      fcntl(socketFd, F_SETFD, 1);
  #endif
  
+ #ifndef AFS_DJGPP_ENV
      /* Use one of three different ways of getting a socket buffer expanded to
       * a reasonable size.
       */
      {
+ 	int greedy = 0;
  	int len1, len2;
  
  	len1 = 32766;
  	len2 = rx_UdpBufSize;
  	greedy =
  	    (setsockopt
  	     (socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&amp;len2,
***************
*** 172,185 ****
  	    (setsockopt
  	     (socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&amp;len2,
  	      sizeof(len2)) &gt;= 0);
! #endif /* AFS_DJGPP_ENV */
      }
- 
- #ifndef AFS_DJGPP_ENV
-     if (!greedy)
- 	(osi_Msg "%s*WARNING* Unable to increase buffering on socket\n",
- 	 name);
  #endif /* AFS_DJGPP_ENV */
      if (rxi_Listen(socketFd) &lt; 0) {
  	goto error;
      }
--- 175,193 ----
  	    (setsockopt
  	     (socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&amp;len2,
  	      sizeof(len2)) &gt;= 0);
! 	if (!greedy)
! 	    (osi_Msg "%s*WARNING* Unable to increase buffering on socket\n",
! 	     name);
! 	MUTEX_ENTER(&amp;rx_stats_mutex);
! 	rx_stats.socketGreedy = greedy;
! 	MUTEX_EXIT(&amp;rx_stats_mutex);
      }
  #endif /* AFS_DJGPP_ENV */
+ 
+ #ifdef AFS_LINUX22_ENV
+     setsockopt(socketFd, SOL_IP, IP_MTU_DISCOVER, &amp;pmtu, sizeof(pmtu));
+ #endif
+ 
      if (rxi_Listen(socketFd) &lt; 0) {
  	goto error;
      }
***************
*** 195,203 ****
  	close(socketFd);
  #endif
  
-     MUTEX_ENTER(&amp;rx_stats_mutex);
-     rx_stats.socketGreedy = greedy;
-     MUTEX_EXIT(&amp;rx_stats_mutex);
      return OSI_NULLSOCKET;
  }
  
--- 203,208 ----
Index: openafs/src/rx/rxdebug.c
diff -c openafs/src/rx/rxdebug.c:1.15.2.1 openafs/src/rx/rxdebug.c:1.15.2.2
*** openafs/src/rx/rxdebug.c:1.15.2.1	Wed Aug 25 03:09:42 2004
--- openafs/src/rx/rxdebug.c	Mon Oct 18 13:43:59 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rxdebug.c,v 1.15.2.1 2004/08/25 07:09:42 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;errno.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rxdebug.c,v 1.15.2.2 2004/10/18 17:43:59 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;errno.h&gt;
***************
*** 109,114 ****
--- 109,115 ----
      int withRxStats;
      int withWaiters;
      int withIdleThreads;
+     int withWaited;
      int withPeers;
      struct rx_debugStats tstats;
      char *portName, *hostName;
***************
*** 253,258 ****
--- 254,260 ----
      withRxStats = (supportedDebugValues &amp; RX_SERVER_DEBUG_RX_STATS);
      withWaiters = (supportedDebugValues &amp; RX_SERVER_DEBUG_WAITER_CNT);
      withIdleThreads = (supportedDebugValues &amp; RX_SERVER_DEBUG_IDLE_THREADS);
+     withIdleThreads = (supportedDebugValues &amp; RX_SERVER_DEBUG_WAITED_CNT);
      withPeers = (supportedDebugValues &amp; RX_SERVER_DEBUG_ALL_PEER);
  
      printf("Free packets: %d, packet reclaims: %d, calls: %d, used FDs: %d\n",
***************
*** 265,270 ****
--- 267,274 ----
  	printf("%d calls waiting for a thread\n", tstats.nWaiting);
      if (withIdleThreads)
  	printf("%d threads are idle\n", tstats.idleThreads);
+     if (withWaited)
+ 	printf("%d calls have waited for a thread\n", tstats.nWaited);
  
      if (rxstats) {
  	if (!withRxStats) {
Index: openafs/src/rx/LINUX/rx_knet.c
diff -c openafs/src/rx/LINUX/rx_knet.c:1.23.2.1 openafs/src/rx/LINUX/rx_knet.c:1.23.2.3
*** openafs/src/rx/LINUX/rx_knet.c:1.23.2.1	Wed Aug 25 03:41:00 2004
--- openafs/src/rx/LINUX/rx_knet.c	Mon Oct 18 13:43:59 2004
***************
*** 16,22 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/LINUX/rx_knet.c,v 1.23.2.1 2004/08/25 07:41:00 shadow Exp $");
  
  #include &lt;linux/version.h&gt;
  #ifdef AFS_LINUX22_ENV
--- 16,22 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/LINUX/rx_knet.c,v 1.23.2.3 2004/10/18 17:43:59 shadow Exp $");
  
  #include &lt;linux/version.h&gt;
  #ifdef AFS_LINUX22_ENV
***************
*** 35,46 ****
      struct socket *sockp;
      struct sockaddr_in myaddr;
      int code;
  
  
      /* We need a better test for this. if you need it back, tell us
       * how to detect it. 
       */
! #if 0/*def LINUX_KERNEL_IS_SELINUX*/
      code = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &amp;sockp, 0);
  #else
      code = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &amp;sockp);
--- 35,48 ----
      struct socket *sockp;
      struct sockaddr_in myaddr;
      int code;
+     KERNEL_SPACE_DECL;
+     int pmtu = IP_PMTUDISC_DONT;
  
  
      /* We need a better test for this. if you need it back, tell us
       * how to detect it. 
       */
! #ifdef LINUX_KERNEL_SOCK_CREATE_V
      code = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &amp;sockp, 0);
  #else
      code = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &amp;sockp);
***************
*** 64,69 ****
--- 66,74 ----
  	return NULL;
      }
  
+     TO_USER_SPACE();
+     sockp-&gt;ops-&gt;setsockopt(sockp, SOL_IP, IP_MTU_DISCOVER, &amp;pmtu, sizeof(pmtu));
+     TO_KERNEL_SPACE();
      return (struct osi_socket *)sockp;
  }
  
Index: openafs/src/rxkad/Makefile.in
diff -c openafs/src/rxkad/Makefile.in:1.19 openafs/src/rxkad/Makefile.in:1.19.2.1
*** openafs/src/rxkad/Makefile.in:1.19	Sat May  8 01:10:41 2004
--- openafs/src/rxkad/Makefile.in	Mon Oct 18 03:12:08 2004
***************
*** 65,72 ****
  	$(AR) crv $@ ${OBJS} AFS_component_version_number.o
  	$(RANLIB) $@
  
- crypt_conn.o: fcrypt.h private_data.h crypt_conn.c ${INCLS}
- 
  rxkad_client.o: fcrypt.h private_data.h rxkad_client.c ${INCLS}
  
  rxkad_server.o: fcrypt.h private_data.h rxkad_server.c ${INCLS}
--- 65,70 ----
***************
*** 89,102 ****
   
  md5.o: md5.c ${INCLS}
  
! fcrypt.o: fcrypt.c fcrypt.h sboxes.h rxkad.h rxkad_prototypes.h
! 	${CCOBJ} ${CFLAGS} -c fcrypt.c
  
  tcrypt: tcrypt.o librxkad.a 
  	${CC} -o tcrypt tcrypt.o librxkad.a
  
- tcrypt.o: tcrypt.c AFS_component_version_number.o
- 
  fc_test: ${fc_test_OBJS} ${fc_test_LIBS}
  	${CC} ${CFLAGS} -o fc_test ${fc_test_OBJS} ${fc_test_LIBS} ${XLIBS}
  
--- 87,104 ----
   
  md5.o: md5.c ${INCLS}
  
! fcrypt.o: domestic/fcrypt.c fcrypt.h sboxes.h rxkad.h rxkad_prototypes.h
! 	${CCOBJ} ${CFLAGS} -c domestic/fcrypt.c
! 
! crypt_conn.o: domestic/crypt_conn.c fcrypt.h private_data.h ${INCLS}
! 	${CCOBJ} ${CFLAGS} -c domestic/crypt_conn.c
! 
! tcrypt.o: domestic/tcrypt.c AFS_component_version_number.o
! 	${CCOBJ} ${CFLAGS} -c domestic/fcrypt.c
  
  tcrypt: tcrypt.o librxkad.a 
  	${CC} -o tcrypt tcrypt.o librxkad.a
  
  fc_test: ${fc_test_OBJS} ${fc_test_LIBS}
  	${CC} ${CFLAGS} -o fc_test ${fc_test_OBJS} ${fc_test_LIBS} ${XLIBS}
  
***************
*** 109,115 ****
  clean: 
  	$(RM) -f *.o *.a tcrypt core rxkad_errs.c rxkad.h \
  		AFS_component_version_number.c \
! 		crypt_conn.c fcrypt.c fcrypt.h sboxes.h \
  		fc_test
  
  test:
--- 111,117 ----
  clean: 
  	$(RM) -f *.o *.a tcrypt core rxkad_errs.c rxkad.h \
  		AFS_component_version_number.c \
! 		fcrypt.h sboxes.h \
  		fc_test
  
  test:
***************
*** 117,137 ****
  # These sources are kept in a separate directory so that we can use an
  # ACL to comply with source export restrictions.
  
- crypt_conn.c: domestic/crypt_conn.c
- 	${INSTALL} $? $@
- 
- fcrypt.c: domestic/fcrypt.c
- 	${INSTALL} $? $@
- 
  fcrypt.h: domestic/fcrypt.h
  	${INSTALL} $? $@
  
  sboxes.h: domestic/sboxes.h
  	${INSTALL} $? $@
  
- tcrypt.c: domestic/tcrypt.c
- 	${INSTALL} $? $@
- 
  include ../config/Makefile.version
  ${DESTDIR}${libdir}/librxkad.a: librxkad.a
  	${INSTALL} $? $@
--- 119,130 ----
Index: openafs/src/rxkad/rxkad.p.h
diff -c openafs/src/rxkad/rxkad.p.h:1.11.2.2 openafs/src/rxkad/rxkad.p.h:1.11.2.3
*** openafs/src/rxkad/rxkad.p.h:1.11.2.2	Wed Aug 25 03:20:28 2004
--- openafs/src/rxkad/rxkad.p.h	Mon Oct 18 13:44:00 2004
***************
*** 16,27 ****
  		/* no ticket good for longer than 30 days */
  #define MAXKTCTICKETLIFETIME (30*24*3600)
  #define MINKTCTICKETLEN	      32
- #ifdef AFS_AIX_ENV
- #define MAXKTCTICKETLEN 344 /* XXX why must this be small? */
- #else
  #define	MAXKTCTICKETLEN	      12000	/* was 344 */
- #endif
- 
  #define	MAXKTCNAMELEN	      64	/* name &amp; inst should be 256 */
  #define MAXKTCREALMLEN	      64	/* should be 256 */
  #define KTC_TIME_UNCERTAINTY (15*60)	/* max skew bet. machines' clocks */
--- 16,22 ----
Index: openafs/src/rxkad/rxkad_prototypes.h
diff -c openafs/src/rxkad/rxkad_prototypes.h:1.9.2.1 openafs/src/rxkad/rxkad_prototypes.h:1.9.2.2
*** openafs/src/rxkad/rxkad_prototypes.h:1.9.2.1	Wed Aug 25 03:09:42 2004
--- openafs/src/rxkad/rxkad_prototypes.h	Mon Oct 18 13:44:00 2004
***************
*** 28,36 ****
  /* domestic/fcrypt.c */
  extern int fc_keysched(struct ktc_encryptionKey *key,
  		       fc_KeySchedule schedule);
! extern afs_int32 fc_ecb_encrypt(afs_uint32 * clear, afs_uint32 * cipher,
  				fc_KeySchedule schedule, int encrypt);
! extern afs_int32 fc_cbc_encrypt(char *input, char *output, afs_int32 length,
  				fc_KeySchedule key, afs_uint32 * xor,
  				int encrypt);
  
--- 28,36 ----
  /* domestic/fcrypt.c */
  extern int fc_keysched(struct ktc_encryptionKey *key,
  		       fc_KeySchedule schedule);
! extern afs_int32 fc_ecb_encrypt(void * clear, void * cipher,
  				fc_KeySchedule schedule, int encrypt);
! extern afs_int32 fc_cbc_encrypt(void *input, void *output, afs_int32 length,
  				fc_KeySchedule key, afs_uint32 * xor,
  				int encrypt);
  
Index: openafs/src/rxkad/domestic/fcrypt.c
diff -c openafs/src/rxkad/domestic/fcrypt.c:1.11.2.1 openafs/src/rxkad/domestic/fcrypt.c:1.11.2.2
*** openafs/src/rxkad/domestic/fcrypt.c:1.11.2.1	Wed Aug 25 03:17:01 2004
--- openafs/src/rxkad/domestic/fcrypt.c	Mon Oct 18 13:44:01 2004
***************
*** 20,26 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rxkad/domestic/fcrypt.c,v 1.11.2.1 2004/08/25 07:17:01 shadow Exp $");
  
  #define DEBUG 0
  #ifdef KERNEL
--- 20,26 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rxkad/domestic/fcrypt.c,v 1.11.2.2 2004/10/18 17:44:01 shadow Exp $");
  
  #define DEBUG 0
  #ifdef KERNEL
***************
*** 110,116 ****
  
  /* IN int encrypt; * 0 ==&gt; decrypt, else encrypt */
  afs_int32
! fc_ecb_encrypt(afs_uint32 * clear, afs_uint32 * cipher,
  	       fc_KeySchedule schedule, int encrypt)
  {
      afs_uint32 L, R;
--- 110,116 ----
  
  /* IN int encrypt; * 0 ==&gt; decrypt, else encrypt */
  afs_int32
! fc_ecb_encrypt(void * clear, void * cipher,
  	       fc_KeySchedule schedule, int encrypt)
  {
      afs_uint32 L, R;
***************
*** 135,142 ****
      memcpy(&amp;L, clear, sizeof(afs_int32));
      memcpy(&amp;R, clear + 1, sizeof(afs_int32));
  #else
!     L = ntohl(*clear);
!     R = ntohl(*(clear + 1));
  #endif
  
      if (encrypt) {
--- 135,142 ----
      memcpy(&amp;L, clear, sizeof(afs_int32));
      memcpy(&amp;R, clear + 1, sizeof(afs_int32));
  #else
!     L = ntohl(*((afs_uint32 *)clear));
!     R = ntohl(*((afs_uint32 *)clear + 1));
  #endif
  
      if (encrypt) {
***************
*** 185,192 ****
      memcpy(cipher, &amp;L, sizeof(afs_int32));
      memcpy(cipher + 1, &amp;R, sizeof(afs_int32));
  #else
!     *cipher = htonl(L);
!     *(cipher + 1) = htonl(R);
  #endif
      return 0;
  }
--- 185,192 ----
      memcpy(cipher, &amp;L, sizeof(afs_int32));
      memcpy(cipher + 1, &amp;R, sizeof(afs_int32));
  #else
!     *((afs_int32 *)cipher) = htonl(L);
!     *((afs_int32 *)cipher + 1) = htonl(R);
  #endif
      return 0;
  }
***************
*** 203,209 ****
    afs_uint32 *xor; * 8 bytes of initialization vector *
  */
  afs_int32
! fc_cbc_encrypt(char *input, char *output, afs_int32 length,
  	       fc_KeySchedule key, afs_uint32 * xor, int encrypt)
  {
      afs_uint32 i, j;
--- 203,209 ----
    afs_uint32 *xor; * 8 bytes of initialization vector *
  */
  afs_int32
! fc_cbc_encrypt(void *input, void *output, afs_int32 length,
  	       fc_KeySchedule key, afs_uint32 * xor, int encrypt)
  {
      afs_uint32 i, j;
***************
*** 215,221 ****
  	for (i = 0; length &gt; 0; i++, length -= 8) {
  	    /* get input */
  	    memcpy(t_input, input, sizeof(t_input));
! 	    input += sizeof(t_input);
  
  	    /* zero pad */
  	    for (j = length; j &lt;= 7; j++)
--- 215,221 ----
  	for (i = 0; length &gt; 0; i++, length -= 8) {
  	    /* get input */
  	    memcpy(t_input, input, sizeof(t_input));
! 	    input=((char *)input) + sizeof(t_input);
  
  	    /* zero pad */
  	    for (j = length; j &lt;= 7; j++)
***************
*** 229,235 ****
  
  	    /* copy temp output and save it for cbc */
  	    memcpy(output, t_output, sizeof(t_output));
! 	    output += sizeof(t_output);
  
  	    /* calculate xor value for next round from plain &amp; cipher text */
  	    xor[0] = t_input[0] ^ t_output[0];
--- 229,235 ----
  
  	    /* copy temp output and save it for cbc */
  	    memcpy(output, t_output, sizeof(t_output));
! 	    output=(char *)output + sizeof(t_output);
  
  	    /* calculate xor value for next round from plain &amp; cipher text */
  	    xor[0] = t_input[0] ^ t_output[0];
***************
*** 244,250 ****
  	for (i = 0; length &gt; 0; i++, length -= 8) {
  	    /* get input */
  	    memcpy(t_input, input, sizeof(t_input));
! 	    input += sizeof(t_input);
  
  	    /* no padding for decrypt */
  	    fc_ecb_encrypt(t_input, t_output, key, encrypt);
--- 244,250 ----
  	for (i = 0; length &gt; 0; i++, length -= 8) {
  	    /* get input */
  	    memcpy(t_input, input, sizeof(t_input));
! 	    input=((char *)input) + sizeof(t_input);
  
  	    /* no padding for decrypt */
  	    fc_ecb_encrypt(t_input, t_output, key, encrypt);
***************
*** 255,261 ****
  
  	    /* copy temp output */
  	    memcpy(output, t_output, sizeof(t_output));
! 	    output += sizeof(t_output);
  
  	    /* calculate xor value for next round from plain &amp; cipher text */
  	    xor[0] = t_input[0] ^ t_output[0];
--- 255,261 ----
  
  	    /* copy temp output */
  	    memcpy(output, t_output, sizeof(t_output));
! 	    output=((char *)output) + sizeof(t_output);
  
  	    /* calculate xor value for next round from plain &amp; cipher text */
  	    xor[0] = t_input[0] ^ t_output[0];
Index: openafs/src/scout/Makefile.in
diff -c openafs/src/scout/Makefile.in:1.8 openafs/src/scout/Makefile.in:1.8.2.1
*** openafs/src/scout/Makefile.in:1.8	Sat Jan 11 02:34:53 2003
--- openafs/src/scout/Makefile.in	Mon Oct 18 03:12:10 2004
***************
*** 24,29 ****
--- 24,30 ----
  LIBS=${TOP_LIBDIR}/libgtx.a \
  	${TOP_LIBDIR}/libfsprobe.a \
  	${TOP_LIBDIR}/libvolser.a \
+         ${TOP_LIBDIR}/libubik.a \
  	${TOP_LIBDIR}/libkauth.a \
  	${TOP_LIBDIR}/libauth.a \
  	${TOP_LIBDIR}/librxkad.a \
***************
*** 31,37 ****
  	${TOP_LIBDIR}/libcmd.a \
  	${TOP_LIBDIR}/vlib.a ${TOP_LIBDIR}/libacl.a \
          ${TOP_LIBDIR}/libvldb.a \
-         ${TOP_LIBDIR}/libubik.a \
  	${TOP_LIBDIR}/libafsint.a \
  	${TOP_LIBDIR}/libsys.a \
  	${TOP_LIBDIR}/librx.a \
--- 32,37 ----
Index: openafs/src/shlibafsauthent/Makefile.in
diff -c openafs/src/shlibafsauthent/Makefile.in:1.9 openafs/src/shlibafsauthent/Makefile.in:1.9.2.1
*** openafs/src/shlibafsauthent/Makefile.in:1.9	Sat Jan 11 02:34:54 2003
--- openafs/src/shlibafsauthent/Makefile.in	Mon Oct 18 03:12:12 2004
***************
*** 53,58 ****
--- 53,59 ----
  	read_passwd.o
  
  UBIKOBJS = \
+ 	uinit.o \
  	ubikclient.o \
  	uerrors.o \
  	ubik_int.cs.o \
***************
*** 175,180 ****
--- 176,184 ----
  ubikclient.o: ${UBIK}/ubikclient.c
  	${CCRULE}
  
+ uinit.o: ${UBIK}/uinit.c
+ 	${CCRULE}
+ 
  uerrors.o: ${UBIK}/uerrors.c
  	${CCRULE}
  
Index: openafs/src/shlibafsrpc/Makefile.in
diff -c openafs/src/shlibafsrpc/Makefile.in:1.15 openafs/src/shlibafsrpc/Makefile.in:1.15.2.1
*** openafs/src/shlibafsrpc/Makefile.in:1.15	Fri Apr  9 02:04:46 2004
--- openafs/src/shlibafsrpc/Makefile.in	Mon Oct 18 03:12:14 2004
***************
*** 209,218 ****
  md5.o: ${RXKAD}/md5.c
  	${CCRULE}
  
! fcrypt.o: ${RXKAD}/fcrypt.c
  	${CCRULE}
  
! crypt_conn.o: ${RXKAD}/crypt_conn.c
  	${CCRULE}
  
  AFS_component_version_number.o: ${RX}/AFS_component_version_number.c
--- 209,218 ----
  md5.o: ${RXKAD}/md5.c
  	${CCRULE}
  
! fcrypt.o: ${RXKAD}/domestic/fcrypt.c
  	${CCRULE}
  
! crypt_conn.o: ${RXKAD}/domestic/crypt_conn.c
  	${CCRULE}
  
  AFS_component_version_number.o: ${RX}/AFS_component_version_number.c
***************
*** 273,279 ****
  #
  #   $ what /opt/langtools/bin/pxdb32
  #   /opt/langtools/bin/pxdb32:
! #           HP92453-02 A.10.0A HP-UX SYMBOLIC DEBUGGER (PXDB) $Revision: 1.15 $
  #
  # The problem occurs when -g and -O are both used when compiling des.c.
  # The simplest way to work around the problem is to leave out either -g or -O.
--- 273,279 ----
  #
  #   $ what /opt/langtools/bin/pxdb32
  #   /opt/langtools/bin/pxdb32:
! #           HP92453-02 A.10.0A HP-UX SYMBOLIC DEBUGGER (PXDB) $Revision: 1.15.2.1 $
  #
  # The problem occurs when -g and -O are both used when compiling des.c.
  # The simplest way to work around the problem is to leave out either -g or -O.
Index: openafs/src/shlibafsrpc/NTMakefile
diff -c openafs/src/shlibafsrpc/NTMakefile:1.3 openafs/src/shlibafsrpc/NTMakefile:removed
*** openafs/src/shlibafsrpc/NTMakefile:1.3	Fri Apr  9 02:49:29 2004
--- openafs/src/shlibafsrpc/NTMakefile	Mon Oct 18 13:53:43 2004
***************
*** 1,349 ****
- # 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
- 
- RELDIR=shlibafsrpc
- !include ..\config\NTMakefile.$(SYS_NAME)
- !include ..\config\NTMakefile.version
- 
- RX = ..\rx
- RXSTAT = ..\rxstat
- RXKAD = ..\rxkad
- DES = ..\des
- UTIL = ..\util
- FSINT = ..\fsint
- COMERR = ..\comerr
- 
- # Additional debugging flag for RX.
- AFSDEV_AUXCDEFINES = -DRXDEBUG -DAFS_PTHREAD_ENV
- 
- LIBFILE = $(DESTDIR)\lib\afsrpc.dll
- 
- # Object files by category.
- MULTIOBJS = $(OUT)\rx_multi.obj
- 
- XDROBJS = $(OUT)\xdr.obj \
-     $(OUT)\xdr_array.obj \
-     $(OUT)\xdr_arrayn.obj \
-     $(OUT)\xdr_float.obj \
-     $(OUT)\xdr_mem.obj \
- 	$(OUT)\xdr_rec.obj \
-     $(OUT)\xdr_refernce.obj \
-     $(OUT)\xdr_rx.obj \
-     $(OUT)\xdr_update.obj \
- 	$(OUT)\xdr_afsuuid.obj \
-     $(OUT)\xdr_int64.obj
- 
- RXOBJS = $(OUT)\rx_event.obj \
-     $(OUT)\rx_user.obj \
-     $(OUT)\rx_pthread.obj \
-     $(OUT)\rx.obj \
- 	$(OUT)\rx_null.obj \
-     $(OUT)\rx_globals.obj \
-     $(OUT)\rx_getaddr.obj \
-     $(OUT)\rx_misc.obj 
-     $(OUT)\rx_packet.obj \
- 	$(OUT)\rx_rdwr.obj \
-     $(OUT)\rx_trace.obj \
-     $(OUT)\rx_xmit_nt.obj \
-     $(OUT)\rx_conncache.obj 
- 
- RXSTATOBJS = $(OUT)\rxstat.obj \
-     $(OUT)\rxstat.ss.obj \
-     $(OUT)\rxstat.xdr.obj \
-     $(OUT)\rxstat.cs.obj
- 
- LIBRXKAD_OBJS = $(OUT)\rxkad_client.obj \
-     $(OUT)\rxkad_server.obj \
-     $(OUT)\rxkad_common.obj \
-     $(OUT)\ticket.obj \
-     $(OUT)\ticket5.obj \
-     $(OUT)\crc.obj \
-     $(OUT)\md4.obj \
-     $(OUT)\md5.obj \
- 	$(OUT)\AFS_component_version_number.obj
- 
- LIBRXKAD_REGOBJS = $(OUT)\fcrypt.obj \
-     $(OUT)\crypt_conn.obj
- 
- DESOBJS = $(OUT)\des.obj \
-     $(OUT)\cbc_encrypt.obj \
-     $(OUT)\pcbc_encrypt.obj \
-     $(OUT)\cksum.obj \
-     $(OUT)\new_rnd_key.obj \
- 	$(OUT)\key_sched.obj \
-     $(OUT)\debug_decl.obj \
-     $(OUT)\quad_cksum.obj \
-     $(OUT)\key_parity.obj \
- 	$(OUT)\weak_key.obj \
-     $(OUT)\strng_to_key.obj \
-     $(OUT)\misc.obj \
-     $(OUT)\util.obj
- 
- UTILOBJS = $(OUT)\casestrcpy.obj \
-     $(OUT)\winsock_nt.obj
- 
- COMERROBJS = $(OUT)\error_msg.obj \    
-     $(OUT)\et_name.obj \
-     $(OUT)\com_err.obj
- 
- FSINTOBJS = $(OUT)\afsint.cs.obj \
-     $(OUT)\afsint.xdr.obj \
-     $(OUT)\afscbint.cs.obj \
-     $(OUT)\afscbint.xdr.obj \
- 	$(OUT)\afsaux.obj
- 
- DLLOBJS = $(MULTIOBJS) $(RXOBJS) $(XDROBJS) $(RXSTATOBJS) $(LIBRXKAD_OBJS) \
- 	$(DESOBJS) $(LIBRXKAD_REGOBJS) $(UTILOBJS) $(COMERROBJS) \
- 	$(FSINTOBJS) afsrpc.res
- 
- rx_multi.obj: $(RX)\rx_multi.c
- 	$(C2OBJ) $(RX)\rx_multi.c
- 
- xdr.obj: $(RX)\xdr.c
- 	$(C2OBJ) $(RX)\xdr.c
- 
- xdr_array.obj: $(RX)\xdr_array.c
- 	$(C2OBJ) $(RX)\xdr_array.c
- 
- xdr_arrayn.obj: $(RX)\xdr_arrayn.c
- 	$(C2OBJ) $(RX)\xdr_arrayn.c
- 
- xdr_float.obj: $(RX)\xdr_float.c
- 	$(C2OBJ) $(RX)\xdr_float.c
- 
- xdr_mem.obj: $(RX)\xdr_mem.c
- 	$(C2OBJ) $(RX)\xdr_mem.c
- 
- xdr_rec.obj: $(RX)\xdr_rec.c
- 	$(C2OBJ) $(RX)\xdr_rec.c
- 
- xdr_refernce.obj: $(RX)\xdr_refernce.c
- 	$(C2OBJ) $(RX)\xdr_refernce.c
- 
- xdr_rx.obj: $(RX)\xdr_rx.c
- 	$(C2OBJ) $(RX)\xdr_rx.c
- 
- xdr_update.obj: $(RX)\xdr_update.c
- 	$(C2OBJ) $(RX)\xdr_update.c
- 
- xdr_afsuuid.obj: $(RX)\xdr_afsuuid.c
- 	$(C2OBJ) $(RX)\xdr_afsuuid.c
- 
- xdr_int64.obj: $(RX)\xdr_int64.c
- 	$(C2OBJ) $(RX)\xdr_int64.c
- 
- rx_event.obj: $(RX)\rx_event.c
- 	$(C2OBJ) $(RX)\rx_event.c
- 
- rx_user.obj: $(RX)\rx_user.c
- 	$(C2OBJ) $(RX)\rx_user.c
- 
- rx_pthread.obj: $(RX)\rx_pthread.c
- 	$(C2OBJ) $(RX)\rx_pthread.c
- 
- rx.obj: $(RX)\rx.c
- 	$(C2OBJ) $(RX)\rx.c
- 
- rx_null.obj: $(RX)\rx_null.c
- 	$(C2OBJ) $(RX)\rx_null.c
- 
- rx_globals.obj: $(RX)\rx_globals.c
- 	$(C2OBJ) $(RX)\rx_globals.c
- 
- rx_getaddr.obj: $(RX)\rx_getaddr.c
- 	$(C2OBJ) $(RX)\rx_getaddr.c
- 
- rx_misc.obj: $(RX)\rx_misc.c
- 	$(C2OBJ) $(RX)\rx_misc.c
- 
- rx_packet.obj: $(RX)\rx_packet.c
- 	$(C2OBJ) $(RX)\rx_packet.c
- 
- rx_rdwr.obj: $(RX)\rx_rdwr.c
- 	$(C2OBJ) $(RX)\rx_rdwr.c
- 
- rx_trace.obj: $(RX)\rx_trace.c
- 	$(C2OBJ) $(RX)\rx_trace.c
- 
- rx_xmit_nt.obj: $(RX)\rx_xmit_nt.c
- 	$(C2OBJ) $(RX)\rx_xmit_nt.c
- 
- rx_conncache.obj: $(RX)\rx_conncache.c
- 	$(C2OBJ) $(RX)\rx_conncache.c
- 
- rxstat.cs.obj:$(RXSTAT)\rxstat.cs.c
- 	$(C2OBJ) $(RXSTAT)\rxstat.cs.c
- 
- rxstat.ss.obj:$(RXSTAT)\rxstat.ss.c
- 	$(C2OBJ) $(RXSTAT)\rxstat.ss.c
- 
- rxstat.xdr.obj:$(RXSTAT)\rxstat.xdr.c
- 	$(C2OBJ) $(RXSTAT)\rxstat.xdr.c
- 
- rxstat.obj:$(RXSTAT)\rxstat.c
- 	$(C2OBJ) $(RXSTAT)\rxstat.c
- 
- rxkad_client.obj:$(RXKAD)\rxkad_client.c
- 	$(C2OBJ) $(RXKAD)\rxkad_client.c
- 
- rxkad_server.obj:$(RXKAD)\rxkad_server.c
- 	$(C2OBJ) $(RXKAD)\rxkad_server.c
- 
- rxkad_common.obj:$(RXKAD)\rxkad_common.c
- 	$(C2OBJ) $(RXKAD)\rxkad_common.c
- 
- ticket.obj:$(RXKAD)\ticket.c
- 	$(C2OBJ) $(RXKAD)\ticket.c
- 
- fcrypt.obj:$(RXKAD)\fcrypt.c
- 	$(C2OBJ) $(RXKAD)\fcrypt.c
- 
- crypt_conn.obj:$(RXKAD)\crypt_conn.c
- 	$(C2OBJ) $(RXKAD)\crypt_conn.c
- 
- AFS_component_version_number.obj:$(RXKAD)\AFS_component_version_number.c
- 	$(C2OBJ) $(RXKAD)\AFS_component_version_number.c
- 
- fcrypt_x.obj:$(RXKAD)\fcrypt.c
- 	$(C2OBJ) $(RXKAD)\fcrypt.c /Fofcrypt_x.obj
- 
- crypt_conn_x.obj:$(RXKAD)\crypt_conn.c
- 	$(C2OBJ) $(RXKAD)\crypt_conn.c /Focrypt_conn_x.obj
- 
- des.obj:$(DES)\des.c
- 	$(C2OBJ) $(DES)\des.c
- 
- cbc_encrypt.obj:$(DES)\cbc_encrypt.c
- 	$(C2OBJ) $(DES)\cbc_encrypt.c
- 
- pcbc_encrypt.obj:$(DES)\pcbc_encrypt.c
- 	$(C2OBJ) $(DES)\pcbc_encrypt.c
- 
- cksum.obj:$(DES)\cksum.c
- 	$(C2OBJ) $(DES)\cksum.c
- 
- new_rnd_key.obj:$(DES)\new_rnd_key.c
- 	$(C2OBJ) $(DES)\new_rnd_key.c
- 
- key_sched.obj:$(DES)\key_sched.c
- 	$(C2OBJ) $(DES)\key_sched.c
- 
- debug_decl.obj:$(DES)\debug_decl.c
- 	$(C2OBJ) $(DES)\debug_decl.c
- 
- quad_cksum.obj:$(DES)\quad_cksum.c
- 	$(C2OBJ) $(DES)\quad_cksum.c
- 
- key_parity.obj:$(DES)\key_parity.c
- 	$(C2OBJ) $(DES)\key_parity.c
- 
- weak_key.obj:$(DES)\weak_key.c
- 	$(C2OBJ) $(DES)\weak_key.c
- 
- strng_to_key.obj:$(DES)\strng_to_key.c
- 	$(C2OBJ) $(DES)\strng_to_key.c
- 
- misc.obj:$(DES)\misc.c
- 	$(C2OBJ) -DDONT_INCL_MAIN $(DES)\misc.c
- 
- util.obj:$(DES)\util.c
- 	$(C2OBJ) $(DES)\util.c
- 
- des_x.obj:$(DES)\des.c
- 	$(C2OBJ) $(DES)\des.c /Fodes_x.obj
- 
- cbc_crypt_x.obj:$(DES)\cbc_encrypt.c
- 	$(C2OBJ) $(DES)\cbc_encrypt.c /Focbc_crypt_x.obj
- 
- pcbc_crypt_x.obj:$(DES)\pcbc_encrypt.c
- 	$(C2OBJ) $(DES)\pcbc_encrypt.c /Fopcbc_crypt_x.obj
- 
- cksum_x.obj:$(DES)\cksum.c
- 	$(C2OBJ) $(DES)\cksum.c /Focksum_x.obj
- 
- nrnd_key_x.obj:$(DES)\new_rnd_key.c
- 	$(C2OBJ) $(DES)\new_rnd_key.c /Fonrnd_key_x.obj
- 
- error_msg.obj:$(COMERR)\error_msg.c
- 	$(C2OBJ) $(COMERR)\error_msg.c
- 
- et_name.obj:$(COMERR)\et_name.c
- 	$(C2OBJ) $(COMERR)\et_name.c
- 
- com_err.obj:$(COMERR)\com_err.c
- 	$(C2OBJ) $(COMERR)\com_err.c
- 
- casestrcpy.obj:$(UTIL)\casestrcpy.c
- 	$(C2OBJ) $(UTIL)\casestrcpy.c
- 
- winsock_nt.obj:$(UTIL)\winsock_nt.c
- 	$(C2OBJ) $(UTIL)\winsock_nt.c
- 
- afsint.cs.obj:$(FSINT)\afsint.cs.c
- 	$(C2OBJ) $(FSINT)\afsint.cs.c
- 
- afsint.xdr.obj:$(FSINT)\afsint.xdr.c
- 	$(C2OBJ) $(FSINT)\afsint.xdr.c
- 
- afscbint.cs.obj:$(FSINT)\afscbint.cs.c
- 	$(C2OBJ) $(FSINT)\afscbint.cs.c
- 
- afscbint.xdr.obj:$(FSINT)\afscbint.xdr.c
- 	$(C2OBJ) $(FSINT)\afscbint.xdr.c
- 
- afsaux.obj:$(FSINT)\afsaux.c
- 	$(C2OBJ) $(FSINT)\afsaux.c
- 
- NTMAKE = nmake /nologo /f ntmakefile
- 
- 
- DLLLIBS =\
- !IF (("$(SYS_NAME)"=="i386_win95" ) || ("$(SYS_NAME)"=="I386_WIN95" ))
- 	$(DESTDIR)\lib\win95\afspthread.lib \
- !ELSE
- 	$(DESTDIR)\lib\afspthread.lib \
- !ENDIF
- 	$(DESTDIR)\lib\afs\afsutil.lib \
- 	$(DESTDIR)\lib\afs\afsreg.lib
- 
- $(DESTDIR)\lib\afsrpc.dll: $(DLLOBJS) $(DLLLIBS)
- 	$(DLLCONLINK) /DEF:afsrpc.def
- 	$(DLLPREP)
- 
- # Definitions for generating versioninfo resources
- afsrpc.res: afsrpc.rc AFS_component_version_number.h
- 	$(RC) $*.rc
- 
- 
- install:
- !       IF (EXIST(..\..\src\des\NTMakefile))
- 		$(NTMAKE) $(LIBFILE)
- !	else
- 		$(NTMAKE) libstub
- !	endif
- 
- install9x: install
- 
- !IF (EXIST(..\..\src\des\NTMakefile))
- !ELSE IF (EXIST(..\..\DESLIB))
- DESPAR = ..\..\DESLIB\dest
- !ELSE IF (EXIST(..\..\..\DESLIB))
- DESPAR = ..\..\..\DESLIB\dest
- !ELSE
- !ERROR Must create DESLIB link in the same directory as PARENT link.
- !ENDIF
- 
- libstub:
- 	$(COPY) $(DESPAR)\lib\afsrpc.dll \
- 		$(DESTDIR)\lib\afsrpc.dll
- 	$(COPY) $(DESPAR)\lib\afsrpc.lib \
- 		$(DESTDIR)\lib\afsrpc.lib
- 	$(COPY) $(DESPAR)\lib\afsrpc.exp \
- 		$(DESTDIR)\lib\afsrpc.exp
- 
- clean::
- 	$(DEL) $(DESTDIR)\lib\afsrpc.dll $(DESTDIR)\lib\afsrpc.lib $(DESTDIR)\lib\afsrpc.exp
\ No newline at end of file
--- 0 ----
Index: openafs/src/shlibafsrpc/afsrpc.def
diff -c openafs/src/shlibafsrpc/afsrpc.def:1.1 openafs/src/shlibafsrpc/afsrpc.def:removed
*** openafs/src/shlibafsrpc/afsrpc.def:1.1	Wed Aug 28 02:05:51 2002
--- openafs/src/shlibafsrpc/afsrpc.def	Mon Oct 18 13:53:43 2004
***************
*** 1,200 ****
- EXPORTS
- 	des_check_key_parity			@2
- 	des_fixup_key_parity			@5
- 	des_init_random_number_generator	@6
- 	des_is_weak_key				@7
- 	des_key_sched				@8
- 	des_random_key				@9
- 	des_string_to_key			@10
- 	ktohl					@11
- 	life_to_time				@12
- 	rx_DestroyConnection			@13
- 	rx_EndCall				@14
- 	rx_Finalize				@15
- 	rx_GetCachedConnection			@16
- 	rx_GetCall				@17
- 	rx_GetIFInfo				@18
- 	rx_Init					@19
- 	rx_NewCall				@20
- 	rx_NewConnection			@21
- 	rx_NewService				@22
- 	rx_PrintPeerStats			@23
- 	rx_PrintStats				@24
- 	rx_PrintTheseStats			@25
- 	rx_ReadProc				@26
- 	rx_ReleaseCachedConnection		@27
- 	rx_ServerProc				@28
- 	rx_StartServer				@29
- 	rx_WriteProc				@30
- 	rxevent_Init				@31
- 	rxevent_Post				@32
- 	rxkad_GetServerInfo			@33
- 	rxkad_NewClientSecurityObject		@34
- 	rxkad_NewServerSecurityObject		@35
- 	rxnull_NewClientSecurityObject		@38
- 	rxnull_NewServerSecurityObject		@39
- 	rxs_Release				@40
- 	time_to_life				@41
- 	tkt_CheckTimes				@42
- 	tkt_DecodeTicket			@43
- 	tkt_MakeTicket				@44
- 	xdr_array				@45
- 	xdr_bool				@46
- 	xdr_bytes				@47
- 	xdr_char				@48
- 	xdr_double				@49
- 	xdr_enum				@50
- 	xdr_float				@51
- 	xdr_int					@52
- 	xdr_long				@53
- 	xdr_opaque				@54
- 	xdr_pointer				@55
- 	xdr_reference				@56
- 	xdr_short				@57
- 	xdr_string				@58
- 	xdr_u_char				@59
- 	xdr_u_int				@60
- 	xdr_u_long				@61
- 	xdr_u_short				@62
- 	xdr_union				@63
- 	xdr_vector				@64
- 	xdr_void				@65
- 	xdr_wrapstring				@66
- 	xdrmem_create				@67
- 	xdrrec_create				@68
- 	xdrrec_endofrecord			@69
- 	xdrrec_eof				@70
- 	xdrrec_skiprecord			@71
- 	xdrrx_create				@72
- 	hton_syserr_conv			@73
- 	rxkad_stats				@74 DATA
- 	com_err					@75
- 	error_message				@76
- 	rx_socket				@77 DATA
- 	AssertionFailed				@79
- 	afs_winsockInit				@80
- 	rxevent_debugFile			@81 DATA
- 	rx_debugFile				@82 DATA
- 	rx_connDeadTime				@83 DATA
- 	rx_maxReceiveSize			@84 DATA
- 	rx_UdpBufSize				@85 DATA
- 	rx_extraQuota				@86 DATA
- 	rx_extraPackets				@87 DATA
- 	rx_tranquil				@88 DATA
- 	rx_getAllAddr				@89
- 	rx_nWaiting				@90 DATA
- 	rx_stats				@91 DATA
- 	rx_SetNoJumbo				@92
- 	rx_SetConnDeadTime			@93
- 	rx_FlushWrite				@94
- 	rx_thread_id_key			@95 DATA
- 	multi_Finalize				@96
- 	multi_Select				@97
- 	multi_Init				@98
- 	multi_Finalize_Ignore			@99
- 	add_to_error_table			@100
- 	xdr_afsUUID				@101
- 	rx_GetSpecific				@102
- 	rx_SetSpecific				@103
- 	rx_KeyCreate				@104
- 	rx_BusyError				@105 DATA
- 	rx_BusyThreshold			@106 DATA
- 	rx_IncrementTimeAndCount		@107
- 	rx_enable_stats				@108 DATA
- 	rx_GetServerDebug			@109
- 	rx_GetServerStats			@110
- 	rx_GetServerVersion			@111
- 	rx_GetServerConnections			@112
- 	rx_stats_mutex				@113 DATA
- 	rx_GetServerPeers			@114
- 	rx_RetrieveProcessRPCStats		@115
- 	rx_RetrievePeerRPCStats			@116
- 	rx_FreeRPCStats				@117
- 	rx_queryProcessRPCStats			@118
- 	rx_queryPeerRPCStats			@119
- 	rx_enableProcessRPCStats		@120
- 	rx_enablePeerRPCStats			@121
- 	rx_disableProcessRPCStats		@122
- 	rx_disablePeerRPCStats			@123
- 	RXSTATS_ExecuteRequest			@124
- 	RXSTATS_RetrieveProcessRPCStats		@125
- 	RXSTATS_RetrievePeerRPCStats		@126
- 	RXSTATS_QueryProcessRPCStats		@127
- 	RXSTATS_QueryPeerRPCStats		@128
- 	RXSTATS_EnableProcessRPCStats		@129
- 	RXSTATS_EnablePeerRPCStats		@130
- 	RXSTATS_DisableProcessRPCStats		@131
- 	RXSTATS_DisablePeerRPCStats		@132
- 	RXSTATS_QueryRPCStatsVersion		@133
- 	RXSTATS_ClearProcessRPCStats		@134
- 	RXSTATS_ClearPeerRPCStats		@135
- 
- 
- 	rxi_connAbortThreshhold			@138 DATA
- 	rxi_connAbortDelay			@139 DATA
- 	rxi_callAbortThreshhold			@140 DATA
- 	rxi_callAbortDelay			@141 DATA
- 	RXSTATS_function_names			@142 DATA
- 	RXAFSCB_function_names			@143 DATA
- 	RXAFSCB_CallBack			@144
- 	StartRXAFSCB_CallBack			@145
- 	EndRXAFSCB_CallBack			@146
- 	RXAFSCB_InitCallBackState		@147
- 	RXAFSCB_Probe				@148
- 	StartRXAFSCB_Probe			@149
- 	EndRXAFSCB_Probe			@150
- 	RXAFSCB_GetLock				@151
- 	RXAFSCB_GetCE				@152
- 	RXAFSCB_XStatsVersion			@153
- 	RXAFSCB_GetXStats			@154
- 	RXAFSCB_InitCallBackState2		@155
- 	RXAFSCB_WhoAreYou			@156
- 	RXAFSCB_InitCallBackState3		@157
- 	RXAFSCB_ProbeUuid			@158
- 	StartRXAFSCB_ProbeUuid			@159
- 	EndRXAFSCB_ProbeUuid			@160
- 	RXAFSCB_GetServerPrefs			@161
- 	RXAFSCB_GetCellServDB			@162
- 	RXAFSCB_GetLocalCell			@163
- 	RXAFSCB_GetCacheConfig			@164
- 	StartRXAFS_FetchData			@165
- 	EndRXAFS_FetchData			@166
- 	RXAFS_FetchACL				@167
- 	RXAFS_FetchStatus			@168
- 	StartRXAFS_StoreData			@169
- 	EndRXAFS_StoreData			@170
- 	RXAFS_StoreACL				@171
- 	RXAFS_StoreStatus			@172
- 	RXAFS_RemoveFile			@173
- 	RXAFS_CreateFile			@174
- 	RXAFS_Rename				@175
- 	RXAFS_Symlink				@176
- 	RXAFS_Link				@177
- 	RXAFS_MakeDir				@178
- 	RXAFS_RemoveDir				@179
- 	RXAFS_OldSetLock			@180
- 	RXAFS_OldExtendLock			@181
- 	RXAFS_OldReleaseLock			@182
- 	RXAFS_GetStatistics			@183
- 	RXAFS_GiveUpCallBacks			@184
- 	RXAFS_GetVolumeInfo			@185
- 	RXAFS_GetVolumeStatus			@186
- 	RXAFS_SetVolumeStatus			@187
- 	RXAFS_GetRootVolume			@188
- 	RXAFS_CheckToken			@189
- 	RXAFS_GetTime				@190
- 	RXAFS_NGetVolumeInfo			@191
- 	RXAFS_BulkStatus			@192
- 	RXAFS_SetLock				@193
- 	RXAFS_ExtendLock			@194
- 	RXAFS_ReleaseLock			@195
- 	RXAFS_XStatsVersion			@196
- 	RXAFS_GetXStats				@197
- 	RXAFS_Lookup				@198
- 	RXAFS_FlushCPS				@199
- 	RXAFS_DFSSymlink			@200
- 	rx_SetRxStatUserOk			@201
- 	rx_RxStatUserOk				@202
- 	rx_enable_hot_thread			@203 DATA
- 	xdr_int64				@204
- 	xdr_uint64				@205
--- 0 ----
Index: openafs/src/shlibafsrpc/afsrpc.rc
diff -c openafs/src/shlibafsrpc/afsrpc.rc:1.2 openafs/src/shlibafsrpc/afsrpc.rc:removed
*** openafs/src/shlibafsrpc/afsrpc.rc:1.2	Thu Jun 19 15:02:48 2003
--- openafs/src/shlibafsrpc/afsrpc.rc	Mon Oct 18 13:53:43 2004
***************
*** 1,18 ****
- /*
-  * 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
-  */
- 
- /* Define VERSIONINFO resource */
- 
- #define  AFS_VERINFO_FILE_DESCRIPTION "AFS Rx RPC DLL"
- #define AFS_VERINFO_DLL
- #define  AFS_VERINFO_NAME "afsrpc"
- #define  AFS_VERINFO_FILENAME "afsrpc.dll"
- 
- #include "AFS_component_version_number.h"
- #include "..\config\NTVersioninfo.rc"
--- 0 ----
Index: openafs/src/sys/pioctl_nt.c
diff -c openafs/src/sys/pioctl_nt.c:1.18 openafs/src/sys/pioctl_nt.c:1.18.2.2
*** openafs/src/sys/pioctl_nt.c:1.18	Thu Aug  5 12:28:10 2004
--- openafs/src/sys/pioctl_nt.c	Mon Oct 18 13:44:02 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/sys/pioctl_nt.c,v 1.18 2004/08/05 16:28:10 jaltman Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;windows.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/sys/pioctl_nt.c,v 1.18.2.2 2004/10/18 17:44:02 shadow Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;windows.h&gt;
***************
*** 98,103 ****
--- 98,127 ----
      rp-&gt;nbytes = 0;
  }
  
+ static BOOL
+ IoctlDebug(void)
+ {
+     static int init = 0;
+     static BOOL debug = 0;
+ 
+     if ( !init ) {
+         HKEY hk;
+ 
+         if (RegOpenKey (HKEY_LOCAL_MACHINE, 
+                          TEXT("Software\\OpenAFS\\Client"), &amp;hk) == 0)
+         {
+             DWORD dwSize = sizeof(BOOL);
+             DWORD dwType = REG_DWORD;
+             RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &amp;dwType, (PBYTE)&amp;debug, &amp;dwSize);
+             RegCloseKey (hk);
+         }
+ 
+         init = 1;
+     }
+ 
+     return debug;
+ }
+ 
  static long
  GetIoctlHandle(char *fileNamep, HANDLE * handlep)
  {
***************
*** 150,157 ****
                  strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
              }
          }
! 	}
! 	if (!tbuffer[0]) {
          /* No file name starting with drive colon specified, use UNC name */
          lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
          sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
--- 174,181 ----
                  strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
              }
          }
!     }
!     if (!tbuffer[0]) {
          /* No file name starting with drive colon specified, use UNC name */
          lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
          sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
***************
*** 163,178 ****
  		    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  		    FILE_FLAG_WRITE_THROUGH, NULL);
      fflush(stdout);
! 	if (fh == INVALID_HANDLE_VALUE) {
          HKEY hk;
          char szUser[64] = "";
          char szClient[MAX_PATH] = "";
          char szPath[MAX_PATH] = "";
          NETRESOURCE nr;
          DWORD res;
  
!         if (GetLastError() != ERROR_DOWNGRADE_DETECTED)
!             return -1;
  
          lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
          sprintf(szPath, "\\\\%s", szClient);
--- 187,220 ----
  		    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  		    FILE_FLAG_WRITE_THROUGH, NULL);
      fflush(stdout);
!     if (fh == INVALID_HANDLE_VALUE) {
          HKEY hk;
          char szUser[64] = "";
          char szClient[MAX_PATH] = "";
          char szPath[MAX_PATH] = "";
          NETRESOURCE nr;
          DWORD res;
+         DWORD ioctlDebug = IoctlDebug();
+         DWORD gle;
  
!         gle = GetLastError();
!         if (gle &amp;&amp; ioctlDebug ) {
!             char buf[4096];
! 
!             if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
!                                NULL,
!                                gle,
!                                MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
!                                buf,
!                                4096,
!                                (va_list *) NULL
!                                ) )
!             {
!                 fprintf(stderr,"pioctl CreateFile(%s) failed: [%s]\r\n",tbuffer,buf);
!             }
!         }
!         if (gle != ERROR_DOWNGRADE_DETECTED)
!             return -1;                                   
  
          lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
          sprintf(szPath, "\\\\%s", szClient);
***************
*** 186,207 ****
              RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &amp;dwType, (PBYTE)szUser, &amp;dwSize);
              RegCloseKey (hk);
          }
  
          memset (&amp;nr, 0x00, sizeof(NETRESOURCE));
          nr.dwType=RESOURCETYPE_DISK;
          nr.lpLocalName=0;
          nr.lpRemoteName=szPath;
          res = WNetAddConnection2(&amp;nr,NULL,szUser,0);
!         if (res)
              return -1;
  
          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)
              return -1;
! 	}
  
      /* return fh and success code */
      *handlep = fh;
--- 228,273 ----
              RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &amp;dwType, (PBYTE)szUser, &amp;dwSize);
              RegCloseKey (hk);
          }
+         if ( ioctlDebug )
+             fprintf(stderr, "pioctl logon user: [%s]\r\n",szUser);
  
          memset (&amp;nr, 0x00, sizeof(NETRESOURCE));
          nr.dwType=RESOURCETYPE_DISK;
          nr.lpLocalName=0;
          nr.lpRemoteName=szPath;
          res = WNetAddConnection2(&amp;nr,NULL,szUser,0);
!         if (res) {
!             if ( ioctlDebug ) {
!                 fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
!                          szPath,szUser,res);
!             }
              return -1;
+         }
  
          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) {
!             gle = GetLastError();
!             if (gle &amp;&amp; ioctlDebug ) {
!                 char buf[4096];
! 
!                 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
!                                     NULL,
!                                     gle,
!                                     MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
!                                     buf,
!                                     4096,
!                                     (va_list *) NULL
!                                     ) )
!                 {
!                     fprintf(stderr,"pioctl CreateFile(%s) failed: [%s]\r\n",tbuffer,buf);
!                 }
!             }
              return -1;
!         }
!     }
  
      /* return fh and success code */
      *handlep = fh;
***************
*** 213,231 ****
  {
      long rcount;
      long ioCount;
  
      rcount = reqp-&gt;mp - reqp-&gt;data;
!     if (rcount &lt;= 0)
  	return EINVAL;		/* not supposed to happen */
  
      if (!WriteFile(handle, reqp-&gt;data, rcount, &amp;ioCount, NULL)) {
  	/* failed to write */
! 	return GetLastError();
      }
  
      if (!ReadFile(handle, reqp-&gt;data, sizeof(reqp-&gt;data), &amp;ioCount, NULL)) {
  	/* failed to read */
! 	return GetLastError();
      }
  
      reqp-&gt;nbytes = ioCount;	/* set # of bytes available */
--- 279,309 ----
  {
      long rcount;
      long ioCount;
+     DWORD gle;
  
      rcount = reqp-&gt;mp - reqp-&gt;data;
!     if (rcount &lt;= 0) {
!         if ( IoctlDebug() )
!             fprintf(stderr, "pioctl Transceive rcount &lt;= 0: %d\r\n",rcount);
  	return EINVAL;		/* not supposed to happen */
+     }
  
      if (!WriteFile(handle, reqp-&gt;data, rcount, &amp;ioCount, NULL)) {
  	/* failed to write */
! 	gle = GetLastError();
! 
!         if ( IoctlDebug() )
!             fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
!         return gle;
      }
  
      if (!ReadFile(handle, reqp-&gt;data, sizeof(reqp-&gt;data), &amp;ioCount, NULL)) {
  	/* failed to read */
! 	gle = GetLastError();
! 
!         if ( IoctlDebug() )
!             fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
!         return gle;
      }
  
      reqp-&gt;nbytes = ioCount;	/* set # of bytes available */
***************
*** 248,253 ****
--- 326,334 ----
  {
      /* not enough data left */
      if (reqp-&gt;nbytes &lt; 4) {
+         if ( IoctlDebug() )
+             fprintf(stderr, "pioctl UnmarshallLong reqp-&gt;nbytes &lt; 4: %d\r\n",
+                      reqp-&gt;nbytes);
  	return -1;
      }
  
***************
*** 269,276 ****
  	count = 1;
  
      /* watch for buffer overflow */
!     if ((reqp-&gt;mp - reqp-&gt;data) + count &gt; sizeof(reqp-&gt;data))
  	return -1;
  
      if (stringp)
  	memcpy(reqp-&gt;mp, stringp, count);
--- 350,360 ----
  	count = 1;
  
      /* watch for buffer overflow */
!     if ((reqp-&gt;mp - reqp-&gt;data) + count &gt; sizeof(reqp-&gt;data)) {
!         if ( IoctlDebug() )
!             fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
  	return -1;
+     }
  
      if (stringp)
  	memcpy(reqp-&gt;mp, stringp, count);
***************
*** 338,352 ****
  	newPath[2] = 0;
  	if (!SetCurrentDirectory(newPath)) {
  	    code = GetLastError();
  	    return code;
  	}
      }
  
      /* now get the absolute path to the current wdir in this drive */
      GetCurrentDirectory(sizeof(tpath), tpath);
! 	if (tpath[1] == ':')
! 	    strcpy(outPathp, tpath + 2);	/* skip drive letter */
! 	else if ( tpath[0] == '\\' &amp;&amp; tpath[1] == '\\') {
          /* UNC path - strip off the server and sharename */
          int i, count;
          for ( i=2,count=2; count &lt; 4 &amp;&amp; tpath[i]; i++ ) {
--- 422,440 ----
  	newPath[2] = 0;
  	if (!SetCurrentDirectory(newPath)) {
  	    code = GetLastError();
+ 
+             if ( IoctlDebug() )
+                 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
+                          newPath, code);
  	    return code;
  	}
      }
  
      /* now get the absolute path to the current wdir in this drive */
      GetCurrentDirectory(sizeof(tpath), tpath);
!     if (tpath[1] == ':')
!         strcpy(outPathp, tpath + 2);	/* skip drive letter */
!     else if ( tpath[0] == '\\' &amp;&amp; tpath[1] == '\\') {
          /* UNC path - strip off the server and sharename */
          int i, count;
          for ( i=2,count=2; count &lt; 4 &amp;&amp; tpath[i]; i++ ) {
***************
*** 366,375 ****
  
      /* if there is a non-null name after the drive, append it */
      if (*firstp != 0) {
! 		int len = strlen(outPathp);
! 		if (outPathp[len-1] != '\\' &amp;&amp; outPathp[len-1] != '/') 
! 			strcat(outPathp, "\\");
! 		strcat(outPathp, firstp);
      }
  
      /* finally, if necessary, switch back to our home drive letter */
--- 454,463 ----
  
      /* if there is a non-null name after the drive, append it */
      if (*firstp != 0) {
!         int len = strlen(outPathp);
!         if (outPathp[len-1] != '\\' &amp;&amp; outPathp[len-1] != '/') 
!             strcat(outPathp, "\\");
!         strcat(outPathp, firstp);
      }
  
      /* finally, if necessary, switch back to our home drive letter */
***************
*** 433,442 ****
      }
  
      /* now unmarshall the return value */
!     UnmarshallLong(&amp;preq, &amp;temp);
      if (temp != 0) {
  	CloseHandle(reqHandle);
  	errno = CMtoUNIXerror(temp);
  	return -1;
      }
  
--- 521,536 ----
      }
  
      /* now unmarshall the return value */
!     if (UnmarshallLong(&amp;preq, &amp;temp) != 0) {
!         CloseHandle(reqHandle);
!         return -1;
!     }
! 
      if (temp != 0) {
  	CloseHandle(reqHandle);
  	errno = CMtoUNIXerror(temp);
+         if ( IoctlDebug() )
+             fprintf(stderr, "pioctl temp != 0: %d\r\n",temp);
  	return -1;
      }
  
Index: openafs/src/ubik/Makefile.in
diff -c openafs/src/ubik/Makefile.in:1.11 openafs/src/ubik/Makefile.in:1.11.2.1
*** openafs/src/ubik/Makefile.in:1.11	Sat Jan 11 02:34:58 2003
--- openafs/src/ubik/Makefile.in	Mon Oct 18 03:12:16 2004
***************
*** 10,16 ****
  
  LIBOBJS=disk.o  remote.o beacon.o recovery.o ubik.o  vote.o lock.o phys.o \
  	ubik_int.cs.o ubik_int.ss.o ubik_int.xdr.o ubikcmd.o \
! 	ubikclient.o uerrors.o
  
  INCLS=${TOP_INCDIR}/lwp.h ${TOP_INCDIR}/lock.h \
  	${TOP_INCDIR}/rx/rx.h ${TOP_INCDIR}/rx/xdr.h \
--- 10,16 ----
  
  LIBOBJS=disk.o  remote.o beacon.o recovery.o ubik.o  vote.o lock.o phys.o \
  	ubik_int.cs.o ubik_int.ss.o ubik_int.xdr.o ubikcmd.o \
! 	ubikclient.o uerrors.o uinit.o
  
  INCLS=${TOP_INCDIR}/lwp.h ${TOP_INCDIR}/lock.h \
  	${TOP_INCDIR}/rx/rx.h ${TOP_INCDIR}/rx/xdr.h \
***************
*** 99,104 ****
--- 99,105 ----
  	$(RANLIB) $@
  
  disk.o: disk.c ${INCLS}
+ uinit.o: uinit.c ${INCLS}
  remote.o: remote.c ${INCLS}
  beacon.o: beacon.c ${INCLS}
  lock.o: lock.c ${INCLS}
Index: openafs/src/ubik/NTMakefile
diff -c openafs/src/ubik/NTMakefile:1.6 openafs/src/ubik/NTMakefile:1.6.2.1
*** openafs/src/ubik/NTMakefile:1.6	Fri Nov 21 03:01:28 2003
--- openafs/src/ubik/NTMakefile	Mon Oct 18 03:12:16 2004
***************
*** 31,36 ****
--- 31,37 ----
  	$(OUT)\beacon.obj \
  	$(OUT)\recovery.obj \
  	$(OUT)\ubik.obj \
+ 	$(OUT)\uinit.obj \
  	$(OUT)\vote.obj \
  	$(OUT)\lock.obj \
  	$(OUT)\phys.obj \
Index: openafs/src/ubik/beacon.c
diff -c openafs/src/ubik/beacon.c:1.19.2.2 openafs/src/ubik/beacon.c:1.19.2.3
*** openafs/src/ubik/beacon.c:1.19.2.2	Wed Aug 25 03:11:03 2004
--- openafs/src/ubik/beacon.c	Mon Oct 18 13:44:03 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/ubik/beacon.c,v 1.19.2.2 2004/08/25 07:11:03 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #ifdef AFS_NT40_ENV
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/ubik/beacon.c,v 1.19.2.3 2004/10/18 17:44:03 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #ifdef AFS_NT40_ENV
***************
*** 569,576 ****
      for (j = 0, found = 0; j &lt; count; j++) {
  	for (i = 0; i &lt; totalServers; i++) {
  	    if (info)
! 		tmpAddr =
! 		    (afs_uint32) info-&gt;hostAddr[i].sin_addr.s_addr;
  	    else
  		tmpAddr = aservers[i];
  	    if (myAddr[j] == tmpAddr) {
--- 569,575 ----
      for (j = 0, found = 0; j &lt; count; j++) {
  	for (i = 0; i &lt; totalServers; i++) {
  	    if (info)
! 		tmpAddr = (afs_uint32) info-&gt;hostAddr[i].sin_addr.s_addr;
  	    else
  		tmpAddr = aservers[i];
  	    if (myAddr[j] == tmpAddr) {
Index: openafs/src/ubik/ubik.p.h
diff -c openafs/src/ubik/ubik.p.h:1.11.2.1 openafs/src/ubik/ubik.p.h:1.11.2.2
*** openafs/src/ubik/ubik.p.h:1.11.2.1	Wed Aug 25 03:09:43 2004
--- openafs/src/ubik/ubik.p.h	Mon Oct 18 13:44:03 2004
***************
*** 359,362 ****
--- 359,373 ----
  			   afs_int32 transMode, struct ubik_trans **transPtr);
  extern int ubik_EndTrans(register struct ubik_trans *transPtr);
  
+ /* uinit.c */
+ 
+ extern afs_int32 ugen_ClientInit(int noAuthFlag, char *confDir, char *cellName,
+ 				 afs_int32 sauth, 
+ 				 struct ubik_client **uclientp,
+ 				 int (*secproc) (), char *funcName, 
+ 				 afs_int32 gen_rxkad_level, 
+ 				 afs_int32 maxservers, afs_int32 serviceid, 
+ 				 afs_int32 deadtime, afs_uint32 server, 
+ 				 afs_uint32 port, afs_int32 usrvid);
+ 
  #endif /* UBIK_H */
Index: openafs/src/ubik/udebug.c
diff -c openafs/src/ubik/udebug.c:1.16 openafs/src/ubik/udebug.c:1.16.2.1
*** openafs/src/ubik/udebug.c:1.16	Thu Jan  1 00:56:25 2004
--- openafs/src/ubik/udebug.c	Mon Oct 18 03:12:16 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/ubik/udebug.c,v 1.16 2004/01/01 05:56:25 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;stdlib.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/ubik/udebug.c,v 1.16.2.1 2004/10/18 07:12:16 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;stdlib.h&gt;
***************
*** 97,103 ****
      register afs_int32 i, j, code;
      short port;
      int int32p;
!     afs_int32 now, diff, newtime;
      struct hostent *th;
      struct rx_connection *tconn;
      struct rx_securityClass *sc;
--- 97,103 ----
      register afs_int32 i, j, code;
      short port;
      int int32p;
!     time_t now, diff, newtime;
      struct hostent *th;
      struct rx_connection *tconn;
      struct rx_securityClass *sc;
Index: openafs/src/ubik/uinit.c
diff -c /dev/null openafs/src/ubik/uinit.c:1.6.2.1
*** /dev/null	Mon Oct 18 13:53:43 2004
--- openafs/src/ubik/uinit.c	Mon Oct 18 03:12:16 2004
***************
*** 0 ****
--- 1,206 ----
+ /*
+  * 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 &lt;afsconfig.h&gt;
+ #include &lt;afs/param.h&gt;
+ 
+ RCSID
+     ("$Header: /cvs/openafs/src/ubik/uinit.c,v 1.6.2.1 2004/10/18 07:12:16 shadow Exp $");
+ 
+ #include &lt;afs/stds.h&gt;
+ #ifdef AFS_NT40_ENV
+ #include &lt;fcntl.h&gt;
+ #include &lt;winsock2.h&gt;
+ #else
+ #include &lt;sys/types.h&gt;
+ #include &lt;sys/file.h&gt;
+ #include &lt;netdb.h&gt;
+ #include &lt;netinet/in.h&gt;
+ #endif /* AFS_NT40_ENV */
+ #include &lt;sys/stat.h&gt;
+ #ifdef AFS_AIX_ENV
+ #include &lt;sys/statfs.h&gt;
+ #endif
+ 
+ #ifdef HAVE_STRING_H
+ #include &lt;string.h&gt;
+ #else
+ #ifdef HAVE_STRINGS_H
+ #include &lt;strings.h&gt;
+ #endif
+ #endif
+ 
+ #include &lt;afs/dirpath.h&gt;
+ #include &lt;errno.h&gt;
+ #include &lt;lock.h&gt;
+ #include &lt;rx/xdr.h&gt;
+ #include &lt;rx/rx.h&gt;
+ #include &lt;rx/rx_globals.h&gt;
+ #include &lt;afs/auth.h&gt;
+ #include &lt;afs/cellconfig.h&gt;
+ #include &lt;afs/keys.h&gt;
+ #include &lt;ubik.h&gt;
+ #include &lt;afs/afsint.h&gt;
+ #include &lt;afs/cmd.h&gt;
+ #include &lt;rx/rxkad.h&gt;
+ 
+ /*
+   Get the appropriate type of ubik client structure out from the system.
+ */
+ afs_int32
+ ugen_ClientInit(int noAuthFlag, char *confDir, char *cellName, afs_int32 sauth,
+ 	       struct ubik_client **uclientp, int (*secproc) (),
+ 	       char *funcName, afs_int32 gen_rxkad_level, 
+ 	       afs_int32 maxservers, afs_int32 serviceid, afs_int32 deadtime,
+ 	       afs_uint32 server, afs_uint32 port, afs_int32 usrvid)
+ {
+     afs_int32 code, scIndex, i;
+     struct afsconf_cell info;
+     struct afsconf_dir *tdir;
+     struct ktc_principal sname;
+     struct ktc_token ttoken;
+     struct rx_securityClass *sc;
+     /* This must change if VLDB_MAXSERVERS becomes larger than MAXSERVERS */
+     static struct rx_connection *serverconns[MAXSERVERS];
+     char cellstr[64];
+ 
+     code = rx_Init(0);
+     if (code) {
+ 	fprintf(stderr, "%s: could not initialize rx.\n", funcName);
+ 	return code;
+     }
+     rx_SetRxDeadTime(deadtime);
+ 
+     if (sauth) {		/* -localauth */
+ 	tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
+ 	if (!tdir) {
+ 	    fprintf(stderr,
+ 		    "%s: Could not process files in configuration directory (%s).\n",
+ 		    funcName, AFSDIR_SERVER_ETC_DIRPATH);
+ 	    return -1;
+ 	}
+ 	code = afsconf_ClientAuth(tdir, &amp;sc, &amp;scIndex);	/* sets sc,scIndex */
+ 	if (code) {
+ 	    fprintf(stderr,
+ 		    "%s: Could not get security object for -localAuth\n",
+ 		    funcName);
+ 	    return -1;
+ 	}
+ 	code =
+ 	    afsconf_GetCellInfo(tdir, tdir-&gt;cellName, serviceid,
+ 				&amp;info);
+ 	if (code) {
+ 	    fprintf(stderr,
+ 		    "%s: can't find cell %s's hosts in %s/%s\n",
+ 		    funcName, cellName, AFSDIR_SERVER_ETC_DIRPATH,
+ 		    AFSDIR_CELLSERVDB_FILE);
+ 	    exit(1);
+ 	}
+     } else {			/* not -localauth */
+ 	tdir = afsconf_Open(confDir);
+ 	if (!tdir) {
+ 	    fprintf(stderr,
+ 		    "%s: Could not process files in configuration directory (%s).\n",
+ 		    funcName, confDir);
+ 	    return -1;
+ 	}
+ 
+ 	if (!cellName) {
+ 	    code = afsconf_GetLocalCell(tdir, cellstr, sizeof(cellstr));
+ 	    if (code) {
+ 		fprintf(stderr,
+ 			"%s: can't get local cellname, check %s/%s\n",
+ 			funcName, confDir, AFSDIR_THISCELL_FILE);
+ 		exit(1);
+ 	    }
+ 	    cellName = cellstr;
+ 	}
+ 
+ 	code =
+ 	    afsconf_GetCellInfo(tdir, cellName, serviceid, &amp;info);
+ 	if (code) {
+ 	    fprintf(stderr,
+ 		    "%s: can't find cell %s's hosts in %s/%s\n",
+ 		    funcName, cellName, confDir, AFSDIR_CELLSERVDB_FILE);
+ 	    exit(1);
+ 	}
+ 	if (noAuthFlag)		/* -noauth */
+ 	    scIndex = 0;
+ 	else {			/* not -noauth */
+ 	    strcpy(sname.cell, info.name);
+ 	    sname.instance[0] = 0;
+ 	    strcpy(sname.name, "afs");
+ 	    code = ktc_GetToken(&amp;sname, &amp;ttoken, sizeof(ttoken), NULL);
+ 	    if (code) {		/* did not get ticket */
+ 		fprintf(stderr,
+ 			"%s: Could not get afs tokens, running unauthenticated.\n",
+ 			funcName);
+ 		scIndex = 0;
+ 	    } else {		/* got a ticket */
+ 		scIndex = 2;
+ 		if ((ttoken.kvno &lt; 0) || (ttoken.kvno &gt; 256)) {
+ 		    fprintf(stderr,
+ 			    "%s: funny kvno (%d) in ticket, proceeding\n",
+ 			    funcName, ttoken.kvno);
+ 		}
+ 	    }
+ 	}
+ 
+ 	switch (scIndex) {
+ 	case 0:
+ 	    sc = rxnull_NewClientSecurityObject();
+ 	    break;
+ 	case 2:
+ 	    sc = rxkad_NewClientSecurityObject(gen_rxkad_level,
+ 					       &amp;ttoken.sessionKey,
+ 					       ttoken.kvno, ttoken.ticketLen,
+ 					       ttoken.ticket);
+ 	    break;
+ 	default:
+ 	    fprintf(stderr, "%s: unsupported security index %d\n",
+ 		    funcName, scIndex);
+ 	    exit(1);
+ 	    break;
+ 	}
+     }
+ 
+     afsconf_Close(tdir);
+ 
+     if (secproc)	/* tell UV module about default authentication */
+ 	(*secproc) (sc, scIndex);
+     if (server) {
+ 	serverconns[0] = rx_NewConnection(server, port,
+ 					  usrvid, sc, scIndex);
+     } else {
+ 	if (info.numServers &gt; maxservers) {
+ 	    fprintf(stderr,
+ 		    "%s: info.numServers=%d (&gt; maxservers=%d)\n",
+ 		    funcName, info.numServers, maxservers);
+ 	    exit(1);
+ 	}
+ 	for (i = 0; i &lt; info.numServers; i++) {
+ 	    serverconns[i] =
+ 		rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
+ 				 info.hostAddr[i].sin_port, usrvid,
+ 				 sc, scIndex);
+ 	}
+     }
+     /* Are we just setting up connections, or is this really ubik stuff? */
+     if (uclientp) {
+ 	*uclientp = 0;
+ 	code = ubik_ClientInit(serverconns, uclientp);
+ 	if (code) {
+ 	    fprintf(stderr, "%s: ubik client init failed.\n", funcName);
+ 	    return code;
+ 	}
+     }
+     return 0;
+ }
+ 
+ 
Index: openafs/src/util/Makefile.in
diff -c openafs/src/util/Makefile.in:1.24 openafs/src/util/Makefile.in:1.24.2.1
*** openafs/src/util/Makefile.in:1.24	Wed Sep  3 12:47:19 2003
--- openafs/src/util/Makefile.in	Mon Oct 18 03:12:17 2004
***************
*** 62,71 ****
  	$(RANLIB) util.a
  
  assert.o: ${srcdir}/assert.c ${includes}
! 	${CC} ${CFLAGS} -c ${srcdir}/assert.c
  
  casestrcpy.o: ${srcdir}/casestrcpy.c ${includes}
! 	${CC} ${CFLAGS} -c ${srcdir}/casestrcpy.c
  
  hputil.o: ${srcdir}/hputil.c ${includes}
  	${CC} ${CFLAGS} -c ${srcdir}/hputil.c
--- 62,71 ----
  	$(RANLIB) util.a
  
  assert.o: ${srcdir}/assert.c ${includes}
! 	${CCOBJ} ${CFLAGS} -c ${srcdir}/assert.c
  
  casestrcpy.o: ${srcdir}/casestrcpy.c ${includes}
! 	${CCOBJ} ${CFLAGS} -c ${srcdir}/casestrcpy.c
  
  hputil.o: ${srcdir}/hputil.c ${includes}
  	${CC} ${CFLAGS} -c ${srcdir}/hputil.c
***************
*** 110,119 ****
  	${CC} ${CFLAGS} -c ${srcdir}/serverLog.c
  
  dirpath.o: ${srcdir}/dirpath.c ${includes}
! 	${CC} ${CFLAGS} -c ${srcdir}/dirpath.c
  
  fileutil.o: ${srcdir}/fileutil.c ${includes}
! 	${CC} ${CFLAGS} -c ${srcdir}/fileutil.c
  
  netutils.o: ${srcdir}/netutils.c ${includes}
  	${CC} ${CFLAGS} -c ${srcdir}/netutils.c
--- 110,119 ----
  	${CC} ${CFLAGS} -c ${srcdir}/serverLog.c
  
  dirpath.o: ${srcdir}/dirpath.c ${includes}
! 	${CCOBJ} ${CFLAGS} -c ${srcdir}/dirpath.c
  
  fileutil.o: ${srcdir}/fileutil.c ${includes}
! 	${CCOBJ} ${CFLAGS} -c ${srcdir}/fileutil.c
  
  netutils.o: ${srcdir}/netutils.c ${includes}
  	${CC} ${CFLAGS} -c ${srcdir}/netutils.c
Index: openafs/src/util/ktime.c
diff -c openafs/src/util/ktime.c:1.10 openafs/src/util/ktime.c:1.10.2.1
*** openafs/src/util/ktime.c:1.10	Sat Nov 29 16:38:03 2003
--- openafs/src/util/ktime.c	Mon Oct 18 03:12:17 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/ktime.c,v 1.10 2003/11/29 21:38:03 jaltman Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;stdio.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/ktime.c,v 1.10.2.1 2004/10/18 07:12:17 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;stdio.h&gt;
***************
*** 165,171 ****
  {
      static char tbuffer[30];
      register char *tp;
!     tp = ctime((time_t *) &amp; atime);
      if (tp) {
  	strcpy(tbuffer, tp);
  	tbuffer[24] = 0;	/* get rid of new line */
--- 165,172 ----
  {
      static char tbuffer[30];
      register char *tp;
!     time_t t = atime;
!     tp = ctime(&amp;t);
      if (tp) {
  	strcpy(tbuffer, tp);
  	tbuffer[24] = 0;	/* get rid of new line */
Index: openafs/src/util/netutils.c
diff -c openafs/src/util/netutils.c:1.13 openafs/src/util/netutils.c:1.13.2.1
*** openafs/src/util/netutils.c:1.13	Tue Jul 15 19:17:16 2003
--- openafs/src/util/netutils.c	Mon Oct 18 03:12:18 2004
***************
*** 20,26 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/netutils.c,v 1.13 2003/07/15 23:17:16 shadow Exp $");
  
  #include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
--- 20,26 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/netutils.c,v 1.13.2.1 2004/10/18 07:12:18 shadow Exp $");
  
  #include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
***************
*** 53,58 ****
--- 53,62 ----
  #define MAX_NETFILE_LINE       2048	/* length of a line in the netrestrict file */
  #define MAXIPADDRS             1024	/* from afsd.c */
  
+ #ifndef INADDR_LOOPBACK
+ #define INADDR_LOOPBACK (afs_uint32)0x7f000001
+ #endif
+ 
  /* 
   * The line parameter is a pointer to a buffer containing a string of 
   * bytes of the form 
***************
*** 382,387 ****
--- 386,396 ----
  		break;
  	    }
  	}
+ 
+ 	/* Always mask loopback address */
+ 	if (found &amp;&amp; addr1[i] == INADDR_LOOPBACK) 
+ 	    found = 0;
+ 
  	if (found) {
  	    taddr[count] = addr1[i];
  	    tmask[count] = mask1[i];
Index: openafs/src/util/serverLog.c
diff -c openafs/src/util/serverLog.c:1.22 openafs/src/util/serverLog.c:1.22.2.1
*** openafs/src/util/serverLog.c:1.22	Sun Dec  7 17:49:40 2003
--- openafs/src/util/serverLog.c	Mon Oct 18 03:12:18 2004
***************
*** 20,26 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/serverLog.c,v 1.22 2003/12/07 22:49:40 jaltman Exp $");
  
  #include &lt;stdio.h&gt;
  #ifdef AFS_NT40_ENV
--- 20,26 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/serverLog.c,v 1.22.2.1 2004/10/18 07:12:18 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #ifdef AFS_NT40_ENV
***************
*** 235,242 ****
  #endif
  
      if (mrafsStyleLogs) {
  	TM_GetTimeOfDay(&amp;Start, 0);
! 	TimeFields = localtime(&amp;Start.tv_sec);
  	if (fileName) {
  	    if (strncmp(fileName, (char *)&amp;ourName, strlen(fileName)))
  		strcpy((char *)&amp;ourName, (char *)fileName);
--- 235,243 ----
  #endif
  
      if (mrafsStyleLogs) {
+         time_t t = Start.tv_sec;
  	TM_GetTimeOfDay(&amp;Start, 0);
! 	TimeFields = localtime(&amp;t);
  	if (fileName) {
  	    if (strncmp(fileName, (char *)&amp;ourName, strlen(fileName)))
  		strcpy((char *)&amp;ourName, (char *)fileName);
Index: openafs/src/util/snprintf.c
diff -c openafs/src/util/snprintf.c:1.21.2.1 openafs/src/util/snprintf.c:1.21.2.2
*** openafs/src/util/snprintf.c:1.21.2.1	Mon Aug  9 16:57:10 2004
--- openafs/src/util/snprintf.c	Mon Oct 18 13:44:05 2004
***************
*** 4,10 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/snprintf.c,v 1.21.2.1 2004/08/09 20:57:10 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;stdarg.h&gt;
--- 4,10 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/snprintf.c,v 1.21.2.2 2004/10/18 17:44:05 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #include &lt;stdarg.h&gt;
***************
*** 436,444 ****
  		} else {
  		    x = "%u.%u.%u.%u";
  		}
! 		sprintf(xbuf, x, (UVAL &amp; 0xff000000) &gt;&gt; 24,
! 			(UVAL &amp; 0x00ff0000) &gt;&gt; 16, (UVAL &amp; 0x0000ff00) &gt;&gt; 8,
! 			(UVAL &amp; 0x000000ff));
  		x = xbuf;
  		len = strlen(xbuf);
  	    }
--- 436,446 ----
  		} else {
  		    x = "%u.%u.%u.%u";
  		}
! 		/* typecast to whatever '%u' is! */
! 		sprintf(xbuf, x, (unsigned int)((UVAL &amp; 0xff000000) &gt;&gt; 24),
! 			(unsigned int)((UVAL &amp; 0x00ff0000) &gt;&gt; 16), 
! 			(unsigned int)((UVAL &amp; 0x0000ff00) &gt;&gt; 8),
! 			(unsigned int)(UVAL &amp; 0x000000ff));
  		x = xbuf;
  		len = strlen(xbuf);
  	    }
Index: openafs/src/venus/fs.c
diff -c openafs/src/venus/fs.c:1.24 openafs/src/venus/fs.c:1.24.2.1
*** openafs/src/venus/fs.c:1.24	Wed Jun  2 02:57:37 2004
--- openafs/src/venus/fs.c	Mon Oct 18 03:12:20 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/venus/fs.c,v 1.24 2004/06/02 06:57:37 shadow Exp $");
  
  #include &lt;afs/afs_args.h&gt;
  #include &lt;rx/xdr.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/venus/fs.c,v 1.24.2.1 2004/10/18 07:12:20 shadow Exp $");
  
  #include &lt;afs/afs_args.h&gt;
  #include &lt;rx/xdr.h&gt;
***************
*** 724,730 ****
  }
  
  static int
! SetACLCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 724,730 ----
  }
  
  static int
! SetACLCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 858,864 ****
  
  
  static int
! CopyACLCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 858,864 ----
  
  
  static int
! CopyACLCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1038,1044 ****
  
  /* clean up an acl to not have bogus entries */
  static int
! CleanACLCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct Acl *ta = 0;
--- 1038,1044 ----
  
  /* clean up an acl to not have bogus entries */
  static int
! CleanACLCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct Acl *ta = 0;
***************
*** 1125,1131 ****
  }
  
  static int
! ListACLCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct Acl *ta;
--- 1125,1131 ----
  }
  
  static int
! ListACLCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct Acl *ta;
***************
*** 1189,1195 ****
  }
  
  static int
! FlushVolumeCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1189,1195 ----
  }
  
  static int
! FlushVolumeCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1211,1217 ****
  }
  
  static int
! FlushCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1211,1217 ----
  }
  
  static int
! FlushCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1238,1244 ****
  
  /* all this command does is repackage its args and call SetVolCmd */
  static int
! SetQuotaCmd(struct cmd_syndesc *as)
  {
      struct cmd_syndesc ts;
  
--- 1238,1244 ----
  
  /* all this command does is repackage its args and call SetVolCmd */
  static int
! SetQuotaCmd(struct cmd_syndesc *as, char *arock)
  {
      struct cmd_syndesc ts;
  
***************
*** 1248,1254 ****
  }
  
  static int
! SetVolCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1248,1254 ----
  }
  
  static int
! SetVolCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1312,1318 ****
  };
  
  static int
! ExamineCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1312,1318 ----
  };
  
  static int
! ExamineCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1353,1359 ****
  }
  
  static int
! ListQuotaCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1353,1359 ----
  }
  
  static int
! ListQuotaCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1384,1390 ****
  }
  
  static int
! WhereIsCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1384,1390 ----
  }
  
  static int
! WhereIsCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1423,1429 ****
  
  
  static int
! DiskFreeCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1423,1429 ----
  
  
  static int
! DiskFreeCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1454,1460 ****
  }
  
  static int
! QuotaCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1454,1460 ----
  }
  
  static int
! QuotaCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1487,1493 ****
  }
  
  static int
! ListMountCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1487,1493 ----
  }
  
  static int
! ListMountCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1608,1614 ****
  }
  
  static
! MakeMountCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      char *cellName, *volName, *tmpName;
--- 1608,1614 ----
  }
  
  static
! MakeMountCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      char *cellName, *volName, *tmpName;
***************
*** 1716,1722 ****
   *      tp: Set to point to the actual name of the mount point to nuke.
   */
  static int
! RemoveMountCmd(struct cmd_syndesc *as)
  {
      afs_int32 code = 0;
      struct ViceIoctl blob;
--- 1716,1722 ----
   *      tp: Set to point to the actual name of the mount point to nuke.
   */
  static int
! RemoveMountCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code = 0;
      struct ViceIoctl blob;
***************
*** 1768,1774 ****
  */
  
  static int
! CheckServersCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1768,1774 ----
  */
  
  static int
! CheckServersCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1867,1873 ****
  }
  
  static int
! MessagesCmd(struct cmd_syndesc *as)
  {
      afs_int32 code = 0;
      struct ViceIoctl blob;
--- 1867,1873 ----
  }
  
  static int
! MessagesCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code = 0;
      struct ViceIoctl blob;
***************
*** 1913,1919 ****
  }
  
  static int
! CheckVolumesCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1913,1919 ----
  }
  
  static int
! CheckVolumesCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1931,1937 ****
  }
  
  static int
! SetCacheSizeCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1931,1937 ----
  }
  
  static int
! SetCacheSizeCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1970,1976 ****
  
  #define MAXGCSIZE	16
  static int
! GetCacheParmsCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 1970,1976 ----
  
  #define MAXGCSIZE	16
  static int
! GetCacheParmsCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 1995,2001 ****
  }
  
  static int
! ListCellsCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      afs_int32 i, j;
--- 1995,2001 ----
  }
  
  static int
! ListCellsCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      afs_int32 i, j;
***************
*** 2046,2052 ****
  }
  
  static int
! ListAliasesCmd(struct cmd_syndesc *as)
  {
      afs_int32 code, i;
      char *tp, *aliasName, *realName;
--- 2046,2052 ----
  }
  
  static int
! ListAliasesCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code, i;
      char *tp, *aliasName, *realName;
***************
*** 2076,2082 ****
  }
  
  static int
! CallBackRxConnCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 2076,2082 ----
  }
  
  static int
! CallBackRxConnCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 2115,2121 ****
  }
  
  static int
! NewCellCmd(struct cmd_syndesc *as)
  {
      afs_int32 code, linkedstate = 0, size = 0, *lp;
      struct ViceIoctl blob;
--- 2115,2121 ----
  }
  
  static int
! NewCellCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code, linkedstate = 0, size = 0, *lp;
      struct ViceIoctl blob;
***************
*** 2227,2233 ****
  }
  
  static int
! NewAliasCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 2227,2233 ----
  }
  
  static int
! NewAliasCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 2262,2268 ****
  }
  
  static int
! WhichCellCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct cmd_item *ti;
--- 2262,2268 ----
  }
  
  static int
! WhichCellCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct cmd_item *ti;
***************
*** 2287,2293 ****
  }
  
  static int
! WSCellCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 2287,2293 ----
  }
  
  static int
! WSCellCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 2317,2323 ****
  */
  
  static int
! MonitorCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 2317,2323 ----
  */
  
  static int
! MonitorCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 2378,2384 ****
  }
  
  static int
! SysNameCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 2378,2384 ----
  }
  
  static int
! SysNameCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 2432,2438 ****
  
  static char *exported_types[] = { "null", "nfs", "" };
  static int
! ExportAfsCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 2432,2438 ----
  
  static char *exported_types[] = { "null", "nfs", "" };
  static int
! ExportAfsCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 2531,2537 ****
  
  
  static int
! GetCellCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 2531,2537 ----
  
  
  static int
! GetCellCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 2582,2588 ****
  }
  
  static int
! SetCellCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 2582,2588 ----
  }
  
  static int
! SetCellCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 2659,2733 ****
  VLDBInit(int noAuthFlag, struct afsconf_cell *info)
  {
      afs_int32 code;
-     struct ktc_principal sname;
-     struct ktc_token ttoken;
-     afs_int32 scIndex;
-     struct rx_securityClass *sc;
-     struct rx_connection *serverconns[VLDB_MAXSERVERS];
-     afs_int32 i;
  
!     code = rx_Init(0);
!     if (code) {
! 	fprintf(stderr, "%s: could not initialize rx.\n", pn);
! 	return code;
!     }
      rxInitDone = 1;
!     rx_SetRxDeadTime(50);
!     if (!noAuthFlag) {		/* we don't need tickets for null */
! 	strcpy(sname.cell, info-&gt;name);
! 	sname.instance[0] = 0;
! 	strcpy(sname.name, "afs");
! 	code = ktc_GetToken(&amp;sname, &amp;ttoken, sizeof(ttoken), NULL);
! 	if (code) {
! 	    fprintf(stderr,
! 		    "%s: Could not get afs tokens, running unauthenticated.\n",
! 		    pn);
! 	    scIndex = 0;
! 	} else {
! 	    /* got a ticket */
! 	    if (ttoken.kvno &gt;= 0 &amp;&amp; ttoken.kvno &lt;= 255)
! 		scIndex = 2;	/* kerberos */
! 	    else {
! 		fprintf(stderr, "%s: funny kvno (%d) in ticket, proceeding\n",
! 			pn, ttoken.kvno);
! 		scIndex = 2;
! 	    }
! 	}
!     } else
! 	scIndex = 0;		/* don't authenticate */
!     switch (scIndex) {
!     case 0:
! 	sc = rxnull_NewClientSecurityObject();
! 	break;
! 
!     case 1:
! 	break;
!     case 2:
! 	sc = (struct rx_securityClass *)
! 	    rxkad_NewClientSecurityObject(rxkad_clear, &amp;ttoken.sessionKey,
! 					  ttoken.kvno, ttoken.ticketLen,
! 					  ttoken.ticket);
! 	break;
!     }
!     if (info-&gt;numServers &gt; VLDB_MAXSERVERS) {
! 	fprintf(stderr, "%s: info.numServers=%d (&gt; VLDB_MAXSERVERS=%d)\n", pn,
! 		info-&gt;numServers, VLDB_MAXSERVERS);
! 	exit(1);
!     }
!     memset(serverconns, 0, sizeof(serverconns));
!     for (i = 0; i &lt; info-&gt;numServers; i++)
! 	serverconns[i] =
! 	    rx_NewConnection(info-&gt;hostAddr[i].sin_addr.s_addr,
! 			     info-&gt;hostAddr[i].sin_port, USER_SERVICE_ID, sc,
! 			     scIndex);
! 
!     code = ubik_ClientInit(serverconns, &amp;uclient);
! 
!     if (code) {
! 	fprintf(stderr, "%s: ubik client init failed.\n", pn);
! 	return code;
!     }
!     return 0;
  }
  
  static struct ViceIoctl gblob;
--- 2659,2672 ----
  VLDBInit(int noAuthFlag, struct afsconf_cell *info)
  {
      afs_int32 code;
  
!     code = ugen_ClientInit(noAuthFlag, AFSDIR_CLIENT_ETC_DIRPATH, 
! 			   info-&gt;name, 0, &amp;uclient, 
!                            NULL, pn, rxkad_clear,
!                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
!                            0, 0, USER_SERVICE_ID);
      rxInitDone = 1;
!     return code;
  }
  
  static struct ViceIoctl gblob;
***************
*** 2827,2833 ****
  
  
  static int
! SetPrefCmd(struct cmd_syndesc *as)
  {
      FILE *infd;
      afs_int32 code;
--- 2766,2772 ----
  
  
  static int
! SetPrefCmd(struct cmd_syndesc *as, char *arock)
  {
      FILE *infd;
      afs_int32 code;
***************
*** 2933,2939 ****
  
  
  static int
! GetPrefCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct cmd_item *ti;
--- 2872,2878 ----
  
  
  static int
! GetPrefCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct cmd_item *ti;
***************
*** 3003,3009 ****
  }
  
  static int
! StoreBehindCmd(struct cmd_syndesc *as)
  {
      afs_int32 code = 0;
      struct ViceIoctl blob;
--- 2942,2948 ----
  }
  
  static int
! StoreBehindCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code = 0;
      struct ViceIoctl blob;
***************
*** 3104,3110 ****
  
  
  static afs_int32
! SetCryptCmd(struct cmd_syndesc *as)
  {
      afs_int32 code = 0, flag;
      struct ViceIoctl blob;
--- 3043,3049 ----
  
  
  static afs_int32
! SetCryptCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code = 0, flag;
      struct ViceIoctl blob;
***************
*** 3131,3137 ****
  
  
  static afs_int32
! GetCryptCmd(struct cmd_syndesc *as)
  {
      afs_int32 code = 0, flag;
      struct ViceIoctl blob;
--- 3070,3076 ----
  
  
  static afs_int32
! GetCryptCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code = 0, flag;
      struct ViceIoctl blob;
***************
*** 3511,3517 ****
  
  /* get clients interface addresses */
  static int
! GetClientAddrsCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct cmd_item *ti;
--- 3450,3456 ----
  
  /* get clients interface addresses */
  static int
! GetClientAddrsCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct cmd_item *ti;
***************
*** 3557,3563 ****
  }
  
  static int
! SetClientAddrsCmd(struct cmd_syndesc *as)
  {
      afs_int32 code, addr;
      struct cmd_item *ti;
--- 3496,3502 ----
  }
  
  static int
! SetClientAddrsCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code, addr;
      struct cmd_item *ti;
***************
*** 3631,3637 ****
  }
  
  static int
! FlushMountCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      struct ViceIoctl blob;
--- 3570,3576 ----
  }
  
  static int
! FlushMountCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      struct ViceIoctl blob;
***************
*** 3747,3753 ****
  }
  
  static int
! RxStatProcCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      afs_int32 flags = 0;
--- 3686,3692 ----
  }
  
  static int
! RxStatProcCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      afs_int32 flags = 0;
***************
*** 3782,3788 ****
  }
  
  static int
! RxStatPeerCmd(struct cmd_syndesc *as)
  {
      afs_int32 code;
      afs_int32 flags = 0;
--- 3721,3727 ----
  }
  
  static int
! RxStatPeerCmd(struct cmd_syndesc *as, char *arock)
  {
      afs_int32 code;
      afs_int32 flags = 0;
Index: openafs/src/viced/callback.c
diff -c openafs/src/viced/callback.c:1.55 openafs/src/viced/callback.c:1.55.2.1
*** openafs/src/viced/callback.c:1.55	Sun Dec  7 20:45:34 2003
--- openafs/src/viced/callback.c	Mon Oct 18 03:12:22 2004
***************
*** 83,89 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/viced/callback.c,v 1.55 2003/12/08 01:45:34 jaltman Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;		/* for malloc() */
--- 83,89 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/viced/callback.c,v 1.55.2.1 2004/10/18 07:12:22 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;		/* for malloc() */
***************
*** 776,781 ****
--- 776,782 ----
  	if (!thishost || (thishost-&gt;hostFlags &amp; HOSTDELETED)) {
  	    continue;
  	}
+ 	rx_GetConnection(thishost-&gt;callback_rxcon);
  	conns[j++] = thishost-&gt;callback_rxcon;
  
  #ifdef	ADAPT_MTU
***************
*** 832,845 ****
  			}
  
  			H_LOCK;
! 			h_Lock_r(hp);
  			hp-&gt;hostFlags |= VENUSDOWN;
  		/**
  		  * We always go into AddCallBack1_r with the host locked
  		  */
  			AddCallBack1_r(hp, afidp-&gt;AFSCBFids_val, itot(idx),
  				       CB_DELAYED, 1);
! 			h_Unlock_r(hp);
  			H_UNLOCK;
  		    }
  		}
--- 833,846 ----
  			}
  
  			H_LOCK;
! 			h_Lock_r(hp); 
  			hp-&gt;hostFlags |= VENUSDOWN;
  		/**
  		  * We always go into AddCallBack1_r with the host locked
  		  */
  			AddCallBack1_r(hp, afidp-&gt;AFSCBFids_val, itot(idx),
  				       CB_DELAYED, 1);
! 			h_Unlock_r(hp); 
  			H_UNLOCK;
  		    }
  		}
***************
*** 853,860 ****
      for (i = 0; i &lt; ncbas; i++) {
  	struct host *hp;
  	hp = cba[i].hp;
! 	if (hp &amp;&amp; xhost != hp)
  	    h_Release_r(hp);
      }
  
      return;
--- 854,863 ----
      for (i = 0; i &lt; ncbas; i++) {
  	struct host *hp;
  	hp = cba[i].hp;
! 	if (hp &amp;&amp; xhost != hp) {
! 	    rx_PutConnection(hp-&gt;callback_rxcon);
  	    h_Release_r(hp);
+ 	}
      }
  
      return;
Index: openafs/src/viced/host.c
diff -c openafs/src/viced/host.c:1.57 openafs/src/viced/host.c:1.57.2.1
*** openafs/src/viced/host.c:1.57	Thu Aug  5 10:48:09 2004
--- openafs/src/viced/host.c	Mon Oct 18 03:12:22 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/viced/host.c,v 1.57 2004/08/05 14:48:09 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;errno.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/viced/host.c,v 1.57.2.1 2004/10/18 07:12:22 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;errno.h&gt;
***************
*** 781,786 ****
--- 781,787 ----
  		    *hp = th-&gt;next;
  		    h_DeleteList_r(host);
  		    FreeHT(host);
+ 		    free(th);
  		    break;
  		}
  	    }
Index: openafs/src/viced/viced.c
diff -c openafs/src/viced/viced.c:1.58 openafs/src/viced/viced.c:1.58.2.1
*** openafs/src/viced/viced.c:1.58	Wed Mar 24 12:36:57 2004
--- openafs/src/viced/viced.c	Mon Oct 18 03:12:24 2004
***************
*** 20,26 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/viced/viced.c,v 1.58 2004/03/24 17:36:57 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
--- 20,26 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/viced/viced.c,v 1.58.2.1 2004/10/18 07:12:24 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
***************
*** 1564,1569 ****
--- 1564,1570 ----
      struct rlimit rlim;		/* max number of open file descriptors */
  #endif
      int curLimit;
+     time_t t;
  
  #ifdef	AFS_AIX32_ENV
      struct sigaction nsa;
***************
*** 1868,1876 ****
      TM_GetTimeOfDay(&amp;tp, 0);
  
  #ifndef AFS_QUIETFS_ENV
!     if (console != NULL) {
  	fprintf(console, "File server has started at %s\r",
! 		afs_ctime(&amp;tp.tv_sec, tbuffer, sizeof(tbuffer)));
      }
  #endif
  
--- 1869,1878 ----
      TM_GetTimeOfDay(&amp;tp, 0);
  
  #ifndef AFS_QUIETFS_ENV
!     if (console != NULL) { 
!         time_t t = tp.tv_sec;
  	fprintf(console, "File server has started at %s\r",
! 		afs_ctime(&amp;t, tbuffer, sizeof(tbuffer)));
      }
  #endif
  
***************
*** 1907,1915 ****
      (void)signal(SIGQUIT, ShutDown_Signal);
  #endif
  
      ViceLog(0,
  	    ("File Server started %s",
! 	     afs_ctime(&amp;tp.tv_sec, tbuffer, sizeof(tbuffer))));
  #if FS_STATS_DETAILED
      afs_FullPerfStats.det.epoch.tv_sec = StartTime = tp.tv_sec;
  #endif
--- 1909,1918 ----
      (void)signal(SIGQUIT, ShutDown_Signal);
  #endif
  
+     t = tp.tv_sec;
      ViceLog(0,
  	    ("File Server started %s",
! 	     afs_ctime(&amp;t, tbuffer, sizeof(tbuffer))));
  #if FS_STATS_DETAILED
      afs_FullPerfStats.det.epoch.tv_sec = StartTime = tp.tv_sec;
  #endif
Index: openafs/src/vlserver/vlclient.c
diff -c openafs/src/vlserver/vlclient.c:1.12 openafs/src/vlserver/vlclient.c:1.12.2.1
*** openafs/src/vlserver/vlclient.c:1.12	Sun Dec  7 17:49:42 2003
--- openafs/src/vlserver/vlclient.c	Mon Oct 18 03:12:25 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vlserver/vlclient.c,v 1.12 2003/12/07 22:49:42 jaltman Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;sys/types.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vlserver/vlclient.c,v 1.12.2.1 2004/10/18 07:12:25 shadow Exp $");
  
  #include &lt;afs/stds.h&gt;
  #include &lt;sys/types.h&gt;
***************
*** 162,263 ****
  
  /* Almost identical's to pr_Initialize in vlserver/pruser.c */
  afs_int32
! vl_Initialize(auth, confDir, server, cellp)
!      int auth, server;
!      char *confDir, *cellp;
  {
!     afs_int32 code;
!     struct afsconf_dir *tdir;
!     struct ktc_principal sname;
!     struct ktc_token ttoken;
!     afs_int32 scIndex = 0;
!     struct rx_securityClass *sc;
!     struct afsconf_cell info;
!     afs_int32 i;
! 
!     code = rx_Init(0);
!     if (code) {
! 	fprintf(stderr, "vl_Initialize:  Could not initialize rx.\n");
! 	return code;
!     }
! 
!     rx_SetRxDeadTime(50);
!     if (!server) {
! 	tdir = afsconf_Open(confDir);
! 	if (!tdir) {
! 	    fprintf(stderr, "Could not open configuration directory (%s).\n",
! 		    confDir);
! 	    return -1;
! 	}
!     }
!     if (auth) {			/* we don't need tickets for null */
! 	if (!server) {
! 	    code = afsconf_GetLocalCell(tdir, sname.cell, sizeof(sname.cell));
! 	    if (code) {
! 		fprintf(stderr,
! 			"vl_Initialize: Could not get local cell name.\n");
! 		return code;
! 	    }
! 	} else
! 	    strncpy(sname.cell, cellp, sizeof(sname.cell));
! 	sname.instance[0] = 0;
! 	strcpy(sname.name, "afs");
! 	code = ktc_GetToken(&amp;sname, &amp;ttoken, sizeof(ttoken), NULL);
! 	if (code) {
! 	    fprintf(stderr,
! 		    "vl_Initialize: Could not get afs tokens, running unauthenticated.\n");
! 	    scIndex = 0;
! 	} else if (ttoken.kvno &lt;= 255)
! 	    scIndex = 2;
! 	else {			/* bcrypt */
! 	    fprintf(stderr,
! 		    "vl_Initialize: funny kvno (%d) in ticket, proceeding\n",
! 		    ttoken.kvno);
! 	    scIndex = 2;
! 	}
!     }
!     switch (scIndex) {
!     case 0:
! 	sc = rxnull_NewClientSecurityObject();
! 	break;
!     case 1:
! 	return -1;
!     case 2:
! 	sc = rxkad_NewClientSecurityObject(rxkad_clear, &amp;ttoken.sessionKey,
! 					   ttoken.kvno, ttoken.ticketLen,
! 					   ttoken.ticket);
!     }
!     if (!server) {
! 	code = afsconf_GetCellInfo(tdir, NULL, AFSCONF_VLDBSERVICE, &amp;info);
! 	if (info.numServers &gt; MAXSERVERS) {
! 	    fprintf(stderr,
! 		    "vl_Initialize: info.numServers=%d (&gt; MAXSERVERS=%d)\n",
! 		    info.numServers, MAXSERVERS);
! 	    exit(1);
! 	}
! 	for (i = 0; i &lt; info.numServers; i++)
! 	    serverconns[i] =
! 		rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
! 				 info.hostAddr[i].sin_port, USER_SERVICE_ID,
! 				 sc, scIndex);
!     } else {
! 	serverconns[0] =
! 	    rx_NewConnection(server, htons(AFSCONF_VLDBPORT), USER_SERVICE_ID,
! 			     sc, scIndex);
!     }
!     code = ubik_ClientInit(serverconns, &amp;cstruct);
! 
!     if (code) {
! 	fprintf(stderr, "vl_Initialize: ubik client init failed.\n");
! 	return code;
!     }
!     return 0;
  }
  
  /* return host address in network byte order */
  afs_int32
! GetServer(aname)
!      char *aname;
  {
      register struct hostent *th;
      afs_int32 addr;
--- 162,178 ----
  
  /* Almost identical's to pr_Initialize in vlserver/pruser.c */
  afs_int32
! vl_Initialize(int auth, char *confDir, int server, char *cellp)
  {
!     return ugen_ClientInit(auth?0:1, confDir, cellp, 0,
! 			  &amp;cstruct, NULL, "vl_Initialize", rxkad_clear, 
! 			  MAXSERVERS, AFSCONF_VLDBSERVICE, 50, server,
! 			  htons(AFSCONF_VLDBPORT), USER_SERVICE_ID);
  }
  
  /* return host address in network byte order */
  afs_int32
! GetServer(char *aname)
  {
      register struct hostent *th;
      afs_int32 addr;
Index: openafs/src/vol/listinodes.c
diff -c openafs/src/vol/listinodes.c:1.13 openafs/src/vol/listinodes.c:1.13.2.1
*** openafs/src/vol/listinodes.c:1.13	Tue Jul 15 19:17:39 2003
--- openafs/src/vol/listinodes.c	Mon Oct 18 03:12:27 2004
***************
*** 21,27 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/listinodes.c,v 1.13 2003/07/15 23:17:39 shadow Exp $");
  
  #ifndef AFS_NAMEI_ENV
  #if defined(AFS_LINUX20_ENV) || defined(AFS_SUN4_ENV)
--- 21,27 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/listinodes.c,v 1.13.2.1 2004/10/18 07:12:27 shadow Exp $");
  
  #ifndef AFS_NAMEI_ENV
  #if defined(AFS_LINUX20_ENV) || defined(AFS_SUN4_ENV)
***************
*** 35,41 ****
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  	       int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
! 	       char *wpath)
  {
      Log("ListViceInodes not implemented for this platform!\n");
      return -1;
--- 35,41 ----
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  	       int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
! 	       char *wpath, void *rock)
  {
      Log("ListViceInodes not implemented for this platform!\n");
      return -1;
***************
*** 167,173 ****
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  	       int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
! 	       char *wpath)
  {
      FILE *inodeFile = NULL;
      char dev[50], rdev[51];
--- 167,173 ----
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  	       int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
! 	       char *wpath, void *rock)
  {
      FILE *inodeFile = NULL;
      char dev[50], rdev[51];
***************
*** 301,307 ****
  	info.u.param[2] = p-&gt;di_vicep3;
  	info.u.param[3] = p-&gt;di_vicep4;
  
! 	if (judgeInode &amp;&amp; (*judgeInode) (&amp;info, judgeParam) == 0)
  	    continue;
  
  	if (fwrite(&amp;info, sizeof info, 1, inodeFile) != 1) {
--- 301,307 ----
  	info.u.param[2] = p-&gt;di_vicep3;
  	info.u.param[3] = p-&gt;di_vicep4;
  
! 	if (judgeInode &amp;&amp; (*judgeInode) (&amp;info, judgeParam, rock) == 0)
  	    continue;
  
  	if (fwrite(&amp;info, sizeof info, 1, inodeFile) != 1) {
***************
*** 469,475 ****
  int
  efs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  		   int (*judgeInode) (), int judgeParam, int *forcep,
! 		   int forceR, char *wpath)
  {
      FILE *inodeFile = NULL;
      char dev[50], rdev[51];
--- 469,475 ----
  int
  efs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  		   int (*judgeInode) (), int judgeParam, int *forcep,
! 		   int forceR, char *wpath, void *rock)
  {
      FILE *inodeFile = NULL;
      char dev[50], rdev[51];
***************
*** 570,576 ****
  	    p-&gt;di_nlink, info.u.param[0], info.u.param[1], info.u.param[2],
  	    info.u.param[3]);
  #endif
! 	if (judgeInode &amp;&amp; (*judgeInode) (&amp;info, judgeParam) == 0)
  	    continue;
  
  	if (fwrite(&amp;info, sizeof info, 1, inodeFile) != 1) {
--- 570,576 ----
  	    p-&gt;di_nlink, info.u.param[0], info.u.param[1], info.u.param[2],
  	    info.u.param[3]);
  #endif
! 	if (judgeInode &amp;&amp; (*judgeInode) (&amp;info, judgeParam, rock) == 0)
  	    continue;
  
  	if (fwrite(&amp;info, sizeof info, 1, inodeFile) != 1) {
***************
*** 823,829 ****
  int
  xfs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  		   int (*judgeInode) (), int judgeParam, int *forcep,
! 		   int forceR, char *wpath)
  {
      FILE *inodeFile = NULL;
      i_list_inode_t info;
--- 823,829 ----
  int
  xfs_ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  		   int (*judgeInode) (), int judgeParam, int *forcep,
! 		   int forceR, char *wpath, void *rock)
  {
      FILE *inodeFile = NULL;
      i_list_inode_t info;
***************
*** 931,937 ****
  		goto err1_exit;
  	    }
  
! 	    if (judgeInode &amp;&amp; (*judgeInode) (&amp;info.ili_info, judgeParam) == 0)
  		continue;
  
  	    rename = 0;
--- 931,937 ----
  		goto err1_exit;
  	    }
  
! 	    if (judgeInode &amp;&amp; (*judgeInode) (&amp;info.ili_info, judgeParam, rock) == 0)
  		continue;
  
  	    rename = 0;
***************
*** 1039,1045 ****
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  	       int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
! 	       char *wpath)
  {
      FILE *inodeFile = NULL;
      char dev[50], rdev[51];
--- 1039,1045 ----
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  	       int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
! 	       char *wpath, void *rock)
  {
      FILE *inodeFile = NULL;
      char dev[50], rdev[51];
***************
*** 1070,1082 ****
  #ifdef AFS_SGI_XFS_IOPS_ENV
      if (!strcmp("xfs", root_inode.st_fstype)) {
  	return xfs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
! 				  judgeParam, forcep, forceR, wpath);
      } else
  #endif
  #ifdef AFS_SGI_EFS_IOPS_ENV
      if (root_inode.st_ino == EFS_ROOTINO) {
  	return efs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
! 				  judgeParam, forcep, forceR, wpath);
      } else
  #endif
      {
--- 1070,1082 ----
  #ifdef AFS_SGI_XFS_IOPS_ENV
      if (!strcmp("xfs", root_inode.st_fstype)) {
  	return xfs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
! 				  judgeParam, forcep, forceR, wpath, rock);
      } else
  #endif
  #ifdef AFS_SGI_EFS_IOPS_ENV
      if (root_inode.st_ino == EFS_ROOTINO) {
  	return efs_ListViceInodes(devname, mountedOn, resultFile, judgeInode,
! 				  judgeParam, forcep, forceR, wpath, rock);
      } else
  #endif
      {
***************
*** 1114,1120 ****
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  	       int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
! 	       char *wpath)
  {
      union {
  #ifdef	AFS_AIX_ENV
--- 1114,1120 ----
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
  	       int (*judgeInode) (), int judgeParam, int *forcep, int forceR,
! 	       char *wpath, void *rock)
  {
      union {
  #ifdef	AFS_AIX_ENV
***************
*** 1212,1218 ****
  	info.u.param[1] = auxp-&gt;aux_param2;
  	info.u.param[2] = auxp-&gt;aux_param3;
  	info.u.param[3] = auxp-&gt;aux_param4;
! 	if (judgeInode &amp;&amp; (*judgeInode) (&amp;info, judgeParam) == 0)
  	    continue;
  	if (fwrite(&amp;info, sizeof info, 1, inodeFile) != 1) {
  	    Log("Error writing inode file for partition %s\n", partition);
--- 1212,1218 ----
  	info.u.param[1] = auxp-&gt;aux_param2;
  	info.u.param[2] = auxp-&gt;aux_param3;
  	info.u.param[3] = auxp-&gt;aux_param4;
! 	if (judgeInode &amp;&amp; (*judgeInode) (&amp;info, judgeParam, rock) == 0)
  	    continue;
  	if (fwrite(&amp;info, sizeof info, 1, inodeFile) != 1) {
  	    Log("Error writing inode file for partition %s\n", partition);
***************
*** 1421,1427 ****
  		    info.inodeNumber = i;
  		    info.byteCount = p-&gt;di_size;
  		    info.linkCount = p-&gt;di_nlink;
! 		    if (judgeInode &amp;&amp; (*judgeInode) (&amp;info, judgeParam) == 0)
  			continue;
  		    if (fwrite(&amp;info, sizeof info, 1, inodeFile) != 1) {
  			Log("Error writing inode file for partition %s\n",
--- 1421,1427 ----
  		    info.inodeNumber = i;
  		    info.byteCount = p-&gt;di_size;
  		    info.linkCount = p-&gt;di_nlink;
! 		    if (judgeInode &amp;&amp; (*judgeInode) (&amp;info, judgeParam, rock) == 0)
  			continue;
  		    if (fwrite(&amp;info, sizeof info, 1, inodeFile) != 1) {
  			Log("Error writing inode file for partition %s\n",
Index: openafs/src/vol/namei_ops.c
diff -c openafs/src/vol/namei_ops.c:1.21.2.1 openafs/src/vol/namei_ops.c:1.21.2.2
*** openafs/src/vol/namei_ops.c:1.21.2.1	Wed Aug 25 03:14:19 2004
--- openafs/src/vol/namei_ops.c	Mon Oct 18 13:44:06 2004
***************
*** 13,19 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/namei_ops.c,v 1.21.2.1 2004/08/25 07:14:19 shadow Exp $");
  
  #ifdef AFS_NAMEI_ENV
  #include &lt;stdio.h&gt;
--- 13,19 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/namei_ops.c,v 1.21.2.2 2004/10/18 17:44:06 shadow Exp $");
  
  #ifdef AFS_NAMEI_ENV
  #include &lt;stdio.h&gt;
***************
*** 1041,1048 ****
  						  struct ViceInodeInfo *,
  						  char *, char *), FILE * fp,
  				int (*judgeFun) (struct ViceInodeInfo *,
! 						 int vid),
! 				int singleVolumeNumber);
  
  
  /* WriteInodeInfo
--- 1041,1048 ----
  						  struct ViceInodeInfo *,
  						  char *, char *), FILE * fp,
  				int (*judgeFun) (struct ViceInodeInfo *,
! 						 int vid, void *),
! 				int singleVolumeNumber, void *rock);
  
  
  /* WriteInodeInfo
***************
*** 1093,1100 ****
   */
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
! 	       int (*judgeInode) (struct ViceInodeInfo * info, int vid),
! 	       int singleVolumeNumber, int *forcep, int forceR, char *wpath)
  {
      FILE *fp = (FILE *) - 1;
      int ninodes;
--- 1093,1101 ----
   */
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
! 	       int (*judgeInode) (struct ViceInodeInfo * info, int vid, void *rock),
! 	       int singleVolumeNumber, int *forcep, int forceR, char *wpath, 
! 	       void *rock)
  {
      FILE *fp = (FILE *) - 1;
      int ninodes;
***************
*** 1114,1120 ****
  
      ninodes =
  	namei_ListAFSFiles(mountedOn, WriteInodeInfo, fp, judgeInode,
! 			   singleVolumeNumber);
  
      if (!resultFile)
  	return ninodes;
--- 1115,1121 ----
  
      ninodes =
  	namei_ListAFSFiles(mountedOn, WriteInodeInfo, fp, judgeInode,
! 			   singleVolumeNumber, rock);
  
      if (!resultFile)
  	return ninodes;
***************
*** 1167,1174 ****
  namei_ListAFSFiles(char *dev,
  		   int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
  				    char *), FILE * fp,
! 		   int (*judgeFun) (struct ViceInodeInfo *, int),
! 		   int singleVolumeNumber)
  {
      IHandle_t ih;
      namei_t name;
--- 1168,1175 ----
  namei_ListAFSFiles(char *dev,
  		   int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
  				    char *), FILE * fp,
! 		   int (*judgeFun) (struct ViceInodeInfo *, int, void *),
! 		   int singleVolumeNumber, void *rock)
  {
      IHandle_t ih;
      namei_t name;
***************
*** 1188,1194 ****
  	namei_HandleToVolDir(&amp;name, &amp;ih);
  	ninodes =
  	    namei_ListAFSSubDirs(&amp;ih, writeFun, fp, judgeFun,
! 				 singleVolumeNumber);
  	if (ninodes &lt; 0)
  	    return ninodes;
      } else {
--- 1189,1195 ----
  	namei_HandleToVolDir(&amp;name, &amp;ih);
  	ninodes =
  	    namei_ListAFSSubDirs(&amp;ih, writeFun, fp, judgeFun,
! 				 singleVolumeNumber, rock);
  	if (ninodes &lt; 0)
  	    return ninodes;
      } else {
***************
*** 1212,1218 ****
  		    if (!DecodeVolumeName(dp2-&gt;d_name, &amp;ih.ih_vid)) {
  			ninodes +=
  			    namei_ListAFSSubDirs(&amp;ih, writeFun, fp, judgeFun,
! 						 0);
  		    }
  		}
  		closedir(dirp2);
--- 1213,1219 ----
  		    if (!DecodeVolumeName(dp2-&gt;d_name, &amp;ih.ih_vid)) {
  			ninodes +=
  			    namei_ListAFSSubDirs(&amp;ih, writeFun, fp, judgeFun,
! 						 0, rock);
  		    }
  		}
  		closedir(dirp2);
***************
*** 1239,1246 ****
  namei_ListAFSSubDirs(IHandle_t * dirIH,
  		     int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
  				      char *), FILE * fp,
! 		     int (*judgeFun) (struct ViceInodeInfo *, int),
! 		     int singleVolumeNumber)
  {
      IHandle_t myIH = *dirIH;
      namei_t name;
--- 1240,1247 ----
  namei_ListAFSSubDirs(IHandle_t * dirIH,
  		     int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
  				      char *), FILE * fp,
! 		     int (*judgeFun) (struct ViceInodeInfo *, int, void *),
! 		     int singleVolumeNumber, void *rock)
  {
      IHandle_t myIH = *dirIH;
      namei_t name;
***************
*** 1283,1289 ****
  		info.linkCount =
  		    namei_GetLinkCount(&amp;linkHandle, (Inode) 0, 0);
  	    }
! 	    if (judgeFun &amp;&amp; !(*judgeFun) (&amp;info, singleVolumeNumber))
  		continue;
  
  	    if ((*writeFun) (fp, &amp;info, path1, dp1-&gt;d_name) &lt; 0) {
--- 1284,1290 ----
  		info.linkCount =
  		    namei_GetLinkCount(&amp;linkHandle, (Inode) 0, 0);
  	    }
! 	    if (judgeFun &amp;&amp; !(*judgeFun) (&amp;info, singleVolumeNumber, rock))
  		continue;
  
  	    if ((*writeFun) (fp, &amp;info, path1, dp1-&gt;d_name) &lt; 0) {
***************
*** 1345,1351 ****
  				continue;
  			    }
  			    if (judgeFun
! 				&amp;&amp; !(*judgeFun) (&amp;info, singleVolumeNumber))
  				continue;
  
  			    if ((*writeFun) (fp, &amp;info, path3, dp3-&gt;d_name) &lt;
--- 1346,1352 ----
  				continue;
  			    }
  			    if (judgeFun
! 				&amp;&amp; !(*judgeFun) (&amp;info, singleVolumeNumber, rock))
  				continue;
  
  			    if ((*writeFun) (fp, &amp;info, path3, dp3-&gt;d_name) &lt;
Index: openafs/src/vol/namei_ops.h
diff -c openafs/src/vol/namei_ops.h:1.6 openafs/src/vol/namei_ops.h:1.6.2.1
*** openafs/src/vol/namei_ops.h:1.6	Fri Aug  8 16:40:45 2003
--- openafs/src/vol/namei_ops.h	Mon Oct 18 03:12:27 2004
***************
*** 50,60 ****
  					 struct ViceInodeInfo * info,
  					 char *dir, char *file), FILE * fp,
  		       int (*judge_fun) (struct ViceInodeInfo * info,
! 					 int vid), int singleVolumeNumber);
  int ListViceInodes(char *devname, char *mountedOn, char *resultFile,
! 		   int (*judgeInode) (struct ViceInodeInfo * info, int vid),
  		   int singleVolumeNumber, int *forcep, int forceR,
! 		   char *wpath);
  
  
  #define NAMEI_LCOMP_LEN 32
--- 50,62 ----
  					 struct ViceInodeInfo * info,
  					 char *dir, char *file), FILE * fp,
  		       int (*judge_fun) (struct ViceInodeInfo * info,
! 					 int vid, void *rock), 
! 		       int singleVolumeNumber, void *rock);
  int ListViceInodes(char *devname, char *mountedOn, char *resultFile,
! 		   int (*judgeInode) (struct ViceInodeInfo * info, int vid, 
! 				      void *rock),
  		   int singleVolumeNumber, int *forcep, int forceR,
! 		   char *wpath, void *rock);
  
  
  #define NAMEI_LCOMP_LEN 32
Index: openafs/src/vol/ntops.c
diff -c openafs/src/vol/ntops.c:1.7 openafs/src/vol/ntops.c:1.7.2.1
*** openafs/src/vol/ntops.c:1.7	Sun Dec  7 17:49:43 2003
--- openafs/src/vol/ntops.c	Mon Oct 18 03:12:28 2004
***************
*** 13,19 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/ntops.c,v 1.7 2003/12/07 22:49:43 jaltman Exp $");
  
  #ifdef AFS_NT40_ENV
  #include &lt;stdio.h&gt;
--- 13,19 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/ntops.c,v 1.7.2.1 2004/10/18 07:12:28 shadow Exp $");
  
  #ifdef AFS_NT40_ENV
  #include &lt;stdio.h&gt;
***************
*** 935,942 ****
  			     int (*write_fun) (FILE *, struct ViceInodeInfo *,
  					       char *, char *), FILE * fp,
  			     int (*judgeFun) (struct ViceInodeInfo *,
! 					      int vid),
! 			     int singleVolumeNumber);
  
  
  /* WriteInodeInfo
--- 935,942 ----
  			     int (*write_fun) (FILE *, struct ViceInodeInfo *,
  					       char *, char *), FILE * fp,
  			     int (*judgeFun) (struct ViceInodeInfo *,
! 					      int vid, void *rock),
! 			     int singleVolumeNumber, void *rock);
  
  
  /* WriteInodeInfo
***************
*** 972,979 ****
   */
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
! 	       int (*judgeInode) (struct ViceInodeInfo * info, int vid),
! 	       int singleVolumeNumber, int *forcep, int forceR, char *wpath)
  {
      FILE *fp = (FILE *) - 1;
      int ninodes;
--- 972,980 ----
   */
  int
  ListViceInodes(char *devname, char *mountedOn, char *resultFile,
! 	       int (*judgeInode) (struct ViceInodeInfo * info, int vid, void *rock),
! 	       int singleVolumeNumber, int *forcep, int forceR, char *wpath, 
! 	       void *rock)
  {
      FILE *fp = (FILE *) - 1;
      int ninodes;
***************
*** 988,994 ****
      }
      ninodes =
  	nt_ListAFSFiles(wpath, WriteInodeInfo, fp, judgeInode,
! 			singleVolumeNumber);
  
      if (!resultFile)
  	return ninodes;
--- 989,995 ----
      }
      ninodes =
  	nt_ListAFSFiles(wpath, WriteInodeInfo, fp, judgeInode,
! 			singleVolumeNumber, rock);
  
      if (!resultFile)
  	return ninodes;
***************
*** 1041,1048 ****
  nt_ListAFSFiles(char *dev,
  		int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
  				 char *), FILE * fp,
! 		int (*judgeFun) (struct ViceInodeInfo *, int),
! 		int singleVolumeNumber)
  {
      IHandle_t h;
      char name[MAX_PATH];
--- 1042,1049 ----
  nt_ListAFSFiles(char *dev,
  		int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
  				 char *), FILE * fp,
! 		int (*judgeFun) (struct ViceInodeInfo *, int, void *),
! 		int singleVolumeNumber, void *rock)
  {
      IHandle_t h;
      char name[MAX_PATH];
***************
*** 1059,1065 ****
  	if (!nt_HandleToVolDir(name, &amp;h))
  	    return -1;
  	ninodes =
! 	    nt_ListAFSSubDirs(&amp;h, writeFun, fp, judgeFun, singleVolumeNumber);
  	if (ninodes &lt; 0)
  	    return ninodes;
      } else {
--- 1060,1066 ----
  	if (!nt_HandleToVolDir(name, &amp;h))
  	    return -1;
  	ninodes =
! 	    nt_ListAFSSubDirs(&amp;h, writeFun, fp, judgeFun, singleVolumeNumber, rock);
  	if (ninodes &lt; 0)
  	    return ninodes;
      } else {
***************
*** 1072,1078 ****
  	    return -1;
  	while (dp = readdir(dirp)) {
  	    if (!DecodeVolumeName(dp-&gt;d_name, &amp;h.ih_vid)) {
! 		ninodes += nt_ListAFSSubDirs(&amp;h, writeFun, fp, judgeFun, 0);
  	    }
  	}
      }
--- 1073,1079 ----
  	    return -1;
  	while (dp = readdir(dirp)) {
  	    if (!DecodeVolumeName(dp-&gt;d_name, &amp;h.ih_vid)) {
! 		ninodes += nt_ListAFSSubDirs(&amp;h, writeFun, fp, judgeFun, 0, rock);
  	    }
  	}
      }
***************
*** 1094,1101 ****
  nt_ListAFSSubDirs(IHandle_t * dirIH,
  		  int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
  				   char *), FILE * fp,
! 		  int (*judgeFun) (struct ViceInodeInfo *, int),
! 		  int singleVolumeNumber)
  {
      int i;
      IHandle_t myIH = *dirIH;
--- 1095,1102 ----
  nt_ListAFSSubDirs(IHandle_t * dirIH,
  		  int (*writeFun) (FILE *, struct ViceInodeInfo *, char *,
  				   char *), FILE * fp,
! 		  int (*judgeFun) (struct ViceInodeInfo *, int, void *),
! 		  int singleVolumeNumber, void *rock)
  {
      int i;
      IHandle_t myIH = *dirIH;
***************
*** 1179,1185 ****
  		    info.u.param[2] = data.ftCreationTime.dwHighDateTime;
  		    info.u.param[3] = data.ftCreationTime.dwLowDateTime;
  		}
! 		if (judgeFun &amp;&amp; !(*judgeFun) (&amp;info, singleVolumeNumber))
  		    goto next_file;
  		if ((*writeFun) (fp, &amp;info, path, data.cFileName) &lt; 0) {
  		    nt_close(linkHandle.fd_fd);
--- 1180,1186 ----
  		    info.u.param[2] = data.ftCreationTime.dwHighDateTime;
  		    info.u.param[3] = data.ftCreationTime.dwLowDateTime;
  		}
! 		if (judgeFun &amp;&amp; !(*judgeFun) (&amp;info, singleVolumeNumber, rock))
  		    goto next_file;
  		if ((*writeFun) (fp, &amp;info, path, data.cFileName) &lt; 0) {
  		    nt_close(linkHandle.fd_fd);
Index: openafs/src/vol/ntops.h
diff -c openafs/src/vol/ntops.h:1.3 openafs/src/vol/ntops.h:1.3.2.1
*** openafs/src/vol/ntops.h:1.3	Tue Jul 15 19:17:39 2003
--- openafs/src/vol/ntops.h	Mon Oct 18 03:12:28 2004
***************
*** 49,60 ****
  int nt_ListAFSFiles(char *dev,
  		    int (*write_fun) (FILE * fp, struct ViceInodeInfo *,
  				      char *dir, char *file), FILE * fp,
! 		    int (*judge_fun) (struct ViceInodeInfo *, int vid),
! 		    int singleVolumeNumber);
  int ListViceInodes(char *devname, char *mountedOn, char *resultFile,
! 		   int (*judgeInode) (struct ViceInodeInfo * info, int vid),
  		   int singleVolumeNumber, int *forcep, int forceR,
! 		   char *wpath);
  
  
  int nt_HandleToName(char *name, IHandle_t * h);
--- 49,60 ----
  int nt_ListAFSFiles(char *dev,
  		    int (*write_fun) (FILE * fp, struct ViceInodeInfo *,
  				      char *dir, char *file), FILE * fp,
! 		    int (*judge_fun) (struct ViceInodeInfo *, int vid, void *rock),
! 		    int singleVolumeNumber, void *rock);
  int ListViceInodes(char *devname, char *mountedOn, char *resultFile,
! 		   int (*judgeInode) (struct ViceInodeInfo * info, int vid, void *rock),
  		   int singleVolumeNumber, int *forcep, int forceR,
! 		   char *wpath, void *rock);
  
  
  int nt_HandleToName(char *name, IHandle_t * h);
Index: openafs/src/vol/nuke.c
diff -c openafs/src/vol/nuke.c:1.13.2.1 openafs/src/vol/nuke.c:1.13.2.2
*** openafs/src/vol/nuke.c:1.13.2.1	Wed Aug 25 03:14:19 2004
--- openafs/src/vol/nuke.c	Mon Oct 18 13:44:06 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/nuke.c,v 1.13.2.1 2004/08/25 07:14:19 shadow Exp $");
  
  #include &lt;rx/xdr.h&gt;
  #include &lt;afs/afsint.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/nuke.c,v 1.13.2.2 2004/10/18 17:44:06 shadow Exp $");
  
  #include &lt;rx/xdr.h&gt;
  #include &lt;afs/afsint.h&gt;
***************
*** 65,78 ****
      afs_int32 freePtr;		/* first free index in this table */
      Inode inode[MAXATONCE];	/* inode # */
      afs_int32 count[MAXATONCE];	/* link count */
! } *allInodes = 0;
  
  /* called with a structure specifying info about the inode, and our rock (which
   * is the volume ID.  Returns true if we should keep this inode, otherwise false.
   * Note that ainfo-&gt;u.param[0] is always the volume ID, for any vice inode.
   */
  static int
! NukeProc(struct ViceInodeInfo *ainfo, afs_int32 avolid)
  {
      struct ilist *ti;
      register afs_int32 i;
--- 65,78 ----
      afs_int32 freePtr;		/* first free index in this table */
      Inode inode[MAXATONCE];	/* inode # */
      afs_int32 count[MAXATONCE];	/* link count */
! };
  
  /* called with a structure specifying info about the inode, and our rock (which
   * is the volume ID.  Returns true if we should keep this inode, otherwise false.
   * Note that ainfo-&gt;u.param[0] is always the volume ID, for any vice inode.
   */
  static int
! NukeProc(struct ViceInodeInfo *ainfo, afs_int32 avolid, struct ilist *allInodes)
  {
      struct ilist *ti;
      register afs_int32 i;
***************
*** 113,119 ****
  {
      /* first process the partition containing this junk */
      struct afs_stat tstat;
!     struct ilist *ti, *ni;
      register afs_int32 code;
      int i, forceSal;
      char devName[64], wpath[100];
--- 113,119 ----
  {
      /* first process the partition containing this junk */
      struct afs_stat tstat;
!     struct ilist *ti, *ni, *li=NULL;
      register afs_int32 code;
      int i, forceSal;
      char devName[64], wpath[100];
***************
*** 127,132 ****
--- 127,133 ----
  #endif
  #endif /* AFS_NAMEI_ENV */
      IHandle_t *fileH;
+     struct ilist *allInodes = 0;
  
      if (avolid == 0)
  	return EINVAL;
***************
*** 169,179 ****
  #ifdef AFS_NAMEI_ENV
      code =
  	ListViceInodes(lastDevComp, aname, NULL, NukeProc, avolid, &amp;forceSal,
! 		       0, wpath);
  #else
      code =
  	ListViceInodes(lastDevComp, aname, "/tmp/vNukeXX", NukeProc, avolid,
! 		       &amp;forceSal, 0, wpath);
      unlink("/tmp/vNukeXX");	/* clean it up now */
  #endif
      if (code == 0) {
--- 170,180 ----
  #ifdef AFS_NAMEI_ENV
      code =
  	ListViceInodes(lastDevComp, aname, NULL, NukeProc, avolid, &amp;forceSal,
! 		       0, wpath, allInodes);
  #else
      code =
  	ListViceInodes(lastDevComp, aname, "/tmp/vNukeXX", NukeProc, avolid,
! 		       &amp;forceSal, 0, wpath, allInodes);
      unlink("/tmp/vNukeXX");	/* clean it up now */
  #endif
      if (code == 0) {
***************
*** 211,218 ****
  #endif /* AFS_NAMEI_ENV */
  	    }
  	    ni = ti-&gt;next;
! 	    free(ti);
  	}
  	code = 0;		/* we really don't care about it except for debugging */
  	allInodes = NULL;
  
--- 212,221 ----
  #endif /* AFS_NAMEI_ENV */
  	    }
  	    ni = ti-&gt;next;
! 	    if (li) free(li);
! 	    li = ti;
  	}
+ 	if (li) free(li);
  	code = 0;		/* we really don't care about it except for debugging */
  	allInodes = NULL;
  
***************
*** 236,243 ****
  	/* just free things */
  	for (ti = allInodes; ti; ti = ni) {
  	    ni = ti-&gt;next;
! 	    free(ti);
  	}
  	allInodes = NULL;
      }
      ReleaseWriteLock(&amp;localLock);
--- 239,248 ----
  	/* just free things */
  	for (ti = allInodes; ti; ti = ni) {
  	    ni = ti-&gt;next;
! 	    if (li) free(li);
! 	    li = ti;
  	}
+ 	if (li) free(li);
  	allInodes = NULL;
      }
      ReleaseWriteLock(&amp;localLock);
Index: openafs/src/vol/vol-salvage.c
diff -c openafs/src/vol/vol-salvage.c:1.41.2.1 openafs/src/vol/vol-salvage.c:1.41.2.2
*** openafs/src/vol/vol-salvage.c:1.41.2.1	Wed Aug 25 03:14:19 2004
--- openafs/src/vol/vol-salvage.c	Mon Oct 18 13:44:06 2004
***************
*** 92,98 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/vol-salvage.c,v 1.41.2.1 2004/08/25 07:14:19 shadow Exp $");
  
  #include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
--- 92,98 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/vol-salvage.c,v 1.41.2.2 2004/10/18 17:44:06 shadow Exp $");
  
  #include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
***************
*** 1520,1526 ****
  }
  
  int
! OnlyOneVolume(struct ViceInodeInfo *inodeinfo, VolumeId singleVolumeNumber)
  {
      if (inodeinfo-&gt;u.vnode.vnodeNumber == INODESPECIAL)
  	return (inodeinfo-&gt;u.special.parentId == singleVolumeNumber);
--- 1520,1526 ----
  }
  
  int
! OnlyOneVolume(struct ViceInodeInfo *inodeinfo, VolumeId singleVolumeNumber, void *rock)
  {
      if (inodeinfo-&gt;u.vnode.vnodeNumber == INODESPECIAL)
  	return (inodeinfo-&gt;u.special.parentId == singleVolumeNumber);
***************
*** 1556,1562 ****
      if ((err =
  	 ListViceInodes(dev, fileSysPath, path,
  			singleVolumeNumber ? OnlyOneVolume : 0,
! 			singleVolumeNumber, &amp;forceSal, forceR, wpath)) &lt; 0) {
  	if (err == -2) {
  	    Log("*** I/O error %d when writing a tmp inode file %s; Not salvaged %s ***\nIncrease space on partition or use '-tmpdir'\n", errno, path, dev);
  	    return -1;
--- 1556,1562 ----
      if ((err =
  	 ListViceInodes(dev, fileSysPath, path,
  			singleVolumeNumber ? OnlyOneVolume : 0,
! 			singleVolumeNumber, &amp;forceSal, forceR, wpath, NULL)) &lt; 0) {
  	if (err == -2) {
  	    Log("*** I/O error %d when writing a tmp inode file %s; Not salvaged %s ***\nIncrease space on partition or use '-tmpdir'\n", errno, path, dev);
  	    return -1;
Index: openafs/src/volser/volmain.c
diff -c openafs/src/volser/volmain.c:1.18 openafs/src/volser/volmain.c:1.18.2.1
*** openafs/src/volser/volmain.c:1.18	Sun Dec  7 17:49:44 2003
--- openafs/src/volser/volmain.c	Mon Oct 18 03:12:29 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/volmain.c,v 1.18 2003/12/07 22:49:44 jaltman Exp $");
  
  #include &lt;sys/types.h&gt;
  #ifdef AFS_NT40_ENV
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/volmain.c,v 1.18.2.1 2004/10/18 07:12:29 shadow Exp $");
  
  #include &lt;sys/types.h&gt;
  #ifdef AFS_NT40_ENV
***************
*** 100,106 ****
  		       }
  
  
! static
  MyBeforeProc(struct rx_call *acall)
  {
      VTRANS_LOCK;
--- 100,106 ----
  		       }
  
  
! static afs_int32
  MyBeforeProc(struct rx_call *acall)
  {
      VTRANS_LOCK;
***************
*** 109,115 ****
      return 0;
  }
  
! static
  MyAfterProc(struct rx_call *acall, afs_int32 code)
  {
      VTRANS_LOCK;
--- 109,115 ----
      return 0;
  }
  
! static afs_int32
  MyAfterProc(struct rx_call *acall, afs_int32 code)
  {
      VTRANS_LOCK;
***************
*** 121,127 ****
  /* Called every GCWAKEUP seconds to try to unlock all our partitions,
   * if we're idle and there are no active transactions 
   */
! static
  TryUnlock()
  {
      /* if there are no running calls, and there are no active transactions, then
--- 121,127 ----
  /* Called every GCWAKEUP seconds to try to unlock all our partitions,
   * if we're idle and there are no active transactions 
   */
! static void
  TryUnlock()
  {
      /* if there are no running calls, and there are no active transactions, then
***************
*** 135,141 ****
  }
  
  /* background daemon for timing out transactions */
! static
  BKGLoop()
  {
      struct timeval tv;
--- 135,141 ----
  }
  
  /* background daemon for timing out transactions */
! static void
  BKGLoop()
  {
      struct timeval tv;
***************
*** 161,167 ****
  
  /* Background daemon for sleeping so the volserver does not become I/O bound */
  afs_int32 TTsleep, TTrun;
! static
  BKGSleep()
  {
      struct volser_trans *tt;
--- 161,167 ----
  
  /* Background daemon for sleeping so the volserver does not become I/O bound */
  afs_int32 TTsleep, TTrun;
! static void
  BKGSleep()
  {
      struct volser_trans *tt;
***************
*** 194,202 ****
  
  #ifndef AFS_NT40_ENV
  int
! volser_syscall(a3, a4, a5)
!      afs_uint32 a3, a4;
!      void *a5;
  {
      afs_uint32 rcode;
      void (*old) ();
--- 194,200 ----
  
  #ifndef AFS_NT40_ENV
  int
! volser_syscall(afs_uint32 a3, afs_uint32 a4, void *a5)
  {
      afs_uint32 rcode;
      void (*old) ();
***************
*** 218,233 ****
  
  /* check whether caller is authorized to manage RX statistics */
  int
! vol_rxstat_userok(call)
!      struct rx_call *call;
  {
      return afsconf_SuperUser(tdir, call, NULL);
  }
  
  #include "AFS_component_version_number.c"
! main(argc, argv)
!      int argc;
!      char **argv;
  {
      register afs_int32 code;
      struct rx_securityClass *(securityObjects[3]);
--- 216,229 ----
  
  /* check whether caller is authorized to manage RX statistics */
  int
! vol_rxstat_userok(struct rx_call *call)
  {
      return afsconf_SuperUser(tdir, call, NULL);
  }
  
  #include "AFS_component_version_number.c"
! int 
! main(int argc, char **argv)
  {
      register afs_int32 code;
      struct rx_securityClass *(securityObjects[3]);
Index: openafs/src/volser/volprocs.c
diff -c openafs/src/volser/volprocs.c:1.34 openafs/src/volser/volprocs.c:1.34.2.1
*** openafs/src/volser/volprocs.c:1.34	Wed Jul 28 23:44:08 2004
--- openafs/src/volser/volprocs.c	Mon Oct 18 03:12:29 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/volprocs.c,v 1.34 2004/07/29 03:44:08 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;sys/types.h&gt;
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/volprocs.c,v 1.34.2.1 2004/10/18 07:12:29 shadow Exp $");
  
  #include &lt;stdio.h&gt;
  #include &lt;sys/types.h&gt;
***************
*** 425,431 ****
      if (error) {
  	Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
  	LogError(error);
! 	DeleteTrans(tt);
  	return EIO;
      }
      V_uniquifier(vp) = 1;
--- 425,431 ----
      if (error) {
  	Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
  	LogError(error);
! 	DeleteTrans(tt, 1);
  	return EIO;
      }
      V_uniquifier(vp) = 1;
***************
*** 442,448 ****
      if (error) {
  	Log("1 Volser: create UpdateVolume failed, code %d\n", error);
  	LogError(error);
! 	DeleteTrans(tt);
  	VDetachVolume(&amp;junk, vp);	/* rather return the real error code */
  	return error;
      }
--- 442,448 ----
      if (error) {
  	Log("1 Volser: create UpdateVolume failed, code %d\n", error);
  	LogError(error);
! 	DeleteTrans(tt, 1);
  	VDetachVolume(&amp;junk, vp);	/* rather return the real error code */
  	return error;
      }
***************
*** 677,683 ****
  	error = VOLSERTRELE_ERROR;
  	goto fail;
      }
!     DeleteTrans(ttc);
      return 0;
  
    fail:
--- 677,683 ----
  	error = VOLSERTRELE_ERROR;
  	goto fail;
      }
!     DeleteTrans(ttc, 1);
      return 0;
  
    fail:
***************
*** 690,696 ****
  	TRELE(tt);
      }
      if (ttc)
! 	DeleteTrans(ttc);
      return error;
  }
  
--- 690,696 ----
  	TRELE(tt);
      }
      if (ttc)
! 	DeleteTrans(ttc, 1);
      return error;
  }
  
***************
*** 840,846 ****
  	goto fail;
      }
  
!     DeleteTrans(ttc);
  
      {
  	struct DiskPartition *tpartp = originalvp-&gt;partition;
--- 840,846 ----
  	goto fail;
      }
  
!     DeleteTrans(ttc, 1);
  
      {
  	struct DiskPartition *tpartp = originalvp-&gt;partition;
***************
*** 856,862 ****
  	TRELE(tt);
      }
      if (ttc)
! 	DeleteTrans(ttc);
      return error;
  }
  
--- 856,862 ----
  	TRELE(tt);
      }
      if (ttc)
! 	DeleteTrans(ttc, 1);
      return error;
  }
  
***************
*** 913,919 ****
  	/* give up */
  	if (tv)
  	    VDetachVolume(&amp;code, tv);
! 	DeleteTrans(tt);
  	return error;
      }
      tt-&gt;volume = tv;
--- 913,919 ----
  	/* give up */
  	if (tv)
  	    VDetachVolume(&amp;code, tv);
! 	DeleteTrans(tt, 1);
  	return error;
      }
      tt-&gt;volume = tv;
***************
*** 1387,1393 ****
  	return ENOENT;
      }
      *rcode = tt-&gt;returnCode;
!     DeleteTrans(tt);		/* this does an implicit TRELE */
  
      return 0;
  }
--- 1387,1393 ----
  	return ENOENT;
      }
      *rcode = tt-&gt;returnCode;
!     DeleteTrans(tt, 1);		/* this does an implicit TRELE */
  
      return 0;
  }
***************
*** 1540,1549 ****
  	td-&gt;maxquota = astatus-&gt;maxquota;
      if (astatus-&gt;dayUse != -1)
  	td-&gt;dayUse = astatus-&gt;dayUse;
-     if (astatus-&gt;creationDate != -1)
- 	td-&gt;creationDate = astatus-&gt;creationDate;
-     if (astatus-&gt;updateDate != -1)
- 	td-&gt;updateDate = astatus-&gt;updateDate;
      VUpdateVolume(&amp;error, tv);
      tt-&gt;rxCallPtr = (struct rx_call *)0;
      if (TRELE(tt))
--- 1540,1545 ----
***************
*** 1868,1874 ****
  	tv = (Volume *) 0;
      }
      if (ttc) {
! 	DeleteTrans(ttc);
  	ttc = (struct volser_trans *)0;
      }
  
--- 1864,1870 ----
  	tv = (Volume *) 0;
      }
      if (ttc) {
! 	DeleteTrans(ttc, 1);
  	ttc = (struct volser_trans *)0;
      }
  
***************
*** 2099,2105 ****
  	tv = (Volume *) 0;
      }
      if (ttc) {
! 	DeleteTrans(ttc);
  	ttc = (struct volser_trans *)0;
      }
  
--- 2095,2101 ----
  	tv = (Volume *) 0;
      }
      if (ttc) {
! 	DeleteTrans(ttc, 1);
  	ttc = (struct volser_trans *)0;
      }
  
***************
*** 2241,2247 ****
  
        drop:
  	if (ttc) {
! 	    DeleteTrans(ttc);
  	    ttc = (struct volser_trans *)0;
  	}
  	pntr++;
--- 2237,2243 ----
  
        drop:
  	if (ttc) {
! 	    DeleteTrans(ttc, 1);
  	    ttc = (struct volser_trans *)0;
  	}
  	pntr++;
***************
*** 2258,2264 ****
  		    tv = (Volume *) 0;
  		}
  		if (ttc) {
! 		    DeleteTrans(ttc);
  		    ttc = (struct volser_trans *)0;
  		}
  		closedir(dirp);
--- 2254,2260 ----
  		    tv = (Volume *) 0;
  		}
  		if (ttc) {
! 		    DeleteTrans(ttc, 1);
  		    ttc = (struct volser_trans *)0;
  		}
  		closedir(dirp);
***************
*** 2276,2282 ****
  	    tv = (Volume *) 0;
  	}
  	if (ttc) {
! 	    DeleteTrans(ttc);
  	    ttc = (struct volser_trans *)0;
  	}
  	GetNextVol(dirp, volname, &amp;volid);
--- 2272,2278 ----
  	    tv = (Volume *) 0;
  	}
  	if (ttc) {
! 	    DeleteTrans(ttc, 1);
  	    ttc = (struct volser_trans *)0;
  	}
  	GetNextVol(dirp, volname, &amp;volid);
***************
*** 2284,2290 ****
      }
      closedir(dirp);
      if (ttc)
! 	DeleteTrans(ttc);
  
      return 0;
  }
--- 2280,2286 ----
      }
      closedir(dirp);
      if (ttc)
! 	DeleteTrans(ttc, 1);
  
      return 0;
  }
***************
*** 2495,2501 ****
  	 * Drop the transaction we have for this volume.
  	 */
  	if (ttc) {
! 	    DeleteTrans(ttc);
  	    ttc = (struct volser_trans *)0;
  	}
  
--- 2491,2497 ----
  	 * Drop the transaction we have for this volume.
  	 */
  	if (ttc) {
! 	    DeleteTrans(ttc, 1);
  	    ttc = (struct volser_trans *)0;
  	}
  
***************
*** 2522,2528 ****
  		    tv = (Volume *) 0;
  		}
  		if (ttc) {
! 		    DeleteTrans(ttc);
  		    ttc = (struct volser_trans *)0;
  		}
  		closedir(dirp);
--- 2518,2524 ----
  		    tv = (Volume *) 0;
  		}
  		if (ttc) {
! 		    DeleteTrans(ttc, 1);
  		    ttc = (struct volser_trans *)0;
  		}
  		closedir(dirp);
***************
*** 2550,2556 ****
  	    tv = (Volume *) 0;
  	}
  	if (ttc) {
! 	    DeleteTrans(ttc);
  	    ttc = (struct volser_trans *)0;
  	}
  	GetNextVol(dirp, volname, &amp;volid);
--- 2546,2552 ----
  	    tv = (Volume *) 0;
  	}
  	if (ttc) {
! 	    DeleteTrans(ttc, 1);
  	    ttc = (struct volser_trans *)0;
  	}
  	GetNextVol(dirp, volname, &amp;volid);
***************
*** 2562,2568 ****
       */
      closedir(dirp);
      if (ttc)
! 	DeleteTrans(ttc);
      return (0);
  
  }				/*SAFSVolXListVolumes */
--- 2558,2564 ----
       */
      closedir(dirp);
      if (ttc)
! 	DeleteTrans(ttc, 1);
      return (0);
  
  }				/*SAFSVolXListVolumes */
Index: openafs/src/volser/voltrans.c
diff -c openafs/src/volser/voltrans.c:1.10 openafs/src/volser/voltrans.c:1.10.2.1
*** openafs/src/volser/voltrans.c:1.10	Fri Nov 21 21:57:04 2003
--- openafs/src/volser/voltrans.c	Mon Oct 18 03:12:29 2004
***************
*** 18,24 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/voltrans.c,v 1.10 2003/11/22 02:57:04 shadow Exp $");
  
  #ifdef AFS_NT40_ENV
  #include &lt;afs/afsutil.h&gt;
--- 18,24 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/voltrans.c,v 1.10.2.1 2004/10/18 07:12:29 shadow Exp $");
  
  #ifdef AFS_NT40_ENV
  #include &lt;afs/afsutil.h&gt;
***************
*** 79,87 ****
  
  /* create a new transaction, returning ptr to same with high ref count */
  struct volser_trans *
! NewTrans(avol, apart)
!      afs_int32 avol;
!      afs_int32 apart;
  {
      /* set volid, next, partition */
      register struct volser_trans *tt;
--- 79,85 ----
  
  /* create a new transaction, returning ptr to same with high ref count */
  struct volser_trans *
! NewTrans(afs_int32 avol, afs_int32 apart)
  {
      /* set volid, next, partition */
      register struct volser_trans *tt;
***************
*** 117,124 ****
  
  /* find a trans, again returning with high ref count */
  struct volser_trans *
! FindTrans(atrans)
!      register afs_int32 atrans;
  {
      register struct volser_trans *tt;
      VTRANS_LOCK;
--- 115,121 ----
  
  /* find a trans, again returning with high ref count */
  struct volser_trans *
! FindTrans(register afs_int32 atrans)
  {
      register struct volser_trans *tt;
      VTRANS_LOCK;
***************
*** 135,142 ****
  }
  
  /* delete transaction if refcount == 1, otherwise queue delete for later.  Does implicit TRELE */
! DeleteTrans(atrans)
!      register struct volser_trans *atrans;
  {
      register struct volser_trans *tt, **lt;
      afs_int32 error;
--- 132,139 ----
  }
  
  /* delete transaction if refcount == 1, otherwise queue delete for later.  Does implicit TRELE */
! afs_int32 
! DeleteTrans(register struct volser_trans *atrans, afs_int32 lock)
  {
      register struct volser_trans *tt, **lt;
      afs_int32 error;
***************
*** 149,155 ****
      }
  
      /* otherwise we zap it ourselves */
!     VTRANS_LOCK;
      lt = &amp;allTrans;
      for (tt = *lt; tt; lt = &amp;tt-&gt;next, tt = *lt) {
  	if (tt == atrans) {
--- 146,152 ----
      }
  
      /* otherwise we zap it ourselves */
!     if (lock) VTRANS_LOCK;
      lt = &amp;allTrans;
      for (tt = *lt; tt; lt = &amp;tt-&gt;next, tt = *lt) {
  	if (tt == atrans) {
***************
*** 158,176 ****
  	    tt-&gt;volume = NULL;
  	    *lt = tt-&gt;next;
  	    free(tt);
! 	    VTRANS_UNLOCK;
  	    return 0;
  	}
      }
!     VTRANS_UNLOCK;
      return -1;			/* failed to find the transaction in the generic list */
  }
  
  /* THOLD is a macro defined in volser.h */
  
  /* put a transaction back */
! TRELE(at)
!      register struct volser_trans *at;
  {
      if (at-&gt;refCount == 0) {
  	Log("TRELE: bad refcount\n");
--- 155,173 ----
  	    tt-&gt;volume = NULL;
  	    *lt = tt-&gt;next;
  	    free(tt);
! 	    if (lock) VTRANS_UNLOCK;
  	    return 0;
  	}
      }
!     if (lock) VTRANS_UNLOCK;
      return -1;			/* failed to find the transaction in the generic list */
  }
  
  /* THOLD is a macro defined in volser.h */
  
  /* put a transaction back */
! afs_int32 
! TRELE(register struct volser_trans *at)
  {
      if (at-&gt;refCount == 0) {
  	Log("TRELE: bad refcount\n");
***************
*** 179,185 ****
  
      at-&gt;time = FT_ApproxTime();	/* we're still using it */
      if (at-&gt;refCount == 1 &amp;&amp; (at-&gt;tflags &amp; TTDeleted)) {
! 	DeleteTrans(at);
  	return 0;
      }
      /* otherwise simply drop refcount */
--- 176,182 ----
  
      at-&gt;time = FT_ApproxTime();	/* we're still using it */
      if (at-&gt;refCount == 1 &amp;&amp; (at-&gt;tflags &amp; TTDeleted)) {
! 	DeleteTrans(at, 1);
  	return 0;
      }
      /* otherwise simply drop refcount */
***************
*** 191,196 ****
--- 188,194 ----
  #define	OLDTRANSTIME	    600	/* seconds */
  #define	OLDTRANSWARN	    300	/* seconds */
  static int GCDeletes = 0;
+ afs_int32
  GCTrans()
  {
      register struct volser_trans *tt, *nt;
***************
*** 212,218 ****
  	if (tt-&gt;time + OLDTRANSTIME &lt; now) {
  	    Log("trans %u on volume %u has timed out\n", tt-&gt;tid, tt-&gt;volid);
  	    tt-&gt;refCount++;	/* we're using it now */
! 	    DeleteTrans(tt);	/* drops refCount or deletes it */
  	    GCDeletes++;
  	}
      }
--- 210,216 ----
  	if (tt-&gt;time + OLDTRANSTIME &lt; now) {
  	    Log("trans %u on volume %u has timed out\n", tt-&gt;tid, tt-&gt;volid);
  	    tt-&gt;refCount++;	/* we're using it now */
! 	    DeleteTrans(tt, 0);	/* drops refCount or deletes it */
  	    GCDeletes++;
  	}
      }
Index: openafs/src/volser/vsutils.c
diff -c openafs/src/volser/vsutils.c:1.16 openafs/src/volser/vsutils.c:1.16.2.1
*** openafs/src/volser/vsutils.c:1.16	Sun Dec  7 17:49:46 2003
--- openafs/src/volser/vsutils.c	Mon Oct 18 03:12:29 2004
***************
*** 11,17 ****
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/vsutils.c,v 1.16 2003/12/07 22:49:46 jaltman Exp $");
  
  #include &lt;afs/stds.h&gt;
  #ifdef AFS_NT40_ENV
--- 11,17 ----
  #include &lt;afs/param.h&gt;
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/vsutils.c,v 1.16.2.1 2004/10/18 07:12:29 shadow Exp $");
  
  #include &lt;afs/stds.h&gt;
  #ifdef AFS_NT40_ENV
***************
*** 445,572 ****
      static struct rx_connection *serverconns[VLDB_MAXSERVERS];
      char cellstr[64];
  
! 
!     code = rx_Init(0);
!     if (code) {
! 	fprintf(STDERR, "vsu_ClientInit: could not initialize rx.\n");
! 	return code;
!     }
!     rx_SetRxDeadTime(90);
! 
!     if (sauth) {		/* -localauth */
! 	tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
! 	if (!tdir) {
! 	    fprintf(STDERR,
! 		    "vsu_ClientInit: Could not process files in configuration directory (%s).\n",
! 		    AFSDIR_SERVER_ETC_DIRPATH);
! 	    return -1;
! 	}
! 	code = afsconf_ClientAuth(tdir, &amp;sc, &amp;scIndex);	/* sets sc,scIndex */
! 	if (code) {
! 	    fprintf(STDERR,
! 		    "vsu_ClientInit: Could not get security object for -localAuth\n");
! 	    return -1;
! 	}
! 	code =
! 	    afsconf_GetCellInfo(tdir, tdir-&gt;cellName, AFSCONF_VLDBSERVICE,
! 				&amp;info);
! 	if (code) {
! 	    fprintf(STDERR,
! 		    "vsu_ClientInit: can't find cell %s's hosts in %s/%s\n",
! 		    cellName, AFSDIR_SERVER_ETC_DIRPATH,
! 		    AFSDIR_CELLSERVDB_FILE);
! 	    exit(1);
! 	}
!     } else {			/* not -localauth */
! 	tdir = afsconf_Open(confDir);
! 	if (!tdir) {
! 	    fprintf(STDERR,
! 		    "vsu_ClientInit: Could not process files in configuration directory (%s).\n",
! 		    confDir);
! 	    return -1;
! 	}
! 
! 	if (!cellName) {
! 	    code = afsconf_GetLocalCell(tdir, cellstr, sizeof(cellstr));
! 	    if (code) {
! 		fprintf(STDERR,
! 			"vsu_ClientInit: can't get local cellname, check %s/%s\n",
! 			confDir, AFSDIR_THISCELL_FILE);
! 		exit(1);
! 	    }
! 	    cellName = cellstr;
! 	}
! 
! 	code =
! 	    afsconf_GetCellInfo(tdir, cellName, AFSCONF_VLDBSERVICE, &amp;info);
! 	if (code) {
! 	    fprintf(STDERR,
! 		    "vsu_ClientInit: can't find cell %s's hosts in %s/%s\n",
! 		    cellName, confDir, AFSDIR_CELLSERVDB_FILE);
! 	    exit(1);
! 	}
! 	if (noAuthFlag)		/* -noauth */
! 	    scIndex = 0;
! 	else {			/* not -noauth */
! 	    strcpy(sname.cell, info.name);
! 	    sname.instance[0] = 0;
! 	    strcpy(sname.name, "afs");
! 	    code = ktc_GetToken(&amp;sname, &amp;ttoken, sizeof(ttoken), NULL);
! 	    if (code) {		/* did not get ticket */
! 		fprintf(STDERR,
! 			"vsu_ClientInit: Could not get afs tokens, running unauthenticated.\n");
! 		scIndex = 0;
! 	    } else {		/* got a ticket */
! 		scIndex = 2;
! 		if ((ttoken.kvno &lt; 0) || (ttoken.kvno &gt; 255)) {
! 		    fprintf(STDERR,
! 			    "vsu_ClientInit: funny kvno (%d) in ticket, proceeding\n",
! 			    ttoken.kvno);
! 		}
! 	    }
! 	}
! 
! 	switch (scIndex) {
! 	case 0:
! 	    sc = rxnull_NewClientSecurityObject();
! 	    break;
! 	case 2:
! 	    sc = rxkad_NewClientSecurityObject(vsu_rxkad_level,
! 					       &amp;ttoken.sessionKey,
! 					       ttoken.kvno, ttoken.ticketLen,
! 					       ttoken.ticket);
! 	    break;
! 	default:
! 	    fprintf(STDERR, "vsu_ClientInit: unsupported security index %d\n",
! 		    scIndex);
! 	    exit(1);
! 	    break;
! 	}
!     }
! 
!     afsconf_Close(tdir);
! 
!     if (secproc)		/* tell UV module about default authentication */
! 	(*secproc) (sc, scIndex);
!     if (info.numServers &gt; VLDB_MAXSERVERS) {
! 	fprintf(STDERR,
! 		"vsu_ClientInit: info.numServers=%d (&gt; VLDB_MAXSERVERS=%d)\n",
! 		info.numServers, VLDB_MAXSERVERS);
! 	exit(1);
!     }
!     for (i = 0; i &lt; info.numServers; i++) {
! 	serverconns[i] =
! 	    rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
! 			     info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
! 			     scIndex);
!     }
!     *uclientp = 0;
!     code = ubik_ClientInit(serverconns, uclientp);
!     if (code) {
! 	fprintf(STDERR, "vsu_ClientInit: ubik client init failed.\n");
! 	return code;
!     }
!     return 0;
  }
  
  
--- 445,454 ----
      static struct rx_connection *serverconns[VLDB_MAXSERVERS];
      char cellstr[64];
  
!     return ugen_ClientInit(noAuthFlag, confDir, cellName, sauth, uclientp, 
! 			   secproc, "vsu_ClientInit", vsu_rxkad_level,
! 			   VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 90,
! 			   0, 0, USER_SERVICE_ID);
  }
  
  
</pre></body></html>