<commit_before>/*
   (c) Copyright 2012  <NAME>

   All rights reserved.

   Written by <NAME> <<EMAIL>>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <curl/curl.h>
#include <errno.h>
#include <fuse.h>
#include <fuse_opt.h>
#include <oauth.h>

#define __STRICT_ANSI__
#include <json/json.h>

#include "kpfs.h"
#include "kpfs_node.h"
#include "kpfs_conf.h"
#include "kpfs_oauth.h"
#include "kpfs_api.h"
#include "kpfs_curl.h"
#include "kpfs_util.h"

static int kpfs_first_run = 1;

static char *kpfs_get_tmpfile(struct fuse_file_info *fi)
{
	return (char *)(uintptr_t) fi->fh;
}

static void kpfs_sha1_replace_slash(char *buf, int len)
{
	int i = 0;
	if (NULL == buf)
		return;
	for (i = 0; i < len; i++) {
		if (buf[i] == '/')
			buf[i] = 'a';
	}
}

static char *kpfs_gen_tmp_fullpath(const char *fullpath)
{
	char *t_key = kpfs_oauth_token_get();
	char *tmp_fullpath = NULL;
	char *sha1 = NULL;

	if (NULL == fullpath)
		return NULL;

	tmp_fullpath = calloc(KPFS_MAX_PATH, 1);
	if (NULL == tmp_fullpath)
		return NULL;

	sha1 = oauth_sign_hmac_sha1(fullpath, t_key);

	kpfs_sha1_replace_slash(sha1, strlen(sha1));

	snprintf(tmp_fullpath, KPFS_MAX_PATH, "%s/%s", kpfs_conf_get_writable_tmp_path(), (char *)sha1);
	KPFS_SAFE_FREE(sha1);
	return tmp_fullpath;
}

static int kpfs_getattr(const char *path, struct stat *stbuf)
{
	kpfs_node *node = NULL;

	if (!path || !stbuf)
		return -1;

	if (1 == kpfs_first_run) {
		kpfs_node_get_root_path();
		kpfs_node_parse_dir((kpfs_node *) kpfs_node_root_get(), "/");
		kpfs_first_run = 0;
	}

	memset(stbuf, 0, sizeof(*stbuf));

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("path: %s\n", path);

	if (0 == strcmp(path, "/.Trash") || 0 == strcmp(path, "/.Trash-1000")) {
		KPFS_FILE_LOG("we will not handle %s\n", path);
		return -1;
	}
	node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), path);
	if (NULL == node) {
		KPFS_FILE_LOG("%s:%d, could not find: %s\n", __FUNCTION__, __LINE__, path);
		return -ENOENT;
	}
	kpfs_node_dump(node);
	memcpy(stbuf, &(node->st), sizeof(node->st));
	return 0;
}

static int kpfs_access(const char *path, int mask)
{
	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, mask: %d.\n", __FUNCTION__, __LINE__, path, mask);
	return 0;
}

static int kpfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
	kpfs_node *node = NULL;

	(void)offset;
	(void)fi;

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	filler(buf, ".", NULL, 0);
	filler(buf, "..", NULL, 0);

	node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), path);
	if (node) {
		GHashTableIter iter;
		char *key = NULL;
		kpfs_node *value = NULL;

		if (1 != strlen(path)) {
			//kpfs_node_parse_dir(node, node->fullpath);
		}

		g_hash_table_iter_init(&iter, node->sub_nodes);
		while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
			KPFS_FILE_LOG("%s:%d, path: %s, filler: %s\n", __FUNCTION__, __LINE__, path, value->name);
			filler(buf, value->name, NULL, 0);
		}
	} else {
		return -1;
	}
	return 0;
}

static int kpfs_read(const char *path, char *rbuf, size_t size, off_t offset, struct fuse_file_info *fi)
{
	char *url = NULL;
	kpfs_node *node = NULL;
	int ret = 0;

	if (NULL == path || NULL == rbuf)
		return -1;
	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, rbuf:%s, size: %lu, offset: %lu, file info: %p\n", __FUNCTION__, __LINE__, path, rbuf, size, offset, fi);

	node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), path);
	if (NULL == node)
		return -1;

	url = kpfs_api_download_link_create(path);
	ret = kpfs_curl_range_get(url, rbuf, offset, offset + size - 1);
	KPFS_SAFE_FREE(url);
	return ret;
}

static int kpfs_write(const char *path, const char *wbuf, size_t size, off_t offset, struct fuse_file_info *fi)
{
	int fd = 0;
	int ret = 0;
	char *tmpfile = NULL;

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, wbuf:%s, size: %lu, offset: %lu, file info: %p\n", __FUNCTION__, __LINE__, path, wbuf, size, offset, fi);

	tmpfile = kpfs_get_tmpfile(fi);
	fd = open(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
	if (fd == -1)
		return -errno;

	ret = pwrite(fd, wbuf, size, offset);
	if (ret == -1)
		ret = -errno;
	close(fd);

	return ret;
}

static int kpfs_statfs(const char *path, struct statvfs *buf)
{
	off_t quota_total = kpfs_util_account_quota_total_get();
	off_t quota_used = kpfs_util_account_quota_used_get();

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, statvfs: %p.\n", __FUNCTION__, __LINE__, path, buf);

	kpfs_util_account_info_dump();

	buf->f_bsize = 1;
	buf->f_frsize = 1;
	buf->f_blocks = quota_total;
	buf->f_bfree = quota_total - quota_used;
	buf->f_bavail = quota_total - quota_used;

	return 0;
}

static int kpfs_mkdir(const char *path, mode_t mode)
{
	kpfs_node *node = NULL;
	kpfs_node *parent_node = NULL;
	char parent_path[KPFS_MAX_PATH] = { 0 };
	char *p = NULL;
	char *tmp = NULL;

	if (NULL == path)
		return -1;

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, mode: %d.\n", __FUNCTION__, __LINE__, path, mode);

	node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), path);
	if (node) {
		KPFS_FILE_LOG("[%s:%d] kpfs_mkdir, %s is existed.\n", __FUNCTION__, __LINE__, path);
		return -EEXIST;
	}
	if (KPFS_RET_FAIL == kpfs_api_create_folder(path))
		return -1;

	p = strrchr(path, '/');
	if (p == path)
		parent_node = kpfs_node_root_get();
	else {
		tmp = (char *)path;
		do {
			memset(parent_path, 0, sizeof(parent_path));
			strncpy(parent_path, tmp, p - tmp);
			parent_node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), parent_path);;
			p = strrchr(parent_path, '/');
			tmp = parent_path;
			if (p == parent_path) {
				parent_node = kpfs_node_root_get();
				break;
			}
		} while (NULL == parent_node);
	}
	KPFS_FILE_LOG("[%s:%d] parent_path: %s, fullpath: %s\n", __FUNCTION__, __LINE__, parent_path, parent_node->fullpath);
	kpfs_node_rebuild(parent_node);

	return 0;
}
<commit_msg>What - refine mkdir of kpfs, we will return after find the parent_node, otherwise, it will enter p==parent_path.<commit_after>/*
   (c) Copyright 2012  <NAME>

   All rights reserved.

   Written by <NAME> <<EMAIL>>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <curl/curl.h>
#include <errno.h>
#include <fuse.h>
#include <fuse_opt.h>
#include <oauth.h>

#define __STRICT_ANSI__
#include <json/json.h>

#include "kpfs.h"
#include "kpfs_node.h"
#include "kpfs_conf.h"
#include "kpfs_oauth.h"
#include "kpfs_api.h"
#include "kpfs_curl.h"
#include "kpfs_util.h"

static int kpfs_first_run = 1;

static char *kpfs_get_tmpfile(struct fuse_file_info *fi)
{
	return (char *)(uintptr_t) fi->fh;
}

static void kpfs_sha1_replace_slash(char *buf, int len)
{
	int i = 0;
	if (NULL == buf)
		return;
	for (i = 0; i < len; i++) {
		if (buf[i] == '/')
			buf[i] = 'a';
	}
}

static char *kpfs_gen_tmp_fullpath(const char *fullpath)
{
	char *t_key = kpfs_oauth_token_get();
	char *tmp_fullpath = NULL;
	char *sha1 = NULL;

	if (NULL == fullpath)
		return NULL;

	tmp_fullpath = calloc(KPFS_MAX_PATH, 1);
	if (NULL == tmp_fullpath)
		return NULL;

	sha1 = oauth_sign_hmac_sha1(fullpath, t_key);

	kpfs_sha1_replace_slash(sha1, strlen(sha1));

	snprintf(tmp_fullpath, KPFS_MAX_PATH, "%s/%s", kpfs_conf_get_writable_tmp_path(), (char *)sha1);
	KPFS_SAFE_FREE(sha1);
	return tmp_fullpath;
}

static int kpfs_getattr(const char *path, struct stat *stbuf)
{
	kpfs_node *node = NULL;

	if (!path || !stbuf)
		return -1;

	if (1 == kpfs_first_run) {
		kpfs_node_get_root_path();
		kpfs_node_parse_dir((kpfs_node *) kpfs_node_root_get(), "/");
		kpfs_first_run = 0;
	}

	memset(stbuf, 0, sizeof(*stbuf));

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("path: %s\n", path);

	if (0 == strcmp(path, "/.Trash") || 0 == strcmp(path, "/.Trash-1000")) {
		KPFS_FILE_LOG("we will not handle %s\n", path);
		return -1;
	}
	node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), path);
	if (NULL == node) {
		KPFS_FILE_LOG("%s:%d, could not find: %s\n", __FUNCTION__, __LINE__, path);
		return -ENOENT;
	}
	kpfs_node_dump(node);
	memcpy(stbuf, &(node->st), sizeof(node->st));
	return 0;
}

static int kpfs_access(const char *path, int mask)
{
	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, mask: %d.\n", __FUNCTION__, __LINE__, path, mask);
	return 0;
}

static int kpfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
	kpfs_node *node = NULL;

	(void)offset;
	(void)fi;

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	filler(buf, ".", NULL, 0);
	filler(buf, "..", NULL, 0);

	node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), path);
	if (node) {
		GHashTableIter iter;
		char *key = NULL;
		kpfs_node *value = NULL;

		if (1 != strlen(path)) {
			//kpfs_node_parse_dir(node, node->fullpath);
		}

		g_hash_table_iter_init(&iter, node->sub_nodes);
		while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
			KPFS_FILE_LOG("%s:%d, path: %s, filler: %s\n", __FUNCTION__, __LINE__, path, value->name);
			filler(buf, value->name, NULL, 0);
		}
	} else {
		return -1;
	}
	return 0;
}

static int kpfs_read(const char *path, char *rbuf, size_t size, off_t offset, struct fuse_file_info *fi)
{
	char *url = NULL;
	kpfs_node *node = NULL;
	int ret = 0;

	if (NULL == path || NULL == rbuf)
		return -1;
	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, rbuf:%s, size: %lu, offset: %lu, file info: %p\n", __FUNCTION__, __LINE__, path, rbuf, size, offset, fi);

	node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), path);
	if (NULL == node)
		return -1;

	url = kpfs_api_download_link_create(path);
	ret = kpfs_curl_range_get(url, rbuf, offset, offset + size - 1);
	KPFS_SAFE_FREE(url);
	return ret;
}

static int kpfs_write(const char *path, const char *wbuf, size_t size, off_t offset, struct fuse_file_info *fi)
{
	int fd = 0;
	int ret = 0;
	char *tmpfile = NULL;

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, wbuf:%s, size: %lu, offset: %lu, file info: %p\n", __FUNCTION__, __LINE__, path, wbuf, size, offset, fi);

	tmpfile = kpfs_get_tmpfile(fi);
	fd = open(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
	if (fd == -1)
		return -errno;

	ret = pwrite(fd, wbuf, size, offset);
	if (ret == -1)
		ret = -errno;
	close(fd);

	return ret;
}

static int kpfs_statfs(const char *path, struct statvfs *buf)
{
	off_t quota_total = kpfs_util_account_quota_total_get();
	off_t quota_used = kpfs_util_account_quota_used_get();

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, statvfs: %p.\n", __FUNCTION__, __LINE__, path, buf);

	kpfs_util_account_info_dump();

	buf->f_bsize = 1;
	buf->f_frsize = 1;
	buf->f_blocks = quota_total;
	buf->f_bfree = quota_total - quota_used;
	buf->f_bavail = quota_total - quota_used;

	return 0;
}

static int kpfs_mkdir(const char *path, mode_t mode)
{
	kpfs_node *node = NULL;
	kpfs_node *parent_node = NULL;
	char parent_path[KPFS_MAX_PATH] = { 0 };
	char *p = NULL;
	char *tmp = NULL;

	if (NULL == path)
		return -1;

	KPFS_FILE_LOG("[%s:%d] enter\n", __FUNCTION__, __LINE__);
	KPFS_FILE_LOG("[%s:%d] path: %s, mode: %d.\n", __FUNCTION__, __LINE__, path, mode);

	node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), path);
	if (node) {
		KPFS_FILE_LOG("[%s:%d] kpfs_mkdir, %s is existed.\n", __FUNCTION__, __LINE__, path);
		return -EEXIST;
	}
	if (KPFS_RET_FAIL == kpfs_api_create_folder(path))
		return -1;

	p = strrchr(path, '/');
	if (p == path)
		parent_node = kpfs_node_root_get();
	else {
		tmp = (char *)path;
		while (1) {
			memset(parent_path, 0, sizeof(parent_path));
			strncpy(parent_path, tmp, p - tmp);
			parent_node = kpfs_node_get_by_path((kpfs_node *) kpfs_node_root_get(), parent_path);;
			if (parent_node)
				break;
			p = strrchr(parent_path, '/');
			tmp = parent_path;
			if (p == parent_path) {
				parent_node = kpfs_node_root_get();
				break;
			}
		};
	}
	KPFS_FILE_LOG("[%s:%d] parent_path: %s, fullpath: %s\n", __FUNCTION__, __LINE__, parent_path, parent_node->fullpath);
	kpfs_node_rebuild(parent_node);

	return 0;
}

{'fraction_non_alphanumeric': 0.15218778810013475, 'fraction_numerical': 0.010141124742926033, 'mean_word_length': 4.5717107862504935, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5119332', 'n_tokens_mistral': 6147, 'n_tokens_neox': 5752, 'n_words': 1431}