]> arthur.barton.de Git - netatalk.git/blobdiff - bin/afile/afile.c
Enhanced machine type
[netatalk.git] / bin / afile / afile.c
index a8d93bb48e256e5376ae775e0489cd74bba2d1b5..e70c850090675c6013b37ef0c3c8245490ffff35 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
- */
-
-/*
- *
- * program afile
- *
- *
- * show creator/type of netatalk file
- *  
- * usage  afile [-a] file ....
- * 
- * looks for MAGIC at start to see if an AppleDouble else assumes it's a
- * data fork and only reports if corresponding  .AppleDouble exists unless -a option set
- * in which case report unknown if not a directory (does not look for
- * extension mappings)
- *
- * returns exit status 0 if all files have corresponding readable  valid .AppleDouble or data fork
- *
- * if both parts of file don't exist in correct form it returns (for last file): 
- *
- *     1  file doesn't exist
- *     2  file is unreadable
- *     3  file is directory
- *     4  file is AppleDouble without data fork
- *      5  file is AppleDouble with unreadable data fork
- *     6  file is data fork without AppleDouble
- *     7  file is data fork with unreadable AppleDouble
- *     8  file is data for with short  AppleDouble
- *     9  bad magic in AppleDouble
- *     99  bad command line options
- *     
- * by gerry.tomlinson@ncl.ac.uk
- * last update 26/2/98
+ * $Id: afile.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:
+
+    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 <netinet/in.h>
 #include <sys/stat.h>
-
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
 
 #include <atalk/adouble.h>
 
+#include "common.h"
+
+/* Possible return types. These are taken from the original afile for
+ * compatibility.
+ */
+#define RET_OK                0 /* everything went fine */
+#define RET_NO_SUCH_FILE      1 /* file doesn't exist */
+#define RET_UNREADABLE        2 /* file is unreadable */
+#define RET_IS_DIR            3 /* file is a directory */
+#define RET_NO_DF             4 /* there is no corresponding data fork */
+#define RET_INVALID_DF        5 /* data fork exists but can't be read */
+#define RET_NO_AD             6 /* AppleDouble file doesn't exist */
+#define RET_INVALID_AD        7 /* AppleDouble file exists but can't be read */
+#define RET_SHORT_AD          8 /* AppleDouble file is too short */
+#define RET_BAD_MAGIC         9 /* AppleDouble file has a bad magic value */
+#define RET_BAD_ARGS         99 /* bad command line options */
+
+
+/* Global Variables */
+static int showall = 0;
 
-extern char *optarg;
-extern int optind, opterr;
 
-#define AD  ".AppleDouble"
+/* Print usage information. */
+static void usage(char *prog)
+{
+  fprintf(stderr, "Usage: %s [-a] FILE ...\n", prog);
+}
+
+/* Print extensive help. */
+static void help(char *prog)
+{
+  usage(prog);
+  fprintf(stderr,
+         "\n"
+         "Determine the MacOS creator/type of FILEs.\n"
+         "\n"
+         "  -a, --show-all    also show unknown files and directories\n"
+         "  -h, --help        show this help and exit\n"
+         "  -v, --version     show version information and exit\n");
+}
 
-main(int argc, char *argv[])
+/* Print the version. */
+static void version(void)
+{
+  fprintf(stderr, "afile (netatalk " VERSION ")\n");
+}
 
