From d0f4558d888602b745e8ed0bd604a0bb8e205a74 Mon Sep 17 00:00:00 2001 From: obarthel Date: Fri, 20 Jul 2018 16:05:04 +0200 Subject: [PATCH] Updated to version 1.166 Please keep in mind that this is still a development version and might surprise you (not necessarily in a good way). Do not let me discourage you to build and test this version, although there will be some risks involved such as data corruption or loss of data. --- documentation/history.doc | 33 ++++ source_code/exall-example.c | 318 ++++++++++++++++++++---------------- source_code/main.c | 59 +++++-- source_code/smbfs_rev.h | 10 +- source_code/smbfs_rev.rev | 2 +- 5 files changed, 255 insertions(+), 167 deletions(-) diff --git a/documentation/history.doc b/documentation/history.doc index eca00fd..c8a3ebe 100644 --- a/documentation/history.doc +++ b/documentation/history.doc @@ -2333,3 +2333,36 @@ smbfs 1.165 (19.7.2018) tree and get stuck in a loop. The new path processing code allows both cases to be different, whereas previously the results could be identical. + + +smbfs 1.166 (20.7.2018) + +- Added the DISABLEEXALL switch which can be used to completely + disable support for the dos.library/ExAll() function within + smbfs. + + Disabling the ExAll() function is recommend if you intend to use + software with smbfs which reserves too little memory for the buffer + which smbfs is to fill when processing the directory contents it + is reading. + + If there is not enough memory provided, smbfs may eventually stop + providing further directory entries, flagging an error. This can + give the appearance of smbfs losing directory entries during the + scanning process when in fact it stopped because was unable to + store the directory entry names in the buffer supplied by the + application which invoked it. + + Stopping because it cannot continue may not necessarily be handled + well by the application, which may just treat it no different from + the any indication that smbfs has no further entries to provide + because the SMB server has already transmitted the last entry. + +- When running out of space trying store another directory entry, the + smbfs ExAll() function could fail to allow for scanning to resume. + This would cause smbfs to lose directory entries. + +- Updated the "exall-example" program to allow easier testing with + small buffer sizes. The default buffer size used to be 4096 bytes + which failed to reproduce most of the smbfs ExAll implementation + problems :-( diff --git a/source_code/exall-example.c b/source_code/exall-example.c index 20bf383..5daf68b 100644 --- a/source_code/exall-example.c +++ b/source_code/exall-example.c @@ -3,25 +3,45 @@ #include #include #include + #include #include #include + +#if defined (__amigaos4__) #include + #include #include +#else +extern struct Library *SysBase; +extern struct Library *DOSBase; + +#include +#include + +#include +#include +#endif /* __amigaos4__ */ #include -/* normally you'd include pragmas here */ - #define BUFFSIZE 4096 int main(int argc,char *argv[]) { + struct + { + STRPTR Name; + STRPTR Pattern; + LONG * BufferSize; + } args; + + struct RDArgs * rda; BPTR obj_lock; LONG res2,more; - struct ExAllData *Buffer = NULL; + struct ExAllData *buffer = NULL; struct ExAllData *ead; struct ExAllControl *control = NULL; LONG rc = RETURN_ERROR; @@ -30,159 +50,171 @@ main(int argc,char *argv[]) char owner_bits[9]; struct DateTime dat; char date[LEN_DATSTRING],time[LEN_DATSTRING]; + ULONG total_num_entries = 0; + int buffer_size = 0; int type; int i; - /* ugly argument parsing */ - if(argc >= 2 && argc <= 3) + memset(&args,0,sizeof(args)); + + rda = ReadArgs("NAME/A,PATTERN/K,BUF=BUFFER/K/N",(LONG *)&args,NULL); + if(rda == NULL) { - /* control MUST be allocated by AllocDosObject! */ - control = (struct ExAllControl *) AllocDosObject(DOS_EXALLCONTROL,NULL); - Buffer = (struct ExAllData *) AllocMem(BUFFSIZE,MEMF_PUBLIC|MEMF_CLEAR); - - /* always check allocations! */ - if (control == NULL || Buffer == NULL) - goto cleanup; - - if (argc == 3) - { - /* parse the pattern for eac_MatchString */ - if (ParsePatternNoCase(argv[2],pattern,sizeof(pattern)) == -1) - { - Printf("ParsePatternNoCase buffer overflow!\n"); - goto cleanup; - } - - control->eac_MatchString = pattern; - } - - /* lock the directory */ - obj_lock = Lock(argv[1],SHARED_LOCK); - if (obj_lock != (BPTR)NULL) - { - control->eac_LastKey = 0; /* paranoia */ - - type = ED_OWNER; - - do /* while more */ - { - more = ExAll(obj_lock,Buffer,BUFFSIZE,type,control); - res2 = IoErr(); - - if(!more && res2 == ERROR_BAD_NUMBER && type == ED_OWNER) - { - type = ED_COMMENT; - - more = ExAll(obj_lock,Buffer,BUFFSIZE,type,control); - res2 = IoErr(); - } - - if (!more) - { - if(res2 != ERROR_NO_MORE_ENTRIES) - Printf("Abnormal exit, error = %ld\n",res2); - - break; - } - - Printf("Returned %ld entries:\n\n",control->eac_Entries); - - if (control->eac_Entries > 0) - { - for(ead = Buffer ; ead != NULL ; ead->ed_Next) - { - if (ead->ed_Type > 0) - Printf("%s (dir)", ead->ed_Name); - else - Printf("%s (file), size=%ld", ead->ed_Name, ead->ed_Size); - - strcpy(user_other_bits, "rwed rwed"); - - for(i = 8 ; i < 16 ; i++) - { - if((ead->ed_Prot & (1 << i)) == 0) - { - int offset; - - if(i < 12) - offset = 12 - i; - else - offset = 21 - i; - - user_other_bits[offset - 1] = '-'; - } - } - - strcpy(owner_bits, "hsparwed"); - - for(i = 0 ; i < 4 ; i++) - { - if((ead->ed_Prot & (1 << i)) != 0) - owner_bits[7 - i] = '-'; - } - - for(i = 4 ; i < 8 ; i++) - { - if((ead->ed_Prot & (1 << i)) == 0) - owner_bits[7 - i] = '-'; - } - - memset(&dat,0,sizeof(dat)); - - memset(date,0,sizeof(date)); - memset(time,0,sizeof(time)); - - dat.dat_Stamp.ds_Days = ead->ed_Days; - dat.dat_Stamp.ds_Minute = ead->ed_Mins; - dat.dat_Stamp.ds_Tick = ead->ed_Ticks; - dat.dat_Format = FORMAT_DEF; - dat.dat_StrDate = date; - dat.dat_StrTime = time; - - DateToStr(&dat); - - Printf(", protection=%s %s (0x%08lx), date=%s %s (%ld/%ld/%ld), comment=\"%s\"", - user_other_bits,owner_bits,ead->ed_Prot, - date,time, - ead->ed_Days,ead->ed_Mins,ead->ed_Ticks, - ead->ed_Comment ? ead->ed_Comment : (STRPTR)""); - - if (type == ED_OWNER) - { - Printf(", uid=%ld, gid=%ld", - ead->ed_OwnerUID, - ead->ed_OwnerGID); - } - - Printf("\n"); - - ead = ead->ed_Next; - } - } - - rc = RETURN_OK; /* success */ - } - while (more); - - UnLock(obj_lock); - } - else - { - Printf("Couldn't find %s\n", argv[1]); - } + PrintFault(IoErr(),FilePart(argv[0])); + goto cleanup; } + + if(args.BufferSize != NULL) + buffer_size = (*args.BufferSize); else + buffer_size = BUFFSIZE; + + /* control MUST be allocated by AllocDosObject! */ + control = (struct ExAllControl *) AllocDosObject(DOS_EXALLCONTROL,NULL); + buffer = (struct ExAllData *) AllocMem(buffer_size,MEMF_PUBLIC|MEMF_CLEAR); + + /* always check allocations! */ + if (control == NULL || buffer == NULL) + goto cleanup; + + if (args.Pattern != NULL) { - Printf("Usage: %s dirname [pattern]\n", argv[0]); + /* parse the pattern for eac_MatchString */ + if (ParsePatternNoCase(args.Pattern,pattern,sizeof(pattern)) == -1) + { + PrintFault(IoErr(), args.Pattern); + goto cleanup; + } + + control->eac_MatchString = pattern; } + /* lock the directory */ + obj_lock = Lock(args.Name,SHARED_LOCK); + if (obj_lock == (BPTR)NULL) + { + PrintFault(IoErr(), args.Name); + goto cleanup; + } + + control->eac_LastKey = 0; /* paranoia */ + + /* Workaround for V37 ROM/disk filesystem bug. */ + type = ED_OWNER; + + Printf("Buffer size = %ld bytes\n", buffer_size); + + do /* while more */ + { + more = ExAll(obj_lock,buffer,buffer_size,type,control); + res2 = IoErr(); + + /* Workaround for V37 ROM/disk filesystem bug. */ + if(!more && res2 == ERROR_BAD_NUMBER && type == ED_OWNER) + { + type = ED_COMMENT; + + more = ExAll(obj_lock,buffer,buffer_size,type,control); + res2 = IoErr(); + } + + if (!more && res2 != ERROR_NO_MORE_ENTRIES) + { + Printf("Abnormal exit, error = %ld\n",res2); + break; + } + + Printf("Returned %ld entries:\n\n",control->eac_Entries); + + if (control->eac_Entries == 0) + continue; + + for(ead = buffer ; ead != NULL ; ead = ead->ed_Next) + { + if (ead->ed_Type > 0) + Printf("%s (dir)", ead->ed_Name); + else + Printf("%s (file), size=%ld", ead->ed_Name, ead->ed_Size); + + strcpy(user_other_bits, "rwed rwed"); + + for(i = 8 ; i < 16 ; i++) + { + if((ead->ed_Prot & (1 << i)) == 0) + { + int offset; + + if(i < 12) + offset = 12 - i; + else + offset = 21 - i; + + user_other_bits[offset - 1] = '-'; + } + } + + strcpy(owner_bits, "hsparwed"); + + for(i = 0 ; i < 4 ; i++) + { + if((ead->ed_Prot & (1 << i)) != 0) + owner_bits[7 - i] = '-'; + } + + for(i = 4 ; i < 8 ; i++) + { + if((ead->ed_Prot & (1 << i)) == 0) + owner_bits[7 - i] = '-'; + } + + memset(&dat,0,sizeof(dat)); + + memset(date,0,sizeof(date)); + memset(time,0,sizeof(time)); + + dat.dat_Stamp.ds_Days = ead->ed_Days; + dat.dat_Stamp.ds_Minute = ead->ed_Mins; + dat.dat_Stamp.ds_Tick = ead->ed_Ticks; + dat.dat_Format = FORMAT_DEF; + dat.dat_StrDate = date; + dat.dat_StrTime = time; + + DateToStr(&dat); + + Printf(", protection=%s %s (0x%08lx), date=%s %s (%ld/%ld/%ld), comment=\"%s\"", + user_other_bits,owner_bits,ead->ed_Prot, + date,time, + ead->ed_Days,ead->ed_Mins,ead->ed_Ticks, + ead->ed_Comment ? ead->ed_Comment : (STRPTR)""); + + if (type == ED_OWNER) + { + Printf(", uid=%ld, gid=%ld", + ead->ed_OwnerUID, + ead->ed_OwnerGID); + } + + Printf("\n"); + + total_num_entries++; + } + } + while (more); + + UnLock(obj_lock); + + Printf("Total number of entries = %lu\n", total_num_entries); + cleanup: - if (Buffer != NULL) - FreeMem(Buffer,BUFFSIZE); + if (rda != NULL) + FreeArgs(rda); + + if (buffer != NULL) + FreeMem(buffer, buffer_size); if (control != NULL) - FreeDosObject(DOS_EXALLCONTROL,control); + FreeDosObject(DOS_EXALLCONTROL, control); return(rc); } diff --git a/source_code/main.c b/source_code/main.c index 53c98aa..5a43020 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -212,6 +212,7 @@ static BOOL Quit; static BOOL Quiet; static BOOL CaseSensitive; static BOOL OmitHidden; +static BOOL DisableExAll; static LONG DSTOffset; static LONG TimeZoneOffset; @@ -556,6 +557,7 @@ main(void) KEY VolumeName; NUMBER MaxNameLen; NUMBER CacheSize; + SWITCH DisableExAll; NUMBER MaxTransmit; NUMBER Timeout; NUMBER TimeZoneOffset; @@ -592,6 +594,7 @@ main(void) "VOLUME=VOLUMENAME/K," "MAXNAMELEN/N/K," "CACHE=CACHESIZE/N/K," + "DISABLEEXALL/S," "MAXTRANSMIT/N/K," "TIMEOUT/N/K," "TZ=TIMEZONEOFFSET/N/K," @@ -739,6 +742,9 @@ main(void) if(FindToolType(Icon->do_ToolTypes,"CHANGECASE") != NULL) args.ChangeCase = TRUE; + if(FindToolType(Icon->do_ToolTypes,"DISABLEEXALL") != NULL) + args.DisableExAll = TRUE; + if(FindToolType(Icon->do_ToolTypes,"OMITHIDDEN") != NULL) args.OmitHidden = TRUE; @@ -1064,8 +1070,9 @@ main(void) TranslateNames = TRUE; } - CaseSensitive = (BOOL)args.CaseSensitive; - OmitHidden = (BOOL)args.OmitHidden; + DisableExAll = (BOOL)(args.DisableExAll != 0); + CaseSensitive = (BOOL)(args.CaseSensitive != 0); + OmitHidden = (BOOL)(args.OmitHidden != 0); /* You don't need to provide a specific workgroup name. smbfs will * work perfectly find with modern (and somewhat older) SMB implementations @@ -6052,7 +6059,7 @@ struct ExAllContext static int dir_scan_callback_func_exall( struct ExAllContext * ec, - int unused_fpos, + int fpos, int nextpos, const TEXT * name, int eof, @@ -6061,6 +6068,7 @@ dir_scan_callback_func_exall( TEXT translated_name[MAX_FILENAME_LEN+1]; int stop_scanning = FALSE; int name_len; + int resume_position = -1; LONG type = ec->ec_Type; UBYTE * buffer = ec->ec_Buffer; struct ExAllData * ed; @@ -6167,6 +6175,13 @@ dir_scan_callback_func_exall( SHOWMSG(" this was the first read attempt -- aborting"); ec->ec_Error = ERROR_NO_FREE_STORE; } + else + { + /* Assuming that the client wants to know the next + * entry, resume with the one which we couldn't store. + */ + resume_position = fpos; + } stop_scanning = TRUE; goto out; @@ -6331,7 +6346,7 @@ dir_scan_callback_func_exall( /* Any more entries to deliver or stop right now? */ if(stop_scanning || eof) { - ec->ec_Control->eac_LastKey = -1; + ec->ec_Control->eac_LastKey = resume_position; SHOWMSG(" that was the last entry"); } @@ -6379,7 +6394,8 @@ Action_ExamineAll( */ if(buffer_size < (LONG)sizeof(ed->ed_Next)) { - SHOWMSG("buffer is far too short."); + D(("buffer is far too short (%ld bytes, minimum is %ld).",buffer_size, sizeof(ed->ed_Next))); + error = ERROR_NO_FREE_STORE; goto out; } @@ -6387,7 +6403,7 @@ Action_ExamineAll( /* No next entry yet. */ ed->ed_Next = NULL; - if(eac->eac_LastKey == (ULONG)-1) + if((LONG)eac->eac_LastKey == -1) { SHOWMSG("scanning already finished."); @@ -6531,30 +6547,29 @@ Action_ExamineAll( smba_readdir(ln->ln_File,offset,&ec,(smba_callback_t)dir_scan_callback_func_exall,&error); - if(error == OK && ec.ec_Error != OK) - { - SHOWMSG("flagging an error"); - - SHOWVALUE(ec.ec_Error); - - error = ec.ec_Error; - } - if(error != OK) { - SHOWMSG("error whilst scanning"); + D(("error whilst scanning (errno=%ld)", error)); error = map_errno_to_ioerr(error); goto out; } + if(error == OK && ec.ec_Error != OK) + { + D(("flagging an error (ioerr=%ld)", ec.ec_Error)); + + error = ec.ec_Error; + goto out; + } + /* The dir_scan_callback_func_exall() function will set the * last key (directory search position) to -1 when there * are no more entries to be read. If we didn't succeed * in reading anything at all, this means that we have to * throw in the towel... */ - if(eac->eac_Entries == 0 && ec.ec_Control->eac_LastKey == (ULONG)-1) + if(eac->eac_Entries == 0 && (LONG)ec.ec_Control->eac_LastKey == -1) { SHOWMSG("nothing more to be read"); @@ -6579,7 +6594,7 @@ Action_ExamineAll( { int num_entries_found = 0; - SHOWVALUE(eac->eac_Entries); + D(("number of entries available = %ld",eac->eac_Entries)); if(eac->eac_Entries > 0) { @@ -8769,6 +8784,14 @@ file_system_handler(BOOL raise_priority, const TEXT * device_name,const TEXT * v case ACTION_EXAMINE_ALL: /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */ + /* Pretend that we do not support the ExAll() functionality? */ + if(DisableExAll) + { + res1 = DOSFALSE; + res2 = ERROR_ACTION_NOT_KNOWN; + break; + } + res1 = Action_ExamineAll(dp->dp_Port,(struct FileLock *)BADDR(dp->dp_Arg1),(UBYTE *)dp->dp_Arg2, dp->dp_Arg3,dp->dp_Arg4,(struct ExAllControl *)dp->dp_Arg5,&res2); diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h index 626722d..93aaaab 100644 --- a/source_code/smbfs_rev.h +++ b/source_code/smbfs_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 165 -#define DATE "19.7.2018" -#define VERS "smbfs 1.165" -#define VSTRING "smbfs 1.165 (19.7.2018)\r\n" -#define VERSTAG "\0$VER: smbfs 1.165 (19.7.2018)" +#define REVISION 166 +#define DATE "20.7.2018" +#define VERS "smbfs 1.166" +#define VSTRING "smbfs 1.166 (20.7.2018)\r\n" +#define VERSTAG "\0$VER: smbfs 1.166 (20.7.2018)" diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev index 9e42f3e..cdffbbc 100644 --- a/source_code/smbfs_rev.rev +++ b/source_code/smbfs_rev.rev @@ -1 +1 @@ -165 +166