linux - Full space occupied by the file system -


how can find how space file system occupies on block device, when file system not cover whole partitions?

consider basic example demonstrate core problem:

dd if=/dev/zero bs=1024 count=20480 of=something.img  losetup -f $pwd/something.img  mke2fs /dev/loop0  mount /dev/loop0 /mnt 

but df -k /mnt gives output:

filesystem     1k-blocks  used available use% mounted on /dev/loop0         19827   172     18631   1% /mnt 

i have created device of precisely 2048kb, statvfs() syscall (and df displayed above) reports file system takes 19827kb.

it seems that statvfs() reports blocks usable user, doesn't report full actual size of file system.

so far, find ext2/3/4-specific hacky solution: tune2fs -l /dev/loop0 | grep 'block count:' or dumpe2fs -h /dev/loop0 | grep 'block count:'. little bit more cleaner use libext2fs library (part of e2fprogs package) read superblock, prefer file-system neutral syscall, if available.

if you're looking posix syscall retrieve device level information, believe there none.

for file system level information [portable] calls, far know, you'll able retrieve total number of data blocks, not remaining overhead (such inode tables etc).

.

the problem

statvfs(2) , fstatvfs(2) retrieve "usable" (aka data blocks) file system level information (eg, vfat, ext2, ext3 ...), not underlying device level information (eg, /dev/loop0, /dev/sda, ...).

.

a [partial / possible] non-portable solution

[edit 3]: not op looking (this device level information , not cover case file system not map entire device size).

under linux (assuming relatively recent kernel version), can use ioctl(2) retrieve device size in bytes (the same approach performed blockdev(8)):

#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h>  #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>  #include <unistd.h>  #include <sys/ioctl.h>  #include <linux/fs.h>  int main(void) {         int fd = 0;         unsigned long long size = 0;          if (getuid() != 0) {                 puts("you need root.");                 exit(exit_failure);         }          if ((fd = open("/dev/loop0", o_rdonly)) < 0) {                 printf("open(): %s\n", strerror(errno));                 exit(exit_failure);         }          if (ioctl(fd, blkgetsize64, &size) < 0) {                 printf("ioctl(): %s\n", strerror(errno));                 exit(exit_failure);         }          printf("%llu\n", size);          return 0; } 

edit:

as discussed in comments, device level information, if file system not map entire device size, won't solve problem (we still won't know total size file system occupy in device).

.

an attempt portable solution :)

i'm afraid you'll really, need by hand, step step.

you'll need know exact file system, understand structure, , math. instance, in example, you're using 20mib ext2 filesystem. so, structure (simplifying sake of example):

block 0:

  • boot record , boot record data: 1 block (2 * 512 bytes)

.

block group 0:

  • superblock: 1 block (1024 bytes)

  • block group descriptor table, block bitmap , inode bitmap: 3 blocks

  • inode table: 214 blocks

    ... data blocks ...

.

block group 1:

  • superblock (backup): 1 block

  • block group descriptor table (backup), block bitmap , inode bitmap: 3 blocks

  • inode table: 214 blocks

    ... data blocks ...

.

block group 2:

  • block bitmap , inode bitmap: 2 blocks

  • inode table: 214 blocks

    ... data blocks ...

.

now doing math:

  • 1 + 1 + 3 + 214 + 1 + 3 + 214 + 2 + 214 == 653

sum 653 19827 (which can retrieve statvfs(2)):

  • 653 + 19827 == 20480 blocks

edit 2:

as discussed in comments, ext2 superblock block count contains total blocks occupied file system (not usable blocks thought). simple test observe (skipped error checking simplicity [of example]):

#include <stdio.h> #include <string.h> #include <inttypes.h> #include <sys/types.h> #include <unistd.h> #include <sys/types.h> #include <fcntl.h>  struct ext2_super_block {         uint32_t        s_inodes_count;         uint32_t        s_blocks_count;         uint32_t        s_r_blocks_count;         uint32_t        s_free_blocks_count;         uint32_t        s_free_inodes_count;         uint32_t        s_first_data_block;         uint32_t        s_log_block_size;         uint32_t        s_dummy3[7];         unsigned char   s_magic[2];         uint16_t        s_state;         uint32_t        s_dummy5[8];         uint32_t        s_feature_compat;         uint32_t        s_feature_incompat;         uint32_t        s_feature_ro_compat;         unsigned char   s_uuid[16];         char            s_volume_name[16];         char            s_last_mounted[64];         uint32_t        s_algorithm_usage_bitmap;         uint8_t         s_prealloc_blocks;         uint8_t         s_prealloc_dir_blocks;         uint16_t        s_reserved_gdt_blocks;         uint8_t         s_journal_uuid[16];         uint32_t        s_journal_inum;         uint32_t        s_journal_dev;         uint32_t        s_last_orphan;         uint32_t        s_hash_seed[4];         uint8_t         s_def_hash_version;         uint8_t         s_jnl_backup_type;         uint16_t        s_reserved_word_pad;         uint32_t        s_default_mount_opts;         uint32_t        s_first_meta_bg;         uint32_t        s_mkfs_time;         uint32_t        s_jnl_blocks[17];         uint32_t        s_blocks_count_hi;         uint32_t        s_r_blocks_count_hi;         uint32_t        s_free_blocks_hi;         uint16_t        s_min_extra_isize;         uint16_t        s_want_extra_isize;         uint32_t        s_flags;         uint16_t        s_raid_stride;         uint16_t        s_mmp_interval;         uint64_t        s_mmp_block;         uint32_t        s_raid_stripe_width;         uint32_t        s_reserved[163]; };  int main(void) {         int fd = 0;         struct ext2_super_block sb;          /* reset sb memory */         memset(&sb, 0, sizeof(struct ext2_super_block));          /*          * /tmp/loop.img created with:          *          * dd if=/dev/zero bs=1024 count=20480 of=/tmp/loop.img          *          * ... , ext2 file system maps entire device.          *          */         fd = open("/tmp/loop.img", o_rdonly);          /* jump superblock */         lseek(fd, 1024, seek_set);          /* read superblock */         read(fd, &sb, sizeof(struct ext2_super_block));          /* print total block count */         printf("s_blocks_count: %" priu32 "\n", sb.s_blocks_count); /* prints 20480 */          return 0; } 

.

some final thoughts

  • doing hand crazy, imo (you must have very, reason :)) [edit 2]: it's simpler thought, [probably] filesystems superblock [may] contain total block count (see answer comments related discussion).
  • if you, evaluate in how many different operating systems that piece of code supposed run, , implement device level information gatherers non-portable calls (being them direct system calls [if any] or library implementations) provided each operating system. then, building process able determine , configure code compile on target machine [edit 2]: still best approach (making use of respective file system libraries).
  • if don't want (or need) code , you're looking linux-specific command-line tool retrieve such data (at device level), go with: blockdev --getsize64 /dev/loop0 [edit 2]: device level information , it's not question refers to.
  • [edit] otherwise, if device level information isn't enough (in case file system maps portion of device size), have answer: dumpe2fs, tune2fs , alike.

Comments

Popular posts from this blog

java - Static nested class instance -

c# - Bluetooth LE CanUpdate Characteristic property -

JavaScript - Replace variable from string in all occurrences -