[Lug-bg] Announce: filejoinfs 1.0
- Subject: [Lug-bg] Announce: filejoinfs 1.0
- From: Georgi Chorbadzhiyski <gf@xxxxxxxxxxx>
- Date: Fri, 01 Oct 2010 19:03:21 +0300
- Organization: Unix Solutions Ltd. (http://unixsol.org)
В крайна сметка се оказа лесна работа да се направи файлова система,
която обединява няколко файла като един.
Резултатът е в прикачения файл, ако на някой му свърши работа, да
почерпи.
А сега отивам аз да се почерпя, петък е все пак.
п.п. C-то не го умея много, тъй че ако искате да ме порицаете, давайте
смело, не съм от сръдливите. ;)
--
Georgi Chorbadzhiyski
http://georgi.unixsol.org/
/*
# filejoinfs v1.0
# Quick'n'dirty FUSE module implementing joining of different files as one
#
# Copyright (c) 2010 Georgi Chorbadzhiyski (georgi@xxxxxxxxxxx)
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# To compile the program run:
# gcc -Wall -Wextra `pkg-config fuse --cflags --libs` filejoinfs.c -lfuse -o filejoinfs
#
# To use it:
# 1. Install fuse module
# sudo modprobe fuse
#
# 2. Create file list
# echo /etc/group >> filelist.txt
# echo /etc/issue >> filelist.txt
# echo /etc/passwd >> filelist.txt
#
# 3. Create an empty file over which the files in the list will be joined
# touch joined.txt
#
# 4. Mount filejoinfs
# ./filejoinfs filelist.txt joined.txt
#
# 5. Check the result with
# cat joined.txt
#
# You will see the contents of files listed in filelist.txt
#
# 6. Unmount the fs
# fusermount -u joined.txt
#
*/
#define FUSE_USE_VERSION 26
#define _XOPEN_SOURCE 500 // for "pread"
#define _GNU_SOURCE 1 // for "getline"
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <fuse.h>
/* Handle list of files */
struct fileinfo {
int fd;
char *name;
off_t size;
};
struct files {
int num_files;
off_t total_size;
int alloc_files;
struct fileinfo **data;
};
struct files *filelist;
struct files *files_alloc() {
struct files *f = calloc(1, sizeof(struct files));
f->alloc_files = 64;
f->data = calloc(f->alloc_files, sizeof(struct fileinfo *));
return f;
}
void files_free(struct files **pfiles) {
struct files *files = *pfiles;
struct fileinfo *file;
int i;
if (files) {
for (i=0; i<files->num_files; i++) {
file = files->data[i];
close(file->fd);
free(file->name);
free(file);
}
free(files->data);
free(*pfiles);
*pfiles = NULL;
}
}
void files_dump(struct files *files) {
int i;
fprintf(stdout,"num_files:%d\n", files->num_files);
fprintf(stdout,"alloc_files:%d\n", files->alloc_files);
fprintf(stdout,"total_sizes:%lld\n", files->total_size);
for (i=0; i<files->num_files; i++) {
struct fileinfo *f = files->data[i];
fprintf(stdout,"file[%d]->fd=%d\n", i, f->fd);
fprintf(stdout,"file[%d]->name=%s\n", i, f->name);
fprintf(stdout,"file[%d]->size=%llu\n", i, f->size);
}
}
int files_add_file(struct files *files, char *filename) {
int ret = 0;
struct stat sb;
if (stat(filename, &sb) != -1) {
struct fileinfo *file;
int fd = open(filename, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "open(%s) error : %s\n", filename, strerror(errno));
return ret;
}
file = calloc(1, sizeof(struct fileinfo));
file->name = strdup(filename);
file->size = sb.st_size;
file->fd = fd;
files->total_size += file->size;
files->data[files->num_files] = file;
files->num_files++;
if (files->num_files >= files->alloc_files-1) {
files->alloc_files *= 2;
files->data = realloc(files->data, files->alloc_files * sizeof(struct fileinfo *));
}
ret = 1;
} else {
fprintf(stderr, "stat(%s) error : %s\n", filename, strerror(errno));
}
return ret;
}
int files_load_filelist(struct files *files, char *filename) {
size_t len;
ssize_t readed;
int ret = 0;
char *line = NULL;
FILE *file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Can't open %s : %s\n", filename, strerror(errno));
return ret;
}
while ((readed = getline(&line, &len, file)) != -1) {
line[readed-1] = '\0';
ret += files_add_file(files, line);
}
free(line);
fclose(file);
return ret;
}
static int fuse_getattr(const char *path, struct stat *stbuf) {
if (strcmp(path, "/") != 0)
return -ENOENT;
if (fstat(filelist->data[0]->fd, stbuf) == -1)
return -errno;
stbuf->st_size = filelist->total_size;
return 0;
}
static int fuse_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
(void)fi; // prevent warning
int i;
struct fileinfo *file = filelist->data[0];
ssize_t readen, totreaden = 0;
off_t fileofs = offset, passed = 0;
int filenum = 0;
if (strcmp(path, "/") != 0)
return -ENOENT;
if (offset >= filelist->total_size) // Hmm :)
return 0;
if (offset + size > filelist->total_size) { // Asking for too much
if (filelist->total_size < offset) // Prevent overflow
return 0;
size = filelist->total_size - offset;
}
if (offset > file->size) { // After the first file
// Find the file that corresponds to the required offset
// Can be slow with lots of files, but do it simple for now
for (i=0; i<filelist->num_files; i++) {
struct fileinfo *f = filelist->data[i];
passed += f->size;
if (passed >= offset) {
file = f;
filenum = i;
fileofs = file->size - (passed - offset);
break;
}
}
}
// Read all data
do {
readen = pread(file->fd, buf, size, fileofs);
if (readen == -1) // Error reading
return -errno;
totreaden += readen;
fileofs += readen;
buf += readen;
size -= readen;
if (fileofs >= file->size) {
fileofs = 0;
filenum++;
if (filenum >= filelist->num_files) {
break;
}
file = filelist->data[filenum];
}
} while(size > 0);
return totreaden;
}
static struct fuse_operations concatfs_op = {
.getattr = fuse_getattr,
.read = fuse_read,
};
int main(int argc, char *argv[]) {
int ret;
char *filenames;
char *mountpoint_file;
struct stat sb;
if (argc < 3) {
fprintf(stderr, "Usage: filejoinfs filelist.txt mount-point-file\n");
exit(EXIT_FAILURE);
}
filenames = argv[1];
mountpoint_file = argv[2];
if (stat(mountpoint_file, &sb) == -1) {
fprintf(stderr, "Can't mount on %s : %s\n", mountpoint_file, strerror(errno));
exit(EXIT_FAILURE);
} else {
if (!S_ISREG(sb.st_mode)) {
fprintf(stderr, "%s is not a file!\n", mountpoint_file);
exit(EXIT_FAILURE);
}
}
filelist = files_alloc();
if (!files_load_filelist(filelist, filenames)) {
fprintf(stderr, "Error no files loaded from %s.\n", argv[1]);
files_free(&filelist);
exit(EXIT_FAILURE);
}
char *fuse_argv[5];
fuse_argv[0] = argv[0];
fuse_argv[1] = mountpoint_file;
fuse_argv[2] = "-o";
fuse_argv[3] = "nonempty,direct_io";
fuse_argv[4] = 0;
ret = fuse_main(4, fuse_argv, &concatfs_op, NULL);
files_free(&filelist);
return ret;
}
_______________________________________________
Lug-bg mailing list
Lug-bg@xxxxxxxxxxxxxxxxxx
http://linux-bulgaria.org/mailman/listinfo/lug-bg
|