0

I am very new to C programming and there is little helpful information anywhere on how to do recursive copying of the contents of a directory in C (not C++,C#, Objective-C, Java, shell, Python, or anything else--this MUST be done in C). Yes, this is homework and it is due tomorrow night, and I have been stuck for almost two weeks trying to get this done.

I am trying to search for any backup versions of a given directory (e.g. a directory "dir" with a backup directory "/dir.bak"). If there is not, create that "/dir.bak" directory, or if there is, create a backup directory named "/dir.bak.MM-DD-YY-HH-MM-SS" instead. Then copy everything from the source directory into the destination directory.

When I attempt to run this code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>

#define BUFSIZE 256

int main (int argc, char* argv[])
{
    DIR *dir;
    struct dirent *dentry;
    struct stat statbuff;
    char buffer[BUFSIZE];//holds time and date suffix
    ssize_t count;
    int fdin, fdout;    
    mode_t  perms =  740;//perms for file I/O ops
    char *cwdNamePntr;
    long maxpath;
    if ( argc != 3 ) //if incorrect number of args passed in...
    {
        printf( "Usage: %s Directory-Path-Name Destination-Folder\n ", argv[0] );
        exit(1);
    }
    char  buffer2[BUFSIZE];//buffer for file I/O ops
    char* datetime;
    int retval;
    time_t  clocktime;
    struct tm  *timeinfo;
    time (&clocktime);
    timeinfo = localtime( &clocktime );
    strftime(buffer, BUFSIZE, "%b-%d-%Y-%H-%M-%S", timeinfo);//store time and date suffix in case we need it
    chdir(argv[1]);
    char *path = argv[2];//source path for I/O ops
    char *newpath = malloc(strlen(path) + 26);//destination paths for I/O ops
    strcpy(newpath,path);
    strcat(newpath,".bak");//test name for backup directory
    if(chdir(newpath)==0)
    {//if our test name is already a directory
        chdir("..");
        strcat(newpath,".");
        strcat(newpath,buffer);//add time and date suffix onto the name of new backup directory
    }
    if ( (mkdir(newpath, perms)) == 0 )//if we successfully made a new backup directory
    {
        chdir(path);
        dir = opendir(".");//move into source directory
        if ( dir ==  0 )
        {//if open directory fails
                fprintf (stderr, "Error in opening directory:  %s\n", path );
            perror( "Could not open directory");
                exit(2);
        }
        dentry = readdir (dir);//load directory

        while (dentry != 0)//while we are reading a directory
        {
            char *filename = dentry->d_name;//get name of file to be copied
            if( (strcmp(filename,".")!=0) && (strcmp(filename,"..")!=0) )
            {
                if  ( (fdin = open ( filename,  O_RDONLY))  == -1)
                {//if cannot open input file
                        perror ( "Error in opening the input file:");
                        exit (2);
                }
                chdir("..");//go back to parent directory
                chdir(newpath);//move to destination directory
                opendir(".");
                if  ( (fdout = open (filename, (O_WRONLY | O_CREAT), perms)) == -1 )
                {//if cannot create output file...
                        perror ( "Error in creating the output file:");
                        exit (3);
                }
                while ( (count=read(fdin, buffer2, BUFSIZE)) > 0 )
                {
                        if ( write (fdout, buffer2, count) != count )
                    {//if cannot write   
                                perror ("Error in writing" );
                                exit(3);
                        }
                } 

                    if ( count == -1 )
                    {//if cannot read
                        perror ( "Error while reading the input file: ");
                        exit(4);
                }

                close(fdin);
                close(fdout);
            }
            chdir("..");//back to parent directory again
            dir = opendir(".");
            if ( dir ==  0 )//if open directory fails
            {
                    fprintf (stderr, "Error in opening directory:  %s\n", path );
                perror( "Could not open directory");
                    exit(666);
            }
            dentry = readdir (dir);//reload directory
        }
    }
    else
    {
        perror("Error in directory creation");
        exit(2);
    }
    return 0;  
}

I get THIS error:

[my-desktop]@ubuntu:~/Desktop$ ./helpmehelpyou.out ~/Desktop new
Error in creating the output file:: Permission denied

A bunch of this code was taken from sample files which our instructors said we could use. I don't understand why this is not working right? The finished function must be recursive and is part of a four-choice program with this being option 4. C is very hard for me to grasp or understand, and like I said, there is very little information about this stuff for C, but an overabundance of it for C#, C++, Objective C, and every other language. And like I also said, we MAY NOT use shell commands or anything else for this assignment.

Can someone please help me? Thanks!

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • That's an awful lot of code you're asking us to look through. I suggest you at least do some debugging on your own to find **when** in the execution of your program this error occurs. Once you know that, you should probably construct a [minimal test-case](http://sscce.org) around it. – Oliver Charlesworth Mar 02 '13 at 17:34
  • do you have permissions for creating the file? – niculare Mar 02 '13 at 17:34
  • This doesn't seem very 'recursive' to me. Don't you have to call the 'search this directory' function for each path and subpath for this to work? – Refugnic Eternium Mar 02 '13 at 17:36
  • @niculare I changed the perms variable to 0740, and then it copied one file from my source directory to my destination directory. I have three files in source: test1, test2, test3. It copied test3 to the destination and then gave me this error: "Error in opening the input file:: No such file or directory" –  Mar 02 '13 at 17:40
  • @Oli Charlesworth, yes, it is a lot of code. I have done a lot of debugging and re-writing of this for two weeks and still do not have answers. The minimal test-case link you gave me is quite long and I cannot spot the information I need to be of use to me. –  Mar 02 '13 at 17:42
  • @RefugnicEternium No this is not recursive yet, I have not yet implemented that but I feel I can. I am just trying to get something working now, to build on that, ya know? –  Mar 02 '13 at 17:43
  • Well this isn't going to be something you can build on, ya know.. first step: build a function that can copy a directory with plain files in it. step two: extend it so it handles the directory entries in the directory. step three: profit. – Karoly Horvath Mar 02 '13 at 17:46
  • @KarolyHorvath Yeah, well, I need help on the first step, that's why I posted a question here. When I get past that, I will worry about steps two and three. –  Mar 02 '13 at 17:50
  • @millerseke: the premise is, find out which line(s) of code causes the problem, and then write a simple test program around that line. Doing this avoids the animosity that naturally arises when people dump all their code on Stack Overflow and ask people to debug it for them ;) – Oliver Charlesworth Mar 02 '13 at 17:52
  • Anyone who can give me SPECIFIC tips and pointers on how to do this, I would really appreciate it! I am not at the level of a lot of you guys! I have been putting in a LOT of effort here for two weeks without any breakthrough! I posted a question here to get HELP!!!!!! –  Mar 02 '13 at 17:54
  • 1
    @millerseke: A specific tip is: add print statements **everywhere** (or use a debugger) in order to trace the activity of your program. This will help you identify **when** the error occurs. – Oliver Charlesworth Mar 02 '13 at 17:55
  • 1
    We are trying to help you, really. It's just that it's a lot of code and we don't have a debugger here to see which line actually causes the problem. Now, have you checked, that the directory it's supposed to go to actually gets created? – Refugnic Eternium Mar 02 '13 at 17:55
  • @OliCharlesworth Out of my three test files (per my above comment to niculare), it copies test3 then breaks down because it cannot find test2. –  Mar 02 '13 at 17:58
  • @millerseke: It may have been snide, but it was a completely valid point. Don't try to write your code in one hit. Get simple things working, and then build around them. – Oliver Charlesworth Mar 02 '13 at 18:02
  • @OliCharlesworth Ain't nothing valid about blatantly mocking my prior remark and then simply telling me I should do something without giving me tips on how to do it. I don't understand what it is with coders who have a lot of experience thinking everyone should be at their level and if they aren't that's like some horrible travesty to them? I am still stuck on the simple things because of my inexperience and it's people like them that really make me grit my teeth about logging on to help websites. –  Mar 02 '13 at 18:08
  • PROBLEM SOLVED. I didn't change back into my source directory. Thanks, Oli, Refugnic, and niculare. I truly do appreciate the help. I will be sure to clean up the code also. Karoly, I will let it slide this time. –  Mar 02 '13 at 18:14
  • I'm trying to help you and you call me an a*? Dude, you have some serious problems. – Karoly Horvath Mar 02 '13 at 18:26
  • @KarolyHorvath Your comment at the time was not helpful at all, that's the way I saw it then. Perhaps you need to more considerately choose your words so nervous newbies like me don't take them as an attack. Good day to you. –  Mar 17 '13 at 01:18

1 Answers1

2

This won't solve your problem, but I spotted a possible error in your code. I don't see the recursion happening.

You see, this code may work fine if you only have one subfolder. But what do you do, if there's a subfolder in that subfolder?

You need a recursive directory search function. This may look like this:

void SearchDirectory(const char *name) {
    DIR *dir = opendir(name);                //Assuming absolute pathname here.
    if(dir) {
        char Path[256], *EndPtr = Path;
        struct dirent *e;
        strcpy(Path, name);                  //Copies the current path to the 'Path' variable.
        EndPtr += strlen(name);              //Moves the EndPtr to the ending position.
        while((e = readdir(dir)) != NULL) {  //Iterates through the entire directory.
            struct stat info;                //Helps us know about stuff
            strcpy(EndPtr, e->d_name);       //Copies the current filename to the end of the path, overwriting it with each loop.
            if(!stat(Path, &info)) {         //stat returns zero on success.
                if(S_ISDIR(info.st_mode)) {  //Are we dealing with a directory?
                    //Make corresponding directory in the target folder here.
                    SearchDirectory(Path);   //Calls this function AGAIN, this time with the sub-name.
                } else if(S_ISREG(info.st_mode) { //Or did we find a regular file?
                    //Run Copy routine
                }
            }
        }
    }
}

This code will call the function SearchDirectory for as many times as there are subdirectories in the current folder. If the architecture runs too deep you may run out of memory and the program may crash, so please beware.

Once it cannot find any more directories in the folder (it has reached the 'leaf'-folders), it will iterate over the remaining files and then end the function, popping the last function call from the stack, allowing the previous call to SearchDirectory to continue searching.

After all is said and done, you'll have a full recursive copy.

P.S: Sorry for the spoiler, I read your comment only after I was done typing.

Refugnic Eternium
  • 4,089
  • 1
  • 15
  • 24