Пример #1
0
/**
 * Create a file or directory that hides path below branch_rw
 */
static int do_create_whiteout(const char *path, int branch_rw, enum whiteout mode) {
	DBG("%s\n", path);

	char metapath[PATHLEN_MAX];

	if (BUILD_PATH(metapath, METADIR, path)) RETURN(-1);

	// p MUST be without path to branch prefix here! 2 x branch_rw is correct here!
	// this creates e.g. branch/.unionfs/some_directory
	path_create_cutlast(metapath, branch_rw, branch_rw);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[branch_rw].path, metapath)) RETURN(-1);
	strcat(p, HIDETAG); // TODO check length

	int res;
	if (mode == WHITEOUT_FILE) {
		res = open(p, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
		if (res == -1) RETURN(-1);
		res = close(res);
	} else {
		res = mkdir(p, S_IRWXU);
		if (res)
			USYSLOG(LOG_ERR, "Creating %s failed: %s\n", p, strerror(errno));
	}

	RETURN(res);
}
Пример #2
0
/*
 * Name:	couchdb_flush
 * Input Args:
 *	handle - handle to the lcb instance
 *
 * Description: Flushes the entire cluster
 */
int
couchdb_flush(void)
{
	lcb_error_t ret;
	int	lock_result;
	lcb_flush_cmd_t *cmd = malloc(sizeof(*cmd));
	const lcb_flush_cmd_t *const flush_cmd[] = { cmd };

	cmd->version = 0;

	lock_result = pthread_rwlock_wrlock(&db_rwlock);
	if (lock_result != 0) {
		syslog(LOG_ERR, "%s: Failed to obtain writelock. Error = %d\n",
			__FUNCTION__, errno);
		return -errno;
	}

	ret = lcb_flush(couchdb_handle, NULL, 1, flush_cmd);
	if (ret != LCB_SUCCESS) {
		syslog(LOG_ERR, "%s: lcb_flush failed with error %s\n",
			__FUNCTION__, lcb_strerror(couchdb_handle, ret));
		return -ret;
	}

	/* Block the thread till this operation completes */
	lcb_wait(couchdb_handle);

	pthread_rwlock_unlock(&db_rwlock);
	USYSLOG(LOG_INFO, "\n%s: lflushed siuccess\n", __FUNCTION__);

	return (1);
}
Пример #3
0
/**
 * initiate the cow-copy action
 */
