From b6b741d8daafc933ada19c3c5143357f87fb0e53 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Fri, 14 Feb 2025 14:24:06 +0800 Subject: [PATCH] erofs-utils: lib: get rid of tmpfile() Currently, `tmpfile()` is problematic: - It uses `FILE *` instead of `fd`; - It may not leverage `$TMPDIR`, see `__gen_tempfd()`: https://sourceware.org/git?p=glibc.git;a=blob;f=stdio-common/tmpfile.c;hb=glibc-2.41 Switch to `erofs_tmpfile()` throughout the codebase. Signed-off-by: Gao Xiang Link: https://lore.kernel.org/r/20250214062407.3281416-2-hsiangkao@linux.alibaba.com --- configure.ac | 1 - include/erofs/fragments.h | 2 +- include/erofs/io.h | 2 + lib/blobchunk.c | 44 +++++++++--------- lib/fragments.c | 94 +++++++++++++++++++-------------------- lib/io.c | 22 +++++++++ lib/liberofs_private.h | 2 + lib/xattr.c | 23 ++++++---- 8 files changed, 108 insertions(+), 82 deletions(-) diff --git a/configure.ac b/configure.ac index 0a069c5..10aa0bd 100644 --- a/configure.ac +++ b/configure.ac @@ -268,7 +268,6 @@ AC_CHECK_FUNCS(m4_flatten([ strrchr strtoull sysconf - tmpfile64 utimensat])) # Detect maximum block size if necessary diff --git a/include/erofs/fragments.h b/include/erofs/fragments.h index 14a1b4a..ccfdd9b 100644 --- a/include/erofs/fragments.h +++ b/include/erofs/fragments.h @@ -22,7 +22,7 @@ int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd, u32 tofcrc); int z_erofs_pack_fragments(struct erofs_inode *inode, void *data, unsigned int len, u32 tofcrc); int erofs_flush_packed_inode(struct erofs_sb_info *sbi); -FILE *erofs_packedfile(struct erofs_sb_info *sbi); +int erofs_packedfile(struct erofs_sb_info *sbi); int erofs_packedfile_init(struct erofs_sb_info *sbi, bool fragments_mkfs); void erofs_packedfile_exit(struct erofs_sb_info *sbi); diff --git a/include/erofs/io.h b/include/erofs/io.h index d9b33d2..3179ea1 100644 --- a/include/erofs/io.h +++ b/include/erofs/io.h @@ -49,6 +49,8 @@ struct erofs_vfile { }; }; +ssize_t __erofs_io_write(int fd, const void *buf, size_t len); + int erofs_io_fstat(struct erofs_vfile *vf, struct stat *buf); ssize_t erofs_io_pwrite(struct erofs_vfile *vf, const void *buf, u64 pos, size_t len); int erofs_io_fsync(struct erofs_vfile *vf); diff --git a/lib/blobchunk.c b/lib/blobchunk.c index 119dd82..abbcba4 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -9,6 +9,7 @@ #include "erofs/blobchunk.h" #include "erofs/block_list.h" #include "erofs/cache.h" +#include "liberofs_private.h" #include "sha256.h" #include @@ -27,7 +28,7 @@ struct erofs_blobchunk { }; static struct hashmap blob_hashmap; -static FILE *blobfile; +static int blobfile = -1; static erofs_blk_t remapped_base; static erofs_off_t datablob_size; static bool multidev; @@ -86,7 +87,7 @@ static struct erofs_blobchunk *erofs_blob_getchunk(struct erofs_sb_info *sbi, chunk->chunksize = chunksize; memcpy(chunk->sha256, sha256, sizeof(sha256)); - blkpos = ftell(blobfile); + blkpos = lseek(blobfile, 0, SEEK_CUR); DBG_BUGON(erofs_blkoff(sbi, blkpos)); if (sbi->extra_devices) @@ -97,18 +98,22 @@ static struct erofs_blobchunk *erofs_blob_getchunk(struct erofs_sb_info *sbi, erofs_dbg("Writing chunk (%llu bytes) to %u", chunksize | 0ULL, chunk->blkaddr); - ret = fwrite(buf, chunksize, 1, blobfile); - if (ret == 1) { + ret = __erofs_io_write(blobfile, buf, chunksize); + if (ret == chunksize) { padding = erofs_blkoff(sbi, chunksize); if (padding) { padding = erofs_blksiz(sbi) - padding; - ret = fwrite(zeroed, padding, 1, blobfile); + ret = __erofs_io_write(blobfile, zeroed, padding); + if (ret > 0 && ret != padding) + ret = -EIO; } + } else if (ret >= 0) { + ret = -EIO; } - if (ret < 1) { + if (ret < 0) { free(chunk); - return ERR_PTR(-ENOSPC); + return ERR_PTR(ret); } hashmap_entry_init(&chunk->ent, hash); @@ -488,9 +493,8 @@ int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi) ssize_t length, ret; u64 pos_in, pos_out; - if (blobfile) { - fflush(blobfile); - length = ftell(blobfile); + if (blobfile >= 0) { + length = lseek(blobfile, 0, SEEK_CUR); if (length < 0) return -errno; @@ -534,11 +538,11 @@ int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi) pos_out = erofs_btell(bh, false); remapped_base = erofs_blknr(sbi, pos_out); pos_out += sbi->bdev.offset; - if (blobfile) { + if (blobfile >= 0) { pos_in = 0; do { length = min_t(erofs_off_t, datablob_size, SSIZE_MAX); - ret = erofs_copy_file_range(fileno(blobfile), &pos_in, + ret = erofs_copy_file_range(blobfile, &pos_in, sbi->bdev.fd, &pos_out, length); } while (ret > 0 && (datablob_size -= ret)); @@ -565,8 +569,8 @@ void erofs_blob_exit(void) struct hashmap_entry *e; struct erofs_blobchunk *bc, *n; - if (blobfile) - fclose(blobfile); + if (blobfile >= 0) + close(blobfile); /* Disable hashmap shrink, effectively disabling rehash. * This way we can iterate over entire hashmap efficiently @@ -620,18 +624,14 @@ static int erofs_insert_zerochunk(erofs_off_t chunksize) int erofs_blob_init(const char *blobfile_path, erofs_off_t chunksize) { if (!blobfile_path) { -#ifdef HAVE_TMPFILE64 - blobfile = tmpfile64(); -#else - blobfile = tmpfile(); -#endif + blobfile = erofs_tmpfile(); multidev = false; } else { - blobfile = fopen(blobfile_path, "wb"); + blobfile = open(blobfile_path, O_WRONLY | O_BINARY); multidev = true; } - if (!blobfile) - return -EACCES; + if (blobfile < 0) + return -errno; hashmap_init(&blob_hashmap, erofs_blob_hashmap_cmp, 0); return erofs_insert_zerochunk(chunksize); diff --git a/lib/fragments.c b/lib/fragments.c index 9633a2b..a4311b1 100644 --- a/lib/fragments.c +++ b/lib/fragments.c @@ -3,9 +3,6 @@ * Copyright (C), 2022, Coolpad Group Limited. * Created by Yue Hu */ -#ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE -#endif #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE #endif @@ -25,6 +22,7 @@ #include "erofs/internal.h" #include "erofs/fragments.h" #include "erofs/bitops.h" +#include "liberofs_private.h" struct erofs_fragment_dedupe_item { struct list_head list; @@ -41,7 +39,7 @@ struct erofs_fragment_dedupe_item { struct erofs_packed_inode { struct list_head *hash; - FILE *file; + int fd; unsigned long *uptodate; #if EROFS_MT_ENABLED pthread_mutex_t mutex; @@ -108,8 +106,7 @@ static int z_erofs_fragments_dedupe_find(struct erofs_inode *inode, int fd, sz = min_t(u64, pos, sizeof(buf[0])); sz = min_t(u64, sz, inode->i_size - i); - if (pread(fileno(epi->file), buf[0], sz, - pos - sz) != sz) + if (pread(epi->fd, buf[0], sz, pos - sz) != sz) break; if (pread(fd, buf[1], sz, inode->i_size - i - sz) != sz) @@ -208,14 +205,10 @@ void z_erofs_fragments_commit(struct erofs_inode *inode) int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd, u32 tofcrc) { struct erofs_packed_inode *epi = inode->sbi->packedinode; -#ifdef HAVE_FTELLO64 - off64_t offset = ftello64(epi->file); -#else - off_t offset = ftello(epi->file); -#endif + s64 offset, rc; char *memblock; - int rc; + offset = lseek(epi->fd, 0, SEEK_CUR); if (offset < 0) return -errno; @@ -234,14 +227,19 @@ int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd, u32 tofcrc) rc = read(fd, buf, sz); if (rc != sz) { - if (rc < 0) - rc = -errno; - else - rc = -EAGAIN; - goto out; + if (rc <= 0) { + if (!rc) + rc = -EIO; + else + rc = -errno; + goto out; + } + sz = rc; } - if (fwrite(buf, sz, 1, epi->file) != 1) { - rc = -EIO; + rc = __erofs_io_write(epi->fd, buf, sz); + if (rc != sz) { + if (rc >= 0) + rc = -EIO; goto out; } remaining -= sz; @@ -251,9 +249,13 @@ int z_erofs_pack_file_from_fd(struct erofs_inode *inode, int fd, u32 tofcrc) rc = -errno; goto out; } - } else if (fwrite(memblock, inode->fragment_size, 1, epi->file) != 1) { - rc = -EIO; - goto out; + } else { + rc = __erofs_io_write(epi->fd, memblock, inode->fragment_size); + if (rc != inode->fragment_size) { + if (rc >= 0) + rc = -EIO; + goto out; + } } erofs_dbg("Recording %llu fragment data at %llu", @@ -279,11 +281,7 @@ int z_erofs_pack_fragments(struct erofs_inode *inode, void *data, unsigned int len, u32 tofcrc) { struct erofs_packed_inode *epi = inode->sbi->packedinode; -#ifdef HAVE_FTELLO64 - off64_t offset = ftello64(epi->file); -#else - off_t offset = ftello(epi->file); -#endif + s64 offset = lseek(epi->fd, 0, SEEK_CUR); int ret; if (offset < 0) @@ -292,8 +290,12 @@ int z_erofs_pack_fragments(struct erofs_inode *inode, void *data, inode->fragmentoff = (erofs_off_t)offset; inode->fragment_size = len; - if (fwrite(data, len, 1, epi->file) != 1) + ret = write(epi->fd, data, len); + if (ret != len) { + if (ret < 0) + return -errno; return -EIO; + } erofs_dbg("Recording %llu fragment data at %llu", inode->fragment_size | 0ULL, inode->fragmentoff | 0ULL); @@ -313,19 +315,18 @@ int erofs_flush_packed_inode(struct erofs_sb_info *sbi) if (!epi || !erofs_sb_has_fragments(sbi)) return -EINVAL; - fflush(epi->file); - if (!ftello(epi->file)) + if (lseek(epi->fd, 0, SEEK_CUR) <= 0) return 0; - inode = erofs_mkfs_build_special_from_fd(sbi, fileno(epi->file), + inode = erofs_mkfs_build_special_from_fd(sbi, epi->fd, EROFS_PACKED_INODE); sbi->packed_nid = erofs_lookupnid(inode); erofs_iput(inode); return 0; } -FILE *erofs_packedfile(struct erofs_sb_info *sbi) +int erofs_packedfile(struct erofs_sb_info *sbi) { - return sbi->packedinode->file; + return sbi->packedinode->fd; } void erofs_packedfile_exit(struct erofs_sb_info *sbi) @@ -347,8 +348,8 @@ void erofs_packedfile_exit(struct erofs_sb_info *sbi) free(epi->hash); } - if (epi->file) - fclose(epi->file); + if (epi->fd >= 0) + close(epi->fd); free(epi); sbi->packedinode = NULL; } @@ -376,14 +377,9 @@ int erofs_packedfile_init(struct erofs_sb_info *sbi, bool fragments_mkfs) init_list_head(&epi->hash[i]); } - epi->file = -#ifdef HAVE_TMPFILE64 - tmpfile64(); -#else - tmpfile(); -#endif - if (!epi->file) { - err = -errno; + epi->fd = erofs_tmpfile(); + if (epi->fd < 0) { + err = epi->fd; goto err_out; } @@ -392,6 +388,7 @@ int erofs_packedfile_init(struct erofs_sb_info *sbi, bool fragments_mkfs) .sbi = sbi, .nid = sbi->packed_nid, }; + s64 offset; err = erofs_read_inode_from_disk(&ei); if (err) { @@ -400,8 +397,8 @@ int erofs_packedfile_init(struct erofs_sb_info *sbi, bool fragments_mkfs) goto err_out; } - err = fseek(epi->file, ei.i_size, SEEK_SET); - if (err) { + offset = lseek(epi->fd, ei.i_size, SEEK_SET); + if (offset < 0) { err = -errno; goto err_out; } @@ -472,13 +469,12 @@ static void *erofs_packedfile_preload(struct erofs_inode *pi, if (err) goto err_out; - fflush(epi->file); - err = pwrite(fileno(epi->file), buffer, map->m_llen, map->m_la); + err = pwrite(epi->fd, buffer, map->m_llen, map->m_la); if (err < 0) { err = -errno; if (err == -ENOSPC) { memset(epi->uptodate, 0, epi->uptodate_size); - (void)!ftruncate(fileno(epi->file), 0); + (void)!ftruncate(epi->fd, 0); } goto err_out; } @@ -557,7 +553,7 @@ int erofs_packedfile_read(struct erofs_sb_info *sbi, if (!uptodate) continue; - err = pread(fileno(epi->file), buf, len, pos); + err = pread(epi->fd, buf, len, pos); if (err < 0) break; if (err == len) { diff --git a/lib/io.c b/lib/io.c index dacf8dc..b6eb22a 100644 --- a/lib/io.c +++ b/lib/io.c @@ -26,6 +26,28 @@ #define EROFS_MODNAME "erofs_io" #include "erofs/print.h" +ssize_t __erofs_io_write(int fd, const void *buf, size_t len) +{ + ssize_t ret, written = 0; + + do { + ret = write(fd, buf, len); + if (ret <= 0) { + if (!ret) + break; + if (errno != EINTR) { + erofs_err("failed to write: %s", strerror(errno)); + return -errno; + } + ret = 0; + } + buf += ret; + written += ret; + } while (written < len); + + return written; +} + int erofs_io_fstat(struct erofs_vfile *vf, struct stat *buf) { if (__erofs_unlikely(cfg.c_dry_run)) { diff --git a/lib/liberofs_private.h b/lib/liberofs_private.h index 0eeca3c..ebd9e70 100644 --- a/lib/liberofs_private.h +++ b/lib/liberofs_private.h @@ -23,3 +23,5 @@ static inline void *memrchr(const void *s, int c, size_t n) return NULL; } #endif + +int erofs_tmpfile(void); diff --git a/lib/xattr.c b/lib/xattr.c index 0860472..2f6ebab 100644 --- a/lib/xattr.c +++ b/lib/xattr.c @@ -811,21 +811,22 @@ static int comp_shared_xattr_item(const void *a, const void *b) int erofs_xattr_flush_name_prefixes(struct erofs_sb_info *sbi) { - FILE *f = erofs_packedfile(sbi); + int fd = erofs_packedfile(sbi); struct ea_type_node *tnode; - off_t offset; + s64 offset; + int err; if (!ea_prefix_count) return 0; - offset = ftello(f); + offset = lseek(fd, 0, SEEK_CUR); if (offset < 0) return -errno; - if (offset > UINT32_MAX) - return -EOVERFLOW; - offset = round_up(offset, 4); - if (fseek(f, offset, SEEK_SET)) + if ((offset >> 2) > UINT32_MAX) + return -EOVERFLOW; + if (lseek(fd, offset, SEEK_SET) < 0) return -errno; + sbi->xattr_prefix_start = (u32)offset >> 2; sbi->xattr_prefix_count = ea_prefix_count; @@ -846,10 +847,14 @@ int erofs_xattr_flush_name_prefixes(struct erofs_sb_info *sbi) infix_len); len = sizeof(struct erofs_xattr_long_prefix) + infix_len; u.s.size = cpu_to_le16(len); - if (fwrite(&u.s, sizeof(__le16) + len, 1, f) != 1) + err = __erofs_io_write(fd, &u.s, sizeof(__le16) + len); + if (err != sizeof(__le16) + len) { + if (err < 0) + return -errno; return -EIO; + } offset = round_up(offset + sizeof(__le16) + len, 4); - if (fseek(f, offset, SEEK_SET)) + if (lseek(fd, offset, SEEK_SET) < 0) return -errno; } erofs_sb_set_fragments(sbi); -- 2.34.1