Commit d1ca5496 authored by Robert Sprowson's avatar Robert Sprowson
Browse files

Workaround for NTFS returning resume keys of zero.

Detail:
  When the underlying FS is NTFS, eg. WinXP Pro, the requested
  resume keys for a directory search are always zero - this is passed
  back via OSGBPB and on the next call it triggers a new search. So
  we get stuck in an infinite loop.
  Now checks for a resume key stuck at zero, and makes a fake one static
  to the search context then sets the continuation bit in the SMB_FIND_NEXT
  call because the server returning the duff key remembers the position.
  Dir_CallbackFn could return with "taken" undefined. Move a few lines
  higher.
  Missing "#else" added to CHECK_ARMBOOT_EXISTS so if this is disabled
  no further attempt is made to find !ArmBoot.
  Couple of typos corrected.
  Spelling of "disk" changed to "disc" in an error message.
Admin:
  Tested with XP Pro SP3 with NTFS, directories which previously hung
  the filer now open correctly. Checked with XP Home SP3 with FAT32 to
  verify behaviour unchanged from 2.32.
  Note, with large directories the initial path translation triggers a
  dir search too which takes ages compared with the actual number of
  entries returned. This could be cached to make counting far faster.

Version 2.33. Tagged as 'LanManFS-2_33'
parent 186192a3
/* (2.32)
/* (2.33)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 2.32
#define Module_MajorVersion_CMHG 2.33
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 15 Apr 2009
#define Module_Date_CMHG 19 Jul 2009
#define Module_MajorVersion "2.32"
#define Module_Version 232
#define Module_MajorVersion "2.33"
#define Module_Version 233
#define Module_MinorVersion ""
#define Module_Date "15 Apr 2009"
#define Module_Date "19 Jul 2009"
#define Module_ApplicationDate "15-Apr-09"
#define Module_ApplicationDate "19-Jul-09"
#define Module_ComponentName "LanManFS"
#define Module_ComponentPath "RiscOS/Sources/Networking/Omni/Protocols/LanManFS"
#define Module_ComponentPath "castle/RiscOS/Sources/Networking/Omni/Protocols/LanManFS"
#define Module_FullVersion "2.32"
#define Module_HelpVersion "2.32 (15 Apr 2009)"
#define Module_LibraryVersionInfo "2:32"
#define Module_FullVersion "2.33"
#define Module_HelpVersion "2.33 (19 Jul 2009)"
#define Module_LibraryVersionInfo "2:33"
......@@ -137,6 +137,9 @@ static char *WriteEntry ( int reason, char *ptr, BYTE *entry, int format )
static err_t Dir_CallbackFn ( BYTE *entry, int format, bool *taken, void *pw )
{
(void) pw;
*taken = false;
#ifdef LONGNAMES
/* Insert check for . and .. here */
if (format == 1) {
......@@ -158,9 +161,7 @@ static err_t Dir_CallbackFn ( BYTE *entry, int format, bool *taken, void *pw )
}
}
*taken = false;
if ( RD_ReqCount > 0 )
{
if ( RD_ReqCount > 0 ) {
char *w_result = WriteEntry ( RD_Reason, RD_BufPtr, entry, format );
if (w_result != NULL) {
RD_BufPtr = w_result;
......
......@@ -408,6 +408,8 @@ static err_t BootMount ( NAMELIST *pNLmount )
#ifdef CHECK_ARMBOOT_EXISTS
if (BootMount_check_file(pNLmount, "!ARMBOOT") != OK)
return OK;
#else
return OK;
#endif
/* Safety check */
......
......@@ -2111,15 +2111,9 @@ err_t SMB_GetFreeSpace ( char lettr, struct disk_size_response *pDSR )
/* ------------------------------- */
#ifdef LONGNAMES
/* Note.
*
* Requesting close_if_done doesn't seem to work (at least on NT 4.0 SP3)
*
*/
enum {
ffirst_FORCE_CLOSE = 1,
ffirst_CLOSE_IF_DONE = 2,
ffirst_CLOSE_IF_DONE = 2, /* Note close_if_done doesn't seem to work (at least on NT 4.0 SP3) */
ffirst_RETURN_KEYS = 4,
fnext_CONTINUE = 8, /* This bit allows continuation without the need to use resume keys */
ffirst_BACKUP_INTENT = 16
......@@ -2142,8 +2136,8 @@ static err_t SMB_ReadDirEntriesX2 ( hSHARE hS, char *path, int count,
int n_read = 0;
int eos;
int i;
int flags;
const int first_flags = ffirst_RETURN_KEYS;
const int stuck_flags = ffirst_RETURN_KEYS | fnext_CONTINUE;
const int next_flags = ffirst_RETURN_KEYS;
bool path_changed = false;
bool taken;
......@@ -2171,39 +2165,44 @@ static err_t SMB_ReadDirEntriesX2 ( hSHARE hS, char *path, int count,
/* Initial search - note we accept SIX return parameters - contrary to
* Microsoft's own document - because it doesn't work if you only pass 5. Grr.
*/
flags = first_flags;
Transact_init(&con->tp, 6 * 2); /* will accept 6 WORD return params */
Transact_init(&con->tp, 6 * 2); /* will accept 6 WORD return params */
Transact_addsetupword(&con->tp, TRANSACT2_FINDFIRST);
if (LM_Vars.namemode & NM_INTERNAL) {
Transact_addword(&con->tp, ATTR_DIR | ATTR_SYS | ATTR_HID); /* findfirst_Attribute */
if (LM_Vars.namemode & NM_INTERNAL) { /* findfirst_Attribute */
Transact_addword(&con->tp, ATTR_DIR | ATTR_SYS | ATTR_HID);
}
else {
Transact_addword(&con->tp, ATTR_DIR); /* findfirst_Attribute */
Transact_addword(&con->tp, ATTR_DIR);
}
Transact_addword(&con->tp, count); /* findfirst_SearchCount */
Transact_addword(&con->tp, first_flags); /* findfirst_flags */
Transact_addword(&con->tp, 1); /* Search level */
Transact_addlong(&con->tp, 0L); /* reserved, MBZ */
Transact_addstring(&con->tp, path+2); /* findfirst_FileName[] */
Transact_addword(&con->tp, count); /* findfirst_SearchCount */
Transact_addword(&con->tp, first_flags); /* findfirst_flags */
Transact_addword(&con->tp, 1); /* Search level */
Transact_addlong(&con->tp, 0L); /* reserved, MBZ */
Transact_addstring(&con->tp, path+2); /* findfirst_FileName[] */
res = SMB_Transact2(hS, &con->tp);
if (res != OK)
return res;
p = con->tp.parms_out_buf;
con->dir_handle = Transact_getword(p); p += 2;
con->dir_handle_valid = true;
con->resume_fake = 0;
con->resume_key_stuck = false;
debug1("SMB_ReadDirEntriesX2 -> new dir handle %x\n", con->dir_handle);
}
else {
/* Continuation */
con->resume_key_encountered = true;
flags = next_flags;
Transact_init(&con->tp, 4 * 2); /* will accept 4 WORD return params */
Transact_addsetupword(&con->tp, TRANSACT2_FINDNEXT);
Transact_addword(&con->tp, con->dir_handle); /* findnext_DirHandle */
Transact_addword(&con->tp, count); /* findnext_SearchCount */
Transact_addword(&con->tp, 1); /* Search level */
Transact_addlong(&con->tp, con->resume_key); /* Resume key from previous */
Transact_addword(&con->tp, next_flags); /* findnext_flags */
if (con->resume_key_stuck) {
Transact_addword(&con->tp, stuck_flags); /* Set continuation bit as NTFS maintains the position */
}
else {
Transact_addword(&con->tp, next_flags); /* Jump to place using the resume key */
con->resume_key_encountered = true;
}
Transact_addstring(&con->tp, ""); /* no name needed */
debug1("SMB_ReadDirEntriesX2 -> continue with key %08x\n", con->resume_key);
res = SMB_Transact2(hS, &con->tp);
......@@ -2216,15 +2215,14 @@ static err_t SMB_ReadDirEntriesX2 ( hSHARE hS, char *path, int count,
eos = Transact_getword(p); p += 2;
if (eos)
debug0(">> Server said it was the end of the search operation\n");
p = con->tp.data_out_buf;
if (n_read == 0)
return ENOMOREFILES;
/* At this point, p is pointing to the start of the returned data
* buffer, n_read contains the number of files known to be in the
* return buffer, eos is non-zero if the search is completed.
*/
if (n_read == 0)
return ENOMOREFILES;
for (i = 1; i <= n_read; i++) {
int length;
DWORD next_resume_key;
......@@ -2232,7 +2230,20 @@ static err_t SMB_ReadDirEntriesX2 ( hSHARE hS, char *path, int count,
/* Get next resume key */
next_resume_key = Transact_getlong(p); p += 4;
length = p[22];
con->resume_fake++;
/* Special case . and .. so the duff resume key detection doesn't see them */
if ( ((p[22] == 1) && (p[23] == '.') && (p[24] == 0)) ||
((p[22] == 2) && (p[24] == '.') && (p[25] == 0) && (p[23] == '.')) ) {
p += 23 + length + 1;
continue;
}
/* Workaround for NTFS always returning zero */
con->resume_key_stuck = (next_resume_key == 0) ? true : false;
if (con->resume_key_stuck) next_resume_key = con->resume_fake;
/* Either consume the name or keep waiting for sync */
if ( con->resume_key_encountered ) {
debug1("SMB_ReadDirEntriesX2 -> call back with key %08x\n", next_resume_key);
res = dirfn(p, 1, &taken, private);
......
......@@ -738,6 +738,7 @@ static err_t Xlt_NameXlateCallbackX2 ( BYTE *entry, int format, bool *taken, voi
err_t res = OK;
*taken = true;
if (dst->dstcpy[0] != '*') {
return EOUTOFMEM;
}
......@@ -908,7 +909,7 @@ static err_t Xlt_NameROtoDOSX2_sub ( char *dst, char *src, int level )
return OK;
}
/* Kicks off the DOS to RISC OS name conversion process - setting up the
/* Kicks off the RISC OS to DOS name conversion process - setting up the
* number of already-translated characters as zero.
*/
static err_t Xlt_NameROtoDOSX2 ( char *dst, char *src )
......
......@@ -962,9 +962,9 @@ typedef struct {
union {
USHORT Pad[6]; // Ensure section is 12 bytes long
struct {
USHORT Reserved; // reserved for obsolescent
requests
USHORT ProcessID;
UCHAR SecuritySignature[8]; // reserved for MIC
USHORT Reserved; // reserved for obsolescent requests
} Extra;
};
USHORT Tid; // Tree identifier
......@@ -984,7 +984,7 @@ have a different number and interpretation of ParameterWords and
Buffer. All reserved fields in the SMB header must be zero.
3.2.1C ommand field
3.2.1 Command field
The Command is the operation code that this SMB is requesting or
responding to. See section 5.1 below for number values, and section 4
......@@ -3403,7 +3403,7 @@ USHORT AndXOffset; Offset to next command WordCount
USHORT OptionalSupport; Optional support bits
USHORT ByteCount; Count of data bytes; min = 3
UCHAR Service[]; Service type connected to. Always
ANSII.
ASCII.
STRING NativeFileSystem[]; Native file system for this tree
......
......@@ -29,6 +29,8 @@ typedef struct {
struct TransactParms tp;
char dir_path[DOS_NAME_LEN];
DWORD resume_key;
DWORD resume_fake;
bool resume_key_stuck;
bool resume_key_encountered;
WORD dir_handle;
bool dir_handle_valid;
......
......@@ -16,11 +16,11 @@
; S.ERRORS - Lan Manager client errors file.
; Keep in step with H.Stdtypes
AREA |C$$data|
AREA |C$$data|
EXPORT Err_XltTable
Err_Base EQU &16600 ; Errors from filing system #66
Err_Base EQU &16600 ; Errors from filing system #66
Err_XltTable DCD Err0
DCD Err1
......@@ -87,263 +87,263 @@ Err_XltTable DCD Err0
DCD Err62
ALIGN
Err0 DCD Err_Base+0
DCB "LanManFS internal error", 0
ALIGN
Err0 DCD Err_Base+0
DCB "LanManFS internal error", 0
ALIGN
Err1 DCD Err_Base+1
DCB "Bad parameters", 0
ALIGN
Err1 DCD Err_Base+1
DCB "Bad parameters", 0
ALIGN
Err2 DCD Err_Base+2
DCB "No connection to server", 0
ALIGN
Err2 DCD Err_Base+2
DCB "No connection to server", 0
ALIGN
Err3 DCD Err_Base+3
DCB "Out of buffers", 0
ALIGN
Err3 DCD Err_Base+3
DCB "Out of buffers", 0
ALIGN
Err4 DCD Err_Base+4
DCB "Connection to server failed", 0
ALIGN
Err4 DCD Err_Base+4
DCB "Connection to server failed", 0
ALIGN
Err5 DCD Err_Base+5
DCB "Out of handles", 0
ALIGN
Err5 DCD Err_Base+5
DCB "Out of handles", 0
ALIGN
Err6 DCD Err_Base+6
DCB "Receive not ready", 0
ALIGN
Err6 DCD Err_Base+6
DCB "Receive not ready", 0
ALIGN
Err7 DCD Err_Base+7
DCB "Connection already exists", 0
ALIGN
Err7 DCD Err_Base+7
DCB "Connection already exists", 0
ALIGN
Err8 DCD Err_Base+8
DCB "Timeout error", 0
ALIGN
Err8 DCD Err_Base+8
DCB "Timeout error", 0
ALIGN
Err9 DCD Err_Base+9
DCB "This workstation name already exists", 0
ALIGN
Err9 DCD Err_Base+9
DCB "This workstation name already exists", 0
ALIGN
Err10 DCD Err_Base+10
DCB "Cannot find given server", 0
ALIGN
Err10 DCD Err_Base+10
DCB "Cannot find given server", 0
ALIGN
Err11 DCD Err_Base+11
DCB "Data length error", 0
ALIGN
Err11 DCD Err_Base+11
DCB "Data length error", 0
ALIGN ; ERRSRV error
Err12 DCD Err_Base+12
DCB "Error from server", 0
ALIGN ; ERRSRV error
Err12 DCD Err_Base+12
DCB "Error from server", 0
ALIGN ; ERRDOS error
Err13 DCD Err_Base+13
DCB "Unable to perform operation", 0
ALIGN ; ERRDOS error
Err13 DCD Err_Base+13
DCB "Unable to perform operation", 0
ALIGN
Err14 DCD Err_Base+14
DCB "Hardware error on server", 0
ALIGN
Err14 DCD Err_Base+14
DCB "Hardware error on server", 0
ALIGN
Err15 DCD Err_Base+15
DCB "Network protocol error", 0
ALIGN
Err15 DCD Err_Base+15
DCB "Network protocol error", 0
ALIGN
Err16 DCD Err_Base+16
DCB "No more files", 0
ALIGN
Err16 DCD Err_Base+16
DCB "No more files", 0
ALIGN
Err17 DCD Err_Base+17
DCB "File not found", 0
ALIGN
Err17 DCD Err_Base+17
DCB "File not found", 0
ALIGN
Err18 DCD Err_Base+18
DCB "Directory not found", 0
ALIGN
Err18 DCD Err_Base+18
DCB "Directory not found", 0
ALIGN
Err19 DCD Err_Base+19
DCB "Server out of file handles", 0
ALIGN
Err19 DCD Err_Base+19
DCB "Server out of file handles", 0
; 28/Jan/97 NAS horrible fudge because some LanMan servers don't return a specific
; "directory not empty" code, but use this instead, and Filer_Action checks on
; exact error return code. [Fault NET-01359]
ALIGN
Err20 DCD Err_Base+&B4
DCB "Access denied", 0
ALIGN
Err20 DCD Err_Base+&B4
DCB "Access denied", 0
ALIGN
Err21 DCD Err_Base+21
DCB "File already exists", 0
ALIGN
Err21 DCD Err_Base+21
DCB "File already exists", 0
ALIGN
Err22 DCD Err_Base+22
DCB "Incorrect password", 0
ALIGN
Err22 DCD Err_Base+22
DCB "Incorrect password", 0
ALIGN
Err23 DCD Err_Base+23
DCB "Illegal name", 0
ALIGN
Err23 DCD Err_Base+23
DCB "Illegal name", 0
ALIGN
Err24 DCD Err_Base+24
DCB "No such connection", 0
ALIGN
Err24 DCD Err_Base+24
DCB "No such connection", 0
ALIGN
Err25 DCD Err_Base+25
DCB "RISCOS 2 directory functions not supported", 0
ALIGN
Err25 DCD Err_Base+25
DCB "RISCOS 2 directory functions not supported", 0
ALIGN
Err26 DCD Err_Base+26
DCB "OS_GBPB not supported", 0
ALIGN
Err26 DCD Err_Base+26
DCB "OS_GBPB not supported", 0
ALIGN
Err27 DCD Err_Base+27
DCB "Unbuffered file functions not supported", 0
ALIGN
Err27 DCD Err_Base+27
DCB "Unbuffered file functions not supported", 0
ALIGN
Err28 DCD Err_Base+28
DCB "LanManFS has not been loaded", 0
ALIGN
Err28 DCD Err_Base+28
DCB "LanManFS has not been loaded", 0
ALIGN
Err29 DCD Err_Base+29
DCB "Function not implemented", 0
ALIGN
Err29 DCD Err_Base+29
DCB "Function not implemented", 0
ALIGN
Err30 DCD Err_Base+30
DCB "Wildcards not allowed", 0
ALIGN
Err30 DCD Err_Base+30
DCB "Wildcards not allowed", 0
ALIGN
Err31 DCD Err_Base+31
DCB "File attributes could not be read", 0
ALIGN
Err31 DCD Err_Base+31
DCB "File attributes could not be read", 0
ALIGN
Err32 DCD Err_Base+32
DCB "File attributes could not be written", 0
ALIGN
Err32 DCD Err_Base+32
DCB "File attributes could not be written", 0
ALIGN
Err33 DCD Err_Base+33
DCB "File sharing violation", 0
ALIGN
Err33 DCD Err_Base+33
DCB "File sharing violation", 0
ALIGN
Err34 DCD Err_Base+34
DCB "Connection limit has been reached", 0
ALIGN
Err34 DCD Err_Base+34
DCB "Connection limit has been reached", 0
ALIGN
Err35 DCD Err_Base+35
DCB "Share name does not exist", 0
ALIGN
Err35 DCD Err_Base+35
DCB "Share name does not exist", 0
ALIGN
Err36 DCD Err_Base+36
DCB "Bad LanManFS command line", 0
ALIGN
Err36 DCD Err_Base+36
DCB "Bad LanManFS command line", 0
ALIGN
Err37 DCD Err_Base+37
DCB "LanManFS requires RISC OS 3.00 or later", 0
ALIGN
Err37 DCD Err_Base+37
DCB "LanManFS requires RISC OS 3.00 or later", 0
ALIGN
Err38 DCD Err_Base+38
DCB "Initialisation failed", 0
ALIGN
Err38 DCD Err_Base+38
DCB "Initialisation failed", 0
ALIGN
Err39 DCD Err_Base+39
DCB "Network driver not found", 0
ALIGN
Err39 DCD Err_Base+39
DCB "Network driver not found", 0
ALIGN
Err40 DCD Err_Base+40
DCB "Network interface is of incorrect type", 0
ALIGN
Err40 DCD Err_Base+40
DCB "Network interface is of incorrect type", 0
ALIGN
Err41 DCD Err_Base+41
DCB "Network driver is not DCI-4 compatible", 0
ALIGN
Err41 DCD Err_Base+41
DCB "Network driver is not DCI-4 compatible", 0
ALIGN
Err42 DCD Err_Base+42
DCB "Already connected to this drive on this server", 0
ALIGN
Err42 DCD Err_Base+42
DCB "Already connected to this drive on this server", 0
ALIGN
Err43 DCD Err_Base+43
DCB "IEEE802.3 frames are already being used by another protocol", 0
ALIGN
Err43 DCD Err_Base+43
DCB "IEEE802.3 frames are already being used by another protocol", 0
ALIGN
Err44 DCD Err_Base+44
DCB "Buffer manager module is not installed", 0
ALIGN
Err44 DCD Err_Base+44
DCB "Buffer manager module is not installed", 0
ALIGN
Err45 DCD Err_Base+45
DCB "RPC call returned error", 0
ALIGN
Err45 DCD Err_Base+45
DCB "RPC call returned error", 0
ALIGN
Err46 DCD Err_Base+46
DCB "Disk full", 0
ALIGN
Err46 DCD Err_Base+46
DCB "Disc full", 0
; Err47 moved to ErrB4 28/Jan/97 NAS because Filer_Action checks on
; exact error return code. [Fault NET-01359]
ALIGN
Err47 DCD Err_Base+&B4
DCB "Directory not empty", 0
ALIGN
Err47 DCD Err_Base+&B4
DCB "Directory not empty", 0
ALIGN
Err48 DCD Err_Base+48
DCB "Can't rename across shares", 0
ALIGN
Err48 DCD Err_Base+48
DCB "Can't rename across shares", 0
ALIGN
Err49 DCD Err_Base+49
DCB "Bad file handle", 0
ALIGN
Err49 DCD Err_Base+49
DCB "Bad file handle", 0
ALIGN
Err50 DCD Err_Base+50
DCB "Cannot create TCP/IP socket", 0
ALIGN
Err50 DCD Err_Base+50
DCB "Cannot create TCP/IP socket", 0
ALIGN
Err51 DCD Err_Base+51
DCB "Cannot make TCP/IP connection", 0
ALIGN
Err51 DCD Err_Base+51