Thread: Help with a file-backup function

  1. #1
    Registered User
    Join Date
    May 2013
    Posts
    228

    Help with a file-backup function

    Hi.
    I'm writing a small function that gets as parameter a file's path and a folder's path, and copies the given file to that folder.

    Code:
    int copy_file(const char* source, const char* folder) {
    
        char copy[PATH_MAX];
        strcpy(copy, folder);
        strcat(copy, "/");
        strcat(copy, source);
    
        int source_fd;
        int copy_fd;
    
        struct stat source_stat;
        if (stat(source, &source_stat)) {
            perror("stat");
            return 1;
        }
    
        if ((source_fd=open(source, O_RDONLY))==-1) {
            perror("open");
            return 1;
        }
    
        if ((copy_fd=open(copy, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode))==-1) {
            perror("open");
            close(source_fd);
            return 1;
        }
    
        char buffer[READ_BLOCK];
        int bytes_read;
        while ((bytes_read=read(source_fd, buffer, READ_BLOCK))!=0) {
            if (bytes_read==-1) {
                perror("read");
                break;
            }
            if (write(copy_fd, buffer, bytes_read)==-1) {
                perror("write");
                break;
            }
        }
    
        close(source_fd);
        close(copy_fd);
        return 0;
    }
    Basically, this function purpose is to make a backup of source in folder every X minutes (depending on user's input).
    The problem is the second call to open():
    This call attempts to open the file for writing, and creates it if it is not already exist.
    It also truncates it before writing to it - and that's my concern:
    Let's say this is the second time this function runs, so copy is already exist. open() will then truncate it, and then one of the system calls in the while loop fails.
    In this situation, I might be left with no backup file.

    The problem also arises for when source is a read-only file:
    If source is a read-only file, and copy is not already exist (meaning - it's the first backup attempt), then everything's fine, but, if source is a read-only file and copy is already exist, then I have to first remove copy altogather, and make a fresh copy of source.

    Making a backup with new name for copy every time copy_file() runs, will solve this problem, and this is where I need some help:
    Any ideas on how can this be accomplished?

    EDIT

    I should say that I'd really prefer that copy and source will have the same names when copy_file() returns...
    Last edited by Absurd; 10-18-2014 at 08:38 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,663
    You've already got source_stat.st_mode, why don't you use it to figure out what your next step should be?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2013
    Posts
    228
    Hi salem, thanks for your comment.
    The problem wasn't wrinting to a read-only file, but rather creating a new backup without deleting the older backup first.

    Anyway, I found an easy solution eventually that seems to work.

    Code:
    int copy_file(const char* source, const char* folder);
    
    // testing copy_file()
    int main(int argc, char *argv[]) {
    
        if (argc!=3) {
            printf("arguments!\n");
            return 1;
        }
    
        char source[PATH_MAX];
        char dest_folder[PATH_MAX];
        realpath(argv[1], source);
        realpath(argv[2], dest_folder);
        copy_file(source, dest_folder);
    
        return 0;
    }
    
    // both 'source' and 'folder' are guaranteed to be absolute paths
    int copy_file(const char* source, const char* folder) {
    
        char copy[PATH_MAX];
        strcpy(copy, folder);
        strcat(copy, "/");
        strcat(copy, strrchr(source, '/')+sizeof(char)); // 'source' is absolute
        strcat(copy, "_"); // adding underscore to distinguish it from (possible) existing copy
    
        int source_fd;
        int copy_fd;
    
        struct stat source_stat;
        if (stat(source, &source_stat)) {
            perror("stat");
            return 1;
        }
    
        if ((source_fd=open(source, O_RDONLY))==-1) {
            perror("open");
            return 1;
        }
    
        if ((copy_fd=open(copy, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode))==-1) {  // making sure open() creates the file
            perror("open");
            close(source_fd);
            return 1;
        }
    
        char buffer[READ_BLOCK];
        int bytes_read;
        while ((bytes_read=read(source_fd, buffer, READ_BLOCK))!=0) {
            if (bytes_read==-1) {
                perror("read");
                break;
            }
            if (write(copy_fd, buffer, bytes_read)==-1) {
                perror("write");
                break;
            }
        }
        close(source_fd);
        close(copy_fd);
    
        
        char older_backup[PATH_MAX]={0};
        strncpy(older_backup, copy, strlen(copy)-1);
        // if an older backup exists
        if (!access(older_backup, F_OK)) {
            if (unlink(older_backup)) {
                perror("unlink");
                return 1;
            }
        }
    
        // renaming new backup
        if (rename(copy, older_backup)) {
            perror("rename");
            return 1;
        }
    
    
        return 0;
    }

  4. #4
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,115
    Why not append the date [and time] to the backup file name when creating the file.

  5. #5
    Registered User
    Join Date
    May 2013
    Posts
    228
    Quote Originally Posted by rstanley View Post
    Why not append the date [and time] to the backup file name when creating the file.
    That's a good idea.
    But then how will I delete the older backup?
    If I'll add some date-time format to the file's name, then it'll be unique.
    How will I locate it?

    EDIT

    To be more specific:

    Code:
        if (!access(/* what should go here? */, F_OK)) {
            if (unlink(/*...*/)) {
                perror("unlink");
                return 1;
            }
        }
    Last edited by Absurd; 10-18-2014 at 12:51 PM.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    If you are only going to have at most two backups at any point of time, then specially designating the newer and older backup file names as in your post #3 makes sense. You would not need to involve date/timestamps since you will not be keeping additional backups long after the newest backup.

    Incidentally, this:
    Code:
    strcpy(copy, folder);
    strcat(copy, "/");
    strcat(copy, source);
    might be better written as:
    Code:
    snprintf(copy, PATH_MAX, "%s/%s", folder, source);
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. We don't need to backup...
    By Salem in forum A Brief History of Cprogramming.com
    Replies: 14
    Last Post: 10-19-2007, 01:12 PM
  2. suggestions for my file backup app (for linux)
    By Lateralus in forum C Programming
    Replies: 4
    Last Post: 08-02-2005, 08:58 AM
  3. Backup software
    By Waldo2k2 in forum Tech Board
    Replies: 4
    Last Post: 11-21-2003, 12:49 PM
  4. Backup - Registry & File :: MFC
    By kuphryn in forum Windows Programming
    Replies: 2
    Last Post: 06-03-2002, 08:32 PM
  5. Backup function
    By Unregistered in forum C Programming
    Replies: 0
    Last Post: 01-02-2002, 07:23 AM