aboutsummaryrefslogtreecommitdiff
path: root/toolchain/uClibc/uClibc-0.9.33-lstat-stat-fstat-Use-64bit-version-of-syscall.patch
blob: a9d1c960c3f5fd4b3c4ff28e27ad99d8b374cd6b (plain)
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
From b813377f6c746118a9d2625e6b29ffeec4233663 Mon Sep 17 00:00:00 2001
From: Khem Raj <raj.khem@gmail.com>
Date: Fri, 3 Feb 2012 20:06:55 -0800
Subject: [PATCH 3/4] lstat/stat/fstat: Use 64bit version of syscall if
 available

This is needed for stat'ing loop devices > 255
since otherwise kernel returns EOVERFLOW becasue
it needs st_rdev/st_dev to be larger than 16bits but
in kernel it uses __old_kernel_stat for stat
syscall which has st_rdev/st_dev as unsigned short

Add a testcase

Signed-off-by: Khem Raj <raj.khem@gmail.com>
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
---
 libc/sysdeps/linux/common/fstat.c |   18 ++++++++++++++----
 libc/sysdeps/linux/common/lstat.c |   19 ++++++++++++++-----
 libc/sysdeps/linux/common/stat.c  |   18 ++++++++++++++----
 test/stat/stat-loop256.c          |   32 ++++++++++++++++++++++++++++++++
 4 files changed, 74 insertions(+), 13 deletions(-)
 create mode 100644 test/stat/stat-loop256.c

diff --git a/libc/sysdeps/linux/common/fstat.c b/libc/sysdeps/linux/common/fstat.c
index acc639b..4726a68 100644
--- a/libc/sysdeps/linux/common/fstat.c
+++ b/libc/sysdeps/linux/common/fstat.c
@@ -12,18 +12,28 @@
 #include <sys/stat.h>
 #include "xstatconv.h"
 
-#define __NR___syscall_fstat __NR_fstat
-static __inline__ _syscall2(int, __syscall_fstat, int, fd, struct kernel_stat *, buf)
-
 int fstat(int fd, struct stat *buf)
 {
 	int result;
+#ifdef __NR_fstat64
+	/* normal stat call has limited values for various stat elements
+	 * e.g. uid device major/minor etc.
+	 * so we use 64 variant if available
+	 * in order to get newer versions of stat elements
+	 */
+	struct kernel_stat64 kbuf;
+	result = INLINE_SYSCALL(fstat64, 2, fd, &kbuf);
+	if (result == 0) {
+		__xstat32_conv(&kbuf, buf);
+	}
+#else
 	struct kernel_stat kbuf;
 
-	result = __syscall_fstat(fd, &kbuf);
+	result = INLINE_SYSCALL(fstat, 2, fd, &kbuf);
 	if (result == 0) {
 		__xstat_conv(&kbuf, buf);
 	}
+#endif
 	return result;
 }
 libc_hidden_def(fstat)
diff --git a/libc/sysdeps/linux/common/lstat.c b/libc/sysdeps/linux/common/lstat.c
index aa77447..db72d1f 100644
--- a/libc/sysdeps/linux/common/lstat.c
+++ b/libc/sysdeps/linux/common/lstat.c
@@ -12,19 +12,28 @@
 #include <sys/stat.h>
 #include "xstatconv.h"
 
-#define __NR___syscall_lstat __NR_lstat
-static __inline__ _syscall2(int, __syscall_lstat,
-		const char *, file_name, struct kernel_stat *, buf)
-
 int lstat(const char *file_name, struct stat *buf)
 {
 	int result;
+#ifdef __NR_lstat64
+	/* normal stat call has limited values for various stat elements
+	 * e.g. uid device major/minor etc.
+	 * so we use 64 variant if available
+	 * in order to get newer versions of stat elements
+	 */
+	struct kernel_stat64 kbuf;
+	result = INLINE_SYSCALL(lstat64, 2, file_name, &kbuf);
+	if (result == 0) {
+		__xstat32_conv(&kbuf, buf);
+	}
+#else
 	struct kernel_stat kbuf;
 
-	result = __syscall_lstat(file_name, &kbuf);
+	result = INLINE_SYSCALL(lstat, 2, file_name, &kbuf);
 	if (result == 0) {
 		__xstat_conv(&kbuf, buf);
 	}
+#endif
 	return result;
 }
 libc_hidden_def(lstat)
diff --git a/libc/sysdeps/linux/common/stat.c b/libc/sysdeps/linux/common/stat.c
index a6ab291..829f35a 100644
--- a/libc/sysdeps/linux/common/stat.c
+++ b/libc/sysdeps/linux/common/stat.c
@@ -12,20 +12,30 @@
 #include <sys/stat.h>
 #include "xstatconv.h"
 
-#define __NR___syscall_stat __NR_stat
 #undef stat
-static __inline__ _syscall2(int, __syscall_stat,
-		const char *, file_name, struct kernel_stat *, buf)
 
 int stat(const char *file_name, struct stat *buf)
 {
 	int result;
+#ifdef __NR_stat64
+	/* normal stat call has limited values for various stat elements
+	 * e.g. uid device major/minor etc.
+	 * so we use 64 variant if available
+	 * in order to get newer versions of stat elements
+	 */
+	struct kernel_stat64 kbuf;
+	result = INLINE_SYSCALL(stat64, 2, file_name, &kbuf);
+	if (result == 0) {
+		__xstat32_conv(&kbuf, buf);
+	}
+#else
 	struct kernel_stat kbuf;
 
-	result = __syscall_stat(file_name, &kbuf);
+	result = INLINE_SYSCALL(stat, 2, file_name, &kbuf);
 	if (result == 0) {
 		__xstat_conv(&kbuf, buf);
 	}
+#endif
 	return result;
 }
 libc_hidden_def(stat)
diff --git a/test/stat/stat-loop256.c b/test/stat/stat-loop256.c
new file mode 100644
index 0000000..14284c1
--- /dev/null
+++ b/test/stat/stat-loop256.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+int main()
+{
+    struct stat statbuf;
+    int ret = 0;
+    char* loop255 = "/dev/loop255";
+    char* loop256 = "/dev/loop256";
+    mode_t mode = 0660;
+    mknod(loop255, mode, 0x7ff);
+    mknod(loop256, mode, 0x100700);
+    ret = stat(loop255, &statbuf);
+    if(ret < 0) {
+	printf("stat: Cant stat %s\n",loop255);
+	unlink(loop255);
+	exit(1);
+    }
+    ret = stat(loop256, &statbuf);
+    if(ret < 0) {
+        printf("stat: Cant stat %s\n",loop256);
+	unlink(loop255);
+	unlink(loop256);
+        exit(1);
+    }
+
+    unlink(loop255);
+    unlink(loop256);
+    exit(0);
+}
+
-- 
1.7.8.3