Beispiel #1
0
int p_lstat(const char *file_name, struct stat *buf)
{
	int namelen, error;
	char alt_name[GIT_PATH_MAX];

	if ((error = do_lstat(file_name, buf)) == GIT_SUCCESS)
		return GIT_SUCCESS;

	/* if file_name ended in a '/', Windows returned ENOENT;
	 * try again without trailing slashes
	 */
	if (error != GIT_EINVALIDPATH)
		return git__throw(GIT_EOSERR, "Failed to lstat file");

	namelen = strlen(file_name);
	if (namelen && file_name[namelen-1] != '/')
		return git__throw(GIT_EOSERR, "Failed to lstat file");

	while (namelen && file_name[namelen-1] == '/')
		--namelen;

	if (!namelen || namelen >= GIT_PATH_MAX)
		return git__throw(GIT_ENOMEM, "Failed to lstat file");

	memcpy(alt_name, file_name, namelen);
	alt_name[namelen] = 0;
	return do_lstat(alt_name, buf);
}
Beispiel #2
0
int p_lstat(const char *file_name, struct stat *buf)
{
	int error;
	size_t namelen;
	char *alt_name;

	if (do_lstat(file_name, buf) == 0)
		return 0;

	/* if file_name ended in a '/', Windows returned ENOENT;
	 * try again without trailing slashes
	 */
	namelen = strlen(file_name);
	if (namelen && file_name[namelen-1] != '/')
		return -1;

	while (namelen && file_name[namelen-1] == '/')
		--namelen;

	if (!namelen)
		return -1;

	alt_name = git__strndup(file_name, namelen);
	if (!alt_name)
		return -1;

	error = do_lstat(alt_name, buf);

	git__free(alt_name);
	return error;
}
Beispiel #3
0
/* We provide our own lstat/fstat functions, since the provided
 * lstat/fstat functions are so slow. These stat functions are
 * tailored for Git's usage (read: fast), and are not meant to be
 * complete. Note that Git stat()s are redirected to mingw_lstat()
 * too, since Windows doesn't really handle symlinks that well.
 */
