Replace the content of a file by zero-bytes and keep the same filesize Here is a little tool for Windows that replaces the content of a file with zero-bytes, keeping the same filesize. It works. The goal is to be sure that the old bytes-content of the file is no more recoverable on disk.

Question: how to be 100% sure that it replaces the content in-place and that it doesn't allocate new sectors on disk to write the zero bytes? (thus leaving the old content somewhere else, still possibly accessible, which would be a security hole!)

Note: I know that freewares exist for this, but I would like to try a simple implementation first

Note2: I know that some more advanced wiping techniques exist (random content and/or multi-pass, etc.), but for me zeroing the content is enough if at least I know that the zeroing is done in-place, i.e. if the new zero bytes replace the old content at the same location on disk (and not moved to another sectors on disk!)

Could you review the following code?

#include &lt;stdio.h&gt;

int main(int argc, char *argv[])
{
    FILE *f;

    if (argc != 2) { fprintf (stderr, "Usage: %s &lt;file&gt;\n", argv[0]); exit(1); }

    if ((f = fopen(argv[1], "rb+")) == NULL) { perror("Error opening the file"); exit(1); }

    fseek(f, 0L, SEEK_END);
    unsigned long size = ftell(f);
    fseek(f, 0L, SEEK_SET);

    char buf[1024] = {0};
    unsigned long num = size / 1024;
    int remaining = size % 1024;

    for (unsigned long i = 0; i &lt; num; i++)
        fwrite(buf, 1, 1024, f);

    fwrite(buf, 1, remaining, f);

    fclose(f);
    exit(0);
}
Here are some suggestions that may help you improve your code.

Use return rather than exit()

The effect of using exit(0) or exit(1) is going to be identical to return 0 or return 1 but with one difference: exit() is a library call and would therefore require #include &lt;stdlib.h&gt; (which this program does not have) while return does not require any particular #include.  Also note that exit(0) implicitly flushes and closes files, as does return 0.  Further, the equivalent to return 0; is provided by the compiler if omitted (since C99), so technically, the last two lines of the program:

fclose(f);
exit(0);


could both be omitted with no change to the function of the program.  If, however, you decided to move this part of the function to a separate function, I'd suggest keeping fclose(f); and using return 0; rather than exit(0);.  Tastes vary on this point.

Don't cram multiple statements per line

Lines such as this:

if ((f = fopen(argv[1], "rb+")) == NULL) { perror("Error opening the file"); exit(1); }


tend to be more readable if formatted as separate lines:

if ((f = fopen(argv[1], "rb+")) == NULL) { 
    perror("Error opening the file"); 
    return 1; 
}


Check return values

The code does check for the return value of fopen, which is good, but does not check the return values for fseek, ftell and fwrite which can also fail.

Use named constants

The number 1024 appears multiple times in the code.  If one wanted, for instance, a 2k buffer instead, one would have to change it all three places.  Using a named constant instead simplifies maintenance and makes the code easier to read as well.

Understand the bounds of standard C

The C language is very expressive and has a great number of handy library functions for doing things like reading and writing files.  However, what exactly the underlying operating system does to manage files on disk is outside the domain of C and squarely in the domain of the OS and hardware designers.  There is, in short, no guarantee that this code will physically overwrite the same sectors of physical media, and more importantly, no provision in standard C for doing so.  To take just one example, if I run a virtual Windows machine on a system that actually runs on a cluster of Linux machines, there might not actually even be any physical media.