123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /* $TOG: dosync.c /main/6 1998/10/26 12:40:53 mgreess $ */
- /************************************<+>*************************************
- ****************************************************************************
- *
- * FILE: dosync.c
- *
- *
- * DESCRIPTION: Routines synchronizing directories
- *
- * FUNCTIONS: CONFIRM
- * CmpPred
- * DTYPE
- * DirCmp
- * DirCmp2
- * DumpDir
- * ERROR_CHECK
- * FreeDir
- * GetDir
- * GetDirEntry
- * SortDir
- * SyncDirRecur
- * SyncDirectory
- * SyncItem
- * cmpSymlink
- * dirEraseCallback
- * dirErrorCallback
- * doCopy
- * doCopyLink
- * doMkdir
- * doSymlink
- * doUnlink
- * targetLink
- *
- * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
- * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
- * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
- * (c) Copyright 1993, 1994, 1995 Novell, Inc.
- *
- ****************************************************************************
- ************************************<+>*************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #include <assert.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/time.h>
- #include <dirent.h>
- #include <sys/file.h>
- #include "fsrtns.h"
- #ifdef PATRTNS
- #include "patrtns.h"
- #endif
- #include "dosync.h"
- /*--------------------------------------------------------------------
- * global variables
- *------------------------------------------------------------------*/
- char *FileOpNames[] = {
- "synchronize",
- "opendir",
- "lstat",
- "stat",
- "readlink",
- "delete",
- "copy",
- "mkdir",
- "copy link",
- "make link",
- "working",
- "is a copy",
- "is a link"
- };
- int (*syncConfirmCallback)(FileOp op,
- char *sname, int stype,
- char *tname, int ttype,
- char *link) = NULL;
- int (*syncErrorCallback)(FileOp op, char *fname, int errnum) = NULL;
- static SyncParams *SP;
- /*--------------------------------------------------------------------
- * macros for invoking callback functions
- *------------------------------------------------------------------*/
- #define DTYPE(delP) ((delP)? (delP)->ftype: ft_noent)
- #define CONFIRM(op, sn, st, tn, tt, l, rc) \
- if (periodicCallback && (*periodicCallback)() != 0) return -1; \
- else if (syncConfirmCallback && \
- (rc = syncConfirmCallback(op, sn, st, tn, tt, l)) != 0) return rc; else
- #define ERROR_CHECK(op, f, rc) \
- if (rc < 0 || rc && syncErrorCallback && syncErrorCallback(op, f, rc) < 0) \
- return -1; else
- /*--------------------------------------------------------------------
- * reading directories
- *------------------------------------------------------------------*/
- /* structure containing information anout a directory entry */
- typedef struct de {
- char name[256]; /* file name */
- int rc, lrc; /* return codes from stat, lstat */
- struct stat stat; /* stat */
- int ftype; /* file type flags (see #defines in dosync.h) */
- char exclude, skip; /* exclude, skip flags */
- char *link; /* value of symbolic link */
- struct de *teP; /* source dir: points to correspond. target dir entry */
- struct de *next; /* next directory entry */
- } DirEntry;
- /*
- * DumpDir: dump linked list of directory entries to stdout (debugging only)
- */
- static void
- DumpDir(DirEntry *dP)
- {
- DirEntry *eP;
- for (eP = dP; eP; eP = eP->next)
- printf(" %-15s %2d %c %c %c %c %c %s\n",
- eP->name,
- eP->rc,
- (eP->ftype & ft_isdir)? 'D': ' ',
- (eP->ftype & ft_islnk)? 'L': ' ',
- eP->exclude? 'X': ' ',
- eP->skip? 'S': ' ',
- eP->teP? 'F': ' ',
- eP->link? eP->link: "");
- }
- /*
- * DirCmp: compare function for sorting directory entries
- */
- static int
- DirCmp(const void *p1, const void *p2)
- {
- return strcmp((*(DirEntry **)p1)->name, (*(DirEntry **)p2)->name);
- }
- /*
- * SortDir: sort linked list of directory entries by name
- */
- static DirEntry *
- SortDir(DirEntry *dP, int (*cmp)(const void*, const void*))
- {
- int i, n;
- DirEntry *eP, **linkPP;
- DirEntry *da[1024], **daP;
- /* count number of directory entries */
- n = 0;
- for (eP = dP; eP; eP = eP->next)
- n++;
- if (n < 2)
- return dP;
- /* allocate pointer array */
- if (n <= 1024)
- daP = da;
- else
- daP = (DirEntry **)malloc(n * sizeof(DirEntry *));
- /* sort pointer array */
- for (eP = dP, i = 0; eP; eP = eP->next, i++)
- daP[i] = eP;
- qsort(daP, n, sizeof(DirEntry *), cmp);
- /* re-link the linked list */
- linkPP = &dP;
- for (i = 0; i < n; i++) {
- *linkPP = daP[i];
- linkPP = &(*linkPP)->next;
- }
- *linkPP = NULL;
- /* free pointer array */
- if (daP != da)
- free(daP);
- return dP;
- }
- /*
- * FreeDir: de-allocate linked list of directory entries
- */
- static void
- FreeDir(DirEntry *deP)
- {
- DirEntry *nextP;
- while (deP) {
- nextP = deP->next;
- free(deP);
- deP = nextP;
- }
- }
- /*
- * GetDirEntry: Get information about one directory entry.
- * If an error occurs, returns the errno in *rc and the operation
- * that failed (op_lstat, op_stat, or op_readlink) in *op.
- */
- static DirEntry *
- GetDirEntry(char *fname, FileOp *op, int *rc)
- {
- DirEntry *deP;
- char *p;
- char link[1024];
- int l;
- /* allocate new DirEntry */
- deP = (DirEntry *)malloc(sizeof(DirEntry));
- memset(deP, 0, sizeof(DirEntry));
- /* get file name */
- p = strrchr(fname, '/');
- if (p && p > fname)
- snprintf(deP->name, sizeof(deP->name), "%s", p + 1);
- else
- snprintf(deP->name, sizeof(deP->name), "%s", fname);
- /* assume everything is fine */
- *op = 0;
- *rc = 0;
- /* get information */
- deP->rc = lstat(fname, &deP->stat);
- if (deP->rc) {
- *op = op_lstat;
- *rc = errno;
- } else if ((deP->stat.st_mode & S_IFMT) == S_IFDIR)
- deP->ftype |= ft_isdir;
- else if ((deP->stat.st_mode & S_IFMT) == S_IFLNK) {
- deP->ftype |= ft_islnk;
- deP->lrc = stat(fname, &deP->stat);
- if (deP->lrc) {
- if (errno != ENOENT) {
- *op = op_stat;
- *rc = errno;
- }
- } else if ((deP->stat.st_mode & S_IFMT) == S_IFDIR)
- deP->ftype |= ft_isdir;
- l = readlink(fname, link, sizeof(link) - 1);
- if (l < 0) {
- *op = op_readlink;
- *rc = errno;
- } else {
- link[l] = 0;
- deP->link = strdup(link);
- }
- }
- return deP;
- }
- /*
- * GetDir: read a directory and return linked list of directory entries
- */
- static int
- GetDir(char *dirname, PatternList *xl, PatternList *sl, DirEntry **listPP)
- {
- DIR *dirP = NULL; /* open directory */
- struct dirent *entryP; /* directory entry */
- DirEntry *deP, *firstP, **linkPP;
- char fname[1024], *fnP;
- PatternList *pl;
- FileOp op;
- int rc;
- /* open directory */
- dirP = opendir(dirname);
- if (dirP == NULL) {
- rc = errno;
- if (syncErrorCallback &&
- syncErrorCallback(op_opendir, dirname, rc) < 0)
- {
- return -1;
- }
- return rc;
- }
- /* copy dirname to file name buffer */
- snprintf(fname, sizeof(fname), "%s", dirname);
- fnP = fname + strlen(fname);
- *fnP++ = '/';
- /* initialize linked list */
- firstP = NULL;
- linkPP = &firstP;
- /* read the directory */
- while ((entryP = readdir(dirP)) != NULL) {
- /* skip . and .. */
- if (strcmp(entryP->d_name, ".") == 0 || strcmp(entryP->d_name, "..") == 0)
- continue;
- /* get new DirEntry */
- strcpy(fnP, entryP->d_name);
- deP = GetDirEntry(fname, &op, &rc);
- /* add to linked list */
- *linkPP = deP;
- linkPP = &deP->next;
- /* if error occurred, call error callback function */
- if (rc != 0 && syncErrorCallback && syncErrorCallback(op, fname, rc) < 0) {
- closedir(dirP);
- FreeDir(firstP);
- return -1;
- }
- /* check exclude and skip list */
- #ifdef PATRTNS
- for (pl = xl ; pl; pl = pl->next)
- if (MatchPattern(pl->pattern, fname))
- deP->exclude++;
- for (pl = sl; pl; pl = pl->next)
- if (MatchPattern(pl->pattern, fname))
- deP->skip++;
- #endif
- }
- closedir(dirP);
- *listPP = SortDir(firstP, DirCmp);
- return 0;
- }
- /*--------------------------------------------------------------------
- * file operations
- *------------------------------------------------------------------*/
- static int erase_rc;
- /*
- * dirEraseCallback: used in doUnlink (below) for confirmation
- * during recursive directory deletes
- */
- static int
- dirEraseCallback(char *fname)
- {
- erase_rc = syncConfirmCallback(op_delete, "", ft_noent, fname, 0, "");
- return erase_rc;
- }
- static int
- dirErrorCallback(char *fname, int errnum)
- {
- erase_rc = syncErrorCallback(op_delete, fname, errnum);
- return erase_rc;
- }
- /*
- * doUnlink: delete a file from the target directory
- */
- static int
- doUnlink(char *fname, DirEntry *fP, int confirm)
- {
- int rc;
- if (confirm)
- CONFIRM(op_delete, "", ft_noent, fname, fP->ftype, "", rc);
- if (SP->dontdoit)
- rc = 0;
- else if (SP->keepold) {
- char newname[1024];
- snprintf(newname, sizeof(newname), "%s%s", fname, SP->keepold);
- fsMove(fname, newname, 1, &rc);
- } else if ((fP->ftype & ft_isdir) && !(fP->ftype & ft_islnk)) {
- /* arrange for syncConfirmCallback's during recursive directory deletes */
- erase_rc = 0;
- if (syncErrorCallback)
- errorCallback = dirErrorCallback;
- if (syncConfirmCallback)
- progressCallback = dirEraseCallback;
- fsErase(fname, &rc, 1);
- if (rc < 0 && erase_rc)
- rc = ENOTEMPTY;
- errorCallback = NULL;
- progressCallback = NULL;
- } else
- rc = (unlink(fname) != 0)? errno: 0;
- /* check for errors */
- ERROR_CHECK(op_delete, fname, rc);
- return rc;
- }
- /*
- * doCopy: copy a file from the source to target directory
- */
- static int
- doCopy(char *sname, DirEntry *sP, char *tname, DirEntry *delP)
- {
- int rc;
- /* display message */
- CONFIRM(op_copy, sname, sP->ftype, tname, DTYPE(delP), "", rc);
- /* if necessary, delete target */
- if (delP && !SP->dontdoit)
- if ((rc = doUnlink(tname, delP, 0)) != 0)
- return rc;
- /* copy the file */
- if (SP->dontdoit)
- rc = 0;
- else
- fsCopy(sname, tname, 0, &rc);
- /* check for errors */
- ERROR_CHECK(op_copy, sname, rc);
- return rc;
- }
- /*
- * doMkdir: create a new sub directory in the target directory
- */
- static int
- doMkdir(char *sname, DirEntry *sP, char *tname, DirEntry *delP)
- {
- int rc;
- /* display message */
- CONFIRM(op_mkdir, sname, sP->ftype, tname, DTYPE(delP), "", rc);
- /* if necessary, delete target */
- if (delP && !SP->dontdoit)
- if ((rc = doUnlink(tname, delP, 0)) != 0)
- return rc;
- /* make a new directory */
- rc = SP->dontdoit? 0: (mkdir(tname, sP->stat.st_mode & 07777) < 0)? errno: 0;
- /* check for errors */
- ERROR_CHECK(op_mkdir, tname, rc);
- return rc;
- }
- /*
- * targetLink: lookup symbloc link in the maplink list
- */
- static void
- targetLink(char *source, char *target, char **tlPP, char **msgPP)
- /*
- *
- */
- {
- static char buf[1024] = " -> ";
- MapList *ml;
- int l;
- for (ml = SP->maplink; ml; ml = ml->next) {
- l = strlen(ml->from);
- if (strncmp(ml->from, source, l) == 0
- && (source[l] == '/' || source[l] == 0))
- {
- strcpy(buf + 4, ml->to);
- if (source[l])
- strcat(buf, source +l);
- if (strcmp(buf + 4, target) != 0) {
- *tlPP = buf + 4;
- *msgPP = buf;
- return;
- }
- }
- }
- *tlPP = source;
- *msgPP = "";
- }
- /*
- * doCopyLink: copy a symbolic link from the source to target directory
- */
- static int
- doCopyLink(char *sname, DirEntry *sP, char *tname, DirEntry *delP)
- {
- char *tl, *msg;
- int rc;
- /* determine where the link should point */
- targetLink(sP->link, tname, &tl, &msg);
- /* display message */
- CONFIRM(op_cplink, sname, sP->ftype, tname, DTYPE(delP), msg, rc);
- /* if necessary, delete target */
- if (delP && !SP->dontdoit)
- if ((rc = doUnlink(tname, delP, 0)) != 0)
- return rc;
- /* create link */
- rc = SP->dontdoit? 0: (symlink(tl, tname) != 0)? errno: 0;
- /* check for errors */
- ERROR_CHECK(op_cplink, tname, rc);
- return rc;
- }
- /*
- * doSymlink: create a symbolic link in the target directory to a file
- * in the source directory
- */
- static int
- doSymlink(char *sname, DirEntry *sP, char *tname, DirEntry *delP)
- {
- char *tl, *msg;
- int rc;
- /* determine where the link should point */
- targetLink(sname, tname, &tl, &msg);
- /* display message */
- CONFIRM(op_mklink, sname, sP->ftype, tname, DTYPE(delP), msg, rc);
- /* if necessary, delete target */
- if (delP && !SP->dontdoit)
- if ((rc = doUnlink(tname, delP, 0)) != 0)
- return rc;
- /* create link */
- targetLink(sname, tname, &tl, &msg);
- rc = SP->dontdoit? 0: (symlink(tl, tname) != 0)? errno: 0;
- /* check for errors */
- ERROR_CHECK(op_mklink, sname, rc);
- return rc;
- }
- /*
- * cmpSymlink: compare two symbolic links
- * return values:
- * -1 error reading one of the links
- * 0 links point to the same file
- * 1 tname link points to sname
- * 2 links point to different files
- */
- static int
- cmpSymlink(char *sname, DirEntry *seP, char *tname, DirEntry *teP)
- {
- char *tl, *msg;
- /* return error if target link could not be read */
- if (!teP->link)
- return -1;
- /* check if target link points to source link */
- if (SP->keeplinks) {
- targetLink(sname, tname, &tl, &msg);
- if (strcmp(teP->link, tl) == 0)
- return 1;
- }
- /* if source not a symbolic link, target must be pointing to wrong file */
- if (!(seP->ftype & ft_islnk))
- return 2;
- /* compare the links */
- targetLink(seP->link, tname, &tl, &msg);
- if (strcmp(teP->link, tl) == 0)
- return 0;
- else
- return 2;
- }
- /*--------------------------------------------------------------------
- * sync directories
- *------------------------------------------------------------------*/
- static int SyncDirRecur(char *sdir, char *tdir);
- /*
- * SyncItem: copy or replace one item from the source to the target directory
- */
- static int
- SyncItem(char *sname, DirEntry *sP, char *tname, DirEntry *tP)
- {
- int rc;
- if (periodicCallback && (*periodicCallback)() != 0)
- return -1;
- if (!tP) {
- /* target does not exist */
- rpl_target:
- /*--------------------------------------------------------------------
- * target does not exist or should be replaced
- *------------------------------------------------------------------*/
- /* check if -dontreplace or -dontadd options apply */
- if (tP && SP->dontreplace || !tP && SP->dontadd)
- return 0;
- if (sP->ftype & ft_islnk) {
- /* source is a link */
- if ((sP->ftype & ft_isdir) && !SP->copydirs ||
- !(sP->ftype & ft_isdir) && !SP->copyfiles)
- {
- /* just copy the link */
- return doCopyLink(sname, sP, tname, tP);
- }
- } else {
- /* source is not a link */
- if ((sP->ftype & ft_isdir) && SP->linkdirs ||
- !(sP->ftype & ft_isdir) && SP->linkfiles)
- {
- /* don't copy; just create a link to the target */
- return doSymlink(sname, sP, tname, tP);
- }
- }
- if (sP->ftype & ft_isdir) {
- /* source is a dir: create target directory and do recursive sync */
- rc = doMkdir(sname, sP, tname, tP);
- if (rc || SP->dontdoit)
- return rc;
- else
- return SyncDirRecur(sname, tname);
- } else
- /* source is a regular file: copy the file */
- return doCopy(sname, sP, tname, tP);
- } else if (tP->ftype & ft_islnk) {
- /*--------------------------------------------------------------------
- * target is a symbolic link
- *------------------------------------------------------------------*/
- if ((tP->ftype & ft_isdir) == (sP->ftype & ft_isdir)) {
- /*
- * target points to the right type of object (dir vs regular file):
- * check if target points to the right place
- */
- rc = cmpSymlink(sname, sP, tname, tP);
- if (rc < 0)
- return 1; /* something is wrong */
- if (SP->listlinks && rc == 1)
- CONFIRM(op_info_link, sname, sP->ftype, tname, tP->ftype, "", rc);
- if (rc < 2)
- /* target is pointing to the right place */
- return 0;
- }
- /*
- * target points to the wrong type of object:
- * delete target link and try again
- */
- goto rpl_target;
- } else if (!(tP->ftype & ft_isdir)) {
- /*--------------------------------------------------------------------
- * target is regular file
- *------------------------------------------------------------------*/
- if (sP->ftype & ft_isdir)
- /* source is a dir: delete target file and try again */
- goto rpl_target;
- else {
- /* source is regular file or link to regular file */
- if (sP->ftype & ft_islnk) {
- /* source is just a link */
- if (!SP->keepcopies && !SP->copyfiles)
- /* replace target by a link */
- goto rpl_target;
- else if (SP->listcopies)
- CONFIRM(op_info_copy, sname, sP->ftype, tname, tP->ftype, "", rc);
- }
- if (!SP->forcecopies &&
- tP->stat.st_mtime == sP->stat.st_mtime &&
- tP->stat.st_size == sP->stat.st_size)
- {
- /* we assume the file hasn't changed: don't do anything */
- return 0;
- }
- if (SP->keepnew && tP->stat.st_mtime > sP->stat.st_mtime)
- /* we should keep the target because it is newer than the source */
- return 0;
- /* replace the target file */
- goto rpl_target;
- }
- } else if (!(tP->ftype & ft_islnk)) {
- /*--------------------------------------------------------------------
- * target is a directory
- *------------------------------------------------------------------*/
- if (sP->ftype & ft_isdir) {
- if (sP->ftype & ft_islnk) {
- /* source is just a link */
- if (!SP->keepcopies && !SP->copydirs)
- /* replace target by a link */
- goto rpl_target;
- else if (SP->listcopies)
- CONFIRM(op_info_copy, sname, sP->ftype, tname, tP->ftype, "", rc);
- }
- /* source is dir: recursively sync source and target dirs */
- return SyncDirRecur(sname, tname);
- } else
- /* source is no dir: delete target dir and try again */
- goto rpl_target;
- }
- /* should never be reached */
- return -1;
- }
- /*
- * CmpPred: returns a precedence number that is used to determine in which
- * order source directory entries are processed:
- * 1 source is regular file
- * 2 source is symbolic link
- * 3 target is not a real directory
- * 4 target exists and is a real directory (not a sym link)
- */
- static int
- CmpPred(DirEntry *dP)
- {
- if (!(dP->ftype & ft_isdir))
- return 1;
- else if (dP->ftype & ft_islnk)
- return 2;
- else if (!dP->teP ||
- !(dP->teP->ftype & ft_isdir) ||
- (dP->teP->ftype & ft_islnk))
- {
- return 3;
- } else
- return 4;
- }
- /*
- * DirCmp2: compare function for sorting directory entries
- */
- static int
- DirCmp2(const void *p1, const void *p2)
- {
- int d = CmpPred(*(DirEntry **)p1) - CmpPred(*(DirEntry **)p2);
- if (d)
- return d;
- else
- return strcmp((*(DirEntry **)p1)->name, (*(DirEntry **)p2)->name);
- }
- /*
- * SyncDirRecur: recursively synchronize source and target directories
- */
- static int
- SyncDirRecur(char *sdir, char *tdir)
- {
- DirEntry *sP, *tP, *seP, *teP;
- char *fsP, *ftP;
- int rc;
- /* informational callback */
- if (SP->verbose)
- CONFIRM(op_sync, sdir, ft_isdir, tdir, ft_isdir, "", rc);
- /* read source and target directories */
- if ((rc = GetDir(sdir, SP->exclude, SP->skip, &sP)) != 0)
- return rc;
- if ((rc = GetDir(tdir, NULL, SP->skip, &tP)) != 0) {
- FreeDir(sP);
- return rc;
- }
- /* append "/" to source and target directory names */
- fsP = sdir + strlen(sdir);
- ftP = tdir + strlen(tdir);
- *fsP++ = '/';
- *ftP++ = '/';
- /* first delete files in target dir that don't exist in source dir */
- seP = sP;
- teP = tP;
- while (teP) {
- /* compare directory entries */
- rc = (seP != NULL)? strcmp(seP->name, teP->name): 1;
- if ((seP != NULL) && seP->exclude) {
- /* skip excluded files */
- seP = seP->next;
- } else if (rc == 0) {
- /* file exists in both directories */
- seP->teP = teP;
- seP = seP->next;
- teP = teP->next;
- } else if (rc < 0) {
- /* source file not in target directory */
- seP = seP->next;
- } else { /* rc > 0 */
- /* target file not in source directory */
- if (!SP->dontdelete && !teP->skip) {
- strcpy(ftP, teP->name);
- if (doUnlink(tdir, teP, 1) < 0) {
- FreeDir(sP);
- FreeDir(tP);
- return -1;
- }
- }
- teP = teP->next;
- }
- }
- /* re-sort source dir so that regular files are processed before sub dirs */
- sP = SortDir(sP, DirCmp2);
- /* process all entires found in the source directory */
- for (seP = sP, rc = 0; seP && rc >= 0; seP = seP->next) {
- /* skip error entries */
- if (seP->rc)
- continue;
- /* skip excluded and to-be-skipped files */
- if (seP->exclude || seP->skip)
- continue;
- /* also skip sub directories if "don't recur" option is set */
- if (SP->dontrecur && (seP->ftype & ft_isdir))
- continue;
- /* construct source and target file names */
- strcpy(fsP, seP->name);
- strcpy(ftP, seP->name);
- /* sync directory item */
- rc = SyncItem(sdir, seP, tdir, seP->teP);
- }
- /* free directory lists */
- FreeDir(sP);
- FreeDir(tP);
- return (rc < 0)? -1: 0;
- }
- /*--------------------------------------------------------------------
- * external entry point
- *------------------------------------------------------------------*/
- void
- SyncDirectory(SyncParams *p)
- {
- char sbuf[1024], tbuf[1024];
- DirEntry *sP, *tP;
- FileOp op;
- int rc;
- /* the lower-level error and progress callbacks are not used */
- errorCallback = NULL;
- progressCallback = NULL;
- /* save pointer to params; copy source & target names */
- SP = p;
- snprintf(sbuf, sizeof(sbuf), "%s", SP->source);
- snprintf(tbuf, sizeof(tbuf), "%s", SP->target);
- /* get info about the source */
- sP = GetDirEntry(sbuf, &op, &rc);
- if (rc) {
- if (syncErrorCallback)
- syncErrorCallback(op, sbuf, rc);
- FreeDir(sP);
- return;
- }
- /*
- * The "copytop" option means: if the top-level source is a symbolic
- * make a copy of the real thing. To get this behavior we just switch
- * off the ft_islnk flag on the source.
- */
- if (SP->copytop)
- sP->ftype &= ~ft_islnk;
- /* get info about the target */
- tP = GetDirEntry(tbuf, &op, &rc);
- if (rc) {
- if (op == op_lstat && rc == ENOENT) {
- /* target does not yet exist; that's ok */
- FreeDir(tP);
- tP = NULL;
- } else {
- /* we'll try to procede anyway ... unless the error callback says no */
- if (syncErrorCallback && syncErrorCallback(op, tbuf, rc) < 0) {
- FreeDir(sP);
- FreeDir(tP);
- return;
- }
- }
- }
- /* now do the real work */
- SyncItem(sbuf, sP, tbuf, tP);
- /* free storage and return */
- FreeDir(sP);
- FreeDir(tP);
- }
|