lib/sb.c: fix super block read failure from disk image file

Unlike mkfs.nilfs2, nilfs-tune and dumpseg commands will cause errors
if used directly on a disk image files.  This is because
__nilfs_sb_read(), which reads superblocks, uses the BLKGETSIZE64 ioctl
command to get the device size, which fails for disk image files.

Fix this issue by using the size information obtained from the fstat
system call for regular files.

Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
This commit is contained in:
Ryusuke Konishi 2024-02-18 19:54:04 +09:00
parent 4d722cd3eb
commit 8414cbfe38

View File

@ -57,6 +57,7 @@
#endif /* HAVE_SYS_IOCTL_H */
#include <linux/nilfs2_ondisk.h>
#include <sys/stat.h> /* fstat(), S_ISBLK(), S_ISREG(), etc */
#include <errno.h>
#include <assert.h>
#include "nilfs.h"
@ -109,16 +110,28 @@ static int __nilfs_sb_read(int devfd, struct nilfs_super_block **sbp,
uint64_t devsize, sb2_offset;
int invalid_fs = 0;
ssize_t ret;
struct stat stat;
sbp[0] = malloc(NILFS_MAX_SB_SIZE);
sbp[1] = malloc(NILFS_MAX_SB_SIZE);
if (unlikely(sbp[0] == NULL || sbp[1] == NULL))
goto failed;
ret = ioctl(devfd, BLKGETSIZE64, &devsize);
if (unlikely(ret != 0))
ret = fstat(devfd, &stat);
if (unlikely(ret < 0))
goto failed;
if (S_ISBLK(stat.st_mode)) {
ret = ioctl(devfd, BLKGETSIZE64, &devsize);
if (unlikely(ret < 0))
goto failed;
} else if (S_ISREG(stat.st_mode)) {
devsize = stat.st_size;
} else {
errno = EBADF;
goto failed;
}
ret = pread(devfd, sbp[0], NILFS_MAX_SB_SIZE, NILFS_SB_OFFSET_BYTES);
if (likely(ret == NILFS_MAX_SB_SIZE)) {
if (nilfs_sb_is_valid(sbp[0], 0))