home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ixemul-45.0-src.tgz / tar.out / contrib / ixemul / library / stat.c < prev    next >
C/C++ Source or Header  |  1996-10-01  |  10KB  |  331 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *
  5.  *  This library is free software; you can redistribute it and/or
  6.  *  modify it under the terms of the GNU Library General Public
  7.  *  License as published by the Free Software Foundation; either
  8.  *  version 2 of the License, or (at your option) any later version.
  9.  *
  10.  *  This library is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  *  Library General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU Library General Public
  16.  *  License along with this library; if not, write to the Free
  17.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  stat.c,v 1.1.1.1 1994/04/04 04:30:35 amiga Exp
  20.  *
  21.  *  stat.c,v
  22.  * Revision 1.1.1.1  1994/04/04  04:30:35  amiga
  23.  * Initial CVS check in.
  24.  *
  25.  *  Revision 1.2  1993/11/05  22:03:10  mwild
  26.  *  grp/oth support, plus new feature
  27.  *
  28.  *  Revision 1.1  1992/05/14  19:55:40  mwild
  29.  *  Initial revision
  30.  *
  31.  */
  32.  
  33. #define _KERNEL
  34. #include "ixemul.h"
  35. #include "kprintf.h"
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include "multiuser.h"
  39.  
  40. /* currently, links are quite buggy.. hope this get cleaned up RSN ;-) */
  41.  
  42. long fill_stat_mode(struct stat *stb, struct FileInfoBlock *fib)
  43. {
  44.   long mode;
  45.  
  46.   mode = 0L;
  47.   /* If this is a directory, and Size is not 0, then this is a volume.
  48.      Since the Protection field seems to be random for volumes, we use
  49.      our own flags (= everything readable & writable) */
  50.   if (fib->fib_DirEntryType > 0 && fib->fib_Size != 0)
  51.     fib->fib_Protection = 0xff00;
  52.   stb->st_amode = fib->fib_Protection;
  53.   if (!(fib->fib_Protection & FIBF_EXECUTE))
  54.     mode |= S_IXUSR;
  55.   else if (fib->fib_Protection & FIBF_SCRIPT)
  56.     mode |= S_IXUSR;
  57.   if (!(fib->fib_Protection & (FIBF_WRITE|FIBF_DELETE)))
  58.     mode |= S_IWUSR;
  59.   if (!(fib->fib_Protection & FIBF_READ))
  60.     mode |= S_IRUSR;
  61. #ifdef FIBF_GRP_EXECUTE
  62.   /* FIBF_GRP_EXECUTE requires at least OS3 headers */
  63.   if (fib->fib_Protection & FIBF_GRP_EXECUTE)
  64.     mode |= S_IXGRP;
  65.   if ((fib->fib_Protection & (FIBF_GRP_WRITE|FIBF_GRP_DELETE)) == (FIBF_GRP_WRITE|FIBF_GRP_DELETE))
  66.     mode |= S_IWGRP;
  67.   if (fib->fib_Protection & FIBF_GRP_READ)
  68.     mode |= S_IRGRP;
  69.   if (fib->fib_Protection & FIBF_OTR_EXECUTE)
  70.     mode |= S_IXOTH;
  71.   if ((fib->fib_Protection & (FIBF_OTR_WRITE|FIBF_OTR_DELETE)) == (FIBF_OTR_WRITE|FIBF_OTR_DELETE))
  72.     mode |= S_IWOTH;
  73.   if (fib->fib_Protection & FIBF_OTR_READ)
  74.     mode |= S_IROTH;
  75.   if (fib->fib_Protection & FIBF_HOLD)
  76.     mode |= S_ISTXT;
  77.   if (fib->fib_Protection & muFIBF_SET_UID)
  78.     mode |= S_ISUID;
  79.   if (fib->fib_Protection & muFIBF_SET_GID)
  80.     mode |= S_ISGID;
  81. #endif
  82.  
  83.   switch (fib->fib_DirEntryType)
  84.     {
  85.     case ST_LINKDIR:
  86.       stb->st_nlink = 3;
  87.       mode |= S_IFDIR;
  88.       break;
  89.     case ST_ROOT:
  90.     case ST_USERDIR:
  91.       stb->st_nlink = 2;
  92.       mode |= S_IFDIR;
  93.       break;
  94.  
  95.     /* at the moment, we NEVER get this entry, since we can't get a lock
  96.      * on a symlink */
  97.     case ST_SOFTLINK:
  98.       mode |= S_IFLNK;
  99.       break;
  100.  
  101.     case ST_PIPEFILE:
  102.       /* don't use S_IFIFO, we don't have a mkfifo() call ! */
  103.       mode |= S_IFCHR;
  104.       break;
  105.  
  106.     case ST_LINKFILE:
  107.       stb->st_nlink = 2;
  108.       mode |= S_IFREG;
  109.       break;
  110.     case ST_FILE:
  111.     default:
  112.       stb->st_nlink = 1;
  113.       mode |= S_IFREG;
  114.     }
  115.  
  116.   /* If a directory is readable, then also allow scanning. */
  117.   if (mode & S_IFDIR)
  118.     mode |= (mode & (S_IRUSR | S_IRGRP | S_IROTH)) >> 2;
  119.   return mode;
  120. }
  121.  
  122. static int
  123. __stat(const char *fname, struct stat *stb, BPTR (*lock_func)())
  124. {
  125.   BPTR lock;
  126.   struct FileInfoBlock *fib;
  127.   struct InfoData *info;
  128.   int omask, err = 0;
  129.  
  130.   bzero (stb, sizeof(*stb));
  131.  
  132.   omask = syscall (SYS_sigsetmask, ~0);
  133.   stb->st_uid = geteuid();
  134.   stb->st_gid = getegid();
  135.  
  136.   if (!(lock = (*lock_func) (fname, ACCESS_READ)))
  137.     {
  138.       err = IoErr ();
  139.  
  140.       /* take special care of NIL:, /dev/null and friends ;-) */
  141.       if (err == 4242)
  142.         {
  143.           stb->st_mode = S_IFCHR | 0777;
  144.           stb->st_nlink = 1;
  145.           stb->st_blksize = ix.ix_fs_buf_factor * 512;
  146.           stb->st_blocks = 0;
  147.           goto rest_sigmask;
  148.         }
  149.  
  150.       /* take special care of /dev/ptyXX and /dev/ttyXX */
  151.       if (err == 5252)
  152.         {
  153.           stb->st_mode = S_IFCHR | 0777;
  154.           stb->st_nlink = 1;
  155.           stb->st_blksize = ix.ix_fs_buf_factor * 512;
  156.           stb->st_blocks = 0;
  157.           goto rest_sigmask;
  158.         }
  159.  
  160.       /* root directory */
  161.       if (err == 6262)
  162.         {
  163.           stb->st_mode = S_IFDIR | 0777;
  164.           stb->st_nlink = 1;
  165.           stb->st_blksize = ix.ix_fs_buf_factor * 512;
  166.           stb->st_blocks = 0;
  167.           goto rest_sigmask;
  168.         }
  169.  
  170.       KPRINTF (("__stat: lock %s failed, err = %ld.\n", fname, err));
  171.       if (err == ERROR_IS_SOFT_LINK)
  172.     {
  173.       /* provide some default stb.. we can't get anymore info than
  174.        * that. Symlinks should work with Lock(), but till now they
  175.        * don't ;-( */
  176.       stb->st_handler = (int) DeviceProc ((UBYTE *)fname);
  177.       stb->st_dev = (dev_t) stb->st_handler;
  178.       /* HELP! no way to reach the fib of this entry except when
  179.        * scanning the parent directory, but this is NOT acceptable ! */
  180.       stb->st_ino = 123;
  181.       /* this is the most important entry ;-) */
  182.       stb->st_mode = S_IFLNK | 0777;
  183.       stb->st_size = 1024; /* again, this should be available... */
  184.       stb->st_nlink = 1;
  185.       stb->st_rdev = 0;
  186.       /* again, these values ARE accessible, but only by ExNext */
  187.       stb->st_atime = stb->st_mtime = stb->st_ctime = 0;
  188.       stb->st_blksize = stb->st_blocks = 0;
  189.       goto rest_sigmask;
  190.         }
  191. error:
  192.       syscall (SYS_sigsetmask, omask);
  193.       errno = __ioerr_to_errno (err);
  194.       KPRINTF (("ioerr = %ld, &errno = %lx, errno = %ld\n", err, &errno, errno));
  195.       return -1;
  196.     }
  197.   KPRINTF (("__stat: lock %s ok.\n",fname));
  198.  
  199.   /* alloca() returns stack memory, so it's guaranteed to be word 
  200.    * aligned (anything else would be deadly for the sp...) Since DOS needs
  201.    * long aligned data, we'll allocate 1 word more and adjust as needed */
  202.   fib = alloca (sizeof(*fib) + 2);
  203.   /* DON'T use LONG_ALIGN(alloca(..)), the argument is evaluated more than once! */
  204.   fib = LONG_ALIGN (fib);
  205.  
  206.   info = alloca (sizeof(*info) + 2);
  207.   info = LONG_ALIGN (info);
  208.  
  209.   if (!(Examine (lock, fib)))
  210.     {
  211.       __unlock (lock);
  212.       goto error;
  213.     }
  214.  
  215.   stb->st_mode = fill_stat_mode(stb, fib);
  216.  
  217.   /* read the uid/gid data */
  218.   if (muBase)
  219.     {
  220.       stb->st_uid = fib->fib_OwnerUID;
  221.       stb->st_gid = fib->fib_OwnerGID;
  222.     }
  223.  
  224.   /* support for annotated attributes (cool name ;-)) */
  225.   if (! strncmp (fib->fib_Comment, "!SP!", 4))
  226.     {
  227.       int sp_mode, sp_addr;
  228.  
  229.       if (sscanf (fib->fib_Comment + 4, "%x!%x", &sp_mode, &sp_addr) == 2)
  230.         stb->st_mode = sp_mode;
  231.     }
  232.   
  233.   /* some kind of a default-size for directories... */
  234.   stb->st_size = fib->fib_DirEntryType < 0 ? fib->fib_Size : 1024; 
  235.   stb->st_handler = (long)((struct FileLock *)((long)lock << 2))->fl_Task;
  236.   stb->st_dev = (dev_t)stb->st_handler; /* trunc to 16 bit */
  237.   /* The fl_Key field of the FileLock structure is always unique. This is
  238.      also true for filesystems like AFS and AFSFloppy. Thanks to Michiel
  239.      Pelt (the AFS author) for helping me with this. */
  240.   stb->st_ino = (ino_t)((struct FileLock *)(BTOCPTR(lock)))->fl_Key;
  241.   stb->st_atime =
  242.   stb->st_ctime =
  243.   stb->st_mtime = (8*365+2)*24*3600 + ix_get_gmt_offset() +
  244.           fib->fib_Date.ds_Days * 24 * 60 * 60 +
  245.           fib->fib_Date.ds_Minute * 60 +
  246.           fib->fib_Date.ds_Tick/TICKS_PER_SECOND;
  247.   /* in a try to count the blocks used for filemanagement, we add one for
  248.    * the fileheader. Note, that this is wrong for large files, where there
  249.    * are some extension-blocks as well */
  250.   stb->st_blocks = fib->fib_NumBlocks + 1;
  251.   
  252.   bzero (info, sizeof (*info));
  253.   stb->st_blksize = 0;
  254.   if (Info(lock, info))
  255.     {
  256.       /* optimal for fileio is as high as possible ;-) This is a
  257.        * compromise between "as high as possible" and not too restricitve
  258.        * for people low on memory */
  259.       stb->st_blksize = info->id_BytesPerBlock * ix.ix_fs_buf_factor;
  260.       stb->st_blocks = (stb->st_blocks * info->id_BytesPerBlock) / 512;
  261.     }
  262.  
  263.   if (! stb->st_blksize) stb->st_blksize = 512;
  264.  
  265.   __unlock (lock);
  266.   if (ix.ix_unix_names)
  267.     {
  268.       ix_lock_base();
  269.       if (find_unix_name(fname))
  270.         stb->st_mode = (stb->st_mode & ~S_IFMT) | S_IFSOCK;
  271.       ix_unlock_base();
  272.     }
  273.  
  274. rest_sigmask:
  275.   syscall (SYS_sigsetmask, omask);
  276.   return 0;
  277. }
  278.  
  279. /***************************************************************************/
  280.  
  281. int
  282. stat (const char *fname, struct stat *stb)
  283. {
  284.   return __stat (fname, stb, __lock);
  285. }
  286.  
  287. int
  288. lstat (const char *fname, struct stat *stb)
  289. {
  290.   return __stat (fname, stb, __llock);
  291. }
  292.  
  293. int
  294. filenamecmp(const char *fname)
  295. {
  296.   BPTR lock;
  297.   struct FileInfoBlock *fib;
  298.   int omask, result = 0;
  299.  
  300.   omask = syscall (SYS_sigsetmask, ~0);
  301.  
  302.   if (!(lock = __llock((char *)fname, ACCESS_READ)))
  303.     {
  304.       syscall (SYS_sigsetmask, omask);
  305.       return 0;
  306.     }
  307.  
  308.   fib = alloca (sizeof(*fib) + 2);
  309.   fib = LONG_ALIGN (fib);
  310.  
  311.   /* Only reject this filename if:
  312.    *
  313.    * 1) fname differs from fib_FileName (case sensitive compare)
  314.    *
  315.    * AND
  316.    *
  317.    * 2) compared case insensitively, fname is equal to fib_FileName.
  318.    *
  319.    * Test 2 is needed for links (both hard and soft), since it is
  320.    * impossible to get the name of the link with Examine. Only
  321.    * ExAll/ExNext can obtain the link name.
  322.    */
  323.    
  324.   if (Examine (lock, fib))
  325.     result = strcmp(basename((char *)fname), fib->fib_FileName) &&
  326.          !stricmp(basename((char *)fname), fib->fib_FileName);
  327.   __unlock (lock);
  328.   syscall (SYS_sigsetmask, omask);
  329.   return result;
  330. }
  331.