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

Support for long filename.

  Support for spaces in machine names.
  Merge of sbrodie_LanManFS_dev branch to trunk.
Detail:
  LanManFS 2.00 supports the "NT LM 0.12" protocol, enabling it to
    use long filenames on mounted shares.
Admin:
  Supporting documentation:
    1215,256/FS: LanManFS Software Functional Specification.
  Same as LanManFS-1_87_1_1_1_1_2_13.

Version 2.00. Tagged as 'LanManFS-2_00'
parent 243543b1
......@@ -18,6 +18,15 @@
#
EXP_HDR = <export$dir>
#
# Component specific options:
#
COMPONENT = LanManFS
ROM_MODULE = aof.${COMPONENT}
RAM_MODULE = rm.${COMPONENT}
DBG_MODULE = rm.${COMPONENT}D
#
# Generic options:
#
......@@ -33,14 +42,16 @@ WIPE = -wipe
CD = dir
AFLAGS = -depend !Depend ${THROWBACK} -Stamp -quit
CFLAGS = -depend !Depend ${THROWBACK} -c -pcc -ff -zps1 -zM -I${INCLUDES},. ${DFLAGS} -UTML -DCOMPAT_INET4
CMHGFLAGS = -p -depend !Depend ${THROWBACK}
CPFLAGS = ~cfr~v
WFLAGS = ~c~v
# 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 -Wpcs -ff -zps1 -zM ${INCLUDES},. ${DFLAGS}
CMHGFLAGS = -depend !Depend ${THROWBACK} -p
INCLUDES = -ITCPIPLibs:,C:
#
# Libraries
#
......@@ -54,106 +65,126 @@ INETLIB = TCPIPLibs:o.inetlibzm
SOCKLIB = TCPIPLibs:o.socklibzm
UNIXLIB = TCPIPLibs:o.unixlibzm
#
# Include files
#
LEVEL= ^
INCLUDES= TCPIPLibs:,C:
#DFLAGS = -dDEBUG
DFLAGS =
COMPONENT = LanManFS
TARGET = rm.LanManFS
ROMTARGET = aof.LanManFS
OBJS = LanMan_MH.o LanMan.o Omni.o Logon.o CoreFn.o Printers.o \
Xlate.o Interface.o RMInfo.o buflib.o \
LLC.o NetBIOS.o SMB.o Errors.o Attr.o RPC.o NBIP.o Stats.o
OBJS = LanMan.o Omni.o Logon.o CoreFn.o Printers.o NameCache.o \
Xlate.o Interface.o RMInfo.o buflib.o Transact.o \
LLC.o NetBIOS.o SMB.o Errors.o Attr.o RPC.o NBIP.o Stats.o LanMan_MH.o
ROM_OBJS = or.LanMan or.Omni or.Logon or.CoreFn or.Printers or.NameCache \
or.Xlate or.buflib Interface.o RMInfo.o Errors.o or.Transact \
or.LLC or.NetBIOS or.SMB or.Attr or.RPC or.NBIP or.Stats LanMan_MH.o
#DBG_OBJS = od.LanMan od.Omni od.Logon od.CoreFn od.Printers od.NameCache \
# od.Xlate od.buflib Interface.o RMInfo.o Errors.o o.Transact \
# od.LLC od.NetBIOS od.SMB od.Attr od.RPC od.NBIP od.Stats LanMan_MH.o
OBJSI = i.LanMan i.Omni i.Logon i.CoreFn i.Printers \
i.Xlate i.buflib \
DBG_OBJS = od.LanMan od.Omni od.Logon od.CoreFn od.Printers od.NameCache \
od.Xlate od.buflib Interface.o RMInfo.o Errors.o od.Transact \
o.LLC o.NetBIOS od.SMB o.Attr od.RPC od.NBIP od.Stats LanMan_MH.o
OBJSI = i.LanMan i.Omni i.Logon i.CoreFn i.Printers i.NameCache \
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.LLC inst.NetBIOS inst.SMB inst.Attr inst.RPC inst.NBIP inst.Stats
inst.Xlate inst.buflib Interface.o RMInfo.o Errors.o inst.Transact\
inst.NameCache\
inst.LLC inst.NetBIOS inst.SMB inst.Attr inst.RPC inst.NBIP inst.Stats
LanMan_MH.h: LanMan_MH.o
${CMHG} ${CMHGFLAGS} cmhg.$* -d $@
#
# Rule patterns
#
.SUFFIXES: .o .s .c .i .h .cmhg .inst
.SUFFIXES: .o .od .or .s .c .i .h .cmhg .inst
.c.o:; ${CC} ${CFLAGS} -o $@ $<
.c.or:; ${CC} ${CFLAGS} -DROM -o $@ $<
.c.od:; ${CC} ${CFLAGS} -DDEBUG -DTRACE -Dprintf=module_printf -o $@ $<
.c.i:; $(CC) $(CFLAGS) -c -C -E $< >> $@
.i.inst:; $(CC) $(CFLAGS) -C++ -o $@ $<
.cmhg.o:; ${CMHG} ${CMHGFLAGS} -o $@ $<
.cmhg.o:; ${CMHG} ${CMHGFLAGS} -o $@ $< -d $*.h
.s.o:; ${AS} ${AFLAGS} $< $@
#
# Build target
#
all: ${TARGET}
all: ${RAM_MODULE}
@echo ${COMPONENT}: all complete
#
# RISC OS ROM build rules:
#
rom: ${ROMTARGET}
rom: ${ROM_MODULE}
@echo ${COMPONENT}: rom module built
preprocess: ${OBJSI} local_dirs
preprocess: ${OBJSI} i.dirs
@echo ${COMPONENT}: preprocess build complete
instrument: ${OBJSINST} inst.instlib local_dirs
$(LD) -rmf -s link/sym -o rm.AcornPOP3u $(OBJSINST) inst.instlib $(STUBS)
ModSqz rm.AcornPOP3u rm.AcornPOP3
instrument: ${OBJSINST} inst.instlib i.dirs o.dirs
$(LD) -rmf -o $@ $(OBJSINST) inst.instlib $(STUBS)
ModSqz $@
@echo ${COMPONENT}: instrument build complete
local_dirs:
o.dirs:
${MKDIR} o
${MKDIR} aof
${MKDIR} rm
${MKDIR} od
${MKDIR} or
create o.dirs
i.dirs:
${MKDIR} i
${MKDIR} inst
export:
@echo ${COMPONENT}: export complete
install_rom: ${ROMTARGET}
${CP} ${ROMTARGET} ${INSTDIR}.${COMPONENT} ${CPFLAGS}
install_rom: ${ROM_MODULE}
${CP} ${ROM_MODULE} ${INSTDIR}.${COMPONENT} ${CPFLAGS}
@echo ${COMPONENT}: rom module installed
clean:
${WIPE} o.* ${WFLAGS}
${WIPE} i.* ${WFLAGS}
${WIPE} inst.* ${WFLAGS}
${RM} ${TARGET}
${RM} ${ROMTARGET}
${RM} map.${COMPONENT}
${RM} linked.${COMPONENT}
${WIPE} o ${WFLAGS}
${WIPE} od ${WFLAGS}
${WIPE} or ${WFLAGS}
${WIPE} i ${WFLAGS}
${WIPE} inst ${WFLAGS}
${WIPE} map ${WFLAGS}
${WIPE} linked ${WFLAGS}
${WIPE} aof ${WFLAGS}
${WIPE} rm ${WFLAGS}
${RM} h.LanMan_MH
${RM} NameCache
@echo ${COMPONENT}: cleaned
#
# Target
#
${TARGET}: ${OBJS}
${RAM_MODULE}: ${OBJS} o.dirs
${MKDIR} rm
${LD} -o $@ -rmf ${OBJS} ${UNIXLIB} ${INETLIB} ${SOCKLIB} ${CLIB}
$(MODSQZ) $(TARGET)
${MODSQZ} $@
Access $@ RW/R
${DBG_MODULE}: ${DBG_OBJS} o.dirs
${MKDIR} rm
${LD} -o $@ -rmf ${DBG_OBJS} ${UNIXLIB} ${INETLIB} ${SOCKLIB} ${CLIB}
${MODSQZ} $@
#
# ROM Target
#
${ROMTARGET}: ${OBJS} ${UNIXLIB} ${INETLIB} ${SOCKLIB}
${LD} -o $@ -aof ${OBJS} ${ROMCSTUBS} ${UNIXLIB} ${INETLIB} ${SOCKLIB}
${ROM_MODULE}: ${ROM_OBJS} ${UNIXLIB} ${INETLIB} ${SOCKLIB} o.dirs
${MKDIR} aof
${LD} -o $@ -aof ${ROM_OBJS} ${ROMCSTUBS} ${UNIXLIB} ${INETLIB} ${SOCKLIB}
#
# Final link for the ROM Image (using given base address)
#
rom_link:
${MKDIR} linked
${MKDIR} map
${LD} -o linked.${COMPONENT} -map -bin -base ${ADDRESS} ${ROMTARGET} ${ABSSYM} > map.${COMPONENT}
truncate map.${COMPONENT} linked.${COMPONENT}
${LD} -o linked.${COMPONENT} -rmf -base ${ADDRESS} ${ROM_MODULE} ${ABSSYM}
${CP} linked.${COMPONENT} ${LINKDIR}.${COMPONENT} ${CPFLAGS}
@echo ${COMPONENT}: rom_link complete
......
/* (1.87)
/* (2.00)
*
* This file is automatically maintained by srccommit, do not edit manually.
*
*/
#define Module_MajorVersion_CMHG 1.87
#define Module_MajorVersion_CMHG 2.00
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 26 Aug 1998
#define Module_Date_CMHG 16 Feb 1999
#define Module_MajorVersion "1.87"
#define Module_Version 187
#define Module_MajorVersion "2.00"
#define Module_Version 200
#define Module_MinorVersion ""
#define Module_Date "26 Aug 1998"
#define Module_Date "16 Feb 1999"
......@@ -322,6 +322,22 @@ void Attr_InvalidateDrive( char drvletter )
in separately.
*/
#ifdef LONGNAMES
static err_t Attr_GetInfoX2 ( char *filename, char *leafname,
RISCOS_ATTRIBS *pRA )
{
char *lastcomma;
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 +346,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 +429,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;
......@@ -455,7 +482,6 @@ close_file:
slot (with a 0 byte at the start of 'name'), which is filled
in.
*/
extern err_t Attr_SetInfo ( char *pathname, RISCOS_ATTRIBS *pRA )
{
err_t err;
......@@ -465,6 +491,15 @@ extern err_t Attr_SetInfo ( char *pathname, RISCOS_ATTRIBS *pRA )
debug1("SetInfo for '%s'\n", pathname);
#ifdef LONGNAMES
/* Wonderfully ehough, we don't actually need an implementation
* of this at all!
*/
if (SMB_IsLongNameFS(pathname))
return OK;
#endif
if ( SetFileName(pathname) != OK )
return EBADNAME;
......@@ -577,6 +612,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 );
......
......@@ -34,6 +34,9 @@
#include "xlate.h"
#include "attr.h"
#include "smb.h"
#include "Omni.h"
#include "Transact.h"
#include "NameCache.h"
/* Some globals ================================== */
......@@ -69,6 +72,7 @@ static char DOSnamebuf [NAMEBUF_LEN];
static char RD_CurrentPath[DOS_NAME_LEN];
static int RD_Reason;
static char *RD_BufPtr;
static int RD_BufLen;
static int RD_ReqCount; /* No. of entries required */
static int RD_ReqOffset; /* Offset of currently required dir entry */
......@@ -77,77 +81,123 @@ static int RD_CurOffset; /* Offset of next entry to be given to
/* ---------------- */
static char *WriteEntry ( int reason, char *ptr, BYTE *entry )
/* SNB: the blocks being written are those required by:
* NAMES_ONLY => OS_GBPB 9 => (FSEntry_Func 14)
* MOST_INFO => OS_GBPB 10 => (FSEntry_Func 15)
* ALL_INFO => OS_GBPB 11 => (FSEntry_Func 19)
*/
static char *WriteEntry ( int reason, char *ptr, BYTE *entry, int format )
{
static char namebuf[DOS_NAME_LEN];
int name_len;
int rec_len;
DOS_ATTRIBS da;
RISCOS_ATTRIBS ra;
int *IntPtr;
#ifndef LONGNAMES
(void) format;
#else
if (format == 1) {
Xlt_ExpandSearchEntryX2(entry, DOSnamebuf, namebuf, &da, &ra);
}
else
#endif
Xlt_ExpandSearchEntry(entry, DOSnamebuf, namebuf, &da, &ra);
name_len = strlen(namebuf) + 1;
switch ( reason )
{
case NAMES_ONLY:
Xlt_ExpandSearchEntry ( entry, DOSnamebuf, ptr, NULL, NULL );
rec_len = strlen(ptr)+1;
rec_len = name_len;
if (rec_len <= RD_BufLen) {
memcpy(ptr, namebuf, name_len);
}
break;
case MOST_INFO:
Xlt_ExpandSearchEntry (entry, DOSnamebuf, ptr+20, &da, &ra );
IntPtr = (int *)ptr;
IntPtr[0] = ra.loadaddr;
IntPtr[1] = ra.execaddr;
IntPtr[2] = da.length;
IntPtr[3] = ra.flags;
IntPtr[4] = (da.attr & ATTR_DIR) ? 2 : 1;
rec_len = 20+strlen(ptr+20)+1;
rec_len = (rec_len+3) & ~3; /* Round up to whole word */
rec_len = (20+name_len+3) & ~3; /* Round up to whole word */
if (rec_len <= RD_BufLen) {
IntPtr = (int *)ptr;
IntPtr[0] = ra.loadaddr;
IntPtr[1] = ra.execaddr;
IntPtr[2] = da.length;
IntPtr[3] = ra.flags;
IntPtr[4] = (da.attr & ATTR_DIR) ? 2 : 1;
memcpy(ptr+20, namebuf, name_len);
}
break;
case ALL_INFO:
Xlt_ExpandSearchEntry (entry, DOSnamebuf, ptr+29, &da, &ra );
IntPtr = (int *)ptr;
IntPtr[0] = ra.loadaddr;
IntPtr[1] = ra.execaddr;
IntPtr[2] = da.length;
IntPtr[3] = ra.flags;
IntPtr[4] = (da.attr & ATTR_DIR) ? 2 : 1;
IntPtr[5] = 0;
IntPtr[6] = ra.execaddr;
ptr[28] = ra.loadaddr & 0xFF;
rec_len = 29+strlen(ptr+29)+1;
rec_len = (rec_len+3) & ~3; /* Round up to whole word */
rec_len = (29+name_len)+3 & ~3; /* Round up to whole word */
if (rec_len <= RD_BufLen) {
IntPtr = (int *)ptr;
IntPtr[0] = ra.loadaddr;
IntPtr[1] = ra.execaddr;
IntPtr[2] = da.length;
IntPtr[3] = ra.flags;
IntPtr[4] = (da.attr & ATTR_DIR) ? 2 : 1;
IntPtr[5] = 0;
IntPtr[6] = ra.execaddr;
ptr[28] = ra.loadaddr & 0xFF;
memcpy(ptr+29, namebuf, name_len);
}
break;
default: /* Shouldn't get here */
return ptr;
}
if (rec_len > RD_BufLen) {
debug2("WriteEntry detects a buffer overflow (%d > %d)\n",
rec_len, RD_BufLen);
RD_BufLen = -1;
return NULL;
}
RD_BufLen -= rec_len;
return (ptr+rec_len);
}
/* ------------------------------ */
static void Dir_CallbackFn ( BYTE *entry, void *pw )
static err_t Dir_CallbackFn ( BYTE *entry, int format, void *pw )
{
(void) pw;
#ifdef LONGNAMES
/* Insert check for . and .. here */
if (format == 1) {
if (entry[23] == '.') return OK;
}
else
#endif
if ( entry[9] == '.' ) /* Ignore '.' and '..' directories */
return;
return OK;
debug3 ("Entry: current %d req %d count %d\n",
RD_CurOffset, RD_ReqOffset, RD_ReqCount );
// debug3 ("Entry: current %d req %d count %d\n",
// RD_CurOffset, RD_ReqOffset, RD_ReqCount );
if ( RD_ReqOffset == RD_CurOffset )
{
if ( RD_ReqCount > 0 )
{
RD_BufPtr = WriteEntry ( RD_Reason, RD_BufPtr, entry );
RD_ReqCount--;
RD_ReqOffset++;
char *w_result = WriteEntry ( RD_Reason, RD_BufPtr, entry, format );
if (w_result != NULL) {
RD_BufPtr = w_result;
RD_ReqCount--;
RD_ReqOffset++;
}
else {
debug0("Oh dear - client ran out of buffer space!\n");
RD_CurOffset++;
return EOUTOFMEM;
}
}
}
RD_CurOffset++;
return OK;
}
/* ----------------- */
......@@ -156,10 +206,11 @@ static err_t Func_ReadDir ( int reason, char *path_name, char *buffer,
int n_names, int dir_offset, int buflen, int *pOutNread,
int *pOutNextOffset )
{
static Transact_SearchContext scon;
int tmp;
err_t res;
debug2 ( "\nReadDir reason %d path %s", reason, path_name );
debug2 ( "\n\n>> ReadDir reason %d path %s", reason, path_name );
debug2 ( " offset %d count %d\n", dir_offset, n_names );
/* Make sure the number of names we read will fit into buffer ---- */
......@@ -167,16 +218,34 @@ static err_t Func_ReadDir ( int reason, char *path_name, char *buffer,
tmp = (reason == NAMES_ONLY) ? 16 :
(reason == MOST_INFO) ? 36 : 44;
#ifdef LONGNAMES
/* Of course, the above calculation assumes that the filename is at most
* 16 characters long (8 + '.' + 3 + \0 + 3 bytes pad). This is
* useless for long filename shares and so the n_names parameter is
* accepted in place, and the buffer writer updated to be able to
* avoid and flag buffer overflow. In the worst case, this may mean
* multiple searches are required, however, as long as the directory
* reading function SMB_ReadDirEntriesX2 is intelligent, it can remember
* the resume keys and last successful filename data for the search and
* attempt to keep our caller in step with the remote server.
*
* The limit is still performed as it is still useful for avoiding
* unnecessary buffer overruns - especially when there are not very
* many files with long names or even no files with long names.
*/
/* There is no code inside this #ifdef - it just marks my comment. */
#endif
if ( n_names*tmp > buflen ) n_names = buflen/tmp;
if ( n_names <= 0 ) return EBADPARAM;
RD_Reason = reason;
RD_BufPtr = buffer;
RD_BufLen = buflen;
RD_ReqCount = n_names;
RD_ReqOffset = dir_offset;
debug1("Actual count=%d", n_names );
debug1("Actual count=%d\n", n_names );
/* Convert path adding wildcard search spec */
......@@ -184,10 +253,17 @@ static err_t Func_ReadDir ( int reason, char *path_name, char *buffer,
if ( res != OK ) return res;
tmp = strlen(DOSnamebuf);
#ifdef LONGNAMES
if ( DOSnamebuf[tmp-1] == '\\' )
strcpy( DOSnamebuf+tmp, "*" );
else
strcpy( DOSnamebuf+tmp, "\\*" );
#else
if ( DOSnamebuf[tmp-1] == '\\' )
strcpy( DOSnamebuf+tmp, "????????.???" );
else
strcpy( DOSnamebuf+tmp, "\\????????.???" );
#endif
/* Start a new search? ----------------------------------- */
......@@ -196,11 +272,11 @@ static err_t Func_ReadDir ( int reason, char *path_name, char *buffer,
RD_ReqOffset < RD_CurOffset || /* Going back in search */
strcmp(DOSnamebuf, RD_CurrentPath) != 0 ) /* New directory */
{
debug0("Start search\n");
debug1("\n>> Start search (%s)\n", DOSnamebuf);
strcpy ( RD_CurrentPath, DOSnamebuf);
RD_CurOffset = 0;
res = SMB_ReadDirEntries ( DOSnamebuf, RD_ReqCount+RD_ReqOffset,
Dir_CallbackFn, NULL );
Dir_CallbackFn, NULL, &scon );
}
else
res = OK;
......@@ -210,14 +286,20 @@ static err_t Func_ReadDir ( int reason, char *path_name, char *buffer,
while ( res == OK && /* More names available */
RD_ReqCount > 0 ) /* More names wanted */
{
debug0("Continue search\n");
debug0("\n>> Continue search\n");
res = SMB_ReadDirEntries ( NULL, RD_ReqCount+RD_ReqOffset-RD_CurOffset,
Dir_CallbackFn, NULL );
Dir_CallbackFn, NULL, &scon );
}
/* Process results */
debug2("End search, res=%d count=%d\n", res, RD_ReqCount);
if (res == EOUTOFMEM && RD_BufLen == -1) {
/* Special result when client buffer space exhausted */
debug0("Client buffer space was exhausted\n");
res = OK;
}
debug2("End search, res=%d RD_ReqCount=%d\n", res, RD_ReqCount);
if ( res != OK ) /* Ran out of files, or error */
{
......@@ -226,7 +308,15 @@ static err_t Func_ReadDir ( int reason, char *path_name, char *buffer,
}
else
{
*pOutNextOffset = RD_CurOffset;
if (RD_BufLen < 0) {
/* OK - was out of buffer space, force restart */
*pOutNextOffset = RD_ReqOffset;
//RD_CurOffset = 0;
//RD_CurrentPath[0] = 0;
}
else {
*pOutNextOffset = RD_ReqOffset;
}
}
*pOutNread = RD_ReqOffset-dir_offset;
......@@ -237,6 +327,35 @@ static err_t Func_ReadDir ( int reason, char *path_name, char *buffer,
return res;
}
static err_t Func_ReadFreeSpace ( int sixtyfourbit, char *name, int *R )
{
_kernel_swi_regs r;
_kernel_oserror *err;
struct disk_size_response dsr;
printf("Read free space\n");
r.r[0] = 2;
r.r[2] = (int) &dsr;
r.r[3] = (int) name;
err = Omni_FreeOp_SWI(&r);
if (err != NULL)
return ENOTPRESENT;
R[0] = dsr.freeblks;
if (sixtyfourbit) {
R[1] = R[4] = 0;
R[2] = 0x7FFFFFFF;
R[3] = dsr.totalblks;
}
else {
R[1] = 0x7FFFFFFF;
R[2] = dsr.totalblks;
}