Skip to content

Commit

Permalink
Improved version of mkdtemp() that support ebcdic (#40)
Browse files Browse the repository at this point in the history
* add mkdtemp()

* ignore build.cache

* add test case and make stdlib.h work for ebcdic too

* getenv replacement is for ascii only

* remove zos-mkdtemp.cc

* fix a bug & add comments
  • Loading branch information
perry-ca authored Jan 2, 2024
1 parent b3bd321 commit 18af824
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 37 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ test/cctest_a
# Build artifacts
*.a
install/
build.cache
build/
zoslib.xml
zoslib_a.xml

38 changes: 32 additions & 6 deletions include/stdlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
#define __XPLAT 1
#include "zos-macros.h"


#if defined(__cplusplus)
extern "C" {
#endif
__Z_EXPORT char *__realpath_extended(const char * __restrict__, char * __restrict__);
#ifdef __NATIVE_ASCII_F
__Z_EXPORT int __mkstemp_ascii(char*);
#endif
#if defined(__cplusplus)
}
#endif
Expand All @@ -29,16 +32,15 @@ __Z_EXPORT int __mkstemp_ascii(char*);
#define mkstemp __mkstemp_replaced
#endif

#if defined(ZOSLIB_OVERRIDE_CLIB_GETENV)
#if defined(ZOSLIB_OVERRIDE_CLIB_GETENV) && defined(__NATIVE_ASCII_F)
#undef getenv
#define getenv __getenv_replaced
#endif


#include_next <stdlib.h>

#if defined(ZOSLIB_OVERRIDE_CLIB) || defined(ZOSLIB_OVERRIDE_CLIB_STDLIB)
#undef mkstemp
#undef realpath

#if defined(__cplusplus)
extern "C" {
Expand All @@ -47,17 +49,23 @@ extern "C" {
/**
* Same as original realpath, but this allocates a buffer if second parm is NULL as defined in Posix.1-2008
*/
#undef realpath
__Z_EXPORT char *realpath(const char * __restrict__, char * __restrict__) __asm("__realpath_extended");

#ifdef __NATIVE_ASCII_F
/**
* Same as C mkstemp but tags fd as ASCII (819)
*/
#undef mkstemp
__Z_EXPORT int mkstemp(char*) __asm("__mkstemp_ascii");
#endif /* __NATIVE_ASCII_F */

#if defined(__cplusplus)
}
#endif
#endif
#endif /* defined(ZOSLIB_OVERRIDE_CLIB) || defined(ZOSLIB_OVERRIDE_CLIB_STDLIB) */

#if defined(ZOSLIB_OVERRIDE_CLIB_GETENV)
#if defined(ZOSLIB_OVERRIDE_CLIB_GETENV) && defined(__NATIVE_ASCII_F)
#undef getenv

#if defined(__cplusplus)
Expand All @@ -80,11 +88,29 @@ extern "C" {
/**
* C Lib functions that do not conflict with z/OS LE
*/
__Z_EXPORT char *mkdtemp(char *templ);
__Z_EXPORT int getloadavg(double loadavg[], int nelem);
__Z_EXPORT const char * getprogname(void);
#if defined(__cplusplus)
}
#endif

#if defined(__cplusplus)
extern "C" {
#endif

__Z_EXPORT char *mkdtemp(char *);
#ifdef __NATIVE_ASCII_F
__Z_EXPORT char *mkdtemp(char *) asm("__mkdtemp_a");
#ifdef __AE_BIMODAL_F
__Z_EXPORT char *__mkdtemp_a(char *);
__Z_EXPORT char *__mkdtemp_e(char *);
#endif
#else
__Z_EXPORT char *mkdtemp(char *) asm("__mkdtemp_e");
#endif

#if defined(__cplusplus)
}
#endif

#endif
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ set(libsrc
zos-tls.cc
zos.cc
zos-mount.c
zos-mkdtemp.c
)
set(zoslib-help zoslib-help.cc)

Expand Down
31 changes: 0 additions & 31 deletions src/zos-io.cc
Original file line number Diff line number Diff line change
Expand Up @@ -930,37 +930,6 @@ int __mkstemp_ascii(char * tmpl) {
return ret;
}

char *mkdtemp(char *templ) {
size_t len = strlen(templ);
int retries = 10; // Number of retries to generate a unique directory name

// Check that the templ ends with "XXXXXX" as required
if (len < 6 || strcmp(templ + len - 6, "XXXXXX") != 0) {
errno = EINVAL;
return NULL;
}

while (retries--) {
// Generate a random string to replace "XXXXXX" in the templ
for (size_t i = len - 6; i < len; i++) {
templ[i] = 'a' + rand() % 26;
}

// Attempt to create the directory
if (mkdir(templ, 0700) == 0) {
return templ;
}

// If mkdir failed, check if it was due to a collision with an existing directory
if (errno != EEXIST) {
return NULL;
}
}

// If all retries fail, return NULL
return NULL;
}

int __close(int fd) {
int ret = __close_orig(fd);
if (ret < 0)
Expand Down
110 changes: 110 additions & 0 deletions src/zos-mkdtemp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//////////////////////////////////////////////////////////////////////////////
//// Licensed Materials - Property of IBM
//// ZOSLIB
//// (C) Copyright IBM Corp. 2020. All Rights Reserved.
//// US Government Users Restricted Rights - Use, duplication
//// or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
/////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>

typedef enum {
cp_ebcdic,
cp_ascii
} CodePage;

#define XXXXXX "XXXXXX"
#define ValidChars "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.,-"
typedef struct CodePage {
char xes[sizeof(XXXXXX)];
char validChars[sizeof(ValidChars)];
} CodePage_t;

#pragma convert("IBM-1047")
static const CodePage_t CharTraitsEbcdic = {
XXXXXX,
ValidChars
};
#pragma convert(pop)

#pragma convert("ISO8859-1")
static const CodePage_t CharTraitsAscii = {
XXXXXX,
ValidChars
};
#pragma convert(pop)

enum {
TempLen = sizeof(XXXXXX)-1
};

char *real_mkdtemp(CodePage_t cp, char *templ) {
if (!templ) {
errno=EINVAL;
return NULL;
}
int len = strlen(templ);

if (len <TempLen || strncmp(templ+len-TempLen,cp.xes ,TempLen)!=0) {
errno=EINVAL;
return NULL;
}
#define validChars cp.validChars
srand(time(NULL));
#define RANDOM_INT(max) (1 + rand()/((RAND_MAX + 1u) / (max) ))
#define UPDATE_CHAR(n) templ[len-TempLen+n-1] = validChars[(s##n+c##n)%(sizeof validChars)]

// Pick the first random letter for each X
int s1 = RANDOM_INT(sizeof validChars);
int s2 = RANDOM_INT(sizeof validChars);
int s3 = RANDOM_INT(sizeof validChars);
int s4 = RANDOM_INT(sizeof validChars);
int s5 = RANDOM_INT(sizeof validChars);
int s6 = RANDOM_INT(sizeof validChars);
// Loop over all of the possible combinations until we find
// a name that doesn't exist. For example: start with
// dir-aaaaaa, if that doesn't exist try dir-aaaaab.
// Of course the try is something more random than dir-aaaaaa.
for (int c1=0; c1<sizeof validChars; ++c1) {
UPDATE_CHAR(1); // dir-aXXXXX
for (int c2=0; c2<sizeof validChars; ++c2) {
UPDATE_CHAR(2); // dir-aaXXXX
for (int c3=0; c3<sizeof validChars; ++c3) {
UPDATE_CHAR(3); // dir-aaaXXX
for (int c4=0; c4<sizeof validChars; ++c4) {
UPDATE_CHAR(4); // dir-aaaaXX
for (int c5=0; c5<sizeof validChars; ++c5) {
UPDATE_CHAR(5); // dir-aaaaaX
for (int c6=0; c6<sizeof validChars; ++c6) {
UPDATE_CHAR(6); // dir-aaaaaa
int rc = mkdir(templ, 0700);
if (rc==0)
return templ;
if (errno!=EEXIST) {
// restore the X's in the template
strncpy(templ+len-TempLen,cp.xes ,TempLen);
return NULL;
}
}
}
}
}
}
}
// restore the X's in the template
strncpy(templ+len-TempLen,cp.xes,TempLen);
return NULL;
}

__Z_EXPORT char *__mkdtemp_a(char *templ) {
return real_mkdtemp(CharTraitsAscii, templ);
}

__Z_EXPORT char *__mkdtemp_e(char *templ) {
return real_mkdtemp(CharTraitsEbcdic, templ);
}
21 changes: 21 additions & 0 deletions test/test-mkdtemp.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "test-args.h"
#include "zos.h"
#include "gtest/gtest.h"
#include <sys/stat.h>
#include <unistd.h>

namespace {

TEST(MkdtempTest, MkdtempCC) {
char templ[] = "/tmp/dirXXXXXX";
char * dirname = mkdtemp(templ);
EXPECT_NE(dirname, nullptr);

struct stat stats;
int rc = stat(dirname, &stats);
rmdir(dirname);
EXPECT_EQ(rc, 0);
EXPECT_TRUE(S_ISDIR(stats.st_mode));
}

}

0 comments on commit 18af824

Please sign in to comment.