There's an ongoing project to bring some kind of path selection
authorRichard Levitte <levitte@openssl.org>
Mon, 15 Jul 2002 15:35:40 +0000 (15:35 +0000)
committerRichard Levitte <levitte@openssl.org>
Mon, 15 Jul 2002 15:35:40 +0000 (15:35 +0000)
mechanism to the ENGINE framework.  This means there there are going
to be new functionality for the DSO part, and ultimately some way of
merging two file specifications together.

This commit places the merging code into the repository.  It's
currently not used anywhere, and hasn't been tested at all.  It may be
full of errors, including syntactical ones.  Those will be fixed as
promptly as possible.

crypto/dso/dso.h
crypto/dso/dso_dl.c
crypto/dso/dso_dlfcn.c
crypto/dso/dso_err.c
crypto/dso/dso_lib.c
crypto/dso/dso_vms.c
crypto/dso/dso_win32.c

index aa721f7..2cf6e1a 100644 (file)
@@ -1,4 +1,4 @@
-/* dso.h */
+/* dso.h -*- mode:C; c-file-style: "eay" -*- */
 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
  * project 2000.
  */
@@ -107,6 +107,22 @@ typedef struct dso_st DSO;
  * condition) or a newly allocated string containing the transformed form that
  * the caller will need to free with OPENSSL_free() when done. */
 typedef char* (*DSO_NAME_CONVERTER_FUNC)(DSO *, const char *);
+/* The function prototype used for method functions (or caller-provided
+ * callbacks) that merge two file specifications. They are passed a
+ * DSO structure pointer (or NULL if they are to be used independantly of
+ * a DSO object) and two file specifications to merge. They should
+ * either return NULL (if there is an error condition) or a newly allocated
+ * string containing the result of merging that the caller will need
+ * to free with OPENSSL_free() when done.
+ * Here, merging means that bits and pieces are taken from each of the
+ * file specifications and added together in whatever fashion that is
+ * sensible for the DSO method in question.  The only rule that really
+ * applies is that if the two specification contain pieces of the same
+ * type, the copy from the string string takes priority.  One could see
+ * it as the first specification is the one given by the user and the
+ * second being a bunch of defaults to add on if they're missing in the
+ * first. */
+typedef char* (*DSO_MERGER_FUNC)(DSO *, const char *, const char *);
 
 typedef struct dso_meth_st
        {
@@ -140,6 +156,9 @@ typedef struct dso_meth_st
        /* The default DSO_METHOD-specific function for converting filenames to
         * a canonical native form. */
        DSO_NAME_CONVERTER_FUNC dso_name_converter;
+       /* The default DSO_METHOD-specific function for converting filenames to
+        * a canonical native form. */
+       DSO_MERGER_FUNC dso_merger;
 
        /* [De]Initialisation handlers. */
        int (*init)(DSO *dso);
@@ -164,9 +183,13 @@ struct dso_st
         * don't touch meth_data! */
        CRYPTO_EX_DATA ex_data;
        /* If this callback function pointer is set to non-NULL, then it will
-        * be used on DSO_load() in place of meth->dso_name_converter. NB: This
+        * be used in DSO_load() in place of meth->dso_name_converter. NB: This
         * should normally set using DSO_set_name_converter(). */
        DSO_NAME_CONVERTER_FUNC name_converter;
+       /* If this callback function pointer is set to non-NULL, then it will
+        * be used in DSO_load() in place of meth->dso_merger. NB: This
+        * should normally set using DSO_set_merger(). */
+       DSO_MERGER_FUNC merger;
        /* This is populated with (a copy of) the platform-independant
         * filename used for this DSO. */
        char *filename;
@@ -209,6 +232,11 @@ int        DSO_set_filename(DSO *dso, const char *filename);
  * caller-created DSO_METHODs can do the same thing. A non-NULL return value
  * will need to be OPENSSL_free()'d. */
 char   *DSO_convert_filename(DSO *dso, const char *filename);
+/* This function will invoke the DSO's merger callback to merge two file
+ * specifications, or if the callback isn't set it will instead use the
+ * DSO_METHOD's merger.  A non-NULL return value will need to be
+ * OPENSSL_free()'d. */
+char   *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2);
 /* If the DSO is currently loaded, this returns the filename that it was loaded
  * under, otherwise it returns NULL. So it is also useful as a test as to
  * whether the DSO is currently loaded. NB: This will not necessarily return
@@ -273,11 +301,13 @@ void ERR_load_DSO_strings(void);
 #define DSO_F_DLFCN_BIND_FUNC                           100
 #define DSO_F_DLFCN_BIND_VAR                            101
 #define DSO_F_DLFCN_LOAD                                102
+#define DSO_F_DLFCN_MERGER                              130
 #define DSO_F_DLFCN_NAME_CONVERTER                      123
 #define DSO_F_DLFCN_UNLOAD                              103
 #define DSO_F_DL_BIND_FUNC                              104
 #define DSO_F_DL_BIND_VAR                               105
 #define DSO_F_DL_LOAD                                   106
+#define DSO_F_DL_MERGER                                         131
 #define DSO_F_DL_NAME_CONVERTER                                 124
 #define DSO_F_DL_UNLOAD                                         107
 #define DSO_F_DSO_BIND_FUNC                             108
@@ -288,24 +318,30 @@ void ERR_load_DSO_strings(void);
 #define DSO_F_DSO_GET_FILENAME                          127
 #define DSO_F_DSO_GET_LOADED_FILENAME                   128
 #define DSO_F_DSO_LOAD                                  112
+#define DSO_F_DSO_MERGE                                         132
 #define DSO_F_DSO_NEW_METHOD                            113
 #define DSO_F_DSO_SET_FILENAME                          129
 #define DSO_F_DSO_SET_NAME_CONVERTER                    122
 #define DSO_F_DSO_UP_REF                                114
 #define DSO_F_VMS_BIND_VAR                              115
 #define DSO_F_VMS_LOAD                                  116
+#define DSO_F_VMS_MERGER                                133
 #define DSO_F_VMS_UNLOAD                                117
 #define DSO_F_WIN32_BIND_FUNC                           118
 #define DSO_F_WIN32_BIND_VAR                            119
 #define DSO_F_WIN32_LOAD                                120
+#define DSO_F_WIN32_MERGER                              134
 #define DSO_F_WIN32_NAME_CONVERTER                      125
 #define DSO_F_WIN32_UNLOAD                              121
 
 /* Reason codes. */
 #define DSO_R_CTRL_FAILED                               100
 #define DSO_R_DSO_ALREADY_LOADED                        110
