/*
 * This file is modified from the src described below by Maorong Zou
 *
 * file - find type of a file or files - main program.
 *
 * Copyright (c) Ian F. Darwin, 1987.
 * Written by Ian F. Darwin.
 *
 * This software is not subject to any license of the American Telephone
 * and Telegraph Company or of the Regents of the University of California.
 *
 * Permission is granted to anyone to use this software for any purpose on
 * any computer system, and to alter it and redistribute it freely, subject
 * to the following restrictions:
 *
 * 1. The author is not responsible for the consequences of use of this
 *    software, no matter how awful, even if they arise from flaws in it.
 *
 * 2. The origin of this software must not be misrepresented, either by
 *    explicit claim or by omission.  Since few users ever read sources,
 *    credits must appear in the documentation.
 *
 * 3. Altered versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.  Since few users
 *    ever read sources, credits must appear in the documentation.
 *
 * 4. This notice may not be removed or altered.
 */
#ifndef	lint
static char *moduleid = 
	"@(#)$Id: file.c,v 1.38 1997/01/15 19:28:35 christos Exp $";
#endif	/* lint */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>	/* for open() */
#if (__COHERENT__ >= 0x420)
# include <sys/utime.h>
#else
# ifdef USE_UTIMES
#  include <sys/time.h>
# else
#  include <utime.h>
# endif
#endif
#include <unistd.h>	/* for read() */

#define __FILE_C__
#include "file.h"

#ifndef MAGIC
# define MAGIC "/etc/ezfmMagic:ezfmMagic"
#endif

int 			/* Global command-line options 		*/
	debug = 0, 	/* debugging 				*/
	lflag = 0,	/* follow Symlinks (BSD only) 		*/
	zflag = 0;	/* follow (uncompress) compressed files */

int			/* Misc globals				*/
	nmagic = 0;	/* number of valid magic[]s 		*/

struct  magic *magic;	/* array of magic entries		*/

char *progname;		/* used throughout 			*/
char *magicfile;	/* where magic be found 		*/
int lineno;		/* line number in the magic file	*/


/*
 * main - parse arguments and handle options
 */
int ProcessMagicFile(file)
     char *file;
{
  if(!(magicfile = getenv("EZFMMAGIC")))
    if((magicfile = file) == NULL)
      magicfile = MAGIC;
  return(apprentice(magicfile, 0));
}

/*
 * process - process input file
 */
void process(inname, wid)
     const char	*inname;
     int wid;
{
  int	ret, fd = 0;
  unsigned char	buf[HOWMANY+1];	/* one extra for terminating '\0' */
  struct stat	sb;
  int nbytes = 0;	/* number of bytes read from a datafile */
  char match = '\0';

  file_type_info = NULL;
  /*
   * first try judging the file based on its filesystem status
   */
  ret = fsmagic(inname, &sb);
  if( ret != 0)  return;
  if((fd = open(inname, O_RDONLY)) < 0) 
    {
      int w = sb.st_mode & 0002;
      int e = sb.st_mode & 0111;
      if(w | e)
	{
	  if(w && e) file_type_info = specialMagicTb[M_SPECIAL_F][L_W_E_ONLY].desc;
	  else if(w) file_type_info = specialMagicTb[M_SPECIAL_F][L_WRITE_ONLY].desc;
	  else file_type_info = specialMagicTb[M_SPECIAL_F][L_EXEC_ONLY].desc;
	  return;
	}
      file_type_info = specialMagicTb[M_SPECIAL_F][L_UNKNOWN].desc;
      return;
    }
	    
  /*
   * try looking at the first HOWMANY bytes
   */
  if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) 
    {
      file_type_info = specialMagicTb[M_SPECIAL_F][L_UNKNOWN].desc;
      close(fd);
      return;      
    }
  if(nbytes == 0)
    {
      file_type_info = specialMagicTb[M_SPECIAL_F][L_EMPTY].desc;      
      close(fd);
      return;
    }
  else 
    {
      buf[nbytes++] = '\0';	/* null-terminate it */
      match = tryit(buf, nbytes, 0);
    }

#ifdef RESTORE_TIME
  /*
   * Try to restore access, modification times if read it.
   */
  {
# ifdef USE_UTIMES
    struct timeval  utsbuf[2];
    utsbuf[0].tv_sec = sb.st_atime;
    utsbuf[1].tv_sec = sb.st_mtime;
    
    (void) utimes(inname, utsbuf); /* don't care if loses */
# else
    struct utimbuf  utbuf;
    
    utbuf.actime = sb.st_atime;
    utbuf.modtime = sb.st_mtime;
    (void) utime(inname, &utbuf); /* don't care if loses */
# endif
  }
#endif
  (void) close(fd);
}

int tryit(buf, nb, zflag)
     unsigned char *buf;
     int nb, zflag;
{
  int ret;

  /* try tests in /etc/magic (or surrogate magic file) */
  ret = softmagic(buf, nb);
  /* printf("\tsoft= %d\n",ret); */
  if(ret > 0) 
    {
      int i = 0, cnt = 0;
      char *ptr = file_type_info;
      while( *ptr && i < 127 && cnt < 6)
	{
	  if(*ptr == ':') cnt++;
	  ptr++;
	}
      if(cnt == 6)  return(ret);
    }

  /* try known keywords, check whether it is ASCII */
  ret = ascmagic(buf, nb);
  /* printf("\tascii= %d\n",ret); */
  if(ret > 0) return(ret);

  /* abandon hope, all ye who remain here */
  file_type_info = specialMagicTb[M_SPECIAL_F][L_DATA].desc;

  return(0);
}


char *GetSpecFromMagic(file) char *file;
{
  if(nmagic == 0) ProcessMagicFile(NULL);
  process(file, 0);
  if(file_type_info == NULL) 
    return(specialMagicTb[M_SPECIAL_F][L_UNKNOWN].desc);
  else
    {
      int i = 0, cnt = 0;
      char *ptr = file_type_info;
      while( *ptr && i < 127 && cnt < 6)
	{
	  if(*ptr == ':') cnt++;
	  ptr++;
	}
      if(cnt < 6) return(specialMagicTb[M_SPECIAL_F][L_DATA].desc);
      else return(file_type_info);
    }
}