int cow_cp(const char *path, int branch_ro, int branch_rw, bool copy_dir) {
	DBG("%s\n", path);

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

	char from[PATHLEN_MAX], to[PATHLEN_MAX];
	if (BUILD_PATH(from, uopt.branches[branch_ro].path, path))
	       RETURN(-ENAMETOOLONG);
	if (BUILD_PATH(to, uopt.branches[branch_rw].path, path))
	       RETURN(-ENAMETOOLONG);

	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:
		       if (copy_dir) {
			       res = copy_directory(path, branch_ro, branch_rw);
		       } else {
			      res = path_create(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);
}
Пример #4
0
/**
 * Set file owner of after an operation, which created a file.
 */
int set_owner(const char *path) {
	struct fuse_context *ctx = fuse_get_context();
	if (ctx->uid != 0 && ctx->gid != 0) {
		int res = lchown(path, ctx->uid, ctx->gid);
		if (res) {
			USYSLOG(LOG_WARNING,
			       ":%s: Setting the correct file owner failed: %s !\n",
			       __func__, strerror(errno));
			RETURN(-errno);
		}
	}
	RETURN(0);
}
Пример #5
0
static void get_cb(lcb_t instance, const void *cookie,
			lcb_error_t error, const lcb_get_resp_t *resp)
{
	if (error != LCB_SUCCESS) {
		COUCHDB_LOG("Error getting the entry for Key %"PRId64"",
			*(uint64_t *)(resp->v.v0.key));
		return;
	}
	USYSLOG(LOG_INFO, "%s: get cb %s %d\n",__FUNCTION__,
		(char *)(resp->v.v0.bytes), (int) resp->v.v0.nbytes);
	memcpy((char *)value, (char *)(resp->v.v0.bytes), resp->v.v0.nbytes);
	num_bytes =  resp->v.v0.nbytes;
}
Пример #6
0
static int unionfs_mknod(const char *path, mode_t mode, dev_t rdev) {
	DBG("%s\n", path);

	int i = find_rw_branch_cutlast(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

	int file_type = mode & S_IFMT;
	int file_perm = mode & (S_PROT_MASK);

	int res = -1;
	if ((file_type) == S_IFREG) {
		// under FreeBSD, only the super-user can create ordinary files using mknod
		// Actually this workaround should not be required any more
		// since we now have the unionfs_create() method
		// So can we remove it?

		USYSLOG (LOG_INFO, "deprecated mknod workaround, tell the unionfs-fuse authors if you see this!\n");

		res = creat(p, 0);
		if (res > 0 && close(res) == -1) USYSLOG(LOG_WARNING, "Warning, cannot close file\n");
	} else {
		res = mknod(p, file_type, rdev);
	}

	if (res == -1) RETURN(-errno);

	set_owner(p); // no error check, since creating the file succeeded
	// NOW, that the file has the proper owner we may set the requested mode
	chmod(p, file_perm);

	remove_hidden(path, i);

	RETURN(0);
}
Пример #7
0
/**
 * init method
 * called before first access to the filesystem
 */
static void * unionfs_init(struct fuse_conn_info *conn) {
	// just to prevent the compiler complaining about unused variables
	(void) conn->max_readahead;

	// we only now (from unionfs_init) may go into the chroot, since otherwise
	// fuse_main() will fail to open /dev/fuse and to call mount
	if (uopt.chroot) {
		int res = chroot(uopt.chroot);
		if (res) {
			USYSLOG(LOG_WARNING, "Chdir to %s failed: %s ! Aborting!\n",
				 uopt.chroot, strerror(errno));
			exit(1);
		}
	}
	return NULL;
}
Пример #8
0
static int unionfs_ioctl(const char *path, int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data) {
	(void) path;
	(void) arg; // avoid compiler warning
	(void) fi;  // avoid compiler warning


	fprintf(stderr, "Got ioctl: %d\n", cmd);

#ifdef FUSE_IOCTL_COMPAT // 32bit-mode within 64-bit
	if (flags & FUSE_IOCTL_COMPAT)
		return -ENOSYS;
#endif

	switch (cmd) {
	case UNIONFS_ONOFF_DEBUG: {
		int on_off = *((int *) data);
		// unionfs-ctl gives the opposite value, so !!
		bool setRes = set_debug_onoff(!!on_off);
		if (!setRes)
			return -EINVAL;
		return 0;
	}
	case UNIONFS_SET_DEBUG_FILE: {
		char *debug_path = (char *) data;

		set_debug_path(debug_path, _IOC_SIZE(cmd));

		debug_init();
		return 0;
	}
	default:
		USYSLOG(LOG_ERR, "Unknown ioctl: %d", cmd);
		return -EINVAL;
		break;
	}

	return 0;
}
Пример #9
0
/**
 * Actually create the directory here.
 */
static int do_create(const char *path, int nbranch_ro, int nbranch_rw) {
	DBG("%s\n", path);

	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);
}
Пример #10
0
/**
 * unionfs rename function
 * TODO: If we rename a directory on a read-only branch, we need to copy over
 *       all files to the renamed directory on the read-write branch.
 */
static int unionfs_rename(const char *from, const char *to) {
	DBG("from %s to %s\n", from, to);

	bool is_dir = false; // is 'from' a file or directory

	int j = find_rw_branch_cutlast(to);
	if (j == -1) RETURN(-errno);

	int i = find_rorw_branch(from);
	if (i == -1) RETURN(-errno);

	if (!uopt.branches[i].rw) {
		i = find_rw_branch_cow_common(from, true);
		if (i == -1) RETURN(-errno);
	}

	if (i != j) {
		USYSLOG(LOG_ERR, "%s: from and to are on different writable branches %d vs %d, which"
		       "is not supported yet.\n", __func__, i, j);
		RETURN(-EXDEV);
	}

	char f[PATHLEN_MAX], t[PATHLEN_MAX];
	if (BUILD_PATH(f, uopt.branches[i].path, from)) RETURN(-ENAMETOOLONG);
	if (BUILD_PATH(t, uopt.branches[i].path, to)) RETURN(-ENAMETOOLONG);

	filetype_t ftype = path_is_dir(f);
	if (ftype == NOT_EXISTING)
		RETURN(-ENOENT);
	else if (ftype == IS_DIR)
		is_dir = true;

	int res;
	if (!uopt.branches[i].rw) {
		// since original file is on a read-only branch, we copied the from file to a writable branch,
		// but since we will rename from, we also need to hide the from file on the read-only branch
		if (is_dir)
			res = hide_dir(from, i);
		else
			res = hide_file(from, i);
		if (res) RETURN(-errno);
	}

	res = rename(f, t);

	if (res == -1) {
		int err = errno; // unlink() might overwrite errno
		// if from was on a read-only branch we copied it, but now rename failed so we need to delete it
		if (!uopt.branches[i].rw) {
			if (unlink(f))
				USYSLOG(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now "
				       "also unlink()  failed\n", __func__, from);

			if (remove_hidden(from, i))
				USYSLOG(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now "
				       "also removing the whiteout  failed\n", __func__, from);
		}
		RETURN(-err);
	}

	if (uopt.branches[i].rw) {
		// A lower branch still *might* have a file called 'from', we need to delete this.
		// We only need to do this if we have been on a rw-branch, since we created
		// a whiteout for read-only branches anyway.
		if (is_dir)
			maybe_whiteout(from, i, WHITEOUT_DIR);
		else
			maybe_whiteout(from, i, WHITEOUT_FILE);
	}

	remove_hidden(to, i); // remove hide file (if any)
	RETURN(0);
}
Пример #11
0
int
couchdb_update(uint64_t key, char *data, size_t len)
{
	char *db_key = NULL;
	lcb_size_t	key_size;
	lcb_error_t	ret;
	int	lock_result = -1;
	lcb_store_cmd_t item;
	const lcb_store_cmd_t *const store_items[] = { &item };
	char *compressed_data = NULL;
	size_t	compressed_len = 0;
	int	res = 0;

	compressed_len = snappy_max_compressed_length(len);
	compressed_data = (char *)malloc(compressed_len);
	if (compressed_data == NULL) {
		syslog(LOG_ERR, "%s: Unable to allocate memory for compressed_data\n", __FUNCTION__);
		return (-ENOMEM);
	}

	if ((res = snappy_compress((const char *)data, len,
 			compressed_data, &compressed_len)) != SNAPPY_OK) {
		free(compressed_data);
		return (-res);
	}

	memset(&item, 0, sizeof(lcb_store_cmd_t));
	db_key = (char *) malloc(MAX_KEY_SIZE);
	if (NULL == db_key) {
		syslog(LOG_ERR, "%s: Unable to allocate memory for db_key\n",
			__FUNCTION__);
		return -ENOMEM;
	}
	sprintf(db_key,"%"PRId64"", key);
	USYSLOG(LOG_INFO, "%s: set1 %"PRId64" %s %s, \n", __FUNCTION__, key,
		(char *) data, db_key);
	key_size = strlen(db_key);

	item.v.v0.key = db_key;
	item.v.v0.nkey = key_size;
	item.v.v0.bytes = compressed_data;
	item.v.v0.nbytes = compressed_len;
	item.v.v0.operation = LCB_REPLACE;

	lock_result = pthread_rwlock_wrlock(&db_rwlock);
	if (lock_result != 0) {
		syslog(LOG_ERR, "%s: Failed to obtain write lock. Error = %d\n",
			__FUNCTION__, errno);
		return -errno;
	}

	ret = lcb_store(couchdb_handle, NULL, 1, store_items);
	if (ret != LCB_SUCCESS) {
		syslog(LOG_ERR, "%s: lcb_store failed with error %s\n",
			__FUNCTION__, lcb_strerror(couchdb_handle, ret));
		return -ret;
	}
	/* Block the thread till this operation completes */
	lcb_wait(couchdb_handle);

	pthread_rwlock_unlock(&db_rwlock);

	return  (1);

}