From 3220d7343883151bbef8df622289bfbe194865fe Mon Sep 17 00:00:00 2001 From: obarthel Date: Sat, 9 Mar 2019 11:04:33 +0100 Subject: [PATCH] Updated to version 2.21 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. --- documentation/history.doc | 26 +- source_code/GNUmakefile.68k | 9 +- source_code/GNUmakefile.os4 | 9 +- source_code/assert.c | 2 +- source_code/assert.h | 2 +- source_code/cp437.c | 2 +- source_code/cp437.h | 2 +- source_code/cp850.c | 2 +- source_code/cp850.h | 2 +- source_code/dump_smb.c | 2 +- source_code/dump_smb.h | 2 +- source_code/errors.h | 2 +- source_code/main.c | 298 +++++++++++++--- source_code/parse-smb-url.c | 520 ++++++++++++++++++++++++++++ source_code/parse-smb-url.h | 55 +++ source_code/proc.c | 34 +- source_code/quad_math.c | 2 +- source_code/quad_math.h | 2 +- source_code/smakefile | 9 +- source_code/smb_abstraction.c | 51 ++- source_code/smb_abstraction.h | 5 +- source_code/smbfs.h | 8 +- source_code/smbfs_rev.h | 10 +- source_code/smbfs_rev.rev | 2 +- source_code/splay.c | 2 +- source_code/splay.h | 2 +- source_code/swap_stack_and_call.asm | 2 +- source_code/system_headers.c | 2 +- source_code/system_headers.h | 2 +- 29 files changed, 957 insertions(+), 111 deletions(-) create mode 100644 source_code/parse-smb-url.c create mode 100644 source_code/parse-smb-url.h 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