diff --git a/docs/README.md b/docs/README.md index 85cae66b..4d877a4a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1049,14 +1049,26 @@ size_t mg_file_size(const char *path); Return file size, or 0 on failure. Empty files also report 0 length. - ### mg\_file\_write() ```c -int mg_file_write(const char *path, const char *fmt, ...); +bool mg_file_write(const char *path, const void *buf, size_t len); ``` -Write into a file `path` using `printf()` semantics. Return number of bytes written. +Write data to a file, return `true` if written, `false` otherwise. +The write is atomic, i.e. data gets written to a temporary file first, +then `rename()-ed` to a destination file name. + + +### mg\_file\_printf() + +```c +int mg_file_printf(const char *path, const char *fmt, ...); +``` + +Write into a file `path` using `printf()` semantics. +Return `true` on success, `false` otherwise. This function prints data to +a temporary in-memory buffer first, then calls `mg_file_write()`. ### mg\_random() diff --git a/mongoose.c b/mongoose.c index 2a798c27..fd009643 100644 --- a/mongoose.c +++ b/mongoose.c @@ -282,7 +282,9 @@ static void dns_cb(struct mg_connection *c, int ev, void *ev_data, if (d->c->is_resolving) { d->c->is_resolving = 0; if (dm.resolved) { +#if MG_ENABLE_LOG char buf[100]; +#endif dm.addr.port = d->c->peer.port; // Save port d->c->peer = dm.addr; // Copy resolved address LOG(LL_DEBUG, ("%lu %s resolved to %s", d->c->id, dm.name, @@ -3738,22 +3740,36 @@ char *mg_file_read(const char *path) { return data; } -int mg_file_write(const char *path, const char *fmt, ...) { - char tmp[100]; - int written = 0; +bool mg_file_write(const char *path, const void *buf, size_t len) { + bool result = false; FILE *fp; + char tmp[PATH_MAX]; snprintf(tmp, sizeof(tmp), "%s.%d", path, rand()); fp = fopen(tmp, "wb"); if (fp != NULL) { - va_list ap; - va_start(ap, fmt); - written = vfprintf(fp, fmt, ap); - va_end(ap); + result = fwrite(buf, 1, len, fp) == len; fclose(fp); - remove(path); - rename(tmp, path); + if (result) { + remove(path); + rename(tmp, path); + } else { + remove(tmp); + } } - return written; + return result; +} + +bool mg_file_printf(const char *path, const char *fmt, ...) { + char tmp[256], *buf = tmp; + bool result; + size_t len; + va_list ap; + va_start(ap, fmt); + len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap); + va_end(ap); + result = mg_file_write(path, buf, len); + if (buf != tmp) free(buf); + return result; } void mg_random(void *buf, size_t len) { diff --git a/mongoose.h b/mongoose.h index 0010a4e7..9e9da925 100644 --- a/mongoose.h +++ b/mongoose.h @@ -16,7 +16,7 @@ // license, as set out in . #pragma once -#define MG_VERSION "7.1" +#define MG_VERSION "7.2" #define MG_ARCH_CUSTOM 0 @@ -414,7 +414,8 @@ void mg_timer_poll(unsigned long uptime_ms); char *mg_file_read(const char *path); size_t mg_file_size(const char *path); -int mg_file_write(const char *path, const char *fmt, ...); +bool mg_file_write(const char *path, const void *buf, size_t len); +bool mg_file_printf(const char *path, const char *fmt, ...); void mg_random(void *buf, size_t len); bool mg_globmatch(const char *pattern, int plen, const char *s, int n); bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v); diff --git a/src/dns.c b/src/dns.c index ecab5764..dba39608 100644 --- a/src/dns.c +++ b/src/dns.c @@ -156,7 +156,9 @@ static void dns_cb(struct mg_connection *c, int ev, void *ev_data, if (d->c->is_resolving) { d->c->is_resolving = 0; if (dm.resolved) { +#if MG_ENABLE_LOG char buf[100]; +#endif dm.addr.port = d->c->peer.port; // Save port d->c->peer = dm.addr; // Copy resolved address LOG(LL_DEBUG, ("%lu %s resolved to %s", d->c->id, dm.name, diff --git a/src/util.c b/src/util.c index b428ac63..71edd895 100644 --- a/src/util.c +++ b/src/util.c @@ -29,22 +29,36 @@ char *mg_file_read(const char *path) { return data; } -int mg_file_write(const char *path, const char *fmt, ...) { - char tmp[100]; - int written = 0; +bool mg_file_write(const char *path, const void *buf, size_t len) { + bool result = false; FILE *fp; + char tmp[PATH_MAX]; snprintf(tmp, sizeof(tmp), "%s.%d", path, rand()); fp = fopen(tmp, "wb"); if (fp != NULL) { - va_list ap; - va_start(ap, fmt); - written = vfprintf(fp, fmt, ap); - va_end(ap); + result = fwrite(buf, 1, len, fp) == len; fclose(fp); - remove(path); - rename(tmp, path); + if (result) { + remove(path); + rename(tmp, path); + } else { + remove(tmp); + } } - return written; + return result; +} + +bool mg_file_printf(const char *path, const char *fmt, ...) { + char tmp[256], *buf = tmp; + bool result; + size_t len; + va_list ap; + va_start(ap, fmt); + len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap); + va_end(ap); + result = mg_file_write(path, buf, len); + if (buf != tmp) free(buf); + return result; } void mg_random(void *buf, size_t len) { diff --git a/src/util.h b/src/util.h index 77a48b2b..9e837e18 100644 --- a/src/util.h +++ b/src/util.h @@ -5,7 +5,8 @@ char *mg_file_read(const char *path); size_t mg_file_size(const char *path); -int mg_file_write(const char *path, const char *fmt, ...); +bool mg_file_write(const char *path, const void *buf, size_t len); +bool mg_file_printf(const char *path, const char *fmt, ...); void mg_random(void *buf, size_t len); bool mg_globmatch(const char *pattern, int plen, const char *s, int n); bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v); diff --git a/test/unit_test.c b/test/unit_test.c index e3136d63..5db4ea35 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1045,12 +1045,16 @@ static void test_dns(void) { } static void test_util(void) { - char buf[100], *s = mg_hexdump("abc", 3); + char buf[100], *s = mg_hexdump("abc", 3), *p; struct mg_addr a; ASSERT(s != NULL); free(s); memset(&a, 0, sizeof(a)); - ASSERT(mg_file_write("data.txt", "%s", "hi") == 2); + ASSERT(mg_file_printf("data.txt", "%s", "hi") == true); + ASSERT((p = mg_file_read("data.txt")) != NULL); + ASSERT(strcmp(p, "hi") == 0); + free(p); + remove("data.txt"); ASSERT(mg_aton(mg_str("0"), &a) == false); ASSERT(mg_aton(mg_str("0.0.0."), &a) == false); ASSERT(mg_aton(mg_str("0.0.0.256"), &a) == false);