fileio: replace read_nul_string() by read_line() with a special flag

read_line() is a lot more careful and optimized than read_nul_string()
but does mostly the same thing. let's replace the latter by the former,
just with a special flag that toggles between the slightly different EOL
rules if both.
This commit is contained in:
Lennart Poettering 2018-12-17 11:50:33 +01:00
parent 2a7797e964
commit 41f11239c0
3 changed files with 27 additions and 53 deletions

View file

@ -667,46 +667,6 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
return fputs(s, f); return fputs(s, f);
} }
int read_nul_string(FILE *f, char **ret) {
_cleanup_free_ char *x = NULL;
size_t allocated = 0, n = 0;
assert(f);
assert(ret);
/* Reads a NUL-terminated string from the specified file. */
for (;;) {
int c;
if (!GREEDY_REALLOC(x, allocated, n+2))
return -ENOMEM;
c = fgetc(f);
if (c == 0) /* Terminate at NUL byte */
break;
if (c == EOF) {
if (ferror(f))
return -errno;
break; /* Terminate at EOF */
}
x[n++] = (char) c;
}
if (x)
x[n] = 0;
else {
x = new0(char, 1);
if (!x)
return -ENOMEM;
}
*ret = TAKE_PTR(x);
return 0;
}
/* A bitmask of the EOL markers we know */ /* A bitmask of the EOL markers we know */
typedef enum EndOfLineMarker { typedef enum EndOfLineMarker {
EOL_NONE = 0, EOL_NONE = 0,
@ -715,11 +675,15 @@ typedef enum EndOfLineMarker {
EOL_THIRTEEN = 1 << 2, /* \r (aka CR) */ EOL_THIRTEEN = 1 << 2, /* \r (aka CR) */
} EndOfLineMarker; } EndOfLineMarker;
static EndOfLineMarker categorize_eol(char c) { static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
if (c == '\n')
return EOL_TEN; if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
if (c == '\r') if (c == '\n')
return EOL_THIRTEEN; return EOL_TEN;
if (c == '\r')
return EOL_THIRTEEN;
}
if (c == '\0') if (c == '\0')
return EOL_ZERO; return EOL_ZERO;
@ -728,7 +692,7 @@ static EndOfLineMarker categorize_eol(char c) {
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile); DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
int read_line(FILE *f, size_t limit, char **ret) { int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
size_t n = 0, allocated = 0, count = 0; size_t n = 0, allocated = 0, count = 0;
_cleanup_free_ char *buffer = NULL; _cleanup_free_ char *buffer = NULL;
int r; int r;
@ -787,7 +751,7 @@ int read_line(FILE *f, size_t limit, char **ret) {
count++; count++;
eol = categorize_eol(c); eol = categorize_eol(c, flags);
if (FLAGS_SET(previous_eol, EOL_ZERO) || if (FLAGS_SET(previous_eol, EOL_ZERO) ||
(eol == EOL_NONE && previous_eol != EOL_NONE) || (eol == EOL_NONE && previous_eol != EOL_NONE) ||

View file

@ -61,8 +61,18 @@ int read_timestamp_file(const char *fn, usec_t *ret);
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space); int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
int read_nul_string(FILE *f, char **ret); typedef enum ReadLineFlags {
READ_LINE_ONLY_NUL = 1 << 0,
} ReadLineFlags;
int read_line(FILE *f, size_t limit, char **ret); int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret);
static inline int read_line(FILE *f, size_t limit, char **ret) {
return read_line_full(f, limit, 0, ret);
}
static inline int read_nul_string(FILE *f, size_t limit, char **ret) {
return read_line_full(f, limit, READ_LINE_ONLY_NUL, ret);
}
int safe_fgetc(FILE *f, char *ret); int safe_fgetc(FILE *f, char *ret);

View file

@ -637,8 +637,8 @@ static int clean_pool_done(Operation *operation, int ret, sd_bus_error *error) {
if (success) /* The resulting temporary file could not be updated, ignore it. */ if (success) /* The resulting temporary file could not be updated, ignore it. */
return ret; return ret;
r = read_nul_string(f, &name); r = read_nul_string(f, LONG_LINE_MAX, &name);
if (r < 0 || isempty(name)) /* Same here... */ if (r <= 0) /* Same here... */
return ret; return ret;
return sd_bus_error_set_errnof(error, ret, "Failed to remove image %s: %m", name); return sd_bus_error_set_errnof(error, ret, "Failed to remove image %s: %m", name);
@ -660,10 +660,10 @@ static int clean_pool_done(Operation *operation, int ret, sd_bus_error *error) {
_cleanup_free_ char *name = NULL; _cleanup_free_ char *name = NULL;
uint64_t size; uint64_t size;
r = read_nul_string(f, &name); r = read_nul_string(f, LONG_LINE_MAX, &name);
if (r < 0) if (r < 0)
return r; return r;
if (isempty(name)) /* reached the end */ if (r == 0) /* reached the end */
break; break;
errno = 0; errno = 0;