Annotation of embedaddon/rsync/util.c, revision 1.1.1.4
1.1 misho 1: /*
2: * Utility routines used in rsync.
3: *
4: * Copyright (C) 1996-2000 Andrew Tridgell
5: * Copyright (C) 1996 Paul Mackerras
6: * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
1.1.1.4 ! misho 7: * Copyright (C) 2003-2020 Wayne Davison
1.1 misho 8: *
9: * This program is free software; you can redistribute it and/or modify
10: * it under the terms of the GNU General Public License as published by
11: * the Free Software Foundation; either version 3 of the License, or
12: * (at your option) any later version.
13: *
14: * This program is distributed in the hope that it will be useful,
15: * but WITHOUT ANY WARRANTY; without even the implied warranty of
16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17: * GNU General Public License for more details.
18: *
19: * You should have received a copy of the GNU General Public License along
20: * with this program; if not, visit the http://fsf.org website.
21: */
22:
23: #include "rsync.h"
24: #include "ifuncs.h"
1.1.1.2 misho 25: #include "itypes.h"
26: #include "inums.h"
1.1 misho 27:
1.1.1.3 misho 28: extern int dry_run;
1.1 misho 29: extern int module_id;
1.1.1.4 ! misho 30: extern int do_fsync;
1.1.1.2 misho 31: extern int protect_args;
1.1 misho 32: extern int modify_window;
33: extern int relative_paths;
34: extern int preserve_times;
35: extern int preserve_xattrs;
1.1.1.2 misho 36: extern int preallocate_files;
1.1.1.4 ! misho 37: extern int force_change;
1.1 misho 38: extern char *module_dir;
39: extern unsigned int module_dirlen;
40: extern char *partial_dir;
1.1.1.2 misho 41: extern filter_rule_list daemon_filter_list;
1.1 misho 42:
43: int sanitize_paths = 0;
44:
45: char curr_dir[MAXPATHLEN];
46: unsigned int curr_dir_len;
47: int curr_dir_depth; /* This is only set for a sanitizing daemon. */
48:
49: /* Set a fd into nonblocking mode. */
50: void set_nonblocking(int fd)
51: {
52: int val;
53:
54: if ((val = fcntl(fd, F_GETFL)) == -1)
55: return;
56: if (!(val & NONBLOCK_FLAG)) {
57: val |= NONBLOCK_FLAG;
58: fcntl(fd, F_SETFL, val);
59: }
60: }
61:
62: /* Set a fd into blocking mode. */
63: void set_blocking(int fd)
64: {
65: int val;
66:
67: if ((val = fcntl(fd, F_GETFL)) == -1)
68: return;
69: if (val & NONBLOCK_FLAG) {
70: val &= ~NONBLOCK_FLAG;
71: fcntl(fd, F_SETFL, val);
72: }
73: }
74:
75: /**
76: * Create a file descriptor pair - like pipe() but use socketpair if
77: * possible (because of blocking issues on pipes).
78: *
79: * Always set non-blocking.
80: */
81: int fd_pair(int fd[2])
82: {
83: int ret;
84:
85: #ifdef HAVE_SOCKETPAIR
86: ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
87: #else
88: ret = pipe(fd);
89: #endif
90:
91: if (ret == 0) {
92: set_nonblocking(fd[0]);
93: set_nonblocking(fd[1]);
94: }
95:
96: return ret;
97: }
98:
99: void print_child_argv(const char *prefix, char **cmd)
100: {
1.1.1.2 misho 101: int cnt = 0;
1.1 misho 102: rprintf(FCLIENT, "%s ", prefix);
103: for (; *cmd; cmd++) {
104: /* Look for characters that ought to be quoted. This
105: * is not a great quoting algorithm, but it's
106: * sufficient for a log message. */
107: if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
108: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
109: "0123456789"
110: ",.-_=+@/") != strlen(*cmd)) {
111: rprintf(FCLIENT, "\"%s\" ", *cmd);
112: } else {
113: rprintf(FCLIENT, "%s ", *cmd);
114: }
1.1.1.2 misho 115: cnt++;
1.1 misho 116: }
1.1.1.2 misho 117: rprintf(FCLIENT, " (%d args)\n", cnt);
1.1 misho 118: }
119:
1.1.1.4 ! misho 120: #ifdef SUPPORT_FORCE_CHANGE
! 121: static int try_a_force_change(const char *fname, STRUCT_STAT *stp)
! 122: {
! 123: uint32 fileflags = ST_FLAGS(*stp);
! 124: if (fileflags == NO_FFLAGS) {
! 125: STRUCT_STAT st;
! 126: if (x_lstat(fname, &st, NULL) == 0)
! 127: fileflags = st.st_flags;
! 128: }
! 129: if (fileflags != NO_FFLAGS && make_mutable(fname, stp->st_mode, fileflags, force_change) > 0) {
! 130: int ret, save_force_change = force_change;
! 131:
! 132: force_change = 0; /* Make certain we can't come back here. */
! 133: ret = set_times(fname, stp);
! 134: force_change = save_force_change;
! 135:
! 136: undo_make_mutable(fname, fileflags);
! 137:
! 138: return ret;
! 139: }
! 140:
! 141: errno = EPERM;
! 142:
! 143: return -1;
! 144: }
! 145: #endif
! 146:
1.1 misho 147: /* This returns 0 for success, 1 for a symlink if symlink time-setting
148: * is not possible, or -1 for any other error. */
1.1.1.4 ! misho 149: int set_times(const char *fname, STRUCT_STAT *stp)
1.1 misho 150: {
151: static int switch_step = 0;
152:
1.1.1.2 misho 153: if (DEBUG_GTE(TIME, 1)) {
1.1.1.4 ! misho 154: rprintf(FINFO,
! 155: "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
! 156: fname, (long)stp->st_mtime,
! 157: timestring(stp->st_mtime), (long)stp->st_atime, timestring(stp->st_atime));
1.1 misho 158: }
159:
160: switch (switch_step) {
1.1.1.4 ! misho 161: #ifdef HAVE_SETATTRLIST
! 162: #include "case_N.h"
! 163: if (do_setattrlist_times(fname, stp) == 0)
! 164: break;
! 165: if (errno != ENOSYS)
! 166: return -1;
! 167: switch_step++;
! 168: #endif
! 169:
1.1 misho 170: #ifdef HAVE_UTIMENSAT
171: #include "case_N.h"
1.1.1.4 ! misho 172: if (do_utimensat(fname, stp) == 0)
! 173: break;
! 174: #ifdef SUPPORT_FORCE_CHANGE
! 175: if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0)
1.1 misho 176: break;
1.1.1.4 ! misho 177: #endif
1.1 misho 178: if (errno != ENOSYS)
179: return -1;
180: switch_step++;
181: #endif
182:
183: #ifdef HAVE_LUTIMES
184: #include "case_N.h"
1.1.1.4 ! misho 185: if (do_lutimes(fname, stp) == 0)
! 186: break;
! 187: #ifdef SUPPORT_FORCE_CHANGE
! 188: if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0)
1.1 misho 189: break;
1.1.1.4 ! misho 190: #endif
1.1 misho 191: if (errno != ENOSYS)
192: return -1;
193: switch_step++;
194: #endif
195:
196: #include "case_N.h"
197: switch_step++;
198: if (preserve_times & PRESERVE_LINK_TIMES) {
199: preserve_times &= ~PRESERVE_LINK_TIMES;
1.1.1.4 ! misho 200: if (S_ISLNK(stp->st_mode))
1.1 misho 201: return 1;
202: }
203:
204: #include "case_N.h"
205: #ifdef HAVE_UTIMES
1.1.1.4 ! misho 206: if (do_utimes(fname, stp) == 0)
1.1 misho 207: break;
208: #else
1.1.1.4 ! misho 209: if (do_utime(fname, stp) == 0)
! 210: break;
! 211: #endif
! 212: #ifdef SUPPORT_FORCE_CHANGE
! 213: if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0)
1.1 misho 214: break;
215: #endif
216:
217: return -1;
218: }
219:
220: return 0;
221: }
222:
223: /* Create any necessary directories in fname. Any missing directories are
1.1.1.2 misho 224: * created with default permissions. Returns < 0 on error, or the number
225: * of directories created. */
1.1.1.4 ! misho 226: int make_path(char *fname, mode_t mode, int flags)
1.1 misho 227: {
1.1.1.2 misho 228: char *end, *p;
1.1 misho 229: int ret = 0;
230:
1.1.1.2 misho 231: if (flags & MKP_SKIP_SLASH) {
232: while (*fname == '/')
233: fname++;
234: }
235:
236: while (*fname == '.' && fname[1] == '/')
1.1 misho 237: fname += 2;
238:
1.1.1.2 misho 239: if (flags & MKP_DROP_NAME) {
240: end = strrchr(fname, '/');
1.1.1.3 misho 241: if (!end || end == fname)
1.1.1.2 misho 242: return 0;
243: *end = '\0';
244: } else
245: end = fname + strlen(fname);
246:
247: /* Try to find an existing dir, starting from the deepest dir. */
248: for (p = end; ; ) {
1.1.1.3 misho 249: if (dry_run) {
250: STRUCT_STAT st;
251: if (do_stat(fname, &st) == 0) {
252: if (S_ISDIR(st.st_mode))
253: errno = EEXIST;
254: else
255: errno = ENOTDIR;
256: }
1.1.1.4 ! misho 257: } else if (do_mkdir(fname, mode) == 0) {
1.1.1.2 misho 258: ret++;
259: break;
260: }
1.1.1.3 misho 261:
1.1.1.2 misho 262: if (errno != ENOENT) {
1.1.1.3 misho 263: STRUCT_STAT st;
264: if (errno != EEXIST || (do_stat(fname, &st) == 0 && !S_ISDIR(st.st_mode)))
1.1.1.2 misho 265: ret = -ret - 1;
266: break;
267: }
268: while (1) {
269: if (p == fname) {
1.1.1.3 misho 270: /* We got a relative path that doesn't exist, so assume that '.'
271: * is there and just break out and create the whole thing. */
272: p = NULL;
1.1.1.2 misho 273: goto double_break;
274: }
275: if (*--p == '/') {
276: if (p == fname) {
1.1.1.3 misho 277: /* We reached the "/" dir, which we assume is there. */
1.1.1.2 misho 278: goto double_break;
279: }
280: *p = '\0';
281: break;
282: }
283: }
1.1 misho 284: }
1.1.1.2 misho 285: double_break:
286:
287: /* Make all the dirs that we didn't find on the way here. */
288: while (p != end) {
1.1.1.3 misho 289: if (p)
290: *p = '/';
291: else
292: p = fname;
1.1.1.2 misho 293: p += strlen(p);
294: if (ret < 0) /* Skip mkdir on error, but keep restoring the path. */
295: continue;
1.1.1.4 ! misho 296: if (do_mkdir(fname, mode) < 0)
1.1.1.2 misho 297: ret = -ret - 1;
298: else
299: ret++;
300: }
301:
302: if (flags & MKP_DROP_NAME)
303: *end = '/';
1.1 misho 304:
305: return ret;
306: }
307:
308: /**
309: * Write @p len bytes at @p ptr to descriptor @p desc, retrying if
310: * interrupted.
311: *
312: * @retval len upon success
313: *
314: * @retval <0 write's (negative) error code
315: *
316: * Derived from GNU C's cccp.c.
317: */
318: int full_write(int desc, const char *ptr, size_t len)
319: {
320: int total_written;
321:
322: total_written = 0;
323: while (len > 0) {
324: int written = write(desc, ptr, len);
325: if (written < 0) {
326: if (errno == EINTR)
327: continue;
328: return written;
329: }
330: total_written += written;
331: ptr += written;
332: len -= written;
333: }
334: return total_written;
335: }
336:
337: /**
338: * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
339: * interrupted.
340: *
341: * @retval >0 the actual number of bytes read
342: *
343: * @retval 0 for EOF
344: *
345: * @retval <0 for an error.
346: *
347: * Derived from GNU C's cccp.c. */
348: static int safe_read(int desc, char *ptr, size_t len)
349: {
350: int n_chars;
351:
352: if (len == 0)
353: return len;
354:
355: do {
356: n_chars = read(desc, ptr, len);
357: } while (n_chars < 0 && errno == EINTR);
358:
359: return n_chars;
360: }
361:
362: /* Copy a file. If ofd < 0, copy_file unlinks and opens the "dest" file.
363: * Otherwise, it just writes to and closes the provided file descriptor.
364: * In either case, if --xattrs are being preserved, the dest file will
365: * have its xattrs set from the source file.
366: *
367: * This is used in conjunction with the --temp-dir, --backup, and
368: * --copy-dest options. */
1.1.1.2 misho 369: int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
1.1 misho 370: {
371: int ifd;
372: char buf[1024 * 8];
373: int len; /* Number of bytes read into `buf'. */
1.1.1.4 ! misho 374: OFF_T prealloc_len = 0, offset = 0;
1.1 misho 375:
376: if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
377: int save_errno = errno;
378: rsyserr(FERROR_XFER, errno, "open %s", full_fname(source));
379: errno = save_errno;
380: return -1;
381: }
382:
383: if (ofd < 0) {
384: if (robust_unlink(dest) && errno != ENOENT) {
385: int save_errno = errno;
386: rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));
1.1.1.4 ! misho 387: close(ifd);
1.1 misho 388: errno = save_errno;
389: return -1;
390: }
391:
1.1.1.2 misho 392: #ifdef SUPPORT_XATTRS
393: if (preserve_xattrs)
394: mode |= S_IWUSR;
395: #endif
396: mode &= INITACCESSPERMS;
1.1 misho 397: if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
1.1.1.2 misho 398: int save_errno = errno;
399: rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest));
400: close(ifd);
401: errno = save_errno;
402: return -1;
403: }
404: }
405:
406: #ifdef SUPPORT_PREALLOCATION
407: if (preallocate_files) {
408: STRUCT_STAT srcst;
409:
410: /* Try to preallocate enough space for file's eventual length. Can
411: * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
412: if (do_fstat(ifd, &srcst) < 0)
413: rsyserr(FWARNING, errno, "fstat %s", full_fname(source));
414: else if (srcst.st_size > 0) {
1.1.1.4 ! misho 415: prealloc_len = do_fallocate(ofd, 0, srcst.st_size);
! 416: if (prealloc_len < 0)
1.1.1.2 misho 417: rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest));
1.1 misho 418: }
419: }
1.1.1.2 misho 420: #endif
1.1 misho 421:
422: while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
423: if (full_write(ofd, buf, len) < 0) {
424: int save_errno = errno;
425: rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest));
426: close(ifd);
427: close(ofd);
428: errno = save_errno;
429: return -1;
430: }
1.1.1.2 misho 431: offset += len;
1.1 misho 432: }
433:
434: if (len < 0) {
435: int save_errno = errno;
436: rsyserr(FERROR_XFER, errno, "read %s", full_fname(source));
437: close(ifd);
438: close(ofd);
439: errno = save_errno;
440: return -1;
441: }
442:
443: if (close(ifd) < 0) {
444: rsyserr(FWARNING, errno, "close failed on %s",
445: full_fname(source));
446: }
447:
1.1.1.2 misho 448: /* Source file might have shrunk since we fstatted it.
449: * Cut off any extra preallocated zeros from dest file. */
1.1.1.4 ! misho 450: if (offset < prealloc_len && do_ftruncate(ofd, offset) < 0) {
1.1.1.2 misho 451: /* If we fail to truncate, the dest file may be wrong, so we
452: * must trigger the "partial transfer" error. */
453: rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest));
454: }
1.1.1.4 ! misho 455:
! 456: if (do_fsync && fsync(ofd) < 0) {
! 457: rsyserr(FERROR, errno, "fsync failed on %s",
! 458: full_fname(dest));
! 459: close(ofd);
! 460: return -1;
! 461: }
1.1.1.2 misho 462:
1.1 misho 463: if (close(ofd) < 0) {
464: int save_errno = errno;
465: rsyserr(FERROR_XFER, errno, "close failed on %s",
466: full_fname(dest));
467: errno = save_errno;
468: return -1;
469: }
470:
471: #ifdef SUPPORT_XATTRS
472: if (preserve_xattrs)
473: copy_xattrs(source, dest);
474: #endif
475:
476: return 0;
477: }
478:
479: /* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
480: #define MAX_RENAMES_DIGITS 3
481: #define MAX_RENAMES 1000
482:
483: /**
484: * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
485: * rename to <path>/.rsyncNNN instead.
486: *
487: * Note that successive rsync runs will shuffle the filenames around a
488: * bit as long as the file is still busy; this is because this function
489: * does not know if the unlink call is due to a new file coming in, or
490: * --delete trying to remove old .rsyncNNN files, hence it renames it
491: * each time.
492: **/
493: int robust_unlink(const char *fname)
494: {
495: #ifndef ETXTBSY
496: return do_unlink(fname);
497: #else
498: static int counter = 1;
499: int rc, pos, start;
500: char path[MAXPATHLEN];
501:
502: rc = do_unlink(fname);
503: if (rc == 0 || errno != ETXTBSY)
504: return rc;
505:
506: if ((pos = strlcpy(path, fname, MAXPATHLEN)) >= MAXPATHLEN)
507: pos = MAXPATHLEN - 1;
508:
509: while (pos > 0 && path[pos-1] != '/')
510: pos--;
511: pos += strlcpy(path+pos, ".rsync", MAXPATHLEN-pos);
512:
513: if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
514: errno = ETXTBSY;
515: return -1;
516: }
517:
518: /* start where the last one left off to reduce chance of clashes */
519: start = counter;
520: do {
521: snprintf(&path[pos], MAX_RENAMES_DIGITS+1, "%03d", counter);
522: if (++counter >= MAX_RENAMES)
523: counter = 1;
524: } while ((rc = access(path, 0)) == 0 && counter != start);
525:
1.1.1.2 misho 526: if (INFO_GTE(MISC, 1)) {
1.1 misho 527: rprintf(FWARNING, "renaming %s to %s because of text busy\n",
528: fname, path);
529: }
530:
531: /* maybe we should return rename()'s exit status? Nah. */
532: if (do_rename(fname, path) != 0) {
533: errno = ETXTBSY;
534: return -1;
535: }
536: return 0;
537: #endif
538: }
539:
540: /* Returns 0 on successful rename, 1 if we successfully copied the file
541: * across filesystems, -2 if copy_file() failed, and -1 on other errors.
542: * If partialptr is not NULL and we need to do a copy, copy the file into
543: * the active partial-dir instead of over the destination file. */
544: int robust_rename(const char *from, const char *to, const char *partialptr,
545: int mode)
546: {
547: int tries = 4;
548:
1.1.1.4 ! misho 549: /* A resumed in-place partial-dir transfer might call us with from and
! 550: * to pointing to the same buf if the transfer failed yet again. */
! 551: if (from == to)
! 552: return 0;
! 553:
1.1 misho 554: while (tries--) {
555: if (do_rename(from, to) == 0)
556: return 0;
557:
558: switch (errno) {
559: #ifdef ETXTBSY
560: case ETXTBSY:
561: if (robust_unlink(to) != 0) {
562: errno = ETXTBSY;
563: return -1;
564: }
565: errno = ETXTBSY;
566: break;
567: #endif
568: case EXDEV:
569: if (partialptr) {
570: if (!handle_partial_dir(partialptr,PDIR_CREATE))
571: return -2;
572: to = partialptr;
573: }
1.1.1.2 misho 574: if (copy_file(from, to, -1, mode) != 0)
1.1 misho 575: return -2;
576: do_unlink(from);
577: return 1;
578: default:
579: return -1;
580: }
581: }
582: return -1;
583: }
584:
585: static pid_t all_pids[10];
586: static int num_pids;
587:
588: /** Fork and record the pid of the child. **/
589: pid_t do_fork(void)
590: {
591: pid_t newpid = fork();
592:
593: if (newpid != 0 && newpid != -1) {
594: all_pids[num_pids++] = newpid;
595: }
596: return newpid;
597: }
598:
599: /**
600: * Kill all children.
601: *
602: * @todo It would be kind of nice to make sure that they are actually
603: * all our children before we kill them, because their pids may have
604: * been recycled by some other process. Perhaps when we wait for a
605: * child, we should remove it from this array. Alternatively we could
606: * perhaps use process groups, but I think that would not work on
607: * ancient Unix versions that don't support them.
608: **/
609: void kill_all(int sig)
610: {
611: int i;
612:
613: for (i = 0; i < num_pids; i++) {
614: /* Let's just be a little careful where we
615: * point that gun, hey? See kill(2) for the
616: * magic caused by negative values. */
617: pid_t p = all_pids[i];
618:
619: if (p == getpid())
620: continue;
621: if (p <= 0)
622: continue;
623:
624: kill(p, sig);
625: }
626: }
627:
628: /** Lock a byte range in a open file */
629: int lock_range(int fd, int offset, int len)
630: {
631: struct flock lock;
632:
633: lock.l_type = F_WRLCK;
634: lock.l_whence = SEEK_SET;
635: lock.l_start = offset;
636: lock.l_len = len;
637: lock.l_pid = 0;
638:
639: return fcntl(fd,F_SETLK,&lock) == 0;
640: }
641:
642: #define ENSURE_MEMSPACE(buf, type, sz, req) \
1.1.1.4 ! misho 643: do { if ((req) > sz) buf = realloc_array(buf, type, sz = MAX(sz * 2, req)); } while(0)
1.1 misho 644:
645: static inline void call_glob_match(const char *name, int len, int from_glob,
646: char *arg, int abpos, int fbpos);
647:
648: static struct glob_data {
649: char *arg_buf, *filt_buf, **argv;
650: int absize, fbsize, maxargs, argc;
651: } glob;
652:
653: static void glob_match(char *arg, int abpos, int fbpos)
654: {
655: int len;
656: char *slash;
657:
658: while (*arg == '.' && arg[1] == '/') {
659: if (fbpos < 0) {
660: ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, glob.absize);
661: memcpy(glob.filt_buf, glob.arg_buf, abpos + 1);
662: fbpos = abpos;
663: }
664: ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + 3);
665: glob.arg_buf[abpos++] = *arg++;
666: glob.arg_buf[abpos++] = *arg++;
667: glob.arg_buf[abpos] = '\0';
668: }
669: if ((slash = strchr(arg, '/')) != NULL) {
670: *slash = '\0';
671: len = slash - arg;
672: } else
673: len = strlen(arg);
674: if (strpbrk(arg, "*?[")) {
675: struct dirent *di;
676: DIR *d;
677:
678: if (!(d = opendir(abpos ? glob.arg_buf : ".")))
679: return;
680: while ((di = readdir(d)) != NULL) {
681: char *dname = d_name(di);
682: if (dname[0] == '.' && (dname[1] == '\0'
683: || (dname[1] == '.' && dname[2] == '\0')))
684: continue;
685: if (!wildmatch(arg, dname))
686: continue;
687: call_glob_match(dname, strlen(dname), 1,
688: slash ? arg + len + 1 : NULL,
689: abpos, fbpos);
690: }
691: closedir(d);
692: } else {
693: call_glob_match(arg, len, 0,
694: slash ? arg + len + 1 : NULL,
695: abpos, fbpos);
696: }
697: if (slash)
698: *slash = '/';
699: }
700:
701: static inline void call_glob_match(const char *name, int len, int from_glob,
702: char *arg, int abpos, int fbpos)
703: {
704: char *use_buf;
705:
706: ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + len + 2);
707: memcpy(glob.arg_buf + abpos, name, len);
708: abpos += len;
709: glob.arg_buf[abpos] = '\0';
710:
711: if (fbpos >= 0) {
712: ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, fbpos + len + 2);
713: memcpy(glob.filt_buf + fbpos, name, len);
714: fbpos += len;
715: glob.filt_buf[fbpos] = '\0';
716: use_buf = glob.filt_buf;
717: } else
718: use_buf = glob.arg_buf;
719:
720: if (from_glob || (arg && len)) {
721: STRUCT_STAT st;
722: int is_dir;
723:
724: if (do_stat(glob.arg_buf, &st) != 0)
725: return;
726: is_dir = S_ISDIR(st.st_mode) != 0;
727: if (arg && !is_dir)
728: return;
729:
730: if (daemon_filter_list.head
731: && check_filter(&daemon_filter_list, FLOG, use_buf, is_dir) < 0)
732: return;
733: }
734:
735: if (arg) {
736: glob.arg_buf[abpos++] = '/';
737: glob.arg_buf[abpos] = '\0';
738: if (fbpos >= 0) {
739: glob.filt_buf[fbpos++] = '/';
740: glob.filt_buf[fbpos] = '\0';
741: }
742: glob_match(arg, abpos, fbpos);
743: } else {
744: ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);
1.1.1.4 ! misho 745: glob.argv[glob.argc++] = strdup(glob.arg_buf);
1.1 misho 746: }
747: }
748:
749: /* This routine performs wild-card expansion of the pathname in "arg". Any
750: * daemon-excluded files/dirs will not be matched by the wildcards. Returns 0
751: * if a wild-card string is the only returned item (due to matching nothing). */
752: int glob_expand(const char *arg, char ***argv_p, int *argc_p, int *maxargs_p)
753: {
754: int ret, save_argc;
755: char *s;
756:
757: if (!arg) {
758: if (glob.filt_buf)
759: free(glob.filt_buf);
760: free(glob.arg_buf);
761: memset(&glob, 0, sizeof glob);
762: return -1;
763: }
764:
765: if (sanitize_paths)
766: s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS);
767: else {
768: s = strdup(arg);
1.1.1.4 ! misho 769: clean_fname(s, CFN_KEEP_DOT_DIRS | CFN_KEEP_TRAILING_SLASH | CFN_COLLAPSE_DOT_DOT_DIRS);
1.1 misho 770: }
771:
772: ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN);
773: *glob.arg_buf = '\0';
774:
775: glob.argc = save_argc = *argc_p;
776: glob.argv = *argv_p;
777: glob.maxargs = *maxargs_p;
778:
779: ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, 100);
780:
781: glob_match(s, 0, -1);
782:
783: /* The arg didn't match anything, so add the failed arg to the list. */
784: if (glob.argc == save_argc) {
785: ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);
786: glob.argv[glob.argc++] = s;
787: ret = 0;
788: } else {
789: free(s);
790: ret = 1;
791: }
792:
793: *maxargs_p = glob.maxargs;
794: *argv_p = glob.argv;
795: *argc_p = glob.argc;
796:
797: return ret;
798: }
799:
800: /* This routine is only used in daemon mode. */
801: void glob_expand_module(char *base1, char *arg, char ***argv_p, int *argc_p, int *maxargs_p)
802: {
803: char *p, *s;
804: char *base = base1;
805: int base_len = strlen(base);
806:
807: if (!arg || !*arg)
808: return;
809:
810: if (strncmp(arg, base, base_len) == 0)
811: arg += base_len;
812:
1.1.1.2 misho 813: if (protect_args) {
814: glob_expand(arg, argv_p, argc_p, maxargs_p);
815: return;
816: }
817:
1.1.1.4 ! misho 818: arg = strdup(arg);
1.1 misho 819:
1.1.1.2 misho 820: if (asprintf(&base," %s/", base1) < 0)
1.1 misho 821: out_of_memory("glob_expand_module");
822: base_len++;
823:
824: for (s = arg; *s; s = p + base_len) {
825: if ((p = strstr(s, base)) != NULL)
826: *p = '\0'; /* split it at this point */
827: glob_expand(s, argv_p, argc_p, maxargs_p);
828: if (!p)
829: break;
830: }
831:
832: free(arg);
833: free(base);
834: }
835:
836: /**
837: * Convert a string to lower case
838: **/
839: void strlower(char *s)
840: {
841: while (*s) {
842: if (isUpper(s))
843: *s = toLower(s);
844: s++;
845: }
846: }
847:
1.1.1.4 ! misho 848: /**
! 849: * Split a string into tokens based (usually) on whitespace & commas. If the
! 850: * string starts with a comma (after skipping any leading whitespace), then
! 851: * splitting is done only on commas. No empty tokens are ever returned. */
! 852: char *conf_strtok(char *str)
! 853: {
! 854: static int commas_only = 0;
! 855:
! 856: if (str) {
! 857: while (isSpace(str)) str++;
! 858: if (*str == ',') {
! 859: commas_only = 1;
! 860: str++;
! 861: } else
! 862: commas_only = 0;
! 863: }
! 864:
! 865: while (commas_only) {
! 866: char *end, *tok = strtok(str, ",");
! 867: if (!tok)
! 868: return NULL;
! 869: /* Trim just leading and trailing whitespace. */
! 870: while (isSpace(tok))
! 871: tok++;
! 872: end = tok + strlen(tok);
! 873: while (end > tok && isSpace(end-1))
! 874: *--end = '\0';
! 875: if (*tok)
! 876: return tok;
! 877: str = NULL;
! 878: }
! 879:
! 880: return strtok(str, " ,\t\r\n");
! 881: }
! 882:
1.1 misho 883: /* Join strings p1 & p2 into "dest" with a guaranteed '/' between them. (If
884: * p1 ends with a '/', no extra '/' is inserted.) Returns the length of both
885: * strings + 1 (if '/' was inserted), regardless of whether the null-terminated
886: * string fits into destsize. */
887: size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2)
888: {
889: size_t len = strlcpy(dest, p1, destsize);
890: if (len < destsize - 1) {
891: if (!len || dest[len-1] != '/')
892: dest[len++] = '/';
893: if (len < destsize - 1)
894: len += strlcpy(dest + len, p2, destsize - len);
895: else {
896: dest[len] = '\0';
897: len += strlen(p2);
898: }
899: }
900: else
901: len += strlen(p2) + 1; /* Assume we'd insert a '/'. */
902: return len;
903: }
904:
905: /* Join any number of strings together, putting them in "dest". The return
906: * value is the length of all the strings, regardless of whether the null-
907: * terminated whole fits in destsize. Your list of string pointers must end
908: * with a NULL to indicate the end of the list. */
909: size_t stringjoin(char *dest, size_t destsize, ...)
910: {
911: va_list ap;
912: size_t len, ret = 0;
913: const char *src;
914:
915: va_start(ap, destsize);
916: while (1) {
917: if (!(src = va_arg(ap, const char *)))
918: break;
919: len = strlen(src);
920: ret += len;
921: if (destsize > 1) {
922: if (len >= destsize)
923: len = destsize - 1;
924: memcpy(dest, src, len);
925: destsize -= len;
926: dest += len;
927: }
928: }
929: *dest = '\0';
930: va_end(ap);
931:
932: return ret;
933: }
934:
1.1.1.4 ! misho 935: /* Append formatted text at *dest_ptr up to a maximum of sz (like snprintf).
! 936: * On success, advance *dest_ptr and return True; on overflow, return False. */
! 937: BOOL snappendf(char **dest_ptr, size_t sz, const char *format, ...)
! 938: {
! 939: va_list ap;
! 940: size_t len;
! 941:
! 942: va_start(ap, format);
! 943: len = vsnprintf(*dest_ptr, sz, format, ap);
! 944: va_end(ap);
! 945:
! 946: if (len >= sz)
! 947: return False;
! 948: else {
! 949: *dest_ptr += len;
! 950: return True;
! 951: }
! 952: }
! 953:
1.1 misho 954: int count_dir_elements(const char *p)
955: {
956: int cnt = 0, new_component = 1;
957: while (*p) {
958: if (*p++ == '/')
959: new_component = (*p != '.' || (p[1] != '/' && p[1] != '\0'));
960: else if (new_component) {
961: new_component = 0;
962: cnt++;
963: }
964: }
965: return cnt;
966: }
967:
968: /* Turns multiple adjacent slashes into a single slash (possible exception:
969: * the preserving of two leading slashes at the start), drops all leading or
970: * interior "." elements unless CFN_KEEP_DOT_DIRS is flagged. Will also drop
971: * a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is flagged, removes
972: * a trailing slash (perhaps after removing the aforementioned dot) unless
973: * CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements
974: * (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged. If the
975: * resulting name would be empty, returns ".". */
1.1.1.3 misho 976: int clean_fname(char *name, int flags)
1.1 misho 977: {
978: char *limit = name - 1, *t = name, *f = name;
979: int anchored;
980:
981: if (!name)
982: return 0;
983:
1.1.1.3 misho 984: #define DOT_IS_DOT_DOT_DIR(bp) (bp[1] == '.' && (bp[2] == '/' || !bp[2]))
985:
1.1 misho 986: if ((anchored = *f == '/') != 0) {
987: *t++ = *f++;
988: #ifdef __CYGWIN__
989: /* If there are exactly 2 slashes at the start, preserve
990: * them. Would break daemon excludes unless the paths are
991: * really treated differently, so used this sparingly. */
992: if (*f == '/' && f[1] != '/')
993: *t++ = *f++;
994: #endif
995: } else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {
996: *t++ = *f++;
997: *t++ = *f++;
1.1.1.3 misho 998: } else if (flags & CFN_REFUSE_DOT_DOT_DIRS && *f == '.' && DOT_IS_DOT_DOT_DIR(f))
999: return -1;
1.1 misho 1000: while (*f) {
1001: /* discard extra slashes */
1002: if (*f == '/') {
1003: f++;
1004: continue;
1005: }
1006: if (*f == '.') {
1007: /* discard interior "." dirs */
1008: if (f[1] == '/' && !(flags & CFN_KEEP_DOT_DIRS)) {
1009: f += 2;
1010: continue;
1011: }
1012: if (f[1] == '\0' && flags & CFN_DROP_TRAILING_DOT_DIR)
1013: break;
1014: /* collapse ".." dirs */
1.1.1.3 misho 1015: if (flags & (CFN_COLLAPSE_DOT_DOT_DIRS|CFN_REFUSE_DOT_DOT_DIRS) && DOT_IS_DOT_DOT_DIR(f)) {
1.1 misho 1016: char *s = t - 1;
1.1.1.3 misho 1017: if (flags & CFN_REFUSE_DOT_DOT_DIRS)
1018: return -1;
1.1 misho 1019: if (s == name && anchored) {
1020: f += 2;
1021: continue;
1022: }
1023: while (s > limit && *--s != '/') {}
1024: if (s != t - 1 && (s < name || *s == '/')) {
1025: t = s + 1;
1026: f += 2;
1027: continue;
1028: }
1029: limit = t + 2;
1030: }
1031: }
1032: while (*f && (*t++ = *f++) != '/') {}
1033: }
1034:
1035: if (t > name+anchored && t[-1] == '/' && !(flags & CFN_KEEP_TRAILING_SLASH))
1036: t--;
1037: if (t == name)
1038: *t++ = '.';
1039: *t = '\0';
1040:
1.1.1.3 misho 1041: #undef DOT_IS_DOT_DOT_DIR
1042:
1.1 misho 1043: return t - name;
1044: }
1045:
1046: /* Make path appear as if a chroot had occurred. This handles a leading
1047: * "/" (either removing it or expanding it) and any leading or embedded
1048: * ".." components that attempt to escape past the module's top dir.
1049: *
1050: * If dest is NULL, a buffer is allocated to hold the result. It is legal
1051: * to call with the dest and the path (p) pointing to the same buffer, but
1052: * rootdir will be ignored to avoid expansion of the string.
1053: *
1054: * The rootdir string contains a value to use in place of a leading slash.
1055: * Specify NULL to get the default of "module_dir".
1056: *
1057: * The depth var is a count of how many '..'s to allow at the start of the
1058: * path.
1059: *
1060: * We also clean the path in a manner similar to clean_fname() but with a
1061: * few differences:
1062: *
1063: * Turns multiple adjacent slashes into a single slash, gets rid of "." dir
1064: * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
1065: * ALWAYS collapses ".." elements (except for those at the start of the
1066: * string up to "depth" deep). If the resulting name would be empty,
1067: * change it into a ".". */
1.1.1.4 ! misho 1068: char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth, int flags)
1.1 misho 1069: {
1070: char *start, *sanp;
1071: int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS);
1072:
1073: if (dest != p) {
1.1.1.4 ! misho 1074: int plen = strlen(p); /* the path len INCLUDING any separating slash */
1.1 misho 1075: if (*p == '/') {
1076: if (!rootdir)
1077: rootdir = module_dir;
1078: rlen = strlen(rootdir);
1079: depth = 0;
1080: p++;
1081: }
1.1.1.4 ! misho 1082: if (!dest)
! 1083: dest = new_array(char, MAX(rlen + plen + 1, 2));
! 1084: else if (rlen + plen + 1 >= MAXPATHLEN)
! 1085: return NULL;
! 1086: if (rlen) { /* only true if p previously started with a slash */
1.1 misho 1087: memcpy(dest, rootdir, rlen);
1.1.1.4 ! misho 1088: if (rlen > 1) /* a rootdir of len 1 is "/", so this avoids a 2nd slash */
1.1 misho 1089: dest[rlen++] = '/';
1090: }
1091: }
1092:
1093: if (drop_dot_dirs) {
1094: while (*p == '.' && p[1] == '/')
1095: p += 2;
1096: }
1097:
1098: start = sanp = dest + rlen;
1099: /* This loop iterates once per filename component in p, pointing at
1100: * the start of the name (past any prior slash) for each iteration. */
1101: while (*p) {
1102: /* discard leading or extra slashes */
1103: if (*p == '/') {
1104: p++;
1105: continue;
1106: }
1107: if (drop_dot_dirs) {
1108: if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
1109: /* skip "." component */
1110: p++;
1111: continue;
1112: }
1113: }
1114: if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
1115: /* ".." component followed by slash or end */
1116: if (depth <= 0 || sanp != start) {
1117: p += 2;
1118: if (sanp != start) {
1119: /* back up sanp one level */
1120: --sanp; /* now pointing at slash */
1121: while (sanp > start && sanp[-1] != '/')
1122: sanp--;
1123: }
1124: continue;
1125: }
1126: /* allow depth levels of .. at the beginning */
1127: depth--;
1128: /* move the virtual beginning to leave the .. alone */
1129: start = sanp + 3;
1130: }
1131: /* copy one component through next slash */
1132: while (*p && (*sanp++ = *p++) != '/') {}
1133: }
1134: if (sanp == dest) {
1135: /* ended up with nothing, so put in "." component */
1136: *sanp++ = '.';
1137: }
1138: *sanp = '\0';
1139:
1140: return dest;
1141: }
1142:
1143: /* Like chdir(), but it keeps track of the current directory (in the
1144: * global "curr_dir"), and ensures that the path size doesn't overflow.
1145: * Also cleans the path using the clean_fname() function. */
1146: int change_dir(const char *dir, int set_path_only)
1147: {
1.1.1.2 misho 1148: static int initialised, skipped_chdir;
1.1 misho 1149: unsigned int len;
1150:
1151: if (!initialised) {
1152: initialised = 1;
1153: if (getcwd(curr_dir, sizeof curr_dir - 1) == NULL) {
1154: rsyserr(FERROR, errno, "getcwd()");
1155: exit_cleanup(RERR_FILESELECT);
1156: }
1157: curr_dir_len = strlen(curr_dir);
1158: }
1159:
1160: if (!dir) /* this call was probably just to initialize */
1161: return 0;
1162:
1163: len = strlen(dir);
1.1.1.2 misho 1164: if (len == 1 && *dir == '.' && (!skipped_chdir || set_path_only))
1.1 misho 1165: return 1;
1166:
1167: if (*dir == '/') {
1168: if (len >= sizeof curr_dir) {
1169: errno = ENAMETOOLONG;
1170: return 0;
1171: }
1172: if (!set_path_only && chdir(dir))
1173: return 0;
1.1.1.2 misho 1174: skipped_chdir = set_path_only;
1.1 misho 1175: memcpy(curr_dir, dir, len + 1);
1176: } else {
1.1.1.4 ! misho 1177: unsigned int save_dir_len = curr_dir_len;
1.1 misho 1178: if (curr_dir_len + 1 + len >= sizeof curr_dir) {
1179: errno = ENAMETOOLONG;
1180: return 0;
1181: }
1182: if (!(curr_dir_len && curr_dir[curr_dir_len-1] == '/'))
1183: curr_dir[curr_dir_len++] = '/';
1184: memcpy(curr_dir + curr_dir_len, dir, len + 1);
1185:
1186: if (!set_path_only && chdir(curr_dir)) {
1.1.1.4 ! misho 1187: curr_dir_len = save_dir_len;
1.1 misho 1188: curr_dir[curr_dir_len] = '\0';
1189: return 0;
1190: }
1.1.1.2 misho 1191: skipped_chdir = set_path_only;
1.1 misho 1192: }
1193:
1.1.1.2 misho 1194: curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
1.1 misho 1195: if (sanitize_paths) {
1196: if (module_dirlen > curr_dir_len)
1197: module_dirlen = curr_dir_len;
1198: curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);
1199: }
1200:
1.1.1.2 misho 1201: if (DEBUG_GTE(CHDIR, 1) && !set_path_only)
1.1 misho 1202: rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir);
1203:
1204: return 1;
1205: }
1206:
1207: /* This will make a relative path absolute and clean it up via clean_fname().
1208: * Returns the string, which might be newly allocated, or NULL on error. */
1209: char *normalize_path(char *path, BOOL force_newbuf, unsigned int *len_ptr)
1210: {
1211: unsigned int len;
1212:
1213: if (*path != '/') { /* Make path absolute. */
1214: int len = strlen(path);
1215: if (curr_dir_len + 1 + len >= sizeof curr_dir)
1216: return NULL;
1217: curr_dir[curr_dir_len] = '/';
1218: memcpy(curr_dir + curr_dir_len + 1, path, len + 1);
1.1.1.4 ! misho 1219: path = strdup(curr_dir);
1.1 misho 1220: curr_dir[curr_dir_len] = '\0';
1.1.1.4 ! misho 1221: } else if (force_newbuf)
! 1222: path = strdup(path);
1.1 misho 1223:
1224: len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
1225:
1226: if (len_ptr)
1227: *len_ptr = len;
1228:
1229: return path;
1230: }
1231:
1.1.1.4 ! misho 1232: /* We need to supply our own strcmp function for file list comparisons
! 1233: * to ensure that signed/unsigned usage is consistent between machines. */
! 1234: int u_strcmp(const char *p1, const char *p2)
! 1235: {
! 1236: for ( ; *p1; p1++, p2++) {
! 1237: if (*p1 != *p2)
! 1238: break;
! 1239: }
! 1240:
! 1241: return (int)*(uchar*)p1 - (int)*(uchar*)p2;
! 1242: }
! 1243:
! 1244: /* We need a memcmp function compares unsigned-byte values. */
! 1245: int u_memcmp(const void *p1, const void *p2, size_t len)
! 1246: {
! 1247: const uchar *u1 = p1;
! 1248: const uchar *u2 = p2;
! 1249:
! 1250: while (len--) {
! 1251: if (*u1 != *u2)
! 1252: return (int)*u1 - (int)*u2;
! 1253: }
! 1254:
! 1255: return 0;
! 1256: }
! 1257:
1.1 misho 1258: /**
1259: * Return a quoted string with the full pathname of the indicated filename.
1260: * The string " (in MODNAME)" may also be appended. The returned pointer
1261: * remains valid until the next time full_fname() is called.
1262: **/
1263: char *full_fname(const char *fn)
1264: {
1265: static char *result = NULL;
1266: char *m1, *m2, *m3;
1267: char *p1, *p2;
1268:
1269: if (result)
1270: free(result);
1271:
1272: if (*fn == '/')
1273: p1 = p2 = "";
1274: else {
1275: p1 = curr_dir + module_dirlen;
1276: for (p2 = p1; *p2 == '/'; p2++) {}
1277: if (*p2)
1278: p2 = "/";
1279: }
1280: if (module_id >= 0) {
1281: m1 = " (in ";
1282: m2 = lp_name(module_id);
1283: m3 = ")";
1284: } else
1285: m1 = m2 = m3 = "";
1286:
1.1.1.2 misho 1287: if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) < 0)
1.1 misho 1288: out_of_memory("full_fname");
1289:
1290: return result;
1291: }
1292:
1293: static char partial_fname[MAXPATHLEN];
1294:
1295: char *partial_dir_fname(const char *fname)
1296: {
1297: char *t = partial_fname;
1298: int sz = sizeof partial_fname;
1299: const char *fn;
1300:
1301: if ((fn = strrchr(fname, '/')) != NULL) {
1302: fn++;
1303: if (*partial_dir != '/') {
1304: int len = fn - fname;
1305: strncpy(t, fname, len); /* safe */
1306: t += len;
1307: sz -= len;
1308: }
1309: } else
1310: fn = fname;
1311: if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
1312: return NULL;
1313: if (daemon_filter_list.head) {
1314: t = strrchr(partial_fname, '/');
1315: *t = '\0';
1316: if (check_filter(&daemon_filter_list, FLOG, partial_fname, 1) < 0)
1317: return NULL;
1318: *t = '/';
1319: if (check_filter(&daemon_filter_list, FLOG, partial_fname, 0) < 0)
1320: return NULL;
1321: }
1322:
1323: return partial_fname;
1324: }
1325:
1326: /* If no --partial-dir option was specified, we don't need to do anything
1327: * (the partial-dir is essentially '.'), so just return success. */
1328: int handle_partial_dir(const char *fname, int create)
1329: {
1330: char *fn, *dir;
1331:
1332: if (fname != partial_fname)
1333: return 1;
1334: if (!create && *partial_dir == '/')
1335: return 1;
1336: if (!(fn = strrchr(partial_fname, '/')))
1337: return 1;
1338:
1339: *fn = '\0';
1340: dir = partial_fname;
1341: if (create) {
1342: STRUCT_STAT st;
1343: int statret = do_lstat(dir, &st);
1344: if (statret == 0 && !S_ISDIR(st.st_mode)) {
1345: if (do_unlink(dir) < 0) {
1346: *fn = '/';
1347: return 0;
1348: }
1349: statret = -1;
1350: }
1.1.1.4 ! misho 1351: if (statret < 0 && make_path(dir, 0700, 0) < 0) {
1.1 misho 1352: *fn = '/';
1353: return 0;
1354: }
1355: } else
1356: do_rmdir(dir);
1357: *fn = '/';
1358:
1359: return 1;
1360: }
1361:
1362: /* Determine if a symlink points outside the current directory tree.
1363: * This is considered "unsafe" because e.g. when mirroring somebody
1364: * else's machine it might allow them to establish a symlink to
1365: * /etc/passwd, and then read it through a web server.
1366: *
1367: * Returns 1 if unsafe, 0 if safe.
1368: *
1369: * Null symlinks and absolute symlinks are always unsafe.
1370: *
1371: * Basically here we are concerned with symlinks whose target contains
1372: * "..", because this might cause us to walk back up out of the
1373: * transferred directory. We are not allowed to go back up and
1374: * reenter.
1375: *
1376: * "dest" is the target of the symlink in question.
1377: *
1378: * "src" is the top source directory currently applicable at the level
1379: * of the referenced symlink. This is usually the symlink's full path
1380: * (including its name), as referenced from the root of the transfer. */
1381: int unsafe_symlink(const char *dest, const char *src)
1382: {
1383: const char *name, *slash;
1384: int depth = 0;
1385:
1386: /* all absolute and null symlinks are unsafe */
1387: if (!dest || !*dest || *dest == '/')
1388: return 1;
1389:
1390: /* find out what our safety margin is */
1391: for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
1392: /* ".." segment starts the count over. "." segment is ignored. */
1393: if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
1394: if (name[1] == '.')
1395: depth = 0;
1396: } else
1397: depth++;
1398: while (slash[1] == '/') slash++; /* just in case src isn't clean */
1399: }
1400: if (*name == '.' && name[1] == '.' && name[2] == '\0')
1401: depth = 0;
1402:
1403: for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
1404: if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
1405: if (name[1] == '.') {
1406: /* if at any point we go outside the current directory
1407: then stop - it is unsafe */
1408: if (--depth < 0)
1409: return 1;
1410: }
1411: } else
1412: depth++;
1413: while (slash[1] == '/') slash++;
1414: }
1415: if (*name == '.' && name[1] == '.' && name[2] == '\0')
1416: depth--;
1417:
1418: return depth < 0;
1419: }
1420:
1421: /* Return the date and time as a string. Some callers tweak returned buf. */
1422: char *timestring(time_t t)
1423: {
1.1.1.4 ! misho 1424: static int ndx = 0;
! 1425: static char buffers[4][20]; /* We support 4 simultaneous timestring results. */
! 1426: char *TimeBuf = buffers[ndx = (ndx + 1) % 4];
1.1 misho 1427: struct tm *tm = localtime(&t);
1.1.1.4 ! misho 1428: int len = snprintf(TimeBuf, sizeof buffers[0], "%4d/%02d/%02d %02d:%02d:%02d",
! 1429: (int)tm->tm_year + 1900, (int)tm->tm_mon + 1, (int)tm->tm_mday,
! 1430: (int)tm->tm_hour, (int)tm->tm_min, (int)tm->tm_sec);
! 1431: assert(len > 0); /* Silence gcc warning */
1.1 misho 1432:
1433: return TimeBuf;
1434: }
1435:
1436: /* Determine if two time_t values are equivalent (either exact, or in
1437: * the modification timestamp window established by --modify-window).
1.1.1.4 ! misho 1438: * Returns 1 if the times the "same", or 0 if they are different. */
! 1439: int same_time(time_t f1_sec, unsigned long f1_nsec, time_t f2_sec, unsigned long f2_nsec)
1.1 misho 1440: {
1.1.1.4 ! misho 1441: if (modify_window == 0)
! 1442: return f1_sec == f2_sec;
! 1443: if (modify_window < 0)
! 1444: return f1_sec == f2_sec && f1_nsec == f2_nsec;
! 1445: /* The nano seconds doesn't figure into these checks -- time windows don't care about that. */
! 1446: if (f2_sec > f1_sec)
! 1447: return f2_sec - f1_sec <= modify_window;
! 1448: return f1_sec - f2_sec <= modify_window;
1.1 misho 1449: }
1450:
1451: #ifdef __INSURE__XX
1452: #include <dlfcn.h>
1453:
1454: /**
1455: This routine is a trick to immediately catch errors when debugging
1456: with insure. A xterm with a gdb is popped up when insure catches
1457: a error. It is Linux specific.
1458: **/
1459: int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1460: {
1461: static int (*fn)();
1.1.1.2 misho 1462: int ret, pid_int = getpid();
1.1 misho 1463: char *cmd;
1464:
1.1.1.2 misho 1465: if (asprintf(&cmd,
1466: "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; "
1467: "gdb /proc/%d/exe %d'", pid_int, pid_int, pid_int) < 0)
1468: return -1;
1.1 misho 1469:
1470: if (!fn) {
1471: static void *h;
1472: h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1473: fn = dlsym(h, "_Insure_trap_error");
1474: }
1475:
1476: ret = fn(a1, a2, a3, a4, a5, a6);
1477:
1478: system(cmd);
1479:
1480: free(cmd);
1481:
1482: return ret;
1483: }
1484: #endif
1485:
1486: /* Take a filename and filename length and return the most significant
1487: * filename suffix we can find. This ignores suffixes such as "~",
1488: * ".bak", ".orig", ".~1~", etc. */
1489: const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr)
1490: {
1491: const char *suf, *s;
1492: BOOL had_tilde;
1493: int s_len;
1494:
1495: /* One or more dots at the start aren't a suffix. */
1496: while (fn_len && *fn == '.') fn++, fn_len--;
1497:
1498: /* Ignore the ~ in a "foo~" filename. */
1499: if (fn_len > 1 && fn[fn_len-1] == '~')
1500: fn_len--, had_tilde = True;
1501: else
1502: had_tilde = False;
1503:
1504: /* Assume we don't find an suffix. */
1505: suf = "";
1506: *len_ptr = 0;
1507:
1508: /* Find the last significant suffix. */
1509: for (s = fn + fn_len; fn_len > 1; ) {
1510: while (*--s != '.' && s != fn) {}
1511: if (s == fn)
1512: break;
1513: s_len = fn_len - (s - fn);
1514: fn_len = s - fn;
1515: if (s_len == 4) {
1516: if (strcmp(s+1, "bak") == 0
1517: || strcmp(s+1, "old") == 0)
1518: continue;
1519: } else if (s_len == 5) {
1520: if (strcmp(s+1, "orig") == 0)
1521: continue;
1.1.1.4 ! misho 1522: } else if (s_len > 2 && had_tilde && s[1] == '~' && isDigit(s + 2))
1.1 misho 1523: continue;
1524: *len_ptr = s_len;
1525: suf = s;
1526: if (s_len == 1)
1527: break;
1528: /* Determine if the suffix is all digits. */
1529: for (s++, s_len--; s_len > 0; s++, s_len--) {
1530: if (!isDigit(s))
1531: return suf;
1532: }
1.1.1.4 ! misho 1533: /* An all-digit suffix may not be that significant. */
1.1 misho 1534: s = suf;
1535: }
1536:
1537: return suf;
1538: }
1539:
1540: /* This is an implementation of the Levenshtein distance algorithm. It
1541: * was implemented to avoid needing a two-dimensional matrix (to save
1542: * memory). It was also tweaked to try to factor in the ASCII distance
1543: * between changed characters as a minor distance quantity. The normal
1544: * Levenshtein units of distance (each signifying a single change between
1545: * the two strings) are defined as a "UNIT". */
1546:
1547: #define UNIT (1 << 16)
1548:
1.1.1.2 misho 1549: uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2)
1.1 misho 1550: {
1551: uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc;
1552: int32 cost;
1.1.1.2 misho 1553: unsigned i1, i2;
1.1 misho 1554:
1555: if (!len1 || !len2) {
1556: if (!len1) {
1557: s1 = s2;
1558: len1 = len2;
1559: }
1560: for (i1 = 0, cost = 0; i1 < len1; i1++)
1561: cost += s1[i1];
1562: return (int32)len1 * UNIT + cost;
1563: }
1564:
1565: for (i2 = 0; i2 < len2; i2++)
1566: a[i2] = (i2+1) * UNIT;
1567:
1568: for (i1 = 0; i1 < len1; i1++) {
1569: diag = i1 * UNIT;
1570: above = (i1+1) * UNIT;
1571: for (i2 = 0; i2 < len2; i2++) {
1572: left = a[i2];
1573: if ((cost = *((uchar*)s1+i1) - *((uchar*)s2+i2)) != 0) {
1574: if (cost < 0)
1575: cost = UNIT - cost;
1576: else
1577: cost = UNIT + cost;
1578: }
1579: diag_inc = diag + cost;
1580: left_inc = left + UNIT + *((uchar*)s1+i1);
1581: above_inc = above + UNIT + *((uchar*)s2+i2);
1582: a[i2] = above = left < above
1583: ? (left_inc < diag_inc ? left_inc : diag_inc)
1584: : (above_inc < diag_inc ? above_inc : diag_inc);
1585: diag = left;
1586: }
1587: }
1588:
1589: return a[len2-1];
1590: }
1591:
1592: #define BB_SLOT_SIZE (16*1024) /* Desired size in bytes */
1593: #define BB_PER_SLOT_BITS (BB_SLOT_SIZE * 8) /* Number of bits per slot */
1594: #define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */
1595:
1596: struct bitbag {
1.1.1.4 ! misho 1597: uint32 **bits;
! 1598: int slot_cnt;
1.1 misho 1599: };
1600:
1601: struct bitbag *bitbag_create(int max_ndx)
1602: {
1603: struct bitbag *bb = new(struct bitbag);
1604: bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS;
1605:
1.1.1.4 ! misho 1606: bb->bits = new_array0(uint32*, bb->slot_cnt);
1.1 misho 1607:
1608: return bb;
1609: }
1610:
1611: void bitbag_set_bit(struct bitbag *bb, int ndx)
1612: {
1613: int slot = ndx / BB_PER_SLOT_BITS;
1614: ndx %= BB_PER_SLOT_BITS;
1615:
1.1.1.4 ! misho 1616: if (!bb->bits[slot])
! 1617: bb->bits[slot] = new_array0(uint32, BB_PER_SLOT_INTS);
1.1 misho 1618:
1619: bb->bits[slot][ndx/32] |= 1u << (ndx % 32);
1620: }
1621:
1622: #if 0 /* not needed yet */
1623: void bitbag_clear_bit(struct bitbag *bb, int ndx)
1624: {
1625: int slot = ndx / BB_PER_SLOT_BITS;
1626: ndx %= BB_PER_SLOT_BITS;
1627:
1628: if (!bb->bits[slot])
1629: return;
1630:
1631: bb->bits[slot][ndx/32] &= ~(1u << (ndx % 32));
1632: }
1633:
1634: int bitbag_check_bit(struct bitbag *bb, int ndx)
1635: {
1636: int slot = ndx / BB_PER_SLOT_BITS;
1637: ndx %= BB_PER_SLOT_BITS;
1638:
1639: if (!bb->bits[slot])
1640: return 0;
1641:
1642: return bb->bits[slot][ndx/32] & (1u << (ndx % 32)) ? 1 : 0;
1643: }
1644: #endif
1645:
1646: /* Call this with -1 to start checking from 0. Returns -1 at the end. */
1647: int bitbag_next_bit(struct bitbag *bb, int after)
1648: {
1649: uint32 bits, mask;
1650: int i, ndx = after + 1;
1651: int slot = ndx / BB_PER_SLOT_BITS;
1652: ndx %= BB_PER_SLOT_BITS;
1653:
1654: mask = (1u << (ndx % 32)) - 1;
1655: for (i = ndx / 32; slot < bb->slot_cnt; slot++, i = mask = 0) {
1656: if (!bb->bits[slot])
1657: continue;
1658: for ( ; i < BB_PER_SLOT_INTS; i++, mask = 0) {
1659: if (!(bits = bb->bits[slot][i] & ~mask))
1660: continue;
1661: /* The xor magic figures out the lowest enabled bit in
1662: * bits, and the switch quickly computes log2(bit). */
1663: switch (bits ^ (bits & (bits-1))) {
1664: #define LOG2(n) case 1u << n: return slot*BB_PER_SLOT_BITS + i*32 + n
1665: LOG2(0); LOG2(1); LOG2(2); LOG2(3);
1666: LOG2(4); LOG2(5); LOG2(6); LOG2(7);
1667: LOG2(8); LOG2(9); LOG2(10); LOG2(11);
1668: LOG2(12); LOG2(13); LOG2(14); LOG2(15);
1669: LOG2(16); LOG2(17); LOG2(18); LOG2(19);
1670: LOG2(20); LOG2(21); LOG2(22); LOG2(23);
1671: LOG2(24); LOG2(25); LOG2(26); LOG2(27);
1672: LOG2(28); LOG2(29); LOG2(30); LOG2(31);
1673: }
1674: return -1; /* impossible... */
1675: }
1676: }
1677:
1678: return -1;
1679: }
1680:
1681: void flist_ndx_push(flist_ndx_list *lp, int ndx)
1682: {
1683: struct flist_ndx_item *item;
1684:
1.1.1.4 ! misho 1685: item = new(struct flist_ndx_item);
1.1 misho 1686: item->next = NULL;
1687: item->ndx = ndx;
1688: if (lp->tail)
1689: lp->tail->next = item;
1690: else
1691: lp->head = item;
1692: lp->tail = item;
1693: }
1694:
1695: int flist_ndx_pop(flist_ndx_list *lp)
1696: {
1697: struct flist_ndx_item *next;
1698: int ndx;
1699:
1700: if (!lp->head)
1701: return -1;
1702:
1703: ndx = lp->head->ndx;
1704: next = lp->head->next;
1705: free(lp->head);
1706: lp->head = next;
1707: if (!next)
1708: lp->tail = NULL;
1709:
1710: return ndx;
1711: }
1712:
1.1.1.3 misho 1713: /* Make sure there is room for one more item in the item list. If there
1714: * is not, expand the list as indicated by the value of "incr":
1715: * - if incr < 0 then increase the malloced size by -1 * incr
1716: * - if incr >= 0 then either make the malloced size equal to "incr"
1717: * or (if that's not large enough) double the malloced size
1718: * After the size check, the list's count is incremented by 1 and a pointer
1719: * to the "new" list item is returned.
1720: */
1.1.1.4 ! misho 1721: void *expand_item_list(item_list *lp, size_t item_size, const char *desc, int incr)
1.1 misho 1722: {
1723: /* First time through, 0 <= 0, so list is expanded. */
1724: if (lp->malloced <= lp->count) {
1725: void *new_ptr;
1.1.1.4 ! misho 1726: size_t expand_size;
1.1 misho 1727: if (incr < 0)
1.1.1.4 ! misho 1728: expand_size = -incr; /* increase slowly */
! 1729: else if (lp->malloced < (size_t)incr)
! 1730: expand_size = incr - lp->malloced;
! 1731: else if (lp->malloced)
! 1732: expand_size = lp->malloced; /* double in size */
1.1.1.3 misho 1733: else
1.1.1.4 ! misho 1734: expand_size = 1;
! 1735: if (SIZE_MAX/item_size - expand_size < lp->malloced)
1.1 misho 1736: overflow_exit("expand_item_list");
1.1.1.4 ! misho 1737: expand_size += lp->malloced;
! 1738: new_ptr = realloc_buf(lp->items, expand_size * item_size);
1.1.1.2 misho 1739: if (DEBUG_GTE(FLIST, 3)) {
1740: rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n",
1.1.1.4 ! misho 1741: who_am_i(), desc, big_num(expand_size * item_size),
1.1 misho 1742: new_ptr == lp->items ? " not" : "");
1743: }
1744:
1745: lp->items = new_ptr;
1.1.1.4 ! misho 1746: lp->malloced = expand_size;
1.1 misho 1747: }
1748: return (char*)lp->items + (lp->count++ * item_size);
1749: }
1.1.1.4 ! misho 1750:
! 1751: /* This zeroing of memory won't be optimized away by the compiler. */
! 1752: void force_memzero(void *buf, size_t len)
! 1753: {
! 1754: volatile uchar *z = buf;
! 1755: while (len-- > 0)
! 1756: *z++ = '\0';
! 1757: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>