Index: openafs/src/NTMakefile
diff -c openafs/src/NTMakefile:1.27.2.8 openafs/src/NTMakefile:1.27.2.9
*** openafs/src/NTMakefile:1.27.2.8	Tue Mar 11 13:02:04 2008
--- openafs/src/NTMakefile	Sat Jun 28 19:42:54 2008
***************
*** 18,23 ****
--- 18,24 ----
  
  # These three macros define the source, object, and destination folders
  SRC=$(AFSROOT)\src
+ DOC=$(AFSROOT)\doc
  
  #If AFS_OBJDIR is not defined then use obj as relative obj folder
  !IFNDEF AFS_OBJDIR
***************
*** 46,52 ****
  	$(NTMAKE)
  	$(CD) ..\..
  
! procmgmt_headers:config
       echo ***** $@
  	$(DOCD) $(SRC)\procmgmt
  	$(CD) $(SRC)\procmgmt
--- 47,60 ----
  	$(NTMAKE)
  	$(CD) ..\..
  
! man-pages: config
!      echo ***** $@
!         $(DOCD) $(DOC)\man-pages
!         $(CD) $(DOC)\man-pages
!         $(NTMAKE)
!         $(CD) ..\..
! 
! procmgmt_headers: man-pages
       echo ***** $@
  	$(DOCD) $(SRC)\procmgmt
  	$(CD) $(SRC)\procmgmt
***************
*** 65,71 ****
  	$(DOCD) $(SRC)\lwp
  	$(CD) $(SRC)\lwp
  	$(NTMAKE_HEADERS)
! 	$(CD) ..\..\..
  
  util: procmgmt_headers afsreg_headers lwp_headers
       echo ***** $@
--- 73,79 ----
  	$(DOCD) $(SRC)\lwp
  	$(CD) $(SRC)\lwp
  	$(NTMAKE_HEADERS)
! 	$(CD) ..\..
  
  util: procmgmt_headers afsreg_headers lwp_headers
       echo ***** $@
Index: openafs/src/ntbuild.bat
diff -c openafs/src/ntbuild.bat:1.18.4.1 openafs/src/ntbuild.bat:1.18.4.2
*** openafs/src/ntbuild.bat:1.18.4.1	Mon Apr 21 12:03:56 2008
--- openafs/src/ntbuild.bat	Fri May  9 11:10:10 2008
***************
*** 50,55 ****
--- 50,58 ----
  REM Location of WDK/DDK (8.3 short name)
  set NTDDKDIR=c:\progra~1\micros~5
  
+ REM Location of Microsoft IDN Normalization SDK
+ set MSIDNNLS=C:\progra~1\MI5913~1
+ 
  REM ########################################################################
  REM NTMakefile optional definitions:
  REM
***************
*** 110,116 ****
  
  set AFSDEV_BUILDTYPE=%AFSBLD_TYPE%
  
! set AFSDEV_INCLUDE=%MSSDKDIR%\include;%MSVCDIR%\include
  IF "%AFSVER_CL%" == "1400" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
  IF "%AFSVER_CL%" == "1310" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
  IF "%AFSVER_CL%" == "1300" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
--- 113,119 ----
  
  set AFSDEV_BUILDTYPE=%AFSBLD_TYPE%
  
! set AFSDEV_INCLUDE=%MSSDKDIR%\include;%MSVCDIR%\include;%MSIDNNLS%\include
  IF "%AFSVER_CL%" == "1400" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
  IF "%AFSVER_CL%" == "1310" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
  IF "%AFSVER_CL%" == "1300" set AFSDEV_INCLUDE=%AFSDEV_INCLUDE%;%MSVCDIR%\atlmfc\include
Index: openafs/src/WINNT/afs_setup_utils/NTMakefile
diff -c openafs/src/WINNT/afs_setup_utils/NTMakefile:1.10 openafs/src/WINNT/afs_setup_utils/NTMakefile:1.10.4.1
*** openafs/src/WINNT/afs_setup_utils/NTMakefile:1.10	Sun Nov 20 20:55:59 2005
--- openafs/src/WINNT/afs_setup_utils/NTMakefile	Wed Jul  2 08:48:01 2008
***************
*** 81,88 ****
      $(DESTDIR)\lib\afs\afsutil.lib
  
  $(AFSRM_EXEFILE): $(AFSRM_EXEOBJS) $(AFSRM_EXELIBS)
!     $(EXECONLINK)
          $(_VC_MANIFEST_EMBED_EXE)
  
  ############################################################################
  
--- 81,89 ----
      $(DESTDIR)\lib\afs\afsutil.lib
  
  $(AFSRM_EXEFILE): $(AFSRM_EXEOBJS) $(AFSRM_EXELIBS)
!         $(EXECONLINK)
          $(_VC_MANIFEST_EMBED_EXE)
+         $(CODESIGN_USERLAND)
  
  ############################################################################
  
***************
*** 132,137 ****
--- 133,139 ----
      $(DLLGUILINK) -entry:DllEntryPoint /DEF:install_utils.def $(VCLIBS)
          $(_VC_MANIFEST_EMBED_DLL)
      $(DLLPREP)
+         $(CODESIGN_USERLAND)
      $(COPY) $*.lib $(ILIBDIR)
      $(DEL) $*.lib $*.exp
  
***************
*** 139,144 ****
--- 141,147 ----
      $(DLLGUILINK) -entry:DllEntryPoint /DEF:server_uninst.def $(VCLIBS)
          $(_VC_MANIFEST_EMBED_DLL)
      $(DLLPREP)
+         $(CODESIGN_USERLAND)
      $(COPY) $*.lib $(ILIBDIR)
      $(DEL) $*.lib $*.exp
  
***************
*** 146,151 ****
--- 149,155 ----
      $(DLLGUILINK) -entry:DllEntryPoint /DEF:client_uninst.def $(VCLIBS)
          $(_VC_MANIFEST_EMBED_DLL)
      $(DLLPREP)
+         $(CODESIGN_USERLAND)
      $(COPY) $*.lib $(ILIBDIR)
      $(DEL) $*.lib $*.exp
  
***************
*** 153,158 ****
--- 157,163 ----
      $(DLLGUILINK) -entry:DllEntryPoint /DEF:cc_uninst.def $(VCLIBS)
          $(_VC_MANIFEST_EMBED_DLL)
      $(DLLPREP)
+         $(CODESIGN_USERLAND)
      $(COPY) $*.lib $(ILIBDIR)
      $(DEL) $*.lib $*.exp
  
***************
*** 160,165 ****
--- 165,171 ----
      $(DLLGUILINK) -entry:DllEntryPoint /DEF:light_client_uninst.def $(VCLIBS)
          $(_VC_MANIFEST_EMBED_DLL)
      $(DLLPREP)
+         $(CODESIGN_USERLAND)
      $(COPY) $*.lib $(ILIBDIR)
      $(DEL) $*.lib $*.exp
  
***************
*** 167,172 ****
--- 173,179 ----
      $(DLLGUILINK) -entry:DllEntryPoint /DEF:docs_uninst.def $(VCLIBS)
          $(_VC_MANIFEST_EMBED_DLL)
      $(DLLPREP)
+         $(CODESIGN_USERLAND)
      $(COPY) $*.lib $(ILIBDIR)
      $(DEL) $*.lib $*.exp
  
Index: openafs/src/WINNT/afs_setup_utils/lang/NTMakefile
diff -c openafs/src/WINNT/afs_setup_utils/lang/NTMakefile:1.4 openafs/src/WINNT/afs_setup_utils/lang/NTMakefile:1.4.14.1
*** openafs/src/WINNT/afs_setup_utils/lang/NTMakefile:1.4	Fri Nov 21 02:59:38 2003
--- openafs/src/WINNT/afs_setup_utils/lang/NTMakefile	Wed Jul  2 08:48:03 2008
***************
*** 44,49 ****
--- 44,50 ----
  $(DLLFILE) : $(DLLOBJS)
  	$(DLLRESLINK)
  	$(DLLPREP) 
+         $(CODESIGN_USERLAND)
  
  install : $(DLLFILE)
  
Index: openafs/src/WINNT/afsadmsvr/NTMakefile
diff -c openafs/src/WINNT/afsadmsvr/NTMakefile:1.8.4.2 openafs/src/WINNT/afsadmsvr/NTMakefile:1.8.4.3
*** openafs/src/WINNT/afsadmsvr/NTMakefile:1.8.4.2	Tue Feb 12 08:32:48 2008
--- openafs/src/WINNT/afsadmsvr/NTMakefile	Wed Jul  2 08:48:05 2008
***************
*** 146,151 ****
--- 146,152 ----
  	$(EXECONLINK)  $(VCLIBS)
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP) 
+         $(CODESIGN_USERLAND)
  
  install : \
  	$(IDLFILES) \
Index: openafs/src/WINNT/afsapplib/NTMakefile
diff -c openafs/src/WINNT/afsapplib/NTMakefile:1.12.4.1 openafs/src/WINNT/afsapplib/NTMakefile:1.12.4.2
*** openafs/src/WINNT/afsapplib/NTMakefile:1.12.4.1	Tue Feb 12 08:32:50 2008
--- openafs/src/WINNT/afsapplib/NTMakefile	Wed Jul  2 08:48:07 2008
***************
*** 129,134 ****
--- 129,135 ----
  	$(DLLGUILINK) $(LOCALLINKFLAGS) $(VCLIBS)
          $(_VC_MANIFEST_EMBED_DLL)
  	$(DLLPREP)
+         $(CODESIGN_USERLAND)
  	$(COPY) $*.lib $(ILIBDIR)
  	$(DEL) $*.lib $*.exp
  
Index: openafs/src/WINNT/afsapplib/lang/NTMakefile
diff -c openafs/src/WINNT/afsapplib/lang/NTMakefile:1.6 openafs/src/WINNT/afsapplib/lang/NTMakefile:1.6.4.1
*** openafs/src/WINNT/afsapplib/lang/NTMakefile:1.6	Sun Nov 20 20:56:04 2005
--- openafs/src/WINNT/afsapplib/lang/NTMakefile	Wed Jul  2 08:48:11 2008
***************
*** 46,51 ****
--- 46,52 ----
  	$(DLLRESLINK)
          $(_VC_MANIFEST_EMBED_DLL)
  	$(DLLPREP) 
+         $(CODESIGN_USERLAND)
  
  install : $(DLLFILE)
  
Index: openafs/src/WINNT/afsapplib/test/NTMakefile
diff -c openafs/src/WINNT/afsapplib/test/NTMakefile:1.5 openafs/src/WINNT/afsapplib/test/NTMakefile:1.5.4.1
*** openafs/src/WINNT/afsapplib/test/NTMakefile:1.5	Sun Nov 20 20:56:05 2005
--- openafs/src/WINNT/afsapplib/test/NTMakefile	Wed Jul  2 08:48:12 2008
***************
*** 40,45 ****
--- 40,46 ----
  	$(EXEGUILINK) comctl32.lib shell32.lib
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP) 
+         $(CODESIGN_USERLAND)
  
  test : $(EXEFILE)
  
Index: openafs/src/WINNT/afsd/NTMakefile
diff -c openafs/src/WINNT/afsd/NTMakefile:1.46.2.11 openafs/src/WINNT/afsd/NTMakefile:1.46.2.14
*** openafs/src/WINNT/afsd/NTMakefile:1.46.2.11	Wed Mar 19 09:59:29 2008
--- openafs/src/WINNT/afsd/NTMakefile	Wed Jul  2 08:48:12 2008
***************
*** 5,11 ****
  # License.  For details, see the LICENSE file in the top-level source
  # directory or online at http://www.openafs.org/dl/license10.html
  
! AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL"  -I..\kfw\inc\loadfuncs -I..\kfw\inc\krb5 -I..\kfw\inc\leash
  AFSDEV_NETGUI = 1
  RELDIR=WINNT\afsd
  !INCLUDE ..\..\config\NTMakefile.$(SYS_NAME)
--- 5,11 ----
  # License.  For details, see the LICENSE file in the top-level source
  # directory or online at http://www.openafs.org/dl/license10.html
  
! AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL"  -I..\kfw\inc\loadfuncs -I..\kfw\inc\krb5 -I..\kfw\inc\leash -DSMB_UNICODE
  AFSDEV_NETGUI = 1
  RELDIR=WINNT\afsd
  !INCLUDE ..\..\config\NTMakefile.$(SYS_NAME)
***************
*** 65,70 ****
--- 65,71 ----
  	$(INCFILEDIR)\cm_freelance.h \
          $(INCFILEDIR)\cm_memmap.h \
  	$(INCFILEDIR)\cm_performance.h \
+         $(INCFILEDIR)\cm_nls.h \
          $(INCFILEDIR)\afsd_eventlog.h \
          $(INCFILEDIR)\afsd_eventmessages.h \
          $(INCFILEDIR)\afskfw.h \
***************
*** 74,80 ****
  	afsrpc.h $(OUT)\afsrpc_c.obj
  
  CONFOBJS=$(OUT)\cm_config.obj \
!          $(OUT)\cm_dns.obj
  
  $(CONFOBJS):
  
--- 75,82 ----
  	afsrpc.h $(OUT)\afsrpc_c.obj
  
  CONFOBJS=$(OUT)\cm_config.obj \
!          $(OUT)\cm_dns.obj \
!          $(OUT)\cm_nls.obj
  
  $(CONFOBJS):
  
***************
*** 120,125 ****
--- 122,128 ----
  	$(OUT)\cm_rpc.obj \
          $(OUT)\cm_memmap.obj \
          $(OUT)\cm_performance.obj \
+         $(OUT)\cm_nls.obj \
  	$(OUT)\afsrpc_s.obj \
  !IFDEF OSICRASH
  	$(OUT)\afsdcrash.obj \
***************
*** 134,140 ****
  $(OUT)\cm_conn.obj: cm_conn.c
  	$(C2OBJ) -DAFS_PTHREAD_ENV /Fo$@ $**
  
! FSOBJS=$(OUT)\fs.obj $(OUT)\fs_utils.obj
  
  CMDBGOBJS=$(OUT)\cmdebug.obj
  
--- 137,144 ----
  $(OUT)\cm_conn.obj: cm_conn.c
  	$(C2OBJ) -DAFS_PTHREAD_ENV /Fo$@ $**
  
! FSOBJS=$(OUT)\fs.obj \
!        $(OUT)\fs_utils.obj
  
  CMDBGOBJS=$(OUT)\cmdebug.obj
  
***************
*** 188,193 ****
--- 192,198 ----
  	$(DLLGUILINK) -def:libafsconf.def dnsapi.lib mpr.lib shell32.lib
          $(_VC_MANIFEST_EMBED_DLL)
  	$(DLLPREP)
+         $(CODESIGN_USERLAND)
  	$(COPY) $*.lib $(ILIBDIR)
  	$(DEL) $*.lib $*.exp
  
***************
*** 225,231 ****
  LOGON_DLLOBJS =\
      $(OUT)\afslogon.obj \
      $(OUT)\logon_ad.obj \
!     $(OUT)\afslogon.res
  
  LOGON_DLLLIBS =\
      $(DESTDIR)\lib\afsauthent.lib \
--- 230,237 ----
  LOGON_DLLOBJS =\
      $(OUT)\afslogon.obj \
      $(OUT)\logon_ad.obj \
!     $(OUT)\afslogon.res \
!     $(OUT)\cm_nls.obj
  
  LOGON_DLLLIBS =\
      $(DESTDIR)\lib\afsauthent.lib \
***************
*** 252,257 ****
--- 258,264 ----
  	$(DLLGUILINK) $(LOGONLINKFLAGS) -def:afslogon.def $(LOGON_DLLSDKLIBS)
          $(_VC_MANIFEST_EMBED_DLL)
  	$(DLLPREP)
+         $(CODESIGN_USERLAND)
  	$(COPY) $*.lib $(DESTDIR)\lib
  	$(DEL) $*.lib $*.exp
  
***************
*** 277,284 ****
  ############################################################################
  # Install target; primary makefile target
  
! install_objs: $(OUT)\cm_dns.obj $(OUT)\cm_config.obj $(LANAHELPERLIB) $(OUT)\afsicf.obj
       $(COPY) $(OUT)\cm_dns.obj $(DESTDIR)\lib
       $(COPY) $(OUT)\cm_config.obj $(DESTDIR)\lib
       $(COPY) $(OUT)\afsicf.obj $(DESTDIR)\lib
  
--- 284,292 ----
  ############################################################################
  # Install target; primary makefile target
  
! install_objs: $(OUT)\cm_dns.obj $(OUT)\cm_config.obj $(OUT)\cm_nls.obj $(LANAHELPERLIB) $(OUT)\afsicf.obj
       $(COPY) $(OUT)\cm_dns.obj $(DESTDIR)\lib
+      $(COPY) $(OUT)\cm_nls.obj $(DESTDIR)\lib
       $(COPY) $(OUT)\cm_config.obj $(DESTDIR)\lib
       $(COPY) $(OUT)\afsicf.obj $(DESTDIR)\lib
  
***************
*** 336,342 ****
  	$(DESTDIR)\lib\afsrx.lib \
  	$(DESTDIR)\lib\afslwp.lib \
  	$(DESTDIR)\lib\libosi.lib \
! 	$(DESTDIR)\lib\libafsconf.lib
  
  EXELIBS2 = \
          $(DESTDIR)\lib\afsrpc.lib \
--- 344,351 ----
  	$(DESTDIR)\lib\afsrx.lib \
  	$(DESTDIR)\lib\afslwp.lib \
  	$(DESTDIR)\lib\libosi.lib \
! 	$(DESTDIR)\lib\libafsconf.lib \
!         $(DESTDIR)\lib\cm_nls.obj
  
  EXELIBS2 = \
          $(DESTDIR)\lib\afsrpc.lib \
***************
*** 357,380 ****
--- 366,393 ----
  	$(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # tokens.exe
  $(EXEDIR)\tokens.exe: $(OUT)\ctokens.obj $(OUT)\tokens.res $(EXELIBS)
  	$(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # unlog.exe
  $(EXEDIR)\unlog.exe: $(OUT)\cunlog.obj $(OUT)\unlog.res $(EXELIBS)
  	$(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # afscpcc.exe
  $(EXEDIR)\afscpcc.exe: $(OUT)\afscpcc.obj $(OUT)\afscpcc.res $(LOGON_DLLLIBS)
  	$(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib userenv.lib
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  
  # afsd.exe
***************
*** 410,451 ****
--- 423,471 ----
  	$(EXEGUILINK) $(AFSD_SDKLIBS)
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # afsd_service.exe
  $(EXEDIR)\afsd_service.exe: $(OUT)\afsd_service.obj $(AFSDOBJS) $(OUT)\afsd_service.res  $(RXOBJS) $(AFSD_EXELIBS)
  	$(EXECONLINK) $(AFSD_SDKLIBS) /MAP /LARGEADDRESSAWARE
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # fs.exe
  $(EXEDIR)\fs.exe: $(FSOBJS) $(OUT)\fs.res $(EXELIBS)
  	$(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # cmdebug.exe
  $(EXEDIR)\cmdebug.exe: $(CMDBGOBJS) $(OUT)\cmdebug.res $(EXELIBS2)
  	$(EXECONLINK) $(EXELIBS2) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib rpcrt4.lib
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # symlink.exe
  $(EXEDIR)\symlink.exe: $(SLOBJS) $(OUT)\symlink.res  $(EXELIBS)
  	$(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # afsshare.exe
  $(EXEDIR)\afsshare.exe: $(OUT)\afsshare.obj $(OUT)\afsshare.res $(EXELIBS)
  	$(EXECONLINK)
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # afsdacl.exe
  $(EXEDIR)\afsdacl.exe: $(OUT)\afsdacl.obj $(OUT)\afsdacl.res
  	$(EXECONLINK)
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  # kpasswd.exe - built in kauth, but rebuild here to make pthread-based,
  #    which is required for Windows 95.  At some point it would be nice
***************
*** 487,492 ****
--- 507,513 ----
  	$(EXECONLINK)
          $(_VC_MANIFEST_EMBED_EXE)
  	$(EXEPREP)
+         $(CODESIGN_USERLAND)
  
  
  ############################################################################
Index: openafs/src/WINNT/afsd/afsd.h
diff -c openafs/src/WINNT/afsd/afsd.h:1.18.2.8 openafs/src/WINNT/afsd/afsd.h:1.18.2.13
*** openafs/src/WINNT/afsd/afsd.h:1.18.2.8	Fri Mar  7 17:24:04 2008
--- openafs/src/WINNT/afsd/afsd.h	Thu Jun 26 12:38:29 2008
***************
*** 14,37 ****
  
  #include <afs/param.h>
  
- #ifndef DJGPP
  BOOL InitClass(HANDLE);
  BOOL InitInstance(HANDLE, int);
  
  LONG APIENTRY MainWndProc(HWND, unsigned int, unsigned int, long);
  BOOL APIENTRY About(HWND, unsigned int, unsigned int, long);
- #endif /* !DJGPP */
  
- #ifndef DJGPP
  #include <nb30.h>
- #else /* DJGPP */
- #include <sys/farptr.h>
- #include <go32.h>
- #include "dosdefs95.h"
- #include "largeint95.h"
- #endif /* !DJGPP */
  
  #include "cm.h"
  
  #include <osi.h>
  #include <afs/vldbint.h>
--- 14,29 ----
  
  #include <afs/param.h>
  
  BOOL InitClass(HANDLE);
  BOOL InitInstance(HANDLE, int);
  
  LONG APIENTRY MainWndProc(HWND, unsigned int, unsigned int, long);
  BOOL APIENTRY About(HWND, unsigned int, unsigned int, long);
  
  #include <nb30.h>
  
  #include "cm.h"
+ #include "cm_nls.h"
  
  #include <osi.h>
  #include <afs/vldbint.h>
***************
*** 53,61 ****
  #include "cm_volume.h"
  #include "cm_dcache.h"
  #include "cm_access.h"
  #include "cm_utils.h"
  #include "cm_vnodeops.h"
! #include "cm_dir.h"
  #include "cm_daemon.h"
  #include "cm_ioctl.h"
  #include "cm_dnlc.h"
--- 45,54 ----
  #include "cm_volume.h"
  #include "cm_dcache.h"
  #include "cm_access.h"
+ #include "cm_dir.h"
  #include "cm_utils.h"
  #include "cm_vnodeops.h"
! #include "cm_btree.h"
  #include "cm_daemon.h"
  #include "cm_ioctl.h"
  #include "cm_dnlc.h"
***************
*** 64,75 ****
  #include "cm_freelance.h"
  #include "cm_performance.h"
  #include "smb_ioctl.h"
  #include "afsd_init.h"
- #ifdef DJGPP
- #include "afs/afsmsg95.h"
- #else
  #include "afsd_eventlog.h"
- #endif
  
  
  #define AFS_DAEMON_SERVICE_NAME AFSREG_CLT_SVC_NAME
--- 57,65 ----
  #include "cm_freelance.h"
  #include "cm_performance.h"
  #include "smb_ioctl.h"
+ #include "smb_iocons.h"
  #include "afsd_init.h"
  #include "afsd_eventlog.h"
  
  
  #define AFS_DAEMON_SERVICE_NAME AFSREG_CLT_SVC_NAME
***************
*** 94,102 ****
  
  extern osi_log_t *afsd_logp;
  
! extern char cm_mountRoot[];
  extern DWORD cm_mountRootLen;
  
  extern char cm_CachePath[];
  
  extern BOOL isGateway;
--- 84,95 ----
  
  extern osi_log_t *afsd_logp;
  
! extern fschar_t cm_mountRoot[];
  extern DWORD cm_mountRootLen;
  
+ extern clientchar_t cm_mountRootC[];
+ extern DWORD cm_mountRootCLen;
+ 
  extern char cm_CachePath[];
  
  extern BOOL isGateway;
Index: openafs/src/WINNT/afsd/afsd95.c
diff -c openafs/src/WINNT/afsd/afsd95.c:1.3 openafs/src/WINNT/afsd/afsd95.c:1.3.8.1
*** openafs/src/WINNT/afsd/afsd95.c:1.3	Tue Nov  2 01:10:29 2004
--- openafs/src/WINNT/afsd/afsd95.c	Thu Jun 26 10:38:23 2008
***************
*** 113,125 ****
          long code;
  	char *reason;
  
- #ifdef DJGPP
- 	osi_Init();
- #endif
-  
- #ifndef DJGPP
  	osi_InitPanic(afsd_notifier);
- #endif
  
          /*sleep(10);*/
          
--- 113,119 ----
***************
*** 149,168 ****
          afs_current_status = AFS_STATUS_RUNNING;
          afsMsg_StatusChange(afs_current_status, 0, NULL);
  
- #ifdef DJGPP
- 	/* Keep the process from just terminating */
- 	while(afs_shutdown == 0)
-         {
-         /*IOMGR_Sleep(180);*/
-           IOMGR_Sleep(8);
- 		/* workaround: WaitForKeystroke(nonzero num) calls 
- 		   IOMGR_Select, though Win95 select works only on sockets */
- 		/* so, we poll instead */
- 		/*if (LWP_WaitForKeystroke(0))
-                   break;*/
-         }
-         afsd_shutdown(0);
- #endif
          afs_exit(0);
          
  	return (TRUE);
--- 143,148 ----
Index: openafs/src/WINNT/afsd/afsd_flushvol.c
diff -c openafs/src/WINNT/afsd/afsd_flushvol.c:1.8 openafs/src/WINNT/afsd/afsd_flushvol.c:1.8.4.2
*** openafs/src/WINNT/afsd/afsd_flushvol.c:1.8	Sat Nov  5 01:47:45 2005
--- openafs/src/WINNT/afsd/afsd_flushvol.c	Thu Jun 26 12:38:29 2008
***************
*** 64,81 ****
      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() ) {
--- 64,81 ----
      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;
!     char        *pszShareName, *pc;
      afs_int32	afsRet = 0;
  
      if ( lana_OnlyLoopback() ) {
***************
*** 152,158 ****
              {
                  // got one!
                  // but we don't want to flush '\\[...]afs\all'
!                 if (_stricmp(lpnr->lpRemoteName, pszShareName) == 0)
                      continue;
                  ++dwTotalVols;
  
--- 152,158 ----
              {
                  // got one!
                  // but we don't want to flush '\\[...]afs\all'
!                 if (cm_stricmp_utf8(lpnr->lpRemoteName, pszShareName) == 0)
                      continue;
                  ++dwTotalVols;
  
Index: openafs/src/WINNT/afsd/afsd_init.c
diff -c openafs/src/WINNT/afsd/afsd_init.c:1.79.2.38.2.1 openafs/src/WINNT/afsd/afsd_init.c:1.79.2.43
*** openafs/src/WINNT/afsd/afsd_init.c:1.79.2.38.2.1	Sun Jun 22 22:50:08 2008
--- openafs/src/WINNT/afsd/afsd_init.c	Thu Jun 26 12:38:29 2008
***************
*** 36,41 ****
--- 36,44 ----
  #include "lanahelper.h"
  #include <strsafe.h>
  #include "cm_memmap.h"
+ #ifdef DEBUG
+ #include <crtdbg.h>
+ #endif
  
  extern int RXAFSCB_ExecuteRequest(struct rx_call *z_call);
  extern int RXSTATS_ExecuteRequest(struct rx_call *z_call);
***************
*** 50,65 ****
  #endif
  extern afs_int32 cm_OfflineROIsValid;
  extern afs_int32 cm_giveUpAllCBs;
! extern const char **smb_ExecutableExtensions;
  
  osi_log_t *afsd_logp;
  
  cm_config_data_t        cm_data;
  
! char cm_rootVolumeName[VL_MAXNAMELEN];
  DWORD cm_rootVolumeNameLen;
! char cm_mountRoot[1024];
  DWORD cm_mountRootLen;
  int cm_logChunkSize;
  int cm_chunkSize;
  
--- 53,73 ----
  #endif
  extern afs_int32 cm_OfflineROIsValid;
  extern afs_int32 cm_giveUpAllCBs;
! extern const clientchar_t **smb_ExecutableExtensions;
  
  osi_log_t *afsd_logp;
  
  cm_config_data_t        cm_data;
  
! fschar_t cm_rootVolumeName[VL_MAXNAMELEN];
  DWORD cm_rootVolumeNameLen;
! 
! fschar_t cm_mountRoot[1024];
  DWORD cm_mountRootLen;
+ 
+ clientchar_t cm_mountRootC[1024];
+ DWORD cm_mountRootCLen;
+ 
  int cm_logChunkSize;
  int cm_chunkSize;
  
***************
*** 79,84 ****
--- 87,93 ----
  unsigned short cm_callbackport = CM_DEFAULT_CALLBACKPORT;
  
  char cm_NetbiosName[MAX_NB_NAME_LENGTH] = "";
+ clientchar_t cm_NetbiosNameC[MAX_NB_NAME_LENGTH] = _C("");
  
  char cm_CachePath[MAX_PATH];
  DWORD cm_ValidateCache = 1;
***************
*** 87,95 ****
  
  cm_initparams_v1 cm_initParams;
  
! char *cm_sysName = 0;
! unsigned int   cm_sysNameCount = 0;
! char *cm_sysNameList[MAXNUMSYSNAMES];
  
  DWORD TraceOption = 0;
  
--- 96,104 ----
  
  cm_initparams_v1 cm_initParams;
  
! clientchar_t *cm_sysName = 0;
! unsigned int  cm_sysNameCount = 0;
! clientchar_t *cm_sysNameList[MAXNUMSYSNAMES];
  
  DWORD TraceOption = 0;
  
***************
*** 134,145 ****
      }
  }
  
- extern initUpperCaseTable();
- void afsd_initUpperCaseTable() 
- {
-     initUpperCaseTable();
- }
- 
  void
  afsi_start()
  {
--- 143,148 ----
***************
*** 296,302 ****
  				 pHostNames, &dwSize) == ERROR_SUCCESS) 
              {
  		for (pName = pHostNames; 
! 		     (pName - pHostNames < dwSize) && *pName ; 
  		     pName += strlen(pName) + 1)
  		{
  		    if ( !stricmp(pName, cm_NetbiosName) ) {
--- 299,305 ----
  				 pHostNames, &dwSize) == ERROR_SUCCESS) 
              {
  		for (pName = pHostNames; 
! 		     (pName - pHostNames < (int) dwSize) && *pName ; 
  		     pName += strlen(pName) + 1)
  		{
  		    if ( !stricmp(pName, cm_NetbiosName) ) {
***************
*** 390,396 ****
  }
  
  
- #if !defined(DJGPP)
  static void afsd_InitServerPreferences(void)
  {
      HKEY hkPrefs = 0;
--- 393,398 ----
***************
*** 540,546 ****
          RegCloseKey(hkPrefs);
      }
  }
- #endif /* DJGPP */
  
  /*
   * AFSD Initialization
--- 542,547 ----
***************
*** 564,570 ****
      long ltt, ltto;
      long rx_nojumbo;
      long virtualCache = 0;
!     char rootCellName[256];
      struct rx_service *serverp;
      static struct rx_securityClass *nullServerSecurityClassp;
      struct hostent *thp;
--- 565,571 ----
      long ltt, ltto;
      long rx_nojumbo;
      long virtualCache = 0;
!     fschar_t rootCellName[256];
      struct rx_service *serverp;
      static struct rx_securityClass *nullServerSecurityClassp;
      struct hostent *thp;
***************
*** 577,583 ****
      /*int freelanceEnabled;*/
      WSADATA WSAjunk;
      int i;
-     char *p, *q; 
      int cm_noIPAddr;         /* number of client network interfaces */
      int cm_IPAddr[CM_MAXINTERFACE_ADDR];    /* client's IP address in host order */
      int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
--- 578,583 ----
***************
*** 586,592 ****
  
      WSAStartup(0x0101, &WSAjunk);
  
-     afsd_initUpperCaseTable();
      init_et_to_sys_error();
  
      /* setup osidebug server at RPC slot 1000 */
--- 586,591 ----
***************
*** 614,620 ****
  
      /* Look up configuration parameters in Registry */
      code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
!                          0, KEY_QUERY_VALUE, &parmKey);
      if (code != ERROR_SUCCESS) {
          FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
                         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
--- 613,619 ----
  
      /* Look up configuration parameters in Registry */
      code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
!                         0, KEY_QUERY_VALUE, &parmKey);
      if (code != ERROR_SUCCESS) {
          FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
                         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
***************
*** 822,850 ****
  
      dummyLen = sizeof(cm_rootVolumeName);
      code = RegQueryValueEx(parmKey, "RootVolume", NULL, NULL,
!                             cm_rootVolumeName, &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, &cm_mountRootLen);
      if (code == ERROR_SUCCESS) {
!         afsi_log("Mount root %s", cm_mountRoot);
!         cm_mountRootLen = (DWORD)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, &regType,
!                             buf, &dummyLen);
      if (code == ERROR_SUCCESS && buf[0]) {
          if (regType == REG_EXPAND_SZ) {
              dummyLen = ExpandEnvironmentStrings(buf, cm_CachePath, sizeof(cm_CachePath));
--- 821,852 ----
  
      dummyLen = sizeof(cm_rootVolumeName);
      code = RegQueryValueEx(parmKey, "RootVolume", NULL, NULL,
!                             (LPBYTE) cm_rootVolumeName, &dummyLen);
      if (code == ERROR_SUCCESS)
          afsi_log("Root volume %s", cm_rootVolumeName);
      else {
!         cm_FsStrCpy(cm_rootVolumeName, lengthof(cm_rootVolumeName), "root.afs");
          afsi_log("Default root volume name root.afs");
      }
  
!     cm_mountRootCLen = sizeof(cm_mountRootC);
!     code = RegQueryValueExW(parmKey, L"MountRoot", NULL, NULL,
!                             (LPBYTE) cm_mountRootC, &cm_mountRootCLen);
      if (code == ERROR_SUCCESS) {
!         afsi_log("Mount root %S", cm_mountRootC);
!         cm_mountRootCLen = cm_ClientStrLen(cm_mountRootC);
      } else {
!         cm_ClientStrCpy(cm_mountRootC, lengthof(cm_mountRootC), _C("/afs"));
!         cm_mountRootCLen = cm_ClientStrLen(cm_mountRootC);
          /* Don't log */
      }
  
+     cm_ClientStringToFsString(cm_mountRootC, -1, cm_mountRoot, lengthof(cm_mountRoot));
+     cm_mountRootLen = cm_FsStrLen(cm_mountRoot);
+ 
      dummyLen = sizeof(buf);
      code = RegQueryValueEx(parmKey, "CachePath", NULL, &regType,
!                            buf, &dummyLen);
      if (code == ERROR_SUCCESS && buf[0]) {
          if (regType == REG_EXPAND_SZ) {
              dummyLen = ExpandEnvironmentStrings(buf, cm_CachePath, sizeof(cm_CachePath));
***************
*** 909,955 ****
      }
  
      for ( i=0; i < MAXNUMSYSNAMES; i++ ) {
!         cm_sysNameList[i] = osi_Alloc(MAXSYSNAME);
          cm_sysNameList[i][0] = '\0';
      }
      cm_sysName = cm_sysNameList[0];
  
!     dummyLen = sizeof(buf);
!     code = RegQueryValueEx(parmKey, "SysName", NULL, NULL, buf, &dummyLen);
!     if (code != ERROR_SUCCESS || !buf[0]) {
  #if defined(_IA64_)
!         StringCbCopyA(buf, sizeof(buf), "ia64_win64");
  #elif defined(_AMD64_)
!         StringCbCopyA(buf, sizeof(buf), "amd64_win64 x86_win32 i386_w2k");
  #else /* assume x86 32-bit */
!         StringCbCopyA(buf, sizeof(buf), "x86_win32 i386_w2k i386_nt40");
  #endif
!     }
!     afsi_log("Sys name %s", buf); 
  
!     /* breakup buf into individual search string entries */
!     for (p = q = buf; p < buf + 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]);
  
      dummyLen = sizeof(cryptall);
      code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
!                             (BYTE *) &cryptall, &dummyLen);
      if (code == ERROR_SUCCESS) {
          afsi_log("SecurityLevel is %s", cryptall?"crypt":"clear");
      } else {
--- 911,959 ----
      }
  
      for ( i=0; i < MAXNUMSYSNAMES; i++ ) {
!         cm_sysNameList[i] = osi_Alloc(MAXSYSNAME * sizeof(clientchar_t));
          cm_sysNameList[i][0] = '\0';
      }
      cm_sysName = cm_sysNameList[0];
  
!     {
!         clientchar_t *p, *q;
!         clientchar_t * cbuf = (clientchar_t *) buf;
!         dummyLen = sizeof(buf);
!         code = RegQueryValueExW(parmKey, L"SysName", NULL, NULL, (LPBYTE) cbuf, &dummyLen);
!         if (code != ERROR_SUCCESS || !cbuf[0]) {
  #if defined(_IA64_)
!             cm_ClientStrCpy(cbuf, lengthof(buf), _C("ia64_win64"));
  #elif defined(_AMD64_)
!             cm_ClientStrCpy(cbuf, lengthof(buf), _C("amd64_win64 x86_win32 i386_w2k"));
  #else /* assume x86 32-bit */
!             cm_ClientStrCpy(cbuf, lengthof(buf), _C("x86_win32 i386_w2k i386_nt40"));
  #endif
!         }
!         afsi_log("Sys name %S", cbuf); 
  
!         /* breakup buf into individual search string entries */
!         for (p = q = cbuf; p < cbuf + dummyLen; p++) {
!             if (*p == '\0' || iswspace(*p)) {
!                 memcpy(cm_sysNameList[cm_sysNameCount],q,(p-q) * sizeof(clientchar_t));
!                 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:
!     cm_ClientStrCpy(cm_sysName, MAXSYSNAME, cm_sysNameList[0]);
  
      dummyLen = sizeof(cryptall);
      code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
!                            (BYTE *) &cryptall, &dummyLen);
      if (code == ERROR_SUCCESS) {
          afsi_log("SecurityLevel is %s", cryptall?"crypt":"clear");
      } else {
***************
*** 996,1001 ****
--- 1000,1014 ----
      }
  #endif /* AFS_FREELANCE_CLIENT */
  
+     dummyLen = sizeof(smb_UseUnicode);
+     code = RegQueryValueEx(parmKey, "NegotiateUnicode", NULL, NULL,
+                            (BYTE *) &smb_UseUnicode, &dummyLen);
+     if (code != ERROR_SUCCESS) {
+         smb_UseUnicode = 1; /* default on */
+     }
+     afsi_log("SMB Server Unicode Support is %s",
+               smb_UseUnicode ? "enabled" : "disabled");
+ 
      dummyLen = sizeof(smb_hideDotFiles);
      code = RegQueryValueEx(parmKey, "HideDotFiles", NULL, NULL,
                             (BYTE *) &smb_hideDotFiles, &dummyLen);
***************
*** 1143,1170 ****
      afsi_log("CM BPlusTrees is not supported");
  #endif
  
!     if ((RegQueryValueEx( parmKey, "PrefetchExecutableExtensions", 0, 
!                           &regType, NULL, &dummyLen) == ERROR_SUCCESS) &&
           (regType == REG_MULTI_SZ)) 
      {
!         char * pSz;
          dummyLen += 3; /* in case the source string is not nul terminated */
          pSz = malloc(dummyLen);
!         if ((RegQueryValueEx( parmKey, "PrefetchExecutableExtensions", 0, &regType, 
!                              pSz, &dummyLen) == ERROR_SUCCESS) &&
               (regType == REG_MULTI_SZ))
          {
              int cnt;
!             char * p;
  
!             for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += strlen(p) + 1);
  
!             smb_ExecutableExtensions = malloc(sizeof(char *) * (cnt+1));
  
!             for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += strlen(p) + 1)
!             {
                  smb_ExecutableExtensions[cnt] = p;
!                 afsi_log("PrefetchExecutableExtension: \"%s\"", p);
              }
              smb_ExecutableExtensions[cnt] = NULL;
          }
--- 1156,1182 ----
      afsi_log("CM BPlusTrees is not supported");
  #endif
  
!     if ((RegQueryValueExW( parmKey, L"PrefetchExecutableExtensions", 0, 
!                            &regType, NULL, &dummyLen) == ERROR_SUCCESS) &&
           (regType == REG_MULTI_SZ)) 
      {
!         clientchar_t * pSz;
          dummyLen += 3; /* in case the source string is not nul terminated */
          pSz = malloc(dummyLen);
!         if ((RegQueryValueExW( parmKey, L"PrefetchExecutableExtensions", 0, &regType, 
!                                (LPBYTE) pSz, &dummyLen) == ERROR_SUCCESS) &&
               (regType == REG_MULTI_SZ))
          {
              int cnt;
!             clientchar_t * p;
  
!             for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += cm_ClientStrLen(p) + 1);
  
!             smb_ExecutableExtensions = malloc(sizeof(clientchar_t *) * (cnt+1));
  
!             for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += cm_ClientStrLen(p) + 1) {
                  smb_ExecutableExtensions[cnt] = p;
!                 afsi_log("PrefetchExecutableExtension: \"%S\"", p);
              }
              smb_ExecutableExtensions[cnt] = NULL;
          }
***************
*** 1244,1249 ****
--- 1256,1263 ----
          
      cm_InitCallback();
  
+     cm_InitNormalization();
+ 
      code = cm_InitMappedMemory(virtualCache, cm_CachePath, stats, volumes, cells, cm_chunkSize, cacheBlocks, blockSize);
      afsi_log("cm_InitMappedMemory code %x", code);
      if (code != 0) {
***************
*** 1266,1271 ****
--- 1280,1287 ----
      }
  
      if ( rx_mtu != -1 ) {
+         extern void rx_SetMaxMTU(int);
+ 
          rx_SetMaxMTU(rx_mtu);
          afsi_log("rx_SetMaxMTU %d successful", rx_mtu);
      }
***************
*** 1315,1321 ****
  
      code = cm_GetRootCellName(rootCellName);
      afsi_log("cm_GetRootCellName code %d, cm_freelanceEnabled= %d, rcn= %s", 
!               code, cm_freelanceEnabled, (code ? "<none>" : rootCellName));
      if (code != 0 && !cm_freelanceEnabled) 
      {
          *reasonP = "can't find root cell name in " AFS_CELLSERVDB;
--- 1331,1337 ----
  
      code = cm_GetRootCellName(rootCellName);
      afsi_log("cm_GetRootCellName code %d, cm_freelanceEnabled= %d, rcn= %s", 
!              code, cm_freelanceEnabled, (code ? "<none>" : rootCellName));
      if (code != 0 && !cm_freelanceEnabled) 
      {
          *reasonP = "can't find root cell name in " AFS_CELLSERVDB;
***************
*** 1343,1351 ****
      /* Initialize the RPC server for session keys */
      RpcInit();
  
- #if !defined(DJGPP)
      afsd_InitServerPreferences();
- #endif
      return 0;
  }
  
--- 1359,1365 ----
***************
*** 1779,1787 ****
    
  void afsd_SetUnhandledExceptionFilter()
  {
      SetUnhandledExceptionFilter(afsd_ExceptionFilter);
  }
!   
  #ifdef _DEBUG
  void afsd_DbgBreakAllocInit()
  {
--- 1793,1803 ----
    
  void afsd_SetUnhandledExceptionFilter()
  {
+ #ifndef NOTRACE
      SetUnhandledExceptionFilter(afsd_ExceptionFilter);
+ #endif
  }
! 
  #ifdef _DEBUG
  void afsd_DbgBreakAllocInit()
  {
Index: openafs/src/WINNT/afsd/afsd_init.h
diff -c openafs/src/WINNT/afsd/afsd_init.h:1.6.6.1 openafs/src/WINNT/afsd/afsd_init.h:1.6.6.3
*** openafs/src/WINNT/afsd/afsd_init.h:1.6.6.1	Sun Oct  8 16:31:36 2006
--- openafs/src/WINNT/afsd/afsd_init.h	Thu Jun 26 12:38:29 2008
***************
*** 9,23 ****
  
  void afsi_start();
  
- #ifndef DJGPP
  int afsd_InitCM(char **reasonP);
  int afsd_InitSMB(char **reasonP, void *aMBfunc);
  
  void GenerateMiniDump(PEXCEPTION_POINTERS ep);
- #else /* DJGPP */
- int afsd_InitCM(char **reasonP, struct cmd_syndesc *as, char *arock);
- int afsd_InitSMB(char **reasonP);
- #endif /* !DJGPP */
  int afsd_InitDaemons(char **reasonP);
  int afsd_ShutdownCM(void);
  void afsd_ForceTrace(BOOL flush);
--- 9,18 ----
***************
*** 25,29 ****
  
  extern char cm_HostName[];
  extern char cm_NetbiosName[];
! 
  
--- 20,24 ----
  
  extern char cm_HostName[];
  extern char cm_NetbiosName[];
! extern clientchar_t cm_NetbiosNameC[];
  
Index: openafs/src/WINNT/afsd/afsd_init95.c
diff -c openafs/src/WINNT/afsd/afsd_init95.c:1.4 openafs/src/WINNT/afsd/afsd_init95.c:1.4.6.1
*** openafs/src/WINNT/afsd/afsd_init95.c:1.4	Fri Mar 11 00:33:21 2005
--- openafs/src/WINNT/afsd/afsd_init95.c	Thu Jun 26 10:38:23 2008
***************
*** 324,330 ****
  
            WSAStartup(0x0101, &WSAjunk);*/
  
- #ifndef DJGPP
  	/* setup osidebug server at RPC slot 1000 */
  	osi_LongToUID(1000, &debugID);
  	code = osi_InitDebug(&debugID);
--- 324,329 ----
***************
*** 334,351 ****
  		*reasonP = "unknown error";
  		return -1;
  	}
- #endif 
  
  	/* who are we ? */
  	gethostname(cm_HostName, sizeof(cm_HostName));
- #ifdef DJGPP
- 	/* For some reason, we may be getting space-padded hostnames.
- 	   If so, we take out the padding so that we can append -AFS later. */
- 	{
- 	  char *space = strchr(cm_HostName,' ');
- 	  if (space) *space = '\0';
- 	}
- #endif
  	afsi_log("gethostname %s", cm_HostName);
  	thp = gethostbyname(cm_HostName);
  	memcpy(&cm_HostAddr, thp->h_addr_list[0], 4);
--- 333,341 ----
Index: openafs/src/WINNT/afsd/afsd_service.c
diff -c openafs/src/WINNT/afsd/afsd_service.c:1.52.4.25 openafs/src/WINNT/afsd/afsd_service.c:1.52.4.26
*** openafs/src/WINNT/afsd/afsd_service.c:1.52.4.25	Wed Mar 19 11:36:25 2008
--- openafs/src/WINNT/afsd/afsd_service.c	Thu Jun 26 12:38:29 2008
***************
*** 14,19 ****
--- 14,22 ----
  #include <stdlib.h>
  #include <winsock2.h>
  #include <WINNT\afsreg.h>
+ #include "cm_btree.h"
+ #include "cm_rpc.h"
+ #include "smb.h"
  
  #include <osi.h>
  
***************
*** 1094,1099 ****
--- 1097,1104 ----
      HMODULE hAdvApi32;
  
  #ifdef _DEBUG
+     void afsd_DbgBreakAllocInit();
+ 
      afsd_DbgBreakAllocInit();
      _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | 
                     _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
Index: openafs/src/WINNT/afsd/afskfw.c
diff -c openafs/src/WINNT/afsd/afskfw.c:1.28.4.18 openafs/src/WINNT/afsd/afskfw.c:1.28.4.19
*** openafs/src/WINNT/afsd/afskfw.c:1.28.4.18	Sun Mar 30 10:13:17 2008
--- openafs/src/WINNT/afsd/afskfw.c	Sat Jul  5 02:27:46 2008
***************
*** 3122,3128 ****
                  retry++;
                  goto retry_gettoken5;
              }
!             goto try_krb524d;
          }
  
          if (atoken.kvno == btoken.kvno &&
--- 3122,3128 ----
                  retry++;
                  goto retry_gettoken5;
              }
!             goto cleanup;
          }
  
          if (atoken.kvno == btoken.kvno &&
Index: openafs/src/WINNT/afsd/afslogon.c
diff -c openafs/src/WINNT/afsd/afslogon.c:1.45.2.13 openafs/src/WINNT/afsd/afslogon.c:1.45.2.14
*** openafs/src/WINNT/afsd/afslogon.c:1.45.2.13	Mon Jan 28 14:51:20 2008
--- openafs/src/WINNT/afsd/afslogon.c	Thu Jun 26 08:45:10 2008
***************
*** 370,376 ****
      if(domain) {
          dwSize = MAX_COMPUTERNAME_LENGTH;
          if(GetComputerName(computerName, &dwSize)) {
!             if(!stricmp(computerName, domain)) {
                  effDomain = "LOCALHOST";
                  opt->flags = LOGON_FLAG_LOCAL;
              }
--- 370,376 ----
      if(domain) {
          dwSize = MAX_COMPUTERNAME_LENGTH;
          if(GetComputerName(computerName, &dwSize)) {
!             if(!cm_stricmp_utf8(computerName, domain)) {
                  effDomain = "LOCALHOST";
                  opt->flags = LOGON_FLAG_LOCAL;
              }
***************
*** 977,983 ****
                              }
  			    p = opt.theseCells;
  			    while ( *p ) {
!                                 if ( stricmp(p, cell) ) {
                                      SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
                                      code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
                                      SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
--- 977,983 ----
                              }
  			    p = opt.theseCells;
  			    while ( *p ) {
!                                 if ( cm_stricmp_utf8(p, cell) ) {
                                      SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
                                      code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
                                      SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
Index: openafs/src/WINNT/afsd/cm_access.c
diff -c openafs/src/WINNT/afsd/cm_access.c:1.7.2.18 openafs/src/WINNT/afsd/cm_access.c:1.7.2.19
*** openafs/src/WINNT/afsd/cm_access.c:1.7.2.18	Sun Mar  2 23:25:40 2008
--- openafs/src/WINNT/afsd/cm_access.c	Thu Jun 26 10:38:23 2008
***************
*** 10,25 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
- #endif
  #include <malloc.h>
  #include <string.h>
  #include <stdlib.h>
- #ifndef DJGPP
  #include <nb30.h>
- #endif
  #include <osi.h>
  
  #include "afsd.h"
--- 10,21 ----
Index: openafs/src/WINNT/afsd/cm_aclent.c
diff -c openafs/src/WINNT/afsd/cm_aclent.c:1.14.2.4 openafs/src/WINNT/afsd/cm_aclent.c:1.14.2.5
*** openafs/src/WINNT/afsd/cm_aclent.c:1.14.2.4	Sun Mar  2 23:25:40 2008
--- openafs/src/WINNT/afsd/cm_aclent.c	Thu Jun 26 10:38:23 2008
***************
*** 10,18 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
- #endif
  #include <stdlib.h>
  #include <string.h>
  #include <malloc.h>
--- 10,16 ----
Index: openafs/src/WINNT/afsd/cm_btree.c
diff -c openafs/src/WINNT/afsd/cm_btree.c:1.1.2.14.2.1 openafs/src/WINNT/afsd/cm_btree.c:1.1.2.20
*** openafs/src/WINNT/afsd/cm_btree.c:1.1.2.14.2.1	Sun Jun 22 22:52:04 2008
--- openafs/src/WINNT/afsd/cm_btree.c	Mon Jul 14 09:01:31 2008
***************
*** 1,5 ****
  /*
!  * Copyright 2007 Secure Endpoints Inc.  
   * 
   * All Rights Reserved.
   *
--- 1,5 ----
  /*
!  * Copyright 2007-2008 Secure Endpoints Inc.  
   * 
   * All Rights Reserved.
   *
***************
*** 15,20 ****
--- 15,21 ----
  #include <stdlib.h>
  #include <assert.h>
  #include "afsd.h"
+ #include <strsafe.h>
  
  #ifdef USE_BPLUS
  #include "cm_btree.h"
***************
*** 43,49 ****
  static void cleanupNodePool(Tree *B);
  
  static Nptr descendToLeaf(Tree *B, Nptr curr);
! static int getSlot(Tree *B, Nptr curr);
  static int findKey(Tree *B, Nptr curr, int lo, int hi);
  static int bestMatch(Tree *B, Nptr curr, int slot);
  
--- 44,50 ----
  static void cleanupNodePool(Tree *B);
  
  static Nptr descendToLeaf(Tree *B, Nptr curr);
! int getSlot(Tree *B, Nptr curr);
  static int findKey(Tree *B, Nptr curr, int lo, int hi);
  static int bestMatch(Tree *B, Nptr curr, int slot);
  
***************
*** 141,147 ****
  {
      Tree *B;
      keyT empty = {NULL};
!     dataT data = {0,0,0,0};
  
      if (fanout > MAX_FANOUT)
          fanout = MAX_FANOUT;
--- 142,148 ----
  {
      Tree *B;
      keyT empty = {NULL};
!     dataT data = {0,0,0,0,0,0,0};
  
      if (fanout > MAX_FANOUT)
          fanout = MAX_FANOUT;
***************
*** 164,170 ****
      setcomparekeys(B, keyCmp);
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "INIT:  B+tree of fanout %d at %10p.\n", fanout, (void *)B);
      OutputDebugString(B->message);
  #endif
  
--- 165,171 ----
      setcomparekeys(B, keyCmp);
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "INIT:  B+tree of fanout %d at %10p.\n", fanout, (void *)B);
      OutputDebugString(B->message);
  #endif
  
***************
*** 178,184 ****
  void freeBtree(Tree *B)
  {
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "FREE:  B+tree at %10p.\n", (void *) B);
      OutputDebugString(B->message);
  #endif
  
--- 179,185 ----
  void freeBtree(Tree *B)
  {
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "FREE:  B+tree at %10p.\n", (void *) B);
      OutputDebugString(B->message);
  #endif
  
***************
*** 266,272 ****
      Nptr	leafNode;
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "LOOKUP:  key %s.\n", key.name);
      OutputDebugString(B->message);
  #endif
  
--- 267,273 ----
      Nptr	leafNode;
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP:  key %s.\n", key.name);
      OutputDebugString(B->message);
  #endif
  
***************
*** 286,299 ****
          dataNode = getnode(leafNode, slot);
          data = getdatavalue(dataNode);
  
!         sprintf(B->message, "LOOKUP: %s found on page %d value (%d.%d.%d).\n",
                   key.name,
                   getnodenumber(B, leafNode), 
                   data.fid.volume, 
                   data.fid.vnode,
                   data.fid.unique);
      } else 
!         sprintf(B->message, "LOOKUP: not found!\n");
      OutputDebugString(B->message);
  #endif
  
--- 287,300 ----
          dataNode = getnode(leafNode, slot);
          data = getdatavalue(dataNode);
  
!         StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: %s found on page %d value (%d.%d.%d).\n",
                   key.name,
                   getnodenumber(B, leafNode), 
                   data.fid.volume, 
                   data.fid.vnode,
                   data.fid.unique);
      } else 
!         StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: not found!\n");
      OutputDebugString(B->message);
  #endif
  
***************
*** 334,340 ****
  }
  
  /********************   find slot for search key   *********************/
! static int getSlot(Tree *B, Nptr curr)
  {
      int slot, entries;
  
--- 335,341 ----
  }
  
  /********************   find slot for search key   *********************/
! int getSlot(Tree *B, Nptr curr)
  {
      int slot, entries;
  
***************
*** 355,361 ****
  
  #ifdef DEBUG_BTREE
          if (findslot == BTERROR) {
!             sprintf(B->message, "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n", 
                      lo, hi, getnodenumber(B, curr), curr);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          }
--- 356,362 ----
  
  #ifdef DEBUG_BTREE
          if (findslot == BTERROR) {
!             StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n", 
                      lo, hi, getnodenumber(B, curr), curr);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          }
***************
*** 372,378 ****
                  findslot = findKey(B, curr, mid + 1, hi);
              break;
          case BTERROR:
!             sprintf(B->message, "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n", 
                      lo, hi, getnodenumber(B, curr), curr);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          }
--- 373,379 ----
                  findslot = findKey(B, curr, mid + 1, hi);
              break;
          case BTERROR:
!             StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n", 
                      lo, hi, getnodenumber(B, curr), curr);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          }
***************
*** 380,386 ****
  
      if (isleaf(curr) && findslot == 0)
      {
!         sprintf(B->message, "FINDKEY: (lo %d hi %d) findslot %d is invalid for leaf nodes, bad key ordering on node %d (0x%p)\n", 
                  lo, hi, findslot, getnodenumber(B, curr), curr);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      }
--- 381,387 ----
  
      if (isleaf(curr) && findslot == 0)
      {
!         StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) findslot %d is invalid for leaf nodes, bad key ordering on node %d (0x%p)\n", 
                  lo, hi, findslot, getnodenumber(B, curr), curr);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      }
***************
*** 435,441 ****
  
      if (findslot == BTERROR || isleaf(curr) && findslot == 0)
      {
!         sprintf(B->message, "BESTMATCH: node %d (0x%p) slot %d diff %d comp %d findslot %d\n", 
                  getnodenumber(B, curr), curr, slot, diff, comp, findslot);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      }
--- 436,442 ----
  
      if (findslot == BTERROR || isleaf(curr) && findslot == 0)
      {
!         StringCbPrintfA(B->message, sizeof(B->message), "BESTMATCH: node %d (0x%p) slot %d diff %d comp %d findslot %d\n", 
                  getnodenumber(B, curr), curr, slot, diff, comp, findslot);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      }
***************
*** 454,460 ****
      Nptr newNode;
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "INSERT:  key %s.\n", key.name);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
  
--- 455,461 ----
      Nptr newNode;
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "INSERT:  key %s.\n", key.name);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
  
***************
*** 528,534 ****
      keyT key;
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "INSERT:  slot %d, down node %d.\n", slot, getnodenumber(B, downPtr));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
  
--- 529,535 ----
      keyT key;
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "INSERT:  slot %d, down node %d.\n", slot, getnodenumber(B, downPtr));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
  
***************
*** 732,738 ****
      Nptr newNode;
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "DELETE:  key %s.\n", key.name);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
  
--- 733,739 ----
      Nptr newNode;
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "DELETE:  key %s.\n", key.name);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
  
***************
*** 741,747 ****
      newNode = descendBalance(B, getroot(B), NONODE, NONODE, NONODE, NONODE, NONODE);
      if (isnode(newNode)) {
  #ifdef DEBUG_BTREE
!         sprintf(B->message, "DELETE: collapsing node %d", getnodenumber(B, newNode));
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
          collapseRoot(B, getroot(B), newNode);	/* remove root when superfluous */
--- 742,748 ----
      newNode = descendBalance(B, getroot(B), NONODE, NONODE, NONODE, NONODE, NONODE);
      if (isnode(newNode)) {
  #ifdef DEBUG_BTREE
!         StringCbPrintfA(B->message, sizeof(B->message), "DELETE: collapsing node %d", getnodenumber(B, newNode));
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
          collapseRoot(B, getroot(B), newNode);	/* remove root when superfluous */
***************
*** 755,761 ****
  {
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "COLLAPSE:  old %d, new %d.\n", getnodenumber(B, oldRoot), getnodenumber(B, newRoot));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      showNode(B, "collapseRoot oldRoot", oldRoot);
      showNode(B, "collapseRoot newRoot", newRoot);
--- 756,762 ----
  {
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "COLLAPSE:  old %d, new %d.\n", getnodenumber(B, oldRoot), getnodenumber(B, newRoot));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      showNode(B, "collapseRoot oldRoot", oldRoot);
      showNode(B, "collapseRoot newRoot", newRoot);
***************
*** 777,783 ****
      int	slot = 0, notleft = 0, notright = 0, fewleft = 0, fewright = 0, test = 0;
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "descendBalance curr %d, left %d, right %d, lAnc %d, rAnc %d, parent %d\n",
               curr ? getnodenumber(B, curr) : -1,
               left ? getnodenumber(B, left) : -1,
               right ? getnodenumber(B, right) : -1,
--- 778,784 ----
      int	slot = 0, notleft = 0, notright = 0, fewleft = 0, fewright = 0, test = 0;
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "descendBalance curr %d, left %d, right %d, lAnc %d, rAnc %d, parent %d\n",
               curr ? getnodenumber(B, curr) : -1,
               left ? getnodenumber(B, left) : -1,
               right ? getnodenumber(B, right) : -1,
***************
*** 918,924 ****
  
      if (newMe != NONODE) {	/* this node removal doesn't consider duplicates */
  #ifdef DEBUG_BTREE
!         sprintf(B->message, "descendBalance DELETE:  slot %d, node %d.\n", slot, getnodenumber(B, curr));
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
  
--- 919,925 ----
  
      if (newMe != NONODE) {	/* this node removal doesn't consider duplicates */
  #ifdef DEBUG_BTREE
!         StringCbPrintfA(B->message, sizeof(B->message), "descendBalance DELETE:  slot %d, node %d.\n", slot, getnodenumber(B, curr));
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
  
***************
*** 972,978 ****
      }
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "descendBalance returns %d\n", getnodenumber(B, newNode));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
      return newNode;
--- 973,979 ----
      }
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "descendBalance returns %d\n", getnodenumber(B, newNode));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #endif
      return newNode;
***************
*** 1004,1010 ****
      int	x, y, z;
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "MERGE:  left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      showNode(B, "pre-merge anchor", anchor);
      showNode(B, "pre-merge left", left);
--- 1005,1011 ----
      int	x, y, z;
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "MERGE:  left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      showNode(B, "pre-merge anchor", anchor);
      showNode(B, "pre-merge left", left);
***************
*** 1061,1067 ****
      int	i, x, y, z;
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "SHIFT:  left %d, right %d, anchor %d.\n", 
               getnodenumber(B, left), 
               getnodenumber(B, right), 
               getnodenumber(B, anchor));
--- 1062,1068 ----
      int	i, x, y, z;
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "SHIFT:  left %d, right %d, anchor %d.\n", 
               getnodenumber(B, left), 
               getnodenumber(B, right), 
               getnodenumber(B, anchor));
***************
*** 1162,1168 ****
      setmergepath(B, NONODE);
  
  #ifdef DEBUG_BTREE
!     sprintf(B->message, "SHIFT:  left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      showNode(B, "post-shift anchor", anchor);
      showNode(B, "post-shift left", left);
--- 1163,1169 ----
      setmergepath(B, NONODE);
  
  #ifdef DEBUG_BTREE
!     StringCbPrintfA(B->message, sizeof(B->message), "SHIFT:  left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      showNode(B, "post-shift anchor", anchor);
      showNode(B, "post-shift left", left);
***************
*** 1192,1198 ****
      if (entry == 0)
          DebugBreak();
  #endif
!     getkey(node,entry + offset).name = strdup(getkey(node,entry).name);
  #ifdef DEBUG_BTREE
      if ( getnode(node, entry) == NONODE )
          DebugBreak();
--- 1193,1199 ----
      if (entry == 0)
          DebugBreak();
  #endif
!     getkey(node,entry + offset).name = cm_NormStrDup(getkey(node,entry).name);
  #ifdef DEBUG_BTREE
      if ( getnode(node, entry) == NONODE )
          DebugBreak();
***************
*** 1205,1211 ****
  {
      if (getkey(node,entry).name != NULL)
          free(getkey(node,entry).name);
!     getkey(node,entry).name = strdup(getkey(node,entry + offset).name);
  #ifdef DEBUG_BTREE
      if ( getnode(node, entry + offset) == NONODE )
          DebugBreak();
--- 1206,1212 ----
  {
      if (getkey(node,entry).name != NULL)
          free(getkey(node,entry).name);
!     getkey(node,entry).name = cm_NormStrDup(getkey(node,entry + offset).name);
  #ifdef DEBUG_BTREE
      if ( getnode(node, entry + offset) == NONODE )
          DebugBreak();
***************
*** 1218,1224 ****
  {
      if (getkey(destNode,destEntry).name != NULL)
          free(getkey(destNode,destEntry).name);
!     getkey(destNode,destEntry).name = strdup(getkey(srcNode,srcEntry).name);
  #ifdef DEBUG_BTREE
      if ( getnode(srcNode, srcEntry) == NONODE )
          DebugBreak();
--- 1219,1225 ----
  {
      if (getkey(destNode,destEntry).name != NULL)
          free(getkey(destNode,destEntry).name);
!     getkey(destNode,destEntry).name = cm_NormStrDup(getkey(srcNode,srcEntry).name);
  #ifdef DEBUG_BTREE
      if ( getnode(srcNode, srcEntry) == NONODE )
          DebugBreak();
***************
*** 1231,1237 ****
  {
      if (getkey(node,entry).name != NULL)
          free(getkey(node,entry).name);
!     getkey(node,entry).name = strdup(key.name);
  #ifdef DEBUG_BTREE
      if ( downNode == NONODE )
          DebugBreak();
--- 1232,1238 ----
  {
      if (getkey(node,entry).name != NULL)
          free(getkey(node,entry).name);
!     getkey(node,entry).name = cm_NormStrDup(key.name);
  #ifdef DEBUG_BTREE
      if ( downNode == NONODE )
          DebugBreak();
***************
*** 1289,1297 ****
                  free(getdatakey(node).name);
                  getdatakey(node).name = NULL;
              }
!             if ( getdatavalue(node).longname ) {
!                 free(getdatavalue(node).longname);
!                 getdatavalue(node).longname = NULL;
              }
          } else { /* data node */
              for ( j=1; j<=getfanout(B); j++ ) {
--- 1290,1302 ----
                  free(getdatakey(node).name);
                  getdatakey(node).name = NULL;
              }
!             if ( getdatavalue(node).cname ) {
!                 free(getdatavalue(node).cname);
!                 getdatavalue(node).cname = NULL;
!             }
!             if ( getdatavalue(node).fsname ) {
!                 free(getdatavalue(node).fsname);
!                 getdatavalue(node).fsname = NULL;
              }
          } else { /* data node */
              for ( j=1; j<=getfanout(B); j++ ) {
***************
*** 1341,1348 ****
      if (isdata(node)) {
          if ( getdatakey(node).name )
              free(getdatakey(node).name);
! 	if ( getdatavalue(node).longname )
! 	    free(getdatavalue(node).longname);
      } else {    /* data node */
          for ( i=1; i<=getfanout(B); i++ ) {
              if (getkey(node, i).name)
--- 1346,1355 ----
      if (isdata(node)) {
          if ( getdatakey(node).name )
              free(getdatakey(node).name);
! 	if ( getdatavalue(node).cname )
! 	    free(getdatavalue(node).cname);
!         if ( getdatavalue(node).fsname )
!             free(getdatavalue(node).fsname);
      } else {    /* data node */
          for ( i=1; i<=getfanout(B); i++ ) {
              if (getkey(node, i).name)
***************
*** 1364,1370 ****
      Nptr	newNode = getFreeNode(B);
  
      setflag(newNode, isDATA);
!     getdatakey(newNode).name = strdup(key.name);
      getdatavalue(newNode) = data;
      getdatanext(newNode) = NONODE;
  
--- 1371,1377 ----
      Nptr	newNode = getFreeNode(B);
  
      setflag(newNode, isDATA);
!     getdatakey(newNode).name = cm_NormStrDup(key.name);
      getdatavalue(newNode) = data;
      getdatanext(newNode) = NONODE;
  
***************
*** 1382,1442 ****
  {
      int x;
  
!     sprintf(B->message, "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "| %-20s                        |\n", where);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "| node %6d                 ", getnodenumber(B, n));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "  magic    %4x  |\n", getmagic(n));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "| flags   %1d%1d%1d%1d ", isfew(n), isfull(n), isroot(n), isleaf(n));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "| keys = %5d ", numentries(n));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "| node = %6d  |\n", getnodenumber(B, getfirstnode(n)));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      for (x = 1; x <= numentries(n); x++) {
!         sprintf(B->message, "| entry %6d ", x);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!         sprintf(B->message, "| key = %6s ", getkey(n, x).name);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!         sprintf(B->message, "| node = %6d  |\n", getnodenumber(B, getnode(n, x)));
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      }
!     sprintf(B->message, "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  }
  
  /******************   B+tree class variable printer   ******************/
  void showBtree(Tree *B)
  {
!     sprintf(B->message, "-  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  B+tree  %10p  |\n", (void *) B);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "-  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  root        %6d  |\n", getnodenumber(B, getroot(B)));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  leaf        %6d  |\n", getnodenumber(B, getleaf(B)));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  fanout         %3d  |\n", getfanout(B) + 1);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  minfanout      %3d  |\n", getminfanout(B, getroot(B)) + 1);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  height         %3d  |\n", gettreeheight(B));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  freenode    %6d  |\n", getnodenumber(B, getfirstfreenode(B)));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  theKey      %6s  |\n", getfunkey(B).name);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "|  theData     %d.%d.%d |\n", getfundata(B).volume,
               getfundata(B).vnode, getfundata(B).unique);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     sprintf(B->message, "-  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  }
  
--- 1389,1449 ----
  {
      int x;
  
!     StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "| %-20s                        |\n", where);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "| node %6d                 ", getnodenumber(B, n));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "  magic    %4x  |\n", getmagic(n));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "| flags   %1d%1d%1d%1d ", isfew(n), isfull(n), isroot(n), isleaf(n));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "| keys = %5d ", numentries(n));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "| node = %6d  |\n", getnodenumber(B, getfirstnode(n)));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      for (x = 1; x <= numentries(n); x++) {
!         StringCbPrintfA(B->message, sizeof(B->message), "| entry %6d ", x);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!         StringCbPrintfA(B->message, sizeof(B->message), "| key = %6s ", getkey(n, x).name);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!         StringCbPrintfA(B->message, sizeof(B->message), "| node = %6d  |\n", getnodenumber(B, getnode(n, x)));
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
      }
!     StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  }
  
  /******************   B+tree class variable printer   ******************/
  void showBtree(Tree *B)
  {
!     StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  B+tree  %10p  |\n", (void *) B);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  root        %6d  |\n", getnodenumber(B, getroot(B)));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  leaf        %6d  |\n", getnodenumber(B, getleaf(B)));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  fanout         %3d  |\n", getfanout(B) + 1);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  minfanout      %3d  |\n", getminfanout(B, getroot(B)) + 1);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  height         %3d  |\n", gettreeheight(B));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  freenode    %6d  |\n", getnodenumber(B, getfirstfreenode(B)));
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  theKey      %6s  |\n", getfunkey(B).name);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "|  theData     %d.%d.%d |\n", getfundata(B).volume,
               getfundata(B).vnode, getfundata(B).unique);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
!     StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  -\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  }
  
***************
*** 1448,1454 ****
      dataT data;
  
      if (isntnode(node)) {
!         sprintf(B->message, "%s - NoNode!!!\n");
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          return;
      } 
--- 1455,1461 ----
      dataT data;
  
      if (isntnode(node)) {
!         StringCbPrintfA(B->message, sizeof(B->message), "%s - NoNode!!!\n");
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          return;
      } 
***************
*** 1456,1462 ****
      if (!isnode(node))
      {
          data = getdatavalue(node);
!         sprintf(B->message, "%s - data node %d (%d.%d.%d)\n", 
                   parent_desc, getnodenumber(B, node),
                   data.fid.volume, data.fid.vnode, data.fid.unique);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
--- 1463,1469 ----
      if (!isnode(node))
      {
          data = getdatavalue(node);
!         StringCbPrintfA(B->message, sizeof(B->message), "%s - data node %d (%d.%d.%d)\n", 
                   parent_desc, getnodenumber(B, node),
                   data.fid.volume, data.fid.vnode, data.fid.unique);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
***************
*** 1465,1471 ****
          showNode(B, parent_desc, node);
  
      if ( isinternal(node) || isroot(node) ) {
!         sprintf(thisnode, "parent %6d", getnodenumber(B , node));
  
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          for ( i= isinternal(node) ? 0 : 1; i <= numentries(node); i++ ) {
--- 1472,1478 ----
          showNode(B, parent_desc, node);
  
      if ( isinternal(node) || isroot(node) ) {
!         StringCbPrintfA(thisnode, sizeof(thisnode), "parent %6d", getnodenumber(B , node));
  
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          for ( i= isinternal(node) ? 0 : 1; i <= numentries(node); i++ ) {
***************
*** 1479,1502 ****
  listBtreeValues(Tree *B, Nptr n, int num)
  {
      int slot;
!     keyT prev = {""};
      dataT data;
  
      for (slot = 1; (n != NONODE) && num && numentries(n); num--) {
          if (comparekeys(B)(getkey(n, slot),prev, 0) < 0) {
!             sprintf(B->message, "BOMB %8s\n", getkey(n, slot).name);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
              DebugBreak();
          }
          prev = getkey(n, slot);
          data = getdatavalue(getnode(n, slot));
!         sprintf(B->message, "%8s (%d.%d.%d)\n", 
                  prev.name, data.fid.volume, data.fid.vnode, data.fid.unique);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          if (++slot > numentries(n))
              n = getnextnode(n), slot = 1;
!     }   
!     sprintf(B->message, "\n\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  }
  
--- 1486,1509 ----
  listBtreeValues(Tree *B, Nptr n, int num)
  {
      int slot;
!     keyT prev = {L""};
      dataT data;
  
      for (slot = 1; (n != NONODE) && num && numentries(n); num--) {
          if (comparekeys(B)(getkey(n, slot),prev, 0) < 0) {
!             StringCbPrintfA(B->message, sizeof(B->message), "BOMB %8s\n", getkey(n, slot).name);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
              DebugBreak();
          }
          prev = getkey(n, slot);
          data = getdatavalue(getnode(n, slot));
!         StringCbPrintfA(B->message, sizeof(B->message), "%8S (%d.%d.%d)\n", 
                  prev.name, data.fid.volume, data.fid.vnode, data.fid.unique);
          osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
          if (++slot > numentries(n))
              n = getnextnode(n), slot = 1;
!     }
!     StringCbPrintfA(B->message, sizeof(B->message), "\n\n");
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  }
  
***************
*** 1514,1524 ****
      int num = -1;
      Nptr n = getleaf(B), l;
      int slot;
!     keyT prev = {""};
  
      for (slot = 1; (n != NONODE) && num && numentries(n); num--) {
          if (comparekeys(B)(getkey(n, slot),prev, 0) < 0) {
!             sprintf(B->message,"BOMB %8s\n", getkey(n, slot).name);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #ifdef DEBUG_BTREE
              DebugBreak();
--- 1521,1531 ----
      int num = -1;
      Nptr n = getleaf(B), l;
      int slot;
!     keyT prev = {L""};
  
      for (slot = 1; (n != NONODE) && num && numentries(n); num--) {
          if (comparekeys(B)(getkey(n, slot),prev, 0) < 0) {
!             StringCbPrintfA(B->message, sizeof(B->message),"BOMB %8s\n", getkey(n, slot).name);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #ifdef DEBUG_BTREE
              DebugBreak();
***************
*** 1528,1536 ****
          l = bplus_Lookup(B, prev);
          if ( l != n ){
              if (l == NONODE)
!                 sprintf(B->message,"BOMB %8s cannot be found\n", prev.name);
              else 
!                 sprintf(B->message,"BOMB lookup(%8s) finds wrong node\n", prev.name);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #ifdef DEBUG_BTREE
              DebugBreak();
--- 1535,1543 ----
          l = bplus_Lookup(B, prev);
          if ( l != n ){
              if (l == NONODE)
!                 StringCbPrintfA(B->message, sizeof(B->message),"BOMB %8S cannot be found\n", prev.name);
              else 
!                 StringCbPrintfA(B->message, sizeof(B->message),"BOMB lookup(%8S) finds wrong node\n", prev.name);
              osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
  #ifdef DEBUG_BTREE
              DebugBreak();
***************
*** 1552,1568 ****
   * match.  Otherwise, the search order might be considered 
   * to be inconsistent when the EXACT_MATCH flag is set.
   */
! static int
! compareKeys(keyT key1, keyT key2, int flags)
  {
      int comp;
  
!     comp = stricmp(key1.name, key2.name);
      if (comp == 0 && (flags & EXACT_MATCH))
!         comp = strcmp(key1.name, key2.name);
      return (comp < 0 ? -1 : (comp > 0 ? 1 : 0));
  }
  
  /* Look up a file name in directory.
  
     On entry:
--- 1559,1661 ----
   * match.  Otherwise, the search order might be considered 
   * to be inconsistent when the EXACT_MATCH flag is set.
   */
! int
! cm_BPlusCompareNormalizedKeys(keyT key1, keyT key2, int flags)
  {
      int comp;
  
!     comp = cm_NormStrCmpI(key1.name, key2.name);
      if (comp == 0 && (flags & EXACT_MATCH))
!         comp = cm_NormStrCmp(key1.name, key2.name);
      return (comp < 0 ? -1 : (comp > 0 ? 1 : 0));
  }
  
+ int
+ cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, clientchar_t *centry,
+                               fschar_t **fsnameRetp)
+ {
+     int rc = EINVAL;
+     keyT key = {NULL};
+     Nptr leafNode = NONODE;
+     LARGE_INTEGER start, end;
+     fschar_t * fsname = NULL;
+     normchar_t * entry = NULL;
+ 
+     if (op->scp->dirBplus == NULL || 
+         op->dataVersion != op->scp->dirDataVersion) {
+         rc = EINVAL;
+         goto done;
+     }
+ 
+     entry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+     key.name = entry;
+ 
+     lock_AssertAny(&op->scp->dirlock);
+ 
+     QueryPerformanceCounter(&start);
+ 
+     leafNode = bplus_Lookup(op->scp->dirBplus, key);
+     if (leafNode != NONODE) {
+         int         slot;
+         Nptr        firstDataNode, dataNode, nextDataNode;
+         int         exact = 0;
+         int         count = 0;
+ 
+         /* Found a leaf that matches the key via a case-insensitive
+          * match.  There may be one or more data nodes that match.
+          * If we have an exact match, return that.
+          * If we have an ambiguous match, return an error.
+          * If we have only one inexact match, return that.
+          */
+         slot = getSlot(op->scp->dirBplus, leafNode);
+         if (slot <= BTERROR) {
+             op->scp->dirDataVersion = 0;
+             rc = (slot == BTERROR ? EINVAL : ENOENT);
+             goto done;
+         }
+         firstDataNode = getnode(leafNode, slot);
+ 
+         for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
+             count++;
+             if (!comparekeys(op->scp->dirBplus)(key, getdatakey(dataNode), EXACT_MATCH) ) {
+                 exact = 1;
+                 break;
+             }
+             nextDataNode = getdatanext(dataNode);
+         }
+ 
+         if (exact) {
+             fsname = getdatavalue(dataNode).fsname;
+             rc = 0;
+             bplus_lookup_hits++;
+         } else if (count == 1) {
+             fsname = getdatavalue(firstDataNode).fsname;
+             rc = CM_ERROR_INEXACT_MATCH;
+             bplus_lookup_hits_inexact++;
+         } else {
+             rc = CM_ERROR_AMBIGUOUS_FILENAME;
+             bplus_lookup_ambiguous++;
+         } 
+     } else {
+         rc = ENOENT;
+         bplus_lookup_misses++;
+     }
+ 
+     if (fsname)
+         *fsnameRetp = cm_FsStrDup(fsname);
+ 
+     QueryPerformanceCounter(&end);
+ 
+     bplus_lookup_time += (end.QuadPart - start.QuadPart);
+ 
+   done:
+     if (entry)
+         free(entry);
+ 
+     return rc;
+ 
+ }
+ 
  /* Look up a file name in directory.
  
     On entry:
***************
*** 1572,1581 ****
         op->scp->dirlock is read locked
  */
  int
! cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
  {
      int rc = EINVAL;
!     keyT key = {entry};
      Nptr leafNode = NONODE;
      LARGE_INTEGER start, end;
  
--- 1665,1675 ----
         op->scp->dirlock is read locked
  */
  int
! cm_BPlusDirLookup(cm_dirOp_t * op, clientchar_t * centry, cm_fid_t * cfid)
  {
      int rc = EINVAL;
!     normchar_t * entry = NULL;
!     keyT key = {NULL};
      Nptr leafNode = NONODE;
      LARGE_INTEGER start, end;
  
***************
*** 1585,1590 ****
--- 1679,1687 ----
          goto done;
      }
  
+     entry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+     key.name = entry;
+ 
      lock_AssertAny(&op->scp->dirlock);
  
      QueryPerformanceCounter(&start);
***************
*** 1641,1646 ****
--- 1738,1746 ----
      bplus_lookup_time += (end.QuadPart - start.QuadPart);
  
    done:
+     if (entry)
+         free(entry);
+ 
      return rc;
  }
  
***************
*** 1652,1664 ****
     On exit:
         op->scp->dirlock is write locked
  */
! long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
  {
      long rc = 0;
!     keyT key = {entry};
      dataT  data;
      LARGE_INTEGER start, end;
!     char shortName[13];
  
      if (op->scp->dirBplus == NULL || 
          op->dataVersion != op->scp->dirDataVersion) {
--- 1752,1764 ----
     On exit:
         op->scp->dirlock is write locked
  */
! long cm_BPlusDirCreateEntry(cm_dirOp_t * op, clientchar_t * entry, cm_fid_t * cfid)
  {
      long rc = 0;
!     keyT key = {NULL};
      dataT  data;
      LARGE_INTEGER start, end;
!     normchar_t * normalizedName = NULL;
  
      if (op->scp->dirBplus == NULL || 
          op->dataVersion != op->scp->dirDataVersion) {
***************
*** 1666,1690 ****
          goto done;
      }
  
  
      lock_AssertWrite(&op->scp->dirlock);
  
      cm_SetFid(&data.fid, cfid->cell, cfid->volume, cfid->vnode, cfid->unique);
!     data.longname = NULL;
  
      QueryPerformanceCounter(&start);
      bplus_create_entry++;
  
      insert(op->scp->dirBplus, key, data);
      if (!cm_Is8Dot3(entry)) {
          cm_dirFid_t dfid;
          dfid.vnode = htonl(data.fid.vnode);
          dfid.unique = htonl(data.fid.unique);
  
!         cm_Gen8Dot3NameInt(entry, &dfid, shortName, NULL);
  
-         key.name = shortName;
-         data.longname = strdup(entry);
          insert(op->scp->dirBplus, key, data);
      }
  
--- 1766,1801 ----
          goto done;
      }
  
+     normalizedName = cm_ClientStringToNormStringAlloc(entry, -1, NULL);
+     key.name = normalizedName;
  
      lock_AssertWrite(&op->scp->dirlock);
  
      cm_SetFid(&data.fid, cfid->cell, cfid->volume, cfid->vnode, cfid->unique);
!     data.cname = cm_ClientStrDup(entry);
!     data.fsname = cm_ClientStringToFsStringAlloc(entry, -1, NULL);
!     data.shortform = FALSE;
  
      QueryPerformanceCounter(&start);
      bplus_create_entry++;
  
      insert(op->scp->dirBplus, key, data);
+     
      if (!cm_Is8Dot3(entry)) {
          cm_dirFid_t dfid;
+         clientchar_t wshortName[13];
+ 
          dfid.vnode = htonl(data.fid.vnode);
          dfid.unique = htonl(data.fid.unique);
  
!         cm_Gen8Dot3NameIntW(entry, &dfid, wshortName, NULL);
! 
!         key.name = wshortName;
! 
!         data.cname = cm_ClientStrDup(entry);
!         data.fsname = cm_ClientStringToFsStringAlloc(entry, -1, NULL);
!         data.shortform = TRUE;
  
          insert(op->scp->dirBplus, key, data);
      }
  
***************
*** 1694,1699 ****
--- 1805,1813 ----
  
    done:
  
+     if (normalizedName != NULL)
+         free(normalizedName);
+ 
      return rc;
  }
  
***************
*** 1704,1715 ****
     On exit:
         op->scp->dirlock is write locked
  */
! int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
  {
      long rc = 0;
!     keyT key = {entry};
      Nptr leafNode = NONODE;
      LARGE_INTEGER start, end;
  
      if (op->scp->dirBplus == NULL || 
          op->dataVersion != op->scp->dirDataVersion) {
--- 1818,1830 ----
     On exit:
         op->scp->dirlock is write locked
  */
! int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, clientchar_t *centry)
  {
      long rc = 0;
!     keyT key = {NULL};
      Nptr leafNode = NONODE;
      LARGE_INTEGER start, end;
+     normchar_t * normalizedEntry = NULL;
  
      if (op->scp->dirBplus == NULL || 
          op->dataVersion != op->scp->dirDataVersion) {
***************
*** 1717,1722 ****
--- 1832,1840 ----
          goto done;
      }
  
+     normalizedEntry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+     key.name = normalizedEntry;
+ 
      lock_AssertWrite(&op->scp->dirlock);
  
      QueryPerformanceCounter(&start);
***************
*** 1724,1733 ****
      bplus_remove_entry++;
  
      if (op->scp->dirBplus) {
!         if (!cm_Is8Dot3(entry)) {
              cm_dirFid_t dfid;
              cm_fid_t fid;
!             char shortName[13];
  
              leafNode = bplus_Lookup(op->scp->dirBplus, key);
              if (leafNode != NONODE) {
--- 1842,1851 ----
      bplus_remove_entry++;
  
      if (op->scp->dirBplus) {
!         if (!cm_Is8Dot3(centry)) {
              cm_dirFid_t dfid;
              cm_fid_t fid;
!             clientchar_t shortName[13];
  
              leafNode = bplus_Lookup(op->scp->dirBplus, key);
              if (leafNode != NONODE) {
***************
*** 1774,1780 ****
              if (rc != CM_ERROR_AMBIGUOUS_FILENAME) {
                  dfid.vnode = htonl(fid.vnode);
                  dfid.unique = htonl(fid.unique);
!                 cm_Gen8Dot3NameInt(entry, &dfid, shortName, NULL);
  
                  /* delete first the long name and then the short name */
                  delete(op->scp->dirBplus, key);
--- 1892,1898 ----
              if (rc != CM_ERROR_AMBIGUOUS_FILENAME) {
                  dfid.vnode = htonl(fid.vnode);
                  dfid.unique = htonl(fid.unique);
!                 cm_Gen8Dot3NameIntW(centry, &dfid, shortName, NULL);
  
                  /* delete first the long name and then the short name */
                  delete(op->scp->dirBplus, key);
***************
*** 1782,1788 ****
                  delete(op->scp->dirBplus, key);
              }
          } else {
!             char * longname = NULL;
              /* We need to lookup the 8dot3 name to determine what the 
               * matching long name is
               */
--- 1900,1907 ----
                  delete(op->scp->dirBplus, key);
              }
          } else {
!             clientchar_t * cname = NULL;
! 
              /* We need to lookup the 8dot3 name to determine what the 
               * matching long name is
               */
***************
*** 1818,1827 ****
                  }
  
                  if (exact) {
!                     longname = getdatavalue(dataNode).longname;
                      rc = 0;
                  } else if (count == 1) {
!                     longname = getdatavalue(firstDataNode).longname;
                      rc = CM_ERROR_INEXACT_MATCH;
                  } else {
                      rc = CM_ERROR_AMBIGUOUS_FILENAME;
--- 1937,1946 ----
                  }
  
                  if (exact) {
!                     cname = getdatavalue(dataNode).cname;
                      rc = 0;
                  } else if (count == 1) {
!                     cname = getdatavalue(firstDataNode).cname;
                      rc = CM_ERROR_INEXACT_MATCH;
                  } else {
                      rc = CM_ERROR_AMBIGUOUS_FILENAME;
***************
*** 1829,1839 ****
              }
  
              if (rc != CM_ERROR_AMBIGUOUS_FILENAME) {
!                 if (longname) {
!                     key.name = longname;
                      delete(op->scp->dirBplus, key);
!                     key.name = entry;
                  }
                  delete(op->scp->dirBplus, key);
              }
          }
--- 1948,1963 ----
              }
  
              if (rc != CM_ERROR_AMBIGUOUS_FILENAME) {
!                 if (cname) {
!                     normchar_t * longNName = cm_NormalizeStringAlloc(cname, -1, NULL);
! 
!                     key.name = longNName;
                      delete(op->scp->dirBplus, key);
!                     key.name = normalizedEntry;
! 
!                     free(longNName);
                  }
+ 
                  delete(op->scp->dirBplus, key);
              }
          }
***************
*** 1844,1849 ****
--- 1968,1976 ----
      bplus_remove_time += (end.QuadPart - start.QuadPart);
  
    done:
+     if (normalizedEntry)
+         free(normalizedEntry);
+ 
      return rc;
        
  }
***************
*** 1852,1878 ****
  int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
                     void *dummy, osi_hyper_t *entryOffsetp)
  {
!     keyT   key = {dep->name};
      dataT  data;
!     char   shortName[13];
  
!     cm_SetFid(&data.fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
!     data.longname = NULL;
  
      /* the Write lock is held in cm_BPlusDirBuildTree() */
      insert(scp->dirBplus, key, data);
!     if (!cm_Is8Dot3(dep->name)) {
          cm_dirFid_t dfid;
          dfid.vnode = dep->fid.vnode;
          dfid.unique = dep->fid.unique;
  
!         cm_Gen8Dot3NameInt(dep->name, &dfid, shortName, NULL);
  
!         key.name = shortName;
!         data.longname = strdup(dep->name);
          insert(scp->dirBplus, key, data);
      }
  
  #ifdef BTREE_DEBUG
      findAllBtreeValues(scp->dirBplus);
  #endif
--- 1979,2031 ----
  int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
                     void *dummy, osi_hyper_t *entryOffsetp)
  {
!     keyT   key = {NULL};
      dataT  data;
!     normchar_t *normalized_name=NULL;
  
!     cm_SetFid(&data.fid, scp->fid.cell, scp->fid.volume, 
!               ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
!     data.cname = NULL;
!     data.fsname = NULL;
  
+     normalized_name = cm_FsStringToNormStringAlloc(dep->name, -1, NULL);
+ 
+     if (normalized_name) {
+         key.name = normalized_name;
+     } else {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         return 0;
+     }
+   
+     data.cname = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
+     data.fsname = cm_FsStrDup(dep->name);
+     data.shortform = FALSE;
+      
      /* the Write lock is held in cm_BPlusDirBuildTree() */
      insert(scp->dirBplus, key, data);
! 
!     if (!cm_Is8Dot3(data.cname)) {
          cm_dirFid_t dfid;
+         wchar_t wshortName[13];
+ 
          dfid.vnode = dep->fid.vnode;
          dfid.unique = dep->fid.unique;
  
!         cm_Gen8Dot3NameIntW(data.cname, &dfid, wshortName, NULL);
  
!         key.name = wshortName;
!         data.cname = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
!         data.fsname = cm_FsStrDup(dep->name);
!         data.shortform = TRUE;
!   
          insert(scp->dirBplus, key, data);
      }
  
+     if (normalized_name)
+         free(normalized_name);
+ 
  #ifdef BTREE_DEBUG
      findAllBtreeValues(scp->dirBplus);
  #endif
***************
*** 1899,1905 ****
      bplus_build_tree++;
  
      if (scp->dirBplus == NULL) {
!         scp->dirBplus = initBtree(64, MAX_FANOUT, compareKeys);
      }
      if (scp->dirBplus == NULL) {
          rc = ENOMEM;
--- 2052,2058 ----
      bplus_build_tree++;
  
      if (scp->dirBplus == NULL) {
!         scp->dirBplus = initBtree(64, MAX_FANOUT, cm_BPlusCompareNormalizedKeys);
      }
      if (scp->dirBplus == NULL) {
          rc = ENOMEM;
***************
*** 1924,1957 ****
      int zilch;
      char output[128];
  
!     sprintf(output, "%s - B+ Lookup    Hits: %-8d\r\n", cookie, bplus_lookup_hits);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -      Inexact Hits: %-8d\r\n", cookie, bplus_lookup_hits_inexact);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -    Ambiguous Hits: %-8d\r\n", cookie, bplus_lookup_ambiguous);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -            Misses: %-8d\r\n", cookie, bplus_lookup_misses);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -            Create: %-8d\r\n", cookie, bplus_create_entry);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -            Remove: %-8d\r\n", cookie, bplus_remove_entry);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -        Build Tree: %-8d\r\n", cookie, bplus_build_tree);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -         Free Tree: %-8d\r\n", cookie, bplus_free_tree);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -          DV Error: %-8d\r\n", cookie, bplus_dv_error);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
  
!     sprintf(output, "%s - B+ Time    Lookup: %-16I64d\r\n", cookie, bplus_lookup_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -            Create: %-16I64d\r\n", cookie, bplus_create_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -            Remove: %-16I64d\r\n", cookie, bplus_remove_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -             Build: %-16I64d\r\n", cookie, bplus_build_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     sprintf(output, "%s -              Free: %-16I64d\r\n", cookie, bplus_free_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
  
      return(0);
--- 2077,2110 ----
      int zilch;
      char output[128];
  
!     StringCbPrintfA(output, sizeof(output), "%s - B+ Lookup    Hits: %-8d\r\n", cookie, bplus_lookup_hits);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -      Inexact Hits: %-8d\r\n", cookie, bplus_lookup_hits_inexact);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -    Ambiguous Hits: %-8d\r\n", cookie, bplus_lookup_ambiguous);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -            Misses: %-8d\r\n", cookie, bplus_lookup_misses);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -            Create: %-8d\r\n", cookie, bplus_create_entry);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -            Remove: %-8d\r\n", cookie, bplus_remove_entry);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -        Build Tree: %-8d\r\n", cookie, bplus_build_tree);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -         Free Tree: %-8d\r\n", cookie, bplus_free_tree);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -          DV Error: %-8d\r\n", cookie, bplus_dv_error);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
  
!     StringCbPrintfA(output, sizeof(output), "%s - B+ Time    Lookup: %-16I64d\r\n", cookie, bplus_lookup_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -            Create: %-16I64d\r\n", cookie, bplus_create_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -            Remove: %-16I64d\r\n", cookie, bplus_remove_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -             Build: %-16I64d\r\n", cookie, bplus_build_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
!     StringCbPrintfA(output, sizeof(output), "%s -              Free: %-16I64d\r\n", cookie, bplus_free_time);
      WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
  
      return(0);
***************
*** 1994,2000 ****
  
  long 
  cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked, 
!                      char * maskp, cm_direnum_t **enumpp)
  {
      afs_uint32 count = 0, slot, numentries;
      Nptr leafNode = NONODE, nextLeafNode;
--- 2147,2153 ----
  
  long 
  cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked, 
!                      clientchar_t * maskp, cm_direnum_t **enumpp)
  {
      afs_uint32 count = 0, slot, numentries;
      Nptr leafNode = NONODE, nextLeafNode;
***************
*** 2021,2036 ****
  	    firstDataNode = getnode(leafNode, slot);
  
  	    for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
                  if (maskp == NULL) {
!                     /* name is in getdatakey(dataNode) */
!                     if (getdatavalue(dataNode).longname != NULL ||
!                         cm_Is8Dot3(getdatakey(dataNode).name))
                          count++;
                  } else {
! 		    if (cm_Is8Dot3(getdatakey(dataNode).name) && 
!                         smb_V3MatchMask(getdatakey(dataNode).name, maskp, CM_FLAG_CASEFOLD) ||
!                         getdatavalue(dataNode).longname == NULL &&
!                         smb_V3MatchMask(getdatavalue(dataNode).longname, maskp, CM_FLAG_CASEFOLD))
                          count++;
                  }
  		nextDataNode = getdatanext(dataNode);
--- 2174,2190 ----
  	    firstDataNode = getnode(leafNode, slot);
  
  	    for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
+ 
+                 /* There can be two data nodes for one file.  One for
+                    the long name and one for the short name.  We only
+                    include one of these for the enumeration */
+ 
                  if (maskp == NULL) {
!                     if (!getdatavalue(dataNode).shortform)
                          count++;
                  } else {
! 		    if (!getdatavalue(dataNode).shortform &&
!                         cm_MatchMask(getdatavalue(dataNode).cname, maskp, CM_FLAG_CASEFOLD))
                          count++;
                  }
  		nextDataNode = getdatanext(dataNode);
***************
*** 2038,2046 ****
  	}
  
  	nextLeafNode = getnextnode(leafNode);
!     }   
  
!     sprintf(buffer, "BPlusTreeEnumerate count = %d", count);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, buffer));
  
      /* Allocate the enumeration object */
--- 2192,2200 ----
  	}
  
  	nextLeafNode = getnextnode(leafNode);
!     }
  
!     StringCbPrintfA(buffer, sizeof(buffer), "BPlusTreeEnumerate count = %d", count);
      osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, buffer));
  
      /* Allocate the enumeration object */
***************
*** 2050,2104 ****
  	rc = ENOMEM;
  	goto done;
      }
! 	
!     /* Copy the name and fid for each longname entry into the enumeration */
      for (count = 0, leafNode = getleaf(scp->dirBplus); leafNode; leafNode = nextLeafNode) {
  
  	for ( slot = 1, numentries = numentries(leafNode); slot <= numentries; slot++) {
  	    firstDataNode = getnode(leafNode, slot);
  
  	    for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
!                 char * name;
!                 int hasShortName;
                  int includeIt = 0;
  
                  if (maskp == NULL) {
!                     if (getdatavalue(dataNode).longname != NULL ||
!                          cm_Is8Dot3(getdatakey(dataNode).name)) 
!                     {
                          includeIt = 1;
                      }
                  } else {
! 		    if (cm_Is8Dot3(getdatakey(dataNode).name) && 
!                         smb_V3MatchMask(getdatakey(dataNode).name, maskp, CM_FLAG_CASEFOLD) ||
!                         getdatavalue(dataNode).longname == NULL &&
!                          smb_V3MatchMask(getdatavalue(dataNode).longname, maskp, CM_FLAG_CASEFOLD)) 
!                     {
                          includeIt = 1;
                      }
                  }
  
                  if (includeIt) {
!                     if (getdatavalue(dataNode).longname) {
!                         name = strdup(getdatavalue(dataNode).longname);
!                         hasShortName = 1;
!                     } else {
!                         name = strdup(getdatakey(dataNode).name);
!                         hasShortName = 0;
!                     }
  
                      if (name == NULL) {
                          osi_Log0(afsd_logp, "cm_BPlusDirEnumerate strdup failed");
                          rc = ENOMEM;
                          goto done;
                      }
                      enump->entry[count].name = name;
                      enump->entry[count].fid  = getdatavalue(dataNode).fid;
!                     if (hasShortName)
!                         strncpy(enump->entry[count].shortName, getdatakey(dataNode).name, 
!                                 sizeof(enump->entry[count].shortName));
!                     else
!                         enump->entry[count].shortName[0] = '\0';
                      count++;
                  }
  		nextDataNode = getdatanext(dataNode);
--- 2204,2256 ----
  	rc = ENOMEM;
  	goto done;
      }
! 
!     /* Copy the name and fid for each cname entry into the enumeration */
      for (count = 0, leafNode = getleaf(scp->dirBplus); leafNode; leafNode = nextLeafNode) {
  
  	for ( slot = 1, numentries = numentries(leafNode); slot <= numentries; slot++) {
  	    firstDataNode = getnode(leafNode, slot);
  
  	    for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
!                 clientchar_t * name;
                  int includeIt = 0;
  
                  if (maskp == NULL) {
!                     if (!getdatavalue(dataNode).shortform) {
                          includeIt = 1;
                      }
                  } else {
! 		    if (!getdatavalue(dataNode).shortform &&
!                         cm_MatchMask(getdatavalue(dataNode).cname, maskp, CM_FLAG_CASEFOLD)) {
                          includeIt = 1;
                      }
                  }
  
                  if (includeIt) {
!                     name = cm_ClientStrDup(getdatavalue(dataNode).cname);
  
                      if (name == NULL) {
                          osi_Log0(afsd_logp, "cm_BPlusDirEnumerate strdup failed");
                          rc = ENOMEM;
                          goto done;
                      }
+ 
                      enump->entry[count].name = name;
                      enump->entry[count].fid  = getdatavalue(dataNode).fid;
! 
!                     if (!cm_Is8Dot3(name)) {
!                         cm_dirFid_t dfid;
! 
!                         dfid.vnode = htonl(getdatavalue(dataNode).fid.vnode);
!                         dfid.unique = htonl(getdatavalue(dataNode).fid.unique);
! 
!                         cm_Gen8Dot3NameIntW(name, &dfid, enump->entry[count].shortName, NULL);
!                     } else {
!                         StringCbCopyW(enump->entry[count].shortName,
!                                       sizeof(enump->entry[count].shortName),
!                                       name);
!                     }
! 
                      count++;
                  }
  		nextDataNode = getdatanext(dataNode);
***************
*** 2130,2135 ****
--- 2282,2339 ----
  }
  
  long 
+ cm_BPlusDirEnumBulkStat(cm_scache_t *dscp, cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp)
+ {
+     cm_bulkStat_t *bsp;
+     afs_uint32 count;
+     afs_uint32 code;
+ 
+     if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
+         return 0;
+ 
+     bsp = malloc(sizeof(cm_bulkStat_t));
+     memset(bsp, 0, sizeof(cm_bulkStat_t));
+ 
+     for ( count = 0; count < enump->count; count++ ) {
+         cm_scache_t   *tscp = cm_FindSCache(&enump->entry[count].fid);
+         int i;
+ 
+         if (tscp) {
+             if (lock_TryWrite(&tscp->rw)) {
+                 /* we have an entry that we can look at */
+                 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && 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_ReleaseWrite(&tscp->rw);
+                     cm_ReleaseSCache(tscp);
+                     continue;
+                 }
+                 lock_ReleaseWrite(&tscp->rw);
+             }	/* got lock */
+             cm_ReleaseSCache(tscp);
+         }	/* found entry */
+ 
+         i = bsp->counter++;
+         bsp->fids[i].Volume = enump->entry[count].fid.volume;
+         bsp->fids[i].Vnode = enump->entry[count].fid.vnode;
+         bsp->fids[i].Unique = enump->entry[count].fid.unique;
+ 
+         if (bsp->counter == AFSCBMAX) {
+             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+             memset(bsp, 0, sizeof(cm_bulkStat_t));
+         }
+     }
+ 
+     if (bsp->counter > 0)
+         code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+ 
+     free(bsp);
+     return 0;
+ }
+ 
+ long 
  cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
  {	
      if (enump == NULL || entrypp == NULL || enump->next > enump->count) {
***************
*** 2213,2219 ****
                  cm_ReleaseSCache(scp);
  	    }
  
! 	    sprintf(buffer, "'%s' Fid = (%d,%d,%d,%d) Short = '%s' Type %s DV %I64d",
  		    entryp->name,
  		    entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique,
  		    entryp->shortName,
--- 2417,2423 ----
                  cm_ReleaseSCache(scp);
  	    }
  
! 	    StringCbPrintfA(buffer, sizeof(buffer), "'%S' Fid = (%d,%d,%d,%d) Short = '%S' Type %s DV %I64d",
  		    entryp->name,
  		    entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique,
  		    entryp->shortName,
Index: openafs/src/WINNT/afsd/cm_btree.h
diff -c openafs/src/WINNT/afsd/cm_btree.h:1.1.2.7 openafs/src/WINNT/afsd/cm_btree.h:1.1.2.10
*** openafs/src/WINNT/afsd/cm_btree.h:1.1.2.7	Mon Nov  5 13:26:49 2007
--- openafs/src/WINNT/afsd/cm_btree.h	Mon Jul 14 09:01:31 2008
***************
*** 48,60 ****
  typedef struct node	*Nptr;
  
  typedef struct key {
!     char *name;
  } keyT;
  
- 
  typedef struct dirdata {
      cm_fid_t    fid;
!     char * longname;
  } dataT;
  
  typedef struct entry {
--- 48,65 ----
  typedef struct node	*Nptr;
  
  typedef struct key {
!     normchar_t  *name;           /* Normalized name */
  } keyT;
  
  typedef struct dirdata {
      cm_fid_t    fid;
!     int         shortform;      /* This is the short form entry.  If
!                                    this value is non-zero, then there
!                                    is another entry in the B-Plus tree
!                                    corresponding to the long name of
!                                    this fid. */
!     clientchar_t  *cname;          /* Client name (long) */
!     fschar_t * fsname;         /* FileServer name */
  } dataT;
  
  typedef struct entry {
***************
*** 136,154 ****
  Nptr	lookup(Tree *B, keyT key);
  
  /******************* cache manager directory operations ***************/
! int  cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid);
! long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid);
! int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry);
  long cm_BPlusDirBuildTree(cm_scache_t *scp, cm_user_t *userp, cm_req_t* reqp);
  void cm_BPlusDumpStats(void);
! int cm_MemDumpBPlusStats(FILE *outputFile, char *cookie, int lock);
! 
  
  /******************* directory enumeration operations ****************/
  typedef struct cm_direnum_entry {
!     char * 	name;
!     cm_fid_t 	fid;
!     char        shortName[13];
  } cm_direnum_entry_t;
  
  typedef struct cm_direnum {
--- 141,161 ----
  Nptr	lookup(Tree *B, keyT key);
  
  /******************* cache manager directory operations ***************/
! 
! int  cm_BPlusCompareNormalizedKeys(keyT key1, keyT key2, int flags);
! int  cm_BPlusDirLookup(cm_dirOp_t * op, clientchar_t *entry, cm_fid_t * cfid);
! int  cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, clientchar_t *entry, fschar_t **originalNameRetp);
! long cm_BPlusDirCreateEntry(cm_dirOp_t * op, clientchar_t *entry, cm_fid_t * cfid);
! int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, clientchar_t *entry);
  long cm_BPlusDirBuildTree(cm_scache_t *scp, cm_user_t *userp, cm_req_t* reqp);
  void cm_BPlusDumpStats(void);
! int  cm_MemDumpBPlusStats(FILE *outputFile, char *cookie, int lock);
  
  /******************* directory enumeration operations ****************/
  typedef struct cm_direnum_entry {
!     clientchar_t *name;
!     cm_fid_t 	 fid;
!     normchar_t   shortName[13];
  } cm_direnum_entry_t;
  
  typedef struct cm_direnum {
***************
*** 157,166 ****
      cm_direnum_entry_t 	entry[1];
  } cm_direnum_t;
  
! long cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked, char *maskp, cm_direnum_t **enumpp);
  long cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp);
  long cm_BPlusDirFreeEnumeration(cm_direnum_t *enump);
  long cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked);
  
  long cm_InitBPlusDir(void);
  
--- 164,174 ----
      cm_direnum_entry_t 	entry[1];
  } cm_direnum_t;
  
! long cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked, clientchar_t *maskp, cm_direnum_t **enumpp);
  long cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp);
  long cm_BPlusDirFreeEnumeration(cm_direnum_t *enump);
  long cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked);
+ long cm_BPlusDirEnumBulkStat(cm_scache_t *dscp, cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp);
  
  long cm_InitBPlusDir(void);
  
***************
*** 179,185 ****
  /* access keys and pointers in a node */
  #define getkey(j, q) (nAdr(j).e[(q)].key)
  #define getnode(j, q) (nAdr(j).e[(q)].downNode)
! #define setkey(j, q, v) ((q > 0) ? nAdr(j).e[(q)].key.name = strdup((v).name) : NULL)
  #define setnode(j, q, v) (nAdr(j).e[(q)].downNode = (v))
  
  /* access tree flag values */
--- 187,193 ----
  /* access keys and pointers in a node */
  #define getkey(j, q) (nAdr(j).e[(q)].key)
  #define getnode(j, q) (nAdr(j).e[(q)].downNode)
! #define setkey(j, q, v) ((q > 0) ? nAdr(j).e[(q)].key.name = cm_NormStrDup((v).name) : NULL)
  #define setnode(j, q, v) (nAdr(j).e[(q)].downNode = (v))
  
  /* access tree flag values */
Index: openafs/src/WINNT/afsd/cm_buf.c
diff -c openafs/src/WINNT/afsd/cm_buf.c:1.31.2.38.2.1 openafs/src/WINNT/afsd/cm_buf.c:1.31.2.41
*** openafs/src/WINNT/afsd/cm_buf.c:1.31.2.38.2.1	Sun Jun 22 23:02:06 2008
--- openafs/src/WINNT/afsd/cm_buf.c	Thu Jun 26 10:38:23 2008
***************
*** 12,20 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
- #endif
  #include <osi.h>
  #include <stdio.h>
  #include <assert.h>
--- 12,18 ----
***************
*** 225,236 ****
  
      while (buf_ShutdownFlag == 0) {
  	if (!wasDirty) {
- #ifndef DJGPP
  	    i = SleepEx(5000, 1);
  	    if (i != 0) continue;
- #else
- 	    thrd_Sleep(5000);
- #endif /* DJGPP */
  	}
  
  	wasDirty = 0;
--- 223,230 ----
***************
*** 481,489 ****
                                 "buf_IncrSyncer");
  
          osi_assertx(phandle != NULL, "buf: can't create incremental sync proc");
- #ifndef DJGPP
          CloseHandle(phandle);
- #endif /* !DJGPP */
      }
  
  #ifdef TESTING
--- 475,481 ----
***************
*** 910,915 ****
--- 902,911 ----
               * we hold the global lock.
               */
  
+             /* Don't recycle a buffer held by the redirector. */
+             if (bp->flags & CM_BUF_REDIR)
+                 continue;
+ 
              /* don't recycle someone in our own chunk */
              if (!cm_FidCmp(&bp->fid, &scp->fid)
                   && (bp->offset.LowPart & (-cm_chunkSize))
Index: openafs/src/WINNT/afsd/cm_buf.h
diff -c openafs/src/WINNT/afsd/cm_buf.h:1.12.4.14 openafs/src/WINNT/afsd/cm_buf.h:1.12.4.16
*** openafs/src/WINNT/afsd/cm_buf.h:1.12.4.14	Thu Apr 24 12:22:44 2008
--- openafs/src/WINNT/afsd/cm_buf.h	Thu Jun 26 12:38:29 2008
***************
*** 106,111 ****
--- 106,112 ----
  #define CM_BUF_WAITING	0x40	/* someone's waiting for a flag to change */
  #define CM_BUF_INDL     0x80    /* in the dirty list */
  #define CM_BUF_EOF	0x100	/* read 0 bytes; used for detecting EOF */
+ #define CM_BUF_REDIR    0x200   /* buffer held by the redirector */
  
  typedef struct cm_buf_ops {
      long (*Writep)(void *, osi_hyper_t *, long, long, struct cm_user *,
***************
*** 202,207 ****
--- 203,210 ----
  
  extern long buf_ForceDataVersion(cm_scache_t * scp, afs_uint64 fromVersion, afs_uint64 toVersion);
  
+ extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
+ 
  /* error codes */
  #define CM_BUF_EXISTS	1	/* buffer exists, and shouldn't */
  #endif /*  _BUF_H__ENV_ */
Index: openafs/src/WINNT/afsd/cm_callback.c
diff -c openafs/src/WINNT/afsd/cm_callback.c:1.41.4.43 openafs/src/WINNT/afsd/cm_callback.c:1.41.4.45
*** openafs/src/WINNT/afsd/cm_callback.c:1.41.4.43	Mon Apr 14 18:44:03 2008
--- openafs/src/WINNT/afsd/cm_callback.c	Thu Jun 26 12:38:29 2008
***************
*** 11,27 ****
  #include <afs/afs_args.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
- #else
- #include <sys/socket.h>
- #endif /* !DJGPP */
  #include <malloc.h>
  #include <string.h>
  #include <stdlib.h>
  
  #include "afsd.h"
  #include <osi.h>
  #include <rx_pthread.h>
  
--- 11,24 ----
  #include <afs/afs_args.h>
  #include <afs/stds.h>
  
  #include <windows.h>
  #include <winsock2.h>
  #include <malloc.h>
  #include <string.h>
  #include <stdlib.h>
  
  #include "afsd.h"
+ #include "smb.h"
  #include <osi.h>
  #include <rx_pthread.h>
  
***************
*** 748,755 ****
              cep->cbExpires = volp->cbExpiresRO;
              cm_PutVolume(volp);
          }
!     } else
!         cep->cbExpires = scp->cbExpires;
      cep->refCount = scp->refCount;
      cep->opens = scp->openReads;
      cep->writers = scp->openWrites;
--- 745,754 ----
              cep->cbExpires = volp->cbExpiresRO;
              cm_PutVolume(volp);
          }
!     } else {
!         /* TODO: deal with time_t below */
!         cep->cbExpires = (afs_int32) scp->cbExpires;
!     }
      cep->refCount = scp->refCount;
      cep->opens = scp->openReads;
      cep->writers = scp->openWrites;
***************
*** 863,870 ****
              cep->cbExpires = volp->cbExpiresRO;
              cm_PutVolume(volp);
          }
!     } else
!         cep->cbExpires = scp->cbExpires;
      cep->refCount = scp->refCount;
      cep->opens = scp->openReads;
      cep->writers = scp->openWrites;
--- 862,871 ----
              cep->cbExpires = volp->cbExpiresRO;
              cm_PutVolume(volp);
          }
!     } else {
!         /* TODO: handle time_t */
!         cep->cbExpires = (afs_int32) scp->cbExpires;
!     }
      cep->refCount = scp->refCount;
      cep->opens = scp->openReads;
      cep->writers = scp->openWrites;
***************
*** 1317,1324 ****
               ntohl(host), ntohs(port));
  
      if (cm_data.rootCellp) {
! 	t_name = (char *)malloc(strlen(cm_data.rootCellp->name)+1);
!         strcpy(t_name, cm_data.rootCellp->name);
      } else {
  	t_name = (char *)malloc(1);
  	t_name[0] = '\0';
--- 1318,1324 ----
               ntohl(host), ntohs(port));
  
      if (cm_data.rootCellp) {
!         t_name = strdup(cm_data.rootCellp->name);
      } else {
  	t_name = (char *)malloc(1);
  	t_name[0] = '\0';
Index: openafs/src/WINNT/afsd/cm_cell.c
diff -c openafs/src/WINNT/afsd/cm_cell.c:1.23.2.13 openafs/src/WINNT/afsd/cm_cell.c:1.23.2.15
*** openafs/src/WINNT/afsd/cm_cell.c:1.23.2.13	Thu Feb 14 22:31:36 2008
--- openafs/src/WINNT/afsd/cm_cell.c	Thu Jun 26 10:38:23 2008
***************
*** 10,20 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <nb30.h>
  #include <winsock2.h>
- #endif /* !DJGPP */
  #include <stdlib.h>
  #include <stdio.h>
  #include <malloc.h>
--- 10,18 ----
***************
*** 151,157 ****
  
      lock_ObtainRead(&cm_cellLock);
      for (cp = cm_data.cellNameHashTablep[hash]; cp; cp=cp->nameNextp) {
!         if (stricmp(namep, cp->name) == 0) {
              strcpy(fullname, cp->name);
              break;
          }
--- 149,155 ----
  
      lock_ObtainRead(&cm_cellLock);
      for (cp = cm_data.cellNameHashTablep[hash]; cp; cp=cp->nameNextp) {
!         if (cm_stricmp_utf8(namep, cp->name) == 0) {
              strcpy(fullname, cp->name);
              break;
          }
***************
*** 178,184 ****
           * to the list so check again while holding the write lock 
           */
          for (cp = cm_data.cellNameHashTablep[hash]; cp; cp=cp->nameNextp) {
!             if (stricmp(namep, cp->name) == 0) {
                  strcpy(fullname, cp->name);
                  break;
              }
--- 176,182 ----
           * to the list so check again while holding the write lock 
           */
          for (cp = cm_data.cellNameHashTablep[hash]; cp; cp=cp->nameNextp) {
!             if (cm_stricmp_utf8(namep, cp->name) == 0) {
                  strcpy(fullname, cp->name);
                  break;
              }
***************
*** 247,253 ****
           */
          hash = CM_CELL_NAME_HASH(fullname);
          for (cp2 = cm_data.cellNameHashTablep[hash]; cp2; cp2=cp2->nameNextp) {
!             if (stricmp(fullname, cp2->name) == 0) {
                  break;
              }
          }   
--- 245,251 ----
           */
          hash = CM_CELL_NAME_HASH(fullname);
          for (cp2 = cm_data.cellNameHashTablep[hash]; cp2; cp2=cp2->nameNextp) {
!             if (cm_stricmp_utf8(fullname, cp2->name) == 0) {
                  break;
              }
          }   
Index: openafs/src/WINNT/afsd/cm_config.c
diff -c openafs/src/WINNT/afsd/cm_config.c:1.26.4.4 openafs/src/WINNT/afsd/cm_config.c:1.26.4.5
*** openafs/src/WINNT/afsd/cm_config.c:1.26.4.4	Mon Apr  7 10:20:19 2008
--- openafs/src/WINNT/afsd/cm_config.c	Thu Jun 26 08:45:11 2008
***************
*** 93,103 ****
      p = strrchr(name, '.');
      if (p) {
  	if (i == 1 && 
! 	    (!stricmp(p,".dll") ||
! 	     !stricmp(p,".exe") ||
! 	     !stricmp(p,".ini") ||
! 	     !stricmp(p,".db") ||
! 	     !stricmp(p,".drv")))
  	    return 1;
      }
      return 0;
--- 93,103 ----
      p = strrchr(name, '.');
      if (p) {
  	if (i == 1 && 
! 	    (!cm_stricmp_utf8N(p,".dll") ||
! 	     !cm_stricmp_utf8N(p,".exe") ||
! 	     !cm_stricmp_utf8N(p,".ini") ||
! 	     !cm_stricmp_utf8N(p,".db") ||
! 	     !cm_stricmp_utf8N(p,".drv")))
  	    return 1;
      }
      return 0;
***************
*** 203,210 ****
  			 inRightCell, osi_LogSaveString(afsd_logp,lineBuffer));
  #endif
  	    }
! 	    else if (strnicmp(lineBuffer+1, cellNamep,
! 			       strlen(cellNamep)) == 0) {
  		/* partial match */
  		if (partial) {	/* ambiguous */
  		    fclose(tfilep);
--- 203,209 ----
  			 inRightCell, osi_LogSaveString(afsd_logp,lineBuffer));
  #endif
  	    }
! 	    else if (cm_stricmp_utf8(lineBuffer+1, cellNamep) == 0) {
  		/* partial match */
  		if (partial) {	/* ambiguous */
  		    fclose(tfilep);
Index: openafs/src/WINNT/afsd/cm_conn.c
diff -c openafs/src/WINNT/afsd/cm_conn.c:1.49.2.43 openafs/src/WINNT/afsd/cm_conn.c:1.49.2.45
*** openafs/src/WINNT/afsd/cm_conn.c:1.49.2.43	Fri May  2 15:28:18 2008
--- openafs/src/WINNT/afsd/cm_conn.c	Wed Jul 16 00:44:27 2008
***************
*** 10,18 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
- #endif /* !DJGPP */
  #include <string.h>
  #include <malloc.h>
  #include <osi.h>
--- 10,16 ----
***************
*** 78,111 ****
  	    dummyLen = sizeof(DWORD);
  	    code = RegQueryValueEx(parmKey, "ConnDeadTimeout", NULL, NULL,
  				    (BYTE *) &dwValue, &dummyLen);
! 	    if (code == ERROR_SUCCESS)
                  ConnDeadtimeout = (unsigned short)dwValue;
! 
  	    dummyLen = sizeof(DWORD);
  	    code = RegQueryValueEx(parmKey, "HardDeadTimeout", NULL, NULL,
  				    (BYTE *) &dwValue, &dummyLen);
! 	    if (code == ERROR_SUCCESS)
                  HardDeadtimeout = (unsigned short)dwValue;
! 	    afsi_log("HardDeadTimeout is %d", HardDeadtimeout);
! 
  	    dummyLen = sizeof(DWORD);
  	    code = RegQueryValueEx(parmKey, "IdleDeadTimeout", NULL, NULL,
  				    (BYTE *) &dwValue, &dummyLen);
! 	    if (code == ERROR_SUCCESS)
                  IdleDeadtimeout = (unsigned short)dwValue;
! 	    afsi_log("IdleDeadTimeout is %d", IdleDeadtimeout);
! 
              RegCloseKey(parmKey);
  	}
  
  	afsi_log("lanmanworkstation : SessTimeout %u", RDRtimeout);
! 	if (ConnDeadtimeout == 0)
  	    ConnDeadtimeout = (unsigned short) (RDRtimeout / 2);
! 	afsi_log("ConnDeadTimeout is %d", ConnDeadtimeout);
! 	if (HardDeadtimeout == 0)
  	    HardDeadtimeout = (unsigned short) RDRtimeout;
! 	afsi_log("HardDeadTimeout is %d", HardDeadtimeout);
! 
  	osi_EndOnce(&once);
      }
  }
--- 76,115 ----
  	    dummyLen = sizeof(DWORD);
  	    code = RegQueryValueEx(parmKey, "ConnDeadTimeout", NULL, NULL,
  				    (BYTE *) &dwValue, &dummyLen);
! 	    if (code == ERROR_SUCCESS) {
                  ConnDeadtimeout = (unsigned short)dwValue;
!                 afsi_log("ConnDeadTimeout is %d", ConnDeadtimeout);
!             }
  	    dummyLen = sizeof(DWORD);
  	    code = RegQueryValueEx(parmKey, "HardDeadTimeout", NULL, NULL,
  				    (BYTE *) &dwValue, &dummyLen);
! 	    if (code == ERROR_SUCCESS) {
                  HardDeadtimeout = (unsigned short)dwValue;
!                 afsi_log("HardDeadTimeout is %d", HardDeadtimeout);
!             }
  	    dummyLen = sizeof(DWORD);
  	    code = RegQueryValueEx(parmKey, "IdleDeadTimeout", NULL, NULL,
  				    (BYTE *) &dwValue, &dummyLen);
! 	    if (code == ERROR_SUCCESS) {
                  IdleDeadtimeout = (unsigned short)dwValue;
!                 afsi_log("IdleDeadTimeout is %d", IdleDeadtimeout);
!             }
              RegCloseKey(parmKey);
  	}
  
  	afsi_log("lanmanworkstation : SessTimeout %u", RDRtimeout);
! 	if (ConnDeadtimeout == 0) {
  	    ConnDeadtimeout = (unsigned short) (RDRtimeout / 2);
!             afsi_log("ConnDeadTimeout is %d", ConnDeadtimeout);
!         }
! 	if (HardDeadtimeout == 0) {
  	    HardDeadtimeout = (unsigned short) RDRtimeout;
!             afsi_log("HardDeadTimeout is %d", HardDeadtimeout);
!         }
! 	if (ConnDeadtimeout == 0) {
! 	    IdleDeadtimeout = (unsigned short) RDRtimeout;
!             afsi_log("IdleDeadTimeout is %d", IdleDeadtimeout);
!         }
  	osi_EndOnce(&once);
      }
  }
***************
*** 113,123 ****
  void cm_InitReq(cm_req_t *reqp)
  {
  	memset((char *)reqp, 0, sizeof(cm_req_t));
- #ifndef DJGPP
  	reqp->startTime = GetTickCount();
- #else
-         gettimeofday(&reqp->startTime, NULL);
- #endif
  }
  
  static long cm_GetServerList(struct cm_fid *fidp, struct cm_user *userp,
--- 117,123 ----
***************
*** 216,227 ****
       * and retry */
      
      /* timeleft - get if from reqp the same way as cmXonnByMServers does */
- #ifndef DJGPP
      timeUsed = (GetTickCount() - reqp->startTime) / 1000;
- #else
-     gettimeofday(&now, NULL);
-     timeUsed = sub_time(now, reqp->startTime) / 1000;
- #endif
  	    
      /* leave 5 seconds margin for sleep */
      if (reqp->flags & CM_REQ_NORETRY)
--- 216,222 ----
***************
*** 429,472 ****
      {       
          char addr[16];
          char *format;
- #ifndef DJGPP
  	DWORD msgID;
- #endif
          switch ( errorCode ) {
          case VNOVOL:
- #ifndef DJGPP
  	    msgID = MSG_SERVER_REPORTS_VNOVOL;
- #endif
              format = "Server %s reported volume %d as not attached.";
              break;
          case VMOVED:
- #ifndef DJGPP
  	    msgID = MSG_SERVER_REPORTS_VMOVED;
- #endif
              format = "Server %s reported volume %d as moved.";
              break;
          case VOFFLINE:
- #ifndef DJGPP
  	    msgID = MSG_SERVER_REPORTS_VOFFLINE;
- #endif
              format = "Server %s reported volume %d as offline.";
              break;
          case VSALVAGE:
- #ifndef DJGPP
  	    msgID = MSG_SERVER_REPORTS_VSALVAGE;
- #endif
              format = "Server %s reported volume %d as needs salvage.";
              break;
          case VNOSERVICE:
- #ifndef DJGPP
  	    msgID = MSG_SERVER_REPORTS_VNOSERVICE;
- #endif
              format = "Server %s reported volume %d as not in service.";
              break;
          case VIO:
- #ifndef DJGPP
  	    msgID = MSG_SERVER_REPORTS_VIO;
- #endif
              format = "Server %s reported volume %d as temporarily unaccessible.";
              break;
          }
--- 424,453 ----
***************
*** 480,488 ****
                      ((serverp->addr.sin_addr.s_addr & 0xff000000)>> 24)); 
  
              osi_Log2(afsd_logp, format, osi_LogSaveString(afsd_logp,addr), fidp->volume);
- #ifndef DJGPP
              LogEvent(EVENTLOG_WARNING_TYPE, msgID, addr, fidp->volume);
- #endif
          }
  
          /* Mark server offline for this volume */
--- 461,467 ----
***************
*** 584,592 ****
                       ((serverp->addr.sin_addr.s_addr & 0xff0000)>> 16),
                       ((serverp->addr.sin_addr.s_addr & 0xff000000)>> 24)); 
  
- #ifndef DJGPP
              LogEvent(EVENTLOG_WARNING_TYPE, MSG_RX_HARD_DEAD_TIME_EXCEEDED, addr);
- #endif /* !DJGPP */
  	  
              osi_Log1(afsd_logp, "cm_Analyze: hardDeadTime exceeded addr[%s]",
                       osi_LogSaveString(afsd_logp,addr));
--- 563,569 ----
***************
*** 793,803 ****
      cm_server_t *tsp;
      long firstError = 0;
      int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
      long timeUsed, timeLeft, hardTimeLeft;
! #ifdef DJGPP
!     struct timeval now;
! #endif /* DJGPP */        
! 
      *connpp = NULL;
  
      if (serversp == NULL) {
--- 770,778 ----
      cm_server_t *tsp;
      long firstError = 0;
      int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
+ #ifdef SET_RX_TIMEOUTS_TO_TIMELEFT
      long timeUsed, timeLeft, hardTimeLeft;
! #endif
      *connpp = NULL;
  
      if (serversp == NULL) {
***************
*** 805,820 ****
  	return CM_ERROR_ALLDOWN;
      }
  
! #ifndef DJGPP
      timeUsed = (GetTickCount() - reqp->startTime) / 1000;
- #else
-     gettimeofday(&now, NULL);
-     timeUsed = sub_time(now, reqp->startTime) / 1000;
- #endif
          
      /* leave 5 seconds margin of safety */
      timeLeft =  ConnDeadtimeout - timeUsed - 5;
      hardTimeLeft = HardDeadtimeout - timeUsed - 5;
  
      lock_ObtainRead(&cm_serverLock);
      for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
--- 780,792 ----
  	return CM_ERROR_ALLDOWN;
      }
  
! #ifdef SET_RX_TIMEOUTS_TO_TIMELEFT
      timeUsed = (GetTickCount() - reqp->startTime) / 1000;
          
      /* leave 5 seconds margin of safety */
      timeLeft =  ConnDeadtimeout - timeUsed - 5;
      hardTimeLeft = HardDeadtimeout - timeUsed - 5;
+ #endif
  
      lock_ObtainRead(&cm_serverLock);
      for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
***************
*** 848,853 ****
--- 820,826 ----
                  code = cm_ConnByServer(tsp, usersp, connpp);
                  if (code == 0) {        /* cm_CBS only returns 0 */
                      cm_PutServer(tsp);
+ #ifdef SET_RX_TIMEOUTS_TO_TIMELEFT
                      /* Set RPC timeout */
                      if (timeLeft > ConnDeadtimeout)
                          timeLeft = ConnDeadtimeout;
***************
*** 859,864 ****
--- 832,838 ----
                      rx_SetConnDeadTime((*connpp)->callp, timeLeft);
                      rx_SetConnHardDeadTime((*connpp)->callp, (u_short) hardTimeLeft);
                      lock_ReleaseMutex(&(*connpp)->mx);
+ #endif
                      return 0;
                  }
                  
Index: openafs/src/WINNT/afsd/cm_conn.h
diff -c openafs/src/WINNT/afsd/cm_conn.h:1.13.4.11 openafs/src/WINNT/afsd/cm_conn.h:1.13.4.13
*** openafs/src/WINNT/afsd/cm_conn.h:1.13.4.11	Mon Apr 28 11:06:14 2008
--- openafs/src/WINNT/afsd/cm_conn.h	Wed Jul 16 00:44:27 2008
***************
*** 13,19 ****
  #define	CM_CONN_DEFAULTRDRTIMEOUT	45
  #define CM_CONN_CONNDEADTIME		 0
  #define CM_CONN_HARDDEADTIME             0
! #define CM_CONN_IDLEDEADTIME            30
  
  extern unsigned short ConnDeadtimeout;
  extern unsigned short HardDeadtimeout;
--- 13,19 ----
  #define	CM_CONN_DEFAULTRDRTIMEOUT	45
  #define CM_CONN_CONNDEADTIME		 0
  #define CM_CONN_HARDDEADTIME             0
! #define CM_CONN_IDLEDEADTIME             0
  
  extern unsigned short ConnDeadtimeout;
  extern unsigned short HardDeadtimeout;
***************
*** 39,54 ****
   * to the cache manager functions.
   */
  typedef struct cm_req {
! 	DWORD startTime;		/* Quit before RDR times us out */
! 	int rpcError;			/* RPC error code */
! 	int volumeError;		/* volume error code */
! 	int accessError;		/* access error code */
!         struct cm_server * tokenIdleErrorServp;  /* server that reported a token/idle error other than expired */
!         int tokenError;
!         int idleError;
! 	afs_uint32 flags;
!         char * tidPathp;
!         char * relPathp;
  } cm_req_t;
  
  /* flags in cm_req structure */
--- 39,54 ----
   * to the cache manager functions.
   */
  typedef struct cm_req {
!     DWORD startTime;		/* Quit before RDR times us out */
!     int rpcError;			/* RPC error code */
!     int volumeError;		/* volume error code */
!     int accessError;		/* access error code */
!     struct cm_server * tokenIdleErrorServp;  /* server that reported a token/idle error other than expired */
!     int tokenError;
!     int idleError;
!     afs_uint32 flags;
!     clientchar_t * tidPathp;
!     clientchar_t * relPathp;
  } cm_req_t;
  
  /* flags in cm_req structure */
Index: openafs/src/WINNT/afsd/cm_daemon.c
diff -c openafs/src/WINNT/afsd/cm_daemon.c:1.16.4.28 openafs/src/WINNT/afsd/cm_daemon.c:1.16.4.29
*** openafs/src/WINNT/afsd/cm_daemon.c:1.16.4.28	Sat Mar  8 18:25:08 2008
--- openafs/src/WINNT/afsd/cm_daemon.c	Thu Jun 26 10:38:23 2008
***************
*** 10,22 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
  #include <iphlpapi.h>
- #else
- #include <netdb.h>
- #endif /* !DJGPP */
  #include <stdlib.h>
  #include <malloc.h>
  #include <string.h>
--- 10,18 ----
***************
*** 58,64 ****
  static EVENT_HANDLE cm_BkgDaemon_ShutdownEvent[CM_MAX_DAEMONS] = 
         {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
  
- #ifndef DJGPP
  void cm_IpAddrDaemon(long parm)
  {
      extern void smb_CheckVCs(void);
--- 54,59 ----
***************
*** 85,91 ****
  
      thrd_SetEvent(cm_IPAddrDaemon_ShutdownEvent);
  }
- #endif
  
  void cm_BkgDaemon(void * parm)
  {
--- 80,85 ----
***************
*** 610,622 ****
          lock_InitializeRWLock(&cm_daemonLock, "cm_daemonLock");
          osi_EndOnce(&once);
  
- #ifndef DJGPP
  	/* creating IP Address Change monitor daemon */
          phandle = thrd_Create((SecurityAttrib) 0, 0,
                                 (ThreadFunc) cm_IpAddrDaemon, 0, 0, &pid, "cm_IpAddrDaemon");
          osi_assertx(phandle != NULL, "cm_IpAddrDaemon thread creation failure");
          thrd_CloseHandle(phandle);
- #endif /* DJGPP */
  
          /* creating pinging daemon */
          phandle = thrd_Create((SecurityAttrib) 0, 0,
--- 604,614 ----
Index: openafs/src/WINNT/afsd/cm_dcache.c
diff -c openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.30 openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.31
*** openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.30	Thu Mar  6 09:34:29 2008
--- openafs/src/WINNT/afsd/cm_dcache.c	Thu Jun 26 10:38:23 2008
***************
*** 10,20 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
  #include <nb30.h>
- #endif /* !DJGPP */
  #ifdef COMMENT
  #include <malloc.h>
  #endif
--- 10,18 ----
Index: openafs/src/WINNT/afsd/cm_dir.c
diff -c openafs/src/WINNT/afsd/cm_dir.c:1.4.4.14 openafs/src/WINNT/afsd/cm_dir.c:1.4.4.18
*** openafs/src/WINNT/afsd/cm_dir.c:1.4.4.14	Sun Mar  2 23:25:40 2008
--- openafs/src/WINNT/afsd/cm_dir.c	Fri Jul 11 18:27:01 2008
***************
*** 10,18 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
- #endif /* !DJGPP */
  #include <string.h>
  #include <malloc.h>
  #include <osi.h>
--- 10,16 ----
***************
*** 123,129 ****
   * the specified name.
   */
  long 
! cm_NameEntries(char *namep, long *lenp)
  {
      long i;
          
--- 121,127 ----
   * the specified name.
   */
  long 
! cm_NameEntries(char *namep, size_t *lenp)
  {
      long i;
          
***************
*** 574,579 ****
--- 572,578 ----
      return rc;
  }
  
+ 
  /* Look up a file name in directory.
  
     On entry:
***************
*** 977,983 ****
      op->scp = scp;
      cm_HoldUser(userp);
      op->userp = userp;
!     cm_InitReq(&op->req);
  
      op->dirtyBufCount = 0;
      op->nBuffers = 0;
--- 976,982 ----
      op->scp = scp;
      cm_HoldUser(userp);
      op->userp = userp;
!     op->req = *reqp;            /* copy the values from the input */
  
      op->dirtyBufCount = 0;
      op->nBuffers = 0;
Index: openafs/src/WINNT/afsd/cm_dir.h
diff -c openafs/src/WINNT/afsd/cm_dir.h:1.4.4.7 openafs/src/WINNT/afsd/cm_dir.h:1.4.4.8
*** openafs/src/WINNT/afsd/cm_dir.h:1.4.4.7	Wed Nov 14 01:23:33 2007
--- openafs/src/WINNT/afsd/cm_dir.h	Sun May 11 09:17:17 2008
***************
*** 139,145 ****
  cm_EndDirOp(cm_dirOp_t * op);
  
  extern long
! cm_NameEntries(char *namep, long *lenp);
  
  extern long
  cm_DirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid);
--- 139,145 ----
  cm_EndDirOp(cm_dirOp_t * op);
  
  extern long
! cm_NameEntries(char *namep, size_t *lenp);
  
  extern long
  cm_DirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid);
Index: openafs/src/WINNT/afsd/cm_dnlc.c
diff -c openafs/src/WINNT/afsd/cm_dnlc.c:1.10.4.6 openafs/src/WINNT/afsd/cm_dnlc.c:1.10.4.9
*** openafs/src/WINNT/afsd/cm_dnlc.c:1.10.4.6	Fri Feb 29 10:58:53 2008
--- openafs/src/WINNT/afsd/cm_dnlc.c	Thu Jun 26 12:38:29 2008
***************
*** 18,27 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
- #endif /* !DJGPP */
  #include <string.h>
  #include <stdlib.h>
  #include <osi.h>
--- 18,25 ----
***************
*** 107,133 ****
  
  void 
  cm_dnlcEnter ( cm_scache_t *adp,
!                char        *aname,
                 cm_scache_t *avc )
  {
      cm_nc_t *tnc;
      unsigned int key, skey, new=0;
!     char *ts = aname;
      int safety;
      int writeLocked = 0;
  
      if (!cm_useDnlc)
  	return ;
  
!     if (!strcmp(aname,".") || !strcmp(aname,".."))
  	return ;
  
      if ( cm_debugDnlc ) 
! 	osi_Log3(afsd_logp,"cm_dnlcEnter dir %x name %s scache %x", 
! 	    adp, osi_LogSaveString(afsd_logp,aname), avc);
  
      dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
!     if (ts - aname >= CM_AFSNCNAMESIZE) 
  	return ;
      skey = key & (NHSIZE -1);
  
--- 105,131 ----
  
  void 
  cm_dnlcEnter ( cm_scache_t *adp,
!                normchar_t  *nname,
                 cm_scache_t *avc )
  {
      cm_nc_t *tnc;
      unsigned int key, skey, new=0;
!     normchar_t *ts = nname;
      int safety;
      int writeLocked = 0;
  
      if (!cm_useDnlc)
  	return ;
  
!     if (!cm_NormStrCmp(nname,_C(".")) || !cm_NormStrCmp(nname,_C("..")))
  	return ;
  
      if ( cm_debugDnlc ) 
! 	osi_Log3(afsd_logp,"cm_dnlcEnter dir %x name %S scache %x", 
! 	    adp, osi_LogSaveStringW(afsd_logp,nname), avc);
  
      dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
!     if (ts - nname >= CM_AFSNCNAMESIZE) 
  	return ;
      skey = key & (NHSIZE -1);
  
***************
*** 135,141 ****
      lock_ObtainRead(&cm_dnlcLock);
    retry:
      for (tnc = cm_data.nameHash[skey], safety=0; tnc; tnc = tnc->next, safety++ )
! 	if ((tnc->dirp == adp) && (!strcmp(tnc->name, aname)))
  	    break;				/* preexisting entry */
  	else if ( tnc->next == cm_data.nameHash[skey])	/* end of list */
  	{
--- 133,139 ----
      lock_ObtainRead(&cm_dnlcLock);
    retry:
      for (tnc = cm_data.nameHash[skey], safety=0; tnc; tnc = tnc->next, safety++ )
! 	if ((tnc->dirp == adp) && (!cm_NormStrCmp(tnc->name, nname)))
  	    break;				/* preexisting entry */
  	else if ( tnc->next == cm_data.nameHash[skey])	/* end of list */
  	{
***************
*** 171,180 ****
  	tnc->dirp = adp;
  	tnc->vp = avc;
  	tnc->key = key;
! 	memcpy (tnc->name, aname, ts-aname+1); /* include the NULL */
  
      	if ( new )	/* insert entry only if it is newly created */ 
! 		InsertEntry(tnc);
  
      }
      if (writeLocked)
--- 169,178 ----
  	tnc->dirp = adp;
  	tnc->vp = avc;
  	tnc->key = key;
! 	memcpy (tnc->name, nname, (ts-nname+1)*sizeof(normchar_t)); /* include the NULL */
  
      	if ( new )	/* insert entry only if it is newly created */ 
!             InsertEntry(tnc);
  
      }
      if (writeLocked)
***************
*** 194,201 ****
  {
      cm_scache_t * tvc;
      unsigned int key, skey;
!     char* aname = sp->searchNamep;
!     char *ts = aname;
      cm_nc_t * tnc, * tnc_begin;
      int safety, match;
    
--- 192,199 ----
  {
      cm_scache_t * tvc;
      unsigned int key, skey;
!     normchar_t* nname = sp->nsearchNamep;
!     normchar_t *ts = nname;
      cm_nc_t * tnc, * tnc_begin;
      int safety, match;
    
***************
*** 203,214 ****
  	return NULL;
  
      if ( cm_debugDnlc ) 
! 	osi_Log2(afsd_logp, "cm_dnlcLookup dir %x name %s", 
! 		adp, osi_LogSaveString(afsd_logp,aname));
  
      dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
  
!     if (ts - aname >= CM_AFSNCNAMESIZE) {
          InterlockedIncrement(&dnlcstats.lookups);
          InterlockedIncrement(&dnlcstats.misses);
  	return NULL;
--- 201,212 ----
  	return NULL;
  
      if ( cm_debugDnlc ) 
! 	osi_Log2(afsd_logp, "cm_dnlcLookup dir %x name %S", 
! 		adp, osi_LogSaveStringW(afsd_logp,nname));
  
      dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
  
!     if (ts - nname >= CM_AFSNCNAMESIZE) {
          InterlockedIncrement(&dnlcstats.lookups);
          InterlockedIncrement(&dnlcstats.misses);
  	return NULL;
***************
*** 227,252 ****
  	if (tnc->dirp == adp) 
  	{
          if( cm_debugDnlc ) 
!             osi_Log1(afsd_logp,"Looking at [%s]",
!                      osi_LogSaveString(afsd_logp,tnc->name));
  
  	    if ( sp->caseFold ) 	/* case insensitive */
  	    {
!             match = cm_stricmp(tnc->name, aname);
              if ( !match )	/* something matches */
              {
                  tvc = tnc->vp;
                  ts = tnc->name;
  
                  /* determine what type of match it is */
!                 if ( !strcmp(tnc->name, aname))
                  {	
                      /* exact match. */
                      sp->ExactFound = 1;
  
                      if( cm_debugDnlc )
!                         osi_Log1(afsd_logp,"DNLC found exact match [%s]",
!                                  osi_LogSaveString(afsd_logp,tnc->name));
                      break;
                  }
                  else if ( cm_NoneUpper(tnc->name))
--- 225,250 ----
  	if (tnc->dirp == adp) 
  	{
          if( cm_debugDnlc ) 
!             osi_Log1(afsd_logp,"Looking at [%S]",
!                      osi_LogSaveStringW(afsd_logp,tnc->name));
  
  	    if ( sp->caseFold ) 	/* case insensitive */
  	    {
!             match = cm_NormStrCmpI(tnc->name, nname);
              if ( !match )	/* something matches */
              {
                  tvc = tnc->vp;
                  ts = tnc->name;
  
                  /* determine what type of match it is */
!                 if ( !cm_NormStrCmp(tnc->name, nname))
                  {	
                      /* exact match. */
                      sp->ExactFound = 1;
  
                      if( cm_debugDnlc )
!                         osi_Log1(afsd_logp,"DNLC found exact match [%S]",
!                                  osi_LogSaveStringW(afsd_logp,tnc->name));
                      break;
                  }
                  else if ( cm_NoneUpper(tnc->name))
***************
*** 260,266 ****
  	    }
  	    else			/* case sensitive */
  	    {
!             match = strcmp(tnc->name, aname);
              if ( !match ) /* found a match */
              {
                  sp->ExactFound = 1;
--- 258,264 ----
  	    }
  	    else			/* case sensitive */
  	    {
!             match = cm_NormStrCmp(tnc->name, nname);
              if ( !match ) /* found a match */
              {
                  sp->ExactFound = 1;
***************
*** 287,295 ****
      }
  
      if(cm_debugDnlc && ts) {
!         osi_Log3(afsd_logp, "DNLC matched [%s] for [%s] with vnode[%ld]",
!                  osi_LogSaveString(afsd_logp,ts),
!                  osi_LogSaveString(afsd_logp,aname),
                   (long) tvc->fid.vnode);
      }
  
--- 285,293 ----
      }
  
      if(cm_debugDnlc && ts) {
!         osi_Log3(afsd_logp, "DNLC matched [%S] for [%W] with vnode[%ld]",
!                  osi_LogSaveStringW(afsd_logp,ts),
!                  osi_LogSaveStringW(afsd_logp,nname),
                   (long) tvc->fid.vnode);
      }
  
***************
*** 339,360 ****
  
  
  void 
! cm_dnlcRemove (cm_scache_t *adp, char *aname)
  {
      unsigned int key, skey, error=0;
      int found= 0, safety;
!     char *ts = aname;
      cm_nc_t *tnc, *tmp;
    
      if (!cm_useDnlc)
  	return ;
  
      if ( cm_debugDnlc )
! 	osi_Log2(afsd_logp, "cm_dnlcRemove dir %x name %s", 
! 		adp, osi_LogSaveString(afsd_logp,aname));
  
      dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
!     if (ts - aname >= CM_AFSNCNAMESIZE) 
  	return ;
  
      skey = key & (NHSIZE -1);
--- 337,358 ----
  
  
  void 
! cm_dnlcRemove (cm_scache_t *adp, normchar_t *nname)
  {
      unsigned int key, skey, error=0;
      int found= 0, safety;
!     normchar_t *ts = nname;
      cm_nc_t *tnc, *tmp;
    
      if (!cm_useDnlc)
  	return ;
  
      if ( cm_debugDnlc )
! 	osi_Log2(afsd_logp, "cm_dnlcRemove dir %x name %S", 
! 		adp, osi_LogSaveStringW(afsd_logp,nname));
  
      dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
!     if (ts - nname >= CM_AFSNCNAMESIZE) 
  	return ;
  
      skey = key & (NHSIZE -1);
***************
*** 364,370 ****
      for (tnc = cm_data.nameHash[skey], safety=0; tnc; safety++) 
      {
  	if ( (tnc->dirp == adp) && (tnc->key == key) 
! 			&& !strcmp(tnc->name,aname) )
  	{
  	    tmp = tnc->next;
      	    error = RemoveEntry(tnc, skey);
--- 362,368 ----
      for (tnc = cm_data.nameHash[skey], safety=0; tnc; safety++) 
      {
  	if ( (tnc->dirp == adp) && (tnc->key == key) 
!              && !cm_NormStrCmp(tnc->name,nname) )
  	{
  	    tmp = tnc->next;
      	    error = RemoveEntry(tnc, skey);
Index: openafs/src/WINNT/afsd/cm_dnlc.h
diff -c openafs/src/WINNT/afsd/cm_dnlc.h:1.4.6.2 openafs/src/WINNT/afsd/cm_dnlc.h:1.4.6.3
*** openafs/src/WINNT/afsd/cm_dnlc.h:1.4.6.2	Tue Feb 26 23:55:16 2008
--- openafs/src/WINNT/afsd/cm_dnlc.h	Thu Jun 26 12:38:29 2008
***************
*** 20,26 ****
      unsigned int key;
      struct nc *next, *prev;
      cm_scache_t *dirp, *vp;
!     unsigned char name[CM_AFSNCNAMESIZE];   
  } cm_nc_t;
  
  typedef struct {
--- 20,26 ----
      unsigned int key;
      struct nc *next, *prev;
      cm_scache_t *dirp, *vp;
!     normchar_t name[CM_AFSNCNAMESIZE];   
  } cm_nc_t;
  
  typedef struct {
***************
*** 29,40 ****
      afs_int32 cycles, lookuprace;
  } cm_dnlcstats_t;
  
! #define dnlcHash(ts, hval) for (hval=0; *ts; ts++) {    \
!                                 hval *= 173;            \
!                                 hval += cm_foldUpper[(unsigned char)(*ts)]; \
!                            }
! extern void cm_dnlcEnter(cm_scache_t *adp, char *name, cm_scache_t *avc);
! extern void cm_dnlcRemove(cm_scache_t *adp, char *name);
  extern void cm_dnlcPurgedp(cm_scache_t *adp);
  extern void cm_dnlcPurgevp(cm_scache_t *avc);
  extern void cm_dnlcPurge(void);
--- 29,40 ----
      afs_int32 cycles, lookuprace;
  } cm_dnlcstats_t;
  
! #define dnlcHash(ts, hval) for (hval=0; *ts; ts++) {                    \
!         hval *= 173;                                                    \
!         hval += cm_NormCharUpr(*ts);                                   \
!     }
! extern void cm_dnlcEnter(cm_scache_t *adp, normchar_t *name, cm_scache_t *avc);
! extern void cm_dnlcRemove(cm_scache_t *adp, normchar_t *name);
  extern void cm_dnlcPurgedp(cm_scache_t *adp);
  extern void cm_dnlcPurgevp(cm_scache_t *avc);
  extern void cm_dnlcPurge(void);
Index: openafs/src/WINNT/afsd/cm_dns.c
diff -c openafs/src/WINNT/afsd/cm_dns.c:1.12.4.1 openafs/src/WINNT/afsd/cm_dns.c:1.12.4.4
*** openafs/src/WINNT/afsd/cm_dns.c:1.12.4.1	Mon Jul  2 20:35:13 2007
--- openafs/src/WINNT/afsd/cm_dns.c	Thu Jun 26 12:38:29 2008
***************
*** 11,21 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  #include <afs/cellconfig.h>
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
- #endif
  #include "cm_dns_private.h"
  #include "cm_dns.h"
  #include <lwp.h>
  #include <afs/afsint.h>
--- 11,20 ----
  #include <afs/param.h>
  #include <afs/stds.h>
  #include <afs/cellconfig.h>
  #include <windows.h>
  #include <winsock2.h>
  #include "cm_dns_private.h"
+ #include "cm_nls.h"
  #include "cm_dns.h"
  #include <lwp.h>
  #include <afs/afsint.h>
***************
*** 24,93 ****
  #define DNSAPI_ENV
  #endif
  #include <errno.h>
  
  /*extern void afsi_log(char *pattern, ...);*/
  
  static char dns_addr[30];
- #ifdef DJGPP
- extern char cm_confDir[];
- #endif
  static int cm_dnsEnabled = -1;
  
  void DNSlowerCase(char *str)
  {
!   int i;
  
!   for (i=0; i<strlen(str); i++)
!     /*str[i] = tolower(str[i]);*/
!     if (str[i] >= 'A' && str[i] <= 'Z')
!       str[i] += 'a' - 'A';
  }
  
  int cm_InitDNS(int enabled)
  {
  #ifndef DNSAPI_ENV
!   char configpath[100];
!   int len;
!   int code;
!   char *addr;
!   
!   if (!enabled) { fprintf(stderr, "DNS support disabled\n"); cm_dnsEnabled = 0; return 0; }
! 
!   /* First try AFS_NS environment var. */
!   addr = getenv("AFS_NS");
!   if (addr && inet_addr(addr) != -1) {
!     strcpy(dns_addr, addr);
!   } else {
!     /* Now check for the AFSDNS.INI file */
! #ifdef DJGPP
!     strcpy(configpath, cm_confDir);
! #elif defined(AFS_WIN95_ENV)
!     char *path = getenv("AFSCONF");
!     if (path) strcpy(configpath, path);
!     else strcpy(configpath, "c:\\afscli");
! #else  /* nt */
!     code = GetWindowsDirectory(configpath, sizeof(configpath));
!     if (code == 0 || code > sizeof(configpath)) return -1;
! #endif
!     strcat(configpath, "\\afsdns.ini");
  
!     /* Currently we only get (and query) the first nameserver.  Getting
!        list of mult. nameservers should be easy to do. */
!     len = GetPrivateProfileString("AFS Domain Name Servers", "ns1", NULL,
! 			    dns_addr, sizeof(dns_addr),
! 			    configpath);
!   
!     if (len == 0 || inet_addr(dns_addr) == -1) {
!       fprintf(stderr, "No valid name server addresses found, DNS lookup is "
!                       "disabled\n");
!       cm_dnsEnabled = 0;  /* failed */
!       return -1;     /* No name servers defined */
      }
-     else fprintf(stderr, "Found DNS server %s\n", dns_addr);
-   }
  #endif /* DNSAPI_ENV */
!   cm_dnsEnabled = 1;
!   return 0;
  }
  
  #ifndef DNSAPI_ENV
--- 23,87 ----
  #define DNSAPI_ENV
  #endif
  #include <errno.h>
+ #include <strsafe.h>
  
  /*extern void afsi_log(char *pattern, ...);*/
  
  static char dns_addr[30];
  static int cm_dnsEnabled = -1;
  
  void DNSlowerCase(char *str)
  {
!     unsigned int i;
  
!     for (i=0; i<strlen(str); i++)
!         /*str[i] = tolower(str[i]);*/
!         if (str[i] >= 'A' && str[i] <= 'Z')
!             str[i] += 'a' - 'A';
  }
  
  int cm_InitDNS(int enabled)
  {
  #ifndef DNSAPI_ENV
!     char configpath[100];
!     int len;
!     int code;
!     char *addr;
!   
!     if (!enabled) { 
!         fprintf(stderr, "DNS support disabled\n"); 
!         cm_dnsEnabled = 0; 
!         return 0; 
!     }
  
!     /* First try AFS_NS environment var. */
!     addr = getenv("AFS_NS");
!     if (addr && inet_addr(addr) != -1) {
!         strcpy(dns_addr, addr);
!     } else {
!         /* Now check for the AFSDNS.INI file */
!         code = GetWindowsDirectory(configpath, sizeof(configpath));
!         if (code == 0 || code > sizeof(configpath)) return -1;
!         strcat(configpath, "\\afsdns.ini");
! 
!         /* Currently we only get (and query) the first nameserver.  Getting
!         list of mult. nameservers should be easy to do. */
!         len = GetPrivateProfileString("AFS Domain Name Servers", "ns1", NULL,
!                                        dns_addr, sizeof(dns_addr),
!                                        configpath);
!   
!         if (len == 0 || inet_addr(dns_addr) == -1) {
!             fprintf(stderr, "No valid name server addresses found, DNS lookup is "
!                      "disabled\n");
!             cm_dnsEnabled = 0;  /* failed */
!             return -1;     /* No name servers defined */
!         }
!         else 
!             fprintf(stderr, "Found DNS server %s\n", dns_addr);
      }
  #endif /* DNSAPI_ENV */
!     cm_dnsEnabled = 1;
!     return 0;
  }
  
  #ifndef DNSAPI_ENV
***************
*** 630,714 ****
                   int *numServers, int *ttl)
  {
  #ifndef DNSAPI_ENV
!    /*static AFS_SRV_LIST srvList;
!     static int ans = 0;*/
!   SOCKET commSock;
!   SOCKADDR_IN sockAddr;
!   PDNS_HDR  pDNShdr;
!   char buffer[BUFSIZE];
!   char query[1024];
!   int rc;
  
  #ifdef DEBUG
!   fprintf(stderr, "getAFSServer: cell %s, cm_dnsEnabled=%d\n", cellName, cm_dnsEnabled);
  #endif
  
  #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
!   if (cm_dnsEnabled == -1) { /* not yet initialized, eg when called by klog */
!     cm_InitDNS(1);    /* assume enabled */
!   }
  #endif
!   if (cm_dnsEnabled == 0) {  /* possibly we failed in cm_InitDNS above */
!     fprintf(stderr, "DNS initialization failed, disabled\n");
!     *numServers = 0;
!     return -1;
!   }
    
!   sockAddr = setSockAddr(dns_addr, DNS_PORT);
    
!   commSock = socket( AF_INET, SOCK_DGRAM, 0 );
!   if ( commSock < 0 )
      {
!       /*afsi_log("socket() failed\n");*/
!       fprintf(stderr, "getAFSServer: socket() failed, errno=%d\n", errno);
!       *numServers = 0;
!       return (-1);
      } 
-   
- #ifdef DJGPP
-   /* the win95 sock.vxd will not allow sendto for unbound sockets, 
-    *   so just bind to nothing and it works */
-   
-   __djgpp_set_socket_blocking_mode(commSock, 0);
-   bind(commSock,0,sizeof( SOCKADDR_IN ) );
- #endif /* DJGPP */
- 
-   strncpy(query, cellName, 1024);
-   query[1023] = 0;
-   if (query[strlen(query)-1] != '.') {
-     strncat(query,".",1024);
-     query[1023] = 0;
-   }
  
!   rc = send_DNS_AFSDB_Query(cellName,commSock,sockAddr, buffer);
!   if (rc < 0) {
!     fprintf(stderr,"getAFSServer: send_DNS_AFSDB_Query failed\n");
!     *numServers = 0;
!     return -1;
!   }
      
!   pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
!   
!   /*printReplyBuffer_AFSDB(pDNShdr);*/
!   if (pDNShdr)
!     processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, numServers, ttl);
!   else
!     *numServers = 0;
    
!   closesocket(commSock);
!   if (*numServers == 0)
!     return(-1);
  
!   else
!     return 0;
  #else /* DNSAPI_ENV */
      PDNS_RECORD pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
!     DWORD i;
      struct sockaddr_in vlSockAddr;
      char query[1024];
  
  #ifdef AFS_FREELANCE_CLIENT
!     if ( stricmp(cellName, "Freelance.Local.Root") == 0 )
          return -1;
  #endif /* AFS_FREELANCE_CLIENT */
  
--- 624,695 ----
                   int *numServers, int *ttl)
  {
  #ifndef DNSAPI_ENV
!     SOCKET commSock;
!     SOCKADDR_IN sockAddr;
!     PDNS_HDR  pDNShdr;
!     char buffer[BUFSIZE];
!     char query[1024];
!     int rc;
  
  #ifdef DEBUG
!     fprintf(stderr, "getAFSServer: cell %s, cm_dnsEnabled=%d\n", cellName, cm_dnsEnabled);
  #endif
  
  #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
!     if (cm_dnsEnabled == -1) { /* not yet initialized, eg when called by klog */
!         cm_InitDNS(1);         /* assume enabled */
!     }
  #endif
!     if (cm_dnsEnabled == 0) {  /* possibly we failed in cm_InitDNS above */
!         fprintf(stderr, "DNS initialization failed, disabled\n");
!         *numServers = 0;
!         return -1;
!     }
    
!     sockAddr = setSockAddr(dns_addr, DNS_PORT);
    
!     commSock = socket( AF_INET, SOCK_DGRAM, 0 );
!     if ( commSock < 0 )
      {
!         /*afsi_log("socket() failed\n");*/
!         fprintf(stderr, "getAFSServer: socket() failed, errno=%d\n", errno);
!         *numServers = 0;
!         return (-1);
      } 
  
!     StringCbCopyA(query, sizeof(query), cellName);
!     if (query[strlen(query)-1] != '.') {
!         StringCbCatA(query, sizeof(query), ".");
!     }
! 
!     rc = send_DNS_AFSDB_Query(cellName,commSock,sockAddr, buffer);
!     if (rc < 0) {
!         fprintf(stderr,"getAFSServer: send_DNS_AFSDB_Query failed\n");
!         *numServers = 0;
!         return -1;
!     }
      
!     pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
    
!     /*printReplyBuffer_AFSDB(pDNShdr);*/
!     if (pDNShdr)
!         processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, numServers, ttl);
!     else
!         *numServers = 0;
  
!     closesocket(commSock);
!     if (*numServers == 0)
!         return(-1);
!     else
!         return 0;
  #else /* DNSAPI_ENV */
      PDNS_RECORD pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
!     int i;
      struct sockaddr_in vlSockAddr;
      char query[1024];
  
  #ifdef AFS_FREELANCE_CLIENT
!     if ( cm_stricmp_utf8N(cellName, "Freelance.Local.Root") == 0 )
          return -1;
  #endif /* AFS_FREELANCE_CLIENT */
  
***************
*** 716,737 ****
      *ttl = 0;
  
      /* query the AFSDB records of cell */
!     strncpy(query, cellName, 1024);
!     query[1023] = 0;
      if (query[strlen(query)-1] != '.') {
!         strncat(query,".",1024);
!         query[1023] = 0;
      }
  
      if (DnsQuery_A(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
          memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
! 		
          /* go through the returned records */
          for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
              /* if we find an AFSDB record with Preference set to 1, we found a volserver */
              if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
!                 strncpy(cellHostNames[*numServers], pDnsIter->Data.Afsdb.pNameExchange, MAXHOSTCHARS);
!                 cellHostNames[*numServers][MAXHOSTCHARS-1]='\0';
                  (*numServers)++;
                  
                  if (!*ttl) 
--- 697,716 ----
      *ttl = 0;
  
      /* query the AFSDB records of cell */
!     StringCbCopyA(query, sizeof(query), cellName);
      if (query[strlen(query)-1] != '.') {
!         StringCbCatA(query, sizeof(query), ".");
      }
  
      if (DnsQuery_A(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
          memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
! 
          /* go through the returned records */
          for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
              /* if we find an AFSDB record with Preference set to 1, we found a volserver */
              if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
!                 StringCbCopyA(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
!                               pDnsIter->Data.Afsdb.pNameExchange);
                  (*numServers)++;
                  
                  if (!*ttl) 
***************
*** 749,757 ****
              if(pDnsIter->wType == DNS_TYPE_A)
                  /* check if its for one of the volservers */
                  for (i=0;i<*numServers;i++)
!                     if(stricmp(pDnsIter->pName, cellHostNames[i]) == 0)
                          cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
!         }       
  
          for (i=0;i<*numServers;i++) {
              /* if we don't have an IP yet, then we should try resolving the volserver hostname
--- 728,736 ----
              if(pDnsIter->wType == DNS_TYPE_A)
                  /* check if its for one of the volservers */
                  for (i=0;i<*numServers;i++)
!                     if(cm_stricmp_utf8(pDnsIter->pName, cellHostNames[i]) == 0)
                          cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
!         }
  
          for (i=0;i<*numServers;i++) {
              /* if we don't have an IP yet, then we should try resolving the volserver hostname
***************
*** 760,773 ****
                  if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
                      for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
                          /* if we get an A record, keep it */
!                         if (pDnsVolIter->wType == DNS_TYPE_A && stricmp(cellHostNames[i], pDnsVolIter->pName)==0) {
                              cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
                              break;
                          }
                          /* if we get a CNAME, look for a corresponding A record */
!                         if (pDnsVolIter->wType == DNS_TYPE_CNAME && stricmp(cellHostNames[i], pDnsVolIter->pName)==0) {
                              for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
!                                 if (pDnsCIter->wType == DNS_TYPE_A && stricmp(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
                                      cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
                                      break;
                                  }
--- 739,752 ----
                  if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
                      for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
                          /* if we get an A record, keep it */
!                         if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
                              cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
                              break;
                          }
                          /* if we get a CNAME, look for a corresponding A record */
!                         if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
                              for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
!                                 if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf8(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
                                      cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
                                      break;
                                  }
***************
*** 791,794 ****
--- 770,869 ----
          return -1;
  #endif /* DNSAPI_ENV */
  }
+ 
+ int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
+                   cm_unichar_t cellHostNames[][MAXHOSTCHARS], 
+                   int *numServers, int *ttl)
+ {
+ #ifdef DNSAPI_ENV
+     PDNS_RECORDW pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
+     int i;
+     struct sockaddr_in vlSockAddr;
+     cm_unichar_t query[1024];
+ 
+ #ifdef AFS_FREELANCE_CLIENT
+     if ( cm_stricmp_utf16(cellName, L"Freelance.Local.Root") == 0 )
+         return -1;
+ #endif /* AFS_FREELANCE_CLIENT */
+ 
+     *numServers = 0; 
+     *ttl = 0;
+ 
+     /* query the AFSDB records of cell */
+     StringCbCopyW(query, sizeof(query), cellName);
+     if (query[wcslen(query)-1] != L'.') {
+         StringCbCatW(query, sizeof(query), L".");
+     }
+ 
+     if (DnsQuery_W(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, (PDNS_RECORD *) &pDnsCell,
+                    NULL) == ERROR_SUCCESS) {
+         memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
+ 
+         /* go through the returned records */
+         for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
+             /* if we find an AFSDB record with Preference set to 1, we found a volserver */
+             if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
+                 StringCbCopyW(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
+                               pDnsIter->Data.Afsdb.pNameExchange);
+                 (*numServers)++;
+                 
+                 if (!*ttl) 
+                     *ttl = pDnsIter->dwTtl;
+                 if (*numServers == AFSMAXCELLHOSTS) 
+                     break;
+             }
+         }
+ 
+         for (i=0;i<*numServers;i++) 
+             cellHostAddrs[i] = 0;
+ 
+         /* now check if there are any A records in the results */
+         for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
+             if(pDnsIter->wType == DNS_TYPE_A)
+                 /* check if its for one of the volservers */
+                 for (i=0;i<*numServers;i++)
+                     if(cm_stricmp_utf16(pDnsIter->pName, cellHostNames[i]) == 0)
+                         cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
+         }
+ 
+         for (i=0;i<*numServers;i++) {
+             /* if we don't have an IP yet, then we should try resolving the volserver hostname
+                in a separate query. */
+             if (!cellHostAddrs[i]) {
+                 if (DnsQuery_W(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL,
+                                (PDNS_RECORD *) &pDnsVol, NULL) == ERROR_SUCCESS) {
+                     for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
+                         /* if we get an A record, keep it */
+                         if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
+                             cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
+                             break;
+                         }
+                         /* if we get a CNAME, look for a corresponding A record */
+                         if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
+                             for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
+                                 if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf16(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
+                                     cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
+                                     break;
+                                 }
+                             }
+                             if (cellHostAddrs[i]) 
+                                 break;
+                             /* TODO: if the additional section is missing, then do another lookup for the CNAME */
+                         }
+                     }
+                     /* we are done with the volserver lookup */
+                     DnsRecordListFree((PDNS_RECORD) pDnsVol, DnsFreeRecordListDeep);
+                 }
+             }
+         }
+         DnsRecordListFree((PDNS_RECORD) pDnsCell, DnsFreeRecordListDeep);
+     }
+ 
+     if ( *numServers > 0 )
+         return 0;
+     else        
+ #endif  /* DNSAPI_ENV */
+         return -1;
+ }
  #endif /* AFS_AFSDB_ENV */
+ 
Index: openafs/src/WINNT/afsd/cm_dns.h
diff -c openafs/src/WINNT/afsd/cm_dns.h:1.2 openafs/src/WINNT/afsd/cm_dns.h:1.2.14.1
*** openafs/src/WINNT/afsd/cm_dns.h:1.2	Sat May 29 19:48:00 2004
--- openafs/src/WINNT/afsd/cm_dns.h	Thu Jun 26 12:38:29 2008
***************
*** 15,20 ****
--- 15,26 ----
     names for the given cell, ending in null */
  int getAFSServer(char *cellname, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], int *numServers, int *ttl);
  
+ /* Same as above, but using cm_unichar_t.  Note that this functon will
+    only be defined for DNSAPI_ENV. */
+ int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
+                   cm_unichar_t cellHostNames[][MAXHOSTCHARS], 
+                   int *numServers, int *ttl);
+ 
  /* a supplement for the DJGPP gethostbyname ... which 
     never bothers calling a DNS server ... so this function
     takes care of that. This should be called when you
Index: openafs/src/WINNT/afsd/cm_dns_private.h
diff -c openafs/src/WINNT/afsd/cm_dns_private.h:1.1 openafs/src/WINNT/afsd/cm_dns_private.h:1.1.22.1
*** openafs/src/WINNT/afsd/cm_dns_private.h:1.1	Tue Oct  9 00:56:00 2001
--- openafs/src/WINNT/afsd/cm_dns_private.h	Thu Jun 26 10:38:24 2008
***************
*** 9,23 ****
  #ifndef __DNS_AFS_private_h_env_
  #define __DNS_AFS_private_h_env_
  
- #ifdef DJGPP
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- /*#else
-   #include <windows.h>*/
- #endif
- 
  #ifdef KERNEL
  #define SOCKET struct osi_socket *
  #else
--- 9,14 ----
***************
*** 29,108 ****
  #include <stdio.h>
  #include <string.h>
  
- 
- #ifdef DJGPP
- 
- char *inet_ntoa(struct in_addr in)
- {
-   static char   out[256];
-   char temp[20];
-   unsigned long sVal,pVal;
- 
-   out[0] = '\0';
- 
- 
-   pVal = ntohl(in.s_addr);
- 
-   sVal = pVal;
-   sVal >>= 24;
-   sprintf(out,"%ld",sVal);
- 
-   sVal = pVal;
-   sVal <<= 8;
-   sVal >>= 24;
-   sprintf(out,"%s.%ld",out,sVal);
- 
-   sVal = pVal;
-   sVal <<= 16;
-   sVal >>= 24;
-   sprintf(out,"%s.%ld",out,sVal);
- 
-   sVal = pVal;
-   sVal <<= 24;
-   sVal >>= 24;
-   sprintf(out,"%s.%ld",out,sVal);
- 
-   return(&out[0]);
- }
- 
- unsigned long inet_addr(const char *cp)
- {
-   
-   unsigned long val=0;
-   unsigned char sVal;
-   
-   char   cp2[256];
- 
-   char*  ptr = cp2;
-   int    i;
-   int    len;
- 
-   strcpy(cp2,cp);
- 
-   for (i=0; i<=strlen(cp); i++)
-     {
-       if (cp2[i] == '.')
- 	{
- 	  cp2[i] = '\0';
- 	  sVal = atoi(ptr);
- 	  ptr = &cp2[i+1];
- 	  val = val << 8;
- 	  val &= 0xffffff00;
- 	  val |= sVal;
- 	  //printf("%x\t%lx\n",sVal,val);
- 	};
-     };
-   sVal = atoi(ptr);
-   val = val << 8;
-   val &= 0xffffff00;
-   val |= sVal;
-   //printf("%x\t%lx\n",sVal,val);
-   
-   return htonl(val);
- }
- 
- #endif /* DJGPP */
- 
  #define BUFSIZE                 2048
  
  /*
--- 20,25 ----
Index: openafs/src/WINNT/afsd/cm_freelance.c
diff -c openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.11.2.1 openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.14
*** openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.11.2.1	Sun Jun 22 23:00:43 2008
--- openafs/src/WINNT/afsd/cm_freelance.c	Thu Jun 26 10:38:24 2008
***************
*** 1,13 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winreg.h>
  #include <winsock2.h>
- #else
- #include <netdb.h>
- #endif /* !DJGPP */
  #include <stdlib.h>
  #include <malloc.h>
  #include <string.h>
--- 1,9 ----
***************
*** 34,47 ****
  time_t FakeFreelanceModTime = 0x3b49f6e2;
  
  static int freelance_ShutdownFlag = 0;
- #if !defined(DJGPP)
  static HANDLE hFreelanceChangeEvent = 0;
  static HANDLE hFreelanceSymlinkChangeEvent = 0;
- #endif
  
  void cm_InitFakeRootDir();
  
- #if !defined(DJGPP)
  void cm_FreelanceChangeNotifier(void * parmp) {
      HKEY   hkFreelance = 0;
  
--- 30,40 ----
***************
*** 131,155 ****
          }
      }
  }
- #endif
  
  void                                          
  cm_FreelanceShutdown(void)                    
  {                                             
      freelance_ShutdownFlag = 1;               
- #if !defined(DJGPP)                           
      if (hFreelanceChangeEvent != 0)           
          thrd_SetEvent(hFreelanceChangeEvent); 
      if (hFreelanceSymlinkChangeEvent != 0)           
          thrd_SetEvent(hFreelanceSymlinkChangeEvent); 
- #endif                                        
  }                                             
  
  void cm_InitFreelance() {
- #if !defined(DJGPP)
      thread_t phandle;
      int lpid;
- #endif
  
      lock_InitializeMutex(&cm_Freelance_Lock, "Freelance Lock");
  
--- 124,143 ----
***************
*** 162,168 ****
      cm_InitFakeRootDir();
      // --- end of yj code
  
- #if !defined(DJGPP)
      /* Start the registry monitor */
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceChangeNotifier,
                            NULL, 0, &lpid, "cm_FreelanceChangeNotifier");
--- 150,155 ----
***************
*** 173,179 ****
                            NULL, 0, &lpid, "cm_FreelanceSymlinkChangeNotifier");
      osi_assertx(phandle != NULL, "cm_FreelanceSymlinkChangeNotifier thread create failure");
      thrd_CloseHandle(phandle);
- #endif
  }
  
  /* yj: Initialization of the fake root directory */
--- 160,165 ----
***************
*** 469,484 ****
      char hdir[260];
      long code;
      char rootCellName[256];
- #if !defined(DJGPP)
      HKEY hkFreelance = 0, hkFreelanceSymlinks = 0;
      DWORD dwType, dwSize;
      DWORD dwMountPoints = 0;
      DWORD dwIndex;
      DWORD dwSymlinks = 0;
      FILETIME ftLastWriteTime;
- #endif
  
- #if !defined(DJGPP)
      if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
                        AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
                        0,
--- 455,467 ----
***************
*** 670,676 ****
          RegCloseKey(hkFreelance);
          return 0;
      }
- #endif
  
      /* What follows is the old code to read freelance mount points 
       * out of a text file modified to copy the data into the registry
--- 653,658 ----
***************
*** 687,693 ****
          fp = fopen(hdir, "r");
      }
  
- #if !defined(DJGPP)
      RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
                      AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
                      0,
--- 669,674 ----
***************
*** 698,709 ****
                      &hkFreelance,
                      NULL);
      dwIndex = 0;
- #endif
  
      if (!fp) {
- #if !defined(DJGPP)
          RegCloseKey(hkFreelance);
- #endif
          rootCellName[0] = '.';
        	code = cm_GetRootCellName(&rootCellName[1]);
          if (code == 0) {
--- 679,687 ----
***************
*** 760,766 ****
          if (t2)
              *(t2+1) = '\0';
  
- #if !defined(DJGPP)
          if ( hkFreelance ) {
              char szIndex[16];
              /* we are migrating to the registry */
--- 738,743 ----
***************
*** 769,775 ****
              dwSize = (DWORD)strlen(line) + 1;
              RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize);
          }
- #endif 
  
          // line is not empty, so let's parse it
          t = strchr(line, '#');
--- 746,751 ----
***************
*** 796,807 ****
          aLocalMountPoint++;
      }
      fclose(fp);
- #if !defined(DJGPP)
      if ( hkFreelance ) {
          RegCloseKey(hkFreelance);
          DeleteFile(hdir);
      }
- #endif
      return 0;
  }
  
--- 772,781 ----
***************
*** 809,815 ****
      return cm_noLocalMountPoints;
  }
  
- #if !defined(DJGPP)
  long cm_FreelanceMountPointExists(char * filename, int prefix_ok)
  {
      char* cp;
--- 783,788 ----
***************
*** 874,880 ****
              memcpy(shortname, line, cp-line);
              shortname[cp-line]=0;
  
!             if (!stricmp(shortname, filename)) {
                  found = 1;
                  break;
              }
--- 847,853 ----
              memcpy(shortname, line, cp-line);
              shortname[cp-line]=0;
  
!             if (!cm_stricmp_utf8(shortname, filename)) {
                  found = 1;
                  break;
              }
***************
*** 957,963 ****
              memcpy(shortname, line, cp-line);
              shortname[cp-line]=0;
  
!             if (!stricmp(shortname, filename)) {
                  found = 1;
                  break;
              }
--- 930,936 ----
              memcpy(shortname, line, cp-line);
              shortname[cp-line]=0;
  
!             if (!cm_stricmp_utf8(shortname, filename)) {
                  found = 1;
                  break;
              }
***************
*** 969,975 ****
  
      return found;
  }
- #endif
  
  long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp)
  {
--- 942,947 ----
***************
*** 979,990 ****
      char fullname[200];
      int n;
      int alias = 0;
- #if !defined(DJGPP)
      HKEY hkFreelance = 0;
      DWORD dwType, dwSize;
      DWORD dwMountPoints;
      DWORD dwIndex;
- #endif
  
      /* before adding, verify the cell name; if it is not a valid cell,
         don't add the mount point.
--- 951,960 ----
***************
*** 1007,1024 ****
              return -1;
      }
  
- #if !defined(DJGPP)
      if ( cm_FreelanceMountPointExists(filename, 0) ||
           cm_FreelanceSymlinkExists(filename, 0) )
          return -1;
- #endif
      
      osi_Log1(afsd_logp,"Freelance Adding Mount for Cell: %s", 
                osi_LogSaveString(afsd_logp,cellname));
  
      lock_ObtainMutex(&cm_Freelance_Lock);
  
- #if !defined(DJGPP)
      if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
                        AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
                        0,
--- 977,991 ----
***************
*** 1073,1079 ****
          }
          RegCloseKey(hkFreelance);
      } else 
- #endif
      {
          cm_GetConfigDir(hfile, sizeof(hfile));
          strcat(hfile, AFS_FREELANCE_INI);
--- 1040,1045 ----
***************
*** 1110,1125 ****
      char hfile[260], hfile2[260];
      FILE *fp1, *fp2;
      int found=0;
- #if !defined(DJGPP)
      HKEY hkFreelance = 0;
      DWORD dwType, dwSize;
      DWORD dwMountPoints;
      DWORD dwIndex;
- #endif
  
      lock_ObtainMutex(&cm_Freelance_Lock);
  
- #if !defined(DJGPP)
      if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
                        AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance",
                        0,
--- 1076,1088 ----
***************
*** 1161,1167 ****
          }
          RegCloseKey(hkFreelance);
      } else 
- #endif
      {
          cm_GetConfigDir(hfile, sizeof(hfile));
          strcat(hfile, AFS_FREELANCE_INI);
--- 1124,1129 ----
***************
*** 1217,1228 ****
      char line[512];
      char fullname[200];
      int alias = 0;
- #if !defined(DJGPP)
      HKEY hkFreelanceSymlinks = 0;
      DWORD dwType, dwSize;
      DWORD dwSymlinks;
      DWORD dwIndex;
- #endif
  
      /* before adding, verify the filename.  If it is already in use, either as 
       * as mount point or a cellname, do not permit the creation of the symlink.
--- 1179,1188 ----
***************
*** 1237,1259 ****
      fullname[0] = '\0';
      if (filename[0] == '.') {
          cm_GetCell_Gen(&filename[1], fullname, CM_FLAG_CREATE);
!         if (stricmp(&filename[1],fullname) == 0)
              return CM_ERROR_EXISTS;
      } else {
          cm_GetCell_Gen(filename, fullname, CM_FLAG_CREATE);
!         if (stricmp(filename,fullname) == 0)
              return CM_ERROR_EXISTS;
      }
  
- #if !defined(DJGPP)
      if ( cm_FreelanceMountPointExists(filename, 0) ||
           cm_FreelanceSymlinkExists(filename, 0) )
          return CM_ERROR_EXISTS;
- #endif
  
      lock_ObtainMutex(&cm_Freelance_Lock);
  
- #if !defined(DJGPP)
      if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
                          AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
                          0,
--- 1197,1216 ----
      fullname[0] = '\0';
      if (filename[0] == '.') {
          cm_GetCell_Gen(&filename[1], fullname, CM_FLAG_CREATE);
!         if (cm_stricmp_utf8(&filename[1],fullname) == 0)
              return CM_ERROR_EXISTS;
      } else {
          cm_GetCell_Gen(filename, fullname, CM_FLAG_CREATE);
!         if (cm_stricmp_utf8(filename,fullname) == 0)
              return CM_ERROR_EXISTS;
      }
  
      if ( cm_FreelanceMountPointExists(filename, 0) ||
           cm_FreelanceSymlinkExists(filename, 0) )
          return CM_ERROR_EXISTS;
  
      lock_ObtainMutex(&cm_Freelance_Lock);
  
      if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
                          AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
                          0,
***************
*** 1308,1314 ****
          }
          RegCloseKey(hkFreelanceSymlinks);
      } 
- #endif
      lock_ReleaseMutex(&cm_Freelance_Lock);
  
      /* cm_reInitLocalMountPoints(); */
--- 1265,1270 ----
***************
*** 1324,1339 ****
      char line[512];
      char shortname[200];
      int found=0;
- #if !defined(DJGPP)
      HKEY hkFreelanceSymlinks = 0;
      DWORD dwType, dwSize;
      DWORD dwSymlinks;
      DWORD dwIndex;
- #endif
  
      lock_ObtainMutex(&cm_Freelance_Lock);
  
- #if !defined(DJGPP)
      if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
                        AFSREG_CLT_OPENAFS_SUBKEY "\\Freelance\\Symlinks",
                        0,
--- 1280,1292 ----
***************
*** 1373,1379 ****
          }
          RegCloseKey(hkFreelanceSymlinks);
      }
- #endif
      
      lock_ReleaseMutex(&cm_Freelance_Lock);
      if (found) {
--- 1326,1331 ----
Index: openafs/src/WINNT/afsd/cm_ioctl.c
diff -c openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.44 openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.50
*** openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.44	Mon Apr 14 18:44:03 2008
--- openafs/src/WINNT/afsd/cm_ioctl.c	Fri Jul 11 18:27:01 2008
***************
*** 13,23 ****
  #include <afs/ptserver.h>
  #include <ubik.h>
  
- #ifndef DJGPP
  #include <windows.h>
- #else
- #include <sys/socket.h>
- #endif /* !DJGPP */
  #include <errno.h>
  #include <stdlib.h>
  #include <malloc.h>
--- 13,19 ----
***************
*** 33,51 ****
  
  #include "smb.h"
  
- #ifndef DJGPP
  #include <rx/rxkad.h>
  #include "afsrpc.h"
- #else
- #include <rx/rxkad.h>
- #include "afsrpc95.h"
- #endif
  
  #include "cm_rpc.h"
  #include <strsafe.h>
  #include <winioctl.h>
  #include <rx\rx.h>
  
  #ifdef _DEBUG
  #include <crtdbg.h>
  #endif
--- 29,44 ----
  
  #include "smb.h"
  
  #include <rx/rxkad.h>
  #include "afsrpc.h"
  
  #include "cm_rpc.h"
  #include <strsafe.h>
  #include <winioctl.h>
  #include <rx\rx.h>
  
+ #include "cm_btree.h"
+ 
  #ifdef _DEBUG
  #include <crtdbg.h>
  #endif
***************
*** 54,63 ****
--- 47,60 ----
  #define PIOCTL_LOGON	0x1
  #define MAX_PATH 260
  
+ const char utf8_prefix[] = UTF8_PREFIX;
+ const int  utf8_prefix_size = sizeof(utf8_prefix) -  sizeof(char);
+ 
  osi_mutex_t cm_Afsdsbmt_Lock;
  
  extern afs_int32 cryptall;
  extern char cm_NetbiosName[];
+ extern clientchar_t cm_NetbiosNameC[];
  
  extern void afsi_log(char *pattern, ...);
  
***************
*** 66,88 ****
      lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
  }
  
! long cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
      long code;
  
      code = buf_CleanVnode(scp, userp, reqp);
!         
!     lock_ObtainWrite(&scp->rw);
!     cm_DiscardSCache(scp);
!     lock_ReleaseWrite(&scp->rw);
! 
      osi_Log2(afsd_logp,"cm_CleanFile scp 0x%x returns error: [%x]",scp, code);
      return code;
  }
  
! long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
--- 63,96 ----
      lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
  }
  
! /* 
!  * Utility function.  (Not currently in use.)
!  * This function forces all dirty buffers to the file server and 
!  * then discards the status info.
!  */
! afs_int32
! cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
      long code;
  
      code = buf_CleanVnode(scp, userp, reqp);
!     if (!code) {
!         lock_ObtainWrite(&scp->rw);
!         cm_DiscardSCache(scp);
!         lock_ReleaseWrite(&scp->rw);
!     }
      osi_Log2(afsd_logp,"cm_CleanFile scp 0x%x returns error: [%x]",scp, code);
      return code;
  }
  
! /* 
!  * Utility function.  Used within this file.
!  * scp must be held but not locked.
!  */
! afs_int32
! cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     afs_int32 code;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
***************
*** 95,110 ****
          
      lock_ObtainWrite(&scp->rw);
      cm_DiscardSCache(scp);
- 
      lock_ReleaseWrite(&scp->rw);
  
      osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
      return code;
  }
  
! long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     long code = 0;
      cm_scache_t * pscp;
    
      pscp = cm_FindSCacheParent(scp);
--- 103,123 ----
          
      lock_ObtainWrite(&scp->rw);
      cm_DiscardSCache(scp);
      lock_ReleaseWrite(&scp->rw);
  
      osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
      return code;
  }
  
! /* 
!  * Utility function.  (Not currently in use)
!  * IoctlPath must be parsed or skipped prior to calling.
!  * scp must be held but not locked.
!  */
! afs_int32
! cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
  {
!     afs_int32 code = 0;
      cm_scache_t * pscp;
    
      pscp = cm_FindSCacheParent(scp);
***************
*** 116,125 ****
      return code;
  }
  
! 
! long cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
  {
!     long code = 0;
      cm_scache_t *scp;
      int i;
  
--- 129,141 ----
      return code;
  }
  
! /* 
!  * Utility function.  Used within this function.
!  */
! afs_int32
! cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
  {
!     afs_int32 code = 0;
      cm_scache_t *scp;
      int i;
  
***************
*** 150,159 ****
  }
  
  /*
!  * cm_ResetACLCache -- invalidate ACL info for a user that has just
!  *			obtained or lost tokens
   */
! void cm_ResetACLCache(cm_user_t *userp)
  {
      cm_scache_t *scp;
      int hash;
--- 166,176 ----
  }
  
  /*
!  * Utility function.  Used within this file.
!  * Invalidate ACL info for a user that has just	obtained or lost tokens.
   */
! void 
! cm_ResetACLCache(cm_user_t *userp)
  {
      cm_scache_t *scp;
      int hash;
***************
*** 178,406 ****
   *
   *  If an extended character (80 - FF) is entered into a file
   *  or directory name in Windows, the character is translated
!  *  into the OEM character map before being passed to us.  Why
!  *  this occurs is unknown.  Our pioctl functions must match
   *  this translation for paths given via our own commands (like
   *  fs).  If we do not do this, then we will try to perform an
   *  operation on a non-translated path, which we will fail to 
   *  find, since the path was created with the translated chars.
   *  This function performs the required translation.
   */
! void TranslateExtendedChars(char *str)
  {
- #ifdef DJGPP
-     char *p;
- #endif
- 
      if (!str || !*str)
          return;
  
! #ifndef DJGPP
!     CharToOem(str, str);
! #else
!     p = str;
!     while (*p) *p++ &= 0x7f;  /* turn off high bit; probably not right */
! #endif
  }
-         
- /* parse the passed-in file name and do a namei on it.  If we fail,
-  * return an error code, otherwise return the vnode located in *scpp.
-  */
- #define CM_PARSE_FLAG_LITERAL 1
  
! long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
! 	cm_scache_t **scpp, afs_uint32 flags)
  {
!     long code;
!     cm_scache_t *substRootp = NULL;
!     cm_scache_t *iscp = NULL;
!     char * relativePath;
!     char * lastComponent = NULL;
!     afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
! 
!     relativePath = ioctlp->inDatap;
!     /* setup the next data value for the caller to use */
!     ioctlp->inDatap += (long)strlen(ioctlp->inDatap) + 1;;
! 
!     osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,relativePath));
! 
!     /* This is usually the file name, but for StatMountPoint it is the path. */
!     /* ioctlp->inDatap can be either of the form:
!      *    \path\.
!      *    \path\file
!      *    \\netbios-name\submount\path\.
!      *    \\netbios-name\submount\path\file
!      */
  
! 	/* We do not perform path name translation on the ioctl path data 
! 	 * because these paths were not translated by Windows through the
! 	 * file system API.  Therefore, they are not OEM characters but 
! 	 * whatever the display character set is.
! 	 */
!     // TranslateExtendedChars(relativePath);
! 
!     /* This is usually nothing, but for StatMountPoint it is the file name. */
!     // TranslateExtendedChars(ioctlp->inDatap);
! 
!     if (relativePath[0] == relativePath[1] &&
!          relativePath[1] == '\\' && 
!          !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) 
!     {
!         char shareName[256];
!         char *sharePath;
!         int shareFound, i;
! 
!         /* We may have found a UNC path. 
!          * If the first component is the NetbiosName,
!          * then throw out the second component (the submount)
!          * since it had better expand into the value of ioctl->tidPathp
!          */
!         char * p;
!         p = relativePath + 2 + strlen(cm_NetbiosName) + 1;			/* buffer overflow vuln.? */
!         if ( !_strnicmp("all", p, 3) )
!             p += 4;
! 
!         for (i = 0; *p && *p != '\\'; i++,p++ ) {
!             shareName[i] = *p;
!         }
!         p++;                    /* skip past trailing slash */
!         shareName[i] = 0;       /* terminate string */
! 
!         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
!         if ( shareFound ) {
!             /* we found a sharename, therefore use the resulting path */
!             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
!                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                              userp, sharePath, reqp, &substRootp);
!             free(sharePath);
!             if (code) {
! 		osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
!                 return code;
! 	    }
! 
! 	    lastComponent = strrchr(p, '\\');
! 	    if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
! 		*lastComponent = '\0';
! 		lastComponent++;
! 
! 		code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
! 				 userp, NULL, reqp, &iscp);
! 		if (code == 0)
! 		    code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
! 				    userp, NULL, reqp, scpp);
! 		if (iscp)
! 		    cm_ReleaseSCache(iscp);
! 	    } else {
! 		code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
! 				userp, NULL, reqp, scpp);
! 	    }
! 	    cm_ReleaseSCache(substRootp);
!             if (code) {
! 		osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", 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 && *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_data.rootSCachep, ioctlp->prefix->data,
!                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                              userp, shareName, reqp, &substRootp);
!             if (code) {
! 		osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
!                 return code;
! 	    }
! 
! 	    lastComponent = strrchr(p, '\\');
! 	    if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
! 		*lastComponent = '\0';
! 		lastComponent++;
! 
! 		code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
! 				 userp, NULL, reqp, &iscp);
! 		if (code == 0)
! 		    code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
! 				    userp, NULL, reqp, scpp);
! 		if (iscp)
! 		    cm_ReleaseSCache(iscp);
! 	    } else {
! 		code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
! 				userp, NULL, reqp, scpp);
! 	    }
! 
! 	    if (code) {
! 		cm_ReleaseSCache(substRootp);
! 		osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
!                 return code;
! 	    }
!         }
      } else {
!         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
!                          CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                          userp, ioctlp->tidPathp, reqp, &substRootp);
!         if (code) {
! 	    osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
!             return code;
! 	}
!         
! 	lastComponent = strrchr(relativePath, '\\');
! 	if (lastComponent && (lastComponent - relativePath) > 1 && strlen(lastComponent) > 1) {
! 	    *lastComponent = '\0';
! 	    lastComponent++;
! 
! 	    code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
! 			     userp, NULL, reqp, &iscp);
! 	    if (code == 0)
! 		code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
! 				 userp, NULL, reqp, scpp);
! 	    if (iscp)
! 		cm_ReleaseSCache(iscp);
! 	} else {
! 	    code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | follow,
! 			     userp, NULL, reqp, scpp);
! 	}
!         if (code) {
! 	    cm_ReleaseSCache(substRootp);
! 	    osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
!             return code;
! 	}
!     }
  
!     if (substRootp)
! 	cm_ReleaseSCache(substRootp);
  
!     /* and return success */
!     osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
!     return 0;
  }
  
! void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
  {
!     size_t temp;
!         
!     temp = strlen(ioctlp->inDatap) + 1;
!     ioctlp->inDatap += temp;
! }       
  
  /* 
!  * Must be called before cm_ParseIoctlPath or cm_SkipIoctlPath 
   */
! static cm_ioctlQueryOptions_t * 
! cm_IoctlGetQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      afs_uint32 pathlen = strlen(ioctlp->inDatap) + 1;
      char *p = ioctlp->inDatap + pathlen;
--- 195,303 ----
   *
   *  If an extended character (80 - FF) is entered into a file
   *  or directory name in Windows, the character is translated
!  *  into the OEM character map before being passed to us.
!  *  The pioctl functions must match
   *  this translation for paths given via our own commands (like
   *  fs).  If we do not do this, then we will try to perform an
   *  operation on a non-translated path, which we will fail to 
   *  find, since the path was created with the translated chars.
   *  This function performs the required translation.
+  *
+  *  OEM character code pages are used by the non-Unicode SMB
+  *  mode.  Do not use if the CM_IOCTLFLAG_USEUTF8 is set.
   */
! void 
! TranslateExtendedChars(char *str)
  {
      if (!str || !*str)
          return;
  
!     CharToOemA(str, str);
  }
  
! void cm_SkipIoctlPath(cm_ioctl_t *ioctlp)
  {
!     size_t temp;
  
!     temp = strlen(ioctlp->inDatap) + 1;
!     ioctlp->inDatap += temp;
! }
  
! 
! clientchar_t * cm_ParseIoctlStringAlloc(cm_ioctl_t *ioctlp, const char * ext_instrp)
! {
!     clientchar_t * rs = NULL;
!     const char * instrp;
! 
!     instrp = (ext_instrp)?ext_instrp:ioctlp->inDatap;
! 
!     if ((ioctlp->flags & CM_IOCTLFLAG_USEUTF8) == CM_IOCTLFLAG_USEUTF8) {
!         rs = cm_Utf8ToClientStringAlloc(instrp, -1, NULL);
      } else {
!         int cch;
  
!         /* Not a UTF-8 string */
!         if (smb_StoreAnsiFilenames) {
!             cch = cm_AnsiToClientString(instrp, -1, NULL, 0);
! #ifdef DEBUG
!             osi_assert(cch > 0);
! #endif
!             rs = malloc(cch * sizeof(clientchar_t));
!             cm_AnsiToClientString(instrp, -1, rs, cch);
!         } else {
!             cch = cm_OemToClientString(instrp, -1, NULL, 0);
! #ifdef DEBUG
!             osi_assert(cch > 0);
! #endif
!             rs = malloc(cch * sizeof(clientchar_t));
!             cm_OemToClientString(instrp, -1, rs, cch);
!         }
!     }
  
!     if (ext_instrp == NULL) {
!         ioctlp->inDatap += strlen(ioctlp->inDatap) + 1;
!     }
!     return rs;
  }
  
! int cm_UnparseIoctlString(cm_ioctl_t *ioctlp,
!                           char * ext_outp,
!                           const clientchar_t * cstr, int cchlen)
  {
!     char *outp;
!     int cchout;
! 
!     outp = ((ext_outp == NULL)? ioctlp->outDatap : ext_outp);
! 
!     if ((ioctlp->flags & CM_IOCTLFLAG_USEUTF8) == CM_IOCTLFLAG_USEUTF8) {
!         cchout = cm_ClientStringToUtf8(cstr, cchlen, outp,
!                                        SMB_IOCTL_MAXDATA - (outp - ioctlp->outAllocp));
!     } else {
!         if (smb_StoreAnsiFilenames) {
!             cchout = WideCharToMultiByte(CP_ACP, 0, cstr, cchlen,
!                                          outp,
!                                          SMB_IOCTL_MAXDATA - (outp - ioctlp->outAllocp),
!                                          NULL, NULL);
!         } else {
!             cchout = WideCharToMultiByte(CP_OEMCP, 0, cstr, cchlen,
!                                          outp,
!                                          SMB_IOCTL_MAXDATA - (outp - ioctlp->outAllocp),
!                                          NULL, NULL);
!         }
!     }
! 
!     if (cchout > 0 && ext_outp == NULL) {
!         ioctlp->outDatap += cchout;
!     }
! 
!     return cchout;
! }
  
  /* 
!  * Must be called before XXX_ParseIoctlPath or cm_SkipIoctlPath 
   */
! cm_ioctlQueryOptions_t * 
! cm_IoctlGetQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      afs_uint32 pathlen = strlen(ioctlp->inDatap) + 1;
      char *p = ioctlp->inDatap + pathlen;
***************
*** 416,427 ****
  }
  
  /* 
!  * Must be called after cm_ParseIoctlPath or cm_SkipIoctlPath
   * or any other time that ioctlp->inDatap points at the 
   * cm_ioctlQueryOptions_t object.
   */
! static void
! cm_IoctlSkipQueryOptions(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_ioctlQueryOptions_t * optionsp = (cm_ioctlQueryOptions_t *)ioctlp->inDatap;
      ioctlp->inDatap += optionsp->size;
--- 313,324 ----
  }
  
  /* 
!  * Must be called after smb_ParseIoctlPath or cm_SkipIoctlPath
   * or any other time that ioctlp->inDatap points at the 
   * cm_ioctlQueryOptions_t object.
   */
! void
! cm_IoctlSkipQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_ioctlQueryOptions_t * optionsp = (cm_ioctlQueryOptions_t *)ioctlp->inDatap;
      ioctlp->inDatap += optionsp->size;
***************
*** 434,616 ****
   * easier (because we can always jump past the initial "/afs" to find
   * the AFS path that should be written into afsdsbmt.ini).
   */
! void cm_NormalizeAfsPath(char *outpathp, long outlen, 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)))
!         StringCbCopy(outpathp, outlen, inpathp);
!     else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
!         StringCbCopy(outpathp, outlen, inpathp);
      else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
!         StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
      else // inpathp looks like "<cell>/usr"
!         StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
  
      for (cp = outpathp; *cp != 0; ++cp) {
          if (*cp == '\\')
              *cp = '/';
-     }       
- 
-     if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
-         outpathp[strlen(outpathp)-1] = 0;
      }
  
!     if (!strcmpi (outpathp, cm_mountRoot)) {
!         StringCbCopy(outpathp, outlen, cm_mountRoot);
      }
- }
  
! #define LEAF_SIZE 256
! /* parse the passed-in file name and do a namei on its parent.  If we fail,
!  * return an error code, otherwise return the vnode located in *scpp.
!  */
! 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 = NULL;
! 
!     StringCbCopyA(tbuffer, sizeof(tbuffer), ioctlp->inDatap);
!     tp = strrchr(tbuffer, '\\');
!     jp = strrchr(tbuffer, '/');
!     if (!tp)
!         tp = jp;
!     else if (jp && (tp - tbuffer) < (jp - tbuffer))
!         tp = jp;
!     if (!tp) {
!         StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
!         if (leafp) 
!             StringCbCopyA(leafp, LEAF_SIZE, ioctlp->inDatap);
      }
-     else {
-         *tp = 0;
-         if (leafp) 
-             StringCbCopyA(leafp, LEAF_SIZE, tp+1);
-     }   
- 
-     if (tbuffer[0] == tbuffer[1] &&
-         tbuffer[1] == '\\' && 
-         !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
-     {
-         char shareName[256];
-         char *sharePath;
-         int shareFound, i;
- 
-         /* We may have found a UNC path. 
-          * If the first component is the NetbiosName,
-          * then throw out the second component (the submount)
-          * since it had better expand into the value of ioctl->tidPathp
-          */
-         char * p;
-         p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
-         if ( !_strnicmp("all", p, 3) )
-             p += 4;
- 
-         for (i = 0; *p && *p != '\\'; i++,p++ ) {
-             shareName[i] = *p;
-         }
-         p++;                    /* skip past trailing slash */
-         shareName[i] = 0;       /* terminate string */
- 
-         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
-         if ( shareFound ) {
-             /* we found a sharename, therefore use the resulting path */
-             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
-                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                              userp, sharePath, reqp, &substRootp);
-             free(sharePath);
-             if (code) return code;
- 
-             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                              userp, NULL, reqp, scpp);
- 	    cm_ReleaseSCache(substRootp);
-             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 && *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_data.rootSCachep, ioctlp->prefix->data,
-                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                              userp, shareName, reqp, &substRootp);
-             if (code) return code;
- 
-             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                             userp, NULL, reqp, scpp);
- 	    cm_ReleaseSCache(substRootp);
-             if (code) return code;
-         }
-     } else {
-         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
-                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                         userp, ioctlp->tidPathp, reqp, &substRootp);
-         if (code) return code;
- 
-         code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
-                         userp, NULL, reqp, scpp);
- 	cm_ReleaseSCache(substRootp);
-         if (code) return code;
-     }
- 
-     /* # of bytes of path */
-     code = (long)strlen(ioctlp->inDatap) + 1;
-     ioctlp->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 afid;
      int tlen;
-     cm_req_t req;
      struct rx_connection * callp;
-     cm_ioctlQueryOptions_t *optionsp;
-     afs_uint32 flags = 0;
- 
-     cm_InitReq(&req);
- 
-     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
- 
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-         cm_fid_t fid;
-         cm_SkipIoctlPath(ioctlp);
-         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                   optionsp->fid.vnode, optionsp->fid.unique);
-         code = cm_GetSCache(&fid, &scp, userp, &req);
-     } else {
-         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-     }
-     if (code) 
-         return code;
  
      /* now make the get acl call */
  #ifdef AFS_FREELANCE_CLIENT
--- 331,387 ----
   * easier (because we can always jump past the initial "/afs" to find
   * the AFS path that should be written into afsdsbmt.ini).
   */
! void 
! cm_NormalizeAfsPath(clientchar_t *outpathp, long cchlen, clientchar_t *inpathp)
  {
!     clientchar_t *cp;
!     clientchar_t bslash_mountRoot[256];
         
!     cm_ClientStrCpy(bslash_mountRoot, lengthof(bslash_mountRoot), cm_mountRootC);
      bslash_mountRoot[0] = '\\';
! 
!     if (!cm_ClientStrCmpNI(inpathp, cm_mountRootC, cm_mountRootCLen))
!         cm_ClientStrCpy(outpathp, cchlen, inpathp);
!     else if (!cm_ClientStrCmpNI(inpathp, bslash_mountRoot,
!                                 cm_ClientStrLen(bslash_mountRoot)))
!         cm_ClientStrCpy(outpathp, cchlen, inpathp);
      else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
!         cm_ClientStrPrintfN(outpathp, cchlen, _C("%s%s"), cm_mountRootC, inpathp);
      else // inpathp looks like "<cell>/usr"
!         cm_ClientStrPrintfN(outpathp, cchlen, _C("%s/%s"), cm_mountRootC, inpathp);
  
      for (cp = outpathp; *cp != 0; ++cp) {
          if (*cp == '\\')
              *cp = '/';
      }
  
!     if (cm_ClientStrLen(outpathp) && (outpathp[cm_ClientStrLen(outpathp)-1] == '/')) {
!         outpathp[cm_ClientStrLen(outpathp)-1] = 0;
      }
  
!     if (!cm_ClientStrCmpI(outpathp, cm_mountRootC)) {
!         cm_ClientStrCpy(outpathp, cchlen, cm_mountRootC);
      }
  }
  
! 
! /* 
!  * VIOCGETAL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlGetACL(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
+     afs_int32 code;
      cm_conn_t *connp;
      AFSOpaque acl;
      AFSFetchStatus fileStatus;
      AFSVolSync volSync;
      AFSFid afid;
      int tlen;
      struct rx_connection * callp;
  
      /* now make the get acl call */
  #ifdef AFS_FREELANCE_CLIENT
***************
*** 626,643 ****
          do {
              acl.AFSOpaque_val = ioctlp->outDatap;
              acl.AFSOpaque_len = 0;
!             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
!             if (code) continue;
  
              callp = cm_GetRxConn(connp);
              code = RXAFS_FetchACL(callp, &afid, &acl, &fileStatus, &volSync);
              rx_PutConnection(callp);
  
!         } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
!         code = cm_MapRPCError(code, &req);
!         cm_ReleaseSCache(scp);
  
!         if (code) return code;
      }
      /* skip over return data */
      tlen = (int)strlen(ioctlp->outDatap) + 1;
--- 397,415 ----
          do {
              acl.AFSOpaque_val = ioctlp->outDatap;
              acl.AFSOpaque_len = 0;
!             code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
!             if (code) 
!                 continue;
  
              callp = cm_GetRxConn(connp);
              code = RXAFS_FetchACL(callp, &afid, &acl, &fileStatus, &volSync);
              rx_PutConnection(callp);
  
!         } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
!         code = cm_MapRPCError(code, reqp);
  
!         if (code) 
!             return code;
      }
      /* skip over return data */
      tlen = (int)strlen(ioctlp->outDatap) + 1;
***************
*** 647,678 ****
      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_ioctlQueryOptions_t *optionsp;
-     afs_uint32 flags = 0;
- 
-     cm_InitReq(&req);
- 
-     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
- 
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-         cm_fid_t fid;
-         cm_SkipIoctlPath(ioctlp);
-         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                   optionsp->fid.vnode, optionsp->fid.unique);
-         code = cm_GetSCache(&fid, &scp, userp, &req);
-     } else {
-         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-     }
-     if (code) 
-         return code;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( cm_freelanceEnabled && 
--- 419,436 ----
      return 0;
  }
  
! 
! /* 
!  * VIOC_FILE_CELL_NAME internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlGetFileCellName(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_cell_t *cellp;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( cm_freelanceEnabled && 
***************
*** 687,721 ****
      {
          cellp = cm_FindCellByID(scp->fid.cell, CM_FLAG_NOPROBE);
          if (cellp) {
!             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cellp->name);
!             ioctlp->outDatap += strlen(ioctlp->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(&req);
- 
-     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
-     if (code) return code;
- 	
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
  	code = CM_ERROR_NOACCESS;
--- 445,481 ----
      {
          cellp = cm_FindCellByID(scp->fid.cell, CM_FLAG_NOPROBE);
          if (cellp) {
!             clientchar_t * cellname;
! 
!             cellname = cm_FsStringToClientStringAlloc(cellp->name, -1, NULL); 
!             cm_UnparseIoctlString(ioctlp, NULL, cellname, -1);
!             free(cellname);
              code = 0;
!         } else
              code = CM_ERROR_NOSUCHCELL;
      }
  
      return code;
  }
  
! 	
! /* 
!  * VIOCSETAL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlSetACL(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
+     afs_int32 code;
      cm_conn_t *connp;
      AFSOpaque acl;
      AFSFetchStatus fileStatus;
      AFSVolSync volSync;
      AFSFid fid;
      struct rx_connection * callp;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
  	code = CM_ERROR_NOACCESS;
***************
*** 729,766 ****
          do {
              acl.AFSOpaque_val = ioctlp->inDatap;
              acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
!             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
!             if (code) continue;
  
              callp = cm_GetRxConn(connp);
              code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
              rx_PutConnection(callp);
  
!         } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
!         code = cm_MapRPCError(code, &req);
  
          /* invalidate cache info, since we just trashed the ACL cache */
          lock_ObtainWrite(&scp->rw);
          cm_DiscardSCache(scp);
          lock_ReleaseWrite(&scp->rw);
      }
-     cm_ReleaseSCache(scp);
  
      return code;
  }
  
! 
! 
! long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
      cm_scache_t *scp;
      int i;
-     cm_req_t req;
- 
-     cm_InitReq(&req);
- 
-     cm_SkipIoctlPath(ioctlp);	/* we don't care about the path */
  
      lock_ObtainWrite(&cm_scacheLock);
      for (i=0; i<cm_data.scacheHashTableSize; i++) {
--- 489,525 ----
          do {
              acl.AFSOpaque_val = ioctlp->inDatap;
              acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
!             code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
!             if (code) 
!                 continue;
  
              callp = cm_GetRxConn(connp);
              code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
              rx_PutConnection(callp);
  
!         } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
!         code = cm_MapRPCError(code, reqp);
  
          /* invalidate cache info, since we just trashed the ACL cache */
          lock_ObtainWrite(&scp->rw);
          cm_DiscardSCache(scp);
          lock_ReleaseWrite(&scp->rw);
      }
  
      return code;
  }
  
! /* 
!  * VIOC_FLUSHALL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlFlushAllVolumes(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_scache_t *scp;
      int i;
  
      lock_ObtainWrite(&cm_scacheLock);
      for (i=0; i<cm_data.scacheHashTableSize; i++) {
***************
*** 769,775 ****
  	    lock_ReleaseWrite(&cm_scacheLock);
  
  	    /* now flush the file */
! 	    code = cm_FlushFile(scp, userp, &req);
  	    lock_ObtainWrite(&cm_scacheLock);
  	    cm_ReleaseSCacheNoLock(scp);
          }
--- 528,534 ----
  	    lock_ReleaseWrite(&cm_scacheLock);
  
  	    /* now flush the file */
! 	    code = cm_FlushFile(scp, userp, reqp);
  	    lock_ObtainWrite(&cm_scacheLock);
  	    cm_ReleaseSCacheNoLock(scp);
          }
***************
*** 779,811 ****
      return code;
  }
  
! long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *scp;
!     unsigned long volume;
!     unsigned long cell;
!     cm_req_t req;
!     cm_ioctlQueryOptions_t *optionsp;
!     afs_uint32 flags = 0;
! 
!     cm_InitReq(&req);
! 
!     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
!     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
!         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
! 
!     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
!         cm_fid_t fid;
!         cm_SkipIoctlPath(ioctlp);
!         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
!                   optionsp->fid.vnode, optionsp->fid.unique);
!         code = cm_GetSCache(&fid, &scp, userp, &req);
!     } else {
!         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
!     }
!     if (code) 
!         return code;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
--- 538,555 ----
      return code;
  }
  
! /* 
!  * VIOC_FLUSHVOLUME internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlFlushVolume(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code;
!     afs_uint32 volume;
!     afs_uint32 cell;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
***************
*** 815,852 ****
      {
          volume = scp->fid.volume;
          cell = scp->fid.cell;
!         cm_ReleaseSCache(scp);
! 
!         code = cm_FlushVolume(userp, &req, cell, volume);
      }
      return code;
  }
  
! long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *scp;
!     cm_req_t req;
!     cm_ioctlQueryOptions_t *optionsp;
!     afs_uint32 flags = 0;
! 
!     cm_InitReq(&req);
! 
!     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
!     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
!         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
! 
!     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
!         cm_fid_t fid;
!         cm_SkipIoctlPath(ioctlp);
!         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
!                   optionsp->fid.vnode, optionsp->fid.unique);
!         code = cm_GetSCache(&fid, &scp, userp, &req);
!     } else {
!         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
!     }
!     if (code) 
!         return code;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
--- 559,579 ----
      {
          volume = scp->fid.volume;
          cell = scp->fid.cell;
!         code = cm_FlushVolume(userp, reqp, cell, volume);
      }
      return code;
  }
  
! /* 
!  * VIOCFLUSH internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlFlushFile(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
***************
*** 854,887 ****
      } else
  #endif
      {
!         cm_FlushFile(scp, userp, &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(&req);
- 
-     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
-     if (code) return code;
- 
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
  	code = CM_ERROR_NOACCESS;
--- 581,614 ----
      } else
  #endif
      {
!         cm_FlushFile(scp, userp, reqp);
      }
      return 0;
  }
  
! 
! /* 
!  * VIOCSETVOLSTAT internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlSetVolumeStatus(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code;
      char volName[32];
      char offLineMsg[256];
      char motd[256];
      cm_conn_t *tcp;
      AFSFetchVolumeStatus volStat;
      AFSStoreVolumeStatus storeStat;
      cm_volume_t *tvp;
      cm_cell_t *cellp;
!     char *cp;
!     clientchar_t *strp;
      struct rx_connection * callp;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
  	code = CM_ERROR_NOACCESS;
***************
*** 891,918 ****
          cellp = cm_FindCellByID(scp->fid.cell, 0);
          osi_assertx(cellp, "null cm_cell_t");
  
!         if (scp->flags & CM_SCACHEFLAG_RO) {
!             cm_ReleaseSCache(scp);
              return CM_ERROR_READONLY;
-         }
  
!         code = cm_FindVolumeByID(cellp, scp->fid.volume, userp, &req, 
                                   CM_GETVOL_FLAG_CREATE, &tvp);
!         if (code) {
!             cm_ReleaseSCache(scp);
              return code;
!         }
          cm_PutVolume(tvp);
  
          /* Copy the junk out, using cp as a roving pointer. */
!         cp = ioctlp->inDatap;
!         memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
!         cp += sizeof(AFSFetchVolumeStatus);
!         StringCbCopyA(volName, sizeof(volName), cp);
!         cp += strlen(volName)+1;
!         StringCbCopyA(offLineMsg, sizeof(offLineMsg), cp);
!         cp +=  strlen(offLineMsg)+1;
!         StringCbCopyA(motd, sizeof(motd), cp);
          storeStat.Mask = 0;
          if (volStat.MinQuota != -1) {
              storeStat.MinQuota = volStat.MinQuota;
--- 618,651 ----
          cellp = cm_FindCellByID(scp->fid.cell, 0);
          osi_assertx(cellp, "null cm_cell_t");
  
!         if (scp->flags & CM_SCACHEFLAG_RO)
              return CM_ERROR_READONLY;
  
!         code = cm_FindVolumeByID(cellp, scp->fid.volume, userp, reqp, 
                                   CM_GETVOL_FLAG_CREATE, &tvp);
!         if (code) 
              return code;
! 
          cm_PutVolume(tvp);
  
          /* Copy the junk out, using cp as a roving pointer. */
!         memcpy((char *)&volStat, ioctlp->inDatap, sizeof(AFSFetchVolumeStatus));
!         ioctlp->inDatap += sizeof(AFSFetchVolumeStatus);
! 
!         strp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
!         cm_ClientStringToFsString(strp, -1, volName, lengthof(volName));
!         free(strp);
! 
!         strp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
!         cm_ClientStringToFsString(strp, -1, offLineMsg, lengthof(offLineMsg));
!         free(strp);
! 
!         strp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
!         cm_ClientStringToFsString(strp, -1, motd, lengthof(motd));
!         free(strp);
! 
!         strp = NULL;
! 
          storeStat.Mask = 0;
          if (volStat.MinQuota != -1) {
              storeStat.MinQuota = volStat.MinQuota;
***************
*** 924,946 ****
          }
  
          do {
!             code = cm_ConnFromFID(&scp->fid, userp, &req, &tcp);
!             if (code) continue;
  
              callp = cm_GetRxConn(tcp);
              code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
!                                           &storeStat, volName, offLineMsg, motd);
              rx_PutConnection(callp);
  
!         } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
!         code = cm_MapRPCError(code, &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
--- 657,678 ----
          }
  
          do {
!             code = cm_ConnFromFID(&scp->fid, userp, reqp, &tcp);
!             if (code)
!                 continue;
  
              callp = cm_GetRxConn(tcp);
              code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
!                                          &storeStat, volName, offLineMsg, motd);
              rx_PutConnection(callp);
  
!         } while (cm_Analyze(tcp, userp, reqp, &scp->fid, NULL, NULL, NULL, code));
!         code = cm_MapRPCError(code, reqp);
      }
      
      /* return on failure */
!     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
***************
*** 962,1002 ****
      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 *connp;
-     register long code;
      AFSFetchVolumeStatus volStat;
!     register char *cp;
      char *Name;
      char *OfflineMsg;
      char *MOTD;
-     cm_req_t req;
      struct rx_connection * callp;
-     cm_ioctlQueryOptions_t *optionsp;
-     afs_uint32 flags = 0;
- 
-     cm_InitReq(&req);
- 
-     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
- 
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-         cm_fid_t fid;
-         cm_SkipIoctlPath(ioctlp);
-         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                   optionsp->fid.vnode, optionsp->fid.unique);
-         code = cm_GetSCache(&fid, &scp, userp, &req);
-     } else {
-         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-     }
-     if (code) 
-         return code;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
--- 694,720 ----
      return 0;
  }       
  
! 
! /* 
!  * VIOCGETVOLSTAT internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlGetVolumeStatus(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code;
!     char volName[32]="(unknown)";
!     char offLineMsg[256]="server temporarily inaccessible";
!     char motd[256]="server temporarily inaccessible";
      cm_conn_t *connp;
      AFSFetchVolumeStatus volStat;
!     char *cp;
      char *Name;
      char *OfflineMsg;
      char *MOTD;
      struct rx_connection * callp;
  
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
***************
*** 1016,1022 ****
  	OfflineMsg = offLineMsg;
  	MOTD = motd;
  	do {
! 	    code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
  	    if (code) continue;
  
  	    callp = cm_GetRxConn(connp);
--- 734,740 ----
  	OfflineMsg = offLineMsg;
  	MOTD = motd;
  	do {
! 	    code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
  	    if (code) continue;
  
  	    callp = cm_GetRxConn(connp);
***************
*** 1024,1035 ****
  					 &volStat, &Name, &OfflineMsg, &MOTD);
  	    rx_PutConnection(callp);
  
! 	} while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
! 	code = cm_MapRPCError(code, &req);
      }
  
!     cm_ReleaseSCache(scp);
!     if (code) return code;
  
      /* Copy all this junk into msg->im_data, keeping track of the lengths. */
      cp = ioctlp->outDatap;
--- 742,753 ----
  					 &volStat, &Name, &OfflineMsg, &MOTD);
  	    rx_PutConnection(callp);
  
! 	} while (cm_Analyze(connp, userp, reqp, &scp->fid, NULL, NULL, NULL, code));
! 	code = cm_MapRPCError(code, reqp);
      }
  
!     if (code) 
!         return code;
  
      /* Copy all this junk into msg->im_data, keeping track of the lengths. */
      cp = ioctlp->outDatap;
***************
*** 1048,1071 ****
      return 0;
  }
  
! long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_scache_t *scp;
!     register long code;
!     register char *cp;
      cm_fid_t fid;
-     cm_req_t req;
-     cm_ioctlQueryOptions_t * optionsp;
-     afs_uint32 flags = 0;
- 
-     cm_InitReq(&req);
- 
-     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
- 
-     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-     if (code) return code;
  
      memset(&fid, 0, sizeof(cm_fid_t));
      fid.cell   = scp->fid.cell;
--- 766,782 ----
      return 0;
  }
  
! /* 
!  * VIOCGETFID internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlGetFid(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     char *cp;
      cm_fid_t fid;
  
      memset(&fid, 0, sizeof(cm_fid_t));
      fid.cell   = scp->fid.cell;
***************
*** 1073,1080 ****
      fid.vnode  = scp->fid.vnode;
      fid.unique = scp->fid.unique;
  
-     cm_ReleaseSCache(scp);
- 
      /* Copy all this junk into msg->im_data, keeping track of the lengths. */
      cp = ioctlp->outDatap;
      memcpy(cp, (char *)&fid, sizeof(cm_fid_t));
--- 784,789 ----
***************
*** 1086,1213 ****
      return 0;
  }
  
! long cm_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_scache_t *scp;
!     register long code;
!     register char *cp;
      afs_uint32 fileType = 0;
-     cm_req_t req;
-     cm_ioctlQueryOptions_t * optionsp;
-     afs_uint32 flags = 0;
- 
-     cm_InitReq(&req);
- 
-     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
- 
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-         cm_fid_t fid;
-         cm_SkipIoctlPath(ioctlp);
-         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                   optionsp->fid.vnode, optionsp->fid.unique);
-         code = cm_GetSCache(&fid, &scp, userp, &req);
-     } else {
-         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-     }
-     if (code) 
-         return code;
  
!     fileType = scp->fileType;
!     cm_ReleaseSCache(scp);
  
!     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
!     cp = ioctlp->outDatap;
!     memcpy(cp, (char *)&fileType, sizeof(fileType));
!     cp += sizeof(fileType);
  
!     /* return new size */
!     ioctlp->outDatap = cp;
  
!     return 0;
  }
  
! long cm_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     cm_scache_t *scp;
!     register long code;
!     register char *cp;
!     cm_req_t req;
!     cm_ioctlQueryOptions_t *optionsp;
!     afs_uint32 flags = 0;
! 
!     cm_InitReq(&req);
! 
!     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
!     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
!         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
! 
!     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
!         cm_fid_t fid;
!         cm_SkipIoctlPath(ioctlp);
!         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
!                   optionsp->fid.vnode, optionsp->fid.unique);
!         code = cm_GetSCache(&fid, &scp, userp, &req);
!     } else {
!         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
!     }
!     if (code) 
!         return code;
! 
!     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
!     cp = ioctlp->outDatap;
!     memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
!     cp += sizeof(afs_uint32);
!     memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
!     cp += sizeof(afs_uint32);
  
!     /* return new size */
!     ioctlp->outDatap = cp;
  
!     cm_ReleaseSCache(scp);
  
!     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_ioctlQueryOptions_t *optionsp;
-     afs_uint32 flags = 0;
- 
-     cm_InitReq(&req);
- 
-     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
- 
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-         cm_fid_t fid;
-         cm_SkipIoctlPath(ioctlp);
-         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                   optionsp->fid.vnode, optionsp->fid.unique);
-         code = cm_GetSCache(&fid, &scp, userp, &req);
-     } else {
-         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-     }
-     if (code) 
-         return code;
  
      volume = scp->fid.volume;
  
      cellp = cm_FindCellByID(scp->fid.cell, 0);
  
-     cm_ReleaseSCache(scp);
- 
      if (!cellp)
  	return CM_ERROR_NOSUCHCELL;
  
--- 795,891 ----
      return 0;
  }
  
! /* 
!  * VIOC_GETFILETYPE internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlGetFileType(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code = 0;
!     char *cp;
      afs_uint32 fileType = 0;
  
!     if (scp->fileType == 0) {
!         lock_ObtainWrite(&scp->rw);
!         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
!                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!         if (code == 0)
!             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!         lock_ReleaseWrite(&scp->rw);
!     }
  
!     if (code == 0) {
!         fileType = scp->fileType;
  
!         /* Copy all this junk into msg->im_data, keeping track of the lengths. */
!         cp = ioctlp->outDatap;
!         memcpy(cp, (char *)&fileType, sizeof(fileType));
!         cp += sizeof(fileType);
  
!         /* return new size */
!         ioctlp->outDatap = cp;
!     }
!     return code;
  }
  
! /* 
!  * VIOCGETOWNER internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlGetOwner(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code = 0;
!     char *cp;
  
!     lock_ObtainWrite(&scp->rw);
!     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (code == 0)
!         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     lock_ReleaseWrite(&scp->rw);
  
!     if (code == 0) {
!         /* Copy all this junk into msg->im_data, keeping track of the lengths. */
!         cp = ioctlp->outDatap;
!         memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
!         cp += sizeof(afs_uint32);
!         memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
!         cp += sizeof(afs_uint32);
  
!         /* return new size */
!         ioctlp->outDatap = cp;
!     }
!     return code;
  }
  
! 
! /* 
!  * VIOCWHEREIS internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlWhereIs(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_cell_t *cellp;
      cm_volume_t *tvp;
      cm_serverRef_t **tsrpp, *current;
      cm_server_t *tsp;
!     afs_uint32 volume;
      char *cp;
  
      volume = scp->fid.volume;
  
      cellp = cm_FindCellByID(scp->fid.cell, 0);
  
      if (!cellp)
  	return CM_ERROR_NOSUCHCELL;
  
***************
*** 1234,1240 ****
      } else 
  #endif
      {
!         code = cm_FindVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
          if (code) 
              return code;
  	
--- 912,918 ----
      } else 
  #endif
      {
!         code = cm_FindVolumeByID(cellp, volume, userp, reqp, CM_GETVOL_FLAG_CREATE, &tvp);
          if (code) 
              return code;
  	
***************
*** 1261,1331 ****
      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(&req);
! 
!     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
!     if (code) return code;
  
!     cp = ioctlp->inDatap;
  
-     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
-     cm_ReleaseSCache(dscp);
-     if (code) return code;
-         
      lock_ObtainWrite(&scp->rw);
  
      /* now check that this is a real mount point */
      if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
!         lock_ReleaseWrite(&scp->rw);
!         cm_ReleaseSCache(scp);
!         return CM_ERROR_INVAL;
      }
  
!     code = cm_ReadMountPoint(scp, userp, &req);
      if (code == 0) {
!         cp = ioctlp->outDatap;
!         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
!         cp += strlen(cp) + 1;
!         ioctlp->outDatap = cp;
      }
      lock_ReleaseWrite(&scp->rw);
      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(&req);
  
!     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
!     if (code) return code;
  
!     cp = ioctlp->inDatap;
! 
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
          
      /* if something went wrong, bail out now */
      if (code)
          goto done3;
          
      lock_ObtainWrite(&scp->rw);
!     code = cm_SyncOp(scp, NULL, userp, &req, 0,
!                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
      if (code)  
          goto done2;
  
--- 939,1022 ----
      return 0;
  }       
  
! /* 
!  * VIOC_AFS_STAT_MT_PT internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlStatMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_scache_t *scp;
!     clientchar_t *cp;
  
!     cp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
!     if (code) 
!         goto done_2;
  
      lock_ObtainWrite(&scp->rw);
+     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+     if (code == 0)
+         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+     else
+         goto done;
  
      /* now check that this is a real mount point */
      if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
!         code = CM_ERROR_INVAL;
!         goto done;
      }
  
!     code = cm_ReadMountPoint(scp, userp, reqp);
      if (code == 0) {
!         char * strp;
!         strp = ioctlp->outDatap;
!         StringCbCopyA(strp, SMB_IOCTL_MAXDATA - (strp - ioctlp->outAllocp), scp->mountPointStringp);
!         strp += strlen(strp) + 1;
!         ioctlp->outDatap = strp;
      }
+ 
+   done:
      lock_ReleaseWrite(&scp->rw);
      cm_ReleaseSCache(scp);
  
+  done_2:
+     if (cp)
+         free(cp);
+ 
      return code;
  }       
  
! /* 
!  * VIOC_AFS_DELETE_MT_PT internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32 
! cm_IoctlDeleteMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_scache_t *scp;
!     clientchar_t *cp = NULL;
!     fschar_t *originalName = NULL;
!     cm_dirOp_t dirop;
  
!     cp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
  
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
          
      /* if something went wrong, bail out now */
      if (code)
          goto done3;
          
      lock_ObtainWrite(&scp->rw);
!     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
!                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
      if (code)  
          goto done2;
  
***************
*** 1338,1359 ****
      /* time to make the RPC, so drop the lock */
      lock_ReleaseWrite(&scp->rw);
  
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
!         /* we are adding the mount point to the root dir., so call
!          * the freelance code to do the add. */
          osi_Log0(afsd_logp,"IoctlDeleteMountPoint from Freelance root dir");
!         code = cm_FreelanceRemoveMount(cp);
      } else 
  #endif
      {
          /* easier to do it this way */
!         code = cm_Unlink(dscp, cp, userp, &req);
      }
      if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
          smb_NotifyChange(FILE_ACTION_REMOVED,
!                           FILE_NOTIFY_CHANGE_DIR_NAME,
!                           dscp, cp, NULL, TRUE);
  
      lock_ObtainWrite(&scp->rw);
    done1:
--- 1029,1071 ----
      /* time to make the RPC, so drop the lock */
      lock_ReleaseWrite(&scp->rw);
  
+ #ifdef USE_BPLUS
+     code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+     if (code == 0) {
+         code = cm_BPlusDirLookupOriginalName(&dirop, cp, &originalName);
+         /* The cm_Dir* functions can't be used to lookup the
+            originalName.  Those functions only know of the original
+            name. */
+         cm_EndDirOp(&dirop);
+     }
+ #endif
+ 
+     /* If this name doesn't have a non-normalized name associated with
+        it, we assume that what we had is what is actually present on
+        the file server. */
+ 
+     if (originalName == NULL) {
+         originalName = cm_ClientStringToFsStringAlloc(cp, -1, NULL);
+     }
+ 
+     /* cp is a normalized name.  originalName is the actual name we
+        saw on the fileserver. */
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
!         /* we are removing the mount point to the root dir., so call
!          * the freelance code to do the deletion. */
          osi_Log0(afsd_logp,"IoctlDeleteMountPoint from Freelance root dir");
!         code = cm_FreelanceRemoveMount(originalName);
      } else 
  #endif
      {
          /* easier to do it this way */
!         code = cm_Unlink(dscp, originalName, cp, userp, reqp);
      }
      if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
          smb_NotifyChange(FILE_ACTION_REMOVED,
!                          FILE_NOTIFY_CHANGE_DIR_NAME,
!                          dscp, cp, NULL, TRUE);
  
      lock_ObtainWrite(&scp->rw);
    done1:
***************
*** 1365,1375 ****
      cm_ReleaseSCache(scp);
  
    done3:
!     cm_ReleaseSCache(dscp);
      return code;
  }
  
! long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_cell_t *cellp;
      chservinfo_t csi;
--- 1077,1098 ----
      cm_ReleaseSCache(scp);
  
    done3:
!     if (originalName != NULL)
!         free(originalName);
! 
!     if (cp != NULL)
!         free(cp);
! 
      return code;
  }
  
! /* 
!  * VIOCCKSERV internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlCheckServers(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_cell_t *cellp;
      chservinfo_t csi;
***************
*** 1379,1385 ****
      cm_server_t *tsp;
      int haveCell;
          
-     cm_SkipIoctlPath(ioctlp);	/* we don't care about the path */
      tp = ioctlp->inDatap;
      haveCell = 0;
  
--- 1102,1107 ----
***************
*** 1406,1412 ****
          ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
          if (cp - ioctlp->inAllocp < ioctlp->inCopied)	/* still more data available */
              haveCell = 1;
!     }       
  
      /* 
       * 1: fast check, don't contact servers.
--- 1128,1134 ----
          ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
          if (cp - ioctlp->inAllocp < ioctlp->inCopied)	/* still more data available */
              haveCell = 1;
!     }
  
      /* 
       * 1: fast check, don't contact servers.
***************
*** 1418,1441 ****
          if (!cellp) 
              return CM_ERROR_NOSUCHCELL;
      }
!     else cellp = (cm_cell_t *) 0;
      if (!cellp && (temp & 2)) {
          /* use local cell */
!         cellp = cm_FindCellByID(1, 0);
      }
      if (!(temp & 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->outDatap;
      lock_ObtainRead(&cm_serverLock);
      for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
!         if (cellp && tsp->cellp != cellp) continue;	/* cell spec'd and wrong */
          if ((tsp->flags & CM_SERVERFLAG_DOWN)
!              && tsp->type == CM_SERVER_FILE) {
              memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
              cp += sizeof(long);
          }
--- 1140,1166 ----
          if (!cellp) 
              return CM_ERROR_NOSUCHCELL;
      }
!     else 
!         cellp = (cm_cell_t *) 0;
      if (!cellp && (temp & 2)) {
          /* use local cell */
!         fschar_t wscell[CELL_MAXNAMELEN+1];
!         cm_GetRootCellName(wscell);
!         cellp = cm_GetCell(wscell, 0);
      }
      if (!(temp & 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->outDatap;
      lock_ObtainRead(&cm_serverLock);
      for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
!         if (cellp && tsp->cellp != cellp) 
!             continue;	/* cell spec'd and wrong */
          if ((tsp->flags & CM_SERVERFLAG_DOWN)
!             && tsp->type == CM_SERVER_FILE) {
              memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
              cp += sizeof(long);
          }
***************
*** 1446,1469 ****
      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_RefreshVolumes();
      return 0;
  }       
  
! long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      afs_uint64 temp;
-     long code;
- 
-     cm_SkipIoctlPath(ioctlp);
  
      memcpy(&temp, ioctlp->inDatap, sizeof(temp));
      if (temp == 0) 
--- 1171,1202 ----
      return 0;
  }
  
! /* 
!  * VIOCCKBACK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlCheckVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp)
  {
      cm_RefreshVolumes();
      return 0;
  }       
  
! /* 
!  * VIOCSETCACHESIZE internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  *
!  * This function is no longer meaningful in the current day world
!  * of persistent caches.  The buf_SetNBuffers() function will
!  * inevitably fail.
!  */
! afs_int32 
! cm_IoctlSetCacheSize(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
+     afs_int32 code;
      afs_uint64 temp;
  
      memcpy(&temp, ioctlp->inDatap, sizeof(temp));
      if (temp == 0) 
***************
*** 1479,1491 ****
      return code;
  }
  
! long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long inValue;
!         
!     cm_SkipIoctlPath(ioctlp);
!         
!     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
  
      /* print trace */
      if (inValue & 8) {
--- 1212,1228 ----
      return code;
  }
  
! /* 
!  * VIOC_TRACECTL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlTraceControl(cm_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     afs_uint32 inValue;
! 
!     memcpy(&inValue, ioctlp->inDatap, sizeof(afs_uint32));
  
      /* print trace */
      if (inValue & 8) {
***************
*** 1514,1525 ****
  
      /* and copy out tracing flag */
      inValue = afsd_logp->enabled;	/* use as a temp vbl */
!     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
!     ioctlp->outDatap += sizeof(long);
      return 0;
  }       
  
! long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_cacheParms_t parms;
  
--- 1251,1268 ----
  
      /* and copy out tracing flag */
      inValue = afsd_logp->enabled;	/* use as a temp vbl */
!     memcpy(ioctlp->outDatap, &inValue, sizeof(afs_uint32));
!     ioctlp->outDatap += sizeof(afs_uint32);
      return 0;
  }       
  
! /* 
!  * VIOCGETCACHEPARMS internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlGetCacheParms(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_cacheParms_t parms;
  
***************
*** 1539,1545 ****
      return 0;
  }
  
! long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      long whichCell;
      long magic = 0;
--- 1282,1294 ----
      return 0;
  }
  
! /* 
!  * VIOCGETCELL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlGetCell(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      long whichCell;
      long magic = 0;
***************
*** 1551,1576 ****
      char *tp;
      char *basep;
  
-     cm_SkipIoctlPath(ioctlp);
- 
      tp = ioctlp->inDatap;
  
      memcpy((char *)&whichCell, tp, sizeof(long));
      tp += sizeof(long);
  
      /* see if more than one long passed in, ignoring the null pathname (the -1) */
!     if (ioctlp->inCopied-1 > sizeof(long)) {
!         memcpy((char *)&magic, tp, sizeof(long));
      }
  
      lock_ObtainRead(&cm_cellLock);
      for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->allNextp) {
!         if (whichCell == 0) break;
          whichCell--;
      }
      lock_ReleaseRead(&cm_cellLock);
      if (tcellp) {
          int max = 8;
  
          cp = ioctlp->outDatap;
  
--- 1300,1325 ----
      char *tp;
      char *basep;
  
      tp = ioctlp->inDatap;
  
      memcpy((char *)&whichCell, tp, sizeof(long));
      tp += sizeof(long);
  
      /* see if more than one long passed in, ignoring the null pathname (the -1) */
!     if (ioctlp->inCopied-1 > sizeof(afs_uint32)) {
!         memcpy((char *)&magic, tp, sizeof(afs_uint32));
      }
  
      lock_ObtainRead(&cm_cellLock);
      for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->allNextp) {
!         if (whichCell == 0)
!             break;
          whichCell--;
      }
      lock_ReleaseRead(&cm_cellLock);
      if (tcellp) {
          int max = 8;
+         clientchar_t * cellnamep;
  
          cp = ioctlp->outDatap;
  
***************
*** 1581,1600 ****
          memset(cp, 0, max * sizeof(long));
          basep = cp;
          lock_ObtainRead(&cm_serverLock);	/* for going down server list */
!         /* jaltman - do the reference counts to serverRefp contents need to be increased? */
!         serverRefp = tcellp->vlServersp;
!         for (i=0; i<max; i++) {
!             if (!serverRefp) break;
              serverp = serverRefp->server;
              memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
              cp += sizeof(long);
-             serverRefp = serverRefp->next;
          }
          lock_ReleaseRead(&cm_serverLock);
!         cp = basep + max * sizeof(afs_int32);
!         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), tcellp->name);
!         cp += strlen(tcellp->name)+1;
!         ioctlp->outDatap = cp;
      }
  
      if (tcellp) 
--- 1330,1348 ----
          memset(cp, 0, max * sizeof(long));
          basep = cp;
          lock_ObtainRead(&cm_serverLock);	/* for going down server list */
!         for (i=0, serverRefp = tcellp->vlServersp; 
!              serverRefp && i<max; 
!              i++, serverRefp = serverRefp->next) {
              serverp = serverRefp->server;
              memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
              cp += sizeof(long);
          }
          lock_ReleaseRead(&cm_serverLock);
!         ioctlp->outDatap = basep + max * sizeof(afs_int32);
! 
!         cellnamep = cm_FsStringToClientStringAlloc(tcellp->name, -1, NULL);
!         cm_UnparseIoctlString(ioctlp, NULL, cellnamep, -1);
!         free(cellnamep);
      }
  
      if (tcellp) 
***************
*** 1603,1613 ****
          return CM_ERROR_NOMORETOKENS;	/* mapped to EDOM */
  }
  
! long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     /* NT cache manager will read cell information from CellServDB each time
!      * cell is accessed. So, this call is necessary only if list of server for a cell 
!      * changes (or IP addresses of cell servers changes).
       * All that needs to be done is to refresh server information for all cells that 
       * are already loaded.
    
--- 1351,1366 ----
          return CM_ERROR_NOMORETOKENS;	/* mapped to EDOM */
  }
  
! 
! /* 
!  * VIOCNEWCELL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlNewCell(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
!     /* 
       * All that needs to be done is to refresh server information for all cells that 
       * are already loaded.
    
***************
*** 1617,1629 ****
      cm_cell_t *cp;
      cm_cell_rock_t rock;
  
-   
-     cm_SkipIoctlPath(ioctlp);
      lock_ObtainWrite(&cm_cellLock);
    
      for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) 
      {
!         long code;
  	lock_ObtainMutex(&cp->mx);
          /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
          cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
--- 1370,1380 ----
      cm_cell_t *cp;
      cm_cell_rock_t rock;
  
      lock_ObtainWrite(&cm_cellLock);
    
      for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) 
      {
!         afs_int32 code;
  	lock_ObtainMutex(&cp->mx);
          /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
          cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
***************
*** 1661,1705 ****
      return 0;       
  }
  
! long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
! 	long code = 0;
  
! 	if (cm_freelanceEnabled) {
!             if (cm_GetRootCellName(ioctlp->outDatap))
!                 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
!             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
! 	} else if (cm_data.rootCellp) {
! 	    /* return the default cellname to the caller */
! 	    StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cm_data.rootCellp->name);
! 	    ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
! 	} else {
! 	    /* if we don't know our default cell, return failure */
!             code = CM_ERROR_NOSUCHCELL;
!     }
  
      return code;
  }
  
! 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(&setSysName, ioctlp->inDatap, sizeof(long));
-     ioctlp->inDatap += sizeof(long);
-         
      if (setSysName) {
          /* check my args */
          if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
              return EINVAL;
          cp2 = ioctlp->inDatap;
          for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
!             /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
              t = (int)strlen(cp);
              if (t >= MAXSYSNAME || t <= 0)
                  return EINVAL;
--- 1412,1468 ----
      return 0;       
  }
  
! /* 
!  * VIOC_GET_WS_CELL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlGetWsCell(cm_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     afs_int32 code = 0;
  
!     if (cm_freelanceEnabled) {
!         if (cm_GetRootCellName(ioctlp->outDatap))
!             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
!         ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
!     } else if (cm_data.rootCellp) {
!         clientchar_t * cellnamep = cm_FsStringToClientStringAlloc(cm_data.rootCellp->name, -1, NULL);
!         /* return the default cellname to the caller */
!         cm_UnparseIoctlString(ioctlp, NULL, cellnamep, -1);
!         free(cellnamep);
!     } else {
!         /* if we don't know our default cell, return failure */
!         code = CM_ERROR_NOSUCHCELL;
!     }   
  
      return code;
  }
  
! /* 
!  * VIOC_AFS_SYSNAME internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlSysName(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
!     afs_uint32 setSysName;
!     char *cp, *cp2;
!     clientchar_t *inname = NULL;
!     int t, count;
! 
!     memcpy(&setSysName, ioctlp->inDatap, sizeof(afs_uint32));
!     ioctlp->inDatap += sizeof(afs_uint32);
  
      if (setSysName) {
          /* check my args */
          if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
              return EINVAL;
          cp2 = ioctlp->inDatap;
          for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
!             /* won't go past end of ioctlp->inDatap since
!                maxsysname*num < ioctlp->inDatap length */
              t = (int)strlen(cp);
              if (t >= MAXSYSNAME || t <= 0)
                  return EINVAL;
***************
*** 1712,1787 ****
  
          /* inname gets first entry in case we're being a translator */
          /* (we are never a translator) */
!         t = (int)strlen(ioctlp->inDatap);
!         memcpy(inname, ioctlp->inDatap, t + 1);
!         ioctlp->inDatap += t + 1;
!         num = count;
      }
  
      /* Not xlating, so local case */
      if (!cm_sysName)
          osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
  
!     if (!setSysName) {      /* user just wants the info */
!         StringCbCopyA(outname, sizeof(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, ... */
!         StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
!         StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
          if (setSysName > 1) {       /* ... or list */
-             cp = ioctlp->inDatap;
              for (count = 1; count < setSysName; ++count) {
                  if (!cm_sysNameList[count])
                      osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
!                                __FILE__, __LINE__);
!                 t = (int)strlen(cp);
!                 StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
!                 cp += t + 1;
              }
          }
          cm_sysNameCount = setSysName;
!     }
  
-     if (!setSysName) {
          /* return the sysname to the caller */
!         cp = ioctlp->outDatap;
!         memcpy(cp, (char *)&foundname, sizeof(afs_int32));
!         cp += sizeof(afs_int32);	/* skip found flag */
!         if (foundname) {
!             StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), outname);
!             cp += strlen(outname) + 1;	/* skip name and terminating null char */
!             for ( count=1; count < foundname ; ++count) {   /* ... or list */
!                 if ( !(*sysnamelist)[count] )
                      osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n", 
!                                __FILE__, __LINE__);
!                 t = (int)strlen((*sysnamelist)[count]);
!                 if (t >= MAXSYSNAME)
!                     osi_panic("cm_IoctlSysName: sysname entry garbled\n", 
!                                __FILE__, __LINE__);
!                 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), (*sysnamelist)[count]);
!                 cp += t + 1;
              }
          }
-         ioctlp->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->inDatap, 0);
      if (!cellp) 
          return CM_ERROR_NOSUCHCELL;
  
--- 1475,1556 ----
  
          /* inname gets first entry in case we're being a translator */
          /* (we are never a translator) */
!         inname = cm_ParseIoctlStringAlloc(ioctlp, NULL);
      }
  
      /* Not xlating, so local case */
      if (!cm_sysName)
          osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
  
!     if (setSysName) {
          /* 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, ... */
! 
!         cm_ClientStrCpy(cm_sysName, lengthof(cm_sysName), inname);
!         cm_ClientStrCpy(cm_sysNameList[0], MAXSYSNAME, inname);
! 
          if (setSysName > 1) {       /* ... or list */
              for (count = 1; count < setSysName; ++count) {
+                 clientchar_t * newsysname;
+ 
                  if (!cm_sysNameList[count])
                      osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
!                               __FILE__, __LINE__);
! 
!                 newsysname = cm_ParseIoctlStringAlloc(ioctlp, NULL);
!                 cm_ClientStrCpy(cm_sysNameList[count], MAXSYSNAME, newsysname);
!                 free(newsysname);
              }
          }
          cm_sysNameCount = setSysName;
!     } else {
!         afs_int32 i32;
  
          /* return the sysname to the caller */
!         i32 = cm_sysNameCount;
!         memcpy(ioctlp->outDatap, &i32, sizeof(afs_int32));
!         ioctlp->outDatap += sizeof(afs_int32);	/* skip found flag */
! 
!         if (cm_sysNameCount) {
!             for ( count=0; count < cm_sysNameCount ; ++count) {   /* ... or list */
!                 if ( !cm_sysNameList[count] || *cm_sysNameList[count] == _C('\0'))
                      osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n", 
!                               __FILE__, __LINE__);
!                 cm_UnparseIoctlString(ioctlp, NULL, cm_sysNameList[count], -1);
              }
          }
      }
! 
!     if (inname) {
!         free(inname);
!         inname = NULL;
!     }
! 
      /* done: success */
      return 0;
  }
  
! /* 
!  * VIOC_GETCELLSTATUS internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlGetCellStatus(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
!     afs_uint32 temp;
      cm_cell_t *cellp;
+     clientchar_t * cellnamep;
+     fschar_t     * fscellnamep;
  
!     cellnamep = cm_ParseIoctlStringAlloc(ioctlp, NULL);
!     fscellnamep = cm_ClientStringToFsStringAlloc(cellnamep, -1, NULL);
!     cellp = cm_GetCell(fscellnamep, 0);
!     free(fscellnamep);
!     free(cellnamep);
  
      if (!cellp) 
          return CM_ERROR_NOSUCHCELL;
  
***************
*** 1790,1818 ****
      if (cellp->flags & CM_CELLFLAG_SUID)
          temp |= CM_SETCELLFLAG_SUID;
      lock_ReleaseMutex(&cellp->mx);
!         
      /* now copy out parm */
!     memcpy(ioctlp->outDatap, &temp, sizeof(long));
!     ioctlp->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->inDatap + 2*sizeof(long), 0);
      if (!cellp) 
          return CM_ERROR_NOSUCHCELL;
  
!     memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
  
      lock_ObtainMutex(&cellp->mx);
!     if (temp & CM_SETCELLFLAG_SUID)
          cellp->flags |= CM_CELLFLAG_SUID;
      else
          cellp->flags &= ~CM_CELLFLAG_SUID;
--- 1559,1598 ----
      if (cellp->flags & CM_CELLFLAG_SUID)
          temp |= CM_SETCELLFLAG_SUID;
      lock_ReleaseMutex(&cellp->mx);
! 
      /* now copy out parm */
!     memcpy(ioctlp->outDatap, &temp, sizeof(afs_uint32));
!     ioctlp->outDatap += sizeof(afs_uint32);
  
      return 0;
  }
  
! /* 
!  * VIOC_SETCELLSTATUS internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlSetCellStatus(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
!     afs_uint32 flags;
      cm_cell_t *cellp;
+     clientchar_t *temp;
+     fschar_t * cellnamep;
  
!     temp = cm_ParseIoctlStringAlloc(ioctlp, ioctlp->inDatap + 2*sizeof(afs_uint32));
!     cellnamep = cm_ClientStringToFsStringAlloc(temp, -1, NULL);
!     cellp = cm_GetCell(cellnamep, 0);
!     free(temp);
!     free(cellnamep);
  
      if (!cellp) 
          return CM_ERROR_NOSUCHCELL;
  
!     memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_uint32));
  
      lock_ObtainMutex(&cellp->mx);
!     if (flags & CM_SETCELLFLAG_SUID)
          cellp->flags |= CM_CELLFLAG_SUID;
      else
          cellp->flags &= ~CM_CELLFLAG_SUID;
***************
*** 1821,1836 ****
      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->inDatap;
      noServers  = spin->num_servers;
--- 1601,1620 ----
      return 0;
  }
  
! /* 
!  * VIOC_SETSPREFS internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32 
! cm_IoctlSetSPrefs(struct cm_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;
  
      spin	   = (cm_SSetPref_t *)ioctlp->inDatap;
      noServers  = spin->num_servers;
***************
*** 1879,1885 ****
      return 0;
  }
  
! long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_SPrefRequest_t *spin; /* input */
      cm_SPrefInfo_t    *spout;   /* output */
--- 1663,1675 ----
      return 0;
  }
  
! /* 
!  * VIOC_GETSPREFS internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlGetSPrefs(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_SPrefRequest_t *spin; /* input */
      cm_SPrefInfo_t    *spout;   /* output */
***************
*** 1887,1894 ****
      cm_server_t       *tsp;
      int 		  i, vlonly, noServers;
  
-     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
- 
      spin      = (cm_SPrefRequest_t *)ioctlp->inDatap;
      spout     = (cm_SPrefInfo_t *) ioctlp->outDatap;
      srvout    = spout->servers;
--- 1677,1682 ----
***************
*** 1925,2000 ****
      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[LEAF_SIZE];
!     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(&req);
!         
!     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
!     if (code) 
!         return code;
! 
!     /* Translate chars for the mount point name */
!     TranslateExtendedChars(leaf);
! 
!     /* 
       * The fs command allows the user to specify partial cell names on NT.  These must
       * be expanded to the full cell name for mount points so that the mount points will
       * work on UNIX clients.
       */
  
      /* Extract the possibly partial cell name */
!     StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1);      /* Skip the mp type character */
!         
!     if (cp = strchr(cell, ':')) {
          /* Extract the volume name */
          *cp = 0;
!         StringCbCopyA(volume,  sizeof(volume), cp + 1);
! 	
          /* Get the full name for this cell */
!         code = cm_SearchCellFile(cell, fullCell, 0, 0);
  #ifdef AFS_AFSDB_ENV
          if (code && cm_dnsEnabled)
!             code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
  #endif
          if (code) {
!             cm_ReleaseSCache(dscp);
!             return CM_ERROR_NOSUCHCELL;
          }
! 	
!         StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
      } else {
!         /* No cell name specified */
!         StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
      }
  
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.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->inDatap == '%', NULL);
!     } else 
  #endif
      {
          /* create the symlink with mode 644.  The lack of X bits tells
--- 1713,1787 ----
      return 0;
  }
  
  
! /* 
!  * VIOC_AFS_CREATE_MT_PT internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * dscp is held but not locked.
!  */
! afs_int32
! cm_IoctlCreateMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp, clientchar_t *leaf)
  {
!     afs_int32 code;
      cm_attr_t tattr;
!     clientchar_t *cp;
!     fschar_t mpInfo[512];           /* mount point string */
!     fschar_t fullCell[MAXCELLCHARS];
!     fschar_t *fscell = NULL;
!     fschar_t *fsvolume = NULL;
!     clientchar_t volume[VL_MAXNAMELEN];
!     clientchar_t *mpp = NULL;
!     clientchar_t *cell = NULL;
      int ttl;
  
!    /* 
       * The fs command allows the user to specify partial cell names on NT.  These must
       * be expanded to the full cell name for mount points so that the mount points will
       * work on UNIX clients.
       */
  
      /* Extract the possibly partial cell name */
!     mpp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
!     cell = cm_ClientCharNext(mpp);
!     if (cp = cm_ClientStrChr(cell, ':')) {
! 
          /* Extract the volume name */
          *cp = 0;
!         cm_ClientStrCpy(volume, lengthof(volume), cm_ClientCharNext(cp));
! 
!         fscell = cm_ClientStringToFsStringAlloc(cell, -1, NULL);
!         fsvolume = cm_ClientStringToFsStringAlloc(volume, -1, NULL);
! 
          /* Get the full name for this cell */
!         code = cm_SearchCellFile(fscell, fullCell, 0, 0);
  #ifdef AFS_AFSDB_ENV
          if (code && cm_dnsEnabled)
!             code = cm_SearchCellByDNS(fscell, fullCell, &ttl, 0, 0);
  #endif
          if (code) {
!             code = CM_ERROR_NOSUCHCELL;
!             goto done;
          }
! 
!         StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", (char) *mpp,
!                         fullCell, fsvolume);
! 
      } else {
!         /* No cell name specified, so cell points at the volume instead. */
!         fsvolume = cm_ClientStringToFsStringAlloc(cell, -1, NULL);
!         cm_ClientStringToFsString(mpp, -1, mpInfo, lengthof(mpInfo));
      }
  
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
!         /* we are adding the mount point to the root dir, so call
           * the freelance code to do the add. */
+         fschar_t * fsleaf = cm_ClientStringToFsStringAlloc(leaf, -1, NULL);
          osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
!         code = cm_FreelanceAddMount(fsleaf, fullCell, fsvolume, *mpInfo == '%', NULL);
!         free(fsleaf);
!     } else
  #endif
      {
          /* create the symlink with mode 644.  The lack of X bits tells
***************
*** 2004,2010 ****
          tattr.unixModeBits = 0644;
          tattr.clientModTime = time(NULL);
  
!         code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
      }
      
      if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
--- 1791,1797 ----
          tattr.unixModeBits = 0644;
          tattr.clientModTime = time(NULL);
  
!         code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, reqp);
      }
      
      if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
***************
*** 2012,2047 ****
                           FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, leaf, NULL, TRUE);
  
!     cm_ReleaseSCache(dscp);
      return code;
  }
  
! long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     char leaf[LEAF_SIZE];
!     long code;
!     cm_scache_t *dscp;
      cm_attr_t tattr;
      char *cp;
!     cm_req_t req;
! 
!     cm_InitReq(&req);
! 
!     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
!     if (code) return code;
  
!     /* Translate chars for the link name */
!     TranslateExtendedChars(leaf);
! 
!     /* Translate chars for the linked to name */
!     TranslateExtendedChars(ioctlp->inDatap);
  
!     cp = ioctlp->inDatap;		/* contents of link */
  
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
          /* we are adding the symlink to the root dir., so call
           * the freelance code to do the add. */
          if (cp[0] == cp[1] && cp[1] == '\\' && 
              !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName))) 
          {
--- 1799,1843 ----
                           FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, leaf, NULL, TRUE);
  
!   done:
!     if (mpp)
!         free(mpp);
!     if (fscell)
!         free(fscell);
!     if (fsvolume)
!         free(fsvolume);
! 
      return code;
  }
  
! /* 
!  * VIOC_SYMLINK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * dscp is held but not locked.
!  */
! afs_int32 
! cm_IoctlSymlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp, clientchar_t *leaf)
  {
!     afs_int32 code;
      cm_attr_t tattr;
      char *cp;
!     char *symlp;
!     int free_syml = FALSE;
  
!     if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
!         /* Translate chars for the linked to name */
!         TranslateExtendedChars(ioctlp->inDatap);
!     }
  
!     cp = symlp = ioctlp->inDatap;		/* contents of link */
  
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
          /* we are adding the symlink to the root dir., so call
           * the freelance code to do the add. */
+         fschar_t *fsleaf;
+ 
          if (cp[0] == cp[1] && cp[1] == '\\' && 
              !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName))) 
          {
***************
*** 2052,2059 ****
                  p += 4;
              cp = p;
          }
          osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
!         code = cm_FreelanceAddSymlink(leaf, cp, NULL);
      } else
  #endif
      {
--- 1848,1858 ----
                  p += 4;
              cp = p;
          }
+ 
          osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
!         fsleaf = cm_ClientStringToFsStringAlloc(leaf, -1, NULL);
!         code = cm_FreelanceAddSymlink(fsleaf, cp, NULL);
!         free(fsleaf);
      } else
  #endif
      {
***************
*** 2061,2067 ****
          tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
          tattr.unixModeBits = 0755;
  
!         code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
      }
  
      if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
--- 1860,1866 ----
          tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
          tattr.unixModeBits = 0755;
  
!         code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, reqp);
      }
  
      if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
***************
*** 2069,2101 ****
                            FILE_NOTIFY_CHANGE_FILE_NAME
                            | FILE_NOTIFY_CHANGE_DIR_NAME,
                            dscp, leaf, NULL, TRUE);
- 
-     cm_ReleaseSCache(dscp);
- 
      return code;
  }
  
  
! 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(&req);
! 
!     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
!     if (code) return code;
  
      cp = ioctlp->inDatap;
  
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
!     cm_ReleaseSCache(dscp);
!     if (code) return code;
  
      /* Check that it's a real symlink */
      if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
--- 1868,1904 ----
                            FILE_NOTIFY_CHANGE_FILE_NAME
                            | FILE_NOTIFY_CHANGE_DIR_NAME,
                            dscp, leaf, NULL, TRUE);
      return code;
  }
  
  
! /* 
!  * VIOC_LISTSYMLINK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * dscp is held but not locked.
!  */
! afs_int32 
! cm_IoctlListlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_scache_t *scp;
      char *cp;
      cm_space_t *spacep;
      cm_scache_t *newRootScp;
!     clientchar_t *clientp;
  
+     if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
+         /* Translate chars for the link name */
+         TranslateExtendedChars(ioctlp->inDatap);
+     }
      cp = ioctlp->inDatap;
  
!     clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
!     free(clientp);
!     if (code) 
!         return code;
  
      /* Check that it's a real symlink */
      if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
***************
*** 2105,2111 ****
          return CM_ERROR_INVAL;
      }
  
!     code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
      cm_ReleaseSCache(scp);
      if (code == 0) {
          cp = ioctlp->outDatap;
--- 1908,1914 ----
          return CM_ERROR_INVAL;
      }
  
!     code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, reqp);
      cm_ReleaseSCache(scp);
      if (code == 0) {
          cp = ioctlp->outDatap;
***************
*** 2136,2160 ****
      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(&req);
! 
!     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
!     if (code) return code;
  
      cp = ioctlp->inDatap;
      osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
  
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
!     cm_ReleaseSCache(dscp);
!     if (code) return code;
  
      /* Check that it's a real symlink */
      if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
--- 1939,1970 ----
      return code;
  }
  
! /* 
!  * VIOC_ISSYMLINK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * dscp is held but not locked.
!  */
! afs_int32 
! cm_IoctlIslink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
  {/*CHECK FOR VALID SYMLINK*/
!     afs_int32 code;
      cm_scache_t *scp;
      char *cp;
!     clientchar_t *clientp;
  
+     if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
+         /* Translate chars for the link name */
+         TranslateExtendedChars(ioctlp->inDatap);
+     }
      cp = ioctlp->inDatap;
      osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
  
!     clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
!     free(clientp);
!     if (code)
!         return code;
  
      /* Check that it's a real symlink */
      if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
***************
*** 2165,2193 ****
      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(&req);
! 
!     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
!     if (code) return code;
! 
      cp = ioctlp->inDatap;
  
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
!         
      /* if something went wrong, bail out now */
      if (code)
          goto done3;
          
      lock_ObtainWrite(&scp->rw);
!     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                        CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
      if (code)
          goto done2;
--- 1975,2011 ----
      return code;
  }
  
! /* 
!  * VIOC_DELSYMLINK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * dscp is held but not locked.
!  */
! afs_int32
! cm_IoctlDeletelink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_scache_t *scp;
      char *cp;
!     char * originalName = NULL;
!     cm_dirOp_t dirop;
!     clientchar_t *clientp;
! 
!     if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
!         /* Translate chars for the link name */
!         TranslateExtendedChars(ioctlp->inDatap);
!     }
      cp = ioctlp->inDatap;
  
!     clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
! 
      /* if something went wrong, bail out now */
      if (code)
          goto done3;
          
      lock_ObtainWrite(&scp->rw);
!     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                        CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
      if (code)
          goto done2;
***************
*** 2203,2225 ****
      /* time to make the RPC, so drop the lock */
      lock_ReleaseWrite(&scp->rw);
          
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
          /* we are adding the mount point to the root dir., so call
           * the freelance code to do the add. */
          osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
!         code = cm_FreelanceRemoveSymlink(cp);
      } else 
  #endif
      {
          /* easier to do it this way */
!         code = cm_Unlink(dscp, cp, userp, &req);
      }
      if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
          smb_NotifyChange(FILE_ACTION_REMOVED,
                            FILE_NOTIFY_CHANGE_FILE_NAME
                            | FILE_NOTIFY_CHANGE_DIR_NAME,
!                           dscp, cp, NULL, TRUE);
  
      lock_ObtainWrite(&scp->rw);
    done1:
--- 2021,2070 ----
      /* time to make the RPC, so drop the lock */
      lock_ReleaseWrite(&scp->rw);
          
+ #ifdef USE_BPLUS
+     code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+     if (code == 0) {
+         code = cm_BPlusDirLookupOriginalName(&dirop, clientp, &originalName);
+         /* cm_Dir*() functions can't be used to lookup the original
+            name since those functions only know of the original
+            name. */
+         cm_EndDirOp(&dirop);
+     }
+ #endif
+ 
+     /* If this name doesn't have a non-normalized name associated with
+        it, we assume that what we had is what is actually present on
+        the file server. */
+ 
+     if (originalName == NULL)
+         originalName = cp;
+ 
+     /* cp is a normalized name.  originalName is the actual name we
+        saw on the fileserver. */
+ 
+ 
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
          /* we are adding the mount point to the root dir., so call
           * the freelance code to do the add. */
          osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
!         code = cm_FreelanceRemoveSymlink(originalName);
      } else 
  #endif
      {
          /* easier to do it this way */
!         code = cm_Unlink(dscp, originalName, clientp, userp, reqp);
      }
      if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
          smb_NotifyChange(FILE_ACTION_REMOVED,
                            FILE_NOTIFY_CHANGE_FILE_NAME
                            | FILE_NOTIFY_CHANGE_DIR_NAME,
!                           dscp, clientp, NULL, TRUE);
! 
!     if (originalName != NULL && originalName != cp) {
!         free(originalName);
!         originalName = NULL;
!     }
  
      lock_ObtainWrite(&scp->rw);
    done1:
***************
*** 2231,2242 ****
      cm_ReleaseSCache(scp);
  
    done3:
!     cm_ReleaseSCache(dscp);
      return code;
  }
  
  #ifdef QUERY_AFSID
! long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
  {
      afs_int32 code;
      namelist lnames;
--- 2076,2093 ----
      cm_ReleaseSCache(scp);
  
    done3:
!     free(clientp);
! 
      return code;
  }
  
  #ifdef QUERY_AFSID
! /* Utility function.  Not currently used.  
!  * This function performs a PTS lookup which has traditionally
!  * not been performed by the cache manager.
!  */
! afs_int32 
! cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
  {
      afs_int32 code;
      namelist lnames;
***************
*** 2292,2298 ****
  	if (*p == '@')
  	    r = p;
      }
!     if (r && !stricmp(r+1,ucellp->cellp->name))
  	*r = '\0';
  
      code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
--- 2143,2149 ----
  	if (*p == '@')
  	    r = p;
      }
!     if (r && !cm_stricmp_utf8(r+1,ucellp->cellp->name))
  	*r = '\0';
  
      code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
***************
*** 2312,2318 ****
  }
  #endif /* QUERY_AFSID */
  
! long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      char *saveDataPtr;
      char *tp;
--- 2163,2175 ----
  }
  #endif /* QUERY_AFSID */
  
! #if 0
! /* This has been copied to smb_IoctlSetToken in its entirety.
!  * An equivalent version will need to be produced for the 
!  * redirector and some extensive refactoring might be required.
!  */
! afs_int32
! cm_IoctlSetToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      char *saveDataPtr;
      char *tp;
***************
*** 2386,2397 ****
                       osi_LogSaveString(smb_logp, uname));
          }
  
! #ifndef DJGPP   /* for win95, session key is back in pioctl */
! 		/* uuid */
          memcpy(&uuid, tp, sizeof(uuid));
          if (!cm_FindTokenEvent(uuid, sessionKey))
              return CM_ERROR_INVAL;
- #endif /* !DJGPP */
      } else {
          cellp = cm_data.rootCellp;
          osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
--- 2243,2253 ----
                       osi_LogSaveString(smb_logp, uname));
          }
  
!         /* for win95, session key is back in pioctl */
!         /* uuid */
          memcpy(&uuid, tp, sizeof(uuid));
          if (!cm_FindTokenEvent(uuid, sessionKey))
              return CM_ERROR_INVAL;
      } else {
          cellp = cm_data.rootCellp;
          osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
***************
*** 2412,2418 ****
          free(ucellp->ticketp);	/* Discard old token if any */
      ucellp->ticketp = malloc(ticketLen);
      memcpy(ucellp->ticketp, ticket, ticketLen);
- #ifndef DJGPP
      /*
       * Get the session key from the RPC, rather than from the pioctl.
       */
--- 2268,2273 ----
***************
*** 2420,2429 ****
      memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
      */
      memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
- #else
-     /* for win95, we are getting the session key from the pioctl */
-     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
- #endif /* !DJGPP */
      ucellp->kvno = ct.AuthHandle;
      ucellp->expirationTime = ct.EndTimestamp;
      ucellp->gen++;
--- 2275,2280 ----
***************
*** 2440,2446 ****
      lock_ReleaseMutex(&userp->mx);
  
      if (flags & PIOCTL_LOGON) {
!         ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
      }
  
      cm_ResetACLCache(userp);
--- 2291,2297 ----
      lock_ReleaseMutex(&userp->mx);
  
      if (flags & PIOCTL_LOGON) {
!         ioctlp->flags |= CM_IOCTLFLAG_LOGON;
      }
  
      cm_ResetACLCache(userp);
***************
*** 2450,2457 ****
  
      return 0;
  }
  
! long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      char *tp, *cp;
      int iterator;
--- 2301,2315 ----
  
      return 0;
  }
+ #endif
  
! /* 
!  * VIOC_GETTOK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlGetTokenIter(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      char *tp, *cp;
      int iterator;
***************
*** 2459,2466 ****
      cm_ucell_t *ucellp;
      struct ClearToken ct;
  
-     cm_SkipIoctlPath(ioctlp);
- 
      tp = ioctlp->inDatap;
      cp = ioctlp->outDatap;
  
--- 2317,2322 ----
***************
*** 2501,2517 ****
  
      /* clear token */
      ct.AuthHandle = ucellp->kvno;
! #ifndef DJGPP
      /*
!      * Don't give out a real session key here
       */
-     /*
-     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
-     */
      memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
- #else
-     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
- #endif /* !DJGPP */
      ct.ViceId = 37;			/* XXX */
      ct.BeginTimestamp = 0;		/* XXX */
      ct.EndTimestamp = ucellp->expirationTime;
--- 2357,2370 ----
  
      /* clear token */
      ct.AuthHandle = ucellp->kvno;
! 
      /*
!      * This field is supposed to hold the session key
!      * but we don't want to make it easier for someone 
!      * to attack the cache.  The user gave us the session
!      * key in the first place.
       */
      memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
      ct.ViceId = 37;			/* XXX */
      ct.BeginTimestamp = 0;		/* XXX */
      ct.EndTimestamp = ucellp->expirationTime;
***************
*** 2538,2544 ****
      return 0;
  }
  
! long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      char *cp;
      int temp;
--- 2391,2403 ----
      return 0;
  }
  
! /* 
!  * VIOC_NEWGETTOK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlGetToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      char *cp;
      int temp;
***************
*** 2546,2556 ****
      cm_ucell_t *ucellp;
      struct ClearToken ct;
      char *tp;
- #ifndef DJGPP
      afs_uuid_t uuid;
- #endif /* !DJGPP */
- 
-     cm_SkipIoctlPath(ioctlp);
  
      tp = ioctlp->inDatap;
  
--- 2405,2411 ----
***************
*** 2562,2571 ****
          return CM_ERROR_NOSUCHCELL;
      tp += strlen(tp) + 1;
  
- #ifndef DJGPP
      /* uuid */
      memcpy(&uuid, tp, sizeof(uuid));
- #endif /* !DJGPP */
  
      lock_ObtainMutex(&userp->mx);
  
--- 2417,2424 ----
***************
*** 2590,2606 ****
  
      /* clear token */
      ct.AuthHandle = ucellp->kvno;
! #ifndef DJGPP
!     /*
!      * Don't give out a real session key here
!      */
!     /*
!     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
!     */
      memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
- #else
-     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
- #endif /* !DJGPP */
      ct.ViceId = 37;			/* XXX */
      ct.BeginTimestamp = 0;		/* XXX */
      ct.EndTimestamp = ucellp->expirationTime;
--- 2443,2451 ----
  
      /* clear token */
      ct.AuthHandle = ucellp->kvno;
! 
!     /* do not give out the session key */
      memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
      ct.ViceId = 37;			/* XXX */
      ct.BeginTimestamp = 0;		/* XXX */
      ct.EndTimestamp = ucellp->expirationTime;
***************
*** 2624,2644 ****
  
      lock_ReleaseMutex(&userp->mx);
  
- #ifndef DJGPP
      cm_RegisterNewTokenEvent(uuid, ucellp->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->outDatap;
  
      /* cell name is right here */
--- 2469,2491 ----
  
      lock_ReleaseMutex(&userp->mx);
  
      cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data);
  
      return 0;
  }
  
! /* 
!  * VIOCDELTOK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlDelToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      char *cp;
      cm_cell_t *cellp;
      cm_ucell_t *ucellp;
  
      cp = ioctlp->outDatap;
  
      /* cell name is right here */
***************
*** 2675,2681 ****
      return 0;
  }
  
! long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_ucell_t *ucellp;
  
--- 2522,2534 ----
      return 0;
  }
  
! /* 
!  * VIOCDELALLTOK internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlDelAllToken(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      cm_ucell_t *ucellp;
  
***************
*** 2704,2710 ****
      return 0;
  }
  
! long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
      char afspath[MAX_PATH];
      char *submountreqp;
--- 2557,2569 ----
      return 0;
  }
  
! /* 
!  * VIOC_MAKESUBMOUNT internals.  (This function should be deprecated)
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp)
  {
      char afspath[MAX_PATH];
      char *submountreqp;
***************
*** 2715,2722 ****
      DWORD dwIndex;
      DWORD dwSubmounts;
  
-     cm_SkipIoctlPath(ioctlp);
- 
      /* Serialize this one, to prevent simultaneous mods
       * to afsdsbmt.ini
       */
--- 2574,2579 ----
***************
*** 2725,2731 ****
      /* Parse the input parameters--first the required afs path,
       * then the requested submount name (which may be "").
       */
-     cm_NormalizeAfsPath (afspath, sizeof(afspath), ioctlp->inDatap);
      submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
  
      /* If the caller supplied a suggested submount name, see if
--- 2582,2587 ----
***************
*** 2744,2750 ****
                      NULL );
  
      if (submountreqp && *submountreqp) {
-         char submountPathNormalized[MAX_PATH];
          char submountPath[MAX_PATH];
  
          dwSize = sizeof(submountPath);
--- 2600,2605 ----
***************
*** 2776,2783 ****
           * supplied path matches the submount's path, we can still
           * use the suggested submount name.
           */
!         cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
!         if (!strcmp (submountPathNormalized, afspath)) {
              StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
              ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
              RegCloseKey( hkSubmounts );
--- 2631,2637 ----
           * supplied path matches the submount's path, we can still
           * use the suggested submount name.
           */
!         if (!strcmp (submountPath, afspath)) {
              StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
              ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
              RegCloseKey( hkSubmounts );
***************
*** 2810,2816 ****
      nextAutoSubmount = 1;
  
      for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
-         char submountPathNormalized[MAX_PATH];
          char submountPath[MAX_PATH] = "";
          DWORD submountPathLen = sizeof(submountPath);
          char submountName[MAX_PATH];
--- 2664,2669 ----
***************
*** 2845,2852 ****
           * that our caller specified. If so, we can return
           * this submount.
           */
!         cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
!         if (!strcmp (submountPathNormalized, afspath)) {
              StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountName);
              ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
              RegCloseKey(hkSubmounts);
--- 2698,2704 ----
           * that our caller specified. If so, we can return
           * this submount.
           */
!         if (!strcmp (submountPath, afspath)) {
              StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountName);
              ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
              RegCloseKey(hkSubmounts);
***************
*** 2879,2885 ****
      return 0;
  }
  
! long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
      memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
      ioctlp->outDatap += sizeof(cryptall);
--- 2731,2743 ----
      return 0;
  }
  
! /* 
!  * VIOC_GETRXKCRYPT internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlGetRxkcrypt(cm_ioctl_t *ioctlp, cm_user_t *userp)
  {
      memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
      ioctlp->outDatap += sizeof(cryptall);
***************
*** 2887,2898 ****
      return 0;
  }
  
! long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
      afs_int32 c = cryptall;
  
-     cm_SkipIoctlPath(ioctlp);
- 
      memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
  
      if (c != cryptall) {
--- 2745,2760 ----
      return 0;
  }
  
! /* 
!  * VIOC_SETRXKCRYPT internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlSetRxkcrypt(cm_ioctl_t *ioctlp, cm_user_t *userp)
  {
      afs_int32 c = cryptall;
  
      memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
  
      if (c != cryptall) {
***************
*** 2904,2916 ****
      return 0;
  }
  
! long cm_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      afs_int32 flags;
      int code = 0;
  
-     cm_SkipIoctlPath(ioctlp);
- 
      memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
      if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
          return -1;
--- 2766,2782 ----
      return 0;
  }
  
! /* 
!  * VIOC_RXSTAT_PROC internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlRxStatProcess(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      afs_int32 flags;
      int code = 0;
  
      memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
      if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
          return -1;
***************
*** 2927,2939 ****
      return 0;
  }
  
! long cm_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
      afs_int32 flags;
      int code = 0;
  
-     cm_SkipIoctlPath(ioctlp);
- 
      memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
      if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
  	return -1;
--- 2793,2809 ----
      return 0;
  }
  
! /* 
!  * VIOC_RXSTAT_PEER internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlRxStatPeer(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
      afs_int32 flags;
      int code = 0;
  
      memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
      if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
  	return -1;
***************
*** 2950,2983 ****
      return 0;
  }
  
! #ifdef DJGPP
! extern int afsd_shutdown(int);
! extern int afs_shutdown;
  
! long cm_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp) {
!   afs_shutdown = 1;   /* flag to shut down */
!   return 0;
! }
! #endif /* DJGPP */
  
! long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
! {
!   smb_user_t *uidp = ioctlp->uidp;
  
!   if (uidp && uidp->unp) {
!     memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
!     ioctlp->outDatap += strlen(uidp->unp->name);
!   }
  
!   return 0;
  }
  
! long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp)
  {
!     long cmd;
      afsUUID uuid;
  
!     memcpy(&cmd, ioctlp->inDatap, sizeof(long));
  
      if (cmd) {             /* generate a new UUID */
          UuidCreate((UUID *) &uuid);
--- 2820,2871 ----
      return 0;
  }
  
! /* 
!  * VIOC_UNICODECTL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlUnicodeControl(struct cm_ioctl *ioctlp, struct cm_user * userp)
! {
!     afs_int32 result = 0;
! #ifdef SMB_UNICODE
!     afs_uint32 cmd;
  
!     memcpy(&cmd, ioctlp->inDatap, sizeof(afs_uint32));
  
!     if (cmd & 2) {
!         /* Setting the Unicode flag */
!         LONG newflag;
! 
!         newflag = ((cmd & 1) == 1);
! 
!         InterlockedExchange(&smb_UseUnicode, newflag);
!     }
  
!     result = smb_UseUnicode;
! #else
!     result = 2;
! #endif
  
!     memcpy(ioctlp->outDatap, &result, sizeof(result));
!     ioctlp->outDatap += sizeof(result);
! 
!     return 0;
  }
  
! /* 
!  * VIOC_UUIDCTL internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlUUIDControl(struct cm_ioctl * ioctlp, struct cm_user *userp)
  {
!     afs_uint32 cmd;
      afsUUID uuid;
  
!     memcpy(&cmd, ioctlp->inDatap, sizeof(afs_uint32));
  
      if (cmd) {             /* generate a new UUID */
          UuidCreate((UUID *) &uuid);
***************
*** 2991,3007 ****
      return 0;
  }
  
  /* 
   * functions to dump contents of various structures. 
   * In debug build (linked with crt debug library) will dump allocated but not freed memory
   */
  extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
  extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
- extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
  
! long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long inValue = 0;
      HANDLE hLogFile;
      char logfileName[MAX_PATH+1];
      char *cookie;
--- 2879,2903 ----
      return 0;
  }
  
+ 
+ 
  /* 
   * functions to dump contents of various structures. 
   * In debug build (linked with crt debug library) will dump allocated but not freed memory
   */
  extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
  extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
  
! /* 
!  * VIOC_TRACEMEMDUMP internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * dscp is held but not locked.
!  */
! afs_int32
! cm_IoctlMemoryDump(struct cm_ioctl *ioctlp, struct cm_user *userp)
  {
!     afs_int32 inValue = 0;
      HANDLE hLogFile;
      char logfileName[MAX_PATH+1];
      char *cookie;
***************
*** 3011,3018 ****
      static _CrtMemState memstate;
  #endif
    
!     cm_SkipIoctlPath(ioctlp);
!     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
    
      dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
      if ( dwSize == 0 || dwSize > sizeof(logfileName) )
--- 2907,2913 ----
      static _CrtMemState memstate;
  #endif
    
!     memcpy(&inValue, ioctlp->inDatap, sizeof(afs_int32));
    
      dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
      if ( dwSize == 0 || dwSize > sizeof(logfileName) )
***************
*** 3027,3034 ****
      {
        /* error */
        inValue = -1;
!       memcpy(ioctlp->outDatap, &inValue, sizeof(long));
!       ioctlp->outDatap += sizeof(long);
        
        return 0;               
      }
--- 2922,2929 ----
      {
        /* error */
        inValue = -1;
!       memcpy(ioctlp->outDatap, &inValue, sizeof(afs_int32));
!       ioctlp->outDatap += sizeof(afs_int32);
        
        return 0;               
      }
***************
*** 3069,3079 ****
      return 0;
  }
  
! 
! static long 
  cm_CheckServersStatus(cm_serverRef_t *serversp)
  {
!     long code = 0;
      cm_serverRef_t *tsrp;
      cm_server_t *tsp;
      int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
--- 2964,2974 ----
      return 0;
  }
  
! /* Utility functon.  Not currently used. */
! static afs_int32
  cm_CheckServersStatus(cm_serverRef_t *serversp)
  {
!     afs_int32 code = 0;
      cm_serverRef_t *tsrp;
      cm_server_t *tsp;
      int someBusy = 0, someOffline = 0, allOffline = 1, allBusy = 1, allDown = 1;
***************
*** 3121,3161 ****
      return code;
  }
  
! 
! long cm_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
!     cm_scache_t *scp;
      cm_cell_t *cellp;
      cm_volume_t *tvp;
      cm_vol_state_t *statep;
      afs_uint32 volume;
-     cm_req_t req;
-     cm_ioctlQueryOptions_t *optionsp;
-     afs_uint32 flags = 0;
- 
-     cm_InitReq(&req);
- 
-     optionsp = cm_IoctlGetQueryOptions(ioctlp, userp);
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
-         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
- 
-     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
-         cm_fid_t fid;
-         cm_SkipIoctlPath(ioctlp);
-         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
-                   optionsp->fid.vnode, optionsp->fid.unique);
-         code = cm_GetSCache(&fid, &scp, userp, &req);
-     } else {
-         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-     }
-     if (code) 
-         return code;
          
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
  	code = 0;
- 	cm_ReleaseSCache(scp);
      } else
  #endif
      {
--- 3016,3039 ----
      return code;
  }
  
! /* 
!  * VIOC_PATH_AVAILABILITY internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  * scp is held but not locked.
!  */
! afs_int32
! cm_IoctlPathAvailability(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_cell_t *cellp;
      cm_volume_t *tvp;
      cm_vol_state_t *statep;
      afs_uint32 volume;
          
  #ifdef AFS_FREELANCE_CLIENT
      if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
  	code = 0;
      } else
  #endif
      {
***************
*** 3163,3174 ****
  
          cellp = cm_FindCellByID(scp->fid.cell, 0);
  
-         cm_ReleaseSCache(scp);
- 
          if (!cellp)
              return CM_ERROR_NOSUCHCELL;
  
!         code = cm_FindVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
          if (code) 
              return code;
  	
--- 3041,3050 ----
  
          cellp = cm_FindCellByID(scp->fid.cell, 0);
  
          if (!cellp)
              return CM_ERROR_NOSUCHCELL;
  
!         code = cm_FindVolumeByID(cellp, volume, userp, reqp, CM_GETVOL_FLAG_CREATE, &tvp);
          if (code) 
              return code;
  	
***************
*** 3193,3213 ****
      return code;
  }       
  
! 
! long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
  {
!     long code;
      cm_cell_t *cellp = NULL;
      cm_volume_t *volp;
      cm_vol_state_t *statep;
      struct VolStatTest * testp;
-     cm_req_t req;
      afs_uint32 n;
-     size_t len;
- 
-     cm_InitReq(&req);
  
-     cm_SkipIoctlPath(ioctlp);	/* we don't care about the path */
      testp = (struct VolStatTest *)ioctlp->inDatap;
  
  #ifdef AFS_FREELANCE_CLIENT
--- 3069,3089 ----
      return code;
  }       
  
! /* 
!  * VIOC_VOLSTAT_TEST internals.
!  * 
!  * Assumes that pioctl path has been parsed or skipped.
!  */
! afs_int32
! cm_IoctlVolStatTest(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_cell_t *cellp = NULL;
      cm_volume_t *volp;
      cm_vol_state_t *statep;
      struct VolStatTest * testp;
      afs_uint32 n;
  
      testp = (struct VolStatTest *)ioctlp->inDatap;
  
  #ifdef AFS_FREELANCE_CLIENT
***************
*** 3258,3268 ****
          if (n)
              testp->fid.volume = n;
          else
!             code = cm_FindVolumeByName(cellp, testp->volname, userp, &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
      }
  
      if (testp->fid.volume > 0)
!         code = cm_FindVolumeByID(cellp, testp->fid.volume, userp, &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
  
      if (code)
          return code;
--- 3134,3144 ----
          if (n)
              testp->fid.volume = n;
          else
!             code = cm_FindVolumeByName(cellp, testp->volname, userp, reqp, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
      }
  
      if (testp->fid.volume > 0)
!         code = cm_FindVolumeByID(cellp, testp->fid.volume, userp, reqp, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
  
      if (code)
          return code;
***************
*** 3281,3285 ****
  
      return code;
  }       
- 
- 
--- 3157,3159 ----
Index: openafs/src/WINNT/afsd/cm_ioctl.h
diff -c openafs/src/WINNT/afsd/cm_ioctl.h:1.14.2.5 openafs/src/WINNT/afsd/cm_ioctl.h:1.14.2.9
*** openafs/src/WINNT/afsd/cm_ioctl.h:1.14.2.5	Tue Jan 15 22:19:52 2008
--- openafs/src/WINNT/afsd/cm_ioctl.h	Fri Jul 11 18:27:01 2008
***************
*** 11,17 ****
  #define __CM_IOCTL_H_ENV__ 1
  
  #ifndef __CM_IOCTL_INTERFACES_ONLY__
- #include "smb.h"
  #include "cm_user.h"
  #else
  typedef struct cm_fid {
--- 11,16 ----
***************
*** 52,57 ****
--- 51,78 ----
          afs_uint64 parms[CM_IOCTLCACHEPARMS];
  } cm_cacheParms_t;
  
+ typedef struct cm_ioctl {
+     /* input side */
+     char *inDatap;			/* ioctl func's current position
+ 					 * in input parameter block */
+     char *inAllocp;			/* allocated input parameter block */
+     afs_uint32 inCopied;		/* # of input bytes copied in so far
+ 					 * by write calls */
+     /* output side */
+     char *outDatap;			/* output results assembled so far */
+     char *outAllocp;		        /* output results assembled so far */
+     afs_uint32 outCopied;		/* # of output bytes copied back so far
+ 	
+     /* flags */
+     afs_uint32 flags;
+ } cm_ioctl_t;
+ 
+ /* flags for smb_ioctl_t */
+ #define CM_IOCTLFLAG_DATAIN	1	/* reading data from client to server */
+ #define CM_IOCTLFLAG_LOGON	2	/* got tokens from integrated logon */
+ #define CM_IOCTLFLAG_USEUTF8    4       /* this request is using UTF-8 strings */
+ 
+ 
  /* 
   * The cm_IoctlQueryOptions structure is designed to be extendible.
   * None of the fields are required but when specified 
***************
*** 96,104 ****
  
  #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];
  
  /* flags for rxstats pioctl */
  
--- 117,134 ----
  
  #define MAXNUMSYSNAMES    16      /* max that current constants allow */
  #define   MAXSYSNAME      128     /* max sysname (i.e. @sys) size */
! extern clientchar_t  *cm_sysName;
  extern unsigned int   cm_sysNameCount;
! extern clientchar_t  *cm_sysNameList[MAXNUMSYSNAMES];
! 
! /* Paths that are passed into pioctl calls can be specified using
!    UTF-8.  These strings are prefixed with UTF8_PREFIX defined below.
!    The sequence ESC '%' 'G' is used by ISO-2022 to designate UTF-8
!    strings. */
! #define UTF8_PREFIX "\33%G"
! 
! extern const char utf8_prefix[];
! extern const int  utf8_prefix_size;
  
  /* flags for rxstats pioctl */
  
***************
*** 109,227 ****
  
  #ifndef __CM_IOCTL_INTERFACES_ONLY__
  
! void cm_InitIoctl(void);
  
! void cm_ResetACLCache(cm_user_t *userp);
  
! extern long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetFileCellName(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlFlushAllVolumes(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlFlushVolume(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlFlushFile(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSetVolumeStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetVolumeStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetFid(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetOwner(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlWhereIs(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlStatMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlDeleteMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlCheckServers(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGag(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlCheckVolumes(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSetCacheSize(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetCacheParms(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlNewCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSysName(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetCellStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSetCellStatus(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSetSPrefs(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetSPrefs(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlStoreBehind(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlCreateMountPoint(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
  
! extern long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
  
! extern long cm_FlushVolume(cm_user_t *, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume);
  
! extern long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
  
! extern long cm_IoctlTraceControl(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSetToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetTokenIter(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlDelToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlDelAllToken(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSymlink(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlIslink(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlListlink(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlDeletelink(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlFreemountAddCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlFreemountRemoveCell(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlMemoryDump(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlRxStatProcess(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlRxStatPeer(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlUUIDControl(struct smb_ioctl * ioctlp, struct cm_user *userp);
  
! extern long cm_IoctlPathAvailability(struct smb_ioctl * ioctlp, struct cm_user *userp);
  
! extern long cm_IoctlGetFileType(smb_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp);
  
  #endif /* __CM_IOCTL_INTERFACES_ONLY__ */
  
--- 139,276 ----
  
  #ifndef __CM_IOCTL_INTERFACES_ONLY__
  
! extern void cm_InitIoctl(void);
! 
! extern void cm_ResetACLCache(cm_user_t *userp);
! 
! extern cm_ioctlQueryOptions_t *
! cm_IoctlGetQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp);
! 
! extern void
! cm_IoctlSkipQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp);
! 
! extern void
! cm_NormalizeAfsPath(clientchar_t *outpathp, long outlen, clientchar_t *inpathp);
! 
! extern void cm_SkipIoctlPath(cm_ioctl_t *ioctlp);
! 
! extern clientchar_t * cm_ParseIoctlStringAlloc(cm_ioctl_t *ioctlp, const char * ext_instrp);
! 
! extern int cm_UnparseIoctlString(cm_ioctl_t *ioctlp, char * ext_outp, const clientchar_t * cstr, int cchlen);
! 
! extern afs_int32 cm_IoctlGetACL(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlGetFileCellName(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlSetACL(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlFlushAllVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlFlushVolume(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlFlushFile(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlSetVolumeStatus(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlGetVolumeStatus(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlGetFid(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlGetOwner(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlWhereIs(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlStatMountPoint(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlDeleteMountPoint(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlCheckServers(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGag(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlCheckVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlSetCacheSize(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGetCacheParms(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGetCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlNewCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGetWsCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlSysName(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGetCellStatus(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlSetCellStatus(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlSetSPrefs(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGetSPrefs(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlStoreBehind(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlCreateMountPoint(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp, clientchar_t *leaf);
  
! extern afs_int32 cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
  
! extern afs_int32 cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
  
! extern afs_int32 cm_FlushVolume(cm_user_t *, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume);
  
! extern afs_int32 cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlTraceControl(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlSetToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGetTokenIter(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGetToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlDelToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlDelAllToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlSymlink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp, clientchar_t *leaf);
  
! extern afs_int32 cm_IoctlIslink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlListlink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlDeletelink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlGetRxkcrypt(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlSetRxkcrypt(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlShutdown(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlFreemountAddCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlFreemountRemoveCell(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlMemoryDump(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlRxStatProcess(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlRxStatPeer(cm_ioctl_t *ioctlp, cm_user_t *userp);
  
! extern afs_int32 cm_IoctlUUIDControl(struct cm_ioctl * ioctlp, struct cm_user *userp);
  
! extern afs_int32 cm_IoctlPathAvailability(struct cm_ioctl * ioctlp, struct cm_user *userp, struct cm_scache *scp, struct cm_req *reqp);
  
! extern afs_int32 cm_IoctlGetFileType(cm_ioctl_t *ioctlp, cm_user_t *userp, struct cm_scache *scp, struct cm_req *reqp);
  
! extern afs_int32 cm_IoctlVolStatTest(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_req_t *reqp);
  
! extern afs_int32 cm_IoctlUnicodeControl(struct cm_ioctl *ioctlp, struct cm_user * userp);
  
! extern void TranslateExtendedChars(char *str);
  
  #endif /* __CM_IOCTL_INTERFACES_ONLY__ */
  
Index: openafs/src/WINNT/afsd/cm_nls.c
diff -c /dev/null openafs/src/WINNT/afsd/cm_nls.c:1.3.2.4
*** /dev/null	Fri Jul 18 12:42:42 2008
--- openafs/src/WINNT/afsd/cm_nls.c	Wed Jul 16 11:23:46 2008
***************
*** 0 ****
--- 1,1168 ----
+ /*
+  * Copyright (c) 2008 Secure Endpoints Inc.
+  *
+  * Permission is hereby granted, free of charge, to any person
+  * obtaining a copy of this software and associated documentation
+  * files (the "Software"), to deal in the Software without
+  * restriction, including without limitation the rights to use, copy,
+  * modify, merge, publish, distribute, sublicense, and/or sell copies
+  * of the Software, and to permit persons to whom the Software is
+  * furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice shall be
+  * included in all copies or substantial portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  * SOFTWARE.
+  */
+ 
+ #include <windows.h>
+ #include <stdlib.h>
+ #include <wchar.h>
+ #include <strsafe.h>
+ #include <errno.h>
+ 
+ #include "cm_nls.h"
+ 
+ #ifdef DEBUG_UNICODE
+ #include <assert.h>
+ #endif
+ 
+ /* This is part of the Microsoft Internationalized Domain Name
+    Mitigation APIs. */
+ #include <normalization.h>
+ 
+ /* TODO: All the normalization and conversion code should NUL
+    terminate destination strings. */
+ 
+ int
+ (WINAPI *pNormalizeString)( __in NORM_FORM NormForm,
+                             __in_ecount(cwSrcLength) LPCWSTR lpSrcString,
+                             __in int cwSrcLength,
+                             __out_ecount(cwDstLength) LPWSTR lpDstString,
+                             __in int cwDstLength ) = NULL;
+ 
+ BOOL
+ (WINAPI *pIsNormalizedString)( __in NORM_FORM NormForm,
+                                __in_ecount(cwLength) LPCWSTR lpString,
+                                __in int cwLength ) = NULL;
+ 
+ 
+ #define NLSDLLNAME "Normaliz.dll"
+ #define NLSMAXCCH  1024
+ #define NLSERRCCH  8
+ 
+ #define AFS_NORM_FORM NormalizationC
+ 
+ long cm_InitNormalization(void)
+ {
+     HMODULE h_Nls;
+ 
+     if (pNormalizeString != NULL)
+         return 0;
+ 
+     h_Nls = LoadLibrary(NLSDLLNAME);
+     if (h_Nls == INVALID_HANDLE_VALUE) {
+         return 1;
+     }
+ 
+     pNormalizeString =
+         (int (WINAPI *)( NORM_FORM, LPCWSTR,
+                          int, LPWSTR, int))
+         GetProcAddress(h_Nls, "NormalizeString");
+ 
+     pIsNormalizedString =
+         (BOOL
+          (WINAPI *)( NORM_FORM, LPCWSTR, int ))
+         GetProcAddress(h_Nls, "IsNormalizedString");
+ 
+     return (pNormalizeString && pIsNormalizedString);
+ }
+ 
+ /* \brief Normalize a UTF-16 string.
+ 
+    If the supplied destination buffer is insufficient or NULL, then a
+    new buffer will be allocated to hold the normalized string.
+ 
+    \param[in] src : Source UTF-16 string.  Length is specified in
+        cch_src.
+ 
+    \param[in] cch_src : The character count in cch_src is assumed to
+        be tight and include the terminating NULL character if there is
+        one.  If the NULL is absent, the resulting string will not be
+        NULL terminated.
+ 
+    \param[out] ext_dest : The destination buffer.  Can be NULL, in
+        which case *pcch_dest MUST be 0.
+ 
+    \param[in,out] pcch_dest : On entry *pcch_dest contains a count of
+        characters in the destination buffer.  On exit, it will contain
+        a count of characters that were copied to the destination
+        buffer.
+ 
+    Returns a pointer to the buffer containing the normalized string or
+    NULL if the call was unsuccessful.  If the returned destination
+    buffer is different from the supplied buffer and non-NULL, it
+    should be freed using free().
+ */
+ static wchar_t * 
+ NormalizeUtf16String(const wchar_t * src, int cch_src, wchar_t * ext_dest, int *pcch_dest)
+ {
+ #ifdef DEBUG_UNICODE
+     assert (pNormalizeString != NULL && pIsNormalizedString != NULL);
+ #endif
+ 
+     if (cch_src == -1)
+         cch_src = wcslen(src) + 1;
+ 
+     if ((pIsNormalizedString && (*pIsNormalizedString)(AFS_NORM_FORM, src, cch_src)) ||
+         (!pNormalizeString)) {
+ 
+         if (ext_dest == NULL || *pcch_dest < cch_src) {
+             ext_dest = malloc(cch_src * sizeof(wchar_t));
+             *pcch_dest = cch_src;
+         }
+ 
+         /* No need to or unable to normalize.  Just copy the string.
+            Note that the string is not NUL terminated if the source
+            string is not NUL terminated. */
+ 
+         if (ext_dest) {
+             memcpy(ext_dest, src, cch_src * sizeof(wchar_t));
+             *pcch_dest = cch_src;
+         } else {
+             *pcch_dest = 0;
+         }
+         return ext_dest;
+ 
+     } else {
+ 
+         int rv;
+         DWORD gle;
+         int tries = 10;
+         wchar_t * dest;
+         int cch_dest = *pcch_dest;
+ 
+         dest = ext_dest;
+ 
+         while (tries-- > 0) {
+ 
+             rv = (*pNormalizeString)(AFS_NORM_FORM, src, cch_src, dest, cch_dest);
+ 
+             if (rv <= 0 && (gle = GetLastError()) != ERROR_SUCCESS) {
+                 if (gle == ERROR_INSUFFICIENT_BUFFER) {
+ 
+                     /* The buffer wasn't big enough.  We are going to
+                        try allocating one. */
+ 
+                     cch_dest = (-rv) + NLSERRCCH;
+                     goto cont;
+ 
+                 } else {
+                     /* Something else is wrong */
+                     break;
+                 }
+ 
+             } else if (rv < 0) { /* rv < 0 && gle == ERROR_SUCCESS */
+ 
+                 /* Technically not one of the expected outcomes */
+                 break;
+ 
+             } else {            /* rv > 0 || (rv == 0 && gle == ERROR_SUCCESS) */
+ 
+                 /* Possibly succeeded */
+ 
+                 if (rv == 0) { /* Succeeded and the return string is empty */
+                     *pcch_dest = 0;
+                     return dest;
+                 }
+ 
+                 if (cch_dest == 0) {
+                     /* Nope.  We only calculated the required size of the buffer */
+ 
+                     cch_dest = rv + NLSERRCCH;
+                     goto cont;
+                 }
+ 
+                 *pcch_dest = rv;
+                 if (cch_dest > rv)
+                     dest[rv] = 0;
+                 else {
+                     /* Can't NUL terminate */
+                     cch_dest = max(rv,cch_dest) + NLSERRCCH;
+                     goto cont;
+                 }
+ 
+                 /* Success! */
+                 return dest;
+             }
+ 
+         cont:
+             if (dest != ext_dest && dest)
+                 free(dest);
+             dest = malloc(cch_dest * sizeof(wchar_t));
+         }
+ 
+         /* Failed */
+ 
+         if (dest != ext_dest && dest)
+             free(dest);
+ 
+         *pcch_dest = 0;
+         return NULL;
+     }
+ }
+ 
+ /*! \brief Normalize a Unicode string into a newly allocated buffer
+ 
+   The input string will be normalized using NFC.
+ 
+   \param[in] s UTF-16 string to be normalized.
+ 
+   \param[in] cch_src The number of characters in the input string.  If
+       this is -1, then the input string is assumed to be NUL
+       terminated.
+ 
+   \param[out] pcch_dest Receives the number of characters copied to
+       the output buffer.  Note that the character count is the number
+       of wchar_t characters copied, and not the count of Unicode code
+       points.  This includes the terminating NUL if cch_src was -1 or
+       included the terminating NUL.
+ 
+   \return A newly allocated buffer holding the normalized string or
+       NULL if the call failed.
+  */
+ cm_normchar_t * cm_NormalizeStringAlloc(const cm_unichar_t * s, int cch_src, int *pcch_dest)
+ {
+     int cch_dest = 0;
+     cm_normchar_t * r;
+ 
+     if (s == NULL || cch_src == 0 || *s == L'\0') {
+         if (pcch_dest)
+             *pcch_dest = ((cch_src != 0)? 1: 0);
+         return wcsdup(L"");
+     }
+ 
+     r = NormalizeUtf16String(s, cch_src, NULL, &cch_dest);
+ 
+     if (pcch_dest)
+         *pcch_dest = cch_dest;
+ 
+     return r;
+ }
+ 
+ int cm_NormalizeString(const cm_unichar_t * s, int cch_src,
+                        cm_normchar_t * dest, int cch_dest)
+ {
+     int tcch = cch_dest;
+     cm_normchar_t * r;
+ 
+     r = NormalizeUtf16String(s, cch_src, dest, &tcch);
+ 
+     if (r != dest) {
+         /* The supplied buffer was insufficient */
+         free(r);
+         return 0;
+     } else {
+         return tcch;
+     }
+ }
+ 
+ /*! \brief Convert a UTF-16 string to a UTF-8 string using a newly allocated buffer
+ 
+   \param[in] s UTF-16 source string
+ 
+   \param[in] cch_src Number of characters in \a s. This can be set to
+       -1 if \a s is NUL terminated.
+ 
+   \param[out] pcch_dest Receives a count of characters that were
+       copied to the target buffer.
+ 
+   \return A newly allocated buffer holding the UTF-8 string.
+ 
+  */
+ cm_utf8char_t * cm_Utf16ToUtf8Alloc(const cm_unichar_t * s, int cch_src, int *pcch_dest)
+ {
+     int cch_dest;
+     cm_utf8char_t * dest;
+ 
+     if (s == NULL || cch_src == 0 || *s == L'\0') {
+         if (pcch_dest)
+             *pcch_dest = ((cch_src != 0)?1:0);
+         return strdup("");
+     }
+ 
+     cch_dest = WideCharToMultiByte(CP_UTF8, 0, s, cch_src, NULL, 0, NULL, FALSE);
+ 
+     if (cch_dest == 0) {
+         if (pcch_dest)
+             *pcch_dest = cch_dest;
+         return NULL;
+     }
+ 
+     dest = malloc((cch_dest + 1) * sizeof(cm_utf8char_t));
+ 
+     WideCharToMultiByte(CP_UTF8, 0, s, cch_src, dest, cch_dest, NULL, FALSE);
+     dest[cch_dest] = 0;
+ 
+     if (pcch_dest)
+         *pcch_dest = cch_dest;
+ 
+     return dest;
+ }
+ 
+ int cm_Utf16ToUtf8(const cm_unichar_t * src, int cch_src,
+                    cm_utf8char_t * dest, int cch_dest)
+ {
+     return WideCharToMultiByte(CP_UTF8, 0, src, cch_src, dest, cch_dest, NULL, FALSE);
+ }
+ 
+ int cm_Utf16ToUtf16(const cm_unichar_t * src, int cch_src,
+                     cm_unichar_t * dest, int cch_dest)
+ {
+     if (cch_src == -1) {
+         StringCchCopyW(dest, cch_dest, src);
+         return wcslen(dest) + 1;
+     } else {
+         int cch_conv = min(cch_src, cch_dest);
+         memcpy(dest, src, cch_conv * sizeof(cm_unichar_t));
+         return cch_conv;
+     }
+ }
+ 
+ /* \brief Normalize a UTF-16 string into a UTF-8 string.
+ 
+    \param[in] src : Source string.
+ 
+    \param[in] cch_src : Count of characters in src. If the count includes the
+        NULL terminator, then the resulting string will be NULL
+        terminated.  If it is -1, then src is assumed to be NULL
+        terminated.
+ 
+    \param[out] adest : Destination buffer.
+ 
+    \param[in] cch_adest : Number of characters in the destination buffer.
+ 
+    Returns the number of characters stored into cch_adest. This will
+    include the terminating NULL if cch_src included the terminating
+    NULL or was -1.  If this is 0, then the operation was unsuccessful.
+  */
+ long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
+                                    char * adest, int cch_adest)
+ {
+     if (cch_src < 0) {
+         size_t cch;
+ 
+         if (FAILED(StringCchLengthW(src, NLSMAXCCH, &cch)))
+             return E2BIG;
+ 
+         cch_src = cch+1;
+     }
+ 
+     {
+         wchar_t nbuf[NLSMAXCCH];
+         wchar_t * normalized;
+         int cch_norm = NLSMAXCCH;
+ 
+         normalized = NormalizeUtf16String(src, cch_src, nbuf, &cch_norm);
+         if (normalized) {
+             cch_adest = WideCharToMultiByte(CP_UTF8, 0, normalized, cch_norm,
+                                             adest, cch_adest, NULL, 0);
+ 
+             if (normalized != nbuf && normalized)
+                 free(normalized);
+ 
+             return cch_adest;
+ 
+         } else {
+ 
+             return 0;
+ 
+         }
+     }
+ }
+ 
+ #define ESCVAL 0x1000
+ #define Esc(c) (ESCVAL + (short)(c))
+ #define IS_ESCAPED(c) (((c) & ESCVAL) == ESCVAL)
+ 
+ /* \brief Character sanitization map for CP-1252
+ 
+    The following map indicates which characters should be escaped in
+    the CP-1252 character map.  Characters that are documented as
+    illegal characters in a file name are marked as escaped.  Escaped
+    characters are marked using the ::Esc macro defined above.  The
+    following exceptions apply:
+ 
+    - Path delimeters '\\' and '/' are NOT escaped because the
+      sanitization map applies to paths.  While those characters are
+      illegal in filenames, they are legal in paths.
+ 
+    - Wildcard characters '*' and '?' ARE escaped.  The document
+      referred below does not specify these characters as invalid.
+      Since no other escape mechanism exists, names containing
+      wildcards are indistinguishable from actual wildcards used in SMB
+      requests.
+ 
+    - Reserved names are not and cannot be represented in this map.
+      Reserved names are :
+ 
+      CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7,
+      COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9,
+      CLOCK$
+ 
+    - Characters 0x80, 0x81, 0x8d, 0x8e, 0x8f, 0x90, 0x9d, 0x9e, 0x9f
+      are also escaped because they are unused in CP-1252 and hence
+      cannot be convered to a Unicode string.
+ 
+      Reserved names with extensions are also invalid. (i.e. NUL.txt)
+ 
+    \note The only bit we are actually interested in from the following
+      table is the ESCVAL bit.  However, the characters themselves are
+      included for ease of maintenance.
+ 
+    \see "Naming a File" topic in the Windows SDK.
+  */
+ static const short sanitized_escapes_1252[] = {
+     Esc(0x00),Esc(0x01),Esc(0x02),Esc(0x03),Esc(0x04),Esc(0x05),Esc(0x06),Esc(0x07),
+     Esc(0x08),Esc(0x09),Esc(0x0a),Esc(0x0b),Esc(0x0c),Esc(0x0d),Esc(0x0e),Esc(0x0f),
+     Esc(0x10),Esc(0x11),Esc(0x12),Esc(0x13),Esc(0x14),Esc(0x15),Esc(0x16),Esc(0x17),
+     Esc(0x18),Esc(0x19),Esc(0x1a),Esc(0x1b),Esc(0x1c),Esc(0x1d),Esc(0x1e),Esc(0x1f),
+     ' ','!',Esc('"'),'#','$','%','&','\'','(',')',Esc('*'),'+',',','-','.','/',
+     '0','1','2','3','4','5','6','7','8','9',Esc(':'),';',Esc('<'),'=',Esc('>'),Esc('?'),
+     '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
+     'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
+     '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
+     'p','q','r','s','t','u','v','w','x','y','z','{',Esc('|'),'}','~',Esc(0x7f),
+     Esc(0x80),Esc(0x81),0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,Esc(0x8d),Esc(0x8e),Esc(0x8f),
+     Esc(0x90),0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,Esc(0x9d),Esc(0x9e),0x9f,
+     0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+     0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+     0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+     0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+     0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+     0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+ };
+ 
+ static int sanitize_bytestring(const char * src, int cch_src,
+                                char * odest, int cch_dest)
+ {
+     char * dest = odest;
+     while (cch_src > 0 && *src && cch_dest > 0) {
+ 
+         unsigned short rc;
+ 
+         rc = sanitized_escapes_1252[*src];
+         if (IS_ESCAPED(rc)) {
+             static const char hex[] = 
+                 {'0','1','2','3','4','5','6','7',
+                  '8','9','a','b','c','d','e','f'};
+ 
+             if (cch_dest < 3) {
+                 *dest++ = '\0';
+                 return 0;
+             }
+ 
+             *dest++ = '%';
+             *dest++ = hex[(((int)*src) >> 4) & 0x0f];
+             *dest++ = hex[(((int)*src) & 0x0f)];
+             cch_dest -= 3;
+ 
+         } else {
+             *dest++ = *src;
+             cch_dest--;
+         }
+ 
+         cch_src--;
+         src++;
+     }
+ 
+     if (cch_src > 0 && cch_dest > 0) {
+         *dest++ = '\0';
+     }
+ 
+     return (int)(dest - odest);
+ }
+ 
+ #undef Esc
+ #undef IS_ESCAPED
+ #undef ESCVAL
+ 
+ long cm_NormalizeUtf8StringToUtf16(const char * src, int cch_src,
+                                    wchar_t * dest, int cch_dest)
+ {
+     wchar_t wsrcbuf[NLSMAXCCH];
+     wchar_t *wnorm;
+     int cch;
+     int cch_norm;
+ 
+     /* Get some edge cases out first, so we don't have to worry about
+        cch_src being 0 etc. */
+     if (cch_src == 0) {
+         return 0;
+     } else if (*src == '\0') {
+         if (cch_dest >= 1)
+             *dest = L'\0';
+         return 1;
+     }
+ 
+     if (cch_src == -1) {
+         cch_src = strlen(src) + 1;
+     }
+ 
+     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                               cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
+ 
+     if (cch == 0) {
+         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+             char sanitized[NLSMAXCCH];
+             int cch_sanitized;
+ 
+             /* If src doesn't have a unicode translation, then it
+                wasn't valid UTF-8.  In this case, we assume that src
+                is CP-1252 and then try to convert again.  But before
+                that, we use a translation table to "sanitize" the
+                input. */
+ 
+             cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                 sizeof(sanitized)/sizeof(char));
+ 
+             if (cch_sanitized == 0) {
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return 0;
+             }
+ 
+             cch = MultiByteToWideChar(1252, 0, sanitized,
+                                       cch_sanitized * sizeof(char), wsrcbuf, NLSMAXCCH);
+             if (cch == 0) {
+                 /* Well, that didn't work either.  Something is very wrong. */
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return 0;
+             }
+         } else {
+             return 0;
+         }
+     }
+ 
+     cch_norm = cch_dest;
+     wnorm = NormalizeUtf16String(wsrcbuf, cch, dest, &cch_norm);
+     if (wnorm == NULL) {
+ #ifdef DEBUG_UNICODE
+         DebugBreak();
+ #endif
+         return 0;
+     }
+ 
+     if (wnorm != dest) {
+         /* The buffer was insufficient */
+         if (dest != NULL && cch_dest > 1) {
+             *dest = L'\0';
+             cch_norm = 0;
+         }
+ 
+         free(wnorm);
+     }
+ 
+     return cch_norm;
+ }
+ 
+ cm_normchar_t *cm_NormalizeUtf8StringToUtf16Alloc(const cm_utf8char_t * src, int cch_src,
+                                                   int *pcch_dest)
+ {
+     wchar_t wsrcbuf[NLSMAXCCH];
+     wchar_t *wnorm;
+     int cch;
+     int cch_norm;
+ 
+     /* Get some edge cases out first, so we don't have to worry about
+        cch_src being 0 etc. */
+     if (cch_src == 0 || src == NULL || *src == '\0') {
+         if (pcch_dest)
+             *pcch_dest = ((cch_src != 0)? 1 : 0);
+         return wcsdup(L"");
+     }
+ 
+     if (cch_src == -1) {
+         cch_src = strlen(src) + 1;
+     }
+ 
+     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                               cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
+ 
+     if (cch == 0) {
+         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+             char sanitized[NLSMAXCCH];
+             int cch_sanitized;
+ 
+             /* If src doesn't have a unicode translation, then it
+                wasn't valid UTF-8.  In this case, we assume that src
+                is CP-1252 and then try to convert again.  But before
+                that, we use a translation table to "sanitize" the
+                input. */
+ 
+             cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                 sizeof(sanitized)/sizeof(char));
+ 
+             if (cch_sanitized == 0) {
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return NULL;
+             }
+ 
+             cch = MultiByteToWideChar(1252, 0, sanitized,
+                                       cch_sanitized * sizeof(char), wsrcbuf, NLSMAXCCH);
+             if (cch == 0) {
+                 /* Well, that didn't work either.  Something is very wrong. */
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return NULL;
+             }
+         } else {
+             return NULL;
+         }
+     }
+ 
+     cch_norm = 0;
+     wnorm = NormalizeUtf16String(wsrcbuf, cch, NULL, &cch_norm);
+     if (wnorm == NULL) {
+ #ifdef DEBUG_UNICODE
+         DebugBreak();
+ #endif
+         return NULL;
+     }
+ 
+     if (pcch_dest)
+         *pcch_dest = cch_norm;
+ 
+     return wnorm;
+ }
+ 
+ int cm_Utf8ToUtf16(const cm_utf8char_t * src, int cch_src,
+                    cm_unichar_t * dest, int cch_dest)
+ {
+     int cch;
+ 
+     if (cch_src == -1) {
+         cch_src = strlen(src) + 1;
+     }
+ 
+     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                               cch_src * sizeof(char), dest, cch_dest);
+ 
+     if (cch == 0) {
+         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+             char sanitized[NLSMAXCCH];
+             int cch_sanitized;
+ 
+             /* If src doesn't have a unicode translation, then it
+                wasn't valid UTF-8.  In this case, we assume that src
+                is CP-1252 and then try to convert again.  But before
+                that, we use a translation table to "sanitize" the
+                input. */
+ 
+             cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                 sizeof(sanitized)/sizeof(char));
+ 
+             if (cch_sanitized == 0) {
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return 0;
+             }
+ 
+             cch = MultiByteToWideChar(1252, 0, sanitized,
+                                       cch_sanitized * sizeof(char), dest, cch_dest);
+             if (cch == 0) {
+                 /* Well, that didn't work either.  Something is very wrong. */
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return 0;
+             } else {
+                 return cch;
+             }
+ 
+         } else {
+             return 0;
+         }
+     } else {
+         return cch;
+     }
+ }
+ 
+ cm_unichar_t  * cm_Utf8ToUtf16Alloc(const cm_utf8char_t * src, int cch_src, int *pcch_dest)
+ {
+     cm_unichar_t * ustr = NULL;
+     int cch;
+ 
+     if (cch_src == 0 || src == NULL || *src == '\0') {
+         if (pcch_dest)
+             *pcch_dest = ((cch_src != 0)? 1 : 0);
+         return wcsdup(L"");
+     }
+ 
+     if (cch_src == -1) {
+         cch_src = strlen(src) + 1;
+     }
+ 
+     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                               cch_src * sizeof(char), NULL, 0);
+ 
+     if (cch == 0) {
+         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+             char sanitized[NLSMAXCCH];
+             int cch_sanitized;
+ 
+             /* If src doesn't have a unicode translation, then it
+                wasn't valid UTF-8.  In this case, we assume that src
+                is CP-1252 and then try to convert again.  But before
+                that, we use a translation table to "sanitize" the
+                input. */
+ 
+             cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                 sizeof(sanitized)/sizeof(char));
+ 
+             if (cch_sanitized == 0) {
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return NULL;
+             }
+ 
+             cch = MultiByteToWideChar(1252, 0, sanitized,
+                                       cch_sanitized * sizeof(char), NULL, 0);
+             if (cch == 0) {
+                 /* Well, that didn't work either.  Something is very wrong. */
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return NULL;
+             }
+ 
+             ustr = malloc((cch + 1) * sizeof(wchar_t));
+ 
+             cch = MultiByteToWideChar(1252, 0, sanitized,
+                                       cch_sanitized * sizeof(char), ustr, cch);
+             ustr[cch] = 0;
+         } else {
+             return NULL;
+         }
+     } else {
+ 
+         ustr = malloc((cch + 1) * sizeof(wchar_t));
+ 
+         cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                                   cch_src * sizeof(char), ustr, cch);
+         ustr[cch] = 0;
+     }
+ 
+     if (pcch_dest)
+         *pcch_dest = cch;
+ 
+     return ustr;
+ }
+ 
+ 
+ 
+ /* \brief Normalize a UTF-8 string.
+ 
+    \param[in] src String to normalize.
+ 
+    \param[in] cch_src : Count of characters in src.  If this value is
+        -1, then src is assumed to be NULL terminated.  The translated
+        string will be NULL terminated only if this is -1 or the count
+        includes the terminating NULL.
+ 
+    \param[out] adest : Destination string.  Only considered valid if
+        \a cch_adest is non-zero.
+ 
+    \param[in] cch_adest : Number of characters in the destination
+        string.  If this is zero, then the return value is the number
+        of bytes required.
+ 
+    \return If \a cch_adest is non-zero, then the return value is the
+        number of bytes stored into adest.  If \a cch_adest is zero,
+        then the return value is the number of bytes required.  In both
+        cases, the return value is 0 if the call was unsuccessful.
+  */
+ long cm_NormalizeUtf8String(const char * src, int cch_src,
+                             char * adest, int cch_adest)
+ {
+     wchar_t wsrcbuf[NLSMAXCCH];
+     wchar_t *wnorm;
+     int cch;
+     int cch_norm;
+ 
+     /* Get some edge cases out first, so we don't have to worry about
+        cch_src being 0 etc. */
+     if (cch_src == 0) {
+         return 0;
+     } else if (*src == '\0') {
+         if (cch_adest >= 1)
+             *adest = '\0';
+         return 1;
+     }
+ 
+     if (cch_src == -1) {
+         cch_src = strlen(src) + 1;
+     }
+ 
+     cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                               cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
+ 
+     if (cch == 0) {
+         if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+             char sanitized[NLSMAXCCH];
+             int cch_sanitized;
+ 
+             /* If src doesn't have a unicode translation, then it
+                wasn't valid UTF-8.  In this case, we assume that src
+                is CP-1252 and then try to convert again.  But before
+                that, we use a translation table to "sanitize" the
+                input. */
+ 
+             cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                 sizeof(sanitized)/sizeof(char));
+ 
+             if (cch_sanitized == 0) {
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return 0;
+             }
+ 
+             cch = MultiByteToWideChar(1252, 0, sanitized,
+                                       cch_sanitized * sizeof(char), wsrcbuf, NLSMAXCCH);
+             if (cch == 0) {
+                 /* Well, that didn't work either.  Something is very wrong. */
+ #ifdef DEBUG_UNICODE
+                 DebugBreak();
+ #endif
+                 return 0;
+             }
+         } else {
+             return 0;
+         }
+     }
+ 
+     cch_norm = 0;
+     wnorm = NormalizeUtf16String(wsrcbuf, cch, NULL, &cch_norm);
+     if (wnorm == NULL) {
+ #ifdef DEBUG_UNICODE
+         DebugBreak();
+ #endif
+         return 0;
+     }
+ 
+     cch = WideCharToMultiByte(CP_UTF8, 0, wnorm,
+                               cch_norm, adest, cch_adest * sizeof(char),
+                               NULL, FALSE);
+ 
+     if (wnorm)
+         free(wnorm);
+ 
+     return cch;
+ }
+ 
+ /*! \brief Case insensitive comparison with specific length
+ 
+   \param[in] str1 First string to compare.  Assumed to be encoded in UTF-8.
+ 
+   \param[in] str2 Second string to compare.  Assumed to be encoded in UTF-8.
+ 
+   \param[in] n Max byte count.
+ 
+  */
+ int cm_strnicmp_utf8(const char * str1, const char * str2, int n)
+ {
+     wchar_t wstr1[NLSMAXCCH];
+     int len1;
+     int len2;
+     wchar_t wstr2[NLSMAXCCH];
+     int rv;
+ 
+     /* first check for NULL pointers (assume NULL < "") */
+     if (str1 == NULL) {
+         if (str2 == NULL)
+             return 0;
+         else
+             return -1;
+     } else if (str2 == NULL) {
+         return 1;
+     }
+ 
+     len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str1, n, wstr1, NLSMAXCCH);
+     if (len1 == 0) {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         wstr1[0] = L'\0';
+     }
+ 
+     len2 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str2, n, wstr2, NLSMAXCCH);
+     if (len2 == 0) {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         wstr2[0] = L'\0';
+     }
+ 
+     rv = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wstr1, len1, wstr2, len2);
+     if (rv > 0)
+         return (rv - 2);
+     else {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         return 0;
+     }
+ }
+ 
+ int cm_strnicmp_utf16(const cm_unichar_t * str1, const cm_unichar_t * str2, int len)
+ {
+     int rv;
+     size_t cch1;
+     size_t cch2;
+ 
+     /* first check for NULL pointers */
+     if (str1 == NULL) {
+         if (str2 == NULL)
+             return 0;
+         else
+             return -1;
+     } else if (str2 == NULL) {
+         return 1;
+     }
+ 
+     if (FAILED(StringCchLengthW(str1, len, &cch1)))
+         cch1 = len;
+ 
+     if (FAILED(StringCchLengthW(str2, len, &cch2)))
+         cch2 = len;
+ 
+     rv = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, str1, cch1, str2, cch2);
+     if (rv > 0)
+         return (rv - 2);
+     else {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         return 0;
+     }
+ }
+ 
+ int cm_stricmp_utf16(const cm_unichar_t * str1, const cm_unichar_t * str2)
+ {
+     int rv;
+ 
+     /* first check for NULL pointers */
+     if (str1 == NULL) {
+         if (str2 == NULL)
+             return 0;
+         else
+             return -1;
+     } else if (str2 == NULL) {
+         return 1;
+     }
+ 
+     rv = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, str1, -1, str2, -1);
+     if (rv > 0)
+         return (rv - 2);
+     else {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         return 0;
+     }
+ }
+ 
+ cm_unichar_t *cm_strlwr_utf16(cm_unichar_t * str)
+ {
+     int rv;
+     int len;
+ 
+     len = wcslen(str) + 1;
+     rv = LCMapStringW(LOCALE_INVARIANT, LCMAP_LOWERCASE, str, len, str, len);
+ #ifdef DEBUG
+     if (rv == 0) {
+         DebugBreak();
+     }
+ #endif
+ 
+     return str;
+ }
+ 
+ cm_unichar_t *cm_strupr_utf16(cm_unichar_t * str)
+ {
+     int rv;
+     int len;
+ 
+     len = wcslen(str) + 1;
+     rv = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, str, len, str, len);
+ #ifdef DEBUG
+     if (rv == 0) {
+         DebugBreak();
+     }
+ #endif
+ 
+     return str;
+ }
+ 
+ 
+ int cm_stricmp_utf8(const char * str1, const char * str2)
+ {
+     wchar_t wstr1[NLSMAXCCH];
+     int len1;
+     int len2;
+     wchar_t wstr2[NLSMAXCCH];
+     int rv;
+ 
+     /* first check for NULL pointers */
+     if (str1 == NULL) {
+         if (str2 == NULL)
+             return 0;
+         else
+             return -1;
+     } else if (str2 == NULL) {
+         return 1;
+     }
+ 
+     len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str1, -1, wstr1, NLSMAXCCH);
+     if (len1 == 0) {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         wstr1[0] = L'\0';
+     }
+ 
+     len2 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str2, -1, wstr2, NLSMAXCCH);
+     if (len2 == 0) {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         wstr2[0] = L'\0';
+     }
+ 
+     rv = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wstr1, len1, wstr2, len2);
+     if (rv > 0)
+         return (rv - 2);
+     else {
+ #ifdef DEBUG
+         DebugBreak();
+ #endif
+         return 0;
+     }
+ }
+ 
+ #if 0
+ wchar_t * strupr_utf16(wchar_t * wstr, size_t cbstr)
+ {
+     wchar_t wstrd[NLSMAXCCH];
+     int len;
+ 
+     len = cbstr / sizeof(wchar_t);
+     len = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, wstr, len, wstrd, NLSMAXCCH);
+     StringCbCopyW(wstr, cbstr, wstrd);
+ 
+     return wstr;
+ }
+ #endif
+ 
+ char * strupr_utf8(char * str, size_t cbstr)
+ {
+     wchar_t wstr[NLSMAXCCH];
+     wchar_t wstrd[NLSMAXCCH];
+     int len;
+ 
+     len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, wstr, NLSMAXCCH);
+     if (len == 0)
+         return str;
+ 
+     len = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, wstr, len, wstrd, NLSMAXCCH);
+ 
+     len = WideCharToMultiByte(CP_UTF8, 0, wstrd, -1, str, cbstr, NULL, FALSE);
+ 
+     return str;
+ }
+ 
+ char * char_next_utf8(const char * c)
+ {
+ #define CH (*((const unsigned char *)c))
+ 
+     if ((CH & 0x80) == 0)
+         return (char *) c+1;
+     else {
+         switch (CH & 0xf0) {
+         case 0xc0:
+         case 0xd0:
+             return (char *) c+2;
+ 
+         case 0xe0:
+             return (char *) c+3;
+ 
+         case 0xf0:
+             return (char *) c+4;
+ 
+         default:
+             return (char *) c+1;
+         }
+     }
+ #undef CH
+ }
+ 
+ 
+ char * char_prev_utf8(const char * c)
+ {
+ #define CH (*((const unsigned char *)c))
+ 
+     c--;
+ 
+     if ((CH & 0x80) == 0)
+         return (char *) c;
+     else
+         while ((CH & 0xc0) == 0x80)
+             (char *) c--;
+     return (char *) c;
+ 
+ #undef CH
+ }
+ 
+ wchar_t * char_next_utf16(const wchar_t * c)
+ {
+     unsigned short sc = (unsigned short) *c;
+ 
+     if (sc >= 0xd800 && sc <= 0xdbff)
+         return (wchar_t *) c+2;
+     return (wchar_t *) c+1;
+ }
+ 
+ wchar_t * char_prev_utf16(const wchar_t * c)
+ {
+     unsigned short sc = (unsigned short) *(--c);
+ 
+     if (sc >= 0xdc00 && sc <= 0xdfff)
+         return (wchar_t *) --c;
+     return (wchar_t *) c;
+ }
+ 
+ wchar_t * char_this_utf16(const wchar_t * c)
+ {
+     unsigned short sc = (unsigned short) *c;
+ 
+     if (sc >= 0xdc00 && sc <= 0xdfff)
+         return (wchar_t *) --c;
+     return (wchar_t *) c;
+ }
+ 
Index: openafs/src/WINNT/afsd/cm_nls.h
diff -c /dev/null openafs/src/WINNT/afsd/cm_nls.h:1.3.2.3
*** /dev/null	Fri Jul 18 12:42:42 2008
--- openafs/src/WINNT/afsd/cm_nls.h	Thu Jun 26 12:38:30 2008
***************
*** 0 ****
--- 1,271 ----
+ /*
+  * Copyright (c) 2008 Secure Endpoints Inc.
+  *
+  * Permission is hereby granted, free of charge, to any person
+  * obtaining a copy of this software and associated documentation
+  * files (the "Software"), to deal in the Software without
+  * restriction, including without limitation the rights to use, copy,
+  * modify, merge, publish, distribute, sublicense, and/or sell copies
+  * of the Software, and to permit persons to whom the Software is
+  * furnished to do so, subject to the following conditions:
+  *
+  * The above copyright notice and this permission notice shall be
+  * included in all copies or substantial portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  * SOFTWARE.
+  */
+ 
+ #ifndef __CM_NLS_H_ENV__
+ #define __CM_NLS_H_ENV__
+ 
+ /* Character types
+ 
+    There are three character types that we use as implementation
+    types.  These should generally only be referenced by the
+    nationalization code.
+ 
+    - ::cm_unichar_t
+ 
+    - ::cm_normchar_t
+ 
+    - ::cm_utf8char_t
+ 
+    The character types that are used by code are :
+ 
+    - ::clientchar_t
+ 
+    - ::normchar_t
+ 
+    - ::fschar_t
+ 
+  */
+ 
+ /*! \brief Unicode UTF-16 Character */
+ typedef wchar_t cm_unichar_t;
+ 
+ /*! \brief Unicode UTF-16 Normalized Character (NF-C) */
+ typedef wchar_t cm_normchar_t;
+ 
+ /*! \brief Unicode UTF-8 Character */
+ typedef unsigned char cm_utf8char_t;
+ 
+ /*! \brief Client name */
+ typedef cm_unichar_t  clientchar_t;
+ 
+ /*! \brief File Server name */
+ typedef cm_utf8char_t fschar_t;
+ 
+ /*! \brief Normalized name */
+ typedef cm_normchar_t normchar_t;
+ 
+ #define __paste(a,b) a ## b
+ #define _C(s) __paste(L,s)
+ #define _FS(s) s
+ #define _N(s) __paste(L,s)
+ 
+ #define cm_ClientStringToNormStringAlloc cm_NormalizeStringAlloc
+ #define cm_ClientStringToFsStringAlloc cm_Utf16ToUtf8Alloc
+ #define cm_ClientStringToUtf8Alloc cm_Utf16ToUtf8Alloc
+ #define cm_FsStringToClientStringAlloc cm_Utf8ToUtf16Alloc
+ #define cm_FsStringToNormStringAlloc cm_NormalizeUtf8StringToUtf16Alloc
+ #define cm_Utf8ToNormStringAlloc cm_NormalizeUtf8StringToUtf16Alloc
+ #define cm_Utf8ToClientStringAlloc cm_Utf8ToUtf16Alloc
+ 
+ #define cm_ClientStringToUtf16 cm_Utf16ToUtf16
+ #define cm_ClientStringToUtf8  cm_Utf16ToUtf8
+ #define cm_ClientStringToFsString cm_Utf16ToUtf8
+ #define cm_ClientStringToNormString cm_NormalizeString
+ #define cm_FsStringToClientString cm_Utf8ToUtf16
+ #define cm_FsStringToNormString cm_NormalizeUtf8StringToUtf16
+ #define cm_Utf8ToClientString cm_Utf8ToUtf16
+ #define cm_OemToClientString(s,cchs,d,cchd) MultiByteToWideChar(CP_OEMCP, 0, s, cchs, d, cchd)
+ #define cm_AnsiToClientString(s,cchs,d,cchd) MultiByteToWideChar(CP_ACP, 0, s, cchs, d, cchd)
+ 
+ #define cm_ClientStrCmp wcscmp
+ #define cm_ClientStrCmpI cm_stricmp_utf16
+ #define cm_ClientStrCmpIA cm_stricmp_utf16
+ #define cm_ClientStrCmpNI cm_strnicmp_utf16
+ #define cm_ClientStrCmpN wcsncmp
+ #define cm_ClientStrChr wcschr
+ #define cm_ClientStrRChr wcsrchr
+ #define cm_ClientStrCpy(d,cch,s) StringCchCopyW(d,cch,s)
+ #define cm_ClientStrCpyN(d,cch,s,n) StringCchCopyNW(d,cch,s,n)
+ #define cm_ClientStrDup wcsdup
+ #define cm_ClientStrCat(d,cch,s) StringCchCatW(d,cch,s)
+ #define cm_ClientStrCatN(d,cch,s,n) StringCchCatNW(d,cch,s,n)
+ #define cm_ClientStrPrintfN StringCchPrintfW
+ #define cm_ClientStrPrintfV StringCchVPrintfW
+ //#define cm_ClientStrPrintf  swprintf
+ #define cm_ClientStrLen wcslen
+ #define cm_ClientStrLwr cm_strlwr_utf16
+ #define cm_ClientStrUpr cm_strupr_utf16
+ #define cm_ClientStrSpn wcsspn
+ #define cm_ClientStrCSpn wcscspn
+ #define osi_LogSaveClientString osi_LogSaveStringW
+ #define cm_ClientCharThis char_this_utf16
+ #define cm_ClientCharNext char_next_utf16
+ #define cm_ClientCharPrev char_prev_utf16
+ 
+ #define cm_FsStrDup strdup
+ #define cm_FsStrLen strlen
+ #define cm_FsStrCat StringCchCatA
+ #define cm_FsStrPrintf StringCchPrintfA
+ #define cm_FsStrRChr strrchr
+ #define cm_FsStrChr  strchr
+ #define cm_FsStrCmpIA cm_stricmp_utf8
+ #define cm_FsStrCmpI cm_stricmp_utf8
+ #define cm_FsStrCmpA  strcmp
+ #define cm_FsStrCmp  strcmp
+ #define cm_FsStrCpy(d,cch,s) StringCchCopyA(d,cch,s)
+ #define osi_LogSaveFsString osi_LogSaveString
+ #define cm_FsStrCpyN(d,cch,s,n) StringCchCopyN(d,cch,s,n)
+ 
+ #define cm_NormStrDup wcsdup
+ #define cm_NormStrCmpI cm_stricmp_utf16
+ #define cm_NormStrCmp wcscmp
+ #define cm_NormCharUpr towupper
+ 
+ #define cm_Utf16ToClientString cm_Utf16ToUtf16
+ 
+ extern long cm_InitNormalization(void);
+ 
+ /* Functions annotated in accordance with sal.h */
+ 
+ extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_normchar_t *
+     cm_NormalizeStringAlloc
+     (__in_ecount(cch_src) const cm_unichar_t * s,
+      int cch_src,
+      __out_ecount_full_opt(1) int *pcch_dest);
+ 
+ extern __success(return != 0) int
+     cm_NormalizeString
+     (__in_ecount(cch_src) const cm_unichar_t * s,
+      int cch_src,
+      __out_ecount_full_z_opt(cch_dest) cm_normchar_t * dest,
+      int cch_dest);
+ 
+ extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_utf8char_t *
+     cm_Utf16ToUtf8Alloc
+     (__in_ecount(cch_src) const cm_unichar_t * s,
+      int cch_src, 
+      __out_ecount_full_opt(1) int *pcch_dest);
+ 
+ extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_unichar_t *
+     cm_Utf8ToUtf16Alloc
+     (__in_ecount(cch_src) const cm_utf8char_t * src,
+      int cch_src,
+      __out_ecount_full_opt(1) int *pcch_dest);
+ 
+ extern __success(return != 0) long
+     cm_NormalizeUtf8StringToUtf16
+     (__in_ecount(cch_src) const char * src,
+      int cch_src,
+      __out_ecount_full_z_opt(cch_dest) cm_normchar_t * dest,
+      int cch_dest);
+ 
+ extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_normchar_t *
+     cm_NormalizeUtf8StringToUtf16Alloc
+     (__in_ecount(cch_src) const cm_utf8char_t * src,
+      int cch_src,
+      __out_ecount_full_opt(1) int *pcch_dest);
+ 
+ extern __success(return != 0) int
+     cm_Utf8ToUtf16
+     (__in_ecount(cch_src) const cm_utf8char_t * src,
+      int cch_src,
+      __out_ecount_full_z_opt(cch_dest) cm_unichar_t * dest,
+      int cch_dest);
+ 
+ extern __success(return != 0) int
+     cm_Utf16ToUtf8
+     (__in_ecount(cch_src) const cm_unichar_t * src,
+      int cch_src,
+      __out_ecount_full_z_opt(cch_dest) cm_utf8char_t * dest,
+      int cch_dest);
+ 
+ extern __success(return != 0) int
+     cm_Utf16ToUtf16
+     (__in_ecount(cch_src) const cm_unichar_t * src,
+      int cch_src,
+      __out_ecount_full_z_opt(cch_dest) cm_unichar_t * dest,
+      int cch_dest);
+ 
+ extern int
+     cm_strnicmp_utf16
+     (__in_z const cm_unichar_t * str1,
+      __in_z const cm_unichar_t * str2,
+      int len);
+ 
+ extern int
+     cm_stricmp_utf16
+     (__in_z const cm_unichar_t * str1,
+      __in_z const cm_unichar_t * str2);
+ 
+ /* The cm_stricmp_utf8N function is identical to cm_stricmp_utf8
+    except it is used in instances where one of the strings is always
+    known to be ASCII. */
+ extern int
+     cm_stricmp_utf8N
+     (__in_z const char * str1,
+      __in_z const char * str2);
+ #define cm_stricmp_utf8N cm_stricmp_utf8
+ 
+ extern int
+     cm_stricmp_utf8
+     (__in_z const char * str1,
+      __in_z const char * str2);
+ 
+ /* The cm_strnicmp_utf8N function is identical to cm_strnicmp_utf8
+    except it is used in instances where one of the strings is always
+    known to be ASCII. */
+ extern int
+     cm_strnicmp_utf8N
+     (__in_z const char * str1,
+      __in_z const char * str2, int n);
+ #define cm_strnicmp_utf8N cm_strnicmp_utf8
+ 
+ extern int
+     cm_strnicmp_utf8
+     (__in_z const char * str1,
+      __in_z const char * str2, int n);
+ 
+ extern __out_z wchar_t *
+ char_next_utf16
+ (__in_z const wchar_t * c);
+ 
+ extern __out_z wchar_t *
+ char_prev_utf16
+ (__in_z const wchar_t * c);
+ 
+ extern __out_z wchar_t *
+ char_this_utf16
+ (__in_z const wchar_t * c);
+ 
+ extern __out_z cm_unichar_t *
+ cm_strlwr_utf16(__inout_z cm_unichar_t * str);
+ 
+ extern __out_z cm_unichar_t *
+ cm_strupr_utf16(__inout_z cm_unichar_t * str);
+ 
+ #if 0
+ 
+ extern long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
+                                           char * adest, int cch_adest);
+ 
+ extern char * char_next_utf8(const char * c);
+ 
+ extern char * char_prev_utf8(const char * c);
+ 
+ extern char * strupr_utf8(char * str, size_t cbstr);
+ 
+ #endif
+ 
+ #define lengthof(a) (sizeof(a)/sizeof(a[0]))
+ #endif
Index: openafs/src/WINNT/afsd/cm_rpc.c
diff -c openafs/src/WINNT/afsd/cm_rpc.c:1.7 openafs/src/WINNT/afsd/cm_rpc.c:1.7.8.1
*** openafs/src/WINNT/afsd/cm_rpc.c:1.7	Sun Jan  2 20:05:07 2005
--- openafs/src/WINNT/afsd/cm_rpc.c	Thu Jun 26 10:38:24 2008
***************
*** 15,25 ****
  #include <malloc.h>
  
  #include <osi.h>
- #ifndef DJGPP
  #include "afsrpc.h"
- #else
- #include "afsrpc95.h"
- #endif
  
  #include "afsd.h"
  #include "afsd_init.h"
--- 15,21 ----
Index: openafs/src/WINNT/afsd/cm_rpc.h
diff -c openafs/src/WINNT/afsd/cm_rpc.h:1.4 openafs/src/WINNT/afsd/cm_rpc.h:1.4.8.1
*** openafs/src/WINNT/afsd/cm_rpc.h:1.4	Sun Jan  2 20:05:07 2005
--- openafs/src/WINNT/afsd/cm_rpc.h	Thu Jun 26 10:38:24 2008
***************
*** 10,20 ****
  #ifndef	__CM_RPC_H__
  #define __CM_RPC_H__
  
- #ifndef DJGPP
  #include "afsrpc.h"
- #else
- #include "afsrpc95.h"
- #endif
  
  void cm_RegisterNewTokenEvent(afs_uuid_t uuid, char sessionKey[8]);
  BOOL cm_FindTokenEvent(afs_uuid_t uuid, char sessionKey[8]);
--- 10,16 ----
Index: openafs/src/WINNT/afsd/cm_scache.c
diff -c openafs/src/WINNT/afsd/cm_scache.c:1.35.2.74.2.2 openafs/src/WINNT/afsd/cm_scache.c:1.35.2.77
*** openafs/src/WINNT/afsd/cm_scache.c:1.35.2.74.2.2	Sun Jun 22 23:05:03 2008
--- openafs/src/WINNT/afsd/cm_scache.c	Thu Jun 26 10:38:24 2008
***************
*** 10,20 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
  #include <nb30.h>
- #endif /* !DJGPP */
  #include <malloc.h>
  #include <string.h>
  #include <stdlib.h>
--- 10,18 ----
Index: openafs/src/WINNT/afsd/cm_scache.h
diff -c openafs/src/WINNT/afsd/cm_scache.h:1.21.2.24.2.1 openafs/src/WINNT/afsd/cm_scache.h:1.21.2.27
*** openafs/src/WINNT/afsd/cm_scache.h:1.21.2.24.2.1	Sun Jun 22 23:05:03 2008
--- openafs/src/WINNT/afsd/cm_scache.h	Thu Jun 26 12:38:30 2008
***************
*** 10,19 ****
  #ifndef __CM_SCACHE_H_ENV__
  #define __CM_SCACHE_H_ENV__ 1
  
- #ifdef DJGPP
- #include "largeint95.h"
- #endif /* DJGPP */
- 
  #define MOUNTPOINTLEN   1024    /* max path length for symlink; same as AFSPATHMAX */
  
  typedef struct cm_fid {
--- 10,15 ----
***************
*** 411,414 ****
--- 407,412 ----
  extern void cm_RemoveSCacheFromHashTable(cm_scache_t *scp);
  
  extern void cm_AdjustScacheLRU(cm_scache_t *scp);
+ 
+ extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
  #endif /*  __CM_SCACHE_H_ENV__ */
Index: openafs/src/WINNT/afsd/cm_server.c
diff -c openafs/src/WINNT/afsd/cm_server.c:1.25.2.28.2.1 openafs/src/WINNT/afsd/cm_server.c:1.25.2.30
*** openafs/src/WINNT/afsd/cm_server.c:1.25.2.28.2.1	Sun Jun 22 22:54:28 2008
--- openafs/src/WINNT/afsd/cm_server.c	Thu Jun 26 10:38:24 2008
***************
*** 10,22 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
  #include <nb30.h>
- #else
- #include <sys/socket.h>
- #endif /* !DJGPP */
  #include <stdlib.h>
  #include <malloc.h>
  #include <string.h>
--- 10,18 ----
Index: openafs/src/WINNT/afsd/cm_server.h
diff -c openafs/src/WINNT/afsd/cm_server.h:1.13.2.13 openafs/src/WINNT/afsd/cm_server.h:1.13.2.14
*** openafs/src/WINNT/afsd/cm_server.h:1.13.2.13	Sat Mar  8 18:25:08 2008
--- openafs/src/WINNT/afsd/cm_server.h	Thu Jun 26 10:38:24 2008
***************
*** 10,20 ****
  #ifndef __CM_SERVER_H_ENV__
  #define __CM_SERVER_H_ENV__ 1
  
- #ifndef DJGPP
  #include <winsock2.h>
- #else /* DJGPP */
- #include <netinet/in.h>
- #endif /* !DJGPP */
  #include <osi.h>
  
  /* this value is set to 1022 in order to  */
--- 10,16 ----
Index: openafs/src/WINNT/afsd/cm_user.c
diff -c openafs/src/WINNT/afsd/cm_user.c:1.8.4.4 openafs/src/WINNT/afsd/cm_user.c:1.8.4.6
*** openafs/src/WINNT/afsd/cm_user.c:1.8.4.4	Wed Feb 20 12:37:09 2008
--- openafs/src/WINNT/afsd/cm_user.c	Thu Jun 26 10:58:05 2008
***************
*** 10,22 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
- #endif /* !DJGPP */
  #include <malloc.h>
  #include <string.h>
  
  #include "afsd.h"
  #include <osi.h>
  #include <rx/rx.h>
  
--- 10,21 ----
  #include <afs/param.h>
  #include <afs/stds.h>
  
  #include <windows.h>
  #include <malloc.h>
  #include <string.h>
  
  #include "afsd.h"
+ #include "smb.h"
  #include <osi.h>
  #include <rx/rx.h>
  
Index: openafs/src/WINNT/afsd/cm_user.h
diff -c openafs/src/WINNT/afsd/cm_user.h:1.8 openafs/src/WINNT/afsd/cm_user.h:1.8.2.1
*** openafs/src/WINNT/afsd/cm_user.h:1.8	Sat Apr 22 15:44:28 2006
--- openafs/src/WINNT/afsd/cm_user.h	Thu Jun 26 12:38:30 2008
***************
*** 31,37 ****
      int gen;			        /* generation number */
      int iterator;			/* for use as ListTokens cookie */
      long flags;			        /* flags */
!     char userName[MAXKTCNAMELEN];	/* user name */
  #ifdef QUERY_AFSID
      afs_uint32 uid;			/* User's AFS ID in this cell */
  #endif
--- 31,37 ----
      int gen;			        /* generation number */
      int iterator;			/* for use as ListTokens cookie */
      long flags;			        /* flags */
!     fschar_t userName[MAXKTCNAMELEN];   /* user name */
  #ifdef QUERY_AFSID
      afs_uint32 uid;			/* User's AFS ID in this cell */
  #endif
Index: openafs/src/WINNT/afsd/cm_utils.c
diff -c openafs/src/WINNT/afsd/cm_utils.c:1.11.4.7 openafs/src/WINNT/afsd/cm_utils.c:1.11.4.12
*** openafs/src/WINNT/afsd/cm_utils.c:1.11.4.7	Thu Jan 31 02:31:56 2008
--- openafs/src/WINNT/afsd/cm_utils.c	Thu Jun 26 12:38:30 2008
***************
*** 11,17 ****
  #include <afs/stds.h>
  
  #include <errno.h>
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
  #ifndef EWOULDBLOCK
--- 11,16 ----
***************
*** 62,68 ****
  #define ESTALE                  WSAESTALE
  #define EREMOTE                 WSAEREMOTE
  #endif /* EWOULDBLOCK */
- #endif /* !DJGPP */
  #include <afs/unified_afs.h>
  
  #include <string.h>
--- 61,66 ----
***************
*** 71,76 ****
--- 69,77 ----
  #include <osi.h>
  #include <rx/rx.h>
  
+ #define STRSAFE_NO_DEPRECATE
+ #include <strsafe.h>
+ 
  
  static osi_once_t cm_utilsOnce;
  
***************
*** 361,363 ****
--- 362,734 ----
  	cm_spaceListp = tsp;
          lock_ReleaseWrite(&cm_utilsLock);
  }
+ 
+ /* characters that are legal in an 8.3 name */
+ /*
+  * We used to have 1's for all characters from 128 to 254.  But
+  * the NT client behaves better if we create an 8.3 name for any
+  * name that has a character with the high bit on, and if we
+  * delete those characters from 8.3 names.  In particular, see
+  * Sybase defect 10859.
+  */
+ char cm_LegalChars[256] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ 
+ #define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
+ 
+ /* return true iff component is a valid 8.3 name */
+ int cm_Is8Dot3(clientchar_t *namep)
+ {
+     int sawDot = 0;
+     clientchar_t 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] == '.' && 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 (!ISLEGALCHAR(tc))
+             return 0;
+         charCount++;
+         if (!sawDot && charCount > 8)
+             /* more than 8 chars in name */
+             return 0;
+         if (sawDot && charCount > 3)
+             /* more than 3 chars in extension */
+             return 0;
+     }
+     return 1;
+ }
+ 
+ /*
+  * Number unparsing map for generating 8.3 names;
+  * The version taken from DFS was on drugs.  
+  * You can't include '&' and '@' in a file name.
+  */
+ char cm_8Dot3Mapping[42] =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
+  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
+  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '+', '='
+ };
+ int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
+ 
+ void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
+                         clientchar_t *shortName, clientchar_t **shortNameEndp)
+ {
+     char number[12];
+     int i, nsize = 0;
+     int vnode = ntohl(pfid->vnode);
+     char *lastDot;
+     int validExtension = 0;
+     char tc, *temp;
+     const char *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(longname, '.');
+     if (lastDot) {
+         temp = lastDot; temp++;
+         while (tc = *temp++)
+             if (ISLEGALCHAR(tc))
+                 break;
+         if (tc)
+             validExtension = 1;
+     }
+ 
+     /* Copy name characters */
+     for (i = 0, name = longname;
+           i < (7 - nsize) && name != lastDot; ) {
+         tc = *name++;
+ 
+         if (tc == 0)
+             break;
+         if (!ISLEGALCHAR(tc))
+             continue;
+         i++;
+         *shortName++ = toupper(tc);
+     }
+ 
+     /* tilde */
+     *shortName++ = '~';
+ 
+     /* Copy uniquifier characters */
+     for (i=0; i < nsize; i++) {
+         *shortName++ = number[i];
+     }
+ 
+     if (validExtension) {
+         /* Copy extension characters */
+         *shortName++ = *lastDot++;	/* copy dot */
+         for (i = 0, tc = *lastDot++;
+              i < 3 && tc;
+              tc = *lastDot++) {
+             if (ISLEGALCHAR(tc)) {
+                 i++;
+                 *shortName++ = toupper(tc);
+             }
+         }
+     }
+ 
+     /* Trailing null */
+     *shortName = 0;
+ 
+     if (shortNameEndp)
+         *shortNameEndp = shortName;
+ }
+ 
+ void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
+                          clientchar_t *shortName, clientchar_t **shortNameEndp)
+ {
+     clientchar_t number[12];
+     int i, nsize = 0;
+     int vnode = ntohl(pfid->vnode);
+     clientchar_t *lastDot;
+     int validExtension = 0;
+     clientchar_t tc, *temp;
+     const clientchar_t *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 = cm_ClientStrRChr(longname, '.');
+     if (lastDot) {
+         temp = lastDot; temp++;
+         while (tc = *temp++)
+             if (ISLEGALCHAR(tc))
+                 break;
+         if (tc)
+             validExtension = 1;
+     }
+ 
+     /* Copy name characters */
+     for (i = 0, name = longname;
+           i < (7 - nsize) && name != lastDot; ) {
+         tc = *name++;
+ 
+         if (tc == 0)
+             break;
+         if (!ISLEGALCHAR(tc))
+             continue;
+         i++;
+         *shortName++ = toupper((char) tc);
+     }
+ 
+     /* tilde */
+     *shortName++ = '~';
+ 
+     /* Copy uniquifier characters */
+     for (i=0; i < nsize; i++) {
+         *shortName++ = number[i];
+     }
+ 
+     if (validExtension) {
+         /* Copy extension characters */
+         *shortName++ = *lastDot++;	/* copy dot */
+         for (i = 0, tc = *lastDot++;
+              i < 3 && tc;
+              tc = *lastDot++) {
+             if (ISLEGALCHAR(tc)) {
+                 i++;
+                 *shortName++ = toupper(tc);
+             }
+         }
+     }
+ 
+     /* Trailing null */
+     *shortName = 0;
+ 
+     if (shortNameEndp)
+         *shortNameEndp = shortName;
+ }
+ 
+ /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
+ 
+   \note This procedure works recursively calling itself.
+ 
+   \param[in] pattern string containing metacharacters.
+   \param[in] name File name to be compared with 'pattern'.
+ 
+   \return BOOL : TRUE/FALSE (match/mistmatch)
+ */
+ static BOOL 
+ szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold) 
+ {
+     clientchar_t upattern[MAX_PATH];
+     clientchar_t uname[MAX_PATH];
+ 
+     clientchar_t * pename;         // points to the last 'name' character
+     clientchar_t * p;
+     clientchar_t * pattern_next;
+ 
+     if (casefold) {
+         cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
+         cm_ClientStrUpr(upattern);
+         pattern = upattern;
+ 
+         cm_ClientStrCpy(uname, lengthof(uname), name);
+         cm_ClientStrUpr(uname);
+         name = uname;
+ 
+         /* The following translations all work on single byte
+            characters */
+         for (p=upattern; *p; p++) {
+             if (*p == '"') *p = '.'; continue;
+             if (*p == '<') *p = '*'; continue;
+             if (*p == '>') *p = '?'; continue;
+         }
+ 
+         for (p=uname; *p; p++) {
+             if (*p == '"') *p = '.'; continue;
+             if (*p == '<') *p = '*'; continue;
+             if (*p == '>') *p = '?'; continue;
+         }
+     }
+ 
+     pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
+ 
+     while (*name) {
+         switch (*pattern) {
+         case '?':
+ 	    pattern = cm_ClientCharNext(pattern);
+             if (*name == '.')
+ 		continue;
+             name = cm_ClientCharNext(name);
+             break;
+ 
+          case '*':
+             pattern = cm_ClientCharNext(pattern);
+             if (*pattern == '\0')
+                 return TRUE;
+ 
+             pattern_next = cm_ClientCharNext(pattern);
+ 
+             for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
+                 if (*p == *pattern &&
+                     szWildCardMatchFileName(pattern_next,
+                                             cm_ClientCharNext(p), FALSE))
+                     return TRUE;
+             } /* endfor */
+             return FALSE;
+ 
+         default:
+             if (*name != *pattern)
+                 return FALSE;
+             pattern = cm_ClientCharNext(pattern);
+             name = cm_ClientCharNext(name);
+             break;
+         } /* endswitch */
+     } /* endwhile */
+ 
+     /* if all we have left are wildcards, then we match */
+     for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
+ 	if (*pattern != '*' && *pattern != '?')
+ 	    return FALSE;
+     }
+     return TRUE;
+ }
+ 
+ /* do a case-folding search of the star name mask with the name in namep.
+  * Return 1 if we match, otherwise 0.
+  */
+ int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
+ {
+     clientchar_t * newmask;
+     int    i, j, star, qmark, casefold, retval;
+ 
+     /* make sure we only match 8.3 names, if requested */
+     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
+         return 0;
+ 
+     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
+ 
+     /* optimize the pattern:
+      * if there is a mixture of '?' and '*',
+      * for example  the sequence "*?*?*?*"
+      * must be turned into the form "*"
+      */
+     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+1)*sizeof(clientchar_t));
+     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
+         switch ( maskp[i] ) {
+         case '?':
+         case '>':
+             qmark++;
+             break;
+         case '<':
+         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, casefold) ? 1:0;
+ 
+     free(newmask);
+     return retval;
+ }
+ 
Index: openafs/src/WINNT/afsd/cm_utils.h
diff -c openafs/src/WINNT/afsd/cm_utils.h:1.3 openafs/src/WINNT/afsd/cm_utils.h:1.3.20.3
*** openafs/src/WINNT/afsd/cm_utils.h:1.3	Tue Sep 18 00:26:54 2001
--- openafs/src/WINNT/afsd/cm_utils.h	Thu Jun 26 12:38:30 2008
***************
*** 12,19 ****
  
  #define CM_UTILS_SPACESIZE		8192	/* space to allocate */
  typedef struct cm_space {
! 	char data[CM_UTILS_SPACESIZE];
!         struct cm_space *nextp;
  } cm_space_t;
  
  /* error code hack */
--- 12,22 ----
  
  #define CM_UTILS_SPACESIZE		8192	/* space to allocate */
  typedef struct cm_space {
!     union {
!         clientchar_t wdata[CM_UTILS_SPACESIZE];
!         char data[CM_UTILS_SPACESIZE];
!     };
!     struct cm_space *nextp;
  } cm_space_t;
  
  /* error code hack */
***************
*** 25,31 ****
--- 28,54 ----
  extern void cm_FreeSpace(cm_space_t *);
  
  extern long cm_MapRPCError(long error, cm_req_t *reqp);
+ 
  extern long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp);
+ 
  extern long cm_MapVLRPCError(long error, cm_req_t *reqp);
  
+ extern void init_et_to_sys_error(void);
+ 
+ extern int cm_Is8Dot3(clientchar_t *namep);
+ 
+ extern void cm_Gen8Dot3Name(struct cm_dirEntry *dep, clientchar_t *shortName,
+                             clientchar_t **shortNameEndp);
+ 
+ #define cm_Gen8Dot3Name(dep,shortName,shortNameEndp)                  \
+ cm_Gen8Dot3NameInt((dep)->name, &(dep)->fid, shortName, shortNameEndp)
+ 
+ extern void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
+                                clientchar_t *shortName, clientchar_t **shortNameEndp);
+ 
+ extern void cm_Gen8Dot3NameIntW(const clientchar_t* longname, cm_dirFid_t * pfid,
+                                 clientchar_t *shortName, clientchar_t **shortNameEndp);
+ 
+ extern int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags);
+ 
  #endif /*  __CM_UTILS_H_ENV__ */
Index: openafs/src/WINNT/afsd/cm_vnodeops.c
diff -c openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.74.2.2 openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.82
*** openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.74.2.2	Sun Jun 22 23:05:03 2008
--- openafs/src/WINNT/afsd/cm_vnodeops.c	Wed Jul 16 11:23:46 2008
***************
*** 10,19 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
- #endif /* !DJGPP */
  #include <stddef.h>
  #include <malloc.h>
  #include <string.h>
--- 10,17 ----
***************
*** 23,30 ****
--- 21,31 ----
  #include <osi.h>
  
  #include "afsd.h"
+ #include "smb.h"
  #include "cm_btree.h"
  
+ #include <strsafe.h>
+ 
  #ifdef DEBUG
  extern void afsi_log(char *pattern, ...);
  #endif
***************
*** 98,253 ****
      }
  }
  
- /* characters that are legal in an 8.3 name */
- /*
-  * We used to have 1's for all characters from 128 to 254.  But
-  * the NT client behaves better if we create an 8.3 name for any
-  * name that has a character with the high bit on, and if we
-  * delete those characters from 8.3 names.  In particular, see
-  * Sybase defect 10859.
-  */
- char cm_LegalChars[256] = {
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- 
- /* return true iff component is a valid 8.3 name */
- int cm_Is8Dot3(char *namep)
- {
-     int sawDot = 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] == '.' && 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;
-         charCount++;
-         if (!sawDot && charCount > 8)
-             /* more than 8 chars in name */
-             return 0;
-         if (sawDot && charCount > 3)
-             /* more than 3 chars in extension */
-             return 0;
-     }
-     return 1;
- }
- 
- /*
-  * Number unparsing map for generating 8.3 names;
-  * The version taken from DFS was on drugs.  
-  * You can't include '&' and '@' in a file name.
-  */
- char cm_8Dot3Mapping[42] =
- {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
-  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
-  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '+', '='
- };
- int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
- 
- void cm_Gen8Dot3NameInt(const char * longname, cm_dirFid_t * pfid,
-                         char *shortName, char **shortNameEndp)
- {
-     char number[12];
-     int i, nsize = 0;
-     int vnode = ntohl(pfid->vnode);
-     char *lastDot;
-     int validExtension = 0;
-     char tc, *temp;
-     const char *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(longname, '.');
-     if (lastDot) {
-         temp = lastDot; temp++;
-         while (tc = *temp++)
-             if (cm_LegalChars[tc])
-                 break;
-         if (tc)
-             validExtension = 1;
-     }
- 
-     /* Copy name characters */
-     for (i = 0, name = longname;
-           i < (7 - nsize) && 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 < 3 && 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,
--- 99,105 ----
***************
*** 577,584 ****
   * cm_lookupSearch_t object.  
   */
  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 ----
   * cm_lookupSearch_t object.  
   */
  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;
***************
*** 648,654 ****
                  if (code == 0) {
  
  #ifdef USE_BPLUS
!                     code = cm_BPlusDirLookup(&dirop, sp->searchNamep, &sp->fid);
                      if (code != EINVAL)
                          usedBplus = 1;
                      else 
--- 500,506 ----
                  if (code == 0) {
  
  #ifdef USE_BPLUS
!                     code = cm_BPlusDirLookup(&dirop, sp->nsearchNamep, &sp->fid);
                      if (code != EINVAL)
                          usedBplus = 1;
                      else 
***************
*** 848,865 ****
      return code;
  }
  
! int cm_NoneUpper(char *s)
  {
!     char c;
      while (c = *s++)
          if (c >= 'A' && c <= 'Z')
              return 0;
      return 1;
  }
  
! int cm_NoneLower(char *s)
  {
!     char c;
      while (c = *s++)
          if (c >= 'a' && c <= 'z')
              return 0;
--- 700,717 ----
      return code;
  }
  
! int cm_NoneUpper(normchar_t *s)
  {
!     normchar_t c;
      while (c = *s++)
          if (c >= 'A' && c <= 'Z')
              return 0;
      return 1;
  }
  
! int cm_NoneLower(normchar_t *s)
  {
!     normchar_t c;
      while (c = *s++)
          if (c >= 'a' && c <= 'z')
              return 0;
***************
*** 867,896 ****
  }
  
  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->name;
      if (sp->caseFold)
!         match = cm_stricmp(matchName, sp->searchNamep);
      else
!         match = strcmp(matchName, sp->searchNamep);
  
      if (match != 0
!          && sp->hasTilde
!          && !cm_Is8Dot3(dep->name)) {
!         matchName = shortName;
!         cm_Gen8Dot3Name(dep, shortName, NULL);
          if (sp->caseFold)
!             match = cm_stricmp(matchName, sp->searchNamep);
          else
!             match = strcmp(matchName, sp->searchNamep);
      }
  
      if (match != 0)
--- 719,749 ----
  }
  
  long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
!                          osi_hyper_t *offp)
  {
      cm_lookupSearch_t *sp;
      int match;
!     normchar_t matchName[MAX_PATH];
!     int looking_for_short_name = FALSE;
  
      sp = (cm_lookupSearch_t *) rockp;
  
!     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
      if (sp->caseFold)
!         match = cm_NormStrCmpI(matchName, sp->nsearchNamep);
      else
!         match = cm_NormStrCmp(matchName, sp->nsearchNamep);
  
      if (match != 0
!         && sp->hasTilde
!         && !cm_Is8Dot3(matchName)) {
! 
!         cm_Gen8Dot3NameInt(dep->name, &dep->fid, matchName, NULL);
          if (sp->caseFold)
!             match = cm_NormStrCmpI(matchName, sp->nsearchNamep);
          else
!             match = cm_NormStrCmp(matchName, sp->nsearchNamep);
!         looking_for_short_name = TRUE;
      }
  
      if (match != 0)
***************
*** 900,906 ****
      if (!sp->caseFold) 
          sp->ExactFound = 1;
  
!     if (!sp->caseFold || matchName == shortName) {
          cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
          return CM_ERROR_STOPNOW;
      }
--- 753,759 ----
      if (!sp->caseFold) 
          sp->ExactFound = 1;
  
!     if (!sp->caseFold || looking_for_short_name) {
          cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
          return CM_ERROR_STOPNOW;
      }
***************
*** 913,919 ****
       */
  
      /* Exact matches are the best. */
!     match = strcmp(matchName, sp->searchNamep);
      if (match == 0) {
          sp->ExactFound = 1;
          cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
--- 766,772 ----
       */
  
      /* Exact matches are the best. */
!     match = cm_NormStrCmp(matchName, sp->nsearchNamep);
      if (match == 0) {
          sp->ExactFound = 1;
          cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
***************
*** 1024,1038 ****
  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 = NULL;
      cm_cell_t *cellp;
!     char mtType;
      cm_fid_t tfid;
      size_t vnLength;
      int targetType;
--- 877,891 ----
  long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
                           cm_req_t *reqp, cm_scache_t **outScpp)
  {
!     fschar_t *cellNamep = NULL;
!     fschar_t *volNamep = NULL;
      int tlen;
!     afs_uint32 code;
!     fschar_t *cp;
!     fschar_t *mpNamep;
      cm_volume_t *volp = NULL;
      cm_cell_t *cellp;
!     fschar_t mtType;
      cm_fid_t tfid;
      size_t vnLength;
      int targetType;
***************
*** 1049,1073 ****
      mpNamep = scp->mountPointStringp;
      if (!mpNamep[0])
  	return CM_ERROR_NOSUCHPATH;
!     tlen = (int)strlen(scp->mountPointStringp);
      mtType = *scp->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 */
          lock_ReleaseWrite(&scp->rw);
          cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
          lock_ObtainWrite(&scp->rw);
!     }
!     else {
          /* normal mt pt */
!         strcpy(volNamep, mpNamep+1);
  
          cellp = cm_FindCellByID(scp->fid.cell, 0);
      }
--- 902,924 ----
      mpNamep = scp->mountPointStringp;
      if (!mpNamep[0])
  	return CM_ERROR_NOSUCHPATH;
!     tlen = cm_FsStrLen(scp->mountPointStringp);
      mtType = *scp->mountPointStringp;
  
!     cp = cm_FsStrChr(mpNamep, _FS(':'));
      if (cp) {
          /* cellular mount point */
!         cellNamep = (fschar_t *)malloc((cp - mpNamep) * sizeof(fschar_t));
!         cm_FsStrCpyN(cellNamep, cp - mpNamep, mpNamep + 1, cp - mpNamep - 1);
!         volNamep = cm_FsStrDup(cp+1);
! 
          /* now look up the cell */
          lock_ReleaseWrite(&scp->rw);
          cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
          lock_ObtainWrite(&scp->rw);
!     } else {
          /* normal mt pt */
!         volNamep = cm_FsStrDup(mpNamep + 1);
  
          cellp = cm_FindCellByID(scp->fid.cell, 0);
      }
***************
*** 1077,1087 ****
          goto done;
      }
  
!     vnLength = strlen(volNamep);
!     if (vnLength >= 8 && strcmp(volNamep + vnLength - 7, ".backup") == 0)
          targetType = BACKVOL;
      else if (vnLength >= 10
!               && strcmp(volNamep + vnLength - 9, ".readonly") == 0)
          targetType = ROVOL;
      else
          targetType = RWVOL;
--- 928,938 ----
          goto done;
      }
  
!     vnLength = cm_FsStrLen(volNamep);
!     if (vnLength >= 8 && cm_FsStrCmp(volNamep + vnLength - 7, ".backup") == 0)
          targetType = BACKVOL;
      else if (vnLength >= 10
!              && cm_FsStrCmp(volNamep + vnLength - 9, ".readonly") == 0)
          targetType = ROVOL;
      else
          targetType = RWVOL;
***************
*** 1153,1164 ****
    done:
      if (volp)
  	cm_PutVolume(volp);
!     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;
--- 1004,1017 ----
    done:
      if (volp)
  	cm_PutVolume(volp);
!     if (cellNamep)
!         free(cellNamep);
!     if (volNamep)
!         free(volNamep);
      return code;
  }       
  
! long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_user_t *userp,
                         cm_req_t *reqp, cm_scache_t **outpScpp)
  {
      long code;
***************
*** 1167,1186 ****
      cm_scache_t *mountedScp;
      cm_lookupSearch_t rock;
      int getroot;
  
      memset(&rock, 0, sizeof(rock));
  
      if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
!          && strcmp(namep, "..") == 0) {
          if (dscp->dotdotFid.volume == 0)
              return CM_ERROR_NOSUCHVOLUME;
          rock.fid = dscp->dotdotFid;
          goto haveFid;
!     } else if (strcmp(namep, ".") == 0) {
  	rock.fid = dscp->fid;
  	goto haveFid;
      }
  
      if (flags & CM_FLAG_NOMOUNTCHASE) {
          /* In this case, we should go and call cm_Dir* functions
             directly since the following cm_ApplyDir() function will
--- 1020,1044 ----
      cm_scache_t *mountedScp;
      cm_lookupSearch_t rock;
      int getroot;
+     normchar_t *nnamep = NULL;
+     fschar_t *fnamep = NULL;
  
      memset(&rock, 0, sizeof(rock));
  
      if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
!         && cm_ClientStrCmp(cnamep, _C("..")) == 0) {
          if (dscp->dotdotFid.volume == 0)
              return CM_ERROR_NOSUCHVOLUME;
          rock.fid = dscp->dotdotFid;
          goto haveFid;
!     } else if (cm_ClientStrCmp(cnamep, _C(".")) == 0) {
  	rock.fid = dscp->fid;
  	goto haveFid;
      }
  
+     nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
+     fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+ 
      if (flags & CM_FLAG_NOMOUNTCHASE) {
          /* In this case, we should go and call cm_Dir* functions
             directly since the following cm_ApplyDir() function will
***************
*** 1194,1205 ****
          code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
          if (code == 0) {
  #ifdef USE_BPLUS
!             code = cm_BPlusDirLookup(&dirop, namep, &rock.fid);
              if (code != EINVAL)
                  usedBplus = 1;
              else
  #endif
!                 code = cm_DirLookup(&dirop, namep, &rock.fid);
  
              cm_EndDirOp(&dirop);
          }
--- 1052,1063 ----
          code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
          if (code == 0) {
  #ifdef USE_BPLUS
!             code = cm_BPlusDirLookup(&dirop, nnamep, &rock.fid);
              if (code != EINVAL)
                  usedBplus = 1;
              else
  #endif
!                 code = cm_DirLookup(&dirop, fnamep, &rock.fid);
  
              cm_EndDirOp(&dirop);
          }
***************
*** 1225,1237 ****
  
      rock.fid.cell = dscp->fid.cell;
      rock.fid.volume = dscp->fid.volume;
!     rock.searchNamep = namep;
      rock.caseFold = (flags & 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, &rock, NULL, userp, reqp,
!                         (flags & CM_FLAG_NOMOUNTCHASE) ? NULL : &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
--- 1083,1096 ----
  
      rock.fid.cell = dscp->fid.cell;
      rock.fid.volume = dscp->fid.volume;
!     rock.searchNamep = fnamep;
!     rock.nsearchNamep = nnamep;
      rock.caseFold = (flags & CM_FLAG_CASEFOLD);
!     rock.hasTilde = ((cm_ClientStrChr(cnamep, '~') != NULL) ? 1 : 0);
  
      /* If NOMOUNTCHASE, bypass DNLC by passing NULL scp pointer */
      code = cm_ApplyDir(dscp, cm_LookupSearchProc, &rock, NULL, userp, reqp,
!                        (flags & CM_FLAG_NOMOUNTCHASE) ? NULL : &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
***************
*** 1244,1274 ****
           */
          if (code == CM_ERROR_NOTDIR) {
              if (flags & CM_FLAG_CHECKPATH)
!                 return CM_ERROR_NOSUCHPATH;
              else
!                 return CM_ERROR_NOSUCHFILE;
          }
!         return code;
      }
  
      getroot = (dscp==cm_data.rootSCachep) ;
      if (!rock.found) {
          if (!cm_freelanceEnabled || !getroot) {
              if (flags & CM_FLAG_CHECKPATH)
!                 return CM_ERROR_NOSUCHPATH;
              else
!                 return CM_ERROR_NOSUCHFILE;
          }
!         else if (!strchr(namep, '#') && !strchr(namep, '%') &&
!                  strcmp(namep, "srvsvc") && strcmp(namep, "wkssvc") &&
!                  strcmp(namep, "ipc$")) 
          {
              /* nonexistent dir on freelance root, so add it */
!             char fullname[200] = ".";
              int  found = 0;
  
!             osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s", 
!                       osi_LogSaveString(afsd_logp,namep));
  
              /* 
               * There is an ugly behavior where a share name "foo" will be searched
--- 1103,1136 ----
           */
          if (code == CM_ERROR_NOTDIR) {
              if (flags & CM_FLAG_CHECKPATH)
!                 code = CM_ERROR_NOSUCHPATH;
              else
!                 code = CM_ERROR_NOSUCHFILE;
          }
!         goto done;
      }
  
      getroot = (dscp==cm_data.rootSCachep) ;
      if (!rock.found) {
          if (!cm_freelanceEnabled || !getroot) {
              if (flags & CM_FLAG_CHECKPATH)
!                 code = CM_ERROR_NOSUCHPATH;
              else
!                 code = CM_ERROR_NOSUCHFILE;
!             goto done;
          }
!         else if (!cm_ClientStrChr(cnamep, '#') &&
!                  !cm_ClientStrChr(cnamep, '%') &&
!                  cm_ClientStrCmpI(cnamep, _C("srvsvc")) &&
!                  cm_ClientStrCmpI(cnamep, _C("wkssvc")) &&
!                  cm_ClientStrCmpI(cnamep, _C("ipc$"))) 
          {
              /* nonexistent dir on freelance root, so add it */
!             fschar_t fullname[200] = ".";
              int  found = 0;
  
!             osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %S", 
!                      osi_LogSaveClientString(afsd_logp,cnamep));
  
              /* 
               * There is an ugly behavior where a share name "foo" will be searched
***************
*** 1278,1316 ****
               */
  
              code = -1;
!             if (namep[0] == '.') {
!                 if (cm_GetCell_Gen(&namep[1], &fullname[1], CM_FLAG_CREATE)) {
                      found = 1;
                      if (!cm_FreelanceMountPointExists(fullname, 0))
!                         code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.", 1, &rock.fid);
!                     if ( stricmp(&namep[1], &fullname[1]) && 
! 						!cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
! 						!cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
!                         code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
                  }
              } else {
!                 if (cm_GetCell_Gen(namep, fullname, CM_FLAG_CREATE)) {
                      found = 1;
                      if (!cm_FreelanceMountPointExists(fullname, 0))
                          code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
!                     if ( stricmp(namep, fullname) && 
! 						!cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
! 						!cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
!                         code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
                  }
              }
              if (!found || code < 0) {   /* add mount point failed, so give up */
                  if (flags & CM_FLAG_CHECKPATH)
!                     return CM_ERROR_NOSUCHPATH;
                  else
!                     return CM_ERROR_NOSUCHFILE;
              }
              tscp = NULL;   /* to force call of cm_GetSCache */
          } else {
              if (flags & CM_FLAG_CHECKPATH)
!                 return CM_ERROR_NOSUCHPATH;
              else
!                 return CM_ERROR_NOSUCHFILE;
          }
      }
  
--- 1140,1181 ----
               */
  
              code = -1;
!             if (cnamep[0] == '.') {
!                 if (cm_GetCell_Gen(&fnamep[1], &fullname[1], CM_FLAG_CREATE)) {
                      found = 1;
                      if (!cm_FreelanceMountPointExists(fullname, 0))
!                         code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.",
!                                                     1, &rock.fid);
!                     if ( cm_FsStrCmpI(&fnamep[1], &fullname[1]) && 
!                          !cm_FreelanceMountPointExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
!                          !cm_FreelanceSymlinkExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
!                         code = cm_FreelanceAddSymlink(fnamep, fullname, &rock.fid);
                  }
              } else {
!                 if (cm_GetCell_Gen(fnamep, fullname, CM_FLAG_CREATE)) {
                      found = 1;
                      if (!cm_FreelanceMountPointExists(fullname, 0))
                          code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
!                     if ( cm_FsStrCmpI(fnamep, fullname) && 
!                          !cm_FreelanceMountPointExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
!                          !cm_FreelanceSymlinkExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
!                         code = cm_FreelanceAddSymlink(fnamep, fullname, &rock.fid);
                  }
              }
              if (!found || code < 0) {   /* add mount point failed, so give up */
                  if (flags & CM_FLAG_CHECKPATH)
!                     code = CM_ERROR_NOSUCHPATH;
                  else
!                     code = CM_ERROR_NOSUCHFILE;
!                 goto done;
              }
              tscp = NULL;   /* to force call of cm_GetSCache */
          } else {
              if (flags & CM_FLAG_CHECKPATH)
!                 code = CM_ERROR_NOSUCHPATH;
              else
!                 code = CM_ERROR_NOSUCHFILE;
!             goto done;
          }
      }
  
***************
*** 1320,1327 ****
          dnlcHit = 0; 
          code = cm_GetSCache(&rock.fid, &tscp, userp, reqp);
          if (code) 
!             return code;
!     }       
      /* tscp is now held */
  
      lock_ObtainWrite(&tscp->rw);
--- 1185,1192 ----
          dnlcHit = 0; 
          code = cm_GetSCache(&rock.fid, &tscp, userp, reqp);
          if (code) 
!             goto done;
!     }
      /* tscp is now held */
  
      lock_ObtainWrite(&tscp->rw);
***************
*** 1330,1336 ****
      if (code) { 
          lock_ReleaseWrite(&tscp->rw);
          cm_ReleaseSCache(tscp);
!         return code;
      }
      cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
      /* tscp is now locked */
--- 1195,1201 ----
      if (code) { 
          lock_ReleaseWrite(&tscp->rw);
          cm_ReleaseSCache(tscp);
!         goto done;
      }
      cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
      /* tscp is now locked */
***************
*** 1343,1354 ****
          code = cm_ReadMountPoint(tscp, userp, reqp);
          if (code == 0)
              code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
!                                         &mountedScp);
          lock_ReleaseWrite(&tscp->rw);
          cm_ReleaseSCache(tscp);
!         if (code) {
!             return code;
!         }
          tscp = mountedScp;
      }
      else {
--- 1208,1219 ----
          code = cm_ReadMountPoint(tscp, userp, reqp);
          if (code == 0)
              code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
!                                        &mountedScp);
          lock_ReleaseWrite(&tscp->rw);
          cm_ReleaseSCache(tscp);
!         if (code)
!             goto done;
! 
          tscp = mountedScp;
      }
      else {
***************
*** 1362,1386 ****
      if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
          /* lock the directory entry to prevent racing callback revokes */
          lock_ObtainRead(&dscp->rw);
!         if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 )
!             cm_dnlcEnter(dscp, namep, tscp);
          lock_ReleaseRead(&dscp->rw);
      }
  
      /* 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 */
--- 1227,1266 ----
      if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
          /* lock the directory entry to prevent racing callback revokes */
          lock_ObtainRead(&dscp->rw);
!         if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 ) {
!             /* TODO: reuse nnamep from above */
!             if (nnamep) 
!                 free(nnamep);
!             nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
!             cm_dnlcEnter(dscp, nnamep, tscp);
!         }
          lock_ReleaseRead(&dscp->rw);
      }
  
      /* and return */
!   done:
!     if (fnamep) {
!         free (fnamep);
!         fnamep = NULL;
!     }
!     if (nnamep) {
!         free (nnamep);
!         nnamep = NULL;
!     }
! 
!     return code;
  }
  
! int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
  {
!     clientchar_t *tp;
      int prefixCount;
  
!     tp = cm_ClientStrRChr(inp, '@');
      if (tp == NULL) 
          return 0;		/* no @sys */
  
!     if (cm_ClientStrCmp(tp, _C("@sys")) != 0) 
          return 0;	/* no @sys */
  
      /* caller just wants to know if this is a valid @sys type of name */
***************
*** 1393,1413 ****
      /* otherwise generate the properly expanded @sys name */
      prefixCount = (int)(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_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
                                  cm_req_t *reqp, cm_scache_t ** outpScpp)
  {
!     long          code = 0;
!     char          cellName[CELL_MAXNAMELEN];
!     char          volumeName[VL_MAXNAMELEN];
      size_t        len;
!     char *        cp;
!     char *        tp;
  
      cm_cell_t *   cellp = NULL;
      cm_volume_t * volp = NULL;
--- 1273,1294 ----
      /* otherwise generate the properly expanded @sys name */
      prefixCount = (int)(tp - inp);
  
!     cm_ClientStrCpyN(outp, outSizeCch, inp, prefixCount);	/* copy out "a." from "a.@sys" */
      outp[prefixCount] = 0;		/* null terminate the "a." */
!     cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);/* append i386_nt40 */
      return 1;
  }   
  
! long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
                                  cm_req_t *reqp, cm_scache_t ** outpScpp)
  {
!     afs_uint32    code = 0;
!     fschar_t      cellName[CELL_MAXNAMELEN];
!     fschar_t      volumeName[VL_MAXNAMELEN];
      size_t        len;
!     fschar_t *        cp;
!     fschar_t *        tp;
!     fschar_t *        fnamep = NULL;
  
      cm_cell_t *   cellp = NULL;
      cm_volume_t * volp = NULL;
***************
*** 1416,1425 ****
      int           volType;
      int           mountType = RWVOL;
  
!     osi_Log1(afsd_logp, "cm_EvaluateVolumeReference for string [%s]",
!              osi_LogSaveString(afsd_logp, namep));
  
!     if (strnicmp(namep, CM_PREFIX_VOL, CM_PREFIX_VOL_CCH) != 0) {
          goto _exit_invalid_path;
      }
  
--- 1297,1306 ----
      int           volType;
      int           mountType = RWVOL;
  
!     osi_Log1(afsd_logp, "cm_EvaluateVolumeReference for string [%S]",
!              osi_LogSaveClientString(afsd_logp, namep));
  
!     if (cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) != 0) {
          goto _exit_invalid_path;
      }
  
***************
*** 1431,1469 ****
  
       */
  
!     cp = namep + CM_PREFIX_VOL_CCH; /* cp points to cell name, hopefully */
!     tp = strchr(cp, '%');
      if (tp == NULL)
!         tp = strchr(cp, '#');
      if (tp == NULL ||
          (len = tp - cp) == 0 ||
          len > CELL_MAXNAMELEN)
          goto _exit_invalid_path;
!     strncpy(cellName, cp, len);
!     cellName[len] = '\0';
  
      if (*tp == '#')
          mountType = ROVOL;
  
      cp = tp+1;                  /* cp now points to volume, supposedly */
!     strncpy(volumeName, cp, VL_MAXNAMELEN-1);
!     volumeName[VL_MAXNAMELEN - 1] = 0;
  
      /* OK, now we have the cell and the volume */
      osi_Log2(afsd_logp, "   Found cell [%s] and volume [%s]",
!              osi_LogSaveString(afsd_logp, cellName),
!              osi_LogSaveString(afsd_logp, volumeName));
  
      cellp = cm_GetCell(cellName, CM_FLAG_CREATE);
      if (cellp == NULL) {
          goto _exit_invalid_path;
      }
  
!     len = strlen(volumeName);
!     if (len >= 8 && strcmp(volumeName + len - 7, ".backup") == 0)
          volType = BACKVOL;
      else if (len >= 10 &&
!              strcmp(volumeName + len - 9, ".readonly") == 0)
          volType = ROVOL;
      else
          volType = RWVOL;
--- 1312,1349 ----
  
       */
  
!     fnamep = cm_ClientStringToFsStringAlloc(namep, -1, NULL);
!     cp = fnamep + CM_PREFIX_VOL_CCH; /* cp points to cell name, hopefully */
!     tp = cm_FsStrChr(cp, '%');
      if (tp == NULL)
!         tp = cm_FsStrChr(cp, '#');
      if (tp == NULL ||
          (len = tp - cp) == 0 ||
          len > CELL_MAXNAMELEN)
          goto _exit_invalid_path;
!     cm_FsStrCpyN(cellName, lengthof(cellName), cp, len);
  
      if (*tp == '#')
          mountType = ROVOL;
  
      cp = tp+1;                  /* cp now points to volume, supposedly */
!     cm_FsStrCpy(volumeName, lengthof(volumeName), cp);
  
      /* OK, now we have the cell and the volume */
      osi_Log2(afsd_logp, "   Found cell [%s] and volume [%s]",
!              osi_LogSaveFsString(afsd_logp, cellName),
!              osi_LogSaveFsString(afsd_logp, volumeName));
  
      cellp = cm_GetCell(cellName, CM_FLAG_CREATE);
      if (cellp == NULL) {
          goto _exit_invalid_path;
      }
  
!     len = cm_FsStrLen(volumeName);
!     if (len >= 8 && cm_FsStrCmp(volumeName + len - 7, ".backup") == 0)
          volType = BACKVOL;
      else if (len >= 10 &&
!              cm_FsStrCmp(volumeName + len - 9, ".readonly") == 0)
          volType = ROVOL;
      else
          volType = RWVOL;
***************
*** 1491,1497 ****
  
      code = cm_GetSCache(&fid, outpScpp, userp, reqp);
  
!  _exit_cleanup:
      if (volp)
          cm_PutVolume(volp);
  
--- 1371,1380 ----
  
      code = cm_GetSCache(&fid, outpScpp, userp, reqp);
  
!   _exit_cleanup:
!     if (fnamep)
!         free(fnamep);
! 
      if (volp)
          cm_PutVolume(volp);
  
***************
*** 1506,1520 ****
  }
  
  #ifdef DEBUG_REFCOUNT
! long cm_LookupDbg(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
                 cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
  #else
! long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
                 cm_req_t *reqp, cm_scache_t **outpScpp)
  #endif
  {
      long code;
!     char tname[AFSPATHMAX];
      int sysNameIndex = 0;
      cm_scache_t *scp = NULL;
  
--- 1389,1403 ----
  }
  
  #ifdef DEBUG_REFCOUNT
! long cm_LookupDbg(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
                 cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
  #else
! long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
                 cm_req_t *reqp, cm_scache_t **outpScpp)
  #endif
  {
      long code;
!     clientchar_t tname[AFSPATHMAX];
      int sysNameIndex = 0;
      cm_scache_t *scp = NULL;
  
***************
*** 1523,1529 ****
      osi_Log2(afsd_logp, "cm_Lookup dscp 0x%p ref %d", dscp, dscp->refCount);
  #endif
  
!     if ( stricmp(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
          if (flags & CM_FLAG_CHECKPATH)
              return CM_ERROR_NOSUCHPATH;
          else
--- 1406,1412 ----
      osi_Log2(afsd_logp, "cm_Lookup dscp 0x%p ref %d", dscp, dscp->refCount);
  #endif
  
!     if ( cm_ClientStrCmpI(namep,_C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ) {
          if (flags & CM_FLAG_CHECKPATH)
              return CM_ERROR_NOSUCHPATH;
          else
***************
*** 1531,1543 ****
      }
  
      if (dscp == cm_data.rootSCachep &&
!         strnicmp(namep, CM_PREFIX_VOL, CM_PREFIX_VOL_CCH) == 0) {
          return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outpScpp);
      }
  
      if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
          for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
!             code = cm_ExpandSysName(namep, tname, sizeof(tname), sysNameIndex);
              if (code > 0) {
                  code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
  #ifdef DEBUG_REFCOUNT
--- 1414,1426 ----
      }
  
      if (dscp == cm_data.rootSCachep &&
!         cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) == 0) {
          return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outpScpp);
      }
  
      if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
          for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
!             code = cm_ExpandSysName(namep, tname, lengthof(tname), sysNameIndex);
              if (code > 0) {
                  code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
  #ifdef DEBUG_REFCOUNT
***************
*** 1580,1586 ****
          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;
--- 1463,1490 ----
          return CM_ERROR_NOSUCHFILE;
  }
  
! /*! \brief Unlink a file name
! 
!   Encapsulates a call to RXAFS_RemoveFile().
! 
!   \param[in] dscp cm_scache_t pointing at the directory containing the
!       name to be unlinked.
! 
!   \param[in] fnamep Original name to be unlinked.  This is the
!       name that will be passed into the RXAFS_RemoveFile() call.
!       This parameter is optional.  If not provided, the value will
!       be looked up.
! 
!   \param[in] came Client name to be unlinked.  This name will be used
!       to update the local directory caches.
! 
!   \param[in] userp cm_user_t for the request.
! 
!   \param[in] reqp Request tracker.
!  
!  */
! long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
!                cm_user_t *userp, cm_req_t *reqp)
  {
      long code;
      cm_conn_t *connp;
***************
*** 1591,1606 ****
      struct rx_connection * callp;
      cm_dirOp_t dirop;
      cm_scache_t *scp = NULL;
  
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
          /* deleting a mount point from the root dir. */
!         code = cm_FreelanceRemoveMount(namep);
!         return code;
      }
  #endif  
  
!     code = cm_Lookup(dscp, namep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
  
      /* make sure we don't screw up the dir status during the merge */
      code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
--- 1495,1526 ----
      struct rx_connection * callp;
      cm_dirOp_t dirop;
      cm_scache_t *scp = NULL;
+     int free_fnamep = FALSE;
+ 
+     if (fnamep == NULL) {
+         code = -1;
+ #ifdef USE_BPLUS
+         code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+         if (code == 0) {
+             code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
+             if (code == 0)
+                 free_fnamep = TRUE;
+             cm_EndDirOp(&dirop);
+         }
+ #endif
+         if (code)
+             goto done;
+     }
  
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
          /* deleting a mount point from the root dir. */
!         code = cm_FreelanceRemoveMount(fnamep);
!         goto done;
      }
  #endif  
  
!     code = cm_Lookup(dscp, cnamep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
  
      /* make sure we don't screw up the dir status during the merge */
      code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
***************
*** 1611,1617 ****
      lock_ReleaseWrite(&dscp->rw);
      if (code) {
          cm_EndDirOp(&dirop);
!         return code;
      }
  
      /* make the RPC */
--- 1531,1537 ----
      lock_ReleaseWrite(&dscp->rw);
      if (code) {
          cm_EndDirOp(&dirop);
!         goto done;
      }
  
      /* make the RPC */
***************
*** 1622,1633 ****
      osi_Log1(afsd_logp, "CALL RemoveFile scp 0x%p", dscp);
      do {
          code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
!         if (code) 
              continue;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_RemoveFile(callp, &afsFid, namep,
!                                  &newDirStatus, &volSync);
          rx_PutConnection(callp);
  
      } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
--- 1542,1553 ----
      osi_Log1(afsd_logp, "CALL RemoveFile scp 0x%p", dscp);
      do {
          code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
!         if (code)
              continue;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_RemoveFile(callp, &afsFid, fnamep,
!                                 &newDirStatus, &volSync);
          rx_PutConnection(callp);
  
      } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
***************
*** 1643,1649 ****
          dirop.lockType = CM_DIRLOCK_WRITE;
      }
      lock_ObtainWrite(&dscp->rw);
!     cm_dnlcRemove(dscp, namep);
      cm_SyncOpDone(dscp, NULL, sflags);
      if (code == 0) {
          cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
--- 1563,1569 ----
          dirop.lockType = CM_DIRLOCK_WRITE;
      }
      lock_ObtainWrite(&dscp->rw);
!     cm_dnlcRemove(dscp, cnamep);
      cm_SyncOpDone(dscp, NULL, sflags);
      if (code == 0) {
          cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
***************
*** 1656,1665 ****
      }
      lock_ReleaseWrite(&dscp->rw);
  
!     if (code == 0 && cm_CheckDirOpForSingleChange(&dirop)) {
!         cm_DirDeleteEntry(&dirop, namep);
  #ifdef USE_BPLUS
!         cm_BPlusDirDeleteEntry(&dirop, namep);
  #endif
      }
      cm_EndDirOp(&dirop);
--- 1576,1585 ----
      }
      lock_ReleaseWrite(&dscp->rw);
  
!     if (code == 0 && cm_CheckDirOpForSingleChange(&dirop) && cnamep) {
!         cm_DirDeleteEntry(&dirop, fnamep);
  #ifdef USE_BPLUS
!         cm_BPlusDirDeleteEntry(&dirop, cnamep);
  #endif
      }
      cm_EndDirOp(&dirop);
***************
*** 1673,1678 ****
--- 1593,1602 ----
          }
      }
  
+   done:
+     if (free_fnamep)
+         free(fnamep);
+ 
      return code;
  }
  
***************
*** 1744,1756 ****
   * 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 = 0;
      long len;
!     char *linkp;
      cm_space_t *tsp;
  
      *newRootScpp = NULL;
--- 1668,1680 ----
   * 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, fschar_t *pathSuffixp,
!                      cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
!                      cm_user_t *userp, cm_req_t *reqp)
  {
      long code = 0;
      long len;
!     fschar_t *linkp;
      cm_space_t *tsp;
  
      *newRootScpp = NULL;
***************
*** 1765,1781 ****
       * bigger than max path length, so we don't really have to worry about
       * being a little conservative here.
       */
!     if (strlen(linkScp->mountPointStringp) + strlen(pathSuffixp) + 2
! 		>= CM_UTILS_SPACESIZE) {
          code = CM_ERROR_TOOBIG;
! 		goto done;
! 	}
  
      tsp = cm_GetSpace();
      linkp = linkScp->mountPointStringp;
      if (strncmp(linkp, cm_mountRoot, cm_mountRootLen) == 0) {
          if (strlen(linkp) > cm_mountRootLen)
!             strcpy(tsp->data, linkp+cm_mountRootLen+1);
          else
              tsp->data[0] = 0;
          *newRootScpp = cm_data.rootSCachep;
--- 1689,1705 ----
       * bigger than max path length, so we don't really have to worry about
       * being a little conservative here.
       */
!     if (cm_FsStrLen(linkScp->mountPointStringp) + cm_FsStrLen(pathSuffixp) + 2
!         >= CM_UTILS_SPACESIZE) {
          code = CM_ERROR_TOOBIG;
!         goto done;
!     }
  
      tsp = cm_GetSpace();
      linkp = linkScp->mountPointStringp;
      if (strncmp(linkp, cm_mountRoot, cm_mountRootLen) == 0) {
          if (strlen(linkp) > cm_mountRootLen)
!             StringCbCopyA((char *) tsp->data, sizeof(tsp->data), linkp+cm_mountRootLen+1);
          else
              tsp->data[0] = 0;
          *newRootScpp = cm_data.rootSCachep;
***************
*** 1787,1793 ****
              if (strnicmp(p, "all", 3) == 0)
                  p += 4;
  
!             strcpy(tsp->data, p);
              for (p = tsp->data; *p; p++) {
                  if (*p == '\\')
                      *p = '/';
--- 1711,1717 ----
              if (strnicmp(p, "all", 3) == 0)
                  p += 4;
  
!             StringCbCopyA(tsp->data, sizeof(tsp->data), p);
              for (p = tsp->data; *p; p++) {
                  if (*p == '\\')
                      *p = '/';
***************
*** 1796,1815 ****
              cm_HoldSCache(cm_data.rootSCachep);
          } else {
              linkScp->fileType = CM_SCACHETYPE_DFSLINK;
!             strcpy(tsp->data, linkp);
              code = CM_ERROR_PATH_NOT_COVERED;
          }
      } else if ( linkScp->fileType == CM_SCACHETYPE_DFSLINK ||
                  !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
          linkScp->fileType = CM_SCACHETYPE_DFSLINK;
!         strcpy(tsp->data, linkp);
          code = CM_ERROR_PATH_NOT_COVERED;
      } else if (*linkp == '\\' || *linkp == '/') {
  #if 0   
          /* formerly, this was considered to be from the AFS root,
           * but this seems to create problems.  instead, we will just
           * reject the link */
!         strcpy(tsp->data, linkp+1);
          *newRootScpp = cm_data.rootSCachep;
          cm_HoldSCache(cm_data.rootSCachep);
  #else
--- 1720,1739 ----
              cm_HoldSCache(cm_data.rootSCachep);
          } else {
              linkScp->fileType = CM_SCACHETYPE_DFSLINK;
!             StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
              code = CM_ERROR_PATH_NOT_COVERED;
          }
      } else if ( linkScp->fileType == CM_SCACHETYPE_DFSLINK ||
                  !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
          linkScp->fileType = CM_SCACHETYPE_DFSLINK;
!         StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
          code = CM_ERROR_PATH_NOT_COVERED;
      } else if (*linkp == '\\' || *linkp == '/') {
  #if 0   
          /* formerly, this was considered to be from the AFS root,
           * but this seems to create problems.  instead, we will just
           * reject the link */
!         StringCchCopyA(tsp->data,lengthof(tsp->data), linkp+1);
          *newRootScpp = cm_data.rootSCachep;
          cm_HoldSCache(cm_data.rootSCachep);
  #else
***************
*** 1817,1861 ****
           * the user can see what the link points to
           */
          linkScp->fileType = CM_SCACHETYPE_INVALID;
!         strcpy(tsp->data, linkp);
          code = CM_ERROR_NOSUCHPATH;
  #endif  
      } else {
          /* a relative link */
!         strcpy(tsp->data, linkp);
      }
      if (pathSuffixp[0] != 0) {	/* if suffix string is non-null */
!         strcat(tsp->data, "\\");
!         strcat(tsp->data, pathSuffixp);
      }
!     if (code == 0)
          *newSpaceBufferp = tsp;
!     else {
          cm_FreeSpace(tsp);
  
!         if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp)
              cm_VolStatus_Notify_DFS_Mapping(linkScp, reqp->tidPathp, reqp->relPathp);
      }
  
!   done:
      lock_ReleaseWrite(&linkScp->rw);
      return code;
  }
  #ifdef DEBUG_REFCOUNT
! long cm_NameIDbg(cm_scache_t *rootSCachep, char *pathp, long flags,
!                cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp, 
! 	       char * file, long line)
  #else
! 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)
  #endif
  {
      long code;
!     char *tp;			/* ptr moving through input buffer */
!     char tc;			/* temp char */
      int haveComponent;		/* has new component started? */
!     char component[AFSPATHMAX];	/* 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 */
--- 1741,1791 ----
           * the user can see what the link points to
           */
          linkScp->fileType = CM_SCACHETYPE_INVALID;
!         StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
          code = CM_ERROR_NOSUCHPATH;
  #endif  
      } else {
          /* a relative link */
!         StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
      }
      if (pathSuffixp[0] != 0) {	/* if suffix string is non-null */
!         StringCchCatA(tsp->data,lengthof(tsp->data), "\\");
!         StringCchCatA(tsp->data,lengthof(tsp->data), pathSuffixp);
      }
!     if (code == 0) {
!         clientchar_t * cpath = cm_FsStringToClientStringAlloc(tsp->data, -1, NULL);
!         cm_ClientStrCpy(tsp->wdata, lengthof(tsp->wdata), cpath);
!         free(cpath);
          *newSpaceBufferp = tsp;
!     } else {
          cm_FreeSpace(tsp);
  
!         if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp) {
              cm_VolStatus_Notify_DFS_Mapping(linkScp, reqp->tidPathp, reqp->relPathp);
+         }
      }
  
!  done:
      lock_ReleaseWrite(&linkScp->rw);
      return code;
  }
  #ifdef DEBUG_REFCOUNT
! long cm_NameIDbg(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
!                  cm_user_t *userp, clientchar_t *tidPathp, cm_req_t *reqp,
!                  cm_scache_t **outScpp, 
!                  char * file, long line)
  #else
! long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
!               cm_user_t *userp, clientchar_t *tidPathp,
!               cm_req_t *reqp, cm_scache_t **outScpp)
  #endif
  {
      long code;
!     clientchar_t *tp;			/* ptr moving through input buffer */
!     clientchar_t tc;			/* temp char */
      int haveComponent;		/* has new component started? */
!     clientchar_t component[AFSPATHMAX];	/* this is the new component */
!     clientchar_t *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 */
***************
*** 1864,1870 ****
      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 */
--- 1794,1800 ----
      cm_space_t *psp;		/* space for current path, if we've hit
      * any symlinks */
      cm_space_t *tempsp;		/* temp vbl */
!     clientchar_t *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 */
***************
*** 1875,1883 ****
  
  #ifdef DEBUG_REFCOUNT
      afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
!     osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %s tidpath %s flags 0x%x",
! 	      rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>", 
! 	      flags);
  #endif
  
      tp = tidPathp;
--- 1805,1813 ----
  
  #ifdef DEBUG_REFCOUNT
      afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
!     osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %S tidpath %S flags 0x%x",
!              rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>", 
!              flags);
  #endif
  
      tp = tidPathp;
***************
*** 1886,1892 ****
          phase = 2;
      }
      if (tp == NULL) {
!         tp = "";
      }
      haveComponent = 0;
      psp = NULL;
--- 1816,1822 ----
          phase = 2;
      }
      if (tp == NULL) {
!         tp = _C("");
      }
      haveComponent = 0;
      psp = NULL;
***************
*** 1933,1948 ****
  		if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
  		    extraFlag = CM_FLAG_NOMOUNTCHASE;
  		code = cm_Lookup(tscp, component,
! 				  flags | extraFlag,
! 				  userp, reqp, &nscp);
  
                  if (code == 0) {
!                     if (!strcmp(component,"..") || !strcmp(component,".")) {
                          /* 
!                          * roll back the fid list until we find the fid 
!                          * that matches where we are now.  Its not necessarily
!                          * one or two fids because they might have been 
!                          * symlinks or mount points or both that were crossed.  
                           */
                          for ( i=fid_count-1; i>=0; i--) {
                              if (!cm_FidCmp(&nscp->fid, &fids[i]))
--- 1863,1880 ----
  		if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
  		    extraFlag = CM_FLAG_NOMOUNTCHASE;
  		code = cm_Lookup(tscp, component,
!                                  flags | extraFlag,
!                                  userp, reqp, &nscp);
  
                  if (code == 0) {
!                     if (!cm_ClientStrCmp(component,_C("..")) ||
!                         !cm_ClientStrCmp(component,_C("."))) {
                          /* 
!                          * roll back the fid list until we find the
!                          * fid that matches where we are now.  Its not
!                          * necessarily one or two fids because they
!                          * might have been symlinks or mount points or
!                          * both that were crossed.
                           */
                          for ( i=fid_count-1; i>=0; i--) {
                              if (!cm_FidCmp(&nscp->fid, &fids[i]))
***************
*** 1972,1979 ****
  		    if (psp) 
  			cm_FreeSpace(psp);
  		    if ((code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) && 
!                          tscp->fileType == CM_SCACHETYPE_SYMLINK) 
!                     {
  			osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_NOSUCHPATH");
  			return CM_ERROR_NOSUCHPATH;
  		    } else {
--- 1904,1910 ----
  		    if (psp) 
  			cm_FreeSpace(psp);
  		    if ((code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) && 
!                         tscp->fileType == CM_SCACHETYPE_SYMLINK) {
  			osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_NOSUCHPATH");
  			return CM_ERROR_NOSUCHPATH;
  		    } else {
***************
*** 1997,2004 ****
                      break;
                  }
  
!                 /* now, if tscp is a symlink, we should follow
!                  * it and assemble the path again.
                   */
                  lock_ObtainWrite(&tscp->rw);
                  code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
--- 1928,1935 ----
                      break;
                  }
  
!                 /* now, if tscp is a symlink, we should follow it and
!                  * assemble the path again.
                   */
                  lock_ObtainWrite(&tscp->rw);
                  code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
***************
*** 2032,2041 ****
                          return CM_ERROR_TOO_MANY_SYMLINKS;
                      }
                      if (tc == 0) 
!                         restp = "";
                      else 
                          restp = tp;
!                     code = cm_AssembleLink(tscp, restp, &linkScp, &tempsp, userp, reqp);
  
                      if (code == 0 && linkScp != NULL) {
                          if (linkScp == cm_data.rootSCachep) 
--- 1963,1980 ----
                          return CM_ERROR_TOO_MANY_SYMLINKS;
                      }
                      if (tc == 0) 
!                         restp = _C("");
                      else 
                          restp = tp;
! 
!                     {
!                         fschar_t * frestp;
! 
!                         /* TODO: make this better */
!                         frestp = cm_ClientStringToFsStringAlloc(restp, -1, NULL);
!                         code = cm_AssembleLink(tscp, frestp, &linkScp, &tempsp, userp, reqp);
!                         free(frestp);
!                     }
  
                      if (code == 0 && linkScp != NULL) {
                          if (linkScp == cm_data.rootSCachep) 
***************
*** 2077,2083 ****
                      if (psp) 
                          cm_FreeSpace(psp);
                      psp = tempsp;
!                     tp = psp->data;
                      cm_ReleaseSCache(tscp);
                      tscp = linkScp;
                      linkScp = NULL;
--- 2016,2022 ----
                      if (psp) 
                          cm_FreeSpace(psp);
                      psp = tempsp;
!                     tp = psp->wdata;
                      cm_ReleaseSCache(tscp);
                      tscp = linkScp;
                      linkScp = NULL;
***************
*** 2175,2183 ****
          cm_HoldSCache(dscp);
      }
  
!     code = cm_NameI(newRootScp, spacep->data,
!                      CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
!                      userp, NULL, reqp, outScpp);
  
      if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
          code = CM_ERROR_NOSUCHPATH;
--- 2114,2122 ----
          cm_HoldSCache(dscp);
      }
  
!     code = cm_NameI(newRootScp, spacep->wdata,
!                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
!                     userp, NULL, reqp, outScpp);
  
      if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
          code = CM_ERROR_NOSUCHPATH;
***************
*** 2196,2218 ****
      return code;
  }
  
- /* make this big enough so that one buffer of dir pages won't overflow.  We'll
-  * check anyway, but we want to minimize the chance that we have to leave stuff
-  * unstat'd.
-  */
- #define CM_BULKMAX		(3 * AFSCBMAX)
- 
- /* 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
   * add it to the list of file IDs to be obtained.
   *
--- 2135,2140 ----
***************
*** 2292,2307 ****
      return 0;
  }       
  
- /* called with a write locked scp and a pointer to a buffer.  Make bulk stat
-  * calls on all undeleted files in the page of the directory specified.
-  */
  afs_int32
! 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 16K or so;
!                          * watch for stack problems */
      AFSCBFids fidStruct;
      AFSBulkStats statStruct;
      cm_conn_t *connp;
--- 2214,2223 ----
      return 0;
  }       
  
  afs_int32
! cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_req_t *reqp)
  {
!     afs_int32 code = 0;
      AFSCBFids fidStruct;
      AFSBulkStats statStruct;
      cm_conn_t *connp;
***************
*** 2316,2356 ****
      cm_fid_t tfid;
      struct rx_connection * callp;
      int inlinebulk = 0;		/* Did we use InlineBulkStatus RPC or not? */
! 
!     osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
! 
!     /* should be on a buffer boundary */
!     osi_assertx((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0, "invalid offset");
! 
!     memset(&bb, 0, sizeof(bb));
!     bb.bufOffset = *offsetp;
! 
!     lock_ReleaseWrite(&dscp->rw);
!     /* first, assemble the file IDs we need to stat */
!     code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) &bb, offsetp, userp, reqp, NULL);
! 
!     /* if we failed, bail out early */
!     if (code && code != CM_ERROR_STOPNOW) {
!         lock_ObtainWrite(&dscp->rw);
!         return code;
!     }
! 
      /* 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 < bb.counter) {
!         filesThisCall = bb.counter - filex;
          if (filesThisCall > AFSCBMAX) 
              filesThisCall = AFSCBMAX;
  
          fidStruct.AFSCBFids_len = filesThisCall;
!         fidStruct.AFSCBFids_val = &bb.fids[filex];
          statStruct.AFSBulkStats_len = filesThisCall;
!         statStruct.AFSBulkStats_val = &bb.stats[filex];
          callbackStruct.AFSCBs_len = filesThisCall;
!         callbackStruct.AFSCBs_val = &bb.callbacks[filex];
          cm_StartCallbackGrantingCall(NULL, &cbReq);
          osi_Log1(afsd_logp, "CALL BulkStatus, %d entries", filesThisCall);
          do {
--- 2232,2253 ----
      cm_fid_t tfid;
      struct rx_connection * callp;
      int inlinebulk = 0;		/* Did we use InlineBulkStatus RPC or not? */
!         
      /* 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.
       */
!     for (filex = 0; filex < bbp->counter; filex += filesThisCall) {
!         filesThisCall = bbp->counter - filex;
          if (filesThisCall > AFSCBMAX) 
              filesThisCall = AFSCBMAX;
  
          fidStruct.AFSCBFids_len = filesThisCall;
!         fidStruct.AFSCBFids_val = &bbp->fids[filex];
          statStruct.AFSBulkStats_len = filesThisCall;
!         statStruct.AFSBulkStats_val = &bbp->stats[filex];
          callbackStruct.AFSCBs_len = filesThisCall;
!         callbackStruct.AFSCBs_val = &bbp->callbacks[filex];
          cm_StartCallbackGrantingCall(NULL, &cbReq);
          osi_Log1(afsd_logp, "CALL BulkStatus, %d entries", filesThisCall);
          do {
***************
*** 2394,2400 ****
          /* otherwise, we should do the merges */
          for (i = 0; i<filesThisCall; i++) {
              j = filex + i;
!             cm_SetFid(&tfid, dscp->fid.cell, bb.fids[j].Volume, bb.fids[j].Vnode, bb.fids[j].Unique);
              code = cm_GetSCache(&tfid, &scp, userp, reqp);
              if (code != 0) 
                  continue;
--- 2291,2297 ----
          /* otherwise, we should do the merges */
          for (i = 0; i<filesThisCall; i++) {
              j = filex + i;
!             cm_SetFid(&tfid, dscp->fid.cell, bbp->fids[j].Volume, bbp->fids[j].Vnode, bbp->fids[j].Unique);
              code = cm_GetSCache(&tfid, &scp, userp, reqp);
              if (code != 0) 
                  continue;
***************
*** 2419,2427 ****
                           | CM_SCACHEFLAG_STORING
                           | CM_SCACHEFLAG_SIZESTORING))) {
                  cm_EndCallbackGrantingCall(scp, &cbReq,
!                                             &bb.callbacks[j],
                                              CM_CALLBACK_MAINTAINCOUNT);
!                 cm_MergeStatus(dscp, scp, &bb.stats[j], &volSync, userp, 0);
              }       
              lock_ReleaseWrite(&scp->rw);
              cm_ReleaseSCache(scp);
--- 2316,2324 ----
                           | CM_SCACHEFLAG_STORING
                           | CM_SCACHEFLAG_SIZESTORING))) {
                  cm_EndCallbackGrantingCall(scp, &cbReq,
!                                             &bbp->callbacks[j],
                                              CM_CALLBACK_MAINTAINCOUNT);
!                 cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, 0);
              }       
              lock_ReleaseWrite(&scp->rw);
              cm_ReleaseSCache(scp);
***************
*** 2429,2448 ****
          /* now tell it to drop the count,
           * after doing the vnode processing above */
          cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
- 
-         filex += filesThisCall;
      }	/* while there are still more files to process */
-     lock_ObtainWrite(&dscp->rw);
  
      /* If we did the InlineBulk RPC pull out the return code and log it */
      if (inlinebulk) {
! 	if ((&bb.stats[0])->errorCode) {
  	    osi_Log1(afsd_logp, "cm_TryBulkStat bulk stat error: %d", 
! 		     (&bb.stats[0])->errorCode);
  	}
      }
  
!     osi_Log0(afsd_logp, "END cm_TryBulkStat");
      return 0;
  }       
  
--- 2326,2380 ----
          /* now tell it to drop the count,
           * after doing the vnode processing above */
          cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
      }	/* while there are still more files to process */
  
      /* If we did the InlineBulk RPC pull out the return code and log it */
      if (inlinebulk) {
! 	if ((&bbp->stats[0])->errorCode) {
  	    osi_Log1(afsd_logp, "cm_TryBulkStat bulk stat error: %d", 
! 		     (&bbp->stats[0])->errorCode);
!             code = (&bbp->stats[0])->errorCode;
  	}
      }
  
!     return code;
! }
! 
! /* called with a write locked scp and a pointer to a buffer.  Make bulk stat
!  * calls on all undeleted files in the page of the directory specified.
!  */
! afs_int32
! cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
! 	       cm_req_t *reqp)
! {
!     afs_int32 code;
!     cm_bulkStat_t *bbp;
! 
!     osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
! 
!     /* should be on a buffer boundary */
!     osi_assertx((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0, "invalid offset");
! 
!     bbp = malloc(sizeof(cm_bulkStat_t));
!     memset(bbp, 0, sizeof(cm_bulkStat_t));
!     bbp->bufOffset = *offsetp;
! 
!     lock_ReleaseWrite(&dscp->rw);
!     /* first, assemble the file IDs we need to stat */
!     code = cm_ApplyDir(dscp, cm_TryBulkProc, (void *) bbp, offsetp, userp, reqp, NULL);
! 
!     /* if we failed, bail out early */
!     if (code && code != CM_ERROR_STOPNOW) {
!         free(bbp);
!         lock_ObtainWrite(&dscp->rw);
!         return code;
!     }
! 
!     code = cm_TryBulkStatRPC(dscp, bbp, userp, reqp);
!     osi_Log1(afsd_logp, "END cm_TryBulkStat code 0x%x", code);
! 
!     lock_ObtainWrite(&dscp->rw);
!     free(bbp);
      return 0;
  }       
  
***************
*** 2653,2659 ****
      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;
--- 2585,2591 ----
      return code;
  }       
  
! long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *attrp,
                 cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp)
  {       
      cm_conn_t *connp;
***************
*** 2671,2681 ****
      AFSVolSync volSync;
      struct rx_connection * callp;
      cm_dirOp_t dirop;
  
      /* 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;
      }
  
--- 2603,2614 ----
      AFSVolSync volSync;
      struct rx_connection * callp;
      cm_dirOp_t dirop;
+     fschar_t * fnamep = NULL;
  
      /* can't create names with @sys in them; must expand it manually first.
       * return "invalid request" if they try.
       */
!     if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
          return CM_ERROR_ATSYS;
      }
  
***************
*** 2707,2712 ****
--- 2640,2647 ----
      }
      didEnd = 0;
  
+     fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+ 
      cm_StatusFromAttr(&inStatus, NULL, attrp);
  
      /* try the RPC now */
***************
*** 2721,2727 ****
          dirAFSFid.Unique = dscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_CreateFile(connp->callp, &dirAFSFid, namep,
                                   &inStatus, &newAFSFid, &newFileStatus,
                                   &updatedDirStatus, &newFileCallback,
                                   &volSync);
--- 2656,2662 ----
          dirAFSFid.Unique = dscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_CreateFile(connp->callp, &dirAFSFid, fnamep,
                                   &inStatus, &newAFSFid, &newFileStatus,
                                   &updatedDirStatus, &newFileCallback,
                                   &volSync);
***************
*** 2760,2768 ****
  	    scp->creator = userp;		/* remember who created it */
              if (!cm_HaveCallback(scp)) {
                  cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
!                                 userp, 0);
                  cm_EndCallbackGrantingCall(scp, &cbReq,
!                                             &newFileCallback, 0);
                  didEnd = 1;     
              }       
              lock_ReleaseWrite(&scp->rw);
--- 2695,2703 ----
  	    scp->creator = userp;		/* remember who created it */
              if (!cm_HaveCallback(scp)) {
                  cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
!                                userp, 0);
                  cm_EndCallbackGrantingCall(scp, &cbReq,
!                                            &newFileCallback, 0);
                  didEnd = 1;     
              }       
              lock_ReleaseWrite(&scp->rw);
***************
*** 2775,2787 ****
          cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
  
      if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
!         cm_DirCreateEntry(&dirop, namep, &newFid);
  #ifdef USE_BPLUS
!         cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
  #endif
      }
      cm_EndDirOp(&dirop);
  
      return code;
  }       
  
--- 2710,2725 ----
          cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
  
      if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
!         cm_DirCreateEntry(&dirop, fnamep, &newFid);
  #ifdef USE_BPLUS
!         cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
  #endif
      }
      cm_EndDirOp(&dirop);
  
+     if (fnamep)
+         free(fnamep);
+ 
      return code;
  }       
  
***************
*** 2808,2814 ****
      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;
--- 2746,2752 ----
      return code;
  }
  
! long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *attrp,
                   cm_user_t *userp, cm_req_t *reqp)
  {
      cm_conn_t *connp;
***************
*** 2826,2836 ****
      AFSVolSync volSync;
      struct rx_connection * callp;
      cm_dirOp_t dirop;
  
      /* 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;
      }
  
--- 2764,2775 ----
      AFSVolSync volSync;
      struct rx_connection * callp;
      cm_dirOp_t dirop;
+     fschar_t * fnamep = NULL;
  
      /* can't create names with @sys in them; must expand it manually first.
       * return "invalid request" if they try.
       */
!     if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
          return CM_ERROR_ATSYS;
      }
  
***************
*** 2862,2867 ****
--- 2801,2807 ----
      }
      didEnd = 0;
  
+     fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
      cm_StatusFromAttr(&inStatus, NULL, attrp);
  
      /* try the RPC now */
***************
*** 2876,2889 ****
          dirAFSFid.Unique = dscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_MakeDir(connp->callp, &dirAFSFid, namep,
                                &inStatus, &newAFSFid, &newDirStatus,
                                &updatedDirStatus, &newDirCallback,
                                &volSync);
          rx_PutConnection(callp);
  
      } while (cm_Analyze(connp, userp, reqp,
!                          &dscp->fid, &volSync, NULL, &cbReq, code));
      code = cm_MapRPCError(code, reqp);
          
      if (code)
--- 2816,2829 ----
          dirAFSFid.Unique = dscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_MakeDir(connp->callp, &dirAFSFid, fnamep,
                                &inStatus, &newAFSFid, &newDirStatus,
                                &updatedDirStatus, &newDirCallback,
                                &volSync);
          rx_PutConnection(callp);
  
      } while (cm_Analyze(connp, userp, reqp,
!                         &dscp->fid, &volSync, NULL, &cbReq, code));
      code = cm_MapRPCError(code, reqp);
          
      if (code)
***************
*** 2929,2946 ****
          cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
  
      if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
!         cm_DirCreateEntry(&dirop, namep, &newFid);
  #ifdef USE_BPLUS
!         cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
  #endif
      }
      cm_EndDirOp(&dirop);
  
      /* 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;
--- 2869,2888 ----
          cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
  
      if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
!         cm_DirCreateEntry(&dirop, fnamep, &newFid);
  #ifdef USE_BPLUS
!         cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
  #endif
      }
      cm_EndDirOp(&dirop);
  
+     free(fnamep);
+ 
      /* and return error code */
      return code;
  }       
  
! long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long flags,
               cm_user_t *userp, cm_req_t *reqp)
  {
      cm_conn_t *connp;
***************
*** 2952,2957 ****
--- 2894,2900 ----
      AFSVolSync volSync;
      struct rx_connection * callp;
      cm_dirOp_t dirop;
+     fschar_t * fnamep = NULL;
  
      if (dscp->fid.cell != sscp->fid.cell ||
          dscp->fid.volume != sscp->fid.volume) {
***************
*** 2968,2973 ****
--- 2911,2918 ----
      if (code)
          return code;
  
+     fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+ 
      /* try the RPC now */
      osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
      do {
***************
*** 2983,2989 ****
          existingAFSFid.Unique = sscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_Link(callp, &dirAFSFid, namep, &existingAFSFid,
              &newLinkStatus, &updatedDirStatus, &volSync);
          rx_PutConnection(callp);
          osi_Log1(afsd_logp,"  RXAFS_Link returns 0x%x", code);
--- 2928,2934 ----
          existingAFSFid.Unique = sscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_Link(callp, &dirAFSFid, fnamep, &existingAFSFid,
              &newLinkStatus, &updatedDirStatus, &volSync);
          rx_PutConnection(callp);
          osi_Log1(afsd_logp,"  RXAFS_Link returns 0x%x", code);
***************
*** 3011,3028 ****
  
      if (code == 0) {
          if (cm_CheckDirOpForSingleChange(&dirop)) {
!             cm_DirCreateEntry(&dirop, namep, &sscp->fid);
  #ifdef USE_BPLUS
!             cm_BPlusDirCreateEntry(&dirop, namep, &sscp->fid);
  #endif
          }
      }
      cm_EndDirOp(&dirop);
  
      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;
--- 2956,2975 ----
  
      if (code == 0) {
          if (cm_CheckDirOpForSingleChange(&dirop)) {
!             cm_DirCreateEntry(&dirop, fnamep, &sscp->fid);
  #ifdef USE_BPLUS
!             cm_BPlusDirCreateEntry(&dirop, cnamep, &sscp->fid);
  #endif
          }
      }
      cm_EndDirOp(&dirop);
  
+     free(fnamep);
+ 
      return code;
  }
  
! long cm_SymLink(cm_scache_t *dscp, clientchar_t *cnamep, fschar_t *contentsp, long flags,
                  cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp)
  {
      cm_conn_t *connp;
***************
*** 3037,3042 ****
--- 2984,2990 ----
      AFSVolSync volSync;
      struct rx_connection * callp;
      cm_dirOp_t dirop;
+     fschar_t *fnamep = NULL;
  
      /* 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
***************
*** 3052,3057 ****
--- 3000,3007 ----
          return code;
      }
  
+     fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+ 
      cm_StatusFromAttr(&inStatus, NULL, attrp);
  
      /* try the RPC now */
***************
*** 3066,3072 ****
          dirAFSFid.Unique = dscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_Symlink(callp, &dirAFSFid, namep, contentsp,
                                &inStatus, &newAFSFid, &newLinkStatus,
                                &updatedDirStatus, &volSync);
          rx_PutConnection(callp);
--- 3016,3022 ----
          dirAFSFid.Unique = dscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_Symlink(callp, &dirAFSFid, fnamep, contentsp,
                                &inStatus, &newAFSFid, &newLinkStatus,
                                &updatedDirStatus, &volSync);
          rx_PutConnection(callp);
***************
*** 3095,3103 ****
          if (cm_CheckDirOpForSingleChange(&dirop)) {
              cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
  
!             cm_DirCreateEntry(&dirop, namep, &newFid);
  #ifdef USE_BPLUS
!             cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
  #endif
          }
      }
--- 3045,3053 ----
          if (cm_CheckDirOpForSingleChange(&dirop)) {
              cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
  
!             cm_DirCreateEntry(&dirop, fnamep, &newFid);
  #ifdef USE_BPLUS
!             cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
  #endif
          }
      }
***************
*** 3121,3133 ****
              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;
--- 3071,3103 ----
              cm_ReleaseSCache(scp);
          }
      }
+ 
+     free(fnamep);
  	
      /* and return error code */
      return code;
  }
  
! /*! \brief Remove a directory
! 
!   Encapsulates a call to RXAFS_RemoveDir().
! 
!   \param[in] dscp cm_scache_t for the directory containing the
!       directory to be removed.
! 
!   \param[in] fnamep This will be the original name of the directory
!       as known to the file server.   It will be passed in to RXAFS_RemoveDir().
!       This parameter is optional.  If it is not provided the value
!       will be looked up.
! 
!   \param[in] cnamep Normalized name used to update the local
!       directory caches.
! 
!   \param[in] userp cm_user_t for the request.
! 
!   \param[in] reqp Request tracker.
! */
! long cm_RemoveDir(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t *cnamep, cm_user_t *userp, cm_req_t *reqp)
  {
      cm_conn_t *connp;
      long code;
***************
*** 3138,3145 ****
      struct rx_connection * callp;
      cm_dirOp_t dirop;
      cm_scache_t *scp = NULL;
  
!     code = cm_Lookup(dscp, namep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
  
      /* 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
--- 3108,3133 ----
      struct rx_connection * callp;
      cm_dirOp_t dirop;
      cm_scache_t *scp = NULL;
+     int free_fnamep = FALSE;
+ 
+     if (fnamep == NULL) {
+         code = -1;
+ #ifdef USE_BPLUS
+         code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+         if (code == 0) {
+             code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
+             if (code == 0)
+                 free_fnamep = TRUE;
+             cm_EndDirOp(&dirop);
+         }
+ #endif
+         if (code)
+             goto done;
+     }
  
!     code = cm_Lookup(dscp, cnamep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
!     if (code)
!         goto done;
  
      /* 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
***************
*** 3151,3157 ****
      lock_ReleaseWrite(&dscp->rw);
      if (code) {
          cm_EndDirOp(&dirop);
!         return code;
      }
      didEnd = 0;
  
--- 3139,3145 ----
      lock_ReleaseWrite(&dscp->rw);
      if (code) {
          cm_EndDirOp(&dirop);
!         goto done;
      }
      didEnd = 0;
  
***************
*** 3167,3178 ****
          dirAFSFid.Unique = dscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_RemoveDir(callp, &dirAFSFid, namep,
!                                 &updatedDirStatus, &volSync);
          rx_PutConnection(callp);
  
      } while (cm_Analyze(connp, userp, reqp,
!                          &dscp->fid, &volSync, NULL, NULL, code));
      code = cm_MapRPCErrorRmdir(code, reqp);
  
      if (code)
--- 3155,3166 ----
          dirAFSFid.Unique = dscp->fid.unique;
  
          callp = cm_GetRxConn(connp);
!         code = RXAFS_RemoveDir(callp, &dirAFSFid, fnamep,
!                                &updatedDirStatus, &volSync);
          rx_PutConnection(callp);
  
      } while (cm_Analyze(connp, userp, reqp,
!                         &dscp->fid, &volSync, NULL, NULL, code));
      code = cm_MapRPCErrorRmdir(code, reqp);
  
      if (code)
***************
*** 3187,3202 ****
      lock_ObtainWrite(&dscp->rw);
      cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
      if (code == 0) {
!         cm_dnlcRemove(dscp, namep); 
          cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
      }
      lock_ReleaseWrite(&dscp->rw);
  
      if (code == 0) {
!         if (cm_CheckDirOpForSingleChange(&dirop)) {
!             cm_DirDeleteEntry(&dirop, namep);
  #ifdef USE_BPLUS
!             cm_BPlusDirDeleteEntry(&dirop, namep);
  #endif
          }
      }
--- 3175,3190 ----
      lock_ObtainWrite(&dscp->rw);
      cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
      if (code == 0) {
!         cm_dnlcRemove(dscp, cnamep); 
          cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
      }
      lock_ReleaseWrite(&dscp->rw);
  
      if (code == 0) {
!         if (cm_CheckDirOpForSingleChange(&dirop) && cnamep != NULL) {
!             cm_DirDeleteEntry(&dirop, fnamep);
  #ifdef USE_BPLUS
!             cm_BPlusDirDeleteEntry(&dirop, cnamep);
  #endif
          }
      }
***************
*** 3211,3216 ****
--- 3199,3208 ----
          }
      }
  
+   done:
+     if (free_fnamep)
+         free(fnamep);
+ 
      /* and return error code */
      return code;
  }
***************
*** 3233,3240 ****
      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;
--- 3225,3257 ----
      return 0;
  }       
  
! /*! \brief Rename a file or directory
! 
!   Encapsulates a RXAFS_Rename() call.
! 
!   \param[in] oldDscp cm_scache_t for the directory containing the old
!       name.
! 
!   \param[in] oldNamep The original old name known to the file server.
!       This is the name that will be passed into the RXAFS_Rename().
!       If it is not provided, it will be looked up.
! 
!   \param[in] normalizedOldNamep Normalized old name.  This is used for
!   updating local directory caches.
! 
!   \param[in] newDscp cm_scache_t for the directory containing the new
!   name.
! 
!   \param[in] newNamep New name. Normalized.
! 
!   \param[in] userp cm_user_t for the request.
! 
!   \param[in,out] reqp Request tracker.
! 
! */
! long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep,
!                cm_scache_t *newDscp, clientchar_t *cNewNamep, cm_user_t *userp,
!                cm_req_t *reqp)
  {
      cm_conn_t *connp;
      long code;
***************
*** 3250,3255 ****
--- 3267,3290 ----
      cm_fid_t   fileFid;
      int        diropCode = -1;
      cm_dirOp_t newDirOp;
+     fschar_t * newNamep = NULL;
+     int free_oldNamep = FALSE;
+ 
+     if (oldNamep == NULL) {
+         code = -1;
+ #ifdef USE_BPLUS
+         code = cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_READ, &oldDirOp);
+         if (code == 0) {
+             code = cm_BPlusDirLookupOriginalName(&oldDirOp, cOldNamep, &oldNamep);
+             if (code == 0)
+                 free_oldNamep = TRUE;
+             cm_EndDirOp(&oldDirOp);
+         }
+ #endif
+         if (code)
+             goto done;
+     }
+ 
  
      /* 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
***************
*** 3258,3271 ****
       */
      if (oldDscp == newDscp) {
          /* check for identical names */
!         if (strcmp(oldNamep, newNamep) == 0)
!             return CM_ERROR_RENAME_IDENTICAL;
  
          oneDir = 1;
          cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
          lock_ObtainWrite(&oldDscp->rw);
!         cm_dnlcRemove(oldDscp, oldNamep);
!         cm_dnlcRemove(oldDscp, newNamep);
          code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                            CM_SCACHESYNC_STOREDATA);
          lock_ReleaseWrite(&oldDscp->rw);
--- 3293,3308 ----
       */
      if (oldDscp == newDscp) {
          /* check for identical names */
!         if (cm_ClientStrCmp(cOldNamep, cNewNamep) == 0) {
!             code = CM_ERROR_RENAME_IDENTICAL;
!             goto done;
!         }
  
          oneDir = 1;
          cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
          lock_ObtainWrite(&oldDscp->rw);
!         cm_dnlcRemove(oldDscp, cOldNamep);
!         cm_dnlcRemove(oldDscp, cNewNamep);
          code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                            CM_SCACHESYNC_STOREDATA);
          lock_ReleaseWrite(&oldDscp->rw);
***************
*** 3277,3307 ****
          /* two distinct dir vnodes */
          oneDir = 0;
          if (oldDscp->fid.cell != newDscp->fid.cell ||
!              oldDscp->fid.volume != newDscp->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->fid.vnode == newDscp->fid.vnode)
!             return CM_ERROR_CROSSDEVLINK;
  
          if (oldDscp->fid.vnode < newDscp->fid.vnode) {
              cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
              lock_ObtainWrite(&oldDscp->rw);
!             cm_dnlcRemove(oldDscp, oldNamep);
              code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
!                               CM_SCACHESYNC_STOREDATA);
              lock_ReleaseWrite(&oldDscp->rw);
              if (code != 0)
                  cm_EndDirOp(&oldDirOp);
              if (code == 0) {
                  cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
                  lock_ObtainWrite(&newDscp->rw);
!                 cm_dnlcRemove(newDscp, newNamep);
                  code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
!                                   CM_SCACHESYNC_STOREDATA);
                  lock_ReleaseWrite(&newDscp->rw);
                  if (code) {
                      cm_EndDirOp(&newDirOp);
--- 3314,3348 ----
          /* two distinct dir vnodes */
          oneDir = 0;
          if (oldDscp->fid.cell != newDscp->fid.cell ||
!              oldDscp->fid.volume != newDscp->fid.volume) {
!             code = CM_ERROR_CROSSDEVLINK;
!             goto done;
!         }
  
          /* 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->fid.vnode == newDscp->fid.vnode) {
!             code = CM_ERROR_CROSSDEVLINK;
!             goto done;
!         }
  
          if (oldDscp->fid.vnode < newDscp->fid.vnode) {
              cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
              lock_ObtainWrite(&oldDscp->rw);
!             cm_dnlcRemove(oldDscp, cOldNamep);
              code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
!                              CM_SCACHESYNC_STOREDATA);
              lock_ReleaseWrite(&oldDscp->rw);
              if (code != 0)
                  cm_EndDirOp(&oldDirOp);
              if (code == 0) {
                  cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
                  lock_ObtainWrite(&newDscp->rw);
!                 cm_dnlcRemove(newDscp, cNewNamep);
                  code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
!                                  CM_SCACHESYNC_STOREDATA);
                  lock_ReleaseWrite(&newDscp->rw);
                  if (code) {
                      cm_EndDirOp(&newDirOp);
***************
*** 3319,3325 ****
              /* lock the new vnode entry first */
              cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
              lock_ObtainWrite(&newDscp->rw);
!             cm_dnlcRemove(newDscp, newNamep);
              code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
                                CM_SCACHESYNC_STOREDATA);
              lock_ReleaseWrite(&newDscp->rw);
--- 3360,3366 ----
              /* lock the new vnode entry first */
              cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
              lock_ObtainWrite(&newDscp->rw);
!             cm_dnlcRemove(newDscp, cNewNamep);
              code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
                                CM_SCACHESYNC_STOREDATA);
              lock_ReleaseWrite(&newDscp->rw);
***************
*** 3328,3334 ****
              if (code == 0) {
                  cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
                  lock_ObtainWrite(&oldDscp->rw);
!                 cm_dnlcRemove(oldDscp, oldNamep);
                  code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                                    CM_SCACHESYNC_STOREDATA);
                  lock_ReleaseWrite(&oldDscp->rw);
--- 3369,3375 ----
              if (code == 0) {
                  cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
                  lock_ObtainWrite(&oldDscp->rw);
!                 cm_dnlcRemove(oldDscp, cOldNamep);
                  code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                                    CM_SCACHESYNC_STOREDATA);
                  lock_ReleaseWrite(&oldDscp->rw);
***************
*** 3346,3356 ****
          }
      }	/* two distinct vnodes */
  
!     if (code) {
!         return code;
!     }
      didEnd = 0;
  
      /* try the RPC now */
      osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p", 
                oldDscp, newDscp);
--- 3387,3399 ----
          }
      }	/* two distinct vnodes */
  
!     if (code) 
!         goto done;
! 
      didEnd = 0;
  
+     newNamep = cm_ClientStringToFsStringAlloc(cNewNamep, -1, NULL);
+ 
      /* try the RPC now */
      osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p", 
                oldDscp, newDscp);
***************
*** 3368,3376 ****
  
          callp = cm_GetRxConn(connp);
          code = RXAFS_Rename(callp, &oldDirAFSFid, oldNamep,
!                              &newDirAFSFid, newNamep,
!                              &updatedOldDirStatus, &updatedNewDirStatus,
!                              &volSync);
          rx_PutConnection(callp);
  
      } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
--- 3411,3419 ----
  
          callp = cm_GetRxConn(connp);
          code = RXAFS_Rename(callp, &oldDirAFSFid, oldNamep,
!                             &newDirAFSFid, newNamep,
!                             &updatedOldDirStatus, &updatedNewDirStatus,
!                             &volSync);
          rx_PutConnection(callp);
  
      } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
***************
*** 3392,3405 ****
  
      if (code == 0)
          cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
!                         userp, CM_MERGEFLAG_DIROP);
      lock_ReleaseWrite(&oldDscp->rw);
  
      if (code == 0) {
          if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
  
  #ifdef USE_BPLUS
!             diropCode = cm_BPlusDirLookup(&oldDirOp, oldNamep, &fileFid);
              if (diropCode == CM_ERROR_INEXACT_MATCH)
                  diropCode = 0;
              else if (diropCode == EINVAL)
--- 3435,3448 ----
  
      if (code == 0)
          cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
!                        userp, CM_MERGEFLAG_DIROP);
      lock_ReleaseWrite(&oldDscp->rw);
  
      if (code == 0) {
          if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
  
  #ifdef USE_BPLUS
!             diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
              if (diropCode == CM_ERROR_INEXACT_MATCH)
                  diropCode = 0;
              else if (diropCode == EINVAL)
***************
*** 3410,3423 ****
                  if (oneDir) {
                      diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
  #ifdef USE_BPLUS
!                     cm_BPlusDirCreateEntry(&oldDirOp, newNamep, &fileFid);
  #endif
                  }
! 
                  if (diropCode == 0) { 
                      diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
  #ifdef USE_BPLUS
!                     cm_BPlusDirDeleteEntry(&oldDirOp, oldNamep);
  #endif
                  }
              }
--- 3453,3466 ----
                  if (oneDir) {
                      diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
  #ifdef USE_BPLUS
!                     cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
  #endif
                  }
!                 
                  if (diropCode == 0) { 
                      diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
  #ifdef USE_BPLUS
!                     cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
  #endif
                  }
              }
***************
*** 3445,3457 ****
              if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
                  cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
  #ifdef USE_BPLUS
!                 cm_BPlusDirCreateEntry(&newDirOp, newNamep, &fileFid);
  #endif
              }
          }
          cm_EndDirOp(&newDirOp);
      }
  
      /* and return error code */
      return code;
  }
--- 3488,3506 ----
              if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
                  cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
  #ifdef USE_BPLUS
!                 cm_BPlusDirCreateEntry(&newDirOp, cNewNamep, &fileFid);
  #endif
              }
          }
          cm_EndDirOp(&newDirOp);
      }
  
+   done:
+     if (free_oldNamep)
+         free(oldNamep);
+ 
+     free(newNamep);
+ 
      /* and return error code */
      return code;
  }
Index: openafs/src/WINNT/afsd/cm_vnodeops.h
diff -c openafs/src/WINNT/afsd/cm_vnodeops.h:1.14.4.9 openafs/src/WINNT/afsd/cm_vnodeops.h:1.14.4.12
*** openafs/src/WINNT/afsd/cm_vnodeops.h:1.14.4.9	Sun Mar  9 11:25:01 2008
--- openafs/src/WINNT/afsd/cm_vnodeops.h	Mon Jul 14 09:01:31 2008
***************
*** 18,29 ****
  
  /* parms for attribute setting call */
  typedef struct cm_attr {
! 	int mask;
! 	time_t clientModTime;
!         osi_hyper_t length;
! 	int unixModeBits;
!         long owner;
!         long group;
  } cm_attr_t;
  
  #define CM_ATTRMASK_CLIENTMODTIME	1	/* set if field is valid */
--- 18,29 ----
  
  /* parms for attribute setting call */
  typedef struct cm_attr {
!     int         mask;
!     time_t      clientModTime;
!     osi_hyper_t length;
!     int         unixModeBits;
!     long        owner;
!     long        group;
  } cm_attr_t;
  
  #define CM_ATTRMASK_CLIENTMODTIME	1	/* set if field is valid */
***************
*** 34,51 ****
  
  /* type of rock for lookup's searches */
  typedef struct cm_lookupSearch {
!         cm_fid_t fid;
!         char *searchNamep;
!         int found;
!         int LCfound, UCfound, NCfound, ExactFound;
!         int caseFold;
!         int hasTilde;
  } cm_lookupSearch_t;
  
  #include "cm_dir.h"
  
  typedef int (*cm_DirFuncp_t)(struct cm_scache *, struct cm_dirEntry *, void *,
! 	osi_hyper_t *entryOffsetp);
  
  /* Special path syntax for direct references to volumes
  
--- 34,52 ----
  
  /* type of rock for lookup's searches */
  typedef struct cm_lookupSearch {
!     cm_fid_t      fid;
!     fschar_t     *searchNamep;
!     normchar_t   *nsearchNamep;
!     int           found;
!     int           LCfound, UCfound, NCfound, ExactFound;
!     int           caseFold;
!     int           hasTilde;
  } cm_lookupSearch_t;
  
  #include "cm_dir.h"
  
  typedef int (*cm_DirFuncp_t)(struct cm_scache *, struct cm_dirEntry *, void *,
!                              osi_hyper_t *entryOffsetp);
  
  /* Special path syntax for direct references to volumes
  
***************
*** 60,165 ****
  
  /* arrays */
  
! extern unsigned char cm_foldUpper[];
  
  /* functions */
  
! extern int cm_NoneLower(char *s);
  
! extern int cm_NoneUpper(char *s);
! 
! extern int cm_Is8Dot3(char *namep);
  
  extern int cm_stricmp(const char *, const char *);
  
- extern void cm_Gen8Dot3Name(struct cm_dirEntry *dep, char *shortName,
- 	char **shortNameEndp);
- 
- #define cm_Gen8Dot3Name(dep,shortName,shortNameEndp) \
- cm_Gen8Dot3NameInt((dep)->name, &(dep)->fid, shortName, shortNameEndp)
- 
- extern void cm_Gen8Dot3NameInt(const char * longname, cm_dirFid_t * pfid,
-                                char *shortName, char **shortNameEndp);
- 
  extern long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp,
                                cm_req_t *reqp);
  
! extern long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
                                         cm_req_t *reqp, cm_scache_t ** outpScpp);
  
  #ifdef DEBUG_REFCOUNT
! extern long cm_NameIDbg(cm_scache_t *rootSCachep, char *pathp, long flags,
! 	cm_user_t *userp, char *tidPathp, cm_req_t *reqp,
! 	cm_scache_t **outScpp, char *, long);
! 
! extern long cm_LookupDbg(cm_scache_t *dscp, char *namep, long flags,
! 	cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp, char *, long);
  
  #define cm_Lookup(a,b,c,d,e,f)  cm_LookupDbg(a,b,c,d,e,f,__FILE__,__LINE__)
  #define cm_NameI(a,b,c,d,e,f,g) cm_NameIDbg(a,b,c,d,e,f,g,__FILE__,__LINE__)
  #else
! extern 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);
! extern long cm_Lookup(cm_scache_t *dscp, char *namep, long flags,
! 	cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp);
  #endif
  
! 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 afs_int32 cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp,
! 	cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
! 	cm_req_t *reqp);
  
! extern long cm_Create(cm_scache_t *scp, char *namep, long flags,
! 	cm_attr_t *attrp, cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
  
  extern void cm_StatusFromAttr(struct AFSStoreStatus *statusp,
! 	struct cm_scache *scp, struct cm_attr *attrp);
  
! extern long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp,
! 	cm_req_t *reqp);
  
  extern 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);
  
! extern long cm_MakeDir(cm_scache_t *dscp, char *lastNamep, long flags,
! 	cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
  
! extern long cm_RemoveDir(cm_scache_t *dscp, char *lastNamep, cm_user_t *userp,
! 	cm_req_t *reqp);
  
! extern long cm_Rename(cm_scache_t *oldDscp, char *oldLastNamep,
! 	cm_scache_t *newDscp, char *newLastNamep, cm_user_t *userp,
! 	cm_req_t *reqp);
  
  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 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);
  
! 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);
  
  extern long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc,
! 	cm_user_t *userp, cm_req_t *reqp);
  
  /*
   * Combinations of file opening access bits for AFS.
--- 61,159 ----
  
  /* arrays */
  
! extern fschar_t cm_foldUpper[];
  
  /* functions */
  
! extern int cm_NoneLower(normchar_t *s);
  
! extern int cm_NoneUpper(normchar_t *s);
  
  extern int cm_stricmp(const char *, const char *);
  
  extern long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp,
                                cm_req_t *reqp);
  
! extern long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
                                         cm_req_t *reqp, cm_scache_t ** outpScpp);
  
  #ifdef DEBUG_REFCOUNT
! extern long cm_NameIDbg(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
!                         cm_user_t *userp, clientchar_t *tidPathp, cm_req_t *reqp,
!                         cm_scache_t **outScpp, char *, long);
! 
! extern long cm_LookupDbg(cm_scache_t *dscp, clientchar_t *namep, long flags,
!                          cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp,
!                          char *, long);
  
  #define cm_Lookup(a,b,c,d,e,f)  cm_LookupDbg(a,b,c,d,e,f,__FILE__,__LINE__)
  #define cm_NameI(a,b,c,d,e,f,g) cm_NameIDbg(a,b,c,d,e,f,g,__FILE__,__LINE__)
  #else
! extern long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
!                      cm_user_t *userp, clientchar_t *tidPathp, cm_req_t *reqp,
!                      cm_scache_t **outScpp);
! extern long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags,
!                       cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp);
  #endif
  
! extern long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *namep, long flags,
                                cm_user_t *userp, cm_req_t *reqp, 
                                cm_scache_t **outpScpp);
  
  extern afs_int32 cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp,
!                                 cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
!                        cm_req_t *reqp);
  
! extern long cm_Create(cm_scache_t *scp, clientchar_t *namep, long flags,
!                       cm_attr_t *attrp, cm_scache_t **scpp,
!                       cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
  
  extern void cm_StatusFromAttr(struct AFSStoreStatus *statusp,
!                               struct cm_scache *scp, struct cm_attr *attrp);
  
! extern long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep,
!                       clientchar_t *cnamep,
!                       cm_user_t *userp, cm_req_t *reqp);
  
  extern 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);
  
! extern long cm_MakeDir(cm_scache_t *dscp, clientchar_t *lastNamep, long flags,
!                        cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
  
! extern long cm_RemoveDir(cm_scache_t *dscp, fschar_t *lastNamep, clientchar_t *originalNamep,
!                          cm_user_t *userp, cm_req_t *reqp);
  
! extern long cm_Rename(cm_scache_t *oldDscp,
!                       fschar_t *oldLastNamep, clientchar_t *normalizedOldNamep,
!                       cm_scache_t *newDscp, clientchar_t *newLastNamep,
!                       cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_HandleLink(cm_scache_t *linkScp, struct cm_user *userp,
!                           cm_req_t *reqp);
  
! extern long cm_Link(cm_scache_t *dscp, clientchar_t *namep, cm_scache_t *sscp,
!                     long flags, cm_user_t *userp, cm_req_t *reqp);
  
! extern long cm_SymLink(cm_scache_t *dscp, clientchar_t *namep, fschar_t *contentsp,
!                        long flags, cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
  
! extern long cm_AssembleLink(cm_scache_t *linkScp, fschar_t *pathSuffixp,
                              cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
                              cm_user_t *userp, cm_req_t *reqp);
  
! extern int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch,
                              unsigned int sysNameIndex);
  
  extern long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp);
  
  extern long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc,
!                          cm_user_t *userp, cm_req_t *reqp);
  
  /*
   * Combinations of file opening access bits for AFS.
***************
*** 179,225 ****
  } cm_lock_data_t;
  
  extern long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
! 	unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp, cm_lock_data_t ** ldpp);
  
  extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp, 
  			       cm_lock_data_t ** ldpp);
  
  extern long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp,
! 	cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
! 	cm_scache_t **outScpp, cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
                                  cm_req_t *reqp, cm_scache_t **outScpp);
  
  
  extern long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
!         LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
! 	int allowWait, cm_user_t *userp, cm_req_t *reqp,
! 	cm_file_lock_t **lockpp);
  
  #define CM_UNLOCK_BY_FID 	0x0001
  
  extern long cm_UnlockByKey(cm_scache_t * scp,
!         cm_key_t key,
!         int flags,
!         cm_user_t * userp,
!         cm_req_t * reqp);
  
  extern long cm_Unlock(cm_scache_t *scp, unsigned char sLockType,
!         LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
! 	cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_LockCheckRead(cm_scache_t *scp, 
!         LARGE_INTEGER LOffset, 
!         LARGE_INTEGER LLength, 
!         cm_key_t key);
  
  extern long cm_LockCheckWrite(cm_scache_t *scp,
!         LARGE_INTEGER LOffset,
!         LARGE_INTEGER LLength,
!         cm_key_t key);
  
  extern void cm_CheckLocks(void);
  
--- 173,221 ----
  } cm_lock_data_t;
  
  extern long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
!                            unsigned int createDisp, cm_user_t *userp,
!                            cm_req_t *reqp, cm_lock_data_t ** ldpp);
  
  extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp, 
  			       cm_lock_data_t ** ldpp);
  
  extern long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp,
!                              cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
!                                cm_scache_t **outScpp, cm_user_t *userp,
!                                cm_req_t *reqp);
  
  extern long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
                                  cm_req_t *reqp, cm_scache_t **outScpp);
  
  
  extern long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
!                     LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
!                     int allowWait, cm_user_t *userp, cm_req_t *reqp,
!                     cm_file_lock_t **lockpp);
  
  #define CM_UNLOCK_BY_FID 	0x0001
  
  extern long cm_UnlockByKey(cm_scache_t * scp,
!                            cm_key_t key,
!                            int flags,
!                            cm_user_t * userp,
!                            cm_req_t * reqp);
  
  extern long cm_Unlock(cm_scache_t *scp, unsigned char sLockType,
!                       LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
!                       cm_user_t *userp, cm_req_t *reqp);
  
  extern long cm_LockCheckRead(cm_scache_t *scp, 
!                              LARGE_INTEGER LOffset, 
!                              LARGE_INTEGER LLength, 
!                              cm_key_t key);
  
  extern long cm_LockCheckWrite(cm_scache_t *scp,
!                               LARGE_INTEGER LOffset,
!                               LARGE_INTEGER LLength,
!                               cm_key_t key);
  
  extern void cm_CheckLocks(void);
  
***************
*** 237,240 ****
--- 233,257 ----
  extern cm_key_t cm_GenerateKey(unsigned int session, unsigned long process_id, unsigned int file_id);
  
  #define MAX_SYMLINK_COUNT 16
+ 
+ /* make this big enough so that one buffer of dir pages won't overflow.  We'll
+  * check anyway, but we want to minimize the chance that we have to leave stuff
+  * unstat'd.
+  */
+ #define CM_BULKMAX		(3 * AFSCBMAX)
+ 
+ /* 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;
+ 
+ extern afs_int32 cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, 
+                                    cm_user_t *userp, cm_req_t *reqp);
+ 
  #endif /*  __CM_VNODEOPS_H_ENV__ */
Index: openafs/src/WINNT/afsd/cm_volstat.c
diff -c openafs/src/WINNT/afsd/cm_volstat.c:1.1.2.6 openafs/src/WINNT/afsd/cm_volstat.c:1.1.2.7
*** openafs/src/WINNT/afsd/cm_volstat.c:1.1.2.6	Thu Mar 13 00:39:17 2008
--- openafs/src/WINNT/afsd/cm_volstat.c	Thu Jun 26 12:38:30 2008
***************
*** 40,45 ****
--- 40,46 ----
  #include <string.h>
  #include <malloc.h>
  #include "afsd.h"
+ #include "smb.h"
  #include <WINNT/afsreg.h>
  
  HMODULE hVolStatus = NULL;
***************
*** 171,177 ****
  #ifdef _WIN64
  cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64)
  #else /* _WIN64 */
! cm_VolStatus_Network_Started(const char * netbios)
  #endif /* _WIN64 */
  {
      long code = 0;
--- 172,178 ----
  #ifdef _WIN64
  cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64)
  #else /* _WIN64 */
! cm_VolStatus_Network_Started(const char * netbios32)
  #endif /* _WIN64 */
  {
      long code = 0;
***************
*** 182,188 ****
  #ifdef _WIN64
      code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios64);
  #else
!     code = dll_funcs.dll_VolStatus_Network_Started(netbios, netbios);
  #endif
  
      return code;
--- 183,189 ----
  #ifdef _WIN64
      code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios64);
  #else
!     code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios32);
  #endif
  
      return code;
***************
*** 196,202 ****
  #ifdef _WIN64
  cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64)
  #else /* _WIN64 */
! cm_VolStatus_Network_Stopped(const char * netbios)
  #endif /* _WIN64 */
  {
      long code = 0;
--- 197,203 ----
  #ifdef _WIN64
  cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64)
  #else /* _WIN64 */
! cm_VolStatus_Network_Stopped(const char * netbios32)
  #endif /* _WIN64 */
  {
      long code = 0;
***************
*** 207,213 ****
  #ifdef _WIN64
      code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios64);
  #else
!     code = dll_funcs.dll_VolStatus_Network_Stopped(netbios, netbios);
  #endif
  
      return code;
--- 208,214 ----
  #ifdef _WIN64
      code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios64);
  #else
!     code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios32);
  #endif
  
      return code;
***************
*** 250,264 ****
  
  
  long
! cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, char *tidPathp, char *pathp)
  {
      long code = 0;
      char src[1024], *p;
      size_t len;
  
      if (hVolStatus == NULL || dll_funcs.version < 2)
          return 0;
  
      snprintf(src,sizeof(src), "\\\\%s%s", volstat_NetbiosName, tidPathp);
      len = strlen(src);
      if ((src[len-1] == '\\' || src[len-1] == '/') &&
--- 251,271 ----
  
  
  long
! cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, const clientchar_t *ctidPathp,
!                                 const clientchar_t *cpathp)
  {
      long code = 0;
      char src[1024], *p;
      size_t len;
+     char * tidPathp = NULL;
+     char * pathp = NULL;
  
      if (hVolStatus == NULL || dll_funcs.version < 2)
          return 0;
  
+     tidPathp = cm_ClientStringToUtf8Alloc(ctidPathp, -1, NULL);
+     pathp = cm_ClientStringToUtf8Alloc(cpathp, -1, NULL);
+ 
      snprintf(src,sizeof(src), "\\\\%s%s", volstat_NetbiosName, tidPathp);
      len = strlen(src);
      if ((src[len-1] == '\\' || src[len-1] == '/') &&
***************
*** 275,280 ****
--- 282,292 ----
      code = dll_funcs.dll_VolStatus_Notify_DFS_Mapping(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
                                                        src, scp->mountPointStringp);
  
+     if (tidPathp)
+         free(tidPathp);
+     if (pathp)
+         free(pathp);
+ 
      return code;
  }
  
***************
*** 299,304 ****
--- 311,318 ----
      cm_req_t    req;
      cm_scache_t *scp;
      cm_volume_t *volp;
+     clientchar_t * cpath = NULL;
+     clientchar_t * cshare = NULL;
  
      if (cellID == NULL || volID == NULL)
          return CM_ERROR_INVAL;
***************
*** 308,314 ****
  
      cm_InitReq(&req);
  
!     code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, cm_rootUserp, (char *)share, &req, &scp);
      if (code)
          goto done;
  
--- 322,333 ----
  
      cm_InitReq(&req);
  
!     cpath = cm_FsStringToClientStringAlloc(path, -1, NULL);
!     cshare = cm_FsStringToClientStringAlloc(share, -1, NULL);
! 
!     code = cm_NameI(cm_data.rootSCachep, cpath,
!                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
!                     cm_rootUserp, cshare, &req, &scp);
      if (code)
          goto done;
  
***************
*** 336,341 ****
--- 355,365 ----
      cm_ReleaseSCache(scp);
  
    done:
+     if (cpath)
+         free(cpath);
+     if (cshare)
+         free(cshare);
+ 
      osi_Log1(afsd_logp,"cm_VolStatus_Path_To_ID code 0x%x",code); 
      return code;
  }
***************
*** 347,352 ****
--- 371,378 ----
      cm_req_t    req;
      cm_scache_t *scp;
      size_t      len;
+     clientchar_t *cpath = NULL;
+     clientchar_t *cshare = NULL;
  
      if (pBufSize == NULL || (pBuffer == NULL && *pBufSize != 0))
          return CM_ERROR_INVAL;
***************
*** 356,363 ****
  
      cm_InitReq(&req);
  
!     code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, 
!                     cm_rootUserp, (char *)share, &req, &scp);
      if (code)
          goto done;
  
--- 382,392 ----
  
      cm_InitReq(&req);
  
!     cpath = cm_FsStringToClientStringAlloc(path, -1, NULL);
!     cshare = cm_FsStringToClientStringAlloc(share, -1, NULL);
! 
!     code = cm_NameI(cm_data.rootSCachep, cpath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, 
!                     cm_rootUserp, cshare, &req, &scp);
      if (code)
          goto done;
  
***************
*** 392,397 ****
--- 421,431 ----
      cm_ReleaseSCache(scp);
  
    done:
+     if (cpath)
+         free(cpath);
+     if (cshare)
+         free(cshare);
+ 
      osi_Log1(afsd_logp,"cm_VolStatus_Path_To_DFSlink code 0x%x",code); 
      return code;
  }
Index: openafs/src/WINNT/afsd/cm_volstat.h
diff -c openafs/src/WINNT/afsd/cm_volstat.h:1.1.2.6 openafs/src/WINNT/afsd/cm_volstat.h:1.1.2.7
*** openafs/src/WINNT/afsd/cm_volstat.h:1.1.2.6	Fri Jan  4 02:58:40 2008
--- openafs/src/WINNT/afsd/cm_volstat.h	Thu Jun 26 12:38:30 2008
***************
*** 42,50 ****
  extern long cm_VolStatus_Service_Stopped(void);
  
  #ifdef _WIN64
! extern long cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64);
  
! extern long cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64);
  #else /* _WIN64 */
  extern long cm_VolStatus_Network_Started(const char * netbios);
  
--- 42,52 ----
  extern long cm_VolStatus_Service_Stopped(void);
  
  #ifdef _WIN64
! extern long cm_VolStatus_Network_Started(const char * netbios32,
!                                          const char * netbios64);
  
! extern long cm_VolStatus_Network_Stopped(const char * netbios32,
!                                          const char * netbios64);
  #else /* _WIN64 */
  extern long cm_VolStatus_Network_Started(const char * netbios);
  
***************
*** 55,65 ****
  
  extern long cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volstatus status);
  
! extern long __fastcall cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cellID, afs_uint32 * volID, enum volstatus *pstatus);
! 
! extern long __fastcall cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *pBufSize, char *pBuffer);
! 
! extern long cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, char *tidPathp, char *pathp);
  
  extern long cm_VolStatus_Invalidate_DFS_Mapping(cm_scache_t *scp);
  
--- 57,75 ----
  
  extern long cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volstatus status);
  
! extern long __fastcall cm_VolStatus_Path_To_ID(const char * share,
!                                                const char * path,
!                                                afs_uint32 * cellID, afs_uint32 * volID,
!                                                enum volstatus *pstatus);
! 
! extern long __fastcall cm_VolStatus_Path_To_DFSlink(const char * share,
!                                                     const char * path,
!                                                     afs_uint32 *pBufSize,
!                                                     char *pBuffer);
! 
! extern long cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp,
!                                             const clientchar_t *tidPathp,
!                                             const clientchar_t *pathp);
  
  extern long cm_VolStatus_Invalidate_DFS_Mapping(cm_scache_t *scp);
  
Index: openafs/src/WINNT/afsd/cm_volume.c
diff -c openafs/src/WINNT/afsd/cm_volume.c:1.14.4.38 openafs/src/WINNT/afsd/cm_volume.c:1.14.4.40
*** openafs/src/WINNT/afsd/cm_volume.c:1.14.4.38	Fri Apr 18 12:46:07 2008
--- openafs/src/WINNT/afsd/cm_volume.c	Thu Jun 26 10:38:24 2008
***************
*** 10,22 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <winsock2.h>
  #include <nb30.h>
- #else
- #include <sys/socket.h>
- #endif /* !DJGPP */
  #include <string.h>
  #include <malloc.h>
  #include "afsd.h"
--- 10,18 ----
***************
*** 1660,1668 ****
      size_t len = strlen(volname);
      cm_vol_state_t *statep;
  
!     if (stricmp(".readonly", &volname[len-9]) == 0)
          statep = &volp->vol[ROVOL];
!     else if (stricmp(".backup", &volname[len-7]) == 0)
          statep = &volp->vol[BACKVOL];
      else 
          statep = &volp->vol[RWVOL];
--- 1656,1664 ----
      size_t len = strlen(volname);
      cm_vol_state_t *statep;
  
!     if (cm_stricmp_utf8N(".readonly", &volname[len-9]) == 0)
          statep = &volp->vol[ROVOL];
!     else if (cm_stricmp_utf8N(".backup", &volname[len-7]) == 0)
          statep = &volp->vol[BACKVOL];
      else 
          statep = &volp->vol[RWVOL];
Index: openafs/src/WINNT/afsd/cm_volume.h
diff -c openafs/src/WINNT/afsd/cm_volume.h:1.5.6.13 openafs/src/WINNT/afsd/cm_volume.h:1.5.6.14
*** openafs/src/WINNT/afsd/cm_volume.h:1.5.6.13	Mon Apr 14 18:44:04 2008
--- openafs/src/WINNT/afsd/cm_volume.h	Wed May 28 13:34:52 2008
***************
*** 126,132 ****
  
  extern void cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID);
  
! extern void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus old, enum volstatus new);
  
  extern enum volstatus cm_GetVolumeStatus(cm_volume_t *volp, afs_uint32 volID);
  
--- 126,132 ----
  
  extern void cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID);
  
! extern void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus oldState, enum volstatus newState);
  
  extern enum volstatus cm_GetVolumeStatus(cm_volume_t *volp, afs_uint32 volID);
  
Index: openafs/src/WINNT/afsd/fs.c
diff -c openafs/src/WINNT/afsd/fs.c:1.32.4.20 openafs/src/WINNT/afsd/fs.c:1.32.4.22
*** openafs/src/WINNT/afsd/fs.c:1.32.4.20	Wed Mar 19 09:24:00 2008
--- openafs/src/WINNT/afsd/fs.c	Thu Jun 26 08:45:11 2008
***************
*** 251,257 ****
      blob.out_size = MAXSIZE;
      blob.out = space;
  
!     code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
      if (code) {
  	if ((errno == EINVAL) || (errno == ENOENT)) 
              return 0;
--- 251,257 ----
      blob.out_size = MAXSIZE;
      blob.out = space;
  
!     code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
      if (code) {
  	if ((errno == EINVAL) || (errno == ENOENT)) 
              return 0;
***************
*** 269,277 ****
      blob.out_size = MAXSIZE;
      blob.out = space;
  
!     code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
      if (code == 0)
!         return !stricmp("Freelance.Local.Root",space);
      return 1;   /* assume it is because it is more restrictive that way */
  }
  
--- 269,277 ----
      blob.out_size = MAXSIZE;
      blob.out = space;
  
!     code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
      if (code == 0)
!         return !cm_stricmp_utf8N("Freelance.Local.Root",space);
      return 1;   /* assume it is because it is more restrictive that way */
  }
  
***************
*** 612,618 ****
      }
      ta->minuslist = first;
  
-   exit:
      return ta;
  
    nminus_err:
--- 612,617 ----
***************
*** 929,935 ****
  	blob.out_size = MAXSIZE;
  	blob.in_size = idf;
  	blob.in = blob.out = space;
! 	code = pioctl(ti->data, VIOCGETAL, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
--- 928,934 ----
  	blob.out_size = MAXSIZE;
  	blob.in_size = idf;
  	blob.in = blob.out = space;
! 	code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
***************
*** 992,998 ****
  	blob.in = AclToString(ta);
  	blob.out_size=0;
  	blob.in_size = 1+(long)strlen(blob.in);
! 	code = pioctl(ti->data, VIOCSETAL, &blob, 1);
  	if (code) {
  	    if (errno == EINVAL) {
  		if (ta->dfs) {
--- 991,997 ----
  	blob.in = AclToString(ta);
  	blob.out_size=0;
  	blob.in_size = 1+(long)strlen(blob.in);
! 	code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
  	if (code) {
  	    if (errno == EINVAL) {
  		if (ta->dfs) {
***************
*** 1069,1075 ****
      blob.out_size = MAXSIZE;
      blob.in_size = idf;
      blob.in = blob.out = space;
!     code = pioctl(as->parms[0].items->data, VIOCGETAL, &blob, 1);
      if (code) {
  	Die(errno, as->parms[0].items->data);
  	return 1;
--- 1068,1074 ----
      blob.out_size = MAXSIZE;
      blob.in_size = idf;
      blob.in = blob.out = space;
!     code = pioctl_utf8(as->parms[0].items->data, VIOCGETAL, &blob, 1);
      if (code) {
  	Die(errno, as->parms[0].items->data);
  	return 1;
***************
*** 1086,1092 ****
  	blob.out_size = MAXSIZE;
  	blob.in_size = idf;
  	blob.in = blob.out = space;
! 	code = pioctl(ti->data, VIOCGETAL, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
--- 1085,1091 ----
  	blob.out_size = MAXSIZE;
  	blob.in_size = idf;
  	blob.in = blob.out = space;
! 	code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
***************
*** 1130,1136 ****
  	blob.in = AclToString(ta);
  	blob.out_size=0;
  	blob.in_size = 1+(long)strlen(blob.in);
! 	code = pioctl(ti->data, VIOCSETAL, &blob, 1);
  	if (code) {
  	    if (errno == EINVAL) {
  		fprintf(stderr,
--- 1129,1135 ----
  	blob.in = AclToString(ta);
  	blob.out_size=0;
  	blob.in_size = 1+(long)strlen(blob.in);
! 	code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
  	if (code) {
  	    if (errno == EINVAL) {
  		fprintf(stderr,
***************
*** 1148,1154 ****
      return error;
  }
  
! /* pioctl() call to get the cellname of a pathname */
  static afs_int32
  GetCell(char *fname, char *cellname)
  {
--- 1147,1153 ----
      return error;
  }
  
! /* pioctl_utf8() call to get the cellname of a pathname */
  static afs_int32
  GetCell(char *fname, char *cellname)
  {
***************
*** 1159,1165 ****
      blob.out_size = MAXCELLCHARS;
      blob.out = cellname;
  
!     code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1);
      return code;
  }
  
--- 1158,1164 ----
      blob.out_size = MAXCELLCHARS;
      blob.out = cellname;
  
!     code = pioctl_utf8(fname, VIOC_FILE_CELL_NAME, &blob, 1);
      return code;
  }
  
***************
*** 1258,1264 ****
  	blob.out_size = MAXSIZE;
  	blob.in_size = 0;
  	blob.out = space;
! 	code = pioctl(ti->data, VIOCGETAL, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
--- 1257,1263 ----
  	blob.out_size = MAXSIZE;
  	blob.in_size = 0;
  	blob.out = space;
! 	code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
***************
*** 1289,1295 ****
  	    blob.in=AclToString(ta);
  	    blob.in_size = (long)strlen(blob.in)+1;
  	    blob.out_size = 0;
! 	    code = pioctl(ti->data, VIOCSETAL, &blob, 1);
  	    if (code) {
  		if (errno == EINVAL) {
  		    fprintf(stderr,
--- 1288,1294 ----
  	    blob.in=AclToString(ta);
  	    blob.in_size = (long)strlen(blob.in)+1;
  	    blob.out_size = 0;
! 	    code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
  	    if (code) {
  		if (errno == EINVAL) {
  		    fprintf(stderr,
***************
*** 1352,1358 ****
  	blob.out_size = MAXSIZE;
  	blob.in_size = idf;
  	blob.in = blob.out = space;
! 	code = pioctl(ti->data, VIOCGETAL, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
--- 1351,1357 ----
  	blob.out_size = MAXSIZE;
  	blob.in_size = idf;
  	blob.in = blob.out = space;
! 	code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
***************
*** 1415,1421 ****
      struct ViceIoctl blob;
  
      blob.in_size = blob.out_size = 0;
!     code = pioctl(NULL, VIOC_FLUSHALL, &blob, 0);
      if (code) {
  	fprintf(stderr, "Error flushing all ");
  	return 1;
--- 1414,1420 ----
      struct ViceIoctl blob;
  
      blob.in_size = blob.out_size = 0;
!     code = pioctl_utf8(NULL, VIOC_FLUSHALL, &blob, 0);
      if (code) {
  	fprintf(stderr, "Error flushing all ");
  	return 1;
***************
*** 1434,1440 ****
      SetDotDefault(&as->parms[0].items);
      for(ti=as->parms[0].items; ti; ti=ti->next) {
  	blob.in_size = blob.out_size = 0;
! 	code = pioctl(ti->data, VIOC_FLUSHVOLUME, &blob, 0);
  	if (code) {
  	    fprintf(stderr, "Error flushing volume ");
              perror(ti->data);
--- 1433,1439 ----
      SetDotDefault(&as->parms[0].items);
      for(ti=as->parms[0].items; ti; ti=ti->next) {
  	blob.in_size = blob.out_size = 0;
! 	code = pioctl_utf8(ti->data, VIOC_FLUSHVOLUME, &blob, 0);
  	if (code) {
  	    fprintf(stderr, "Error flushing volume ");
              perror(ti->data);
***************
*** 1468,1474 ****
          blob.in = &options;
  
  	blob.out_size = 0;
! 	code = pioctl(ti->data, VIOCFLUSH, &blob, 0);
  	if (code) {
  	    if (errno == EMFILE) {
  		fprintf(stderr, "%s: Can't flush active file %s\n", pn, 
--- 1467,1473 ----
          blob.in = &options;
  
  	blob.out_size = 0;
! 	code = pioctl_utf8(ti->data, VIOCFLUSH, &blob, 0);
  	if (code) {
  	    if (errno == EMFILE) {
  		fprintf(stderr, "%s: Can't flush active file %s\n", pn, 
***************
*** 1550,1556 ****
  	    input += strlen(motd) + 1;
  	} else 
              *(input++) = '\0';
! 	code = pioctl(ti->data,VIOCSETVOLSTAT, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
--- 1549,1555 ----
  	    input += strlen(motd) + 1;
  	} else 
              *(input++) = '\0';
! 	code = pioctl_utf8(ti->data,VIOCSETVOLSTAT, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
***************
*** 1619,1625 ****
  
          blob.out_size = sizeof(cm_fid_t);
          blob.out = (char *) &fid;
!         if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
              options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
              options.fid = fid;
          } else {
--- 1618,1624 ----
  
          blob.out_size = sizeof(cm_fid_t);
          blob.out = (char *) &fid;
!         if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1)) {
              options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
              options.fid = fid;
          } else {
***************
*** 1631,1642 ****
          blob.out_size = sizeof(filetype);
          blob.out = &filetype;
  
!         code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
  
          blob.out_size = MAXCELLCHARS;
          blob.out = cell;
  
!         code = pioctl(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
          printf("%s %s (%u.%u.%u) contained in cell %s\n",
                  filetypestr(filetype),
                  ti->data, fid.volume, fid.vnode, fid.unique,
--- 1630,1641 ----
          blob.out_size = sizeof(filetype);
          blob.out = &filetype;
  
!         code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
  
          blob.out_size = MAXCELLCHARS;
          blob.out = cell;
  
!         code = pioctl_utf8(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
          printf("%s %s (%u.%u.%u) contained in cell %s\n",
                  filetypestr(filetype),
                  ti->data, fid.volume, fid.vnode, fid.unique,
***************
*** 1644,1650 ****
  
  	blob.out_size = 2 * sizeof(afs_uint32);
          blob.out = (char *) &owner;
! 	if (0 == pioctl(ti->data, VIOCGETOWNER, &blob, 1)) {
  	    char oname[PR_MAXNAMELEN] = "(unknown)";
              char confDir[257];
  
--- 1643,1649 ----
  
  	blob.out_size = 2 * sizeof(afs_uint32);
          blob.out = (char *) &owner;
! 	if (0 == pioctl_utf8(ti->data, VIOCGETOWNER, &blob, 1)) {
  	    char oname[PR_MAXNAMELEN] = "(unknown)";
              char confDir[257];
  
***************
*** 1658,1664 ****
  
  	blob.out = space;
  	blob.out_size = MAXSIZE;
! 	code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
  	if (code == 0) {
              status = (VolumeStatus *)space;
              name = (char *)status + sizeof(*status);
--- 1657,1663 ----
  
  	blob.out = space;
  	blob.out_size = MAXSIZE;
! 	code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
  	if (code == 0) {
              status = (VolumeStatus *)space;
              name = (char *)status + sizeof(*status);
***************
*** 1671,1677 ****
          }
  
          errno = 0;
!         code = pioctl(ti->data, VIOC_PATH_AVAILABILITY, &blob, 1);
          switch (errno) {
          case 0:
              printf("Volume is online\n");
--- 1670,1676 ----
          }
  
          errno = 0;
!         code = pioctl_utf8(ti->data, VIOC_PATH_AVAILABILITY, &blob, 1);
          switch (errno) {
          case 0:
              printf("Volume is online\n");
***************
*** 1713,1719 ****
  	blob.out_size = MAXSIZE;
  	blob.in_size = 0;
  	blob.out = space;
! 	code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
--- 1712,1718 ----
  	blob.out_size = MAXSIZE;
  	blob.in_size = 0;
  	blob.out = space;
! 	code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
***************
*** 1759,1765 ****
          
          blob.out_size = sizeof(cm_fid_t);
          blob.out = (char *) &fid;
!         if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
              options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
              options.fid = fid;
          } else {
--- 1758,1764 ----
          
          blob.out_size = sizeof(cm_fid_t);
          blob.out = (char *) &fid;
!         if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1)) {
              options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
              options.fid = fid;
          } else {
***************
*** 1771,1782 ****
          blob.out_size = sizeof(filetype);
          blob.out = &filetype;
  
!         code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
  
          blob.out_size = MAXSIZE;
  	blob.out = space;
  	memset(space, 0, sizeof(space));
! 	code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
--- 1770,1781 ----
          blob.out_size = sizeof(filetype);
          blob.out = &filetype;
  
!         code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
  
          blob.out_size = MAXSIZE;
  	blob.out = space;
  	memset(space, 0, sizeof(space));
! 	code = pioctl_utf8(ti->data, VIOCWHEREIS, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
***************
*** 1817,1823 ****
  	blob.out_size = MAXSIZE;
  	blob.in_size = 0;
  	blob.out = space;
! 	code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
--- 1816,1822 ----
  	blob.out_size = MAXSIZE;
  	blob.in_size = 0;
  	blob.out = space;
! 	code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
***************
*** 1846,1852 ****
  	blob.out_size = MAXSIZE;
  	blob.in_size = 0;
  	blob.out = space;
! 	code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
--- 1845,1851 ----
  	blob.out_size = MAXSIZE;
  	blob.in_size = 0;
  	blob.out = space;
! 	code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
***************
*** 1994,2000 ****
  	blob.out = space;
  	memset(space, 0, MAXSIZE);
  
! 	code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
  
  	if (code == 0) {
  	    printf("'%s' is a %smount point for volume '%s'\n",
--- 1993,1999 ----
  	blob.out = space;
  	memset(space, 0, MAXSIZE);
  
! 	code = pioctl_utf8(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
  
  	if (code == 0) {
  	    printf("'%s' is a %smount point for volume '%s'\n",
***************
*** 2091,2097 ****
  	    blob.in_size = 0;
  	    blob.out_size = sizeof(localCellName);
  	    blob.out = localCellName;
! 	    code = pioctl(parent, VIOC_GET_WS_CELL, &blob, 1);
  	    if (!code)
  		cellName = localCellName;
  	}
--- 2090,2096 ----
  	    blob.in_size = 0;
  	    blob.out_size = sizeof(localCellName);
  	    blob.out = localCellName;
! 	    code = pioctl_utf8(parent, VIOC_GET_WS_CELL, &blob, 1);
  	    if (!code)
  		cellName = localCellName;
  	}
***************
*** 2142,2148 ****
      blob.in_size = 1 + (long)strlen(space);
      blob.in = space;
      blob.out = NULL;
!     code = pioctl(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
  #else /* not WIN32 */
      code = symlink(space, path);
  #endif /* not WIN32 */
--- 2141,2147 ----
      blob.in_size = 1 + (long)strlen(space);
      blob.in = space;
      blob.out = NULL;
!     code = pioctl_utf8(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
  #else /* not WIN32 */
      code = symlink(space, path);
  #endif /* not WIN32 */
***************
*** 2203,2209 ****
  	blob.in_size = (long)strlen(tp)+1;
  	blob.out = lsbuffer;
  	blob.out_size = sizeof(lsbuffer);
! 	code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
  	if (code) {
  	    if (errno == EINVAL) {
  		fprintf(stderr,"%s: '%s' is not a mount point.\n", pn, ti->data);
--- 2202,2208 ----
  	blob.in_size = (long)strlen(tp)+1;
  	blob.out = lsbuffer;
  	blob.out_size = sizeof(lsbuffer);
! 	code = pioctl_utf8(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
  	if (code) {
  	    if (errno == EINVAL) {
  		fprintf(stderr,"%s: '%s' is not a mount point.\n", pn, ti->data);
***************
*** 2223,2229 ****
          blob.out_size = 0;
  	blob.in = tp;
  	blob.in_size = (long)strlen(tp)+1;
! 	code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
--- 2222,2228 ----
          blob.out_size = 0;
  	blob.in = tp;
  	blob.in_size = (long)strlen(tp)+1;
! 	code = pioctl_utf8(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
  	if (code) {
  	    Die(errno, ti->data);
              error = 1;
***************
*** 2306,2312 ****
  #endif /* WIN32 */
      }
  
!     code = pioctl(0, VIOCCKSERV, &blob, 1);
      if (code) {
  	if ((errno == EACCES) && (checkserv.tinterval > 0)) {
  	    printf("Must be root to change -interval\n");
--- 2305,2311 ----
  #endif /* WIN32 */
      }
  
!     code = pioctl_utf8(0, VIOCCKSERV, &blob, 1);
      if (code) {
  	if ((errno == EACCES) && (checkserv.tinterval > 0)) {
  	    printf("Must be root to change -interval\n");
***************
*** 2376,2382 ****
      if (code)
          return 1;
  
!     code = pioctl(0, VIOC_GAG, &blob, 1);
      if (code) {
  	Die(errno, 0);
          return 1;
--- 2375,2381 ----
      if (code)
          return 1;
  
!     code = pioctl_utf8(0, VIOC_GAG, &blob, 1);
      if (code) {
  	Die(errno, 0);
          return 1;
***************
*** 2392,2398 ****
      
      blob.in_size = 0;
      blob.out_size = 0;
!     code = pioctl(0, VIOCCKBACK, &blob, 1);
      if (code) {
  	Die(errno, 0);
  	return 1;
--- 2391,2397 ----
      
      blob.in_size = 0;
      blob.out_size = 0;
!     code = pioctl_utf8(0, VIOCCKBACK, &blob, 1);
      if (code) {
  	Die(errno, 0);
  	return 1;
***************
*** 2436,2442 ****
      blob.in = (char *) &temp;
      blob.in_size = sizeof(afs_int32);
      blob.out_size = 0;
!     code = pioctl(0, VIOCSETCACHESIZE, &blob, 1);
      if (code) {
  	Die(errno, (char *) 0);
          return 1;
--- 2435,2441 ----
      blob.in = (char *) &temp;
      blob.in_size = sizeof(afs_int32);
      blob.out_size = 0;
!     code = pioctl_utf8(0, VIOCSETCACHESIZE, &blob, 1);
      if (code) {
  	Die(errno, (char *) 0);
          return 1;
***************
*** 2458,2464 ****
      blob.in_size = 0;
      blob.out_size = sizeof(parms);
      blob.out = (char *) &parms;
!     code = pioctl(0, VIOCGETCACHEPARMS, &blob, 1);
      if (code) {
  	Die(errno, NULL);
          return 1;
--- 2457,2463 ----
      blob.in_size = 0;
      blob.out_size = sizeof(parms);
      blob.out = (char *) &parms;
!     code = pioctl_utf8(0, VIOCGETCACHEPARMS, &blob, 1);
      if (code) {
  	Die(errno, NULL);
          return 1;
***************
*** 2494,2500 ****
  	blob.in_size = sizeof(afs_int32);
  	blob.in = space;
  	blob.out = space;
! 	code = pioctl(0, VIOCGETCELL, &blob, 1);
  	if (code < 0) {
  	    if (errno == EDOM) 
                  break;	/* done with the list */
--- 2493,2499 ----
  	blob.in_size = sizeof(afs_int32);
  	blob.in = space;
  	blob.out = space;
! 	code = pioctl_utf8(0, VIOCGETCELL, &blob, 1);
  	if (code < 0) {
  	    if (errno == EDOM) 
                  break;	/* done with the list */
***************
*** 2545,2551 ****
  	blob.in_size = sizeof(afs_int32);
  	blob.in = space;
  	blob.out = space;
! 	code = pioctl(0, VIOC_GETALIAS, &blob, 1);
  	if (code < 0) {
  	    if (errno == EDOM)
  		break;		/* done with the list */
--- 2544,2550 ----
  	blob.in_size = sizeof(afs_int32);
  	blob.in = space;
  	blob.out = space;
! 	code = pioctl_utf8(0, VIOC_GETALIAS, &blob, 1);
  	if (code < 0) {
  	    if (errno == EDOM)
  		break;		/* done with the list */
***************
*** 2592,2598 ****
      blob.in = (char *) &hostAddr;
      blob.out = (char *) &hostAddr;
      
!     code = pioctl(0, VIOC_CBADDR, &blob, 1);
      if (code < 0) {
  	Die(errno, 0);
  	return 1;
--- 2591,2597 ----
      blob.in = (char *) &hostAddr;
      blob.out = (char *) &hostAddr;
      
!     code = pioctl_utf8(0, VIOC_CBADDR, &blob, 1);
      if (code < 0) {
  	Die(errno, 0);
  	return 1;
***************
*** 2667,2673 ****
      blob.in_size = size;
      blob.in = space;
      blob.out_size = 0;
!     code = pioctl(0, VIOCNEWCELL, &blob, 1);
      if (code < 0)
  	Die(errno, 0);
      return 0;
--- 2666,2672 ----
      blob.in_size = size;
      blob.in = space;
      blob.out_size = 0;
!     code = pioctl_utf8(0, VIOCNEWCELL, &blob, 1);
      if (code < 0)
  	Die(errno, 0);
      return 0;
***************
*** 2685,2691 ****
      blob.out_size = MAXSIZE;
      blob.out = space;
  
!     code = pioctl((char *) 0, VIOCNEWCELL, &blob, 1);
  
      if (code) {
          Die(errno, (char *) 0);
--- 2684,2690 ----
      blob.out_size = MAXSIZE;
      blob.out = space;
  
!     code = pioctl_utf8((char *) 0, VIOCNEWCELL, &blob, 1);
  
      if (code) {
          Die(errno, (char *) 0);
***************
*** 2719,2725 ****
      blob.in = space;
      blob.out_size = 0;
      blob.out = space;
!     code = pioctl(0, VIOC_NEWALIAS, &blob, 1);
      if (code < 0) {
  	if (errno == EEXIST) {
  	    fprintf(stderr,
--- 2718,2724 ----
      blob.in = space;
      blob.out_size = 0;
      blob.out = space;
!     code = pioctl_utf8(0, VIOC_NEWALIAS, &blob, 1);
      if (code < 0) {
  	if (errno == EEXIST) {
  	    fprintf(stderr,
***************
*** 2765,2771 ****
  
          blob.out_size = sizeof(cm_fid_t);
          blob.out = (char *) &fid;
!         if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
              options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
              options.fid = fid;
          } else {
--- 2764,2770 ----
  
          blob.out_size = sizeof(cm_fid_t);
          blob.out = (char *) &fid;
!         if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1)) {
              options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
              options.fid = fid;
          } else {
***************
*** 2777,2788 ****
          blob.out_size = sizeof(filetype);
          blob.out = &filetype;
  
!         code = pioctl(ti->data, VIOC_GETFILETYPE, &blob, 1);
  
          blob.out_size = MAXCELLCHARS;
          blob.out = cell;
  
!         code = pioctl(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
  	if (code) {
  	    if (errno == ENOENT)
  		fprintf(stderr,"%s: no such cell as '%s'\n", pn, ti->data);
--- 2776,2787 ----
          blob.out_size = sizeof(filetype);
          blob.out = &filetype;
  
!         code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
  
          blob.out_size = MAXCELLCHARS;
          blob.out = cell;
  
!         code = pioctl_utf8(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
  	if (code) {
  	    if (errno == ENOENT)
  		fprintf(stderr,"%s: no such cell as '%s'\n", pn, ti->data);
***************
*** 2809,2815 ****
      blob.out_size = MAXSIZE;
      blob.out = space;
  
!     code = pioctl(NULL, VIOC_GET_WS_CELL, &blob, 1);
  
      if (code) {
  	Die(errno, NULL);
--- 2808,2814 ----
      blob.out_size = MAXSIZE;
      blob.out = space;
  
!     code = pioctl_utf8(NULL, VIOC_GET_WS_CELL, &blob, 1);
  
      if (code) {
  	Die(errno, NULL);
***************
*** 2871,2877 ****
      blob.out_size = sizeof(afs_int32);
      blob.in = (char *) &hostAddr;
      blob.out = (char *) &hostAddr;
!     code = pioctl(0, VIOC_AFS_MARINER_HOST, &blob, 1);
      if (code) {
  	Die(errno, 0);
  	return 1;
--- 2870,2876 ----
      blob.out_size = sizeof(afs_int32);
      blob.in = (char *) &hostAddr;
      blob.out = (char *) &hostAddr;
!     code = pioctl_utf8(0, VIOC_AFS_MARINER_HOST, &blob, 1);
      if (code) {
  	Die(errno, 0);
  	return 1;
***************
*** 2934,2940 ****
          *(input++) = '\0';
      }
      memcpy(space, &setp, sizeof(afs_int32));
!     code = pioctl(0, VIOC_AFS_SYSNAME, &blob, 1);
      if (code) {
          Die(errno, 0);
          return 1;
--- 2933,2939 ----
          *(input++) = '\0';
      }
      memcpy(space, &setp, sizeof(afs_int32));
!     code = pioctl_utf8(0, VIOC_AFS_SYSNAME, &blob, 1);
      if (code) {
          Die(errno, 0);
          return 1;
***************
*** 3040,3046 ****
      blob.in_size = sizeof(afs_int32);
      blob.out = (char *) &exportcall;
      blob.out_size = sizeof(afs_int32);
!     code = pioctl(0, VIOC_EXPORTAFS, &blob, 1);
      if (code) {
  	if (errno == ENODEV) {
  	    fprintf(stderr,
--- 3039,3045 ----
      blob.in_size = sizeof(afs_int32);
      blob.out = (char *) &exportcall;
      blob.out_size = sizeof(afs_int32);
!     code = pioctl_utf8(0, VIOC_EXPORTAFS, &blob, 1);
      if (code) {
  	if (errno == ENODEV) {
  	    fprintf(stderr,
***************
*** 3090,3096 ****
  	}
  	blob.in_size = 1+(long)strlen(info.name);
  	blob.in = info.name;
! 	code = pioctl(0, VIOC_GETCELLSTATUS, &blob, 1);
  	if (code) {
  	    if (errno == ENOENT)
  		fprintf(stderr,"%s: the cell named '%s' does not exist\n", pn, info.name);
--- 3089,3095 ----
  	}
  	blob.in_size = 1+(long)strlen(info.name);
  	blob.in = info.name;
! 	code = pioctl_utf8(0, VIOC_GETCELLSTATUS, &blob, 1);
  	if (code) {
  	    if (errno == ENOENT)
  		fprintf(stderr,"%s: the cell named '%s' does not exist\n", pn, info.name);
***************
*** 3166,3172 ****
  	blob.in = (caddr_t) &args;
  	blob.out_size = 0;
  	blob.out = (caddr_t) 0;
! 	code = pioctl(0, VIOC_SETCELLSTATUS, &blob, 1);
  	if (code) {
  	    Die(errno, info.name);      /* XXX added cell name to Die() call */
              error = 1;
--- 3165,3171 ----
  	blob.in = (caddr_t) &args;
  	blob.out_size = 0;
  	blob.out = (caddr_t) 0;
! 	code = pioctl_utf8(0, VIOC_SETCELLSTATUS, &blob, 1);
  	if (code) {
  	    Die(errno, info.name);      /* XXX added cell name to Die() call */
              error = 1;
***************
*** 3218,3224 ****
  {
      int code;
      cm_SSetPref_t *ssp;
!     code = pioctl(0, VIOC_SETSPREFS, &gblob, 1);
  
      ssp = (cm_SSetPref_t *)space;
      gblob.in_size = (long)(((char *)&(ssp->servers[0])) - (char *)ssp);
--- 3217,3223 ----
  {
      int code;
      cm_SSetPref_t *ssp;
!     code = pioctl_utf8(0, VIOC_SETSPREFS, &gblob, 1);
  
      ssp = (cm_SSetPref_t *)space;
      gblob.in_size = (long)(((char *)&(ssp->servers[0])) - (char *)ssp);
***************
*** 3236,3249 ****
  {
      int code;
  
!     code = pioctl(0, VIOC_SETSPREFS, &gblob, 1);
      if (code && (errno == EINVAL)) {
  	struct setspref *ssp;
  	ssp = (struct setspref *)gblob.in;
  	if (!(ssp->flags & DBservers)) {
  	    gblob.in = (void *)&(ssp->servers[0]);
  	    gblob.in_size -= ((char *)&(ssp->servers[0])) - (char *)ssp;
! 	    code = pioctl(0, VIOC_SETSPREFS33, &gblob, 1);
  	    return code ? errno : 0;
  	}
  	fprintf(stderr,
--- 3235,3248 ----
  {
      int code;
  
!     code = pioctl_utf8(0, VIOC_SETSPREFS, &gblob, 1);
      if (code && (errno == EINVAL)) {
  	struct setspref *ssp;
  	ssp = (struct setspref *)gblob.in;
  	if (!(ssp->flags & DBservers)) {
  	    gblob.in = (void *)&(ssp->servers[0]);
  	    gblob.in_size -= ((char *)&(ssp->servers[0])) - (char *)ssp;
! 	    code = pioctl_utf8(0, VIOC_SETSPREFS33, &gblob, 1);
  	    return code ? errno : 0;
  	}
  	fprintf(stderr,
***************
*** 3617,3623 ****
          in->num_servers = (MAXSIZE - 2*sizeof(short))/sizeof(struct cm_SPref);
          in->flags = vlservers; 
  
!         code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
          if (code){
              perror("getserverprefs pioctl");
              Die (errno,0);
--- 3616,3622 ----
          in->num_servers = (MAXSIZE - 2*sizeof(short))/sizeof(struct cm_SPref);
          in->flags = vlservers; 
  
!         code = pioctl_utf8(0, VIOC_GETSPREFS, &blob, 1);
          if (code){
              perror("getserverprefs pioctl");
              Die (errno,0);
***************
*** 3689,3695 ****
  	    (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
  	in->flags = vlservers;
  
! 	code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
  	if (code) {
  	    perror("getserverprefs pioctl");
  	    return 1;
--- 3688,3694 ----
  	    (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
  	in->flags = vlservers;
  
! 	code = pioctl_utf8(0, VIOC_GETSPREFS, &blob, 1);
  	if (code) {
  	    perror("getserverprefs pioctl");
  	    return 1;
***************
*** 3716,3721 ****
--- 3715,3766 ----
  }
  #endif /* WIN32 */
  
+ static afs_int32
+ SmbUnicodeCmd(struct cmd_syndesc * asp, void * arock)
+ {
+     long inValue = 0;
+     long outValue = 0;
+     long code;
+ 
+     struct ViceIoctl blob;
+ 
+     if (asp->parms[0].items) {
+         /* On */
+ 
+         inValue = 3;
+     } else if (asp->parms[1].items) {
+         /* Off */
+ 
+         inValue = 2;
+     }
+ 
+     if (inValue != 0 && !IsAdmin()) {
+         fprintf (stderr, "Permission denied: Requires AFS Client Administrator access.\n");
+         return EACCES;
+     }
+ 
+     blob.in_size = sizeof(inValue);
+     blob.in = (char *) &inValue;
+     blob.out_size = sizeof(outValue);
+     blob.out = (char *) &outValue;
+ 
+     code = pioctl_utf8(NULL, VIOC_UNICODECTL, &blob, 1);
+     if (code) {
+         Die(errno, NULL);
+         return code;
+     }
+ 
+     if (outValue != 2) {
+         printf("Unicode support is %s%s.\n",
+                ((outValue != 0)? "enabled":"disabled"),
+                ((inValue != 0)? " for new SMB connections":""));
+     } else {
+         printf("Unicode support is absent in this installation of OpenAFS.\n");
+     }
+ 
+     return 0;
+ }
+ 
  static int
  UuidCmd(struct cmd_syndesc *asp, void *arock)
  {
***************
*** 3747,3753 ****
      blob.out_size = sizeof(outValue);
      blob.out = (char *) &outValue;
  
!     code = pioctl(NULL, VIOC_UUIDCTL, &blob, 1);
      if (code) {
          Die(errno, NULL);
          return code;
--- 3792,3798 ----
      blob.out_size = sizeof(outValue);
      blob.out = (char *) &outValue;
  
!     code = pioctl_utf8(NULL, VIOC_UUIDCTL, &blob, 1);
      if (code) {
          Die(errno, NULL);
          return code;
***************
*** 3806,3812 ****
      blob.out_size = sizeof(long);
      blob.out = (char *) &outValue;
          
!     code = pioctl(NULL, VIOC_TRACECTL, &blob, 1);
      if (code) {
          Die(errno, NULL);
          return code;
--- 3851,3857 ----
      blob.out_size = sizeof(long);
      blob.out = (char *) &outValue;
          
!     code = pioctl_utf8(NULL, VIOC_TRACECTL, &blob, 1);
      if (code) {
          Die(errno, NULL);
          return code;
***************
*** 3887,3900 ****
      /* once per -file */
      for (ti = as->parms[1].items; ti; ti = ti->next) {
  	/* Do this solely to see if the file is there */
! 	code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
  	    continue;
  	}
  
! 	code = pioctl(ti->data, VIOC_STOREBEHIND, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
--- 3932,3945 ----
      /* once per -file */
      for (ti = as->parms[1].items; ti; ti = ti->next) {
  	/* Do this solely to see if the file is there */
! 	code = pioctl_utf8(ti->data, VIOCWHEREIS, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
  	    continue;
  	}
  
! 	code = pioctl_utf8(ti->data, VIOC_STOREBEHIND, &blob, 1);
  	if (code) {
  	    Die(errno, ti->data);
  	    error = 1;
***************
*** 3918,3924 ****
       */
      if (!as->parms[1].items || (allfiles != -1)) {
  	tsb.sb_default = allfiles;
! 	code = pioctl(0, VIOC_STOREBEHIND, &blob, 1);
  	if (code) {
  	    Die(errno, ((allfiles == -1) ? 0 : "-allfiles"));
  	    error = 1;
--- 3963,3969 ----
       */
      if (!as->parms[1].items || (allfiles != -1)) {
  	tsb.sb_default = allfiles;
! 	code = pioctl_utf8(0, VIOC_STOREBEHIND, &blob, 1);
  	if (code) {
  	    Die(errno, ((allfiles == -1) ? 0 : "-allfiles"));
  	    error = 1;
***************
*** 3961,3967 ****
      blob.in = (char *) &flag;
      blob.in_size = sizeof(flag);
      blob.out_size = 0;
!     code = pioctl(0, VIOC_SETRXKCRYPT, &blob, 1);
      if (code)
          Die(code, NULL);
      return 0;
--- 4006,4012 ----
      blob.in = (char *) &flag;
      blob.in_size = sizeof(flag);
      blob.out_size = 0;
!     code = pioctl_utf8(0, VIOC_SETRXKCRYPT, &blob, 1);
      if (code)
          Die(code, NULL);
      return 0;
***************
*** 3979,3985 ****
      blob.out_size = sizeof(flag);
      blob.out = space;
  
!     code = pioctl(0, VIOC_GETRXKCRYPT, &blob, 1);
  
      if (code) 
          Die(code, NULL);
--- 4024,4030 ----
      blob.out_size = sizeof(flag);
      blob.out = space;
  
!     code = pioctl_utf8(0, VIOC_GETRXKCRYPT, &blob, 1);
  
      if (code) 
          Die(code, NULL);
***************
*** 4025,4031 ****
      blob.out_size = sizeof(long);
      blob.out = (char *) &outValue;
  
!     code = pioctl(NULL, VIOC_TRACEMEMDUMP, &blob, 1);
      if (code) {
          Die(errno, NULL);
          return code;
--- 4070,4076 ----
      blob.out_size = sizeof(long);
      blob.out = (char *) &outValue;
  
!     code = pioctl_utf8(NULL, VIOC_TRACEMEMDUMP, &blob, 1);
      if (code) {
          Die(errno, NULL);
          return code;
***************
*** 4217,4223 ****
  	in->num_servers =
  	    (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
  	/* returns addr in network byte order */
! 	code = pioctl(0, VIOC_GETCPREFS, &blob, 1);
  	if (code) {
  	    perror("getClientInterfaceAddr pioctl");
  	    return 1;
--- 4262,4268 ----
  	in->num_servers =
  	    (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
  	/* returns addr in network byte order */
! 	code = pioctl_utf8(0, VIOC_GETCPREFS, &blob, 1);
  	if (code) {
  	    perror("getClientInterfaceAddr pioctl");
  	    return 1;
***************
*** 4306,4312 ****
      }
      blob.in_size = sizeUsed - sizeof(struct spref);
  
!     code = pioctl(0, VIOC_SETCPREFS, &blob, 1);	/* network order */
      if (code) {
  	Die(errno, 0);
  	error = 1;
--- 4351,4357 ----
      }
      blob.in_size = sizeUsed - sizeof(struct spref);
  
!     code = pioctl_utf8(0, VIOC_SETCPREFS, &blob, 1);	/* network order */
      if (code) {
  	Die(errno, 0);
  	error = 1;
***************
*** 4417,4423 ****
  	blob.out_size = 0;
  	memset(space, 0, MAXSIZE);
  
! 	code = pioctl(parent_dir, VIOC_AFS_FLUSHMOUNT, &blob, 1);
  
  	if (code != 0) {
  	    if (errno == EINVAL) {
--- 4462,4468 ----
  	blob.out_size = 0;
  	memset(space, 0, MAXSIZE);
  
! 	code = pioctl_utf8(parent_dir, VIOC_AFS_FLUSHMOUNT, &blob, 1);
  
  	if (code != 0) {
  	    if (errno == EINVAL) {
***************
*** 4457,4463 ****
      blob.in_size = sizeof(afs_int32);
      blob.out_size = 0;
  
!     code = pioctl(NULL, VIOC_RXSTAT_PROC, &blob, 1);
      if (code != 0) {
  	Die(errno, NULL);
  	return 1;
--- 4502,4508 ----
      blob.in_size = sizeof(afs_int32);
      blob.out_size = 0;
  
!     code = pioctl_utf8(NULL, VIOC_RXSTAT_PROC, &blob, 1);
      if (code != 0) {
  	Die(errno, NULL);
  	return 1;
***************
*** 4491,4497 ****
      blob.in_size = sizeof(afs_int32);
      blob.out_size = 0;
  
!     code = pioctl(NULL, VIOC_RXSTAT_PEER, &blob, 1);
      if (code != 0) {
  	Die(errno, NULL);
  	return 1;
--- 4536,4542 ----
      blob.in_size = sizeof(afs_int32);
      blob.out_size = 0;
  
!     code = pioctl_utf8(NULL, VIOC_RXSTAT_PEER, &blob, 1);
      if (code != 0) {
  	Die(errno, NULL);
  	return 1;
***************
*** 4571,4577 ****
      blob.in_size = sizeof(test);
      blob.out_size = 0;
  
!     code = pioctl(NULL, VIOC_VOLSTAT_TEST, &blob, 1);
      if (code != 0) {
  	Die(errno, NULL);
  	return 1;
--- 4616,4622 ----
      blob.in_size = sizeof(test);
      blob.out_size = 0;
  
!     code = pioctl_utf8(NULL, VIOC_VOLSTAT_TEST, &blob, 1);
      if (code != 0) {
  	Die(errno, NULL);
  	return 1;
***************
*** 4584,4593 ****
  #include "AFS_component_version_number.c"
  #endif
  
! main(int argc, char **argv)
  {
      afs_int32 code;
      struct cmd_syndesc *ts;
  
  #ifdef	AFS_AIX32_ENV
      /*
--- 4629,4683 ----
  #include "AFS_component_version_number.c"
  #endif
  
! static void
! FreeUtf8CmdLine(int argc, char ** argv)
! {
!     int i;
!     for (i=0; i < argc; i++) {
!         if (argv[i])
!             free(argv[i]);
!     }
!     free(argv);
! }
! 
! static char **
! MakeUtf8Cmdline(int argc, const wchar_t **wargv)
! {
!     char ** argv;
!     int i;
! 
!     argv = calloc(argc, sizeof(argv[0]));
!     if (argv == NULL)
!         return NULL;
! 
!     for (i=0; i < argc; i++) {
!         int s;
! 
!         s = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, FALSE);
!         if (s == 0 ||
!             (argv[i] = calloc(s+1, sizeof(char))) == NULL) {
!             break;
!         }
! 
!         s = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], s+1, NULL, FALSE);
!         if (s == 0) {
!             break;
!         }
!     }
! 
!     if (i < argc) {
!         FreeUtf8CmdLine(argc, argv);
!         return NULL;
!     }
! 
!     return argv;
! }
! 
! int wmain(int argc, wchar_t **wargv)
  {
      afs_int32 code;
      struct cmd_syndesc *ts;
+     char ** argv;
  
  #ifdef	AFS_AIX32_ENV
      /*
***************
*** 4609,4614 ****
--- 4699,4706 ----
      WSAStartup(0x0101, &WSAjunk);
  #endif /* WIN32 */
  
+     argv = MakeUtf8Cmdline(argc, wargv);
+ 
      /* try to find volume location information */
      osi_Init();
  
***************
*** 4885,4895 ****
--- 4977,4993 ----
      cmd_AddParm(ts, "-volume",  CMD_SINGLE, CMD_OPTIONAL, "volume name or number");
      cmd_AddParm(ts, "-state",   CMD_SINGLE, CMD_OPTIONAL, "new volume state: online, busy, offline, down");
  
+     ts = cmd_CreateSyntax("smbunicode", SmbUnicodeCmd, NULL, "enable or disable Unicode on new SMB connections");
+     cmd_AddParm(ts, "-on", CMD_FLAG, CMD_OPTIONAL, "enable Unicode on new connections");
+     cmd_AddParm(ts, "-off", CMD_FLAG, CMD_OPTIONAL, "disable Unicode on new connections");
+ 
      code = cmd_Dispatch(argc, argv);
  
      if (rxInitDone) 
          rx_Finalize();
      
+     FreeUtf8CmdLine(argc, argv);
+     
      return code;
  }
  
Index: openafs/src/WINNT/afsd/fs_utils.c
diff -c openafs/src/WINNT/afsd/fs_utils.c:1.10.2.4 openafs/src/WINNT/afsd/fs_utils.c:1.10.2.5
*** openafs/src/WINNT/afsd/fs_utils.c:1.10.2.4	Fri Feb  8 21:32:19 2008
--- openafs/src/WINNT/afsd/fs_utils.c	Fri May  9 11:10:11 2008
***************
*** 74,81 ****
  		/* there's a drive letter there */
          firstp = pathp+2;
          pathHasDrive = 1;
!     }
!     else {
          firstp = pathp;
  		pathHasDrive = 0;
  	}   
--- 74,80 ----
  		/* there's a drive letter there */
          firstp = pathp+2;
          pathHasDrive = 1;
!     } else {
          firstp = pathp;
  		pathHasDrive = 0;
  	}   
***************
*** 86,92 ****
          return 0;
      }
          
!     GetCurrentDirectory(sizeof(origPath), origPath);
          
  	doSwitch = 0;
      if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
--- 85,91 ----
          return 0;
      }
          
!     GetCurrentDirectoryA(sizeof(origPath), origPath);
          
  	doSwitch = 0;
      if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
***************
*** 98,111 ****
          newPath[0] = *pathp;
          newPath[1] = ':';
          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);
      strcpy(outPathp, tpath+2);	/* skip drive letter */
  	/* if there is a non-null name after the drive, append it */
  	if (*firstp != 0) {
--- 97,110 ----
          newPath[0] = *pathp;
          newPath[1] = ':';
          newPath[2] = 0;
!         if (!SetCurrentDirectoryA(newPath)) {
  			code = GetLastError();
              return code;
          }
      }
          
      /* now get the absolute path to the current wdir in this drive */
!     GetCurrentDirectoryA(sizeof(tpath), tpath);
      strcpy(outPathp, tpath+2);	/* skip drive letter */
  	/* if there is a non-null name after the drive, append it */
  	if (*firstp != 0) {
***************
*** 115,121 ****
  
  	/* finally, if necessary, switch back to our home drive letter */
      if (doSwitch) {
! 		SetCurrentDirectory(origPath);
      }
          
      return 0;
--- 114,120 ----
  
  	/* finally, if necessary, switch back to our home drive letter */
      if (doSwitch) {
!         SetCurrentDirectoryA(origPath);
      }
          
      return 0;
***************
*** 197,205 ****
      char *pmount=mountRoot;
      DWORD len=sizeof(mountRoot)-1;
      printf("int mountroot \n");
!     if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, 
                        (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey)!= ERROR_SUCCESS)
!          || (RegQueryValueEx(parmKey, "Mountroot", NULL, NULL,(LPBYTE)(mountRoot), &len)!= ERROR_SUCCESS)
           || (len==sizeof(mountRoot)-1)
           ) 
          strcpy(mountRoot, "\\afs"); 
--- 196,204 ----
      char *pmount=mountRoot;
      DWORD len=sizeof(mountRoot)-1;
      printf("int mountroot \n");
!     if ((RegOpenKeyExA(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, 
                        (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey)!= ERROR_SUCCESS)
!         || (RegQueryValueExA(parmKey, "Mountroot", NULL, NULL,(LPBYTE)(mountRoot), &len)!= ERROR_SUCCESS)
           || (len==sizeof(mountRoot)-1)
           ) 
          strcpy(mountRoot, "\\afs"); 
Index: openafs/src/WINNT/afsd/rawops.c
diff -c openafs/src/WINNT/afsd/rawops.c:1.2.4.6 openafs/src/WINNT/afsd/rawops.c:1.2.4.7
*** openafs/src/WINNT/afsd/rawops.c:1.2.4.6	Wed Mar 19 11:36:27 2008
--- openafs/src/WINNT/afsd/rawops.c	Thu Jun 26 10:38:24 2008
***************
*** 321,332 ****
              nbytes = count;	/* don't go past end of request */
  
          /* now copy the data */
! #ifdef DJGPP
!         if (dosflag)
!             dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
!         else
! #endif /* DJGPP */
!             memcpy(bufferp->datap + bufIndex, op, nbytes);
          buf_SetDirty(bufferp, bufIndex, nbytes);
  
          /* and record the last writer */
--- 321,327 ----
              nbytes = count;	/* don't go past end of request */
  
          /* now copy the data */
!         memcpy(bufferp->datap + bufIndex, op, nbytes);
          buf_SetDirty(bufferp, bufIndex, nbytes);
  
          /* and record the last writer */
Index: openafs/src/WINNT/afsd/smb.c
diff -c openafs/src/WINNT/afsd/smb.c:1.118.2.70.2.1 openafs/src/WINNT/afsd/smb.c:1.118.2.81
*** openafs/src/WINNT/afsd/smb.c:1.118.2.70.2.1	Sun Jun 22 23:05:04 2008
--- openafs/src/WINNT/afsd/smb.c	Wed Jul 16 11:23:46 2008
***************
*** 10,25 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #pragma warning(push)
  #pragma warning(disable: 4005)
  #include <ntstatus.h>
  #pragma warning(pop)
- #else
- #include <sys/timeb.h>
- #include <tzfile.h>
- #endif /* !DJGPP */
  #include <stddef.h>
  #include <stdlib.h>
  #include <malloc.h>
--- 10,20 ----
***************
*** 36,43 ****
  #include "smb.h"
  #include "lanahelper.h"
  
  /* These characters are illegal in Windows filenames */
! static char *illegalChars = "\\/:*?\"<>|";
  
  static int smbShutdownFlag = 0;
  static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
--- 31,41 ----
  #include "smb.h"
  #include "lanahelper.h"
  
+ #define STRSAFE_NO_DEPRECATE
+ #include <strsafe.h>
+ 
  /* These characters are illegal in Windows filenames */
! static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
  
  static int smbShutdownFlag = 0;
  static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
***************
*** 65,71 ****
  osi_rwlock_t smb_rctLock;
  osi_mutex_t  smb_ListenerLock;
  osi_mutex_t  smb_StartedLock;
!  
  unsigned char smb_LANadapter = LANA_INVALID;
  unsigned char smb_sharename[NCBNAMSZ+1] = {0};
  int  smb_LanAdapterChangeDetected = 0;
--- 63,69 ----
  osi_rwlock_t smb_rctLock;
  osi_mutex_t  smb_ListenerLock;
  osi_mutex_t  smb_StartedLock;
! 
  unsigned char smb_LANadapter = LANA_INVALID;
  unsigned char smb_sharename[NCBNAMSZ+1] = {0};
  int  smb_LanAdapterChangeDetected = 0;
***************
*** 113,125 ****
  LANA_ENUM lana_list;
  /* for raw I/O */
  osi_mutex_t smb_RawBufLock;
- #ifdef DJGPP
- #define SMB_RAW_BUFS 4
- dos_ptr smb_RawBufs;
- int smb_RawBufSel[SMB_RAW_BUFS];
- #else
  char *smb_RawBufs;
- #endif /* DJGPP */
  
  #define SMB_MASKFLAG_TILDE 1
  #define SMB_MASKFLAG_CASEFOLD 2
--- 111,117 ----
***************
*** 128,143 ****
  
  /* for raw write */
  typedef struct raw_write_cont {
! 	long code;
! 	osi_hyper_t offset;
! 	long count;
! #ifndef DJGPP
! 	char *buf;
! #else
! 	dos_ptr buf;
! #endif /* DJGPP */
! 	int writeMode;
! 	long alreadyWritten;
  } raw_write_cont_t;
  
  /* dir search stuff */
--- 120,131 ----
  
  /* for raw write */
  typedef struct raw_write_cont {
!     long code;
!     osi_hyper_t offset;
!     long count;
!     char *buf;
!     int writeMode;
!     long alreadyWritten;
  } raw_write_cont_t;
  
  /* dir search stuff */
***************
*** 148,161 ****
  /* hide dot files? */
  int smb_hideDotFiles;
  
  /* global state about V3 protocols */
  int smb_useV3;		/* try to negotiate V3 */
  
! #ifndef DJGPP
! static showErrors = 0;
  /* MessageBox or something like it */
! int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
! #endif /* DJGPP */
  
  /* GMT time info:
   * Time in Unix format of midnight, 1/1/1970 local time.
--- 136,151 ----
  /* hide dot files? */
  int smb_hideDotFiles;
  
+ /* Negotiate Unicode support? */
+ LONG smb_UseUnicode;
+ 
  /* global state about V3 protocols */
  int smb_useV3;		/* try to negotiate V3 */
  
! static int showErrors = 0;
  /* MessageBox or something like it */
! int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
! = NULL;
  
  /* GMT time info:
   * Time in Unix format of midnight, 1/1/1970 local time.
***************
*** 185,216 ****
  void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
  			NCB *ncbp, raw_write_cont_t *rwcp);
  int smb_NetbiosInit(int);
- #ifdef DJGPP
- #ifndef AFS_WIN95_ENV
- DWORD smb_ServerExceptionFilter(void);
- #endif
- 
- extern char cm_HostName[];
- extern char cm_confDir[];
- #endif
- 
- #ifdef DJGPP
- #define LPTSTR char *
- #define GetComputerName(str, sizep) \
-        strcpy((str), cm_HostName); \
-        *(sizep) = strlen(cm_HostName)
- #endif /* DJGPP */
  
  #ifdef LOG_PACKET
  void smb_LogPacket(smb_packet_t *packet);
  #endif /* LOG_PACKET */
! 
! char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
  int smb_ServerDomainNameLength = 0;
! char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
! int smb_ServerOSLength = sizeof(smb_ServerOS);
! char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
! int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
  
  /* Faux server GUID. This is never checked. */
  GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
--- 175,191 ----
  void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
  			NCB *ncbp, raw_write_cont_t *rwcp);
  int smb_NetbiosInit(int);
  
  #ifdef LOG_PACKET
  void smb_LogPacket(smb_packet_t *packet);
  #endif /* LOG_PACKET */
!                                                          
! clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
  int smb_ServerDomainNameLength = 0;
! clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
! int smb_ServerOSLength = lengthof(smb_ServerOS);
! clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
! int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
  
  /* Faux server GUID. This is never checked. */
  GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
***************
*** 519,526 ****
  /* 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 && (*s == '\\' || *s == '/'); s++);
--- 494,502 ----
  /* 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(clientchar_t *lastComp) {
!     clientchar_t *s;
! 
      if(lastComp) {
          /* skip over slashes */
          for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
***************
*** 529,540 ****
          return 0;
  
      /* nulls, curdir and parent dir doesn't count */
!     if (!*s) 
          return 0;
!     if (*s == '.') {
          if (!*(s + 1)) 
              return 0;
!         if(*(s+1) == '.' && !*(s + 2)) 
              return 0;
          return 1;
      }
--- 505,516 ----
          return 0;
  
      /* nulls, curdir and parent dir doesn't count */
!     if (!*s)
          return 0;
!     if (*s == _C('.')) {
          if (!*(s + 1)) 
              return 0;
!         if(*(s+1) == _C('.') && !*(s + 2)) 
              return 0;
          return 1;
      }
***************
*** 554,560 ****
      return (int)num;
  }
  
- #ifndef DJGPP
  void ShowUnixTime(char *FuncName, time_t unixTime)
  {
      FILETIME ft;
--- 530,535 ----
***************
*** 580,588 ****
          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)
  {
--- 555,561 ----
***************
*** 625,642 ****
       */
      *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(&t);
-     *pDST = t.dstflag;
-     *pDstBias = -60;    /* where can this be different? */
-     *pBias = t.timezone;
- }       
- #endif /* DJGPP */
   
  
  void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
--- 598,603 ----
***************
*** 700,706 ****
  }
  #endif /* USE_NUMERIC_TIME_CONV */
  
- #ifndef DJGPP
  #ifdef USE_NUMERIC_TIME_CONV
  void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
  {
--- 661,666 ----
***************
*** 752,780 ****
      SystemTimeToFileTime(&stm, largeTimep);
  }
  #endif /* USE_NUMERIC_TIME_CONV */
- #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
  #ifdef USE_NUMERIC_TIME_CONV
  void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
  {
--- 712,718 ----
***************
*** 814,840 ****
      _timezone = save_timezone;
  }       
  #endif /* USE_NUMERIC_TIME_CONV */
- #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(afs_uint32 *searchTimep, time_t unixTime)
  {
--- 752,757 ----
***************
*** 893,904 ****
  
  void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 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)
--- 810,816 ----
***************
*** 985,1000 ****
      return vcp;
  }
  
! int smb_IsStarMask(char *maskp)
  {
      int i;
!     char tc;
          
      for(i=0; i<11; i++) {
          tc = *maskp++;
!         if (tc == '?' || tc == '*' || tc == '>')
  	    return 1;
!     }	
      return 0;
  }
  
--- 897,912 ----
      return vcp;
  }
  
! int smb_IsStarMask(clientchar_t *maskp)
  {
      int i;
!     clientchar_t tc;
          
      for(i=0; i<11; i++) {
          tc = *maskp++;
!         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
  	    return 1;
!     }
      return 0;
  }
  
***************
*** 1035,1040 ****
--- 947,964 ----
               */
              vcp->refCount++;
          }
+     } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
+         /* The reference count is non-zero but the VC is dead.
+          * This implies that some FIDs, TIDs, etc on the VC have yet to 
+          * be cleaned up.  Add a reference that will be dropped by
+          * smb_CleanupDeadVC() and try to cleanup the VC again.
+          * Eventually the refCount will drop to zero when all of the
+          * active threads working with the VC end their task.
+          */
+         vcp->refCount++;        /* put the refCount back */
+         lock_ReleaseWrite(&smb_rctLock);
+         smb_CleanupDeadVC(vcp);
+         lock_ObtainWrite(&smb_rctLock);
      }
  }
  
***************
*** 1077,1083 ****
      smb_user_t *uidpIter;
      smb_user_t *uidpNext;
      smb_vc_t **vcpp;
! 
  
      lock_ObtainMutex(&vcp->mx);
      if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
--- 1001,1007 ----
      smb_user_t *uidpIter;
      smb_user_t *uidpNext;
      smb_vc_t **vcpp;
!     afs_uint32 refCount = 0;
  
      lock_ObtainMutex(&vcp->mx);
      if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
***************
*** 1107,1113 ****
      for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
          fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
  
!         if (fidpIter->delete)
              continue;
  
          fid = fidpIter->fid;
--- 1031,1037 ----
      for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
          fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
  
!         if (fidpIter->deleteOk)
              continue;
  
          fid = fidpIter->fid;
***************
*** 1125,1133 ****
  
      for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
  	tidpNext = tidpIter->nextp;
! 	if (tidpIter->delete)
  	    continue;
! 	tidpIter->delete = 1;
  
  	tid = tidpIter->tid;
  	osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
--- 1049,1057 ----
  
      for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
  	tidpNext = tidpIter->nextp;
! 	if (tidpIter->deleteOk)
  	    continue;
! 	tidpIter->deleteOk = 1;
  
  	tid = tidpIter->tid;
  	osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
***************
*** 1139,1147 ****
  
      for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
  	uidpNext = uidpIter->nextp;
! 	if (uidpIter->delete)
  	    continue;
! 	uidpIter->delete = 1;
  
  	/* do not add an additional reference count for the smb_user_t
  	 * as the smb_vc_t already is holding a reference */
--- 1063,1071 ----
  
      for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
  	uidpNext = uidpIter->nextp;
! 	if (uidpIter->deleteOk)
  	    continue;
! 	uidpIter->deleteOk = 1;
  
  	/* do not add an additional reference count for the smb_user_t
  	 * as the smb_vc_t already is holding a reference */
***************
*** 1155,1162 ****
  
      /* The vcp is now on the deadVCsp list.  We intentionally drop the
       * reference so that the refcount can reach 0 and we can delete it */
      smb_ReleaseVCNoLock(vcp);
!     
      lock_ReleaseWrite(&smb_rctLock);
      osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
  }
--- 1079,1098 ----
  
      /* The vcp is now on the deadVCsp list.  We intentionally drop the
       * reference so that the refcount can reach 0 and we can delete it */
+     refCount = vcp->refCount;
      smb_ReleaseVCNoLock(vcp);
! 
!     /* 
!      * If the refCount == 1 going into the ReleaseVCNoLock call 
!      * the object will be freed and it won't be safe to clear 
!      * the flag.
!      */
!     if (refCount > 1) {
!         lock_ObtainMutex(&vcp->mx);
!         vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
!         lock_ReleaseMutex(&vcp->mx);
!     }
! 
      lock_ReleaseWrite(&smb_rctLock);
      osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
  }
***************
*** 1168,1174 ****
      lock_ObtainWrite(&smb_rctLock);
    retry:
      for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
! 	if (tidp->refCount == 0 && tidp->delete) {
  	    tidp->refCount++;
  	    smb_ReleaseTID(tidp, TRUE);
  	    goto retry;
--- 1104,1110 ----
      lock_ObtainWrite(&smb_rctLock);
    retry:
      for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
! 	if (tidp->refCount == 0 && tidp->deleteOk) {
  	    tidp->refCount++;
  	    smb_ReleaseTID(tidp, TRUE);
  	    goto retry;
***************
*** 1177,1183 ****
          if (tid == tidp->tid) {
              tidp->refCount++;
              break;
!         }	
      }
      if (!tidp && (flags & SMB_FLAG_CREATE)) {
          tidp = malloc(sizeof(*tidp));
--- 1113,1119 ----
          if (tid == tidp->tid) {
              tidp->refCount++;
              break;
!         }
      }
      if (!tidp && (flags & SMB_FLAG_CREATE)) {
          tidp = malloc(sizeof(*tidp));
***************
*** 1192,1198 ****
      }
      lock_ReleaseWrite(&smb_rctLock);
      return tidp;
! }       	
  
  void smb_HoldTIDNoLock(smb_tid_t *tidp)
  {
--- 1128,1134 ----
      }
      lock_ReleaseWrite(&smb_rctLock);
      return tidp;
! }
  
  void smb_HoldTIDNoLock(smb_tid_t *tidp)
  {
***************
*** 1209,1215 ****
      if (!locked)
          lock_ObtainWrite(&smb_rctLock);
      osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
!     if (tidp->refCount == 0 && (tidp->delete)) {
          ltpp = &tidp->vcp->tidsp;
          for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
              if (tp == tidp) 
--- 1145,1151 ----
      if (!locked)
          lock_ObtainWrite(&smb_rctLock);
      osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
!     if (tidp->refCount == 0 && (tidp->deleteOk)) {
          ltpp = &tidp->vcp->tidsp;
          for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
              if (tp == tidp) 
***************
*** 1237,1245 ****
      for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
          if (uid == uidp->userID) {
              uidp->refCount++;
!             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
  		     vcp, uidp->userID, 
! 		     osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
              break;
          }
      }
--- 1173,1181 ----
      for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
          if (uid == uidp->userID) {
              uidp->refCount++;
!             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
  		     vcp, uidp->userID, 
! 		     ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
              break;
          }
      }
***************
*** 1253,1274 ****
          vcp->usersp = uidp;
          lock_InitializeMutex(&uidp->mx, "user_t mutex");
          uidp->userID = uid;
!         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
! 		 vcp, uidp->userID, 
! 		 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
      }
      lock_ReleaseWrite(&smb_rctLock);
      return uidp;
  }       	
  
! smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
  {
      smb_username_t *unp= NULL;
  
      lock_ObtainWrite(&smb_rctLock);
      for(unp = usernamesp; unp; unp = unp->nextp) {
!         if (stricmp(unp->name, usern) == 0 &&
!              stricmp(unp->machine, machine) == 0) {
              unp->refCount++;
              break;
          }
--- 1189,1211 ----
          vcp->usersp = uidp;
          lock_InitializeMutex(&uidp->mx, "user_t mutex");
          uidp->userID = uid;
!         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
! 		 vcp, uidp->userID,
! 		 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
      }
      lock_ReleaseWrite(&smb_rctLock);
      return uidp;
  }       	
  
! smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
!                                    afs_uint32 flags)
  {
      smb_username_t *unp= NULL;
  
      lock_ObtainWrite(&smb_rctLock);
      for(unp = usernamesp; unp; unp = unp->nextp) {
!         if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
!             cm_ClientStrCmpI(unp->machine, machine) == 0) {
              unp->refCount++;
              break;
          }
***************
*** 1278,1285 ****
          memset(unp, 0, sizeof(*unp));
          unp->refCount = 1;
          unp->nextp = usernamesp;
!         unp->name = strdup(usern);
!         unp->machine = strdup(machine);
          usernamesp = unp;
          lock_InitializeMutex(&unp->mx, "username_t mutex");
  	if (flags & SMB_FLAG_AFSLOGON)
--- 1215,1222 ----
          memset(unp, 0, sizeof(*unp));
          unp->refCount = 1;
          unp->nextp = usernamesp;
!         unp->name = cm_ClientStrDup(usern);
!         unp->machine = cm_ClientStrDup(machine);
          usernamesp = unp;
          lock_InitializeMutex(&unp->mx, "username_t mutex");
  	if (flags & SMB_FLAG_AFSLOGON)
***************
*** 1290,1296 ****
      return unp;
  }	
  
! smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
  {
      smb_user_t *uidp= NULL;
  
--- 1227,1233 ----
      return unp;
  }	
  
! smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
  {
      smb_user_t *uidp= NULL;
  
***************
*** 1298,1307 ****
      for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
          if (!uidp->unp) 
              continue;
!         if (stricmp(uidp->unp->name, usern) == 0) {
              uidp->refCount++;
!             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
! 		     vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
              break;
          } else
              continue;
--- 1235,1244 ----
      for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
          if (!uidp->unp) 
              continue;
!         if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
              uidp->refCount++;
!             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
! 		     vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
              break;
          } else
              continue;
***************
*** 1334,1340 ****
  	free(unp->name);
  	free(unp->machine);
  	free(unp);
!     }		
      lock_ReleaseWrite(&smb_rctLock);
      if (userp)
          cm_ReleaseUser(userp);
--- 1271,1277 ----
  	free(unp->name);
  	free(unp->machine);
  	free(unp);
!     }
      lock_ReleaseWrite(&smb_rctLock);
      if (userp)
          cm_ReleaseUser(userp);
***************
*** 1419,1425 ****
   * Return a pointer to a pathname extracted from a TID structure.  The
   * TID structure is not held; assume it won't go away.
   */
! long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
  {
      smb_tid_t *tidp;
      long code = 0;
--- 1356,1362 ----
   * Return a pointer to a pathname extracted from a TID structure.  The
   * TID structure is not held; assume it won't go away.
   */
! long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
  {
      smb_tid_t *tidp;
      long code = 0;
***************
*** 1478,1484 ****
  
    retry:
      for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
! 	if (fidp->refCount == 0 && fidp->delete) {
  	    fidp->refCount++;
  	    lock_ReleaseWrite(&smb_rctLock);
  	    smb_ReleaseFID(fidp);
--- 1415,1421 ----
  
    retry:
      for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
! 	if (fidp->refCount == 0 && fidp->deleteOk) {
  	    fidp->refCount++;
  	    lock_ReleaseWrite(&smb_rctLock);
  	    smb_ReleaseFID(fidp);
***************
*** 1577,1583 ****
      lock_ObtainMutex(&fidp->mx);
      lock_ObtainWrite(&smb_rctLock);
      osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
!     if (fidp->refCount == 0 && (fidp->delete)) {
          vcp = fidp->vcp;
          fidp->vcp = NULL;
          scp = fidp->scp;    /* release after lock is released */
--- 1514,1520 ----
      lock_ObtainMutex(&fidp->mx);
      lock_ObtainWrite(&smb_rctLock);
      osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
!     if (fidp->refCount == 0 && (fidp->deleteOk)) {
          vcp = fidp->vcp;
          fidp->vcp = NULL;
          scp = fidp->scp;    /* release after lock is released */
***************
*** 1600,1609 ****
          if (ioctlp) {
              if (ioctlp->prefix)
                  cm_FreeSpace(ioctlp->prefix);
!             if (ioctlp->inAllocp)
!                 free(ioctlp->inAllocp);
!             if (ioctlp->outAllocp)
!                 free(ioctlp->outAllocp);
              free(ioctlp);
          }       
  	lock_ReleaseMutex(&fidp->mx);
--- 1537,1546 ----
          if (ioctlp) {
              if (ioctlp->prefix)
                  cm_FreeSpace(ioctlp->prefix);
!             if (ioctlp->ioctl.inAllocp)
!                 free(ioctlp->ioctl.inAllocp);
!             if (ioctlp->ioctl.outAllocp)
!                 free(ioctlp->ioctl.outAllocp);
              free(ioctlp);
          }       
  	lock_ReleaseMutex(&fidp->mx);
***************
*** 1629,1640 ****
   * Case-insensitive search for one string in another;
   * used to find variable names in submount pathnames.
   */
! static char *smb_stristr(char *str1, char *str2)
  {
!     char *cursor;
  
      for (cursor = str1; *cursor; cursor++)
!         if (stricmp(cursor, str2) == 0)
              return cursor;
  
      return NULL;
--- 1566,1577 ----
   * Case-insensitive search for one string in another;
   * used to find variable names in submount pathnames.
   */
! static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
  {
!     clientchar_t *cursor;
  
      for (cursor = str1; *cursor; cursor++)
!         if (cm_ClientStrCmpI(cursor, str2) == 0)
              return cursor;
  
      return NULL;
***************
*** 1645,1734 ****
   * name has been identified by smb_stristr() and is in substr.  Variable name
   * 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%";
! char VNComputerName[] = "%COMPUTERNAME%";
! char VNLCComputerName[] = "%LCCOMPUTERNAME%";
! 
! #ifdef DJGPP
! /* List available shares */
! int smb_ListShares()
! {
!     char sbmtpath[AFSPATHMAX];
!     char pathName[AFSPATHMAX];
!     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 > 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, AFSPATHMAX,
!                                        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 */
  
  typedef struct smb_findShare_rock {
!     char * shareName;
!     char * match;
      int matchType;
  } smb_findShare_rock_t;
  
--- 1582,1605 ----
   * name has been identified by smb_stristr() and is in substr.  Variable name
   * length (plus one) is in substr_size.  Variable value is in newstr.
   */
! static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr, 
!                       unsigned int substr_size, clientchar_t *newstr)
  {
!     clientchar_t temp[1024];
  
!     cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
!     cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
!     cm_ClientStrCat(str1, cchstr1, temp);
  }
! 
! clientchar_t VNUserName[] = _C("%USERNAME%");
! clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
! clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
! clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
  
  typedef struct smb_findShare_rock {
!     clientchar_t * shareName;
!     clientchar_t * match;
      int matchType;
  } smb_findShare_rock_t;
  
***************
*** 1740,1752 ****
  {
      int matchType = 0;
      smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
!     if (!strnicmp(dep->name, vrock->shareName, 12)) {
!         if(!stricmp(dep->name, vrock->shareName))
              matchType = SMB_FINDSHARE_EXACT_MATCH;
          else
              matchType = SMB_FINDSHARE_PARTIAL_MATCH;
          if(vrock->match) free(vrock->match);
!         vrock->match = strdup(dep->name);
          vrock->matchType = matchType;
  
          if(matchType == SMB_FINDSHARE_EXACT_MATCH)
--- 1611,1627 ----
  {
      int matchType = 0;
      smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
!     normchar_t normName[MAX_PATH];
! 
!     cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
! 
!     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
!         if(!cm_ClientStrCmpI(normName, vrock->shareName))
              matchType = SMB_FINDSHARE_EXACT_MATCH;
          else
              matchType = SMB_FINDSHARE_PARTIAL_MATCH;
          if(vrock->match) free(vrock->match);
!         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
          vrock->matchType = matchType;
  
          if(matchType == SMB_FINDSHARE_EXACT_MATCH)
***************
*** 1757,1774 ****
  
  
  /* find a shareName in the table of submounts */
! 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;
--- 1632,1648 ----
  
  
  /* find a shareName in the table of submounts */
! int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
!                   clientchar_t *shareName,
!                   clientchar_t **pathNamep)
! {
!     DWORD cblen;
!     DWORD cchlen;
!     clientchar_t pathName[1024];
!     clientchar_t *var;
      DWORD sizeTemp;
!     clientchar_t *p, *q;
!     fschar_t *cellname = NULL;
      HKEY parmKey;
      DWORD code;
      DWORD allSubmount = 1;
***************
*** 1779,1796 ****
       * world to do so.
       */
      code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
!                          0, KEY_QUERY_VALUE, &parmKey);
      if (code == ERROR_SUCCESS) {
!         len = sizeof(allSubmount);
          code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
!                                 (BYTE *) &allSubmount, &len);
          if (code != ERROR_SUCCESS) {
              allSubmount = 1;
          }
          RegCloseKey (parmKey);
      }
  
!     if (allSubmount && _stricmp(shareName, "all") == 0) {
          *pathNamep = NULL;
          return 1;
      }
--- 1653,1670 ----
       * world to do so.
       */
      code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
!                         0, KEY_QUERY_VALUE, &parmKey);
      if (code == ERROR_SUCCESS) {
!         cblen = sizeof(allSubmount);
          code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
!                                (BYTE *) &allSubmount, &cblen);
          if (code != ERROR_SUCCESS) {
              allSubmount = 1;
          }
          RegCloseKey (parmKey);
      }
  
!     if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
          *pathNamep = NULL;
          return 1;
      }
***************
*** 1798,1814 ****
      /* 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, "srvsvc") == 0 ||
!         _stricmp(shareName, "wkssvc") == 0 ||
!         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
!         _stricmp(shareName, "DESKTOP.INI") == 0
!          ) {
          *pathNamep = NULL;
          return 0;
      }
--- 1672,1688 ----
      /* In case, the all share is disabled we need to still be able
       * to handle ioctl requests 
       */
!     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
!         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
          return 1;
      }
  
!     if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
!         cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
!         cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
!         cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
!         cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
!         ) {
          *pathNamep = NULL;
          return 0;
      }
***************
*** 1817,1841 ****
  
         They look like <cell>{%,#}<volume>
      */
!     if (strchr(shareName, '%') != NULL ||
!         strchr(shareName, '#') != NULL) {
!         char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
!                                 /* make room for '/@vol:' + mountchar + NULL terminator*/
! 
!         osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
!                  osi_LogSaveString(smb_logp, shareName));
! 
!         snprintf(pathstr, sizeof(pathstr)/sizeof(char),
!                  "/" CM_PREFIX_VOL "%s", shareName);
!         pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
!         len = (DWORD)(strlen(pathstr) + 1);
! 
!         *pathNamep = malloc(len);
          if (*pathNamep) {
!             strcpy(*pathNamep, pathstr);
!             strlwr(*pathNamep);
!             osi_Log1(smb_logp, "   returning pathname [%s]",
!                      osi_LogSaveString(smb_logp, *pathNamep));
  
              return 1;
          } else {
--- 1691,1714 ----
  
         They look like <cell>{%,#}<volume>
      */
!     if (cm_ClientStrChr(shareName, '%') != NULL ||
!          cm_ClientStrChr(shareName, '#') != NULL) {
!         clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
!         /* make room for '/@vol:' + mountchar + NULL terminator*/
! 
!         osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
!                  osi_LogSaveClientString(smb_logp, shareName));
! 
!         cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
!                             _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
!         cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
!   
!         *pathNamep = malloc(cchlen * sizeof(clientchar_t));
          if (*pathNamep) {
!             cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
!             cm_ClientStrLwr(*pathNamep);
!             osi_Log1(smb_logp, "   returning pathname [%S]",
!                      osi_LogSaveClientString(smb_logp, *pathNamep));
  
              return 1;
          } else {
***************
*** 1843,1914 ****
          }
      }
  
- #ifndef DJGPP
      code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
!                          0, KEY_QUERY_VALUE, &parmKey);
      if (code == ERROR_SUCCESS) {
!         len = sizeof(pathName);
!         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
!                                 (BYTE *) pathName, &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 && len != sizeof(pathName) - 1) {
          /* We can accept either unix or PC style AFS pathnames.  Convert
           * Unix-style to PC style here for internal use. 
           */
          p = pathName;
!         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
!             p += strlen(cm_mountRoot);  /* skip mount path */
          q = p;
          while (*q) {
!             if (*q == '/') *q = '\\';    /* change to \ */
              q++;
          }
  
          while (1)
          {
              if (var = smb_stristr(p, VNUserName)) {
                  if (uidp && uidp->unp)
!                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
                  else
!                     smb_subst(p, var, sizeof(VNUserName)," ");
              }
              else if (var = smb_stristr(p, VNLCUserName)) 
              {
                  if (uidp && uidp->unp)
!                     strcpy(temp, uidp->unp->name);
                  else 
!                     strcpy(temp, " ");
!                 _strlwr(temp);
!                 smb_subst(p, var, sizeof(VNLCUserName), temp);
              }
              else if (var = smb_stristr(p, VNComputerName)) 
              {
!                 sizeTemp = sizeof(temp);
!                 GetComputerName((LPTSTR)temp, &sizeTemp);
!                 smb_subst(p, var, sizeof(VNComputerName), temp);
              }
              else if (var = smb_stristr(p, VNLCComputerName)) 
              {
!                 sizeTemp = sizeof(temp);
                  GetComputerName((LPTSTR)temp, &sizeTemp);
!                 _strlwr(temp);
!                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
              }
              else     
                  break;
          }
!         *pathNamep = strdup(p);
          return 1;
      } 
      else
--- 1716,1791 ----
          }
      }
  
      code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
!                         0, KEY_QUERY_VALUE, &parmKey);
      if (code == ERROR_SUCCESS) {
!         cblen = sizeof(pathName);
!         code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
!                                 (BYTE *) pathName, &cblen);
          if (code != ERROR_SUCCESS)
!             cblen = 0;
          RegCloseKey (parmKey);
      } else {
!         cblen = 0;
!     }
!     cchlen = cblen / sizeof(clientchar_t);
!     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
          /* We can accept either unix or PC style AFS pathnames.  Convert
           * Unix-style to PC style here for internal use. 
           */
          p = pathName;
!         cchlen = lengthof(pathName);
! 
!         /* within this code block, we maintain, cchlen = writeable
!            buffer length of p */
! 
!         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
!             p += cm_mountRootCLen;  /* skip mount path */
!             cchlen -= (p - pathName);
!         }
! 
          q = p;
          while (*q) {
!             if (*q == _C('/')) *q = _C('\\');    /* change to \ */
              q++;
          }
  
          while (1)
          {
+             clientchar_t temp[1024];
+ 
              if (var = smb_stristr(p, VNUserName)) {
                  if (uidp && uidp->unp)
!                     smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
                  else
!                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
              }
              else if (var = smb_stristr(p, VNLCUserName)) 
              {
                  if (uidp && uidp->unp)
!                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
                  else 
!                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
!                 cm_ClientStrLwr(temp);
!                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
              }
              else if (var = smb_stristr(p, VNComputerName)) 
              {
!                 sizeTemp = lengthof(temp);
!                 GetComputerNameW(temp, &sizeTemp);
!                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
              }
              else if (var = smb_stristr(p, VNLCComputerName)) 
              {
!                 sizeTemp = lengthof(temp);
                  GetComputerName((LPTSTR)temp, &sizeTemp);
!                 cm_ClientStrLwr(temp);
!                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
              }
              else     
                  break;
          }
!         *pathNamep = cm_ClientStrDup(p);
          return 1;
      } 
      else
***************
*** 1917,1923 ****
          cm_req_t req;
          smb_findShare_rock_t vrock;
          osi_hyper_t thyper;
!         char * p = shareName; 
          int rw = 0;
  
          /*  attempt to locate a partial match in root.afs.  This is because
--- 1794,1801 ----
          cm_req_t req;
          smb_findShare_rock_t vrock;
          osi_hyper_t thyper;
!         fschar_t ftemp[1024];
!         clientchar_t * p = shareName; 
          int rw = 0;
  
          /*  attempt to locate a partial match in root.afs.  This is because
***************
*** 1927,1944 ****
          thyper.HighPart = 0;
          thyper.LowPart = 0;
  
!         vrock.shareName = shareName;
          vrock.match = NULL;
          vrock.matchType = 0;
  
          cm_HoldSCache(cm_data.rootSCachep);
          code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
!             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
          cm_ReleaseSCache(cm_data.rootSCachep);
  
          if (vrock.matchType) {
!             sprintf(pathName,"/%s/",vrock.match);
!             *pathNamep = strdup(strlwr(pathName));
              free(vrock.match);
              return 1;
          }
--- 1805,1825 ----
          thyper.HighPart = 0;
          thyper.LowPart = 0;
  
!         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
          vrock.match = NULL;
          vrock.matchType = 0;
  
          cm_HoldSCache(cm_data.rootSCachep);
          code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
!                            (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
          cm_ReleaseSCache(cm_data.rootSCachep);
  
+         free(vrock.shareName);
+         vrock.shareName = NULL;
+ 
          if (vrock.matchType) {
!             cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
!             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
              free(vrock.match);
              return 1;
          }
***************
*** 1950,1966 ****
              rw = 1;
          }
          /* Get the full name for this cell */
!         code = cm_SearchCellFile(p, temp, 0, 0);
  #ifdef AFS_AFSDB_ENV
          if (code && cm_dnsEnabled) {
              int ttl;
!             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
          }
  #endif
          /* construct the path */
!         if (code == 0) {     
!             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
!             *pathNamep = strdup(strlwr(pathName));
              return 1;
          }
      }
--- 1831,1855 ----
              rw = 1;
          }
          /* Get the full name for this cell */
!         cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
!         code = cm_SearchCellFile(cellname, ftemp, 0, 0);
  #ifdef AFS_AFSDB_ENV
          if (code && cm_dnsEnabled) {
              int ttl;
!             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
          }
  #endif
+         if (cellname)
+             free(cellname);
+ 
          /* construct the path */
!         if (code == 0) {
!             clientchar_t temp[1024];
! 
!             cm_FsStringToClientString(ftemp, cm_FsStrLen(ftemp), temp, 1024);
!             cm_ClientStrPrintfN(pathName, lengthof(pathName),
!                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
!             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
              return 1;
          }
      }
***************
*** 1975,1984 ****
  #define CSC_POLICY_PROGRAMS 2
  #define CSC_POLICY_DISABLE 3
  
! int smb_FindShareCSCPolicy(char *shareName)
  {
      DWORD len;
!     char policy[1024];
      DWORD dwType;
      HKEY hkCSCPolicy;
      int  retval = CSC_POLICY_MANUAL;
--- 1864,1873 ----
  #define CSC_POLICY_PROGRAMS 2
  #define CSC_POLICY_DISABLE 3
  
! int smb_FindShareCSCPolicy(clientchar_t *shareName)
  {
      DWORD len;
!     clientchar_t policy[1024];
      DWORD dwType;
      HKEY hkCSCPolicy;
      int  retval = CSC_POLICY_MANUAL;
***************
*** 1994,2012 ****
                      NULL );
  
      len = sizeof(policy);
!     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &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;
      }
--- 1883,1901 ----
                      NULL );
  
      len = sizeof(policy);
!     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
           len == 0) {
!         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
      }
!     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
      {
          retval = CSC_POLICY_DOCUMENTS;
      }
!     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
      {
          retval = CSC_POLICY_PROGRAMS;
      }
!     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
      {
          retval = CSC_POLICY_DISABLE;
      }
***************
*** 2229,2237 ****
  static smb_packet_t *GetPacket(void)
  {
      smb_packet_t *tbp;
- #ifdef DJGPP
-     unsigned int npar, seg, tb_sel;
- #endif
  
      lock_ObtainWrite(&smb_globalLock);
      tbp = smb_packetFreeListp;
--- 2118,2123 ----
***************
*** 2239,2249 ****
          smb_packetFreeListp = tbp->nextp;
      lock_ReleaseWrite(&smb_globalLock);
      if (!tbp) {
! #ifndef DJGPP
!         tbp = calloc(65540,1);
! #else /* DJGPP */
!         tbp = malloc(sizeof(smb_packet_t));
! #endif /* !DJGPP */
          tbp->magic = SMB_PACKETMAGIC;
          tbp->ncbp = NULL;
          tbp->vcp = NULL;
--- 2125,2131 ----
          smb_packetFreeListp = tbp->nextp;
      lock_ReleaseWrite(&smb_globalLock);
      if (!tbp) {
!         tbp = calloc(sizeof(*tbp),1);
          tbp->magic = SMB_PACKETMAGIC;
          tbp->ncbp = NULL;
          tbp->vcp = NULL;
***************
*** 2256,2281 ****
          tbp->ncb_length = 0;
          tbp->flags = 0;
          tbp->spacep = NULL;
!         
! #ifdef DJGPP
!         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
!         {
!             signed int retval =
!                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
!             if (retval == -1) {
!                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
!                           npar);
!                 osi_panic("",__FILE__,__LINE__);
!             }
!             else {
!                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
!                           npar, retval);
!                 seg = retval;
!             }
!         }
!         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
!         tbp->dos_pkt_sel = tb_sel;
! #endif /* DJGPP */
      }
      osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
  
--- 2138,2144 ----
          tbp->ncb_length = 0;
          tbp->flags = 0;
          tbp->spacep = NULL;
!         tbp->stringsp = NULL;
      }
      osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
  
***************
*** 2288,2293 ****
--- 2151,2157 ----
      tbp = GetPacket();
      memcpy(tbp, pkt, sizeof(smb_packet_t));
      tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
+     tbp->stringsp = NULL;
      if (tbp->vcp)
  	smb_HoldVC(tbp->vcp);
      return tbp;
***************
*** 2297,2305 ****
  {
      smb_ncb_t *tbp;
      NCB *ncbp;
- #ifdef DJGPP
-     unsigned int npar, seg, tb_sel;
- #endif /* DJGPP */
  
      lock_ObtainWrite(&smb_globalLock);
      tbp = smb_ncbFreeListp;
--- 2161,2166 ----
***************
*** 2307,2333 ****
          smb_ncbFreeListp = tbp->nextp;
      lock_ReleaseWrite(&smb_globalLock);
      if (!tbp) {
- #ifndef DJGPP
          tbp = calloc(sizeof(*tbp),1);
- #else /* DJGPP */
-         tbp = malloc(sizeof(*tbp));
-         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
-         {
-             signed int retval =
-                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
-             if (retval == -1) {
-                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
-                           npar);
-                 osi_panic("",__FILE__,__LINE__);
-             } else {
-                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
-                           npar, retval);
-                 seg = retval;
-             }
-         }
-         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
-         tbp->dos_ncb_sel = tb_sel;
- #endif /* !DJGPP */
          tbp->magic = SMB_NCBMAGIC;
      }
          
--- 2168,2174 ----
***************
*** 2335,2346 ****
  
      memset(&tbp->ncb, 0, sizeof(NCB));
      ncbp = &tbp->ncb;
- #ifdef DJGPP
-     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
- #endif /* DJGPP */
      return ncbp;
  }
  
  void smb_FreePacket(smb_packet_t *tbp)
  {
      smb_vc_t * vcp = NULL;
--- 2176,2196 ----
  
      memset(&tbp->ncb, 0, sizeof(NCB));
      ncbp = &tbp->ncb;
      return ncbp;
  }
  
+ static void FreeSMBStrings(smb_packet_t * pkt)
+ {
+     cm_space_t * s;
+     cm_space_t * ns;
+ 
+     for (s = pkt->stringsp; s; s = ns) {
+         ns = s->nextp;
+         cm_FreeSpace(s);
+     }
+     pkt->stringsp = NULL;
+ }
+ 
  void smb_FreePacket(smb_packet_t *tbp)
  {
      smb_vc_t * vcp = NULL;
***************
*** 2361,2366 ****
--- 2211,2217 ----
      tbp->oddByte = 0;
      tbp->ncb_length = 0;
      tbp->flags = 0;
+     FreeSMBStrings(tbp);
      lock_ReleaseWrite(&smb_globalLock);
  
      if (vcp)
***************
*** 2428,2437 ****
                  parm, parmCount, smbp->ncb_length);
  	osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
                   parm, parmCount, smbp->ncb_length);
- #ifndef DJGPP
  	LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
  		 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
- #endif /* !DJGPP */
          osi_panic(s, __FILE__, __LINE__);
      }
      parmDatap = smbp->wctp + (2*parm) + 1;
--- 2279,2286 ----
***************
*** 2478,2487 ****
                  parm, parmCount, smbp->ncb_length);
  	osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
                   parm, parmCount, smbp->ncb_length);
- #ifndef DJGPP
  	LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
  		 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
- #endif /* !DJGPP */
          osi_panic(s, __FILE__, __LINE__);
      }
      parmDatap = smbp->wctp + (2*parm) + 1;
--- 2327,2334 ----
***************
*** 2502,2511 ****
  
          sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
                  parm, offset, parmCount, smbp->ncb_length);
- #ifndef DJGPP
  	LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
  		 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
- #endif /* !DJGPP */
          osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
                  parm, offset, parmCount, smbp->ncb_length);
          osi_panic(s, __FILE__, __LINE__);
--- 2349,2356 ----
***************
*** 2517,2523 ****
  
  void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     char *parmDatap;
  
      /* make sure we have enough slots */
      if (*smbp->wctp <= slot) 
--- 2362,2368 ----
  
  void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     unsigned char *parmDatap;
  
      /* make sure we have enough slots */
      if (*smbp->wctp <= slot) 
***************
*** 2530,2536 ****
  
  void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     char *parmDatap;
  
      /* make sure we have enough slots */
      if (*smbp->wctp <= slot) 
--- 2375,2381 ----
  
  void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     unsigned char *parmDatap;
  
      /* make sure we have enough slots */
      if (*smbp->wctp <= slot) 
***************
*** 2545,2551 ****
  
  void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
  {
!     char *parmDatap;
      int i;
  
      /* make sure we have enough slots */
--- 2390,2396 ----
  
  void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
  {
!     unsigned char *parmDatap;
      int i;
  
      /* make sure we have enough slots */
***************
*** 2559,2565 ****
  
  void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     char *parmDatap;
  
      /* make sure we have enough slots */
      if (*smbp->wctp <= slot) {
--- 2404,2410 ----
  
  void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
  {
!     unsigned char *parmDatap;
  
      /* make sure we have enough slots */
      if (*smbp->wctp <= slot) {
***************
*** 2574,2584 ****
      *parmDatap++ = parmValue & 0xff;
  }
  
! void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
  {
!     char *lastSlashp;
          
!     lastSlashp = strrchr(inPathp, '\\');
      if (lastComponentp)
          *lastComponentp = lastSlashp;
      if (lastSlashp) {
--- 2419,2432 ----
      *parmDatap++ = parmValue & 0xff;
  }
  
! 
! 
! void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
!                             clientchar_t *inPathp)
  {
!     clientchar_t *lastSlashp;
          
!     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
      if (lastComponentp)
          *lastComponentp = lastSlashp;
      if (lastSlashp) {
***************
*** 2594,2607 ****
      }
  }
  
! 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)
--- 2442,2696 ----
      }
  }
  
! clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
!                                   char **chainpp, int flags)
  {
+     size_t cb;
+ 
      if (*inp++ != 0x4) 
          return NULL;
! 
! #ifdef SMB_UNICODE
!     if (!WANTS_UNICODE(pktp))
!         flags |= SMB_STRF_FORCEASCII;
! #endif
! 
!     cb = sizeof(pktp->data) - (inp - pktp->data);
!     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
! #ifdef DEBUG_UNICODE
!         DebugBreak();
! #endif
!         cb = sizeof(pktp->data);
!     }
!     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
! }
! 
! clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
!                               char ** chainpp, int flags)
! {
!     size_t cb;
! 
! #ifdef SMB_UNICODE
!     if (!WANTS_UNICODE(pktp))
!         flags |= SMB_STRF_FORCEASCII;
! #endif
! 
!     cb = sizeof(pktp->data) - (inp - pktp->data);
!     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
! #ifdef DEBUG_UNICODE
!         DebugBreak();
! #endif
!         cb = sizeof(pktp->data);
!     }
!     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
! }
! 
! clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
!                                 size_t cb, char ** chainpp, int flags)
! {
! #ifdef SMB_UNICODE
!     if (!WANTS_UNICODE(pktp))
!         flags |= SMB_STRF_FORCEASCII;
! #endif
! 
!     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
! }
! 
! clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
!                                  size_t cch, char ** chainpp, int flags)
! {
!     size_t cb = cch;
! 
! #ifdef SMB_UNICODE
!     if (!WANTS_UNICODE(pktp))
!         flags |= SMB_STRF_FORCEASCII;
!     else
!         cb = cch * sizeof(wchar_t);
! #endif
! 
!     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
! }
! 
! clientchar_t *
! smb_ParseStringBuf(const unsigned char * bufbase,
!                    cm_space_t ** stringspp,
!                    unsigned char *inp, size_t *pcb_max,
!                    char **chainpp, int flags)
! {
! #ifdef SMB_UNICODE
!     if (!(flags & SMB_STRF_FORCEASCII)) {
!         size_t cch_src;
!         cm_space_t * spacep;
!         int    null_terms = 0;
! 
!         if (bufbase && ((inp - bufbase) % 2) != 0) {
!             inp++;              /* unicode strings are always word aligned */
!         }
! 
!         if (*pcb_max > 0) {
!             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
!                                         &cch_src))) {
!                 cch_src = *pcb_max / sizeof(wchar_t);
!                 *pcb_max = 0;
!                 null_terms = 0;
!             } else {
!                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
!                 null_terms = 1;
!             }
!         } else {
!             cch_src = 0;
!         }
! 
!         spacep = cm_GetSpace();
!         spacep->nextp = *stringspp;
!         *stringspp = spacep;
! 
!         if (cch_src == 0) {
!             if (chainpp) {
!                 *chainpp = inp + sizeof(wchar_t);
!             }
! 
!             *(spacep->wdata) = 0;
!             return spacep->wdata;
!         }
! 
!         StringCchCopyNW(spacep->wdata,
!                         lengthof(spacep->wdata),
!                         (const clientchar_t *) inp, cch_src);
! 
!         if (chainpp)
!             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
! 
!         return spacep->wdata;
! 
!     } else {
! #endif
!         cm_space_t * spacep;
!         int cchdest;
! 
!         /* Not using Unicode */
!         if (chainpp) {
!             *chainpp = inp + strlen(inp) + 1;
!         }
! 
!         spacep = cm_GetSpace();
!         spacep->nextp = *stringspp;
!         *stringspp = spacep;
! 
!         cchdest = lengthof(spacep->wdata);
!         cm_Utf8ToUtf16(inp, *pcb_max, spacep->wdata, cchdest);
! 
!         return spacep->wdata;
! #ifdef SMB_UNICODE
!     }
! #endif
! }
! 
! unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
!                             clientchar_t * str,
!                             size_t * plen, int flags)
! {
!     size_t buffersize;
!     int align = 0;
! 
!     if (outp == NULL) {
!         /* we are only calculating the required size */
! 
!         if (plen == NULL)
!             return NULL;
! 
! #ifdef SMB_UNICODE
! 
!         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
! 
!             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
!             if (!(flags & SMB_STRF_IGNORENULL))
!                 *plen += sizeof(wchar_t);
! 
!             return (unsigned char *) 1; /* return TRUE if we are using unicode */
!         }
!         else
! #endif
!         {
!             /* Storing ANSI */
! 
!             int cch_str;
!             int cch_dest;
! 
!             cch_str = cm_ClientStrLen(str);
!             cch_dest = cm_ClientStringToUtf8(str, cch_str, NULL, 0);
! 
!             if (plen)
!                 *plen = ((flags & SMB_STRF_IGNORENULL)? cch_dest: cch_dest+1);
! 
!             return NULL;
!         }
! 
!         /* Not reached. */
!     }
! 
!     /* if outp != NULL ... */
! 
!     /* Number of bytes left in the buffer.
! 
!        If outp lies inside the packet data buffer, we assume that the
!        buffer is the packet data buffer.  Otherwise we assume that the
!        buffer is sizeof(packet->data).
! 
!     */
!     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
!         align = ((outp - pktp->data) % 2);
!         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
!     } else {
!         align = (((size_t) outp) % 2);
!         buffersize = sizeof(pktp->data);
!     }
! 
! #ifdef SMB_UNICODE
! 
!     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
!         int nchars;
! 
!         if (align)
!             *outp++ = '\0';
! 
!         if (*str == _C('\0')) {
! 
!             if (buffersize < sizeof(wchar_t))
!                 return NULL;
! 
!             *((wchar_t *) outp) = L'\0';
!             if (plen && !(flags & SMB_STRF_IGNORENULL))
!                 *plen += sizeof(wchar_t);
!             return outp + sizeof(wchar_t);
!         }
! 
!         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, buffersize / sizeof(wchar_t));
!         if (nchars == 0) {
!             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
!                      osi_LogSaveClientString(smb_logp, str),
!                      GetLastError());
!             return NULL;
!         }
! 
!         if (plen)
!             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
! 
!         return outp + sizeof(wchar_t) * nchars;
!     }
!     else
! #endif
!     {
!         /* Storing ANSI */
!         size_t cch_dest;
! 
!         cch_dest = cm_ClientStringToUtf8(str, -1, outp, buffersize);
! 
!         if (plen)
!             *plen += ((flags & SMB_STRF_IGNORENULL)? cch_dest - 1: cch_dest);
! 
!         return outp + cch_dest;
      }
  }
  
  unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
***************
*** 2623,2628 ****
--- 2712,2734 ----
      return inp;
  }	
  
+ unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
+ {
+     int tlen;
+ 
+     if (*inp++ != 0x1) return NULL;
+     tlen = inp[0] + (inp[1]<<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)
  {
***************
*** 2656,2661 ****
--- 2762,2771 ----
      outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
  #endif
      outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
+ #ifdef SMB_UNICODE
+     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
+         outp->flg2 |= SMB_FLAGS2_UNICODE;
+ #endif
  
      /* copy fields in generic packet area */
      op->wctp = &outp->wct;
***************
*** 2671,2688 ****
      long code = 0;
      unsigned char *tp;
      int localNCB = 0;
- #ifdef DJGPP
-     dos_ptr dos_ncb;
- #endif /* DJGPP */
          
      ncbp = inp->ncbp;
      if (ncbp == NULL) {
          ncbp = GetNCB();
          localNCB = 1;
      }
- #ifdef DJGPP
-     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
- #endif /* DJGPP */
   
      memset((char *)ncbp, 0, sizeof(NCB));
  
--- 2781,2792 ----
***************
*** 2696,2719 ****
      ncbp->ncb_lsn = (unsigned char) vcp->lsn;	/* vc to use */
      ncbp->ncb_lana_num = vcp->lana;
      ncbp->ncb_command = NCBSEND;	/* op means send data */
- #ifndef DJGPP
      ncbp->ncb_buffer = (char *) inp;/* packet */
      code = Netbios(ncbp);
- #else /* DJGPP */
-     ncbp->ncb_buffer = inp->dos_pkt;/* packet */
-     ((smb_ncb_t*)ncbp)->orig_pkt = inp;
- 
-     /* copy header information from virtual to DOS address space */
-     dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
-     code = Netbios(ncbp, dos_ncb);
- #endif /* !DJGPP */
          
      if (code != 0) {
  	const char * s = ncb_error_string(code);
          osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
- #ifndef DJGPP
  	LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
- #endif /* !DJGPP */
  
  	lock_ObtainMutex(&vcp->mx);
  	if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
--- 2800,2812 ----
***************
*** 3077,3082 ****
--- 3170,3176 ----
      return CM_ERROR_BADOP;
  }
  
+ /* SMB_COM_ECHO */
  long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      unsigned short EchoCount, i;
***************
*** 3097,3102 ****
--- 3191,3197 ----
      return 0;
  }
  
+ /* SMB_COM_READ_RAW */
  long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      osi_hyper_t offset;
***************
*** 3109,3120 ****
      cm_user_t *userp = NULL;
      NCB *ncbp;
      int rc;
- #ifndef DJGPP
      char *rawBuf = NULL;
- #else
-     dos_ptr rawBuf = NULL;
-     dos_ptr dos_ncb;
- #endif /* DJGPP */
  
      rawBuf = NULL;
      finalCount = 0;
--- 3204,3210 ----
***************
*** 3184,3194 ****
      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(&smb_RawBufLock);
      if (!rawBuf)
--- 3274,3280 ----
***************
*** 3198,3216 ****
      if (fidp->flags & SMB_FID_IOCTL)
      {
  	lock_ReleaseMutex(&fidp->mx);
- #ifndef DJGPP
          rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
- #else
-         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
- #endif
          if (rawBuf) {
              /* Give back raw buffer */
              lock_ObtainMutex(&smb_RawBufLock);
- #ifndef DJGPP
              *((char **) rawBuf) = smb_RawBufs;
- #else /* DJGPP */
-             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
- #endif /* !DJGPP */
              
              smb_RawBufs = rawBuf;
              lock_ReleaseMutex(&smb_RawBufLock);
--- 3284,3294 ----
***************
*** 3224,3236 ****
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
- #ifndef DJGPP
      code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
- #else /* DJGPP */
-     /* have to give ReadData flag so it will treat buffer as DOS mem. */
-     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
-                         userp, &finalCount, TRUE /* rawFlag */);
- #endif /* !DJGPP */
  
      if (code != 0)
          goto send;
--- 3302,3308 ----
***************
*** 3243,3251 ****
  
    send1:
      ncbp = outp->ncbp;
- #ifdef DJGPP
-     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
- #endif /* DJGPP */
      memset((char *)ncbp, 0, sizeof(NCB));
  
      ncbp->ncb_length = (unsigned short) finalCount;
--- 3315,3320 ----
***************
*** 3254,3275 ****
      ncbp->ncb_command = NCBSEND;
      ncbp->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(&smb_RawBufLock);
- #ifndef DJGPP
          *((char **) rawBuf) = smb_RawBufs;
- #else /* DJGPP */
-         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
- #endif /* !DJGPP */
  
          smb_RawBufs = rawBuf;
          lock_ReleaseMutex(&smb_RawBufLock);
--- 3323,3336 ----
***************
*** 3292,3297 ****
--- 3353,3359 ----
      return 0;
  }
  
+ /* SMB_COM_NEGOTIATE */
  long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      char *namep;
***************
*** 3411,3417 ****
           * and NT Find *
           * and NT SMB's *
           * and raw mode 
!          * and DFS */
          caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
  #ifdef DFS_SUPPORT
                 NTNEGOTIATE_CAPABILITY_DFS |
--- 3473,3480 ----
           * and NT Find *
           * and NT SMB's *
           * and raw mode 
!          * and DFS
!          * and Unicode */
          caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
  #ifdef DFS_SUPPORT
                 NTNEGOTIATE_CAPABILITY_DFS |
***************
*** 3426,3431 ****
--- 3489,3500 ----
          if ( smb_authType == SMB_AUTH_EXTENDED )
              caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
  
+ #ifdef SMB_UNICODE
+         if ( smb_UseUnicode ) {
+             caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
+         }
+ #endif
+ 
          smb_SetSMBParmLong(outp, 9, caps);
          time(&unixTime);
          smb_SearchTimeFromUnixTime(&dosTime, unixTime);
***************
*** 3442,3448 ****
              datap = smb_GetSMBData(outp, NULL);
              memcpy(datap,vcp->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;
--- 3511,3519 ----
              datap = smb_GetSMBData(outp, NULL);
              memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
              /* and the faux domain name */
!             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
!                                   datap + MSV1_0_CHALLENGE_LENGTH,
!                                   sizeof(outp->data)/sizeof(char) - (datap - outp->data));
          } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
              void * secBlob;
              int secBlobLength;
***************
*** 3504,3510 ****
              /* paste in a new encryption key */
              memcpy(datap, vcp->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 */
--- 3575,3583 ----
              /* paste in a new encryption key */
              memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
              /* and the faux domain name */
!             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
!                                   datap + MSV1_0_CHALLENGE_LENGTH,
!                                   sizeof(outp->data)/sizeof(char) - (datap - outp->data));
          } else {
              smb_SetSMBParm(outp, 11, 0); /* encryption key length */
              smb_SetSMBParm(outp, 12, 0); /* resvd */
***************
*** 3606,3612 ****
  	now = osi_Time();
  	lock_ObtainWrite(&smb_rctLock);
  	for ( unpp=&usernamesp; *unpp; ) {
! 	    int delete = 0;
  	    smb_username_t *unp;
  
  	    lock_ObtainMutex(&(*unpp)->mx);
--- 3679,3685 ----
  	now = osi_Time();
  	lock_ObtainWrite(&smb_rctLock);
  	for ( unpp=&usernamesp; *unpp; ) {
! 	    int deleteOk = 0;
  	    smb_username_t *unp;
  
  	    lock_ObtainMutex(&(*unpp)->mx);
***************
*** 3616,3625 ****
  		;
  	    else if (!smb_LogoffTokenTransfer ||
  		     ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
! 		delete = 1;
  	    lock_ReleaseMutex(&(*unpp)->mx);
  
! 	    if (delete) {
  		cm_user_t * userp;
  
  		unp = *unpp;	
--- 3689,3698 ----
  		;
  	    else if (!smb_LogoffTokenTransfer ||
  		     ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
! 		deleteOk = 1;
  	    lock_ReleaseMutex(&(*unpp)->mx);
  
! 	    if (deleteOk) {
  		cm_user_t * userp;
  
  		unp = *unpp;	
***************
*** 3801,3831 ****
      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[AFSPATHMAX];
!     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, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
!     passwordp = smb_ParseASCIIBlock(tp, &tp);
!     tp = strrchr(pathp, '\\');
      if (!tp)
          return CM_ERROR_BADSMB;
!     strcpy(shareName, tp+1);
  
      lock_ObtainMutex(&vcp->mx);
      newTid = vcp->tidCounter++;
--- 3874,3904 ----
      return 0;
  }
  
+ /* SMB_COM_TREE_CONNECT */
  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;
!     clientchar_t shareName[AFSPATHMAX];
!     clientchar_t *sharePath;
      int shareFound;
!     clientchar_t *tp;
!     clientchar_t *pathp;
      cm_user_t *userp;
  
      osi_Log0(smb_logp, "SMB receive tree connect");
  
      /* parse input parameters */
!     {
!         char *tbp;
!         tbp = smb_GetSMBData(inp, NULL);
!         pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
!     }
!     tp = cm_ClientStrRChr(pathp, '\\');
      if (!tp)
          return CM_ERROR_BADSMB;
!     cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
  
      lock_ObtainMutex(&vcp->mx);
      newTid = vcp->tidCounter++;
***************
*** 3855,3886 ****
      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]<<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.
   * Mask is 11 bytes long (8.3 with the dot elided).
   * Returns true if succeeds with a valid name, otherwise it does
   * its best, but returns false.
   */
! int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
  {
!     char *tp;
!     char *up;
      int i;
      int tc;
      int valid8Dot3;
--- 3928,3942 ----
      return 0;
  }
  
  /* set maskp to the mask part of the incoming path.
   * Mask is 11 bytes long (8.3 with the dot elided).
   * Returns true if succeeds with a valid name, otherwise it does
   * its best, but returns false.
   */
! int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
  {
!     clientchar_t *tp;
!     clientchar_t *up;
      int i;
      int tc;
      int valid8Dot3;
***************
*** 3893,3899 ****
      maskp[11] = '\0';
  
      /* find last backslash, or use whole thing if there is none */
!     tp = strrchr(pathp, '\\');
      if (!tp) 
          tp = pathp;
      else 
--- 3949,3955 ----
      maskp[11] = '\0';
  
      /* find last backslash, or use whole thing if there is none */
!     tp = cm_ClientStrRChr(pathp, '\\');
      if (!tp) 
          tp = pathp;
      else 
***************
*** 3938,3954 ****
      /* unreachable */
  }
  
! 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) 
--- 3994,4010 ----
      /* unreachable */
  }
  
! int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
  {
!     clientchar_t umask[11];
      int valid;
      int i;
!     clientchar_t tc1;
!     clientchar_t tc2;
!     clientchar_t *tp1;
!     clientchar_t *tp2;
  
!     /* XXX redo this, calling cm_MatchMask with a converted mask */
  
      valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
      if (!valid) 
***************
*** 3960,3969 ****
      tp1 = umask;	/* real name, in mask format */
      tp2 = maskp;	/* mask, in mask format */
      for(i=0; i<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 == '?' && tc1 != ' ') 
--- 4016,4025 ----
      tp1 = umask;	/* real name, in mask format */
      tp2 = maskp;	/* mask, in mask format */
      for(i=0; i<11; i++) {
!         tc1 = *tp1++;	/* clientchar_t from real name */
!         tc2 = *tp2++;	/* clientchar_t from mask */
!         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
!         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
          if (tc1 == tc2) 
              continue;
          if (tc2 == '?' && tc1 != ' ') 
***************
*** 3977,3987 ****
      return 1;
  }
  
! char *smb_FindMask(char *pathp)
  {
!     char *tp;
          
!     tp = strrchr(pathp, '\\');	/* find last slash */
  
      if (tp) 
          return tp+1;	/* skip the slash */
--- 4033,4043 ----
      return 1;
  }
  
! clientchar_t *smb_FindMask(clientchar_t *pathp)
  {
!     clientchar_t *tp;
          
!     tp = cm_ClientStrRChr(pathp, '\\');	/* find last slash */
  
      if (tp) 
          return tp+1;	/* skip the slash */
***************
*** 3989,3999 ****
          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[12];
      unsigned char *statBlockp;
      unsigned char initStatBlock[21];
      int statLen;
--- 4045,4059 ----
          return pathp;	/* no slash, return the entire path */
  }       
  
+ /* SMB_COM_SEARCH for a volume label
+ 
+    (This is called from smb_ReceiveCoreSearchDir() and not an actual
+    dispatch function.) */
  long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp;
      unsigned char *tp;
!     clientchar_t mask[12];
      unsigned char *statBlockp;
      unsigned char initStatBlock[21];
      int statLen;
***************
*** 4002,4012 ****
  
      /* pull pathname and stat block out of request */
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
      osi_assertx(pathp != NULL, "null path");
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
!     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
      osi_assertx(statBlockp != NULL, "null statBlock");
      if (statLen == 0) {
          statBlockp = initStatBlock;
--- 4062,4071 ----
  
      /* pull pathname and stat block out of request */
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
!                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
      osi_assertx(pathp != NULL, "null path");
!     statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
      osi_assertx(statBlockp != NULL, "null statBlock");
      if (statLen == 0) {
          statBlockp = initStatBlock;
***************
*** 4048,4053 ****
--- 4107,4115 ----
      *tp++ = 0;
      *tp++ = 0;
  
+     /* The filename is a UCHAR buffer that is ASCII even if Unicode
+        was negotiated. */
+ 
      /* finally, null-terminated 8.3 pathname, which we set to AFS */
      memset(tp, ' ', 13);
      strcpy(tp, "AFS");
***************
*** 4061,4067 ****
  
  static long 
  smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
!                         char * tidPathp, char * relPathp,
                          cm_user_t *userp, cm_req_t *reqp)
  {
      long code = 0;
--- 4123,4129 ----
  
  static long 
  smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
!                         clientchar_t * tidPathp, clientchar_t * relPathp,
                          cm_user_t *userp, cm_req_t *reqp)
  {
      long code = 0;
***************
*** 4072,4085 ****
      char attr;
      smb_dirListPatch_t *patchp;
      smb_dirListPatch_t *npatchp;
!     char path[AFSPATHMAX];
  
      for (patchp = *dirPatchespp; patchp; patchp =
           (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
  
          dptr = patchp->dptr;
  
!         snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
          reqp->relPathp = path;
          reqp->tidPathp = tidPathp;
  
--- 4134,4148 ----
      char attr;
      smb_dirListPatch_t *patchp;
      smb_dirListPatch_t *npatchp;
!     clientchar_t path[AFSPATHMAX];
  
      for (patchp = *dirPatchespp; patchp; patchp =
           (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
  
          dptr = patchp->dptr;
  
!         cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
!                             relPathp ? relPathp : _C(""), patchp->dep->name);
          reqp->relPathp = path;
          reqp->tidPathp = tidPathp;
  
***************
*** 4143,4155 ****
      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 = 0;
      int maxCount;
      smb_dirListPatch_t *dirListPatchesp;
--- 4206,4219 ----
      return code;
  }
  
+ /* SMB_COM_SEARCH */
  long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      int attribute;
      long nextCookie;
!     unsigned char *tp;
      long code = 0;
!     clientchar_t *pathp;
      cm_dirEntry_t *dep = 0;
      int maxCount;
      smb_dirListPatch_t *dirListPatchesp;
***************
*** 4170,4179 ****
      cm_pageHeader_t *pageHeaderp;
      cm_user_t *userp = NULL;
      int slotInPage;
!     char shortName[13];
!     char *actualName;
!     char *shortNameEnd;
!     char mask[12];
      int returnedNames;
      long nextEntryCookie;
      int numDirChunks;		/* # of 32 byte dir chunks in this entry */
--- 4234,4240 ----
      cm_pageHeader_t *pageHeaderp;
      cm_user_t *userp = NULL;
      int slotInPage;
!     clientchar_t mask[12];
      int returnedNames;
      long nextEntryCookie;
      int numDirChunks;		/* # of 32 byte dir chunks in this entry */
***************
*** 4184,4190 ****
      int starPattern;
      int rootPath = 0;
      int caseFold;
!     char *tidPathp = 0;
      cm_req_t req;
      cm_fid_t fid;
      int fileType;
--- 4245,4251 ----
      int starPattern;
      int rootPath = 0;
      int caseFold;
!     clientchar_t *tidPathp = 0;
      cm_req_t req;
      cm_fid_t fid;
      int fileType;
***************
*** 4198,4206 ****
      caseFold = CM_FLAG_CASEFOLD;
  
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
      inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
  
      /* bail out if request looks bad */
--- 4259,4266 ----
      caseFold = CM_FLAG_CASEFOLD;
  
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
!                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
      inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
  
      /* bail out if request looks bad */
***************
*** 4223,4230 ****
          if (attribute & 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 & SMB_ATTR_DIRECTORY))	/* exclude dirs */
--- 4283,4290 ----
          if (attribute & 0x8)
              return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
  
!         osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
!                  maxCount, osi_LogSaveClientString(smb_logp, pathp));
  
          if (*pathp == 0) {	/* null pathp, treat as root dir */
              if (!(attribute & SMB_ATTR_DIRECTORY))	/* exclude dirs */
***************
*** 4249,4256 ****
          dsp = smb_FindDirSearch(inCookiep[12]);
          if (!dsp) {
              /* can't find dir search status; fatal error */
!             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
!                      inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
              return CM_ERROR_BADFD;
          }
          attribute = dsp->attribute;
--- 4309,4316 ----
          dsp = smb_FindDirSearch(inCookiep[12]);
          if (!dsp) {
              /* can't find dir search status; fatal error */
!             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
!                      inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
              return CM_ERROR_BADFD;
          }
          attribute = dsp->attribute;
***************
*** 4283,4289 ****
          code = 0;
      } else {
          spacep = inp->spacep;
!         smb_StripLastComponent(spacep->data, NULL, pathp);
          code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
          if (code) {
              lock_ReleaseMutex(&dsp->mx);
--- 4343,4349 ----
          code = 0;
      } else {
          spacep = inp->spacep;
!         smb_StripLastComponent(spacep->wdata, NULL, pathp);
          code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
          if (code) {
              lock_ReleaseMutex(&dsp->mx);
***************
*** 4292,4306 ****
              smb_ReleaseDirSearch(dsp);
              return CM_ERROR_NOFILES;
          }
!         strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
!         strcpy(dsp->relPath, spacep->data);
  
!         code = cm_NameI(cm_data.rootSCachep, spacep->data,
                          caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
          if (code == 0) {
  #ifdef DFS_SUPPORT
              if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
                  cm_ReleaseSCache(scp);
                  lock_ReleaseMutex(&dsp->mx);
                  cm_ReleaseUser(userp);
--- 4352,4368 ----
              smb_ReleaseDirSearch(dsp);
              return CM_ERROR_NOFILES;
          }
!         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
!         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
  
!         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                          caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
          if (code == 0) {
  #ifdef DFS_SUPPORT
              if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc;
! 
!                 pnc  = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
                  cm_ReleaseSCache(scp);
                  lock_ReleaseMutex(&dsp->mx);
                  cm_ReleaseUser(userp);
***************
*** 4373,4378 ****
--- 4435,4444 ----
      code = 0;
      returnedNames = 0;
      while (1) {
+         clientchar_t *actualName;
+         clientchar_t shortName[13];
+         clientchar_t *shortNameEnd;
+ 
          /* 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,
***************
*** 4527,4541 ****
          nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
  
          /* Compute 8.3 name if necessary */
!         actualName = dep->name;
          if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
!             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
              actualName = shortName;
          }
  
!         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
!                   dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
!                   osi_LogSaveString(smb_logp, actualName));
  
          if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
              /* this is one of the entries to use: it is not deleted
--- 4593,4608 ----
          nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
  
          /* Compute 8.3 name if necessary */
!         actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
          if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
!             free(actualName);
!             cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
              actualName = shortName;
          }
  
!         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
!                  dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
!                  osi_LogSaveClientString(smb_logp, actualName));
  
          if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
              /* this is one of the entries to use: it is not deleted
***************
*** 4569,4579 ****
  
              *op++ = resByte;
              memcpy(op, mask, 11); op += 11;
!             *op++ = (char) dsp->cookie;	/* they say it must be non-zero */
!             *op++ = (char)(nextEntryCookie & 0xff);
!             *op++ = (char)((nextEntryCookie>>8) & 0xff);
!             *op++ = (char)((nextEntryCookie>>16) & 0xff);
!             *op++ = (char)((nextEntryCookie>>24) & 0xff);
              memcpy(op, &clientCookie, 4); op += 4;
  
              /* now we emit the attribute.  This is sort of tricky,
--- 4636,4646 ----
  
              *op++ = resByte;
              memcpy(op, mask, 11); op += 11;
!             *op++ = (unsigned char) dsp->cookie;	/* they say it must be non-zero */
!             *op++ = (unsigned char)(nextEntryCookie & 0xff);
!             *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
!             *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
!             *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
              memcpy(op, &clientCookie, 4); op += 4;
  
              /* now we emit the attribute.  This is sort of tricky,
***************
*** 4614,4622 ****
               * it fits in 8.3 or the pattern wouldn't match, but it
               * never hurts to be sure.
               */
!             strncpy(op, actualName, 13);
              if (smb_StoreAnsiFilenames)
                  CharToOem(op, op);
  
              /* Uppercase if requested by client */
              if (!KNOWS_LONG_NAMES(inp))
--- 4681,4691 ----
               * it fits in 8.3 or the pattern wouldn't match, but it
               * never hurts to be sure.
               */
!             cm_ClientStringToUtf8(actualName, -1, op, 13);
              if (smb_StoreAnsiFilenames)
                  CharToOem(op, op);
+             /* This is a UCHAR field, which is ASCII even if Unicode
+                is negotiated. */
  
              /* Uppercase if requested by client */
              if (!KNOWS_LONG_NAMES(inp))
***************
*** 4674,4681 ****
       */
      temp -= 3;		/* deduct vbl block info */
      osi_assertx(temp == (43 * returnedNames), "unexpected data length");
!     origOp[1] = (char)(temp & 0xff);
!     origOp[2] = (char)((temp>>8) & 0xff);
      if (returnedNames == 0) 
          smb_DeleteDirSearch(dsp);
      smb_ReleaseDirSearch(dsp);
--- 4743,4750 ----
       */
      temp -= 3;		/* deduct vbl block info */
      osi_assertx(temp == (43 * returnedNames), "unexpected data length");
!     origOp[1] = (unsigned char)(temp & 0xff);
!     origOp[2] = (unsigned char)((temp>>8) & 0xff);
      if (returnedNames == 0) 
          smb_DeleteDirSearch(dsp);
      smb_ReleaseDirSearch(dsp);
***************
*** 4684,4714 ****
      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(&req);
  
!     pathp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(pathp, NULL);
      if (!pathp)
          return CM_ERROR_BADFD;
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
!     osi_Log1(smb_logp, "SMB receive check path %s",
!              osi_LogSaveString(smb_logp, pathp));
          
      rootScp = cm_data.rootSCachep;
          
--- 4753,4785 ----
      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.
+  *
+  * SMB_COM_CHECK_DIRECTORY
   */
  long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp;
      long code = 0;
      cm_scache_t *rootScp;
      cm_scache_t *newScp;
      cm_user_t *userp;
      unsigned int attrs;
      int caseFold;
!     clientchar_t *tidPathp;
      cm_req_t req;
+     char * pdata;
  
      cm_InitReq(&req);
  
!     pdata = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
      if (!pathp)
          return CM_ERROR_BADFD;
!     osi_Log1(smb_logp, "SMB receive check path %S",
!              osi_LogSaveClientString(smb_logp, pathp));
          
      rootScp = cm_data.rootSCachep;
          
***************
*** 4769,4777 ****
      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;
--- 4840,4849 ----
      return code;
  }	
  
+ /* SMB_COM_SET_INFORMATION */
  long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp;
      long code = 0;
      cm_scache_t *rootScp;
      unsigned short attribute;
***************
*** 4780,4786 ****
      afs_uint32 dosTime;
      cm_user_t *userp;
      int caseFold;
!     char *tidPathp;
      cm_req_t req;
  
      cm_InitReq(&req);
--- 4852,4859 ----
      afs_uint32 dosTime;
      cm_user_t *userp;
      int caseFold;
!     clientchar_t *tidPathp;
!     char * datap;
      cm_req_t req;
  
      cm_InitReq(&req);
***************
*** 4789,4800 ****
      attribute = smb_GetSMBParm(inp, 0);
      dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
  
!     pathp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(pathp, NULL);
      if (!pathp)
          return CM_ERROR_BADSMB;
-     if (smb_StoreAnsiFilenames)
-         OemToChar(pathp,pathp);
                 
      osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
               dosTime, attribute);
--- 4862,4871 ----
      attribute = smb_GetSMBParm(inp, 0);
      dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
  
!     datap = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
      if (!pathp)
          return CM_ERROR_BADSMB;
                 
      osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
               dosTime, attribute);
***************
*** 4884,4892 ****
      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;
--- 4955,4964 ----
      return code;
  }
  
+ 
  long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp;
      long code = 0;
      cm_scache_t *rootScp;
      cm_scache_t *newScp, *dscp;
***************
*** 4894,4919 ****
      int attrs;
      cm_user_t *userp;
      int caseFold;
!     char *tidPathp;
      cm_space_t *spacep;
!     char *lastComp;
      cm_req_t req;
  
      cm_InitReq(&req);
  
!     pathp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(pathp, NULL);
      if (!pathp)
          return CM_ERROR_BADSMB;
          
      if (*pathp == 0)		/* null path */
!         pathp = "\\";
!     else
!         if (smb_StoreAnsiFilenames)
!             OemToChar(pathp,pathp);
  
!     osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
!              osi_LogSaveString(smb_logp, pathp));
  
      rootScp = cm_data.rootSCachep;
          
--- 4966,4989 ----
      int attrs;
      cm_user_t *userp;
      int caseFold;
!     clientchar_t *tidPathp;
      cm_space_t *spacep;
!     clientchar_t *lastComp;
!     char * datap;
      cm_req_t req;
  
      cm_InitReq(&req);
  
!     datap = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
      if (!pathp)
          return CM_ERROR_BADSMB;
          
      if (*pathp == 0)		/* null path */
!         pathp = _C("\\");
  
!     osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
!              osi_LogSaveClientString(smb_logp, pathp));
  
      rootScp = cm_data.rootSCachep;
          
***************
*** 4946,4961 ****
       * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
       */
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &lastComp, pathp);
  #ifndef SPECIAL_FOLDERS
!     if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
!         code = cm_NameI(rootScp, spacep->data,
                          caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
                          userp, tidPathp, &req, &dscp);
          if (code == 0) {
  #ifdef DFS_SUPPORT
              if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
                  if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                      return CM_ERROR_PATH_NOT_COVERED;
                  else
--- 5016,5032 ----
       * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
       */
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
  #ifndef SPECIAL_FOLDERS
!     if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
!         code = cm_NameI(rootScp, spacep->wdata,
                          caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
                          userp, tidPathp, &req, &dscp);
          if (code == 0) {
  #ifdef DFS_SUPPORT
              if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
!                                                           spacep->wdata);
                  if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                      return CM_ERROR_PATH_NOT_COVERED;
                  else
***************
*** 5050,5055 ****
--- 5121,5127 ----
      return 0;
  }	
  
+ /* SMB_COM_TREE_DISCONNECT */
  long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_tid_t *tidp;
***************
*** 5060,5066 ****
      tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
      if (tidp) {
  	lock_ObtainWrite(&smb_rctLock);
!         tidp->delete = 1;
          smb_ReleaseTID(tidp, TRUE);
          lock_ReleaseWrite(&smb_rctLock);
      }
--- 5132,5138 ----
      tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
      if (tidp) {
  	lock_ObtainWrite(&smb_rctLock);
!         tidp->deleteOk = 1;
          smb_ReleaseTID(tidp, TRUE);
          lock_ReleaseWrite(&smb_rctLock);
      }
***************
*** 5068,5078 ****
      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;
--- 5140,5151 ----
      return 0;
  }
  
+ /* SMB_COM_0PEN */
  long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_fid_t *fidp;
!     clientchar_t *pathp;
!     clientchar_t *lastNamep;
      int share;
      int attribute;
      long code = 0;
***************
*** 5081,5097 ****
      afs_uint32 dosTime;
      int caseFold;
      cm_space_t *spacep;
!     char *tidPathp;
      cm_req_t req;
  
      cm_InitReq(&req);
  
!     pathp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(pathp, NULL);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
! 	
!     osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
  
  #ifdef DEBUG_VERBOSE
      {
--- 5154,5169 ----
      afs_uint32 dosTime;
      int caseFold;
      cm_space_t *spacep;
!     clientchar_t *tidPathp;
!     char * datap;
      cm_req_t req;
  
      cm_InitReq(&req);
  
!     datap = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
! 
!     osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
  
  #ifdef DEBUG_VERBOSE
      {
***************
*** 5107,5114 ****
      attribute = smb_GetSMBParm(inp, 1);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
!     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
          /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
--- 5179,5186 ----
      attribute = smb_GetSMBParm(inp, 1);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
!     if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
          /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
***************
*** 5224,5230 ****
      cm_user_t *userp;
      cm_req_t *reqp;
      smb_vc_t *vcp;
!     char *maskp;		/* pointer to the star pattern */
      int flags;
      int any;
      cm_dirEntryList_t * matches;
--- 5296,5302 ----
      cm_user_t *userp;
      cm_req_t *reqp;
      smb_vc_t *vcp;
!     clientchar_t *maskp;		/* pointer to the star pattern */
      int flags;
      int any;
      cm_dirEntryList_t * matches;
***************
*** 5236,5243 ****
      smb_unlinkRock_t *rockp;
      int caseFold;
      int match;
!     char shortName[13];
!     char *matchName;
          
      rockp = vrockp;
  
--- 5308,5314 ----
      smb_unlinkRock_t *rockp;
      int caseFold;
      int match;
!     normchar_t matchName[MAX_PATH];
          
      rockp = vrockp;
  
***************
*** 5245,5270 ****
      if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
          caseFold |= CM_FLAG_8DOT3;
  
!     matchName = dep->name;
!     match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
      if (!match &&
!          (rockp->flags & SMB_MASKFLAG_TILDE) &&
!          !cm_Is8Dot3(dep->name)) {
!         cm_Gen8Dot3Name(dep, shortName, NULL);
!         matchName = shortName;
          /* 8.3 matches are always case insensitive */
!         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
      }
      if (match) {
!         osi_Log1(smb_logp, "Found match %s",
!                  osi_LogSaveString(smb_logp, matchName));
  
          cm_DirEntryListAdd(dep->name, &rockp->matches);
  
          rockp->any = 1;
  
          /* If we made a case sensitive exact match, we might as well quit now. */
!         if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
              code = CM_ERROR_STOPNOW;
          else
              code = 0;
--- 5316,5340 ----
      if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
          caseFold |= CM_FLAG_8DOT3;
  
!     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
!     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
      if (!match &&
!         (rockp->flags & SMB_MASKFLAG_TILDE) &&
!         !cm_Is8Dot3(matchName)) {
!         cm_Gen8Dot3Name(dep, matchName, NULL);
          /* 8.3 matches are always case insensitive */
!         match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
      }
      if (match) {
!         osi_Log1(smb_logp, "Found match %S",
!                  osi_LogSaveClientString(smb_logp, matchName));
  
          cm_DirEntryListAdd(dep->name, &rockp->matches);
  
          rockp->any = 1;
  
          /* If we made a case sensitive exact match, we might as well quit now. */
!         if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
              code = CM_ERROR_STOPNOW;
          else
              code = 0;
***************
*** 5274,5293 ****
      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(&req);
--- 5344,5364 ----
      return code;
  }
  
+ /* SMB_COM_DELETE */
  long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      int attribute;
      long code = 0;
!     clientchar_t *pathp;
!     unsigned char *tp;
      cm_space_t *spacep;
      cm_scache_t *dscp;
!     clientchar_t *lastNamep;
      smb_unlinkRock_t rock;
      cm_user_t *userp;
      osi_hyper_t thyper;
      int caseFold;
!     clientchar_t *tidPathp;
      cm_req_t req;
  
      cm_InitReq(&req);
***************
*** 5295,5309 ****
      attribute = smb_GetSMBParm(inp, 0);
          
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
  
!     osi_Log1(smb_logp, "SMB receive unlink %s",
!              osi_LogSaveString(smb_logp, pathp));
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
--- 5366,5378 ----
      attribute = smb_GetSMBParm(inp, 0);
          
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
  
!     osi_Log1(smb_logp, "SMB receive unlink %S",
!              osi_LogSaveClientString(smb_logp, pathp));
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
***************
*** 5314,5320 ****
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
                      &req, &dscp);
      if (code) {
          cm_ReleaseUser(userp);
--- 5383,5389 ----
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
                      &req, &dscp);
      if (code) {
          cm_ReleaseUser(userp);
***************
*** 5323,5329 ****
          
  #ifdef DFS_SUPPORT
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
--- 5392,5398 ----
          
  #ifdef DFS_SUPPORT
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
***************
*** 5340,5347 ****
          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;
--- 5409,5416 ----
          lastNamep++;
  
      rock.any = 0;
!     rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
!     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
  
      thyper.LowPart = 0;
      thyper.HighPart = 0;
***************
*** 5374,5388 ****
          cm_dirEntryList_t * entry;
  
          for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
  
              osi_Log1(smb_logp, "Unlinking %s",
                       osi_LogSaveString(smb_logp, entry->name));
!             code = cm_Unlink(dscp, entry->name, userp, &req);
  
              if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                  smb_NotifyChange(FILE_ACTION_REMOVED,
                                   FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
!                                  dscp, entry->name, NULL, TRUE);
          }
      }
  
--- 5443,5464 ----
          cm_dirEntryList_t * entry;
  
          for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
+             normchar_t normalizedName[MAX_PATH];
+ 
+             /* Note: entry->name is a non-normalized name */
  
              osi_Log1(smb_logp, "Unlinking %s",
                       osi_LogSaveString(smb_logp, entry->name));
! 
!             cm_FsStringToNormString(entry->name, -1,
!                                     normalizedName, lengthof(normalizedName));
! 
!             code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
  
              if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                  smb_NotifyChange(FILE_ACTION_REMOVED,
                                   FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
!                                  dscp, normalizedName, NULL, TRUE);
          }
      }
  
***************
*** 5392,5412 ****
          
      cm_ReleaseSCache(dscp);
  
      if (code == 0 && !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 */
!     char oldName[MAX_PATH];
      int any;
  } smb_renameRock_t;
  
--- 5468,5491 ----
          
      cm_ReleaseSCache(dscp);
  
+     free(rock.maskp);
+ 
      if (code == 0 && !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 */
!     normchar_t *maskp;   /* pointer to star pattern of old file name */
!     int flags;           /* tilde, casefold, etc */
!     clientchar_t *newNamep;     /* ptr to the new file's name */
!     fschar_t fsOldName[MAX_PATH]; /* raw FS name */
!     clientchar_t clOldName[MAX_PATH]; /* client name */
      int any;
  } smb_renameRock_t;
  
***************
*** 5416,5442 ****
      smb_renameRock_t *rockp;
      int caseFold;
      int match;
!     char shortName[13]="";
  
      rockp = (smb_renameRock_t *) vrockp;
  
      caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
      if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
          caseFold |= CM_FLAG_8DOT3;
  
!     match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
      if (!match &&
          (rockp->flags & SMB_MASKFLAG_TILDE) &&
!          !cm_Is8Dot3(dep->name)) {
!         cm_Gen8Dot3Name(dep, shortName, NULL);
!         match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
      }
  
      if (match) {
  	rockp->any = 1;
!         strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
!         rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
!             code = CM_ERROR_STOPNOW;
      } else {
  	code = 0;
      }
--- 5495,5523 ----
      smb_renameRock_t *rockp;
      int caseFold;
      int match;
!     normchar_t matchName[MAX_PATH];
  
      rockp = (smb_renameRock_t *) vrockp;
  
+     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
      caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
      if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
          caseFold |= CM_FLAG_8DOT3;
  
!     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
      if (!match &&
          (rockp->flags & SMB_MASKFLAG_TILDE) &&
!         !cm_Is8Dot3(matchName)) {
!         cm_Gen8Dot3Name(dep, matchName, NULL);
!         match = cm_MatchMask(matchName, rockp->maskp, caseFold);
      }
  
      if (match) {
  	rockp->any = 1;
!         StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
!         cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
!                         matchName);
!         code = CM_ERROR_STOPNOW;
      } else {
  	code = 0;
      }
***************
*** 5446,5452 ****
  
  
  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;
--- 5527,5533 ----
  
  
  long 
! smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
  {
      long code = 0;
      cm_space_t *spacep = NULL;
***************
*** 5455,5466 ****
      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;
  
--- 5536,5547 ----
      cm_scache_t *newDscp = NULL;
      cm_scache_t *tmpscp= NULL;
      cm_scache_t *tmpscp2 = NULL;
!     clientchar_t *oldLastNamep;
!     clientchar_t *newLastNamep;
      osi_hyper_t thyper;
      cm_user_t *userp;
      int caseFold;
!     clientchar_t *tidPathp;
      DWORD filter;
      cm_req_t req;
  
***************
*** 5473,5482 ****
  
      cm_InitReq(&req);
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
  
      caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
!     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
                      userp, tidPathp, &req, &oldDscp);
      if (code) {
          cm_ReleaseUser(userp);
--- 5554,5563 ----
  
      cm_InitReq(&req);
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
  
      caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
                      userp, tidPathp, &req, &oldDscp);
      if (code) {
          cm_ReleaseUser(userp);
***************
*** 5485,5491 ****
          
  #ifdef DFS_SUPPORT
      if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
--- 5566,5572 ----
          
  #ifdef DFS_SUPPORT
      if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
***************
*** 5495,5502 ****
      }
  #endif /* DFS_SUPPORT */
  
!     smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
!     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
                      userp, tidPathp, &req, &newDscp);
  
      if (code) {
--- 5576,5583 ----
      }
  #endif /* DFS_SUPPORT */
  
!     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
                      userp, tidPathp, &req, &newDscp);
  
      if (code) {
***************
*** 5507,5513 ****
  
  #ifdef DFS_SUPPORT
      if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseSCache(newDscp);
          cm_ReleaseUser(userp);
--- 5588,5594 ----
  
  #ifdef DFS_SUPPORT
      if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseSCache(newDscp);
          cm_ReleaseUser(userp);
***************
*** 5543,5552 ****
      rock.userp = userp;
      rock.reqp = &req;
      rock.vcp = vcp;
!     rock.maskp = oldLastNamep;
!     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
      rock.newNamep = newLastNamep;
!     rock.oldName[0] = '\0';
      rock.any = 0;
  
      /* Check if the file already exists; if so return error */
--- 5624,5634 ----
      rock.userp = userp;
      rock.reqp = &req;
      rock.vcp = vcp;
!     rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
!     rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
      rock.newNamep = newLastNamep;
!     rock.fsOldName[0] = '\0';
!     rock.clOldName[0] = '\0';
      rock.any = 0;
  
      /* Check if the file already exists; if so return error */
***************
*** 5554,5566 ****
      if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) && 
          (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
      {
!         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
!                  osi_LogSaveString(smb_logp, newLastNamep));
  
          /* Check if the old and the new names differ only in case. If so return
           * success, else return CM_ERROR_EXISTS 
           */
!         if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
  
              /* This would be a success only if the old file is *as same as* the new file */
              code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
--- 5636,5648 ----
      if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) && 
          (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
      {
!         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
!                  osi_LogSaveClientString(smb_logp, newLastNamep));
  
          /* Check if the old and the new names differ only in case. If so return
           * success, else return CM_ERROR_EXISTS 
           */
!         if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
  
              /* This would be a success only if the old file is *as same as* the new file */
              code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
***************
*** 5585,5590 ****
--- 5667,5675 ----
          cm_ReleaseSCache(newDscp);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
+ 
+         free(rock.maskp);
+         rock.maskp = NULL;
          return code; 
      }
  
***************
*** 5601,5610 ****
      }
      osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
  
!     if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
! 	code = cm_Rename(rock.odscp, rock.oldName,
                           rock.ndscp, rock.newNamep, rock.userp,
!                          rock.reqp);	
          /* if the call worked, stop doing the search now, since we
           * really only want to rename one file.
           */
--- 5686,5695 ----
      }
      osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
  
!     if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
! 	code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
                           rock.ndscp, rock.newNamep, rock.userp,
!                          rock.reqp);
          /* if the call worked, stop doing the search now, since we
           * really only want to rename one file.
           */
***************
*** 5619,5640 ****
      * filter, since we'd have to do a lookup.
      */
      if (code == 0) {
!     filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
!     if (oldDscp == newDscp) {
!         if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
!             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
!                              filter, oldDscp, oldLastNamep,
!                              newLastNamep, TRUE);
!     } else {
!         if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
!             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
!                              filter, oldDscp, oldLastNamep,
!                              NULL, TRUE);
!         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
!             smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
!                              filter, newDscp, newLastNamep,
!                              NULL, TRUE);
!     }
      }
  
      if (tmpscp != NULL) 
--- 5704,5725 ----
      * filter, since we'd have to do a lookup.
      */
      if (code == 0) {
!         filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
!         if (oldDscp == newDscp) {
!             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
!                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
!                                  filter, oldDscp, rock.clOldName,
!                                  newLastNamep, TRUE);
!         } else {
!             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
!                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
!                                  filter, oldDscp, rock.clOldName,
!                                  NULL, TRUE);
!             if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
!                 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
!                                  filter, newDscp, newLastNamep,
!                                  NULL, TRUE);
!         }
      }
  
      if (tmpscp != NULL) 
***************
*** 5642,5652 ****
      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;
--- 5727,5741 ----
      cm_ReleaseUser(userp);
      cm_ReleaseSCache(oldDscp);
      cm_ReleaseSCache(newDscp);
+ 
+     free(rock.maskp);
+     rock.maskp = NULL;
+ 
      return code;
  }       
  
  long 
! smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp) 
  {
      long code = 0;
      cm_space_t *spacep = NULL;
***************
*** 5655,5665 ****
      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;
  
--- 5744,5754 ----
      cm_scache_t *tmpscp= NULL;
      cm_scache_t *tmpscp2 = NULL;
      cm_scache_t *sscp = NULL;
!     clientchar_t *oldLastNamep;
!     clientchar_t *newLastNamep;
      cm_user_t *userp;
      int caseFold;
!     clientchar_t *tidPathp;
      DWORD filter;
      cm_req_t req;
  
***************
*** 5676,5684 ****
      caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
      
!     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
                      userp, tidPathp, &req, &oldDscp);
      if (code) {
          cm_ReleaseUser(userp);
--- 5765,5773 ----
      caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
      
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
                      userp, tidPathp, &req, &oldDscp);
      if (code) {
          cm_ReleaseUser(userp);
***************
*** 5687,5693 ****
          
  #ifdef DFS_SUPPORT
      if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
--- 5776,5782 ----
          
  #ifdef DFS_SUPPORT
      if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
***************
*** 5697,5704 ****
      }
  #endif /* DFS_SUPPORT */
  
!     smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
!     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
                      userp, tidPathp, &req, &newDscp);
      if (code) {
          cm_ReleaseSCache(oldDscp);
--- 5786,5793 ----
      }
  #endif /* DFS_SUPPORT */
  
!     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
                      userp, tidPathp, &req, &newDscp);
      if (code) {
          cm_ReleaseSCache(oldDscp);
***************
*** 5708,5714 ****
  
  #ifdef DFS_SUPPORT
      if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
          cm_ReleaseSCache(newDscp);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
--- 5797,5803 ----
  
  #ifdef DFS_SUPPORT
      if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
          cm_ReleaseSCache(newDscp);
          cm_ReleaseSCache(oldDscp);
          cm_ReleaseUser(userp);
***************
*** 5742,5748 ****
          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, &req, &sscp);
      if (code) {
          cm_ReleaseSCache(oldDscp);
--- 5831,5837 ----
          newLastNamep++;
  
      /* now lookup the old name */
!     osi_Log1(smb_logp,"  looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
      code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
      if (code) {
          cm_ReleaseSCache(oldDscp);
***************
*** 5756,5763 ****
      if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
          (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
      {
!         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
!                  osi_LogSaveString(smb_logp, newLastNamep));
  
          /* if the existing link is to the same file, then we return success */
          if (!code) {
--- 5845,5852 ----
      if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
          (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
      {
!         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
!                  osi_LogSaveClientString(smb_logp, newLastNamep));
  
          /* if the existing link is to the same file, then we return success */
          if (!code) {
***************
*** 5779,5785 ****
      }
  
      /* 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, &req);
      osi_Log1(smb_logp,"  Link returns 0x%x", code);
  
--- 5868,5874 ----
      }
  
      /* now create the hardlink */
!     osi_Log1(smb_logp,"  Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
      code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
      osi_Log1(smb_logp,"  Link returns 0x%x", code);
  
***************
*** 5801,5825 ****
      return code;
  }
  
  long 
  smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     char *oldPathp;
!     char *newPathp;
!     char *tp;
      long code;
  
      tp = smb_GetSMBData(inp, NULL);
!     oldPathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(oldPathp,oldPathp);
!     newPathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(newPathp,newPathp);
! 
!     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
!              osi_LogSaveString(smb_logp, oldPathp),
!              osi_LogSaveString(smb_logp, newPathp));
  
      code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
  
--- 5890,5911 ----
      return code;
  }
  
+ /* SMB_COM_RENAME */
  long 
  smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *oldPathp;
!     clientchar_t *newPathp;
!     unsigned char *tp;
      long code;
  
      tp = smb_GetSMBData(inp, NULL);
!     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
!     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
! 
!     osi_Log2(smb_logp, "smb rename [%S] to [%S]",
!              osi_LogSaveClientString(smb_logp, oldPathp),
!              osi_LogSaveClientString(smb_logp, newPathp));
  
      code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
  
***************
*** 5833,5839 ****
      cm_scache_t *dscp;
      cm_user_t *userp;
      cm_req_t *reqp;
!     char *maskp;		/* pointer to the star pattern */
      int flags;
      int any;
      cm_dirEntryList_t * matches;
--- 5919,5925 ----
      cm_scache_t *dscp;
      cm_user_t *userp;
      cm_req_t *reqp;
!     normchar_t *maskp;		/* pointer to the star pattern */
      int flags;
      int any;
      cm_dirEntryList_t * matches;
***************
*** 5844,5899 ****
      long code = 0;
      smb_rmdirRock_t *rockp;
      int match;
!     char shortName[13];
!     char *matchName;
          
      rockp = (smb_rmdirRock_t *) vrockp;
  
!     matchName = dep->name;
      if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
!         match = (cm_stricmp(matchName, rockp->maskp) == 0);
      else
!         match = (strcmp(matchName, rockp->maskp) == 0);
      if (!match &&
           (rockp->flags & SMB_MASKFLAG_TILDE) &&
!          !cm_Is8Dot3(dep->name)) {
!         cm_Gen8Dot3Name(dep, shortName, NULL);
!         matchName = shortName;
!         match = (cm_stricmp(matchName, rockp->maskp) == 0);
      }       
  
      if (match) {
!             rockp->any = 1;
          cm_DirEntryListAdd(dep->name, &rockp->matches);
      }
  
      return 0;
  }
  
  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(&req);
  
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
--- 5930,5982 ----
      long code = 0;
      smb_rmdirRock_t *rockp;
      int match;
!     normchar_t matchName[MAX_PATH];
          
      rockp = (smb_rmdirRock_t *) vrockp;
  
!     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
      if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
!         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
      else
!         match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
      if (!match &&
           (rockp->flags & SMB_MASKFLAG_TILDE) &&
!          !cm_Is8Dot3(matchName)) {
!         cm_Gen8Dot3Name(dep, matchName, NULL);
!         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
      }       
  
      if (match) {
!         rockp->any = 1;
          cm_DirEntryListAdd(dep->name, &rockp->matches);
      }
  
      return 0;
  }
  
+ 
  long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      long code = 0;
!     clientchar_t *pathp;
!     unsigned char *tp;
      cm_space_t *spacep;
      cm_scache_t *dscp;
!     clientchar_t *lastNamep;
      smb_rmdirRock_t rock;
      cm_user_t *userp;
      osi_hyper_t thyper;
      int caseFold;
!     clientchar_t *tidPathp;
      cm_req_t req;
  
      cm_InitReq(&req);
  
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
***************
*** 5904,5910 ****
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
                      userp, tidPathp, &req, &dscp);
  
      if (code) {
--- 5987,5993 ----
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
                      userp, tidPathp, &req, &dscp);
  
      if (code) {
***************
*** 5914,5920 ****
          
  #ifdef DFS_SUPPORT
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
--- 5997,6003 ----
          
  #ifdef DFS_SUPPORT
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
***************
*** 5931,5938 ****
          lastNamep++;
  	
      rock.any = 0;
!     rock.maskp = lastNamep;
!     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
  
      thyper.LowPart = 0;
      thyper.HighPart = 0;
--- 6014,6021 ----
          lastNamep++;
  	
      rock.any = 0;
!     rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
!     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
  
      thyper.LowPart = 0;
      thyper.HighPart = 0;
***************
*** 5954,5968 ****
          cm_dirEntryList_t * entry;
  
          for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
              osi_Log1(smb_logp, "Removing directory %s",
                       osi_LogSaveString(smb_logp, entry->name));
  
!             code = cm_RemoveDir(dscp, entry->name, userp, &req);
  
              if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                  smb_NotifyChange(FILE_ACTION_REMOVED,
                                   FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
!                                  dscp, entry->name, NULL, TRUE);
          }
      }
  
--- 6037,6055 ----
          cm_dirEntryList_t * entry;
  
          for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
+             clientchar_t clientName[MAX_PATH];
+ 
+             cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
+ 
              osi_Log1(smb_logp, "Removing directory %s",
                       osi_LogSaveString(smb_logp, entry->name));
  
!             code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
  
              if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                  smb_NotifyChange(FILE_ACTION_REMOVED,
                                   FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
!                                  dscp, clientName, NULL, TRUE);
          }
      }
  
***************
*** 5974,5982 ****
--- 6061,6074 ----
  
      if (code == 0 && !rock.any)
          code = CM_ERROR_NOSUCHFILE;        
+ 
+     free(rock.maskp);
+     rock.maskp = NULL;
+ 
      return code;
  }
  
+ /* SMB_COM_FLUSH */
  long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      unsigned short fid;
***************
*** 6032,6081 ****
  }
  
  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->name)) {
          cm_Gen8Dot3Name(dep, shortName, NULL);
  
!         if (cm_stricmp(shortName, vrockp->name) == 0) {
!             vrockp->fullName = strdup(dep->name);
              return CM_ERROR_STOPNOW;
          }
      }
!     if (cm_stricmp(dep->name, vrockp->name) == 0 &&
          ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
          ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
!         vrockp->fullName = strdup(dep->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, &rock, NULL, userp, reqp, NULL); 
!     if (code == CM_ERROR_STOPNOW)
          *newPathp = rock.fullName;
!     else
!         *newPathp = strdup(pathp);
  }
  
  long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
--- 6124,6185 ----
  }
  
  struct smb_FullNameRock {
!     clientchar_t *name;
!     cm_scache_t  *vnode;
!     clientchar_t *fullName;
!     fschar_t     *originalName;
  };
  
  int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
                       osi_hyper_t *offp)
  {
!     normchar_t matchName[MAX_PATH];
      struct smb_FullNameRock *vrockp;
  
      vrockp = (struct smb_FullNameRock *)rockp;
  
!     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
! 
!     if (!cm_Is8Dot3(matchName)) {
!         clientchar_t shortName[13];
! 
          cm_Gen8Dot3Name(dep, shortName, NULL);
  
!         if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
!             vrockp->fullName = cm_ClientStrDup(matchName);
!             vrockp->originalName = cm_FsStrDup(dep->name);
              return CM_ERROR_STOPNOW;
          }
      }
!     if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
          ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
          ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
!         vrockp->fullName = cm_ClientStrDup(matchName);
!         vrockp->originalName = cm_FsStrDup(dep->name);
          return CM_ERROR_STOPNOW;
      }
      return 0;
  }
  
! void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
!                   clientchar_t **newPathp, fschar_t ** originalPathp,
!                   cm_user_t *userp, cm_req_t *reqp)
  {
      struct smb_FullNameRock rock;
      long code = 0;
  
+     memset(&rock, 0, sizeof(rock));
      rock.name = pathp;
      rock.vnode = scp;
  
      code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
!     if (code == CM_ERROR_STOPNOW) {
          *newPathp = rock.fullName;
!         *originalPathp = rock.originalName;
!     } else {
!         *newPathp = cm_ClientStrDup(pathp);
!         *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
!     }
  }
  
  long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
***************
*** 6083,6089 ****
      long code = 0;
      cm_req_t req;
      cm_scache_t *dscp = NULL;
!     char *pathp = NULL;
      cm_scache_t * scp = NULL;
      cm_scache_t *delscp = NULL;
      int nullcreator = 0;
--- 6187,6193 ----
      long code = 0;
      cm_req_t req;
      cm_scache_t *dscp = NULL;
!     clientchar_t *pathp = NULL;
      cm_scache_t * scp = NULL;
      cm_scache_t *delscp = NULL;
      int nullcreator = 0;
***************
*** 6107,6118 ****
      cm_InitReq(&req);
  
      lock_ObtainWrite(&smb_rctLock);
!     if (fidp->delete) {
  	osi_Log0(smb_logp, "  Fid already closed.");
  	lock_ReleaseWrite(&smb_rctLock);
  	return CM_ERROR_BADFD;
      }
!     fidp->delete = 1;
      lock_ReleaseWrite(&smb_rctLock);
  
      lock_ObtainMutex(&fidp->mx);
--- 6211,6222 ----
      cm_InitReq(&req);
  
      lock_ObtainWrite(&smb_rctLock);
!     if (fidp->deleteOk) {
  	osi_Log0(smb_logp, "  Fid already closed.");
  	lock_ReleaseWrite(&smb_rctLock);
  	return CM_ERROR_BADFD;
      }
!     fidp->deleteOk = 1;
      lock_ReleaseWrite(&smb_rctLock);
  
      lock_ObtainMutex(&fidp->mx);
***************
*** 6122,6128 ****
      }
  
      if (fidp->NTopen_pathp) {
! 	pathp = strdup(fidp->NTopen_pathp);
      }
  
      if (fidp->scp) {
--- 6226,6232 ----
      }
  
      if (fidp->NTopen_pathp) {
! 	pathp = cm_ClientStrDup(fidp->NTopen_pathp);
      }
  
      if (fidp->scp) {
***************
*** 6191,6197 ****
      }
  
      if (fidp->flags & SMB_FID_DELONCLOSE) {
!         char *fullPathp;
  
  	lock_ReleaseMutex(&fidp->mx);
  
--- 6295,6302 ----
      }
  
      if (fidp->flags & SMB_FID_DELONCLOSE) {
!         clientchar_t *fullPathp = NULL;
!         fschar_t *originalNamep = NULL;
  
  	lock_ReleaseMutex(&fidp->mx);
  
***************
*** 6200,6208 ****
              cm_HoldSCache(scp);
              delscp = scp;
          }
!         smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
          if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
!             code = cm_RemoveDir(dscp, fullPathp, userp, &req);
  	    if (code == 0) {
  		if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
  		    smb_NotifyChange(FILE_ACTION_REMOVED,
--- 6305,6313 ----
              cm_HoldSCache(scp);
              delscp = scp;
          }
!         smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
          if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
!             code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
  	    if (code == 0) {
  		if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
  		    smb_NotifyChange(FILE_ACTION_REMOVED,
***************
*** 6210,6216 ****
  				      dscp, fullPathp, NULL, TRUE);
  	    }
          } else {
!             code = cm_Unlink(dscp, fullPathp, userp, &req);
  	    if (code == 0) {				
  		if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
  		    smb_NotifyChange(FILE_ACTION_REMOVED,
--- 6315,6321 ----
  				      dscp, fullPathp, NULL, TRUE);
  	    }
          } else {
!             code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
  	    if (code == 0) {				
  		if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
  		    smb_NotifyChange(FILE_ACTION_REMOVED,
***************
*** 6218,6224 ****
  				      dscp, fullPathp, NULL, TRUE);
  	    }
          }
!         free(fullPathp);
  	lock_ObtainMutex(&fidp->mx);
  	fidp->flags &= ~SMB_FID_DELONCLOSE;
      }
--- 6323,6334 ----
  				      dscp, fullPathp, NULL, TRUE);
  	    }
          }
! 
!         if (fullPathp)
!             free(fullPathp);
!         if (originalNamep)
!             free(originalNamep);
! 
  	lock_ObtainMutex(&fidp->mx);
  	fidp->flags &= ~SMB_FID_DELONCLOSE;
      }
***************
*** 6274,6279 ****
--- 6384,6390 ----
      return code;
  }
  
+ /* SMB_COM_CLOSE */
  long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      unsigned short fid;
***************
*** 6305,6317 ****
  /*
   * smb_ReadData -- common code for Read, Read And X, and Raw Read
   */
- #ifndef DJGPP
  long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
  	cm_user_t *userp, long *readp)
- #else /* DJGPP */
- long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
- 	cm_user_t *userp, long *readp, int dosflag)
- #endif /* !DJGPP */
  {
      osi_hyper_t offset;
      long code = 0;
--- 6416,6423 ----
***************
*** 6450,6461 ****
          if (nbytes > count) nbytes = count;	/* don't go past EOF */
  
          /* now copy the data */
! #ifdef DJGPP
!         if (dosflag)
!             dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
!         else
! #endif /* DJGPP */
!             memcpy(op, bufferp->datap + bufIndex, nbytes);
                  
          /* adjust counters, pointers, etc. */
          op += nbytes;
--- 6556,6562 ----
          if (nbytes > count) nbytes = count;	/* don't go past EOF */
  
          /* now copy the data */
!         memcpy(op, bufferp->datap + bufIndex, nbytes);
                  
          /* adjust counters, pointers, etc. */
          op += nbytes;
***************
*** 6484,6496 ****
  /*
   * smb_WriteData -- common code for Write and Raw Write
   */
- #ifndef DJGPP
  long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
  	cm_user_t *userp, long *writtenp)
- #else /* DJGPP */
- long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
- 	cm_user_t *userp, long *writtenp, int dosflag)
- #endif /* !DJGPP */
  {
      osi_hyper_t offset = *offsetp;
      long code = 0;
--- 6585,6592 ----
***************
*** 6684,6695 ****
              nbytes = count;	/* don't go past end of request */
  
          /* now copy the data */
! #ifdef DJGPP
!         if (dosflag)
!             dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
!         else
! #endif /* DJGPP */
!             memcpy(bufferp->datap + bufIndex, op, nbytes);
          buf_SetDirty(bufferp, bufIndex, nbytes);
  
          /* and record the last writer */
--- 6780,6786 ----
              nbytes = count;	/* don't go past end of request */
  
          /* now copy the data */
!         memcpy(bufferp->datap + bufIndex, op, nbytes);
          buf_SetDirty(bufferp, bufIndex, nbytes);
  
          /* and record the last writer */
***************
*** 6756,6761 ****
--- 6847,6853 ----
      return code;
  }
  
+ /* SMB_COM_WRITE */
  long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      unsigned short fd;
***************
*** 6870,6880 ****
  
      code = 0;
      while ( code == 0 && count > 0 ) {
- #ifndef DJGPP
  	code = smb_WriteData(fidp, &offset, count, op, userp, &written);
- #else /* DJGPP */
- 	code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
- #endif /* !DJGPP */
  	if (code == 0 && written == 0)
              code = CM_ERROR_PARTIALWRITE;
  
--- 6962,6968 ----
***************
*** 6909,6919 ****
      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;
  
--- 6997,7003 ----
***************
*** 6931,6946 ****
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
- #ifndef DJGPP
      rawBuf = rwcp->buf;
      code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
  						 &written);
- #else /* DJGPP */
-     rawBuf = (dos_ptr) rwcp->buf;
-     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
-                          (unsigned char *) rawBuf, userp,
-                          &written, TRUE);
- #endif /* !DJGPP */
  
      if (rwcp->writeMode & 0x1) {	/* synchronous */
          smb_t *op;
--- 7015,7023 ----
***************
*** 6963,6973 ****
  
      /* Give back raw buffer */
      lock_ObtainMutex(&smb_RawBufLock);
- #ifndef DJGPP
      *((char **)rawBuf) = smb_RawBufs;
- #else /* DJGPP */
-     _farpokel(_dos_ds, rawBuf, smb_RawBufs);
- #endif /* !DJGPP */
      smb_RawBufs = rawBuf;
      lock_ReleaseMutex(&smb_RawBufLock);
  
--- 7040,7046 ----
***************
*** 6980,6985 ****
--- 7053,7059 ----
      return 0;
  }
  
+ /* SMB_COM_WRITE_RAW */
  long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
  {
      osi_hyper_t offset;
***************
*** 6992,7002 ****
      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);
--- 7066,7072 ----
***************
*** 7097,7107 ****
  
      code = 0;
      while ( code == 0 && count > 0 ) {
- #ifndef DJGPP
  	code = smb_WriteData(fidp, &offset, count, op, userp, &written);
- #else /* DJGPP */
- 	code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
- #endif /* !DJGPP */
  	if (code == 0 && written == 0)
              code = CM_ERROR_PARTIALWRITE;
  
--- 7167,7173 ----
***************
*** 7120,7130 ****
          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;
--- 7186,7192 ----
***************
*** 7171,7176 ****
--- 7233,7239 ----
      return 0;
  }
  
+ /* SMB_COM_READ */
  long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      osi_hyper_t offset;
***************
*** 7256,7266 ****
      *op++ = (unsigned char) (count & 0xff);
      *op++ = (unsigned char) ((count >> 8) & 0xff);
                  
- #ifndef DJGPP
      code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
- #else /* DJGPP */
-     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
- #endif /* !DJGPP */
  
      /* fix some things up */
      smb_SetSMBParm(outp, 0, finalCount);
--- 7319,7325 ----
***************
*** 7272,7291 ****
      return code;
  }
  
  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 */
      cm_scache_t *scp;			/* file we're creating */
      cm_attr_t setAttr;
      int initialModeBits;
!     char *lastNamep;
      int caseFold;
!     char *tidPathp;
      cm_req_t req;
  
      cm_InitReq(&req);
--- 7331,7351 ----
      return code;
  }
  
+ /* SMB_COM_CREATE_DIRECTORY */
  long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp;
      long code = 0;
      cm_space_t *spacep;
!     unsigned char *tp;
      cm_user_t *userp;
      cm_scache_t *dscp;			/* dir we're dealing with */
      cm_scache_t *scp;			/* file we're creating */
      cm_attr_t setAttr;
      int initialModeBits;
!     clientchar_t *lastNamep;
      int caseFold;
!     clientchar_t *tidPathp;
      cm_req_t req;
  
      cm_InitReq(&req);
***************
*** 7296,7310 ****
      initialModeBits = 0777;
          
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
  
!     if (strcmp(pathp, "\\") == 0)
          return CM_ERROR_EXISTS;
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
--- 7356,7368 ----
      initialModeBits = 0777;
          
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
  
!     if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
          return CM_ERROR_EXISTS;
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
***************
*** 7316,7322 ****
          return CM_ERROR_NOSUCHPATH;
      }
  
!     code = cm_NameI(cm_data.rootSCachep, spacep->data,
                      caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
                      userp, tidPathp, &req, &dscp);
  
--- 7374,7380 ----
          return CM_ERROR_NOSUCHPATH;
      }
  
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                      caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
                      userp, tidPathp, &req, &dscp);
  
***************
*** 7327,7333 ****
          
  #ifdef DFS_SUPPORT
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
--- 7385,7391 ----
          
  #ifdef DFS_SUPPORT
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
***************
*** 7377,7383 ****
      return 0;
  }
  
! BOOL smb_IsLegalFilename(char *filename)
  {
      /* 
       *  Find the longest substring of filename that does not contain
--- 7435,7441 ----
      return 0;
  }
  
! BOOL smb_IsLegalFilename(clientchar_t *filename)
  {
      /* 
       *  Find the longest substring of filename that does not contain
***************
*** 7385,7402 ****
       *  than the length of the whole string, then one or more of the
       *  illegal chars is in filename. 
       */
!     if (strcspn(filename, illegalChars) < strlen(filename))
          return FALSE;
  
      return TRUE;
! }        
  
  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;
      cm_scache_t *dscp;			/* dir we're dealing with */
--- 7443,7461 ----
       *  than the length of the whole string, then one or more of the
       *  illegal chars is in filename. 
       */
!     if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
          return FALSE;
  
      return TRUE;
! }
  
+ /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
  long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp;
      long code = 0;
      cm_space_t *spacep;
!     unsigned char *tp;
      int excl;
      cm_user_t *userp;
      cm_scache_t *dscp;			/* dir we're dealing with */
***************
*** 7405,7414 ****
      int initialModeBits;
      smb_fid_t *fidp;
      int attributes;
!     char *lastNamep;
      int caseFold;
      afs_uint32 dosTime;
!     char *tidPathp;
      cm_req_t req;
      int created = 0;			/* the file was new */
  
--- 7464,7473 ----
      int initialModeBits;
      smb_fid_t *fidp;
      int attributes;
!     clientchar_t *lastNamep;
      int caseFold;
      afs_uint32 dosTime;
!     clientchar_t *tidPathp;
      cm_req_t req;
      int created = 0;			/* the file was new */
  
***************
*** 7426,7437 ****
  	initialModeBits &= ~0222;
          
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
--- 7485,7494 ----
  	initialModeBits &= ~0222;
          
      tp = smb_GetSMBData(inp, NULL);
!     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
***************
*** 7442,7448 ****
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
                      userp, tidPathp, &req, &dscp);
  
      if (code) {
--- 7499,7505 ----
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
                      userp, tidPathp, &req, &dscp);
  
      if (code) {
***************
*** 7452,7458 ****
          
  #ifdef DFS_SUPPORT
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
--- 7509,7515 ----
          
  #ifdef DFS_SUPPORT
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
          if ( WANTS_DFS_PATHNAMES(inp) || pnc )
***************
*** 7473,7479 ****
      if (!smb_IsLegalFilename(lastNamep))
          return CM_ERROR_BADNTFILENAME;
  
!     osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
  #ifdef DEBUG_VERBOSE
      {
          char *hexp;
--- 7530,7536 ----
      if (!smb_IsLegalFilename(lastNamep))
          return CM_ERROR_BADNTFILENAME;
  
!     osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
  #ifdef DEBUG_VERBOSE
      {
          char *hexp;
***************
*** 7590,7595 ****
--- 7647,7653 ----
      return 0;
  }
  
+ /* SMB_COM_SEEK */
  long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      long code = 0;
***************
*** 7701,7710 ****
      /* Sanity check */
      if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
          /* log it and discard it */
- #ifndef DJGPP
  	LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT, 
  		 __FILE__, __LINE__, ncbp->ncb_length);
- #endif /* !DJGPP */
  	osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
          return;
      }
--- 7759,7766 ----
***************
*** 7766,7774 ****
                  /* Raw Write */
                  code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
              else {
!                 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",opName,vcp,vcp->lana,vcp->lsn);
                  code = (*(dp->procp)) (vcp, inp, outp);
!                 osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
  #ifdef LOG_PACKET
                  if ( code == CM_ERROR_BADSMB ||
                       code == CM_ERROR_BADOP )
--- 7822,7832 ----
                  /* Raw Write */
                  code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
              else {
!                 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
!                          opName,vcp,vcp->lana,vcp->lsn);
                  code = (*(dp->procp)) (vcp, inp, outp);
!                 osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",
!                          code,vcp,vcp->lana,vcp->lsn);
  #ifdef LOG_PACKET
                  if ( code == CM_ERROR_BADSMB ||
                       code == CM_ERROR_BADOP )
***************
*** 7780,7801 ****
              osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
  
              if (oldGen != sessionGen) {
- #ifndef DJGPP
  		LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
  			 newTime - oldTime, ncbp->ncb_length);
- #endif /* !DJGPP */
  		osi_Log3(smb_logp, "Request %s straddled session startup, "
                            "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
              }
!         }
!         else {
              /* bad opcode, fail the request, after displaying it */
              osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
  #ifdef LOG_PACKET
              smb_LogPacket(inp);
  #endif  /* LOG_PACKET */
  
- #ifndef DJGPP
              if (showErrors) {
                  sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
                  code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
--- 7838,7857 ----
              osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
  
              if (oldGen != sessionGen) {
  		LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
  			 newTime - oldTime, ncbp->ncb_length);
  		osi_Log3(smb_logp, "Request %s straddled session startup, "
                            "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
              }
! 
!             FreeSMBStrings(inp);
!         } else {
              /* bad opcode, fail the request, after displaying it */
              osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
  #ifdef LOG_PACKET
              smb_LogPacket(inp);
  #endif  /* LOG_PACKET */
  
              if (showErrors) {
                  sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
                  code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
***************
*** 7803,7818 ****
                  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
  	    LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID, 
  		     ncbp->ncb_length);
- #endif /* !DJGPP */
  #ifdef LOG_PACKET
              smb_LogPacket(inp);
  #endif /* LOG_PACKET */
--- 7859,7871 ----
***************
*** 7923,7929 ****
      return;
  }
  
- #ifndef DJGPP
  /* Wait for Netbios() calls to return, and make the results available to server
   * threads.  Note that server threads can't wait on the NCBevents array
   * themselves, because NCB events are manual-reset, and the servers would race
--- 7976,7981 ----
***************
*** 7977,7983 ****
          thrd_SetEvent(NCBreturns[0][idx]);
      }
  }
- #endif /* !DJGPP */
  
  /*
   * Try to have one NCBRECV request waiting for every live session.  Not more
--- 8029,8034 ----
***************
*** 7988,7996 ****
      DWORD code;
      int idx_session, idx_NCB;
      NCB *ncbp;
- #ifdef DJGPP
-     dos_ptr dos_ncb;
- #endif /* DJGPP */
  
      while (smbShutdownFlag == 0) {
          /* Get a session */
--- 8039,8044 ----
***************
*** 8083,8101 ****
          ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
          ncbp->ncb_command = NCBRECV | ASYNCH;
          ncbp->ncb_lana_num = lanas[idx_session];
- #ifndef DJGPP
          ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
          ncbp->ncb_event = NCBevents[idx_NCB];
          ncbp->ncb_length = SMB_PACKETSIZE;
          Netbios(ncbp);
- #else /* DJGPP */
-         ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
-         ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
-         ncbp->ncb_event = NCBreturns[0][idx_NCB];
-         ncbp->ncb_length = SMB_PACKETSIZE;
-         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-         Netbios(ncbp, dos_ncb);
- #endif /* !DJGPP */
      }
  }
  
--- 8131,8140 ----
***************
*** 8121,8129 ****
      UCHAR rc;
      smb_vc_t *vcp = NULL;
      smb_t *smbp;
! #ifdef DJGPP
!     dos_ptr dos_ncb;
! #endif /* DJGPP */
  
      rx_StartClientThread();
  
--- 8160,8166 ----
      UCHAR rc;
      smb_vc_t *vcp = NULL;
      smb_t *smbp;
!     extern void rx_StartClientThread(void);
  
      rx_StartClientThread();
  
***************
*** 8185,8193 ****
          }
  
          ncbp = NCBs[idx_NCB];
- #ifdef DJGPP
-         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
- #endif /* DJGPP */
          idx_session = NCBsessions[idx_NCB];
          rc = ncbp->ncb_retcode;
  
--- 8222,8227 ----
***************
*** 8206,8215 ****
  
          case NRC_SNUMOUT:
  	case NRC_SABORT:
- #ifndef DJGPP
  	    LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
  	    /* fallthrough */
- #endif /* !DJGPP */
  	case NRC_SCLOSED:
              /* Client closed session */
              vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
--- 8240,8247 ----
***************
*** 8234,8243 ****
  
          case NRC_INCOMP:
              /* Treat as transient error */
- #ifndef DJGPP
  	    LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE, 
  		     ncbp->ncb_length);
- #endif /* !DJGPP */
  	    osi_Log1(smb_logp,
  		     "dispatch smb recv failed, message incomplete, ncb_length %d",
  		     ncbp->ncb_length);
--- 8266,8273 ----
***************
*** 8333,8354 ****
  
          vcp->errorCount = 0;
          bufp = (struct smb_packet *) ncbp->ncb_buffer;
- #ifdef DJGPP
-         bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
-         /* copy whole packet to virtual memory */
-         /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
-         "bufp=0x%x\n",
-         bufp->dos_pkt / 16, bufp);*/
-         fflush(stderr);
-         dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
- #endif /* DJGPP */
          smbp = (smb_t *)bufp->data;
          outbufp->flags = 0;
  
! #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
          __try
          {
  #endif
              if (smbp->com == 0x1d) {
                  /* Special handling for Write Raw */
                  raw_write_cont_t rwc;
--- 8363,8377 ----
  
          vcp->errorCount = 0;
          bufp = (struct smb_packet *) ncbp->ncb_buffer;
          smbp = (smb_t *)bufp->data;
          outbufp->flags = 0;
  
! #if !defined(AFS_WIN32_ENV)
! #ifndef NOTRACE
          __try
          {
  #endif
+ #endif
              if (smbp->com == 0x1d) {
                  /* Special handling for Write Raw */
                  raw_write_cont_t rwc;
***************
*** 8366,8376 ****
                      ncbp->ncb_buffer = rwc.buf;
                      ncbp->ncb_length = 65535;
                      ncbp->ncb_event = rwevent;
- #ifndef DJGPP
                      Netbios(ncbp);
- #else
-                     Netbios(ncbp, dos_ncb);
- #endif /* !DJGPP */
                      rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
                      thrd_CloseHandle(rwevent);
                  }
--- 8389,8395 ----
***************
*** 8390,8399 ****
                  /* TODO: what else needs to be serialized? */
                  smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
              }
! #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
          }
          __except( smb_ServerExceptionFilter() ) {
          }
  #endif
  
          smb_concurrentCalls--;
--- 8409,8420 ----
                  /* TODO: what else needs to be serialized? */
                  smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
              }
! #if !defined(AFS_WIN95_ENV)
! #ifndef NOTRACE
          }
          __except( smb_ServerExceptionFilter() ) {
          }
+ #endif /* NOTRACE */
  #endif
  
          smb_concurrentCalls--;
***************
*** 8411,8417 ****
   * force trace and give control to upstream exception handlers. Useful for
   * debugging.
   */
! #if !defined(DJGPP) && !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
--- 8432,8438 ----
   * force trace and give control to upstream exception handlers. Useful for
   * debugging.
   */
! #if !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
***************
*** 8444,8455 ****
      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<=i<smb_NumServerThreads][%d]", idx);
      retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
--- 8465,8474 ----
***************
*** 8474,8495 ****
      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_PTR lana = (INT_PTR) parmp;
      char eventName[MAX_PATH];
  
!     sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
      ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          thrd_ResetEvent(ListenerShutdown[lana]);
  
      ncbp = GetNCB();
- #ifdef DJGPP
-     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
- #endif /* DJGPP */
  
      /* retrieve computer name */
      GetComputerName(cname, &cnamelen);
--- 8493,8507 ----
      char rname[NCBNAMSZ+1];
      char cname[MAX_COMPUTERNAME_LENGTH+1];
      int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
      INT_PTR lana = (INT_PTR) parmp;
      char eventName[MAX_PATH];
  
!     sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
      ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
          thrd_ResetEvent(ListenerShutdown[lana]);
  
      ncbp = GetNCB();
  
      /* retrieve computer name */
      GetComputerName(cname, &cnamelen);
***************
*** 8513,8523 ****
          
          ncbp->ncb_lana_num = (UCHAR)lana;
  
- #ifndef DJGPP
          code = Netbios(ncbp);
- #else /* DJGPP */
-         code = Netbios(ncbp, dos_ncb);
- #endif
          if (code == NRC_NAMERR) {
              /* An smb shutdown or Vista resume must have taken place */
  	    osi_Log2(smb_logp,
--- 8525,8531 ----
***************
*** 8566,8574 ****
  	}
  #if 0
          else if (code != 0) {
- #ifndef DJGPP
              char tbuffer[AFSPATHMAX];
- #endif
  
              /* terminate silently if shutdown flag is set */
              while (!lock_TryMutex(&smb_StartedLock)) {
--- 8574,8580 ----
***************
*** 8583,8589 ****
              osi_Log0(smb_logp, 
                       "Client exiting due to network failure. Please restart client.\n");
  
- #ifndef DJGPP
              sprintf(tbuffer, 
                       "Client exiting due to network failure.  Please restart client.\n"
                       "NCBLISTEN lana=%d failed with code %d [%s]",
--- 8589,8594 ----
***************
*** 8592,8605 ****
                  code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
                                        MB_OK|MB_SERVICE_NOTIFICATION);
  	    osi_panic(tbuffer, __FILE__, __LINE__);
- #else
-             fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
-                      ncbp->ncb_lana_num, code);
-             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 */
  
              lock_ReleaseMutex(&smb_StartedLock);
              break;
--- 8597,8602 ----
***************
*** 8643,8660 ****
  		     ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
  
  	    if (reportSessionStartups) {
- #ifndef DJGPP
  		LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
- #else /* DJGPP */
- 		time(&now);
- 		fprintf(stderr, "%s: New session %d starting from host %s\n",
- 			asctime(localtime(&now)), ncbp->ncb_lsn, rname);
- 		fflush(stderr);
- #endif /* !DJGPP */
  	    }
  	    
  	    lock_ObtainMutex(&vcp->mx);
! 	    strcpy(vcp->rname, rname);
  	    vcp->flags |= flags;
  	    lock_ReleaseMutex(&vcp->mx);
  
--- 8640,8650 ----
  		     ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
  
  	    if (reportSessionStartups) {
  		LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
  	    }
  	    
  	    lock_ObtainMutex(&vcp->mx);
!             cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
  	    vcp->flags |= flags;
  	    lock_ReleaseMutex(&vcp->mx);
  
***************
*** 8686,8699 ****
  		     ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
  
  	    if (reportSessionStartups) {
- #ifndef DJGPP
  		LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
- #else /* DJGPP */
- 		time(&now);
- 		fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
- 			asctime(localtime(&now)), ncbp->ncb_lsn, rname);
- 		fflush(stderr);
- #endif /* !DJGPP */
  	    }
  	}
  
--- 8676,8682 ----
***************
*** 8732,8737 ****
--- 8715,8721 ----
                  smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
                  smbp->rcls = errClass;
              }
+ 
              smb_SendPacket(vcp, outp);
              smb_FreePacket(outp);
  
***************
*** 8892,8900 ****
  int smb_NetbiosInit(int locked)
  {
      NCB *ncbp;
- #ifdef DJGPP
-     dos_ptr dos_ncb;
- #endif /* DJGPP */
      int i, lana, code, l;
      char s[100];
      int delname_tried=0;
--- 8876,8881 ----
***************
*** 8914,8922 ****
      }
      /* setup the NCB system */
      ncbp = GetNCB();
- #ifdef DJGPP
-     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
- #endif /* DJGPP */
  
      /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
      if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
--- 8895,8900 ----
***************
*** 8946,8953 ****
      strcpy(smb_localNamep, cm_NetbiosName);
      afsi_log("smb_localNamep is >%s<", smb_localNamep);
  
  
- #ifndef DJGPP
      if (smb_LANadapter == LANA_INVALID) {
          ncbp->ncb_command = NCBENUM;
          ncbp->ncb_buffer = (PUCHAR)&lana_list;
--- 8924,8932 ----
      strcpy(smb_localNamep, cm_NetbiosName);
      afsi_log("smb_localNamep is >%s<", smb_localNamep);
  
+     /* Also copy the value to the client character encoded string */
+     cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
  
      if (smb_LANadapter == LANA_INVALID) {
          ncbp->ncb_command = NCBENUM;
          ncbp->ncb_buffer = (PUCHAR)&lana_list;
***************
*** 8981,8999 ****
              afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
          }
      }
- #else
-     /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset.  so
-        we will just fake the LANA list */
-     if (smb_LANadapter == LANA_INVALID) {
-         for (i = 0; i < 8; i++)
- 	    lana_list.lana[i] = i;
-         lana_list.length = 8;
-     }
-     else {
-         lana_list.length = 1;
-         lana_list.lana[0] = smb_LANadapter;
-     }
- #endif /* !DJGPP */
  
      /* and declare our name so we can receive connections */
      memset(ncbp, 0, sizeof(*ncbp));
--- 8960,8965 ----
***************
*** 9009,9019 ****
          ncbp->ncb_command = NCBADDNAME;
          ncbp->ncb_lana_num = lana;
          memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
- #ifndef DJGPP
          code = Netbios(ncbp);
- #else /* DJGPP */
-         code = Netbios(ncbp, dos_ncb);
- #endif /* !DJGPP */
            
          afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
                   lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
--- 8975,8981 ----
***************
*** 9029,9039 ****
  
          if (code == 0) {
              afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
- #ifdef DJGPP
-             /* we only use one LANA with djgpp */
-             lana_list.lana[0] = lana;
-             lana_list.length = 1;
- #endif	  
          }
          else {
              afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
--- 8991,8996 ----
***************
*** 9047,9057 ****
                  ncbp->ncb_command = NCBDELNAME;
                  memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
                  ncbp->ncb_lana_num = lana;
- #ifndef DJGPP
                  code = Netbios(ncbp);
- #else
-                 code = Netbios(ncbp, dos_ncb);
- #endif /* DJGPP */
                  if (code == 0) 
                      code = ncbp->ncb_retcode;
                  else {
--- 9004,9010 ----
***************
*** 9076,9084 ****
          if (code == 0) {
              smb_LANadapter = lana;
              lana_found = 1;   /* at least one worked */
- #ifdef DJGPP
-             break;
- #endif
          }
      }
  
--- 9029,9034 ----
***************
*** 9238,9268 ****
          lock_ReleaseMutex(&smb_StartedLock);
  }
  
! void smb_Init(osi_log_t *logp, int useV3,
!               int nThreads
! #ifndef DJGPP
!               , void *aMBfunc
! #endif
!   )
! 
  {
      thread_t phandle;
      int lpid;
      INT_PTR i;
      struct tm myTime;
- #ifdef DJGPP
-     int npar, seg, sel;
-     dos_ptr rawBuf;
- #endif /* DJGPP */
      EVENT_HANDLE retHandle;
      char eventName[MAX_PATH];
      int startListeners = 0;
  
      smb_TlsRequestSlot = TlsAlloc();
  
- #ifndef DJGPP
      smb_MBfunc = aMBfunc;
- #endif /* DJGPP */
  
      smb_useV3 = useV3;
  
--- 9188,9206 ----
          lock_ReleaseMutex(&smb_StartedLock);
  }
  
! void smb_Init(osi_log_t *logp, int useV3, int nThreads, void *aMBfunc)
  {
      thread_t phandle;
      int lpid;
      INT_PTR i;
      struct tm myTime;
      EVENT_HANDLE retHandle;
      char eventName[MAX_PATH];
      int startListeners = 0;
  
      smb_TlsRequestSlot = TlsAlloc();
  
      smb_MBfunc = aMBfunc;
  
      smb_useV3 = useV3;
  
***************
*** 9299,9305 ****
      lock_InitializeMutex(&smb_StartedLock, "smb started lock");
  	
      /* 4 Raw I/O buffers */
- #ifndef DJGPP
      smb_RawBufs = calloc(65536,1);
      *((char **)smb_RawBufs) = NULL;
      for (i=0; i<3; i++) {
--- 9237,9242 ----
***************
*** 9307,9345 ****
          *((char **)rawBuf) = smb_RawBufs;
          smb_RawBufs = rawBuf;
      }
- #else /* DJGPP */
-     npar = 65536 >> 4;  /* number of paragraphs */
-     seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
-     if (seg == -1) {
-         afsi_log("Cannot allocate %d paragraphs of DOS memory",
-                   npar);
-         osi_panic("",__FILE__,__LINE__);
-     }
-     else {
-         afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
-                   npar, seg);
-     }
-     smb_RawBufs = (seg * 16) + 0;  /* DOS physical address */
-         
-     _farpokel(_dos_ds, smb_RawBufs, NULL);
-     for (i=0; i<SMB_RAW_BUFS-1; i++) {
-         npar = 65536 >> 4;  /* number of paragraphs */
-         seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
-         if (seg == -1) {
-             afsi_log("Cannot allocate %d paragraphs of DOS memory",
-                       npar);
-             osi_panic("",__FILE__,__LINE__);
-         }
-         else {
-             afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
-                       npar, seg);
-         }
-         rawBuf = (seg * 16) + 0;  /* DOS physical address */
-         /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
-         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
-         smb_RawBufs = rawBuf;
-     }
- #endif /* !DJGPP */
  
      /* global free lists */
      smb_ncbFreeListp = NULL;
--- 9244,9249 ----
***************
*** 9606,9627 ****
           * 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, &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 */
      if (startListeners)
          smb_StartListeners(1);
  
- #ifndef DJGPP
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
                            NULL, 0, &lpid, "smb_ClientWaiter");
      osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
      thrd_CloseHandle(phandle);
- #endif /* !DJGPP */
  
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
                            NULL, 0, &lpid, "smb_ServerWaiter");
--- 9510,9529 ----
           * It is actually the domain for local logins, and we are acting as
           * a local SMB server. 
           */
!         bufsize = lengthof(smb_ServerDomainName) - 1;
!         GetComputerNameW(smb_ServerDomainName, &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 */
      if (startListeners)
          smb_StartListeners(1);
  
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
                            NULL, 0, &lpid, "smb_ClientWaiter");
      osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
      thrd_CloseHandle(phandle);
  
      phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
                            NULL, 0, &lpid, "smb_ServerWaiter");
***************
*** 9645,9654 ****
      osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
      thrd_CloseHandle(phandle);
  
- #ifdef DJGPP
-     smb_ListShares();
- #endif
- 
      lock_ReleaseMutex(&smb_StartedLock);
      return;
  }
--- 9547,9552 ----
***************
*** 9656,9664 ****
  void smb_Shutdown(void)
  {
      NCB *ncbp;
- #ifdef DJGPP
-     dos_ptr dos_ncb;
- #endif
      long code = 0;
      afs_uint32 i;
      smb_vc_t *vcp;
--- 9554,9559 ----
***************
*** 9667,9675 ****
          
      /* setup the NCB system */
      ncbp = GetNCB();
- #ifdef DJGPP
-     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
- #endif
  
      /* Block new sessions by setting shutdown flag */
      smbShutdownFlag = 1;
--- 9562,9567 ----
***************
*** 9685,9695 ****
          ncbp->ncb_command = NCBHANGUP;
          ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
          ncbp->ncb_lsn = (UCHAR)LSNs[i];
- #ifndef DJGPP
          code = Netbios(ncbp);
- #else
-         code = Netbios(ncbp, dos_ncb);
- #endif
          /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
          if (code == 0) code = ncbp->ncb_retcode;
          if (code != 0) {
--- 9577,9583 ----
***************
*** 9723,9733 ****
          ncbp->ncb_command = NCBDELNAME;
          ncbp->ncb_lana_num = lana_list.lana[i];
          memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
- #ifndef DJGPP
          code = Netbios(ncbp);
- #else
-         code = Netbios(ncbp, dos_ncb);
- #endif
          if (code == 0) 
              code = ncbp->ncb_retcode;
          if (code != 0) {
--- 9611,9617 ----
***************
*** 9786,9791 ****
--- 9670,9676 ----
  char *smb_GetSharename()
  {
      char *name;
+     int len;
  
      /* Make sure we have been properly initialized. */
      if (smb_localNamep == NULL)
***************
*** 9794,9809 ****
      /* Allocate space for \\<servername>\<sharename>, plus the
       * terminator.
       */
!     name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
!     sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
      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'};
--- 9679,9696 ----
      /* Allocate space for \\<servername>\<sharename>, plus the
       * terminator.
       */
!     len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
!     name = malloc(len);
!     snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
      return name;
! }
  
  
  #ifdef LOG_PACKET
  void smb_LogPacket(smb_packet_t *packet)
  {
      BYTE *vp, *cp;
+     smb_t * smbp;
      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'};
***************
*** 9812,9822 ****
  
      osi_Log0(smb_logp, "*** SMB packet dump ***");
  
      vp = (BYTE *) packet->data;
  
!     datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
!     length = paramlen + 2 + datalen;
! 
  
      for (i=0;i < length; i+=16)
      {
--- 9699,9710 ----
  
      osi_Log0(smb_logp, "*** SMB packet dump ***");
  
+     smbp = (smb_t *) packet->data;
      vp = (BYTE *) packet->data;
  
!     paramlen = smbp->wct * 2;
!     datalen = *((WORD *) (smbp->vdata + paramlen));
!     length = sizeof(*smbp) + paramlen + 1 + datalen;
  
      for (i=0;i < length; i+=16)
      {
***************
*** 9891,9898 ****
          {
              sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n", 
                       cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
!                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
!                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
              WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
          }
        
--- 9779,9786 ----
          {
              sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n", 
                       cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
!                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
!                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
              WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
          }
        
***************
*** 9921,9928 ****
          {
              sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n", 
                       cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
!                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
!                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
              WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
          }
        
--- 9809,9816 ----
          {
              sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n", 
                       cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
!                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
!                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
              WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
          }
        
Index: openafs/src/WINNT/afsd/smb.h
diff -c openafs/src/WINNT/afsd/smb.h:1.41.2.27 openafs/src/WINNT/afsd/smb.h:1.41.2.32
*** openafs/src/WINNT/afsd/smb.h:1.41.2.27	Thu Feb 28 12:17:16 2008
--- openafs/src/WINNT/afsd/smb.h	Thu Jun 26 12:38:31 2008
***************
*** 10,25 ****
  #ifndef __SMB_H_ENV__
  #define __SMB_H_ENV__ 1
  
- #ifdef DJGPP
- #include "netbios95.h"
- #endif /* DJGPP */
- 
  #if _WIN32_WINNT < 0x0501
  #undef _WIN32_WINNT
  #define _WIN32_WINNT 0x0501
  #endif
  #include <ntsecapi.h>
  
  /* Support largefiles by default */
  #define AFS_LARGEFILES
  
--- 10,23 ----
  #ifndef __SMB_H_ENV__
  #define __SMB_H_ENV__ 1
  
  #if _WIN32_WINNT < 0x0501
  #undef _WIN32_WINNT
  #define _WIN32_WINNT 0x0501
  #endif
  #include <ntsecapi.h>
  
+ #include <cm_nls.h>
+ 
  /* Support largefiles by default */
  #define AFS_LARGEFILES
  
***************
*** 51,57 ****
  #define SMB_FLAGS_CANONICAL_PATHNAMES      0x10
  #define SMB_FLAGS_REQUEST_OPLOCK           0x20
  #define SMB_FLAGS_REQUEST_BATCH_OPLOCK     0x40
! #define SMB_FLAGS_SERVER_TO_CLIENT         0x80           
  
  /* flg2 values */
  
--- 49,55 ----
  #define SMB_FLAGS_CANONICAL_PATHNAMES      0x10
  #define SMB_FLAGS_REQUEST_OPLOCK           0x20
  #define SMB_FLAGS_REQUEST_BATCH_OPLOCK     0x40
! #define SMB_FLAGS_SERVER_TO_CLIENT         0x80
  
  /* flg2 values */
  
***************
*** 68,73 ****
--- 66,72 ----
  
  #define KNOWS_LONG_NAMES(inp) ((((smb_t *)inp)->flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES)?1:0)
  #define WANTS_DFS_PATHNAMES(inp) ((((smb_t *)inp)->flg2 & SMB_FLAGS2_DFS_PATHNAMES)?1:0)
+ #define WANTS_UNICODE(inp) ((((smb_t *)inp)->flg2 & SMB_FLAGS2_UNICODE)?1:0)
  
  /* Information Levels */
  #define SMB_INFO_STANDARD               1
***************
*** 129,134 ****
--- 128,135 ----
  #define SMB_PACKETSIZE	32768 /* was 8400 */
  /* raw mode is considered obsolete and cannot be used with message signing */
  #define SMB_MAXRAWSIZE  65536
+ /* max STRING characters per packet per request */
+ #define SMB_STRINGBUFSIZE 4096
  
  /* Negotiate protocol constants */
  /* Security */
***************
*** 190,199 ****
      unsigned char oddByte;
      unsigned short ncb_length;
      unsigned char flags;
! #ifdef DJGPP
!     dos_ptr dos_pkt;
!     unsigned int dos_pkt_sel;
! #endif /* DJGPP */
  } smb_packet_t;
  
  /* smb_packet flags */
--- 191,197 ----
      unsigned char oddByte;
      unsigned short ncb_length;
      unsigned char flags;
!     cm_space_t *stringsp;               /* decoded strings from this packet */
  } smb_packet_t;
  
  /* smb_packet flags */
***************
*** 206,216 ****
      NCB ncb;			        /* ncb to use */
      struct myncb *nextp;		/* when on free list */
      long magic;
- #ifdef DJGPP
-     dos_ptr dos_ncb;
-     smb_packet_t *orig_pkt;
-     unsigned int dos_ncb_sel;
- #endif /* DJGPP */
  } smb_ncb_t;
  
  /* structures representing environments from kernel / SMB network.
--- 204,209 ----
***************
*** 235,241 ****
      struct smb_user *usersp;	        /* the first child in the user session list */
      struct smb_fid *fidsp;		/* the first child in the open file list */
      unsigned char errorCount;
!     char rname[17];
      int lana;
      char encKey[MSV1_0_CHALLENGE_LENGTH]; /* MSV1_0_CHALLENGE_LENGTH is 8 */
      void * secCtx;                      /* security context when negotiating SMB extended auth
--- 228,234 ----
      struct smb_user *usersp;	        /* the first child in the user session list */
      struct smb_fid *fidsp;		/* the first child in the open file list */
      unsigned char errorCount;
!     clientchar_t rname[17];
      int lana;
      char encKey[MSV1_0_CHALLENGE_LENGTH]; /* MSV1_0_CHALLENGE_LENGTH is 8 */
      void * secCtx;                      /* security context when negotiating SMB extended auth
***************
*** 255,260 ****
--- 248,254 ----
  #define SMB_VCFLAG_SESSX_RCVD	0x40	/* we received at least one session setups on this vc */
  #define SMB_VCFLAG_AUTH_IN_PROGRESS 0x80 /* a SMB NT extended authentication is in progress */
  #define SMB_VCFLAG_CLEAN_IN_PROGRESS 0x100
+ #define SMB_VCFLAG_USEUNICODE   0x200   /* une UNICODE for STRING fields (NTLM 0.12 or later) */
  
  /* one per user session */
  typedef struct smb_user {
***************
*** 265,271 ****
      unsigned short userID;		/* the session identifier */
      struct smb_vc *vcp;		        /* back ptr to virtual circuit */
      struct smb_username *unp;           /* user name struct */
!     afs_uint32	delete;			/* ok to del: locked by smb_rctLock */
  } smb_user_t;
  
  #define SMB_USERFLAG_DELETE	    1	/* delete struct when ref count zero */
--- 259,265 ----
      unsigned short userID;		/* the session identifier */
      struct smb_vc *vcp;		        /* back ptr to virtual circuit */
      struct smb_username *unp;           /* user name struct */
!     afs_uint32	deleteOk;		/* ok to del: locked by smb_rctLock */
  } smb_user_t;
  
  #define SMB_USERFLAG_DELETE	    1	/* delete struct when ref count zero */
***************
*** 276,283 ****
      long flags;			        /* flags; locked by mx */
      osi_mutex_t mx;
      struct cm_user *userp;		/* CM user structure */
!     char *name;			        /* user name */
!     char *machine;                      /* machine name */
      time_t last_logoff_t;		/* most recent logoff time */
  } smb_username_t;
  
--- 270,277 ----
      long flags;			        /* flags; locked by mx */
      osi_mutex_t mx;
      struct cm_user *userp;		/* CM user structure */
!     clientchar_t *name;                 /* user name */
!     clientchar_t *machine;              /* machine name */
      time_t last_logoff_t;		/* most recent logoff time */
  } smb_username_t;
  
***************
*** 310,317 ****
      struct smb_vc *vcp;		        /* back ptr */
      struct cm_user *userp;		/* user logged in at the
  					 * tree connect level (base) */
!     char *pathname;			/* pathname derived from sharename */
!     afs_uint32	delete;			/* ok to del: locked by smb_rctLock */
  } smb_tid_t;
  
  #define SMB_TIDFLAG_IPC		1 	/* IPC$ */
--- 304,311 ----
      struct smb_vc *vcp;		        /* back ptr */
      struct cm_user *userp;		/* user logged in at the
  					 * tree connect level (base) */
!     clientchar_t *pathname;             /* pathname derived from sharename */
!     afs_uint32	deleteOk;		/* ok to del: locked by smb_rctLock */
  } smb_tid_t;
  
  #define SMB_TIDFLAG_IPC		1 	/* IPC$ */
***************
*** 326,361 ****
      struct smb_tid *tidp;		/* back ptr */
  } smb_pid_t;
  
! /* ioctl parameter, while being assembled and/or processed */
! typedef struct smb_ioctl {
!     /* input side */
!     char *inDatap;			/* ioctl func's current position
! 					 * in input parameter block */
!     char *inAllocp;			/* allocated input parameter block */
!     afs_uint32 inCopied;			/* # of input bytes copied in so far
! 					 * by write calls */
!     cm_space_t *prefix;		        /* prefix for subst drives */
!     char *tidPathp;			/* Pathname associated with Tree ID */
! 
!     /* output side */
!     char *outDatap;			/* output results assembled so far */
!     char *outAllocp;		        /* output results assembled so far */
!     afs_uint32 outCopied;		/* # of output bytes copied back so far
!                                          * by read calls */
! 	
!     /* flags */
!     afs_uint32 flags;
! 
!     /* fid pointer */
!     struct smb_fid *fidp;
! 
!     /* uid pointer */
!     smb_user_t *uidp;
! } smb_ioctl_t;
! 
! /* flags for smb_ioctl_t */
! #define SMB_IOCTLFLAG_DATAIN	1	/* reading data from client to server */
! #define SMB_IOCTLFLAG_LOGON	2	/* got tokens from integrated logon */
  
  /* one per file ID; these are really file descriptors */
  typedef struct smb_fid {
--- 320,328 ----
      struct smb_tid *tidp;		/* back ptr */
  } smb_pid_t;
  
! 
! /* Defined in smb_ioctl.h */
! struct smb_ioctl;
  
  /* one per file ID; these are really file descriptors */
  typedef struct smb_fid {
***************
*** 371,390 ****
                                             the file if session is
                                             terminated) */
      osi_hyper_t offset;			/* our file pointer */
!     smb_ioctl_t *ioctlp;		/* ptr to ioctl structure */
  					/* Under NT, we may need to know the
  					 * parent directory and pathname used
  					 * to open the file, either to delete
  					 * the file on close, or to do a
  					 * change notification */
      struct cm_scache *NTopen_dscp;	/* parent directory (NT) */
!     char *NTopen_pathp;		        /* path used in open (NT) */
!     char *NTopen_wholepathp;	        /* entire path, not just last name */
      int curr_chunk;			/* chunk being read */
      int prev_chunk;			/* previous chunk read */
      int raw_writers;		        /* pending async raw writes */
      EVENT_HANDLE raw_write_event;	/* signal this when raw_writers zero */
!     afs_uint32	delete;			/* ok to del: locked by smb_rctLock */
  } smb_fid_t;
  
  #define SMB_FID_OPENREAD_LISTDIR	1	/* open for reading / listing directory */
--- 338,357 ----
                                             the file if session is
                                             terminated) */
      osi_hyper_t offset;			/* our file pointer */
!     struct smb_ioctl *ioctlp;		/* ptr to ioctl structure */
  					/* Under NT, we may need to know the
  					 * parent directory and pathname used
  					 * to open the file, either to delete
  					 * the file on close, or to do a
  					 * change notification */
      struct cm_scache *NTopen_dscp;	/* parent directory (NT) */
!     clientchar_t *NTopen_pathp;		/* path used in open (NT) */
!     clientchar_t *NTopen_wholepathp;	/* entire path, not just last name */
      int curr_chunk;			/* chunk being read */
      int prev_chunk;			/* previous chunk read */
      int raw_writers;		        /* pending async raw writes */
      EVENT_HANDLE raw_write_event;	/* signal this when raw_writers zero */
!     afs_uint32	deleteOk;		/* ok to del: locked by smb_rctLock */
  } smb_fid_t;
  
  #define SMB_FID_OPENREAD_LISTDIR	1	/* open for reading / listing directory */
***************
*** 460,468 ****
  					 * locked by smb_globalLock */
      unsigned short attribute;	        /* search attribute
  					 * (used for extended protocol) */
!     char tidPath[256];                  /* tid path */
!     char relPath[1024];                 /* relative path */        
!     char mask[256];			/* search mask for V3 */
  } smb_dirSearch_t;
  
  #define SMB_DIRSEARCH_DELETE	1	/* delete struct when ref count zero */
--- 427,435 ----
  					 * locked by smb_globalLock */
      unsigned short attribute;	        /* search attribute
  					 * (used for extended protocol) */
!     clientchar_t tidPath[256];          /* tid path */
!     clientchar_t relPath[1024];         /* relative path */        
!     clientchar_t mask[256];	        /* search mask for V3 */
  } smb_dirSearch_t;
  
  #define SMB_DIRSEARCH_DELETE	1	/* delete struct when ref count zero */
***************
*** 473,479 ****
  /* type for patching directory listings */
  typedef struct smb_dirListPatch {
      osi_queue_t q;
!     char *dptr;		                /* ptr to attr, time, data, sizel, sizeh */
      long flags;                         /* flags.  See below */
      cm_fid_t fid;
      cm_dirEntry_t *dep;                 /* temp */
--- 440,446 ----
  /* type for patching directory listings */
  typedef struct smb_dirListPatch {
      osi_queue_t q;
!     char *dptr;                      /* ptr to attr, time, data, sizel, sizeh */
      long flags;                         /* flags.  See below */
      cm_fid_t fid;
      cm_dirEntry_t *dep;                 /* temp */
***************
*** 532,543 ****
  
  /* prototypes */
  
! extern void smb_Init(osi_log_t *logp, int useV3,
! 	int nThreads
! #ifndef DJGPP
!         , void *aMBfunc
! #endif
!   );
  
  extern void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime);
  
--- 499,505 ----
  
  /* prototypes */
  
! extern void smb_Init(osi_log_t *logp, int useV3, int nThreads, void *aMBfunc);
  
  extern void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime);
  
***************
*** 569,577 ****
  
  extern smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags);
  
! extern smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags);
  
! extern smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern); 
  
  extern void smb_ReleaseUsername(smb_username_t *unp);
  
--- 531,541 ----
  
  extern smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags);
  
! extern smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags);
  
! extern cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags);
! 
! extern smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern); 
  
  extern void smb_ReleaseUsername(smb_username_t *unp);
  
***************
*** 583,589 ****
  
  extern cm_user_t *smb_GetUserFromUID(smb_user_t *uidp);
  
! extern long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** tidPathp);
  
  extern smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags);
  
--- 547,553 ----
  
  extern cm_user_t *smb_GetUserFromUID(smb_user_t *uidp);
  
! extern long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** tidPathp);
  
  extern smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags);
  
***************
*** 596,604 ****
  extern long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                           afs_uint32 dosTime);
  
! extern int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName, char **pathNamep);
  
! extern int smb_FindShareCSCPolicy(char *shareName);
  
  extern smb_dirSearch_t *smb_FindDirSearchNL(long cookie);
  
--- 560,568 ----
  extern long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                           afs_uint32 dosTime);
  
! extern int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, clientchar_t *shareName, clientchar_t **pathNamep);
  
! extern int smb_FindShareCSCPolicy(clientchar_t *shareName);
  
  extern smb_dirSearch_t *smb_FindDirSearchNL(long cookie);
  
***************
*** 634,646 ****
  
  extern void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue);
  
! extern void smb_StripLastComponent(char *outPathp, char **lastComponentp,
! 	char *inPathp);
  
! extern unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp);
  
  extern unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp,
! 	int *lengthp);
  
  extern smb_packet_t *smb_GetResponsePacket(smb_vc_t *vcp, smb_packet_t *inp);
  
--- 598,633 ----
  
  extern void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue);
  
! extern void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
! 	clientchar_t *inPathp);
! 
! #define SMB_STRF_FORCEASCII (1<<0)
! #define SMB_STRF_ANSIPATH   (1<<1)
! #define SMB_STRF_IGNORENULL (1<<2)
! 
! extern clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
!                                          char **chainpp, int flags);
! 
! extern clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
!                                      char ** chainpp, int flags);
  
! extern clientchar_t *smb_ParseStringBuf(const unsigned char * bufbase,
!                                         cm_space_t ** stringspp,
!                                         unsigned char *inp, size_t *pcb_max,
!                                         char **chainpp, int flags);
! 
! extern clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
!                                        size_t cb, char ** chainpp, int flags);
! 
! extern clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
!                                         size_t cch, char ** chainpp, int flags);
! 
! extern unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
!                                    clientchar_t * str,
!                                    size_t * plen, int flags);
  
  extern unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp,
!                                   int *lengthp);
  
  extern smb_packet_t *smb_GetResponsePacket(smb_vc_t *vcp, smb_packet_t *inp);
  
***************
*** 672,678 ****
  
  extern int smb_StoreAnsiFilenames;
  extern int smb_hideDotFiles;
! extern unsigned int smb_IsDotFile(char *lastComp);
  extern afs_uint32 smb_AsyncStore;
  extern afs_uint32 smb_AsyncStoreSize;
  
--- 659,665 ----
  
  extern int smb_StoreAnsiFilenames;
  extern int smb_hideDotFiles;
! extern unsigned int smb_IsDotFile(clientchar_t *lastComp);
  extern afs_uint32 smb_AsyncStore;
  extern afs_uint32 smb_AsyncStoreSize;
  
***************
*** 685,698 ****
  
  extern HANDLE smb_lsaHandle; /* LSA handle obtained during smb_init if using SMB auth */
  extern ULONG smb_lsaSecPackage; /* LSA security package id. Set during smb_init */
! extern char smb_ServerDomainName[];
  extern int smb_ServerDomainNameLength;
! extern char smb_ServerOS[];
  extern int smb_ServerOSLength;
! extern char smb_ServerLanManager[];
  extern int smb_ServerLanManagerLength;
  extern GUID smb_ServerGUID;
  extern LSA_STRING smb_lsaLogonOrigin;
  
  /* used for getting a challenge for SMB auth */
  typedef struct _MSV1_0_LM20_CHALLENGE_REQUEST {  
--- 672,686 ----
  
  extern HANDLE smb_lsaHandle; /* LSA handle obtained during smb_init if using SMB auth */
  extern ULONG smb_lsaSecPackage; /* LSA security package id. Set during smb_init */
! extern clientchar_t smb_ServerDomainName[];
  extern int smb_ServerDomainNameLength;
! extern clientchar_t smb_ServerOS[];
  extern int smb_ServerOSLength;
! extern clientchar_t smb_ServerLanManager[];
  extern int smb_ServerLanManagerLength;
  extern GUID smb_ServerGUID;
  extern LSA_STRING smb_lsaLogonOrigin;
+ extern LONG smb_UseUnicode;
  
  /* used for getting a challenge for SMB auth */
  typedef struct _MSV1_0_LM20_CHALLENGE_REQUEST {  
***************
*** 705,713 ****
  } MSV1_0_LM20_CHALLENGE_RESPONSE, *PMSV1_0_LM20_CHALLENGE_RESPONSE;
  /**/
  
! extern long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength);
  
! extern long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName);
  
  extern void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp,
  	smb_packet_t *op);
--- 693,701 ----
  } MSV1_0_LM20_CHALLENGE_RESPONSE, *PMSV1_0_LM20_CHALLENGE_RESPONSE;
  /**/
  
! extern long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength);
  
! extern long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName);
  
  extern void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp,
  	smb_packet_t *op);
***************
*** 724,756 ****
  
  extern unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp);
  
- extern unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp);
- 
  extern unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp);
  
  extern int smb_SUser(cm_user_t *userp);
  
- #ifndef DJGPP
  long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
  	cm_user_t *userp, long *writtenp);
- #else /* DJGPP */
- long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
- 	cm_user_t *userp, long *writtenp, int dosflag);
- #endif /* !DJGPP */
  
- #ifndef DJGPP
  extern long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count,
  	char *op, cm_user_t *userp, long *readp);
- #else /* DJGPP */
- extern long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count,
- 	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);
  
--- 712,732 ----
  
  extern unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp);
  
  extern unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp);
  
  extern int smb_SUser(cm_user_t *userp);
  
  long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
  	cm_user_t *userp, long *writtenp);
  
  extern long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count,
  	char *op, cm_user_t *userp, long *readp);
  
! extern long smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t *oldPathp, clientchar_t *newPathp, int attrs);
  
! extern long smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t *oldPathp, clientchar_t *newPathp);
  
! extern BOOL smb_IsLegalFilename(clientchar_t *filename);
  
  extern char *smb_GetSharename(void);
  
***************
*** 776,782 ****
  #include "smb_ioctl.h"
  #include "smb_iocons.h"
  
! cm_user_t *smb_FindOrCreateUser(smb_vc_t *vcp, char *usern);
  
  #ifdef NOTSERVICE
  extern void smb_LogPacket(smb_packet_t *packet);
--- 752,762 ----
  #include "smb_ioctl.h"
  #include "smb_iocons.h"
  
! cm_user_t *smb_FindOrCreateUser(smb_vc_t *vcp, clientchar_t *usern);
! 
! int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
! 
! void smb_Shutdown(void);
  
  #ifdef NOTSERVICE
  extern void smb_LogPacket(smb_packet_t *packet);
Index: openafs/src/WINNT/afsd/smb3.c
diff -c openafs/src/WINNT/afsd/smb3.c:1.95.2.58 openafs/src/WINNT/afsd/smb3.c:1.95.2.66
*** openafs/src/WINNT/afsd/smb3.c:1.95.2.58	Sun Mar  9 11:25:02 2008
--- openafs/src/WINNT/afsd/smb3.c	Mon Jul 14 09:38:23 2008
***************
*** 10,16 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #pragma warning(push)
  #pragma warning(disable: 4005)
--- 10,15 ----
***************
*** 19,25 ****
  #include <security.h>
  #include <lmaccess.h>
  #pragma warning(pop)
- #endif /* !DJGPP */
  #include <stdlib.h>
  #include <malloc.h>
  #include <string.h>
--- 18,23 ----
***************
*** 31,36 ****
--- 29,35 ----
  #include <WINNT\afsreg.h>
  
  #include "smb.h"
+ #include <strsafe.h>
  
  extern osi_hyper_t hzero;
  
***************
*** 44,50 ****
  /* protected by the smb_globalLock */
  smb_tran2Packet_t *smb_tran2AssemblyQueuep;
  
! const char **smb_ExecutableExtensions = NULL;
  
  /* retrieve a held reference to a user structure corresponding to an incoming
   * request */
--- 43,49 ----
  /* protected by the smb_globalLock */
  smb_tran2Packet_t *smb_tran2AssemblyQueuep;
  
! const clientchar_t **smb_ExecutableExtensions = NULL;
  
  /* retrieve a held reference to a user structure corresponding to an incoming
   * request */
***************
*** 68,85 ****
   * Return boolean specifying if the path name is thought to be an 
   * executable file.  For now .exe or .dll.
   */
! afs_uint32 smb_IsExecutableFileName(const char *name)
  {
      int i, j, len;
          
      if ( smb_ExecutableExtensions == NULL || name == NULL)
          return 0;
  
!     len = (int)strlen(name);
  
      for ( i=0; smb_ExecutableExtensions[i]; i++) {
!         j = len - (int)strlen(smb_ExecutableExtensions[i]);
!         if (_stricmp(smb_ExecutableExtensions[i], &name[j]) == 0)
              return 1;
      }
  
--- 67,84 ----
   * Return boolean specifying if the path name is thought to be an 
   * executable file.  For now .exe or .dll.
   */
! afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
  {
      int i, j, len;
          
      if ( smb_ExecutableExtensions == NULL || name == NULL)
          return 0;
  
!     len = (int)cm_ClientStrLen(name);
  
      for ( i=0; smb_ExecutableExtensions[i]; i++) {
!         j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
!         if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
              return 1;
      }
  
***************
*** 105,112 ****
  #endif /* SPECIAL_FOLDERS */
      } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
          attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
!     } 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.
--- 104,114 ----
  #endif /* SPECIAL_FOLDERS */
      } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
          attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
!     } else if (scp->fid.vnode & 0x1)
!         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.
***************
*** 125,133 ****
      return attrs;
  }
  
! int smb_V3IsStarMask(char *maskp)
  {
!     char tc;
  
      while (tc = *maskp++)
          if (tc == '?' || tc == '*' || tc == '<' || tc == '>') 
--- 127,135 ----
      return attrs;
  }
  
! int smb_V3IsStarMask(clientchar_t *maskp)
  {
!     clientchar_t tc;
  
      while (tc = *maskp++)
          if (tc == '?' || tc == '*' || tc == '<' || tc == '>') 
***************
*** 135,163 ****
      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;
! }   
! 
! void OutputDebugF(char * format, ...) {
      va_list args;
!     int len;
!     char * buffer;
  
      va_start( args, format );
!     len = _vscprintf( format, args ) // _vscprintf doesn't count
!                                + 3; // terminating '\0' + '\n'
!     buffer = malloc( len * sizeof(char) );
!     vsprintf( buffer, format, args );
!     osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
!     strcat(buffer, "\n");
!     OutputDebugString(buffer);
!     free( buffer );
  }
  
  void OutputDebugHexDump(unsigned char * buffer, int len) {
--- 137,151 ----
      return 0;
  }
  
! void OutputDebugF(clientchar_t * format, ...) {
      va_list args;
!     clientchar_t vbuffer[1024];
  
      va_start( args, format );
!     cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
!     osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
!     cm_ClientStrCat(vbuffer, lengthof(vbuffer), _C("\n"));
!     OutputDebugStringW(vbuffer);
  }
  
  void OutputDebugHexDump(unsigned char * buffer, int len) {
***************
*** 165,180 ****
      char buf[256];
      static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  
!     OutputDebugF("Hexdump length [%d]",len);
  
      for (i=0;i<len;i++) {
          if(!(i%16)) {
              if(i) {
                  osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
!                 strcat(buf,"\r\n");
                  OutputDebugString(buf);
              }
!             sprintf(buf,"%5x",i);
              memset(buf+5,' ',80);
              buf[85] = 0;
          }
--- 153,168 ----
      char buf[256];
      static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  
!     OutputDebugF(_C("Hexdump length [%d]"),len);
  
      for (i=0;i<len;i++) {
          if(!(i%16)) {
              if(i) {
                  osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
!                 StringCchCatA(buf, lengthof(buf), "\r\n");
                  OutputDebugString(buf);
              }
!             StringCchPrintfA(buf, lengthof(buf), "%5x", i);
              memset(buf+5,' ',80);
              buf[85] = 0;
          }
***************
*** 192,198 ****
      }    
      if(i) {
          osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
!         strcat(buf,"\r\n");
          OutputDebugString(buf);
      }   
  }
--- 180,186 ----
      }    
      if(i) {
          osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
!         StringCchCatA(buf, lengthof(buf), "\r\n");
          OutputDebugString(buf);
      }   
  }
***************
*** 211,217 ****
      *secBlob = NULL;
      *secBlobLength = 0;
  
!     OutputDebugF("Negotiating Extended Security");
  
      status = AcquireCredentialsHandle( NULL,
                                         SMB_EXT_SEC_PACKAGE_NAME,
--- 199,205 ----
      *secBlob = NULL;
      *secBlobLength = 0;
  
!     OutputDebugF(_C("Negotiating Extended Security"));
  
      status = AcquireCredentialsHandle( NULL,
                                         SMB_EXT_SEC_PACKAGE_NAME,
***************
*** 225,231 ****
  
      if (status != SEC_E_OK) {
          /* Really bad. We return an empty security blob */
!         OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
          goto nes_0;
      }
  
--- 213,219 ----
  
      if (status != SEC_E_OK) {
          /* Really bad. We return an empty security blob */
!         OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
          goto nes_0;
      }
  
***************
*** 251,260 ****
                                      );
  
      if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
!         OutputDebugF("Completing token...");
          istatus = CompleteAuthToken(&ctx, &secOut);
          if ( istatus != SEC_E_OK )
!             OutputDebugF("Token completion failed: %x", istatus);
      }
  
      if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
--- 239,248 ----
                                      );
  
      if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
!         OutputDebugF(_C("Completing token..."));
          istatus = CompleteAuthToken(&ctx, &secOut);
          if ( istatus != SEC_E_OK )
!             OutputDebugF(_C("Token completion failed: %x"), istatus);
      }
  
      if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
***************
*** 265,271 ****
          }
      } else {
          if ( status != SEC_E_OK )
!             OutputDebugF("AcceptSecurityContext status != CONTINUE  %lX", status);
      }
  
      /* Discard partial security context */
--- 253,259 ----
          }
      } else {
          if ( status != SEC_E_OK )
!             OutputDebugF(_C("AcceptSecurityContext status != CONTINUE  %lX"), status);
      }
  
      /* Discard partial security context */
***************
*** 287,293 ****
      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;
--- 275,283 ----
      void * partialToken;
  };      
  
! long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
!                              char * secBlobIn, int secBlobInLength,
!                              char ** secBlobOut, int * secBlobOutLength) {
      SECURITY_STATUS status, istatus;
      CredHandle creds;
      TimeStamp expiry;
***************
*** 303,309 ****
      int assembledBlobLength = 0;
      ULONG flags;
  
!     OutputDebugF("In smb_AuthenticateUserExt");
  
      *secBlobOut = NULL;
      *secBlobOutLength = 0;
--- 293,299 ----
      int assembledBlobLength = 0;
      ULONG flags;
  
!     OutputDebugF(_C("In smb_AuthenticateUserExt"));
  
      *secBlobOut = NULL;
      *secBlobOutLength = 0;
***************
*** 317,328 ****
      }
  
      if (secBlobIn) {
!         OutputDebugF("Received incoming token:");
          OutputDebugHexDump(secBlobIn,secBlobInLength);
      }
      
      if (secCtx) {
!         OutputDebugF("Continuing with existing context.");		
          creds = secCtx->creds;
          ctx = secCtx->ctx;
  
--- 307,318 ----
      }
  
      if (secBlobIn) {
!         OutputDebugF(_C("Received incoming token:"));
          OutputDebugHexDump(secBlobIn,secBlobInLength);
      }
      
      if (secCtx) {
!         OutputDebugF(_C("Continuing with existing context."));		
          creds = secCtx->creds;
          ctx = secCtx->ctx;
  
***************
*** 344,350 ****
                                             &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;
          }
--- 334,340 ----
                                             &expiry);
  
          if (status != SEC_E_OK) {
!             OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
              code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
              goto aue_0;
          }
***************
*** 386,399 ****
                                      );
  
      if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
!         OutputDebugF("Completing token...");
          istatus = CompleteAuthToken(&ctx, &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));
  
--- 376,389 ----
                                      );
  
      if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
!         OutputDebugF(_C("Completing token..."));
          istatus = CompleteAuthToken(&ctx, &secBufOut);
          if ( istatus != SEC_E_OK )
!             OutputDebugF(_C("Token completion failed: %lX"), istatus);
      }
  
      if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
!         OutputDebugF(_C("Continue needed"));
  
          newSecCtx = malloc(sizeof(*newSecCtx));
  
***************
*** 413,428 ****
      if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
            status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) && 
           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));
  
--- 403,418 ----
      if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
            status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) && 
           secTokOut.pvBuffer) {
!         OutputDebugF(_C("Need to send token back to client"));
  
          *secBlobOutLength = secTokOut.cbBuffer;
          *secBlobOut = malloc(secTokOut.cbBuffer);
          memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
  
!         OutputDebugF(_C("Outgoing token:"));
          OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
      } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
!         OutputDebugF(_C("Incomplete message"));
  
          newSecCtx = malloc(sizeof(*newSecCtx));
  
***************
*** 442,493 ****
  
      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(&ctx, SECPKG_ATTR_NAMES, &names)) {
!             OutputDebugF("Received name [%s]", names.sUserName);
!             strcpy(usern, names.sUserName);
!             strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
              FreeContextBuffer(names.sUserName);
          } else {
              /* Force the user to retry if the context is invalid */
!             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");
              break;
          case SEC_E_INVALID_HANDLE:
!             OutputDebugF("Returning bad password :: INVALID_HANDLE");
              break;
          case SEC_E_LOGON_DENIED:
!             OutputDebugF("Returning bad password :: LOGON_DENIED");
              break;
          case SEC_E_UNKNOWN_CREDENTIALS:
!             OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
              break;
          case SEC_E_NO_CREDENTIALS:
!             OutputDebugF("Returning bad password :: NO_CREDENTIALS");
              break;
          case SEC_E_CONTEXT_EXPIRED:
!             OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
              break;
          case SEC_E_INCOMPLETE_CREDENTIALS:
!             OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
              break;
          case SEC_E_WRONG_PRINCIPAL:
!             OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
              break;
          case SEC_E_TIME_SKEW:
!             OutputDebugF("Returning bad password :: TIME_SKEW");
              break;
          default:
!             OutputDebugF("Returning bad password :: Status == %lX", status);
          }
          code = CM_ERROR_BADPASSWORD;
      }
--- 432,483 ----
  
      if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
          /* woo hoo! */
!         SecPkgContext_NamesW names;
  
!         OutputDebugF(_C("Authentication completed"));
!         OutputDebugF(_C("Returned flags : [%lX]"), flags);
  
!         if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
!             OutputDebugF(_C("Received name [%s]"), names.sUserName);
!             cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
!             cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
              FreeContextBuffer(names.sUserName);
          } else {
              /* Force the user to retry if the context is invalid */
!             OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
              code = CM_ERROR_BADPASSWORD; 
          }
      } else if (!code) {
          switch ( status ) {
          case SEC_E_INVALID_TOKEN:
!             OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
              break;
          case SEC_E_INVALID_HANDLE:
!             OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
              break;
          case SEC_E_LOGON_DENIED:
!             OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
              break;
          case SEC_E_UNKNOWN_CREDENTIALS:
!             OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
              break;
          case SEC_E_NO_CREDENTIALS:
!             OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
              break;
          case SEC_E_CONTEXT_EXPIRED:
!             OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
              break;
          case SEC_E_INCOMPLETE_CREDENTIALS:
!             OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
              break;
          case SEC_E_WRONG_PRINCIPAL:
!             OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
              break;
          case SEC_E_TIME_SKEW:
!             OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
              break;
          default:
!             OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
          }
          code = CM_ERROR_BADPASSWORD;
      }
***************
*** 529,535 ****
      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;
--- 519,525 ----
      TOKEN_SOURCE tsource;
  };
  
! long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) 
  {
      NTSTATUS nts, ntsEx;
      struct Lm20AuthBlob lmAuth;
***************
*** 540,550 ****
      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 > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
!         OutputDebugF("ciPwdLength or csPwdLength is too long");
          return CM_ERROR_BADPASSWORD;
      }
  
--- 530,540 ----
      LUID lmSession;
      HANDLE lmToken;
  
!     OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
!     OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
  
      if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
!         OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
          return CM_ERROR_BADPASSWORD;
      }
  
***************
*** 553,564 ****
      lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
  	
      lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
!     mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
      lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(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 = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
      lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
  
--- 543,554 ----
      lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
  	
      lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
!     cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
      lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
      lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
  
      lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
!     cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
      lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
      lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
  
***************
*** 586,594 ****
      lmAuth.tgroups.Groups[0].Sid = NULL;
      lmAuth.tgroups.Groups[0].Attributes = 0;
  
      lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
      lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
!     strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
  
      nts = LsaLogonUser( smb_lsaHandle,
                          &smb_lsaLogonOrigin,
--- 576,589 ----
      lmAuth.tgroups.Groups[0].Sid = NULL;
      lmAuth.tgroups.Groups[0].Attributes = 0;
  
+ #ifdef _WIN64
      lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
+ #else
+     lmAuth.tsource.SourceIdentifier.HighPart = 0;
+ #endif
      lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
!     StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
!                    "OpenAFS"); /* 8 char limit */
  
      nts = LsaLogonUser( smb_lsaHandle,
                          &smb_lsaLogonOrigin,
***************
*** 609,616 ****
          osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
                    nts, ntsEx);
  
!     OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
!     OutputDebugF("Extended status is 0x%lX", ntsEx);
  
      if (nts == ERROR_SUCCESS) {
          /* free the token */
--- 604,611 ----
          osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
                    nts, ntsEx);
  
!     OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
!     OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
  
      if (nts == ERROR_SUCCESS) {
          /* free the token */
***************
*** 627,639 ****
  }
  
  /* 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) > SMB_MAX_USERNAME_LENGTH)
          return 1;
  
      /* we could get : [accountName][domainName]
--- 622,634 ----
  }
  
  /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
! long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName) 
  {
!     clientchar_t * atsign;
!     const clientchar_t * domain;
  
      /* check if we have sane input */
!     if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
          return 1;
  
      /* we could get : [accountName][domainName]
***************
*** 642,648 ****
         [user][]/[user][?]
         [][]/[][?] */
  
!     atsign = strchr(accountName, '@');
  
      if (atsign) /* [user@domain][] -> [user@domain][domain] */
          domain = atsign + 1;
--- 637,643 ----
         [user][]/[user][?]
         [][]/[][?] */
  
!     atsign = cm_ClientStrChr(accountName, '@');
  
      if (atsign) /* [user@domain][] -> [user@domain][domain] */
          domain = atsign + 1;
***************
*** 655,672 ****
          /* 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;
  }
--- 650,667 ----
          /* 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* */
!         cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
      else {
          /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
!         cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
!         cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
          if (atsign)
!             cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
          else
!             cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
!     }
  
!     cm_ClientStrLwr(usern);
  
      return 0;
  }
***************
*** 678,683 ****
--- 673,679 ----
   * sending a session setup packet, which means that we can't rely on a
   * UID in subsequent packets.  Though in practice we get one anyway.
   */
+ /* SMB_COM_SESSION_SETUP_ANDX */
  long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      char *tp;
***************
*** 685,693 ****
      unsigned short newUid;
      unsigned long caps = 0;
      smb_username_t *unp;
!     char *s1 = " ";
      long code = 0; 
!     char usern[SMB_MAX_USERNAME_LENGTH];
      char *secBlobOut = NULL;
      int  secBlobOutLength = 0;
  
--- 681,689 ----
      unsigned short newUid;
      unsigned long caps = 0;
      smb_username_t *unp;
!     clientchar_t *s1 = _C(" ");
      long code = 0; 
!     clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
      char *secBlobOut = NULL;
      int  secBlobOutLength = 0;
  
***************
*** 701,707 ****
              char *secBlobIn;
              int secBlobInLength;
  
!             OutputDebugF("NT Session Setup: Extended");
          
              if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
                  caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
--- 697,703 ----
              char *secBlobIn;
              int secBlobInLength;
  
!             OutputDebugF(_C("NT Session Setup: Extended"));
          
              if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
                  caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
***************
*** 713,747 ****
              code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
  
              if (code == CM_ERROR_GSSCONTINUE) {
                  smb_SetSMBParm(outp, 2, 0);
                  smb_SetSMBParm(outp, 3, secBlobOutLength);
!                 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
                  tp = smb_GetSMBData(outp, NULL);
                  if (secBlobOutLength) {
                      memcpy(tp, secBlobOut, secBlobOutLength);
                      free(secBlobOut);
                      tp += secBlobOutLength;
                  }	
!                 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
!                 tp += smb_ServerOSLength;
!                 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
!                 tp += smb_ServerLanManagerLength;
!                 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
!                 tp += smb_ServerDomainNameLength;
              }
  
              /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
          } else {
              unsigned ciPwdLength, csPwdLength;
              char *ciPwd, *csPwd;
!             char *accountName;
!             char *primaryDomain;
              int  datalen;
  
              if (smb_authType == SMB_AUTH_NTLM)
!                 OutputDebugF("NT Session Setup: NTLM");
              else
!                 OutputDebugF("NT Session Setup: None");
  
              /* TODO: parse for extended auth as well */
              ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
--- 709,745 ----
              code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
  
              if (code == CM_ERROR_GSSCONTINUE) {
+                 size_t cb_data = 0;
+ 
                  smb_SetSMBParm(outp, 2, 0);
                  smb_SetSMBParm(outp, 3, secBlobOutLength);
! 
                  tp = smb_GetSMBData(outp, NULL);
                  if (secBlobOutLength) {
                      memcpy(tp, secBlobOut, secBlobOutLength);
                      free(secBlobOut);
                      tp += secBlobOutLength;
+                     cb_data += secBlobOutLength;
                  }	
!                 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
!                 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
!                 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
! 
!                 smb_SetSMBDataLength(outp, cb_data);
              }
  
              /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
          } else {
              unsigned ciPwdLength, csPwdLength;
              char *ciPwd, *csPwd;
!             clientchar_t *accountName;
!             clientchar_t *primaryDomain;
              int  datalen;
  
              if (smb_authType == SMB_AUTH_NTLM)
!                 OutputDebugF(_C("NT Session Setup: NTLM"));
              else
!                 OutputDebugF(_C("NT Session Setup: None"));
  
              /* TODO: parse for extended auth as well */
              ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
***************
*** 749,768 ****
  
              tp = smb_GetSMBData(inp, &datalen);
  
!             OutputDebugF("Session packet data size [%d]",datalen);
  
              ciPwd = tp;
              tp += ciPwdLength;
              csPwd = tp;
              tp += csPwdLength;
  
!             accountName = smb_ParseString(tp, &tp);
!             primaryDomain = smb_ParseString(tp, NULL);
  
!             OutputDebugF("Account Name: %s",accountName);
!             OutputDebugF("Primary Domain: %s", primaryDomain);
!             OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
!             OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
  
              if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
                  /* shouldn't happen */
--- 747,768 ----
  
              tp = smb_GetSMBData(inp, &datalen);
  
!             OutputDebugF(_C("Session packet data size [%d]"),datalen);
  
              ciPwd = tp;
              tp += ciPwdLength;
              csPwd = tp;
              tp += csPwdLength;
  
!             accountName = smb_ParseString(inp, tp, &tp, 0);
!             primaryDomain = smb_ParseString(inp, tp, NULL, 0);
  
!             OutputDebugF(_C("Account Name: %s"),accountName);
!             OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
!             OutputDebugF(_C("Case Sensitive Password: %s"),
!                          csPwd && csPwd[0] ? _C("yes") : _C("no"));
!             OutputDebugF(_C("Case Insensitive Password: %s"),
!                          ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
  
              if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
                  /* shouldn't happen */
***************
*** 778,815 ****
              if (smb_authType == SMB_AUTH_NTLM) {
                  code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
                  if ( code )
!                     OutputDebugF("LM authentication failed [%d]", code);
                  else
!                     OutputDebugF("LM authentication succeeded");
              }
          }
      }  else { /* V3 */
          unsigned ciPwdLength;
          char *ciPwd;
!         char *accountName;
!         char *primaryDomain;
  
          switch ( smb_authType ) {
          case SMB_AUTH_EXTENDED:
!             OutputDebugF("V3 Session Setup: Extended");
              break;
          case SMB_AUTH_NTLM:
!             OutputDebugF("V3 Session Setup: NTLM");
              break;
          default:
!             OutputDebugF("V3 Session Setup: None");
          }
          ciPwdLength = smb_GetSMBParm(inp, 7);
          tp = smb_GetSMBData(inp, NULL);
          ciPwd = tp;
          tp += ciPwdLength;
  
!         accountName = smb_ParseString(tp, &tp);
!         primaryDomain = smb_ParseString(tp, NULL);
  
!         OutputDebugF("Account Name: %s",accountName);
!         OutputDebugF("Primary Domain: %s", primaryDomain);
!         OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
  
          if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
              /* shouldn't happen */
--- 778,815 ----
              if (smb_authType == SMB_AUTH_NTLM) {
                  code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
                  if ( code )
!                     OutputDebugF(_C("LM authentication failed [%d]"), code);
                  else
!                     OutputDebugF(_C("LM authentication succeeded"));
              }
          }
      }  else { /* V3 */
          unsigned ciPwdLength;
          char *ciPwd;
!         clientchar_t *accountName;
!         clientchar_t *primaryDomain;
  
          switch ( smb_authType ) {
          case SMB_AUTH_EXTENDED:
!             OutputDebugF(_C("V3 Session Setup: Extended"));
              break;
          case SMB_AUTH_NTLM:
!             OutputDebugF(_C("V3 Session Setup: NTLM"));
              break;
          default:
!             OutputDebugF(_C("V3 Session Setup: None"));
          }
          ciPwdLength = smb_GetSMBParm(inp, 7);
          tp = smb_GetSMBData(inp, NULL);
          ciPwd = tp;
          tp += ciPwdLength;
  
!         accountName = smb_ParseString(inp, tp, &tp, 0);
!         primaryDomain = smb_ParseString(inp, tp, NULL, 0);
  
!         OutputDebugF(_C("Account Name: %s"),accountName);
!         OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
!         OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
  
          if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
              /* shouldn't happen */
***************
*** 823,831 ****
          if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
              code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
              if ( code )
!                 OutputDebugF("LM authentication failed [%d]", code);
              else
!                 OutputDebugF("LM authentication succeeded");
          }
      }
  
--- 823,831 ----
          if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
              code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
              if ( code )
!                 OutputDebugF(_C("LM authentication failed [%d]"), code);
              else
!                 OutputDebugF(_C("LM authentication succeeded"));
          }
      }
  
***************
*** 838,843 ****
--- 838,849 ----
          if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
              vcp->flags |= SMB_VCFLAG_STATUS32;
          }       
+ 
+ #ifdef SMB_UNICODE
+         if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
+             vcp->flags |= SMB_VCFLAG_USEUNICODE;
+         }
+ #endif
          lock_ReleaseMutex(&vcp->mx);
      }
  
***************
*** 849,855 ****
          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
--- 855,861 ----
          return code;
      }
  
!     OutputDebugF(_C("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
***************
*** 890,896 ****
  	lock_ObtainMutex(&vcp->mx);
          if (!vcp->uidCounter)
              vcp->uidCounter++; /* handle unlikely wraparounds */
!         newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
          lock_ReleaseMutex(&vcp->mx);
  
          /* Create a new smb_user_t structure and connect them up */
--- 896,902 ----
  	lock_ObtainMutex(&vcp->mx);
          if (!vcp->uidCounter)
              vcp->uidCounter++; /* handle unlikely wraparounds */
!         newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
          lock_ReleaseMutex(&vcp->mx);
  
          /* Create a new smb_user_t structure and connect them up */
***************
*** 913,952 ****
      /* Also to the next chained message */
      ((smb_t *)inp)->uid = newUid;
  
!     osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
!              osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
  
      smb_SetSMBParm(outp, 2, 0);
  
      if (vcp->flags & SMB_VCFLAG_USENT) {
          if (smb_authType == SMB_AUTH_EXTENDED) {
              smb_SetSMBParm(outp, 3, secBlobOutLength);
!             smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
              tp = smb_GetSMBData(outp, NULL);
              if (secBlobOutLength) {
                  memcpy(tp, secBlobOut, secBlobOutLength);
                  free(secBlobOut);
                  tp += secBlobOutLength;
              }	
!             memcpy(tp,smb_ServerOS,smb_ServerOSLength);
!             tp += smb_ServerOSLength;
!             memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
!             tp += smb_ServerLanManagerLength;
!             memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
!             tp += smb_ServerDomainNameLength;
          } else {
              smb_SetSMBDataLength(outp, 0);
          }
      } else {
          if (smb_authType == SMB_AUTH_EXTENDED) {
!             smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
              tp = smb_GetSMBData(outp, NULL);
!             memcpy(tp,smb_ServerOS,smb_ServerOSLength);
!             tp += smb_ServerOSLength;
!             memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
!             tp += smb_ServerLanManagerLength;
!             memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
!             tp += smb_ServerDomainNameLength;
          } else {
              smb_SetSMBDataLength(outp, 0);
          }
--- 919,963 ----
      /* Also to the next chained message */
      ((smb_t *)inp)->uid = newUid;
  
!     osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
!              osi_LogSaveClientString(smb_logp, usern), newUid,
!              osi_LogSaveClientString(smb_logp, s1));
  
      smb_SetSMBParm(outp, 2, 0);
  
      if (vcp->flags & SMB_VCFLAG_USENT) {
          if (smb_authType == SMB_AUTH_EXTENDED) {
+             size_t cb_data = 0;
+ 
              smb_SetSMBParm(outp, 3, secBlobOutLength);
! 
              tp = smb_GetSMBData(outp, NULL);
              if (secBlobOutLength) {
                  memcpy(tp, secBlobOut, secBlobOutLength);
                  free(secBlobOut);
                  tp += secBlobOutLength;
+                 cb_data +=  secBlobOutLength;
              }	
! 
!             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
!             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
!             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
! 
!             smb_SetSMBDataLength(outp, cb_data);
          } else {
              smb_SetSMBDataLength(outp, 0);
          }
      } else {
          if (smb_authType == SMB_AUTH_EXTENDED) {
!             size_t cb_data = 0;
! 
              tp = smb_GetSMBData(outp, NULL);
! 
!             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
!             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
!             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
! 
!             smb_SetSMBDataLength(outp, cb_data);
          } else {
              smb_SetSMBDataLength(outp, 0);
          }
***************
*** 955,960 ****
--- 966,972 ----
      return 0;
  }
  
+ /* SMB_COM_LOGOFF_ANDX */
  long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_user_t *uidp;
***************
*** 964,971 ****
      if (uidp) {
  	smb_username_t * unp;
  
!         osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
!                   osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
  
          lock_ObtainMutex(&uidp->mx);
          uidp->flags |= SMB_USERFLAG_DELETE;
--- 976,983 ----
      if (uidp) {
  	smb_username_t * unp;
  
!         osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
!                  osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
  
          lock_ObtainMutex(&uidp->mx);
          uidp->flags |= SMB_USERFLAG_DELETE;
***************
*** 1002,1019 ****
  #define SMB_SUPPORT_SEARCH_BITS        0x0001
  #define SMB_SHARE_IS_IN_DFS            0x0002
  
  long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_tid_t *tidp;
      smb_user_t *uidp = NULL;
      unsigned short newTid;
!     char shareName[AFSPATHMAX];
!     char *sharePath;
      int shareFound;
      char *tp;
!     char *pathp;
!     char *passwordp;
!     char *servicep;
      cm_user_t *userp = NULL;
      int ipc = 0;
          
--- 1014,1033 ----
  #define SMB_SUPPORT_SEARCH_BITS        0x0001
  #define SMB_SHARE_IS_IN_DFS            0x0002
  
+ /* SMB_COM_TREE_CONNECT_ANDX */
  long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_tid_t *tidp;
      smb_user_t *uidp = NULL;
      unsigned short newTid;
!     clientchar_t shareName[AFSPATHMAX];
!     clientchar_t *sharePath;
      int shareFound;
      char *tp;
!     clientchar_t *slashp;
!     clientchar_t *pathp;
!     clientchar_t *passwordp;
!     clientchar_t *servicep;
      cm_user_t *userp = NULL;
      int ipc = 0;
          
***************
*** 1021,1043 ****
  
      /* parse input parameters */
      tp = smb_GetSMBData(inp, NULL);
!     passwordp = smb_ParseString(tp, &tp);
!     pathp = smb_ParseString(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
!     servicep = smb_ParseString(tp, &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;
--- 1035,1057 ----
  
      /* parse input parameters */
      tp = smb_GetSMBData(inp, NULL);
!     passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
!     pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
!     servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
  
!     slashp = cm_ClientStrRChr(pathp, '\\');
!     if (!slashp) {
          return CM_ERROR_BADSMB;
      }
!     cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
  
!     osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
!              osi_LogSaveClientString(smb_logp, pathp),
!              osi_LogSaveClientString(smb_logp, shareName),
!              osi_LogSaveClientString(smb_logp, servicep));
  
!     if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
!         cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
  #ifndef NO_IPC
          osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
          ipc = 1;
***************
*** 1057,1064 ****
      tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
  
      if (!ipc) {
! 	if (!strcmp(shareName, "*."))
! 	    strcpy(shareName, "all");
  	shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
  	if (!shareFound) {
  	    if (uidp)
--- 1071,1078 ----
      tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
  
      if (!ipc) {
! 	if (!cm_ClientStrCmp(shareName, _C("*.")))
! 	    cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
  	shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
  	if (!shareFound) {
  	    if (uidp)
***************
*** 1085,1091 ****
              }
              smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | 
                             (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
!                             (policy << 2));
          }
      } else {
          smb_SetSMBParm(outp, 2, 0);
--- 1099,1105 ----
              }
              smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | 
                             (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
!                            (policy << 2));
          }
      } else {
          smb_SetSMBParm(outp, 2, 0);
***************
*** 1106,1123 ****
      ((smb_t *)inp)->tid = newTid;
      tp = smb_GetSMBData(outp, NULL);
      if (!ipc) {
!         /* XXX - why is this a drive letter? */
!         *tp++ = 'A';
!         *tp++ = ':';
!         *tp++ = 0;
!         *tp++ = 'A';
!         *tp++ = 'F';
!         *tp++ = 'S';
!         *tp++ = 0;
!         smb_SetSMBDataLength(outp, 7);
      } else {
!         strcpy(tp, "IPC");
!         smb_SetSMBDataLength(outp, 4);
      }
  
      osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
--- 1120,1135 ----
      ((smb_t *)inp)->tid = newTid;
      tp = smb_GetSMBData(outp, NULL);
      if (!ipc) {
!         size_t cb_data = 0;
! 
!         tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
!         tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
!         smb_SetSMBDataLength(outp, cb_data);
      } else {
!         size_t cb_data = 0;
! 
!         tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
!         smb_SetSMBDataLength(outp, cb_data);
      }
  
      osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
***************
*** 1139,1145 ****
  }
  
  smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
! 	int totalParms, int totalData)
  {
      smb_tran2Packet_t *tp;
      smb_t *smbp;
--- 1151,1157 ----
  }
  
  smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
!                                       int totalParms, int totalData)
  {
      smb_tran2Packet_t *tp;
      smb_t *smbp;
***************
*** 1169,1186 ****
          tp->com = 0x32;
      }
      tp->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));
      smb_HoldVC(vcp);
--- 1181,1202 ----
          tp->com = 0x32;
      }
      tp->flags |= SMB_TRAN2PFLAG_ALLOC;
+ #ifdef SMB_UNICODE
+     if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
+         tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
+ #endif
      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));
      smb_HoldVC(vcp);
***************
*** 1228,1241 ****
          if (t2p->datap)
              free(t2p->datap);
      }       
      free(t2p);
  }
  
  /* called with a VC, an input packet to respond to, and an error code.
   * sends an error response.
   */
  void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
! 	smb_packet_t *tp, long code)
  {
      smb_t *smbp;
      unsigned short errCode;
--- 1244,1287 ----
          if (t2p->datap)
              free(t2p->datap);
      }       
+     while (t2p->stringsp) {
+         cm_space_t * ns;
+ 
+         ns = t2p->stringsp;
+         t2p->stringsp = ns->nextp;
+         cm_FreeSpace(ns);
+     }
      free(t2p);
  }
  
+ clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
+                                     char ** chainpp, int flags)
+ {
+     size_t cb;
+ 
+ #ifdef SMB_UNICODE
+     if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
+         flags |= SMB_STRF_FORCEASCII;
+ #endif
+ 
+     cb = p->totalParms - (inp - (char *)p->parmsp);
+     if (inp < (char *) p->parmsp ||
+         inp >= ((char *) p->parmsp) + p->totalParms) {
+ #ifdef DEBUG_UNICODE
+         DebugBreak();
+ #endif
+         cb = p->totalParms;
+     }
+ 
+     return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
+                               inp, &cb, chainpp, flags);
+ }
+ 
  /* called with a VC, an input packet to respond to, and an error code.
   * sends an error response.
   */
  void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
!                         smb_packet_t *tp, long code)
  {
      smb_t *smbp;
      unsigned short errCode;
***************
*** 1333,1338 ****
--- 1379,1386 ----
      smb_SendPacket(vcp, tp);
  }   
  
+ 
+ /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
  long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_tran2Packet_t *asp;
***************
*** 1351,1359 ****
      /* We sometimes see 0 word count.  What to do? */
      if (*inp->wctp == 0) {
          osi_Log0(smb_logp, "Transaction2 word count = 0"); 
- #ifndef DJGPP
  	LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
- #endif /* !DJGPP */
  
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
--- 1399,1405 ----
***************
*** 1457,1487 ****
      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
--- 1503,1534 ----
      return 0;
  }
  
! /* ANSI versions. */
! 
! #pragma pack(push, 1)
  
  typedef struct smb_rap_share_info_0 {
!     BYTE                shi0_netname[13];
  } smb_rap_share_info_0_t;
  
  typedef struct smb_rap_share_info_1 {
!     BYTE                shi1_netname[13];
!     BYTE                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 {
!     BYTE		shi2_netname[13];
!     BYTE		shi2_pad;
!     WORD        	shi2_type;
      DWORD			shi2_remark; /* char *shi2_remark; data offset */
!     WORD        	shi2_permissions;
!     WORD        	shi2_max_uses;
!     WORD        	shi2_current_uses;
      DWORD			shi2_path;  /* char *shi2_path; data offset */
!     WORD        	shi2_passwd[9];
!     WORD        	shi2_pad2;
  } smb_rap_share_info_2_t;
  
  #define SMB_RAP_MAX_SHARES 512
***************
*** 1492,1509 ****
      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->name;
! 
!     if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
          return 0; /* skip over '.' and '..' */
  
      sp = (smb_rap_share_list_t *) vrockp;
  
!     strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
      sp->shares[sp->cShare].shi0_netname[12] = 0;
  
      sp->cShare++;
--- 1539,1555 ----
      smb_rap_share_info_0_t * shares;
  } smb_rap_share_list_t;
  
+ #pragma pack(pop)
+ 
  int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
      smb_rap_share_list_t * sp;
  
!     if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
          return 0; /* skip over '.' and '..' */
  
      sp = (smb_rap_share_list_t *) vrockp;
  
!     strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
      sp->shares[sp->cShare].shi0_netname[12] = 0;
  
      sp->cShare++;
***************
*** 1514,1519 ****
--- 1560,1566 ----
          return 0;
  }       
  
+ /* RAP NetShareEnumRequest */
  long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
      smb_tran2Packet_t *outp;
***************
*** 1534,1540 ****
      smb_rap_share_info_1_t * shares;
      USHORT cshare = 0;
      char * cstrp;
!     char thisShare[AFSPATHMAX];
      int i,j;
      DWORD dw;
      int nonrootShares;
--- 1581,1587 ----
      smb_rap_share_info_1_t * shares;
      USHORT cshare = 0;
      char * cstrp;
!     clientchar_t thisShare[AFSPATHMAX];
      int i,j;
      DWORD dw;
      int nonrootShares;
***************
*** 1544,1551 ****
      osi_hyper_t thyper;
  
      tp = p->parmsp + 1; /* skip over function number (always 0) */
!     (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
!     (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
      infoLevel = tp[0];
      bufsize = tp[1];
  
--- 1591,1608 ----
      osi_hyper_t thyper;
  
      tp = p->parmsp + 1; /* skip over function number (always 0) */
! 
!     {
!         clientchar_t * cdescp;
! 
!         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
!         if (cm_ClientStrCmp(cdescp,  _C("WrLeh")))
!             return CM_ERROR_INVAL;
!         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
!         if (cm_ClientStrCmp(cdescp,  _C("B13BWz")))
!             return CM_ERROR_INVAL;
!     }
! 
      infoLevel = tp[0];
      bufsize = tp[1];
  
***************
*** 1553,1558 ****
--- 1610,1627 ----
          return CM_ERROR_INVAL;
      }
  
+     /* We are supposed to use the same ASCII data structure even if
+        Unicode is negotiated, which ultimately means that the share
+        names that we return must be at most 13 characters in length,
+        including the NULL terminator.
+ 
+        The RAP specification states that shares with names longer than
+        12 characters should not be included in the enumeration.
+        However, since we support prefix cell references and since many
+        cell names are going to exceed 12 characters, we lie and send
+        the first 12 characters.
+     */
+ 
      /* first figure out how many shares there are */
      rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                        KEY_QUERY_VALUE, &hkParam);
***************
*** 1617,1623 ****
      memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
  
      if (allSubmount) {
!         strcpy( shares[cshare].shi1_netname, "all" );
          shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
          /* type and pad are zero already */
          cshare++;
--- 1686,1693 ----
      memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
  
      if (allSubmount) {
!         StringCchCopyA(shares[cshare].shi1_netname,
!                        lengthof(shares[cshare].shi1_netname), "all" );
          shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
          /* type and pad are zero already */
          cshare++;
***************
*** 1627,1635 ****
      if (hkSubmount) {
          for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
              len = sizeof(thisShare);
!             rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
!             if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
!                 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
                  shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
                  shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
                  cshare++;
--- 1697,1708 ----
      if (hkSubmount) {
          for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
              len = sizeof(thisShare);
!             rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
!             if (rv == ERROR_SUCCESS &&
!                 cm_ClientStrLen(thisShare) &&
!                 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
!                 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
!                                       lengthof( shares[cshare].shi1_netname ));
                  shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
                  shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
                  cshare++;
***************
*** 1645,1653 ****
      nonrootShares = cshare;
  
      for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
!         /* in case there are collisions with submounts, submounts have higher priority */		
          for (j=0; j < nonrootShares; j++)
!             if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
                  break;
  		
          if (j < nonrootShares) {
--- 1718,1727 ----
      nonrootShares = cshare;
  
      for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
!         /* in case there are collisions with submounts, submounts have
!            higher priority */		
          for (j=0; j < nonrootShares; j++)
!             if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
                  break;
  		
          if (j < nonrootShares) {
***************
*** 1655,1661 ****
              continue;
          }
  
!         strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
          shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
          cshare++;
          cstrp+=REMARK_LEN;
--- 1729,1736 ----
              continue;
          }
  
!         StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
!                        rootShares.shares[i].shi0_netname);
          shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
          cshare++;
          cstrp+=REMARK_LEN;
***************
*** 1677,1687 ****
      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;
--- 1752,1763 ----
      return code;
  }
  
+ /* RAP NetShareGetInfo */
  long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
      smb_tran2Packet_t *outp;
      unsigned short * tp;
!     clientchar_t * shareName;
      BOOL shareFound = FALSE;
      unsigned short infoLevel;
      unsigned short bufsize;
***************
*** 1700,1708 ****
      cm_InitReq(&req);
  
      tp = p->parmsp + 1; /* skip over function number (always 1) */
!     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
!     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
!     shareName = smb_ParseString( (char *) tp, (char **) &tp);
      infoLevel = *tp++;
      bufsize = *tp++;
      
--- 1776,1799 ----
      cm_InitReq(&req);
  
      tp = p->parmsp + 1; /* skip over function number (always 1) */
! 
!     {
!         clientchar_t * cdescp;
! 
!         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
!         if (cm_ClientStrCmp(cdescp,  _C("zWrLh")))
! 
!             return CM_ERROR_INVAL;
! 
!         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
!         if (cm_ClientStrCmp(cdescp,  _C("B13")) &&
!             cm_ClientStrCmp(cdescp,  _C("B13BWz")) &&
!             cm_ClientStrCmp(cdescp,  _C("B13BWzWWWzB9B")))
! 
!             return CM_ERROR_INVAL;
!     }
!     shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
! 
      infoLevel = *tp++;
      bufsize = *tp++;
      
***************
*** 1717,1723 ****
      else
          return CM_ERROR_INVAL;
  
!     if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
          rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                            KEY_QUERY_VALUE, &hkParam);
          if (rv == ERROR_SUCCESS) {
--- 1808,1814 ----
      else
          return CM_ERROR_INVAL;
  
!     if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
          rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                            KEY_QUERY_VALUE, &hkParam);
          if (rv == ERROR_SUCCESS) {
***************
*** 1749,1755 ****
              rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
                                KEY_QUERY_VALUE, &hkSubmount);
              if (rv == ERROR_SUCCESS) {
!                 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
                  if (rv == ERROR_SUCCESS) {
                      shareFound = TRUE;
                  }
--- 1840,1846 ----
              rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
                                KEY_QUERY_VALUE, &hkSubmount);
              if (rv == ERROR_SUCCESS) {
!                 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
                  if (rv == ERROR_SUCCESS) {
                      shareFound = TRUE;
                  }
***************
*** 1770,1787 ****
  
      if (infoLevel == 0) {
          smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
!         strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
!         info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
      } else if(infoLevel == SMB_INFO_STANDARD) {
          smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
!         strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
          info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
          info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
          /* type and pad are already zero */
      } else { /* infoLevel==2 */
          smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
!         strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
!         info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
          info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
          info->shi2_permissions = ACCESS_ALL;
          info->shi2_max_uses = (unsigned short) -1;
--- 1861,1877 ----
  
      if (infoLevel == 0) {
          smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
!         cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
!                               lengthof(info->shi0_netname));
      } else if(infoLevel == SMB_INFO_STANDARD) {
          smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
!         cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
          info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
          info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
          /* type and pad are already zero */
      } else { /* infoLevel==2 */
          smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
!         cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
          info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
          info->shi2_permissions = ACCESS_ALL;
          info->shi2_max_uses = (unsigned short) -1;
***************
*** 1797,1812 ****
      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)
  {
--- 1887,1905 ----
      return code;
  }
  
+ #pragma pack(push, 1)
+ 
  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;*/
!     BYTE  	wki10_ver_major;
!     BYTE	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;
  
+ #pragma pack(pop)
  
  long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
***************
*** 1822,1829 ****
      smb_user_t *uidp;
  
      tp = p->parmsp + 1; /* Skip over function number */
!     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
!     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
      infoLevel = *tp++;
      bufsize = *tp++;
  
--- 1915,1935 ----
      smb_user_t *uidp;
  
      tp = p->parmsp + 1; /* Skip over function number */
! 
!     {
!         clientchar_t * cdescp;
! 
!         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
!                                        SMB_STRF_FORCEASCII);
!         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
!             return CM_ERROR_INVAL;
! 
!         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
!                                        SMB_STRF_FORCEASCII);
!         if (cm_ClientStrCmp(cdescp,  _C("zzzBBzz")))
!             return CM_ERROR_INVAL;
!     }
! 
      infoLevel = *tp++;
      bufsize = *tp++;
  
***************
*** 1850,1856 ****
      cstrp = (char *) (info + 1);
  
      info->wki10_computername = (DWORD) (cstrp - outp->datap);
!     strcpy(cstrp, smb_localNamep);
      cstrp += strlen(cstrp) + 1;
  
      info->wki10_username = (DWORD) (cstrp - outp->datap);
--- 1956,1962 ----
      cstrp = (char *) (info + 1);
  
      info->wki10_computername = (DWORD) (cstrp - outp->datap);
!     StringCbCopyA(cstrp, totalData, smb_localNamep);
      cstrp += strlen(cstrp) + 1;
  
      info->wki10_username = (DWORD) (cstrp - outp->datap);
***************
*** 1858,1871 ****
      if (uidp) {
          lock_ObtainMutex(&uidp->mx);
          if(uidp->unp && uidp->unp->name)
!             strcpy(cstrp, uidp->unp->name);
          lock_ReleaseMutex(&uidp->mx);
          smb_ReleaseUID(uidp);
      }
      cstrp += strlen(cstrp) + 1;
  
      info->wki10_langroup = (DWORD) (cstrp - outp->datap);
!     strcpy(cstrp, "WORKGROUP");
      cstrp += strlen(cstrp) + 1;
  
      /* TODO: Not sure what values these should take, but these work */
--- 1964,1978 ----
      if (uidp) {
          lock_ObtainMutex(&uidp->mx);
          if(uidp->unp && uidp->unp->name)
!             cm_ClientStringToUtf8(uidp->unp->name, -1,
!                                   cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
          lock_ReleaseMutex(&uidp->mx);
          smb_ReleaseUID(uidp);
      }
      cstrp += strlen(cstrp) + 1;
  
      info->wki10_langroup = (DWORD) (cstrp - outp->datap);
!     StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
      cstrp += strlen(cstrp) + 1;
  
      /* TODO: Not sure what values these should take, but these work */
***************
*** 1873,1879 ****
      info->wki10_ver_minor = 1;
  
      info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
!     strcpy(cstrp, smb_ServerDomainName);
      cstrp += strlen(cstrp) + 1;
  
      info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
--- 1980,1987 ----
      info->wki10_ver_minor = 1;
  
      info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
!     cm_ClientStringToUtf8(smb_ServerDomainName, -1,
!                           cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
      cstrp += strlen(cstrp) + 1;
  
      info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
***************
*** 1889,1906 ****
      return code;
  }
  
  typedef struct smb_rap_server_info_0 {
!     char    sv0_name[16];
  } smb_rap_server_info_0_t;
  
  typedef struct smb_rap_server_info_1 {
!     char            sv1_name[16];
!     char            sv1_version_major;
!     char            sv1_version_minor;
!     unsigned long   sv1_type;
!     DWORD           *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
  } smb_rap_server_info_1_t;
  
  char smb_ServerComment[] = "OpenAFS Client";
  int smb_ServerCommentLen = sizeof(smb_ServerComment);
  
--- 1997,2018 ----
      return code;
  }
  
+ #pragma pack(push, 1)
+ 
  typedef struct smb_rap_server_info_0 {
!     BYTE    sv0_name[16];
  } smb_rap_server_info_0_t;
  
  typedef struct smb_rap_server_info_1 {
!     BYTE            sv1_name[16];
!     BYTE            sv1_version_major;
!     BYTE            sv1_version_minor;
!     DWORD           sv1_type;
!     DWORD           sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
  } smb_rap_server_info_1_t;
  
+ #pragma pack(pop)
+ 
  char smb_ServerComment[] = "OpenAFS Client";
  int smb_ServerCommentLen = sizeof(smb_ServerComment);
  
***************
*** 1922,1929 ****
      char * cstrp;
  
      tp = p->parmsp + 1; /* Skip over function number */
!     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
!     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
      infoLevel = *tp++;
      bufsize = *tp++;
  
--- 2034,2054 ----
      char * cstrp;
  
      tp = p->parmsp + 1; /* Skip over function number */
! 
!     {
!         clientchar_t * cdescp;
! 
!         cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
!                                        SMB_STRF_FORCEASCII);
!         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
!             return CM_ERROR_INVAL;
!         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
!                                        SMB_STRF_FORCEASCII);
!         if (cm_ClientStrCmp(cdescp,  _C("B16")) ||
!             cm_ClientStrCmp(cdescp,  _C("B16BBDz")))
!             return CM_ERROR_INVAL;
!     }
! 
      infoLevel = *tp++;
      bufsize = *tp++;
  
***************
*** 1945,1955 ****
      if (infoLevel == 0) {
          info0 = (smb_rap_server_info_0_t *) outp->datap;
          cstrp = (char *) (info0 + 1);
!         strcpy(info0->sv0_name, "AFS");
      } else { /* infoLevel == SMB_INFO_STANDARD */
          info1 = (smb_rap_server_info_1_t *) outp->datap;
          cstrp = (char *) (info1 + 1);
!         strcpy(info1->sv1_name, "AFS");
  
          info1->sv1_type = 
              SMB_SV_TYPE_SERVER |
--- 2070,2080 ----
      if (infoLevel == 0) {
          info0 = (smb_rap_server_info_0_t *) outp->datap;
          cstrp = (char *) (info0 + 1);
!         StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
      } else { /* infoLevel == SMB_INFO_STANDARD */
          info1 = (smb_rap_server_info_1_t *) outp->datap;
          cstrp = (char *) (info1 + 1);
!         StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
  
          info1->sv1_type = 
              SMB_SV_TYPE_SERVER |
***************
*** 1958,1968 ****
  
          info1->sv1_version_major = 5;
          info1->sv1_version_minor = 1;
!         info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
  
!         strcpy(cstrp, smb_ServerComment);
  
!         cstrp += smb_ServerCommentLen;
      }
  
      totalData = (DWORD)(cstrp - outp->datap);
--- 2083,2093 ----
  
          info1->sv1_version_major = 5;
          info1->sv1_version_minor = 1;
!         info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
  
!         StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
  
!         cstrp += smb_ServerCommentLen / sizeof(char);
      }
  
      totalData = (DWORD)(cstrp - outp->datap);
***************
*** 1977,1982 ****
--- 2102,2108 ----
      return code;
  }
  
+ /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
  long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_tran2Packet_t *asp;
***************
*** 1994,2002 ****
      /* We sometimes see 0 word count.  What to do? */
      if (*inp->wctp == 0) {
          osi_Log0(smb_logp, "Transaction2 word count = 0"); 
- #ifndef DJGPP
  	LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
- #endif /* !DJGPP */
  
          smb_SetSMBDataLength(outp, 0);
          smb_SendPacket(vcp, outp);
--- 2120,2126 ----
***************
*** 2097,2105 ****
      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;
--- 2221,2230 ----
      return 0;
  }
  
+ /* TRANS2_OPEN2 */
  long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
!     clientchar_t *pathp;
      smb_tran2Packet_t *outp;
      long code = 0;
      cm_space_t *spacep;
***************
*** 2111,2117 ****
      int initialModeBits;
      smb_fid_t *fidp;
      int attributes;
!     char *lastNamep;
      afs_uint32 dosTime;
      int openFun;
      int trunc;
--- 2236,2242 ----
      int initialModeBits;
      smb_fid_t *fidp;
      int attributes;
!     clientchar_t *lastNamep;
      afs_uint32 dosTime;
      int openFun;
      int trunc;
***************
*** 2120,2126 ****
      int openAction;
      int parmSlot;			/* which parm we're dealing with */
      long returnEALength;
!     char *tidPathp;
      cm_req_t req;
      int created = 0;
  
--- 2245,2251 ----
      int openAction;
      int parmSlot;			/* which parm we're dealing with */
      long returnEALength;
!     clientchar_t *tidPathp;
      cm_req_t req;
      int created = 0;
  
***************
*** 2145,2164 ****
      if (attributes & SMB_ATTR_READONLY) 
          initialModeBits &= ~0222;
          
!     pathp = (char *) (&p->parmsp[14]);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
      
      outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
  
      spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
  
      if (lastNamep && 
!          (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
!            stricmp(lastNamep, "\\srvsvc") == 0 ||
!            stricmp(lastNamep, "\\wkssvc") == 0 ||
!            stricmp(lastNamep, "\\ipc$") == 0)) {
          /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
--- 2270,2288 ----
      if (attributes & SMB_ATTR_READONLY) 
          initialModeBits &= ~0222;
          
!     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
!                                   SMB_STRF_ANSIPATH);
      
      outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
  
      spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
  
      if (lastNamep && 
!         (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
!          cm_ClientStrCmpI(lastNamep,  _C("\\srvsvc")) == 0 ||
!          cm_ClientStrCmpI(lastNamep,  _C("\\wkssvc")) == 0 ||
!          cm_ClientStrCmpI(lastNamep,  _C("\\ipc$")) == 0)) {
          /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
***************
*** 2239,2245 ****
                       CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                       userp, tidPathp, &req, &scp);
      if (code != 0) {
!         code = cm_NameI(cm_data.rootSCachep, spacep->data,
                           CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                           userp, tidPathp, &req, &dscp);
          cm_FreeSpace(spacep);
--- 2363,2369 ----
                       CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                       userp, tidPathp, &req, &scp);
      if (code != 0) {
!         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                           CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                           userp, tidPathp, &req, &dscp);
          cm_FreeSpace(spacep);
***************
*** 2252,2258 ****
          
  #ifdef DFS_SUPPORT
          if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
              cm_ReleaseSCache(dscp);
              cm_ReleaseUser(userp);
              smb_FreeTran2Packet(outp);
--- 2376,2383 ----
          
  #ifdef DFS_SUPPORT
          if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
!                                                       (clientchar_t*) spacep->data);
              cm_ReleaseSCache(dscp);
              cm_ReleaseUser(userp);
              smb_FreeTran2Packet(outp);
***************
*** 2494,2537 ****
      return CM_ERROR_BAD_LEVEL;
  }
  
  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;
!     static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
          
      osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
  
      switch (p->parmsp[0]) {
      case SMB_INFO_ALLOCATION: 
  	responseSize = sizeof(qi.u.allocInfo); 
- 	break;
-     case SMB_INFO_VOLUME: 
- 	responseSize = sizeof(qi.u.volumeInfo); 
- 	break;
-     case SMB_QUERY_FS_VOLUME_INFO: 
- 	responseSize = sizeof(qi.u.FSvolumeInfo); 
- 	break;
-     case SMB_QUERY_FS_SIZE_INFO: 
- 	responseSize = sizeof(qi.u.FSsizeInfo); 
- 	break;
-     case SMB_QUERY_FS_DEVICE_INFO: 
- 	responseSize = sizeof(qi.u.FSdeviceInfo); 
- 	break;
-     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
- 	responseSize = sizeof(qi.u.FSattributeInfo); 
- 	break;
-     case SMB_INFO_UNIX: 	/* CIFS Unix Info */
-     case SMB_INFO_MACOS: 	/* Mac FS Info */
-     default: 
- 	return CM_ERROR_BADOP;
-     }
  
-     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
-     switch (p->parmsp[0]) {
-     case SMB_INFO_ALLOCATION: 
-         /* alloc info */
          qi.u.allocInfo.FSID = 0;
          qi.u.allocInfo.sectorsPerAllocUnit = 1;
          qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
--- 2619,2639 ----
      return CM_ERROR_BAD_LEVEL;
  }
  
+ /* TRANS2_QUERY_FS_INFORMATION */
  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;
!     size_t sz = 0;
          
      osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
  
      switch (p->parmsp[0]) {
      case SMB_INFO_ALLOCATION: 
+         /* alloc info */
  	responseSize = sizeof(qi.u.allocInfo); 
  
          qi.u.allocInfo.FSID = 0;
          qi.u.allocInfo.sectorsPerAllocUnit = 1;
          qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
***************
*** 2541,2563 ****
  
      case SMB_INFO_VOLUME: 
          /* 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(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
!         memcpy(qi.u.volumeInfo.label, "AFS", 4);
          break;
  
      case SMB_QUERY_FS_VOLUME_INFO: 
          /* FS volume info */
!         memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
          qi.u.FSvolumeInfo.vsn = 1234;
!         qi.u.FSvolumeInfo.vnCount = 8;
!         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
          break;
  
      case SMB_QUERY_FS_SIZE_INFO: 
          /* FS size info */
          qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
  	qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
          qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
--- 2643,2676 ----
  
      case SMB_INFO_VOLUME: 
          /* volume info */
!         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
!         qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
! 
          /* we're supposed to pad it out with zeroes to the end */
          memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
!         smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
! 
!         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
          break;
  
      case SMB_QUERY_FS_VOLUME_INFO: 
          /* FS volume info */
! 	responseSize = sizeof(qi.u.FSvolumeInfo);
! 
!         {
!             FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
!             memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
!         }
! 
          qi.u.FSvolumeInfo.vsn = 1234;
!         qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
!         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
          break;
  
      case SMB_QUERY_FS_SIZE_INFO: 
          /* FS size info */
+ 	responseSize = sizeof(qi.u.FSsizeInfo); 
+ 
          qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
  	qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
          qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
***************
*** 2568,2579 ****
--- 2681,2695 ----
  
      case SMB_QUERY_FS_DEVICE_INFO: 
          /* FS device info */
+ 	responseSize = sizeof(qi.u.FSdeviceInfo); 
+ 
          qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
          qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
          break;
  
      case SMB_QUERY_FS_ATTRIBUTE_INFO: 
          /* FS attribute info */
+ 
          /* attributes, defined in WINNT.H:
           *	FILE_CASE_SENSITIVE_SEARCH	0x1
           *	FILE_CASE_PRESERVED_NAMES	0x2
***************
*** 2584,2595 ****
           *	   despite our protestations to the contrary.
           */
          qi.u.FSattributeInfo.attributes = 0x4003;
          qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
!         qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
!         memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
          break;
      }   
          
      /* copy out return data, and set corresponding sizes */
      outp->totalParms = 0;
      outp->totalData = responseSize;
--- 2700,2734 ----
           *	   despite our protestations to the contrary.
           */
          qi.u.FSattributeInfo.attributes = 0x4003;
+         /* The maxCompLength is supposed to be in bytes */
+ #ifdef SMB_UNICODE
+         if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
+             qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
+         else {
+ #endif
          qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
! #ifdef SMB_UNICODE
!         }
! #endif
!         smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, 0);
!         qi.u.FSattributeInfo.FSnameLength = sz;
! 
! 	responseSize =
!             sizeof(qi.u.FSattributeInfo.attributes) +
!             sizeof(qi.u.FSattributeInfo.maxCompLength) +
!             sizeof(qi.u.FSattributeInfo.FSnameLength) +
!             sz;
! 
          break;
+ 
+     case SMB_INFO_UNIX: 	/* CIFS Unix Info */
+     case SMB_INFO_MACOS: 	/* Mac FS Info */
+     default: 
+ 	return CM_ERROR_BADOP;
      }   
          
+     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
+         
      /* copy out return data, and set corresponding sizes */
      outp->totalParms = 0;
      outp->totalData = responseSize;
***************
*** 2609,2617 ****
  }
  
  struct smb_ShortNameRock {
!     char *maskp;
      unsigned int vnode;
!     char *shortName;
      size_t shortNameLen;
  };      
  
--- 2748,2756 ----
  }
  
  struct smb_ShortNameRock {
!     clientchar_t *maskp;
      unsigned int vnode;
!     clientchar_t *shortName;
      size_t shortNameLen;
  };      
  
***************
*** 2619,2645 ****
                           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->name, rockp->maskp) != 0)
          return 0;
      if (ntohl(dep->fid.vnode) != rockp->vnode)
          return 0;
      /* This is the entry */
      cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
      rockp->shortNameLen = shortNameEnd - rockp->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;
--- 2758,2790 ----
                           osi_hyper_t *offp)
  {       
      struct smb_ShortNameRock *rockp;
!     normchar_t normName[MAX_PATH];
!     clientchar_t *shortNameEnd;
  
      rockp = vrockp;
+ 
+     cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t));
+ 
      /* compare both names and vnodes, though probably just comparing vnodes
       * would be safe enough.
       */
!     if (cm_NormStrCmpI(normName,  rockp->maskp) != 0)
          return 0;
      if (ntohl(dep->fid.vnode) != rockp->vnode)
          return 0;
+ 
      /* This is the entry */
      cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
      rockp->shortNameLen = shortNameEnd - rockp->shortName;
+ 
      return CM_ERROR_STOPNOW;
! }
  
! long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
! 	clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
  {
      struct smb_ShortNameRock rock;
!     clientchar_t *lastNamep;
      cm_space_t *spacep;
      cm_scache_t *dscp;
      int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
***************
*** 2647,2656 ****
      osi_hyper_t thyper;
  
      spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
  
!     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
!                      reqp, &dscp);
      cm_FreeSpace(spacep);
      if (code) 
          return code;
--- 2792,2802 ----
      osi_hyper_t thyper;
  
      spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
  
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
!                     caseFold, userp, tidPathp,
!                     reqp, &dscp);
      cm_FreeSpace(spacep);
      if (code) 
          return code;
***************
*** 2659,2665 ****
--- 2805,2813 ----
      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
          cm_ReleaseSCache(dscp);
          cm_ReleaseUser(userp);
+ #ifdef DEBUG
          DebugBreak();
+ #endif
          return CM_ERROR_PATH_NOT_COVERED;
      }
  #endif /* DFS_SUPPORT */
***************
*** 2684,2689 ****
--- 2832,2838 ----
      return code;
  }
  
+ /* TRANS2_QUERY_PATH_INFORMATION */
  long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
      smb_tran2Packet_t *outp;
***************
*** 2694,2710 ****
      int responseSize;
      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;
      int scp_mx_held = 0;
      int delonclose = 0;
      long code = 0;
!     char *pathp;
!     char *tidPathp;
!     char *lastComp;
      cm_req_t req;
  
      cm_InitReq(&req);
--- 2843,2859 ----
      int responseSize;
      unsigned short attributes;
      unsigned long extAttributes;
!     clientchar_t shortName[13];
!     size_t len;
      cm_user_t *userp;
      cm_space_t *spacep;
      cm_scache_t *scp, *dscp;
      int scp_mx_held = 0;
      int delonclose = 0;
      long code = 0;
!     clientchar_t *pathp;
!     clientchar_t *tidPathp;
!     clientchar_t *lastComp;
      cm_req_t req;
  
      cm_InitReq(&req);
***************
*** 2735,2745 ****
          return 0;
      }
  
!     pathp = (char *)(&p->parmsp[3]);
!     if (smb_StoreAnsiFilenames)
! 	OemToChar(pathp,pathp);
!     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
!               osi_LogSaveString(smb_logp, pathp));
  
      outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
  
--- 2884,2892 ----
          return 0;
      }
  
!     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
!     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
!               osi_LogSaveClientString(smb_logp, pathp));
  
      outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
  
***************
*** 2790,2801 ****
       */
      if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
          spacep = cm_GetSpace();
!         smb_StripLastComponent(spacep->data, &lastComp, pathp);
  #ifndef SPECIAL_FOLDERS
          /* Make sure that lastComp is not NULL */
          if (lastComp) {
!             if (stricmp(lastComp, "\\desktop.ini") == 0) {
!                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
                                   CM_FLAG_CASEFOLD
                                   | CM_FLAG_DIRSEARCH
                                   | CM_FLAG_FOLLOW,
--- 2937,2948 ----
       */
      if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
          spacep = cm_GetSpace();
!         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
  #ifndef SPECIAL_FOLDERS
          /* Make sure that lastComp is not NULL */
          if (lastComp) {
!             if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
!                 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                                   CM_FLAG_CASEFOLD
                                   | CM_FLAG_DIRSEARCH
                                   | CM_FLAG_FOLLOW,
***************
*** 2803,2809 ****
                  if (code == 0) {
  #ifdef DFS_SUPPORT
                      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
                          if ( WANTS_DFS_PATHNAMES(p) || pnc )
                              code = CM_ERROR_PATH_NOT_COVERED;
                          else
--- 2950,2957 ----
                  if (code == 0) {
  #ifdef DFS_SUPPORT
                      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
!                                                                   spacep->wdata);
                          if ( WANTS_DFS_PATHNAMES(p) || pnc )
                              code = CM_ERROR_PATH_NOT_COVERED;
                          else
***************
*** 2873,2878 ****
--- 3021,3028 ----
          
      lock_ConvertWToR(&scp->rw);
  
+     len = 0;
+ 
      /* now we have the status in the cache entry, and everything is locked.
       * Marshall the output data.
       */
***************
*** 2880,2899 ****
      if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
          code = cm_GetShortName(pathp, userp, &req,
                                  tidPathp, scp->fid.vnode, shortName,
!                                 (size_t *) &len);
          if (code) {
              goto done;
          }
  
! 	qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
!         mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
  
          goto done;
      }
      else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
! 	len = (unsigned int)strlen(lastComp);
! 	qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
!         mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
  
          goto done;
      }
--- 3030,3048 ----
      if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
          code = cm_GetShortName(pathp, userp, &req,
                                  tidPathp, scp->fid.vnode, shortName,
!                                &len);
          if (code) {
              goto done;
          }
  
!         smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, 0);
! 	qpi.u.QPfileAltNameInfo.fileNameLength = len;
  
          goto done;
      }
      else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
!         smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, 0);
! 	qpi.u.QPfileNameInfo.fileNameLength = len;
  
          goto done;
      }
***************
*** 2969,2977 ****
  	qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
  	qpi.u.QPfileAllInfo.mode = 0;
  	qpi.u.QPfileAllInfo.alignmentRequirement = 0;
! 	len = (unsigned int)strlen(lastComp);
! 	qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
!         mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
      }
  
      /* send and free the packets */
--- 3118,3126 ----
  	qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
  	qpi.u.QPfileAllInfo.mode = 0;
  	qpi.u.QPfileAllInfo.alignmentRequirement = 0;
! 
!         smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, 0);
! 	qpi.u.QPfileAllInfo.fileNameLength = len;
      }
  
      /* send and free the packets */
***************
*** 2991,2996 ****
--- 3140,3146 ----
      return 0;
  }
  
+ /* TRANS2_SET_PATH_INFORMATION */
  long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
  #if 0
***************
*** 3000,3014 ****
      long code = 0;
      smb_fid_t *fidp;
      unsigned short infoLevel;
!     char * pathp;
      smb_tran2Packet_t *outp;
      smb_tran2QPathInfo_t *spi;
      cm_user_t *userp;
      cm_scache_t *scp, *dscp;
      cm_req_t req;
      cm_space_t *spacep;
!     char *tidPathp;
!     char *lastComp;
  
      cm_InitReq(&req);
  
--- 3150,3164 ----
      long code = 0;
      smb_fid_t *fidp;
      unsigned short infoLevel;
!     clientchar_t * pathp;
      smb_tran2Packet_t *outp;
      smb_tran2QPathInfo_t *spi;
      cm_user_t *userp;
      cm_scache_t *scp, *dscp;
      cm_req_t req;
      cm_space_t *spacep;
!     clientchar_t *tidPathp;
!     clientchar_t *lastComp;
  
      cm_InitReq(&req);
  
***************
*** 3024,3034 ****
          return 0;
      }
  
!     pathp = (char *)(&p->parmsp[3]);
!     if (smb_StoreAnsiFilenames)
! 	OemToChar(pathp,pathp);
!     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
!               osi_LogSaveString(smb_logp, pathp));
  
      userp = smb_GetTran2User(vcp, p);
      if (!userp) {
--- 3174,3183 ----
          return 0;
      }
  
!     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
! 
!     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
!               osi_LogSaveClientString(smb_logp, pathp));
  
      userp = smb_GetTran2User(vcp, p);
      if (!userp) {
***************
*** 3065,3076 ****
      */
      if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
          spacep = cm_GetSpace();
!         smb_StripLastComponent(spacep->data, &lastComp, pathp);
  #ifndef SPECIAL_FOLDERS
          /* Make sure that lastComp is not NULL */
          if (lastComp) {
!             if (stricmp(lastComp, "\\desktop.ini") == 0) {
!                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
                                   CM_FLAG_CASEFOLD
                                   | CM_FLAG_DIRSEARCH
                                   | CM_FLAG_FOLLOW,
--- 3214,3225 ----
      */
      if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
          spacep = cm_GetSpace();
!         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
  #ifndef SPECIAL_FOLDERS
          /* Make sure that lastComp is not NULL */
          if (lastComp) {
!             if (cm_ClientStrCmpI(lastComp,  _C("\\desktop.ini")) == 0) {
!                 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                                   CM_FLAG_CASEFOLD
                                   | CM_FLAG_DIRSEARCH
                                   | CM_FLAG_FOLLOW,
***************
*** 3078,3084 ****
                  if (code == 0) {
  #ifdef DFS_SUPPORT
                      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
                          if ( WANTS_DFS_PATHNAMES(p) || pnc )
                              code = CM_ERROR_PATH_NOT_COVERED;
                          else
--- 3227,3234 ----
                  if (code == 0) {
  #ifdef DFS_SUPPORT
                      if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
!                                                                   spacep->wdata);
                          if ( WANTS_DFS_PATHNAMES(p) || pnc )
                              code = CM_ERROR_PATH_NOT_COVERED;
                          else
***************
*** 3218,3223 ****
--- 3368,3374 ----
  #endif
  }
  
+ /* TRANS2_QUERY_FILE_INFORMATION */
  long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
      smb_tran2Packet_t *outp;
***************
*** 3328,3335 ****
          qfi.u.QFeaInfo.eaSize = 0;
      }
      else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
!         unsigned long len;
!         char *name;
  
  	lock_ReleaseRead(&scp->rw);
  	lock_ObtainMutex(&fidp->mx);
--- 3479,3486 ----
          qfi.u.QFeaInfo.eaSize = 0;
      }
      else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
!         size_t len = 0;
!         clientchar_t *name;
  
  	lock_ReleaseRead(&scp->rw);
  	lock_ObtainMutex(&fidp->mx);
***************
*** 3337,3348 ****
          if (fidp->NTopen_wholepathp)
              name = fidp->NTopen_wholepathp;
          else
!             name = "\\";	/* probably can't happen */
  	lock_ReleaseMutex(&fidp->mx);
!         len = (unsigned long)strlen(name);
!         outp->totalData = ((len+1)*2) + 4;	/* this is actually what we want to return */
!         qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
!         mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
      }
  
      /* send and free the packets */
--- 3488,3499 ----
          if (fidp->NTopen_wholepathp)
              name = fidp->NTopen_wholepathp;
          else
!             name = _C("\\");	/* probably can't happen */
  	lock_ReleaseMutex(&fidp->mx);
! 
!         smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, 0);
!         outp->totalData = len + 4;	/* this is actually what we want to return */
!         qfi.u.QFfileNameInfo.fileNameLength = len;
      }
  
      /* send and free the packets */
***************
*** 3365,3370 ****
--- 3516,3523 ----
      return 0;
  }       
  
+ 
+ /* TRANS2_SET_FILE_INFORMATION */
  long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
      long code = 0;
***************
*** 3553,3558 ****
--- 3706,3712 ----
      return 0;
  }
  
+ /* TRANS2_FSCTL */
  long 
  smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
***************
*** 3560,3565 ****
--- 3714,3720 ----
      return CM_ERROR_BADOP;
  }
  
+ /* TRANS2_IOCTL2 */
  long 
  smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
***************
*** 3567,3572 ****
--- 3722,3728 ----
      return CM_ERROR_BADOP;
  }
  
+ /* TRANS2_FIND_NOTIFY_FIRST */
  long 
  smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
***************
*** 3574,3579 ****
--- 3730,3736 ----
      return CM_ERROR_BADOP;
  }
  
+ /* TRANS2_FIND_NOTIFY_NEXT */
  long 
  smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
***************
*** 3581,3586 ****
--- 3738,3744 ----
      return CM_ERROR_BADOP;
  }
  
+ /* TRANS2_CREATE_DIRECTORY */
  long 
  smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
***************
*** 3588,3593 ****
--- 3746,3752 ----
      return CM_ERROR_BADOP;
  }
  
+ /* TRANS2_SESSION_SETUP */
  long 
  smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
***************
*** 3605,3610 ****
--- 3764,3770 ----
      USHORT NetworkAddressOffset;
  };
  
+ /* TRANS2_GET_DFS_REFERRAL */
  long 
  smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
  {
***************
*** 3620,3627 ****
  #ifdef DFS_SUPPORT
      long code = 0;
      int maxReferralLevel = 0;
!     char requestFileName[1024] = "";
!     char referralPath[1024] = "";
      smb_tran2Packet_t *outp = 0;
      cm_user_t *userp = 0;
      cm_scache_t *scp = 0;
--- 3780,3787 ----
  #ifdef DFS_SUPPORT
      long code = 0;
      int maxReferralLevel = 0;
!     clientchar_t requestFileName[1024] = _C("");
!     clientchar_t referralPath[1024] = _C("");
      smb_tran2Packet_t *outp = 0;
      cm_user_t *userp = 0;
      cm_scache_t *scp = 0;
***************
*** 3636,3661 ****
      maxReferralLevel = p->parmsp[0];
  
      GetCPInfo(CP_ACP, &CodePageInfo);
!     WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
!                         requestFileName, 1024, NULL, NULL);
  
!     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
!              maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
  
!     nbnLen = (int)strlen(cm_NetbiosName);
!     reqLen = (int)strlen(requestFileName);
  
      if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
!         !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
          requestFileName[nbnLen+1] == '\\') 
      {
          int found = 0;
  
!         if (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
!              !_strnicmp("*.",&requestFileName[nbnLen+2],2)) 
!         {
              found = 1;
!             strcpy(referralPath, requestFileName);
              refLen = reqLen;
          } else {
              userp = smb_GetTran2User(vcp, p);
--- 3796,3819 ----
      maxReferralLevel = p->parmsp[0];
  
      GetCPInfo(CP_ACP, &CodePageInfo);
!     cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
  
!     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]", 
!              maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
  
!     nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
!     reqLen = (int)cm_ClientStrLen(requestFileName);
  
      if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
!         !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
          requestFileName[nbnLen+1] == '\\') 
      {
          int found = 0;
  
!         if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
!             !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
              found = 1;
!             cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
              refLen = reqLen;
          } else {
              userp = smb_GetTran2User(vcp, p);
***************
*** 3664,3670 ****
                  code = CM_ERROR_BADSMB;
                  goto done;
              }   
! 
              /* 
               * We have a requested path.  Check to see if it is something 
               * we know about.
--- 3822,3828 ----
                  code = CM_ERROR_BADSMB;
                  goto done;
              }   
!             
              /* 
               * We have a requested path.  Check to see if it is something 
               * we know about.
***************
*** 3679,3698 ****
              if (code == 0) {
                  /* Yes it is. */
                  found = 1;
!                 strcpy(referralPath, requestFileName);
                  refLen = reqLen;
              } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
!                 char temp[1024];
!                 char pathName[1024];
!                 char *lastComponent;
                  /* 
                   * we have a msdfs link somewhere in the path
                   * we should figure out where in the path the link is.
                   * and return it.
                   */
!                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%s]", requestFileName);
  
!                 strcpy(temp, &requestFileName[nbnLen+2]);
  
                  do {
                      if (dscp) {
--- 3837,3856 ----
              if (code == 0) {
                  /* Yes it is. */
                  found = 1;
!                 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
                  refLen = reqLen;
              } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
!                 clientchar_t temp[1024];
!                 clientchar_t pathName[1024];
!                 clientchar_t *lastComponent;
                  /* 
                   * we have a msdfs link somewhere in the path
                   * we should figure out where in the path the link is.
                   * and return it.
                   */
!                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
  
!                 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
  
                  do {
                      if (dscp) {
***************
*** 3720,3734 ****
                  /* scp should now be the DfsLink we are looking for */
                  if (scp) {
                      /* figure out how much of the input path was used */
!                     reqLen = (int)(nbnLen+2 + strlen(pathName) + 1 + strlen(lastComponent));
  
!                     strcpy(referralPath, &scp->mountPointStringp[strlen("msdfs:")]);
!                     refLen = (int)strlen(referralPath);
                      found = 1;
                  }
              } else {
!                 char shareName[MAX_PATH + 1];
!                 char *p, *q;
                  /* we may have a sharename that is a volume reference */
  
                  for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
--- 3878,3893 ----
                  /* scp should now be the DfsLink we are looking for */
                  if (scp) {
                      /* figure out how much of the input path was used */
!                     reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
  
!                     cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
!                                               referralPath, lengthof(referralPath));
!                     refLen = (int)cm_ClientStrLen(referralPath);
                      found = 1;
                  }
              } else {
!                 clientchar_t shareName[MAX_PATH + 1];
!                 clientchar_t *p, *q;
                  /* we may have a sharename that is a volume reference */
  
                  for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
***************
*** 3738,3751 ****
                  *q = '\0';
                  
                  if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
!                     code = cm_NameI(cm_data.rootSCachep, "", 
                                      CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                                      userp, p, &req, &scp);
                      free(p);
  
                      if (code == 0) {
                          found = 1;
!                         strcpy(referralPath, requestFileName);
                          refLen = reqLen;
                      }
                  }
--- 3897,3911 ----
                  *q = '\0';
                  
                  if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
!                     code = cm_NameI(cm_data.rootSCachep, _C(""), 
                                      CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                                      userp, p, &req, &scp);
                      free(p);
  
                      if (code == 0) {
                          found = 1;
!                         cm_ClientStrCpy(referralPath, lengthof(referralPath),
!                                         requestFileName);
                          refLen = reqLen;
                      }
                  }
***************
*** 3811,3816 ****
--- 3971,3977 ----
  #endif /* DFS_SUPPORT */
  }
  
+ /* TRANS2_REPORT_DFS_INCONSISTENCY */
  long 
  smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
  {
***************
*** 3829,3852 ****
  
  static long 
  smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp, 
!                           char * tidPathp, char * relPathp, 
                            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;
      afs_uint32 dosTime;
      FILETIME ft;
-     int shortTemp;
      unsigned short attr;
      unsigned long lattr;
      smb_dirListPatch_t *patchp;
      smb_dirListPatch_t *npatchp;
      afs_uint32 rights;
      afs_int32 mustFake = 0;
!     char path[AFSPATHMAX];
  
      code = cm_FindACLCache(dscp, userp, &rights);
      if (code == 0 && !(rights & PRSFS_READ))
--- 3990,4011 ----
  
  static long 
  smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp, 
!                           clientchar_t * tidPathp, clientchar_t * relPathp, 
                            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 */
      afs_uint32 dosTime;
      FILETIME ft;
      unsigned short attr;
      unsigned long lattr;
      smb_dirListPatch_t *patchp;
      smb_dirListPatch_t *npatchp;
      afs_uint32 rights;
      afs_int32 mustFake = 0;
!     clientchar_t path[AFSPATHMAX];
  
      code = cm_FindACLCache(dscp, userp, &rights);
      if (code == 0 && !(rights & PRSFS_READ))
***************
*** 3866,3872 ****
  
      for(patchp = *dirPatchespp; patchp; patchp =
           (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
!         snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
          reqp->relPathp = path;
          reqp->tidPathp = tidPathp;
  
--- 4025,4032 ----
  
      for(patchp = *dirPatchespp; patchp; patchp =
           (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
!         cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
!                             relPathp ? relPathp : _C(""), patchp->dep->name);
          reqp->relPathp = path;
          reqp->tidPathp = tidPathp;
  
***************
*** 3882,3918 ****
          if (mustFake || code) { 
              lock_ReleaseWrite(&scp->rw);
  
-             dptr = patchp->dptr;
- 
              /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
                 errors in the client. */
              if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
                  /* 1969-12-31 23:59:59 +00 */
                  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;
  
                  switch (scp->fileType) {
                  case CM_SCACHETYPE_DIRECTORY:
                  case CM_SCACHETYPE_MOUNTPOINT:
                  case CM_SCACHETYPE_SYMLINK:
                  case CM_SCACHETYPE_INVALID:
!                     *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
                      break;
                  default:
                      /* if we get here we either have a normal file
--- 4042,4068 ----
          if (mustFake || code) { 
              lock_ReleaseWrite(&scp->rw);
  
              /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
                 errors in the client. */
              if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+                 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
+ 
                  /* 1969-12-31 23:59:59 +00 */
                  ft.dwHighDateTime = 0x19DB200;
                  ft.dwLowDateTime = 0x5BB78980;
  
                  /* copy to Creation Time */
!                 fa->creationTime = ft;
!                 fa->lastAccessTime = ft;
!                 fa->lastWriteTime = ft;
!                 fa->lastChangeTime = ft;
  
                  switch (scp->fileType) {
                  case CM_SCACHETYPE_DIRECTORY:
                  case CM_SCACHETYPE_MOUNTPOINT:
                  case CM_SCACHETYPE_SYMLINK:
                  case CM_SCACHETYPE_INVALID:
!                     fa->extFileAttributes = SMB_ATTR_DIRECTORY;
                      break;
                  default:
                      /* if we get here we either have a normal file
***************
*** 3923,3971 ****
                       * and odd means it is to be treated as a file.
                       */
                      if (mustFake && (scp->fid.vnode & 0x1))
!                         *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
                      else
!                         *((u_long *)dptr) = SMB_ATTR_NORMAL;
!                         
                  }
                  /* merge in hidden attribute */
                  if ( patchp->flags & 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>>16) & 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
! 
!                 /* copy out creation time */
!                 shortTemp = dosTime & 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
! 
!                 /* and copy out date */
!                 shortTemp = (dosTime>>16) & 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
!     			
!                 /* copy out access time */
!                 shortTemp = dosTime & 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
! 
!                 /* and copy out date */
!                 shortTemp = (dosTime>>16) & 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 2;
!     			
!                 /* copy out mod time */
!                 shortTemp = dosTime & 0xffff;
!                 *((u_short *)dptr) = shortTemp;
!                 dptr += 10;
  
                  /* set the attribute */
                  switch (scp->fileType) {
--- 4073,4095 ----
                       * and odd means it is to be treated as a file.
                       */
                      if (mustFake && (scp->fid.vnode & 0x1))
!                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
                      else
!                         fa->extFileAttributes = SMB_ATTR_NORMAL;
                  }
                  /* merge in hidden attribute */
                  if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
!                     fa->extFileAttributes |= SMB_ATTR_HIDDEN;
                  }
              } else {
+                 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+ 
                  /* 1969-12-31 23:59:58 +00*/
                  dosTime = 0xEBBFBF7D;
  
!                 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
!                 fa->lastAccessDateTime = fa->creationDateTime;
!                 fa->lastWriteDateTime = fa->creationDateTime;
  
                  /* set the attribute */
                  switch (scp->fileType) {
***************
*** 3973,3988 ****
                  case CM_SCACHETYPE_MOUNTPOINT:
                  case CM_SCACHETYPE_SYMLINK:
                  case CM_SCACHETYPE_INVALID:
!                     attr = SMB_ATTR_DIRECTORY;
                  default:
!                     attr = SMB_ATTR_NORMAL;
                  }
                  /* merge in hidden (dot file) attribute */
                  if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
!                     attr |= SMB_ATTR_HIDDEN;
                  }       
-                 *dptr++ = attr & 0xff;
-                 *dptr++ = (attr >> 8) & 0xff;
              }
              
              cm_ReleaseSCache(scp);
--- 4097,4121 ----
                  case CM_SCACHETYPE_MOUNTPOINT:
                  case CM_SCACHETYPE_SYMLINK:
                  case CM_SCACHETYPE_INVALID:
!                     fa->attributes = SMB_ATTR_DIRECTORY;
!                     break;
                  default:
!                     /* if we get here we either have a normal file
!                      * or we have a file for which we have never 
!                      * received status info.  In this case, we can
!                      * check the even/odd value of the entry's vnode.
!                      * even means it is to be treated as a directory
!                      * and odd means it is to be treated as a file.
!                      */
!                     if (mustFake && (scp->fid.vnode & 0x1))
!                         fa->attributes = SMB_ATTR_DIRECTORY;
!                     else
!                         fa->attributes = SMB_ATTR_NORMAL;
                  }
                  /* merge in hidden (dot file) attribute */
                  if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
!                     fa->attributes |= SMB_ATTR_HIDDEN;
                  }       
              }
              
              cm_ReleaseSCache(scp);
***************
*** 3995,4001 ****
          code = 0;
          while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
              lock_ReleaseWrite(&scp->rw);
!             snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
              reqp->relPathp = path;
              reqp->tidPathp = tidPathp;
              code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
--- 4128,4135 ----
          code = 0;
          while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
              lock_ReleaseWrite(&scp->rw);
!             cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
!                                 relPathp ? relPathp : _C(""), patchp->dep->name);
              reqp->relPathp = path;
              reqp->tidPathp = tidPathp;
              code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
***************
*** 4015,4047 ****
  
          lock_ConvertWToR(&scp->rw);
  
-         dptr = patchp->dptr;
- 
          if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
              /* get filetime */
              smb_LargeSearchTimeFromUnixTime(&ft, scp->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->length;
!             dptr += 8;
!             *((LARGE_INTEGER *)dptr) = scp->length;
!             dptr += 8;
  
              /* Copy attributes */
              lattr = smb_ExtAttributes(scp);
--- 4149,4168 ----
  
          lock_ConvertWToR(&scp->rw);
  
          if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+             smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
+ 
              /* get filetime */
              smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
  
!             fa->creationTime = ft;
!             fa->lastAccessTime = ft;
!             fa->lastWriteTime = ft;
!             fa->lastChangeTime = ft;
  
              /* Use length for both file length and alloc length */
!             fa->endOfFile = scp->length;
!             fa->allocationSize = scp->length;
  
              /* Copy attributes */
              lattr = smb_ExtAttributes(scp);
***************
*** 4059,4107 ****
                  else
                      lattr |= SMB_ATTR_HIDDEN;
              }
!             *((u_long *)dptr) = lattr;
!             dptr += 4;
          } else {
              /* get dos time */
              smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
  
!             /* and copy out date */
!             shortTemp = (dosTime>>16) & 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* copy out creation time */
!             shortTemp = dosTime & 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* and copy out date */
!             shortTemp = (dosTime>>16) & 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* copy out access time */
!             shortTemp = dosTime & 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* and copy out date */
!             shortTemp = (dosTime>>16) & 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
! 
!             /* copy out mod time */
!             shortTemp = dosTime & 0xffff;
!             *((u_short *)dptr) = shortTemp;
!             dptr += 2;
  
              /* copy out file length and alloc length,
               * using the same for both
               */
!             *((u_long *)dptr) = scp->length.LowPart;
!             dptr += 4;
!             *((u_long *)dptr) = scp->length.LowPart;
!             dptr += 4;
  
              /* finally copy out attributes as short */
              attr = smb_Attributes(scp);
--- 4180,4202 ----
                  else
                      lattr |= SMB_ATTR_HIDDEN;
              }
! 
!             fa->extFileAttributes = lattr;
          } else {
+             smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+ 
              /* get dos time */
              smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
  
!             fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
!             fa->lastAccessDateTime = fa->creationDateTime;
!             fa->lastWriteDateTime = fa->creationDateTime;
  
              /* copy out file length and alloc length,
               * using the same for both
               */
!             fa->dataSize = scp->length.LowPart;
!             fa->allocationSize = scp->length.LowPart;
  
              /* finally copy out attributes as short */
              attr = smb_Attributes(scp);
***************
*** 4112,4119 ****
                  else
                      lattr |= SMB_ATTR_HIDDEN;
              }
!             *dptr++ = attr & 0xff;
!             *dptr++ = (attr >> 8) & 0xff;
          }
  
          lock_ReleaseRead(&scp->rw);
--- 4207,4213 ----
                  else
                      lattr |= SMB_ATTR_HIDDEN;
              }
!             fa->attributes = attr;
          }
  
          lock_ReleaseRead(&scp->rw);
***************
*** 4132,4261 ****
      return code;
  }
  
- // char table for case insensitive comparison
- char mapCaseTable[256];
- 
- VOID initUpperCaseTable(VOID) 
- {
-     int i;
-     for (i = 0; i < 256; ++i) 
-        mapCaseTable[i] = toupper(i);
-     // make '"' match '.' 
-     mapCaseTable[(int)'"'] = toupper('.');
-     // make '<' match '*' 
-     mapCaseTable[(int)'<'] = toupper('*');
-     // make '>' match '?' 
-     mapCaseTable[(int)'>'] = toupper('?');    
- }
- 
- // Compare 'pattern' (containing metacharacters '*' and '?') with the file
- // name 'name'.
- // Note : this procedure works recursively calling itself.
- // Parameters
- // PSZ pattern    : string containing metacharacters.
- // PSZ name       : file name to be compared with 'pattern'.
- // Return value
- // BOOL : TRUE/FALSE (match/mistmatch)
- 
- BOOL 
- szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
- {
-     PSZ pename;         // points to the last 'name' character
-     PSZ p;
-     pename = name + strlen(name) - 1;
-     while (*name) {
-         switch (*pattern) {
-         case '?':
- 	    ++pattern;
-             if (*name == '.')
- 		continue;
-             ++name;
-             break;
-          case '*':
-             ++pattern;
-             if (*pattern == '\0')
-                 return TRUE;
-             for (p = pename; p >= name; --p) {
-                 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
-                      !casefold && (*p == *pattern)) &&
-                      szWildCardMatchFileName(pattern + 1, p + 1, casefold))
-                     return TRUE;
-             } /* endfor */
-             return FALSE;
-         default:
-             if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
-                 (!casefold && *name != *pattern))
-                 return FALSE;
-             ++pattern, ++name;
-             break;
-         } /* endswitch */
-     } /* endwhile */ 
- 
-     /* if all we have left are wildcards, then we match */
-     for (;*pattern; pattern++) {
- 	if (*pattern != '*' && *pattern != '?')
- 	    return FALSE;
-     }
-     return TRUE;
- }
- 
- /* do a case-folding search of the star name mask with the name in namep.
-  * Return 1 if we match, otherwise 0.
-  */
- int smb_V3MatchMask(char *namep, char *maskp, int flags) 
- {
-     char * newmask;
-     int    i, j, star, qmark, casefold, retval;
- 
-     /* make sure we only match 8.3 names, if requested */
-     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
-         return 0;
-     
-     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 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 '>':
-             qmark++;
-             break;
-         case '<':
-         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, casefold) ? 1:0;
- 
-     free(newmask);
-     return retval;
- }
- 
- 
  /* smb_ReceiveTran2SearchDir implements both 
   * Tran2_Find_First and Tran2_Find_Next
   */
--- 4226,4231 ----
***************
*** 4273,4313 ****
     the usual mechanism. 
     
     This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
     */
  long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
      int attribute;
      long nextCookie;
      long code = 0, code2 = 0;
!     char *pathp = 0;
      int maxCount;
      smb_dirListPatch_t *dirListPatchesp;
      smb_dirListPatch_t *curPatchp;
!     long orbytes;			/* # of bytes in this output record */
!     long ohbytes;			/* # of bytes, except file name */
!     long onbytes;			/* # of bytes in name, incl. term. null */
      cm_scache_t *scp = NULL;
      cm_scache_t *targetscp = NULL;
      cm_user_t *userp = NULL;
      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 */
      long bytesInBuffer;			/* # data bytes in the output buffer */
!     char *maskp;			/* mask part of path */
      int infoLevel;
      int searchFlags;
      int eos;
      smb_tran2Packet_t *outp;		/* response packet */
!     char *tidPathp = 0;
      int align;
!     char shortName[13];			/* 8.3 name if needed */
      int NeedShortName;
!     char *shortNameEnd;
      cm_dirEntry_t * dep = NULL;
      cm_req_t req;
      char * s;
  
      cm_InitReq(&req);
  
--- 4243,4287 ----
     the usual mechanism. 
     
     This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
+ 
+    TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
     */
  long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
      int attribute;
      long nextCookie;
      long code = 0, code2 = 0;
!     clientchar_t *pathp = 0;
      int maxCount;
      smb_dirListPatch_t *dirListPatchesp;
      smb_dirListPatch_t *curPatchp;
!     size_t orbytes;			/* # of bytes in this output record */
!     size_t ohbytes;			/* # of bytes, except file name */
!     size_t onbytes;			/* # of bytes in name, incl. term. null */
      cm_scache_t *scp = NULL;
      cm_scache_t *targetscp = NULL;
      cm_user_t *userp = NULL;
      char *op;				/* output data ptr */
      char *origOp;			/* original value of op */
      cm_space_t *spacep;			/* for pathname buffer */
!     unsigned long maxReturnData;	/* max # of return data */
      long maxReturnParms;		/* max # of return parms */
      long bytesInBuffer;			/* # data bytes in the output buffer */
!     clientchar_t *maskp;			/* mask part of path */
      int infoLevel;
      int searchFlags;
      int eos;
      smb_tran2Packet_t *outp;		/* response packet */
!     clientchar_t *tidPathp = 0;
      int align;
!     clientchar_t shortName[13];			/* 8.3 name if needed */
      int NeedShortName;
!     clientchar_t *shortNameEnd;
      cm_dirEntry_t * dep = NULL;
      cm_req_t req;
      char * s;
+     void * attrp = NULL;
+     smb_tran2Find_t * fp;
  
      cm_InitReq(&req);
  
***************
*** 4323,4365 ****
      maxCount = p->parmsp[1];
      infoLevel = p->parmsp[3];
      searchFlags = p->parmsp[2];
!     pathp = ((char *) p->parmsp) + 12;	/* points to path */
      nextCookie = 0;
!     maskp = strrchr(pathp, '\\');
      if (maskp == NULL) 
  	maskp = pathp;
      else 
  	maskp++;	/* skip over backslash */
      /* track if this is likely to match a lot of entries */
  
!     osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
!             osi_LogSaveString(smb_logp, pathp),
!             osi_LogSaveString(smb_logp, maskp));
  
      switch ( infoLevel ) {
      case SMB_INFO_STANDARD:
  	s = "InfoStandard";
      	break;
      case SMB_INFO_QUERY_EA_SIZE:
  	s = "InfoQueryEaSize";
      	break;
      case SMB_INFO_QUERY_EAS_FROM_LIST:
  	s = "InfoQueryEasFromList";
      	break;
      case SMB_FIND_FILE_DIRECTORY_INFO:
  	s = "FindFileDirectoryInfo";
      	break;
      case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
  	s = "FindFileFullDirectoryInfo";
      	break;
      case SMB_FIND_FILE_NAMES_INFO:
  	s = "FindFileNamesInfo";
      	break;
      case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
  	s = "FindFileBothDirectoryInfo";
      	break;
      default:
  	s = "unknownInfoLevel";
      }
  
      osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
--- 4297,4354 ----
      maxCount = p->parmsp[1];
      infoLevel = p->parmsp[3];
      searchFlags = p->parmsp[2];
!     pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
      nextCookie = 0;
!     maskp = cm_ClientStrRChr(pathp,  '\\');
      if (maskp == NULL) 
  	maskp = pathp;
      else 
  	maskp++;	/* skip over backslash */
      /* track if this is likely to match a lot of entries */
  
!     osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
!              osi_LogSaveClientString(smb_logp, pathp),
!              osi_LogSaveClientString(smb_logp, maskp));
  
      switch ( infoLevel ) {
      case SMB_INFO_STANDARD:
  	s = "InfoStandard";
+         ohbytes = sizeof(fp->u.FstandardInfo);
      	break;
+ 
      case SMB_INFO_QUERY_EA_SIZE:
+         ohbytes = sizeof(fp->u.FeaSizeInfo);
  	s = "InfoQueryEaSize";
      	break;
+ 
      case SMB_INFO_QUERY_EAS_FROM_LIST:
+         ohbytes = sizeof(fp->u.FeasFromListInfo);
  	s = "InfoQueryEasFromList";
      	break;
+ 
      case SMB_FIND_FILE_DIRECTORY_INFO:
  	s = "FindFileDirectoryInfo";
+         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
      	break;
+ 
      case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
  	s = "FindFileFullDirectoryInfo";
+         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
      	break;
+ 
      case SMB_FIND_FILE_NAMES_INFO:
  	s = "FindFileNamesInfo";
+         ohbytes = sizeof(fp->u.FfileNamesInfo);
      	break;
+ 
      case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
  	s = "FindFileBothDirectoryInfo";
+         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
      	break;
+ 
      default:
  	s = "unknownInfoLevel";
+         ohbytes = 0;
      }
  
      osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
***************
*** 4368,4374 ****
               "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
               attribute, infoLevel, maxCount, searchFlags);
      
!     if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
          osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
          return CM_ERROR_INVAL;
      }
--- 4357,4363 ----
               "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
               attribute, infoLevel, maxCount, searchFlags);
      
!     if (ohbytes == 0) {
          osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
          return CM_ERROR_INVAL;
      }
***************
*** 4376,4381 ****
--- 4365,4373 ----
      if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
          searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;	/* no resume keys */
  
+     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+         ohbytes += 4;
+ 
      dirListPatchesp = NULL;
  
      maxReturnData = p->maxReturnData;
***************
*** 4390,4397 ****
      outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                        maxReturnData);
  
!     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
!              maxCount, osi_LogSaveString(smb_logp, pathp));
          
      /* bail out if request looks bad */
      if (!pathp) {
--- 4382,4389 ----
      outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                        maxReturnData);
  
!     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
!              maxCount, osi_LogSaveClientString(smb_logp, pathp));
          
      /* bail out if request looks bad */
      if (!pathp) {
***************
*** 4408,4414 ****
  
      /* try to get the vnode for the path name next */
      spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep->data, NULL, pathp);
      code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
      if (code) {
          cm_ReleaseUser(userp);
--- 4400,4406 ----
  
      /* try to get the vnode for the path name next */
      spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep->wdata, NULL, pathp);
      code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
      if (code) {
          cm_ReleaseUser(userp);
***************
*** 4417,4423 ****
          return 0;
      }
  
!     code = cm_NameI(cm_data.rootSCachep, spacep->data,
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                      userp, tidPathp, &req, &scp);
      cm_FreeSpace(spacep);
--- 4409,4415 ----
          return 0;
      }
  
!     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                      userp, tidPathp, &req, &scp);
      cm_FreeSpace(spacep);
***************
*** 4484,4489 ****
--- 4476,4483 ----
          op += 4;
      }
  
+     fp = (smb_tran2Find_t *) op;
+ 
      if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
          && targetscp->fid.vnode != 0
          && !cm_Is8Dot3(maskp)) {
***************
*** 4492,4508 ****
          dfid.vnode = htonl(targetscp->fid.vnode);
          dfid.unique = htonl(targetscp->fid.unique);
  
!         cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
          NeedShortName = 1;
      } else {
          NeedShortName = 0;
      }
  
!     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
! 	      htonl(targetscp->fid.vnode),
! 	      htonl(targetscp->fid.unique),
! 	      osi_LogSaveString(smb_logp, pathp),
! 	      NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
  
      /* Eliminate entries that don't match requested attributes */
      if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
--- 4486,4502 ----
          dfid.vnode = htonl(targetscp->fid.vnode);
          dfid.unique = htonl(targetscp->fid.unique);
  
!         cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
          NeedShortName = 1;
      } else {
          NeedShortName = 0;
      }
  
!     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
!              htonl(targetscp->fid.vnode),
!              htonl(targetscp->fid.unique),
!              osi_LogSaveClientString(smb_logp, pathp),
!              (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
  
      /* Eliminate entries that don't match requested attributes */
      if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
***************
*** 4526,4554 ****
  
      }
  
-     /* Check if the name will fit */
-     if (infoLevel < 0x101)
-         ohbytes = 23;           /* pre-NT */
-     else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-         ohbytes = 12;           /* NT names only */
-     else
-         ohbytes = 64;           /* NT */
- 
-     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
-         ohbytes += 26;          /* Short name & length */
- 
-     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
-         ohbytes += 4;           /* if resume key required */
-     }
- 
-     if (infoLevel != SMB_INFO_STANDARD
-         && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
-         && infoLevel != SMB_FIND_FILE_NAMES_INFO)
-         ohbytes += 4;           /* EASIZE */
- 
      /* add header to name & term. null */
!     onbytes = (int)strlen(maskp);
!     orbytes = ohbytes + onbytes + 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
--- 4520,4529 ----
  
      }
  
      /* add header to name & term. null */
!     onbytes = 0;
!     smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH);
!     orbytes = ohbytes + onbytes;
  
      /* 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
***************
*** 4576,4617 ****
       * preceded by its length.
       */
      /* First zero everything else */
!     memset(origOp, 0, ohbytes);
  
!     if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
!         *(origOp + ohbytes - 1) = (unsigned char) onbytes;
!     else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
!         *((u_long *)(op + 8)) = onbytes;
!     else
!         *((u_long *)(op + 60)) = onbytes;
!     strcpy(origOp+ohbytes, maskp);
!     if (smb_StoreAnsiFilenames)
!         CharToOem(origOp+ohbytes, origOp+ohbytes);
  
!     /* Short name if requested and needed */
!     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
          if (NeedShortName) {
!             strcpy(op + 70, shortName);
!             if (smb_StoreAnsiFilenames)
!                 CharToOem(op + 70, op + 70);
!             *(op + 68) = (char)(shortNameEnd - shortName);
!         }
      }
  
!     /* NextEntryOffset and FileIndex */
!     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
!         int entryOffset = orbytes + align;
!         *((u_long *)op) = 0;
!         *((u_long *)(op+4)) = 0;
      }
  
      if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
          curPatchp = malloc(sizeof(*curPatchp));
          osi_QAdd((osi_queue_t **) &dirListPatchesp,
                   &curPatchp->q);
!         curPatchp->dptr = op;
!         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
!             curPatchp->dptr += 8;
  
          if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
              curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
--- 4551,4629 ----
       * preceded by its length.
       */
      /* First zero everything else */
!     memset(origOp, 0, orbytes);
  
!     onbytes = 0;
!     smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH);
! 
!     switch (infoLevel) {
!     case SMB_INFO_STANDARD:
!         fp->u.FstandardInfo.fileNameLength = onbytes;
!         attrp = &fp->u.FstandardInfo.fileAttrs;
!         break;
  
!     case SMB_INFO_QUERY_EA_SIZE:
!         fp->u.FeaSizeInfo.fileNameLength = onbytes;
!         attrp = &fp->u.FeaSizeInfo.fileAttrs;
!         fp->u.FeaSizeInfo.eaSize = 0;
!         break;
! 
!     case SMB_INFO_QUERY_EAS_FROM_LIST:
!         fp->u.FeasFromListInfo.fileNameLength = onbytes;
!         attrp = &fp->u.FeasFromListInfo.fileAttrs;
!         fp->u.FeasFromListInfo.eaSize = 0;
!         break;
! 
!     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
          if (NeedShortName) {
! #ifdef SMB_UNICODE
!             int nchars;
! 
!             nchars = cm_ClientStringToUtf16(shortName, -1,
!                                             fp->u.FfileBothDirectoryInfo.shortName,
!                                             sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
!             if (nchars > 0)
!                 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
!             else
!                 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
!             fp->u.FfileBothDirectoryInfo.reserved = 0;
! #else
!             strcpy(fp->u.FfileBothDirectoryInfo.shortName,
!                    shortName);
!             fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
! #endif
      }
+         /* Fallthrough */
  
!     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
!         fp->u.FfileFullDirectoryInfo.eaSize = 0;
!         /* Fallthrough */
! 
!     case SMB_FIND_FILE_DIRECTORY_INFO:
!         fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
!         fp->u.FfileDirectoryInfo.fileIndex = 0;
!         attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
!         fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
!         break;
! 
!     case SMB_FIND_FILE_NAMES_INFO:
!         fp->u.FfileNamesInfo.nextEntryOffset = 0;
!         fp->u.FfileNamesInfo.fileIndex = 0;
!         fp->u.FfileNamesInfo.fileNameLength = onbytes;
!         break;
! 
!     default:
!         /* we shouldn't hit this case */
!         osi_assertx(FALSE, "Unknown query type");
      }
  
      if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+         osi_assert(attrp != NULL);
+ 
          curPatchp = malloc(sizeof(*curPatchp));
          osi_QAdd((osi_queue_t **) &dirListPatchesp,
                   &curPatchp->q);
!         curPatchp->dptr = attrp;
  
          if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
              curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
***************
*** 4622,4629 ****
          cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
  
          /* temp */
!         dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+strlen(maskp));
!         strcpy(dep->name, maskp);
          dep->fid.vnode = targetscp->fid.vnode;
          dep->fid.unique = targetscp->fid.unique;
          curPatchp->dep = dep;
--- 4634,4644 ----
          cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
  
          /* temp */
!         {
!             int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
!             dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
!             cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
!         }
          dep->fid.vnode = targetscp->fid.vnode;
          dep->fid.unique = targetscp->fid.unique;
          curPatchp->dep = dep;
***************
*** 4645,4651 ****
      }
  
      /* apply the patches */
!     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->data, infoLevel, userp, &req);
  
      outp->parmsp[0] = 0;
      outp->parmsp[1] = 1;        /* number of names returned */
--- 4660,4666 ----
      }
  
      /* apply the patches */
!     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
  
      outp->parmsp[0] = 0;
      outp->parmsp[1] = 1;        /* number of names returned */
***************
*** 4680,4701 ****
  }
  
  
  long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
      int attribute;
      long nextCookie;
      char *tp;
      long code = 0, code2 = 0;
!     char *pathp;
      cm_dirEntry_t *dep = 0;
      int maxCount;
      smb_dirListPatch_t *dirListPatchesp = 0;
      smb_dirListPatch_t *curPatchp = 0;
      cm_buf_t *bufferp;
      long temp;
!     long orbytes;			/* # of bytes in this output record */
!     long ohbytes;			/* # of bytes, except file name */
!     long onbytes;			/* # of bytes in name, incl. term. null */
      osi_hyper_t dirLength;
      osi_hyper_t bufferOffset;
      osi_hyper_t curOffset;
--- 4695,4717 ----
  }
  
  
+ /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
  long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
  {
      int attribute;
      long nextCookie;
      char *tp;
      long code = 0, code2 = 0;
!     clientchar_t *pathp;
      cm_dirEntry_t *dep = 0;
      int maxCount;
      smb_dirListPatch_t *dirListPatchesp = 0;
      smb_dirListPatch_t *curPatchp = 0;
      cm_buf_t *bufferp;
      long temp;
!     size_t orbytes;			/* # of bytes in this output record */
!     size_t ohbytes;			/* # of bytes, except file name */
!     size_t onbytes;			/* # of bytes in name, incl. term. null */
      osi_hyper_t dirLength;
      osi_hyper_t bufferOffset;
      osi_hyper_t curOffset;
***************
*** 4713,4737 ****
      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 */
      long bytesInBuffer;		/* # data bytes in the output buffer */
      int starPattern;
!     char *maskp;			/* mask part of path */
      int infoLevel;
      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;
      char * s;
  
      cm_InitReq(&req);
  
--- 4729,4755 ----
      char *op;			/* output data ptr */
      char *origOp;			/* original value of op */
      cm_space_t *spacep;		/* for pathname buffer */
!     unsigned long maxReturnData;		/* max # of return data */
!     unsigned long maxReturnParms;		/* max # of return parms */
      long bytesInBuffer;		/* # data bytes in the output buffer */
      int starPattern;
!     clientchar_t *maskp;			/* mask part of path */
      int infoLevel;
      int searchFlags;
      int eos;
      smb_tran2Packet_t *outp;	/* response packet */
!     clientchar_t *tidPathp;
!     unsigned int align;
!     clientchar_t shortName[13];		/* 8.3 name if needed */
      int NeedShortName;
      int foundInexact;
!     clientchar_t *shortNameEnd;
      int fileType;
      cm_fid_t fid;
      cm_req_t req;
+     void * attrp;
      char * s;
+     smb_tran2Find_t * fp;
  
      cm_InitReq(&req);
  
***************
*** 4742,4752 ****
          maxCount = p->parmsp[1];
          infoLevel = p->parmsp[3];
          searchFlags = p->parmsp[2];
!         pathp = ((char *) p->parmsp) + 12;	/* points to path */
!         if (smb_StoreAnsiFilenames)
!             OemToChar(pathp,pathp);
          nextCookie = 0;
!         maskp = strrchr(pathp, '\\');
          if (maskp == NULL) 
              maskp = pathp;
          else 
--- 4760,4768 ----
          maxCount = p->parmsp[1];
          infoLevel = p->parmsp[3];
          searchFlags = p->parmsp[2];
!         pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
          nextCookie = 0;
!         maskp = cm_ClientStrRChr(pathp,  '\\');
          if (maskp == NULL) 
              maskp = pathp;
          else 
***************
*** 4772,4783 ****
                  return code;
              }
          }
! #endif
          dir_enums++;
  
          dsp = smb_NewDirSearch(1);
          dsp->attribute = attribute;
!         strcpy(dsp->mask, maskp);	/* and save mask */
      }
      else {
          osi_assertx(p->opcode == 2, "invalid opcode");
--- 4788,4799 ----
                  return code;
              }
          }
! #endif  /* NOFINDFIRSTOPTIMIZE */
          dir_enums++;
  
          dsp = smb_NewDirSearch(1);
          dsp->attribute = attribute;
!         cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask),  maskp);	/* and save mask */
      }
      else {
          osi_assertx(p->opcode == 2, "invalid opcode");
***************
*** 4801,4827 ****
--- 4817,4858 ----
      switch ( infoLevel ) {
      case SMB_INFO_STANDARD:
  	s = "InfoStandard";
+         ohbytes = sizeof(fp->u.FstandardInfo);
      	break;
+ 
      case SMB_INFO_QUERY_EA_SIZE:
+         ohbytes = sizeof(fp->u.FeaSizeInfo);
  	s = "InfoQueryEaSize";
      	break;
+ 
      case SMB_INFO_QUERY_EAS_FROM_LIST:
+         ohbytes = sizeof(fp->u.FeasFromListInfo);
  	s = "InfoQueryEasFromList";
      	break;
+ 
      case SMB_FIND_FILE_DIRECTORY_INFO:
  	s = "FindFileDirectoryInfo";
+         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
      	break;
+ 
      case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
  	s = "FindFileFullDirectoryInfo";
+         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
      	break;
+ 
      case SMB_FIND_FILE_NAMES_INFO:
  	s = "FindFileNamesInfo";
+         ohbytes = sizeof(fp->u.FfileNamesInfo);
      	break;
+ 
      case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
  	s = "FindFileBothDirectoryInfo";
+         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
      	break;
+ 
      default:
  	s = "unknownInfoLevel";
+         ohbytes = 0;
      }
  
      osi_Log1(smb_logp, "T2 search dir info level: %s", s);
***************
*** 4833,4839 ****
      osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
                p->opcode, dsp->cookie, nextCookie);
  
!     if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
          osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
          smb_ReleaseDirSearch(dsp);
          return CM_ERROR_INVAL;
--- 4864,4870 ----
      osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
                p->opcode, dsp->cookie, nextCookie);
  
!     if (ohbytes == 0) {
          osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
          smb_ReleaseDirSearch(dsp);
          return CM_ERROR_INVAL;
***************
*** 4842,4847 ****
--- 4873,4881 ----
      if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
          searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;	/* no resume keys */
  
+     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+         ohbytes += 4;
+ 
      dirListPatchesp = NULL;
  
      maxReturnData = p->maxReturnData;
***************
*** 4858,4865 ****
      outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                        maxReturnData);
  
!     osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
!              maxCount, osi_LogSaveString(smb_logp, pathp));
          
      /* bail out if request looks bad */
      if (p->opcode == 1 && !pathp) {
--- 4892,4899 ----
      outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                        maxReturnData);
  
!     osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
!              maxCount, osi_LogSaveClientString(smb_logp, pathp));
          
      /* bail out if request looks bad */
      if (p->opcode == 1 && !pathp) {
***************
*** 4888,4894 ****
          code = 0;
      } else {
          spacep = cm_GetSpace();
!         smb_StripLastComponent(spacep->data, NULL, pathp);
          code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
          if (code) {
              cm_ReleaseUser(userp);
--- 4922,4928 ----
          code = 0;
      } else {
          spacep = cm_GetSpace();
!         smb_StripLastComponent(spacep->wdata, NULL, pathp);
          code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
          if (code) {
              cm_ReleaseUser(userp);
***************
*** 4900,4909 ****
              return 0;
          }
  
!         strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
!         strcpy(dsp->relPath, spacep->data);
  
!         code = cm_NameI(cm_data.rootSCachep, spacep->data,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &scp);
          cm_FreeSpace(spacep);
--- 4934,4943 ----
              return 0;
          }
  
!         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
!         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
  
!         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &scp);
          cm_FreeSpace(spacep);
***************
*** 4982,4992 ****
--- 5016,5031 ----
      returnedNames = 0;
      bytesInBuffer = 0;
      while (1) {
+         normchar_t normName[MAX_PATH]; /* Normalized name */
+         clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
+ 
          op = origOp;
          if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
              /* skip over resume key */
              op += 4;
  
+         fp = (smb_tran2Find_t *) op;
+ 
          /* 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,
***************
*** 5152,5179 ****
          if (dep->fid.vnode == 0) 
              goto nextEntry;             /* This entry is not in use */
  
          /* Need 8.3 name? */
          NeedShortName = 0;
          if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO && 
!              !cm_Is8Dot3(dep->name)) {
              cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
              NeedShortName = 1;
          }
  
!         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
!                   dep->fid.vnode, dep->fid.unique, 
!                   osi_LogSaveString(smb_logp, dep->name),
!                   NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
  
          /* 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 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
!              (NeedShortName && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD))) 
          {
              /* Eliminate entries that don't match requested attributes */
              if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
!                  smb_IsDotFile(dep->name)) {
                  osi_Log0(smb_logp, "T2 search dir skipping hidden");
                  goto nextEntry; /* no hidden files */
              }
--- 5191,5221 ----
          if (dep->fid.vnode == 0) 
              goto nextEntry;             /* This entry is not in use */
  
+         cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName));
+         cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName));
+ 
          /* Need 8.3 name? */
          NeedShortName = 0;
          if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO && 
!             !cm_Is8Dot3(cfileName)) {
              cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
              NeedShortName = 1;
          }
  
!         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
!                  dep->fid.vnode, dep->fid.unique, 
!                  osi_LogSaveClientString(smb_logp, cfileName),
!                  NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
  
          /* 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 (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
!             (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD))) 
          {
              /* Eliminate entries that don't match requested attributes */
              if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
!                 smb_IsDotFile(cfileName)) {
                  osi_Log0(smb_logp, "T2 search dir skipping hidden");
                  goto nextEntry; /* no hidden files */
              }
***************
*** 5181,5187 ****
              if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
              {
                  /* We have already done the cm_TryBulkStat above */
!                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
                  fileType = cm_FindFileType(&fid);
                  /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
                   * "has filetype %d", dep->name, fileType);
--- 5223,5230 ----
              if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
              {
                  /* We have already done the cm_TryBulkStat above */
!                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
!                           ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
                  fileType = cm_FindFileType(&fid);
                  /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
                   * "has filetype %d", dep->name, fileType);
***************
*** 5195,5223 ****
              }
  
              /* finally check if this name will fit */
! 
!             /* standard dir entry stuff */
!             if (infoLevel < 0x101)
!                 ohbytes = 23;	/* pre-NT */
!             else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
!                 ohbytes = 12;	/* NT names only */
!             else
!                 ohbytes = 64;	/* NT */
! 
!             if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
!                 ohbytes += 26;	/* Short name & length */
! 
!             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
!                 ohbytes += 4;	/* if resume key required */
!             }   
! 
!             if ( infoLevel != SMB_INFO_STANDARD && 
!                  infoLevel != SMB_FIND_FILE_DIRECTORY_INFO &&
!                  infoLevel != SMB_FIND_FILE_NAMES_INFO)
!                 ohbytes += 4;	/* EASIZE */
! 
!             /* add header to name & 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
--- 5238,5246 ----
              }
  
              /* finally check if this name will fit */
!             onbytes = 0;
!             smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH);
!             orbytes = ohbytes + onbytes;
  
              /* now, we round up the record to a 4 byte alignment,
               * and we make sure that we have enough room here for
***************
*** 5229,5237 ****
                  align = (4 - (orbytes & 3)) & 3;
              else
                  align = 0;
              if (orbytes + bytesInBuffer + align > maxReturnData) {
                  osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
!                           maxReturnData);
                  break;      
              }       
  
--- 5252,5261 ----
                  align = (4 - (orbytes & 3)) & 3;
              else
                  align = 0;
+ 
              if (orbytes + bytesInBuffer + align > maxReturnData) {
                  osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
!                          maxReturnData);
                  break;      
              }       
  
***************
*** 5240,5277 ****
               * Put out the name, preceded by its length.
               */
              /* First zero everything else */
!             memset(origOp, 0, ohbytes);
  
!             if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
!                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
!             else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
!                 *((u_long *)(op + 8)) = onbytes;
!             else
!                 *((u_long *)(op + 60)) = onbytes;
!             strcpy(origOp+ohbytes, dep->name);
!             if (smb_StoreAnsiFilenames)
!                 CharToOem(origOp+ohbytes, origOp+ohbytes);
  
!             /* Short name if requested and needed */
!             if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
                  if (NeedShortName) {
!                     strcpy(op + 70, shortName);
!                     if (smb_StoreAnsiFilenames)
!                         CharToOem(op + 70, op + 70);
!                     *(op + 68) = (char)(shortNameEnd - shortName);
                  }
              }
  
              /* now, adjust the # of entries copied */
              returnedNames++;
  
-             /* NextEntryOffset and FileIndex */
-             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
-                 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
--- 5264,5340 ----
               * Put out the name, preceded by its length.
               */
              /* First zero everything else */
!             memset(origOp, 0, orbytes);
  
!             onbytes = 0;
!             smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH);
! 
!             switch (infoLevel) {
!             case SMB_INFO_STANDARD:
!                 fp->u.FstandardInfo.fileNameLength = onbytes;
!                 attrp = &fp->u.FstandardInfo.fileAttrs;
!                 break;
! 
!             case SMB_INFO_QUERY_EA_SIZE:
!                 fp->u.FeaSizeInfo.fileNameLength = onbytes;
!                 attrp = &fp->u.FeaSizeInfo.fileAttrs;
!                 fp->u.FeaSizeInfo.eaSize = 0;
!                 break;
  
!             case SMB_INFO_QUERY_EAS_FROM_LIST:
!                 fp->u.FeasFromListInfo.fileNameLength = onbytes;
!                 attrp = &fp->u.FeasFromListInfo.fileAttrs;
!                 fp->u.FeasFromListInfo.eaSize = 0;
!                 break;
! 
!             case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
                  if (NeedShortName) {
! #ifdef SMB_UNICODE
!                     int nchars;
! 
!                     nchars = cm_ClientStringToUtf16(shortName, -1,
!                                                     fp->u.FfileBothDirectoryInfo.shortName,
!                                                     sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
!                     if (nchars > 0)
!                         fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
!                     else
!                         fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
!                     fp->u.FfileBothDirectoryInfo.reserved = 0;
! #else
!                     cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
!                                     lengthof(fp->u.FfileBothDirectoryInfo.shortName),
!                                     shortName);
!                     fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
! #endif
                  }
+                 /* Fallthrough */
+ 
+             case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+                 fp->u.FfileFullDirectoryInfo.eaSize = 0;
+                 /* Fallthrough */
+ 
+             case SMB_FIND_FILE_DIRECTORY_INFO:
+                 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
+                 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
+                 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
+                 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
+                 break;
+ 
+             case SMB_FIND_FILE_NAMES_INFO:
+                 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
+                 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
+                 fp->u.FfileNamesInfo.fileNameLength = onbytes;
+                 attrp = NULL;
+                 break;
+ 
+             default:
+                 /* we shouldn't hit this case */
+                 osi_assertx(FALSE, "Unknown query type");
              }
  
              /* now, adjust the # of entries copied */
              returnedNames++;
  
              /* 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
***************
*** 5286,5302 ****
               * safe to unlock the directory.
               */
              if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
                  curPatchp = malloc(sizeof(*curPatchp));
                  osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
!                 curPatchp->dptr = op;
!                 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
!                     curPatchp->dptr += 8;
  
!                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
                      curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
!                 }       
!                 else    
                      curPatchp->flags = 0;
  
                  cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
  
--- 5349,5364 ----
               * safe to unlock the directory.
               */
              if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+                 osi_assert(attrp != NULL);
                  curPatchp = malloc(sizeof(*curPatchp));
                  osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
!                 curPatchp->dptr = attrp;
  
!                 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
                      curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
!                 } else {
                      curPatchp->flags = 0;
+                 }
  
                  cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
  
***************
*** 5313,5326 ****
              bytesInBuffer += orbytes;
  
              /* and pad the record out */
!             while (--align >= 0) {
                  *origOp++ = 0;
                  bytesInBuffer++;
              }
          }	/* if we're including this name */
          else if (!starPattern &&
!                   !foundInexact &&
!                   smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
              /* We were looking for exact matches, but here's an inexact one*/
              foundInexact = 1;
          }
--- 5375,5388 ----
              bytesInBuffer += orbytes;
  
              /* and pad the record out */
!             while (align-- > 0) {
                  *origOp++ = 0;
                  bytesInBuffer++;
              }
          }	/* if we're including this name */
          else if (!starPattern &&
!                  !foundInexact &&
!                  cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
              /* We were looking for exact matches, but here's an inexact one*/
              foundInexact = 1;
          }
***************
*** 5414,5419 ****
--- 5476,5482 ----
      return 0;
  }
  
+ /* SMB_COM_FIND_CLOSE2 */
  long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      int dirHandle;
***************
*** 5438,5452 ****
      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;
--- 5501,5518 ----
      return 0;
  }
  
+ 
+ /* SMB_COM_FIND_NOTIFY_CLOSE */
  long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_SetSMBDataLength(outp, 0);
      return 0;
  }
  
+ /* SMB_COM_OPEN_ANDX */
  long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp;
      long code = 0;
      cm_space_t *spacep;
      int excl;
***************
*** 5457,5471 ****
      int initialModeBits;
      smb_fid_t *fidp;
      int attributes;
!     char *lastNamep;
!     afs_uint32 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;
      int created = 0;
  
--- 5523,5537 ----
      int initialModeBits;
      smb_fid_t *fidp;
      int attributes;
!     clientchar_t *lastNamep;
!     unsigned long dosTime;
      int openFun;
      int trunc;
      int openMode;
      int extraInfo;
      int openAction;
      int parmSlot;			/* which parm we're dealing with */
!     clientchar_t *tidPathp;
      cm_req_t req;
      int created = 0;
  
***************
*** 5488,5505 ****
      if (attributes & SMB_ATTR_READONLY) 
  	initialModeBits &= ~0222;
          
!     pathp = smb_GetSMBData(inp, NULL);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(pathp,pathp);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
  
      if (lastNamep && 
!          (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
!            stricmp(lastNamep, "\\srvsvc") == 0 ||
!            stricmp(lastNamep, "\\wkssvc") == 0 ||
!            stricmp(lastNamep, "ipc$") == 0)) {
          /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
--- 5554,5570 ----
      if (attributes & SMB_ATTR_READONLY) 
  	initialModeBits &= ~0222;
          
!     pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
!                                 SMB_STRF_ANSIPATH);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
  
      if (lastNamep && 
!         (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
!          cm_ClientStrCmpIA(lastNamep,  _C("\\srvsvc")) == 0 ||
!          cm_ClientStrCmpIA(lastNamep,  _C("\\wkssvc")) == 0 ||
!          cm_ClientStrCmpIA(lastNamep,  _C("ipc$")) == 0)) {
          /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
***************
*** 5573,5579 ****
  #endif /* DFS_SUPPORT */
  
      if (code != 0) {
!         code = cm_NameI(cm_data.rootSCachep, spacep->data,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &dscp);
          if (code) {
--- 5638,5644 ----
  #endif /* DFS_SUPPORT */
  
      if (code != 0) {
!         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &dscp);
          if (code) {
***************
*** 5583,5589 ****
  
  #ifdef DFS_SUPPORT
          if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
              cm_ReleaseSCache(dscp);
              cm_ReleaseUser(userp);
              if ( WANTS_DFS_PATHNAMES(inp) || pnc )
--- 5648,5655 ----
  
  #ifdef DFS_SUPPORT
          if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
!                                                       spacep->wdata);
              cm_ReleaseSCache(dscp);
              cm_ReleaseUser(userp);
              if ( WANTS_DFS_PATHNAMES(inp) || pnc )
***************
*** 5649,5656 ****
      }
      else {
          osi_assertx(dscp != NULL, "null cm_scache_t");
!         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(&setAttr.clientModTime, dosTime);
--- 5715,5722 ----
      }
      else {
          osi_assertx(dscp != NULL, "null cm_scache_t");
!         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
!                  osi_LogSaveClientString(smb_logp, lastNamep));
          openAction = 2;	/* created file */
          setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
          smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
***************
*** 5791,5796 ****
--- 5857,5863 ----
      }
  }
  
+ /* SMB_COM_LOCKING_ANDX */
  long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      cm_req_t req;
***************
*** 6085,6090 ****
--- 6152,6158 ----
      return code;
  }
  
+ /* SMB_COM_QUERY_INFORMATION2 */
  long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      unsigned short fid;
***************
*** 6172,6177 ****
--- 6240,6246 ----
      return code;
  }       
  
+ /* SMB_COM_SET_INFORMATION2 */
  long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      unsigned short fid;
***************
*** 6241,6246 ****
--- 6310,6316 ----
      return code;
  }
  
+ /* SMB_COM_WRITE_ANDX */
  long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      osi_hyper_t offset;
***************
*** 6349,6359 ****
  
      code = 0;
      while ( code == 0 && count > 0 ) {
- #ifndef DJGPP
  	code = smb_WriteData(fidp, &offset, count, op, userp, &written);
- #else /* DJGPP */
- 	code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
- #endif /* !DJGPP */
  	if (code == 0 && written == 0)
              code = CM_ERROR_PARTIALWRITE;
  
--- 6419,6425 ----
***************
*** 6379,6384 ****
--- 6445,6451 ----
      return code;
  }
  
+ /* SMB_COM_READ_ANDX */
  long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      osi_hyper_t offset;
***************
*** 6495,6505 ****
      /* set the packet data length the count of the # of bytes */
      smb_SetSMBDataLength(outp, count);
  
- #ifndef DJGPP
      code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
- #else /* DJGPP */
-     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
- #endif /* !DJGPP */
  
      /* fix some things up */
      smb_SetSMBParm(outp, 5, finalCount);
--- 6562,6568 ----
***************
*** 6537,6545 ****
  #define FILE_DELETE_ON_CLOSE      0x1000
  #define FILE_OPEN_BY_FILE_ID      0x2000
  
  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;
--- 6600,6609 ----
  #define FILE_DELETE_ON_CLOSE      0x1000
  #define FILE_OPEN_BY_FILE_ID      0x2000
  
+ /* SMB_COM_NT_CREATE_ANDX */
  long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp, *realPathp;
      long code = 0;
      cm_space_t *spacep;
      cm_user_t *userp;
***************
*** 6547,6554 ****
      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;
--- 6611,6618 ----
      cm_scache_t *scp;		/* file to create or open */
      cm_scache_t *targetScp;	/* if scp is a symlink */
      cm_attr_t setAttr;
!     clientchar_t *lastNamep;
!     clientchar_t *treeStartp;
      unsigned short nameLength;
      unsigned int flags;
      unsigned int requestOpLock;
***************
*** 6572,6578 ****
      long fidflags;
      FILETIME ft;
      LARGE_INTEGER sz;
!     char *tidPathp;
      BOOL foundscp;
      cm_req_t req;
      int created = 0;
--- 6636,6642 ----
      long fidflags;
      FILETIME ft;
      LARGE_INTEGER sz;
!     clientchar_t *tidPathp;
      BOOL foundscp;
      cm_req_t req;
      int created = 0;
***************
*** 6633,6658 ****
      if (extAttributes & SMB_ATTR_READONLY) 
          initialModeBits &= ~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;
!     if (smb_StoreAnsiFilenames)
!         OemToChar(realPathp,realPathp);
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->data, &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_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
  
  	if (lastNamep && 
!              (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
!                stricmp(lastNamep, "\\srvsvc") == 0 ||
!                stricmp(lastNamep, "\\wkssvc") == 0 ||
!                stricmp(lastNamep, "ipc$") == 0)) {
          /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
--- 6697,6722 ----
      if (extAttributes & SMB_ATTR_READONLY) 
          initialModeBits &= ~0222;
  
!     pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
!                               NULL, SMB_STRF_ANSIPATH);
! 
      /* Sometimes path is not null-terminated, so we make a copy. */
!     realPathp = malloc(nameLength+sizeof(clientchar_t));
!     memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
!     realPathp[nameLength/sizeof(clientchar_t)] = 0;
  
      spacep = inp->spacep;
!     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
  
!     osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
      osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
!     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
  
  	if (lastNamep && 
!             (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
!              cm_ClientStrCmpIA(lastNamep,  _C("\\srvsvc")) == 0 ||
!              cm_ClientStrCmpIA(lastNamep,  _C("\\wkssvc")) == 0 ||
!              cm_ClientStrCmpIA(lastNamep,  _C("ipc$")) == 0)) {
          /* special case magic file name for receiving IOCTL requests
           * (since IOCTL calls themselves aren't getting through).
           */
***************
*** 6744,6750 ****
          tidPathp = NULL;
      }
  
!     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
  
      /* compute open mode */
      fidflags = 0;
--- 6808,6814 ----
          tidPathp = NULL;
      }
  
!     osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
  
      /* compute open mode */
      fidflags = 0;
***************
*** 6776,6787 ****
      if ( createDisp == FILE_CREATE || 
           createDisp == FILE_OVERWRITE ||
           createDisp == FILE_OVERWRITE_IF) {
!         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &dscp);
          if (code == 0) {
  #ifdef DFS_SUPPORT
              if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
                  cm_ReleaseSCache(dscp);
                  cm_ReleaseUser(userp);
                  free(realPathp);
--- 6840,6852 ----
      if ( createDisp == FILE_CREATE || 
           createDisp == FILE_OVERWRITE ||
           createDisp == FILE_OVERWRITE_IF) {
!         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &dscp);
          if (code == 0) {
  #ifdef DFS_SUPPORT
              if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
!                                                           spacep->wdata);
                  cm_ReleaseSCache(dscp);
                  cm_ReleaseUser(userp);
                  free(realPathp);
***************
*** 6844,6858 ****
  
          if (dscp == NULL) {
              do {
!                 char *tp;
  
!                 code = cm_NameI(baseDirp, spacep->data,
!                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
!                              userp, tidPathp, &req, &dscp);
  
  #ifdef DFS_SUPPORT
                  if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                     int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
                      if (scp)
                          cm_ReleaseSCache(scp);
                      cm_ReleaseSCache(dscp);
--- 6909,6924 ----
  
          if (dscp == NULL) {
              do {
!                 clientchar_t *tp;
  
!                 code = cm_NameI(baseDirp, spacep->wdata,
!                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
!                                 userp, tidPathp, &req, &dscp);
  
  #ifdef DFS_SUPPORT
                  if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                     int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
!                                                               spacep->wdata);
                      if (scp)
                          cm_ReleaseSCache(scp);
                      cm_ReleaseSCache(dscp);
***************
*** 6867,6879 ****
                  }
  #endif /* DFS_SUPPORT */
  
!                 if (code && 
!                      (tp = strrchr(spacep->data,'\\')) &&
!                      (createDisp == FILE_CREATE) &&
!                      (realDirFlag == 1)) {
                      *tp++ = 0;
                      treeCreate = TRUE;
!                     treeStartp = realPathp + (tp - spacep->data);
  
                      if (*tp && !smb_IsLegalFilename(tp)) {
                          cm_ReleaseUser(userp);
--- 6933,6945 ----
                  }
  #endif /* DFS_SUPPORT */
  
!                 if (code &&
!                     (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
!                     (createDisp == FILE_CREATE) &&
!                     (realDirFlag == 1)) {
                      *tp++ = 0;
                      treeCreate = TRUE;
!                     treeStartp = realPathp + (tp - spacep->wdata);
  
                      if (*tp && !smb_IsLegalFilename(tp)) {
                          cm_ReleaseUser(userp);
***************
*** 7038,7045 ****
          return CM_ERROR_NOSUCHFILE;
      } else if (realDirFlag == 0 || realDirFlag == -1) {
          osi_assertx(dscp != NULL, "null cm_scache_t");
!         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);
--- 7104,7111 ----
          return CM_ERROR_NOSUCHFILE;
      } else if (realDirFlag == 0 || realDirFlag == -1) {
          osi_assertx(dscp != NULL, "null cm_scache_t");
!         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
!                   osi_LogSaveClientString(smb_logp, lastNamep));
          openAction = 2;		/* created file */
          setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
          setAttr.clientModTime = time(NULL);
***************
*** 7086,7093 ****
              }	/* lookup succeeded */
          }
      } else {
!         char *tp, *pp;
!         char *cp; /* This component */
          int clen = 0; /* length of component */
          cm_scache_t *tscp1, *tscp2;
          int isLast = 0;
--- 7152,7159 ----
              }	/* lookup succeeded */
          }
      } else {
!         clientchar_t *tp, *pp;
!         clientchar_t *cp; /* This component */
          int clen = 0; /* length of component */
          cm_scache_t *tscp1, *tscp2;
          int isLast = 0;
***************
*** 7096,7103 ****
          if ( !treeCreate ) 
              treeStartp = lastNamep;
          osi_assertx(dscp != NULL, "null cm_scache_t");
!         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
!                   osi_LogSaveString(smb_logp, treeStartp));
          openAction = 2;		/* created directory */
  
  	/* if the request is to create the root directory 
--- 7162,7169 ----
          if ( !treeCreate ) 
              treeStartp = lastNamep;
          osi_assertx(dscp != NULL, "null cm_scache_t");
!         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
!                   osi_LogSaveClientString(smb_logp, treeStartp));
          openAction = 2;		/* created directory */
  
  	/* if the request is to create the root directory 
***************
*** 7111,7130 ****
          setAttr.clientModTime = time(NULL);
  
          pp = treeStartp;
!         cp = spacep->data;
          tscp1 = dscp;
          cm_HoldSCache(tscp1);
          tscp2 = NULL;
  
          while (pp && *pp) {
!             tp = strchr(pp, '\\');
              if (!tp) {
!                 strcpy(cp,pp);
!                 clen = (int)strlen(cp);
                  isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
              } else {
                  clen = (int)(tp - pp);
!                 strncpy(cp,pp,clen);
                  *(cp + clen) = 0;
                  tp++;
              }
--- 7177,7197 ----
          setAttr.clientModTime = time(NULL);
  
          pp = treeStartp;
!         cp = spacep->wdata;
          tscp1 = dscp;
          cm_HoldSCache(tscp1);
          tscp2 = NULL;
  
          while (pp && *pp) {
!             tp = cm_ClientStrChr(pp, '\\');
              if (!tp) {
!                 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
!                 clen = (int)cm_ClientStrLen(cp);
                  isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
              } else {
                  clen = (int)(tp - pp);
!                 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
!                                  pp, clen);
                  *(cp + clen) = 0;
                  tp++;
              }
***************
*** 7137,7146 ****
              code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
              if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
                  smb_NotifyChange(FILE_ACTION_ADDED,
!                                   FILE_NOTIFY_CHANGE_DIR_NAME,
!                                   tscp1, cp, NULL, TRUE);
!             if (code == 0 || 
!                  (code == CM_ERROR_EXISTS && 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
--- 7204,7213 ----
              code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
              if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
                  smb_NotifyChange(FILE_ACTION_ADDED,
!                                  FILE_NOTIFY_CHANGE_DIR_NAME,
!                                  tscp1, cp, NULL, TRUE);
!             if (code == 0 ||
!                 (code == CM_ERROR_EXISTS && 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
***************
*** 7148,7155 ****
                   * started this call.
                   */
                  code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
!                                   userp, &req, &tscp2);
!             }       
              if (code) 
                  break;
  
--- 7215,7222 ----
                   * started this call.
                   */
                  code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
!                                  userp, &req, &tscp2);
!             }
              if (code) 
                  break;
  
***************
*** 7306,7312 ****
          fidp->flags |= SMB_FID_NTOPEN;
          fidp->NTopen_dscp = dscp;
  	dscp = NULL;
!         fidp->NTopen_pathp = strdup(lastNamep);
      }
      fidp->NTopen_wholepathp = realPathp;
      lock_ReleaseMutex(&fidp->mx);
--- 7373,7379 ----
          fidp->flags |= SMB_FID_NTOPEN;
          fidp->NTopen_dscp = dscp;
  	dscp = NULL;
!         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
      }
      fidp->NTopen_wholepathp = realPathp;
      lock_ReleaseMutex(&fidp->mx);
***************
*** 7354,7361 ****
      }
      lock_ReleaseRead(&scp->rw);
  
!     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
!               osi_LogSaveString(smb_logp, realPathp));
  
      cm_ReleaseUser(userp);
      smb_ReleaseFID(fidp);
--- 7421,7428 ----
      }
      lock_ReleaseRead(&scp->rw);
  
!     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
!               osi_LogSaveClientString(smb_logp, realPathp));
  
      cm_ReleaseUser(userp);
      smb_ReleaseFID(fidp);
***************
*** 7371,7379 ****
   * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
   * Instead, ultimately, would like to use a subroutine for common code.
   */
  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;
--- 7438,7448 ----
   * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
   * Instead, ultimately, would like to use a subroutine for common code.
   */
+ 
+ /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
  long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *pathp, *realPathp;
      long code = 0;
      cm_space_t *spacep;
      cm_user_t *userp;
***************
*** 7381,7387 ****
      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;
--- 7450,7456 ----
      cm_scache_t *scp;		/* file to create or open */
      cm_scache_t *targetScp;     /* if scp is a symlink */
      cm_attr_t setAttr;
!     clientchar_t *lastNamep;
      unsigned long nameLength;
      unsigned int flags;
      unsigned int requestOpLock;
***************
*** 7409,7415 ****
      int parmSlot;
      long fidflags;
      FILETIME ft;
!     char *tidPathp;
      BOOL foundscp;
      int parmOffset, dataOffset;
      char *parmp;
--- 7478,7484 ----
      int parmSlot;
      long fidflags;
      FILETIME ft;
!     clientchar_t *tidPathp;
      BOOL foundscp;
      int parmOffset, dataOffset;
      char *parmp;
***************
*** 7479,7494 ****
      if (extAttributes & SMB_ATTR_READONLY) 
          initialModeBits &= ~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;
-     if (smb_StoreAnsiFilenames)
-         OemToChar(realPathp,realPathp);
- 
      spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
  
      /*
       * Nothing here to handle SMB_IOCTL_FILENAME.
--- 7548,7561 ----
      if (extAttributes & SMB_ATTR_READONLY) 
          initialModeBits &= ~0222;
  
!     pathp = smb_ParseStringCch(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
!                                nameLength, NULL, SMB_STRF_ANSIPATH);
      /* Sometimes path is not null-terminated, so we make a copy. */
!     realPathp = malloc((nameLength+1) * sizeof(clientchar_t));
!     memcpy(realPathp, pathp, nameLength * sizeof(clientchar_t));
      realPathp[nameLength] = 0;
      spacep = cm_GetSpace();
!     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
  
      /*
       * Nothing here to handle SMB_IOCTL_FILENAME.
***************
*** 7578,7589 ****
      if ( createDisp == FILE_OPEN || 
           createDisp == FILE_OVERWRITE ||
           createDisp == FILE_OVERWRITE_IF) {
!         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &dscp);
          if (code == 0) {
  #ifdef DFS_SUPPORT
              if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
                  cm_ReleaseSCache(dscp);
                  cm_ReleaseUser(userp);
                  free(realPathp);
--- 7645,7656 ----
      if ( createDisp == FILE_OPEN || 
           createDisp == FILE_OVERWRITE ||
           createDisp == FILE_OVERWRITE_IF) {
!         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &dscp);
          if (code == 0) {
  #ifdef DFS_SUPPORT
              if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
                  cm_ReleaseSCache(dscp);
                  cm_ReleaseUser(userp);
                  free(realPathp);
***************
*** 7637,7648 ****
      if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
          /* look up parent directory */
          if ( !dscp ) {
!             code = cm_NameI(baseDirp, spacep->data,
                               CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                               userp, tidPathp, &req, &dscp);
  #ifdef DFS_SUPPORT
              if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
                  cm_ReleaseSCache(dscp);
                  cm_ReleaseUser(userp);
                  free(realPathp);
--- 7704,7715 ----
      if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
          /* look up parent directory */
          if ( !dscp ) {
!             code = cm_NameI(baseDirp, spacep->wdata,
                               CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                               userp, tidPathp, &req, &dscp);
  #ifdef DFS_SUPPORT
              if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
!                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
                  cm_ReleaseSCache(dscp);
                  cm_ReleaseUser(userp);
                  free(realPathp);
***************
*** 7773,7780 ****
      }
      else if (realDirFlag == 0 || realDirFlag == -1) {
          osi_assertx(dscp != NULL, "null cm_scache_t");
!         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);
--- 7840,7847 ----
      }
      else if (realDirFlag == 0 || realDirFlag == -1) {
          osi_assertx(dscp != NULL, "null cm_scache_t");
!         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
!                   osi_LogSaveClientString(smb_logp, lastNamep));
          openAction = 2;		/* created file */
          setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
          setAttr.clientModTime = time(NULL);
***************
*** 7825,7832 ****
          /* create directory */
          osi_assertx(dscp != NULL, "null cm_scache_t");
          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);
--- 7892,7899 ----
          /* create directory */
          osi_assertx(dscp != NULL, "null cm_scache_t");
          osi_Log1(smb_logp,
!                   "smb_ReceiveNTTranCreate creating directory %S",
!                   osi_LogSaveClientString(smb_logp, lastNamep));
          openAction = 2;		/* created directory */
          setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
          setAttr.clientModTime = time(NULL);
***************
*** 7972,7978 ****
          fidp->NTopen_dscp = dscp;
  	osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
  	dscp = NULL;
!         fidp->NTopen_pathp = strdup(lastNamep);
      }
      fidp->NTopen_wholepathp = realPathp;
      lock_ReleaseMutex(&fidp->mx);
--- 8039,8045 ----
          fidp->NTopen_dscp = dscp;
  	osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
  	dscp = NULL;
!         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
      }
      fidp->NTopen_wholepathp = realPathp;
      lock_ReleaseMutex(&fidp->mx);
***************
*** 8109,8114 ****
--- 8176,8182 ----
      return 0;
  }
  
+ /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
  long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
  	smb_packet_t *outp)
  {
***************
*** 8151,8158 ****
      lock_ReleaseMutex(&smb_Dir_Watch_Lock);
  
      scp = fidp->scp;
!     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"", 
! 	      fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
      osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
               filter, fid, watchtree);
      if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
--- 8219,8226 ----
      lock_ReleaseMutex(&smb_Dir_Watch_Lock);
  
      scp = fidp->scp;
!     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"", 
! 	      fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
      osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
               filter, fid, watchtree);
      if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
***************
*** 8207,8212 ****
--- 8275,8281 ----
                                          /* "null SID" group SID */
  };      
  
+ /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
  long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      int parmOffset, parmCount, dataOffset, dataCount;
***************
*** 8275,8280 ****
--- 8344,8353 ----
          return CM_ERROR_BUFFERTOOSMALL;
  }
  
+ /* SMB_COM_NT_TRANSACT
+ 
+    SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
+  */
  long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      unsigned short function;
***************
*** 8288,8307 ****
          ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
          
      switch (function) {
!     case 1: 
          return smb_ReceiveNTTranCreate(vcp, inp, outp);
!     case 2:
  	osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
  	break;
!     case 3:
  	osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
  	break;
!     case 4:
          return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
!     case 5:
  	osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
  	break;
!     case 6:
          return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
      case 7:
          osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
--- 8361,8380 ----
          ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
          
      switch (function) {
!     case 1:                     /* NT_TRANSACT_CREATE */
          return smb_ReceiveNTTranCreate(vcp, inp, outp);
!     case 2:                     /* NT_TRANSACT_IOCTL */
  	osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
  	break;
!     case 3:                     /* NT_TRANSACT_SET_SECURITY_DESC */
  	osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
  	break;
!     case 4:                     /* NT_TRANSACT_NOTIFY_CHANGE */
          return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
!     case 5:                     /* NT_TRANSACT_RENAME */
  	osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
  	break;
!     case 6:                     /* NT_TRANSACT_QUERY_SECURITY_DESC */
          return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
      case 7:
          osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
***************
*** 8324,8334 ****
   * has the isDirectParent parameter set to FALSE.  
   */
  void smb_NotifyChange(DWORD action, DWORD notifyFilter,
! 	cm_scache_t *dscp, char *filename, char *otherFilename,
  	BOOL isDirectParent)
  {
      smb_packet_t *watch, *lastWatch, *nextWatch;
!     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
      char *outData, *oldOutData;
      ULONG filter;
      USHORT fid, wtree;
--- 8397,8407 ----
   * has the isDirectParent parameter set to FALSE.  
   */
  void smb_NotifyChange(DWORD action, DWORD notifyFilter,
! 	cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
  	BOOL isDirectParent)
  {
      smb_packet_t *watch, *lastWatch, *nextWatch;
!     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
      char *outData, *oldOutData;
      ULONG filter;
      USHORT fid, wtree;
***************
*** 8344,8351 ****
          otherAction = FILE_ACTION_RENAMED_NEW_NAME;
      }
  
!     osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
!              osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
      if (action == 0)
  	osi_Log0(smb_logp,"      FILE_ACTION_NONE");
      if (action == FILE_ACTION_ADDED)
--- 8417,8424 ----
          otherAction = FILE_ACTION_RENAMED_NEW_NAME;
      }
  
!     osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
!              osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
      if (action == 0)
  	osi_Log0(smb_logp,"      FILE_ACTION_NONE");
      if (action == FILE_ACTION_ADDED)
***************
*** 8398,8405 ****
          smb_ReleaseFID(fidp);
  
          osi_Log4(smb_logp,
!                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
!                   fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
  	if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
  	    osi_Log0(smb_logp, "      Notify Change File Name");
  	if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
--- 8471,8478 ----
          smb_ReleaseFID(fidp);
  
          osi_Log4(smb_logp,
!                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
!                   fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
  	if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
  	    osi_Log0(smb_logp, "      Notify Change File Name");
  	if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
***************
*** 8448,8461 ****
          ((smb_t *) watch)->wct = 0;
  
          /* out parms */
!         if (filename == NULL)
              parmCount = 0;
!         else {
!             nameLen = (ULONG)strlen(filename);
              parmCount = 3*4 + nameLen*2;
              parmCount = (parmCount + 3) & ~3;	/* pad to 4 */
              if (twoEntries) {
!                 otherNameLen = (ULONG)strlen(otherFilename);
                  oldParmCount = parmCount;
                  parmCount += 3*4 + otherNameLen*2;
                  parmCount = (parmCount + 3) & ~3; /* pad to 4 */
--- 8521,8534 ----
          ((smb_t *) watch)->wct = 0;
  
          /* out parms */
!         if (filename == NULL) {
              parmCount = 0;
!         } else {
!             nameLen = (ULONG)cm_ClientStrLen(filename);
              parmCount = 3*4 + nameLen*2;
              parmCount = (parmCount + 3) & ~3;	/* pad to 4 */
              if (twoEntries) {
!                 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
                  oldParmCount = parmCount;
                  parmCount += 3*4 + otherNameLen*2;
                  parmCount = (parmCount + 3) & ~3; /* pad to 4 */
***************
*** 8489,8495 ****
          smb_SetSMBDataLength(watch, parmCount + 1);
  
          if (parmCount != 0) {
-             char * p;
              outData = smb_GetSMBData(watch, NULL);
              outData++;	/* round to get to parmOffset */
              oldOutData = outData;
--- 8562,8567 ----
***************
*** 8499,8510 ****
              /* Action */
              *((DWORD *)outData) = nameLen*2; outData += 4;
              /* File Name Length */
!             p = strdup(filename);
!             if (smb_StoreAnsiFilenames)
!                 CharToOem(p,p);
!             mbstowcs((WCHAR *)outData, p, nameLen);
!             free(p);
              /* File Name */
              if (twoEntries) {
                  outData = oldOutData + oldParmCount;
                  *((DWORD *)outData) = 0; outData += 4;
--- 8571,8580 ----
              /* Action */
              *((DWORD *)outData) = nameLen*2; outData += 4;
              /* File Name Length */
! 
!             smb_UnparseString(watch, outData, filename, NULL, 0);
              /* File Name */
+ 
              if (twoEntries) {
                  outData = oldOutData + oldParmCount;
                  *((DWORD *)outData) = 0; outData += 4;
***************
*** 8513,8525 ****
                  /* Action */
                  *((DWORD *)outData) = otherNameLen*2;
                  outData += 4;	/* File Name Length */
!                 p = strdup(otherFilename);
!                 if (smb_StoreAnsiFilenames)
!                     CharToOem(p,p);
!                 mbstowcs((WCHAR *)outData, p, otherNameLen);	/* File Name */
!                 free(p);
              }       
!         }       
  
          /*
           * If filename is null, we don't know the cause of the
--- 8583,8591 ----
                  /* Action */
                  *((DWORD *)outData) = otherNameLen*2;
                  outData += 4;	/* File Name Length */
!                 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
              }       
!         }
  
          /*
           * If filename is null, we don't know the cause of the
***************
*** 8544,8549 ****
--- 8610,8616 ----
      lock_ReleaseMutex(&smb_Dir_Watch_Lock);
  }       
  
+ /* SMB_COM_NT_CANCEL */
  long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      unsigned char *replyWctp;
***************
*** 8577,8585 ****
  
              fidp = smb_FindFID(vcp, fid, 0);
              if (fidp) {
!                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
!                           fid, watchtree,
!                           osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
  
                  scp = fidp->scp;
  		osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
--- 8644,8652 ----
  
              fidp = smb_FindFID(vcp, fid, 0);
              if (fidp) {
!                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S", 
!                          fid, watchtree,
!                          (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
  
                  scp = fidp->scp;
  		osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
***************
*** 8627,8633 ****
  
  long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     char *oldPathp, *newPathp;
      long code = 0;
      char * tp;
      int attrs;
--- 8694,8700 ----
  
  long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     clientchar_t *oldPathp, *newPathp;
      long code = 0;
      char * tp;
      int attrs;
***************
*** 8642,8657 ****
      }
  
      tp = smb_GetSMBData(inp, NULL);
!     oldPathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(oldPathp,oldPathp);
!     newPathp = smb_ParseASCIIBlock(tp, &tp);
!     if (smb_StoreAnsiFilenames)
!         OemToChar(newPathp,newPathp);
! 
!     osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
!              osi_LogSaveString(smb_logp, oldPathp),
!              osi_LogSaveString(smb_logp, newPathp),
               ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
  
      if (rename_type == RENAME_FLAG_RENAME) {
--- 8709,8720 ----
      }
  
      tp = smb_GetSMBData(inp, NULL);
!     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
!     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
! 
!     osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
!              osi_LogSaveClientString(smb_logp, oldPathp),
!              osi_LogSaveClientString(smb_logp, newPathp),
               ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
  
      if (rename_type == RENAME_FLAG_RENAME) {
***************
*** 8667,8673 ****
      lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
  }
  
! cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
  {
      smb_username_t *unp;
      cm_user_t *     userp;
--- 8730,8736 ----
      lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
  }
  
! cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
  {
      smb_username_t *unp;
      cm_user_t *     userp;
***************
*** 8677,8685 ****
          lock_ObtainMutex(&unp->mx);
          unp->userp = cm_NewUser();
          lock_ReleaseMutex(&unp->mx);
!         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
      }  else	{
!         osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
      }
      userp = unp->userp;
      cm_HoldUser(userp);
--- 8740,8748 ----
          lock_ObtainMutex(&unp->mx);
          unp->userp = cm_NewUser();
          lock_ReleaseMutex(&unp->mx);
!         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
      }  else	{
!         osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
      }
      userp = unp->userp;
      cm_HoldUser(userp);
Index: openafs/src/WINNT/afsd/smb3.h
diff -c openafs/src/WINNT/afsd/smb3.h:1.12.2.5 openafs/src/WINNT/afsd/smb3.h:1.12.2.8
*** openafs/src/WINNT/afsd/smb3.h:1.12.2.5	Mon Dec 11 23:01:26 2006
--- openafs/src/WINNT/afsd/smb3.h	Thu Jun 26 12:38:31 2008
***************
*** 30,39 ****
--- 30,41 ----
  	unsigned short res[6];		/* contains PidHigh */
          unsigned short *parmsp;		/* parms */
          unsigned char *datap;		/* data bytes */
+         cm_space_t * stringsp;          /* decoded strings */
  } smb_tran2Packet_t;
  
  /* for flags field */
  #define SMB_TRAN2PFLAG_ALLOC	1
+ #define SMB_TRAN2PFLAG_USEUNICODE  2
  
  typedef struct smb_tran2Dispatch {
  	long (*procp)(smb_vc_t *, smb_tran2Packet_t *, smb_packet_t *);
***************
*** 56,69 ****
          struct {
              unsigned long vsn;			/* volume serial number */
              char vnCount;			/* count of chars in label, incl null */
!             char label[12];			/* pad out with nulls */
          } volumeInfo;
          struct {
              FILETIME      vct;		/* volume creation time */
              unsigned long vsn;	        /* volume serial number */
              unsigned long vnCount;	/* length of volume label in bytes */
              char res[2];		/* reserved */
!             char label[10];		/* volume label */
          } FSvolumeInfo;
          struct {
              LARGE_INTEGER totalAllocUnits;	/* on the disk */
--- 58,71 ----
          struct {
              unsigned long vsn;			/* volume serial number */
              char vnCount;			/* count of chars in label, incl null */
!             char /* STRING */ label[24];        /* pad out with nulls */
          } volumeInfo;
          struct {
              FILETIME      vct;		/* volume creation time */
              unsigned long vsn;	        /* volume serial number */
              unsigned long vnCount;	/* length of volume label in bytes */
              char res[2];		/* reserved */
!             char /* STRING */ label[20];	/* volume label */
          } FSvolumeInfo;
          struct {
              LARGE_INTEGER totalAllocUnits;	/* on the disk */
***************
*** 79,85 ****
              unsigned long attributes;
              unsigned long maxCompLength;	/* max path component length */
              unsigned long FSnameLength;		/* length of file system name */
!             unsigned char FSname[12];
          } FSattributeInfo;
      } u;
  } smb_tran2QFSInfo_t;
--- 81,87 ----
              unsigned long attributes;
              unsigned long maxCompLength;	/* max path component length */
              unsigned long FSnameLength;		/* length of file system name */
!             unsigned char /* STRING */ FSname[24]; /* File system name */
          } FSattributeInfo;
      } u;
  } smb_tran2QFSInfo_t;
***************
*** 137,143 ****
  	} QPfileEaInfo;
  	struct {
  	    unsigned long  fileNameLength;
! 	    unsigned char  fileName[512];
  	} QPfileNameInfo;
  	struct {
  	    FILETIME       creationTime;
--- 139,145 ----
  	} QPfileEaInfo;
  	struct {
  	    unsigned long  fileNameLength;
! 	    unsigned char  fileName[512]; /* STRING */
  	} QPfileNameInfo;
  	struct {
  	    FILETIME       creationTime;
***************
*** 158,175 ****
  	    unsigned long  mode;
  	    unsigned long  alignmentRequirement;
  	    unsigned long  fileNameLength;
! 	    unsigned char  fileName[512];
  	} QPfileAllInfo;
  	struct {
  	    unsigned long  fileNameLength;
! 	    unsigned char  fileName[512];
  	} QPfileAltNameInfo;
  	struct {
  	    unsigned long  nextEntryOffset;
  	    unsigned long  streamNameLength;
  	    LARGE_INTEGER  streamSize;
  	    LARGE_INTEGER  streamAllocationSize;
! 	    unsigned char  fileName[512];
  	} QPfileStreamInfo;
  	struct {
  	    LARGE_INTEGER  compressedFileSize;
--- 160,177 ----
  	    unsigned long  mode;
  	    unsigned long  alignmentRequirement;
  	    unsigned long  fileNameLength;
! 	    unsigned char  fileName[512]; /* STRING */
  	} QPfileAllInfo;
  	struct {
  	    unsigned long  fileNameLength;
! 	    unsigned char  fileName[512]; /* STRING */
  	} QPfileAltNameInfo;
  	struct {
  	    unsigned long  nextEntryOffset;
  	    unsigned long  streamNameLength;
  	    LARGE_INTEGER  streamSize;
  	    LARGE_INTEGER  streamAllocationSize;
! 	    unsigned char  fileName[512]; /* STRING */
  	} QPfileStreamInfo;
  	struct {
  	    LARGE_INTEGER  compressedFileSize;
***************
*** 207,212 ****
--- 209,287 ----
  	} QFfileNameInfo;
      } u;
  } smb_tran2QFileInfo_t;
+ 
+ typedef struct {
+     unsigned long  creationDateTime;	/* SMB_DATE / SMB_TIME */
+     unsigned long  lastAccessDateTime;	/* SMB_DATE / SMB_TIME */
+     unsigned long  lastWriteDateTime;	/* SMB_DATE / SMB_TIME */
+     unsigned long  dataSize;
+     unsigned long  allocationSize;
+     unsigned short attributes;
+ } smb_V3FileAttrsShort;
+ 
+ typedef struct {
+     FILETIME       creationTime;
+     FILETIME       lastAccessTime;
+     FILETIME       lastWriteTime;
+     FILETIME       lastChangeTime;
+     LARGE_INTEGER  endOfFile;
+     LARGE_INTEGER  allocationSize;
+     unsigned long  extFileAttributes;
+ } smb_V3FileAttrsLong;
+ 
+ typedef struct {
+     union {
+ 	struct {
+             smb_V3FileAttrsShort fileAttrs;
+ 	    unsigned char  fileNameLength;
+             /* STRING fileName */
+ 	} FstandardInfo;
+ 
+ 	struct {
+             smb_V3FileAttrsShort fileAttrs;
+ 	    unsigned long  eaSize;
+             unsigned char  fileNameLength;
+             /* STRING fileName */
+ 	} FeaSizeInfo, FeasFromListInfo;
+ 
+         struct {
+             unsigned long  nextEntryOffset;
+             unsigned long  fileIndex;
+             smb_V3FileAttrsLong fileAttrs;
+             unsigned long  fileNameLength;
+             /* STRING fileName */
+         } FfileDirectoryInfo;
+ 
+         struct {
+             unsigned long  nextEntryOffset;
+             unsigned long  fileIndex;
+             smb_V3FileAttrsLong fileAttrs;
+             unsigned long  fileNameLength;
+             unsigned long  eaSize;
+             /* STRING fileName */
+         } FfileFullDirectoryInfo;
+ 
+         struct {
+             unsigned long  nextEntryOffset;
+             unsigned long  fileIndex;
+             smb_V3FileAttrsLong fileAttrs;
+             unsigned long  fileNameLength;
+             unsigned long  eaSize;
+             unsigned char  shortNameLength;
+             unsigned char  reserved;
+             wchar_t        shortName[12];
+             /* STRING fileName */
+         } FfileBothDirectoryInfo;
+ 
+         struct {
+             unsigned long  nextEntryOffset;
+             unsigned long  fileIndex;
+             unsigned long  fileNameLength;
+             /* STRING fileName */
+         } FfileNamesInfo;
+     } u;
+ } smb_tran2Find_t;
+ 
  #pragma pack(pop)
  
  /* more than enough opcodes for today, anyway */
***************
*** 314,344 ****
  extern long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
  
  extern void smb_NotifyChange(DWORD action, DWORD notifyFilter,
! 	cm_scache_t *dscp, char *filename, char *otherFilename,
  	BOOL isDirectParent);
  
  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();
- extern cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags);
  
  /* SMB auth related functions */
  extern void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength);
  
- #ifdef DJGPP
- #define DELETE (0x00010000)
- #define READ_CONTROL (0x00020000)
- #define SYNCHRONIZE (0x00100000)
- #define FILE_WRITE_ATTRIBUTES ( 0x0100 )
- #define FILE_GENERIC_READ (0x00120089)
- #define FILE_GENERIC_WRITE (0x00120116)
- #define FILE_GENERIC_EXECUTE (0x001200a0)
- #endif /* DJGPP */
- 
  /* Some of the FILE_NOTIFY_CHANGE values are undefined in winnt.h */
  #define FILE_NOTIFY_CHANGE_EA           0x00000080
  #define FILE_NOTIFY_CHANGE_STREAM_NAME  0x00000200
--- 389,408 ----
  extern long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp);
  
  extern void smb_NotifyChange(DWORD action, DWORD notifyFilter,
! 	cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
  	BOOL isDirectParent);
  
  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 unsigned long smb_ExtAttributes(cm_scache_t *scp);
  
  extern void smb3_Init();
  
  /* SMB auth related functions */
  extern void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength);
  
  /* Some of the FILE_NOTIFY_CHANGE values are undefined in winnt.h */
  #define FILE_NOTIFY_CHANGE_EA           0x00000080
  #define FILE_NOTIFY_CHANGE_STREAM_NAME  0x00000200
Index: openafs/src/WINNT/afsd/smb_iocons.h
diff -c openafs/src/WINNT/afsd/smb_iocons.h:1.10.4.6 openafs/src/WINNT/afsd/smb_iocons.h:1.10.4.8
*** openafs/src/WINNT/afsd/smb_iocons.h:1.10.4.6	Tue Jan 15 22:19:52 2008
--- openafs/src/WINNT/afsd/smb_iocons.h	Thu Jun 26 10:58:06 2008
***************
*** 21,27 ****
  } chservinfo_t;
  
  struct gaginfo {
! 	unsigned long showflags, logflags, logwritethruflag, spare[3];
          unsigned char spare2[128];
  };
  
--- 21,27 ----
  } chservinfo_t;
  
  struct gaginfo {
! 	afs_uint32 showflags, logflags, logwritethruflag, spare[3];
          unsigned char spare2[128];
  };
  
***************
*** 94,100 ****
  #define VIOC_UUIDCTL                    0x30
  #define VIOC_PATH_AVAILABILITY          0x31
  #define VIOC_GETFILETYPE                0x32
  
  #define VIOC_VOLSTAT_TEST               0x3F
! /* Not to exceed SMB_IOCTL_MAXPROCS from smb_ioctl.h */
  #endif /*  __SMB_IOCONS_H_ENV_ */
--- 94,109 ----
  #define VIOC_UUIDCTL                    0x30
  #define VIOC_PATH_AVAILABILITY          0x31
  #define VIOC_GETFILETYPE                0x32
+ #define VIOC_UNICODECTL                 0x33
  
  #define VIOC_VOLSTAT_TEST               0x3F
! 
! /* magic file name for ioctl opens */
! #define CM_IOCTL_FILENAME	"\\_._AFS_IOCTL_._"	/* double backslashes for C compiler */
! #define CM_IOCTL_FILENAME_NOSLASH "_._AFS_IOCTL_._"
! 
! /* max parms for ioctl, in either direction */
! #define CM_IOCTL_MAXDATA	        8192*2
! #define CM_IOCTL_MAXPROCS               64
! 
  #endif /*  __SMB_IOCONS_H_ENV_ */
Index: openafs/src/WINNT/afsd/smb_ioctl.c
diff -c openafs/src/WINNT/afsd/smb_ioctl.c:1.25.2.8 openafs/src/WINNT/afsd/smb_ioctl.c:1.25.2.13
*** openafs/src/WINNT/afsd/smb_ioctl.c:1.25.2.8	Tue Jan 15 22:19:52 2008
--- openafs/src/WINNT/afsd/smb_ioctl.c	Fri Jul 11 18:27:01 2008
***************
*** 10,23 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
- #endif /* !DJGPP */
  #include <stdlib.h>
  #include <malloc.h>
  #include <string.h>
  #include <stdio.h>
  #include <time.h>
  
  #include <osi.h>
  
--- 10,22 ----
  #include <afs/param.h>
  #include <afs/stds.h>
  
  #include <windows.h>
  #include <stdlib.h>
  #include <malloc.h>
  #include <string.h>
  #include <stdio.h>
  #include <time.h>
+ #include <strsafe.h>
  
  #include <osi.h>
  
***************
*** 25,96 ****
  
  #include "smb.h"
  
! smb_ioctlProc_t *smb_ioctlProcsp[SMB_IOCTL_MAXPROCS];
  
! /*extern unsigned char smb_LANadapter;*/
  
! void smb_InitIoctl(void)
  {
!         int i;
!         for (i=0; i<SMB_IOCTL_MAXPROCS; i++)
! 	    smb_ioctlProcsp[i] = NULL;
! 
! 	smb_ioctlProcsp[VIOCGETAL] = cm_IoctlGetACL;
!         smb_ioctlProcsp[VIOC_FILE_CELL_NAME] = cm_IoctlGetFileCellName;
!         smb_ioctlProcsp[VIOCSETAL] = cm_IoctlSetACL;
!         smb_ioctlProcsp[VIOC_FLUSHVOLUME] = cm_IoctlFlushVolume;
!         smb_ioctlProcsp[VIOCFLUSH] = cm_IoctlFlushFile;
!         smb_ioctlProcsp[VIOCSETVOLSTAT] = cm_IoctlSetVolumeStatus;
!         smb_ioctlProcsp[VIOCGETVOLSTAT] = cm_IoctlGetVolumeStatus;
!         smb_ioctlProcsp[VIOCWHEREIS] = cm_IoctlWhereIs;
!         smb_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = cm_IoctlStatMountPoint;
!         smb_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = cm_IoctlDeleteMountPoint;
!         smb_ioctlProcsp[VIOCCKSERV] = cm_IoctlCheckServers;
!         smb_ioctlProcsp[VIOC_GAG] = cm_IoctlGag;
!         smb_ioctlProcsp[VIOCCKBACK] = cm_IoctlCheckVolumes;
!         smb_ioctlProcsp[VIOCSETCACHESIZE] = cm_IoctlSetCacheSize;
!         smb_ioctlProcsp[VIOCGETCACHEPARMS] = cm_IoctlGetCacheParms;
!         smb_ioctlProcsp[VIOCGETCELL] = cm_IoctlGetCell;
!         smb_ioctlProcsp[VIOCNEWCELL] = cm_IoctlNewCell;
!         smb_ioctlProcsp[VIOC_GET_WS_CELL] = cm_IoctlGetWsCell;
!         smb_ioctlProcsp[VIOC_AFS_SYSNAME] = cm_IoctlSysName;
!         smb_ioctlProcsp[VIOC_GETCELLSTATUS] = cm_IoctlGetCellStatus;
!         smb_ioctlProcsp[VIOC_SETCELLSTATUS] = cm_IoctlSetCellStatus;
!         smb_ioctlProcsp[VIOC_SETSPREFS] = cm_IoctlSetSPrefs;
!         smb_ioctlProcsp[VIOC_GETSPREFS] = cm_IoctlGetSPrefs;
!         smb_ioctlProcsp[VIOC_STOREBEHIND] = cm_IoctlStoreBehind;
!         smb_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = cm_IoctlCreateMountPoint;
!         smb_ioctlProcsp[VIOC_TRACECTL] = cm_IoctlTraceControl;
! 	smb_ioctlProcsp[VIOCSETTOK] = cm_IoctlSetToken;
! 	smb_ioctlProcsp[VIOCGETTOK] = cm_IoctlGetTokenIter;
! 	smb_ioctlProcsp[VIOCNEWGETTOK] = cm_IoctlGetToken;
! 	smb_ioctlProcsp[VIOCDELTOK] = cm_IoctlDelToken;
! 	smb_ioctlProcsp[VIOCDELALLTOK] = cm_IoctlDelAllToken;
! 	smb_ioctlProcsp[VIOC_SYMLINK] = cm_IoctlSymlink;
! 	smb_ioctlProcsp[VIOC_LISTSYMLINK] = cm_IoctlListlink;
! 	smb_ioctlProcsp[VIOC_DELSYMLINK] = cm_IoctlDeletelink;
! 	smb_ioctlProcsp[VIOC_MAKESUBMOUNT] = cm_IoctlMakeSubmount;
! 	smb_ioctlProcsp[VIOC_GETRXKCRYPT] = cm_IoctlGetRxkcrypt;
! 	smb_ioctlProcsp[VIOC_SETRXKCRYPT] = cm_IoctlSetRxkcrypt;
! 	smb_ioctlProcsp[VIOC_ISSYMLINK] = cm_IoctlIslink;
! #ifdef DJGPP
! 	smb_ioctlProcsp[VIOC_SHUTDOWN] = cm_IoctlShutdown;
! #endif
! 	smb_ioctlProcsp[VIOC_TRACEMEMDUMP] = cm_IoctlMemoryDump;
! 	smb_ioctlProcsp[VIOC_ISSYMLINK] = cm_IoctlIslink;
!         smb_ioctlProcsp[VIOC_FLUSHALL] = cm_IoctlFlushAllVolumes;
!         smb_ioctlProcsp[VIOCGETFID] = cm_IoctlGetFid;
!         smb_ioctlProcsp[VIOCGETOWNER] = cm_IoctlGetOwner;
!         smb_ioctlProcsp[VIOC_RXSTAT_PROC] = cm_IoctlRxStatProcess;
!         smb_ioctlProcsp[VIOC_RXSTAT_PEER] = cm_IoctlRxStatPeer;
!         smb_ioctlProcsp[VIOC_UUIDCTL] = cm_IoctlUUIDControl;
!         smb_ioctlProcsp[VIOC_PATH_AVAILABILITY] = cm_IoctlPathAvailability;
!         smb_ioctlProcsp[VIOC_GETFILETYPE] = cm_IoctlGetFileType;
!         smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = cm_IoctlVolStatTest;
! }
  
  /* called to make a fid structure into an IOCTL fid structure */
! void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
  {
      smb_ioctl_t *iop;
      cm_space_t *copyPrefix;
--- 24,97 ----
  
  #include "smb.h"
  
! #include "cm_rpc.h"
! #include "afs/afsrpc.h"
! #include "afs/auth.h"
  
! smb_ioctlProc_t *smb_ioctlProcsp[SMB_IOCTL_MAXPROCS];
  
! void 
! smb_InitIoctl(void)
  {
!     int i;
!     for (i=0; i<SMB_IOCTL_MAXPROCS; i++)
!         smb_ioctlProcsp[i] = NULL;
! 
!     smb_ioctlProcsp[VIOCGETAL] = smb_IoctlGetACL;
!     smb_ioctlProcsp[VIOC_FILE_CELL_NAME] = smb_IoctlGetFileCellName;
!     smb_ioctlProcsp[VIOCSETAL] = smb_IoctlSetACL;
!     smb_ioctlProcsp[VIOC_FLUSHVOLUME] = smb_IoctlFlushVolume;
!     smb_ioctlProcsp[VIOCFLUSH] = smb_IoctlFlushFile;
!     smb_ioctlProcsp[VIOCSETVOLSTAT] = smb_IoctlSetVolumeStatus;
!     smb_ioctlProcsp[VIOCGETVOLSTAT] = smb_IoctlGetVolumeStatus;
!     smb_ioctlProcsp[VIOCWHEREIS] = smb_IoctlWhereIs;
!     smb_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = smb_IoctlStatMountPoint;
!     smb_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = smb_IoctlDeleteMountPoint;
!     smb_ioctlProcsp[VIOCCKSERV] = smb_IoctlCheckServers;
!     smb_ioctlProcsp[VIOC_GAG] = smb_IoctlGag;
!     smb_ioctlProcsp[VIOCCKBACK] = smb_IoctlCheckVolumes;
!     smb_ioctlProcsp[VIOCSETCACHESIZE] = smb_IoctlSetCacheSize;
!     smb_ioctlProcsp[VIOCGETCACHEPARMS] = smb_IoctlGetCacheParms;
!     smb_ioctlProcsp[VIOCGETCELL] = smb_IoctlGetCell;
!     smb_ioctlProcsp[VIOCNEWCELL] = smb_IoctlNewCell;
!     smb_ioctlProcsp[VIOC_GET_WS_CELL] = smb_IoctlGetWsCell;
!     smb_ioctlProcsp[VIOC_AFS_SYSNAME] = smb_IoctlSysName;
!     smb_ioctlProcsp[VIOC_GETCELLSTATUS] = smb_IoctlGetCellStatus;
!     smb_ioctlProcsp[VIOC_SETCELLSTATUS] = smb_IoctlSetCellStatus;
!     smb_ioctlProcsp[VIOC_SETSPREFS] = smb_IoctlSetSPrefs;
!     smb_ioctlProcsp[VIOC_GETSPREFS] = smb_IoctlGetSPrefs;
!     smb_ioctlProcsp[VIOC_STOREBEHIND] = smb_IoctlStoreBehind;
!     smb_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = smb_IoctlCreateMountPoint;
!     smb_ioctlProcsp[VIOC_TRACECTL] = smb_IoctlTraceControl;
!     smb_ioctlProcsp[VIOCSETTOK] = smb_IoctlSetToken;
!     smb_ioctlProcsp[VIOCGETTOK] = smb_IoctlGetTokenIter;
!     smb_ioctlProcsp[VIOCNEWGETTOK] = smb_IoctlGetToken;
!     smb_ioctlProcsp[VIOCDELTOK] = smb_IoctlDelToken;
!     smb_ioctlProcsp[VIOCDELALLTOK] = smb_IoctlDelAllToken;
!     smb_ioctlProcsp[VIOC_SYMLINK] = smb_IoctlSymlink;
!     smb_ioctlProcsp[VIOC_LISTSYMLINK] = smb_IoctlListlink;
!     smb_ioctlProcsp[VIOC_DELSYMLINK] = smb_IoctlDeletelink;
!     smb_ioctlProcsp[VIOC_MAKESUBMOUNT] = smb_IoctlMakeSubmount;
!     smb_ioctlProcsp[VIOC_GETRXKCRYPT] = smb_IoctlGetRxkcrypt;
!     smb_ioctlProcsp[VIOC_SETRXKCRYPT] = smb_IoctlSetRxkcrypt;
!     smb_ioctlProcsp[VIOC_ISSYMLINK] = smb_IoctlIslink;
!     smb_ioctlProcsp[VIOC_TRACEMEMDUMP] = smb_IoctlMemoryDump;
!     smb_ioctlProcsp[VIOC_ISSYMLINK] = smb_IoctlIslink;
!     smb_ioctlProcsp[VIOC_FLUSHALL] = smb_IoctlFlushAllVolumes;
!     smb_ioctlProcsp[VIOCGETFID] = smb_IoctlGetFid;
!     smb_ioctlProcsp[VIOCGETOWNER] = smb_IoctlGetOwner;
!     smb_ioctlProcsp[VIOC_RXSTAT_PROC] = smb_IoctlRxStatProcess;
!     smb_ioctlProcsp[VIOC_RXSTAT_PEER] = smb_IoctlRxStatPeer;
!     smb_ioctlProcsp[VIOC_UUIDCTL] = smb_IoctlUUIDControl;
!     smb_ioctlProcsp[VIOC_PATH_AVAILABILITY] = smb_IoctlPathAvailability;
!     smb_ioctlProcsp[VIOC_GETFILETYPE] = smb_IoctlGetFileType;
!     smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = smb_IoctlVolStatTest;
!     smb_ioctlProcsp[VIOC_UNICODECTL] = smb_IoctlUnicodeControl;
! }       
  
  /* called to make a fid structure into an IOCTL fid structure */
! void 
! smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
  {
      smb_ioctl_t *iop;
      cm_space_t *copyPrefix;
***************
*** 107,113 ****
      }
      if (prefix) {
          copyPrefix = cm_GetSpace();
!         strcpy(copyPrefix->data, prefix->data);
          fidp->ioctlp->prefix = copyPrefix;
      }
      lock_ReleaseMutex(&fidp->mx);
--- 108,114 ----
      }
      if (prefix) {
          copyPrefix = cm_GetSpace();
!         StringCbCopy(copyPrefix->data, CM_UTILS_SPACESIZE, prefix->data);
          fidp->ioctlp->prefix = copyPrefix;
      }
      lock_ReleaseMutex(&fidp->mx);
***************
*** 117,138 ****
   * this is the first read call.  This is the function that actually makes the
   * call to the ioctl code.
   */
! long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     long opcode;
      smb_ioctlProc_t *procp = NULL;
!     long code;
  
!     if (ioctlp->flags & SMB_IOCTLFLAG_DATAIN) {
!         ioctlp->flags &= ~SMB_IOCTLFLAG_DATAIN;
  
          /* do the call now, or fail if we didn't get an opcode, or
           * enough of an opcode.
           */
!         if (ioctlp->inCopied < sizeof(long)) 
              return CM_ERROR_INVAL;
!         memcpy(&opcode, ioctlp->inDatap, sizeof(long));
!         ioctlp->inDatap += sizeof(long);
  
          osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
  
--- 118,140 ----
   * this is the first read call.  This is the function that actually makes the
   * call to the ioctl code.
   */
! afs_int32
! smb_IoctlPrepareRead(struct smb_fid *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
  {
!     afs_int32 opcode;
      smb_ioctlProc_t *procp = NULL;
!     afs_int32 code;
  
!     if (ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN) {
!         ioctlp->ioctl.flags &= ~CM_IOCTLFLAG_DATAIN;
  
          /* do the call now, or fail if we didn't get an opcode, or
           * enough of an opcode.
           */
!         if (ioctlp->ioctl.inCopied < sizeof(afs_int32)) 
              return CM_ERROR_INVAL;
!         memcpy(&opcode, ioctlp->ioctl.inDatap, sizeof(afs_int32));
!         ioctlp->ioctl.inDatap += sizeof(afs_int32);
  
          osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
  
***************
*** 146,158 ****
              return CM_ERROR_BADOP;
  
          /* otherwise, make the call */
!         ioctlp->outDatap += sizeof(long);	/* reserve room for return code */
          code = (*procp)(ioctlp, userp);
  
          osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
  
          /* copy in return code */
!         memcpy(ioctlp->outAllocp, &code, sizeof(long));
      }
      return 0;
  }
--- 148,160 ----
              return CM_ERROR_BADOP;
  
          /* otherwise, make the call */
!         ioctlp->ioctl.outDatap += sizeof(afs_int32); /* reserve room for return code */
          code = (*procp)(ioctlp, userp);
  
          osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
  
          /* copy in return code */
!         memcpy(ioctlp->ioctl.outAllocp, &code, sizeof(afs_int32));
      }
      return 0;
  }
***************
*** 161,336 ****
   * a series of reads (or the very first call), then we start a new call.
   * We also ensure that things are properly initialized for the start of a call.
   */
! void smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
  {
! 	/* make sure the buffer(s) are allocated */
! 	if (!ioctlp->inAllocp) ioctlp->inAllocp = malloc(SMB_IOCTL_MAXDATA);
!         if (!ioctlp->outAllocp) ioctlp->outAllocp = malloc(SMB_IOCTL_MAXDATA);
! 
! 	/* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
!        (void) memset(ioctlp->inAllocp, 0, SMB_IOCTL_MAXDATA);
!        (void) memset(ioctlp->outAllocp, 0, SMB_IOCTL_MAXDATA);
! 
! 	/* and make sure that we've reset our state for the new incoming request */
! 	if (!(ioctlp->flags & SMB_IOCTLFLAG_DATAIN)) {
! 	        ioctlp->inCopied = 0;
! 	        ioctlp->outCopied = 0;
! 		ioctlp->inDatap = ioctlp->inAllocp;
! 		ioctlp->outDatap = ioctlp->outAllocp;
! 	        ioctlp->flags |= SMB_IOCTLFLAG_DATAIN;
! 	}
! }
  
  /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
! long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
! 	smb_packet_t *outp)
  {
! 	smb_ioctl_t *iop;
!         long count;
!         long leftToCopy;
!         char *op;
!         long code;
!         cm_user_t *userp;
! 
!         iop = fidp->ioctlp;
!         count = smb_GetSMBParm(inp, 1);
!         userp = smb_GetUserFromVCP(vcp, inp);
  
! 	/* Identify tree */
      code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
      if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
  
! 	/* turn the connection around, if required */
! 	code = smb_IoctlPrepareRead(fidp, iop, userp);
  
! 	if (code) {
! 		cm_ReleaseUser(userp);
! 		return code;
!         }
  
! 	leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
!         if (count > leftToCopy) count = leftToCopy;
!         
!         /* now set the parms for a read of count bytes */
!         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);
! 
! 	smb_SetSMBDataLength(outp, count+3);
! 
!         op = smb_GetSMBData(outp, NULL);
!         *op++ = 1;
!         *op++ = (char)(count & 0xff);
!         *op++ = (char)((count >> 8) & 0xff);
!         
! 	/* now copy the data into the response packet */
!         memcpy(op, iop->outCopied + iop->outAllocp, count);
  
!         /* and adjust the counters */
!         iop->outCopied += count;
!         
!         cm_ReleaseUser(userp);
  
!         return 0;
  }
  
  /* called from smb_ReceiveCoreWrite when we receive a write call on the IOCTL
   * file descriptor.
   */
! long smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	smb_ioctl_t *iop;
!         long count;
!         long code;
!         char *op;
!         int inDataBlockCount;
! 
! 	code = 0;
! 	count = smb_GetSMBParm(inp, 1);
!         iop = fidp->ioctlp;
          
! 	smb_IoctlPrepareWrite(fidp, iop);
  
!         op = smb_GetSMBData(inp, NULL);
! 	op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
  	
!         if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
! 		code = CM_ERROR_TOOBIG;
!                 goto done;
!         }
          
! 	/* copy data */
!         memcpy(iop->inDatap + iop->inCopied, op, count);
          
!         /* adjust counts */
!         iop->inCopied += count;
  
! done:
! 	/* return # of bytes written */
! 	if (code == 0) {
! 		smb_SetSMBParm(outp, 0, count);
!                 smb_SetSMBDataLength(outp, 0);
!         }
  
!         return code;
! }
  
  /* called from smb_ReceiveV3WriteX when we receive a write call on the IOCTL
   * file descriptor.
   */
! long smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
! 	smb_ioctl_t *iop;
!         long count;
!         long code;
!         char *op;
!         int inDataBlockCount;
! 
! 	code = 0;
! 	count = smb_GetSMBParm(inp, 10);
!         iop = fidp->ioctlp;
!         
! 	smb_IoctlPrepareWrite(fidp, iop);
  
!         op = inp->data + smb_GetSMBParm(inp, 11);
!         inDataBlockCount = count;
! 	
!         if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
! 		code = CM_ERROR_TOOBIG;
!                 goto done;
!         }
!         
! 	/* copy data */
!         memcpy(iop->inDatap + iop->inCopied, op, count);
          
!         /* adjust counts */
!         iop->inCopied += count;
  
! done:
! 	/* return # of bytes written */
! 	if (code == 0) {
! 		smb_SetSMBParm(outp, 2, count);
!                 smb_SetSMBParm(outp, 3, 0); /* reserved */
! 	        smb_SetSMBParm(outp, 4, 0); /* reserved */
! 	        smb_SetSMBParm(outp, 5, 0); /* reserved */
! 	        smb_SetSMBDataLength(outp, 0);
!         }
  
!         return code;
! }
  
  
  /* called from V3 read to handle IOCTL descriptor reads */
! long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_ioctl_t *iop;
      long count;
!     long code;
      long leftToCopy;
      char *op;
      cm_user_t *userp;
--- 163,345 ----
   * a series of reads (or the very first call), then we start a new call.
   * We also ensure that things are properly initialized for the start of a call.
   */
! void 
! smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
  {
!     /* make sure the buffer(s) are allocated */
!     if (!ioctlp->ioctl.inAllocp) 
!         ioctlp->ioctl.inAllocp = malloc(SMB_IOCTL_MAXDATA);
!     if (!ioctlp->ioctl.outAllocp)
!         ioctlp->ioctl.outAllocp = malloc(SMB_IOCTL_MAXDATA);
! 
!     /* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
!     (void) memset(ioctlp->ioctl.inAllocp, 0, SMB_IOCTL_MAXDATA);
!     (void) memset(ioctlp->ioctl.outAllocp, 0, SMB_IOCTL_MAXDATA);
! 
!     /* and make sure that we've reset our state for the new incoming request */
!     if (!(ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN)) {
!         ioctlp->ioctl.inCopied = 0;
!         ioctlp->ioctl.outCopied = 0;
!         ioctlp->ioctl.inDatap = ioctlp->ioctl.inAllocp;
!         ioctlp->ioctl.outDatap = ioctlp->ioctl.outAllocp;
!         ioctlp->ioctl.flags |= CM_IOCTLFLAG_DATAIN;
!     }
! }       
  
  /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
! afs_int32
! smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     smb_ioctl_t *iop;
!     long count;
!     afs_int32 leftToCopy;
!     char *op;
!     afs_int32 code;
!     cm_user_t *userp;
! 
!     iop = fidp->ioctlp;
!     count = smb_GetSMBParm(inp, 1);
!     userp = smb_GetUserFromVCP(vcp, inp);
  
!     /* Identify tree */
      code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
      if(code) {
          cm_ReleaseUser(userp);
          return CM_ERROR_NOSUCHPATH;
      }
  
!     /* turn the connection around, if required */
!     code = smb_IoctlPrepareRead(fidp, iop, userp);
  
!     if (code) {
!         cm_ReleaseUser(userp);
!         return code;
!     }
  
!     leftToCopy = (afs_int32)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
!     if (count > leftToCopy)
!         count = leftToCopy;
! 
!     /* now set the parms for a read of count bytes */
!     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);
  
!     smb_SetSMBDataLength(outp, count+3);
! 
!     op = smb_GetSMBData(outp, NULL);
!     *op++ = 1;
!     *op++ = (char)(count & 0xff);
!     *op++ = (char)((count >> 8) & 0xff);
! 
!     /* now copy the data into the response packet */
!     memcpy(op, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
  
!     /* and adjust the counters */
!     iop->ioctl.outCopied += count;
! 
!     cm_ReleaseUser(userp);
! 
!     return 0;
  }
  
  /* called from smb_ReceiveCoreWrite when we receive a write call on the IOCTL
   * file descriptor.
   */
! afs_int32
! smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     smb_ioctl_t *iop;
!     long count;
!     afs_int32 code;
!     char *op;
!     int inDataBlockCount;
! 
!     code = 0;
!     count = smb_GetSMBParm(inp, 1);
!     iop = fidp->ioctlp;
          
!     smb_IoctlPrepareWrite(fidp, iop);
  
!     op = smb_GetSMBData(inp, NULL);
!     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
  	
!     if (count + iop->ioctl.inCopied > SMB_IOCTL_MAXDATA) {
!         code = CM_ERROR_TOOBIG;
!         goto done;
!     }
          
!     /* copy data */
!     memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, op, count);
          
!     /* adjust counts */
!     iop->ioctl.inCopied += count;
  
!   done:
!     /* return # of bytes written */
!     if (code == 0) {
!         smb_SetSMBParm(outp, 0, count);
!         smb_SetSMBDataLength(outp, 0);
!     }
  
!     return code;
! }       
  
  /* called from smb_ReceiveV3WriteX when we receive a write call on the IOCTL
   * file descriptor.
   */
! afs_int32
! smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
!     smb_ioctl_t *iop;
!     long count;
!     afs_int32 code;
!     char *op;
!     int inDataBlockCount;
  
!     code = 0;
!     count = smb_GetSMBParm(inp, 10);
!     iop = fidp->ioctlp;
! 
!     smb_IoctlPrepareWrite(fidp, iop);
! 
!     op = inp->data + smb_GetSMBParm(inp, 11);
!     inDataBlockCount = count;
! 
!     if (count + iop->ioctl.inCopied > SMB_IOCTL_MAXDATA) {
!         code = CM_ERROR_TOOBIG;
!         goto done;
!     }
          
!     /* copy data */
!     memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, op, count);
  
!     /* adjust counts */
!     iop->ioctl.inCopied += count;
  
!   done:
!     /* return # of bytes written */
!     if (code == 0) {
!         smb_SetSMBParm(outp, 2, count);
!         smb_SetSMBParm(outp, 3, 0); /* reserved */
!         smb_SetSMBParm(outp, 4, 0); /* reserved */
!         smb_SetSMBParm(outp, 5, 0); /* reserved */
!         smb_SetSMBDataLength(outp, 0);
!     }
! 
!     return code;
! }       
  
  
  /* called from V3 read to handle IOCTL descriptor reads */
! afs_int32
! smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  {
      smb_ioctl_t *iop;
      long count;
!     afs_int32 code;
      long leftToCopy;
      char *op;
      cm_user_t *userp;
***************
*** 344,352 ****
      osi_assertx(userp != NULL, "null cm_user_t");
      iop->uidp = uidp;
      if (uidp && uidp->unp) {
!         osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
                    uidp->userID, userp,
!                   osi_LogSaveString(afsd_logp, uidp->unp->name));
      } else {
          if (uidp)
  	    osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
--- 353,361 ----
      osi_assertx(userp != NULL, "null cm_user_t");
      iop->uidp = uidp;
      if (uidp && uidp->unp) {
!         osi_Log3(afsd_logp, "Ioctl uid %d user %x name %S",
                    uidp->userID, userp,
!                   osi_LogSaveClientString(afsd_logp, uidp->unp->name));
      } else {
          if (uidp)
  	    osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
***************
*** 374,381 ****
  	return code;
      }
  
!     leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
!     if (count > leftToCopy) count = leftToCopy;
          
      /* 0 and 1 are reserved for request chaining, were setup by our caller,
       * and will be further filled in after we return.
--- 383,391 ----
  	return code;
      }
  
!     leftToCopy = (long)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
!     if (count > leftToCopy) 
!         count = leftToCopy;
          
      /* 0 and 1 are reserved for request chaining, were setup by our caller,
       * and will be further filled in after we return.
***************
*** 403,412 ****
      smb_SetSMBDataLength(outp, count);
          
      /* now copy the data into the response packet */
!     memcpy(op, iop->outCopied + iop->outAllocp, count);
  
      /* and adjust the counters */
!     iop->outCopied += count;
  
      /* and cleanup things */
      cm_ReleaseUser(userp);
--- 413,422 ----
      smb_SetSMBDataLength(outp, count);
          
      /* now copy the data into the response packet */
!     memcpy(op, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
  
      /* and adjust the counters */
!     iop->ioctl.outCopied += count;
  
      /* and cleanup things */
      cm_ReleaseUser(userp);
***************
*** 415,479 ****
  }	
  
  /* called from Read Raw to handle IOCTL descriptor reads */
! long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
! 		      smb_packet_t *outp
! #ifdef DJGPP
! 		      , dos_ptr rawBuf
! #endif /* DJGPP */
! 		      )
  {
      smb_ioctl_t *iop;
      long leftToCopy;
      NCB *ncbp;
!     long code;
      cm_user_t *userp;
! #ifdef DJGPP
!     dos_ptr dos_ncb;
! 
!     if (rawBuf == 0)
!     {
! 	osi_Log0(afsd_logp, "Failed to get raw buf for smb_IoctlReadRaw");
! 	return -1;
!     }
! #endif /* DJGPP */
  
      iop = fidp->ioctlp;
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
      /* Log the user */
!     {
! 	smb_user_t *uidp;
! 
! 	uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
! 	if (uidp && uidp->unp) {
! 	    osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
! 		     uidp->userID, userp,
! 		     osi_LogSaveString(afsd_logp, uidp->unp->name));
! 	} else if (uidp) {
! 	    osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
! 		     uidp->userID, userp);
! 	} else {
! 	    osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
! 		     userp);
! 	}
! 	if (uidp) 
! 	    smb_ReleaseUID(uidp);
!     }	
  
      code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
      if (code) {
!         cm_ReleaseUser(userp);
!         return CM_ERROR_NOSUCHPATH;
      }
  
      code = smb_IoctlPrepareRead(fidp, iop, userp);
      if (code) {
! 	cm_ReleaseUser(userp);
! 	return code;
      }
  
!     leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
  
      ncbp = outp->ncbp;
      memset((char *)ncbp, 0, sizeof(NCB));
--- 425,473 ----
  }	
  
  /* called from Read Raw to handle IOCTL descriptor reads */
! afs_int32
! smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
!                  smb_packet_t *outp)
  {
      smb_ioctl_t *iop;
      long leftToCopy;
      NCB *ncbp;
!     afs_int32 code;
      cm_user_t *userp;
!     smb_user_t *uidp;
  
      iop = fidp->ioctlp;
  
      userp = smb_GetUserFromVCP(vcp, inp);
  
      /* Log the user */
!     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
!     if (uidp && uidp->unp) {
!         osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
!                  uidp->userID, userp,
!                  osi_LogSaveClientString(afsd_logp, uidp->unp->name));
!     } else if (uidp) {
!         osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
!                  uidp->userID, userp);
!     } else {
!         osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
!                   userp);
!     }
!     if (uidp) 
!         smb_ReleaseUID(uidp);
  
      code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
      if (code) {
!         code = CM_ERROR_NOSUCHPATH;
!         goto done;
      }
  
      code = smb_IoctlPrepareRead(fidp, iop, userp);
      if (code) {
! 	goto done;
      }
  
!     leftToCopy = (long)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
  
      ncbp = outp->ncbp;
      memset((char *)ncbp, 0, sizeof(NCB));
***************
*** 484,503 ****
      /*ncbp->ncb_lana_num = smb_LANadapter;*/
      ncbp->ncb_lana_num = vcp->lana;
  
! #ifndef DJGPP
!     ncbp->ncb_buffer = iop->outCopied + iop->outAllocp;
      code = Netbios(ncbp);
- #else /* DJGPP */
-     dosmemput(iop->outCopied + iop->outAllocp, ncbp->ncb_length, rawBuf);
-     ncbp->ncb_buffer = rawBuf;
-     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-     code = Netbios(ncbp, dos_ncb);
- #endif /* !DJGPP */
  
      if (code != 0)
  	osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
  
      cm_ReleaseUser(userp);
  
      return 0;
  }
--- 478,1839 ----
      /*ncbp->ncb_lana_num = smb_LANadapter;*/
      ncbp->ncb_lana_num = vcp->lana;
  
!     ncbp->ncb_buffer = iop->ioctl.outCopied + iop->ioctl.outAllocp;
      code = Netbios(ncbp);
  
      if (code != 0)
  	osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
  
+   done:
      cm_ReleaseUser(userp);
  
+     return code;
+ }
+ 
+ /* parse the passed-in file name and do a namei on it.  If we fail,
+  * return an error code, otherwise return the vnode located in *scpp.
+  */
+ #define CM_PARSE_FLAG_LITERAL 1
+ 
+ afs_int32
+ smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
+                    cm_scache_t **scpp, afs_uint32 flags)
+ {
+     long code;
+     cm_scache_t  *substRootp = NULL;
+     cm_scache_t  *iscp = NULL;
+     char      *inPath;
+     clientchar_t *relativePath = NULL;
+     clientchar_t *lastComponent = NULL;
+     afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
+ 
+     inPath = ioctlp->ioctl.inDatap;
+     /* setup the next data value for the caller to use */
+     ioctlp->ioctl.inDatap += (long)strlen(ioctlp->ioctl.inDatap) + 1;
+ 
+     osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,inPath));
+ 
+     /* This is usually the file name, but for StatMountPoint it is the path. */
+     /* ioctlp->ioctl.inDatap can be either of the form:
+      *    \path\.
+      *    \path\file
+      *    \\netbios-name\submount\path\.
+      *    \\netbios-name\submount\path\file
+      */
+ 
+     /* We do not perform path name translation on the ioctl path data
+      * because these paths were not translated by Windows through the
+      * file system API.  Therefore, they are not OEM characters but
+      * whatever the display character set is.
+      */
+ 
+     // TranslateExtendedChars(relativePath);
+ 
+     /* This is usually nothing, but for StatMountPoint it is the file name. */
+     // TranslateExtendedChars(ioctlp->ioctl.inDatap);
+ 
+     /* If the string starts with our UTF-8 prefix (which is the
+        sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
+        strings), we assume that the provided path is UTF-8.  Otherwise
+        we have to convert the string to UTF-8, since that is what we
+        want to use everywhere else.*/
+ 
+     if (memcmp(inPath, utf8_prefix, utf8_prefix_size) == 0) {
+         /* String is UTF-8 */
+         inPath += utf8_prefix_size;
+         ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
+ 
+         relativePath = cm_Utf8ToClientStringAlloc(inPath, -1, NULL);
+     } else {
+         int cch;
+ 
+         /* Not a UTF-8 string */
+         /* TODO: If this is an OEM string, we should convert it to
+            UTF-8. */
+         if (smb_StoreAnsiFilenames) {
+             cch = cm_AnsiToClientString(inPath, -1, NULL, 0);
+ #ifdef DEBUG
+             osi_assert(cch > 0);
+ #endif
+             relativePath = malloc(cch * sizeof(clientchar_t));
+             cm_AnsiToClientString(inPath, -1, relativePath, cch);
+         } else {
+             TranslateExtendedChars(inPath);
+ 
+             cch = cm_OemToClientString(inPath, -1, NULL, 0);
+ #ifdef DEBUG
+             osi_assert(cch > 0);
+ #endif
+             relativePath = malloc(cch * sizeof(clientchar_t));
+             cm_OemToClientString(inPath, -1, relativePath, cch);
+         }
+     }
+ 
+     if (relativePath[0] == relativePath[1] &&
+         relativePath[1] == '\\' && 
+         !cm_ClientStrCmpNI(cm_NetbiosNameC, relativePath+2,
+                            cm_ClientStrLen(cm_NetbiosNameC))) 
+     {
+         clientchar_t shareName[256];
+         clientchar_t *sharePath;
+         int shareFound, i;
+ 
+         /* We may have found a UNC path. 
+          * If the first component is the NetbiosName,
+          * then throw out the second component (the submount)
+          * since it had better expand into the value of ioctl->tidPathp
+          */
+         clientchar_t * p;
+         p = relativePath + 2 + cm_ClientStrLen(cm_NetbiosNameC) + 1;			/* buffer overflow vuln.? */
+         if ( !cm_ClientStrCmpNI(_C("all"),  p,  3) )
+             p += 4;
+ 
+         for (i = 0; *p && *p != '\\'; i++,p++ ) {
+             shareName[i] = *p;
+         }
+         p++;                    /* skip past trailing slash */
+         shareName[i] = 0;       /* terminate string */
+ 
+         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
+         if ( shareFound ) {
+             /* we found a sharename, therefore use the resulting path */
+             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, sharePath, reqp, &substRootp);
+             free(sharePath);
+             if (code) {
+ 		osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
+                 if (relativePath)
+                     free(relativePath);
+                 return code;
+ 	    }
+ 
+ 	    lastComponent = cm_ClientStrRChr(p,  '\\');
+ 	    if (lastComponent && (lastComponent - p) > 1 &&
+                 cm_ClientStrLen(lastComponent) > 1) {
+ 		*lastComponent = '\0';
+ 		lastComponent++;
+ 
+ 		code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                                 userp, NULL, reqp, &iscp);
+ 		if (code == 0)
+ 		    code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+ 				    userp, NULL, reqp, scpp);
+ 		if (iscp)
+ 		    cm_ReleaseSCache(iscp);
+ 	    } else {
+ 		code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
+ 				userp, NULL, reqp, scpp);
+ 	    }
+ 	    cm_ReleaseSCache(substRootp);
+             if (code) {
+ 		osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", code);
+                 if (relativePath)
+                     free(relativePath);
+                 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 + cm_ClientStrLen(cm_NetbiosNameC) + 1;
+             if ( !cm_ClientStrCmpNI(_C("all"),  p,  3) )
+                 p += 4;
+ 
+             shareName[0] = '/';
+             for (i = 1; *p && *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_data.rootSCachep, ioctlp->prefix->wdata,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, shareName, reqp, &substRootp);
+             if (code) {
+ 		osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
+                 if (relativePath)
+                     free(relativePath);
+                 return code;
+ 	    }
+ 
+ 	    lastComponent = cm_ClientStrRChr(p,  '\\');
+ 	    if (lastComponent && (lastComponent - p) > 1 &&
+                 cm_ClientStrLen(lastComponent) > 1) {
+ 		*lastComponent = '\0';
+ 		lastComponent++;
+ 
+ 		code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                                 userp, NULL, reqp, &iscp);
+ 		if (code == 0)
+ 		    code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+ 				    userp, NULL, reqp, scpp);
+ 		if (iscp)
+ 		    cm_ReleaseSCache(iscp);
+ 	    } else {
+ 		code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
+ 				userp, NULL, reqp, scpp);
+ 	    }
+ 
+ 	    if (code) {
+ 		cm_ReleaseSCache(substRootp);
+ 		osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
+                 if (relativePath)
+                     free(relativePath);
+                 return code;
+ 	    }
+         }
+     } else {
+         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+                          CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                          userp, ioctlp->tidPathp, reqp, &substRootp);
+         if (code) {
+ 	    osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
+             if (relativePath)
+                 free(relativePath);
+             return code;
+ 	}
+         
+ 	lastComponent = cm_ClientStrRChr(relativePath,  '\\');
+ 	if (lastComponent && (lastComponent - relativePath) > 1 &&
+             cm_ClientStrLen(lastComponent) > 1) {
+ 	    *lastComponent = '\0';
+ 	    lastComponent++;
+ 
+ 	    code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, &iscp);
+ 	    if (code == 0)
+ 		code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
+                                 userp, NULL, reqp, scpp);
+ 	    if (iscp)
+ 		cm_ReleaseSCache(iscp);
+ 	} else {
+ 	    code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | follow,
+                             userp, NULL, reqp, scpp);
+ 	}
+         if (code) {
+ 	    cm_ReleaseSCache(substRootp);
+ 	    osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
+             if (relativePath)
+                 free(relativePath);
+             return code;
+ 	}
+     }
+ 
+     if (substRootp)
+ 	cm_ReleaseSCache(substRootp);
+ 
+     /* and return success */
+     osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
+ 
+     if (relativePath)
+         free(relativePath);
+     return 0;
+ }
+ 
+ 
+ 
+ #define LEAF_SIZE 256
+ /* parse the passed-in file name and do a namei on its parent.  If we fail,
+  * return an error code, otherwise return the vnode located in *scpp.
+  */
+ afs_int32
+ smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
+                      cm_scache_t **scpp, clientchar_t *leafp)
+ {
+     long code;
+     clientchar_t tbuffer[1024];
+     clientchar_t *tp, *jp;
+     cm_scache_t *substRootp = NULL;
+     clientchar_t *inpathp = NULL;
+     char *inpathdatap;
+ 
+     inpathdatap = ioctlp->ioctl.inDatap;
+ 
+     /* If the string starts with our UTF-8 prefix (which is the
+        sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
+        strings), we assume that the provided path is UTF-8.  Otherwise
+        we have to convert the string to UTF-8, since that is what we
+        want to use everywhere else.*/
+ 
+     if (memcmp(inpathdatap, utf8_prefix, utf8_prefix_size) == 0) {
+ 
+         /* String is UTF-8 */
+         inpathdatap += utf8_prefix_size;
+         ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
+ 
+         inpathp = cm_Utf8ToClientStringAlloc(inpathdatap, -1, NULL);
+     } else {
+         int cch;
+ 
+         /* Not a UTF-8 string */
+         /* TODO: If this is an OEM string, we should convert it to
+            UTF-8. */
+         if (smb_StoreAnsiFilenames) {
+             cch = cm_AnsiToClientString(inpathdatap, -1, NULL, 0);
+ #ifdef DEBUG
+             osi_assert(cch > 0);
+ #endif
+             inpathp = malloc(cch * sizeof(clientchar_t));
+             cm_AnsiToClientString(inpathdatap, -1, inpathp, cch);
+         } else {
+             TranslateExtendedChars(inpathdatap);
+ 
+             cch = cm_OemToClientString(inpathdatap, -1, NULL, 0);
+ #ifdef DEBUG
+             osi_assert(cch > 0);
+ #endif
+             inpathp = malloc(cch * sizeof(clientchar_t));
+             cm_OemToClientString(inpathdatap, -1, inpathp, cch);
+         }
+     }
+ 
+     cm_ClientStrCpy(tbuffer, lengthof(tbuffer), inpathp);
+     tp = cm_ClientStrRChr(tbuffer, '\\');
+     jp = cm_ClientStrRChr(tbuffer, '/');
+     if (!tp)
+         tp = jp;
+     else if (jp && (tp - tbuffer) < (jp - tbuffer))
+         tp = jp;
+     if (!tp) {
+         cm_ClientStrCpy(tbuffer, lengthof(tbuffer), _C("\\"));
+         if (leafp)
+             cm_ClientStrCpy(leafp, LEAF_SIZE, inpathp);
+     }
+     else {
+         *tp = 0;
+         if (leafp) 
+             cm_ClientStrCpy(leafp, LEAF_SIZE, tp+1);
+     }
+ 
+     free(inpathp);
+     inpathp = NULL;             /* We don't need this from this point on */
+ 
+     if (tbuffer[0] == tbuffer[1] &&
+         tbuffer[1] == '\\' && 
+         !cm_ClientStrCmpNI(cm_NetbiosNameC, tbuffer+2,
+                            cm_ClientStrLen(cm_NetbiosNameC))) 
+     {
+         clientchar_t shareName[256];
+         clientchar_t *sharePath;
+         int shareFound, i;
+ 
+         /* We may have found a UNC path. 
+          * If the first component is the NetbiosName,
+          * then throw out the second component (the submount)
+          * since it had better expand into the value of ioctl->tidPathp
+          */
+         clientchar_t * p;
+         p = tbuffer + 2 + cm_ClientStrLen(cm_NetbiosNameC) + 1;
+         if ( !cm_ClientStrCmpNI(_C("all"),  p,  3) )
+             p += 4;
+ 
+         for (i = 0; *p && *p != '\\'; i++,p++ ) {
+             shareName[i] = *p;
+         }
+         p++;                    /* skip past trailing slash */
+         shareName[i] = 0;       /* terminate string */
+ 
+         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
+         if ( shareFound ) {
+             /* we found a sharename, therefore use the resulting path */
+             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, sharePath, reqp, &substRootp);
+             free(sharePath);
+             if (code) return code;
+ 
+             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, scpp);
+ 	    cm_ReleaseSCache(substRootp);
+             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 + cm_ClientStrLen(cm_NetbiosNameC) + 1;
+             if ( !cm_ClientStrCmpNI(_C("all"),  p,  3) )
+                 p += 4;
+ 
+             shareName[0] = '/';
+             for (i = 1; *p && *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_data.rootSCachep, ioctlp->prefix->wdata,
+                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, shareName, reqp, &substRootp);
+             if (code) return code;
+ 
+             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                             userp, NULL, reqp, scpp);
+ 	    cm_ReleaseSCache(substRootp);
+             if (code) return code;
+         }
+     } else {
+         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                         userp, ioctlp->tidPathp, reqp, &substRootp);
+         if (code) return code;
+ 
+         code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                         userp, NULL, reqp, scpp);
+ 	cm_ReleaseSCache(substRootp);
+         if (code) return code;
+     }
+ 
+     /* # of bytes of path */
+     code = (long)strlen(ioctlp->ioctl.inDatap) + 1;
+     ioctlp->ioctl.inDatap += code;
+ 
+     /* and return success */
      return 0;
  }
+ 
+ afs_int32 
+ smb_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;
+     afs_uuid_t uuid;
+     int flags;
+     char sessionKey[8];
+     int release_userp = 0;
+     clientchar_t *uname = NULL;
+     clientchar_t *smbname = NULL;
+     clientchar_t *wdir = NULL;
+     afs_int32 code = 0;
+ 
+     saveDataPtr = ioctlp->ioctl.inDatap;
+ 
+     cm_SkipIoctlPath(&ioctlp->ioctl);
+ 
+     tp = ioctlp->ioctl.inDatap;
+ 
+     /* ticket length */
+     memcpy(&ticketLen, tp, sizeof(ticketLen));
+     tp += sizeof(ticketLen);
+     if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
+         return CM_ERROR_INVAL;
+ 
+     /* remember ticket and skip over it for now */
+     ticket = tp;
+     tp += ticketLen;
+ 
+     /* clear token size */
+     memcpy(&ctSize, tp, sizeof(ctSize));
+     tp += sizeof(ctSize);
+     if (ctSize != sizeof(struct ClearToken))
+         return CM_ERROR_INVAL;
+ 
+     /* clear token */
+     memcpy(&ct, tp, ctSize);
+     tp += ctSize;
+     if (ct.AuthHandle == -1)
+         ct.AuthHandle = 999;	/* more rxvab compat stuff */
+ 
+     /* more stuff, if any */
+     if (ioctlp->ioctl.inCopied > tp - saveDataPtr) {
+         /* flags:  logon flag */
+         memcpy(&flags, tp, sizeof(int));
+         tp += sizeof(int);
+ 
+         /* cell name */
+         {
+             fschar_t * cellnamep;
+             clientchar_t * temp;
+ 
+             temp = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
+             cellnamep = cm_ClientStringToFsStringAlloc(temp, -1, NULL);
+             cellp = cm_GetCell(cellnamep, CM_FLAG_CREATE | CM_FLAG_NOPROBE);
+             free(cellnamep);
+             free(temp);
+         }
+ 
+         if (!cellp) {
+             code = CM_ERROR_NOSUCHCELL;
+             goto done;
+         }
+         tp += strlen(tp) + 1;
+ 
+         /* user name */
+         uname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
+         tp += strlen(tp) + 1;
+ 
+         if (flags & PIOCTL_LOGON) {
+             /* SMB user name with which to associate tokens */
+             smbname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
+             osi_Log2(smb_logp,"cm_IoctlSetToken for user [%S] smbname [%S]",
+                      osi_LogSaveClientString(smb_logp,uname),
+                      osi_LogSaveClientString(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_LogSaveClientString(smb_logp, uname));
+         }
+ 
+         /* uuid */
+         memcpy(&uuid, tp, sizeof(uuid));
+         if (!cm_FindTokenEvent(uuid, sessionKey)) {
+             code = CM_ERROR_INVAL;
+             goto done;
+         }
+     } else {
+         cellp = cm_data.rootCellp;
+         osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
+     }
+ 
+     if (flags & PIOCTL_LOGON) {
+         userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
+ 				     SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+ 	release_userp = 1;
+     }
+ 
+     /* store the token */
+     lock_ObtainMutex(&userp->mx);
+     ucellp = cm_GetUCell(userp, cellp);
+     osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
+     ucellp->ticketLen = ticketLen;
+     if (ucellp->ticketp)
+         free(ucellp->ticketp);	/* Discard old token if any */
+     ucellp->ticketp = malloc(ticketLen);
+     memcpy(ucellp->ticketp, ticket, ticketLen);
+     /*
+      * Get the session key from the RPC, rather than from the pioctl.
+      */
+     /*
+     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
+     */
+     memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
+     ucellp->kvno = ct.AuthHandle;
+     ucellp->expirationTime = ct.EndTimestamp;
+     ucellp->gen++;
+ #ifdef QUERY_AFSID
+     ucellp->uid = ANONYMOUSID;
+ #endif
+     if (uname) {
+         cm_ClientStringToFsString(uname, -1, ucellp->userName, MAXKTCNAMELEN);
+ #ifdef QUERY_AFSID
+ 	cm_UsernameToId(uname, ucellp, &ucellp->uid);
+ #endif
+     }
+     ucellp->flags |= CM_UCELLFLAG_RXKAD;
+     lock_ReleaseMutex(&userp->mx);
+ 
+     if (flags & PIOCTL_LOGON) {
+         ioctlp->ioctl.flags |= CM_IOCTLFLAG_LOGON;
+     }
+ 
+     cm_ResetACLCache(userp);
+ 
+   done:
+     if (release_userp)
+ 	cm_ReleaseUser(userp);
+ 
+     if (uname)
+         free(uname);
+ 
+     if (smbname)
+         free(smbname);
+ 
+     return code;
+ }
+ 
+ 
+ 
+ afs_int32
+ smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
+ {
+     smb_user_t *uidp = ioctlp->uidp;
+ 
+     if (uidp && uidp->unp) {
+         int cch;
+ 
+         cch = cm_ClientStringToUtf8(uidp->unp->name,
+                                     cm_ClientStrLen(uidp->unp->name),
+ 
+                                     ioctlp->ioctl.outDatap,
+                                     (SMB_IOCTL_MAXDATA -
+                                      (ioctlp->ioctl.outDatap - ioctlp->ioctl.outAllocp))
+                                     / sizeof(cm_utf8char_t));
+ 
+         ioctlp->ioctl.outDatap += cch * sizeof(cm_utf8char_t);
+     }
+ 
+     return 0;
+ }
+ 
+ afs_int32 
+ smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
+ {
+     cm_scache_t *scp;
+     afs_int32 code;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t *optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->ioctl);
+         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                   optionsp->fid.vnode, optionsp->fid.unique);
+         code = cm_GetSCache(&fid, &scp, userp, &req);
+     } else {
+         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     }
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlGetACL(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
+ {
+     cm_scache_t *scp;
+     afs_int32 code;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t *optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->ioctl);
+         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                   optionsp->fid.vnode, optionsp->fid.unique);
+         code = cm_GetSCache(&fid, &scp, userp, &req);
+     } else {
+         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     }
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlSetACL(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+     return code;
+ }
+ 
+ afs_int32
+ smb_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t *optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->ioctl);
+         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                   optionsp->fid.vnode, optionsp->fid.unique);
+         code = cm_GetSCache(&fid, &scp, userp, &req);
+     } else {
+         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     }
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlGetFileCellName(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+ 
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     cm_req_t req;
+ 
+     cm_InitReq(&req);
+ 
+     cm_SkipIoctlPath(&ioctlp->ioctl);	/* we don't care about the path */
+ 
+     return cm_IoctlFlushAllVolumes(&ioctlp->ioctl, userp, &req);
+ }
+ 
+ afs_int32 
+ smb_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t *optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->ioctl);
+         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                   optionsp->fid.vnode, optionsp->fid.unique);
+         code = cm_GetSCache(&fid, &scp, userp, &req);
+     } else {
+         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     }
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlFlushVolume(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+ 
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t *optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->ioctl);
+ 	cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                   optionsp->fid.vnode, optionsp->fid.unique);
+         code = cm_GetSCache(&fid, &scp, userp, &req);
+     } else {
+         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     }
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlFlushFile(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_req_t req;
+ 
+     cm_InitReq(&req);
+ 
+     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
+     if (code) return code;
+ 
+     code = cm_IoctlSetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
+     cm_ReleaseSCache(scp);
+ 
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_ioctlQueryOptions_t *optionsp;
+     afs_uint32 flags = 0;
+     cm_req_t req;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->ioctl);
+         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                   optionsp->fid.vnode, optionsp->fid.unique);
+         code = cm_GetSCache(&fid, &scp, userp, &req);
+     } else {
+         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     }
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlGetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+ 
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t * optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlGetFid(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+ 
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t * optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->ioctl);
+         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+                   optionsp->fid.vnode, optionsp->fid.unique);
+         code = cm_GetSCache(&fid, &scp, userp, &req);
+     } else {
+         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     }
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlGetFileType(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+ 
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t *optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->ioctl);
+         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                   optionsp->fid.vnode, optionsp->fid.unique);
+         code = cm_GetSCache(&fid, &scp, userp, &req);
+     } else {
+         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+     }
+     if (code) 
+         return code;
+ 
+     code = cm_IoctlGetOwner(&ioctlp->ioctl, userp, scp, &req);
+ 
+     cm_ReleaseSCache(scp);
+ 
+     return code;
+ }
+ 
+ afs_int32 
+ smb_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+ {
+     afs_int32 code;
+     cm_scache_t *scp;
+     cm_req_t req;
+     cm_ioctlQueryOptions_t *optionsp;
+     afs_uint32 flags = 0;
+ 
+     cm_InitReq(&req);
+ 
+     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+ 
+     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+         cm_fid_t fid;
+         cm_SkipIoctlPath(&ioctlp->i