コード例 #1
0
ファイル: cow.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * copy a directory between branches (includes all contents of the directory)
 */
int copy_directory(const char *path, int branch_ro, int branch_rw) {
	DBG_IN();

	/* create the directory on the destination branch */
	int res = path_create(path, branch_ro, branch_rw);
	if (res != 0) {
		return res;
	}

	/* determine path to source directory on read-only branch */
	char from[PATHLEN_MAX];
	if (BUILD_PATH(from, uopt.branches[branch_ro].path, path)) return 1;

	DIR *dp = opendir(from);
	if (dp == NULL) return 1;

	struct dirent *de;
	while ((de = readdir(dp)) != NULL) {
		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;

		char member[PATHLEN_MAX];
		if (BUILD_PATH(member, path, de->d_name)) return 1;
		res = cow_cp(member, branch_ro, branch_rw);
		if (res != 0) return res;
	}

	closedir(dp);
	return 0;
}
コード例 #2
0
ファイル: cow_utils.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * copy a fifo, actually we recreate the fifo and only copy
 * its stat() data
 **/
int copy_fifo(struct cow *cow)
{
	DBG_IN();

	if (mkfifo(cow->to_path, cow->stat->st_mode)) {
		usyslog(LOG_WARNING,   "mkfifo: %s", cow->to_path);
		return (1);
	}
	return setfile(cow->to_path, cow->stat);
}
コード例 #3
0
ファイル: cow_utils.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * copy a special file, actually we recreate this file and only copy
 * its stat() data
 */
int copy_special(struct cow *cow)
{
	DBG_IN();

	if (mknod(cow->to_path, cow->stat->st_mode, cow->stat->st_rdev)) {
		usyslog(LOG_WARNING,   "mknod: %s", cow->to_path);
		return (1);
	}
	return setfile(cow->to_path, cow->stat);
}
コード例 #4
0
ファイル: cow.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * Same as  path_create(), but ignore the last segment in path,
 * i.e. it might be a filename.
 */
int path_create_cutlast(const char *path, int nbranch_ro, int nbranch_rw) {
	DBG_IN();

	char *dname = u_dirname(path);
	if (dname == NULL)
		return -ENOMEM;
	int ret = path_create(dname, nbranch_ro, nbranch_rw);
	free(dname);

	return ret;
}
コード例 #5
0
ファイル: cow_utils.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * set the stat() data of a file
 **/
int setfile(const char *path, struct stat *fs)
{
	DBG_IN();

	struct utimbuf ut;
	int rval;

	rval = 0;
	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;

	ut.actime  = fs->st_atime;
	ut.modtime = fs->st_mtime;
	if (utime(path, &ut)) {
		usyslog(LOG_WARNING,   "utimes: %s", path);
		rval = 1;
	}
	/*
	* Changing the ownership probably won't succeed, unless we're root
	* or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
	* the mode; current BSD behavior is to remove all setuid bits on
	* chown.  If chown fails, lose setuid/setgid bits.
	*/
	if (chown(path, fs->st_uid, fs->st_gid)) {
		if (errno != EPERM) {
			usyslog(LOG_WARNING,   "chown: %s", path);
			rval = 1;
		}
		fs->st_mode &= ~(S_ISTXT | S_ISUID | S_ISGID);
	}
	
	if (chmod(path, fs->st_mode)) {
		usyslog(LOG_WARNING,   "chown: %s", path);
		rval = 1;
	}

#ifdef HAVE_CHFLAGS
		/*
		 * XXX
		 * NFS doesn't support chflags; ignore errors unless there's reason
		 * to believe we're losing bits.  (Note, this still won't be right
		 * if the server supports flags and we were trying to *remove* flags
		 * on a file that we copied, i.e., that we didn't create.)
		 */
		errno = 0;
		if (chflags(path, fs->st_flags)) {
			if (errno != EOPNOTSUPP || fs->st_flags != 0) {
				usyslog(LOG_WARNING,   "chflags: %s", path);
				rval = 1;
			}
			return (rval);
		}
#endif
	return 0;
}
コード例 #6
0
ファイル: cow_utils.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * set the stat() data of a link
 **/
static int setlink(const char *path, struct stat *fs)
{
	DBG_IN();

	if (lchown(path, fs->st_uid, fs->st_gid)) {
		if (errno != EPERM) {
			usyslog(LOG_WARNING,   "lchown: %s", path);
			return (1);
		}
	}
	return (0);
}
コード例 #7
0
ファイル: cow.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * initiate the cow-copy action
 */
