roken: Add rk_undumptext() and support ttys and such
Add rk_undumptext(), which NUL-terminates the contents it reads. rk_undumptext(), and now also rk_undumpdata(), can read from regular and non-regular files (e.g., ttys, pipes, devices, but -on Windows- not sockets). This means that `asn1_print` can now read from `/dev/stdin`, which can be a pipe. There's a way to set a limit on how much to read from non-regular files, and that limit defaults to 10MB. At any rate, the rk_dumpdata(), rk_undumpdata(), and rk_undumptext() functions really do not belong in lib/roken but in lib/base. There are other utility functions in lib/roken that don't belong there too. A rationalization of the split between lib/roken and lib/base is overdue. And while we're at it -lest I forget- it'd be nice to move all the krb5_storage functions out of lib/krb5 and into lib/base, as those could come in handy for, e.g., implementing OpenSSH style certificates and other things outside the krb5 universe.
This commit is contained in:
@@ -51,8 +51,84 @@ rk_dumpdata (const char *filename, const void *buf, size_t size)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* For not-regular files */
|
||||
static int
|
||||
undump_not_file(int fd, char **out, size_t *size, int nul_terminate)
|
||||
{
|
||||
size_t lim = 10 * 1024 * 1024;
|
||||
size_t bufsz = 0;
|
||||
size_t sz = 0;
|
||||
char *buf = NULL;
|
||||
char *tmp;
|
||||
|
||||
*out = NULL;
|
||||
if (size && *size != 0 && *size < lim)
|
||||
lim = *size;
|
||||
if (size)
|
||||
*size = 0;
|
||||
|
||||
/*
|
||||
* We can't use net_read() if we're on WIN32 because that really wants a
|
||||
* socket FD, which is in a distinct FD namespace from those returned by
|
||||
* open() on Windows.
|
||||
*/
|
||||
do {
|
||||
ssize_t bytes;
|
||||
|
||||
if (sz == bufsz) {
|
||||
if (bufsz == 0)
|
||||
bufsz = 1024;
|
||||
else
|
||||
bufsz += bufsz >> 1;
|
||||
|
||||
tmp = realloc(buf, bufsz);
|
||||
if (tmp == NULL) {
|
||||
free(buf);
|
||||
return ENOMEM;
|
||||
}
|
||||
buf = tmp;
|
||||
}
|
||||
|
||||
bytes = read(fd, buf + sz, bufsz - sz);
|
||||
if (bytes == 0)
|
||||
break;
|
||||
if (bytes < 0 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK))
|
||||
continue;
|
||||
if (bytes < 0)
|
||||
return errno;
|
||||
sz += bytes;
|
||||
} while (sz < lim);
|
||||
|
||||
*out = buf;
|
||||
if (size)
|
||||
*size = sz;
|
||||
|
||||
if (!nul_terminate)
|
||||
return 0;
|
||||
|
||||
if (bufsz > sz) {
|
||||
buf[sz] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = realloc(buf, bufsz + 1);
|
||||
if (tmp == NULL) {
|
||||
free(buf);
|
||||
return ENOMEM;
|
||||
}
|
||||
buf = tmp;
|
||||
buf[sz] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read all data from a filename, care about errors.
|
||||
* Read all data from a file, care about errors.
|
||||
*
|
||||
* If `*size' is not zero and the file is not a regular file, then up to that
|
||||
* many bytes will be read.
|
||||
*
|
||||
* Returns zero on success or a system error code on failure.
|
||||
*/
|
||||
|
||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
||||
@@ -71,6 +147,14 @@ rk_undumpdata(const char *filename, void **buf, size_t *size)
|
||||
ret = errno;
|
||||
goto out;
|
||||
}
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
char *char_buf;
|
||||
|
||||
ret = undump_not_file(fd, &char_buf, size, 0);
|
||||
(void) close(fd);
|
||||
*buf = char_buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sb.st_size < 0)
|
||||
sb.st_size = 0;
|
||||
@@ -97,3 +181,63 @@ rk_undumpdata(const char *filename, void **buf, size_t *size)
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read all text from a file.
|
||||
*
|
||||
* Outputs a C string. It is up to the caller to check for embedded NULs.
|
||||
* The number of bytes read will be stored in `*size' if `size' is not NULL.
|
||||
*
|
||||
* If `size' is not NULL and `*size' is not zero and the file is not a regular
|
||||
* file, then up to that many bytes will be read.
|
||||
*
|
||||
* Returns zero on success or a system error code on failure.
|
||||
*/
|
||||
|
||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
||||
rk_undumptext(const char *filename, char **out, size_t *size)
|
||||
{
|
||||
struct stat sb;
|
||||
int fd, ret;
|
||||
ssize_t sret;
|
||||
char *buf;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
fd = open(filename, O_RDONLY, 0);
|
||||
if (fd < 0 || fstat(fd, &sb) != 0)
|
||||
return errno;
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
ret = undump_not_file(fd, out, size, 1);
|
||||
(void) close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sb.st_size < 0)
|
||||
sb.st_size = 0;
|
||||
buf = malloc(sb.st_size + 1);
|
||||
if (buf == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (size)
|
||||
*size = sb.st_size;
|
||||
|
||||
sret = read(fd, buf, sb.st_size);
|
||||
if (sret < 0)
|
||||
ret = errno;
|
||||
else if (sret != (ssize_t)sb.st_size)
|
||||
ret = EINVAL;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (ret) {
|
||||
free(buf);
|
||||
} else {
|
||||
buf[sb.st_size] = '\0';
|
||||
*out = buf;
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -532,6 +532,9 @@ rk_dumpdata (const char *, const void *, size_t);
|
||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
||||
rk_undumpdata (const char *, void **, size_t *);
|
||||
|
||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
||||
rk_undumptext (const char *, char **, size_t *);
|
||||
|
||||
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
|
||||
rk_xfree (void *);
|
||||
|
||||
|
@@ -171,6 +171,7 @@ HEIMDAL_ROKEN_2.0 {
|
||||
rk_tsearch;
|
||||
rk_twalk;
|
||||
rk_undumpdata;
|
||||
rk_undumptext;
|
||||
rk_unparse_flags;
|
||||
rk_unparse_time;
|
||||
rk_unparse_time_approx;
|
||||
|
Reference in New Issue
Block a user