Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * llseek.c -- stub calling the llseek system call
      3  *
      4  * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
      5  *
      6  * %Begin-Header%
      7  * This file may be redistributed under the terms of the GNU Library
      8  * General Public License, version 2.
      9  * %End-Header%
     10  */
     11 
     12 #ifndef _LARGEFILE_SOURCE
     13 #define _LARGEFILE_SOURCE
     14 #endif
     15 #ifndef _LARGEFILE64_SOURCE
     16 #define _LARGEFILE64_SOURCE
     17 #endif
     18 
     19 #include "config.h"
     20 #if HAVE_SYS_TYPES_H
     21 #include <sys/types.h>
     22 #endif
     23 
     24 #if HAVE_ERRNO_H
     25 #include <errno.h>
     26 #endif
     27 #if HAVE_UNISTD_H
     28 #include <unistd.h>
     29 #endif
     30 #ifdef __MSDOS__
     31 #include <io.h>
     32 #endif
     33 #include "et/com_err.h"
     34 #include "ext2fs/ext2_io.h"
     35 
     36 #ifdef __linux__
     37 
     38 #if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
     39 
     40 #define my_llseek lseek64
     41 
     42 #else
     43 #if defined(HAVE_LLSEEK)
     44 #include <sys/syscall.h>
     45 
     46 #ifndef HAVE_LLSEEK_PROTOTYPE
     47 extern long long llseek (int fd, long long offset, int origin);
     48 #endif
     49 
     50 #define my_llseek llseek
     51 
     52 #else	/* ! HAVE_LLSEEK */
     53 
     54 #if SIZEOF_LONG == SIZEOF_LONG_LONG
     55 
     56 #define my_llseek lseek
     57 
     58 #else /* SIZEOF_LONG != SIZEOF_LONG_LONG */
     59 
     60 #include <linux/unistd.h>
     61 
     62 #ifndef __NR__llseek
     63 #define __NR__llseek            140
     64 #endif
     65 
     66 #ifndef __i386__
     67 static int _llseek (unsigned int, unsigned long,
     68 		   unsigned long, ext2_loff_t *, unsigned int);
     69 
     70 static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high,
     71 		 unsigned long, offset_low,ext2_loff_t *,result,
     72 		 unsigned int, origin)
     73 #endif
     74 
     75 static ext2_loff_t my_llseek (int fd, ext2_loff_t offset, int origin)
     76 {
     77 	ext2_loff_t result;
     78 	int retval;
     79 
     80 #ifndef __i386__
     81 	retval = _llseek(fd, ((unsigned long long) offset) >> 32,
     82 #else
     83 	retval = syscall(__NR__llseek, fd, (unsigned long long) (offset >> 32),
     84 #endif
     85 			  ((unsigned long long) offset) & 0xffffffff,
     86 			&result, origin);
     87 	return (retval == -1 ? (ext2_loff_t) retval : result);
     88 }
     89 
     90 #endif	/* SIZE_LONG == SIZEOF_LONG_LONG */
     91 
     92 #endif /* HAVE_LLSEEK */
     93 #endif /* defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) */
     94 
     95 ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
     96 {
     97 #if SIZEOF_OFF_T >= SIZEOF_LONG_LONG
     98 	return my_llseek (fd, offset, origin);
     99 #else
    100 	ext2_loff_t result;
    101 	static int do_compat = 0;
    102 
    103 	if (do_compat)
    104 		goto fallback;
    105 
    106 	result = my_llseek (fd, offset, origin);
    107 	if (result == -1 && errno == ENOSYS) {
    108 		/*
    109 		 * Just in case this code runs on top of an old kernel
    110 		 * which does not support the llseek system call
    111 		 */
    112 		do_compat++;
    113 	fallback:
    114 		if (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))
    115 			return lseek(fd, (off_t) offset, origin);
    116 		errno = EINVAL;
    117 		return -1;
    118 	}
    119 	return result;
    120 #endif
    121 }
    122 
    123 #else /* !linux */
    124 
    125 #ifndef EINVAL
    126 #define EINVAL EXT2_ET_INVALID_ARGUMENT
    127 #endif
    128 
    129 ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
    130 {
    131 #if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
    132 	return lseek64 (fd, offset, origin);
    133 #else
    134 	if ((sizeof(off_t) < sizeof(ext2_loff_t)) &&
    135 	    (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) {
    136 		errno = EINVAL;
    137 		return -1;
    138 	}
    139 	return lseek (fd, (off_t) offset, origin);
    140 #endif
    141 }
    142 
    143 #endif 	/* linux */
    144 
    145 
    146