int mingw_lstat(const char *file_name, struct mingw_stat *buf)
{
	int namelen;
	static char alt_name[PATH_MAX];

	if (!do_lstat(file_name, buf))
		return 0;

	/* if file_name ended in a '/', Windows returned ENOENT;
	 * try again without trailing slashes
	 */
	if (errno != ENOENT)
		return -1;

	namelen = strlen(file_name);
	if (namelen && file_name[namelen-1] != '/')
		return -1;
	while (namelen && file_name[namelen-1] == '/')
		--namelen;
	if (!namelen || namelen >= PATH_MAX)
		return -1;

	memcpy(alt_name, file_name, namelen);
	alt_name[namelen] = 0;
	return do_lstat(alt_name, buf);
}
Beispiel #4
0
/****************************************************************************
Create a directory given an absolute path, perms based upon another directory
path
****************************************************************************/
static int make_bak_dir(char *fname,char *bak_path)
{
        STRUCT_STAT st;
        STRUCT_STAT *st2;
        char fullpath[MAXPATHLEN];
        extern int orig_umask;
        char *p;
        char *q;

        while(strncmp(bak_path,"./",2)==0) bak_path += 2;

        if(bak_path[strlen(bak_path)-1]!='/') {
                snprintf(fullpath,sizeof(fullpath),"%s/",bak_path);
        } else {
                snprintf(fullpath,sizeof(fullpath),"%s",bak_path);
        }
        p=fullpath;
        q=&fullpath[strlen(fullpath)];  /* End of bak_path string */
        strcat(fullpath,fname);

        /* Make the directories */
        while ((p=strchr(p,'/'))) {
                *p = 0;
                if(do_lstat(fullpath,&st)!=0) {
                        do_mkdir(fullpath,0777 & ~orig_umask);
                        if(p>q) {
                                if(do_lstat(q,&st)!=0) {
                                        rprintf(FERROR,"make_bak_dir stat %s : %s\n",fullpath,strerror(errno));
                                } else {
                                        st2=&st;
                                        set_modtime(fullpath,st2->st_mtime);
                                        if(do_lchown(fullpath,st2->st_uid,st2->st_gid)!=0) {
                                                rprintf(FERROR,"make_bak_dir chown %s : %s\n",fullpath,strerror(errno));
                                        };
                                        if(do_chmod(fullpath,st2->st_mode)!=0) {
                                                rprintf(FERROR,"make_bak_dir failed to set permissions on %s : %s\n",fullpath,strerror(errno));
                                        };
                                };
                        }
                };
                *p = '/';
                p++;
        }
        return 0;
}
static int
fudge_lstat(const char *path, struct stat *st)
{
    Attrib *a;

    if (!(a = do_lstat(cur.conn, (char *)path, 0)))
        return(-1);

    attrib_to_stat(a, st);

    return(0);
}
Beispiel #6
0
int link_stat(const char *path, STRUCT_STAT *buffer, int follow_dirlinks)
{
#ifdef SUPPORT_LINKS
	if (copy_links)
		return do_stat(path, buffer);
	if (do_lstat(path, buffer) < 0)
		return -1;
	if (follow_dirlinks && S_ISLNK(buffer->st_mode)) {
		STRUCT_STAT st;
		if (do_stat(path, &st) == 0 && S_ISDIR(st.st_mode))
			*buffer = st;
	}
	return 0;
#else
	return do_stat(path, buffer);
#endif
}
Beispiel #7
0
/* Returns -1 on error, 0 on missing dir, and 1 on present dir. */
static int validate_backup_dir(void)
{
	STRUCT_STAT st;

	if (do_lstat(backup_dir_buf, &st) < 0) {
		if (errno == ENOENT)
			return 0;
		rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
		return -1;
	}
	if (!S_ISDIR(st.st_mode)) {
		int flags = get_del_for_flag(st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
		if (delete_item(backup_dir_buf, st.st_mode, flags) == 0)
			return 0;
		return -1;
	}
	return 1;
}
Beispiel #8
0
static void list_file(const char *fname)
{
	STRUCT_STAT buf;
	char permbuf[PERMSTRING_SIZE];
	struct tm *mt;
	char datebuf[50];
	char linkbuf[4096];

	if (do_lstat(fname, &buf) < 0)
		failed("stat", fname);
#ifdef SUPPORT_XATTRS
	if (am_root < 0)
		stat_xattr(fname, &buf);
#endif

	/* The size of anything but a regular file is probably not
	 * worth thinking about. */
	if (!S_ISREG(buf.st_mode))
		buf.st_size = 0;

	/* On some BSD platforms the mode bits of a symlink are
	 * undefined.  Also it tends not to be possible to reset a
	 * symlink's mtime, so we default to ignoring it too. */
	if (S_ISLNK(buf.st_mode)) {
		int len;
		buf.st_mode &= ~0777;
		if (!link_times)
			buf.st_mtime = (time_t)0;
		if (!link_owner)
			buf.st_uid = buf.st_gid = 0;
		strlcpy(linkbuf, " -> ", sizeof linkbuf);
		/* const-cast required for silly UNICOS headers */
		len = do_readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4);
		if (len == -1)
			failed("do_readlink", fname);
		else
			/* it's not nul-terminated */
			linkbuf[4+len] = 0;
	} else {
		linkbuf[0] = 0;
	}

	permstring(permbuf, buf.st_mode);

	if (buf.st_mtime) {
		int len;
		mt = gmtime(&buf.st_mtime);

		len = snprintf(datebuf, sizeof datebuf,
			"%04d-%02d-%02d %02d:%02d:%02d",
			(int)mt->tm_year + 1900,
			(int)mt->tm_mon + 1,
			(int)mt->tm_mday,
			(int)mt->tm_hour,
			(int)mt->tm_min,
			(int)mt->tm_sec);
#ifdef ST_MTIME_NSEC
		if (nsec_times) {
			snprintf(datebuf + len, sizeof datebuf - len,
				".%09d", (int)buf.ST_MTIME_NSEC);
		}
#endif
	} else {
		int len = MIN(19 + 9*nsec_times, (int)sizeof datebuf - 1);
		memset(datebuf, ' ', len);
		datebuf[len] = '\0';
	}

	/* TODO: Perhaps escape special characters in fname? */

	printf("%s ", permbuf);
	if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
		printf("%5ld,%6ld",
		    (long)major(buf.st_rdev),
		    (long)minor(buf.st_rdev));
	} else
		printf("%15s", do_big_num(buf.st_size, 1, NULL));
	printf(" %6ld.%-6ld %6ld %s %s%s\n",
	       (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
	       datebuf, fname, linkbuf);
}
Beispiel #9
0
/*
 * delete a file or directory. If force_delet is set then delete 
 * recursively 
 */
