]> arthur.barton.de Git - netatalk.git/blobdiff - bin/afile/achfile.c
call readt with ONE_DELAY = 5 s
[netatalk.git] / bin / afile / achfile.c
index c03708ed40e6c9fc0617a860c76d85a67214d7ad..99133cc95d13b01037dbc97727b33323b4bc93e0 100644 (file)
 /*
- * Copyright 1998 The University of Newcastle upon Tyne
- * 
- * Permission to use, copy, modify and distribute this software and its
- * documentation for any purpose other than its commercial exploitation
- * is hereby granted without fee, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of The University of Newcastle upon Tyne not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. The University of
- * Newcastle upon Tyne makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- * 
- * THE UNIVERSITY OF NEWCASTLE UPON TYNE DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * NEWCASTLE UPON TYNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- * 
- * Author:  Gerry Tomlinson (gerry.tomlinson@newcastle.ac.uk)
- *          Computing Science Department, University of Newcastle upon Tyne, UK
- */
+ * $Id: achfile.c,v 1.7 2009-10-14 01:38:28 didg Exp $
+ *
+    afile - determine the MacOS creator/type of files
 
+    Copyright (C) 2001 Sebastian Rittau.
+    All rights reserved.
 
+    This file may be distributed and/or modfied under the terms of the
+    following license:
 
-/*
- *
- * program achfile
- *
- *
- * change creator/type of netatalk file
- *  
- * usage  achfile [-t type] [-c creator] file ....
- *
- * returns exit status 0 if all files changed successfully
- *
- * by gerry.tomlinson@newcastle.ac.uk 
- * last update 26/2/98
- *
- */
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. Neither the name of the author nor the names of its contributors
+       may be used to endorse or promote products derived from this software
+       without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
 
 #include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <strings.h>
+#include <string.h>
+#include <errno.h>
+
 #include <sys/types.h>
 #include <sys/stat.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
 
 #include <atalk/adouble.h>
 
-extern char *optarg;
-extern int optind, opterr;
+#include "common.h"
 
-#define AD  ".AppleDouble"
+/* Global Variables */
+static const char *type    = NULL;
+static const char *creator = NULL;
 
 
-main(int argc, char *argv[])
+/* Print usage information. */
+static void usage(char *prog)
+{
+  fprintf(stderr, "Usage: %s [-t TYPE] [-c CREATOR] FILE ...\n", prog);
+}
 
