mirror of https://gerrit.osmocom.org/asn1c
213 lines
3.9 KiB
C
213 lines
3.9 KiB
C
#include "asn1c_internal.h"
|
|
#include "asn1c_compat.h"
|
|
|
|
#ifndef MAXPATHLEN
|
|
#define MAXPATHLEN 1024
|
|
#endif
|
|
|
|
/* 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 *name, const char *ext, char **opt_tmpname) {
|
|
int created = 1;
|
|
#ifndef _WIN32
|
|
struct stat sb;
|
|
#endif
|
|
char *fname;
|
|
size_t len;
|
|
FILE *fp;
|
|
int ret;
|
|
int fd;
|
|
|
|
/*
|
|
* Compute filenames.
|
|
*/
|
|
len = strlen(name) + strlen(ext) + sizeof(".XXXXXX");
|
|
fname = alloca(len);
|
|
ret = snprintf(fname, len, "%s%s%s", name, ext,
|
|
opt_tmpname ? ".XXXXXX" : "");
|
|
assert(ret > 0 && ret < (ssize_t)len);
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
char *
|
|
a1c_basename(const char *path) {
|
|
static char strbuf[MAXPATHLEN];
|
|
const char *pend;
|
|
const char *name;
|
|
|
|
pend = path + strlen(path);
|
|
if(pend == path) {
|
|
strcpy(strbuf, ".");
|
|
return strbuf;
|
|
}
|
|
|
|
/* Skip tailing slashes */
|
|
for(pend--; pend > path && *pend == '/'; pend--);
|
|
|
|
if(pend == path && *path == '/') {
|
|
strcpy(strbuf, "/");
|
|
return strbuf;
|
|
}
|
|
|
|
for(name = pend; name > path && name[-1] != '/'; name--);
|
|
|
|
if((pend - name) >= (int)sizeof(strbuf) - 1) {
|
|
errno = ENAMETOOLONG;
|
|
return 0;
|
|
}
|
|
|
|
memcpy(strbuf, name, pend - name + 1);
|
|
strbuf[pend - name + 1] = '\0';
|
|
|
|
return strbuf;
|
|
}
|
|
|
|
|
|
char *
|
|
a1c_dirname(const char *path) {
|
|
static char strbuf[MAXPATHLEN];
|
|
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;
|
|
}
|
|
|