readdir() 32/64 compatibility issues
Asked Answered
T

2

7

I'm trying to get some old legacy code working on new 64-bit systems, and I'm currently stuck. Below is a small C file I'm using to test functionality that exists in the actual program that is currently breaking.

#define _POSIX_SOURCE
#include <dirent.h>
#include <sys/types.h>
#undef _POSIX_SOURCE
#include <stdio.h>

main(){
    DIR *dirp;
    struct dirent *dp;
    char *const_dir;

    const_dir = "/any/path/goes/here";

    if(!(dirp = opendir(const_dir)))
        perror("opendir() error");
    else{
        puts("contents of path:");
        while(dp = readdir(dirp))
            printf(" %s\n", dp->d_name);
        closedir(dirp);
    }
}

The Problem:

The OS is Red Hat 7.0 Maipo x86_64. The legacy code is 32-bit, and must be kept that way.

I've gotten the compile for the program working fine using the -m32 flag with g++. The problem that arises is during runtime, readdir() gets a 64-bit inode and then throws an EOVERFLOW errno and of course nothing gets printed out.

I've tried using readdir64() in place of readdir() to some success. I no longer get the errno EOVERFLOW, and the lines come out on the terminal, but the files themselves don't get printed. I'm assuming this is due to the buffer not being what dirent expects.

I've attempted to use dirent64 to try to alleviate this problem but whenever I attempt this I get:

test.c:19:22 error: dereferencing pointer to incomplete type 
  printf(" %s\n", dp->d_name);

I'm wondering if there's a way to manually shift the dp->d_name buffer for dirent to be used with readdir(). I've noticed in Gdb that using readdir() and dirent results in dp->d_name having directories listed at dp->d_name[1], whereas readdir64() and dirent gives the first directory at dp->d_name[8].

That or somehow get dirent64 to work, or maybe I'm just on the wrong path completely.

Lastly, it's worth noting that the program functions perfectly without the -m32 flag included, so I'm assuming it has to be a 32/64 compatibility error somewhere. Any help is appreciated.

Topheavy answered 18/12, 2014 at 19:35 Comment(3)
Why don't you simply define the missing type and use dirent64?Ola
You mean define dirent64 the same way it's defined in dirent.h only in my program?Topheavy
That...actually worked perfectly after yanking the struct out of bits/dirent.h and just putting it manually in my code. I'm sure there's a define somewhere that can probably used instead but this works for now. Thanks!Topheavy
T
1

Thanks to @Martin in the comments above I was led to try defining the dirent64 struct in my code. This works. There's probably a #define that can be used to circumvent pasting libc .h code into my own code, but this works for now.

The code I needed was found in <bits/dirent.h>

I guess I should also note that this makes it work using both readdir64() and dirent64

Topheavy answered 18/12, 2014 at 20:31 Comment(3)
And why don't you include <bits/dirent.h> in your program?Manhandle
The code in dirent.h is under some #define, so the preprocessor throws it away. There is some compilation flag that has to be defined in order to enable the 64-bit code in dirent.h. The page here suggests _FILE_OFFSET_BITS=64.Hardhack
Yeah I tried using a bunch of the #define's found in the .h files but I never got it to pick up dirent64 with it. I can't include <bits/dirent.h> unfortunately, if you open up that header files it specifies not to directly include it, but instead include <dirent.h> and use #defines to access it's functionality :(Topheavy
E
1

In order to get a 64-bit ino_t with GCC and Glibc, you need to define the features _XOPEN_SOURCE and _FILE_OFFSET_BITS=64.

$ echo '#include <dirent.h>' | gcc -m32 -E -D_XOPEN_SOURCE -D_FILE_OFFSET_BITS=64 - | grep ino
__extension__ typedef unsigned long int __ino_t;
__extension__ typedef __u_quad_t __ino64_t;
typedef __ino64_t ino_t;
    __ino64_t d_ino;

I say this from documentation reading and checking the preprocessor, not from deep experience or testing with a filesystem with inode numbers above 2^32, so I don't guarantee that you won't run into other problems down the line.

Exotic answered 20/12, 2014 at 12:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.