+/* Print extensive help. */
+static void help(char *prog)
 {
-    int fdata, fres;
-    struct stat statbuf;
-    int n,i;
-    char rbuf [AD_DATASZ];
-    struct adouble  *ad = (struct adouble*)&rbuf;
-    char *dname;
-    char *rname;
-    char *slash;
-    char c;
-    char *type = 0;
-    char *creator = 0;
-    char *p;
-    int errflag = 0;
-    int status = 0;
-
-    while ((c = getopt(argc, argv, "t:c:")) != -1)
-    switch (c) {
-       case 't':
-               type = optarg;
-               if (strlen(type) != 4)
-                   {fprintf(stderr,"achfile: bad type length\n");exit(1);}
-               break;
-       case 'c':
-               creator = optarg; 
-               if (strlen(creator) != 4)
-                   {fprintf(stderr,"achfile: bad creator length\n");exit(1);}
-               break;
-       case '?' :
-               errflag = 1; break;
+  usage(prog);
+  fprintf(stderr,
+         "\n"
+         "Change the MacOS creator/type of FILEs.\n"
+         "\n"
+         "  -t, --type=TYPE        choose type\n"
+         "  -c, --creator=CREATOR  choose creator\n"
+         "  -h, --help             show this help and exit\n"
+         "  -v, --version          show version information and exit\n");
+}
+
+/* Print the version. */
+static void version(void)
+{
+  fprintf(stderr, "achfile (netatalk " VERSION ")\n");
+}
+
+/* Argument Handling
+ * known options: -t, -c, -h, -v
+ * known long options: --help, --version
+ */
+#define OPTSTRING "t:c:hv-:"
+static const char *get_long_arg(int argc, char *argv[], const char *arg, const char *oa) {
+  switch (*oa) {
+  case '=':
+    return &oa[1];
+  case '\0':
+    if (optind == argc) {
+      fprintf(stderr, "%s: option \'%s\' requires an argument\n", argv[0], arg);
+      return NULL;
     }
+    return argv[optind++];
+  default:
+    fprintf(stderr, "%s: unrecognized option \'%s\'\n", argv[0], arg);
+    usage(argv[0]);
+    return NULL;
+  }
+}
+
+static int parse_args(int argc, char *argv[])
+{
+  int c;
+  const char *longarg;
 
-    if (errflag ||  argc == optind || (!type && !creator) ) 
-               {fprintf(stderr,"usage: achfile [-t type] [-c creator]  file ...\n");exit(1);}
-
-    
-    for (; optind < argc; optind++) {
-        close (fdata);
-        close (fres);
-
-       dname = argv[optind];
-
-        if ((fdata = open(dname,O_RDONLY,0)) == -1)
-           {fprintf(stderr,"achfile: can't open %s\n",dname); status = 2; continue;}
-       fstat(fdata, &statbuf);
-        if (S_ISDIR(statbuf.st_mode)) 
-           {status = 2; continue;}
-       
-       rname = calloc(strlen(dname)+strlen(AD)+2, 1);
-       slash = rindex(dname,'/');
-       strncpy(rname,dname,slash ? slash + 1 - dname : 0);
-       strcat(rname,AD);
-       strcat(rname,"/");
-       strcat(rname,slash ? slash+1 : dname);
-       
-       if ((fres = open(rname, O_RDWR,0)) == -1)
-           {fprintf(stderr, "can't open %s\n",rname); status = 2; continue;}
-       if ( read(fres,rbuf,AD_DATASZ)  != AD_DATASZ)
-           {fprintf(stderr,"can't read %s\n",rname); status = 2; continue;}
-       if  (ad->ad_magic != AD_MAGIC) 
-           {fprintf(stderr,"bad MAGIC in %s\n",rname); status = 2 ; continue;}
-       if (type) 
-           for (i=0,p=type;i<4;i++) *(rbuf + ADEDOFF_FINDERI +i) = *p++;
-       if (creator)
-           for (i=0,p=creator;i<4;i++) *(rbuf + ADEDOFF_FINDERI +4 +i) = *p++;
-       lseek(fres,0,0);
-       if (write(fres,rbuf,AD_DATASZ)  != AD_DATASZ)
-           {fprintf(stderr,"can't update %s\n",rname); status = 3; continue;}
-       
+  /* iterate through the command line */
+  while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
+    switch (c) {
+    case 'h':
+      help(argv[0]);
+      exit(0);
+    case 'v':
+      version();
+      exit(0);
+    case 't':
+      type = optarg;
+      break;
+    case 'c':
+      creator = optarg;
+      break;
+    case '-':
+      if (strcmp(optarg, "help") == 0) {
+       help(argv[0]);
+       exit(0);
+      }
+      if (strcmp(optarg, "version") == 0) {
+       version();
+       exit(0);
+      }
+      if (strncmp(optarg, "type", 4) == 0) {
+       longarg = get_long_arg(argc, argv, "type", &optarg[4]);
+       if (!longarg)
+         return -1;
+       type = longarg;
+      } else if (strncmp(optarg, "creator", 7) == 0) {
+       longarg = get_long_arg(argc, argv, "creator", &optarg[7]);
+       if (!longarg)
+         return -1;
+       creator = longarg;
+      }
+      break;
+    default:
+      usage(argv[0]);
+      return -1;
     }
-    exit (0);
+  }
+
+  /* At least one file argument is required. */
+  if (argc == optind) {
+    usage(argv[0]);
+    return -1;
+  }
+
+  /* Either type or creator is required. */
+  if (!type && !creator) {
+    fprintf(stderr, "achfile: either type or creator must be specified\n");
+    return -1;
+  }
+
+  /* Type and creator must be exactly four characters long. */
+  if ((type && strlen(type) != 4) || (creator && strlen(creator) != 4)) {
+    fprintf(stderr, "achfile: type and creator must be four character IDs\n");
+    return -1;
+  }
+
+  return 0;
+}
+
+
+/* Change the owner/creator of each file specified on the command line. */
+static int handle_file(const char *filename)
+{
+  int fd;
+  struct stat statbuf;
+  char *adname;
+  ssize_t sz;
+  char buf[AD_DATASZ];
+  struct adouble *ad = (struct adouble *) &buf;
+
+  if (stat(filename, &statbuf) == -1) {
+    fprintf(stderr, "achfile:%s: %s\n", filename, strerror(errno));
+    return -1;
+  }
+
+  adname = dataname_to_adname(filename);
+  fd = open(adname, O_RDWR, 0);
+  if (fd == -1) {
+    if (errno == ENOENT)
+      fprintf(stderr, "achfile:%s: no resource fork\n", filename);
+    else
+      fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
+    free(adname);
+    return -1;
+  }
+  sz = read(fd, buf, AD_DATASZ);
+  if (sz == -1) {
+    fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
+    free(adname);
+    close(fd);
+    return -1;
+  } else if (sz < AD_DATASZ) {
+    fprintf(stderr, "achfile:%s: corrupt resource fork\n", filename);
+    free(adname);
+    close(fd);
+    return -1;
+  }
+  if ( ntohl(ad->ad_magic) != AD_MAGIC) {
+    fprintf(stderr, "achfile:%s: corrupt resource fork\n", filename);
+    free(adname);
+    close(fd);
+    return -1;
+  }
+
+  /* Change Type */
+  if (type) {
+    buf[ADEDOFF_FINDERI + 0] = type[0];
+    buf[ADEDOFF_FINDERI + 1] = type[1];
+    buf[ADEDOFF_FINDERI + 2] = type[2];
+    buf[ADEDOFF_FINDERI + 3] = type[3];
+ }
+
+  /* Change Creator */
+  if (creator) {
+    buf[ADEDOFF_FINDERI + 4] = creator[0];
+    buf[ADEDOFF_FINDERI + 5] = creator[1];
+    buf[ADEDOFF_FINDERI + 6] = creator[2];
+    buf[ADEDOFF_FINDERI + 7] = creator[3];
+ }
+
+  /* Write file back to disk. */
+  if (lseek(fd, 0, SEEK_SET) == -1) {
+    fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
+    free(adname);
+    close(fd);
+    return -1;
+  }
+  if (write(fd, &buf, AD_DATASZ) < AD_DATASZ) {
+    fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
+    free(adname);
+    close(fd);
+    return -1;
+  }
+
+  /* Clean Up */
+  free(adname);
+  close(fd);
+
+  return 0;
 }
 
-/* end of program achfile */
+
+int main(int argc, char *argv[])
+{
+  /* argument handling */
+  if (parse_args(argc, argv) == -1)
+    return 1;
+
+  while (optind < argc)
+    handle_file(argv[optind++]);
+
+  return 0;
+}