How can I copy a file on Unix using C?

前端 未结 8 665
说谎
说谎 2020-11-27 12:39

I\'m looking for the Unix equivalent of Win32\'s CopyFile, I don\'t want to reinvent the wheel by writing my own version.

相关标签:
8条回答
  • 2020-11-27 13:06

    There is a way to do this, without resorting to the system call, you need to incorporate a wrapper something like this:

    #include <sys/sendfile.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    /* 
    ** http://www.unixguide.net/unix/programming/2.5.shtml 
    ** About locking mechanism...
    */
    
    int copy_file(const char *source, const char *dest){
       int fdSource = open(source, O_RDWR);
    
       /* Caf's comment about race condition... */
       if (fdSource > 0){
         if (lockf(fdSource, F_LOCK, 0) == -1) return 0; /* FAILURE */
       }else return 0; /* FAILURE */
    
       /* Now the fdSource is locked */
    
       int fdDest = open(dest, O_CREAT);
       off_t lCount;
       struct stat sourceStat;
       if (fdSource > 0 && fdDest > 0){
          if (!stat(source, &sourceStat)){
              int len = sendfile(fdDest, fdSource, &lCount, sourceStat.st_size);
              if (len > 0 && len == sourceStat.st_size){
                   close(fdDest);
                   close(fdSource);
    
                   /* Sanity Check for Lock, if this is locked -1 is returned! */
                   if (lockf(fdSource, F_TEST, 0) == 0){
                       if (lockf(fdSource, F_ULOCK, 0) == -1){
                          /* WHOOPS! WTF! FAILURE TO UNLOCK! */
                       }else{
                          return 1; /* Success */
                       }
                   }else{
                       /* WHOOPS! WTF! TEST LOCK IS -1 WTF! */
                       return 0; /* FAILURE */
                   }
              }
          }
       }
       return 0; /* Failure */
    }
    

    The above sample (error checking is omitted!) employs open, close and sendfile.

    Edit: As caf has pointed out a race condition can occur between the open and stat so I thought I'd make this a bit more robust...Keep in mind that the locking mechanism varies from platform to platform...under Linux, this locking mechanism with lockf would suffice. If you want to make this portable, use the #ifdef macros to distinguish between different platforms/compilers...Thanks caf for spotting this...There is a link to a site that yielded "universal locking routines" here.

    0 讨论(0)
  • 2020-11-27 13:10
    sprintf( cmd, "/bin/cp -p \'%s\' \'%s\'", old, new);
    
    system( cmd);
    

    Add some error checks...

    Otherwise, open both and loop on read/write, but probably not what you want.

    ...

    UPDATE to address valid security concerns:

    Rather than using "system()", do a fork/wait, and call execv() or execl() in the child.

    execl( "/bin/cp", "-p", old, new);
    
    0 讨论(0)
提交回复
热议问题