]>
Commit | Line | Data |
---|---|---|
0d83b42e | 1 | /* Get file-specific information about a file. Linux version. |
688903eb | 2 | Copyright (C) 1991-2018 Free Software Foundation, Inc. |
24f25de6 UD |
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 | |
41bdb6e2 AJ |
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. | |
24f25de6 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
24f25de6 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
24f25de6 | 18 | |
9c7ff11a | 19 | #include <errno.h> |
4e5f31c8 UD |
20 | #include <mntent.h> |
21 | #include <stdio_ext.h> | |
bfc9dc9b | 22 | #include <string.h> |
4e5f31c8 UD |
23 | #include <unistd.h> |
24 | #include <sys/sysmacros.h> | |
443db178 | 25 | |
0d83b42e | 26 | #include "pathconf.h" |
9c7ff11a | 27 | #include "linux_fsinfo.h" |
443db178 | 28 | #include <not-cancel.h> |
24f25de6 | 29 | |
0d83b42e | 30 | static long int posix_pathconf (const char *file, int name); |
24f25de6 | 31 | |
0d83b42e RM |
32 | /* Define this first, so it can be inlined. */ |
33 | #define __pathconf static posix_pathconf | |
34 | #include <sysdeps/posix/pathconf.c> | |
24f25de6 UD |
35 | |
36 | ||
0d83b42e | 37 | /* Get file-specific information about FILE. */ |
24f25de6 | 38 | long int |
0d83b42e | 39 | __pathconf (const char *file, int name) |
24f25de6 | 40 | { |
69c708ed RM |
41 | struct statfs fsbuf; |
42 | ||
43 | switch (name) | |
24f25de6 | 44 | { |
69c708ed | 45 | case _PC_LINK_MAX: |
4e5f31c8 | 46 | return __statfs_link_max (__statfs (file, &fsbuf), &fsbuf, file, -1); |
564cd8b6 | 47 | |
69c708ed | 48 | case _PC_FILESIZEBITS: |
9c7ff11a | 49 | return __statfs_filesize_max (__statfs (file, &fsbuf), &fsbuf); |
564cd8b6 UD |
50 | |
51 | case _PC_2_SYMLINKS: | |
9c7ff11a | 52 | return __statfs_symlinks (__statfs (file, &fsbuf), &fsbuf); |
564cd8b6 | 53 | |
443db178 UD |
54 | case _PC_CHOWN_RESTRICTED: |
55 | return __statfs_chown_restricted (__statfs (file, &fsbuf), &fsbuf); | |
56 | ||
69c708ed RM |
57 | default: |
58 | return posix_pathconf (file, name); | |
24f25de6 | 59 | } |
24f25de6 | 60 | } |
9c7ff11a UD |
61 | |
62 | ||
4e5f31c8 UD |
63 | static long int |
64 | distinguish_extX (const struct statfs *fsbuf, const char *file, int fd) | |
65 | { | |
66 | char buf[64]; | |
67 | char path[PATH_MAX]; | |
68 | struct stat64 st; | |
69 | ||
70 | if ((file == NULL ? fstat64 (fd, &st) : stat64 (file, &st)) != 0) | |
71 | /* Strange. The statfd call worked, but stat fails. Default to | |
72 | the more pessimistic value. */ | |
73 | return EXT2_LINK_MAX; | |
74 | ||
75 | __snprintf (buf, sizeof (buf), "/sys/dev/block/%u:%u", | |
76 | gnu_dev_major (st.st_dev), gnu_dev_minor (st.st_dev)); | |
77 | ||
78 | ssize_t n = __readlink (buf, path, sizeof (path)); | |
79 | if (n != -1 && n < sizeof (path)) | |
80 | { | |
81 | path[n] = '\0'; | |
cf06a4e3 | 82 | char *base = strdupa (__basename (path)); |
4e5f31c8 UD |
83 | __snprintf (path, sizeof (path), "/sys/fs/ext4/%s", base); |
84 | ||
85 | return __access (path, F_OK) == 0 ? EXT4_LINK_MAX : EXT2_LINK_MAX; | |
86 | } | |
87 | ||
88 | /* XXX Is there a better way to distinguish ext2/3 from ext4 than | |
89 | iterating over the mounted filesystems and compare the device | |
90 | numbers? */ | |
91 | FILE *mtab = __setmntent ("/proc/mounts", "r"); | |
92 | if (mtab == NULL) | |
93 | mtab = __setmntent (_PATH_MOUNTED, "r"); | |
94 | ||
95 | /* By default be conservative. */ | |
96 | long int result = EXT2_LINK_MAX; | |
97 | if (mtab != NULL) | |
98 | { | |
99 | struct mntent mntbuf; | |
100 | char tmpbuf[1024]; | |
101 | ||
102 | /* No locking needed. */ | |
103 | (void) __fsetlocking (mtab, FSETLOCKING_BYCALLER); | |
104 | ||
105 | while (__getmntent_r (mtab, &mntbuf, tmpbuf, sizeof (tmpbuf))) | |
106 | { | |
107 | if (strcmp (mntbuf.mnt_type, "ext2") != 0 | |
108 | && strcmp (mntbuf.mnt_type, "ext3") != 0 | |
109 | && strcmp (mntbuf.mnt_type, "ext4") != 0) | |
110 | continue; | |
111 | ||
112 | struct stat64 fsst; | |
113 | if (stat64 (mntbuf.mnt_dir, &fsst) >= 0 | |
114 | && st.st_dev == fsst.st_dev) | |
115 | { | |
116 | if (strcmp (mntbuf.mnt_type, "ext4") == 0) | |
117 | result = EXT4_LINK_MAX; | |
118 | break; | |
119 | } | |
120 | } | |
121 | ||
122 | /* Close the file. */ | |
123 | __endmntent (mtab); | |
124 | } | |
125 | ||
126 | return result; | |
127 | } | |
128 | ||
129 | ||
9c7ff11a UD |
130 | /* Used like: return statfs_link_max (__statfs (name, &buf), &buf); */ |
131 | long int | |
4e5f31c8 UD |
132 | __statfs_link_max (int result, const struct statfs *fsbuf, const char *file, |
133 | int fd) | |
9c7ff11a UD |
134 | { |
135 | if (result < 0) | |
136 | { | |
137 | if (errno == ENOSYS) | |
138 | /* Not possible, return the default value. */ | |
139 | return LINUX_LINK_MAX; | |
140 | ||
141 | /* Some error occured. */ | |
142 | return -1; | |
143 | } | |
144 | ||
145 | switch (fsbuf->f_type) | |
146 | { | |
147 | case EXT2_SUPER_MAGIC: | |
4e5f31c8 UD |
148 | /* Unfortunately the kernel does not return a different magic number |
149 | for ext4. This would be necessary to easily detect etx4 since it | |
150 | has a different LINK_MAX value. Therefore we have to find it out | |
151 | the hard way. */ | |
152 | return distinguish_extX (fsbuf, file, fd); | |
9c7ff11a | 153 | |
67525cb8 AJ |
154 | case F2FS_SUPER_MAGIC: |
155 | return F2FS_LINK_MAX; | |
156 | ||
9c7ff11a UD |
157 | case MINIX_SUPER_MAGIC: |
158 | case MINIX_SUPER_MAGIC2: | |
159 | return MINIX_LINK_MAX; | |
160 | ||
161 | case MINIX2_SUPER_MAGIC: | |
162 | case MINIX2_SUPER_MAGIC2: | |
163 | return MINIX2_LINK_MAX; | |
164 | ||
165 | case XENIX_SUPER_MAGIC: | |
166 | return XENIX_LINK_MAX; | |
167 | ||
168 | case SYSV4_SUPER_MAGIC: | |
169 | case SYSV2_SUPER_MAGIC: | |
170 | return SYSV_LINK_MAX; | |
171 | ||
172 | case COH_SUPER_MAGIC: | |
173 | return COH_LINK_MAX; | |
174 | ||
175 | case UFS_MAGIC: | |
176 | case UFS_CIGAM: | |
177 | return UFS_LINK_MAX; | |
178 | ||
179 | case REISERFS_SUPER_MAGIC: | |
180 | return REISERFS_LINK_MAX; | |
181 | ||
182 | case XFS_SUPER_MAGIC: | |
183 | return XFS_LINK_MAX; | |
184 | ||
de283087 AD |
185 | case LUSTRE_SUPER_MAGIC: |
186 | return LUSTRE_LINK_MAX; | |
187 | ||
9c7ff11a UD |
188 | default: |
189 | return LINUX_LINK_MAX; | |
190 | } | |
191 | } | |
192 | ||
193 | ||
194 | /* Used like: return statfs_filesize_max (__statfs (name, &buf), &buf); */ | |
195 | long int | |
196 | __statfs_filesize_max (int result, const struct statfs *fsbuf) | |
197 | { | |
198 | if (result < 0) | |
199 | { | |
200 | if (errno == ENOSYS) | |
201 | /* Not possible, return the default value. */ | |
202 | return 32; | |
203 | ||
204 | /* Some error occured. */ | |
205 | return -1; | |
206 | } | |
207 | ||
208 | switch (fsbuf->f_type) | |
209 | { | |
67525cb8 AJ |
210 | case F2FS_SUPER_MAGIC: |
211 | return 256; | |
212 | ||
6484ba5e AJ |
213 | case BTRFS_SUPER_MAGIC: |
214 | return 255; | |
215 | ||
9c7ff11a UD |
216 | case EXT2_SUPER_MAGIC: |
217 | case UFS_MAGIC: | |
218 | case UFS_CIGAM: | |
219 | case REISERFS_SUPER_MAGIC: | |
220 | case XFS_SUPER_MAGIC: | |
221 | case SMB_SUPER_MAGIC: | |
222 | case NTFS_SUPER_MAGIC: | |
223 | case UDF_SUPER_MAGIC: | |
224 | case JFS_SUPER_MAGIC: | |
17f83e56 | 225 | case VXFS_SUPER_MAGIC: |
6484ba5e | 226 | case CGROUP_SUPER_MAGIC: |
de283087 | 227 | case LUSTRE_SUPER_MAGIC: |
9c7ff11a UD |
228 | return 64; |
229 | ||
230 | case MSDOS_SUPER_MAGIC: | |
231 | case JFFS_SUPER_MAGIC: | |
232 | case JFFS2_SUPER_MAGIC: | |
233 | case NCP_SUPER_MAGIC: | |
234 | case ROMFS_SUPER_MAGIC: | |
235 | return 32; | |
236 | ||
237 | default: | |
238 | return 32; | |
239 | } | |
240 | } | |
241 | ||
242 | ||
243 | /* Used like: return statfs_link_max (__statfs (name, &buf), &buf); */ | |
244 | long int | |
245 | __statfs_symlinks (int result, const struct statfs *fsbuf) | |
246 | { | |
247 | if (result < 0) | |
248 | { | |
249 | if (errno == ENOSYS) | |
250 | /* Not possible, return the default value. */ | |
251 | return 1; | |
252 | ||
253 | /* Some error occured. */ | |
254 | return -1; | |
255 | } | |
256 | ||
257 | switch (fsbuf->f_type) | |
258 | { | |
259 | case ADFS_SUPER_MAGIC: | |
260 | case BFS_MAGIC: | |
261 | case CRAMFS_MAGIC: | |
262 | case DEVPTS_SUPER_MAGIC: | |
263 | case EFS_SUPER_MAGIC: | |
264 | case EFS_MAGIC: | |
265 | case MSDOS_SUPER_MAGIC: | |
266 | case NTFS_SUPER_MAGIC: | |
267 | case QNX4_SUPER_MAGIC: | |
268 | case ROMFS_SUPER_MAGIC: | |
269 | /* No symlink support. */ | |
270 | return 0; | |
271 | ||
272 | default: | |
273 | return 1; | |
274 | } | |
275 | } | |
443db178 UD |
276 | |
277 | ||
278 | /* Used like: return __statfs_chown_restricted (__statfs (name, &buf), &buf);*/ | |
279 | long int | |
280 | __statfs_chown_restricted (int result, const struct statfs *fsbuf) | |
281 | { | |
282 | if (result < 0) | |
283 | { | |
284 | if (errno == ENOSYS) | |
285 | /* Not possible, return the default value. */ | |
286 | return 1; | |
287 | ||
288 | /* Some error occured. */ | |
289 | return -1; | |
290 | } | |
291 | ||
d755bba4 | 292 | return 1; |
443db178 | 293 | } |