'preventing errors when implementing the mv command and copying strings from argv

I implemented the move command from linux. I did not try to prevent errors. The program would check if the source file named in argv [1] exists and can be opened, how can I do that? I also think it's a problem copying strings from argv, because I need to call malloc and free which also use system calls and thus affect the performance of the program (if I'm not mistaken)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

int main(int argc, char **argv)
{

  char *source, *destination, *new_source, *new_destination;
  char *current_directory;
  if (argc != 3) {
    printf("usage- %s source destination\n", *argv);
    exit(EXIT_FAILURE);
  }
  // work on copy
  source = (char*)malloc(strlen(argv[1]) + 1);
  strcpy(source, argv[1]);
  destination = (char*)malloc(strlen(argv[2]) + 1);
  strcpy(destination, argv[2]);


            
            current_directory = getenv("PWD");
            new_source = (char*)malloc(strlen(source) + 1 + strlen(current_directory) + 1);
            strcpy(new_source,current_directory);
            strcat(new_source,"/");
            strcat(new_source,source);

  new_destination = (char*)malloc(strlen(destination) + 1 + strlen(current_directory) + 1 + strlen(source) + 1);
  strcpy(new_destination,current_directory);
  strcat(new_destination,"/");
  strcat(new_destination,destination);
  strcat(new_destination,"/");
  strcat(new_destination,source);
  
  /*execute systemcall*/
  if(rename(new_source,new_destination) != 0){
    fprintf(stderr,"error: %s\n",strerror(errno));
  }

  free(new_source);
  free(new_destination);
  free(source);
  free(destination);

  exit(EXIT_SUCCESS)


Solution 1:[1]

The use-cases i see :

  • src || target is a directory
  • src || target is a symlink
  • src || target are not accessible (bad rights)

Take a look at this snippet :

int main(int ac, char **av) {
    if (ac < 3)
        return (1); // bad arguments
    int sfd, tfd = -1;
    if ((sfd = open(av[1], O_RDONLY | O_SYMLINK)) < 0 || (tfd = open(av[2], O_WRONLY | O_CREAT | O_TRUNC | O_SYMLINK, 0666)) < 0)
        return (2); // opens fail
    struct stat sstat, tstat;
    if (stat(av[1], &sstat) || S_ISDIR(sstat.st_mode) || !stat(av[2], &tstat) && S_ISDIR(tstat.st_mode))
        return (3); // no source or source is a directory or target is a directory
    char *sdata = malloc(sstat.st_size);
    if (read(sfd, sdata, sstat.st_size) < 0)
        return (4); // read fail
    if (write(tfd, sdata, sstat.st_size) < 0)
        return (5); // write fail
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1