<commit_before>#include "debug.h"
#include "path.h"
#include "query.h"
#include "strlcpy.h"

#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define FUSE_USE_VERSION 27

#include <fuse/fuse.h>

#include <libpq-fe.h>


static PGconn *dbconn;
static time_t starttime;



static int
switch_database(struct dbpath *dbpath)
{
	PGconn *newdbconn;

	if (dbpath_is_root(*dbpath))
		return 1;

	if (strcmp(dbpath->database, PQdb(dbconn)) == 0)
		return 1;

	newdbconn = PQsetdbLogin(PQhost(dbconn),
							 PQport(dbconn),
							 PQoptions(dbconn),
							 PQtty(dbconn),
							 dbpath->database,
							 PQuser(dbconn),
							 PQpass(dbconn));

	if (PQstatus(newdbconn) != CONNECTION_OK)
	{
		debug("new connection failed");
		PQfinish(newdbconn);
		return 0;
	}

	PQfinish(dbconn);
	dbconn = newdbconn;
	return 1;
}


static int
postgresqlfs_getattr(const char *path, struct stat *buf)
{
	struct dbpath dbpath;

	buf->st_mode = 0;

	debug("path=%s", path);

	split_path(path, &dbpath);

	debug("%s", dbpath_to_string(&dbpath));

	if (!dbpath_is_database(dbpath) && !switch_database(&dbpath))
		return -EIO;

	if (!dbpath_exists(&dbpath, dbconn))
		return -ENOENT;

	buf->st_nlink = 1;
	buf->st_uid = getuid();
	buf->st_gid = getgid();

	if (dbpath_is_column(dbpath))
		buf->st_mode |= S_IFREG | 0444;
	else
		buf->st_mode |= S_IFDIR | 0755;

	buf->st_atime = starttime;
	buf->st_mtime = starttime;
	buf->st_ctime = starttime;

	buf->st_blksize = 1;

	if (dbpath_is_column(dbpath))
	{
		PGresult *res;

		res = db_query(dbconn,
					   "SELECT octet_length(CAST(%s AS text)) FROM %s.%s WHERE ctid = '%s';",
					   dbpath.column + 3, dbpath.schema, dbpath.table, rowname_to_ctid(dbpath.row));
		if (!res)
			return -EIO;

		buf->st_size = atol(PQgetvalue(res, 0, 0));

		PQclear(res);
	}
	else
	{
		buf->st_size = 42;
	}

	buf->st_blocks = buf->st_size;

	return 0;
}


static int
postgresqlfs_mkdir(const char *path, mode_t mode __attribute__((unused)))
{
	struct dbpath dbpath;

	split_path(path, &dbpath);

	// TODO: use mode sensibly

	if (dbpath_is_root(dbpath))
		return -EEXIST;
	else if (dbpath_is_database(dbpath))
		return db_command(dbconn, "CREATE DATABASE %s;", dbpath.database);
	else {
		/* Note: Don't switch the database when creating a database. */
		if (!switch_database(&dbpath))
			return -EIO;

		if (dbpath_is_schema(dbpath))
			return db_command(dbconn, "CREATE SCHEMA %s;", dbpath.schema);
		else if (dbpath_is_table(dbpath))
			return -ENOSYS; /* maybe: create zero column table */
		else if (dbpath_is_row(dbpath))
			return -ENOSYS; /* maybe: translate to INSERT with primary key and default values? */
		else
			return -EINVAL; /* column is a file, not directory, XXX maybe ENOTDIR */
	}
}