+/* Argument Handling
+ * known options: -a, -h, -v
+ * known long options: --show-all, --help, --version
+ */
+#define OPTSTRING "ahv-:"
+static int parse_args(int argc, char *argv[])
 {
-    int fdata, fres;
-    struct stat statbuf;
-    int n,i;
-    char adbuf [AD_DATASZ];
-    struct adouble  *ad;
-    int datafork;
-    char *dname;
-    char *rname;
-    mode_t dmode;
-    mode_t rmode;
-    char *slash;
-    char c;
-    char *type = 0;
-    char *creator = 0;
-    char *p;
-    int errflag = 0;
-    int aflag = 0;
-    int status = 0;
-    int gotdata;
-
-    while ((c = getopt(argc, argv, "a")) != -1)
+  int c;
+
+  /* iterate through the command line */
+  while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
     switch (c) {
-       case 'a':
-               aflag = 1; break;
-       case '?' :
-               errflag = 1; break;
+    case 'h':
+      help(argv[0]);
+      exit(0);
+    case 'v':
+      version();
+      exit(0);
+    case 'a':
+      showall = 1;
+      break;
+    case '-':
+      if (strcmp(optarg, "help") == 0) {
+       help(argv[0]);
+       exit(0);
+      }
+      if (strcmp(optarg, "version") == 0) {
+       version();
+       exit(0);
+      }
+      if (strcmp(optarg, "show-all") == 0)
+       showall = 1;
+      break;
+    default:
+      usage(argv[0]);
+      return -1;
     }
+  }
 
-    if (errflag ||  argc == optind) { 
-         fprintf(stderr,"usage: afile [-a] file ...\n");
-          exit(99);
-    }
+  /* At least one file argument is required. */
+  if (argc == optind) {
+    usage(argv[0]);
+    return -1;
+  }
+
+  return 0;
+}
 
