A single-threaded file backup program using the C language in Windows system _c language

Source: Internet
Author: User
Tags stdin strlen

It's written in the front.

Source path: That is, From-path, you are ready to back up the information
Destination path: To-path, where you are prepared to store the backed-up data
In retrospect, the last time you wrote the code, the task is to traverse the directory and its subdirectories, then this time to do is the last traversed data, move the nest, to where we want them to go.
This involves two operations, traversal and copy, the previous action we have achieved in the last time, just make a small change, you can use. The latter action also needs to rely on the Windows API to complete, as for which, later mentioned.
Now let's finish a magic, 3, 2, 1! :

 do{
   puts ("-------------------------------------------------");
   fprintf (stdout, "The Default Path is:%s \ n", Default_to_path);
   fprintf (stdout, "Now's Path is   :%s \ n", Get_backup_topath ());
   Puts ("-------------------------------------------------");
   Puts ("that are a System back up Software for windows!");
   Puts ("List of the Software function:");
   Puts ("1"). Back up ");
   Puts ("2"). Set back up To-path ");
   Puts ("3"). Show To-path History ");
   Puts ("4"). Read Me ");
   Puts ("5"). Exit ");
   Puts ("-------------------------------------------------");

There have been some changes to the interface slightly.

The system default destination path and the currently used destination path for the third and fourth lines are added.

Added the fourth line to view the history of the destination path.

extern Default_to_path is required outside of the main function because a global variable in the SETPATH.C is referenced.

Written in the middle

We have mentioned that to make functions clearer, in order to achieve this, we should wrap up some of the native library functions that might be used, so that possible errors can be held in our own hands.

Security functions

New SafeFunc.h SAFEFUNC.C
Consider the functions we need to wrap: malloc, free, fopen three library functions.

In order not to let the rear multithreaded implementations produce more later, the global error output is not used alone.
Let me make it happen.
I will not omit some seemingly unnecessary things, such as annotations, but the complete presentation, if you feel too long, you can choose to jump reading.
Magic is coming, 3, 2, 1!

 #include <stdio.h>/* size_t/#include <stdlib.h> #include <setjmp.h>
   #define TRY_TIMES 3 typedef struct _input_para{char * File/* file name to be opened or created */char * mode;/* Open mode */

   }params; Jmp_buf malc_jmp; /*malloc_s*/jmp_buf fopn_jmp; /*fopen*//** * @version 1.0 2015/10/01 * @author wushengixin * @param ...  See structure description can be passed in any number of, in the form of. File = "xxx",. Mode = "X" The parameter * function is used to use the default parameters, and call the function Fopen to open the operation * * #define Fopen_s (...)  Fopen (params) {. File = NULL,. Mode = "R", __va_args__}) file* Fopen (const params file_open);/** * @version 1.0 2015/10/01 * @author wushengxin * param sizes input Required size * function to hide some processing of errors, and call malloc library function allocation space */V

   OID * malloc_s (size_t sizes); /** * @version 1.0 2015/10/01 * @author wushengxin * @param input the incoming wait-free pointer * function is used to hide some processing of errors and to tune

Free Library function is used to release the pointer/void free_s (void * input); 

Some new features are used, and if you use Gcc/clang as a compiler, remember to turn on-STD=C11 support.

These functions are no longer explained in detail, but simply a few, followed by the implementation code:

   file* Fopen (const params file_open) {int times = 0;
     file* ret_p = NULL; if (File_open.file = = NULL) {fputs ("The file Name is empty!
       Comfirm it and Try Again ", stderr);
     return ret_p; } setjmp (FOPN_JMP);
     /* FOPN_JMP to There * * ret_p = fopen (File_open.file, File_open.mode);
       if (ret_p = = NULL) {if (times++ < Try_times) longjmp (fopn_jmp, 0);/* FOPN_JMP from here * *
     fprintf (stderr, "The File:%s Open with Mode (%s) fail!\n", File_open.file, File_open.mode);
   return ret_p;
     } void * MALLOC_S (size_t sizes) {int times = 0;
     void * ret_p = NULL;
     if (sizes = = 0) return NULL; SETJMP (MALC_JMP);
     /* MALC_JMP to There * * ret_p = malloc (sizes);
       if (ret_p = = NULL) {if (times++ < try_times)/* malc_jmp from Here/longjmp (malc_jmp, 0);
     Fputs ("Allocate Memory fail!", stderr);
   return ret_p; } void free_s(void * Input) {if (input = = null) {#if!defined (not_debug_at_all) fputs ("Sent A null pointer to the free_s functio
   n! ", stderr);
     #endif return;
     Free (input);
   input = NULL;

 }

The first function is to start it with an externally defined macro ' fopen_s ', which is not implemented to hide it.

A preprocessing mechanism is used in the last function, and if ' #define Not_debug_at_all ' is defined in the header file, this output will not appear
The security function has been written, and the next step is to do the right thing.

SetPath.h

We first want to save the program in the default destination path, first thought to use constant #define ...
Second, to ensure that the current destination path is not accessed by other illegal channels, it should be stored with a static character array.
The next step is to provide a function as an interface (where the term "interface" is not known to fit) to obtain the current Get_backup_topath of the destination path in use.
There is also a need to implement the previously implemented REPL_STR once again, because the previous display function is only testing, and will not actually apply to the program.
After completing these two functional functions, consider how the implementation sets the path, stores the path, and caches the historical destination path using file flow operations.

   #include "safeFunc.h"

   #define Self_load_default_path "c:/"
   #define MIN_PATH_NAME _max_path/* Minimum limit * *
   Define Largest_path_name 32767/* Path Maximum limit *
    * * * @version 1.0 2015/10/02
    * @author  wushengxin
    * function is used to return the currently used destination path
   /const char * get_backup_topath ();

   /**
   * @version 1.0 2015/09/28
   * @author wushengxin *
   @param  src outside, for adjustment
   * @function */
   void repl_str (char * src) in the replacement path;

