*! Version 1.4 Andrés Castañeda. * fix bugs in copy option *===================================================================* * WORLD BANK - LCSPP * PROYECT: Program to make daily backup of important files. *-------------------------------------------------------------------* * Author: Andres Castaneda * Update: Dec/2013 *===================================================================* cap program drop backup program define backup syntax , Source(string) Destination(string) [ /// mirror /// copy(string) /// Files(string) /// STart(string) /// NFolders(int 8) /// Period(string) /// speed(int 32) /// XDir(string) /// XFile(string) /// INFile(string) /// ] version 10.0 /* ********** * 0. errors ************ */ * check to determine whether it can be run if ("`c(os)'" != "Windows") { disp as error "Unfortunately," in smcl "{cmd: backup }" as error "only works over Windows." error } * Check multi-threads are not greater than 128 or less that 1 if (!inrange(`speed', 1,128)) { disp as error "the multi-threaded copies can not be greater than 128 or lower than 1" error } * Incompatibility of excluding and including files at the same time if ("`xfile'" != "" & "`infile'" != "" ) { disp in red "You cannot exclude and include type of file at the same time. use either xfile or infile option" error } /******************************* 1. define locals and consistency ********************************/ * 1.1 define locals local mt "/MT:`speed'" //define multi threads if ("`xdir'" == "") local xd "" // define folder to exclude else local xd `"/XD "`xdir'" "' * define file format to exclude if ("`xfile'" == "") local xf "" else { local xf "/XF " foreach file of local xfile { local xf "`xf' *.`file'" } } * define file format to include local inf "" if ("`infile'" != "") { foreach file of local infile { local inf "`inf' *.`file'" } } * Copy option if ("`copy'" == "") local copy "DAT" local copy = upper("`copy'") if (!regexm("`copy'", "[^DATSOU]")) local flags "/copy:`copy'" else if ("`copy'" == "all") local flags "/copyall" else local flags "/copy:DAT" * Make sure user does not want to take so long copying unnecessary files properties if (regexm("`copy'", "[SOU]")) { cap window stop rusure `"copying files with properties such as "NTFS access control list (ACL)" "Owner information" or "Auditing information" "' /// `"May take a long time"' "click OK if you want to proceed any way" if (_rc) exit } * define type of copy: tree folder or just files if ( "`mirror'" == "mirror" ) local mir "/MIR" else local mir "/e" * default period if ("`period'" == "") local period "2w" * to erase local destination "L:\backup\datalib" * define date local date: di %tdMonth_dd,_CCYY date("$S_DATE", "DMY") local date = lower(trim("`date'")) * 1.2 check if the date folder already exists local fdates: dir "`destination'" dirs "*" foreach fdate of local fdates { if ("`date'" == "`fdate'") { disp in y "There is a backup of " in g "`destination'/`date'" in y " already" exit } } /* ************************************************************* 2. erase old folders and check whether the folder to be created meets period and number-of-folders conditions ****************************************************************/ local nfold: word count `fdates' // number of folders with dates * 2.1 copy if date is according to the period specification. *2.1.1 Specify period cap confirm number `period' if (_rc == 0) local freq `period' // in case number of days selected else { // in case compounded periods are selected local per = substr("`period'",-1,.) local times = substr("`period'",1,`: disp length("`period'")' - 1) // " get only the numeric part if ("`per'" == "d") local freq `times' // daily if ("`per'" == "w") local freq `times'*7 // weekly if ("`per'" == "m") local freq `times'*30 // monthly if ("`per'" == "q") local freq `times'*90 // quarterly if ("`per'" == "s") local freq `times'*180 // semester if ("`per'" == "y") local freq `times'*360 // yearly } // end of else *2.1.2 Check number of folders already in house local dnumbers "" if (`nfold' > 0 & `nfold' < .) { // in case there is at least one folder foreach fdate of local fdates { local lower(trim("`fdate'")) // everything in lower cases and with no blank spaces at the end local dnumbers `"`dnumbers' `: disp date("`fdate'", "MDY")' "' } // end of loop for folder names local dnumbers = itrim(trim("`dnumbers'")) // get rid of multiple internal, leading or trailing blanks local dnumbers: subinstr local dnumbers " " ", ", all // replace blanks for comma and then blank if (`nfold' > 1) local newdate = max(`dnumbers') if (`nfold' == 1) local newdate = `dnumbers' * check whether current date is higher than minimum period to create backup if (`: disp date("$S_DATE", "DMY")' - `newdate' >= `freq') local copy 1 else local copy 0 } else local copy 1 * 2.2 Delete old folders while (`nfold' > `nfolders') { local dnumbers "" foreach fdate of local fdates { local lower(trim("`fdate'")) // everything in lower cases and with no blank spaces at the end local dnumbers `"`dnumbers' `: disp date("`fdate'", "MDY")' "' } // end of loop for folder names local dnumbers = itrim(trim("`dnumbers'")) // get rid of multiple internal, leading or trailing blanks local dnumbers: subinstr local dnumbers " " ", ", all // replace blanks for comma and then blank local olddate = min(`dnumbers') local name: di %tdMonth_dd,_CCYY `olddate' // convert to date local name = trim("`name'") // get rid of preceding spaces disp in w "deleting folder `destination'/`name'" shell rd /s /q "`destination'/`name'" // delete folder that is older than number of folders allowed local fdates: dir "`destination'" dirs "*" local nfold: word count `fdates' // number of folders with dates } // end of conditional /* *********** 3. Crete copy *************/ if (`copy' == 1) { *3.1 Path after the start point /* path after start point. Start point is the directory from which -backup- will copy the folder structure from the source path */ if (regexm("`source'","(^.*)(\\\`start'.*$)")) local tree = regexs(2) local basedir "`destination'/`date'" // base directory for destination folder cap mkdir "`basedir'" // create date folder local destdir = "`basedir'`tree'" // rename destination directory with tree and date *3.2 Copy shell ROBOCOPY "`source'" "`destdir'" `files' `flags' `mir' `inf' `mt' `xd' `xf' } end exit ******************************************************************************************************** History of the file 1.3 Andrés Castañeda. fix bugs add 'copy' option 1.2 Andrés Castañeda. Change encoding format to ANSI 1.1 Andrés Castañeda. include a check at the beginning to determine whether it can be run 1.0 Andrés Castañeda 0.1 Andrés Castañeda 0.2 Andrés Castañeda