Adjust LPdir_unix.c on VMS for OpenSSL expectations
authorRichard Levitte <levitte@openssl.org>
Sun, 11 Mar 2018 22:48:04 +0000 (23:48 +0100)
committerRichard Levitte <levitte@openssl.org>
Mon, 12 Mar 2018 22:01:02 +0000 (23:01 +0100)
When OPENSSL_DIR_read implemented by LPdir_unix.c gets a Unixy path,
it will return file names like you'd expect them on Unix.

However, if given a path with VMS syntax, such as "[.foo]", it returns
file names with generation numbers, such as "bar.txt;1", which makes
sense for VMS expectations, but can be surprising for OpenSSL.

Our solution is to simply shave off the generation number if
OPENSSL_DIR_read() expects there should be one, and make sure not to
return the same file name twice.  Note that VMS filesystems are case
insensitive, so the check for duplicate file names are done without
regard to character case.

Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5587)

crypto/LPdir_unix.c

index 6648a60..356089d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -11,7 +11,7 @@
  * This file is dual-licensed and is also available under the following
  * terms:
  *
- * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
+ * Copyright (c) 2004, 2018, Richard Levitte <richard@levitte.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,6 +46,9 @@
 #ifndef LPDIR_H
 # include "LPdir.h"
 #endif
+#ifdef __VMS
+# include <ctype.h>
+#endif
 
 /*
  * The POSIXly macro for the maximum number of characters in a file path is
 struct LP_dir_context_st {
     DIR *dir;
     char entry_name[LP_ENTRY_SIZE + 1];
+#ifdef __VMS
+    int expect_file_generations;
+    char previous_entry_name[LP_ENTRY_SIZE + 1];
+#endif
 };
 
 const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
@@ -93,6 +100,15 @@ const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
         }
         memset(*ctx, 0, sizeof(**ctx));
 
+#ifdef __VMS
+        {
+            char c = directory[strlen(directory) - 1];
+
+            if (c == ']' || c == '>' || c == ':')
+                (*ctx)->expect_file_generations = 1;
+        }
+#endif
+
         (*ctx)->dir = opendir(directory);
         if ((*ctx)->dir == NULL) {
             int save_errno = errno; /* Probably not needed, but I'm paranoid */
@@ -103,6 +119,13 @@ const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
         }
     }
 
+#ifdef __VMS
+    strncpy((*ctx)->previous_entry_name, (*ctx)->entry_name,
+            sizeof((*ctx)->previous_entry_name));
+
+ again:
+#endif
+
     direntry = readdir((*ctx)->dir);
     if (direntry == NULL) {
         return 0;
@@ -111,6 +134,18 @@ const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
     strncpy((*ctx)->entry_name, direntry->d_name,
             sizeof((*ctx)->entry_name) - 1);
     (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
+#ifdef __VMS
+    if ((*ctx)->expect_file_generations) {
+        char *p = (*ctx)->entry_name + strlen((*ctx)->entry_name);
+
+        while(p > (*ctx)->entry_name && isdigit(p[-1]))
+            p--;
+        if (p > (*ctx)->entry_name && p[-1] == ';')
+            p[-1] = '\0';
+        if (strcasecmp((*ctx)->entry_name, (*ctx)->previous_entry_name) == 0)
+            goto again;
+    }
+#endif
     return (*ctx)->entry_name;
 }