In the corresponding implementation, a static character array is defined and can be seen in the header file, many of which are defined in ' showfiles '.

Defined functions such as ' repl_str ' need to implement * * in ' showfiles.c ', use ' #if 0 ... #endif ' to comment out, or a redefinition error will occur.
Setpath.c

   #include "setPath.h"

   static char to_path_buf[largest_path_name] = Self_load_default_path;
   const char * default_to_path = Self_load_default_path;
   const int largest_path = Largest_path_name;

   const char * Get_backup_topath ()
   {return
     to_path_buf;
   }

   void Repl_str (char * src)
   {
     size_t length = strlen (src);
     for (size_t i = 0; I <= length; ++i)
     {
       if (src[i] = = '/')
         src[i] = ' \ n ';
     }
     return;
   }

With the above code, the main interface will be able to run again, then the rest is the implementation, set the destination path, storage destination path to local, display destination path, respectively corresponding to the main interface of 2, 3.
How to achieve better, before you start, analyze the situation you will encounter:
After we get the destination path, we copy it to the default path To_path_buf and store it in the local cache file so that the previous path can be used directly the next time the program starts
You can also use another file to store all of the used history paths, including time information.
Then this requires us to first realize the function of the storage destination path, then realize the function of setting the destination path, and finally realize the function of displaying the destination path.
Note: Two seemingly useless global variables (const) are created for the visibility of other files, and can save some insignificant space relative to #define.

Storage Destination Path Store_hist_path

