Search code examples
c++copymemory-efficientrobustnessrobust

C++ most robust way to copy a file


Okay, so I know that disk writing errors are very rare, so please just look past that because the data I am working with is very incredibly important (like SSIDs kind of important). So, I want to copy a file in the absolute most robust way using the absolute minimal amount of memory to do so. So far, this is was far as I have got. It sucks up a lot of memory, but I can't find the source. The way it works is by rechecking tons of times until it gets a confirmed result (it may increase the number of false positives for errors by a lot, but it might reduce the chance of an actual error by a big margin). Also, the sleep at the bottom is so you have time to analyze the programs overall performance using the windows task manager.


#include <cstdio>   // fopen, fclose, fread, fwrite, BUFSIZ
#include <cstdlib>
#include <unistd.h>
#include <iostream>

using namespace std;

__inline__ bool copy_file(const char* From, const char* To)
{
    FILE infile = (*fopen(From, "rb"));
    FILE outfile = (*fopen(To, "rwb+"));
    setvbuf( &infile, nullptr, _IONBF, 0);
    setvbuf( &outfile, nullptr, _IONBF, 0);

    fseek(&infile,0,SEEK_END);
    long int size = ftell(&infile);
    fseek(&infile,0,SEEK_SET);
    unsigned short error_amount;
    bool success;
    char c;
    char w;
    char l;

    for ( fpos_t i=0; (i != size); ++i ) {
        error_amount=0;
        fsetpos( &infile, &i );
        c = fgetc(&infile);
        fsetpos( &infile, &i );
        success=true;
        for ( l=0; (l != 126); ++l ) {
            fsetpos( &infile, &i );
            success = ( success == ( fgetc(&infile)==c ) );
        }
        while (success==false) {
            fsetpos( &infile, &i );
            if (error_amount==32767) {
                cerr << "There were 32768 failed attemps at accessing a part of the file! exiting the program...";
                return false;
            }
            ++error_amount;
            //cout << "an error has occured at position ";
            //printf("%d in the file.\n", (int)i);
            c = fgetc(&infile);
            fsetpos( &infile, &i );
            success=true;
            for ( l=0; (l != 126); ++l ) {
                fsetpos( &infile, &i );
                success = ( success == ( fgetc(&infile)==c ) );
            }
        }



        fsetpos( &infile, &i );
        fputc( c, &outfile);
        fsetpos( &outfile, &i );


        error_amount=0;
        w = fgetc(&infile);
        fsetpos( &outfile, &i );
        success=true;
        for ( l=0; (l != 126); ++l ) {
            fsetpos( &outfile, &i );
            success = ( success == ( fgetc(&outfile)==w ) );
        }
        while (success==false) {
            fsetpos( &outfile, &i );
            fputc( c, &outfile);
            if (error_amount==32767) {
                cerr << "There were 32768 failed attemps at writing to a part of the file! exiting the program...";
                return false;
            }
            ++error_amount;
            w = fgetc(&infile);
            fsetpos( &infile, &i );
            success=true;
            for ( l=0; (l != 126); ++l ) {
                fsetpos( &outfile, &i );
                success = ( success == ( fgetc(&outfile)==w ) );
            }
        }
        fsetpos( &infile, &i );
    }

    fclose(&infile);
    fclose(&outfile);

    return true;
}

int main( void )
{
    int CopyResult = copy_file("C:\\Users\\Admin\\Desktop\\example file.txt","C:\\Users\\Admin\\Desktop\\example copy.txt");

    std::cout << "Could it copy the file? " << CopyResult << '\n';

    sleep(65535);
    return 1;
}


So, if my code is on the right track with the best way, then what can be done with my code to improve it? But, if my code is totally off with the best solution, then what is the best solution? Please note that this question is essentially about detection of rare disk writing errors for the application of copying very very very very (etc.) important data.


Solution

  • #include <boost/filesystem.hpp>
    #include <iostream>
    
    int main()
    {
        try
        {
            boost::filesystem::copy_file( "C:\\Users\\Admin\\Desktop\\example file.txt",
                                          "C:\\Users\\Admin\\Desktop\\example copy.txt" );
        }
        catch ( boost::filesystem::filesystem_error const & ex )
        {
            std::cerr << "Copy failed: " << ex.what();
        }
    }
    

    This will call the arguably most robust implementation available -- the one provided by the operating system -- and report any failure.


    My point being:

    The chance of having your saved data end up corrupted are astronomically small to begin with.

    Any application where this might actually be an issue should be running on redundant storage, a.k.a. RAID arrays, filesystems doing checksums (like Btrfs, ZFS) etc., again reducing chance of failure significantly.

    Doing complex things in home-grown I/O functions, on the other hand, increases the probability of mistakes and / or false negatives immensely.