Commit d7d9868e authored by Stewart Brodie's avatar Stewart Brodie
Browse files

A few more battles have been won. War finally starting to go my way.

Detail:
  LanManFS now uses ,xxx type notation on long filename shares.
  Character mappings improved (necessary because Windows allows so
    many extra daft characters to appear in filenames) and one-to-many
    mappings for awkward charcacters in the RISC OS->DOS world have
    been added.
  Directory searching improved so that the wildcard matching can be
    done properly.  Only Microsoft could provide you an API call to
    discover information about a filename specified with wildcards and
    NOT tell you which filename it matched. :-/
  Things remaining unimplemented so far:
    Setting filetypes.
    Creating files with specific types
    Renaming.
  All those outstanding things relate to the work done by Attr_SetInfo
    which should be the final major piece of hacking required.
Admin:
  Tested by connecting to a long filename share from both a RISC OS
    machine and a Windows NT machine.  All behaviour of the RISC OS
    machine has been verified against what the NT machine is seeing
    happening.  No surprises.  One-to-many character mappings are
    being matched correctly.
  Also tested using the Filer at the RISC OS end to navigate, run,
    and edit things on the remote share.

Version 1.87, 1.1.1.1.2.4. Tagged as 'LanManFS-1_87-1_1_1_1_2_4'
parent 28a6a425
......@@ -45,7 +45,8 @@ CD = dir
CPFLAGS = ~cfr~v
WFLAGS = ~c~v
DFLAGS = -UTML -DCOMPAT_INET4 -DLONGNAMES
# sbrodie 5/1/99: Define LANMANFS to enable use of NFS headers
DFLAGS = -UTML -DCOMPAT_INET4 -DLANMANFS -DLONGNAMES
AFLAGS = -depend !Depend ${THROWBACK} -Stamp -quit
CFLAGS = -depend !Depend ${THROWBACK} -c -Wpc -ff -zps1 -zM ${INCLUDES},. ${DFLAGS}
CMHGFLAGS = -depend !Depend ${THROWBACK} -p
......@@ -79,16 +80,17 @@ ROM_OBJS = or.LanMan or.Omni or.Logon or.CoreFn or.Printers \
# od.LLC od.NetBIOS od.SMB od.Attr od.RPC od.NBIP od.Stats LanMan_MH.o
DBG_OBJS = od.LanMan o.Omni od.Logon od.CoreFn od.Printers \
od.Xlate od.buflib Interface.o RMInfo.o Errors.o od.Transact \
od.LLC o.NetBIOS od.SMB o.Attr od.RPC o.NBIP od.Stats LanMan_MH.o
od.Xlate od.buflib Interface.o RMInfo.o Errors.o od.Transact \
o.LLC o.NetBIOS o.SMB o.Attr od.RPC o.NBIP od.Stats LanMan_MH.o
OBJSI = i.LanMan i.Omni i.Logon i.CoreFn i.Printers \
OBJSI = i.LanMan i.Omni i.Logon i.CoreFn i.Printers i.PathMunge \
i.Xlate i.buflib i.Transact \
i.LLC i.NetBIOS i.SMB i.Attr i.RPC i.NBIP i.Stats
OBJSINST = LanMan_MH.o inst.LanMan inst.Omni inst.Logon inst.CoreFn inst.Printers \
inst.Xlate inst.buflib Interface.o RMInfo.o Errors.o inst.Transact\
inst.LLC inst.NetBIOS inst.SMB inst.Attr inst.RPC inst.NBIP inst.Stats
inst.LLC inst.NetBIOS inst.SMB inst.Attr inst.RPC inst.NBIP inst.Stats \
inst.PathMunge
LanMan_MH.h: LanMan_MH.o
${CMHG} ${CMHGFLAGS} cmhg.$* -d $@
......
......@@ -4,11 +4,11 @@
*
*/
#define Module_MajorVersion_CMHG 1.87
#define Module_MinorVersion_CMHG 1.1.1.1.2.3
#define Module_Date_CMHG 14 Dec 1998
#define Module_MinorVersion_CMHG 1.1.1.1.2.4
#define Module_Date_CMHG 08 Jan 1999
#define Module_MajorVersion "1.87"
#define Module_Version 187
#define Module_MinorVersion "1.1.1.1.2.3"
#define Module_Date "14 Dec 1998"
#define Module_MinorVersion "1.1.1.1.2.4"
#define Module_Date "08 Jan 1999"
......@@ -322,6 +322,24 @@ void Attr_InvalidateDrive( char drvletter )
in separately.
*/
#ifdef LONGNAMES
static err_t Attr_GetInfoX2 ( char *filename, char *leafname,
RISCOS_ATTRIBS *pRA )
{
char *lastcomma;
(void) leafname;
if (Xlt_SplitLeafnameX2 ( leafname?leafname:filename, pRA, &lastcomma ) != OK) {
/* Something asked using a RISC OS name. Need to do a lookup
* for the file.
*/
//GetDefaultType ( leafname, pRA );
//return EATTRIBREAD;
}
return OK;
}
#endif
err_t Attr_GetInfo ( char *filename, char *leafname,
RISCOS_ATTRIBS *pRA )
......@@ -330,6 +348,12 @@ err_t Attr_GetInfo ( char *filename, char *leafname,
int pos;
DOS_ATTRIBS da;
#ifdef LONGNAMES
if (SMB_IsLongNameFS(filename))
return Attr_GetInfoX2 ( filename, leafname, pRA );
#endif
if ( SetFileName(filename) != OK )
return EBADNAME;
......@@ -407,6 +431,11 @@ err_t Attr_DeleteInfo ( char *pathname )
int pos;
DOS_ATTRIBS da;
#ifdef LONGNAMES
if (SMB_IsLongNameFS(pathname))
return OK;
#endif
if ( SetFileName(pathname) != OK )
return EBADNAME;
......@@ -456,6 +485,12 @@ close_file:
in.
*/
#ifdef LONGNAMES
static err_t Attr_SetInfoX2 ( char *pathname, RISCOS_ATTRIBS *pRA )
{
}
#endif
extern err_t Attr_SetInfo ( char *pathname, RISCOS_ATTRIBS *pRA )
{
err_t err;
......@@ -465,6 +500,12 @@ extern err_t Attr_SetInfo ( char *pathname, RISCOS_ATTRIBS *pRA )
debug1("SetInfo for '%s'\n", pathname);
#ifdef LONGNAMES
if (SMB_IsLongNameFS(pathname))
return Attr_SetInfoX2 ( pathname, pRA );
#endif
if ( SetFileName(pathname) != OK )
return EBADNAME;
......@@ -577,6 +618,14 @@ void Attr_CheckEmptyDir (char *dirname)
AttrAllInCache = false;
AttrCacheLen = 0;
#ifdef LONGNAMES
/* Shouldn't be any RISCOS.EA file present - user must delete it if
* there is one - we're not hiding it away on long filename shares
*/
if (SMB_IsLongNameFS(dirname))
return;
#endif
/* Open Attr file */
sprintf ( AttrFileName, "%s\\%s", dirname, ATTR_FILENAME );
......
......@@ -92,12 +92,16 @@ static char *WriteEntry ( int reason, char *ptr, BYTE *entry, int format )
RISCOS_ATTRIBS ra;
int *IntPtr;
#ifndef LONGNAMES
(void) format;
#else
if (format == 1) {
Xlt_ExpandSearchEntryX2(entry, DOSnamebuf, namebuf, &da, &ra);
}
else {
else
#endif
Xlt_ExpandSearchEntry(entry, DOSnamebuf, namebuf, &da, &ra);
}
name_len = strlen(namebuf) + 1;
switch ( reason )
......@@ -359,6 +363,11 @@ _kernel_oserror *fsentry_func ( int *R )
if ( err == OK )
err = SMB_Rename ( DOSnamebuf, DOSnamebuf+DOS_NAME_LEN );
#ifdef LONGNAMES
if (SMB_IsLongNameFS(DOSnamebuf + DOS_NAME_LEN)) break;
/* Don't bother with any of this rubbish for long filename discs */
#endif
if ( err == OK ) /* If rename worked, swap attribs */
{
RISCOS_ATTRIBS ra;
......@@ -423,11 +432,12 @@ static err_t FileGetAttribs ( char *filename, DOS_ATTRIBS *pda,
{
err_t err;
debug1("FileGetAttribs(%s) ... \n", filename);
err = SMB_GetAttribs ( filename, pda );
if ( err == OK )
{
Xlt_CnvDOStoRO ( pda, pra, CNV_DATETIME | CNV_ATTRIBS );
Attr_GetInfo ( DOSnamebuf, NULL, pra );
Attr_GetInfo ( filename, NULL, pra );
}
return err;
}
......
......@@ -610,6 +610,13 @@ static void SendFindRequest ( struct sockaddr *pDst, NAME_ENTRY *pNE )
p = PutNetname( p, &(pNE->nn) ); /* Query section */
p = PutLong (p, INET_NAME_TAG );
#ifdef DEBUG
{
struct sockaddr_in *sin = (void *) pDst;
debug1("SendFindRequest -> [%s]\n", inet_ntoa(sin->sin_addr));
}
#endif
SendDatagram ( pDst, DatagramBuf, p );
}
......@@ -929,6 +936,7 @@ static void NameFindReply ( struct NBNS_packet *pNBP,
pNBRR->data_length >= 6 /* At least one entry in reply */
)
{
debug0("NameFindReply - found\n");
pNE->status = RMT_FOUND;
pNE->nbflags = GetShort(dp);
pNE->IPaddress = GetIPAddr(dp+2);
......
......@@ -745,31 +745,34 @@ static err_t SMB_WriteRaw ( hSHARE hS, int fid, int offset,
/* sbrodie: Abstract the dialect strings here - means debug version can
* can this function to find out which protocol was accepted.
*/
static char *SMB_Dialect(int num)
static char *dialects[] = {
"PC NETWORK PROGRAM 1.0",
"DOS LM1.2X002",
"LM1.2X002",
"NT LM 0.12"
};
#define MAX_DIALECT ((sizeof(dialects)/sizeof(*dialects))-1)
static char *SMB_Dialect(unsigned int num)
{
if (num == 0) return "PC NETWORK PROGRAM 1.0";
if (num == 1) return "DOS LM1.2X002";
if (num == 2) return "LM1.2X002";
if (num == 3) return "NT LM 0.12";
if (num <= MAX_DIALECT) return dialects[num];
return "";
}
#define MAX_DIALECT 3
/* ---------------------------- */
static err_t SMB_Negotiate( hSHARE hS )
{
err_t res;
int dcount;
unsigned int dcount;
BUFCHAIN pB;
pB = NULL;
/* Must be entered in reverse order */
for (dcount = MAX_DIALECT; dcount >= 0; --dcount) {
for (dcount = MAX_DIALECT; ; --dcount) {
pB = MkDataString( pB, DATA_DIALECT, SMB_Dialect(dcount));
if (pB == NULL) break;
if (pB == NULL || dcount == 0) break;
}
if ( pB == NULL )
......@@ -1215,8 +1218,7 @@ bool SMB_IsLongNameFS( const char * path)
hSHARE hS;
hS = GetShare(path, &e);
if (e != OK) return false;
if (hS->use_t2) return true;
if (e == OK && hS->use_t2) return true;
return false;
}
......@@ -1621,6 +1623,7 @@ static err_t SMB_GetAttribsX2 (hSHARE hS, char *filename, DOS_ATTRIBS *pAttr )
swap_time_date(tp.data_out_buf+4);
swap_time_date(tp.data_out_buf+8);
/* end workaround */
strcpy((char *)tp.data_out_buf+23, filename); /* Xlt_ExpandSearchEntryX2 relies on this */
return Xlt_ExpandSearchEntryX2 ( tp.data_out_buf, NULL, NULL, pAttr, NULL);
}
#endif /* LONGNAMES */
......@@ -1950,7 +1953,7 @@ static err_t SMB_ReadDirEntriesX2 ( hSHARE hS, char *path, int count,
* and it will have to restart the search next time around.
*/
//NextSearchOK = eos ? false : true;
debug0("Bugger. Looks like client ran out of space\n");
debug0("Bugger. Looks like client ran out of space (or could be name xlate code)\n");
if (eos) {
(void) SMB_AbandonFind2( hS, dir_handle );
}
......@@ -2582,7 +2585,9 @@ static err_t SMB_Transact2 ( hSHARE hS, struct TransactParms *pT )
*/
int padbytes; /* Temp variable */
int sc;
int retry = 3;
retry_transact2:
debug2("SMB_Transact2: processing (Tid = %#04x, sub-cmd=%#04x)...\n", hS->Tid,
pT->setup_in[0]);
......@@ -2634,6 +2639,12 @@ static err_t SMB_Transact2 ( hSHARE hS, struct TransactParms *pT )
res = Do_SMB ( hS, SMBtrans2, 14 + pT->setup_in_len, pB, &pBres );
if ( res != OK ) {
if (SMB_RxHdr.errclass == ERRSRV && SMB_RxHdr.errlo == 1 && SMB_RxHdr.errhi == 0 && retry)
{
--retry;
debug0("SMB_Transact2: retrying request\n");
goto retry_transact2;
}
debug0("SMB_Transact2: Do_SMB failed\n");
DumpBuffer(&SMB_RxHdr, SMBHDR_SIZE);
return res;
......@@ -2687,7 +2698,8 @@ static err_t SMB_Transact2 ( hSHARE hS, struct TransactParms *pT )
if ( padbytes > 0 )
pBres = GetData(pBres, NULL, padbytes);
pBres = GetData(pBres, pT->data_out_buf, pT->data_out_len);
//if (pT->setup_in[0] == 5) DumpBuffer(pT->data_out_buf, pT->data_out_len);
if (pT->setup_in[0] == TRANSACT2_QUERYPATHINFORMATION)
DumpBuffer(pT->data_out_buf, pT->data_out_len);
}
if ( pBres == NULL ) { /* Oh no! Techo fear! */
......
<
......@@ -25,6 +25,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "kernel.h"
......@@ -35,17 +36,49 @@
#include "lmvars.h"
#include "SMB.h"
#ifdef LONGNAMES
//#include "NFSConsts.h"
#define FileChar_TypedNamePrefix ','
#define FileString_DeadFile "xxx"
#define FileString_UntypedFile "lxa"
#endif
/* stricmp(): ignore-case string compare ------------------------ */
/* returns 0 if they match, > 0 if s1 > s2, < 0 if s1 < s2 */
int stricmp ( const char *s1, const char *s2 )
/* Function to compare two strings case insensitively
*
* Originally: sbrodie
*
* Parameters: matches those of strcmp.
* Result: matches the exit conditions of strcmp.
*
*
* The conversions to unsigned int stop the compiler messing around with
* shifts all over the place whilst trying to promote the chars to int
* whilst retaining the sign.
*
* Problems: Choice of return value when strings do not match is based
* upon character number rather than any alphabetic sorting.
*
*/
int stricmp(const char *first, const char *second)
{
while ( toupper(*s1) == toupper(*s2) )
{
if ( *s1 == 0 ) return 0;
s1++, s2++;
}
return toupper(*s1) - toupper(*s2);
for (;;) {
unsigned int a = *first++;
unsigned int b = *second++;
if (a == 0) return -b;
if (a != b) {
unsigned int c = (unsigned int) tolower(a);
unsigned int d = (unsigned int) tolower(b);
signed int result = c - d;
if (result != 0) return result;
}
}
}
/* strcpyn(): copies a string with given max length. Note that
......@@ -57,10 +90,14 @@ int stricmp ( const char *s1, const char *s2 )
void strcpyn ( char *d, const char *s, int len )
{
#ifdef OLD_SLOW_METHOD
while ( --len > 0 && *s != 0 )
*d++ = *s++;
*d = 0;
#else
*d = 0;
(void) strncat(d, s, len);
#endif
}
/* strcpyn_upper(): copies a string making all characters uppercase --- */
......@@ -121,9 +158,11 @@ static uint DMYtoUtime ( int dtime, int ddate )
min = (dtime >> 5) & 63;
hrs = (dtime >> 11) & 31;
/*
debug2("%08x %08x => ", dtime, ddate);
debug3("HH:MM:SS => %02d:%02d:%02d ", hrs, min, sec);
debug3("DD:MM:YY => %02d:%02d:%04d \n", dd, mm, yy + 1980);
*/
/* Calc. no. of days since 1-1-70 */
x = 3652 + (yy*365) + ((yy+3)/4);
......@@ -529,53 +568,201 @@ void Xlt_NameDOStoRO ( char *dst, char *src )
}
#ifdef LONGNAMES
/* Originally, this came from NFS(pathmunge.c):move_nfsname_to_riscos_name */
static const char nfs_lookup_table[257]=
"________________________________"
"!\"_<__'()_+,-//0123456789_;<=>?"
"_ABCDEFGHIJKLMNOPQRSTUVWXYZ[_]__"
"`abcdefghijklmnopqrstuvwxyz{|}~_"
""
""
""
"";
static const char nfs_lookup_inverse_table[257]=
"________________________________"
"!\"_<__'()_+,-/.0123456789_;<=>?"
"_ABCDEFGHIJKLMNOPQRSTUVWXYZ[_]__"
"`abcdefghijklmnopqrstuvwxyz{|}~_"
""
""
""
"";
void Xlt_NameDOStoROX2 ( char *dst, char *src )
/* OK, the mappings for long filename discs are different.
*
* They are:
*
* DOS -> RISC OS -> DOS
*
* * * * (wildcard)
* ? # ? (wildcard)
* # ? # (swap match for above)
*
* : : : (won't be seen)
* \ . \ (dir sep)
* . / .
*
* & + + or &
* + + & or +
* @ = @ or =
* = = = or @
* % > % or >
* > > > or %
* $ < $ or <
* < < < or $
* ^ , ^ or , (don't like this map)
* , , (or extn) , or ^
* space hard space space or hard space
* hard space hard space hard space or space
*
*/
static const char lanmanfs_lookup_table[257]=
"________________________________"
"\xa0!\"?<>+'()*+,-/_0123456789:;<=>#"
"=ABCDEFGHIJKLMNOPQRSTUVWXYZ[.],_"
"`abcdefghijklmnopqrstuvwxyz{|}~_"
""
"\xa0、ウЖ渦慨偽係杭纂従"
"請唾津毒班碧麺力佰厶壞嶐慵无槿渤"
"珀矣粤肄蓍裨跋鈿韵鴦";
static const char lanmanfs_inverse_lookup_table[257]=
"________________________________"
"\xa0!\"?<>+'()*+,-\\.0123456789:;<=>#"
"=ABCDEFGHIJKLMNOPQRSTUVWXYZ[.],_"
"`abcdefghijklmnopqrstuvwxyz{|}~_"
""
"\xa0、ウЖ渦慨偽係杭纂従"
"請唾津毒班碧麺力佰厶壞嶐慵无槿渤"
"珀矣粤肄蓍裨跋鈿韵鴦";
static const char lanmanfs_contentious_characters[]=
"+=><,\xa0";
//static const char lanmanfs_contentious_pairing[]=
// "&@%$^\x20";
static void Xlt_NameDOStoROX2 ( char *dst, char *src, RISCOS_ATTRIBS *pRA )
{
int i;
char *odst = dst;
for ( i=0; i<255; i++ ) /* No limit on length, except 255 chars */
for ( i=0; i<255; i++ ) /* Length limit is 255 chars */
{
int c = src[i] & 0xFF;
if (c == 0) break;
*dst++ = nfs_lookup_table[c];
if (c == 0) break; /* Found the terminator */
*dst++ = lanmanfs_lookup_table[c];
}
*dst = 0;
dst = strrchr(odst, '.');
if (dst == NULL) dst = odst; else ++dst;
if (dst != NULL) {
if (Xlt_SplitLeafnameX2 ( dst, pRA, &dst ) == OK) {
/* Strip off the extension */
*dst = 0;
}
}
}
static err_t Xlt_NameROtoDOSX2 ( char *dst, char *src )
/* This is slightly more complicated now by the ,xxx naming scheme.
*
* This function returns ENOWILDCARD if the file exists remotely and
* has exactly the same name as was requested. This implies that it
* was a text file or a directory.
*
* If it returns OK, then it means that the file exists but requires
* a wildcard lookup.
*
* If it returns ENOTPRESENT, then it means that the file definitely
* is not there.
*/
static int Xlt_CopyViaInverseTable( char *dst, const char *src, int blat )
{
int i, c;
int wild_count = 0, c, i;
for ( i=0; i<(DOS_NAME_LEN-1); i++ )
{
c = src[i] & 0xFF;
if (c == 0) break;
*dst++ = nfs_lookup_inverse_table[c];
if (strchr(lanmanfs_contentious_characters, c)) {
++wild_count;
if (blat) {
dst[i] = '?';
continue;
}
}
dst[i] = lanmanfs_inverse_lookup_table[c];
}
dst[i] = 0;
return wild_count;
}
*dst = 0;
static err_t Xlt_LookupNameROtoDOSX2 ( char *dst, char *src )
{
static char NameBuf[DOS_NAME_LEN + 4];
DOS_ATTRIBS dos_attr;
int i, wild_count;
char *eos;
int already_has_extn = 0;
eos = strchr(src, '\0');
if ((eos - src) >= 5) {
int len, type;
if (sscanf(eos-4, ",%x%n", &type, &len) == 1 && len == 3) {
already_has_extn = 1;
}
}
NameBuf[0] = *dst++; /* Copy the A: bit of the name */
NameBuf[1] = *dst++;
wild_count = Xlt_CopyViaInverseTable(NameBuf+2, src, 0);
strcpy(dst, NameBuf+2);
debug1("Looking for %s\n", NameBuf);
if (SMB_GetAttribs(NameBuf, &dos_attr) == OK) {
debug0("Found verbatim\n");
return OK;
}
eos = strchr(NameBuf, '\0');
if (!already_has_extn) {
strcpy(eos, ",???");
debug1("Looking for %s\n", NameBuf);
if (SMB_GetAttribs(NameBuf, &dos_attr) == OK) {
strcpy(dst, NameBuf+2);
debug0("Had a type\n");
return OK;
}
}
*eos = '\0';
if (wild_count == 0) return OK;
Xlt_CopyViaInverseTable(NameBuf+2, src, 1); /* Blat with wildcards */
debug1("Looking for %s\n", NameBuf);
if (SMB_GetAttribs(NameBuf, &dos_attr) != OK) {
if (!already_has_extn) {
Xlt_CopyViaInverseTable(dst, src, 0);
return ENOTPRESENT;
}
strcpy(NameBuf+i, ",???");
debug1("Looking for %s\n", NameBuf);
if (SMB_GetAttribs(NameBuf, &dos_attr) != OK) {
Xlt_CopyViaInverseTable(dst, src, 0); /* Unblat */
return ENOTPRESENT;
}
debug0("Had a type\n");
}
debug0("Had contentious characters\n");
strcpy(dst, NameBuf+2);
return OK;
}
static err_t Xlt_NameXlateCallbackX2 ( BYTE *entry, int format, void *dst )
{
strcpy(dst, (char *) entry+23);
debug1("Xlt_NameXlateCallbackX2: `%s'\n", dst);
return EOUTOFMEM; /* Match first only */
}
static err_t Xlt_NameROtoDOSX2 ( char *dst, char *src )
{
debug1("Xlt_NameROtoDOSX2: `%s'\n", src);
if (Xlt_LookupNameROtoDOSX2 ( dst, src ) == OK) {
/* Need to perform a search to find the exact name now */
static char dstcpy[DOS_NAME_LEN];
err_t res;
debug1("Searching for a match for `%s'\n", dst);
strcpy(dstcpy, dst); /* Copy the wildcarded filespec */
res = SMB_ReadDirEntries(dstcpy, 1, Xlt_NameXlateCallbackX2,
1 + strrchr(dstcpy, '\\'));
strcpy(dst, dstcpy);
debug1("End of search for a match - result `%s'\n", dst);
}
return OK;
}
#endif
......@@ -634,7 +821,7 @@ err_t Xlt_ConvertPath ( char *name_in, char *name_out )
{
#ifdef LONGNAMES
if (SMB_IsLongNameFS( name_out )) {
return ( Xlt_NameROtoDOSX2 ( name_out+2, name_in+1 ) );
return ( Xlt_NameROtoDOSX2 ( name_out, name_in+1 ) );
}
#endif
return ( nameROtoDOS ( name_out+2, name_in+1 ) );
......@@ -729,13 +916,21 @@ err_t Xlt_ExpandSearchEntryX2 ( BYTE *entry, char *path_base,
* =====
*/