Print this page
NEX-1348 It takes 23 hours and 37 minutes to run NDMP backup 43.9 GB with10000000 3KB files
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-13094 Netbackup 8.0 failed to back up files in NDMP certification test
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-9532 NDMP: readdir errors when file/directory has special characters
Reviewed by: Peer Dampmann <peer.dampmann@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2947 Volumes with more than a small fixed about don't traverse properly
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-2692 ndmpd intermittently dumps core due to SIGABRT in umem
SUP-898 nscd is extremely slow when a local file is missing
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
NEX-2500 Conflict between NDMP backup job and 'zfs send' leads to NDMP job abort.
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/ndmpd/tlm/tlm_traverse.c
+++ new/usr/src/cmd/ndmpd/tlm/tlm_traverse.c
1 1 /*
2 2 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
3 3 */
4 4
5 5 /*
6 6 * BSD 3 Clause License
7 7 *
8 8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 9 *
10 10 * Redistribution and use in source and binary forms, with or without
11 11 * modification, are permitted provided that the following conditions
12 12 * are met:
13 13 * - Redistributions of source code must retain the above copyright
14 14 * notice, this list of conditions and the following disclaimer.
15 15 *
16 16 * - Redistributions in binary form must reproduce the above copyright
17 17 * notice, this list of conditions and the following disclaimer in
18 18 * the documentation and/or other materials provided with the
19 19 * distribution.
20 20 *
21 21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 22 * nor the names of its contributors may be used to endorse or promote
23 23 * products derived from this software without specific prior written
24 24 * permission.
25 25 *
26 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
↓ open down ↓ |
27 lines elided |
↑ open up ↑ |
28 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 36 * POSSIBILITY OF SUCH DAMAGE.
37 37 */
38 +/* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
39 +
38 40 /*
39 41 * This file implemets the post-order, pre-order and level-order
40 42 * traversing of the file system. The related macros and constants
41 43 * are defined in traverse.h.
42 44 */
43 45
44 46 #include <sys/stat.h>
45 47 #include <sys/types.h>
46 48 #include <sys/param.h>
47 49 #include <assert.h>
48 50 #include <cstack.h>
49 51 #include <dirent.h>
50 52 #include <errno.h>
51 53 #include <traverse.h>
52 54 #include <limits.h>
53 55 #include <stdarg.h>
54 56 #include <stdio.h>
55 57 #include <stdlib.h>
56 58 #include <string.h>
57 59 #include <syslog.h>
58 60 #include <fcntl.h>
59 61 #include <unistd.h>
60 62 #include <tlm.h>
61 63 #include "tlm_proto.h"
62 64
63 65 /*
64 66 * Check if it's "." or ".."
65 67 */
66 68 boolean_t
67 69 rootfs_dot_or_dotdot(char *name)
68 70 {
69 71 if (*name != '.')
70 72 return (FALSE);
71 73
72 74 if ((name[1] == 0) || (name[1] == '.' && name[2] == 0))
|
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
73 75 return (TRUE);
74 76
75 77 return (FALSE);
76 78 }
77 79
78 80 /*
79 81 * Macros on fs_traverse flags.
80 82 */
81 83 #define STOP_ONERR(f) ((f)->ft_flags & FST_STOP_ONERR)
82 84 #define STOP_ONLONG(f) ((f)->ft_flags & FST_STOP_ONLONG)
83 -#define VERBOSE(f) ((f)->ft_flags & FST_VERBOSE)
84 85
85 86 #define CALLBACK(pp, ep) \
86 87 (*(ftp)->ft_callbk)((ftp)->ft_arg, pp, ep)
87 88
88 89 #define NEGATE(rv) ((rv) = -(rv))
89 90
90 91 /*
91 92 * The traversing state that is pushed onto the stack.
92 93 * This include:
93 94 * - The end of the path of the current directory.
94 95 * - The position of the last component on it.
95 96 * - The read position in the directory.
96 97 * - The file handle of the directory.
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
97 98 * - The stat of the directory.
98 99 */
99 100 typedef struct traverse_state {
100 101 char *ts_end;
101 102 char *ts_ent;
102 103 long ts_dpos; /* position in the directory when reading its entries */
103 104 fs_fhandle_t ts_fh;
104 105 struct stat64 ts_st;
105 106 } traverse_state_t;
106 107
107 -/*
108 - * Statistics gathering structure.
109 - */
110 -typedef struct traverse_statistics {
111 - ulong_t fss_newdirs;
112 - ulong_t fss_readdir_err;
113 - ulong_t fss_longpath_err;
114 - ulong_t fss_lookup_err;
115 - ulong_t fss_nondir_calls;
116 - ulong_t fss_dir_calls;
117 - ulong_t fss_nondir_skipped;
118 - ulong_t fss_dir_skipped;
119 - ulong_t fss_pushes;
120 - ulong_t fss_pops;
121 - ulong_t fss_stack_residue;
122 -} traverse_statistics_t;
123 -
124 -/*
125 - * Global instance of statistics variable.
126 - */
127 -traverse_statistics_t traverse_stats;
128 -
129 -#define MAX_DENT_BUF_SIZE (8 * 1024)
130 -
131 108 typedef struct {
132 109 struct stat64 fd_attr;
133 110 fs_fhandle_t fd_fh;
134 111 short fd_len;
135 112 char fd_name[1];
136 113 } fs_dent_info_t;
137 114
138 115 typedef struct dent_arg {
139 116 char *da_buf;
140 117 int da_end;
141 118 int da_size;
142 119 } dent_arg_t;
143 120
144 121 static int traverse_level_nondir(struct fs_traverse *ftp,
145 - traverse_state_t *tsp, struct fst_node *pnp,
146 - dent_arg_t *darg);
122 + traverse_state_t *tsp, struct fst_node *pnp);
147 123
148 124 /*
149 - * Gather some directory entry information and return them
150 - */
151 -static int
152 -fs_populate_dents(void *arg, int namelen,
153 - char *name, long *countp, struct stat64 *attr,
154 - fs_fhandle_t *fh)
155 -{
156 - dent_arg_t *darg = (dent_arg_t *)arg;
157 - int reclen = sizeof (fs_dent_info_t) + namelen;
158 - fs_dent_info_t *dent;
159 -
160 - if ((darg->da_end + reclen) > darg->da_size)
161 - return (-1);
162 -
163 - /* LINTED improper alignment */
164 - dent = (fs_dent_info_t *)(darg->da_buf + darg->da_end);
165 -
166 - dent->fd_attr = *attr;
167 - dent->fd_fh = *fh;
168 - (void) strcpy(dent->fd_name, name);
169 -
170 - dent->fd_len = reclen;
171 - darg->da_end += reclen;
172 -
173 - if (countp)
174 - (*countp)++;
175 -
176 - return (0);
177 -}
178 -
179 -/*
180 125 * Creates a new traversing state based on the path passed to it.
181 126 */
182 127 static traverse_state_t *
183 128 new_tsp(char *path)
184 129 {
185 130 traverse_state_t *tsp;
186 131 tsp = ndmp_malloc(sizeof (traverse_state_t));
187 132 if (!tsp)
188 133 return (NULL);
189 134
190 135 tsp->ts_end = strchr(path, '\0');
191 136 if (*(tsp->ts_end-1) == '/')
192 137 *--tsp->ts_end = '\0';
193 138 tsp->ts_ent = NULL;
194 139 tsp->ts_dpos = 0;
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
195 140
196 141 return (tsp);
197 142 }
198 143
199 144 /*
200 145 * Create a file handle and get stats for the given path
201 146 */
202 147 int
203 148 fs_getstat(char *path, fs_fhandle_t *fh, struct stat64 *st)
204 149 {
205 - if (lstat64(path, st) == -1)
150 + if (lstat64(path, st) == -1) {
151 + syslog(LOG_INFO,
152 + "lstat64() says [%s] not found errno=(%d)", path, errno);
206 153 return (errno);
154 + }
207 155
208 156 fh->fh_fid = st->st_ino;
209 157
210 158 if (!S_ISDIR(st->st_mode))
211 159 fh->fh_fpath = NULL;
212 160 else
213 161 fh->fh_fpath = strdup(path);
214 162 return (0);
215 163 }
216 164
217 165 /*
218 - * Get directory entries info and return in the buffer. Cookie
219 - * will keep the state of each call
220 - */
221 -static int
222 -fs_getdents(int fildes, struct dirent *buf, size_t *nbyte,
223 - char *pn_path, long *dpos, longlong_t *cookie,
224 - long *n_entries, dent_arg_t *darg)
225 -{
226 - struct dirent *ptr;
227 - char file_path[PATH_MAX + 1];
228 - fs_fhandle_t fh;
229 - struct stat64 st;
230 - char *p;
231 - int len;
232 - int rv;
233 -
234 - if (*nbyte == 0) {
235 - (void) memset((char *)buf, 0, MAX_DENT_BUF_SIZE);
236 - *nbyte = rv = getdents(fildes, buf, darg->da_size);
237 - *cookie = 0LL;
238 -
239 - if (rv <= 0)
240 - return (rv);
241 - }
242 -
243 - p = (char *)buf + *cookie;
244 - len = *nbyte;
245 - do {
246 - /* LINTED improper alignment */
247 - ptr = (struct dirent *)p;
248 - *dpos = ptr->d_off;
249 -
250 - if (rootfs_dot_or_dotdot(ptr->d_name))
251 - goto skip_entry;
252 -
253 - (void) snprintf(file_path, PATH_MAX, "%s/", pn_path);
254 - (void) strlcat(file_path, ptr->d_name, PATH_MAX + 1);
255 - (void) memset(&fh, 0, sizeof (fs_fhandle_t));
256 -
257 - if (lstat64(file_path, &st) != 0) {
258 - rv = -1;
259 - break;
260 - }
261 -
262 - fh.fh_fid = st.st_ino;
263 -
264 - if (S_ISDIR(st.st_mode))
265 - goto skip_entry;
266 -
267 - if (fs_populate_dents(darg, strlen(ptr->d_name),
268 - (char *)ptr->d_name, n_entries, &st, &fh) != 0)
269 - break;
270 -
271 -skip_entry:
272 - p = p + ptr->d_reclen;
273 - len -= ptr->d_reclen;
274 - } while (len);
275 -
276 - *cookie = (longlong_t)(p - (char *)buf);
277 - *nbyte = len;
278 - return (rv);
279 -}
280 -
281 -/*
282 166 * Read the directory entries and return the information about
283 167 * each entry
284 168 */
285 169 int
286 170 fs_readdir(fs_fhandle_t *ts_fh, char *path, long *dpos,
287 171 char *nm, int *el, fs_fhandle_t *efh, struct stat64 *est)
288 172 {
289 173 struct dirent *dp;
290 174 char file_path[PATH_MAX + 1];
291 175 DIR *dirp;
292 176 int rv;
293 177
294 178 if ((dirp = opendir(ts_fh->fh_fpath)) == NULL)
295 179 return (errno);
296 180
297 181 seekdir(dirp, *dpos);
298 182 if ((dp = readdir(dirp)) == NULL) {
299 183 rv = 0; /* skip this dir */
300 184 *el = 0;
301 185 } else {
302 186 (void) snprintf(file_path, PATH_MAX, "%s/", path);
303 187 (void) strlcat(file_path, dp->d_name, PATH_MAX + 1);
304 188
305 189 rv = fs_getstat(file_path, efh, est);
306 190 if (rv == 0) {
307 191 *dpos = telldir(dirp);
308 192 (void) strlcpy(nm, dp->d_name, NAME_MAX + 1);
309 193 *el = strlen(dp->d_name);
310 194 } else {
311 195 *el = 0;
312 196 }
313 197 }
314 198 (void) closedir(dirp);
315 199 return (rv);
316 200 }
317 201
318 202 /*
319 203 * Traverse the file system in the post-order way. The description
320 204 * and example is in the header file.
321 205 *
322 206 * The callback function should return 0, on success and non-zero on
323 207 * failure. If the callback function returns non-zero return value,
324 208 * the traversing stops.
325 209 */
326 210 int
327 211 traverse_post(struct fs_traverse *ftp)
328 212 {
329 213 char path[PATH_MAX + 1]; /* full path name of the current dir */
330 214 char nm[NAME_MAX + 1]; /* directory entry name */
|
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
331 215 char *lp; /* last position on the path */
332 216 int next_dir, rv;
333 217 int pl, el; /* path and directory entry length */
334 218 cstack_t *sp;
335 219 fs_fhandle_t pfh, efh;
336 220 struct stat64 pst, est;
337 221 traverse_state_t *tsp;
338 222 struct fst_node pn, en; /* parent and entry nodes */
339 223
340 224 if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
341 - NDMP_LOG(LOG_DEBUG, "Invalid argument");
342 225 errno = EINVAL;
343 226 return (-1);
344 227 }
345 228
346 229 /* set the default log function if it's not already set */
347 230 if (!ftp->ft_logfp) {
348 231 ftp->ft_logfp = (ft_log_t)syslog;
349 - NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
232 + syslog(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
350 233 }
351 234
352 235 /* set the logical path to physical path if it's not already set */
353 236 if (!ftp->ft_lpath) {
354 - NDMP_LOG(LOG_DEBUG,
237 + syslog(LOG_DEBUG,
355 238 "report the same paths: \"%s\"", ftp->ft_path);
356 239 ftp->ft_lpath = ftp->ft_path;
357 240 }
358 241
359 242 pl = strlen(ftp->ft_lpath);
360 243 if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
361 - NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
244 + syslog(LOG_ERR, "lpath too long \"%s\"", ftp->ft_path);
362 245 errno = ENAMETOOLONG;
363 246 return (-1);
364 247 }
365 248 (void) strcpy(path, ftp->ft_lpath);
366 249 (void) memset(&pfh, 0, sizeof (pfh));
367 250 rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
368 251
369 252 if (rv != 0) {
370 - NDMP_LOG(LOG_DEBUG,
253 + syslog(LOG_ERR,
371 254 "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
372 255 return (rv);
373 256 }
374 257
375 258 if (!S_ISDIR(pst.st_mode)) {
376 259 pn.tn_path = ftp->ft_lpath;
377 260 pn.tn_fh = &pfh;
378 261 pn.tn_st = &pst;
379 262 en.tn_path = NULL;
380 263 en.tn_fh = NULL;
381 264 en.tn_st = NULL;
382 265 rv = CALLBACK(&pn, &en);
383 - if (VERBOSE(ftp))
384 - NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
385 266 free(pfh.fh_fpath);
386 267 return (rv);
387 268 }
388 269
389 270 sp = cstack_new();
390 271 if (!sp) {
391 272 errno = ENOMEM;
392 273 free(pfh.fh_fpath);
393 274 return (-1);
394 275 }
395 276 tsp = new_tsp(path);
396 277 if (!tsp) {
397 278 cstack_delete(sp);
398 279 errno = ENOMEM;
399 280 free(pfh.fh_fpath);
400 281 return (-1);
401 282 }
402 283 tsp->ts_ent = tsp->ts_end;
|
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
403 284 tsp->ts_fh = pfh;
404 285 tsp->ts_st = pst;
405 286 pn.tn_path = path;
406 287 pn.tn_fh = &tsp->ts_fh;
407 288 pn.tn_st = &tsp->ts_st;
408 289
409 290 rv = 0;
410 291 next_dir = 1;
411 292 do {
412 293 if (next_dir) {
413 - traverse_stats.fss_newdirs++;
414 -
415 294 *tsp->ts_end = '\0';
416 - if (VERBOSE(ftp))
417 - NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
418 295 }
419 296
420 297 next_dir = 0;
421 298 do {
422 299 el = NAME_MAX;
423 300 rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
424 301 &tsp->ts_dpos, nm, &el,
425 302 &efh, &est);
426 303
427 304 if (rv != 0) {
428 - free(efh.fh_fpath);
429 - traverse_stats.fss_readdir_err++;
430 -
431 - NDMP_LOG(LOG_DEBUG,
305 + syslog(LOG_ERR,
432 306 "Error %d on readdir(%s) pos %d",
433 307 rv, path, tsp->ts_dpos);
434 308 if (STOP_ONERR(ftp))
435 309 break;
436 310 rv = SKIP_ENTRY;
437 311
438 312 continue;
439 313 }
440 314
441 315 /* done with this directory */
442 316 if (el == 0) {
443 - if (VERBOSE(ftp))
444 - NDMP_LOG(LOG_DEBUG,
445 - "Done(%s)", pn.tn_path);
446 317 break;
447 318 }
448 319 nm[el] = '\0';
449 320
450 321 if (rootfs_dot_or_dotdot(nm)) {
451 322 free(efh.fh_fpath);
452 323 continue;
453 324 }
454 325
455 - if (VERBOSE(ftp))
456 - NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
457 - tsp->ts_dpos, nm);
458 -
459 326 if (pl + 1 + el > PATH_MAX) {
460 - traverse_stats.fss_longpath_err++;
461 -
462 - NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
327 + syslog(LOG_ERR, "Path %s/%s is too long.",
463 328 path, nm);
464 329 if (STOP_ONLONG(ftp))
465 330 rv = ENAMETOOLONG;
466 331 free(efh.fh_fpath);
467 332 continue;
468 333 }
469 334
470 335 /*
471 336 * Push the current directory on to the stack and
472 337 * dive into the entry found.
473 338 */
474 339 if (S_ISDIR(est.st_mode)) {
475 340
476 341 assert(tsp != NULL);
477 342 if (cstack_push(sp, tsp, 0)) {
478 343 rv = ENOMEM;
479 344 free(efh.fh_fpath);
480 345 break;
481 346 }
482 - traverse_stats.fss_pushes++;
483 347
484 348 /*
485 349 * Concatenate the current entry with the
486 350 * current path. This will be the path of
487 351 * the new directory to be scanned.
488 352 *
489 353 * Note:
490 354 * sprintf(tsp->ts_end, "/%s", de->d_name);
491 355 * could be used here, but concatenating
492 356 * strings like this might be faster.
493 357 * The length of the new path has been
494 358 * checked above. So strcpy() can be
495 359 * safe and should not lead to a buffer
496 360 * over-run.
497 361 */
498 362 lp = tsp->ts_end;
499 363 *tsp->ts_end = '/';
500 364 (void) strcpy(tsp->ts_end + 1, nm);
501 365
502 366 tsp = new_tsp(path);
503 367 if (!tsp) {
504 368 free(efh.fh_fpath);
505 369 rv = ENOMEM;
506 370 } else {
507 371 next_dir = 1;
508 372 pl += el;
509 373 tsp->ts_fh = efh;
510 374 tsp->ts_st = est;
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
511 375 tsp->ts_ent = lp;
512 376 pn.tn_fh = &tsp->ts_fh;
513 377 pn.tn_st = &tsp->ts_st;
514 378 }
515 379 break;
516 380 } else {
517 381 /*
518 382 * The entry is not a directory so the
519 383 * callback function must be called.
520 384 */
521 - traverse_stats.fss_nondir_calls++;
522 -
523 385 en.tn_path = nm;
524 386 en.tn_fh = &efh;
525 387 en.tn_st = &est;
526 388 rv = CALLBACK(&pn, &en);
527 389 free(efh.fh_fpath);
528 - if (VERBOSE(ftp))
529 - NDMP_LOG(LOG_DEBUG,
530 - "CALLBACK(%s/%s): %d",
531 - pn.tn_path, en.tn_path, rv);
532 -
533 390 if (rv != 0)
534 391 break;
535 392 }
536 393 } while (rv == 0);
537 394
538 395 /*
539 396 * A new directory must be processed, go to the start of
540 397 * the loop, open it and process it.
541 398 */
542 399 if (next_dir)
543 400 continue;
544 401
545 402 if (rv == SKIP_ENTRY)
546 403 rv = 0; /* We should skip the current directory */
547 404
548 405 if (rv == 0) {
549 406 /*
550 407 * Remove the ent from the end of path and send it
551 408 * as an entry of the path.
552 409 */
553 410 lp = tsp->ts_ent;
|
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
554 411 *lp = '\0';
555 412 efh = tsp->ts_fh;
556 413 est = tsp->ts_st;
557 414 free(tsp);
558 415 if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
559 416 break;
560 417
561 418 assert(tsp != NULL);
562 419 pl = tsp->ts_end - path;
563 420
564 - if (VERBOSE(ftp))
565 - NDMP_LOG(LOG_DEBUG, "poped pl %d 0x%p \"%s\"",
566 - pl, tsp, path);
567 -
568 - traverse_stats.fss_pops++;
569 - traverse_stats.fss_dir_calls++;
570 -
571 421 pn.tn_fh = &tsp->ts_fh;
572 422 pn.tn_st = &tsp->ts_st;
573 423 en.tn_path = lp + 1;
574 424 en.tn_fh = &efh;
575 425 en.tn_st = &est;
576 426
577 427 rv = CALLBACK(&pn, &en);
578 428 free(efh.fh_fpath);
579 - if (VERBOSE(ftp))
580 - NDMP_LOG(LOG_DEBUG, "CALLBACK(%s/%s): %d",
581 - pn.tn_path, en.tn_path, rv);
582 429 /*
583 430 * Does not need to free tsp here. It will be released
584 431 * later.
585 432 */
586 433 }
587 434
588 435 if (rv != 0 && tsp) {
589 436 free(tsp->ts_fh.fh_fpath);
590 437 free(tsp);
591 438 }
592 439
593 440 } while (rv == 0);
594 441
595 442 /*
596 443 * For the 'ftp->ft_path' directory itself.
597 444 */
598 445 if (rv == 0) {
599 - traverse_stats.fss_dir_calls++;
600 -
601 446 pn.tn_fh = &efh;
602 447 pn.tn_st = &est;
603 448 en.tn_path = NULL;
604 449 en.tn_fh = NULL;
605 450 en.tn_st = NULL;
606 451 rv = CALLBACK(&pn, &en);
607 - if (VERBOSE(ftp))
608 - NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
609 452 }
610 453
611 454 /*
612 455 * Pop and free all the remaining entries on the stack.
613 456 */
614 457 while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
615 - traverse_stats.fss_stack_residue++;
616 -
617 458 free(tsp->ts_fh.fh_fpath);
618 459 free(tsp);
619 460 }
620 461
621 462 cstack_delete(sp);
622 463 return (rv);
623 464 }
624 465
625 466 /*
626 467 * In one pass, read all the directory entries of the specified
627 468 * directory and call the callback function for non-directory
628 469 * entries.
629 470 *
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
630 471 * On return:
631 472 * 0: Lets the directory to be scanned for directory entries.
632 473 * < 0: Completely stops traversing.
633 474 * FST_SKIP: stops further scanning of the directory. Traversing
634 475 * will continue with the next directory in the hierarchy.
635 476 * SKIP_ENTRY: Failed to get the directory entries, so the caller
636 477 * should skip this entry.
637 478 */
638 479 static int
639 480 traverse_level_nondir(struct fs_traverse *ftp,
640 - traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg)
481 + traverse_state_t *tsp, struct fst_node *pnp)
641 482 {
642 - int pl; /* path length */
643 - int rv;
483 + struct stat64 st;
484 + fs_fhandle_t fh;
485 + DIR *dp;
486 + struct dirent *dirp;
644 487 struct fst_node en; /* entry node */
645 - longlong_t cookie_verf;
646 - fs_dent_info_t *dent;
647 - struct dirent *buf;
648 - size_t len = 0;
649 - int fd;
488 + char path[MAXPATHLEN+MAXNAMELEN+2];
489 + int rv = 0;
650 490
651 - rv = 0;
652 - pl = strlen(pnp->tn_path);
653 -
654 - buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
655 - if (buf == NULL)
491 + if ((dp = opendir(tsp->ts_fh.fh_fpath)) == NULL) {
492 + syslog(LOG_ERR,
493 + "traverse_level_nondir: open directory "
494 + "%s failed: %m", tsp->ts_fh.fh_fpath);
656 495 return (errno);
657 -
658 - fd = open(tsp->ts_fh.fh_fpath, O_RDONLY);
659 - if (fd == -1) {
660 - free(buf);
661 - return (errno);
662 496 }
663 497
664 - while (rv == 0) {
665 - long i, n_entries;
498 + while ((dirp = readdir(dp)) != NULL) {
499 + if ((strcmp(dirp->d_name, ".") == 0) ||
500 + (strcmp(dirp->d_name, "..") == 0)) {
501 + continue;
502 + }
666 503
667 - darg->da_end = 0;
668 - n_entries = 0;
669 - rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos,
670 - &cookie_verf, &n_entries, darg);
671 - if (rv < 0) {
672 - traverse_stats.fss_readdir_err++;
504 + if (!tlm_cat_path(path, tsp->ts_fh.fh_fpath,
505 + dirp->d_name)) {
506 + continue;
507 + }
673 508
674 - NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d",
675 - rv, pnp->tn_path, tsp->ts_dpos);
676 - if (STOP_ONERR(ftp))
677 - break;
678 - /*
679 - * We cannot read the directory entry, we should
680 - * skip to the next directory.
681 - */
682 - rv = SKIP_ENTRY;
509 + if (lstat64(path, &st) != 0) {
510 + syslog(LOG_ERR,
511 + "traverse_level_nondir: failed to get file"
512 + " status for %s skipping: %m", tsp->ts_fh.fh_fpath);
683 513 continue;
684 - } else {
685 - /* Break at the end of directory */
686 - if (rv > 0)
687 - rv = 0;
688 - else
689 - break;
690 514 }
515 + fh.fh_fid = st.st_ino;
691 516
692 - /* LINTED imporper alignment */
693 - dent = (fs_dent_info_t *)darg->da_buf;
694 - /* LINTED imporper alignment */
695 - for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *)
696 - ((char *)dent + dent->fd_len)) {
697 -
698 - if (VERBOSE(ftp))
699 - NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"",
700 - dent->fd_fh.fh_fid, dent->fd_name);
701 -
702 - if ((pl + strlen(dent->fd_name)) > PATH_MAX) {
703 - traverse_stats.fss_longpath_err++;
704 -
705 - NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
706 - pnp->tn_path, dent->fd_name);
707 - if (STOP_ONLONG(ftp))
708 - rv = -ENAMETOOLONG;
709 - free(dent->fd_fh.fh_fpath);
710 - continue;
517 + /*
518 + * The entry is not a directory so the callback
519 + * function must be called.
520 + */
521 + if (!S_ISDIR(st.st_mode)) {
522 + en.tn_path = dirp->d_name;
523 + en.tn_fh = &fh;
524 + en.tn_st = &st;
525 + rv = CALLBACK(pnp, &en);
526 + if (rv < 0) {
527 + syslog(LOG_DEBUG,
528 + "traverse_level_nondir: result is %d "
529 + "with %s", rv, path);
530 + break;
711 531 }
712 -
713 - /*
714 - * The entry is not a directory so the callback
715 - * function must be called.
716 - */
717 - if (!S_ISDIR(dent->fd_attr.st_mode)) {
718 - traverse_stats.fss_nondir_calls++;
719 -
720 - en.tn_path = dent->fd_name;
721 - en.tn_fh = &dent->fd_fh;
722 - en.tn_st = &dent->fd_attr;
723 - rv = CALLBACK(pnp, &en);
724 - dent->fd_fh.fh_fpath = NULL;
725 - if (rv < 0)
726 - break;
727 - if (rv == FST_SKIP) {
728 - traverse_stats.fss_nondir_skipped++;
729 - break;
730 - }
532 + if (rv == FST_SKIP) {
533 + syslog(LOG_DEBUG,
534 + "traverse_level_nondir: skipping "
535 + "%s", path);
536 + break;
731 537 }
732 538 }
733 539 }
734 540
735 - free(buf);
736 - (void) close(fd);
541 + (void) closedir(dp);
737 542 return (rv);
738 543 }
739 544
740 545 /*
741 546 * Traverse the file system in the level-order way. The description
742 547 * and example is in the header file.
743 548 */
744 549 int
745 550 traverse_level(struct fs_traverse *ftp)
746 551 {
747 552 char path[PATH_MAX + 1]; /* full path name of the current dir */
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
748 553 char nm[NAME_MAX + 1]; /* directory entry name */
749 554 char *lp; /* last position on the path */
750 555 int next_dir, rv;
751 556 int pl, el; /* path and directory entry length */
752 557
753 558 cstack_t *sp;
754 559 fs_fhandle_t pfh, efh;
755 560 struct stat64 pst, est;
756 561 traverse_state_t *tsp;
757 562 struct fst_node pn, en; /* parent and entry nodes */
758 - dent_arg_t darg;
759 563
760 564 if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
761 - NDMP_LOG(LOG_DEBUG, "Invalid argument");
762 565 errno = EINVAL;
763 566 return (-1);
764 567 }
765 568 /* set the default log function if it's not already set */
766 569 if (!ftp->ft_logfp) {
767 570 ftp->ft_logfp = (ft_log_t)syslog;
768 - NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
571 + syslog(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
769 572 }
770 573 if (!ftp->ft_lpath) {
771 - NDMP_LOG(LOG_DEBUG,
574 + syslog(LOG_DEBUG,
772 575 "report the same paths \"%s\"", ftp->ft_path);
773 576 ftp->ft_lpath = ftp->ft_path;
774 577 }
775 578
776 579 pl = strlen(ftp->ft_lpath);
777 580 if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
778 - NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
581 + syslog(LOG_ERR, "lpath too long \"%s\"", ftp->ft_path);
779 582 errno = ENAMETOOLONG;
780 583 return (-1);
781 584 }
782 585 (void) strcpy(path, ftp->ft_lpath);
783 586 (void) memset(&pfh, 0, sizeof (pfh));
784 587 rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
785 588 if (rv != 0) {
786 - NDMP_LOG(LOG_DEBUG,
787 - "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
589 + syslog(LOG_DEBUG,
590 + "Error %d on fs_getstat(%s)", rv, ftp->ft_lpath);
788 591 return (-1);
789 592 }
790 593
791 594 en.tn_path = NULL;
792 595 en.tn_fh = NULL;
793 596 en.tn_st = NULL;
794 597 if (!S_ISDIR(pst.st_mode)) {
795 598 pn.tn_path = ftp->ft_lpath;
796 599 pn.tn_fh = &pfh;
797 600 pn.tn_st = &pst;
798 601 rv = CALLBACK(&pn, &en);
799 - if (VERBOSE(ftp))
800 - NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
801 -
802 602 free(pfh.fh_fpath);
803 603 return (rv);
804 604 }
805 605
806 606 sp = cstack_new();
807 607 if (!sp) {
808 608 free(pfh.fh_fpath);
809 609 errno = ENOMEM;
810 610 return (-1);
811 611 }
812 612 tsp = new_tsp(path);
813 613 if (!tsp) {
814 614 cstack_delete(sp);
815 615 free(pfh.fh_fpath);
816 616 errno = ENOMEM;
817 617 return (-1);
818 618 }
819 619
820 - darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
821 - if (!darg.da_buf) {
822 - cstack_delete(sp);
823 - free(pfh.fh_fpath);
824 - free(tsp);
825 - errno = ENOMEM;
826 - return (-1);
827 - }
828 - darg.da_size = MAX_DENT_BUF_SIZE;
829 -
830 620 tsp->ts_ent = tsp->ts_end;
831 621 tsp->ts_fh = pfh;
832 622 tsp->ts_st = pst;
833 623 pn.tn_path = path;
834 624 pn.tn_fh = &tsp->ts_fh;
835 625 pn.tn_st = &tsp->ts_st;
836 626
837 627 /* call the callback function on the path itself */
838 - traverse_stats.fss_dir_calls++;
839 628 rv = CALLBACK(&pn, &en);
840 629 if (rv < 0) {
841 630 free(tsp);
842 631 goto end;
843 632 }
844 633 if (rv == FST_SKIP) {
845 - traverse_stats.fss_dir_skipped++;
846 634 free(tsp);
847 635 rv = 0;
848 636 goto end;
849 637 }
850 638
851 639 rv = 0;
852 640 next_dir = 1;
853 641 do {
854 642 if (next_dir) {
855 - traverse_stats.fss_newdirs++;
856 -
857 643 *tsp->ts_end = '\0';
858 - if (VERBOSE(ftp))
859 - NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
860 -
861 - rv = traverse_level_nondir(ftp, tsp, &pn, &darg);
644 + rv = traverse_level_nondir(ftp, tsp, &pn);
862 645 if (rv < 0) {
863 646 NEGATE(rv);
864 647 free(tsp->ts_fh.fh_fpath);
865 648 free(tsp);
866 649 break;
867 650 }
868 651 /*
869 652 * If skipped by the callback function or
870 653 * error happened reading the information
871 654 */
872 655 if (rv == FST_SKIP || rv == SKIP_ENTRY) {
873 656 /*
874 657 * N.B. next_dir should be set to 0 as
875 658 * well. This prevents the infinite loop.
876 659 * If it's not set the same directory will
877 660 * be poped from the stack and will be
878 661 * scanned again.
879 662 */
880 663 next_dir = 0;
881 664 rv = 0;
882 665 goto skip_dir;
883 666 }
884 667
885 668 /* re-start reading entries of the directory */
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
886 669 tsp->ts_dpos = 0;
887 670 }
888 671
889 672 next_dir = 0;
890 673 do {
891 674 el = NAME_MAX;
892 675 rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
893 676 &tsp->ts_dpos, nm, &el, &efh,
894 677 &est);
895 678 if (rv != 0) {
896 - traverse_stats.fss_readdir_err++;
897 -
898 - NDMP_LOG(LOG_DEBUG,
679 + syslog(LOG_DEBUG,
899 680 "Error %d on readdir(%s) pos %d",
900 681 rv, path, tsp->ts_dpos);
901 682 if (STOP_ONERR(ftp))
902 683 break;
903 684 rv = SKIP_ENTRY;
904 685 continue;
905 686 }
906 687
907 688 /* done with this directory */
908 689 if (el == 0)
909 690 break;
910 691
911 692 nm[el] = '\0';
912 693
913 694 if (rootfs_dot_or_dotdot(nm)) {
914 695 free(efh.fh_fpath);
915 696 continue;
916 697 }
917 698
918 - if (VERBOSE(ftp))
919 - NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
920 - tsp->ts_dpos, nm);
921 -
922 699 if (pl + 1 + el > PATH_MAX) {
923 700 /*
924 701 * The long paths were already encountered
925 702 * when processing non-dir entries in.
926 703 * traverse_level_nondir.
927 704 * We don't increase fss_longpath_err
928 705 * counter for them again here.
929 706 */
930 - NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
707 + syslog(LOG_ERR, "Path %s/%s is too long.",
931 708 path, nm);
932 709 if (STOP_ONLONG(ftp))
933 710 rv = ENAMETOOLONG;
934 711 free(efh.fh_fpath);
935 712 continue;
936 713 }
937 714
938 715 if (!S_ISDIR(est.st_mode))
939 716 continue;
940 717
941 718 /*
942 719 * Call the callback function for the new
943 720 * directory found, then push the current
944 721 * directory on to the stack. Then dive
945 722 * into the entry found.
946 723 */
947 - traverse_stats.fss_dir_calls++;
948 724 en.tn_path = nm;
949 725 en.tn_fh = &efh;
950 726 en.tn_st = &est;
951 727 rv = CALLBACK(&pn, &en);
952 728
953 729 if (rv < 0) {
954 730 NEGATE(rv);
955 731 free(efh.fh_fpath);
956 732 break;
957 733 }
958 734 if (rv == FST_SKIP) {
959 - traverse_stats.fss_dir_skipped++;
960 735 free(efh.fh_fpath);
961 736 rv = 0;
962 737 continue;
963 738 }
964 739
965 740 /*
966 741 * Push the current directory on to the stack and
967 742 * dive into the entry found.
968 743 */
969 744 if (cstack_push(sp, tsp, 0)) {
970 745 rv = ENOMEM;
971 746 } else {
972 - traverse_stats.fss_pushes++;
973 -
974 747 lp = tsp->ts_end;
975 748 *tsp->ts_end = '/';
976 749 (void) strcpy(tsp->ts_end + 1, nm);
977 750
978 751 tsp = new_tsp(path);
979 752 if (!tsp)
980 753 rv = ENOMEM;
981 754 else {
982 755 next_dir = 1;
983 756 pl += el + 1;
984 757 tsp->ts_fh = efh;
985 758 tsp->ts_st = est;
986 759 tsp->ts_ent = lp;
987 760 pn.tn_fh = &tsp->ts_fh;
988 761 pn.tn_st = &tsp->ts_st;
989 762 }
990 763 }
991 764 break;
992 765
993 766 } while (rv == 0);
994 767
995 768 /*
996 769 * A new directory must be processed, go to the start of
997 770 * the loop, open it and process it.
998 771 */
999 772 if (next_dir)
1000 773 continue;
1001 774 skip_dir:
1002 775 if (tsp) {
1003 776 free(tsp->ts_fh.fh_fpath);
|
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
1004 777 free(tsp);
1005 778 }
1006 779
1007 780 if (rv == SKIP_ENTRY)
1008 781 rv = 0;
1009 782
1010 783 if (rv == 0) {
1011 784 if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
1012 785 break;
1013 786
1014 - traverse_stats.fss_pops++;
1015 -
1016 - if (VERBOSE(ftp))
1017 - NDMP_LOG(LOG_DEBUG,
1018 - "Poped pl %d \"%s\"", pl, path);
1019 -
1020 787 *tsp->ts_end = '\0';
1021 788 pl = tsp->ts_end - path;
1022 789 pn.tn_fh = &tsp->ts_fh;
1023 790 pn.tn_st = &tsp->ts_st;
1024 791 }
1025 792 } while (rv == 0);
1026 793
1027 794 /*
1028 795 * Pop and free all the remaining entries on the stack.
1029 796 */
1030 797 while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
1031 - traverse_stats.fss_stack_residue++;
1032 -
1033 798 free(tsp->ts_fh.fh_fpath);
1034 799 free(tsp);
1035 800 }
1036 801 end:
1037 - free(darg.da_buf);
1038 802 cstack_delete(sp);
1039 803 return (rv);
1040 804 }
1041 805
1042 806 /*
1043 807 * filecopy - Copy a file
1044 808 *
1045 809 * Parameters:
1046 810 * char *dest - Destination path
1047 811 * char *src - Source path
1048 812 *
1049 813 * Returns:
1050 814 * 0 - No errors
1051 815 * #0 - Error occured
1052 816 * -4 - read/write error
1053 817 * -5 - source modified during copy
1054 818 *
1055 819 * Simplified version for Solaris
1056 820 */
1057 821 #define BUFSIZE 32768
1058 822 int
1059 823 filecopy(char *dest, char *src)
1060 824 {
1061 825 FILE *src_fh = 0;
1062 826 FILE *dst_fh = 0;
1063 827 struct stat64 src_attr;
1064 828 struct stat64 dst_attr;
1065 829 char *buf = 0;
1066 830 u_longlong_t bytes_to_copy;
1067 831 size_t nbytes;
1068 832 int file_copied = 0;
1069 833
1070 834 buf = ndmp_malloc(BUFSIZE);
1071 835 if (!buf)
1072 836 return (-1);
1073 837
1074 838 src_fh = fopen(src, "r");
1075 839 if (src_fh == 0) {
1076 840 free(buf);
1077 841 return (-2);
1078 842 }
1079 843
1080 844 dst_fh = fopen(dest, "w");
1081 845 if (dst_fh == NULL) {
1082 846 free(buf);
1083 847 (void) fclose(src_fh);
1084 848 return (-3);
1085 849 }
1086 850
1087 851 if (stat64(src, &src_attr) < 0) {
1088 852 free(buf);
1089 853 (void) fclose(src_fh);
1090 854 (void) fclose(dst_fh);
1091 855 return (-2);
1092 856 }
1093 857
1094 858 bytes_to_copy = src_attr.st_size;
1095 859 while (bytes_to_copy) {
1096 860 if (bytes_to_copy > BUFSIZE)
1097 861 nbytes = BUFSIZE;
1098 862 else
1099 863 nbytes = bytes_to_copy;
1100 864
1101 865 if ((fread(buf, nbytes, 1, src_fh) != 1) ||
1102 866 (fwrite(buf, nbytes, 1, dst_fh) != 1))
1103 867 break;
1104 868 bytes_to_copy -= nbytes;
1105 869 }
1106 870
1107 871 (void) fclose(src_fh);
1108 872 (void) fclose(dst_fh);
1109 873
1110 874 if (bytes_to_copy > 0) {
1111 875 free(buf);
1112 876 /* short read/write, remove the partial file */
1113 877 return (-4);
1114 878 }
1115 879
1116 880 if (stat64(src, &dst_attr) < 0) {
1117 881 free(buf);
1118 882 return (-2);
1119 883 }
1120 884
1121 885 free(buf);
1122 886
1123 887 if (!file_copied)
1124 888 return (-5); /* source modified during copy */
1125 889 else
1126 890 return (0);
1127 891 }
|
↓ open down ↓ |
80 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX