views:

634

answers:

2

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

+3  A: 

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.

Matt Joiner
but still you will have to issue fread/fwrite with number-of-bytes as parameter, right? That doesnt solve this problem. As you said, he will first have to determine the sector size of his drive and then read n*sector_size data to read nth sector. Correct me if I am wrong here.
vinit dhatrak
you are wrong. :P the point is behind the scenes stdio performs buffering that involves reading whole chunks of size s, and then only providing the pieces you've asked for.
Matt Joiner
exactly, e.g. first 1 byte fread will actually read no of bytes set by setvbuf (sector size in your code) but it will provide just one byte to the application. So to read complete sector, application will have to perform fread of sector-size. Now to determine exact sector size, application will first have to issue an ioctl (BLKSSZGET). I guess this is what Macroideal wants so that he can do I/O in terms of sector.
vinit dhatrak
It seems that i cannot read byte by byte, maybe systems or drive devices were designed to be sector-align....we have no priviilege to change this trait...even with drivers...thanx all the same
Macroideal
+1  A: 

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;
    }
vinit dhatrak