int cow_cp(const char *path, int branch_ro, int branch_rw) {
	DBG_IN();

	// create the path to the file
	path_create_cutlast(path, branch_ro, branch_rw);

	char from[PATHLEN_MAX], to[PATHLEN_MAX];
	snprintf(from, PATHLEN_MAX, "%s%s", uopt.branches[branch_ro].path, path);
	snprintf(to, PATHLEN_MAX, "%s%s", uopt.branches[branch_rw].path, path);

	setlocale(LC_ALL, "");

	struct cow cow;

	cow.uid = getuid();

	// Copy the umask for explicit mode setting.
	cow.umask = umask(0);
	umask(cow.umask);

	cow.from_path = from;
	cow.to_path = to;

	struct stat buf;
	lstat(cow.from_path, &buf);
	cow.stat = &buf;

	int res;
	switch (buf.st_mode & S_IFMT) {
		case S_IFLNK:
			res = copy_link(&cow);
			break;
		case S_IFDIR:
			res = copy_directory(path, branch_ro, branch_rw);
			break;
		case S_IFBLK:
		case S_IFCHR:
			res = copy_special(&cow);
			break;
		case S_IFIFO:
			res = copy_fifo(&cow);
			break;
		case S_IFSOCK:
			usyslog(LOG_WARNING, "COW of sockets not supported: %s\n", cow.from_path);
			return 1;
		default:
			res = copy_file(&cow);
	}

	return res;
}
コード例 #8
0
CanvasInitDimensions()
{
    DBG_IN("CanvasInitDimensions") ;
    RESET_NUM_ARGS ;
    GET_WID_ARG(XmNx,        &Gcvs.wid.x) ;
    GET_WID_ARG(XmNy,        &Gcvs.wid.y) ;
    GET_WID_ARG(XmNwidth,    &Gcvs.wid.width) ;
    GET_WID_ARG(XmNheight,   &Gcvs.wid.height) ;
    GET_WID_VALUES(Gcvs.wid.id) ;


    DBG_OUT("CanvasInitDimensions") ;
    return(DT_OK);
}
コード例 #9
0
CanvasInit()
{
    DBG_IN("CanvasInit") ;

    Gcvs.wid.win   = XtWindow (Gcvs.wid.id) ;

    /* Get necessary data from the widget internals */


    RESET_NUM_ARGS ;
    GET_WID_ARG(XmNcolormap,   &Gcvs.wid.cmap) ;
    GET_WID_ARG(XmNforeground, &Gcvs.pixel.fg) ;
    GET_WID_ARG(XmNbackground, &Gcvs.pixel.bg) ;

    GET_WID_VALUES(Gcvs.wid.id) ;

    /* Get related shadow colors */
    {
        Pixel nu_fg, nu_select, nu_top;

        /* Get background_shadow */
        XmGetColors(XtScreen(Gcvs.wid.id), Gcvs.wid.cmap, 
			Gcvs.pixel.bg,
                            &nu_fg, &nu_top,
                                &Gcvs.pixel.sh_bg, &nu_select) ;

        /* Get foregrournd shadow */
        XmGetColors(XtScreen(Gcvs.wid.id), Gcvs.wid.cmap,
			Gcvs.pixel.fg,
                            &nu_fg, &nu_top,
                                &Gcvs.pixel.sh_fg, &nu_select) ;
    }


    Gcvs.pixmap.bg      = (Pixmap)NULL ;
    Gcvs.pixmap.bg_stip = (Pixmap)NULL ;

    Gcvs.gc.fg		= NULL ;
    Gcvs.gc.shadow	= NULL ;

    CanvasInitDimensions() ;
    CreateCanvasGCs() ;
    CreateCanvasPixmaps() ;

    DBG_OUT("CanvasInit") ;
    return(DT_OK) ;
}
コード例 #10
0
ファイル: cow_utils.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * copy a link, actually we recreate the link and only copy its stat() data.
 */
int copy_link(struct cow *cow)
{
	DBG_IN();

	int len;
	char link[PATHLEN_MAX];

	if ((len = readlink(cow->from_path, link, sizeof(link)-1)) == -1) {
		usyslog(LOG_WARNING,   "readlink: %s", cow->from_path);
		return (1);
	}

	link[len] = '\0';
	
	if (symlink(link, cow->to_path)) {
		usyslog(LOG_WARNING,   "symlink: %s", link);
		return (1);
	}
	
	return setlink(cow->to_path, cow->stat);
}
コード例 #11
0
ファイル: cow.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * l_nbranch (lower nbranch than nbranch) is write protected, create the dir path on
 * nbranch for an other COW operation.
 */
int path_create(const char *path, int nbranch_ro, int nbranch_rw) {
	DBG_IN();

	if (!uopt.cow_enabled) return 0;

	if (strlen(path) + strlen(uopt.branches[nbranch_rw].path) > PATHLEN_MAX
	|| strlen(path) + strlen(uopt.branches[nbranch_ro].path) > PATHLEN_MAX) {
		// TODO: how to handle that?
		return 1;
	}

	char p[PATHLEN_MAX];
	snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[nbranch_rw].path, path);

	struct stat st;
	if (!stat(p, &st)) {
		// path does already exists, no need to create it
		return 0;
	}

	char *walk = (char *)path;

	// first slashes, e.g. we have path = /dir1/dir2/, will set walk = dir1/dir2/
	while (*walk != '\0' && *walk == '/') walk++;

	do {
		// walk over the directory name, walk will now be /dir2
		while (*walk != '\0' && *walk != '/') walk++;

		// +1 due to \0, which gets added automatically
		snprintf(p, (walk - path) + 1, "%s", path); // walk - path = strlen(/dir1)
		int res = do_create(p, nbranch_ro, nbranch_rw);
		if (res) return res; // creating the directory failed

		// as above the do loop, walk over the next slashes, walk = dir2/
		while (*walk != '\0' && *walk == '/') walk++;
	} while (*walk != '\0');

	return 0;
}
コード例 #12
0
ファイル: cow.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * Actually create the directory here.
 */
