Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query size of block device file in Python

I have a Python script that reads a file (typically from optical media) marking the unreadable sectors, to allow a re-attempt to read said unreadable sectors on a different optical reader.

I discovered that my script does not work with block devices (e.g. /dev/sr0), in order to create a copy of the contained ISO9660/UDF filesystem, because os.stat().st_size is zero. The algorithm currently needs to know the filesize in advance; I can change that, but the issue (of knowing the block device size) remains, and it's not answered here, so I open this question.

I am aware of the following two related SO questions:

  • Determine the size of a block device (/proc/partitions, ioctl through ctypes)
  • how to check file size in python? (about non-special files)

Therefore, I'm asking: in Python, how can I get the file size of a block device file?

like image 705
tzot Avatar asked May 05 '10 13:05

tzot


2 Answers

The “most clean” (i.e. not dependent on external volumes and most reusable) Python solution I've reached, is to open the device file and seek at the end, returning the file offset:

def get_file_size(filename):
    "Get the file size by seeking at end"
    fd= os.open(filename, os.O_RDONLY)
    try:
        return os.lseek(fd, 0, os.SEEK_END)
    finally:
        os.close(fd)
like image 162
tzot Avatar answered Oct 17 '22 17:10

tzot


Linux-specific ioctl-based solution:

import fcntl
import struct

device_path = '/dev/sr0'

req = 0x80081272 # BLKGETSIZE64, result is bytes as unsigned 64-bit integer (uint64)
buf = b' ' * 8
fmt = 'L'

with open(device_path) as dev:
    buf = fcntl.ioctl(dev.fileno(), req, buf)
bytes = struct.unpack('L', buf)[0]

print device_path, 'is about', bytes / (1024 ** 2), 'megabytes'

Other unixes will have different values for req, buf, fmt of course.

like image 8
rmsr Avatar answered Oct 17 '22 15:10

rmsr