asn1c/libasn1compiler/asn1c_compat.c

213 lines
4.0 KiB
C

#include "asn1c_internal.h"
#include "asn1c_compat.h"
/* Normally file permissions are (DEFFILEMODE & ~umask(2)) */
#ifndef DEFFILEMODE /* Normally in <sys/stat.h> */
#ifdef _WIN32
#define DEFFILEMODE (S_IREAD|S_IWRITE)
#define REASONABLE_FILE_MODE DEFFILEMODE
#else
#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
#define REASONABLE_FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#endif
#else /* !DEFFILEMODE */
#ifdef _WIN32
#define REASONABLE_FILE_MODE DEFFILEMODE
#else
#define REASONABLE_FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#endif
#endif
#ifdef _WIN32
int mkstemp(char *template) {
char *tmpFN = _mktemp(template);
if(tmpFN)
return open(tmpFN, O_CREAT | O_EXCL | O_WRONLY, DEFFILEMODE);
else
return -1;
}
#undef HAVE_MKSTEMPS
#endif
#ifdef HAVE_MKSTEMPS
#undef mkstemp
#define mkstemp(foo) mkstemps(foo, 0)
#endif
FILE *
asn1c_open_file(const char* destdir, const char *name, const char *ext, char **opt_tmpname) {
char fname[PATH_MAX];
int created = 1;
#ifndef _WIN32
struct stat sb;
#endif
FILE *fp;
int ret;
int fd;
/*
* Compute filenames.
*/
ret = snprintf(fname, sizeof(fname), "%s%s%s%s",
opt_tmpname ? "" : destdir,
name, ext,
opt_tmpname ? ".XXXXXX" : "");
assert(ret > 0 && ret < (ssize_t)sizeof(fname));
if(opt_tmpname) {
/*
* Create temporary file.
*/
fd = mkstemp(fname);
#ifndef _WIN32
/* fchmod() does not respect umask */
(void)fchmod(fd, REASONABLE_FILE_MODE);
#endif
} else {
/*
* Create specified file, or open the old one.
*/
fd = open(fname, O_CREAT | O_EXCL | O_WRONLY, DEFFILEMODE);
if(fd == -1 && errno == EEXIST) {
fd = open(fname, O_WRONLY, DEFFILEMODE);
created = 0;
}
}
if(fd == -1) {
perror(fname);
return NULL;
}
#ifndef _WIN32
/*
* Check sanity.
*/
if(fstat(fd, &sb) || !S_ISREG(sb.st_mode)) {
fprintf(stderr, "%s: Not a regular file\n", fname);
if(created) unlink(fname);
close(fd);
return NULL;
}
if(ftruncate(fd, 0) == -1) {
fprintf(stderr, "%s: ftruncate failed: %s\n",
fname, strerror(errno));
if(created) unlink(fname);
return NULL;
}
#else
_chsize(fd, 0);
#endif /* _WIN32 */
/*
* Convert file descriptor into file pointer.
*/
fp = fdopen(fd, "w");
if(fp == NULL) {
if(created) unlink(fname);
close(fd);
return NULL;
}
/* Return the temporary file name */
if(opt_tmpname) {
*opt_tmpname = strdup(fname);
if(*opt_tmpname) {
/* Successfull */
} else {
if(created) unlink(fname);
fclose(fp);
return NULL;
}
}
return fp;
}
const char *
a1c_basename(const char *path, const char *destdir) {
static char strbuf[PATH_MAX];
const char *pend;
const char *name;
char *sbuf = strbuf;
if(destdir) {
strncpy(strbuf, destdir, PATH_MAX - 1);
strbuf[PATH_MAX - 1] = '\0';
sbuf = strbuf + strlen(strbuf);
}
pend = path + strlen(path);
if(pend == path) {
strcpy(sbuf, ".");
return strbuf;
}
/* Skip tailing slashes */
for(pend--; pend > path && *pend == '/'; pend--);
if(pend == path && *path == '/') {
strcpy(sbuf, "/");
return strbuf;
}
for(name = pend; name > path && name[-1] != '/'; name--);
if((pend - name) >= (int)sizeof(strbuf) - 1) {
errno = ENAMETOOLONG;
return 0;
}
memcpy(sbuf, name, pend - name + 1);
sbuf[pend - name + 1] = '\0';
return strbuf;
}
const char *
a1c_dirname(const char *path) {
static char strbuf[PATH_MAX];
const char *pend;
const char *last = 0;
int in_slash = 0;
/* One-pass determination of the last char of the pathname */
for(pend = path; ; pend++) {
switch(*pend) {
case '\0': break;
case '/':
if(!in_slash) {
last = pend;
in_slash = 1;
}
continue;
default:
if(in_slash) in_slash = 0;
continue;
}
break;
}
if(last <= path) {
strcpy(strbuf, *path == '/' ? "/" : ".");
return strbuf;
}
if(!last) {
strcpy(strbuf, "/");
return strbuf;
}
if((last - path) >= (int)sizeof(strbuf)) {
errno = ENAMETOOLONG;
return 0;
}
memcpy(strbuf, path, last - path);
strbuf[last - path] = '\0';
return strbuf;
}