Commit a5829ae2 authored by Richard Levitte's avatar Richard Levitte
Browse files

Adjust LPdir_unix.c on VMS for OpenSSL expectations



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: default avatarTim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5587)
parent 86a227ee
Loading
Loading
Loading
Loading
+37 −2
Original line number Diff line number Diff line
/*
 * 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
@@ -73,6 +76,10 @@
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;
}