SetPath.h

    #include <time.h>
    /**
     * @version 1.0 2015/10/02
     * @version wushengxin
     * @param  path needs to be stored The c6/>* @function is used to store the path to the local file "Show_hist" and "use_hist"/
    void Store_hist_path (const char * path);
setpath.c

    void Store_hist_path (const char * path)
    {
      time_t ctimes; 
      Time (&ctimes); /* Get time
      /file* input_use = fopen_s (. FILE = "lastpath.conf",. Mode = "W");//per write overwrite * * file*
      input_show = Fope n_s (. File = "PathHistory.txt",. Mode = "a");
      if (!input_show | |!input_use)
      {
    #if!defined (not_debug_at_all)
        fputs ("Open/create the File fail!", STDERR);
    #endif return
        ;
      }
      fprintf (Input_use, "%s\n", Path); /* Write
      /* fprintf (Input_show, "%s%s", Path, CTime (&ctimes));
      Fclose (input_show);
      Fclose (input_use);
      return;
    }

The use of the ' time ' and ' CTime ' functions on the web is more comprehensive, not explained here.

After the stored function is completed, it is the implementation of reading from the keyboard and setting the default path
Set Destination Path Set_enter_path

Here you need to stop to think about it, if the user entered the wrong path (invalid path or malicious path), should also be read? Therefore, a check should be added to confirm the validity of the path.
SetPath.h

    #include <string.h>
    #include <io.h>/* _access
    /enum {not_exist = 0, EXIST = 1};
    /**
     * @version 1.0 2015/10/02
     * @author  wushengxin
     * @function is used to read the path entered from the keyboard and set it as the default path and store.
     * *
    void Set_enter_path ();

    /**
     * @version 1.0 2015/10/02
     * @author  wushengxin *
     @param  path used to check for paths
     * @function Used to check whether the path entered by the user is a valid
    /int Is_valid_path (const char * path);

Setpath.c

    int Is_valid_path (const char * path) {/* _access has an explanation for */if (_access (path, 0) = = 0)//RET
      Urn EXIST;
    else return not_exist; } void Set_enter_path () {int intjudge = 0;/* is used to determine whether the input/char tmpbuf[largest_path_name is determined to be completed;/** Temporary
        Buffer **/while (1) {printf ("Enter the Path for You want!\n"); Fgets (Tmpbuf, largest_path_name*sizeof (char), stdin);
        /* Get input path/sscanf (Tmpbuf, "%s", to_path_buf);  if (Is_valid_path (to_path_buf) = = not_exist) {fprintf stderr, Your Enter is Empty, so Load the Default
          Path\n ");
          fprintf (stderr, "%s \ n", Self_load_default_path);
        strcpy (To_path_buf, Self_load_default_path); fprintf (stdout, Your Enter is \%s \)? (

        1 for Yes, 0 for no) \ n ", to_path_buf);
        Fgets (Tmpbuf, largest_path_name*sizeof (char), stdin); SSCANF (Tmpbuf, "%d", &intjudge);
 /* Get the input of the judgement number/if (Intjudge!= 0)       {if (To_path_buf[strlen (TO_PATH_BUF)-1]!= '/') strcat (To_path_buf, "/");/* If the last character is not '/',
          Is added, here is not considered whether Cross-border/Store_hist_path (TO_PATH_BUF);
        Break
    }/* IF (intjudge) * *}/* while (1) * * return;

 }/* Set_enter_path * *

The function of this group of functions is slightly complex, generally speaking, is ' Read path input-> check path validity-> read judgment number-> end Loop '

The ' _access ' function has some origins, because this function is known as this form of ' access ', but because this form is the **posix** standard, so **windows** it as a ' _access ', usage or the same, is the name is different.
Show History Path Show_hist_path

SetPath.h

    /**
     * @version 1.0 2015/10/02
     * Author  wushengxin
     * function is used to display all historical paths in the window/
    void Show_hist _path ();

Setpath.c

    void Show_hist_path ()
    {
      system ("CLS");
      Char Outbufname[largest_path_name] = {' i '};
      file* reading = fopen_s (. File = "PathHistory.txt",. Mode = "R");
      if (!reading) return
      ;

      for (int i = 1; I <= && (!feof (reading)); ++i)  
      {
        fgets (outbufname, largest_path_name*sizeof (char), R eading);
        fprintf (stdout, "%2d.") %s ", I, Outbufname);
      }
      Fclose (reading);
      System ("pause");
      return;
    }

The last finishing touches left.

Initialize path
Every time the program is started, we will read the local file to get the last path used by the previous program, as the target path for the current use
Initialization destination Path Init_path

SetPath.h

    /**
     * @versions 1.0 2015/10/02
     * @author  wushengxin
     * @function for initializing the destination path
    each time the program starts. void Init_path ();

Setpath.c

    void Init_path ()
    {
      int len = 0;
      Char Last_path[largest_path_name] = {' i '};
      file* hist_file = fopen_s (. File = "lastpath.conf",. Mode = "R");
      if (!hist_file)/* Open failure does not initialize/return
        ;
      Fgets (Last_path, Largest_path_name, hist_file);
      Len = strlen (Last_path);
      if (Len > 1)
      {
        last_path[len-1] = ' I ';/* eliminate an unwanted ' \ n ' *
        /strcpy (To_path_buf, Last_path);
      } return
      ;
    }

This is done, for this function in the post ' 8 ' line code, did not use the usual ' fgets with sscanf ' because if so, need to match a ' memset ' function to clear zero, there will be an explanation later.

The explanation for Memset
This function is actually very slow for the initialization of large chunks of memory, of course, we this 30KB about the memory may affect not so much, but after the trillion, call memset is a performance problem, in many cases, The compiler automatically cancels memset implicit calls after the high level of optimization is turned on
What implicit invocation, such as Init_path's second line of code, declares and initializes the array with curly braces, calls the implicit memset.

Written in the middle

This completes most of the interface's functions, and the rest is the main function of backup.
Before you complete the backup, think about how you want to construct the backup model

Since it is a backup, if you do not want to expand into multithreaded form, reference to the first write traversal function (show_structure) directly to the file will be called the Windows API (described later) for replication, do not need to talk about the file path to be backed up to save.
If you want to consider multithreaded extensions, we need to take a long-term view.
For a backup model, the best thing to do is to use a queue, still implement traversal mode, but save the file path found and put it in a first-in, first-out queue, so that we can make sure that there is a clear model reference when expanding into multiple threads.
The task now is to implement this queue model for backup.
Queue Model

    • There should be a container space: for storing paths
    • There's the first team tail sign.
    • O (1) Complexity check whether the queue is empty interface or flag
    • O (1) The complexity of the return container capacity of the interface or logo, the container capacity should be fixed unchanged

Using some object-oriented black magic, save some action functions to prevent code clutter.

    • initialization function
    • Release function
    • Eject action function
    • Press into Operation function
    • Queue Entities

Considering that you want to store a string, and because of the Windows API parameter requirements, for a file, we need to store the path of two < source path, the destination path, this should use a path model structure to wrap them, then the type of space will be changed
New Queue.h queue.c

Queue.h

  typedef struct _VECTOR_QUEUE queue;
  typedef struct _COMBINE Combine;

      |  return Value  | | function type name | |  Parameter Type  |
  typedef int       (*fppushback) (Queue * __restrict, const char * __restrict, const char * __restrict);
  typedef const COMBINE * (*fppopfront) (queue *);
  typedef void      (*fpdelete) (queue *);

Five typedef do not know whether there is a Meng. , I hope I can understand it well.

The first two are the declaration of the structure body, corresponding to the queue model and the path model respectively.

The latter two are function pointers, the role is placed in the structure, so that the C language structure can also have some simple object-oriented functions, such as member function function, the principle is that these function pointer types of variables can be assigned values. A later example is more obvious. Try to read it, it's simple.

  struct _combine{
  char * src_from_path;/* Source path *
  /char * DST_TO_PATH;  /* Destination path *
  /};

  struct _vector_queue{
    Combine * *   path_contain;/* Storage path container body/
    unsigned int  rear;     /* Team Tail coordinates *
    /unsigned int  front;    /* Team First coordinate
    *       /int empty;    /* is an empty
    /unsigned int  capcity;   /* Container capacity * *
    fppushback   Pushback/* will element pressure team tail   /Fppopfront Popfront;    Delete;  /* destructor frees entire queue space
  /};

  /**
   * @version 1.0 2015/10/03
   * @author  wushengxin *
   @param  object pointer passed outside of object, equivalent to this
   * @function Initialize the queue model, establish the queue entity, allocate space, and set properties.
   *
  /int Newqueue (queue* object);

As you can see, the above function pointer type, which is used in the structure body, is missing an initialization function because it is not intended to be a member function (borrow object-oriented terminology)

Can be directly obj_name when used. Pushback (..., ...);

In more detail, you can look at the implementation section later. The three functions that become member functions are implemented as static functions and are not accessed by the outside world.

Queue.c

 int Newqueue (Queue * object)
 {
   queue*   Loc_que = object;
   combine**  Loc_arr = NULL;

   Loc_arr = (combine**) malloc_s (capcity * sizeof (combine*));
   if (!loc_arr) return
     1;

   loc_que->capcity = capcity; * * Capacity
   /loc_que->front = 0;    * * Team head
   /loc_que->rear = 0;    * * Team Tail * *

   Loc_que->path_contain = loc_arr/* Will allocate the space, put into the object
   /loc_que->pushback = push_back;
   Loc_que->popfront = Pop_front;
   Loc_que->delete  = del_queue;

   return 0;
 }

In the initialization function, you can see that the first team tail and capacity are set, the container space is allocated, and member functions are configured.

In the last three sentences of the configuration function, Push_back, Pop_front, and Del_queue are implemented as static functions in the rear.

But since there is no declaration, remember to put the implementation of three static functions in front of newqueue

 /** * @version 1.0 2015/10/03 * @author wushengxin * @param object pointers passed outside of object are equivalent to this * @function free space for the entire queue entity
   * * static void Del_queue (Queue * object) {free_s (object->path_contain);
 Return
        }/** * @version 1.0 2015/10/03 * @author wushengxin * @param object pointers passed outside of objects equivalent to this src source path DST Destination Path * @function External incoming < source path, destination path > Deposit queue/static int push_back (Queue * __restrict object, const char * _
   _restrict SRC, const char * __restrict DST) {int times = 0; char* loc_src = NULL;
   /* Local variables, as far as possible using registers and cache/char* LOC_DST = NULL;
   combine* loc_com = NULL;

   queue* Loc_que = object; size_t len_src = strlen (src);
   /* Get path length * * size_t LEN_DST = strlen (DST);  size_t rear = loc_que->rear; /* Get Team Tail * * size_t front = loc_que->front; /* Get team head/loc_src = malloc_s (len_src + 1);

   /* Allocation space */if (!LOC_SRC) return 1;
   LOC_DST = malloc_s (len_dst + 1);
   if (!LOC_DST) return 2; strcpy (loc_src, SRC);

   strcpy (LOC_DST, DST);
   loc_com = malloc_s (sizeof (combine));
   if (!loc_com) return 3; 
   Loc_com->dst_to_path = LOC_DST;

   Loc_com->src_from_path = LOC_SRC; loc_que->path_contain[rear++] = loc_com;   /* Add local Path to entity */loc_que->rear = (rear% capcity);
   /* Steps to implement a circular queue using an array/if (loc_que->rear = = loc_que->front) loc_que->empty = 0;
 return 0; }/** * @version 1.0 2015/10/03 * @author wushengxin * @param object pointer to incoming objects/static const combine * POP_          Front (queue* object) {size_t Loc_front = object->front; * * Get current team head/combine* loc_com = object->path_contain[loc_front];   /* Get current filename/* Object->path_contain[loc_front] = NULL; /* OUT Team Operation * * Object->front = ((Object->front) + 1)% 20;
   /* Complete the team * * (Object->front = = object->rear) Object->empty = 1;
   else Object->empty = 0;
 return loc_com;

 }

One to say these functions

Del_queue: Release function, call free_s directly

Push_back: Press into function, the external incoming two of the original not composed path string, combined into a combine, and pressed into the path, each time to determine whether the null flag bit, in fact, this function has a redundant code suspected, should be another function, dedicated to allocate three space, Prevents this function from being too long (nearly 40 lines)

Pop_front: Pop-up function, the queue will be the first combine pop-up, for replication, but there is a hidden danger, is to release the work to the outside, if the negligence, the hidden danger is the memory leak.

There is no specially provided an interface to determine whether it is empty, because when the compiler is optimized, it will also be optimized to directly use the form of members, some form of inline.

The queue model is finished and you can begin to design the backup model
The backup model can recall the previous traversal function, the general structure, just to expand into multiple threads here, you need to add some multithreaded call functions, and for normalization, you need to add a level two interface
Design the two-level interface first.

Second-level interface

Think about what this interface is going to do
Choose whether to start a backup
and the source path needs to be entered here
Go back to the previous level
New Backup.h backup.c File
The function of the level two interface is called after the main interface is selected 1
List options for level two interfaces
1 Start back up
2 Back to last level
Backup.h

  /** * @version 1.0 2015/10/03 * @author wushengxin * Function shows a level two interface * * void sec_main_windows ();
    backup.c void Sec_main_windows () {char tmpbuf[256];
    int selects;
      do{setjmp (SELECT_JMP);
      System ("CLS"); Puts ("-------------------1".
      Back up------------------");
      Puts ("For this Select, can choose two Options:"); Puts ("1").
      Start back up (the Directory Path so you Enter later)); Puts ("2").
      Back to last Level ");
      Puts ("-----------------------------------------------");
      fprintf (stdout, "Enter Your Selection:");
      Fgets (TMPBUF, 256, stdin);
      SSCANF (Tmpbuf, "%d", &selects); if (selects!= 1 && selects!= 2) {fprintf (stdout, "\ nthe Your Select \"%s \ "is invalid!\n Try Agai
        \ n ", tmpbuf);
      LONGJMP (select_jmp, 1); 
      Switch (selects) {jmp_buf enter_path_jmp; Case 1: {char Tmpbuf[largest_path], tmppath[largest_PATH];     /* Use stack allocation space, because only use the allocation once/setjmp (ENTER_PATH_JMP);
        /* Enter Jump to There * * Puts ("Enter the full Path for you want to BackUp (e.g:c:/programing/)");
        fprintf (stdout, "Or enter Q to Back to Select\nyour enter:");
        Fgets (Tmpbuf, Largest_path, stdin);
        SSCANF (Tmpbuf, "%s", Tmppath); 
            if (_access (tmppath, 0)!= 0)/* Check the path exists, valid/{if (tmppath[0] = = ' Q ' | | tmppath[0] = = ' Q ') longjmp (select_jmp, 0); /* Back to the interface you can choose to return * * fprintf (stderr, "The Path you are not exit!
          \ n Try Again: "); longjmp (enter_path_jmp, 0);
      /* Enter jump from Here */}} break;
      Case 2:return;
      Default:break;
    }/* Switch */} while (1);
  Return

 }

This function only says a few things, first of all, ' switch ' ' Case 1 ', the reason for wrapping with * * curly braces is that it is possible to define * * local variable * *, which is defined directly after the colon is * * * Compilation Error * *, this feature may be less used, here to mention, before also said.
written on the last side

The rest is to write the main functional functions and thread call functions.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.