static int
postgresqlfs_rmdir(const char *path)
{
	struct dbpath dbpath;

	split_path(path, &dbpath);

	if (!switch_database(&dbpath))
		return -EIO;

	if (dbpath_is_root(dbpath))
		return -EBUSY;
	else if (dbpath_is_database(dbpath))
		return -ENOTEMPTY;
	else if (dbpath_is_schema(dbpath))
		return db_command(dbconn, "DROP SCHEMA %s;", dbpath.schema);
	else if (dbpath_is_table(dbpath))<commit_msg>Alter error codes.<commit_after>#include "debug.h"
#include "path.h"
#include "query.h"
#include "strlcpy.h"

#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define FUSE_USE_VERSION 27

#include <fuse/fuse.h>

#include <libpq-fe.h>


static PGconn *dbconn;
static time_t starttime;



static int
switch_database(struct dbpath *dbpath)
{
	PGconn *newdbconn;

	if (dbpath_is_root(*dbpath))
		return 1;

	if (strcmp(dbpath->database, PQdb(dbconn)) == 0)
		return 1;

	newdbconn = PQsetdbLogin(PQhost(dbconn),
							 PQport(dbconn),
							 PQoptions(dbconn),
							 PQtty(dbconn),
							 dbpath->database,
							 PQuser(dbconn),
							 PQpass(dbconn));

	if (PQstatus(newdbconn) != CONNECTION_OK)
	{
		debug("new connection failed");
		PQfinish(newdbconn);
		return 0;
	}

	PQfinish(dbconn);
	dbconn = newdbconn;
	return 1;
}


static int
postgresqlfs_getattr(const char *path, struct stat *buf)
{
	struct dbpath dbpath;

	buf->st_mode = 0;

	debug("path=%s", path);

	split_path(path, &dbpath);

	debug("%s", dbpath_to_string(&dbpath));

	if (!dbpath_is_database(dbpath) && !switch_database(&dbpath))
		return -EIO;

	if (!dbpath_exists(&dbpath, dbconn))
		return -ENOENT;

	buf->st_nlink = 1;
	buf->st_uid = getuid();
	buf->st_gid = getgid();

	if (dbpath_is_column(dbpath))
		buf->st_mode |= S_IFREG | 0444;
	else
		buf->st_mode |= S_IFDIR | 0755;

	buf->st_atime = starttime;
	buf->st_mtime = starttime;
	buf->st_ctime = starttime;

	buf->st_blksize = 1;

	if (dbpath_is_column(dbpath))
	{
		PGresult *res;

		res = db_query(dbconn,
					   "SELECT octet_length(CAST(%s AS text)) FROM %s.%s WHERE ctid = '%s';",
					   dbpath.column + 3, dbpath.schema, dbpath.table, rowname_to_ctid(dbpath.row));
		if (!res)
			return -EIO;

		buf->st_size = atol(PQgetvalue(res, 0, 0));

		PQclear(res);
	}
	else
	{
		buf->st_size = 42;
	}

	buf->st_blocks = buf->st_size;

	return 0;
}


static int
postgresqlfs_mkdir(const char *path, mode_t mode __attribute__((unused)))
{
	struct dbpath dbpath;

	split_path(path, &dbpath);

	// TODO: use mode sensibly

	if (dbpath_is_root(dbpath))
		return -EEXIST;
	else if (dbpath_is_database(dbpath))
		return db_command(dbconn, "CREATE DATABASE %s;", dbpath.database);
	else {
		/* Note: Don't switch the database when creating a database. */
		if (!switch_database(&dbpath))
			return -EIO;

		if (dbpath_is_schema(dbpath))
			return db_command(dbconn, "CREATE SCHEMA %s;", dbpath.schema);
		else if (dbpath_is_table(dbpath))
			return -ENOSYS; /* maybe: create zero column table */
		else if (dbpath_is_row(dbpath))
			return -ENOSYS; /* maybe: translate to INSERT with primary key and default values? */
		else
			return -ENOENT;
	}
}


static int
postgresqlfs_rmdir(const char *path)
{
	struct dbpath dbpath;

	split_path(path, &dbpath);

	if (!switch_database(&dbpath))
		return -EIO;

	if (dbpath_is_root(dbpath))
		return -EBUSY;
	else if (dbpath_is_database(dbpath))
		return -ENOTEMPTY;
	else if (dbpath_is_schema(dbpath))
		return db_command(dbconn, "DROP SCHEMA %s;", dbpath.schema);
	else if (dbpath_is_table(dbpath))
{'fraction_non_alphanumeric': 0.14328125, 'fraction_numerical': 0.0075, 'mean_word_length': 4.174616006467259, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6109125', 'n_tokens_mistral': 2842, 'n_tokens_neox': 2515, 'n_words': 568}