int delete_file(char *fname)
{
	DIR *d;
	struct dirent *di;
	char buf[MAXPATHLEN];
	extern int force_delete;
	STRUCT_STAT st;
	int ret;
	extern int recurse;

	if (robust_unlink(fname) == 0 || errno == ENOENT) return 0;

#if SUPPORT_LINKS
	ret = do_lstat(fname, &st);
#else
	ret = do_stat(fname, &st);
#endif
	if (ret) {
		rprintf(FERROR,"stat(%s) : %s\n", fname, strerror(errno));
		return -1;
	}

	if (!S_ISDIR(st.st_mode)) {
		rprintf(FERROR,"unlink(%s) : %s\n", fname, strerror(errno));
		return -1;
	}

	if (do_rmdir(fname) == 0 || errno == ENOENT) return 0;
	if (!force_delete || !recurse || 
	    (errno != ENOTEMPTY && errno != EEXIST)) {
		rprintf(FERROR,"rmdir(%s) : %s\n", fname, strerror(errno));
		return -1;
	}

	/* now we do a recsursive delete on the directory ... */
	d = opendir(fname);
	if (!d) {
		rprintf(FERROR,"opendir(%s): %s\n",
			fname,strerror(errno));
		return -1;
	}

	for (di=readdir(d); di; di=readdir(d)) {
		char *dname = d_name(di);
		if (strcmp(dname,".")==0 ||
		    strcmp(dname,"..")==0)
			continue;
		slprintf(buf, sizeof(buf), "%s/%s", fname, dname);
		if (verbose > 0)
			rprintf(FINFO,"deleting %s\n", buf);
		if (delete_file(buf) != 0) {
			closedir(d);
			return -1;
		}
	}	

	closedir(d);
	
	if (do_rmdir(fname) != 0) {
		rprintf(FERROR,"rmdir(%s) : %s\n", fname, strerror(errno));
		return -1;
	}

	return 0;
}
Beispiel #10
0
/* sftp ls.1 replacement which handles path globs */
static int
do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
    int lflag)
{
	glob_t g;
	u_int i, c = 1, colspace = 0, columns = 1;
	Attrib *a = NULL;

	memset(&g, 0, sizeof(g));

	if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE,
	    NULL, &g) || (g.gl_pathc && !g.gl_matchc)) {
		if (g.gl_pathc)
			globfree(&g);
		error("Can't ls: \"%s\" not found", path);
		return (-1);
	}

	if (interrupted)
		goto out;

	/*
	 * If the glob returns a single match and it is a directory,
	 * then just list its contents.
	 */
	if (g.gl_matchc == 1) {
		if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) {
			globfree(&g);
			return (-1);
		}
		if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
		    S_ISDIR(a->perm)) {
			int err;

			err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
			globfree(&g);
			return (err);
		}
	}

	if (!(lflag & LS_SHORT_VIEW)) {
		u_int m = 0, width = 80;
		struct winsize ws;

		/* Count entries for sort and find longest filename */
		for (i = 0; g.gl_pathv[i]; i++)
			m = MAX(m, strlen(g.gl_pathv[i]));

		if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
			width = ws.ws_col;

		columns = width / (m + 2);
		columns = MAX(columns, 1);
		colspace = width / columns;
	}

	for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) {
		char *fname;

		fname = path_strip(g.gl_pathv[i], strip_path);

		if (lflag & LS_LONG_VIEW) {
			char *lname;
			struct stat sb;

			/*
			 * XXX: this is slow - 1 roundtrip per path
			 * A solution to this is to fork glob() and
			 * build a sftp specific version which keeps the
			 * attribs (which currently get thrown away)
			 * that the server returns as well as the filenames.
			 */
			memset(&sb, 0, sizeof(sb));
			if (a == NULL)
				a = do_lstat(conn, g.gl_pathv[i], 1);
			if (a != NULL)
				attrib_to_stat(a, &sb);
			lname = ls_file(fname, &sb, 1);
			printf("%s\n", lname);
			xfree(lname);
		} else {
			printf("%-*s", colspace, fname);
			if (c >= columns) {
				printf("\n");
				c = 1;
			} else
				c++;
		}
		xfree(fname);
	}

	if (!(lflag & LS_LONG_VIEW) && (c != 1))
		printf("\n");

 out:
	if (g.gl_pathc)
		globfree(&g);

	return (0);
}
Beispiel #11
0
/* if we have a backup_dir, then we get here from make_backup().
   We will move the file to be deleted into a parallel directory tree */
