Logo Search packages:      
Sourcecode: zlibc version File versions  Download package

filetype.c

/*
 * filetype.c
 *
 * Copyright (C) 1993 Alain Knaff
 */

#define _LARGEFILE64_SOURCE
#define _GNU_SOURCE

#include "sysincludes.h"


static int is_initialised=0;
static FilenameActions *filenameActions;
static char *default_uncompressor[]= { UNCOMPR, 0 };

#ifndef SECURITY
static char *custom_uncompressor[]= { 0, 0 };
#endif

char *zlib_ext;
int zlib_extlen;

int zlib_mode;
char *zlib_tmp;

char **zlib_uncompressor;

#define ENV_PREFIX "LD_ZLIB_"


/**
 * Remove LD_PRELOAD=uncompress.o from environment in case CM_DISAB_CHILDREN
 * is set
 * We cannot use putenv or setenv here, because they work on a copy of the
 * environment, which will be overwritten between the time this _init is
 * called, and main is called
 */
static void remove_ld_preload() {
  if(zlib_mode & CM_DISAB_CHILD) {
    char preload_name[]="LD_PRELOAD=";
    char *uncompr = "/uncompress.o";      
    int i;
    for(i=0; environ[i]; i++) {
      if(!strncmp(environ[i], preload_name, sizeof(preload_name)-1)) {
      /* strip out all items contains "uncompress.o" from LD_PRELOAD var */
      char *rptr = environ[i] + sizeof(preload_name) - 1;
      char *lastbegin=rptr;
      char *wptr = rptr;
      int comp=1;
      int atbegin=1;
      lastbegin = wptr;
      while(1) {
        if(*rptr == ':') {
          if(uncompr[comp] == '\0') {
            wptr = lastbegin;
            if(atbegin) {
            rptr++;
            comp=1;
            continue;
            }
          }
          comp = 1;
          lastbegin = wptr;
          atbegin=0;
        } else if(*rptr == '\0') {
          if(uncompr[comp] == '\0') {
            wptr = lastbegin;
          }
          *wptr='\0';
          break;      
        } else if(*rptr == uncompr[comp]) {
          comp++;
        } else {
          comp=0;
        }
        *wptr++=*rptr++;       
      }     
      }
    }
  }
}


static char *mode_table[] = {
  "DISABLE",
  "READDIR_COMPR",
  "VERBOSE",
  "UNLINK",
  "NOCONF"};

void zlib_initialise(void)
{
  int modemask;
  int olderrno;

#ifndef SECURITY
  int i;
  char env_buffer[1024];
  char *value;
#endif

  olderrno = errno;
  if ( !is_initialised ){
    CommandActions *cma;

#ifdef HAVE_PROC
    char cmdline[1025];
    int fd,n;
#else
    char *cmdline;
#endif
    char *progname=0;

    zlib_mode = modemask = 0;

    zlib_ext = EXT;
    zlib_extlen = strlen(zlib_ext);
    zlib_uncompressor = default_uncompressor;
    zlib_tmp = TMP;

#ifndef SECURITY
    if (getuid() == geteuid() || getgid() == getegid()){
      zlib_tmp = getenv("LD_ZLIB_TMP");
      if ( zlib_tmp == 0 )
      zlib_tmp = TMP;
      
      zlib_ext= getenv("LD_ZLIB_EXT");
      if ( zlib_ext == 0 )
      zlib_ext = EXT;
      zlib_extlen = strlen(zlib_ext);
      if ( zlib_extlen > MAXEXTLEN ){
      fprintf(stderr,"extension too long, taking default\n");
      zlib_ext = EXT;
      }
      custom_uncompressor[0] = getenv("LD_ZLIB_UNCOMPRESSOR");
      if ( custom_uncompressor[0] ){
      zlib_uncompressor = custom_uncompressor;
      } else
      zlib_uncompressor = default_uncompressor;
      
      strcpy(env_buffer, ENV_PREFIX);
      for ( i=0; i< ( sizeof(mode_table) / sizeof(char *) ); i++){
      strcpy( env_buffer+(sizeof( ENV_PREFIX ) - 1 ), mode_table[i] );
      if ( (value=getenv ( env_buffer )) ){
        if ( ( strcmp( value, "on" ) == 0 ) || ( strcmp( value, "1" ) == 0 )){
          zlib_mode |= ( 1 << ( i + 1 ));
        }else 
          if ( ( strcmp( value, "off" ) ) && ( strcmp( value, "0" ) ))
            continue;
        modemask |= ( 1 << ( i + 1 ));      
      }
      }
      if ( zlib_mode & CM_DISAB){
      is_initialised = 2;
      errno = olderrno;
      return;
      }
    }
#endif

#ifdef HAVE_PROC
    /* get command line */    
    strcpy(cmdline, "unknown");
    fd=syscall(SYS_open,"/proc/self/cmdline", O_RDONLY);
    if ( fd > 0 ){
      cmdline[1024]='\0';
      n = read( fd, cmdline,1024 );
      if ( n < 1 )
      cmdline[0] = '\0';
      else
      cmdline[n] = '\0';
      close(fd);
    }
#else
    /* where does the command line live on a sun ? */
    /* horrible undocumented kludge... This might even work on a proc-less 
     * linux*/

    do {
      extern char **environ;
      int zerosfound;

      if ( environ == 0 ){
      cmdline="";
      break;
      }
      cmdline = *environ;

      if ( cmdline == 0 ){
      cmdline="";
      break;
      }

      zerosfound = 0;
      while(zerosfound < 2 ){
      cmdline--;
      if ( *cmdline == 0 )
        zerosfound++;
      else
        zerosfound = 0;
      }
      cmdline +=2;
    } while(0);
#endif

    progname = strrchr(cmdline, '/' );

    if ( !progname )
      progname = cmdline;
    else
      progname++;

    if ( zlib_mode & CM_VERBOSE)
      fprintf(stderr,"progname = %s\n",progname);

    is_initialised = 1;

    /* get user configuration */
#ifndef NO_RT_CONF
    if ( ! ( zlib_mode & CM_NORTCONF ) )
      zlib_getuserconf(progname, &filenameActions, &zlib_mode, &modemask);
#endif
    if ( modemask != CM_ALL_MODES ){
      /* if we couldn't get the user configuration, use compiled in defaults */
      cma = zlib_commandActions;
      while ( cma->name && strcmp(cma->name, progname ) )
      cma++;

      if ( ( modemask & CM_HAVE_FA ) == 0 )
      filenameActions = cma->actions;

      zlib_mode |= ( cma->cm_type & ~modemask);
    }


    remove_ld_preload();
    is_initialised = 2;
    /* initialisation completely done */
  } 
  errno = olderrno;
}

