diff --git a/README.md b/README.md index 22f2d50..2acbd94 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,7 @@ You can enter these options as command line parameters, or, if you start the **s Here is how the options look like, in alphabetical order (as command line parameters):
+ADDVOLUME/K
CACHE=CACHESIZE/N/K
CASE=CASESENSITIVE/S
CHANGEUSERNAMECASE/K
@@ -177,8 +178,8 @@ WRITEBEHIND/S
In order to use a shared networked file system, you need the following information:
1. The name or the IPv4 address of the file server and the name of the "share" (file system) you want to access.
-2. The user name required to access the "share" (file system), unless the server does not need it.
-3. The password required to access the "share" (file system), unless the server does not need it.
+2. The user name required to access the "share" (file system), unless the server does not need it ("guest" access).
+3. The password required to access the "share" (file system), unless the server does not need it ("guest" access).
The parameters relevant for this information are described below.
@@ -194,6 +195,8 @@ If necessary, you can specify which port number should be used when making the c
Finally, you need to tell the *SMB* server which service you want to connect to, which for the **smbfs** program should be the name of a shared network file system. In the example the name of the shared network file system would be `share-name`.
+Unless you use the `VOLUMENAME` option (e.g. `VOLUMENAME=MyData`), **smbfs** will pick a volume name identical to the share name, e.g for `//nas:445/pictures` the volume name would be `pictures` and a disk icon named **pictures** will appear in the Workbench window.
+
#### 5.1.2. `USER=USERNAME/K`
In order to connect to an *SMB* share, the server requires that a user name is provided. If you omit the user name, the **smbfs** program will use `GUEST` as a replacement.
@@ -213,10 +216,6 @@ You may also use the `smbfs_user` environment variable in place of the `smbfs_us
You may not need to provide a password in order to connect to an *SMB* share. If you omit it, the **smbfs** program will use an empty password.
-If password encryption is supported by the server the usable length of the password will be limited to 23 characters.
-
-Whether or not password encryption is supported cannot be guessed/detected before the protocol negotiation has concluded. Note that you will probably only ever encounter SMB servers which require password encryption, so a sensible upper limit appears to be 23 characters.
-
You need not provide for a password on the command line. Alternatively, you may configure an environment variable whose contents will be used instead. The variable could be set up like this:
@@ -449,23 +448,16 @@ Note that **smbfs** does not know when daylight savings time begins and ends. It
### 5.6. Miscellaneous
-#### 5.6.1. `DEVICE=DEVICENAME/K` and `VOLUME=VOLUMENAME/K`
+#### 5.6.1. `DEVICE=DEVICENAME/K`, `ADDVOLUME/K` and `VOLUME=VOLUMENAME/K`
-The **smbfs** program can announce itself as an AmigaDOS file system by using one of two different methods.
+By default the **smbfs** program will pick a unique file system device name such as `smbfs0:` and a volume name which is identical to the share name. For example, for `//192.168.0.1/pictures` the volume name would be `pictures` and a disk icon named **pictures** will appear in the Workbench window.
-The first method involves announcing itself only as a file system device. This should be sufficient in most cases but has a drawback in that the device will not be usable from *Workbench* since the file system will not appear as a disk icon.
+You may override the device name which **smbfs** will use, e.g. the `DEVICE=nas:` option will try to use `nas:` if possible. Please note that device names have to be unique and **smbfs** may refuse to use it if there is already a file system device of that name.
-You tell **smbfs** to use a specific device name by using the `DEVICE` command line parameter, e.g. `DEVICE=SMBFS:`. Note that device names must be unique, i.e. there must be no other device by the same name in the system; **smbfs** will report an error and exit if it finds one.
+You can tell **smbfs** not to add a volume, which may be useful because the native Amiga Samba port can hang as soon as the file system is started. In such cases, use the `ADDVOLUME=NO` option. Please note that the `ADDVOLUME=NO` option will keep **smbfs** from showing the file system's disk icon in the Workbench window. If you omit the `ADDVOLUME` option, **smbfs** will pretend that `ADDVOLUME=YES` was in effect.
-The second method involves announcing itself as a volume. This has the benefit of making the file system usable from Workbench since a disk icon will appear for it.
-
-You tell **smbfs** to use a specific volume name by using the `VOLUME` command line parameter, e.g. `VOLUME=Sourcery:`.
-
-Both methods have advantages and drawbacks. The drawback of the `VOLUME` method is that it may deadlock the native *Amiga Samba* port as soon as the file system is mounted. The drawback of the `DEVICE` method is that the file system will not be usable from *Workbench*.
-
-If you wish, you can combine both methods; this is the approach most other file systems use. And in fact, when you tell **smbfs** to add a volume it will also add a device to go along with it.
-
-The `VOLUME` and `DEVICE` keywords are optional; if you omit both, **smbfs** will pretend that you had used the `DEVICE=SMBFS:` parameter.
+If you want to use a specific volume name, use the `VOLUME` option,
+e.g. `VOLUME=Sourcery:`. Otherwise a volume name derived from the share name will be used instead.
#### 5.6.2. `OMITHIDDEN/S`
diff --git a/documentation/history.doc b/documentation/history.doc
index 491a74a..bfce3f7 100644
--- a/documentation/history.doc
+++ b/documentation/history.doc
@@ -2645,3 +2645,47 @@ smbfs 2.2 (1.12.2018)
before the protocol negotiation has concluded. Note that you will probably
only ever encounter SMB servers which require password encryption, so
a sensible upper limit appears to be 23 characters.
+
+
+smbfs 2.3 (8.12.2018)
+
+- Added the ADDVOLUME option, which defaults to "yes". If no volume name is
+ provided, smbfs will use the service name as the template, e.g. if you
+ connect to //server-name/pictures then the default volume name will
+ be "pictures". The idea is that if the file server allows this, you
+ should not need to start the smbfs program with any parameter other
+ than the service/share name and it should work out of the box.
+
+- Preparations for showing error messages when running as a Workbench
+ program would corrupt memory once the message was ready for display,
+ but this only happened in the AmigaOS4 build. As far as I can tell
+ this never worked correctly on AmigaOS4. Thanks go to Matthew Kille
+ who reported the problem!
+
+- Simplified the icon parameter processing used when running smbfs
+ as a Workbench program. The reworked code is now basically limited
+ to processing and setting up the same configuration data which the
+ shell command use employs. Both paths share the same configuration
+ data checking and handling.
+
+- Turns out that the ACTION_CURRENT_VOLUME function does need to return
+ the volume node, not the device node. Note to self: a 'struct DeviceList'
+ refers to a volume (DLT_VOLUME), whereas a 'struct DeviceNode' refers
+ to a device (DLT_DEVICE). See? This could have been easily been avoided :-/
+
+- Added more code documentation, especially for the various constants and
+ data structures defined and used in "main.c".
+
+- Reading from the file name translation file now performs better error
+ detection and reporting. If read errors should crop up, the error message
+ will now say so. If the file is shorter than required the error message
+ will reflect this.
+
+- Reworked the smb_proc_reconnect() function so that it does not end up
+ truncating the password before it is encrypted. This means that up to
+ 63 characters of the password can be used to produce the encrypted
+ form, resolving problems with longer server passwords not quite
+ matching what you entered. However, since this long encrypted password
+ is still accompanied by the legacy encrypted form which truncates the
+ password to 14 characters (which are converted to all-upper-case
+ letters) there is no actual gain in terms of security...
diff --git a/documentation/smbfs.doc b/documentation/smbfs.doc
index 0685ea9..814aac4 100644
--- a/documentation/smbfs.doc
+++ b/documentation/smbfs.doc
@@ -183,6 +183,7 @@ smbfs program from Workbench, you can set these options as icon tool types.
Here is how the options look like, in alphabetical order (as command line
parameters):
+ ADDVOLUME/K
CACHE=CACHESIZE/N/K
CASE=CASESENSITIVE/S
CHANGEUSERNAMECASE/K
@@ -223,9 +224,9 @@ information:
1. The name or the IPv4 address of the file server and the name of
the "share" (file system) you want to access.
2. The user name required to access the "share" (file system),
- unless the server does not need it.
+ unless the server does not need it ("guest" access).
3. The password required to access the "share" (file system),
- unless the server does not need it.
+ unless the server does not need it ("guest" access).
The parameters relevant for this information are described below.
@@ -251,6 +252,11 @@ which for the smbfs program should be the name of a shared network file
system. In the example the name of the shared network file system would be
"share-name".
+Unless you use the "VOLUMENAME" option (e.g. "VOLUMENAME=MyData"), smbfs will
+pick a volume name identical to the share name, e.g for "//nas:445/pictures"
+the volume name would be "pictures" and a disk icon named "pictures" will
+appear in the Workbench window.
+
5.1.2. "USER=USERNAME/K"
In order to connect to an SMB share, the server requires that a user name is
@@ -280,14 +286,6 @@ you omit it, the smbfs program will use an empty password.
If you do need a password to go along with the user name, your password cannot
be longer than 63 characters.
-If password encryption is supported by the server the usable length of the
-password will be limited to 23 characters.
-
-Whether or not password encryption is supported cannot be guessed/detected
-before the protocol negotiation has concluded. Note that you will probably
-only ever encounter SMB servers which require password encryption, so a
-sensible upper limit appears to be 23 characters.
-
You need not provide for a password on the command line. Alternatively, you
may configure an environment variable whose contents will be used instead. The
variable could be set up like this:
@@ -676,39 +674,28 @@ is up to you to select the correct adjustment value when appropriate.
5.6. Miscellaneous
-5.6.1. "DEVICE=DEVICENAME/K" and "VOLUME=VOLUMENAME/K"
+5.6.1. "DEVICE=DEVICENAME/K", "ADDVOLUME/K" and "VOLUME=VOLUMENAME/K"
-The smbfs program can announce itself as an AmigaDOS file system by using one
-of two different methods.
+By default the smbfs program will pick a unique file system device name such
+as "smbfs0:" and a volume name which is identical to the share name. For
+example, for "//192.168.0.1/pictures" the volume name would be "pictures"
+and a disk icon named "pictures" will appear in the Workbench window.
-The first method involves announcing itself only as a file system device. This
-should be sufficient in most cases but has a drawback in that the device will
-not be usable from Workbench since the file system will not appear as a disk
-icon.
+You may override the device name which smbfs will use, e.g. the "DEVICE=nas:"
+option will try to use "nas:" if possible. Please note that device names have
+to be unique and smbfs may refuse to use it if there is already a file system
+device of that name.
-You tell smbfs to use a specific device name by using the "DEVICE" command
-line parameter, e.g. "DEVICE=SMBFS:". Note that device names must be unique,
-i.e. there must be no other device by the same name in the system; smbfs will
-report an error and exit if it finds one.
+You can tell smbfs not to add a volume, which may be useful because the native
+Amiga Samba port can hang as soon as the file system is started. In such cases,
+use the "ADDVOLUME=NO" option. Please note that the "ADDVOLUME=NO" option will
+keep smbfs from showing the file system's disk icon in the Workbench window.
+If you omit the "ADDVOLUME" option, smbfs will pretend that "ADDVOLUME=YES"
+was in effect.
-The second method involves announcing itself as a volume. This has the benefit
-of making the file system usable from Workbench since a disk icon will appear
-for it.
-
-You tell smbfs to use a specific volume name by using the "VOLUME" command
-line parameter, e.g. "VOLUME=Sourcery:".
-
-Both methods have advantages and drawbacks. The drawback of the "VOLUME"
-method is that it may deadlock the native Amiga Samba port as soon as the file
-system is mounted. The drawback of the "DEVICE" method is that the file system
-will not be usable from Workbench.
-
-If you wish, you can combine both methods; this is the approach most other
-file systems use. And in fact, when you tell smbfs to add a volume it will
-also add a device to go along with it.
-
-The "VOLUME" and "DEVICE" keywords are optional; if you omit both, smbfs will
-pretend that you had used the "DEVICE=SMBFS:" parameter.
+If you want to use a specific volume name, use the "VOLUME" option, e.g.
+"VOLUME=Sourcery:". Otherwise a volume name derived from the share name will
+be used instead.
5.6.2. "OMITHIDDEN/S"
diff --git a/source_code/GNUmakefile.68k b/source_code/GNUmakefile.68k
index 3eac8c3..99c996f 100644
--- a/source_code/GNUmakefile.68k
+++ b/source_code/GNUmakefile.68k
@@ -35,9 +35,9 @@ WARNINGS = \
-Wundef -Wbad-function-cast -Wmissing-declarations -Wconversion
CPU = -m68020-60
-OPTIONS = -DNDEBUG -fno-builtin -Inetinclude -Iinclude
+OPTIONS = -fno-builtin -Inetinclude -Iinclude
OPTIMIZE = -O2 -fomit-frame-pointer
-DEBUG = -g
+DEBUG = -DNDEBUG -g
###############################################################################
diff --git a/source_code/GNUmakefile.os4 b/source_code/GNUmakefile.os4
index 49ed267..cfe8716 100644
--- a/source_code/GNUmakefile.os4
+++ b/source_code/GNUmakefile.os4
@@ -38,8 +38,8 @@ WARNINGS = \
-Wall -W -Wshadow -Wpointer-arith -Wsign-compare -Wmissing-prototypes \
-Wundef -Wbad-function-cast -Wmissing-declarations
-#OPTIONS = -DNDEBUG
-OPTIONS = -DDEBUG=1 -DDUMP_SMB=1
+OPTIONS = -DNDEBUG
+#OPTIONS = -DDEBUG=1 -DDUMP_SMB=1
OPTIMIZE = -O3
DEBUG = -ggdb
diff --git a/source_code/assert.c b/source_code/assert.c
index 47bc00b..10a5fb2 100644
--- a/source_code/assert.c
+++ b/source_code/assert.c
@@ -362,7 +362,7 @@ static void __asm putch(register __d0 UBYTE c)
#elif defined(__GNUC__) && defined(__amigaos4__)
-static void putch(UBYTE c)
+static void putch(UBYTE c, APTR unused)
{
if(c != '\0')
kputc(c);
diff --git a/source_code/crypt.c b/source_code/crypt.c
index dba1690..53e712e 100644
--- a/source_code/crypt.c
+++ b/source_code/crypt.c
@@ -46,13 +46,13 @@ static void concat (char *out, char *in1, char *in2, int l1, int l2);
static void xor (char *out, char *in1, char *in2, int n);
static void dohash (char *out, char *in, char *key, int forw);
static void str_to_key (unsigned char *str, unsigned char *key);
-static void smbhash (unsigned char *out, unsigned char *in, unsigned char *key, int forw);
+static void smbhash (unsigned char *out, const unsigned char *in, unsigned char *key, int forw);
static void E_P16 (unsigned char *p14, unsigned char *p16);
-static void E_P24 (unsigned char *p21, unsigned char *c8, unsigned char *p24);
+static void E_P24 (unsigned char *p21, const unsigned char *c8, unsigned char *p24);
static int local_wcslen (short *str);
-static int local_mbstowcs (short *dst, unsigned char *src, int len);
-static void E_md4hash (unsigned char *passwd, unsigned char *p16);
-static void smb_owf_encrypt (unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+static int local_mbstowcs (short *dst, const unsigned char *src, int len);
+static void E_md4hash (const unsigned char *passwd, unsigned char *p16);
+static void smb_owf_encrypt (unsigned char *passwd, const unsigned char *c8, unsigned char *p24);
static unsigned long F (unsigned long X, unsigned long Y, unsigned long Z);
static unsigned long G (unsigned long X, unsigned long Y, unsigned long Z);
static unsigned long H (unsigned long X, unsigned long Y, unsigned long Z);
@@ -375,7 +375,7 @@ str_to_key (unsigned char *str, unsigned char *key)
}
static void
-smbhash (unsigned char *out, unsigned char *in, unsigned char *key, int forw)
+smbhash (unsigned char *out, const unsigned char *in, unsigned char *key, int forw)
{
int i;
char outb[64];
@@ -407,7 +407,7 @@ smbhash (unsigned char *out, unsigned char *in, unsigned char *key, int forw)
static void
E_P16 (unsigned char *p14, unsigned char *p16)
{
- unsigned char sp8[8] =
+ const unsigned char sp8[8] =
{
0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
};
@@ -417,7 +417,7 @@ E_P16 (unsigned char *p14, unsigned char *p16)
}
static void
-E_P24 (unsigned char *p21, unsigned char *c8, unsigned char *p24)
+E_P24 (unsigned char *p21, const unsigned char *c8, unsigned char *p24)
{
smbhash (p24, c8, p21, 1);
smbhash (p24 + 8, c8, p21 + 7, 1);
@@ -430,7 +430,7 @@ E_P24 (unsigned char *p21, unsigned char *c8, unsigned char *p24)
It takes a password, a 8 byte "crypt key" and puts 24 bytes of
encrypted password into p24 */
void
-smb_encrypt (unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+smb_encrypt (unsigned char *passwd, const unsigned char *c8, unsigned char *p24)
{
unsigned char p14[15], p21[21];
int len;
@@ -469,7 +469,7 @@ local_wcslen (short *str)
this must be in intel (little-endian)
format. */
static int
-local_mbstowcs (short *dst, unsigned char *src, int len)
+local_mbstowcs (short *dst, const unsigned char *src, int len)
{
int i;
short val;
@@ -489,7 +489,7 @@ local_mbstowcs (short *dst, unsigned char *src, int len)
/* Creates the MD4 Hash of the users password in NT UNICODE. */
static void
-E_md4hash (unsigned char *passwd, unsigned char *p16)
+E_md4hash (const unsigned char *passwd, unsigned char *p16)
{
short wpwd[129];
int len;
@@ -511,7 +511,7 @@ E_md4hash (unsigned char *passwd, unsigned char *p16)
/* Does the des encryption from the NT or LM MD4 hash. */
static void
-smb_owf_encrypt (unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+smb_owf_encrypt (unsigned char *passwd, const unsigned char *c8, unsigned char *p24)
{
unsigned char p21[21];
@@ -523,9 +523,9 @@ smb_owf_encrypt (unsigned char *passwd, unsigned char *c8, unsigned char *p24)
/****************************************************************************/
-/* Does the NT MD4 hash then des encryption. */
+/* Does the NT MD4 hash then DES encryption. */
void
-smb_nt_encrypt (unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+smb_nt_encrypt (const unsigned char *passwd, const unsigned char *c8, unsigned char *p24)
{
unsigned char p21[21];
diff --git a/source_code/main.c b/source_code/main.c
index f4eefe8..03df387 100644
--- a/source_code/main.c
+++ b/source_code/main.c
@@ -65,55 +65,121 @@ TEXT Version[] = VERSTAG;
/****************************************************************************/
+/* Difference between January 1st 1970 and January 1st 1978 in seconds. */
#define UNIX_TIME_OFFSET 252460800
+
+/* Maximum length of a file name, as supported by AmigaDOS. */
#define MAX_FILENAME_LEN 255
/****************************************************************************/
+/* This is the root of the SMB directory path, sort of like the
+ * equivalent to ":" as used with AmigaDOS.
+ */
#define SMB_ROOT_DIR_NAME "\\"
+
+/* Individual directory/file names are separated by the
+ * backslash for SMB path names. AmigaDOS uses the slash.
+ */
#define SMB_PATH_SEPARATOR '\\'
/****************************************************************************/
-typedef STRPTR KEY;
-typedef LONG * NUMBER;
-typedef LONG SWITCH;
+/* This is for use with the ReadArgs() argument processing. */
+typedef STRPTR KEY; /* PARAMETER/K, /A, /F */
+typedef LONG * NUMBER; /* PARAMETER/N */
+typedef LONG SWITCH; /* PARAMETER/S */
/****************************************************************************/
+/* The internal data structure which ties an AmigaDOS FileHandle to the
+ * smbfs representation.
+ */
struct FileNode
{
struct MinNode fn_MinNode;
- ULONG fn_Magic;
+ ULONG fn_Magic; /* Magic number which helps to
+ * identify this data structure
+ * as being managed by smbfs.
+ * We use this as a safety measure
+ * in case smbfs receives a file
+ * handle that it did not create.
+ */
- struct DosList * fn_Volume;
+ struct DosList * fn_Volume; /* Points back to the volume which
+ * the file is associated with.
+ */
- struct FileHandle * fn_Handle;
+ struct FileHandle * fn_Handle; /* The AmigaDOS file handle which
+ * this data structure is associated
+ * with.
+ */
- QUAD fn_OffsetQuad;
- LONG fn_Mode;
+ QUAD fn_OffsetQuad; /* Current file read/write position,
+ * as an unsigned 64 bit integer.
+ */
+ LONG fn_Mode; /* File access mode, e.g. MODE_NEWFILE,
+ * MODE_OLDFILE, MODE_READWRITE.
+ */
- smba_file_t * fn_File;
- STRPTR fn_FullName;
+ smba_file_t * fn_File; /* The SMB file system interface to
+ * the remote file.
+ */
+ STRPTR fn_FullName; /* The name of the file at the time
+ * it was opened. Note that this
+ * includes the full path, using the
+ * SMB path syntax.
+ */
};
/****************************************************************************/
+/* The internal data structure which ties an AmigaDOS FileLock to the
+ * smbfs representation. smbfs creates this and returns a pointer to
+ * the ln_FileLock member.
+ */
struct LockNode
{
struct MinNode ln_MinNode;
- ULONG ln_Magic;
+ ULONG ln_Magic; /* Magic number which helps to
+ * identify this data structure
+ * as being managed by smbfs.
+ * We use this as a safety measure
+ * in case smbfs receives a file
+ * lock that it did not create.
+ */
struct FileLock ln_FileLock;
+ /* The AmigaDOS file lock which this
+ * data structure is associated with.
+ */
- smba_file_t * ln_File;
+ smba_file_t * ln_File; /* The SMB file system interface to
+ * the remote file or directory.
+ */
STRPTR ln_FullName;
+ /* The name of the file or directory
+ * at the time it was accessed. Note
+ * that this includes the full path,
+ * using the SMB path syntax.
+ */
const struct MsgPort * ln_LastUser;
+ /* This identifies the last Process
+ * which used this file lock. We need
+ * this to handle deleting from a
+ * directory and scanning that directory
+ * at the same time more smoothly.
+ */
BOOL ln_RestartExamine;
+ /* If this a file lock on a directory,
+ * this flag states if directory
+ * scanning in progress needs to
+ * start over.
+ */
};
/****************************************************************************/
@@ -136,6 +202,10 @@ struct LockNode
/****************************************************************************/
+/* If possible, we want to use the memory pool functions in amiga.lib rather
+ * than those in ROM. The V37 build has to include these in the program itself
+ * since Kickstart 2.04 lacks them.
+ */
#if (MINIMUM_OS_VERSION < 39)
/* These are in amiga.lib */
@@ -161,7 +231,7 @@ static ULONG stack_usage_exit(const struct StackSwapStruct * stk);
static LONG CVSPrintf(const TEXT * format_string, APTR args);
static int LocalVSNPrintf(STRPTR buffer, int limit, const TEXT * formatString, APTR args);
static void cleanup(void);
-static BOOL setup(const TEXT * program_name, const TEXT * service, const TEXT * workgroup, STRPTR username, STRPTR opt_password, BOOL opt_change_username_case, BOOL opt_change_password_case, const TEXT * opt_clientname, const TEXT * opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, LONG *opt_time_zone_offset, LONG *opt_dst_offset, BOOL opt_raw_smb, BOOL opt_unicode, BOOL opt_prefer_core_protocol, BOOL opt_session_setup_delay_unicode, BOOL opt_write_behind, const TEXT * device_name, const TEXT * volume_name, const TEXT * translation_file);
+static BOOL setup(const TEXT * program_name, const TEXT * service, const TEXT * workgroup, STRPTR username, STRPTR opt_password, BOOL opt_change_username_case, BOOL opt_change_password_case, const TEXT * opt_clientname, const TEXT * opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, LONG *opt_time_zone_offset, LONG *opt_dst_offset, BOOL opt_raw_smb, BOOL opt_unicode, BOOL opt_prefer_core_protocol, BOOL opt_session_setup_delay_unicode, BOOL opt_write_behind, const TEXT * device_name, const TEXT * volume_name, BOOL add_volume, const TEXT * translation_file);
static void file_system_handler(BOOL raise_priority, const TEXT * device_name, const TEXT * volume_name, const TEXT * service_name);
/****************************************************************************/
@@ -401,7 +471,7 @@ _start(STRPTR args, LONG args_length, struct ExecBase * exec_base)
/* Allocate the new stack swapping data structure
* and the stack space separately.
*/
- stk = AllocVec(sizeof(*stk),MEMF_PUBLIC|MEMF_ANY);
+ stk = AllocMem(sizeof(*stk),MEMF_PUBLIC|MEMF_ANY);
if(stk == NULL)
goto out;
@@ -437,7 +507,7 @@ _start(STRPTR args, LONG args_length, struct ExecBase * exec_base)
out:
if(stk != NULL)
- FreeVec(stk);
+ FreeMem(stk, sizeof(*stk));
if(new_stack != NULL && new_stack_size > 0)
FreeMem(new_stack,new_stack_size);
@@ -561,10 +631,10 @@ stack_usage_exit(const struct StackSwapStruct * stk)
* and fall back onto a default value if no keyword was provided,
* or the keyword provided does not match what we have.
*/
-static BOOL
-get_switch_status(const TEXT * value,BOOL default_value)
+static LONG
+get_switch_status(const TEXT * value,LONG default_value)
{
- BOOL result = default_value;
+ LONG result = default_value;
if(value != NULL)
{
@@ -596,6 +666,26 @@ get_switch_status(const TEXT * value,BOOL default_value)
/****************************************************************************/
+/* Shortcut for retrieving the value of an icon tool type, even if it
+ * has more than one name.
+ */
+static STRPTR
+get_icon_tool_type_value(TEXT * name,TEXT * alternative_name)
+{
+ STRPTR value = NULL;
+
+ if(Icon != NULL)
+ {
+ value = FindToolType(Icon->do_ToolTypes, name);
+ if(value == NULL && alternative_name != NULL)
+ value = FindToolType(Icon->do_ToolTypes, alternative_name);
+ }
+
+ return(value);
+}
+
+/****************************************************************************/
+
/* This is the traditional main() program. */
static LONG
main(void)
@@ -617,6 +707,7 @@ main(void)
KEY ServerName;
KEY DeviceName;
KEY VolumeName;
+ KEY AddVolume;
NUMBER MaxNameLen;
NUMBER CacheSize;
SWITCH DisableExAll;
@@ -656,6 +747,7 @@ main(void)
"SERVER=SERVERNAME/K,"
"DEVICE=DEVICENAME/K,"
"VOLUME=VOLUMENAME/K,"
+ "ADDVOLUME/K,"
"MAXNAMELEN/N/K,"
"CACHE=CACHESIZE/N/K,"
"DISABLEEXALL/S,"
@@ -682,48 +774,57 @@ main(void)
BOOL close_debug_file = FALSE;
TEXT program_name[MAX_FILENAME_LEN+1];
LONG result = RETURN_FAIL;
- LONG number;
LONG tz_number, dst_number, debug_number;
LONG cache_size = 0;
LONG max_transmit = -1;
LONG timeout = 0;
- char env_protocol[8];
- char env_workgroup_name[17];
- char env_user_name[64];
- char env_password[64];
+ TEXT env_protocol[8];
+ TEXT env_workgroup_name[17];
+ TEXT env_user_name[64];
+ TEXT env_password[64];
/* Don't emit any debugging output before we are ready. */
SETDEBUGLEVEL(0);
/* This needs to be set up properly for report_error()
- * to work.
+ * to work. The cleanup() function will eventually
+ * call it.
*/
NewList((struct List *)&ErrorList);
+ /* The command parameters will be filled in either from
+ * icon tool types or from the CLI command line arguments.
+ */
memset(&args,0,sizeof(args));
- /* If this program was launched from Workbench,
- * parameter passing will have to be handled
- * differently.
+ /* If this program was launched from Workbench, the
+ * command parameters will have to be from the icon
+ * tool types.
*/
if(WBStartup != NULL)
{
+ TEXT * icon_file_name;
+ BPTR icon_file_lock;
STRPTR str;
BPTR old_dir;
- LONG n;
-
- if(WBStartup->sm_NumArgs > 1)
- n = 1;
- else
- n = 0;
+ int size;
+ int n;
/* Get the name of the program, as it was launched
* from Workbench. We actually prefer the name of
* the first project file, if there is one.
*/
- strlcpy(program_name,WBStartup->sm_ArgList[n].wa_Name,sizeof(program_name));
+ if(WBStartup->sm_NumArgs > 1)
+ n = 1;
+ else
+ n = 0;
- SETPROGRAMNAME(FilePart(program_name));
+ icon_file_name = WBStartup->sm_ArgList[n].wa_Name;
+ icon_file_lock = WBStartup->sm_ArgList[n].wa_Lock;
+
+ strlcpy(program_name,FilePart(icon_file_name),sizeof(program_name));
+
+ SETPROGRAMNAME(program_name);
/* Now open icon.library and read that icon. */
IconBase = OpenLibrary("icon.library",0);
@@ -748,50 +849,43 @@ main(void)
goto out;
}
- old_dir = CurrentDir(WBStartup->sm_ArgList[n].wa_Lock);
- Icon = GetDiskObject(WBStartup->sm_ArgList[n].wa_Name);
+ old_dir = CurrentDir(icon_file_lock);
+ Icon = GetDiskObject(icon_file_name);
CurrentDir(old_dir);
if(Icon == NULL)
{
- report_error("Icon not found.");
+ report_error("Icon file for '%s' not found.", icon_file_name);
goto out;
}
/* Only input validation errors are reported below. */
result = RETURN_ERROR;
- /* Examine the icon's tool types and use the
- * information to fill the startup parameter
- * data structure.
+ /* Get the debug options ready before we will deal
+ * with the remaining parameters.
*/
- str = FindToolType(Icon->do_ToolTypes,"DEBUG");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"DEBUGLEVEL");
-
- if(str != NULL)
- {
- if(StrToLong(str,&debug_number) == -1)
- {
- report_error("Invalid number '%s' for 'DEBUG' parameter.",str);
- goto out;
- }
-
- args.DebugLevel = &debug_number;
- }
-
- str = FindToolType(Icon->do_ToolTypes,"DEBUGFILE");
- if(str != NULL)
- args.DebugFile = str;
-
- /* Configure the debugging options. */
- if(args.DebugLevel != NULL)
- SETDEBUGLEVEL(*args.DebugLevel);
- else
- SETDEBUGLEVEL(0);
-
#if DEBUG
{
+ str = get_icon_tool_type_value("DEBUG","DEBUGLEVEL");
+ if(str != NULL)
+ {
+ if(StrToLong(str,&debug_number) == -1 || debug_number < 0)
+ {
+ report_error("Invalid number '%s' for 'DEBUG' parameter.",str);
+ goto out;
+ }
+
+ args.DebugLevel = &debug_number;
+ }
+
+ /* Configure the debugging options. */
+ if(args.DebugLevel != NULL)
+ SETDEBUGLEVEL(*args.DebugLevel);
+ else
+ SETDEBUGLEVEL(0);
+
+ args.DebugFile = get_icon_tool_type_value("DEBUGFILE",NULL);
if(args.DebugFile != NULL)
{
/* Try to append the output to an existing file
@@ -810,7 +904,7 @@ main(void)
* line feeds to it, so that any new output
* will be separated from the old contents.
*/
- if(ExamineFH(debug_file, fib) && fib->fib_Size)
+ if(ExamineFH(debug_file, fib) && fib->fib_Size > 0)
FPrintf(debug_file,"\n\n");
SETDEBUGFILE(debug_file);
@@ -821,105 +915,67 @@ main(void)
}
#endif /* DEBUG */
- str = FindToolType(Icon->do_ToolTypes,"DOMAIN");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"WORKGROUP");
+ /* Examine the icon's tool types and use the
+ * information to fill the startup parameter
+ * data structure.
+ */
+ args.Service = get_icon_tool_type_value("SERVICE", "SHARE");
+ if(args.Service == NULL)
+ {
+ report_error("'SERVICE' parameter needs an argument.");
+ goto out;
+ }
- args.Workgroup = str;
+ /* Set up the name of the program, as it will be
+ * displayed in error requesters.
+ */
+ size = strlen(icon_file_name) + strlen(" ''") + strlen(args.Service)+1;
- str = FindToolType(Icon->do_ToolTypes,"USER");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"USERNAME");
+ NewProgramName = AllocVec(size,MEMF_ANY|MEMF_PUBLIC);
+ if(NewProgramName != NULL)
+ LocalSNPrintf(NewProgramName,size,"%s '%s'",icon_file_name,args.Service);
- args.UserName = str;
+ args.Workgroup = get_icon_tool_type_value("DOMAIN","WORKGROUP");
+ args.UserName = get_icon_tool_type_value("USER","USERNAME");
- str = FindToolType(Icon->do_ToolTypes,"CHANGEUSERNAMECASE");
+ str = get_icon_tool_type_value("CHANGEUSERNAMECASE", NULL);
args.ChangeUserNameCase = (str != NULL) ? str : (STRPTR)"yes";
- args.Password = FindToolType(Icon->do_ToolTypes,"PASSWORD");
+ args.Password = get_icon_tool_type_value("PASSWORD", NULL);
- args.ChangePasswordCase = FindToolType(Icon->do_ToolTypes,"CHANGEPASSWORDCASE");
- if(args.ChangePasswordCase == NULL && FindToolType(Icon->do_ToolTypes,"CHANGECASE") != 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";
- if(FindToolType(Icon->do_ToolTypes,"DISABLEEXALL") != NULL)
- args.DisableExAll = TRUE;
+ 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.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;
+ args.WriteBehind = get_icon_tool_type_value("WRITEBEHIND", NULL) != NULL;
- if(FindToolType(Icon->do_ToolTypes,"OMITHIDDEN") != NULL)
- args.OmitHidden = TRUE;
+ args.ClientName = get_icon_tool_type_value("CLIENT", "CLIENTNAME");
+ args.ServerName = get_icon_tool_type_value("SERVER", "SERVERNAME");
+ args.DeviceName = get_icon_tool_type_value("DEVICE", "DEVICENAME");
+ args.VolumeName = get_icon_tool_type_value("VOLUME", "VOLUMENAME");
- if(FindToolType(Icon->do_ToolTypes,"QUIET") != NULL)
- args.Quiet = TRUE;
-
- if(FindToolType(Icon->do_ToolTypes,"RAISEPRIORITY") != NULL)
- args.RaisePriority = TRUE;
-
- if(FindToolType(Icon->do_ToolTypes,"CASE") != NULL ||
- FindToolType(Icon->do_ToolTypes,"CASESENSITIVE") != NULL)
- {
- args.CaseSensitive = TRUE;
- }
-
- str = FindToolType(Icon->do_ToolTypes,"CLIENT");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"CLIENTNAME");
-
- args.ClientName = str;
-
- str = FindToolType(Icon->do_ToolTypes,"SERVER");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"SERVERNAME");
-
- args.ServerName = str;
-
- str = FindToolType(Icon->do_ToolTypes,"DEVICE");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"DEVICENAME");
-
- args.DeviceName = str;
-
- str = FindToolType(Icon->do_ToolTypes,"VOLUME");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"VOLUMENAME");
-
- args.VolumeName = str;
-
- str = FindToolType(Icon->do_ToolTypes,"SERVICE");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"SHARE");
-
- args.Service = str;
+ if(args.VolumeName == NULL)
+ args.AddVolume = get_icon_tool_type_value("ADDVOLUME", NULL);
+ str = get_icon_tool_type_value("MAXNAMELEN", NULL);
if(str != NULL)
{
- int size;
-
- /* Set up the name of the program, as it will be
- * displayed in error requesters.
- */
- size = strlen(WBStartup->sm_ArgList[0].wa_Name) + strlen(" ''") + strlen(str)+1;
-
- NewProgramName = AllocVec(size,MEMF_ANY|MEMF_PUBLIC);
- if(NewProgramName != NULL)
- LocalSNPrintf(NewProgramName,size,"%s '%s'",WBStartup->sm_ArgList[0].wa_Name,str);
- }
-
- str = FindToolType(Icon->do_ToolTypes,"MAXNAMELEN");
- if(str != NULL)
- {
- if(StrToLong(str,&number) == -1)
+ if(StrToLong(str,&MaxNameLen) == -1)
{
report_error("Invalid number '%s' for 'MAXNAMELEN' parameter.",str);
goto out;
}
- MaxNameLen = number;
+ args.MaxNameLen = &MaxNameLen;
}
- str = FindToolType(Icon->do_ToolTypes,"TZ");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"TIMEZONEOFFSET");
-
+ str = get_icon_tool_type_value("TZ","TIMEZONEOFFSET");
if(str != NULL)
{
if(StrToLong(str,&tz_number) == -1)
@@ -931,10 +987,7 @@ main(void)
args.TimeZoneOffset = &tz_number;
}
- str = FindToolType(Icon->do_ToolTypes,"DST");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"DSTOFFSET");
-
+ str = get_icon_tool_type_value("DST", "DSTOFFSET");
if(str != NULL)
{
if(StrToLong(str,&dst_number) == -1)
@@ -946,82 +999,55 @@ main(void)
args.DSTOffset = &dst_number;
}
- args.Protocol = FindToolType(Icon->do_ToolTypes,"PROTOCOL");
+ args.Protocol = get_icon_tool_type_value("PROTOCOL", NULL);
+ args.SessionSetup = get_icon_tool_type_value("SESSIONSETUP", NULL);
- if(FindToolType(Icon->do_ToolTypes,"NETBIOS") != NULL)
- args.NetBIOSTransport = TRUE;
-
- if(FindToolType(Icon->do_ToolTypes,"WRITEBEHIND") != NULL)
- args.WriteBehind = TRUE;
-
- args.SessionSetup = FindToolType(Icon->do_ToolTypes,"SESSIONSETUP");
-
- str = FindToolType(Icon->do_ToolTypes,"TRANSLATE");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"TRANSLATIONFILE");
+ args.TranslationFile = get_icon_tool_type_value("TRANSLATE", "TRANSLATIONFILE");
+ args.Unicode = get_icon_tool_type_value("UNICODE", NULL);
+ args.CP437 = get_icon_tool_type_value("CP437", NULL) != NULL;
+ args.CP850 = get_icon_tool_type_value("CP850", NULL) != NULL;
+ str = get_icon_tool_type_value("CACHE","CACHESIZE");
if(str != NULL)
{
- args.TranslationFile = str;
- }
- else
- {
- str = FindToolType(Icon->do_ToolTypes,"UNICODE");
- if (str != NULL)
- args.Unicode = str;
- else if (FindToolType(Icon->do_ToolTypes,"CP437") != NULL)
- args.CP437 = TRUE;
- else if (FindToolType(Icon->do_ToolTypes,"CP850") != NULL)
- args.CP850 = TRUE;
- }
-
- str = FindToolType(Icon->do_ToolTypes,"CACHE");
- if(str == NULL)
- str = FindToolType(Icon->do_ToolTypes,"CACHESIZE");
-
- if(str != NULL)
- {
- if(StrToLong(str,&number) == -1)
+ if(StrToLong(str,&cache_size) == -1)
{
report_error("Invalid number '%s' for 'CACHE' parameter.",str);
goto out;
}
- cache_size = number;
+ args.CacheSize = &cache_size;
}
- str = FindToolType(Icon->do_ToolTypes,"MAXTRANSMIT");
+ str = get_icon_tool_type_value("MAXTRANSMIT", NULL);
if(str != NULL)
{
- if(StrToLong(str,&number) == -1)
+ if(StrToLong(str,&max_transmit) == -1)
{
report_error("Invalid number '%s' for 'MAXTRANSMIT' parameter.",str);
goto out;
}
- max_transmit = number;
+ args.MaxTransmit = &max_transmit;
}
- str = FindToolType(Icon->do_ToolTypes,"TIMEOUT");
+ str = get_icon_tool_type_value("TIMEOUT", NULL);
if(str != NULL)
{
- if(StrToLong(str,&number) == -1 || number < 0)
+ if(StrToLong(str,&timeout) == -1)
{
report_error("Invalid number '%s' for 'TIMEOUT' parameter.",str);
goto out;
}
- timeout = number;
- }
-
- if(args.Service == NULL)
- {
- report_error("'SERVICE' parameter needs an argument.");
- goto out;
+ args.Timeout = &timeout;
}
}
else
{
+ const TEXT * name;
+ int size;
+
/* Only input validation errors are reported below. */
result = RETURN_ERROR;
@@ -1036,14 +1062,14 @@ main(void)
goto out;
}
- /* Configure the debugging options. */
- if(args.DebugLevel != NULL)
- SETDEBUGLEVEL(*args.DebugLevel);
- else
- SETDEBUGLEVEL(0);
-
#if DEBUG
{
+ /* Configure the debugging options. */
+ if(args.DebugLevel != NULL)
+ SETDEBUGLEVEL(*args.DebugLevel);
+ else
+ SETDEBUGLEVEL(0);
+
if(args.DebugFile != NULL)
{
/* Try to append the output to an existing file
@@ -1062,7 +1088,7 @@ main(void)
* line feeds to it, so that any new output
* will be separated from the old contents.
*/
- if(ExamineFH(debug_file, fib) && fib->fib_Size)
+ if(ExamineFH(debug_file, fib) && fib->fib_Size > 0)
FPrintf(debug_file,"\n\n");
}
}
@@ -1077,32 +1103,18 @@ main(void)
D(("%s (%s)", VERS, DATE));
- if(args.Service != NULL)
- {
- const TEXT * name = FilePart(program_name);
- int size;
+ ASSERT( args.Service != NULL );
- /* Set up the name of the program, as it will be
- * displayed in the proces status list.
- */
- size = strlen(name) + strlen(" ''") + strlen(args.Service)+1;
+ /* Set up the name of the program, as it will be
+ * displayed in the proces status list.
+ */
+ name = FilePart(program_name);
- NewProgramName = AllocVec(size,MEMF_ANY|MEMF_PUBLIC);
- if(NewProgramName != NULL)
- LocalSNPrintf(NewProgramName,size,"%s '%s'",name,args.Service);
- }
+ size = strlen(name) + strlen(" ''") + strlen(args.Service)+1;
- if(args.MaxNameLen != NULL)
- MaxNameLen = (*args.MaxNameLen);
-
- if(args.CacheSize != NULL)
- cache_size = (*args.CacheSize);
-
- if(args.MaxTransmit != NULL)
- max_transmit = (*args.MaxTransmit);
-
- if(args.Timeout != NULL && (*args.Timeout) >= 0)
- timeout = (*args.Timeout);
+ NewProgramName = AllocVec(size,MEMF_ANY|MEMF_PUBLIC);
+ if(NewProgramName != NULL)
+ LocalSNPrintf(NewProgramName,size,"%s '%s'",name,args.Service);
}
/* If no workgroup/domain was given, try the environment variables. */
@@ -1199,6 +1211,9 @@ main(void)
D(("no device/volume name given, using 'devicename=%s' instead.", args.DeviceName));
}
+ if(args.VolumeName != NULL)
+ args.AddVolume = "yes";
+
/* Restrict the command set which smbfs uses? */
if(args.Protocol == NULL)
{
@@ -1234,21 +1249,37 @@ main(void)
D(("using 'unicode=%s'.", args.Unicode));
}
- if(Stricmp(args.Unicode,"OFF") != SAME && Stricmp(args.Unicode,"ON") != SAME)
+ /* Is the Unicode parameter even valid? */
+ if(get_switch_status(args.Unicode,-1) == -1)
{
report_error("'UNICODE' parameter must be either 'ON' or 'OFF'.");
goto out;
}
/* Code page based translation using a file disables
- * the built-in CP437 and CP850 translation.
+ * Unicode support and the built-in CP437 and CP850
+ * translation.
*/
- if(args.TranslationFile != NULL)
+ if (args.TranslationFile != NULL)
+ {
args.CP437 = args.CP850 = FALSE;
- else if (args.CP437)
- args.CP850 = FALSE;
- else if (args.CP850)
- args.CP437 = FALSE;
+ args.Unicode = "off";
+ }
+ /* Unicode support disables the code-page based
+ * translation.
+ */
+ else if (get_switch_status(args.Unicode, FALSE))
+ {
+ args.CP437 = args.CP850 = FALSE;
+ }
+ else
+ {
+ if(args.CP437 && args.CP850)
+ {
+ report_error("You can use either the 'CP437' or the 'CP850' parameters, but not both.");
+ goto out;
+ }
+ }
/* Use one of the built-in code page translation tables? */
if (args.CP437)
@@ -1270,6 +1301,46 @@ main(void)
TranslateNames = TRUE;
}
+ if(args.MaxNameLen != NULL)
+ {
+ MaxNameLen = (*args.MaxNameLen);
+ if(MaxNameLen <= 0)
+ {
+ report_error("'MAXNAMELEN' parameter must be > 0.");
+ goto out;
+ }
+ }
+
+ if(args.CacheSize != NULL)
+ {
+ cache_size = (*args.CacheSize);
+ if(cache_size <= 0)
+ {
+ report_error("'CACHESIZE' parameter must be > 0.");
+ goto out;
+ }
+ }
+
+ if(args.MaxTransmit != NULL)
+ {
+ max_transmit = (*args.MaxTransmit);
+ if(max_transmit <= 0)
+ {
+ report_error("'MAXTRANSMIT' parameter must be > 0.");
+ goto out;
+ }
+ }
+
+ if(args.Timeout != NULL)
+ {
+ timeout = (*args.Timeout);
+ if(timeout <= 0)
+ {
+ report_error("'TIMEOUT' parameter must be > 0.");
+ goto out;
+ }
+ }
+
DisableExAll = (BOOL)(args.DisableExAll != 0);
CaseSensitive = (BOOL)(args.CaseSensitive != 0);
OmitHidden = (BOOL)(args.OmitHidden != 0);
@@ -1345,6 +1416,8 @@ main(void)
else
D(("volume name = NULL."));
+ D(("add volume = %s", args.AddVolume));
+
if(args.TranslationFile != NULL)
D(("translation file = '%s'.", args.TranslationFile));
else
@@ -1381,6 +1454,7 @@ main(void)
args.WriteBehind,
args.DeviceName,
args.VolumeName,
+ get_switch_status(args.AddVolume, TRUE),
args.TranslationFile))
{
char setenv_name[40];
@@ -1470,11 +1544,11 @@ main(void)
if(close_debug_file && debug_file != ZERO)
{
- Close(debug_file);
-
SETDEBUGFILE(ZERO);
SETDEBUGLEVEL(0);
+
+ Close(debug_file);
}
return(result);
@@ -1482,6 +1556,12 @@ main(void)
/****************************************************************************/
+/* Our own FPrintf(), which is needed because this code has to build
+ * both for AmigaOS 2.x/3.x and 4.x, and with Lattice/SAS/GCC and the
+ * header files make it difficult to do this. The FPrintf() declaration
+ * is not always usable, depending upon which AmigaOS header file set
+ * you are using.
+ */
static LONG VARARGS68K
LocalFPrintf(BPTR output, const TEXT * format, ...)
{
@@ -1631,124 +1711,130 @@ string_toupper(STRPTR s)
/* Prepare the accumulated list of error messages for display
* and purge the contents of that list.
+ *
+ * Unless the program was started from Workbench this function
+ * will do nothing.
*/
static void
display_error_message_list(void)
{
- struct MinNode * last = NULL;
- struct MinNode * mn;
- TEXT * message = NULL;
- const TEXT * str;
- int size;
-
- /* Determine how much memory will have to be
- * allocated to hold all the accumulated
- * error messages.
- */
- size = 0;
-
- for(mn = ErrorList.mlh_Head ;
- mn->mln_Succ != NULL ;
- mn = mn->mln_Succ)
+ if(WBStartup != NULL)
{
- last = mn;
+ struct MinNode * last = NULL;
+ struct MinNode * mn;
+ TEXT * message = NULL;
+ const TEXT * str;
+ int size;
- str = (TEXT *)(mn + 1);
+ /* Determine how much memory will have to be
+ * allocated to hold all the accumulated
+ * error messages.
+ */
+ size = 0;
- size += strlen(str)+1;
- }
+ for(mn = ErrorList.mlh_Head ;
+ mn->mln_Succ != NULL ;
+ mn = mn->mln_Succ)
+ {
+ last = mn;
- /* Allocate the memory for the messages, then
- * copy them there.
- */
- if(size > 0)
- {
- message = AllocVec(size,MEMF_ANY);
+ str = (TEXT *)(mn + 1);
+
+ size += strlen(str)+1;
+ }
+
+ /* Allocate the memory for the messages, then
+ * copy them there.
+ */
+ if(size > 0)
+ {
+ message = AllocVec(size,MEMF_ANY);
+ if(message != NULL)
+ {
+ int message_len;
+ int len;
+
+ message_len = 0;
+
+ for(mn = ErrorList.mlh_Head ;
+ mn->mln_Succ != NULL ;
+ mn = mn->mln_Succ)
+ {
+ str = (TEXT *)(mn + 1);
+ len = strlen(str);
+
+ memcpy(&message[message_len], str, len);
+ message_len += len;
+
+ if(mn != last)
+ message[message_len++] = '\n';
+ }
+
+ ASSERT( message_len < size );
+
+ message[message_len] = '\0';
+ }
+ }
+
+ /* Purge the list. */
+ while((mn = (struct MinNode *)RemHead((struct List *)&ErrorList)) != NULL)
+ FreeVec(mn);
+
+ /* Display the error messages. */
if(message != NULL)
{
- int message_len;
- int len;
+ IntuitionBase = OpenLibrary("intuition.library",37);
- message_len = 0;
-
- for(mn = ErrorList.mlh_Head ;
- mn->mln_Succ != NULL ;
- mn = mn->mln_Succ)
+ #if defined(__amigaos4__)
{
- str = (TEXT *)(mn + 1);
- len = strlen(str);
+ if(IntuitionBase != NULL)
+ {
+ IIntuition = (struct IntuitionIFace *)GetInterface(IntuitionBase, "main", 1, 0);
+ if(IIntuition == NULL)
+ {
+ CloseLibrary(IntuitionBase);
+ IntuitionBase = NULL;
+ }
+ }
+ }
+ #endif /* __amigaos4__ */
- memcpy(&message[message_len], str, len);
- message_len += len;
+ if(IntuitionBase != NULL)
+ {
+ struct EasyStruct es;
+ STRPTR title;
- if(mn != last)
- message[message_len++] = '\n';
+ memset(&es,0,sizeof(es));
+
+ if(NewProgramName != NULL)
+ title = NewProgramName;
+ else
+ title = WBStartup->sm_ArgList[0].wa_Name;
+
+ es.es_StructSize = sizeof(es);
+ es.es_Title = title;
+ es.es_TextFormat = message;
+ es.es_GadgetFormat = "OK";
+
+ EasyRequestArgs(NULL,&es,NULL,NULL);
}
- ASSERT( message_len < size );
-
- message[message_len] = '\0';
+ FreeVec(message);
}
- }
-
- /* Purge the list. */
- while((mn = (struct MinNode *)RemHead((struct List *)&ErrorList)) != NULL)
- FreeVec(mn);
-
- /* Display the error messages. */
- if(message != NULL)
- {
- IntuitionBase = OpenLibrary("intuition.library",37);
#if defined(__amigaos4__)
{
- if(IntuitionBase != NULL)
+ if(IIntuition != NULL)
{
- IIntuition = (struct IntuitionIFace *)GetInterface(IntuitionBase, "main", 1, 0);
- if(IIntuition == NULL)
- {
- CloseLibrary(IntuitionBase);
- IntuitionBase = NULL;
- }
+ DropInterface((struct Interface *)IIntuition);
+ IIntuition = NULL;
}
}
#endif /* __amigaos4__ */
- if(IntuitionBase != NULL)
- {
- struct EasyStruct es;
- STRPTR title;
-
- memset(&es,0,sizeof(es));
-
- if(NewProgramName == NULL)
- title = WBStartup->sm_ArgList[0].wa_Name;
- else
- title = NewProgramName;
-
- es.es_StructSize = sizeof(es);
- es.es_Title = title;
- es.es_TextFormat = message;
- es.es_GadgetFormat = "OK";
-
- EasyRequestArgs(NULL,&es,NULL,NULL);
- }
-
- FreeVec(message);
+ CloseLibrary(IntuitionBase);
+ IntuitionBase = NULL;
}
-
- #if defined(__amigaos4__)
- {
- if(IIntuition != NULL)
- {
- DropInterface((struct Interface *)IIntuition);
- IIntuition = NULL;
- }
- }
- #endif /* __amigaos4__ */
-
- CloseLibrary(IntuitionBase);
- IntuitionBase = NULL;
}
/* Add another error message to the list; the messages are
@@ -1789,6 +1875,10 @@ report_error(const TEXT * fmt,...)
{
va_list args;
+ /* If this program was started from Workbench the
+ * error messages will be collected for later
+ * display.
+ */
if(WBStartup != NULL)
{
#if defined(__amigaos4__)
@@ -2076,22 +2166,29 @@ tm_to_seconds(const struct tm * const tm)
/****************************************************************************/
+/* This is used by the CVSPrintf() and LocalSNPrintf() functions below. */
struct FormatContext
{
- TEXT * fc_Buffer;
- int fc_Limit;
- int fc_Size;
+ TEXT * fc_Buffer; /* Where to store the next character. */
+ int fc_Limit; /* How many more characters may be stored. */
+ int fc_Size; /* How many characters were stored so far. */
};
/****************************************************************************/
+/* We just count the number of characters here. Note that this function
+ * has two parameters and uses only one: this is needed for OS4 for which
+ * RawDoFmt() always passes both.
+ */
static void ASM
-CountChar(REG(a3,struct FormatContext * fc))
+CountChar(REG(d0,TEXT unused_c),REG(a3,struct FormatContext * fc))
{
fc->fc_Size++;
}
-/* Count the number of characters LocalSNPrintf() would put into a string. */
+/* Count the number of characters LocalSNPrintf() would put into a string.
+ * Note that this includes the terminating NUL character.
+ */
static LONG
CVSPrintf(const TEXT * format_string,APTR args)
{
@@ -2106,6 +2203,7 @@ CVSPrintf(const TEXT * format_string,APTR args)
/****************************************************************************/
+/* Store the next character in the buffer, but only if there is still room. */
static void ASM
StuffChar(REG(d0,TEXT c),REG(a3,struct FormatContext * fc))
{
@@ -2119,13 +2217,14 @@ StuffChar(REG(d0,TEXT c),REG(a3,struct FormatContext * fc))
}
}
+/* This is the non-varargs variant of LocalSNPrintf() below. */
static int
LocalVSNPrintf(STRPTR buffer, int limit, const TEXT * formatString, APTR args)
{
struct FormatContext fc;
fc.fc_Buffer = buffer;
- fc.fc_Limit = limit-1;
+ fc.fc_Limit = limit-1; /* One less character for terminating NUL. */
fc.fc_Size = 0;
RawDoFmt(formatString,args,(void (*)())StuffChar,&fc);
@@ -2138,7 +2237,10 @@ LocalVSNPrintf(STRPTR buffer, int limit, const TEXT * formatString, APTR args)
/****************************************************************************/
-/* Format a string for output. */
+/* Format a string for output. The number of characters which may be
+ * stored in the string cannot exceed what the limit parameter states.
+ * Unless limit is 0, the string will be NUL-terminated.
+ */
void VARARGS68K
LocalSNPrintf(STRPTR buffer, int limit, const TEXT * formatString,...)
{
@@ -2162,7 +2264,7 @@ LocalSNPrintf(STRPTR buffer, int limit, const TEXT * formatString,...)
/****************************************************************************/
/* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
- * Thanks very much, Chris!
+ * Thank you very much, Chris!
*/
struct addr_entry
{
@@ -2852,7 +2954,8 @@ check_access_mode_collision(const TEXT * name,LONG mode)
}
/* Find out whether there already exists a reference to a
- * certain file or directory.
+ * certain file or directory. Returns an AmigaDOS error
+ * code if so, and 0 otherwise.
*/
static int
name_already_in_use(const TEXT * name)
@@ -2887,7 +2990,7 @@ name_already_in_use(const TEXT * name)
* should be avoided when used with the SMB file sharing protocol.
*/
static BOOL
-is_reserved_name(const TEXT * name)
+name_contains_reserved_smb_characters(const TEXT * name)
{
BOOL result = TRUE;
@@ -3131,7 +3234,9 @@ validate_amigados_file_name(const TEXT * name,int len)
/* Pick up all the DOS packets waiting to be processed and
* return them with an error, claiming that the packet cannot
- * be processed.
+ * be processed. This is used while the file system has been
+ * disabled, to avoid packets piling up which are not going
+ * to be processed any time soon.
*/
static void
reject_all_pending_packets(struct MsgPort * port)
@@ -3199,7 +3304,9 @@ really_remove_dosentry(struct DosList * entry)
{
dl = AttemptLockDosList(LDF_WRITE|kind);
- /* Workaround for dos.library bug... */
+ /* Workaround for dos.library bug present in
+ * Kickstart 2.0 through Kickstart 3.0.
+ */
if(((ULONG)dl) == 1)
dl = NULL;
@@ -3441,6 +3548,7 @@ setup(
BOOL opt_write_behind,
const TEXT * device_name,
const TEXT * volume_name,
+ BOOL opt_add_volume,
const TEXT * translation_file)
{
BOOL result = FALSE;
@@ -3450,6 +3558,7 @@ setup(
const TEXT * actual_volume_name;
int actual_volume_name_len;
TEXT name[MAX_FILENAME_LEN+1];
+ smba_connect_parameters_t par;
BOOL device_exists = FALSE;
int len,i;
@@ -3584,12 +3693,29 @@ setup(
file = Open(translation_file,MODE_OLDFILE);
if(file != ZERO)
{
- if(Read(file,map_amiga_to_smb_name,256) != 256 ||
- Read(file,map_smb_to_amiga_name,256) != 256)
+ LONG num_bytes_read = 0;
+ LONG n;
+
+ n = Read(file,map_amiga_to_smb_name,256);
+ if(n == 256)
+ {
+ num_bytes_read += n;
+
+ n = Read(file,map_smb_to_amiga_name,256);
+ if(n > 0)
+ num_bytes_read += n;
+ }
+
+ if(n < 0)
{
msg = "Could not read translation file";
+
error = IoErr();
}
+ else if (num_bytes_read < 512)
+ {
+ msg = "Translation file is too short";
+ }
Close(file);
}
@@ -3599,10 +3725,15 @@ setup(
error = IoErr();
}
- if(msg == NULL)
+ if (msg == NULL)
{
TranslateNames = TRUE;
}
+ else if (error == OK)
+ {
+ report_error("%s '%s'.",msg,translation_file);
+ goto out;
+ }
else
{
TEXT description[100];
@@ -3620,6 +3751,8 @@ setup(
}
}
+ memset(&par,0,sizeof(par));
+
if(smba_start(
service,
workgroup,
@@ -3639,6 +3772,7 @@ setup(
&error,
&smb_error_class,
&smb_error,
+ &par,
&ServerData) < 0)
{
goto out;
@@ -3652,7 +3786,8 @@ setup(
}
/* If a device name was provided, check whether it is
- * well-formed.
+ * well-formed, and whether a device of that name
+ * already exists.
*/
if(device_name != NULL)
{
@@ -3673,9 +3808,15 @@ setup(
dl = LockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
+ /* Does this device name already exist? Note that
+ * device names must be unique.
+ */
if(FindDosEntry(dl,name,LDF_DEVICES) != NULL)
device_exists = TRUE;
}
+ /* Otherwise pick a device name of the form SMBFS0..SMBFS99,
+ * which is not currently in use.
+ */
else
{
dl = LockDosList(LDF_WRITE|LDF_VOLUMES|LDF_DEVICES);
@@ -3714,6 +3855,12 @@ setup(
DeviceNode->dol_Task = FileSystemPort;
+ /* If requested, add a volume name, using the service
+ * name as the default value.
+ */
+ if(opt_add_volume && volume_name == NULL)
+ volume_name = par.service;
+
/* Examine the volume name; make sure that it is
* well-formed.
*/
@@ -3785,7 +3932,8 @@ setup(
if(VolumeNodeAdded)
send_disk_change_notification(IECLASS_DISKINSERTED);
- SetProgramName(NewProgramName);
+ if(Cli() != NULL)
+ SetProgramName(NewProgramName);
result = TRUE;
@@ -3956,7 +4104,10 @@ escape_name(const TEXT * name)
/****************************************************************************/
-/* Convert a BCPL string into a standard NUL-terminated 'C' string. */
+/* Convert a BCPL string into a standard NUL-terminated 'C' string.
+ * Note that these must be different strings which must not
+ * overlap!
+ */
static int
convert_from_bcpl_to_c_string(STRPTR cstring,int cstring_size,const void * bstring)
{
@@ -3992,8 +4143,8 @@ convert_from_c_to_bcpl_string(void * bstring,int bstring_size,const TEXT * cstri
if(bstring_size > 0)
{
- if(bstring_size > 256)
- bstring_size = 256;
+ if(bstring_size > MAX_FILENAME_LEN+1)
+ bstring_size = MAX_FILENAME_LEN+1;
if(len > bstring_size-1)
len = bstring_size-1;
@@ -4672,6 +4823,13 @@ get_parent_dir_name(const TEXT * name,int name_len,STRPTR * parent_name_ptr)
/* Translate an Amiga file name into an encoded form, such as
* through a code page translation table. The file name provided will
* be modified in place and may become longer than it already is.
+ *
+ * Note that if code page based file name translation is disabled
+ * then this function will do nothing and leave the file name
+ * unchanged.
+ *
+ * This function returns an AmigaDOS error code if the translation
+ * cannot be performed and 0 otherwise.
*/
static int
translate_amiga_name_to_smb_name(TEXT * name, int name_len, int name_size)
@@ -4714,6 +4872,9 @@ translate_amiga_name_to_smb_name(TEXT * name, int name_len, int name_size)
* through a code page translation table, into a form suitable
* for use with AmigaDOS. The file name provided will be modified
* in place and may become longer than it already is.
+ *
+ * This function returns an AmigaDOS error code if the translation
+ * cannot be performed and 0 otherwise.
*/
static int
translate_smb_name_to_amiga_name(TEXT * name, int name_len, int name_size)
@@ -4797,8 +4958,10 @@ restart_directory_scanning(const struct MsgPort * user,const TEXT * parent_dir_n
/* Check if a file lock was not created by this file system
* through CreateDir(), Lock(), ParentDir(), ParentOfFH(),
* DupLock() or DupLockFromFH(). Returns TRUE if this is case,
- * FALSE otherwise. If this function returns FALSE, then the
- * file lock has a valid LockNode attached.
+ * FALSE otherwise.
+ *
+ * If this function returns FALSE, then the file lock has a
+ * valid LockNode attached.
*
* Note that the ZERO lock is always rejected as invalid
* by this function.
@@ -4904,8 +5067,6 @@ file_is_invalid(const struct FileNode * fn,int * error_ptr)
/****************************************************************************/
-/****************************************************************************/
-
/* Check if the name of a file or drawer contains MS-DOS
* wildcard characters ("?" and "*") which may not be
* suitable for some file system operations, e.g. rename
@@ -5475,7 +5636,7 @@ Action_LocateObject(
goto out;
}
- if(is_reserved_name(FilePart(name)))
+ if(name_contains_reserved_smb_characters(FilePart(name)))
{
error = ERROR_OBJECT_NOT_FOUND;
goto out;
@@ -6813,15 +6974,39 @@ Action_ExamineNext(
/****************************************************************************/
+/* This is used by the dir_scan_callback_func_exall() function which needs
+ * to add new records to the buffer provided to the ExAll() function.
+ */
struct ExAllContext
{
- struct ExAllData * ec_Last;
- UBYTE * ec_Buffer;
- int ec_BufferSize;
- int ec_RecordSize;
- struct ExAllControl * ec_Control;
- LONG ec_Type;
- LONG ec_Error;
+ struct ExAllData * ec_Last; /* Points to last ExAllData
+ * record, which may need to
+ * be linked up the next
+ * record that is added.
+ */
+ UBYTE * ec_Buffer; /* This is the buffer we need
+ * to fill.
+ */
+ int ec_BufferSize; /* How much room there is in
+ * the buffer.
+ */
+ int ec_RecordSize; /* Each ExAllData record has the
+ * same header size, and the
+ * type of information returned
+ * controls how large that header
+ * is. Here is the header size
+ * we have to use.
+ */
+ struct ExAllControl * ec_Control; /* This was passed to the
+ * ExAll() function.
+ */
+ LONG ec_Type; /* This was passed to the
+ * ExAll() function.
+ */
+ LONG ec_Error; /* If the scanning process has to
+ * be stopped, this is where the
+ * error returned will go.
+ */
};
/* This function is called for every directory entry the directory scanner
@@ -7583,7 +7768,7 @@ Action_Find(
goto out;
}
- if(is_reserved_name(FilePart(name)))
+ if(name_contains_reserved_smb_characters(FilePart(name)))
{
error = ERROR_OBJECT_NOT_FOUND;
goto out;
@@ -7887,6 +8072,10 @@ Action_End(
D(("file opened on '%s'", escape_name(which_fn->fn_FullName)));
+ /* Make sure that the file is still open. This is to avoid
+ * trouble if the client ends up trying to close the
+ * same file twice.
+ */
found = NULL;
for(fn = (struct FileNode *)FileList.mlh_Head ;
@@ -7912,6 +8101,11 @@ Action_End(
smba_close(ServerData,found->fn_File);
+ /* This will make the file_is_invalid() tests return
+ * TRUE, which should make it easier to detect
+ * files which have been closed already, should the
+ * file system receive them.
+ */
found->fn_Magic = 0;
free_memory(found->fn_FullName);
@@ -8756,7 +8950,7 @@ Action_CurrentVolume(
D(("file opened on '%s'", escape_name(fn->fn_FullName)));
- if(NOT DeviceNodeAdded)
+ if(NOT VolumeNodeAdded)
{
error = ERROR_ACTION_NOT_KNOWN;
goto out;
@@ -8766,7 +8960,7 @@ Action_CurrentVolume(
* requester. Not that it should be needed, but you never know...
*/
- result = MKBADDR(DeviceNode);
+ result = MKBADDR(VolumeNode);
error = 0; /* This is actually the unit number. */
out:
@@ -9147,12 +9341,18 @@ Action_LockRecord(
if((mode == REC_SHARED_IMMED) || (mode == REC_EXCLUSIVE_IMMED))
timeout = 0;
+ /* If a timeout was given, it must be converted from ticks
+ * per second into milliseconds.
+ */
if(timeout > 0)
{
- if(timeout > 214748364)
+ /* Is the timeout too large to be converted into
+ * milliseconds?
+ */
+ if(timeout > 0xFFFFFFFFUL / TICKS_PER_SECOND)
timeout = ~0UL; /* wait forever */
else
- timeout *= 20; /* milliseconds instead of Ticks */
+ timeout *= 1000 / TICKS_PER_SECOND;
}
if(smba_lockrec (fn->fn_File, offset, length, umode, 0, (long)timeout, &error) < 0)
@@ -9350,6 +9550,9 @@ file_system_handler(
LONG which;
LONG i;
+ /* Figure out which CLI process number
+ * this command is associated with.
+ */
Forbid();
which = max_cli = MaxCli();
diff --git a/source_code/proc.c b/source_code/proc.c
index 18604ea..1b5ce7e 100644
--- a/source_code/proc.c
+++ b/source_code/proc.c
@@ -4373,43 +4373,26 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr)
if(server->security_mode & NEGOTIATE_ENCRYPT_PASSWORDS)
{
+ char smb_password[15];
+
SHOWMSG("encrypted passwords required");
- memset(oem_password,0,sizeof(oem_password));
- strlcpy(oem_password,server->mount_data.password,sizeof(oem_password));
+ /* Maximum password length for smb_encrypt() is 14 characters, which
+ * does not include the terminating NUL byte. The password will be
+ * converted to all-upper-case characters prior to encryption which
+ * is why we make a copy first.
+ */
+ strlcpy(smb_password,server->mount_data.password,sizeof(smb_password));
smb_encrypt(oem_password,server->crypt_key,oem_password);
oem_password_len = 24;
- /*
- PRINTHEADER();
- PRINTF(("password: "));
- for(i = 0 ; i < 24 ; i++)
- PRINTF(("%02lx ",oem_password[i]));
- PRINTF(("\n"));
- */
-
- memset(unicode_password,0,sizeof(unicode_password));
- strlcpy(unicode_password,server->mount_data.password,sizeof(unicode_password));
-
- smb_nt_encrypt(unicode_password,server->crypt_key,unicode_password);
+ /* Maximum password length for smb_nt_encrypt() is 128 characters, which
+ * does not include the terminating NUL byte. The password provided
+ * will not be changed prior to encryption.
+ */
+ smb_nt_encrypt(server->mount_data.password,server->crypt_key,unicode_password);
unicode_password_len = 24;
-
- /*
- PRINTHEADER();
- PRINTF(("unicode_password: "));
- for(i = 0 ; i < 24 ; i++)
- PRINTF(("%02lx ",unicode_password[i]));
- PRINTF(("\n"));
- */
-
- /*
- PRINTHEADER();
- PRINTF(("crypt_key: "));
- for(i = 0 ; i < server->crypt_key_length ; i++)
- PRINTF(("%02lx ",server->crypt_key[i]));
- PRINTF(("\n"));
- */
}
else
{
@@ -4644,7 +4627,10 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr)
p += oem_password_len;
/* User name must be NUL-terminated. */
- memcpy (p, server->mount_data.username, user_len+1);
+ if(user_len > 0)
+ memcpy (p, server->mount_data.username, user_len+1);
+ else
+ (*p) = 0;
}
result = smb_request_ok (server, SMBsesssetupX, 3, 0, error_ptr);
diff --git a/source_code/smakefile b/source_code/smakefile
index 5cd1a6f..ceb17c4 100644
--- a/source_code/smakefile
+++ b/source_code/smakefile
@@ -56,8 +56,8 @@ VERSION = 2
OPTIMIZE = optimize opttime optinline optinlocal
CPU = any
#CPU = 060 optschedule
-#DEBUG = line
- DEBUG = symbolflush noopt define=DEBUG define=DUMP_SMB
+ DEBUG = line
+#DEBUG = symbolflush noopt define=DEBUG define=DUMP_SMB
###############################################################################
diff --git a/source_code/smb_abstraction.c b/source_code/smb_abstraction.c
index 6cdb7e9..d48288e 100644
--- a/source_code/smb_abstraction.c
+++ b/source_code/smb_abstraction.c
@@ -1805,6 +1805,8 @@ smba_start(
int * error_ptr,
int * smb_error_class_ptr,
int * smb_error_ptr,
+ smba_connect_parameters_t *
+ smba_connect_par,
smba_server_t ** smba_server_ptr)
{
smba_connect_parameters_t par;
@@ -2073,6 +2075,9 @@ smba_start(
goto out;
}
+ if(smba_connect_par != NULL)
+ (*smba_connect_par) = par;
+
(*smba_server_ptr) = the_server;
result = 0;
diff --git a/source_code/smb_abstraction.h b/source_code/smb_abstraction.h
index 9055955..cb2e74d 100644
--- a/source_code/smb_abstraction.h
+++ b/source_code/smb_abstraction.h
@@ -133,7 +133,7 @@ int smba_rmdir(smba_server_t *s, const char *path, int *error_ptr);
int smba_rename(smba_server_t *s, const char *from, const char *to, int *error_ptr);
int smba_statfs(smba_server_t *s, long *bsize, long *blocks, long *bfree, int *error_ptr);
void smb_invalidate_all_inodes(struct smb_server *server);
-int smba_start(const char *service, const char *opt_workgroup, const char *opt_username, const char *opt_password, const char *opt_clientname, const char *opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, int opt_raw_smb, int opt_unicode, int opt_prefer_core_protocol, int opt_case_sensitive, int opt_session_setup_delay_unicode, int opt_write_behind, int *error_ptr, int *smb_error_class_ptr, int *smb_error_ptr, smba_server_t **smba_server_ptr);
+int smba_start(const char *service, const char *opt_workgroup, const char *opt_username, const char *opt_password, const char *opt_clientname, const char *opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, int opt_raw_smb, int opt_unicode, int opt_prefer_core_protocol, int opt_case_sensitive, int opt_session_setup_delay_unicode, int opt_write_behind, int *error_ptr, int *smb_error_class_ptr, int *smb_error_ptr, smba_connect_parameters_t *smba_connect_par, smba_server_t **smba_server_ptr);
int smba_get_dircache_size(struct smba_server *server);
int smba_change_dircache_size(struct smba_server *server, int cache_size);
diff --git a/source_code/smbfs.h b/source_code/smbfs.h
index ea4e72b..376bd47 100644
--- a/source_code/smbfs.h
+++ b/source_code/smbfs.h
@@ -159,8 +159,8 @@ size_t strlcat(char *dst, const char *src, size_t siz);
/****************************************************************************/
-extern void smb_encrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
-extern void smb_nt_encrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+extern void smb_encrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24);
+extern void smb_nt_encrypt(const unsigned char *passwd, const unsigned char *c8, unsigned char *p24);
/****************************************************************************/
diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h
index 157bd95..4d7d960 100644
--- a/source_code/smbfs_rev.h
+++ b/source_code/smbfs_rev.h
@@ -1,6 +1,6 @@
#define VERSION 2
-#define REVISION 2
-#define DATE "1.12.2018"
-#define VERS "smbfs 2.2"
-#define VSTRING "smbfs 2.2 (1.12.2018)\r\n"
-#define VERSTAG "\0$VER: smbfs 2.2 (1.12.2018)"
+#define REVISION 3
+#define DATE "8.12.2018"
+#define VERS "smbfs 2.3"
+#define VSTRING "smbfs 2.3 (8.12.2018)\r\n"
+#define VERSTAG "\0$VER: smbfs 2.3 (8.12.2018)"
diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev
index 0cfbf08..00750ed 100644
--- a/source_code/smbfs_rev.rev
+++ b/source_code/smbfs_rev.rev
@@ -1 +1 @@
-2
+3