-    
-    for (; optind < argc; optind++) {
-        close (fdata);
-        close (fres);
-
-       dname = argv[optind];
-       rname = 0;
-       datafork = 1;   /* assume file is a data fork */
-       gotdata = 1;    /* assume data fork ok */
-
-       if (stat(dname, &statbuf)) {
-           fprintf(stderr,"afile: %s does not exist\n",dname);
-           status = 1;
-           continue;
-       }
-
-        if ((fdata = open(dname,O_RDONLY,0)) == -1) {
-           fprintf(stderr,"afile: cannot open %s\n",dname);
-           status = 2;
-            continue;
-       }
-        
-       fstat(fdata, &statbuf);
-        if (S_ISDIR(statbuf.st_mode)) { 
-            if (aflag) 
-                 printf("directory %s\n",dname);
-            status = 3; 
-            continue;
-       }
-       
-       if ( read(fdata,adbuf,AD_DATASZ)  == AD_DATASZ) {
-            ad = (struct adouble*)adbuf;
-           if  (ad->ad_magic == ntohl(AD_MAGIC)) {  /*  AppleDouble Header */
-               datafork = 0;
-               rmode = statbuf.st_mode;
-               rname = dname;
-               dname = calloc(strlen(rname)+4,1);
-               slash = rindex(rname,'/');
-               if (!slash) {
-                   strcpy(dname,"../");
-                   strcat(dname,rname);
-               }
-               else {
-                   strncpy(dname, rname, slash + 1 - rname);
-                   strcat(dname,"../");
-                   strcat(dname,slash+1);
-               }
-               if (stat(dname, &statbuf)) {
-                   status = 4;         /* data fork doesn't exist */
-                   gotdata = 0;                    
-               } else if ((fdata = open(dname,O_RDONLY,0)) == -1) {        
-                   status = 5;         /* can't open data fork for reading */
-                   gotdata = 0;
-               }
-               dmode = statbuf.st_mode;               
-           }    
-        }
-
-       if (datafork)   {
-           dmode = statbuf.st_mode;
-           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 (stat(rname, &statbuf)) {
-               if (aflag)
-                    printf("unknown %s\n",dname); 
-               else
-                   status = 6;
-               continue;
-           }
-           rmode = statbuf.st_mode;
-           if ((fres = open(rname, O_RDONLY,0)) == -1) {
-                   fprintf(stderr,"afile: cannot read   %s\n",rname);
-               status = 7;
-               continue;
-            }
-           if (read(fres,adbuf,AD_DATASZ)  != AD_DATASZ) {
-                fprintf(stderr,"afile: %s too small\n",rname);
-                status = 8;
-                continue;
-           }
-         
-           ad = (struct adouble*)adbuf;
-       }
-       
-       if  (ad->ad_magic != ntohl(AD_MAGIC)) {
-           fprintf(stderr,"afile: bad MAGIC in %s\n",rname);
-           status = 9;
-           continue;
-       }
-
-       printf("%4.4s %4.4s %s\n",adbuf+ADEDOFF_FINDERI, adbuf+ADEDOFF_FINDERI+4, 
-               datafork ? dname : rname);
-
-       if (!gotdata) {
-           if (status == 4)
-               fprintf(stderr,"afile: %s does not exist\n",dname);                        
-           if (status == 5)         
-               fprintf(stderr,"afile: cannot read %s\n",dname);
-       } else if (dmode != rmode) {
-           fprintf(stderr,"afile: %s mode does not match\n",datafork ? rname : dname);
-           status = 0;
-       } 
 
+/* Print the creator/type as taken from the supplied character stream, which
+ * must be a AppleDouble file header.
+ */
+static void print_type(const char *filename, const char *creator, const char *type)
+{
+  printf("%4.4s %4.4s %s\n", creator, type, filename);
+}
+
+
+static int handle_ad(struct AFile *rfile)
+{
+  int fd;
+  char *dataname;
+
+  dataname = adname_to_dataname(afile_filename(rfile));
+
+  /* Try to open data file. */
+  fd = open(dataname, O_RDONLY);
+  free(dataname);
+  if (fd == -1) {
+    if (errno == ENOENT)
+      return RET_NO_DF;      /* There is no data fork. */
+    else
+      return RET_INVALID_DF; /* The data fork can't be read. */
+  }
+  /* FIXME: stat */
+
+  close(fd);
+
+  return RET_OK;
+}
+
+
+static int handle_datafile(struct AFile *datafile)
+{
+  int ret;
+  char *adname;
+  struct AFile *rfile;
+
+  /* Try to load AppleDouble file. */
+  adname = dataname_to_adname(afile_filename(datafile));
+  rfile = afile_new(adname);
+  if (!rfile) {
+    if (errno == ENOENT) {
+      free(adname);
+      if (showall)
+       printf("unknown %s\n", afile_filename(datafile));
+      return RET_NO_AD;
     }
-    exit (status);
+    fprintf(stderr, "afile:%s: %s\n", adname, strerror(errno));
+    free(adname);
+    return RET_INVALID_AD;
+  }
+  free(adname);
+
+  /* Check if this is really an AppleDouble file. */
+  if (afile_is_ad(rfile)) {
+    print_type(afile_filename(datafile),
+              afile_creator(rfile), afile_type(rfile));
+    if (afile_mode(datafile) != afile_mode(rfile))
+      fprintf(stderr, "afile:%s: mode does not match", afile_filename(datafile));
+    ret = RET_OK;
+  } else
+    ret = RET_INVALID_AD;
+
+  afile_delete(rfile);
+
+  return ret;
+}
+
+
+/* Parse a file and its resource fork. Output the file's creator/type. */
+static int parse_file(char *filename)
+{
+  int ret;
+  struct AFile *afile;
+
+  afile = afile_new(filename);
+  if (!afile) {
+    fprintf(stderr, "afile:%s: %s\n", filename, strerror(errno));
+    return errno == ENOENT ? RET_NO_SUCH_FILE : RET_UNREADABLE;
+  }
+
+  if (afile_is_dir(afile)) {
+    if (showall)
+      printf("directory %s\n", filename);
+    ret = RET_IS_DIR;
+  } else if (afile_is_ad(afile))
+    ret = handle_ad(afile);
+  else
+    ret = handle_datafile(afile);
+
+  afile_delete(afile);
+
+  return ret;
 }
 
-/* end of program afile */
+
+int main(int argc, char *argv[])
+{
+  int ret = RET_OK;
+
+  /* argument handling */
+  if (parse_args(argc, argv) == -1)
+    return RET_BAD_ARGS;
+
+  /* iterate through all files specified as arguments */
+  while (optind < argc)
+    ret = parse_file(argv[optind++]);
+
+  return ret;
+}