static int keep_backup(char *fname)
{

	static int initialised;

	char keep_name [MAXPATHLEN];
	STRUCT_STAT st;
	struct file_struct *file;

	int kept=0;
	int ret_code;

	if (!initialised) {
		if (backup_dir[strlen(backup_dir) - 1] == '/')
			backup_dir[strlen(backup_dir) - 1] = 0;
		if (verbose > 0)
			rprintf (FINFO, "backup_dir is %s\n", backup_dir);
		initialised = 1;
	}

	/* return if no file to keep */
#if SUPPORT_LINKS
	if (do_lstat (fname, &st)) return 1;
#else
	if (do_stat (fname, &st)) return 1;
#endif

	file = make_file(-1, fname, NULL, 1);

	/* the file could have disappeared */
	if (!file) return 1;

        /* make a complete pathname for backup file */
        if (strlen(backup_dir) + strlen(fname) + 
		(suffix_specified ? strlen(backup_suffix) : 0) > (MAXPATHLEN - 1)) {
                rprintf (FERROR, "keep_backup filename too long\n");
                return 0;
        }

	if (suffix_specified) {
        	snprintf(keep_name, sizeof (keep_name), "%s/%s%s", backup_dir, fname, backup_suffix);
		} else {
        	snprintf(keep_name, sizeof (keep_name), "%s/%s", backup_dir, fname);
		}


#ifdef HAVE_MKNOD
	/* Check to see if this is a device file, or link */
        if(IS_DEVICE(file->mode)) {
                if(am_root && preserve_devices) {
                        make_bak_dir(fname,backup_dir);
                        if(do_mknod(keep_name,file->mode,file->rdev)!=0) {
                                rprintf(FERROR,"mknod %s : %s\n",keep_name,strerror(errno));
                        } else {
                                if(verbose>2)
                                        rprintf(FINFO,"make_backup : DEVICE %s successful.\n",fname);
                        };
                };
		kept=1;
                do_unlink(fname);
        };
#endif

	if(!kept && S_ISDIR(file->mode)) {
		/* make an empty directory */
                make_bak_dir(fname,backup_dir);
                do_mkdir(keep_name,file->mode);
                ret_code=do_rmdir(fname);
                if(verbose>2)
                        rprintf(FINFO,"make_backup : RMDIR %s returns %i\n",fname,ret_code);
		kept=1;
        };

#if SUPPORT_LINKS
        if(!kept && preserve_links && S_ISLNK(file->mode)) {
                extern int safe_symlinks;
                if (safe_symlinks && unsafe_symlink(file->link, keep_name)) {
                        if (verbose) {
                                rprintf(FINFO,"ignoring unsafe symlink %s -> %s\n",
                                        keep_name,file->link);
                        }
			kept=1;
                }
                make_bak_dir(fname,backup_dir);
                if(do_symlink(file->link,keep_name) != 0) {
                        rprintf(FERROR,"link %s -> %s : %s\n",keep_name,file->link,strerror(errno));
                };
                do_unlink(fname);
		kept=1;
        };
#endif
        if(!kept && preserve_hard_links && check_hard_link(file)) {
                if(verbose > 1) rprintf(FINFO,"%s is a hard link\n",f_name(file));
        };

        if(!kept && !S_ISREG(file->mode)) {
                rprintf(FINFO,"make_bak: skipping non-regular file %s\n",fname);
        }

	/* move to keep tree if a file */
	if(!kept) {
		if (!robust_move (fname, keep_name))
			rprintf(FERROR, "keep_backup failed %s -> %s : %s\n",
				fname, keep_name, strerror(errno));
	};
	set_perms (keep_name, file, NULL, 0);
	free_file (file);
	free (file);

	if (verbose > 1)
		rprintf (FINFO, "keep_backup %s -> %s\n", fname, keep_name);
	return 1;
} /* keep_backup */
Beispiel #12
0
/* Hard-link, rename, or copy an item to the backup name.  Returns 0 for
 * failure, 1 if item was moved, 2 if item was duplicated or hard linked
 * into backup area, or 3 if item doesn't exist or isn't a regular file. */
