//
//  Fixperms - set and get permissions on lists of files
//  Copyright (C) 1993-1994  Anthony Edward Hall (aehall@seattleu.edu)
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id: file.C,v 1.12 1994/01/29 15:01:45 aehall Exp $

static char rcsid[] = "$Id: file.C,v 1.12 1994/01/29 15:01:45 aehall Exp $";

#include <unistd.h>    // for readlink and getcwd
#include <sys/stat.h>  // for file mode defines
#include <dirent.h>    // for NAME_MAX and PATH_MAX
#include <stdio.h>     // for perror
#include <sys/sysmacros.h>  // for major & minor
#include <string.h>    // for string stuff
#include "file.H"
#include "fixperms.H"

// dummy function to prevent "rcsid not used" warning on compile
void file_C_rcsid()
  {
  printf("%s",rcsid);
  };

// file constructor
file::file()
  {
  fname=new(char[MAX_NAME_LEN]);
  linkname=new(char[MAX_NAME_LEN]);
  ftype='?';
  }; // end file::file

// file destructor
file::~file()
  {
  delete(fname);
  delete(linkname);
  };  // end file::~file

// get file type, stats, etc.
int file::get_file(char *name, int options)
  {
  int linksize;
  char *fname_tmp=NULL;

  strcpy(fname,name);
  if ((fname[0] != '/') && (!O_IS_ABSOLUTE(options)))
    {
    printf("%s: must be an absolute pathname\n",fname);
    return 1;
    };
  if ((fname[0] != '/') && (O_IS_ABSOLUTE(options)))
    {                        // should files have current dir added?
    fname_tmp=new(char[MAX_NAME_LEN]);
    strcpy(fname_tmp,fname);
    strcpy(fname,"\0");
    if ((fname=getcwd(fname,(sizeof(char)*NAME_MAX+sizeof(char)*PATH_MAX+1))) == NULL)
      {
      perror(fname);
      return 1;
      };
    strcat(fname,"/");
    strcat(fname,fname_tmp);
    delete(fname_tmp);
    }
  if (stat(fname,&fstats))
    {
    perror(fname);
    return 1;
    };
  if ((linksize=readlink(fname,linkname,NAME_MAX+sizeof(char)*PATH_MAX+1)) >= 0)
    {
    linkname[linksize]='\0';          // link
    ftype='l';
    if (linkname[0] == '/')
      {
      fprintf(stderr,"%s: link should be relative pathname\n",fname);
      return 1;
      };
    }
  else
    {
    if (S_ISREG(fstats.st_mode))        // regular
      ftype='-';
    else if (S_ISDIR(fstats.st_mode))   // directory
      ftype='d';
    else if (S_ISCHR(fstats.st_mode))   // character device
      {
      ftype='c';
      major=major(fstats.st_rdev);
      minor=minor(fstats.st_rdev);
      }
    else if (S_ISBLK(fstats.st_mode))   // block device
      {
      ftype='b';
      major=major(fstats.st_rdev);
      minor=minor(fstats.st_rdev);
      }
    else if (S_ISFIFO(fstats.st_mode))  // FIFO
      ftype='p';
    else if (S_ISSOCK(fstats.st_mode))  // socket
      ftype='s';
    else ftype='?';                    // unknown
    };
  fstats.st_mode=fstats.st_mode & 0007777;   // get only rwxrwxrwx perms,
  return 0;                                  // not suid, etc
  }; // end file::get_file

// output file stuff
void file::output(FILE *stream, file *fptr, int options)
  {
  if (O_IS_VERBOSE(options))
    {
    switch(fptr->ftype)
      {
      case 'r':
        fprintf(stream,r_FORMAT);
        break;
      case 'l':
        fprintf(stream,l_FORMAT);
        break;
      case 'c':
      case 'b':
        fprintf(stream,cb_FORMAT);
        break;
      default:
        fprintf(stream,o_FORMAT);
        break;
      };
    };
  }; // end file::output

// input file stuff
void file::input(FILE *stream, file *fptr)
  {
  char letter='\0';

  do
    {
    fscanf(stream,"%c",&fptr->ftype);
    switch (fptr->ftype)
      {
      case '#':
        break;
      default:
        fscanf(stream,"%s",fptr->fname);
        fscanf(stream,"%hu",&fptr->fstats.st_uid);
        fscanf(stream,"%hu",&fptr->fstats.st_gid);
        fscanf(stream,"%ho",&fptr->fstats.st_mode);
        switch (fptr->ftype)
          {
          case 'l':
            fscanf(stream,"%s",fptr->linkname);
            break;
          case 'c':
          case 'b':
            fscanf(stream,"%d",&fptr->major);
            fscanf(stream,"%d",&fptr->minor);
            break;
          default:
            break;
          };
        break;
      };
    do   // read until end of line (i.e. skip any comments, extraneous stuff)
      {
      fscanf(stream,"%c",&letter);
      }
    while ((letter != '\n') && (!feof(stream)));
    }
  while ((fptr->ftype == '#') && (!feof(stream)));  // skip over comments
  }; // end file::input

// end $Id: file.C,v 1.12 1994/01/29 15:01:45 aehall Exp $
