diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
| commit | dcacc00e3750300617ba6e16eb346713f91a783a (patch) | |
| tree | 38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/dte/load-save.c | |
| parent | 58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff) | |
| download | crep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz | |
Remove testing data
Diffstat (limited to 'examples/dte/load-save.c')
| -rw-r--r-- | examples/dte/load-save.c | 505 |
1 files changed, 0 insertions, 505 deletions
diff --git a/examples/dte/load-save.c b/examples/dte/load-save.c deleted file mode 100644 index b3ea3fa..0000000 --- a/examples/dte/load-save.c +++ /dev/null @@ -1,505 +0,0 @@ -#include "compat.h" -#include <errno.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <unistd.h> -#include "load-save.h" -#include "block.h" -#include "convert.h" -#include "encoding.h" -#include "error.h" -#include "util/debug.h" -#include "util/fd.h" -#include "util/list.h" -#include "util/log.h" -#include "util/path.h" -#include "util/str-util.h" -#include "util/time-util.h" -#include "util/xmalloc.h" -#include "util/xreadwrite.h" - -static void add_block(Buffer *buffer, Block *blk) -{ - buffer->nl += blk->nl; - list_add_before(&blk->node, &buffer->blocks); -} - -static Block *add_utf8_line ( - Buffer *buffer, - Block *blk, - const unsigned char *line, - size_t len -) { - size_t size = len + 1; - if (blk) { - size_t avail = blk->alloc - blk->size; - if (size <= avail) { - goto copy; - } - add_block(buffer, blk); - } - size = MAX(size, 8192); - blk = block_new(size); -copy: - memcpy(blk->data + blk->size, line, len); - blk->size += len; - blk->data[blk->size++] = '\n'; - blk->nl++; - return blk; -} - -static bool decode_and_add_blocks(Buffer *buffer, const unsigned char *buf, size_t size, bool utf8_bom) -{ - EncodingType bom_type = detect_encoding_from_bom(buf, size); - EncodingType enc_type = buffer->encoding.type; - if (enc_type == ENCODING_AUTODETECT) { - if (bom_type != UNKNOWN_ENCODING) { - BUG_ON(buffer->encoding.name); - Encoding e = encoding_from_type(bom_type); - if (conversion_supported_by_iconv(e.name, "UTF-8")) { - buffer_set_encoding(buffer, e, utf8_bom); - } else { - buffer_set_encoding(buffer, encoding_from_type(UTF8), utf8_bom); - } - } - } - - // Skip BOM only if it matches the specified file encoding - if (bom_type != UNKNOWN_ENCODING && bom_type == buffer->encoding.type) { - const ByteOrderMark *bom = get_bom_for_encoding(bom_type); - if (bom) { - const size_t bom_len = bom->len; - buf += bom_len; - size -= bom_len; - buffer->bom = true; - } - } - - FileDecoder *dec = new_file_decoder(buffer->encoding.name, buf, size); - if (!dec) { - return false; - } - - const char *line; - size_t len; - if (file_decoder_read_line(dec, &line, &len)) { - if (len && line[len - 1] == '\r') { - buffer->crlf_newlines = true; - len--; - } - Block *blk = add_utf8_line(buffer, NULL, line, len); - while (file_decoder_read_line(dec, &line, &len)) { - if (buffer->crlf_newlines && len && line[len - 1] == '\r') { - len--; - } - blk = add_utf8_line(buffer, blk, line, len); - } - if (blk) { - add_block(buffer, blk); - } - } - - if (buffer->encoding.type == ENCODING_AUTODETECT) { - const char *enc = file_decoder_get_encoding(dec); - buffer_set_encoding(buffer, encoding_from_name(enc ? enc : "UTF-8"), utf8_bom); - } - - free_file_decoder(dec); - return true; -} - -static void fixup_blocks(Buffer *buffer) -{ - if (list_empty(&buffer->blocks)) { - Block *blk = block_new(1); - list_add_before(&blk->node, &buffer->blocks); - } else { - // Incomplete lines are not allowed because they are special cases - // and cause lots of trouble - Block *blk = BLOCK(buffer->blocks.prev); - if (blk->size && blk->data[blk->size - 1] != '\n') { - if (blk->size == blk->alloc) { - blk->alloc = round_size_to_next_multiple(blk->size + 1, 64); - xrenew(blk->data, blk->alloc); - } - blk->data[blk->size++] = '\n'; - blk->nl++; - buffer->nl++; - } - } -} - -static int xmadvise_sequential(void *addr, size_t len) -{ -#if HAVE_POSIX_MADVISE - return posix_madvise(addr, len, POSIX_MADV_SEQUENTIAL); -#else - // "The posix_madvise() function shall have no effect on the semantics - // of access to memory in the specified range, although it may affect - // the performance of access". Ergo, doing nothing is a valid fallback. - (void)addr; - (void)len; - return 0; -#endif -} - -static bool update_file_info(FileInfo *info, const struct stat *st) -{ - *info = (FileInfo) { - .size = st->st_size, - .mode = st->st_mode, - .gid = st->st_gid, - .uid = st->st_uid, - .dev = st->st_dev, - .ino = st->st_ino, - .mtime = *get_stat_mtime(st), - }; - return true; -} - -static bool buffer_stat(FileInfo *info, const char *filename) -{ - struct stat st; - return !stat(filename, &st) && update_file_info(info, &st); -} - -static bool buffer_fstat(FileInfo *info, int fd) -{ - struct stat st; - return !fstat(fd, &st) && update_file_info(info, &st); -} - -bool read_blocks(Buffer *buffer, int fd, bool utf8_bom) -{ - const size_t map_size = 64 * 1024; - size_t size = buffer->file.size; - unsigned char *buf = NULL; - bool mapped = false; - bool ret = false; - - if (size >= map_size) { - // NOTE: size must be greater than 0 - buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (buf != MAP_FAILED) { - xmadvise_sequential(buf, size); - mapped = true; - goto decode; - } - buf = NULL; - } - - if (likely(size > 0)) { - buf = malloc(size); - if (unlikely(!buf)) { - goto error; - } - ssize_t rc = xread_all(fd, buf, size); - if (unlikely(rc < 0)) { - goto error; - } - size = rc; - } else { - // st_size is zero for some files in /proc - size_t alloc = map_size; - BUG_ON(!IS_POWER_OF_2(alloc)); - buf = malloc(alloc); - if (unlikely(!buf)) { - goto error; - } - size_t pos = 0; - while (1) { - ssize_t rc = xread_all(fd, buf + pos, alloc - pos); - if (rc < 0) { - goto error; - } - if (rc == 0) { - break; - } - pos += rc; - if (pos == alloc) { - size_t new_alloc = alloc << 1; - if (unlikely(alloc >= new_alloc)) { - errno = EOVERFLOW; - goto error; - } - alloc = new_alloc; - char *new_buf = realloc(buf, alloc); - if (unlikely(!new_buf)) { - goto error; - } - buf = new_buf; - } - } - size = pos; - } - -decode: - ret = decode_and_add_blocks(buffer, buf, size, utf8_bom); - -error: - if (mapped) { - munmap(buf, size); - } else { - free(buf); - } - - if (ret) { - fixup_blocks(buffer); - } - - return ret; -} - -bool load_buffer(Buffer *buffer, const char *filename, const GlobalOptions *gopts, bool must_exist) -{ - int fd = xopen(filename, O_RDONLY | O_CLOEXEC, 0); - - if (fd < 0) { - if (errno != ENOENT) { - return error_msg("Error opening %s: %s", filename, strerror(errno)); - } - if (must_exist) { - return error_msg("File %s does not exist", filename); - } - fixup_blocks(buffer); - } else { - if (!buffer_fstat(&buffer->file, fd)) { - error_msg("fstat failed on %s: %s", filename, strerror(errno)); - goto error; - } - if (!S_ISREG(buffer->file.mode)) { - error_msg("Not a regular file %s", filename); - goto error; - } - if (unlikely(buffer->file.size < 0)) { - error_msg("Invalid file size: %jd", (intmax_t)buffer->file.size); - goto error; - } - if (buffer->file.size / 1024 / 1024 > gopts->filesize_limit) { - error_msg ( - "File size exceeds 'filesize-limit' option (%uMiB): %s", - gopts->filesize_limit, filename - ); - goto error; - } - if (!read_blocks(buffer, fd, gopts->utf8_bom)) { - error_msg("Error reading %s: %s", filename, strerror(errno)); - goto error; - } - xclose(fd); - } - - if (buffer->encoding.type == ENCODING_AUTODETECT) { - Encoding enc = encoding_from_type(UTF8); - buffer_set_encoding(buffer, enc, gopts->utf8_bom); - } - - return true; - -error: - xclose(fd); - return false; -} - -static mode_t get_umask(void) -{ - // Wonderful get-and-set API - mode_t old = umask(0); - umask(old); - return old; -} - -static bool write_buffer(Buffer *buffer, FileEncoder *enc, int fd, EncodingType bom_type) -{ - size_t size = 0; - const ByteOrderMark *bom = get_bom_for_encoding(bom_type); - if (bom) { - size = bom->len; - BUG_ON(size == 0); - if (xwrite_all(fd, bom->bytes, size) < 0) { - return error_msg_errno("write"); - } - } - - Block *blk; - block_for_each(blk, &buffer->blocks) { - ssize_t rc = file_encoder_write(enc, blk->data, blk->size); - if (rc < 0) { - return error_msg_errno("write"); - } - size += rc; - } - - size_t nr_errors = file_encoder_get_nr_errors(enc); - if (nr_errors > 0) { - // Any real error hides this message - error_msg ( - "Warning: %zu non-reversible character conversion%s; file saved", - nr_errors, - (nr_errors > 1) ? "s" : "" - ); - } - - // Need to truncate if writing to existing file - if (xftruncate(fd, size)) { - return error_msg_errno("ftruncate"); - } - - return true; -} - -static int tmp_file(const char *filename, const FileInfo *info, char *buf, size_t buflen) -{ - if (str_has_prefix(filename, "/tmp/")) { - // Don't use temporary file when saving file in /tmp because crontab - // command doesn't like the file to be replaced - return -1; - } - - const char *base = path_basename(filename); - const StringView dir = path_slice_dirname(filename); - const int dlen = (int)dir.length; - int n = snprintf(buf, buflen, "%.*s/.tmp.%s.XXXXXX", dlen, dir.data, base); - if (unlikely(n <= 0 || n >= buflen)) { - buf[0] = '\0'; - return -1; - } - - int fd = mkstemp(buf); - if (fd < 0) { - // No write permission to the directory? - buf[0] = '\0'; - return -1; - } - - if (!info->mode) { - // New file - if (xfchmod(fd, 0666 & ~get_umask()) != 0) { - LOG_WARNING("failed to set file mode: %s", strerror(errno)); - } - return fd; - } - - // Preserve ownership and mode of the original file if possible - if (xfchown(fd, info->uid, info->gid) != 0) { - LOG_WARNING("failed to preserve file ownership: %s", strerror(errno)); - } - if (xfchmod(fd, info->mode) != 0) { - LOG_WARNING("failed to preserve file mode: %s", strerror(errno)); - } - - return fd; -} - -static int xfsync(int fd) -{ -#if HAVE_FSYNC - retry: - if (fsync(fd) == 0) { - return 0; - } - - switch (errno) { - // EINVAL is ignored because it just means "operation not possible - // on this descriptor" rather than indicating an actual error - case EINVAL: - case ENOTSUP: - case ENOSYS: - return 0; - case EINTR: - goto retry; - } - - return -1; -#else - (void)fd; - return 0; -#endif -} - -bool save_buffer ( - Buffer *buffer, - const char *filename, - const Encoding *encoding, - bool crlf, - bool write_bom, - bool hardlinks -) { - char tmp[8192]; - tmp[0] = '\0'; - int fd = -1; - if (hardlinks) { - LOG_INFO("target file has hard links; writing in-place"); - } else { - // Try to use temporary file (safer) - fd = tmp_file(filename, &buffer->file, tmp, sizeof(tmp)); - } - - if (fd < 0) { - // Overwrite the original file directly (if it exists). - // Ownership is preserved automatically if the file exists. - mode_t mode = buffer->file.mode; - if (mode == 0) { - // New file - mode = 0666 & ~get_umask(); - } - fd = xopen(filename, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, mode); - if (fd < 0) { - return error_msg_errno("open"); - } - } - - FileEncoder *enc = new_file_encoder(encoding, crlf, fd); - if (unlikely(!enc)) { - // This should never happen because encoding is validated early - error_msg_errno("new_file_encoder"); - goto error; - } - - EncodingType bom_type = write_bom ? encoding->type : UNKNOWN_ENCODING; - if (!write_buffer(buffer, enc, fd, bom_type)) { - goto error; - } - - if (buffer->options.fsync && xfsync(fd) != 0) { - error_msg_errno("fsync"); - goto error; - } - - int r = xclose(fd); - fd = -1; - if (r != 0) { - error_msg_errno("close"); - goto error; - } - - if (tmp[0] && rename(tmp, filename)) { - error_msg_errno("rename"); - goto error; - } - - free_file_encoder(enc); - buffer_stat(&buffer->file, filename); - return true; - -error: - if (fd >= 0) { - xclose(fd); - } - if (enc) { - free_file_encoder(enc); - } - if (tmp[0]) { - unlink(tmp); - } else { - // Not using temporary file, therefore mtime may have changed. - // Update stat to avoid "File has been modified by someone else" - // error later when saving the file again. - buffer_stat(&buffer->file, filename); - } - return false; -} |
