5

I am making a small program as follows:

void reserve_file_space(char* file_path, size_t amount)
{
    FILE* fp = fopen(file_path, "w+b");
    if(!fp)
    {
        printf("could not create a new file\n");
        return;
    }

    int fseek_ret = fseek(fp, amount, SEEK_SET);
    if(fseek_ret != 0)
    {
        printf("could not seek to the desired position\n");
        fclose(fp);
        return;
    }

    char garbage = 1;
    size_t ret = fwrite(&garbage, 1, 1, fp);
    if(ret != 1)
    {
        printf("could not write the garbage character\n");
    }

    fclose(fp);
}

int main(int argc, char* argv[])
{
    reserve_file_space("C:\\Users\\SysPart\\Desktop\\test.bin", 1 << 30);
    return 0;
}

The free disk space on my PC is around 500 MBs. In the main() if I invokes reserve_file_space("C:\\Users\\SysPart\\Desktop\\test.bin", 1 << 28 /*256 MB*/); it outputs a file created with exact size of 256 MB. However if I invokes reserve_file_space("C:\\Users\\SysPart\\Desktop\\test.bin", 1 << 30 /*1 GB*/); it produces the output file with size of 0 and without printing out any error notice.

How can I learn if the disk space is sufficient to handle correctly?

duong_dajgja
  • 4,196
  • 1
  • 38
  • 65

1 Answers1

3

How can I be learn if the disk space is sufficient to handle correctly?

The standard library has no functions for this. Seeking forward (like you did) is not guaranteed to fail, as the filesystem is at liberty to delay the actual allocation of disk space until that space is actually needed (because you are writing data to it). You only write one character, so only space for that one character (and some metainformation) is actually needed at this point.

To be really sure you will have enough space (even when considering other processes that might take up space after you checked), you would have to write random data of the desired size, then overwrite that with your actual data -- which is not an efficient way to do things.

Standard practice is to just attempt the write (without preallocation), and check that write operation for success. This also avoids a process termination leaving some "pre-reserved" but useless files lying around.

To check available disk space beforehand, you have to rely on OS specific functionality.

For POSIX systems, there is statvfs().

For WinAPI, there is GetDiskFreeSpace().

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 1
    But as always checking if there is enough space then doing your operation creates a race condition where another program might have already used the free space before you get to it. See [this post](https://blogs.msdn.microsoft.com/oldnewthing/20160714-00/?p=93875) for a solution for windows on how to pre-allocate the space without having to write to the file. – RedX Jul 27 '16 at 08:03
  • @RedX: I mentioned that race condition, and I also mentioned why preallocation might not be the best way forward in the first place. – DevSolar Jul 27 '16 at 08:05
  • Sorry, I missed the very important sentence in parenthesis. The link I provide is to a post that details how to reserve space under windows without having to write to the file. I tried to clarify it in my first comment. – RedX Jul 27 '16 at 08:08
  • POSIX statvfs will give you a rough guess, based on the filesystem reserves (e.g. root hold-back that is part of the filesystem, but are not reflective of any further system resources held back. If an exact number of the remaining blocks/size is needed, you will need any OS limits as well. – David C. Rankin Jul 27 '16 at 08:47
  • @DavidC.Rankin: Since the filesystem could conceivably be *compressing*, and there are other processes using and releasing diskspace all the time, a rough guess is all you will get anyway... – DevSolar Jul 27 '16 at 08:51
  • That is a good point as well that I hadn't considered. I took a quick look on my laptop (`640G` drive). `statvfs` reports `425G user available` while `df` says `417` (that's only `8G` off, but that a pretty big deal if you need an exact number) – David C. Rankin Jul 27 '16 at 08:55
  • Bottom line -- attempt the write, check the result. – DevSolar Jul 27 '16 at 08:56
  • I prefer to use `boost::filesystem::space(...)` to check free amount of a directory. However, as mentioned by @RedX we may face to race conditions – duong_dajgja Jul 27 '16 at 08:56
  • 1
    @duong_dajgja: I did not bring up Boost as you tagged the question "C". But yes, that's a convenient wrapper for the OS-specific functions... with all their drawbacks. – DevSolar Jul 27 '16 at 09:02