+#define DSO_R_EMPTY_FILE_STRUCTURE                      113
+#define DSO_R_FAILURE                                   114
 #define DSO_R_FILENAME_TOO_BIG                          101
 #define DSO_R_FINISH_FAILED                             102
+#define DSO_R_INCORRECT_FILE_SYNTAX                     115
 #define DSO_R_LOAD_FAILED                               103
 #define DSO_R_NAME_TRANSLATION_FAILED                   109
 #define DSO_R_NO_FILENAME                               111
index 195717e..32a8d41 100644 (file)
@@ -1,4 +1,4 @@
-/* dso_dl.c */
+/* dso_dl.c -*- mode:C; c-file-style: "eay" -*- */
 /* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
  * project 2000.
  */
@@ -84,6 +84,7 @@ static int dl_finish(DSO *dso);
 static int dl_ctrl(DSO *dso, int cmd, long larg, void *parg);
 #endif
 static char *dl_name_converter(DSO *dso, const char *filename);
+static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2);
 
 static DSO_METHOD dso_meth_dl = {
        "OpenSSL 'dl' shared library method",
@@ -98,6 +99,7 @@ static DSO_METHOD dso_meth_dl = {
 #endif
        NULL, /* ctrl */
        dl_name_converter,
+       dl_merger,
        NULL, /* init */
        NULL  /* finish */
        };
@@ -238,6 +240,72 @@ static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname)
        return((DSO_FUNC_TYPE)sym);
        }
 
