Whamcloud - gitweb
LU-2034 changelog: redo changelog using OSD llog
[fs/lustre-release.git] / libsysio / src / lseek.c
index d16efc4..91d865d 100644 (file)
@@ -9,7 +9,7 @@
  *    terms of the GNU Lesser General Public License
  *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
  *
- *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
+ *    Cplant(TM) Copyright 1998-2005 Sandia Corporation. 
  *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
  *    license for use of this work by or on behalf of the US Government.
  *    Export of this program may require a license from the United States
@@ -46,6 +46,7 @@
 #include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <sys/queue.h>
 
 #include "sysio.h"
 
 #include "sysio-symbols.h"
 
-static _SYSIO_OFF_T
-_sysio_lseek(int fd, _SYSIO_OFF_T offset, int whence)
+_SYSIO_OFF_T
+_sysio_lseek_prepare(struct file *fil,
+                    _SYSIO_OFF_T offset,
+                    int whence,
+                    _SYSIO_OFF_T max)
 {
-       struct file *fil;
        _SYSIO_OFF_T off, pos;
        struct intnl_stat stbuf;
-       SYSIO_INTERFACE_DISPLAY_BLOCK;
-
-       SYSIO_INTERFACE_ENTER;
-       fil = _sysio_fd_find(fd);
-       if (!fil)
-               return -EBADF;
 
        off = -1;
        switch (whence) {
@@ -80,12 +77,17 @@ _sysio_lseek(int fd, _SYSIO_OFF_T offset, int whence)
                {
                        int     err;
 
+                       /*
+                        * Don't blindly trust the attributes
+                        * in the inode record for this. Give the
+                        * driver a chance to refresh them.
+                        */
                        err =
                            (*fil->f_ino->i_ops.inop_getattr)(NULL,
                                                              fil->f_ino,
                                                              &stbuf);
                        if (err)
-                               SYSIO_INTERFACE_RETURN((off_t )-1, (int )err);
+                               return err;
        
                }
                off = stbuf.st_size;
@@ -95,32 +97,57 @@ _sysio_lseek(int fd, _SYSIO_OFF_T offset, int whence)
        }
        pos = off + offset;
        if ((offset < 0 && -offset > off) || (offset > 0 && pos <= off))
-               SYSIO_INTERFACE_RETURN((off_t )-1, -EINVAL);
+               return -EINVAL;
+       if (pos >= max)
+               return -EOVERFLOW;
+       return pos;
+}
 
-#ifdef O_LARGEFILE
-       if (pos >= ((fil->f_flags & O_LARGEFILE) ? _SYSIO_OFF_T_MAX : LONG_MAX))
-               SYSIO_INTERFACE_RETURN((off_t )-1, -EOVERFLOW);
-#else
-       if (pos >= _SYSIO_OFF_T_MAX)
-               SYSIO_INTERFACE_RETURN((off_t )-1, -EOVERFLOW);
-#endif
+static _SYSIO_OFF_T
+_sysio_lseek(struct file *fil,
+            _SYSIO_OFF_T offset,
+            int whence,
+            _SYSIO_OFF_T max)
+{
+       _SYSIO_OFF_T pos;
+
+       pos = _sysio_lseek_prepare(fil, offset, whence, max);
+       if (pos < 0)
+               return pos;
        pos = (fil->f_ino->i_ops.inop_pos)(fil->f_ino, pos);
        if (pos < 0)
-               SYSIO_INTERFACE_RETURN((off_t )-1, (int )pos);
+               return pos;
        fil->f_pos = pos;
-       SYSIO_INTERFACE_RETURN((off_t )pos, 0);
+       return pos;
 }
 
-#if _LARGEFILE64_SOURCE
+#ifdef _LARGEFILE64_SOURCE
 #undef lseek64
-sysio_sym_weak_alias(_sysio_lseek, SYSIO_INTERFACE_NAME(lseek64))
+
+extern off64_t
+SYSIO_INTERFACE_NAME(lseek64)(int fd, off64_t offset, int whence)
+{
+       struct file *fil;
+       off64_t off;
+       SYSIO_INTERFACE_DISPLAY_BLOCK;
+
+       SYSIO_INTERFACE_ENTER;
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN((off64_t )-1, -EBADF);
+       off = _sysio_lseek(fil, offset, whence, _SEEK_MAX(fil));
+       SYSIO_INTERFACE_RETURN(off < 0 ? (off64_t )-1 : off,
+                              off < 0 ? (int )off : 0);
+
+}
 #ifdef __GLIBC__
 #undef __lseek64
-sysio_sym_weak_alias(_sysio_lseek, PREPEND(__, SYSIO_INTERFACE_NAME(lseek64)))
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(lseek64),
+                    PREPEND(__, SYSIO_INTERFACE_NAME(lseek64)))
 #endif
 #ifdef REDSTORM
 #undef __libc_lseek64
-sysio_sym_weak_alias(_sysio_lseek, 
+sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(lseek64),
                     PREPEND(__, SYSIO_INTERFACE_NAME(libc_lseek64)))
 #endif
 #endif
@@ -130,12 +157,16 @@ sysio_sym_weak_alias(_sysio_lseek,
 extern off_t
 SYSIO_INTERFACE_NAME(lseek)(int fd, off_t offset, int whence)
 {
+       struct file *fil;
        _SYSIO_OFF_T off;
        off_t   rtn;
        SYSIO_INTERFACE_DISPLAY_BLOCK;
 
        SYSIO_INTERFACE_ENTER;
-       off = _sysio_lseek(fd, offset, whence);
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN((off_t )-1, -EBADF);
+       off = _sysio_lseek(fil, offset, whence, LONG_MAX);
        if (off < 0)
                SYSIO_INTERFACE_RETURN((off_t )-1, (int )off);
        rtn = (off_t )off;
@@ -149,7 +180,6 @@ sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(lseek),
                     PREPEND(__, SYSIO_INTERFACE_NAME(lseek)))
 #endif
 
-#if 0
 #ifdef __linux__
 #undef llseek
 int
@@ -159,17 +189,38 @@ SYSIO_INTERFACE_NAME(llseek)(unsigned int fd __IS_UNUSED,
        loff_t *result __IS_UNUSED,
        unsigned int whence __IS_UNUSED)
 {
+       struct file *fil;
+       loff_t  off;
        SYSIO_INTERFACE_DISPLAY_BLOCK;
 
        /*
-        * Something is very wrong if this was called.
+        * This is just plain goofy.
         */
        SYSIO_INTERFACE_ENTER;
-       SYSIO_INTERFACE_RETURN(-1, -ENOTSUP);
+       fil = _sysio_fd_find(fd);
+       if (!fil)
+               SYSIO_INTERFACE_RETURN(-1, -EBADF);
+#ifndef _LARGEFILE64_SOURCE
+       if (offset_high) {
+               /*
+                * We are using 32-bit internals. This just isn't
+                * going to work.
+                */
+               SYSIO_INTERFACE_RETURN(-1, -EOVERFLOW);
+       }
+#else
+       off = offset_high;
+       off <<= 32;
+       off |= offset_low;
+#endif
+       off = _sysio_lseek(fil, off, whence, _SEEK_MAX(fil));
+       if (off < 0)
+               SYSIO_INTERFACE_RETURN((off_t )-1, (int )off);
+       *result = off;
+       SYSIO_INTERFACE_RETURN(0, 0);
 }
 
 #undef __llseek
 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(llseek), 
                     PREPEND(__, SYSIO_INTERFACE_NAME(llseek)))
 #endif
-#endif