Auto USB copy program

TheDennis

New Member
Joined
Jan 23, 2019
Messages
11
Reaction score
2
Credits
0
I made a c code to automatically copy a folder in an usb drive whenever you plug the stick in. In the "softwares that run at start" thing ( don't know the name in english), I added a new program, linked to the main.c class I made. But it obviously doesn't work. Ideas? (that's my first time doing this kind of things btw ;D)
Code, if it helps:
Code:
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#define PATH "/media/dennis_orlando/ORLANDO D/Foto"

int main(){
    int done = 0;
    while (1== 1){
            DIR *dir;
            dir = opendir(PATH);
            if (dir != NULL){
                if (done == 0){
                    int a = system("echo password | cp -na '/media/dennis_orlando/ORLANDO D/Foto' '/home/dennis_orlando/Scrivania/'");
                    if (a == -1) printf("something went wrong while copying files");
                    else {
                        done = 1;
                        printf("\nsuccesfully copied files\n");
                    }
                }
            }
            else done = 0;
            sleep(1);
    }
    return 0;
}

PS: I'm using Eclipse

EDIT: changed title of this thread
 
Last edited:


@JasKinasis ....where are you mate ?....this looks like it might be right up your alley.

(definitely not my forte !!)
 
The main thing you are missing is the -r (recursive) flag in your cp command.
Without that the cp command will fail to copy the content of the directory.

Another problem is the infinite loop you have set up.
I would change the condition to while (done != 1). Otherwise, after copying the files - your program will reiterate again, re-detect the source directory and run the cp command over and over again. Which will probably be as bad as not doing anything!

By changing the condition of the while loop, your program will only run until the required directory appears and is copied successfully. As soon as the files have been copied, it will end.

Also, the sleep() command should only be used if we need to reiterate through the loop again. We don't need to sleep the process after successfully copying the files - it would make more sense to just end the program straight away.

So I have put the sleep inside the else condition. And setting the value of done to zero in the else is redundant. It is initialised to zero when the program starts up and only gets changed to 1 when the files have been copied. Which is immediately before the program ends.

Also, in the case where there is a problem copying the files - I have made the program exit with an error status. Otherwise you are likely to end up getting the error message over and over again as it tries and fails to copy the files....

To test the code - I made a couple of test directories.
/home/jason/tmp/dir1/ <<<< Note no space in the directory name
/home/jason/tmp/dir2/

I set up the program to look for a source directory called "/home/jason/tmp/dir 1/" <<< Note the space
And then when "dir 1" is detected it recursively copies all of "dir 1" to "/home/jason/tmp/dir2/".
After building your program and running it in a terminal, the program went into its loop because it could not find "dir 1". (my directory was called "dir1")

I opened up a second terminal window and executed the following command:
Code:
mv /home/jason/tmp/dir1 /home/jason/tmp/dir\ 1/
which renamed "dir1" to "dir 1".
And immediately I got a message in my other terminal window saying "sucessfully copied files".
And I quickly navigated into /home/jason/tmp/dir2/ to see that "dir 1" and its contents were copied to dir2!

So with the changes I have suggested, your code should work and should look something like this:
Code:
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>

#define PATH "/media/dennis_orlando/ORLANDO D/Foto"

int main()
{
    int done = 0;
    while (done != 1)
   {
            DIR *dir;
            dir = opendir(PATH);
            if (dir != NULL){
                if (done == 0)
               {
                   int a = system("echo password | cp -na '/media/dennis_orlando/ORLANDO D/Foto' '/home/dennis_orlando/Scrivania/'");
                   if (a == -1) 
                   {
                       printf("something went wrong while copying files");
                       return 1;
                   }
                   else
                   {
                        done = 1;
                        printf("\nsuccesfully copied files\n");
                    }
                }
            }
            else
               sleep(1);
    }
    return 0;
}

I just compiled and linked using gcc:
gcc main.c -oname_of_program

Simple!
 
Last edited:
As an aside - rather than using hard-coded paths in your program - you could make your program a bit more useful by accepting command-line parameters.
For example,
parameter 1 could be the path to the source directory to watch out for - the directory that you will be copying from
parameter 2 could be the path to the output directory - where the source directory will be copied to

That way, you could use several instances of your program to watch for different directories. It would not only make the program more useful for you and it could be useful for other people too.

But doing all of this in C could be a bit of a PITA. You would need to add a lot of error checks in there.
For example - your program currently does not check that the output directory exists. You might want to consider checking whether the output directory exists when the program starts. And you might want to consider checking that the output directory still exists when the source directory is found. Just in case the user, or the system removed or renamed the output directory.

Personally, I would have performed a task like this using a shellscript instead of using C:
copywhenexists.sh
Code:
#!/usr/bin/env bash

# function to display usage information
function usage
{
   echo
   echo "$1"
   echo
   echo "Usage:"
   echo "copywhenexists.sh /path/to/source_dir /path/to/output_dir &"
   echo
   echo "will wait until /path/to/source_dir exists and copy its content to /path/to/output_dir"
   echo "Where: /path to source_dir is the source directory to watch for"
   echo "And: /path/to/output_dir is the directory to copy to when the source directory exists"
   echo "NOTE: The output directory must already exist"
   echo
   echo "This script will run in an infinite loop, waiting until the specified directory exists"
   echo "as soon as it exists - its contents will be recursively copied to the output directory!"
   echo
   echo "Alternative usage:"
   echo "copywhenexists.sh -h"
   echo
   echo "- Will display this usage information"
   echo
   echo
}

# if user asked for help - display usage information and exit
if [[ $# -eq 1 ]] && [[ $1 -eq "-h" ]]; then
   usage "copywhenexists.sh Help"
   exit 0
fi

# if user failed to pass in two parameters
# display usage information and exit with an error
if [[ $# -ne 2 ]]; then
   usage "ERROR: Requires two parameters"
   exit 1
fi

# if target directory does not exist
# display usage information and exit with an error
if [[ ! -d "$2" ]];then
   usage "ERROR: $2 is not a valid directory!"
   exit 1
fi

# Wait until the source directory exists
echo
echo "Waiting for $1 to exist."
echo "$1 will be copied to $2"
echo
while true; do
   if [[ -d "$1" ]]; then
       # double check the target directory still exists
       # in case the user or the system removed or renamed it
       # while we were waiting
       if [[ ! -d $2 ]]; then
           echo
           echo "ERROR: $2 no longer exists"
           echo
           exit 1
       fi
       # source directory exists: so copy files to target
       cp -rna "$1" "$2"
       if [[ ! $? ]]; then
           echo
           echo "Something went wrong while copying files"
           echo
           exit 1
       else
           echo
           echo "Successfully copied files"
           echo
           exit 0
       fi
   fi
   sleep 1
done

The above script only took a few minutes to knock up. It contains a few more lines of code than your C program, but it is a bit more robust - it has a lot of error checks and does not have hard-coded paths in it. There is even a help option. And it accepts command-line parameters, potentially allowing you to run several instances of the script - watching for different directories.

With the above script, you could copy it into your personal bin directory /home/yourusername/bin/
Then add another script in your bin directory - that you can run on startup, that runs copywhenexists.sh and tells it the directory to look out for and the directory to copy to.

e.g.
mywatchdirs.sh
Code:
#!/usr/bin/env bash

copywhenexists.sh /media/dennis_orlando/ORLANDO\ D/Foto /home/dennis_orlando/Scrivania/ &

If you had any other devices/directories that you wanted to automatically sync to somewhere on your PC - you can run additional instances of copywhenexists.sh in your mywatchdirs.sh.
You set mywatchdirs.sh to run on startup and each time you start up - the script will run each instance of copywhenexists.sh in the background until the directories exist and their contents are copied.
 
@JasKinasis

Woah, didn't expect that much help xD
The reason I use a while loop is to allow copying multiple times. If you got an error or you just pull out your usb to add more files, and then you want to stick it another time in, you should reboot the entire system to copy another time.

I actually didn't think about sharing this, but I think it can be useful so let's give it a try :)

As you said, I should use bash scripts because they are more linux-friendly. But I never used them:rolleyes: (I just UPGRADED from win10 like 3 days ago)
... but I see it's pretty much C, if not even better, so I don't think I will have many problems learning bash coding

I like the command thing to allow the user to modify the directories: I think I'm gonna think about something to join toghether commands + the multiple instance thing you suggested. Maybe about storing a list of "copy-paste" directories (in an xml file or something), so you still have only 1 instance for as many directories as you want.
Another problem I instantly saw was that people don't really copy 1kb files... it can take a bunch of time for the process to complete. I may be able to log a % to show the copy status (hope you understand), but I think an icon (maybe near the battery) would be cool to. But for all those ideas I need to get informations from that cp command: how big (in bytes) is the file and how many bytes did he already copy. I honestly don't have any idea, if not creating a cp command from scratch
 
Last edited:
G'day @TheDennis , how are you doing? :)

I don't understand a lot of the above (yet!) ... I leave that to Jas (@JasKinasis ) ... He De Man! IMO :D... but I think the sort of thing you are talking about here

I may be able to log a % to show the copy status (hope you understand), but I think an icon (maybe near the battery) would be cool to.

... is what we might call a progress indicator or progress bar.

A Google search on

linux progress indicator

... shows some interesting results, including

https://linoxide.com/linux-how-to/show-progress-bar-linux-commands/

https://stackoverflow.com/questions/238073/how-to-add-a-progress-bar-to-a-shell-script

and

https://www.tecmint.com/advanced-copy-command-shows-progress-bar-while-copying-files/

Do note that, while some of the articles are old (one goes back to 2008, another to 2013), they have current input to them dating as recently as 2017 and 2018, so may still be of use.

Hope this helps, and I will watch this Thread with interest.

Good luck

Wizard
 
G'day @TheDennis , how are you doing? :)

I don't understand a lot of the above (yet!) ... I leave that to Jas (@JasKinasis ) ... He De Man! IMO :D... but I think the sort of thing you are talking about here



... is what we might call a progress indicator or progress bar.

A Google search on

linux progress indicator

... shows some interesting results, including

https://linoxide.com/linux-how-to/show-progress-bar-linux-commands/

https://stackoverflow.com/questions/238073/how-to-add-a-progress-bar-to-a-shell-script

and

https://www.tecmint.com/advanced-copy-command-shows-progress-bar-while-copying-files/

Do note that, while some of the articles are old (one goes back to 2008, another to 2013), they have current input to them dating as recently as 2017 and 2018, so may still be of use.

Hope this helps, and I will watch this Thread with interest.

Good luck

Wizard
We meet again wizard ;)
That stackoverflow post has just made my day. I also figured out how to get informations from the copy command: I get the size of the file I want to copy and I compare it to the size of the file that's still being created. I'm currently busy with school, so I can't work on the code, but one day I'll finish it (I hope)
 
@TheDennis - Sorry for the delay in replying here - I've been ill for a few days.

After seeing what your initial C code was doing - I merely suggested that a shell-script would probably be the best way of doing things. I didn't realise you had such big aims with your program.

Also, in my post I made a few assumptions.
I thought the infinite loop, even after the device was found was an accidental flaw in your logic. I didn't realise that was deliberate. I thought that you only wanted to wait until the device was plugged in and then copy everything once. I didn't realise you wanted to monitor the directory after it had been detected and copied from.

So what you're saying is - after the device has been plugged in and the directory detected - you want all files recursively copied to the target directory. And then afterwards the directory should be monitored until any files are added or changed and then sync any changes across to the destination?

If that's the case - that would require a bit of extra logic. I don't have my thinker screwed completely on ATM thanks to a nasty cold I've come down with. But I'm sure there are ways around this.

However - If you want a progress bar to appear in the dock-bar/notification area of your desktop - that is another kettle of fish altogether. That would almost certainly require some C or C++ (or possibly another programming language - depending on your preferred desktop environment and the language bindings available to implement a widget in the notification area).

It would complicate things quite a lot, because you'd suddenly have a lot more things to think about.
Not only the workings of the code that deals with monitoring directories and copying files, but also with the GUI library you'll be using and other usage-based considerations that will complicate the logic and the code.

But it is certainly a viable option. Your entire program could be set up as a GUI widget that sits in the notification area of the desktop when it is running.

But you will need to carefully think about the features that you need for your program and get it all planned out BEFORE you start coding it.

The code required to do something like that would be a lot more complex than the simple terminal program you posted originally. You'd need to break the project into several components, spread across multiple source-files rather than just one main.c.

But it could potentially be a useful project! The project itself could be a good one for you to learn from and it certainly sounds like it might be something that users would be interested in!
 
Get well soon, Jas ... hit the Vitamin C :)

Wiz
 

Members online


Latest posts

Top