В крайна сметка се оказа лесна работа да се направи файлова система,
която обединява няколко файла като един.

Резултатът е в прикачения файл, ако на някой му свърши работа, да
почерпи.

А сега отивам аз да се почерпя, петък е все пак.

п.п. 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 ([email protected])
# 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
[email protected]
http://linux-bulgaria.org/mailman/listinfo/lug-bg

Reply via email to