int make_backup(const char *fname, BOOL prefer_rename)
{
	stat_x sx;
	struct file_struct *file;
	int save_preserve_xattrs;
	char *buf;
	int ret = 0;

	init_stat_x(&sx);
	/* Return success if no file to keep. */
	if (x_lstat(fname, &sx.st, NULL) < 0)
		return 3;

	if (!(buf = get_backup_name(fname)))
		return 0;

	/* Try a hard-link or a rename first.  Using rename is not atomic, but
	 * is more efficient than forcing a copy for larger files when no hard-
	 * linking is possible. */
	if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
		goto success;
	if (errno == EEXIST || errno == EISDIR) {
		STRUCT_STAT bakst;
		if (do_lstat(buf, &bakst) == 0) {
			int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
			if (delete_item(buf, bakst.st_mode, flags) != 0)
				return 0;
		}
		if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
			goto success;
	}

	/* Fall back to making a copy. */
	if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS)))
		return 3; /* the file could have disappeared */

#ifdef SUPPORT_ACLS
	if (preserve_acls && !S_ISLNK(file->mode)) {
		get_acl(fname, &sx);
		cache_tmp_acl(file, &sx);
		free_acl(&sx);
	}
#endif
#ifdef SUPPORT_XATTRS
	if (preserve_xattrs) {
		get_xattr(fname, &sx);
		cache_tmp_xattr(file, &sx);
		free_xattr(&sx);
	}
#endif

	/* Check to see if this is a device file, or link */
	if ((am_root && preserve_devices && IS_DEVICE(file->mode))
	 || (preserve_specials && IS_SPECIAL(file->mode))) {
		if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0)
			rsyserr(FERROR, errno, "mknod %s failed", full_fname(buf));
		else if (DEBUG_GTE(BACKUP, 1))
			rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname);
		ret = 2;
	}