static int do_create(const char *path, int nbranch_ro, int nbranch_rw) {
	DBG_IN();

	char dirp[PATHLEN_MAX]; // dir path to create
	sprintf(dirp, "%s%s", uopt.branches[nbranch_rw].path, path);

	struct stat buf;
	int res = stat(dirp, &buf);
	if (res != -1) return 0; // already exists

	if (nbranch_ro == nbranch_rw) {
		// special case nbranch_ro = nbranch_rw, this is if we a create
		// unionfs meta directories, so not directly on cow operations
		buf.st_mode = S_IRWXU | S_IRWXG;
	} else {
		// data from the ro-branch
		char o_dirp[PATHLEN_MAX]; // the pathname we want to copy
		sprintf(o_dirp, "%s%s", uopt.branches[nbranch_ro].path, path);
		res = stat(o_dirp, &buf);
		if (res == -1) return 1; // lower level branch removed in the mean time?
	}

	res = mkdir(dirp, buf.st_mode);
	if (res == -1) {
		usyslog(LOG_DAEMON, "Creating %s failed: \n", dirp);
		return 1;
	}

	if (nbranch_ro == nbranch_rw) return 0; // the special case again

	if (setfile(dirp, &buf))  return 1; // directory already removed by another process?

	// TODO: time, but its values are modified by the next dir/file creation steps?

	return 0;
}
コード例 #13
0
ファイル: cow_utils.c プロジェクト: ystk/debian-unionfs-fuse
/**
 * copy an ordinary file with all of its stat() data
 **/
int copy_file(struct cow *cow)
{
	DBG_IN();

	static char buf[MAXBSIZE];
	struct stat to_stat, *fs;
	int from_fd, rcount, to_fd, wcount;
	int rval = 0;
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
	char *p;
#endif

	if ((from_fd = open(cow->from_path, O_RDONLY, 0)) == -1) {
		usyslog(LOG_WARNING, "%s", cow->from_path);
		return (1);
	}

	fs = cow->stat;

	to_fd = open(cow->to_path, O_WRONLY | O_TRUNC | O_CREAT,
	             fs->st_mode & ~(S_ISTXT | S_ISUID | S_ISGID));

	if (to_fd == -1) {
		usyslog(LOG_WARNING, "%s", cow->to_path);
		(void)close(from_fd);
		return (1);
	}

	/*
	 * Mmap and write if less than 8M (the limit is so we don't totally
	 * trash memory on big files.  This is really a minor hack, but it
	 * wins some CPU back.
	 */
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
	if (fs->st_size > 0 && fs->st_size <= 8 * 1048576) {
		if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
		    MAP_FILE|MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
			usyslog(LOG_WARNING,   "mmap: %s", cow->from_path);
			rval = 1;
		} else {
			madvise(p, fs->st_size, MADV_SEQUENTIAL);
			if (write(to_fd, p, fs->st_size) != fs->st_size) {
				usyslog(LOG_WARNING,   "%s", cow->to_path);
				rval = 1;
			}
			/* Some systems don't unmap on close(2). */
			if (munmap(p, fs->st_size) < 0) {
				usyslog(LOG_WARNING,   "%s", cow->from_path);
				rval = 1;
			}
		}
	} else
#endif
	{
		while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
			wcount = write(to_fd, buf, rcount);
			if (rcount != wcount || wcount == -1) {
				usyslog(LOG_WARNING,   "%s", cow->to_path);
				rval = 1;
				break;
			}
		}
		if (rcount < 0) {
			usyslog(LOG_WARNING,   "copy failed: %s", cow->from_path);
			return 1;
		}
	}

	if (rval == 1) {
		(void)close(from_fd);
		(void)close(to_fd);
		return (1);
	}

	if (setfile(cow->to_path, cow->stat))
		rval = 1;
	/*
	 * If the source was setuid or setgid, lose the bits unless the
	 * copy is owned by the same user and group.
	 */
#define	RETAINBITS \
	(S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
	else if (fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == cow->uid) {
		if (fstat(to_fd, &to_stat)) {
			usyslog(LOG_WARNING,   "%s", cow->to_path);
			rval = 1;
		} else if (fs->st_gid == to_stat.st_gid &&
		    fchmod(to_fd, fs->st_mode & RETAINBITS & ~cow->umask)) {
			usyslog(LOG_WARNING,   "%s", cow->to_path);
			rval = 1;
		}
	}
	(void)close(from_fd);
	if (close(to_fd)) {
		usyslog(LOG_WARNING,   "%s", cow->to_path);
		rval = 1;
	}
	
	return (rval);
}