diff --git a/.gitignore b/.gitignore index 2b751a3..0069b2a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,15 @@ -*.o -*.kate-swp +# Binaries httpdirfs +sonicfs + +# Intermediates +*.o .depend -doc/html + +# Documentation +doc + +# Editor related .vscode httpdirfs.code-workspace +*.kate-swp \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index de66032..d6ca3e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.3.0] +### Changed +Now generate separate binaries +- ``HTTDirFS`` for mounting HTTP directory listings. +- ``SonicFS`` for mounting Airsonic / Subsonic server. +### Fixed +- macOS uninstallation in Makefile. ## [1.2.1] - 2021-05-27 ### Added -- macOS compilation support +- macOS compilation support. ## [1.2.0] - 2019-11-01 ### Added @@ -177,8 +184,9 @@ ${XDG_CONFIG_HOME}/httpdirfs, rather than ${HOME}/.httpdirfs ## [1.0] - 2018-08-22 - Initial release, everything works correctly, as far as I know. -[Unreleased]: https://github.com/fangfufu/httpdirfs/compare/Unreleased...1.2.1 -[1.2.1]: https://github.com/fangfufu/httpdirfs/compare/Unreleased...1.2.0 +[Unreleased]: https://github.com/fangfufu/httpdirfs/compare/Unreleased...1.3.0 +[1.3.0]: https://github.com/fangfufu/httpdirfs/compare/1.3.0...1.2.1 +[1.2.1]: https://github.com/fangfufu/httpdirfs/compare/1.2.1...1.2.0 [1.2.0]: https://github.com/fangfufu/httpdirfs/compare/1.2.0...1.1.10 [1.1.10]: https://github.com/fangfufu/httpdirfs/compare/1.1.9...1.1.10 [1.1.9]: https://github.com/fangfufu/httpdirfs/compare/1.1.8...1.1.9 diff --git a/Doxyfile b/Doxyfile index 56a01a6..44b100e 100644 --- a/Doxyfile +++ b/Doxyfile @@ -901,7 +901,7 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = CALLOC exit_failure # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include diff --git a/Makefile b/Makefile index b563bb6..189e116 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION = 1.2.1 +VERSION = 1.3.0 CFLAGS += -O2 -Wall -Wextra -Wshadow -rdynamic -D_GNU_SOURCE\ -D_FILE_OFFSET_BITS=64 -DVERSION=\"$(VERSION)\"\ @@ -23,57 +23,81 @@ endif prefix ?= /usr/local -all: httpdirfs +all: httpdirfs sonicfs %.o: src/%.c $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -c -o $@ $< -httpdirfs: $(COBJS) +httpdirfs: httpdirfs.o $(COBJS) $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) -install: +sonicfs: sonicfs.o $(COBJS) + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + +install: all ifeq ($(OS),Linux) install -m 755 -D httpdirfs \ $(DESTDIR)$(prefix)/bin/httpdirfs install -m 644 -D doc/man/httpdirfs.1 \ $(DESTDIR)$(prefix)/share/man/man1/httpdirfs.1 + install -m 755 -D sonicfs \ + $(DESTDIR)$(prefix)/bin/sonicfs + install -m 644 -D doc/man/sonicfs.1 \ + $(DESTDIR)$(prefix)/share/man/man1/sonicfs.1 endif ifeq ($(OS),FreeBSD) - install -m 755 httpdirfs \ + install -m 755 httpdirfs\ $(DESTDIR)$(prefix)/bin/httpdirfs gzip -f -k doc/man/httpdirfs.1 install -m 644 doc/man/httpdirfs.1.gz \ $(DESTDIR)$(prefix)/man/man1/httpdirfs.1.gz + install -m 755 sonicfs\ + $(DESTDIR)$(prefix)/bin/sonicfs + gzip -f -k doc/man/sonicfs.1 + install -m 644 doc/man/sonicfs.1.gz \ + $(DESTDIR)$(prefix)/man/man1/sonicfs.1.gz endif ifeq ($(OS),Darwin) install -d $(DESTDIR)$(prefix)/bin - install -m 755 httpdirfs \ + install -m 755 httpdirfs\ $(DESTDIR)$(prefix)/bin/httpdirfs + install -m 755 sonicfs\ + $(DESTDIR)$(prefix)/bin/sonicfs install -d $(DESTDIR)$(prefix)/share/man/man1 install -m 644 doc/man/httpdirfs.1 \ $(DESTDIR)$(prefix)/share/man/man1/httpdirfs.1 + install -m 644 doc/man/sonicfs.1 \ + $(DESTDIR)$(prefix)/share/man/man1/sonicfs.1 endif doc: doxygen Doxyfile +man: all + help2man --no-discard-stderr ./httpdirfs > doc/man/httpdirfs.1 + help2man --no-discard-stderr ./sonicfs > doc/man/sonicfs.1 + clean: -rm -f *.o - -rm -f httpdirfs - -rm -rf doc/html + -rm -f httpdirfs sonicfs distclean: clean + -rm -rf doc/html uninstall: -rm -f $(DESTDIR)$(prefix)/bin/httpdirfs + -rm -f $(DESTDIR)$(prefix)/bin/sonicfs ifeq ($(OS),Linux) -rm -f $(DESTDIR)$(prefix)/share/man/man1/httpdirfs.1 + -rm -f $(DESTDIR)$(prefix)/share/man/man1/sonicfs.1 endif ifeq ($(OS),FreeBSD) -rm -f $(DESTDIR)$(prefix)/man/man1/httpdirfs.1.gz + -rm -f $(DESTDIR)$(prefix)/man/man1/sonicfs.1.gz endif ifeq ($(OS),Darwin) -rm -f $(DESTDIR)$(prefix)/share/man/man1/httpdirfs.1 + -rm -f $(DESTDIR)$(prefix)/share/man/man1/sonicfs.1 endif depend: .depend @@ -82,4 +106,4 @@ depend: .depend $(CC) $(CFLAGS) -MM $^ -MF ./.depend; include .depend -.PHONY: all doc install clean distclean uninstall depend +.PHONY: all doc man install clean distclean uninstall depend diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..a074c3d --- /dev/null +++ b/TODO.md @@ -0,0 +1,6 @@ +## Todo +- [ ] Improve debug functions +- [ ] Automatic generation of man page with proper description +- [ ] Update change log +- [ ] Create a new release +- [ ] Contact maintainer for a new Debian package \ No newline at end of file diff --git a/src/fuse_local.c b/src/fuse_local.c index a427dac..0948897 100644 --- a/src/fuse_local.c +++ b/src/fuse_local.c @@ -113,14 +113,23 @@ static int fs_open(const char *path, struct fuse_file_info *fi) return 0; } -/** \brief read the directory indicated by the path*/ +/** + * \brief read the directory indicated by the path + * \note + * - releasedir() is not implemented, because I don't see why anybody want + * the LinkTables to be evicted from the memory during the runtime of this + * program. If you want to evict LinkTables, just unmount the filesystem. + * - There is no real need to associate the LinkTable with the fi of each + * directory data structure. If you want a deep level directory, you need to + * generate the LinkTables for previous level directories. We might + * as well maintain our own tree structure. + */ static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t dir_add, off_t offset, struct fuse_file_info *fi) { (void) offset; (void) fi; - Link *link; LinkTable *linktbl; if (!strcmp(path, "/")) { @@ -136,7 +145,7 @@ static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t dir_add, dir_add(buf, ".", NULL, 0); dir_add(buf, "..", NULL, 0); for (int i = 1; i < linktbl->num; i++) { - link = linktbl->links[i]; + Link *link = linktbl->links[i]; if (link->type != LINK_INVALID) { dir_add(buf, link->linkname, NULL, 0); } diff --git a/src/httpdirfs.c b/src/httpdirfs.c new file mode 100644 index 0000000..f6fa6f8 --- /dev/null +++ b/src/httpdirfs.c @@ -0,0 +1,6 @@ +#include "main.h" + +int main(int argc, char **argv) +{ + return common_main(&argc, &argv); +} \ No newline at end of file diff --git a/src/main.c b/src/main.c index 154f052..39a5a71 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,5 @@ +#include "main.h" + #include "cache.h" #include "fuse_local.h" #include "network.h" @@ -6,92 +8,7 @@ #include #include -void add_arg(char ***fuse_argv_ptr, int *fuse_argc, char *opt_string); -static void print_help(char *program_name, int long_help); -static void print_version(); -static void print_long_help(); -static int -parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc); -void parse_config_file(char ***argv, int *argc); - -static char *config_path = NULL; - -int main(int argc, char **argv) -{ - /* Automatically print help if not enough arguments are supplied */ - if (argc < 2) { - print_help(argv[0], 0); - fprintf(stderr, "For more information, run \"%s --help.\"\n", argv[0]); - exit(EXIT_FAILURE); - } - - /* These are passed into fuse initialiser */ - char **fuse_argv = NULL; - int fuse_argc = 0; - /* These are the combined argument with the config file */ - char **all_argv = NULL; - int all_argc = 0; - - /*--- Add the program's name to the combined argument list ---*/ - add_arg(&all_argv, &all_argc, argv[0]); - /*--- FUSE expects the first initialisation to be the program's name ---*/ - add_arg(&fuse_argv, &fuse_argc, argv[0]); - - /* initialise network configuration struct */ - Config_init(); - - /* initialise network subsystem */ - NetworkSystem_init(); - - /* Copy the command line argument list to the combined argument list */ - for (int i = 1; i < argc; i++) { - add_arg(&all_argv, &all_argc, argv[i]); - if (!strcmp(argv[i], "--config")) { - config_path = strdup(argv[i+1]); - } - } - - /* parse the config file, if it exists, store it in all_argv and all_argc */ - parse_config_file(&all_argv, &all_argc); - - /* parse the combined argument list */ - if (parse_arg_list(all_argc, all_argv, &fuse_argv, &fuse_argc)) { - /* - * The user basically didn't supply enough arguments, if we reach here - * The point is to print some error messages - */ - goto fuse_start; - } - - /*--- Add the last remaining argument, which is the mountpoint ---*/ - add_arg(&fuse_argv, &fuse_argc, argv[argc-1]); - - /* The second last remaining argument is the URL */ - char *base_url = argv[argc-2]; - if (strncmp(base_url, "http://", 7) && strncmp(base_url, "https://", 8)) { - fprintf(stderr, "Error: Please supply a valid URL.\n"); - print_help(argv[0], 0); - exit(EXIT_FAILURE); - } else { - if (CONFIG.sonic_username && CONFIG.sonic_password) { - CONFIG.sonic_mode = 1; - } else if (CONFIG.sonic_username || CONFIG.sonic_password) { - fprintf(stderr, - "Error: You have to supply both username and password to \ -activate Sonic mode.\n"); - exit(EXIT_FAILURE); - } - if(!LinkSystem_init(base_url)) { - fprintf(stderr, "Error: Network initialisation failed.\n"); - exit(EXIT_FAILURE); - } - } - - fuse_start: - fuse_local_init(fuse_argc, fuse_argv); - - return 0; -} +char *config_path = NULL; void parse_config_file(char ***argv, int *argc) { @@ -136,8 +53,7 @@ void parse_config_file(char ***argv, int *argc) } } -static int -parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc) +int parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc) { char c; int long_index = 0; @@ -267,10 +183,6 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc) return 0; } -/** - * \brief add an argument to an argv array - * \details This is basically how you add a string to an array of string - */ void add_arg(char ***fuse_argv_ptr, int *fuse_argc, char *opt_string) { (*fuse_argc)++; @@ -279,7 +191,7 @@ void add_arg(char ***fuse_argv_ptr, int *fuse_argc, char *opt_string) fuse_argv[*fuse_argc - 1] = strdup(opt_string); } -static void print_help(char *program_name, int long_help) +void print_help(char *program_name, int long_help) { fprintf(stderr, "usage: %s [options] URL mountpoint\n", program_name); @@ -288,19 +200,25 @@ static void print_help(char *program_name, int long_help) } } -static void print_version() +void print_version() { - fprintf(stderr, "HTTPDirFS version " VERSION "\n"); + char *fs_name; + if (!CONFIG.sonic_mode) { + fs_name = "HTTPDirFS"; + } else { + fs_name = "SonicFS"; + } + fprintf(stderr, "%s version " VERSION "\n", fs_name); /* --------- Print off SSL engine version --------- */ curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); fprintf(stderr, "libcurl SSL engine: %s\n", data->ssl_version); } -static void print_long_help() +void print_long_help() { fprintf(stderr, "\n\ -general options:\n\ +General options:\n\ --config Specify a configuration file \n\ -o opt,[opt...] Mount options\n\ -h --help Print help\n\ @@ -333,8 +251,17 @@ HTTPDirFS options:\n\ for HTTP range requests\n\ --insecure_tls Disable licurl TLS certificate verification by\n\ setting CURLOPT_SSL_VERIFYHOST to 0\n\ -\n\ - For mounting a Airsonic / Subsonic server:\n\ +\n"); + if (CONFIG.sonic_mode) { + print_sonic_help(); + } +} + +void print_sonic_help() +{ + fprintf(stderr, +"\n\ +Airsonic / Subsonic server specific options:\n\ --sonic-username The username for your Airsonic / Subsonic server\n\ --sonic-password The password for your Airsonic / Subsonic server\n\ --sonic-id3 Enable ID3 mode - this present the server content in\n\ @@ -344,3 +271,83 @@ HTTPDirFS options:\n\ scheme\n\ \n"); } + +int common_main(int *argc_in, char ***argv_in) +{ + int argc = *argc_in; + char **argv = *argv_in; + + /* Automatically print help if not enough arguments are supplied */ + if (argc < 2) { + print_help(argv[0], 0); + fprintf(stderr, "For more information, run \"%s --help.\"\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* These are passed into fuse initialiser */ + char **fuse_argv = NULL; + int fuse_argc = 0; + /* These are the combined argument with the config file */ + char **all_argv = NULL; + int all_argc = 0; + + /*--- Add the program's name to the combined argument list ---*/ + add_arg(&all_argv, &all_argc, argv[0]); + /*--- FUSE expects the first initialisation to be the program's name ---*/ + add_arg(&fuse_argv, &fuse_argc, argv[0]); + + /* initialise network configuration struct */ + Config_init(); + + /* initialise network subsystem */ + NetworkSystem_init(); + + /* Copy the command line argument list to the combined argument list */ + for (int i = 1; i < argc; i++) { + add_arg(&all_argv, &all_argc, argv[i]); + if (!strcmp(argv[i], "--config")) { + config_path = strdup(argv[i+1]); + } + } + + /* parse the config file, if it exists, store it in all_argv and all_argc */ + parse_config_file(&all_argv, &all_argc); + + /* parse the combined argument list */ + if (parse_arg_list(all_argc, all_argv, &fuse_argv, &fuse_argc)) { + /* + * The user basically didn't supply enough arguments, if we reach here + * The point is to print some error messages + */ + goto fuse_start; + } + + /*--- Add the last remaining argument, which is the mountpoint ---*/ + add_arg(&fuse_argv, &fuse_argc, argv[argc-1]); + + /* The second last remaining argument is the URL */ + char *base_url = argv[argc-2]; + if (strncmp(base_url, "http://", 7) && strncmp(base_url, "https://", 8)) { + fprintf(stderr, "Error: Please supply a valid URL.\n"); + print_help(argv[0], 0); + exit(EXIT_FAILURE); + } + + if (CONFIG.sonic_mode && + !(CONFIG.sonic_username && CONFIG.sonic_password)) { + fprintf(stderr, + "Error: You have to supply both username and password for your\ +Sonic server account.\n"); + exit(EXIT_FAILURE); + } + + if(!LinkSystem_init(base_url)) { + fprintf(stderr, "Error: Network initialisation failed.\n"); + exit(EXIT_FAILURE); + } + + fuse_start: + fuse_local_init(fuse_argc, fuse_argv); + + return 0; +} \ No newline at end of file diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..b7ae7a0 --- /dev/null +++ b/src/main.h @@ -0,0 +1,49 @@ +#ifndef MAIN_H +#define MAIN_H + +/** + * \brief Configuration path + */ +extern char *config_path; + +/** + * \brief Parse the configuration file + */ +void parse_config_file(char ***argv, int *argc); + +/** + * \brief Parse argument list + */ +int parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc); + +/** + * \brief Add an argument to an argv array + * \details This is basically how you add a string to an array of string + */ +void add_arg(char ***fuse_argv_ptr, int *fuse_argc, char *opt_string); + +/** + * \brief Print short help information + */ +void print_help(char *program_name, int long_help); + +/** + * \brief Print version number + */ +void print_version(); + +/** + * \brief Print long help information + */ +void print_long_help(); + +/** + * \brief Print Sonic server related help information + */ +void print_sonic_help(); + +/** + * @brief The old main function that is common to both HTTPDirFS and SonicFS + */ +int common_main(int *argc_in, char ***argv_in); +#endif \ No newline at end of file diff --git a/src/sonicfs.c b/src/sonicfs.c new file mode 100644 index 0000000..3e6eb70 --- /dev/null +++ b/src/sonicfs.c @@ -0,0 +1,9 @@ +#include "main.h" + +#include "util.h" + +int main(int argc, char **argv) +{ + CONFIG.sonic_mode = 1; + return common_main(&argc, &argv); +} \ No newline at end of file diff --git a/src/util.c b/src/util.c index f2141bd..2ee2046 100644 --- a/src/util.c +++ b/src/util.c @@ -86,8 +86,6 @@ void Config_init(void) CONFIG.max_segbc = DEFAULT_MAX_SEGBC; /*-------------- Sonic related -------------*/ - CONFIG.sonic_mode = 0; - CONFIG.sonic_username = NULL; CONFIG.sonic_password = NULL; diff --git a/src/util.h b/src/util.h index d7c7c15..9b15cc3 100644 --- a/src/util.h +++ b/src/util.h @@ -26,11 +26,6 @@ */ #define DEFAULT_USER_AGENT "HTTPDirFS-" VERSION - - - - - /** * \brief configuration data structure * \note The opening curly bracket should be at line 39, so the code belong