What does #define __REDIRECT_NTH do in unistd.h?
Asked Answered
E

3

6

GNU unistd.h has this bit of magic:

/* Move FD's file position to OFFSET bytes from the
   beginning of the file (if WHENCE is SEEK_SET),
   the current position (if WHENCE is SEEK_CUR),
   or the end of the file (if WHENCE is SEEK_END).
   Return the new file position.  */
#ifndef __USE_FILE_OFFSET64
extern __off_t lseek (int __fd, __off_t __offset, int __whence) __THROW;                                                                    
#else
# ifdef __REDIRECT_NTH
extern __off64_t __REDIRECT_NTH (lseek,
                              (int __fd, __off64_t __offset, int __whence),
                               lseek64);                                                                                                    
# else
#  define lseek lseek64
# endif
#endif
#ifdef __USE_LARGEFILE64
extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence) __THROW;                                                              
#endif

What does __REDIRECT_NTH mean?

Emrick answered 19/12, 2010 at 2:21 Comment(0)
M
10

More detail on what REDIRECT_NTH means: The macro generates a function declaration that tells the compiler to use a specific symbol for the function in the compiler's ELF output. By default, the compiler uses the ELF symbol "lseek" for a C function named "lseek" (or, on some systems, "_lseek"). This macro expands to code that tells the compiler to use the symbol "lseek64" instead. So the C code has a function named "lseek", but when you look in the object code (e.g. with program 'nm'), you see "lseek64".

The purpose of that is that the function really is lseek64 at a binary level - it deals in 64 bit file offsets. But the source code has declared that it wants to call it lseek, for backward source compatibility reasons (that's what _FILE_OFFSET_BITS=64 says).

If the source program wants to call lseek64 by that name, and have lseek refer to the old 32 bit version, it must define _LARGEFILE64_SOURCE and not _FILE_OFFSET_BITS=64.

By the way, the "NTH" in "REDIRECT_NTH" refers to "no throw," which is an attribute of the function declaration the macro generates.

Michaella answered 28/11, 2013 at 20:45 Comment(1)
Wow. Thanks for the details. It's great to have this documented.Emrick
D
2

It is a macro in the namespace reserved to the implementation. It only appears on your platform; it does whatever is appropriate on your platform because the implementation decided it is correct.

If you can't find out easily, you probably shouldn't be using it directly. Even if you can find out, there's a good chance you should not be using it directly.

That said, it looks as though it arranges for calls to lseek() to be translated to lseek64(), presumably to provide support for large files (bigger than 2 GiB) on 32-bit machines (or under the 32-bit system API on your 64-bit machine).

Duodecimo answered 19/12, 2010 at 2:25 Comment(10)
It's actually doing the reverse. Because of all of those squirlly #defines, it's actually defining lseek() to take a 64-bit number as the second argument and lseek64 is not being prototyped. However lseek64 is still in the library. My problem is that my code needs to run on many different systems, so I explicitly check to see if lseek64 is available and, if so, I use it. On this system (FC14) I'm getting the error that there is no prototype for lseek64. Of course, I could just create one myself. I'd rather not go through all of this nonsense...Emrick
... but if I don't do the nonsense, my program breaks on all sorts of legacy systems that are still in use.Emrick
@vy32: OK - it is hard to tell which way round it is working without knowing the platform or seeing the macro definition. How are you doing your test for lseek64()? Are you using autoconf or one its relatives? If lseek64() is being defined (in the library) not prototyped, you have to make a judgement call - do you provide an appropriate declaration for it, or do you fall back on lseek(). Presumably, your code has appropriate mappable type definitions such that you can handle all the types you need (32-bit or 64-bit) and you can determine the correct values/names on this platform.Duodecimo
@jonathan leffler - Thanks for your comments. The unistd.h is the standard GNU unistd.h from FC14 (also present on Debian). My code won't work on a system without a 64-bit lseek. I guess I just need to prototype it. It's very frustrating. I wish there was some easy way to detect non-standard implementations.Emrick
@vy32: FC14? Fedora Core version 14? And didn't you say that the macro ensures that lseek() is equipped with a 64-bit offset, so you should just use that, shouldn't you? There's no need for lseek64() when lseek() is equipped for 64-bit offsets.Duodecimo
@Jonathan, yes Fedora Core 14. The problem is that there is no obvious way to test lseek() in autoconf to see if it is a real 64-bit version of lseek (as it is on FC14), or an old, broken version of lseek() on systems that provide a 32-bit lseek() and a 64-bit lseek64() (there are many of these systems still in use).Emrick
@vy32: Can't you just test for the length of off_t?Control
Yes, you can test for length of off_t. That's going to be a runtime test that you can't do with an #ifdef. So what do you do if it turns out that off_t is 32 bits? And what do you do on systems that don't have off_t? The mingw cross-compiler defines lseek as lseek(int,long,int) and has a separate lseek64.Emrick
Send a bug report to the mingw team. There's no excuse for them to export broken interfaces when the correct ones exist. In the mean time, adding your own hackish fixes (#define lseek lseek64 etc.) in a file that is isolated and will never be included on conformant systems is probably the best bet. Forget __REDIRECT_NTH. It's a hack to make the ugly way glibc does large file support slightly less non-conformant than it would otherwise be.Anthropo
@vy32: This is exactly the kind of problem that configure scripts were invented to solve.Control
A
0

Never touch the largefile hacks yourself. Always include -D_FILE_OFFSET_BITS=64 in your CFLAGS and you can never go wrong.

Anthropo answered 19/12, 2010 at 14:31 Comment(5)
Well, actually, that's not true. I have -D_FILE_OFFSET_BITS=64 in my configure file. The problem is that people are using my code on versions of Unix that do not have _FILE_OFFSET_BITS.Emrick
Do these versions of unix have a different way to enable a 64-bit file offset compilation environment? Try sysconf _POSIX_V6_ILP32_OFFBIG or similar. If they don't, then IMO you shouldn't try hacking the OS to force it. Just tell users of these broken systems they should complain to their vendor to fix large file support or switch to a decent OS.Anthropo
your recommendation is really not an option in most environments.Emrick
@vy32: Which part? I'm not aware of any implementation that makes you roll your own hacks copying and pasting macros from the glibc headers to get 64-bit off_t...Anthropo
Telling my users that their systems are broken and they should fix or upgrade is not an option. They have their systems and my software has to work on them. Period, end of story.Emrick

© 2022 - 2024 — McMap. All rights reserved.