-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathhelpers.c
143 lines (121 loc) · 4.82 KB
/
helpers.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#define _POSIX_C_SOURCE 201112L
#include <dlfcn.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include "helpers.h"
// we're linking against musl...
struct glibc_dirent
{
#ifndef __USE_FILE_OFFSET64
unsigned long int d_ino;
unsigned long int d_off;
#else
ino64_t d_ino;
off64_t d_off;
#endif
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256]; /* We must not include limits.h! */
};
extern int (*glibc_readdir_r)(void *dir, struct glibc_dirent *entry, struct glibc_dirent **result);
extern void *(*glibc_readdir)(void *dir);
struct bionic_dirent {
uint64_t d_ino;
int64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[256];
};
int my_readdir_r(DIR *dir, struct bionic_dirent *entry,
struct bionic_dirent **result)
{
struct glibc_dirent entry_r;
struct glibc_dirent *result_r;
int res = glibc_readdir_r(dir, &entry_r, &result_r);
if (res == 0) {
if (result_r != NULL) {
*result = entry;
entry->d_ino = entry_r.d_ino;
entry->d_off = entry_r.d_off;
entry->d_reclen = entry_r.d_reclen;
entry->d_type = entry_r.d_type;
memcpy(entry->d_name, entry_r.d_name, sizeof(entry->d_name));
// Make sure the string is zero-terminated, even if cut off (which
// shouldn't happen, as both bionic and glibc have d_name defined
// as fixed array of 256 chars)
entry->d_name[sizeof(entry->d_name) - 1] = '\0';
} else {
*result = NULL;
}
}
return res;
}
struct bionic_dirent *my_readdir(DIR *dirp)
{
/**
* readdir(3) manpage says:
* The data returned by readdir() may be overwritten by subsequent calls
* to readdir() for the same directory stream.
*
* XXX: At the moment, for us, the data will be overwritten even by
* subsequent calls to /different/ directory streams. Eventually fix that
* (e.g. by storing per-DIR * bionic_dirent structs, and removing them on
* closedir, requires hooking of all funcs returning/taking DIR *) and
* handling the additional data attachment there)
**/
static struct bionic_dirent result;
struct glibc_dirent *real_result = glibc_readdir(dirp);
if (!real_result) {
return NULL;
}
result.d_ino = real_result->d_ino;
result.d_off = real_result->d_off;
result.d_reclen = real_result->d_reclen;
result.d_type = real_result->d_type;
memcpy(result.d_name, real_result->d_name, sizeof(result.d_name));
// Make sure the string is zero-terminated, even if cut off (which
// shouldn't happen, as both bionic and glibc have d_name defined
// as fixed array of 256 chars)
result.d_name[sizeof(result.d_name)-1] = '\0';
return &result;
}
static inline void swap(void **a, void **b)
{
void *tmp = *a;
*a = *b;
*b = tmp;
}
extern int (*glibc_getaddrinfo)(const char *hostname, const char *servname,
const void *hints, struct addrinfo **res);
extern int (*glibc_freeaddrinfo)(struct addrinfo *__ai);
int my_getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
// make a local copy of hints
struct addrinfo *fixed_hints = (struct addrinfo*)malloc(sizeof(struct addrinfo));
memcpy(fixed_hints, hints, sizeof(struct addrinfo));
// fix bionic -> glibc missmatch
swap((void**)&(fixed_hints->ai_canonname), (void**)&(fixed_hints->ai_addr));
// do glibc getaddrinfo
int result = glibc_getaddrinfo(hostname, servname, fixed_hints, res);
// release the copy of hints
free(fixed_hints);
// fix bionic <- glibc missmatch
struct addrinfo *it = *res;
while(NULL != it)
{
swap((void**)&(it->ai_canonname), (void**)&(it->ai_addr));
it = it->ai_next;
}
return result;
}
void my_freeaddrinfo(struct addrinfo *__ai)
{
swap((void**)&(__ai->ai_canonname), (void**)&(__ai->ai_addr));
glibc_freeaddrinfo(__ai);
}