erofs-utils: lib: get rid of tmpfile()
authorGao Xiang <hsiangkao@linux.alibaba.com>
Fri, 14 Feb 2025 06:24:06 +0000 (14:24 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Sat, 15 Feb 2025 01:00:57 +0000 (09:00 +0800)
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 <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20250214062407.3281416-2-hsiangkao@linux.alibaba.com
configure.ac
include/erofs/fragments.h
include/erofs/io.h
lib/blobchunk.c
lib/fragments.c
lib/io.c
lib/liberofs_private.h
lib/xattr.c

index 0a069c5197cb5971405e0972c41b3a72a40cea64..10aa0bd4c89229405a6a4d3aff6462f7f6dd9593 100644 (file)
@@ -268,7 +268,6 @@ AC_CHECK_FUNCS(m4_flatten([
        strrchr
        strtoull
        sysconf
-       tmpfile64
        utimensat]))
 
 # Detect maximum block size if necessary
index 14a1b4aa0c10874158824376bee87e9125828c12..ccfdd9bc7594c1add75d5546f79d975a87580ade 100644 (file)
@@ -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);
index d9b33d237aa73b05d71f1811101dca828fdcfda1..3179ea183a1c5a103620719af879f74490c18efe 100644 (file)
@@ -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);
index 119dd82934043734c0dfc9e31eb8da93ec4b5c2f..abbcba4427cc9ec9c037434e3d9d87186574d8b1 100644 (file)
@@ -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 <unistd.h>
 
@@ -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);
index 9633a2bebb9b594509060c0506cfdfeb8b8f934c..a4311b1a6055a2bdbff0256c687ba5443449095d 100644 (file)
@@ -3,9 +3,6 @@
  * Copyright (C), 2022, Coolpad Group Limited.
  * Created by Yue Hu <huyue2@coolpad.com>
  */
-#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) {
index dacf8dc3843a6848780ae13db3c68b94faadf457..b6eb22aedb43b79eaef51e0a05b6bc3e83292bc0 100644 (file)
--- a/lib/io.c
+++ b/lib/io.c
 #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)) {
index 0eeca3c1d6017f640c5c9fd4c7413e3fef7fb46d..ebd9e7034860b8458102f3a7bc51deae5bd86c7c 100644 (file)
@@ -23,3 +23,5 @@ static inline void *memrchr(const void *s, int c, size_t n)
        return NULL;
 }
 #endif
+
+int erofs_tmpfile(void);
index 086047272bec5ef01bcd8fb2e93e7c2157ca1022..2f6ebab916020980bf14f234f7c1d7593d4b7a23 100644 (file)
@@ -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);