Patches redone. Main changes:
rename inusefile -> lockfile
check the error code from ext2fs_block_iterate3
diff -urN e2fsprogs-1.47.2~rc1.orig/misc/fuse2fs.c e2fsprogs-1.47.2~rc1/misc/fuse2fs.c
--- e2fsprogs-1.47.2~rc1.orig/misc/fuse2fs.c	2024-11-29 08:02:27.000000000 +0000
+++ e2fsprogs-1.47.2~rc1/misc/fuse2fs.c	2024-11-29 08:02:27.000000000 +0000
@@ -1238,6 +1238,25 @@
 	return update_mtime(fs, dir, NULL);
 }
 
+static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
+			       e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+			       blk64_t ref_block EXT2FS_ATTR((unused)),
+			       int ref_offset EXT2FS_ATTR((unused)),
+			       void *private)
+{
+	blk64_t	block = *blocknr;
+	blk64_t *last_cluster = (blk64_t *)private;
+	blk64_t cluster = EXT2FS_B2C(fs, block);
+
+	if (cluster == *last_cluster)
+		return 0;
+
+	*last_cluster = cluster;
+
+	ext2fs_block_alloc_stats2(fs, block, -1);
+	return 0;
+}
+
 static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino)
 {
 	ext2_filsys fs = ff->fs;
@@ -1279,8 +1298,9 @@
 		goto write_out;
 
 	if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) {
-		err = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL,
-				   0, ~0ULL);
+		blk64_t last_cluster = 0;
+		err = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY,
+				      NULL, release_blocks_proc, &last_cluster);
 		if (err) {
 			ret = translate_error(fs, ino, err);
 			goto write_out;
diff -urN e2fsprogs-1.47.2~rc1.orig/misc/fuse2fs.c e2fsprogs-1.47.2~rc1/misc/fuse2fs.c
--- e2fsprogs-1.47.2~rc1.orig/misc/fuse2fs.c	2024-11-29 08:02:27.000000000 +0000
+++ e2fsprogs-1.47.2~rc1/misc/fuse2fs.c	2024-11-29 08:02:27.000000000 +0000
@@ -348,6 +348,8 @@
 	unsigned long offset;
 	FILE *err_fp;
 	unsigned int next_generation;
+	int haslockfile;
+	char* lockfile;
 };
 
 #define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \
@@ -3873,6 +3875,8 @@
 	FUSE2FS_OPT("no_default_opts",	no_default_opts,	1),
 	FUSE2FS_OPT("norecovery",	norecovery,		1),
 	FUSE2FS_OPT("offset=%lu",	offset,		0),
+	FUSE2FS_OPT("lockfile",		haslockfile,		1),
+	FUSE2FS_OPT("lockfile=%s",	lockfile,		0),
 
 	FUSE_OPT_KEY("-V",             FUSE2FS_VERSION),
 	FUSE_OPT_KEY("--version",      FUSE2FS_VERSION),
@@ -3914,6 +3918,8 @@
 	"    -o offset=<bytes>      similar to mount -o offset=<bytes>, mount the partition starting at <bytes>\n"
 	"    -o norecovery	    don't replay the journal (implies ro)\n"
 	"    -o fuse2fs_debug       enable fuse2fs debugging\n"
+	"    -o lockfile            use <image>.lck to show that fuse is still using the file system image\n"
+	"    -o lockfile=<file>     file to show that fuse is still using the file system image\n"
 	"\n",
 			outargs->argv[0]);
 		if (key == FUSE2FS_HELPFULL) {
@@ -3975,7 +3981,7 @@
 		fctx.err_fp = fopen(logfile, "a");
 		if (!fctx.err_fp) {
 			perror(logfile);
-			goto out;
+			exit(1);
 		}
 	} else
 		fctx.err_fp = stderr;
@@ -3987,6 +3993,42 @@
 		fctx.alloc_all_blocks = 1;
 	}
 
+	ret = 1;
+	if (fctx.haslockfile && !fctx.lockfile) {
+		fctx.lockfile = malloc(strlen(fctx.device) + 5);
+		if (!fctx.lockfile) {
+			fprintf(stderr, "Out of memory\n");
+			goto out;
+		}
+		strcpy(fctx.lockfile, fctx.device);
+		strcat(fctx.lockfile, ".lck");
+	}
+	if (fctx.lockfile) {
+		int fd = open(fctx.lockfile, O_CREAT | O_EXCL | O_WRONLY, 0400);
+		if (fd == -1) {
+			if (errno == EEXIST)
+				fprintf(stderr, "Requested lockfile=%s but it already exists\n", fctx.lockfile);
+			else
+				fprintf(stderr, "Requested lockfile=%s but couldn't create: %s\n", fctx.lockfile, strerror(errno));
+			free(fctx.lockfile);
+			fctx.lockfile = NULL;
+			goto out;
+		}
+		close(fd);
+		char resolved[PATH_MAX];
+		if (!realpath(fctx.lockfile, resolved)) {
+			fprintf(stderr, "Could not resolve realpath for lockfile=%s: %s\n", fctx.lockfile, strerror(errno));
+			goto out;
+		}
+		char* resolveddup = strdup(resolved);
+		if (!resolveddup) {
+			fprintf(stderr, "Out of memory\n");
+			goto out;
+		}
+		free(fctx.lockfile);
+		fctx.lockfile = resolveddup;
+	}
+
 	/* Start up the fs (while we still can use stdout) */
 	ret = 2;
 	if (!fctx.ro)
@@ -4107,6 +4149,11 @@
 			com_err(argv[0], err, "while closing fs");
 		global_fs = NULL;
 	}
