10

Using the following code, I'm able to successfully open a raw disk on my machine, but when I get the disk length I get 0 each time...

// Where "Path" is /dev/rdisk1 -- is rdisk1 versus disk1 the proper way to open a raw disk?
Device = open(Path, O_RDWR);
if (Device == -1)
{
    throw xException("Error opening device");
}

And getting size with both of these methods returns 0:

struct stat st;

if (stat(Path, &st) == 0)
    _Length = st.st_size;

/

_Length = (INT64)lseek(Device, 0, SEEK_END);
        lseek(Device, 0, SEEK_SET);

I'm not totally familiar with programming on non-Windows platforms, so please forgive anything that seems odd. My questions here are:

  1. Is this the proper way to open a raw disk under OS X?
  2. What might be causing the disk size to be returned as 0?

The disk in question is an unformatted disk, but for those wanting the info from Disk Utility (with non-important stuff removed):

Name :  ST920217 AS Media
Type :  Disk

Partition Map Scheme :  Unformatted
Disk Identifier      :  disk1
Media Name           :  ST920217 AS Media
Media Type           :  Generic
Writable             :  Yes
Total Capacity       :  20 GB (20,003,880,960 Bytes)
Disk Number          :  1
Partition Number     :  0
tshepang
  • 12,111
  • 21
  • 91
  • 136
Lander
  • 3,369
  • 2
  • 37
  • 53
  • While a good way to access the raw disk, getting the size like that might not work as you noticed (also, you should probably try `lseek64` first). It might be possible to get the size using `ioctl` or `fcntl`, otherwise you have to resort to getting the information through some special OSX-specific function. – Some programmer dude Jan 31 '12 at 06:59
  • @JoachimPileborg Well I have _FILE_OFFSET_BITS 64 defined... do these not act the same? – Lander Jan 31 '12 at 19:04
  • @JoachimPileborg doing: `lseek(Device, 0x7FFFFFFF - 1, SEEK_SET)` actually returns 0x7FFFFFFE, so either bits are being dropped or disks don't support `lseek(..., 0, SEEK_END);`, but from my understanding they should. edit: I don't know why I didn't do `lseek(Device, 0xFFFFFFFF + 5, SEEK_SET)` before, but that returns 4, so I assume bits are being dropped. – Lander Jan 31 '12 at 19:38
  • Okay. I went out today and realized that I'm just not on top of my game today. 0xFFFFFFFF + 5 produced 4 because of the bit overflow (and not casting it as an INT64). When I seek directly to `20003880960L`, my app outputs "Disk opened successfully. Length: 0x4A8530000". So sorry for that confusion... – Lander Feb 01 '12 at 00:28
  • @Lander: would you care to edit or briefly answer your question yourself? – Jirka Hanika Mar 18 '12 at 21:18
  • @JirkaHanika I would have done so already if I actually did find the answer, but I've still gotten nothing and sort of put this issue off to the backburner for now. I'll look into using `ioctl` calls and if I get something I will do so. Thank you for reminding me that I have left this unanswered though, as finding empty results in Google is no fun. – Lander Mar 19 '12 at 02:04
  • @JirkaHanika found a solution, posted the answer. – Lander Mar 19 '12 at 03:07

1 Answers1

8

After a little bit of searching through ioctl request codes, I found something that actually works.

#include <sys/disk.h>
#include <sys/ioctl.h>
#include <fcntl.h>

int main()
{
    // Open disk
    uint32_t dev = open("/dev/disk1", O_RDONLY);

    if (dev == -1) {
        perror("Failed to open disk");
        return -1;
    }

    uint64_t sector_count = 0;
    // Query the number of sectors on the disk
    ioctl(dev, DKIOCGETBLOCKCOUNT, &sector_count);

    uint32_t sector_size = 0;
    // Query the size of each sector
    ioctl(dev, DKIOCGETBLOCKSIZE, &sector_size);

    uint64_t disk_size = sector_count * sector_size;
    printf("%ld", disk_size);
    return 0;
}

Something like that should do the trick. I just copied the code I had into that, so I'm not sure if it would compile alright but it should.

Lander
  • 3,369
  • 2
  • 37
  • 53
  • Actually it wont work like that - unsigned int Sectors needs to be at least unsigned Long, otherwise the first ioctl will result in other stack variables being trashed ( "dev" gets written to zero with default compiler settings and a reasonably small disk being probed ) More appropriately, these variables need to be uint64_t and uint32_t as per data structures in sys/disk.h – kert Nov 26 '13 at 22:36
  • @Lander I am trying your code but I always get error in "open", do you know what the cause may be? – RuLoViC Nov 12 '18 at 17:31
  • @RuLoViC could be related to [System Integrity Protection](https://apple.stackexchange.com/questions/208478/how-do-i-disable-system-integrity-protection-sip-aka-rootless-on-macos-os-x) or perhaps you need to run your application as root. Mapping the error code would give you a better idea. The syscall will set `errno` which you can then compare against the values [here](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/open.2.html). – Lander Nov 19 '18 at 17:48
  • What would be the correct way to work around SIP? I'm trying to open a device (external USB disk), but even as root, MacOS (10.1.4.2) will not give me access. – Hanzaplastique Feb 07 '19 at 10:35