Recently, i am on a project which needs raw read / write sector of drives

2.6k views Asked by At

Before, I post a question here asking for advice on how to read and write data from and into drive, not via file label like "aaa.txt", but just sectors.. I was advised to try read and write.... but new problems'v raised... the hairy parameters

int _read( int handle, void *buffer, unsigned int count );

when i use the function and wanto read sectors from drive...i seems i need to set the count to be x*512. it has to be several times of 512 bytes...

why??? Are there some raw functions allowing me to use directly byte by byte... Thanx... btb, if i wanto do that, I should develope my own I/O driver programs? thanx

2

There are 2 answers

4
Matt Joiner On BEST ANSWER

Reads and writes to devices must be both sector aligned, and with byte counts that are integer multiples of the sector size.

Don't make assumptions about the sector size, you should query the sector size for any device, and work dynamically with that. Typical sizes are 512 for hard drives, and 2048 for optical drives.

If you want functions that allow you to read byte by byte on devices, without incurring wasteful overhead, try this trick:

FILE *file_pointer = fopen("/path/to/device", "rb");
size_t sector_size;
ioctl(fd, BLKSSZGET, &sector_size);
setvbuf(file_pointer, NULL, _IOFBF, sector_size);

If you need to get the sector size on Windows you can call DeviceIoControl() with IOCTL_DISK_GET_DRIVE_GEOMETRY.

Stdio will align seeks to s and read chunks of size s. Additionally you can provide a buffer of your own using posix_memalign(), or _aligned_malloc(), if your underlying stdio implementation doesn't do this.

Edit: To clear up some confusion in a comment

You're working with a device with sector size 512, with FILE *f;. You fseek() to offset 37. f's position is updated, but no seek is made on the device. You fread() 500 bytes. lseek() is called with an offset of 0. 512 bytes are read into f's buffer. Bytes 37 to 512 are copied to the buffer you provided. lseek() is called with an offset of 512. 512 bytes are read, and the remaining 463 bytes you're expecting are copied out to the buffer you passed to fread(). If you were to now fread() a single byte, that would simply be copied out of the existing buffer in f, without hitting the device.

0
Vinit Dhatrak On

Here, I am assuming you are using linux as the platform. On linux, each device is a file. You will find a device entry in /dev. This means you can do I/O using read/write on that drive e.g. you can directly open your hard disk partition by opening /dev/sda1 and read n number of bytes.

Use following code to determine exact sector size for your drive (no error handling in the code). If you want to read nth sector then just read n*sector_size bytes from the opened device. Hope this helps to solve your problem.

    #include <stdio.h>
    #include <linux/fs.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>

    #define SECTOR_NO 10 /*read 10th sector*/

    int main()
    {
            int sector_size;
            char *buf;
            int n = SECTOR_NO;

            int fd = open("/dev/sda1", O_RDONLY|O_NONBLOCK);
            ioctl(fd, BLKSSZGET, &sector_size);
            printf("%d\n", sector_size);
            lseek(fd, n*sector_size, SEEK_SET);

            buf = malloc(sector_size);
            read(fd, buf, sector_size);

            return 0;
    }