+	if(fctx.lockfile) {
+		err = unlink(fctx.lockfile);
+		if (err)
+			com_err(argv[0], err, "unlink: %s while unlinking '%s'", strerror(errno), fctx.lockfile);
+	}
 	return ret;
 }
 

Attachment: test.sh
Description: Bourne shell script

diff -urN e2fsprogs-1.47.2~rc1.orig/misc/fuse2fs.c e2fsprogs-1.47.2~rc1/misc/fuse2fs.c
--- e2fsprogs-1.47.2~rc1.orig/misc/fuse2fs.c	2024-11-29 08:02:27.000000000 +0000
+++ e2fsprogs-1.47.2~rc1/misc/fuse2fs.c	2024-11-29 08:02:27.000000000 +0000
@@ -2040,6 +2040,147 @@
 	return ret;
 }
 
+struct block_context {
+	e2_blkcnt_t next_block;
+	off_t blksize;
+	off_t offset;
+	off_t pos;
+	off_t next_hole;
+	off_t next_data;
+};
+
+static int
+dumponeblock(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt,
+      blk64_t ref_block, int ref_offset, void * privdata)
+{
+	struct block_context *p;
+	e2_blkcnt_t i;
+
+	p = (struct block_context *)privdata;
+	printf("p->pos = %ld p->offset=%ld blockcnt=%lld\n", p->pos, p->offset, blockcnt);
+
+	// Stepping over a hole
+	e2_blkcnt_t holesize = blockcnt - p->next_block;
+	if (p->pos <= p->offset && p->pos + holesize * p->blksize > p->offset) {
+		// offset is in this hole
+		p->next_hole = p->offset;
+	} else if (p->pos > p->offset && p->pos < p->next_hole) {
+		// First hole after offset
+		p->next_hole = p->pos;
+	}
+	p->pos += p->blksize * holesize;
+
+	// A data block
+	p->next_block = blockcnt + 1;
+	if (p->pos <= p->offset && p->pos + p->blksize > p->offset) {
+		// offset is in this data block
+		p->next_data = p->offset;
+	} else if (p->pos > p->offset && p->pos < p->next_data) {
+		// first data block after offset
+		p->next_data = p->pos;
+	}
+	p->pos += p->blksize;
+	return 0;
+}
+
+
+static off_t op_lseek(const char* path, off_t offset, int whence, struct fuse_file_info *fp)
+{
+	struct fuse_context *ctxt = fuse_get_context();
+	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
+	struct fuse2fs_file_handle *fh =
+		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
+	ext2_filsys fs;
+	struct ext2_inode_large inode;
+	blk64_t start, end;
+	__u64 i_size;
+	errcode_t err;
+	int flags;
+
+	FUSE2FS_CHECK_CONTEXT(ff);
+	fs = ff->fs;
+	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
+
+	memset(&inode, 0, sizeof(inode));
+	err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
+				     sizeof(inode));
+	if (err)
+		return err;
+	i_size = EXT2_I_SIZE(&inode);
+
+	if (offset >= i_size)
+		return -ENXIO;
+
+	struct block_context bc = {
+		.next_block = 0,
+		.blksize = fs->blocksize,
+		.offset = offset,
+		.pos = 0,
+		.next_hole = i_size,
+		.next_data = i_size,
+	};
+
+	if (inode.i_mode & S_IFREG && inode.i_flags & EXT4_EXTENTS_FL) {
+		ext2_extent_handle_t handle = NULL;
+		struct ext2fs_extent extent;
+		int op = EXT2_EXTENT_ROOT;
+
+		err = ext2fs_extent_open(fs, fh->ino, &handle);
+		if (err) {
+			// Why doesn't op_create do this?
+			err = translate_error(fs, fh->ino, err);
+			return err;
+		}
+		while (1) {
+			err = ext2fs_extent_get(handle, op, &extent);
+			if (err == EXT2_ET_EXTENT_NO_NEXT)
+				break;
+			if (err) {
+				err = translate_error(fs, fh->ino, err);
+				ext2fs_extent_free(handle);
+				return err;
+			}
+			op = EXT2_EXTENT_NEXT;
+
+			if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) {
+				continue;
+			}
+			if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
+				continue;
+			}
+
+			blk64_t start = extent.e_pblk;
+			e2_blkcnt_t blockcnt = extent.e_lblk;
+			for(blk64_t blocknr = start; blocknr < start + extent.e_len; ++blocknr, ++blockcnt) {
+				// TODO We can be much more efficient here
+				dumponeblock(fs, &blocknr, blockcnt, 0, 0, &bc);
+			}
+		}
+		ext2fs_extent_free(handle);
+	} else if (inode.i_mode & S_IFREG && inode.i_flags & EXT4_INLINE_DATA_FL) {
+		if (whence == SEEK_DATA) {
+			return offset;
+		} else {
+			return i_size;
+		}
+	} else {
+		ext2fs_block_iterate3(fs, fh->ino, BLOCK_FLAG_DATA_ONLY, NULL, dumponeblock, &bc);
+	}
+
+	/* deal with holes at the end of the inode */
+	if (i_size > bc.pos) {
+		if (bc.next_hole == i_size)
+			bc.next_hole = bc.pos > bc.offset ? bc.pos : bc.offset;
+	}
+
+	if (whence == SEEK_DATA) {
+		if (bc.next_data == i_size) return -ENXIO;
+		return bc.next_data;
+	} else {
+		return bc.next_hole;
+	}
+}
+
 static int op_truncate(const char *path, off_t len
 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
 			, struct fuse_file_info *fi EXT2FS_ATTR((unused))
@@ -3695,6 +3836,7 @@
 	.fallocate = op_fallocate,
 # endif
 #endif
+	.lseek = op_lseek,
 };
 
 static int get_random_bytes(void *p, size_t sz)

Reply via email to