bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

multiple firmlinks


From: James A Morrison
Subject: multiple firmlinks
Date: Sat, 9 Mar 2002 17:50:52 -0500 (EST)

Hi,

  This firmlink patch should conform to the GCS, and the time mode works
nicely.  

2002-03-09  James A. Morrison <ja2morri@uwaterloo.ca>

        * firmlink.c: Added the functionality for multiple targets decided
        on by a command line option choosing randomly, sequencially, or
        based on the date/time.
 
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  9 Mar 2002 21:41:03 -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 <miles@gnu.ai.mit.edu>
+   Extended by James A. Morrison <ja2morri@uwaterloo.ca>
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -26,42 +27,91 @@
 #include <fcntl.h>
 #include <argp.h>
 #include <error.h>
+#include <time.h>
 #include <sys/mman.h>
 
 #include <hurd/trivfs.h>
 
 #include <version.h>
 
+#define TIME_MODE 0
+#define RANDOM_MODE 1
+#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 doc[] = "A translator for firmlinks."
+static const char args_doc[] = "[file1 file2 ...]";
+static const char doc[] = "A translator for multiple firmlinks."
 "\vA firmlink is sort of half-way between a symbolic link and a hard link:"
 "\n"
 "\nLike a symbolic link, it is `by name', and contains no actual reference to"
 " the target.  However, the lookup returns a node which will redirect parent"
 " lookups so that attempts to find the cwd that go through the link will"
 " reflect the link name, not the target name.  The target referenced by the"
-" firmlink is looked up in the namespace of the translator, not the client.";
+" firmlink is looked up in the namespace of the translator, not the client."
+" A multiple firmlink can point to more than one file, and can also create"
+" files based on dates.";
 
 /* 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
-    return ARGP_ERR_UNKNOWN;
+  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 +124,16 @@
   mach_port_t bootstrap;
   struct trivfs_control *fsys;
 
+  config.size = 0;
+  config.type = RANDOM_MODE;
+  config.args = (char**) malloc (argc);
+  if (! config.args)
+    error (ENOMEM, 1, "Starting up");
+
   /* 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 +160,26 @@
 {
   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 ( target == MACH_PORT_NULL    /* did the lookup fail? */
+       && config.type == TIME_MODE /* Are we in a mode to create files? */
+       && errno == ENOENT )   /* Did we fail because the file doesn't exist */
+    {
+      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 +208,48 @@
 
 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 +261,14 @@
         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 +292,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 +340,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 +352,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 +377,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;
 }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]