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 / lseek.c < prev    next >
C/C++ Source or Header  |  1996-10-01  |  7KB  |  269 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.  *  lseek.c,v 1.1.1.1 1994/04/04 04:30:29 amiga Exp
  20.  *
  21.  *  lseek.c,v
  22.  * Revision 1.1.1.1  1994/04/04  04:30:29  amiga
  23.  * Initial CVS check in.
  24.  *
  25.  *  Revision 1.1  1992/05/14  19:55:40  mwild
  26.  *  Initial revision
  27.  *
  28.  */
  29.  
  30. #define _KERNEL
  31. #include "ixemul.h"
  32. #include "kprintf.h"
  33.  
  34. #include <string.h>
  35.  
  36. static inline int
  37. __extend_file (struct file *f, int add_to_eof, int *err)
  38. {
  39.   int res = 0;
  40.   int buf_size, written;
  41.   char *buf;
  42.  
  43.   /* now you know perhaps, that starting with OS2.0 there's a packet that
  44.      sets the size of a file (used in [f]truncate()). Too bad, that the 
  45.      following statement from the autodocs render this packet useless... :
  46.  
  47.      `` Do NOT count on any specific values to be in the extended area. ''
  48.    
  49.      Since **IX requires the new area to be zero'd, we can just as well
  50.      write zeros without the use of the new packet ;-(( */
  51.   
  52.       
  53.   buf_size = add_to_eof > 32*1024 ? 32*1024 : add_to_eof;
  54.   while (! (buf = (char *) kmalloc (buf_size)) && buf_size)
  55.     buf_size >>= 1;
  56.   if (buf)
  57.     {
  58.       bzero (buf, buf_size);
  59.  
  60.       for (written = 0; written < add_to_eof; )
  61.         {
  62.       SendPacket3(f,__srwport,ACTION_WRITE,f->f_fh->fh_Arg1,(long)buf,buf_size);
  63.       __wait_sync_packet(&f->f_sp);
  64.       res = LastResult (f);
  65.           if (res < 0)
  66.             {
  67.               *err = LastError (f);
  68.               break;
  69.             }
  70.           written += res;
  71.           buf_size = add_to_eof - written > buf_size ? 
  72.                buf_size : add_to_eof - written;
  73.     }
  74.       kfree (buf);
  75.     }
  76.   else
  77.     {
  78.       *err = ENOMEM;
  79.       res = -1;
  80.     }
  81.  
  82.   if (res >= 0)
  83.     {
  84.       SendPacket3(f,__srwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  85.      __wait_sync_packet (&f->f_sp);
  86.       LastError(f) = 0;
  87.       SendPacket3(f,__srwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  88.      __wait_sync_packet (&f->f_sp);
  89.      res = LastError (f) ? -1 : LastResult (f);
  90.      *err = __ioerr_to_errno (LastError (f));
  91.    }
  92.  
  93.   return res;
  94. }
  95.  
  96.  
  97. off_t
  98. lseek (int fd, off_t off, int dir)
  99. {
  100.   struct file *f = u.u_ofile[fd];
  101.   int omask;
  102.   int err, res;
  103.   int previous_pos = 0, shouldbe_pos;
  104.  
  105.   /* if this is an open fd */
  106.   if (fd >= 0 && fd < NOFILE && f)
  107.     {
  108.       if (f->f_type == DTYPE_FILE)
  109.     {
  110.           if (HANDLER_NIL(f))
  111.         {
  112.           /* This is always possible with /dev/null */
  113.           if (off == 0)
  114.             return 0;
  115.           errno = ESPIPE;
  116.           KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  117.           return -1;
  118.         }
  119.  
  120.       omask = syscall (SYS_sigsetmask, ~0);
  121.       __get_file (f);
  122.  
  123.       /* there's a subtle difference between Unix lseek() and AmigaOS
  124.        * Seek(): lseek() returns the *current* position of the `pointer',
  125.        * Seek() returns the *previous* position. So in some cases, we
  126.        * have to do another Seek() to find out where we are.
  127.        * Thanks Mike for pointing me at this! */
  128.  
  129.       switch (dir)
  130.         {
  131.         case SEEK_SET:
  132.           /* previous doesn't matter, don't need to seek */
  133.           previous_pos = 0;
  134.           break;
  135.  
  136.         case SEEK_CUR:
  137.           /* first find out current position */
  138.           LastError(f) = 0;
  139.           SendPacket3(f,__srwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  140.           __wait_sync_packet (&f->f_sp);
  141.           if (LastError(f) || LastResult(f) < 0)
  142.             {
  143.               err = __ioerr_to_errno(LastError(f));
  144.               previous_pos = -1;
  145.             }
  146.           else
  147.             previous_pos = LastResult(f);
  148.           break;
  149.           
  150.         case SEEK_END:
  151.           /* first find out end position (have to do twice.. argl) */
  152.           SendPacket3(f,__srwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  153.           __wait_sync_packet (&f->f_sp);
  154.           LastError(f) = 0;
  155.           SendPacket3(f,__srwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  156.           __wait_sync_packet (&f->f_sp);
  157.           if (LastError(f) || LastResult(f) < 0)
  158.             {
  159.               err = __ioerr_to_errno(LastError(f));
  160.               previous_pos = -1;
  161.             }
  162.           else
  163.             previous_pos = LastResult(f);
  164.           break;
  165.         }
  166.       
  167.       shouldbe_pos = previous_pos + off;
  168.       if (shouldbe_pos < 0)
  169.         {
  170.           /* that way we make sure that invalid seek errors later result
  171.              from seeking past eof, so we can enlarge the file */
  172.  
  173.           err = EINVAL;
  174.           res = -1;
  175.         }
  176.       else if (previous_pos >= 0)
  177.         {
  178.           /* reset the error field */
  179.           LastError(f) = 0;
  180.           SendPacket3(f,__srwport,ACTION_SEEK,f->f_fh->fh_Arg1,off,dir-1);
  181.           __wait_sync_packet(&f->f_sp);
  182.  
  183.           if (LastError (f) == ERROR_SEEK_ERROR)
  184.             {
  185.               /* in this case, assume the user wanted to seek past eof.
  186.                  Thus get the current eof position, so that we can
  187.                  tell __extend_file how much to enlarge the file */
  188.           
  189.           LastError(f) = 0;
  190.           SendPacket3(f,__srwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  191.           __wait_sync_packet (&f->f_sp);
  192.             }
  193.       
  194.           if (LastError (f) || LastResult (f) < 0)
  195.             {
  196.               err = __ioerr_to_errno(LastError(f));
  197.               res = -1;
  198.             }
  199.           else
  200.             {
  201.               err = 0;
  202.  
  203.               if (previous_pos != shouldbe_pos)
  204.             {
  205.               SendPacket3(f,__srwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  206.               __wait_sync_packet (&f->f_sp);
  207.               if (LastError (f) || LastResult(f) < 0)
  208.                 {
  209.                       err = __ioerr_to_errno(LastError(f));
  210.                       res = -1;
  211.                     }
  212.               else
  213.                     res = LastResult(f);
  214.  
  215.                   if (res >= 0 && res < shouldbe_pos && (f->f_flags & FWRITE))
  216.                     {
  217.                       /* extend the file... */
  218.                   res = __extend_file (f, shouldbe_pos - res, &err);
  219.                 }
  220.             }
  221.           else
  222.             res = shouldbe_pos;
  223.             }
  224.         }
  225.       else
  226.         res = -1;
  227.       
  228.       LastResult(f) = 0;
  229.       __release_file (f);
  230.       syscall (SYS_sigsetmask, omask);
  231.       errno = err;
  232.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  233.       return res;
  234.     }
  235.       else if (f->f_type == DTYPE_MEM)
  236.     {
  237.       int real_off;
  238.       int old_off;
  239.  
  240.       omask = syscall (SYS_sigsetmask, ~0);
  241.       __get_file (f);
  242.       old_off = f->f_mf.mf_offset;
  243.       
  244.       real_off = (dir == L_SET ? off : 
  245.               (dir == L_INCR ? 
  246.                old_off + off : f->f_stb.st_size + off));
  247.       if (real_off < 0) real_off = 0;
  248.       else if (real_off > f->f_stb.st_size) real_off = f->f_stb.st_size;
  249.       f->f_mf.mf_offset = real_off;
  250.       __release_file (f);
  251.       syscall (SYS_sigsetmask, omask);
  252.       return old_off;
  253.     }
  254.       else
  255.     {
  256.       errno = ESPIPE;
  257.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  258.     }
  259.     }
  260.   else
  261.     {
  262.       errno = EBADF;
  263.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  264.     }
  265.  
  266.   return -1;
  267. }
  268.  
  269.