The command to compile and run the application:
gcc -lsqlite3 -lfuse -D_FILE_OFFSET_BITS=64 sfs.c -o sfs
./sfs -f db.sqlite dir
The full code as of now:
#define FUSE_USE_VERSION 29
#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
int count_slashes(const char *str) {
int count = 0;
int i;
for (i = 0; i < strlen(str); i++) {
if (str[i] == '/') {
count++;
}
}
return count;
}
int sfs_getattr(const char *path, struct stat *st)
{
printf("Getting attributes for: %s\n",path);
int slashes = count_slashes(path);
if (slashes == 1) {
st->st_mode = S_IFDIR | 0755;
st->st_nlink = 2;
st->st_size = 4096; // file size
} else {
st->st_mode = S_IFREG | 0644;
st->st_nlink = 2;
st->st_size = 4096;
}
st->st_uid = getuid();
st->st_gid = getgid();
return 0;
}
int sq_getTables(void *buffer, fuse_fill_dir_t filler) {
sqlite3 *db;
int rc = sqlite3_open("db.sqlite", &db);
char *sql = "select name from sqlite_master where type = 'table' and name not like 'sqlite_%';";
sqlite3_stmt *stmt = NULL;
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
rc = sqlite3_step(stmt);
while (rc != SQLITE_DONE && rc != SQLITE_OK) {
const unsigned char * table = sqlite3_column_text(stmt,0);
filler(buffer, table, NULL, 0);
rc = sqlite3_step(stmt);
}
rc = sqlite3_finalize(stmt);
rc = sqlite3_close(db);
return rc;
}
int sq_getKeys(char *tableName, void *buffer, fuse_fill_dir_t filler) {
sqlite3 *db;
int rc = sqlite3_open("db.sqlite", &db);
char *sql = "select * from ";
char *sc = ";";
int length = strlen(sql) + strlen(tableName) + strlen(sc);
char *result = malloc(length + 1);
strcpy(result, sql);
strcat(result, tableName);
strcat(result, sc);
sqlite3_stmt *stmt = NULL;
sqlite3_prepare_v2(db, result, -1, &stmt, NULL);
rc = sqlite3_step(stmt);
while (rc != SQLITE_DONE && rc != SQLITE_OK) {
const unsigned char *key = sqlite3_column_text(stmt,0);
filler(buffer, key, NULL, 0);
rc = sqlite3_step(stmt);
}
rc = sqlite3_finalize(stmt);
rc = sqlite3_close(db);
free(result);
return rc;
}
int sfs_readdir(const char *path, void *buffer, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
printf("Calling readdir on: %s\n",path);
int slashes = count_slashes(path);
filler(buffer, ".", NULL, 0);
filler(buffer, "..", NULL, 0);
if (slashes == 1) {
if (!strcmp(path, "/")) {
sq_getTables(buffer, filler);
} else {
int length = strlen(path);
char *new_path = malloc(length + 1);
strcpy(new_path, path);
char *tableName = strtok(new_path, "/");
sq_getKeys(tableName, buffer, filler);
free(new_path);
}
}
return 0;
}
char *sq_getData(char *tableName, char *key, char *buffer, off_t offset) {
sqlite3 *db;
int rc = sqlite3_open("db.sqlite", &db);
char *sql = "select * from ";
char *where = " where title = '";
char *sc = "';";
int length = strlen(sql) + strlen(tableName) + strlen(where) + strlen(key) + strlen(sc);
char *query = malloc(length + 1);
strcpy(query, sql);
strcat(query, tableName);
strcat(query, where);
strcat(query, key);
strcat(query, sc);
sqlite3_stmt *stmt = NULL;
sqlite3_prepare_v2(db, query, -1, &stmt, NULL);
rc = sqlite3_step(stmt);
int count = sqlite3_column_count(stmt);
char **strings = (char**) malloc(count * sizeof(char*));
int i;
for (i = 0; i<count; i++) {
const char * col = sqlite3_column_name(stmt, i);
const unsigned char *val = sqlite3_column_text(stmt,i);
int length = snprintf(NULL, 0, "%s = '%s'", col, val);
strings[i] = (char*) malloc(length + 1);
snprintf(strings[i], length + 1, "%s = '%s'", col,val);
}
rc = sqlite3_finalize(stmt);
rc = sqlite3_close(db);
free(query);
int total_length = 0;
for (i = 0; i < count; i++) {
total_length += strlen(strings[i]);
}
char *result = (char*) malloc(total_length + count - 1);
result[0] = '\0';
for (i = 0; i < count; i++) {
strcat(result, strings[i]);
if (i < count - 1) {
strcat(result, "\n");
}
}
for (i = 0; i < count; i++) {
free(strings[i]);
}
free(strings);
return result;
}
static int sfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
printf("Reading: %s\n",path);
int slashes = count_slashes(path);
if (slashes != 2) {
return 0;
}
char *new_path = malloc(strlen(path) + 1);
strcpy(new_path, path);
char *tableName = strtok(new_path, "/");
char *key = strtok(NULL, "/");
char* filecontent = sq_getData(tableName, key, buf, offset);
size_t len = strlen(filecontent);
if (offset >= len) {
return 0;
}
if (offset + size > len) {
memcpy(buf, filecontent + offset, len - offset);
return len - offset;
}
memcpy(buf, filecontent + offset, size);
free(new_path);
return size;
}
int sq_updateData(char *tableName, char *key, const char *buffer) {
sqlite3 *db;
int rc = sqlite3_open("db.sqlite", &db);
char *data = strdup(buffer);
int datalen = strlen(data);
int i;
for (i = 0; i<datalen; i++) {
if (data[i] == '\n') {
data[i] = ',';
}
}
if (data[datalen-1] == ',') {
data[datalen-1] = '\0';
}
int length = snprintf(NULL, 0, "update %s set %s where title = '%s';", tableName, data, key);
char *query = (char*) malloc(length + 1);
snprintf(query, length, "update %s set %s where title = '%s';", tableName, data, key);
sqlite3_stmt *stmt = NULL;
sqlite3_prepare_v2(db, query, -1, &stmt, NULL);
rc = sqlite3_step(stmt);
rc = sqlite3_finalize(stmt);
rc = sqlite3_close(db);
free(data);
return rc;
}
static int sfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
printf("Writing: %s\n",path);
int slashes = count_slashes(path);
if (slashes != 2) {
return 0;
}
char *new_path = malloc(strlen(path) + 1);
strcpy(new_path, path);
char *tableName = strtok(new_path, "/");
char *key = strtok(NULL, "/");
sq_updateData(tableName, key, buf);
return strlen(buf);
}
static struct fuse_operations sfs_ops = {
.getattr = sfs_getattr,
.readdir = sfs_readdir,
.read = sfs_read,
.write = sfs_write,
};
int main(int argc, char **argv)
{
int i;
for (i = 1; i < argc && argv[i][0] == '-'; i++);
if (i < argc) {
memcpy(&argv[i], &argv[i+1], (argc-i) * sizeof(argv[0]));
argc--;
}
printf("Lighting FUSE...\n");
return fuse_main(argc, argv, &sfs_ops, NULL);
}