1 /* 2 * llseek.c -- stub calling the llseek system call 3 * 4 * Copyright (C) 1994 Remy Card. This file may be redistributed 5 * under the terms of the GNU Public License. 6 * 7 * This file is borrowed from the util-linux-2.10q tarball's implementation 8 * of fdisk. It allows seeks to 64 bit offsets, if supported. 9 * Changed "ext2_" prefix to "llse". 10 */ 11 12 #include <sys/types.h> 13 14 #include <errno.h> 15 #include <unistd.h> 16 #include <syscall.h> 17 #include <linux/unistd.h> /* for __NR_llseek */ 18 19 #if defined(__GNUC__) || defined(HAS_LONG_LONG) 20 typedef long long llse_loff_t; 21 #else 22 typedef long llse_loff_t; 23 #endif 24 25 extern llse_loff_t llse_llseek(unsigned int, llse_loff_t, unsigned int); 26 27 #ifdef __linux__ 28 29 #if defined(__alpha__) || defined(__ia64__) 30 31 #ifdef __NR_lseek 32 static off_t my_lseek(int fd, off_t off, int whence) 33 { 34 return syscall(__NR_lseek, fd, off, whence); 35 } 36 #else /* undefined __NR_lseek */ 37 static off_t my_lseek(int fd, off_t off, int whence) 38 { 39 errno = ENOSYS; 40 return -1; 41 } 42 #endif /* __NR_lseek */ 43 44 #define my_llseek my_lseek 45 46 #else /* !__alpha__ && !__ia64__ */ 47 48 static int _llseek(unsigned int, unsigned long, 49 unsigned long, llse_loff_t *, unsigned int); 50 51 #ifndef __NR_llseek 52 /* no __NR_llseek on compilation machine - might give it explicitly */ 53 static int _llseek(unsigned int fd, unsigned long oh, 54 unsigned long ol, llse_loff_t * result, unsigned int origin) 55 { 56 errno = ENOSYS; 57 return -1; 58 } 59 #else 60 static int _llseek(unsigned int fd, unsigned long oh, 61 unsigned long ol, llse_loff_t * result, unsigned int origin) 62 { 63 return syscall(__NR_llseek, fd, oh, ol, result, origin); 64 } 65 #endif 66 67 static llse_loff_t my_llseek(unsigned int fd, llse_loff_t offset, 68 unsigned int origin) 69 { 70 llse_loff_t result; 71 int retval; 72 73 retval = _llseek(fd, ((unsigned long long)offset) >> 32, 74 ((unsigned long long)offset) & 0xffffffff, 75 &result, origin); 76 return (retval == -1 ? (llse_loff_t) retval : result); 77 } 78 79 #endif /* __alpha__ */ 80 81 llse_loff_t llse_llseek(unsigned int fd, llse_loff_t offset, 82 unsigned int origin) 83 { 84 llse_loff_t result; 85 static int do_compat = 0; 86 87 if (!do_compat) { 88 result = my_llseek(fd, offset, origin); 89 if (!(result == -1 && errno == ENOSYS)) 90 return result; 91 92 /* 93 * Just in case this code runs on top of an old kernel 94 * which does not support the llseek system call 95 */ 96 do_compat = 1; 97 /* 98 * Now try ordinary lseek. 99 */ 100 } 101 102 if ((sizeof(off_t) >= sizeof(llse_loff_t)) || 103 (offset < ((llse_loff_t) 1 << ((sizeof(off_t) * 8) - 1)))) 104 return lseek(fd, (off_t) offset, origin); 105 106 errno = EINVAL; 107 return -1; 108 } 109 110 #else /* !linux */ 111 112 llse_loff_t llse_llseek(unsigned int fd, llse_loff_t offset, 113 unsigned int origin) 114 { 115 if ((sizeof(off_t) < sizeof(llse_loff_t)) && 116 (offset >= ((llse_loff_t) 1 << ((sizeof(off_t) * 8) - 1)))) { 117 errno = EINVAL; 118 return -1; 119 } 120 return lseek(fd, (off_t) offset, origin); 121 } 122 123 #endif /* linux */ 124