#ifdef SUPPORT_LINKS
	if (!ret && preserve_links && S_ISLNK(file->mode)) {
		const char *sl = F_SYMLINK(file);
		if (safe_symlinks && unsafe_symlink(sl, fname)) {
			if (INFO_GTE(SYMSAFE, 1)) {
				rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
					fname, sl);
			}
			ret = 2;
		} else {
			if (do_symlink(sl, buf) < 0)
				rsyserr(FERROR, errno, "link %s -> \"%s\"", full_fname(buf), sl);
			else if (DEBUG_GTE(BACKUP, 1))
				rprintf(FINFO, "make_backup: SYMLINK %s successful.\n", fname);
			ret = 2;
		}
	}
#endif

	if (!ret && !S_ISREG(file->mode)) {
		rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname);
		unmake_file(file);
#ifdef SUPPORT_ACLS
		uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
		uncache_tmp_xattrs();
#endif
		return 3;
	}

	/* Copy to backup tree if a file. */
	if (!ret) {
		if (copy_file(fname, buf, -1, file->mode) < 0) {
			rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
				full_fname(fname), buf);
			unmake_file(file);
#ifdef SUPPORT_ACLS
			uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
			uncache_tmp_xattrs();
#endif
			return 0;
		}
		if (DEBUG_GTE(BACKUP, 1))
			rprintf(FINFO, "make_backup: COPY %s successful.\n", fname);
		ret = 2;
	}

	save_preserve_xattrs = preserve_xattrs;
	preserve_xattrs = 0;
	set_file_attrs(buf, file, NULL, fname, ATTRS_SET_NANO);
	preserve_xattrs = save_preserve_xattrs;

	unmake_file(file);
#ifdef SUPPORT_ACLS
	uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
	uncache_tmp_xattrs();
#endif

  success:
	if (INFO_GTE(BACKUP, 1))
		rprintf(FINFO, "backed up %s to %s\n", fname, buf);
	return ret;
}
Beispiel #13
0
int p_stat(const char* path, struct stat* buf)
{
	return do_lstat(path, buf);
}
Beispiel #14
0
static void list_file(const char *fname)
{
	STRUCT_STAT buf;
	char permbuf[PERMSTRING_SIZE];
	struct tm *mt;
	char datebuf[50];
	char linkbuf[4096];

	if (do_lstat(fname, &buf) < 0)
		failed("stat", fname);

	/* The size of anything but a regular file is probably not
	 * worth thinking about. */
	if (!S_ISREG(buf.st_mode))
		buf.st_size = 0;

	/* On some BSD platforms the mode bits of a symlink are
	 * undefined.  Also it tends not to be possible to reset a
	 * symlink's mtime, so we have to ignore it too. */
	if (S_ISLNK(buf.st_mode)) {
		int len;
		buf.st_mode &= ~0777;
		buf.st_mtime = (time_t)0;
		buf.st_uid = buf.st_gid = 0;
		strlcpy(linkbuf, " -> ", sizeof linkbuf);
		/* const-cast required for silly UNICOS headers */
		len = readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4);
		if (len == -1)
			failed("readlink", fname);
		else
			/* it's not nul-terminated */
			linkbuf[4+len] = 0;
	} else {
		linkbuf[0] = 0;
	}

	permstring(permbuf, buf.st_mode);

	if (buf.st_mtime) {
		mt = gmtime(&buf.st_mtime);

		snprintf(datebuf, sizeof datebuf,
			"%04d-%02d-%02d %02d:%02d:%02d",
			(int)mt->tm_year + 1900,
			(int)mt->tm_mon + 1,
			(int)mt->tm_mday,
			(int)mt->tm_hour,
			(int)mt->tm_min,
			(int)mt->tm_sec);
	} else
		strlcpy(datebuf, "                   ", sizeof datebuf);

	/* TODO: Perhaps escape special characters in fname? */

	printf("%s ", permbuf);
	if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
		printf("%5ld,%6ld",
		    (long)major(buf.st_rdev),
		    (long)minor(buf.st_rdev));
	} else /* NB: use double for size since it might not fit in a long. */
		printf("%12.0f", (double)buf.st_size);
	printf(" %6ld.%-6ld %6ld %s %s%s\n",
	       (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
	       datebuf, fname, linkbuf);
}
Beispiel #15
0
int p_lstat(const char *filename, struct stat *buf)
{
	return do_lstat(filename, buf, 0);
}
Beispiel #16
0
int p_lstat_posixly(const char *filename, struct stat *buf)
{
	return do_lstat(filename, buf, 1);
}
Beispiel #17
0
/* If we have a --backup-dir, then we get here from make_backup().
 * We will move the file to be deleted into a parallel directory tree. */
