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: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5587)
This commit is contained in:
Richard Levitte 2018-03-11 23:48:04 +01:00
parent 86a227ee1b
commit a5829ae282

View 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
@ -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;
}