3 Copyright 1988, 92,93,94,95,96,97, 1999 Free Software Foundation, Inc.
4 Written by John Gilmore, starting 1985-08-25.
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any later
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 Massively changed from GNU TAR source code to adapt to Bacula
30 extern size_t name_max; /* filename max length */
31 extern size_t path_max; /* path name max length */
33 #ifndef HAVE_READDIR_R
34 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
38 /* ****FIXME**** debug until stable */
40 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
44 * Structure for keeping track of hard linked files
68 * handle_file is the callback for handling the file.
70 * parent_device is the device we are currently on
71 * top_level is 1 when not recursing.
74 find_one_file(FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), void *pkt,
75 char *p, dev_t parent_device, int top_level)
77 struct utimbuf restore_times;
80 ff_pkt->fname = ff_pkt->link = p;
81 if (ff_pkt->compute_MD5) {
82 ff_pkt->flags |= FO_MD5;
84 if (ff_pkt->GZIP_compression) {
85 ff_pkt->flags |= FO_GZIP;
88 /* Use stat if following (rather than dumping) 4.2BSD's symbolic links.
89 Otherwise, use lstat (which falls back to stat if no symbolic links). */
91 if (ff_pkt->dereference != 0
92 #if STX_HIDDEN && !_LARGE_FILES /* AIX */
93 ? statx(p, &ff_pkt->statp, STATSIZE, STX_HIDDEN)
94 : statx(p, &ff_pkt->statp, STATSIZE, STX_HIDDEN | STX_LINK)
96 ? stat(p, &ff_pkt->statp) : lstat(p, &ff_pkt->statp)
100 /* Cannot stat file */
101 ff_pkt->type = FT_NOSTAT;
102 ff_pkt->ff_errno = errno;
103 return handle_file(ff_pkt, pkt);
106 Dmsg1(60, "File ----: %s\n", p);
107 if (S_ISLNK(ff_pkt->statp.st_mode))
108 Dmsg1(60, "Link-------------: %s \n", p);
110 /* Save current times of this directory in case we need to
111 * reset them because the user doesn't want them changed.
113 restore_times.actime = ff_pkt->statp.st_atime;
114 restore_times.modtime = ff_pkt->statp.st_mtime;
118 if (S_ISHIDDEN(ff_pkt->statp.st_mode)) {
119 char *new = alloca(strlen(p) + 2);
129 /* See if we want only new files, and check if this one is too old to
130 put in the archive. */
132 if (ff_pkt->incremental && !S_ISDIR(ff_pkt->statp.st_mode)) {
133 Dmsg1(100, "Non-directory incremental: %s\n", ff_pkt->fname);
134 /* Not a directory */
135 if (ff_pkt->statp.st_mtime < ff_pkt->save_time
136 && (ff_pkt->mtime_only ||
137 ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
138 /* Incremental option, file not changed */
139 ff_pkt->type = FT_NOCHG;
140 Dmsg1(100, "File not changed: %s\n", ff_pkt->fname);
141 Dmsg4(200, "save_time=%d mtime=%d mtime_only=%d st_ctime=%d\n",
142 ff_pkt->save_time, ff_pkt->statp.st_mtime,
143 ff_pkt->mtime_only, ff_pkt->statp.st_ctime);
144 return handle_file(ff_pkt, pkt);
149 /* See if we are trying to dump the archive. */
150 if (ar_dev && ff_pkt->statp.st_dev == ar_dev && ff_pkt->statp.st_ino == ar_ino) {
151 ff_pkt->type = FT_ISARCH;
152 return handle_file(ff_pkt, pkt);
156 /* Check for multiple links.
157 NOTE: CTG is Masscomp contiguous files
159 We maintain a list of all such files that we've written so far. Any
160 time we see another, we check the list and avoid dumping the data
161 again if we've done it once already. */
163 if (ff_pkt->statp.st_nlink > 1
164 && (S_ISREG(ff_pkt->statp.st_mode)
165 || S_ISCTG(ff_pkt->statp.st_mode)
166 || S_ISCHR(ff_pkt->statp.st_mode)
167 || S_ISBLK(ff_pkt->statp.st_mode)
168 || S_ISFIFO(ff_pkt->statp.st_mode)
169 || S_ISSOCK(ff_pkt->statp.st_mode))) {
173 /* FIXME: First quick and dirty. Hashing, etc later. */
174 for (lp = ff_pkt->linklist; lp; lp = lp->next)
175 if (lp->ino == ff_pkt->statp.st_ino && lp->dev == ff_pkt->statp.st_dev) {
176 ff_pkt->link = lp->name;
177 ff_pkt->type = FT_LNKSAVED;
178 return handle_file(ff_pkt, pkt);
181 /* Not found. Add it to the list of possible links. */
183 lp = (struct f_link *)bmalloc(sizeof (struct f_link) + strlen(p));
184 lp->ino = ff_pkt->statp.st_ino;
185 lp->dev = ff_pkt->statp.st_dev;
186 strcpy (lp->name, p);
187 lp->next = ff_pkt->linklist;
188 ff_pkt->linklist = lp;
191 /* This is not a link to a previously dumped file, so dump it. */
192 if (S_ISREG(ff_pkt->statp.st_mode) || S_ISCTG(ff_pkt->statp.st_mode)) {
198 sizeleft = ff_pkt->statp.st_size;
200 /* Don't bother opening empty, world readable files. Also do not open
201 files when archive is meant for /dev/null. */
202 if (ff_pkt->null_output_device || (sizeleft == 0
203 && MODE_R == (MODE_R & ff_pkt->statp.st_mode))) {
204 ff_pkt->type = FT_REGE;
206 ff_pkt->type = FT_REG;
208 return handle_file(ff_pkt, pkt);
210 } else if (S_ISLNK(ff_pkt->statp.st_mode)) {
212 char *buffer = (char *)alloca(PATH_MAX + 1);
214 size = readlink(p, buffer, PATH_MAX + 1);
216 /* Could not follow link */
217 ff_pkt->type = FT_NOFOLLOW;
218 ff_pkt->ff_errno = errno;
219 return handle_file(ff_pkt, pkt);
222 ff_pkt->link = buffer;
223 ff_pkt->type = FT_LNK; /* got a real link */
224 return handle_file(ff_pkt, pkt);
226 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
228 struct dirent *entry, *result;
233 dev_t our_device = ff_pkt->statp.st_dev;
235 if (access(p, R_OK) == -1 && geteuid () != 0) {
236 /* Could not access() directory */
237 ff_pkt->type = FT_NOACCESS;
238 ff_pkt->ff_errno = errno;
239 return handle_file(ff_pkt, pkt);
242 /* Build new prototype name. Ensure exactly one trailing slash. */
244 buflen = len + NAME_FIELD_SIZE;
245 namebuf = (char *)bmalloc(buflen + 2);
246 strncpy(namebuf, p, buflen);
247 while (len >= 1 && namebuf[len - 1] == '/')
249 namebuf[len++] = '/';
252 ff_pkt->link = namebuf;
253 if (ff_pkt->incremental &&
254 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
255 ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
256 /* Incremental option, directory entry not changed */
257 ff_pkt->type = FT_DIRNOCHG;
259 ff_pkt->type = FT_DIR;
261 handle_file(ff_pkt, pkt); /* handle directory entry */
263 ff_pkt->link = ff_pkt->fname; /* reset "link" */
265 /* See if we are about to recurse into a directory, and avoid doing
266 so if the user wants that we do not descend into directories. */
268 if (ff_pkt->no_recursion) {
270 /* No recursion into this directory */
271 ff_pkt->type = FT_NORECURSE;
272 return handle_file(ff_pkt, pkt);
275 /* See if we are crossing from one file system to another, and
276 avoid doing so if the user only wants to dump one file system. */
278 if (ff_pkt->one_file_system && !top_level
279 && parent_device != ff_pkt->statp.st_dev) {
281 ff_pkt->type = FT_NOFSCHG;
282 return handle_file(ff_pkt, pkt);
285 /* Now output all the files in the directory. */
287 errno = 0; /* FIXME: errno should be read-only */
289 if ((directory = opendir(p)) == NULL) {
291 ff_pkt->type = FT_NOOPEN;
292 ff_pkt->ff_errno = errno;
293 return handle_file(ff_pkt, pkt);
296 /* FIXME: Should speed this up by cd-ing into the dir. */
299 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 10);
303 status = readdir_r(directory, entry, &result);
304 Dmsg3(200, "readdir stat=%d result=%x name=%s\n", status, result,
306 if (status != 0 || result == NULL) {
310 /* Skip `.', `..', and excluded file names. */
311 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
312 (p[1] == '.' && p[2] == '\0')))) {
316 if ((int)NAMLEN(entry) + len >= buflen) {
317 buflen = len + NAMLEN(entry);
318 namebuf = (char *)brealloc(namebuf, buflen + 2);
320 strcpy(namebuf + len, entry->d_name);
321 if (!file_is_excluded(ff_pkt, namebuf)) {
322 rtn_stat = find_one_file(ff_pkt, handle_file, pkt, namebuf, our_device, 0);
328 if (ff_pkt->atime_preserve) {
329 utime(p, &restore_times);
332 } /* end check for directory */
334 /* The only remaining types are special (character, ...) files */
335 ff_pkt->type = FT_SPEC;
336 return handle_file(ff_pkt, pkt);
339 void term_find_one(FF_PKT *ff)
341 struct f_link *lp, *lc;
343 /* Free up list of hard linked files */
344 for (lp = ff->linklist; lp;) {