kikkus
kikkus

Reputation: 31

Mount vfat image win linux using C

I'm trying to mount a vfat disk image from DOS, using .C

if( mount( "/mypath/disk.img", "/mypath/img/", "vfat", MS_DIRSYNC | MS_SYNCHRONOUS, "utf8" ) ) { 
  printf( "Error mount %s errno=%d %s\n", dst.c_str(), errno, strerror( errno ) );
}

I get all the times the error "Block device required". Should i add some parameter or flag?

Note:I can mount from the bash the same file in the same target without any error.

UPDATE: I had some good result using the function to mount an ISO. When I run the program, it remains stacked on the call ioctl(loop_device_fd, LOOP_CLR_FD, 0);. When I exit from the program (ctrl-c), the image is mounted. Is LOOP_CLR_FD necessary to complete all the steps? In additional,it is mounted in read only and seems not possible to change it in read/write.

const auto loop_control = std::fopen( "/dev/loop-control", "r" );
const auto loop_control_fd = fileno(loop_control);
const auto devnr = ioctl(loop_control_fd, LOOP_CTL_GET_FREE);
std::stringstream loopname;
loopname << "/dev/loop" << devnr;
const auto loop_device_name = loopname.str();
const auto loop_device = std::fopen(loop_device_name.c_str(), "r");
const auto loop_device_fd = fileno(loop_device);
const auto image = std::fopen( dst.c_str(), "r" );
const auto image_fd = fileno(image);
//Associate the loop device with the open file whose file descriptor is passed as the (third) ioctl(2) argument.
ioctl(loop_device_fd, LOOP_SET_FD, image_fd);
const auto result = mount(loop_device_name.c_str(), dst_path_img.c_str(), "vfat", MS_RDONLY, NULL);
if( result ) {
printf( "Error mount %s errno=%d %s\n", dst.c_str(), errno, strerror( errno ) );
return;
}
ioctl(loop_device_fd, LOOP_CLR_FD, 0);

Upvotes: 3

Views: 1311

Answers (3)

Alex Skalozub
Alex Skalozub

Reputation: 2576

The example code from the link above seems to mount your image quite fine, with minor modifications to retrieve free loop device (I'm assuming it is Dos3.3 diskette image from allbootdisks.com):

#include <sys/mount.h>
#include <linux/loop.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main()
{
    int control_fd, file_fd, device_fd;
    char loop_device[16];

    control_fd = open("/dev/loop-control", O_RDWR);
    if (control_fd < 0) {
        perror("open loop control device failed");
        return 1;
    }

    int loop_id = ioctl(control_fd, LOOP_CTL_GET_FREE);
    sprintf(loop_device, "/dev/loop%d", loop_id);
    close(control_fd);

    printf("using loop device: %s\n", loop_device);

    file_fd = open("./Dos3.3.img", O_RDWR);
    if (file_fd < 0) {
        perror("open backing file failed");
        return 1;
    }

    device_fd = open(loop_device, O_RDWR);
    if (device_fd < 0) {
        perror("open loop device failed");
        close(file_fd);
        return 1;
    }

    if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) {
        perror("ioctl LOOP_SET_FD failed");
        close(file_fd);
        close(device_fd);
        return 1;
    }

    close(file_fd);

    if (mount(loop_device, "./mnt/", "vfat", MS_DIRSYNC | MS_SYNCHRONOUS, "") < 0) {
        perror("mount failed");
    } else {
        printf("mount successful\n");
    }

    // always free loop device in the end
    ioctl(device_fd, LOOP_CLR_FD, 0);      
    close(device_fd);
}

Upvotes: 3

MisterEncryptor
MisterEncryptor

Reputation: 66

The problem here is you're trying to mount an image as you you would do with a block device. A block device has more bindings to the operating system than an image file would, so you need to find a way around this.

Try a loopback device! A loopback device can give you the operating system reference to that image /mypath/disk.img as a block device. You can create a loopback device in bash like so:

# set up a block device
losetup -fP /mypath/disk.img
# now list the loopback devices 
losetup -a

Anyway, this solution is in bash, but certainly there is a library out there somewhere for c.

Upvotes: 1

Seppo Takalo
Seppo Takalo

Reputation: 101

As the disk image is not really a device, it cannot be directly mounted. What you are trying to do, is to mount via a loop device. Command line equivalent is: mount /mypath/disk.img /mypath/img -t vfat -o loop

I'm not sure, but try whether adding the "loop, utf8" as your last parameter would fix the problem.

Upvotes: 1

Related Questions