static int keep_backup(const char *fname)
{
	STRUCT_STAT st;
	struct file_struct *file;
	char *buf;
	int kept = 0;
	int ret_code;

	/* return if no file to keep */
	if (do_lstat(fname, &st) < 0)
		return 1;

	if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
		return 1; /* the file could have disappeared */

	if (!(buf = get_backup_name(fname))) {
		unmake_file(file);
		return 0;
	}

	/* Check to see if this is a device file, or link */
	if ((am_root && preserve_devices && IS_DEVICE(file->mode))
	 || (preserve_specials && IS_SPECIAL(file->mode))) {
		uint32 *devp = F_RDEV_P(file);
		dev_t rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
		do_unlink(buf);
		if (do_mknod(buf, file->mode, rdev) < 0
		    && (errno != ENOENT || make_bak_dir(buf) < 0
		     || do_mknod(buf, file->mode, rdev) < 0)) {
			rsyserr(FERROR, errno, "mknod %s failed",
				full_fname(buf));
		} else if (verbose > 2) {
			rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
				fname);
		}
		kept = 1;
		do_unlink(fname);
	}

	if (!kept && S_ISDIR(file->mode)) {
		/* make an empty directory */
		if (do_mkdir(buf, file->mode) < 0
		    && (errno != ENOENT || make_bak_dir(buf) < 0
		     || do_mkdir(buf, file->mode) < 0)) {
			rsyserr(FINFO, errno, "mkdir %s failed",
				full_fname(buf));
		}

		ret_code = do_rmdir(fname);
		if (verbose > 2) {
			rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
				full_fname(fname), ret_code);
		}
		kept = 1;
	}

#ifdef SUPPORT_LINKS
	if (!kept && preserve_links && S_ISLNK(file->mode)) {
		const char *sl = F_SYMLINK(file);
		if (safe_symlinks && unsafe_symlink(sl, buf)) {
			if (verbose) {
				rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
					full_fname(buf), sl);
			}
			kept = 1;
		} else {
			do_unlink(buf);
			if (do_symlink(sl, buf) < 0
			    && (errno != ENOENT || make_bak_dir(buf) < 0
			     || do_symlink(sl, buf) < 0)) {
				rsyserr(FERROR, errno, "link %s -> \"%s\"",
					full_fname(buf), sl);
			}
			do_unlink(fname);
			kept = 1;
		}
	}
#endif

	if (!kept && !S_ISREG(file->mode)) {
		rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
			fname);
		unmake_file(file);
		return 1;
	}

	/* move to keep tree if a file */
	if (!kept) {
		if (robust_move(fname, buf) != 0) {
			rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
				full_fname(fname), buf);
		} else if (st.st_nlink > 1) {
			/* If someone has hard-linked the file into the backup
			 * dir, rename() might return success but do nothing! */
			robust_unlink(fname); /* Just in case... */
		}
	}
	set_file_attrs(buf, file, NULL, 0);
	unmake_file(file);

	if (verbose > 1) {
		rprintf(FINFO, "backed up %s to %s\n",
			fname, buf);
	}
	return 1;
}