Hi, here is my lastest multiple firmlink translator, as a patch to the official firmlink source. This is also available from http://hurd.dyndns.org/tarballs/filemux-0.2.0.tar.gz
The old invocation of firmlink still works the same, but directly reading a firmlink has changed. 2002-02-24 James A. Morrison <[EMAIL PROTECTED]> * firmlink.c: Added support for multiple targets by choice of date format, random selection, or sequencial selection Index: firmlink.c =================================================================== RCS file: /cvsroot/hurd/hurd/trans/firmlink.c,v retrieving revision 1.12 diff -u -r1.12 firmlink.c --- firmlink.c 26 Feb 2001 04:16:01 -0000 1.12 +++ firmlink.c 24 Feb 2002 16:39:54 -0000 @@ -1,8 +1,9 @@ /* A translator for `firmlinks' - Copyright (C) 1997, 1998, 1999, 2001 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999, 2001, 2002 Free Software Foundation, Inc. Written by Miles Bader <[EMAIL PROTECTED]> + Extended by James A. Morrison <[EMAIL PROTECTED]> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -26,20 +27,29 @@ #include <fcntl.h> #include <argp.h> #include <error.h> +#include <time.h> #include <sys/mman.h> #include <hurd/trivfs.h> -#include <version.h> +#include <version.h> + +#define RANDOM_MODE 1 +#define TIME_MODE 0 +#define SEQUENCE_MODE 2 const char *argp_program_version = STANDARD_HURD_VERSION (firmlink); static const struct argp_option options[] = { + {"randomized", 'r', NULL, 0, "Randomize selection of files, default" }, + {"sequencial", 's', NULL, 0, "Choose files sequencially" }, + {"format",'f',"DATE FORMAT", 0, + "Create files named file1/file2.DATE FORMAT"}, { 0 } }; -static const char args_doc[] = "TARGET"; +static const char args_doc[] = "[file1 file2 ...]"; static const char doc[] = "A translator for firmlinks." "\vA firmlink is sort of half-way between a symbolic link and a hard link:" "\n" @@ -50,18 +60,54 @@ " firmlink is looked up in the namespace of the translator, not the client."; /* Link parameters. */ -static char *target = 0; /* What we translate too. */ + +struct arg_struct { + char **args; + char *date_format; + int type; + int flags; + unsigned long lastused; + unsigned long size; +}; + +struct arg_struct config; /* Parse a single option/argument. */ static error_t parse_opt (int key, char *arg, struct argp_state *state) { - if (key == ARGP_KEY_ARG && state->arg_num == 0) - target = arg; - else if (key == ARGP_KEY_ARG || key == ARGP_KEY_NO_ARGS) - argp_usage (state); - else + struct arg_struct *arguments = state->input; + + switch (key) { + case 'r': + arguments->type = RANDOM_MODE; + arguments->flags = O_CREAT; + break; + case 's': + arguments->type = SEQUENCE_MODE; + arguments->flags = O_CREAT; + arguments->lastused = 0; + break; + case 'f': + arguments->type = TIME_MODE; + arguments->date_format = arg; + arguments->flags = 0; + break; + case ARGP_KEY_ARG: + arguments->args[arguments->size] = arg; + arguments->size++; + break; + case ARGP_KEY_END: + if ( arguments->type == TIME_MODE && arguments->size != 2 ) + argp_usage(state); + break; + case ARGP_KEY_NO_ARGS: + argp_usage(state); + break; + default: return ARGP_ERR_UNKNOWN; + } + return 0; } @@ -74,8 +120,12 @@ mach_port_t bootstrap; struct trivfs_control *fsys; + config.size = 0; + config.type = RANDOM_MODE; + config.args = (char**)malloc(argc); /* Parse our options... */ - argp_parse (&argp, argc, argv, 0, 0, 0); + argp_parse (&argp, argc, argv, 0, 0, &config); + if ( config.type == RANDOM_MODE ) srand(time(NULL)); task_get_bootstrap_port (mach_task_self (), &bootstrap); if (bootstrap == MACH_PORT_NULL) @@ -102,7 +152,21 @@ { error_t err; file_t authed_link; - file_t target = file_name_lookup (target_name, flags & ~O_CREAT, 0); + file_t target = file_name_lookup (target_name, flags & ~config.flags, 0); + + /* if the file doesn't exist for TIME_MODE, create it */ + if ( config.type == TIME_MODE && errno == ENOENT ) { + file_t file; + char *filename; + file_t dir = file_name_split(target_name, &filename); + if (dir == MACH_PORT_NULL) + return errno; + dir_mkfile(dir, flags, 0666 & ~getumask() , &file); + dir_link(dir,file,filename,0); + + target = file; + mach_port_deallocate(mach_task_self(), dir); + } if (target == MACH_PORT_NULL) return errno; @@ -131,6 +195,40 @@ int trivfs_allow_open = O_READ; +/* choose a filename based on arguments->type and arguments->args. + The returned string is allocated within choose_filename and must + by the caller of choose_filename. + + On error NULL is returned and errno is set appropriatly. +*/ +char* choose_filename(struct arg_struct *arguments) { + + char *target; + if ( arguments->type == TIME_MODE ) { + char buf[256]; + time_t curtime; + struct tm loctime; + error_t err; + + curtime = time(NULL); + localtime_r(&curtime, &loctime); + if ( !strftime(buf, 256, arguments->date_format, &loctime) ) + error(errno, errno, "formatting time"); + err = asprintf(&target, "%s/%s.%s", arguments->args[0], arguments->args[1], + buf); + if ( err < 0 ) target = NULL; + } + + if ( arguments->type == SEQUENCE_MODE ) { + target = strdup(arguments->args[arguments->lastused % arguments->size]); + if ( target ) arguments->lastused++; + } + + if ( arguments->type == RANDOM_MODE ) { + target = strdup(arguments->args[rand() % arguments->size]); + } + return target; +} /* Return the root node of our file system: A firmlink to TARGET, unless TARGET doesn't exist, in which case we return a symlink-like node. */ static error_t @@ -142,7 +240,13 @@ retry_type *do_retry, char *retry_name, mach_port_t *node, mach_msg_type_name_t *node_type) { - error_t err = firmlink (dotdot, target, flags, node); + + error_t err; + char *target = choose_filename(&config); + if ( target == NULL ) return errno; + + err = firmlink (dotdot, target, flags, node); + free(target); if (err == ENOENT) /* No target? Act like a link. */ @@ -166,7 +270,7 @@ void trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) { - st->st_size = strlen (target); + st->st_size = config.size; /* strlen (target); */ st->st_blocks = 0; st->st_mode &= ~S_IFMT; st->st_mode |= S_IFLNK; @@ -214,7 +318,7 @@ err = EBADF; else { - off_t max = strlen (target); + off_t max = config.size; /* strlen (target); */ off_t start = offs >= 0 ? offs : (off_t)cred->po->hook; if (start < 0) return EINVAL; @@ -226,7 +330,7 @@ err = (*data == -1) ? errno : 0; if (!err && amount > 0) { - memcpy ((char *)(*data + start), target, amount); + memcpy ((char *)(*data + start), config.args, amount); if (offs < 0) cred->po->hook = (void *)(start + amount); /* Update PO offset. */ } @@ -251,7 +355,7 @@ else if ((off_t)cred->po->hook < 0) return EINVAL; else - *amount = strlen (target) - (off_t)cred->po->hook; + *amount = config.size - (off_t)cred->po->hook; return 0; } _______________________________________________ Bug-hurd mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/bug-hurd