diff --git a/documentation/history.doc b/documentation/history.doc index 358a565..6c88f91 100644 --- a/documentation/history.doc +++ b/documentation/history.doc @@ -3019,5 +3019,27 @@ smbfs 2.20 (27.2.2019) - Rewrote the smba_readdir() function to perform its only task in a much simpler manner. It now either fills the directory cache or retrieves - the cache entries to the caller, resuming the retrieval at a predefined - position if required. + the cache entries to be delivered to the caller, resuming the retrieval + at a predefined position if required. + + +smbfs 2.21 (9.3.2019) + +- Added more diagnostic output and debug functionality, e.g. regarding + how many directory caches are currently being used. + +- Long name directory scanning is a bit more paranoid when retrying a + scan operation which might have been triggered by the server connection + getting dropped. + +- Added the new READONLY option (why stop at 47 options when you can + have 48?) which makes the file system read-only by default and does not + require you to use the "Lock" shell command to achieve the same effect. + Note that the shell "Lock" command cannot be used to turn the read-only + mode off again. + +- Added support for the smb:// URI scheme, which means that instead of + using "smbfs username=barney password=secret domain=workgroup //nas:445/share" + you can now use "smbfs smb://workgroup;barney:secret@nas:445/share" instead. + It is a bit shorter than the alternative and has an advantage in allowing + you to reuse smb:// URLs which you know work well on other systems. diff --git a/source_code/GNUmakefile.68k b/source_code/GNUmakefile.68k index 874c9d6..78569fd 100644 --- a/source_code/GNUmakefile.68k +++ b/source_code/GNUmakefile.68k @@ -3,7 +3,7 @@ # # SMB file system wrapper for AmigaOS, using the AmiTCP V3 API # -# Copyright (C) 2000-2019 by Olaf `Olsen' Barthel +# Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -47,8 +47,8 @@ LFLAGS = -nostartfiles -nostdlib -L. ############################################################################### OBJS = \ - main.o proc.o smb_abstraction.o sock.o crypt.o quad_math.o dump_smb.o \ - cp437.o cp850.o splay.o + main.o cp437.o cp850.o crypt.o dump_smb.o parse-smb-url.o proc.o \ + quad_math.o smb_abstraction.o sock.o splay.o ############################################################################### @@ -73,7 +73,8 @@ cp437.o : cp437.c cp850.o : cp850.c crypt.o : crypt.c system_headers.h assert.h quad_math.h splay.h smbfs.h dump_smb.o : dump_smb.c system_headers.h assert.h quad_math.h splay.h smbfs.h dump_smb.h -main.o : main.c system_headers.h assert.h quad_math.h splay.h smbfs.h smb_abstraction.h cp437.h cp850.h errors.h dump_smb.h smbfs_rev.h +main.o : main.c system_headers.h assert.h quad_math.h splay.h smbfs.h smb_abstraction.h cp437.h cp850.h errors.h dump_smb.h parse-smb-url.h smbfs_rev.h +parse-smb-url.o : parse-smb-url.c system_headers.h assert.h quad_math.h splay.h smbfs.h parse-smb-url.h proc.o : proc.c system_headers.h assert.h quad_math.h splay.h smbfs.h errors.h smbfs_rev.h quad_math.o : quad_math.c quad_math.h smb_abstraction.o : smb_abstraction.c system_headers.h assert.h quad_math.h splay.h smbfs.h errors.h smb_abstraction.h diff --git a/source_code/GNUmakefile.os4 b/source_code/GNUmakefile.os4 index 1eabe78..b6c4b98 100644 --- a/source_code/GNUmakefile.os4 +++ b/source_code/GNUmakefile.os4 @@ -3,7 +3,7 @@ # # SMB file system wrapper for AmigaOS, using the AmiTCP V3 API # -# Copyright (C) 2000-2019 by Olaf `Olsen' Barthel +# Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -66,8 +66,8 @@ LFLAGS = -nostartfiles -nostdlib -L. ########################################################################### OBJS = \ - main.o proc.o smb_abstraction.o sock.o crypt.o quad_math.o dump_smb.o \ - cp437.o cp850.o splay.o assert.o + main.o assert.o cp437.o cp850.o crypt.o dump_smb.o parse-smb-url.o \ + proc.o quad_math.o smb_abstraction.o sock.o splay.o ########################################################################### @@ -92,7 +92,8 @@ cp437.o : cp437.c cp850.o : cp850.c crypt.o : crypt.c system_headers.h assert.h quad_math.h splay.h smbfs.h dump_smb.o : dump_smb.c system_headers.h assert.h quad_math.h splay.h smbfs.h dump_smb.h -main.o : main.c system_headers.h assert.h quad_math.h splay.h smbfs.h smb_abstraction.h cp437.h cp850.h errors.h dump_smb.h smbfs_rev.h +main.o : main.c system_headers.h assert.h quad_math.h splay.h smbfs.h smb_abstraction.h cp437.h cp850.h errors.h dump_smb.h parse-smb-url.h smbfs_rev.h +parse-smb-url.o : parse-smb-url.c system_headers.h assert.h quad_math.h splay.h smbfs.h parse-smb-url.h proc.o : proc.c system_headers.h assert.h quad_math.h splay.h smbfs.h errors.h smbfs_rev.h quad_math.o : quad_math.c quad_math.h smb_abstraction.o : smb_abstraction.c system_headers.h assert.h quad_math.h splay.h smbfs.h errors.h smb_abstraction.h diff --git a/source_code/assert.c b/source_code/assert.c index adc912f..6cfbfe8 100644 --- a/source_code/assert.c +++ b/source_code/assert.c @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/assert.h b/source_code/assert.h index be6c662..c34f3d9 100644 --- a/source_code/assert.h +++ b/source_code/assert.h @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/cp437.c b/source_code/cp437.c index e9ef0af..2aa2cb6 100644 --- a/source_code/cp437.c +++ b/source_code/cp437.c @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/cp437.h b/source_code/cp437.h index eebd866..cf087c7 100644 --- a/source_code/cp437.h +++ b/source_code/cp437.h @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/cp850.c b/source_code/cp850.c index 72768ea..5971dee 100644 --- a/source_code/cp850.c +++ b/source_code/cp850.c @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/cp850.h b/source_code/cp850.h index 5e65081..165361d 100644 --- a/source_code/cp850.h +++ b/source_code/cp850.h @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/dump_smb.c b/source_code/dump_smb.c index 560ef99..eecc99c 100644 --- a/source_code/dump_smb.c +++ b/source_code/dump_smb.c @@ -3,7 +3,7 @@ * * dump_smb.c * - * Copyright (C) 2016-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2016-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/dump_smb.h b/source_code/dump_smb.h index 90d069c..7391ff7 100644 --- a/source_code/dump_smb.h +++ b/source_code/dump_smb.h @@ -3,7 +3,7 @@ * * dump_smb.h * - * Copyright (C) 2016-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2016-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/errors.h b/source_code/errors.h index a178037..e461255 100644 --- a/source_code/errors.h +++ b/source_code/errors.h @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/main.c b/source_code/main.c index cd82fef..49cde98 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ * Samba 4.7.6: smbfs debuglevel=2 debugfile=ram:ubuntu-18.log volume=ubuntu-test //ubuntu-18-olaf/test * Samba 4.7.6: smbfs debuglevel=2 debugfile=ram:ubuntu-18.log cachesize=30 volume=ubuntu-etc //ubuntu-18-olaf/etc * Samba 3.0.25: smbfs debuglevel=2 debugfile=ram:samba-3.0.25.log user=olsen password=... volume=olsen //192.168.1.118/olsen + * Samba 3.0.25: smbfs debuglevel=2 debugfile=ram:samba-3.0.25.log smb://olsen:...@192.168.1.118/olsen * * diskspeed drive olsen:Documents dir seek fast byte nocpu */ @@ -46,6 +47,7 @@ #include "errors.h" #include "quad_math.h" #include "dump_smb.h" +#include "parse-smb-url.h" /****************************************************************************/ @@ -341,6 +343,8 @@ static BOOL OverrideLocaleTimeZone; static BOOL WriteProtected; static ULONG WriteProtectKey; +static BOOL ReadOnly; + static struct MinList FileList; static struct MinList LockList; @@ -763,6 +767,7 @@ main(void) SWITCH CaseSensitive; SWITCH OmitHidden; SWITCH Quiet; + SWITCH ReadOnly; SWITCH RaisePriority; SWITCH SetEnv; KEY ClientName; @@ -813,6 +818,7 @@ main(void) "CASE=CASESENSITIVE/S," "OMITHIDDEN/S," "QUIET/S," + "READONLY/S," "RAISEPRIORITY/S," "SETENV/S," "CLIENT=CLIENTNAME/K," @@ -869,6 +875,7 @@ main(void) TEXT env_workgroup_name[17]; TEXT env_user_name[64]; TEXT env_password[64]; + struct smb_url_args * smb_url_args = NULL; /* Don't emit any debugging output before we are ready. */ SETDEBUGLEVEL(0); @@ -879,6 +886,13 @@ main(void) */ NewList((struct List *)&ErrorList); + MemoryPool = CreatePool(MEMF_ANY|MEMF_PUBLIC, 4096, 4096); + if(MemoryPool == NULL) + { + report_error("Could not create memory pool."); + goto out; + } + /* The command parameters will be filled in either from * icon tool types or from the CLI command line arguments. */ @@ -890,6 +904,7 @@ main(void) */ if(WBStartup != NULL) { + TEXT * smb_url = NULL; TEXT * icon_file_name; BPTR icon_file_lock; STRPTR str; @@ -1023,6 +1038,71 @@ main(void) goto out; } + /* Check if the service name is an SMB url. */ + if(could_be_smb_url(args.Service)) + { + smb_url = (TEXT *)args.Service; + + smb_url_args = parse_smb_url_args(smb_url); + if(smb_url_args == NULL) + { + report_error("Not enough memory."); + goto out; + } + } + + if(smb_url_args != NULL) + { + /* We need both a server and a share name for the + * SMB URL to be useful. + */ + if(smb_url_args->server != NULL && smb_url_args->share != NULL) + { + STRPTR new_service; + int new_service_size; + + /* Combine share name, an optional port number/service name + * and the share name. + */ + new_service_size = 1 + + 2 + strlen(smb_url_args->server) + + 1 + strlen(smb_url_args->share); + + if(smb_url_args->port != NULL) + new_service_size += 1 + strlen(smb_url_args->port); + + new_service = malloc(new_service_size); + if(new_service != NULL) + { + strlcpy(new_service, "//", new_service_size); + strlcat(new_service, smb_url_args->server, new_service_size); + + if(smb_url_args->port != NULL) + { + strlcat(new_service, ":", new_service_size); + strlcat(new_service, smb_url_args->port, new_service_size); + } + + strlcat(new_service, "/", new_service_size); + strlcat(new_service, smb_url_args->share, new_service_size); + + D(("SMB URL translates into service '%s'.", new_service)); + + args.Service = new_service; + } + else + { + report_error("Not enough memory."); + goto out; + } + } + else + { + report_error("Service '%s' lacks a complete server and share description.", smb_url); + smb_url_args = NULL; + } + } + /* Set up the name of the program, as it will be * displayed in error requesters. */ @@ -1032,17 +1112,30 @@ main(void) if(NewProgramName != NULL) LocalSNPrintf(NewProgramName,size,"%s '%s'",icon_file_name,args.Service); - args.Workgroup = get_icon_tool_type_value("DOMAIN","WORKGROUP"); - args.UserName = get_icon_tool_type_value("USER","USERNAME"); + /* Use the SMB URL's domain information, if provided. */ + if(smb_url_args != NULL && smb_url_args->domain != NULL) + args.Workgroup = smb_url_args->domain; + else + args.Workgroup = get_icon_tool_type_value("DOMAIN", "WORKGROUP"); + + /* Use the SMB URL's user name information, if provided. */ + if(smb_url_args != NULL && smb_url_args->username != NULL) + args.UserName = smb_url_args->username; + else + args.UserName = get_icon_tool_type_value("USER", "USERNAME"); + + /* Use the SMB URL's password information, if provided. */ + if(smb_url_args != NULL && smb_url_args->password != NULL) + args.Password = smb_url_args->password; + else + args.Password = get_icon_tool_type_value("PASSWORD", NULL); str = get_icon_tool_type_value("CHANGEUSERNAMECASE", NULL); args.ChangeUserNameCase = (str != NULL) ? str : (STRPTR)"yes"; - args.Password = get_icon_tool_type_value("PASSWORD", NULL); - args.ChangePasswordCase = get_icon_tool_type_value("CHANGEPASSWORDCASE", NULL); if(args.ChangePasswordCase == NULL && get_icon_tool_type_value("CHANGECASE", NULL) != NULL) - args.ChangePasswordCase = "yes"; + args.ChangePasswordCase = (STRPTR)"yes"; args.TCPDelay = get_icon_tool_type_value("TCPDELAY", NULL); if(args.TCPDelay == NULL && get_icon_tool_type_value("TCPNODELAY", "TCP_NODELAY") != NULL) @@ -1051,6 +1144,7 @@ main(void) args.DisableExAll = get_icon_tool_type_value("DISABLEEXALL", NULL) != NULL; args.OmitHidden = get_icon_tool_type_value("OMITHIDDEN", NULL) != NULL; args.Quiet = get_icon_tool_type_value("QUIET", NULL) != NULL; + args.ReadOnly = get_icon_tool_type_value("READONLY", NULL) != NULL; args.RaisePriority = get_icon_tool_type_value("RAISEPRIORITY", NULL) != NULL; args.CaseSensitive = get_icon_tool_type_value("CASE", "CASESENSITIVE") != NULL; args.NetBIOSTransport = get_icon_tool_type_value("NETBIOS", NULL) != NULL; @@ -1276,6 +1370,73 @@ main(void) D(("%s (%s)", VERS, DATE)); + if(could_be_smb_url(args.Service)) + { + smb_url_args = parse_smb_url_args(args.Service); + if(smb_url_args != NULL) + { + if(smb_url_args->server != NULL && smb_url_args->share) + { + STRPTR new_service; + int new_service_size; + + new_service_size = 1 + + 2 + strlen(smb_url_args->server) + + 1 + strlen(smb_url_args->share); + + if(smb_url_args->port != NULL) + new_service_size += 1 + strlen(smb_url_args->port); + + new_service = malloc(new_service_size); + if(new_service != NULL) + { + strlcpy(new_service, "//", new_service_size); + strlcat(new_service, smb_url_args->server, new_service_size); + + if(smb_url_args->port != NULL) + { + strlcat(new_service, ":", new_service_size); + strlcat(new_service, smb_url_args->port, new_service_size); + } + + strlcat(new_service, "/", new_service_size); + strlcat(new_service, smb_url_args->share, new_service_size); + + D(("SMB URL translates into service '%s'.", new_service)); + + args.Service = new_service; + + /* Use the domain, user name and password information, + * if provided. + */ + if(smb_url_args->domain != NULL) + args.Workgroup = smb_url_args->domain; + + if(smb_url_args->username != NULL) + args.UserName = smb_url_args->username; + + if(smb_url_args->password != NULL) + args.Password = smb_url_args->password; + } + else + { + PrintFault(ERROR_NO_FREE_STORE, FilePart(program_name)); + goto out; + } + } + else + { + report_error("Service '%s' lacks a complete server and share description.", args.Service); + goto out; + } + } + else + { + PrintFault(ERROR_NO_FREE_STORE, FilePart(program_name)); + goto out; + } + } + ASSERT( args.Service != NULL ); /* Set up the name of the program, as it will be @@ -1576,6 +1737,9 @@ main(void) D(("disable exall = %s", DisableExAll ? "yes": "no")); D(("case sensitive = %s", CaseSensitive ? "yes": "no")); D(("omit hidden = %s", OmitHidden ? "yes": "no")); + D(("raise priority = %s", args.RaisePriority ? "yes": "no")); + D(("read only = %s", args.ReadOnly ? "yes": "no")); + D(("quiet = %s", args.Quiet ? "yes": "no")); /* Enable SMB packet decoding, but only if not started from Workbench. */ #if defined(DUMP_SMB) @@ -1696,6 +1860,7 @@ main(void) char setenv_name[40]; Quiet = args.Quiet; + ReadOnly = args.ReadOnly; if(Locale != NULL) SHOWVALUE(Locale->loc_GMTOffset); @@ -1787,6 +1952,12 @@ main(void) Close(debug_file); } + if(MemoryPool != NULL) + { + DeletePool(MemoryPool); + MemoryPool = NULL; + } + return(result); } @@ -2283,6 +2454,37 @@ allocate_memory(LONG size) /****************************************************************************/ +APTR +allocate_cleared_memory(LONG count, LONG record_size) +{ + APTR result = NULL; + LONG size; + + size = count * record_size; + + if(size > 0) + { + ULONG * mem; + + size = sizeof(*mem) + ((size + 7) & ~7UL); + + mem = AllocPooled(MemoryPool,size); + + if(mem != NULL) + { + (*mem++) = size; + + memset(mem, 0, size); + + result = mem; + } + } + + return(result); +} + +/****************************************************************************/ + /* Allocate memory for a new lock node and initialize it. */ static struct LockNode * allocate_lock_node( @@ -3945,12 +4147,6 @@ cleanup(void) LocaleBase = NULL; } - if(MemoryPool != NULL) - { - DeletePool(MemoryPool); - MemoryPool = NULL; - } - PROFILE_ON(); LEAVE(); @@ -4050,13 +4246,6 @@ setup( } #endif /* USE_SPLAY_TREE */ - MemoryPool = CreatePool(MEMF_ANY|MEMF_PUBLIC, 4096, 4096); - if(MemoryPool == NULL) - { - report_error("Could not create memory pool."); - goto out; - } - LocaleBase = OpenLibrary("locale.library",38); #if defined(__amigaos4__) @@ -5882,7 +6071,7 @@ Action_DeleteObject( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -6073,7 +6262,7 @@ Action_CreateDir( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -6596,7 +6785,7 @@ Action_SetProtect( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -6768,7 +6957,7 @@ Action_RenameObject( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -6932,7 +7121,7 @@ Action_DiskInfo( if(smba_statfs(ServerData,&block_size,&num_blocks,&num_blocks_free,&error) >= 0) { - if(NOT WriteProtected) + if(NOT ReadOnly && NOT WriteProtected) id->id_DiskState = ID_VALIDATED; SHOWMSG("got the disk data"); @@ -8142,12 +8331,6 @@ Action_ExamineAll( SHOWVALUE(ec.ec_RecordSize); - /* If this 0, we start reading the directory contents beginning - * with the first entry. A value > 0 is supposed to resume - * directory scanning at the given directory entry index. - */ - offset = eac->eac_LastKey; - /* Check if we should restart scanning the directory * contents. This is tricky at best and may produce * irritating results :( @@ -8164,6 +8347,7 @@ Action_ExamineAll( else { restart = FALSE; + offset = eac->eac_LastKey; } /* Start from the top? Check if the lock actually refers to a directory. */ @@ -8449,7 +8633,7 @@ Action_Find( STRPTR dir_name,base_name; smba_file_t * dir; - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -8624,7 +8808,7 @@ Action_Write( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -8924,7 +9108,7 @@ Action_SetFileSize( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -9055,7 +9239,7 @@ Action_SetDate( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -9577,7 +9761,7 @@ Action_RenameDisk( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -9829,6 +10013,7 @@ Action_WriteProtect( LONG * error_ptr) { LONG result = DOSFALSE; + BOOL changed = FALSE; int error; ENTER(); @@ -9851,31 +10036,27 @@ Action_WriteProtect( WriteProtected = FALSE; - if(VolumeNodeAdded) - { - send_disk_change_notification(IECLASS_DISKREMOVED); - send_disk_change_notification(IECLASS_DISKINSERTED); - } + changed = TRUE; } } else { - if(NOT WriteProtected) - { - WriteProtected = TRUE; - WriteProtectKey = key; - - if(VolumeNodeAdded) - { - send_disk_change_notification(IECLASS_DISKREMOVED); - send_disk_change_notification(IECLASS_DISKINSERTED); - } - } - else + if(WriteProtected) { error = ERROR_INVALID_LOCK; goto out; } + + WriteProtected = TRUE; + WriteProtectKey = key; + + changed = TRUE; + } + + if(changed && NOT ReadOnly && VolumeNodeAdded) + { + send_disk_change_notification(IECLASS_DISKREMOVED); + send_disk_change_notification(IECLASS_DISKINSERTED); } result = DOSTRUE; @@ -9942,7 +10123,7 @@ Action_SetComment( goto out; } - if(WriteProtected) + if(ReadOnly || WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; goto out; @@ -11213,3 +11394,14 @@ strlcat(char *dst, const char *src, size_t siz) return(result); } + +/****************************************************************************/ + +/* Wrapper function for case-insensitive string comparison, as used + * by the SMB url parser. + */ +LONG +strncasecmp(const char *a, const char *b, LONG n) +{ + return(Strnicmp((STRPTR)a, (STRPTR)b, n)); +} diff --git a/source_code/parse-smb-url.c b/source_code/parse-smb-url.c new file mode 100644 index 0000000..162d773 --- /dev/null +++ b/source_code/parse-smb-url.c @@ -0,0 +1,520 @@ +/* + * :ts=4 + * + * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API + * + * Copyright (C) 2019 by Olaf 'Olsen' Barthel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "smbfs.h" +#include "parse-smb-url.h" + +/****************************************************************************/ + +#include + +/****************************************************************************/ + +/* Free all the memory allocated by parse_smb_url_args(). */ +void +free_smb_url_args(struct smb_url_args *args) +{ + if(args != NULL) + { + if(args->domain != NULL) + free(args->domain); + + if(args->username != NULL) + free(args->username); + + if(args->password != NULL) + free(args->password); + + if(args->server != NULL) + free(args->server); + + if(args->port != NULL) + free(args->port); + + if(args->share != NULL) + free(args->share); + + if(args->path != NULL) + free(args->path); + } +} + +/****************************************************************************/ + +/* Allocate memory for the SMB url parser and initialize its + * contents to be empty. + */ +static struct smb_url_args * +allocate_smb_url_args(void) +{ + struct smb_url_args * args; + + args = calloc(1, sizeof(*args)); + + return(args); +} + +/****************************************************************************/ + +/* Allocate enough memory to hold a a NUL-terminated copy of the substring + * whose start/end position is provided, then copy its contents. Returns + * NULL on failure. Note that the start/end positions are expected to be + * start <= end. + */ +static char * +copy_substring(const char * arg, size_t start, size_t end) +{ + char * buffer; + size_t len; + + ASSERT( arg != NULL ); + ASSERT( start <= end ); + + len = end - start; + + buffer = malloc(len+1); + if(buffer != NULL) + { + memcpy(buffer, &arg[start], len); + buffer[len] = '\0'; + } + + return(buffer); +} + +/****************************************************************************/ + +/* Quick check if a character can be part of a hexadecimal digit string. */ +static int +is_hex(int c) +{ + return(('0' <= c && c <= '9') || + ('a' <= c && c <= 'f') || + ('A' <= c && c <= 'F')); +} + +/* Convert a character which is known to be valid as part of a hexadecimal + * string into its numeric representation. + */ +static int +hex_to_dec(int c) +{ + int result; + + if('0' <= c && c <= '9') + result = c - '0'; + else + result = 9 + (c & 7); + + return(result); +} + +/****************************************************************************/ + +/* Scan a string for URI escape sequences, replacing them with the + * decoded octet value in place. Replacing the encoded sequence will + * cause the string to become shorter. The resulting string will + * be NUL-terminated. + */ +static void +replace_escape_sequences(char * s, size_t len) +{ + size_t i, j, n; + int c; + + for(i = j = n = 0 ; i < len ; i++, j++) + { + c = s[i]; + + if(c == '%' && i+2 < len && is_hex(s[i+1]) && is_hex(s[i+2])) + { + c = 16 * hex_to_dec(s[i+1]) + hex_to_dec(s[i+2]); + + i += 2; + + s[j] = c; + } + else if (i != j) + { + s[j] = c; + } + } + + s[j] = '\0'; +} + +/****************************************************************************/ + +/* Check if the string could be an SMB file sharing URI, which + * means that it begins with "smb://". + */ +int +could_be_smb_url(const char * arg) +{ + int result; + + result = (arg != NULL && strncasecmp(arg, "smb://", 6) == 0); + + return(result); +} + +/****************************************************************************/ + +/* Attempt to process an SMB file sharing URI, as described in the + * January 8, 2007 IETF draft titled "SMB File Sharing URI Scheme", + * as submitted by Christopher R. Hertel and the Samba Team. + * + * This implementation does not use the parameters which the draft + * describes since they are not supported by the Amiga smbfs program. + * + * This function will return NULL in case of failure. Processing and + * validating the individual URI components is the job of the caller, + * we only try to parse the URI string here. Note that the parser is + * not particularly sophisticated... + */ +struct smb_url_args * +parse_smb_url_args(const char * arg) +{ + size_t len = strlen(arg); + + size_t domain_start = 0; + size_t domain_end = 0; + size_t username_start = 0; + size_t username_end = 0; + size_t password_start = 0; + size_t password_end = 0; + size_t server_start = 0; + size_t server_end = 0; + size_t port_start = 0; + size_t port_end = 0; + size_t share_start = 0; + size_t share_end = 0; + size_t path_start = 0; + size_t path_end = 0; + size_t i; + + struct smb_url_args * result = NULL; + struct smb_url_args * smb_url_args = NULL; + + ENTER(); + + /* This should be an SMB url to begin with. */ + if(len <= 6 || !could_be_smb_url(arg)) + { + SHOWMSG("not a valid SMB url"); + goto out; + } + + /* Skip the "smb://" part. */ + arg += 6; + len -= 6; + + smb_url_args = allocate_smb_url_args(); + if(smb_url_args == NULL) + goto out; + + /* Try to find the optional domain name, user name + * and password in the URL. We look for the '@' character + * which separates this optional part from the + * server name. + */ + for(i = 0 ; i < len ; i++) + { + if(arg[i] == '@') + { + size_t at = i; + size_t j; + + /* Could there be a domain name in front + * of the user name? + */ + for(j = 0 ; j < at ; j++) + { + if(arg[j] == ';') + { + domain_end = j; + + username_start = j+1; + break; + } + } + + /* Try to obtain the user name and the + * optional password. + */ + for(j = username_start ; j <= at ; j++) + { + if(j == at || arg[j] == ':') + { + username_end = j; + + /* The password follows the ':' + * character, if there is one. + */ + if(j < at) + { + password_start = j+1; + password_end = at; + } + + break; + } + } + + /* The server name should follow the + * '@' character. + */ + server_start = at+1; + + break; + } + } + + /* Try to find the server name, which may be followed + * by a port number/service name, the share name + * or the parameter list. + */ + for(i = server_start ; i <= len ; i++) + { + if(i == len || arg[i] == '/' || arg[i] == ':') + { + server_end = i; + + if(i < len) + { + /* The port number/service name follow the + * ':' character. + */ + if(arg[i] == ':') + { + size_t j; + + port_start = i+1; + + /* Figure out how long the port number/service + * name text is, and pick up the start of the + * share name or the parameter list. + */ + for(j = port_start ; j <= len ; j++) + { + if(j == len || arg[j] == '/' || arg[j] == '?') + { + port_end = j; + + /* Did we find the share name? */ + if(j < len && arg[j] == '/') + share_start = j+1; + + break; + } + } + } + /* We'll look for the share name instead. + * Of course, we could look for the parameter + * list, but the SMB URI is none too useful + * without the share name, so we prefer that + * instead. + */ + else + { + share_start = i+1; + } + } + + break; + } + } + + /* Try to find the share name, and pick up the + * path name or the parameter list which may + * follow it. + */ + if(share_start > 0) + { + for(i = share_start ; i <= len ; i++) + { + if(i == len || arg[i] == '/' || arg[i] == '?') + { + share_end = i; + + if(i < len) + { + /* Pick up the path name? */ + if(arg[i] == '/') + path_start = i+1; + } + + break; + } + } + } + + /* Try to pick up the path name. */ + if(path_start > 0) + { + for(i = path_start ; i <= len ; i++) + { + if(i == len || arg[i] == '?') + { + path_end = i; + break; + } + } + } + + if(domain_start < domain_end) + { + smb_url_args->domain = copy_substring(arg, domain_start, domain_end); + if(smb_url_args->domain == NULL) + { + SHOWMSG("not enough memory"); + goto out; + } + + replace_escape_sequences(smb_url_args->domain, domain_end - domain_start); + + D(("domain: '%s'", smb_url_args->domain)); + } + else + { + SHOWMSG("no domain name provided"); + } + + if(username_start < username_end) + { + smb_url_args->username = copy_substring(arg, username_start, username_end); + if(smb_url_args->username == NULL) + { + SHOWMSG("not enough memory"); + goto out; + } + + replace_escape_sequences(smb_url_args->username, username_end - username_start); + + D(("username: '%s'", smb_url_args->username)); + } + else + { + SHOWMSG("no user name provided"); + } + + if(password_start < password_end) + { + smb_url_args->password = copy_substring(arg, password_start, password_end); + if(smb_url_args->password == NULL) + { + SHOWMSG("not enough memory"); + goto out; + } + + replace_escape_sequences(smb_url_args->password, password_end - password_start); + + D(("password: ...")); + } + else + { + SHOWMSG("no password provided"); + } + + if(server_start < server_end) + { + smb_url_args->server = copy_substring(arg, server_start, server_end); + if(smb_url_args->server == NULL) + { + SHOWMSG("not enough memory"); + goto out; + } + + replace_escape_sequences(smb_url_args->server, server_end - server_start); + + D(("server: '%s'", smb_url_args->server)); + } + else + { + SHOWMSG("no server name provided"); + } + + if(port_start < port_end) + { + smb_url_args->port = copy_substring(arg, port_start, port_end); + if(smb_url_args->port == NULL) + { + SHOWMSG("not enough memory"); + goto out; + } + + replace_escape_sequences(smb_url_args->port, port_end - port_start); + + D(("port: '%s'", smb_url_args->port)); + } + else + { + SHOWMSG("no port number/service name provided"); + } + + if(share_start < share_end) + { + smb_url_args->share = copy_substring(arg, share_start, share_end); + if(smb_url_args->share == NULL) + { + SHOWMSG("not enough memory"); + goto out; + } + + replace_escape_sequences(smb_url_args->share, share_end - share_start); + + D(("share: '%s'", smb_url_args->share)); + } + else + { + SHOWMSG("no share name provided"); + } + + if(path_start < path_end) + { + smb_url_args->path = copy_substring(arg, path_start, path_end); + if(smb_url_args->path == NULL) + { + SHOWMSG("not enough memory"); + goto out; + } + + replace_escape_sequences(smb_url_args->path, path_end - path_start); + + D(("path: '%s'", smb_url_args->path)); + } + else + { + SHOWMSG("no path name provided"); + } + + result = smb_url_args; + smb_url_args = NULL; + + out: + + if(smb_url_args != NULL) + free_smb_url_args(smb_url_args); + + RETURN(result); + return(result); +} diff --git a/source_code/parse-smb-url.h b/source_code/parse-smb-url.h new file mode 100644 index 0000000..6a14443 --- /dev/null +++ b/source_code/parse-smb-url.h @@ -0,0 +1,55 @@ +/* + * :ts=4 + * + * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API + * + * Copyright (C) 2019 by Olaf 'Olsen' Barthel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _PARSE_SMB_URL_H +#define _PARSE_SMB_URL_H + +/****************************************************************************/ + +#include + +/****************************************************************************/ + +/* SMB URI parameters, as processed and produced by parse_smb_url_args(). */ +struct smb_url_args +{ + /* Each string pointer is either a NULL pointer (not provided by the + * URI text), or it points to a NUL-terminated string. + */ + char * domain; + char * username; + char * password; + char * server; + char * port; + char * share; + char * path; +}; + +/****************************************************************************/ + +int could_be_smb_url(const char * arg); +struct smb_url_args * parse_smb_url_args(const char * arg); +void free_smb_url_args(struct smb_url_args *args); + +/****************************************************************************/ + +#endif /* _PARSE_SMB_URL_H */ diff --git a/source_code/proc.c b/source_code/proc.c index 328ad04..fa53548 100644 --- a/source_code/proc.c +++ b/source_code/proc.c @@ -2643,6 +2643,8 @@ smb_proc_readdir_short ( if (count == 0) break; + ASSERT( count <= entries_asked ); + ASSERT (bcc == count * SMB_DIRINFO_SIZE + 3); if (bcc != count * SMB_DIRINFO_SIZE + 3) @@ -2665,7 +2667,7 @@ smb_proc_readdir_short ( p = smb_decode_word (p, &datalength); - if(datalength != 43 * count) + if(datalength != SMB_DIRINFO_SIZE * count) { D(("data length (%ld) does not match expected size (%ld)", datalength, count * SMB_DIRINFO_SIZE)); @@ -2682,6 +2684,11 @@ smb_proc_readdir_short ( entry = get_next_dircache_entry(dircache); + ASSERT( entry == NULL || i+1 == count ); + + if(entry == NULL && i+1 < count) + SHOWMSG("ran out of directory cache entries, which should never happen..."); + total_count++; } @@ -3058,7 +3065,7 @@ smb_proc_readdir_long ( int ff_searchcount; int ff_end_of_search = 0; - int ff_dir_handle = 0; + int ff_dir_handle = -1; int ff_resume_key = 0; int loop_count = 0; @@ -3115,6 +3122,9 @@ smb_proc_readdir_long ( { is_first = TRUE; + ff_dir_handle = -1; + ff_resume_key = 0; + SHOWMSG("start scanning from the top"); } else @@ -3258,6 +3268,8 @@ smb_proc_readdir_long ( } /* Bail out if this is empty. */ + ASSERT( resp_param != NULL ); + if (resp_param == NULL) { SHOWMSG("no response parameters to process; stopping the search for now"); @@ -3269,6 +3281,8 @@ smb_proc_readdir_long ( if (is_first) { + ASSERT( resp_param_len >= 6 ); + if(resp_param_len < 6) { SHOWMSG("not enough response parameter data to process; stopping the search for now"); @@ -3286,6 +3300,8 @@ smb_proc_readdir_long ( } else { + ASSERT( resp_param_len >= 4 ); + if(resp_param_len < 4) { SHOWMSG("not enough response parameter data to process; stopping the search for now"); @@ -3296,6 +3312,8 @@ smb_proc_readdir_long ( ff_end_of_search = WVAL (p, 2); } + ASSERT( ff_searchcount <= max_matches ); + D(("received %ld entries (end of search = %s)",ff_searchcount, ff_end_of_search ? "yes" : "no")); if (ff_searchcount == 0) @@ -3305,17 +3323,16 @@ smb_proc_readdir_long ( } /* Bail out if this is empty. */ + ASSERT( resp_data != NULL ); + if (resp_data == NULL) { SHOWMSG("no directory data to process; stopping the search for now"); break; } - /* point to the data bytes */ - p = resp_data; - /* Now we are ready to parse smb directory entries. */ - for (i = 0, entry_length = 0 ; + for (i = 0, p = resp_data, entry_length = 0 ; i < ff_searchcount && entry != NULL && p < &resp_data[resp_data_len]; i++, p += entry_length) { @@ -3341,6 +3358,11 @@ smb_proc_readdir_long ( entry = get_next_dircache_entry(dircache); + ASSERT( entry != NULL || i+1 == ff_searchcount ); + + if(entry == NULL && i+1 < ff_searchcount) + SHOWMSG("ran out of directory cache entries, which should never happen..."); + total_count++; } diff --git a/source_code/quad_math.c b/source_code/quad_math.c index 5bb6a92..e237c1e 100644 --- a/source_code/quad_math.c +++ b/source_code/quad_math.c @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/quad_math.h b/source_code/quad_math.h index ee16222..b440db7 100644 --- a/source_code/quad_math.h +++ b/source_code/quad_math.h @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/smakefile b/source_code/smakefile index 3d3cc7c..ffa89fb 100644 --- a/source_code/smakefile +++ b/source_code/smakefile @@ -3,7 +3,7 @@ # # SMB file system wrapper for AmigaOS, using the AmiTCP V3 API # -# Copyright (C) 2000-2019 by Olaf `Olsen' Barthel +# Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -98,8 +98,8 @@ LFLAGS = \ ############################################################################### OBJS = \ - main.o proc.o smb_abstraction.o sock.o crypt.o quad_math.o dump_smb.o \ - cp437.o cp850.o splay.o swap_stack_and_call.o + main.o cp437.o cp850.o crypt.o dump_smb.o parse-smb-url.o proc.o \ + quad_math.o smb_abstraction.o sock.o splay.o swap_stack_and_call.o ############################################################################### @@ -130,7 +130,8 @@ cp437.o : cp437.c cp850.o : cp850.c crypt.o : crypt.c system_headers.h assert.h quad_math.h splay.h smbfs.h dump_smb.o : dump_smb.c system_headers.h assert.h quad_math.h splay.h smbfs.h dump_smb.h -main.o : main.c system_headers.h assert.h quad_math.h splay.h smbfs.h smb_abstraction.h cp437.h cp850.h errors.h dump_smb.h smbfs_rev.h +main.o : main.c system_headers.h assert.h quad_math.h splay.h smbfs.h smb_abstraction.h cp437.h cp850.h errors.h dump_smb.h parse-smb-url.h smbfs_rev.h +parse-smb-url.o : parse-smb-url.c system_headers.h assert.h quad_math.h splay.h smbfs.h parse-smb-url.h proc.o : proc.c system_headers.h assert.h quad_math.h splay.h smbfs.h errors.h smbfs_rev.h quad_math.o : quad_math.c quad_math.h smb_abstraction.o : smb_abstraction.c system_headers.h assert.h quad_math.h splay.h smbfs.h errors.h smb_abstraction.h diff --git a/source_code/smb_abstraction.c b/source_code/smb_abstraction.c index 43f4776..5ba3fcf 100644 --- a/source_code/smb_abstraction.c +++ b/source_code/smb_abstraction.c @@ -47,6 +47,7 @@ reset_dircache (dircache_t * dircache) dircache->is_valid = TRUE; dircache->sid = -1; dircache->close_sid = -1; + dircache->num_entries_read = 0; } /*****************************************************************************/ @@ -136,6 +137,7 @@ invalidate_dircache(dircache_t * dircache) dircache->cache_used = dircache->base = 0; dircache->is_valid = FALSE; dircache->sid = -1; + dircache->num_entries_read = 0; if(dircache->cache_for != NULL) { @@ -352,7 +354,7 @@ smba_connect ( NewList ((struct List *)&res->dircache_list); - /* Use raw SMB over TCP rather than NetBIOS. */ + /* Use raw SMB over TCP rather than NetBIOS? */ if(opt_raw_smb) res->server.raw_smb = TRUE; @@ -672,10 +674,10 @@ make_open (smba_file_t * f, int need_fid, int writable, int truncate_file, int * if (!f->is_valid || file_attributes_are_stale(f)) { - if (!f->is_valid || f->attr_time == 0) - D(("file '%s' attributes are not yet known",escape_name(f->dirent.complete_path))); - else - D(("file '%s' attributes are need to be updated",escape_name(f->dirent.complete_path))); + D(("file '%s' attributes %s", + escape_name(f->dirent.complete_path), + (!f->is_valid || f->attr_time == 0) ? "are not yet known" : "need to be updated" + )); if (!f->server->server.prefer_core_protocol && f->server->server.protocol >= PROTOCOL_LANMAN2) { @@ -1032,6 +1034,9 @@ smba_close (smba_server_t * s, smba_file_t * f) /* release the directory cache */ if (f->dircache != NULL) { + if(f->dircache->is_valid) + SHOWMSG("dropping directory cache"); + Remove((struct Node *)f->dircache); AddTail((struct List *)&s->dircache_list, (struct Node *)f->dircache); @@ -1651,7 +1656,7 @@ smba_setattr (smba_file_t * f, const smba_stat_t * st, const QUAD * const size, if (result < 0) goto out; - f->attr_time = get_current_time(); + f->attr_time = get_current_time(); } } @@ -1705,11 +1710,25 @@ smba_readdir (smba_file_t * f, int offs, int restart, void *callback_data, smba_ if (result < 0) goto out; - /* get a cache for this directory unless we already have one */ + /* Get a cache for this directory unless we already have one. */ if (f->dircache == NULL) { + int num_directory_caches_in_use = 0; + int num_directory_caches_total = 0; dircache_t * dircache; + for(dircache = (dircache_t *)f->server->dircache_list.mlh_Head ; + dircache->min_node.mln_Succ != NULL ; + dircache = (dircache_t *)dircache->min_node.mln_Succ) + { + if(dircache->cache_for != NULL) + num_directory_caches_in_use++; + + num_directory_caches_total++; + } + + D(("number of directory caches in use = %ld (of %ld)", num_directory_caches_in_use, num_directory_caches_total)); + /* Grab the least recently used cache table entry, which * should sit at the end of the list. */ @@ -1755,6 +1774,7 @@ smba_readdir (smba_file_t * f, int offs, int restart, void *callback_data, smba_ while(TRUE) { + /* Refill the directory cache? */ if(cache_index >= f->dircache->cache_used) { if(f->dircache->eof) @@ -1770,8 +1790,8 @@ smba_readdir (smba_file_t * f, int offs, int restart, void *callback_data, smba_ /* Start over and read the next entries. */ f->dircache->cache_used = cache_index = 0; - /* Try to read up as many entries as will fit into - * the cache (cache_size). + /* Try to read as many entries as will fit into + * the cache. */ num_entries = smb_proc_readdir (&f->server->server, f->dirent.complete_path, f->dircache, &eof, error_ptr); if (num_entries < 0) @@ -1810,11 +1830,12 @@ smba_readdir (smba_file_t * f, int offs, int restart, void *callback_data, smba_ dirent = &f->dircache->cache[cache_index]; - D(("delivering '%s', cache index=%ld, last entry=%s", + D(("delivering '%s', cache index=%ld, last entry=%s, total entries read so far = %ld", escape_name(dirent->complete_path), cache_index, - eof ? "yes" : "no") - ); + eof ? "yes" : "no", + f->dircache->num_entries_read + )); copy_dirent_to_stat_data(&data, dirent); @@ -1822,8 +1843,10 @@ smba_readdir (smba_file_t * f, int offs, int restart, void *callback_data, smba_ break; cache_index++; + + f->dircache->num_entries_read++; } - + result = 0; out: @@ -1831,7 +1854,7 @@ smba_readdir (smba_file_t * f, int offs, int restart, void *callback_data, smba_ if(eof && eof_ptr != NULL) (*eof_ptr) = TRUE; - return result; + return(result); } /*****************************************************************************/ diff --git a/source_code/smb_abstraction.h b/source_code/smb_abstraction.h index 2105911..d081eed 100644 --- a/source_code/smb_abstraction.h +++ b/source_code/smb_abstraction.h @@ -107,7 +107,10 @@ typedef struct dircache /* For resuming directory scanning with * SMB_COM_FIND. */ - + int num_entries_read; + /* Total number of cache entries read + * over multiple cache refill operations. + */ ULONG created_at; /* for invalidation */ struct smba_file * cache_for; /* owner of this cache */ diff --git a/source_code/smbfs.h b/source_code/smbfs.h index f0d252d..3b85749 100644 --- a/source_code/smbfs.h +++ b/source_code/smbfs.h @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -170,9 +170,15 @@ extern void smb_nt_encrypt(const unsigned char *passwd, const unsigned char *c8, extern void free_memory(APTR address); extern APTR allocate_memory(LONG size); +extern APTR allocate_cleared_memory(LONG count, LONG record_size); #define malloc(s) allocate_memory(s) #define free(m) free_memory(m) +#define calloc(n, s) allocate_cleared_memory(n, s) + +/****************************************************************************/ + +extern LONG strncasecmp(const char *a, const char *b, LONG n); /****************************************************************************/ diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h index 25050c5..8e94e62 100644 --- a/source_code/smbfs_rev.h +++ b/source_code/smbfs_rev.h @@ -1,6 +1,6 @@ #define VERSION 2 -#define REVISION 20 -#define DATE "27.2.2019" -#define VERS "smbfs 2.20" -#define VSTRING "smbfs 2.20 (27.2.2019)\r\n" -#define VERSTAG "\0$VER: smbfs 2.20 (27.2.2019)" +#define REVISION 21 +#define DATE "9.3.2019" +#define VERS "smbfs 2.21" +#define VSTRING "smbfs 2.21 (9.3.2019)\r\n" +#define VERSTAG "\0$VER: smbfs 2.21 (9.3.2019)" diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev index 209e3ef..aabe6ec 100644 --- a/source_code/smbfs_rev.rev +++ b/source_code/smbfs_rev.rev @@ -1 +1 @@ -20 +21 diff --git a/source_code/splay.c b/source_code/splay.c index f445aa6..842eb49 100644 --- a/source_code/splay.c +++ b/source_code/splay.c @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/splay.h b/source_code/splay.h index e334eea..05700b9 100644 --- a/source_code/splay.h +++ b/source_code/splay.h @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/swap_stack_and_call.asm b/source_code/swap_stack_and_call.asm index 4eed588..06efc10 100644 --- a/source_code/swap_stack_and_call.asm +++ b/source_code/swap_stack_and_call.asm @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * -* Copyright (C) 2016 by Olaf `Olsen' Barthel +* Copyright (C) 2016-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/system_headers.c b/source_code/system_headers.c index c7efd3e..56aad4b 100644 --- a/source_code/system_headers.c +++ b/source_code/system_headers.c @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source_code/system_headers.h b/source_code/system_headers.h index aade30d..6dcb40b 100644 --- a/source_code/system_headers.h +++ b/source_code/system_headers.h @@ -3,7 +3,7 @@ * * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API * - * Copyright (C) 2000-2019 by Olaf `Olsen' Barthel + * Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by