#ifdef __ELF__
static void _init_rtld(void);

#ifdef RTLD_NEXT
#define WRAP(type, name, args, arg_names) \
  static type preinit_ ## name args { \
    _init_rtld(); \
    return zlib_real_ ## name arg_names; \
  } \
  type (*zlib_real_ ## name) args = preinit_ ## name;

WRAP(int, access, (const char *file_name, int mode), (file_name, mode))
WRAP(int, chmod, (const char *file_name, mode_t mode), (file_name, mode))
WRAP(int, chown, (const char *file_name, uid_t owner, gid_t group), (file_name, owner, group))
WRAP(int, getdents, (unsigned int fd, struct dirent *dirp, unsigned int count), (fd, dirp, count))
WRAP(int, link, (const char *file_name1, const char *file_name2), (file_name1, file_name2))
WRAP(int, open, (const char *name, int flags, mode_t mode), (name, flags, mode))
WRAP(struct dirent *, readdir, (DIR *dirp), (dirp))
WRAP(struct dirent64 *, readdir64, (DIR *dirp), (dirp))
WRAP(int, readlink, (const char *file_name, char *buf, size_t len), (file_name, buf, len))
WRAP(int, rename, (const char *file_name1, const char *file_name2), (file_name1, file_name2))


# ifdef HAVE___XSTAT
WRAP(int, xstat, (int vers, const char *name, struct stat *buf), (vers, name, buf))
WRAP(int, fxstat, (int vers, int fd, struct stat *buf), (vers, fd, buf))
WRAP(int, lxstat, (int vers, const char *name, struct stat *buf), (vers, name, buf))
# else
WRAP(int, stat, (const char *name, struct stat *buf), (name, buf))
WRAP(int, lstat, (const char *name, struct STAT32 *buf), (name, buf))
# endif

# ifdef HAVE___XSTAT64
WRAP(int, xstat64, (int vers, const char *name, struct stat64 *buf), (vers, name, buf))
WRAP(int, lxstat64, (int vers, const char *name, struct stat64 *buf), (vers, name, buf))
# elif defined HAVE_STAT64
WRAP(int, stat64, (const char *name, struct stat64 *buf), (name, buf))
WRAP(int, lstat64, (const char *name, struct stat64 *buf), (name, buf))
# endif


WRAP(int, symlink, (const char *file_name1, const char *file_name2), (file_name1, file_name2))
WRAP(int, unlink, (const char *file_name), (file_name))
WRAP(int, utime, (const char *file_name, struct utimbuf *buf), (file_name, buf))
WRAP(int, utimes, (const char *file_name, struct timeval *buf), (file_name, buf))
#endif

static int _is_rtld_initialized = 0;

void _init(void)
{
    if(_is_rtld_initialized) {
      return;
    }
    _init_rtld();
}

static void _init_rtld(void)
{
    _is_rtld_initialized=1;
#ifdef RTLD_NEXT
  zlib_real_access = dlsym(RTLD_NEXT, "access");
  zlib_real_chmod = dlsym(RTLD_NEXT, "chmod");
  zlib_real_chown = dlsym(RTLD_NEXT, "chown");
  zlib_real_getdents = dlsym(RTLD_NEXT, "getdents");
  zlib_real_link = dlsym(RTLD_NEXT, "link");
# ifdef HAVE___LIBC_OPEN
  zlib_real_open = dlsym(RTLD_NEXT, "__libc_open");
# else
  zlib_real_open = dlsym(RTLD_NEXT, "open");
# endif
  zlib_real_readdir = dlsym(RTLD_NEXT, "readdir");
  zlib_real_readdir64 = dlsym(RTLD_NEXT, "readdir64");
  zlib_real_readlink = dlsym(RTLD_NEXT, "readlink");
  zlib_real_rename = dlsym(RTLD_NEXT, "rename");
  zlib_real_symlink = dlsym(RTLD_NEXT, "symlink");
  zlib_real_unlink = dlsym(RTLD_NEXT, "unlink");
  zlib_real_utime = dlsym(RTLD_NEXT, "utime");
  zlib_real_utimes = dlsym(RTLD_NEXT, "utimes");

# ifdef HAVE___XSTAT
  zlib_real_xstat = dlsym(RTLD_NEXT, "__xstat");
  zlib_real_fxstat = dlsym(RTLD_NEXT, "__fxstat");
  zlib_real_lxstat = dlsym(RTLD_NEXT, "__lxstat");
# else
  zlib_real_stat = dlsym(RTLD_NEXT, "stat");
  zlib_real_lstat = dlsym(RTLD_NEXT, "lstat");
# endif


# ifdef HAVE___XSTAT64
  zlib_real_xstat64 = dlsym(RTLD_NEXT, "__xstat64");
  zlib_real_lxstat64 = dlsym(RTLD_NEXT, "__lxstat64");
# elif defined HAVE_STAT64
  zlib_real_stat64 = dlsym(RTLD_NEXT, "stat64");
  zlib_real_lstat64 = dlsym(RTLD_NEXT, "lstat64");
# endif

#endif

  zlib_initialise();
}

#endif

static int masks[]= { 
      PM_READ_MASK,
      PM_CREATE_MASK,
      PM_APPEND_MASK,
      PM_UNCOMPR_MASK,
      PM_SIZE_COMPR_MASK
};
#define     NUMBER(x)   (sizeof(x) / sizeof(*(x)))


static void quick_stat(__const char *name, dev_t *dev, ino_t *ino)
{
  int olderrno;
  int st;
  struct STAT32 buf;

  olderrno = errno;
  st = ___zlibc_stat(name, &buf );
  errno = olderrno;
  if ( st < 0 ) {
    /* file not found */
    *ino = 0;
    *dev = 0;
  } else {
    *dev = buf.st_dev;
    *ino = buf.st_ino;
  }
}

static void initialize_fa(FilenameActions *fa)
{
  if(fa->is_initialized)
    return;
  fa->is_initialized = 1;
  quick_stat(fa->name, &fa->dev, &fa->ino);
}

static int check_subdir(__const char *name, int dirlength,
                  int fd, FilenameActions *fa, int subdir)
{
  char dirname[MAXPATHLEN+1];
  struct stat buf;
  dev_t last_dev=0;
  ino_t last_ino=0;
  int cwd;
  int cfd;
  int closefd=0; /* fd must be closed on exit */
  int r;

  initialize_fa(fa);
  if(!fa->ino)
    return 0;

  if(fd == -1){
    if(dirlength - 1 > MAXPATHLEN)
      return 0;
    if(!dirlength)
      strcpy(dirname,".");
    else
      strncpy(dirname,name, dirlength-1);
    closefd = fd = zlib_real_open(dirname, O_RDONLY, 0);
    if(fd < 0)
      return 0;
  }

  cwd = -1;
  cfd = fd;
  while(1) {
      fstat(cfd, &buf);
    if(cwd >= 0)
      close(cfd);
    if(buf.st_dev == fa->dev &&
       buf.st_ino == fa->ino) {
      r = 1;
      break;
    }
    if(!subdir) {
      r = 0;
      break;
    }
    if(cwd >= 0 &&
       buf.st_dev == last_dev &&
       buf.st_ino == last_ino) {      
      /* root reached */
      r = 0;
      break;
    }
    last_dev = buf.st_dev;
    last_ino = buf.st_ino;
#ifdef HAVE_FCHDIR
    if(cwd < 0) {
      /* remember old directory */
      cwd = zlib_real_open(".", O_RDONLY, 0);
      if(cwd < 0) {
      r = 0;
      break;
      }
      fchdir(fd);  /* go to the new directory */
    }
    chdir(".."); /* move up one level */
    cfd = zlib_real_open(".", O_RDONLY, 0);
    if(cfd < 0) {
      r = 0;
      break;
    }
#else
    if(fd != -1) {
      /* unknown filename */
      r = 0;
      break;
    }
    if(strlen(dirname) > MAXPATHLEN - 3) {
      r = 0; /* filename too long */
      break;
    }
    strcat(dirname, "/..");
    cfd = zlib_real_open(dirname, O_RDONLY, 0);
    if(cfd < 0) {
      r = 0;
      break;
    }
#endif
  }

#ifdef HAVE_FCHDIR
  if(cwd != -1) {
    /* revert back to real current directory */
    fchdir(cwd);
    close(cwd);
  }
#endif
  if(closefd)
    close(fd);
  return r;
}

int zlib_getfiletype(__const char *name, int fd)
{
  __const char *basename;

  FilenameActions *fa;
  int length;
  int dirlength;
  int basenamelength;
  int pipe_mode;
  int i;
  int match;
  int dostop;
  int dev;
  struct STAT32 buf;
  int olderrno;
  int st;

  /* preprocessing */
  dev=-1;
  basename = strrchr( name, '/' );
  if ( !basename )
    basename = name;
  else
    basename++;
  
  dirlength = basename - name;
  basenamelength = strlen(basename);
  length = dirlength + basenamelength;

  zlib_initialise();

  if ( is_initialised == 1 )
    /* transition period, loading user supplied defaults */
    return PM_SHOW_PIPE;

  fa = filenameActions;
  pipe_mode=0;
  while ( 1 ){
    match=0;
    switch( fa->fa_type ){
      /* before calling strncmp, the length are compared in order to speed up
       * the search. In most cases, the length doesn't match, this way we don't
       * need a costly call to strncmp */
    case FA_ALL:
    case FA_ALL2:
      match=1;
      break;
    case FA_DIR:
      if(fd == -1 && name[0] == '/')
      match= fa->namelength == dirlength &&
        !strncmp(fa->name, name, dirlength);
      else
      match = check_subdir(name, dirlength, fd, fa, 0);
      break;
    case FA_SUBDIR:
      if(fd == -1 && name[0] == '/')      
      match= fa->namelength<=dirlength &&
        !strncmp(fa->name,name,fa->namelength);
      else
      match = check_subdir(name, dirlength, fd, fa, 1);
      break;
    case FA_BASENAME:
      match= fa->namelength == basenamelength && !strcmp(fa->name, basename);
      break;
    case FA_FILENAME:
      match= fa->namelength == length && !strcmp(fa->name, name);
      break;
    case FA_SUFFIX:
      match= fa->namelength <= basenamelength &&
            !strcmp(fa->name, basename + (basenamelength - fa->namelength));
      break;
    case FA_FS:
      if ( dev == -1 ){
      olderrno = errno;

      if ( fd != -1 )
        st = fSTAT32(fd,&buf );
      else {
        char namez[MAXPATHLEN + MAXEXTLEN + 1];
        strncpy(namez, name, MAXPATHLEN);
        strncat(namez, zlib_ext, MAXPATHLEN);
        st = ___zlibc_stat(namez, &buf );
      }
      errno = olderrno;
      if ( st < 0 )
        dev = 0;
      else
        dev = buf.st_dev;
      }
      match = buf.st_dev == fa->namelength;
      break;
    default:
      fprintf(stderr,"Error in filenameActions %x in %d\n", fa->fa_type, 
            (int) getpid());
      sleep(3);
      return 0;
      break;
    }
    if (match){
      dostop=1;
      for (i=0; i< NUMBER(masks); i++){
      if (!(pipe_mode & masks[i]))
        pipe_mode |= fa->pipe_mode & masks[i];
      if (!(pipe_mode & masks[i]))
        dostop=0;
      }
      if ( dostop || fa->fa_type == FA_ALL){
#ifdef DEBUG
      fprintf(stderr,"pm=%x\n", pipe_mode);
#endif
      return pipe_mode;
      }
    }
    fa++;
  }
}



Generated by  Doxygen 1.6.0   Back to index