#define O_CTG 0
#endif
+static int separate_path_and_file(void *jcr, char *fname, char *ofile);
+static int path_already_seen(char *path, int pnl);
+
/*
* Create the file, or the directory
uid_t uid;
gid_t gid;
int stat = 0;
- int fnl, pnl;
- char *f, *p, savechr;
+ int pnl;
binit(ofd);
new_mode = statp->st_mode;
}
switch (type) {
case FT_LNKSAVED: /* Hard linked, file already saved */
- Dmsg2(130, "Hard link %s => %s\n", ofile, lname);
- if (link(lname, ofile) != 0) {
- Jmsg3(jcr, M_ERROR, 0, _("Could not hard link %s ==> %s: ERR=%s\n"),
- ofile, lname, strerror(errno));
- return CF_ERROR;
- }
- return CF_CREATED;
+ case FT_LNK:
+ case FT_RAW:
+ case FT_FIFO:
+ case FT_SPEC:
case FT_REGE: /* empty file */
case FT_REG: /* regular file */
- /* Separate pathname and filename */
- for (p=f=ofile; *p; p++) {
- if (*p == '/') {
- f = p; /* possible filename */
- }
- }
- if (*f == '/') {
- f++;
- }
-
- fnl = p - f;
- if (fnl == 0) {
- /* The filename length must not be zero here because we
- * are dealing with a file (i.e. FT_REGE or FT_REG).
- */
- Jmsg1(jcr, M_ERROR, 0, _("Zero length filename: %s\n"), fname);
+ /*
+ * Here we do some preliminary work for all the above
+ * types to create the path to the file if it does
+ * not already exist. Below, we will split to
+ * do the file type specific work
+ */
+ pnl = separate_path_and_file(jcr, fname, ofile);
+ if (pnl < 0) {
return CF_ERROR;
}
- pnl = f - ofile - 1;
-
/*
* If path length is <= 0 we are making a file in the root
* directory. Assume that the directory already exists.
*/
if (pnl > 0) {
+ char savechr;
savechr = ofile[pnl];
ofile[pnl] = 0; /* terminate path */
- Dmsg1(50, "Make path %s\n", ofile);
- /*
- * If we need to make the directory, ensure that it is with
- * execute bit set (i.e. parent_mode), and preserve what already
- * exists. Normally, this should do nothing.
- */
- stat = !make_path(jcr, ofile, parent_mode, parent_mode, uid, gid, 1, NULL);
- if (stat == 0) {
- Dmsg1(0, "Could not make path. %s\n", ofile);
- Jmsg1(jcr, M_ERROR, 0, _("Could not make path. %s\n"), ofile);
- return CF_ERROR;
+ if (!path_already_seen(ofile, pnl)) {
+ Dmsg1(50, "Make path %s\n", ofile);
+ /*
+ * If we need to make the directory, ensure that it is with
+ * execute bit set (i.e. parent_mode), and preserve what already
+ * exists. Normally, this should do nothing.
+ */
+ stat = !make_path(jcr, ofile, parent_mode, parent_mode, uid, gid, 1, NULL);
+ if (stat == 0) {
+ Dmsg1(0, "Could not make path. %s\n", ofile);
+ Jmsg1(jcr, M_ERROR, 0, _("Could not make path. %s\n"), ofile);
+ return CF_ERROR;
+ }
}
-
ofile[pnl] = savechr; /* restore full name */
}
- Dmsg1(100, "Create file %s\n", ofile);
- mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; /* O_NOFOLLOW; */
- if (IS_CTG(statp->st_mode)) {
- mode |= O_CTG; /* set contiguous bit if needed */
- }
- Dmsg1(50, "Create file: %s\n", ofile);
- if ((bopen(ofd, ofile, mode, S_IRUSR | S_IWUSR)) < 0) {
- Jmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), ofile, strerror(errno));
- return CF_ERROR;
- }
- return CF_EXTRACT;
- case FT_LNK:
- Dmsg2(130, "FT_LNK should restore: %s -> %s\n", ofile, lname);
- if (symlink(lname, ofile) != 0 && errno != EEXIST) {
- Jmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"),
- ofile, lname, strerror(errno));
+ /* Now we do the specific work for each file type */
+ switch(type) {
+ case FT_REGE:
+ case FT_REG:
+ Dmsg1(100, "Create file %s\n", ofile);
+ mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; /* O_NOFOLLOW; */
+ if (IS_CTG(statp->st_mode)) {
+ mode |= O_CTG; /* set contiguous bit if needed */
+ }
+ Dmsg1(50, "Create file: %s\n", ofile);
+ if ((bopen(ofd, ofile, mode, S_IRUSR | S_IWUSR)) < 0) {
+ Jmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), ofile, strerror(errno));
+ return CF_ERROR;
+ }
+ return CF_EXTRACT;
+
+ case FT_RAW: /* Bacula raw device e.g. /dev/sda1 */
+ case FT_FIFO: /* Bacula fifo to save data */
+ case FT_SPEC:
+ if (S_ISFIFO(statp->st_mode)) {
+ Dmsg1(200, "Restore fifo: %s\n", ofile);
+ if (mkfifo(ofile, statp->st_mode) != 0 && errno != EEXIST) {
+ Jmsg2(jcr, M_ERROR, 0, _("Cannot make fifo %s: ERR=%s\n"), ofile, strerror(errno));
+ return CF_ERROR;
+ }
+ } else {
+ Dmsg1(200, "Restore node: %s\n", ofile);
+ if (mknod(ofile, statp->st_mode, statp->st_rdev) != 0 && errno != EEXIST) {
+ Jmsg2(jcr, M_ERROR, 0, _("Cannot make node %s: ERR=%s\n"), ofile, strerror(errno));
+ return CF_ERROR;
+ }
+ }
+ if (type == FT_RAW || type == FT_FIFO) {
+ btimer_id tid;
+ Dmsg1(200, "FT_RAW|FT_FIFO %s\n", ofile);
+ mode = O_WRONLY | O_BINARY;
+ /* Timeout open() in 60 seconds */
+ if (type == FT_FIFO) {
+ tid = start_thread_timer(pthread_self(), 60);
+ } else {
+ tid = NULL;
+ }
+ if ((bopen(ofd, ofile, mode, 0)) < 0) {
+ Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), ofile, strerror(errno));
+ stop_thread_timer(tid);
+ return CF_ERROR;
+ }
+ stop_thread_timer(tid);
+ return CF_EXTRACT;
+ }
+ Dmsg1(200, "FT_SPEC %s\n", ofile);
+ return CF_CREATED;
+
+ case FT_LNK:
+ Dmsg2(130, "FT_LNK should restore: %s -> %s\n", ofile, lname);
+ if (symlink(lname, ofile) != 0 && errno != EEXIST) {
+ Jmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"),
+ ofile, lname, strerror(errno));
+ return CF_ERROR;
+ }
+ return CF_CREATED;
+
+ case FT_LNKSAVED: /* Hard linked, file already saved */
+ Dmsg2(130, "Hard link %s => %s\n", ofile, lname);
+ if (link(lname, ofile) != 0) {
+ Jmsg3(jcr, M_ERROR, 0, _("Could not hard link %s ==> %s: ERR=%s\n"),
+ ofile, lname, strerror(errno));
return CF_ERROR;
}
return CF_CREATED;
+
+ } /* End inner switch */
+
case FT_DIR:
Dmsg2(300, "Make dir mode=%o dir=%s\n", new_mode, ofile);
if (make_path(jcr, ofile, new_mode, parent_mode, uid, gid, 0, NULL) != 0) {
return CF_ERROR;
}
return CF_CREATED;
- case FT_RAW:
- case FT_FIFO:
- case FT_SPEC:
- if (S_ISFIFO(statp->st_mode)) {
- Dmsg1(200, "Restore fifo: %s\n", ofile);
- if (mkfifo(ofile, statp->st_mode) != 0 && errno != EEXIST) {
- Jmsg2(jcr, M_ERROR, 0, _("Cannot make fifo %s: ERR=%s\n"), ofile, strerror(errno));
- return CF_ERROR;
- }
- } else {
- Dmsg1(200, "Restore node: %s\n", ofile);
- if (mknod(ofile, statp->st_mode, statp->st_rdev) != 0 && errno != EEXIST) {
- Jmsg2(jcr, M_ERROR, 0, _("Cannot make node %s: ERR=%s\n"), ofile, strerror(errno));
- return CF_ERROR;
- }
- }
- if (type == FT_RAW || type == FT_FIFO) {
- btimer_id tid;
- Dmsg1(200, "FT_RAW|FT_FIFO %s\n", ofile);
- mode = O_WRONLY | O_BINARY;
- /* Timeout open() in 60 seconds */
- if (type == FT_FIFO) {
- tid = start_thread_timer(pthread_self(), 60);
- } else {
- tid = NULL;
- }
- if ((bopen(ofd, ofile, mode, 0)) < 0) {
- Jmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"), ofile, strerror(errno));
- stop_thread_timer(tid);
- return CF_ERROR;
- }
- stop_thread_timer(tid);
- return CF_EXTRACT;
- }
- Dmsg1(200, "FT_SPEC %s\n", ofile);
- return CF_CREATED;
/* The following should not occur */
case FT_NOACCESS:
}
return CF_ERROR;
}
+
+/*
+ * Returns: > 0 index into path where last path char is.
+ * 0 no path
+ * -1 filename is zero
+ */
+static int separate_path_and_file(void *jcr, char *fname, char *ofile)
+{
+ char *f, *p;
+ int fnl, pnl;
+
+ /* Separate pathname and filename */
+ for (p=f=ofile; *p; p++) {
+ if (*p == '/') {
+ f = p; /* possible filename */
+ }
+ }
+ if (*f == '/') {
+ f++;
+ }
+
+ fnl = p - f;
+ if (fnl == 0) {
+ /* The filename length must not be zero here because we
+ * are dealing with a file (i.e. FT_REGE or FT_REG).
+ */
+ Jmsg1(jcr, M_ERROR, 0, _("Zero length filename: %s\n"), fname);
+ return -1;
+ }
+ pnl = f - ofile - 1;
+ return pnl;
+}
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Primitive caching of path to prevent recreating a pathname
+ * each time as long as we remain in the same directory.
+ */
+static int path_already_seen(char *path, int pnl)
+{
+ static int cached_pnl = 0;
+ static char cached_path[1000];
+
+ P(mutex);
+ if (cached_pnl == pnl && strcmp(path, cached_path) == 0) {
+ V(mutex);
+ return 1;
+ }
+ if (pnl < (int)(sizeof(cached_path)-1)) {
+ strcpy(cached_path, path);
+ cached_pnl = pnl;
+ }
+ V(mutex);
+ return 0;
+}
#include <dirent.h>
#define NAMELEN(dirent) (strlen((dirent)->d_name))
#endif
+
#include <sys/file.h>
+#if HAVE_UTIME_H
#include <utime.h>
+#else
+struct utimbuf {
+ long actime;
+ long modtime;
+};
+#endif
#define MODE_RALL (S_IRUSR|S_IRGRP|S_IROTH)
#include "save-cwd.h"
+#ifndef HAVE_READDIR_R
+int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+#endif
+
+
/*
* Status codes returned by create_file()
*/
-#define CF_SKIP 1 /* skip file (not newer or something) */
-#define CF_ERROR 2 /* error creating file */
-#define CF_EXTRACT 3 /* file created, data to extract */
-#define CF_CREATED 4 /* file created, no data to extract */
+#define CF_SKIP 1 /* skip file (not newer or something) */
+#define CF_ERROR 2 /* error creating file */
+#define CF_EXTRACT 3 /* file created, data to extract */
+#define CF_CREATED 4 /* file created, no data to extract */
/*
* NOTE!!! These go on the tape, so don't change them. If
* need be, add to them.
*/
-#define FT_LNKSAVED 1 /* hard link to file already saved */
-#define FT_REGE 2 /* Regular file but empty */
-#define FT_REG 3 /* Regular file */
-#define FT_LNK 4 /* Soft Link */
-#define FT_DIR 5 /* Directory */
-#define FT_SPEC 6 /* Special file -- chr, blk, fifo, sock */
-#define FT_NOACCESS 7 /* Not able to access */
-#define FT_NOFOLLOW 8 /* Could not follow link */
-#define FT_NOSTAT 9 /* Could not stat file */
-#define FT_NOCHG 10 /* Incremental option, file not changed */
-#define FT_DIRNOCHG 11 /* Incremental option, directory not changed */
-#define FT_ISARCH 12 /* Trying to save archive file */
-#define FT_NORECURSE 13 /* No recursion into directory */
-#define FT_NOFSCHG 14 /* Different file system, prohibited */
-#define FT_NOOPEN 15 /* Could not open directory */
-#define FT_RAW 16 /* Raw block device */
-#define FT_FIFO 17 /* Raw fifo device */
+#define FT_LNKSAVED 1 /* hard link to file already saved */
+#define FT_REGE 2 /* Regular file but empty */
+#define FT_REG 3 /* Regular file */
+#define FT_LNK 4 /* Soft Link */
+#define FT_DIR 5 /* Directory */
+#define FT_SPEC 6 /* Special file -- chr, blk, fifo, sock */
+#define FT_NOACCESS 7 /* Not able to access */
+#define FT_NOFOLLOW 8 /* Could not follow link */
+#define FT_NOSTAT 9 /* Could not stat file */
+#define FT_NOCHG 10 /* Incremental option, file not changed */
+#define FT_DIRNOCHG 11 /* Incremental option, directory not changed */
+#define FT_ISARCH 12 /* Trying to save archive file */
+#define FT_NORECURSE 13 /* No recursion into directory */
+#define FT_NOFSCHG 14 /* Different file system, prohibited */
+#define FT_NOOPEN 15 /* Could not open directory */
+#define FT_RAW 16 /* Raw block device */
+#define FT_FIFO 17 /* Raw fifo device */
/* Options saved in "flag" of ff packet */
-#define FO_MD5 0x001 /* Do MD5 checksum */
-#define FO_GZIP 0x002 /* Do Zlib compression */
-#define FO_NO_RECURSION 0x004 /* no recursion in directories */
-#define FO_MULTIFS 0x008 /* multiple file systems */
-#define FO_SPARSE 0x010 /* do sparse file checking */
-#define FO_IF_NEWER 0x020 /* replace if newer */
-#define FO_NOREPLACE 0x040 /* never replace */
-#define FO_READFIFO 0x080 /* read data from fifo */
-#define FO_SHA1 0x100 /* Do SHA1 checksum */
+#define FO_MD5 0x001 /* Do MD5 checksum */
+#define FO_GZIP 0x002 /* Do Zlib compression */
+#define FO_NO_RECURSION 0x004 /* no recursion in directories */
+#define FO_MULTIFS 0x008 /* multiple file systems */
+#define FO_SPARSE 0x010 /* do sparse file checking */
+#define FO_IF_NEWER 0x020 /* replace if newer */
+#define FO_NOREPLACE 0x040 /* never replace */
+#define FO_READFIFO 0x080 /* read data from fifo */
+#define FO_SHA1 0x100 /* Do SHA1 checksum */
/*
* Options saved in "options" of include list
#define OPT_compute_MD5 0x01 /* compute MD5 of file's data */
#define OPT_GZIP_compression 0x02 /* use GZIP compression */
#define OPT_no_recursion 0x04 /* no recursion in directories */
-#define OPT_multifs 0x08 /* multiple file systems */
-#define OPT_sparse 0x10 /* do sparse file checking */
+#define OPT_multifs 0x08 /* multiple file systems */
+#define OPT_sparse 0x10 /* do sparse file checking */
#define OPT_replace_if_newer 0x20 /* replace file if newer */
#define OPT_never_replace 0x40 /* never replace */
-#define OPT_read_fifo 0x80 /* read data from fifo (named pipe) */
+#define OPT_read_fifo 0x80 /* read data from fifo (named pipe) */
#define OPT_compute_SHA1 0x100 /* compute SHA1 of file's data */
struct s_included_file {
struct s_included_file *next;
- int options; /* backup options */
- int level; /* compression level */
- int len; /* length of fname */
- int pattern; /* set if pattern */
- char VerifyOpts[20]; /* Options for verify */
+ int options; /* backup options */
+ int level; /* compression level */
+ int len; /* length of fname */
+ int pattern; /* set if pattern */
+ char VerifyOpts[20]; /* Options for verify */
char fname[1];
};
};
typedef struct s_bfile {
- int fid; /* file id on Unix */
+ int fid; /* file id on Unix */
} BFILE;
* first argument to the find_files callback subroutine.
*/
typedef struct s_ff {
- char *fname; /* filename */
- char *link; /* link if file linked */
- POOLMEM *sys_fname; /* system filename */
- struct stat statp; /* stat packet */
- uint32_t FileIndex; /* FileIndex of this file */
- uint32_t LinkFI; /* FileIndex of main hard linked file */
- struct f_link *linked; /* Set if we are hard linked */
- int type; /* FT_ type from above */
- int flags; /* control flags */
- int ff_errno; /* errno */
- int incremental; /* do incremental save */
- BFILE bfd; /* Bacula file descriptor */
- time_t save_time; /* start of incremental time */
- int mtime_only; /* incremental on mtime_only */
- int dereference; /* follow links */
- int GZIP_level; /* compression level */
- int atime_preserve; /* preserve access times */
- int null_output_device; /* using null output device */
+ char *fname; /* filename */
+ char *link; /* link if file linked */
+ POOLMEM *sys_fname; /* system filename */
+ struct stat statp; /* stat packet */
+ uint32_t FileIndex; /* FileIndex of this file */
+ uint32_t LinkFI; /* FileIndex of main hard linked file */
+ struct f_link *linked; /* Set if we are hard linked */
+ int type; /* FT_ type from above */
+ int flags; /* control flags */
+ int ff_errno; /* errno */
+ int incremental; /* do incremental save */
+ BFILE bfd; /* Bacula file descriptor */
+ time_t save_time; /* start of incremental time */
+ int mtime_only; /* incremental on mtime_only */
+ int dereference; /* follow links */
+ int GZIP_level; /* compression level */
+ int atime_preserve; /* preserve access times */
+ int null_output_device; /* using null output device */
char VerifyOpts[20];
struct s_included_file *included_files_list;
struct s_excluded_file *excluded_files_list;
struct s_excluded_file *excluded_paths_list;
- struct f_link *linklist; /* hard linked files */
+ struct f_link *linklist; /* hard linked files */
} FF_PKT;
#include "bacula.h"
#include "find.h"
-
extern size_t name_max; /* filename max length */
extern size_t path_max; /* path name max length */
-#ifndef HAVE_READDIR_R
-int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
-#endif
-
-
/*
* Structure for keeping track of hard linked files, we
* keep an entry for each hardlinked file that we save,
char name[1]; /* The name */
};
-
-#if HAVE_UTIME_H
-# include <utime.h>
-#else
-struct utimbuf {
- long actime;
- long modtime;
-};
-#endif
-
-
/*
* Find a single file.
* handle_file is the callback for handling the file.
}
Dmsg1(60, "File ----: %s\n", fname);
-#ifdef DEBUG
- if (S_ISLNK(ff_pkt->statp.st_mode))
- Dmsg1(60, "Link-------------: %s \n", fname);
-#endif
/* Save current times of this directory in case we need to
* reset them because the user doesn't want them changed.
ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
/* Incremental option, file not changed */
ff_pkt->type = FT_NOCHG;
- Dmsg1(100, "File not changed: %s\n", ff_pkt->fname);
- Dmsg4(200, "save_time=%d mtime=%d mtime_only=%d st_ctime=%d\n",
- ff_pkt->save_time, ff_pkt->statp.st_mtime,
- ff_pkt->mtime_only, ff_pkt->statp.st_ctime);
return handle_file(ff_pkt, pkt);
}
}
+/* ***FIXME*** implement this */
#if xxxxxxx
/* See if we are trying to dump the archive. */
if (ar_dev && ff_pkt->statp.st_dev == ar_dev && ff_pkt->statp.st_ino == ar_ino) {
return rtn_stat;
- } else if (S_ISLNK(ff_pkt->statp.st_mode)) {
+ } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
int size;
- char *buffer = (char *)alloca(path_max + name_max + 2);
+ char *buffer = (char *)alloca(path_max + name_max + 102);
- size = readlink(fname, buffer, path_max + name_max + 1);
+ size = readlink(fname, buffer, path_max + name_max + 101);
if (size < 0) {
/* Could not follow link */
ff_pkt->type = FT_NOFOLLOW;
return rtn_stat;
}
buffer[size] = 0;
- ff_pkt->link = buffer;
- ff_pkt->type = FT_LNK; /* got a real link */
+ ff_pkt->link = buffer; /* point to link */
+ ff_pkt->type = FT_LNK; /* got a real link */
rtn_stat = handle_file(ff_pkt, pkt);
if (ff_pkt->linked) {
ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
struct dirent *entry, *result;
char *link;
int link_len;
- int len;
+ int len;
int status;
dev_t our_device = ff_pkt->statp.st_dev;
return rtn_stat;
}
- /* Build a canonical directory name with a trailing slash. */
+ /* Build a canonical directory name with a trailing slash in link var */
len = strlen(fname);
link_len = len + 200;
link = (char *)bmalloc(link_len + 2);
} else {
ff_pkt->type = FT_DIR;
}
- handle_file(ff_pkt, pkt); /* handle directory entry */
- if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
- }
-
+ FF_PKT *dir_ff_pkt;
+ dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
+ memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
+ dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
+ dir_ff_pkt->link = bstrdup(ff_pkt->link);
+
ff_pkt->link = ff_pkt->fname; /* reset "link" */
/*
if (ff_pkt->linked) {
ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
}
+ free(dir_ff_pkt->fname);
+ free(dir_ff_pkt->link);
+ free(dir_ff_pkt);
return rtn_stat;
}
if (ff_pkt->linked) {
ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
}
+ free(dir_ff_pkt->fname);
+ free(dir_ff_pkt->link);
+ free(dir_ff_pkt);
return rtn_stat;
}
/*
- * Now process the files in this directory.
+ * Open directory for reading files within
*/
errno = 0;
if ((directory = opendir(fname)) == NULL) {
if (ff_pkt->linked) {
ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
}
+ free(dir_ff_pkt->fname);
+ free(dir_ff_pkt->link);
+ free(dir_ff_pkt);
return rtn_stat;
}
/*
- * This would possibly run faster if we chdir to the directory
- * before traversing it.
+ * Process all files in this directory entry (recursing).
+ * This would possibly run faster if we chdir to the directory
+ * before traversing it.
*/
rtn_stat = 1;
entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
int i;
status = readdir_r(directory, entry, &result);
- Dmsg3(200, "readdir stat=%d result=%x name=%s\n", status, result,
- entry->d_name);
if (status != 0 || result == NULL) {
break;
}
free(link);
free(entry);
+ /*
+ * Now that we have recursed through all the files in the
+ * directory, we "save" the directory so that after all
+ * the files are restored, this entry will serve to reset
+ * the directory modes and dates. Temp directory values
+ * were used without this record.
+ */
+ handle_file(dir_ff_pkt, pkt); /* handle directory entry */
+ if (ff_pkt->linked) {
+ ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
+ }
+ free(dir_ff_pkt->fname);
+ free(dir_ff_pkt->link);
+ free(dir_ff_pkt);
+
if (ff_pkt->atime_preserve) {
utime(fname, &restore_times);
}