-
Notifications
You must be signed in to change notification settings - Fork 0
/
inode64.c
263 lines (229 loc) · 7.25 KB
/
inode64.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/* A library for fixing programs which object to 64 bit inodes on Linux.
*
* (c) 15/8/2014, MJ Rutter
*
* Can be distributed under the Gnu Public Licence version 2
* ( http://www.gnu.org/licenses/gpl-2.0.html )
*
* WARNING!! USE AT OWN RISK -- AUTHOR ACCEPTS NO RESPONSIBILITY
* IF THIS DESTROYS YOUR DATA, OR CAUSES ANY OTHER FORM OF INCONVENIENCE
* OR DISASTER. AUTHOR RECOMMENDS YOU DO NOT USE IT.
*
*
* Problem: if a filesystem has 64 bit inodes, 32 bit programs calling
* *stat() or readdir() will get EOVERFLOW unless they have been compiled
* with large file support. However, it is likely that the only field which
* overflows is the inode number, which is usually ignored.
*
* This library forces the inode number to 32 bits, and returns the rest
* of the structure correctly. It is similar to mounting an NFS filesystem
* with the kernel parameter nfs.enable_ino64=0
*
* To build:
*
* 1/ Create a linker script called "vers" containing:
*
GLIBC_2.0 {
global:
readdir;
__fxstat;
__xstat;
__lxstat;
};
*
* 2/ compile:
*
* gcc -c -fPIC -m32 inode64.c
*
* (Some reports say "gcc -c -fPIC -m32 -fno-stack-protector inode64.c"
* but I am no longer in a position to check.)
*
* 3/ link
*
* ld -shared -melf_i386 --version-script vers -o inode64.so inode64.o
*
* Then use by pointing LD_PRELOAD to the library
*
*
* Bugs:
*
* 1/ No attempt is made to fix readdir_r()
*
* 2/ readdir() overwrites its buffer on every call, even on calls to
* different directory streams
*
* If compiled with INPLACE defined (the default), then the returned structure
* from readdir64() is modified in place, and this bug does not apply. Does
* POSIX permit modifying the returned structure? Unclear to me...
*
*/
#define INPLACE
#include<stdlib.h>
#include<bits/types.h>
#include<stdint.h>
#include<unistd.h>
#include<errno.h>
struct dirent32 {
uint32_t d_ino; /* inode number */
uint32_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
#ifdef INPLACE
struct dirent64 {
uint64_t d_ino; /* inode number */
union {
uint64_t d_off; /* not an offset; see NOTES */
uint32_t i32[2];
} fudge;
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
#else
struct dirent64 {
uint64_t d_ino; /* inode number */
uint64_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
#endif
struct stat32 {
dev_t st_dev; /* ID of device containing file */
unsigned short int pad1;
uint32_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
unsigned short int pad2;
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last status change */
uint32_t unused1;
uint32_t unused2;
};
struct stat64 {
dev_t st_dev; /* ID of device containing file */
unsigned short int pad1;
uint32_t st_ino32; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
// unsigned short int pad2;
unsigned int pad2;
uint64_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
uint64_t st_blocks; /* number of 512B blocks allocated */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last status change */
uint64_t st_ino;
};
typedef struct __dirstream DIR;
struct dirent64 *readdir64(DIR *dirp);
#ifdef INPLACE
struct dirent32 *readdir(DIR *dirp){
struct dirent64 *ptr;
int inode,ioff;
ptr=readdir64(dirp);
if (!ptr) return NULL;
inode=ptr->d_ino^(ptr->d_ino>>32);
ioff=ptr->fudge.d_off;
ptr->fudge.i32[0]=inode;
ptr->fudge.i32[1]=ioff;
ptr->d_reclen-=8;
return (struct dirent32 *)&(ptr->fudge);
}
#else
struct dirent32 *readdir(DIR *dirp){
static struct dirent32 d32;
struct dirent64 *ptr;
int i;
ptr=readdir64(dirp);
if (!ptr) return NULL;
d32.d_ino=ptr->d_ino^(ptr->d_ino>>32);
d32.d_off=ptr->d_off;
d32.d_reclen=ptr->d_reclen-8;
d32.d_type=ptr->d_type;
for(i=0;i<256;i++) d32.d_name[i]=ptr->d_name[i];
return &d32;
}
#endif
int __fxstat64 (int ver, int fd, struct stat64 *buf);
int __fxstat (int ver, int fd, struct stat32 *buf){
struct stat64 s64;
int i;
i=__fxstat64(ver,fd,&s64);
if (i) return i;
buf->st_dev=s64.st_dev;
buf->st_ino=s64.st_ino^(s64.st_ino>>32);
buf->st_mode=s64.st_mode;
buf->st_nlink=s64.st_nlink;
buf->st_uid=s64.st_uid;
buf->st_gid=s64.st_gid;
buf->st_rdev=s64.st_rdev;
if (s64.st_size>>32) {errno=EOVERFLOW; return -1;}
buf->st_size=s64.st_size;
buf->st_blksize=s64.st_blksize;
buf->st_blocks=s64.st_blocks;
buf->st_atim=s64.st_atim;
buf->st_mtim=s64.st_mtim;
buf->st_ctim=s64.st_ctim;
return 0;
}
int __xstat64 (int ver, const char *path, struct stat64 *buf);
int __xstat (int ver, const char* path, struct stat32 *buf){
struct stat64 s64;
int i;
i=__xstat64(ver,path,&s64);
if (i) return i;
buf->st_dev=s64.st_dev;
buf->st_ino=s64.st_ino^(s64.st_ino>>32);
buf->st_mode=s64.st_mode;
buf->st_nlink=s64.st_nlink;
buf->st_uid=s64.st_uid;
buf->st_gid=s64.st_gid;
buf->st_rdev=s64.st_rdev;
if (s64.st_size>>32) {errno=EOVERFLOW; return -1;}
buf->st_size=s64.st_size;
buf->st_blksize=s64.st_blksize;
buf->st_blocks=s64.st_blocks;
buf->st_atim=s64.st_atim;
buf->st_mtim=s64.st_mtim;
buf->st_ctim=s64.st_ctim;
return 0;
}
int __lxstat64 (int ver, const char *path, struct stat64 *buf);
int __lxstat (int ver, const char* path, struct stat32 *buf){
struct stat64 s64;
int i;
i=__lxstat64(ver,path,&s64);
if (i) return i;
buf->st_dev=s64.st_dev;
buf->st_ino=s64.st_ino^(s64.st_ino>>32);
buf->st_mode=s64.st_mode;
buf->st_nlink=s64.st_nlink;
buf->st_uid=s64.st_uid;
buf->st_gid=s64.st_gid;
buf->st_rdev=s64.st_rdev;
if (s64.st_size>>32) {errno=EOVERFLOW; return -1;}
buf->st_size=s64.st_size;
buf->st_blksize=s64.st_blksize;
buf->st_blocks=s64.st_blocks;
buf->st_atim=s64.st_atim;
buf->st_mtim=s64.st_mtim;
buf->st_ctim=s64.st_ctim;
return 0;
}