1 /* Convert between the kernel's `struct stat' format, and libc's.
2    Copyright (C) 1991-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <kernel_stat.h>
22 #include <sysdep.h>
23 
24 #if !STAT_IS_KERNEL_STAT
25 
26 #include <string.h>
27 
28 
29 #if XSTAT_IS_XSTAT64
30 int
__xstat_conv(int vers,struct kernel_stat * kbuf,void * ubuf)31 __xstat_conv (int vers, struct kernel_stat *kbuf, void *ubuf)
32 {
33   switch (vers)
34     {
35     case _STAT_VER_KERNEL:
36       /* Nothing to do.  The struct is in the form the kernel expects.
37          We should have short-circuted before we got here, but for
38          completeness... */
39       *(struct kernel_stat *) ubuf = *kbuf;
40       break;
41 
42     case _STAT_VER_LINUX:
43       {
44 	struct stat *buf = ubuf;
45 
46 	/* Convert to current kernel version of `struct stat'.  */
47 	buf->st_dev = kbuf->st_dev;
48 #ifdef _HAVE_STAT___PAD1
49 	buf->__pad1 = 0;
50 #endif
51 	buf->st_ino = kbuf->st_ino;
52 	buf->st_mode = kbuf->st_mode;
53 	buf->st_nlink = kbuf->st_nlink;
54 	buf->st_uid = kbuf->st_uid;
55 	buf->st_gid = kbuf->st_gid;
56 	buf->st_rdev = kbuf->st_rdev;
57 #ifdef _HAVE_STAT___PAD2
58 	buf->__pad2 = 0;
59 #endif
60 	buf->st_size = kbuf->st_size;
61 	buf->st_blksize = kbuf->st_blksize;
62 	buf->st_blocks = kbuf->st_blocks;
63 #ifdef _HAVE_STAT_NSEC
64 	buf->st_atim.tv_sec = kbuf->st_atim.tv_sec;
65 	buf->st_atim.tv_nsec = kbuf->st_atim.tv_nsec;
66 	buf->st_mtim.tv_sec = kbuf->st_mtim.tv_sec;
67 	buf->st_mtim.tv_nsec = kbuf->st_mtim.tv_nsec;
68 	buf->st_ctim.tv_sec = kbuf->st_ctim.tv_sec;
69 	buf->st_ctim.tv_nsec = kbuf->st_ctim.tv_nsec;
70 #else
71 	buf->st_atime = kbuf->st_atime;
72 	buf->st_mtime = kbuf->st_mtime;
73 	buf->st_ctime = kbuf->st_ctime;
74 #endif
75 #ifdef _HAVE_STAT___UNUSED1
76 	buf->__glibc_reserved1 = 0;
77 #endif
78 #ifdef _HAVE_STAT___UNUSED2
79 	buf->__glibc_reserved2 = 0;
80 #endif
81 #ifdef _HAVE_STAT___UNUSED3
82 	buf->__glibc_reserved3 = 0;
83 #endif
84 #ifdef _HAVE_STAT___UNUSED4
85 	buf->__glibc_reserved4 = 0;
86 #endif
87 #ifdef _HAVE_STAT___UNUSED5
88 	buf->__glibc_reserved5 = 0;
89 #endif
90       }
91       break;
92 
93     default:
94       return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
95     }
96 
97   return 0;
98 }
99 #endif
100 
101 int
__xstat64_conv(int vers,struct kernel_stat * kbuf,void * ubuf)102 __xstat64_conv (int vers, struct kernel_stat *kbuf, void *ubuf)
103 {
104 #if XSTAT_IS_XSTAT64
105   return __xstat_conv (vers, kbuf, ubuf);
106 #else
107   switch (vers)
108     {
109     case _STAT_VER_LINUX:
110       {
111 	struct stat64 *buf = ubuf;
112 
113 	/* Convert to current kernel version of `struct stat64'.  */
114 	buf->st_dev = kbuf->st_dev;
115 #ifdef _HAVE_STAT64___PAD1
116 	buf->__pad1 = 0;
117 #endif
118 	buf->st_ino = kbuf->st_ino;
119 #ifdef _HAVE_STAT64___ST_INO
120 	buf->__st_ino = kbuf->st_ino;
121 #endif
122 	buf->st_mode = kbuf->st_mode;
123 	buf->st_nlink = kbuf->st_nlink;
124 	buf->st_uid = kbuf->st_uid;
125 	buf->st_gid = kbuf->st_gid;
126 	buf->st_rdev = kbuf->st_rdev;
127 #ifdef _HAVE_STAT64___PAD2
128 	buf->__pad2 = 0;
129 #endif
130 	buf->st_size = kbuf->st_size;
131 	buf->st_blksize = kbuf->st_blksize;
132 	buf->st_blocks = kbuf->st_blocks;
133 #ifdef _HAVE_STAT64_NSEC
134 	buf->st_atim.tv_sec = kbuf->st_atim.tv_sec;
135 	buf->st_atim.tv_nsec = kbuf->st_atim.tv_nsec;
136 	buf->st_mtim.tv_sec = kbuf->st_mtim.tv_sec;
137 	buf->st_mtim.tv_nsec = kbuf->st_mtim.tv_nsec;
138 	buf->st_ctim.tv_sec = kbuf->st_ctim.tv_sec;
139 	buf->st_ctim.tv_nsec = kbuf->st_ctim.tv_nsec;
140 #else
141 	buf->st_atime = kbuf->st_atime;
142 	buf->st_mtime = kbuf->st_mtime;
143 	buf->st_ctime = kbuf->st_ctime;
144 #endif
145 #ifdef _HAVE_STAT64___UNUSED1
146 	buf->__glibc_reserved1 = 0;
147 #endif
148 #ifdef _HAVE_STAT64___UNUSED2
149 	buf->__glibc_reserved2 = 0;
150 #endif
151 #ifdef _HAVE_STAT64___UNUSED3
152 	buf->__glibc_reserved3 = 0;
153 #endif
154 #ifdef _HAVE_STAT64___UNUSED4
155 	buf->__glibc_reserved4 = 0;
156 #endif
157 #ifdef _HAVE_STAT64___UNUSED5
158 	buf->__glibc_reserved5 = 0;
159 #endif
160       }
161       break;
162 
163       /* If struct stat64 is different from struct stat then
164 	 _STAT_VER_KERNEL does not make sense.  */
165     case _STAT_VER_KERNEL:
166     default:
167       return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
168     }
169 
170   return 0;
171 #endif
172 }
173 
174 int
__xstat32_conv(int vers,struct stat64 * kbuf,struct stat * buf)175 __xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
176 {
177   switch (vers)
178     {
179     case _STAT_VER_LINUX:
180       {
181 	/* Convert current kernel version of `struct stat64' to
182            `struct stat'.  */
183 	buf->st_dev = kbuf->st_dev;
184 #ifdef _HAVE_STAT___PAD1
185 	buf->__pad1 = 0;
186 #endif
187 	buf->st_ino = kbuf->st_ino;
188 	if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino)
189 	    && buf->st_ino != kbuf->st_ino)
190 	  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
191 	buf->st_mode = kbuf->st_mode;
192 	buf->st_nlink = kbuf->st_nlink;
193 	buf->st_uid = kbuf->st_uid;
194 	buf->st_gid = kbuf->st_gid;
195 	buf->st_rdev = kbuf->st_rdev;
196 #ifdef _HAVE_STAT___PAD2
197 	buf->__pad2 = 0;
198 #endif
199 	buf->st_size = kbuf->st_size;
200 	/* Check for overflow.  */
201 	if (sizeof (buf->st_size) != sizeof (kbuf->st_size)
202 	    && buf->st_size != kbuf->st_size)
203 	  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
204 	buf->st_blksize = kbuf->st_blksize;
205 	buf->st_blocks = kbuf->st_blocks;
206 	/* Check for overflow.  */
207 	if (sizeof (buf->st_blocks) != sizeof (kbuf->st_blocks)
208 	    && buf->st_blocks != kbuf->st_blocks)
209 	  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
210 #ifdef _HAVE_STAT_NSEC
211 	buf->st_atim.tv_sec = kbuf->st_atim.tv_sec;
212 	buf->st_atim.tv_nsec = kbuf->st_atim.tv_nsec;
213 	buf->st_mtim.tv_sec = kbuf->st_mtim.tv_sec;
214 	buf->st_mtim.tv_nsec = kbuf->st_mtim.tv_nsec;
215 	buf->st_ctim.tv_sec = kbuf->st_ctim.tv_sec;
216 	buf->st_ctim.tv_nsec = kbuf->st_ctim.tv_nsec;
217 #else
218 	buf->st_atime = kbuf->st_atime;
219 	buf->st_mtime = kbuf->st_mtime;
220 	buf->st_ctime = kbuf->st_ctime;
221 #endif
222 
223 #ifdef _HAVE_STAT___UNUSED1
224 	buf->__glibc_reserved1 = 0;
225 #endif
226 #ifdef _HAVE_STAT___UNUSED2
227 	buf->__glibc_reserved2 = 0;
228 #endif
229 #ifdef _HAVE_STAT___UNUSED3
230 	buf->__glibc_reserved3 = 0;
231 #endif
232 #ifdef _HAVE_STAT___UNUSED4
233 	buf->__glibc_reserved4 = 0;
234 #endif
235 #ifdef _HAVE_STAT___UNUSED5
236 	buf->__glibc_reserved5 = 0;
237 #endif
238       }
239       break;
240 
241       /* If struct stat64 is different from struct stat then
242 	 _STAT_VER_KERNEL does not make sense.  */
243     case _STAT_VER_KERNEL:
244     default:
245       return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
246     }
247 
248   return 0;
249 }
250 
251 #endif
252