+static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2)
+       {
+       char *merged;
+
+       if(!filespec1 && !filespec2)
+               {
+               DSOerr(DSO_F_DL_MERGER,
+                               ERR_R_PASSED_NULL_PARAMETER);
+               return(NULL);
+               }
+       /* If the first file specification is a rooted path, it rules.
+          same goes if the second file specification is missing. */
+       if (!filespec2 || filespec1[0] == '/')
+               {
+               merged = OPENSSL_malloc(strlen(filespec1) + 1);
+               if(!merged)
+                       {
+                       DSOerr(DSO_F_DL_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               strcpy(merged, filespec1);
+               }
+       /* If the first file specification is missing, the second one rules. */
+       else if (!filespec1)
+               {
+               merged = OPENSSL_malloc(strlen(filespec2) + 1);
+               if(!merged)
+                       {
+                       DSOerr(DSO_F_DL_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               strcpy(merged, filespec2);
+               }
+       else
+               /* This part isn't as trivial as it looks.  It assumes that
+                  the second file specification really is a directory, and
+                  makes no checks whatsoever.  Therefore, the result becomes
+                  the concatenation of filespec2 followed by a slash followed
+                  by filespec1. */
+               {
+               int spec2len, len;
+
+               spec2len = (filespec2 ? strlen(filespec2) : 0);
+               len = spec2len + (filespec1 ? strlen(filespec1) : 0);
+
+               if(filespec2 && filespec2[spec2len - 1] == '/')
+                       {
+                       spec2len--;
+                       len--;
+                       }
+               merged = OPENSSL_malloc(len + 2);
+               if(!merged)
+                       {
+                       DSOerr(DSO_F_DL_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               strcpy(merged, filespec2);
+               merged[spec2len] = '/';
+               strcpy(&merged[spec2len + 1], filespec1);
+               }
+       return(merged);
+       }
+
 /* This function is identical to the one in dso_dlfcn.c, but as it is highly
  * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at the
  * same time, there's no great duplicating the code. Figuring out an elegant 
index 906b470..de88b2f 100644 (file)
@@ -1,4 +1,4 @@
-/* dso_dlfcn.c */
+/* dso_dlfcn.c -*- mode:C; c-file-style: "eay" -*- */
 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
  * project 2000.
  */
@@ -85,6 +85,8 @@ static int dlfcn_finish(DSO *dso);
 static long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg);
 #endif
 static char *dlfcn_name_converter(DSO *dso, const char *filename);
+static char *dlfcn_merger(DSO *dso, const char *filespec1,
+       const char *filespec2);
 
 static DSO_METHOD dso_meth_dlfcn = {
        "OpenSSL 'dlfcn' shared library method",
@@ -99,6 +101,7 @@ static DSO_METHOD dso_meth_dlfcn = {
 #endif
        NULL, /* ctrl */
        dlfcn_name_converter,
+       dlfcn_merger,
        NULL, /* init */
        NULL  /* finish */
        };
@@ -252,6 +255,73 @@ static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
        return(sym);
        }
 
+static char *dlfcn_merger(DSO *dso, const char *filespec1,
+       const char *filespec2)
+       {
+       char *merged;
+
+       if(!filespec1 && !filespec2)
+               {
+               DSOerr(DSO_F_DLFCN_MERGER,
+                               ERR_R_PASSED_NULL_PARAMETER);
+               return(NULL);
+               }
+       /* If the first file specification is a rooted path, it rules.
+          same goes if the second file specification is missing. */
+       if (!filespec2 || filespec1[0] == '/')
+               {
+               merged = OPENSSL_malloc(strlen(filespec1) + 1);
+               if(!merged)
+                       {
+                       DSOerr(DSO_F_DLFCN_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               strcpy(merged, filespec1);
+               }
+       /* If the first file specification is missing, the second one rules. */
+       else if (!filespec1)
+               {
+               merged = OPENSSL_malloc(strlen(filespec2) + 1);
+               if(!merged)
+                       {
+                       DSOerr(DSO_F_DLFCN_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               strcpy(merged, filespec2);
+               }
+       else
+               /* This part isn't as trivial as it looks.  It assumes that
+                  the second file specification really is a directory, and
+                  makes no checks whatsoever.  Therefore, the result becomes
+                  the concatenation of filespec2 followed by a slash followed
+                  by filespec1. */
+               {
+               int spec2len, len;
+
+               spec2len = (filespec2 ? strlen(filespec2) : 0);
+               len = spec2len + (filespec1 ? strlen(filespec1) : 0);
+
+               if(filespec2 && filespec2[spec2len - 1] == '/')
+                       {
+                       spec2len--;
+                       len--;
+                       }
+               merged = OPENSSL_malloc(len + 2);
+               if(!merged)
+                       {
+                       DSOerr(DSO_F_DLFCN_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               strcpy(merged, filespec2);
+               merged[spec2len] = '/';
+               strcpy(&merged[spec2len + 1], filespec1);
+               }
+       return(merged);
+       }
+
 static char *dlfcn_name_converter(DSO *dso, const char *filename)
        {
        char *translated;
index cf452de..23ccfc0 100644 (file)
@@ -1,6 +1,6 @@
 /* crypto/dso/dso_err.c */
 /* ====================================================================
- * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2002 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -69,11 +69,13 @@ static ERR_STRING_DATA DSO_str_functs[]=
 {ERR_PACK(0,DSO_F_DLFCN_BIND_FUNC,0),  "DLFCN_BIND_FUNC"},
 {ERR_PACK(0,DSO_F_DLFCN_BIND_VAR,0),   "DLFCN_BIND_VAR"},
 {ERR_PACK(0,DSO_F_DLFCN_LOAD,0),       "DLFCN_LOAD"},
+{ERR_PACK(0,DSO_F_DLFCN_MERGER,0),     "DLFCN_MERGER"},
 {ERR_PACK(0,DSO_F_DLFCN_NAME_CONVERTER,0),     "DLFCN_NAME_CONVERTER"},
 {ERR_PACK(0,DSO_F_DLFCN_UNLOAD,0),     "DLFCN_UNLOAD"},
 {ERR_PACK(0,DSO_F_DL_BIND_FUNC,0),     "DL_BIND_FUNC"},
 {ERR_PACK(0,DSO_F_DL_BIND_VAR,0),      "DL_BIND_VAR"},
 {ERR_PACK(0,DSO_F_DL_LOAD,0),  "DL_LOAD"},
+{ERR_PACK(0,DSO_F_DL_MERGER,0),        "DL_MERGER"},
 {ERR_PACK(0,DSO_F_DL_NAME_CONVERTER,0),        "DL_NAME_CONVERTER"},
 {ERR_PACK(0,DSO_F_DL_UNLOAD,0),        "DL_UNLOAD"},
 {ERR_PACK(0,DSO_F_DSO_BIND_FUNC,0),    "DSO_bind_func"},
@@ -84,16 +86,19 @@ static ERR_STRING_DATA DSO_str_functs[]=
 {ERR_PACK(0,DSO_F_DSO_GET_FILENAME,0), "DSO_get_filename"},
 {ERR_PACK(0,DSO_F_DSO_GET_LOADED_FILENAME,0),  "DSO_get_loaded_filename"},
 {ERR_PACK(0,DSO_F_DSO_LOAD,0), "DSO_load"},
+{ERR_PACK(0,DSO_F_DSO_MERGE,0),        "DSO_merge"},
 {ERR_PACK(0,DSO_F_DSO_NEW_METHOD,0),   "DSO_new_method"},
 {ERR_PACK(0,DSO_F_DSO_SET_FILENAME,0), "DSO_set_filename"},
 {ERR_PACK(0,DSO_F_DSO_SET_NAME_CONVERTER,0),   "DSO_set_name_converter"},
 {ERR_PACK(0,DSO_F_DSO_UP_REF,0),       "DSO_up_ref"},
 {ERR_PACK(0,DSO_F_VMS_BIND_VAR,0),     "VMS_BIND_VAR"},
 {ERR_PACK(0,DSO_F_VMS_LOAD,0), "VMS_LOAD"},
+{ERR_PACK(0,DSO_F_VMS_MERGER,0),       "VMS_MERGER"},
 {ERR_PACK(0,DSO_F_VMS_UNLOAD,0),       "VMS_UNLOAD"},
 {ERR_PACK(0,DSO_F_WIN32_BIND_FUNC,0),  "WIN32_BIND_FUNC"},
 {ERR_PACK(0,DSO_F_WIN32_BIND_VAR,0),   "WIN32_BIND_VAR"},
 {ERR_PACK(0,DSO_F_WIN32_LOAD,0),       "WIN32_LOAD"},
+{ERR_PACK(0,DSO_F_WIN32_MERGER,0),     "WIN32_MERGER"},
 {ERR_PACK(0,DSO_F_WIN32_NAME_CONVERTER,0),     "WIN32_NAME_CONVERTER"},
 {ERR_PACK(0,DSO_F_WIN32_UNLOAD,0),     "WIN32_UNLOAD"},
 {0,NULL}
@@ -103,8 +108,11 @@ static ERR_STRING_DATA DSO_str_reasons[]=
        {
 {DSO_R_CTRL_FAILED                       ,"control command failed"},
 {DSO_R_DSO_ALREADY_LOADED                ,"dso already loaded"},
+{DSO_R_EMPTY_FILE_STRUCTURE              ,"empty file structure"},
+{DSO_R_FAILURE                           ,"failure"},
 {DSO_R_FILENAME_TOO_BIG                  ,"filename too big"},
 {DSO_R_FINISH_FAILED                     ,"cleanup method function failed"},
+{DSO_R_INCORRECT_FILE_SYNTAX             ,"incorrect file syntax"},
 {DSO_R_LOAD_FAILED                       ,"could not load the shared library"},
 {DSO_R_NAME_TRANSLATION_FAILED           ,"name translation failed"},
 {DSO_R_NO_FILENAME                       ,"no filename"},
index 556069b..e7ddfd5 100644 (file)
@@ -1,4 +1,4 @@
-/* dso_lib.c */
+/* dso_lib.c -*- mode:C; c-file-style: "eay" -*- */
 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
  * project 2000.
  */
@@ -390,6 +390,33 @@ int DSO_set_filename(DSO *dso, const char *filename)
        return(1);
        }
 
+char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
+       {
+       char *result = NULL;
+
+       if(dso == NULL || dir == NULL)
+               {
+               DSOerr(DSO_F_DSO_MERGE,ERR_R_PASSED_NULL_PARAMETER);
+               return(NULL);
+               }
+       if(filespec1 == NULL)
+               filespec1 = dso->filename;
+       if(filespec1 == NULL)
+               {
+               DSOerr(DSO_F_DSO_MERGE,DSO_R_NO_FILENAME);
+               return(NULL);
+               }
+       if((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0)
+               {
+               if(dso->merger != NULL)
+                       result = dso->merger(dso, filespec1, filespec2);
+               else if(dso->meth->dso_merger != NULL)
+                       result = dso->meth->dso_merger(dso,
+                               filespec1, filespec2);
+               }
+       return(result);
+       }
+
 char *DSO_convert_filename(DSO *dso, const char *filename)
        {
        char *result = NULL;
index 1674619..696e1cc 100644 (file)
@@ -1,4 +1,4 @@
-/* dso_vms.c */
+/* dso_vms.c -*- mode:C; c-file-style: "eay" -*- */
 /* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
  * project 2000.
  */
@@ -63,6 +63,7 @@
 #include <openssl/dso.h>
 #ifdef OPENSSL_SYS_VMS
 #pragma message disable DOLLARID
+#include <rms.h>
 #include <lib$routines.h>
 #include <stsdef.h>
 #include <descrip.h>
@@ -89,6 +90,8 @@ static int vms_finish(DSO *dso);
 static long vms_ctrl(DSO *dso, int cmd, long larg, void *parg);
 #endif
 static char *vms_name_converter(DSO *dso, const char *filename);
+static char *vms_merger(DSO *dso, const char *filespec1,
+       const char *filespec2);
 
 static DSO_METHOD dso_meth_vms = {
        "OpenSSL 'VMS' shared library method",
@@ -103,6 +106,7 @@ static DSO_METHOD dso_meth_vms = {
 #endif
        NULL, /* ctrl */
        vms_name_converter,
+       vms_merger,
        NULL, /* init */
        NULL  /* finish */
        };
@@ -368,6 +372,128 @@ static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname)
        return sym;
        }
 
+static char *vms_merger(DSO *dso, const char *filespec1, const char *filespec2)
+       {
+       int status;
+       int filespec1len, filespec2len;
+       struct FAB fab;
+#ifdef NAML$C_MAXRSS
+       struct NAML nam;
+       char esa[NAML$C_MAXRSS];
+#else
+       struct NAM nam;
+       char esa[NAM$C_MAXRSS];
+#endif
+       char *merged;
+
+       if (!filespec1) filespec1 = "";
+       if (!filespec2) filespec2 = "";
+       filespec1len = strlen(filespec1);
+       filespec2len = strlen(filespec2);
+
+       fab = cc$rms_fab;
+#ifdef NAML$C_MAXRSS
+       nam = cc$rms_naml;
+#else
+       nam = cc$rms_nam;
+#endif
+
+       fab.fab$l_fna = filespec1;
+       fab.fab$b_fns = filespec1len;
+       fab.fab$l_dna = filespec2;
+       fab.fab$b_dns = filespec2len;
+#ifdef NAML$C_MAXRSS
+       if (filespec1len > NAM$C_MAXRSS)
+               {
+               fab.fab$l_fna = -1;
+               fab.fab$b_fns = 0;
+               nam.naml$l_long_filename = filespec1;
+               nam.naml$l_long_filename_size = filespec1len;
+               }
+       if (filespec2len > NAM$C_MAXRSS)
+               {
+               fab.fab$l_dna = -1;
+               fab.fab$b_dns = 0;
+               nam.naml$l_long_defname = filespec2;
+               nam.naml$l_long_defname_size = filespec2len;
+               }
+       nam.naml$l_esa = esa;
+       nam.naml$b_ess = NAM$C_MAXRSS;
+       nam.naml$l_long_expand = esa;
+       nam.naml$l_long_expand_alloc = sizeof(esa);
+       nam.naml$b_nop = NAM$M_SYNCHK | NAM$M_PWD;
+       nam.naml$v_no_short_updase = 1;
+#else
+       nam.nam$l_esa = esa;
+       nam.nam$b_ess = NAM$C_MAXRSS;
+       nam.nam$b_nop = NAM$M_SYNCHK | NAM$M_PWD;
+#endif
+       fab.fab$l_nam = &nam;
+
+       status = sys$parse(&fab, 0, 0);
+
+       if(!$VMS_STATUS_SUCCESS(status))
+               {
+               unsigned short length;
+               char errstring[257];
+               struct dsc$descriptor_s errstring_dsc;
+
+               errstring_dsc.dsc$w_length = sizeof(errstring);
+               errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+               errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
+               errstring_dsc.dsc$a_pointer = errstring;
+
+               *sym = NULL;
+
+               status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
+
+               if (!$VMS_STATUS_SUCCESS(status))
+                       lib$signal(status); /* This is really bad.  Abort!  */
+               else
+                       {
+                       errstring[length] = '\0';
+
+                       DSOerr(DSO_F_VMS_MERGER,DSO_R_FAILURE);
+                       ERR_add_error_data(9,
+                               "filespec \"", filespec1, "\", ",
+                               "defaults \"", filespec2, "\": "
+                               errstring);
+                       }
+               return(NULL);
+               }
+#ifdef NAML$C_MAXRSS
+       if (nam.naml$l_long_expand_size)
+               {
+               merged = OPENSSL_malloc(nam.naml$l_long_expand_size + 1);
+               if(!merged)
+                       goto malloc_err;
+               strncpy(merged, nam.naml$l_long_expand,
+                       nam.naml$l_long_expand_size);
+               merged[nam.naml$l_long_expand_size] = '\0';
+               }
+       else
+               {
+               merged = OPENSSL_malloc(nam.naml$l_esl + 1);
+               if(!merged)
+                       goto malloc_err;
+               strncpy(merged, nam.naml$l_esa,
+                       nam.naml$l_esl);
+               merged[nam.naml$l_esl] = '\0';
+               }
+#else
+       merged = OPENSSL_malloc(nam.nam$l_esl + 1);
+       if(!merged)
+               goto malloc_err;
+       strncpy(merged, nam.nam$l_esa,
+               nam.nam$l_esl);
+       merged[nam.nam$l_esl] = '\0';
+#endif
+       return(merged);
+ malloc_err:
+       DSOerr(DSO_F_VMS_MERGER,
+               ERR_R_MALLOC_FAILURE);
+       }
+
 static char *vms_name_converter(DSO *dso, const char *filename)
        {
         int len = strlen(filename);
index af8586d..4ce9a5d 100644 (file)
@@ -1,4 +1,4 @@
-/* dso_win32.c */
+/* dso_win32.c -*- mode:C; c-file-style: "eay" -*- */
 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
  * project 2000.
  */
@@ -83,6 +83,8 @@ static int win32_finish(DSO *dso);
 static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg);
 #endif
 static char *win32_name_converter(DSO *dso, const char *filename);
+static char *win32_merger(DSO *dso, const char *filespec1,
+       const char *filespec2);
 
 static DSO_METHOD dso_meth_win32 = {
        "OpenSSL 'win32' shared library method",
@@ -97,6 +99,7 @@ static DSO_METHOD dso_meth_win32 = {
 #endif
        NULL, /* ctrl */
        win32_name_converter,
+       win32_merger,
        NULL, /* init */
        NULL  /* finish */
        };
@@ -248,6 +251,304 @@ static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname)
        return((DSO_FUNC_TYPE)sym);
        }
 
+struct file_st
+       {
+       const char *node; int nodelen;
+       const char *device; int devicelen;
+       const char *predir; int predirlen;
+       const char *dir; int dirlen;
+       const char *file; int filelen;
+       }
+
+static struct file_st *win32_splitter(DSO *dso, const char *filename,
+       int assume_last_is_dir)
+       {
+       struct file_st *result = NULL;
+       enum { IN_NODE, IN_DEVICE, IN_FILE } position;
+       const char *start = filename;
+
+       if (!filename)
+               {
+               DSOerr(DSO_F_WIN32_MERGER,DSO_R_NO_FILENAME);
+               goto err;
+               }
+
+       result = OPENSSL_malloc(sizeof(struct file_st));
+       if(result == NULL)
+               {
+               DSOerr(DSO_F_WIN32_MERGER,
+                       ERR_R_MALLOC_FAILURE);
+               return(NULL);
+               }
+
+       memset(result, 0, sizeof(struct file_st));
+       position = IN_DEVICE;
+
+       if(filename[0] == '\\' && filename[1] == '\\'
+               || filename[0] == '/' && filename[1] == '/')
+               {
+               position = IN_NODE;
+               filename += 2;
+               start = filename;
+               result->node = start;
+               }
+
+       do
+               {
+               switch(filename[0])
+                       {
+               case ':':
+                       if(position != IN_DEVICE)
+                               {
+                               DSOerr(DSO_F_WIN32_MERGER,
+                                       DSO_R_INCORRECT_FILE_SYNTAX);
+                               goto err;
+                               }
+                       result->device = start;
+                       result->devicelen = filename - start;
+                       position = IN_FILE;
+                       start = ++filename;
+                       result->dir = start;
+                       break;
+               case '\\':
+               case '/':
+                       if(position == IN_NODE)
+                               {
+                               result->nodelen = filename - start;
+                               position = IN_FILE;
+                               start = ++filename;
+                               result->dir = start;
+                               }
+                       else
+                               {
+                               filename++;
+                               result->dirlen += filename - start;
+                               }
+                       break;
+               case '\0':
+                       if(position == IN_NODE)
+                               {
+                               result->nodelen = filename - start;
+                               }
+                       else
+                               {
+                               if(filename - start > 0)
+                                       {
+                                       if (assume_last_is_dir)
+                                               {
+                                               result->devicelen += filename - start;
+                                               }
+                                       else
+                                               {
+                                               result->file = start;
+                                               result->filelen = filename - start;
+                                               }
+                                       }
+                               }
+                       break;
+               default:
+                       filename++;
+                       break;
+                       }
+               }
+       while(*filename);
+
+       if(!result->nodelen) result->node = NULL;
+       if(!result->devicelen) result->devicce = NULL;
+       if(!result->dirlen) result->dir = NULL;
+       if(!result->filelen) result->file = NULL;
+
+       return(result);
+       }
+
+static char *win32_joiner(DSO *dso, const file_st *file_split)
+       {
+       int len = 0, offset = 0;
+       char *result = NULL;
+       const char *start;
+
+       if(!file_split)
+               {
+               DSOerr(DSO_F_WIN32_MERGER,
+                               ERR_R_PASSED_NULL_PARAMETER);
+               return(NULL);
+               }
+       if(file_split->node)
+               {
+               len += 2 + file_split->nodelen; /* 2 for starting \\ */
+               if(file_split->predir || file_split->dir || file_split->file)
+                       len++;  /* 1 for ending \ */
+               }
+       else if(file_split->device)
+               {
+               len += file_split->devicelen + 1; /* 1 for ending : */
+               }
+       len += file_split->predirlen;
+       if(file_split->predir && (file_split->dir || file_split->file))
+               {
+               len++;  /* 1 for ending \ */
+               }
+       len += file_split->dirlen;
+       if(file_split->dir && file_split->file)
+               {
+               len++;  /* 1 for ending \ */
+               }
+       len += file_split->filelen;
+
+       if(!len)
+               {
+               DSOerr(DSO_F_WIN32_MERGER, DSO_R_EMPTY_FILE_STRUCTURE);
+               return(NULL);
+               }
+
+       result = OPENSSL_malloc(len + 1);
+       if (!result)
+               {
+               DSOerr(DSO_F_WIN32_MERGER,
+                       ERR_R_MALLOC_FAILURE);
+               return(NULL);
+               }
+
+       if(file_split->node)
+               {
+               strcpy(&result[offset], "\\\\"); offset += 2;
+               strncpy(&result[offset], file_split->node,
+                       file_split->nodelen); offset += file_split->nodelen;
+               if(file_split->predir || file_split->dir || file_split->file)
+                       {
+                       result[offset] = '\\'; offset++;
+                       }
+               }
+       else if(file_split->device)
+               {
+               strncpy(&result[offset], file_split->device,
+                       file_split->devicelen); offset += file_split->devicelen;
+               result[offset] = ':'; offset++;
+               }
+       start = file_split->predir;
+       while(file_split->predirlen > (start - file_split->predir))
+               {
+               const char *end = strnchr(start, '/',
+                       file_split->predirlen - (start - file_split->predir));
+               if(!end)
+                       end = start
+                               + file_split->predirlen
+                               - (start - file_split->predir);
+               strncpy(&result[offset], start,
+                       end - start); offset += end - start;
+               result[offset] = '\\'; offset++;
+               start = end + 1;
+               }
+       if(file_split->predir && (file_split->dir || file_split->file))
+               {
+               result[offset] = '\\'; offset++;
+               }
+       start = file_split->dir;
+       while(file_split->dirlen > (start - file_split->dir))
+               {
+               const char *end = strnchr(start, '/',
+                       file_split->dirlen - (start - file_split->dir));
+               if(!end)
+                       end = start
+                               + file_split->dirlen
+                               - (start - file_split->dir);
+               strncpy(&result[offset], start,
+                       end - start); offset += end - start;
+               result[offset] = '\\'; offset++;
+               start = end + 1;
+               }
+       if(file_split->dir && file_split->file)
+               {
+               result[offset] = '\\'; offset++;
+               }
+       strncpy(&result[offset], file_split->file,
+               file_split->filelen); offset += file_split->filelen;
+       result[offset] = '\0';
+       return(result);
+       }
+
+static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2)
+       {
+       char *merged = NULL;
+       struct file_st *filespec1_split = NULL;
+       struct file_st *filespec2_split = NULL;
+
+       if(!filespec1 && !filespec2)
+               {
+               DSOerr(DSO_F_WIN32_MERGER,
+                               ERR_R_PASSED_NULL_PARAMETER);
+               return(NULL);
+               }
+       if (!filespec2)
+               {
+               merged = OPENSSL_malloc(strlen(filespec1) + 1);
+               if(!merged)
+                       {
+                       DSOerr(DSO_F_WIN32_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               strcpy(merged, filespec1);
+               }
+       else if (!filespec1)
+               {
+               merged = OPENSSL_malloc(strlen(filespec2) + 1);
+               if(!merged)
+                       {
+                       DSOerr(DSO_F_WIN32_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               strcpy(merged, filespec2);
+               }
+       else
+               {
+               filespec1_split = win32_splitter(dso, filespec1, 1);
+               if (!filespec1_split)
+                       {
+                       DSOerr(DSO_F_WIN32_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       return(NULL);
+                       }
+               filespec2_split = win32_splitter(dso, filespec2, 0);
+               if (!filespec1_split)
+                       {
+                       DSOerr(DSO_F_WIN32_MERGER,
+                               ERR_R_MALLOC_FAILURE);
+                       OPENSSL_free(filespec1_split);
+                       return(NULL);
+                       }
+
+               /* Fill in into filespec1_split */
+               if (!filespec1_split->node && !filespec1_split->device)
+                       {
+                       filespec1_split->node = filespec2_split->node;
+                       filespec1_split->nodelen = filespec2_split->nodelen;
+                       filespec1_split->device = filespec2_split->device;
+                       filespec1_split->devicelen = filespec2_split->devicelen;
+                       }
+               if (!filespec1_split->dir)
+                       {
+                       filespec1_split->dir = filespec2_split->dir;
+                       filespec1_split->dirlen = filespec2_split->dirlen;
+                       }
+               else if (filespec1_split->dir[0] != '\\'
+                       && filespec1_split->dir[0] != '/')
+                       {
+                       filespec1_split->predir = filespec2_split->dir;
+                       filespec1_split->predirlen = filespec2_split->dirlen;
+                       }
+               if (!filespec1_split->file)
+                       {
+                       filespec1_split->file = filespec2_split->file;
+                       filespec1_split->filelen = filespec2_split->filelen;
+                       }
+
+               merged = win32_joiner(dso, filespec1_split);
+               }
+       return(merged);
+       }
+
 static char *win32_name_converter(DSO *dso, const char *filename)
        {
        char *translated;