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