1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <pathconf.h>
30 #include <sys/vfs.h>
31 #include <sys/limits.h>
32 #include <errno.h>
33 
34 /* these may not be defined yet by our headers */
35 #ifndef _POSIX_VDISABLE
36 #define _POSIX_VDISABLE  -1
37 #endif
38 
39 #ifndef _POSIX_SYNC_IO
40 #define _POSIX_SYNC_IO  -1
41 #endif
42 
43 #ifndef _POSIX_PRIO_IO
44 #define _POSIX_PRIO_IO  -1
45 #endif
46 
47 #ifndef _POSIX_ASYNC_IO
48 #define _POSIX_ASYNC_IO  -1
49 #endif
50 
51 
52 static long
__filesizebits(struct statfs * s)53 __filesizebits( struct statfs*  s )
54 {
55 #define   EOL_MAGIC   0x0000U
56 
57     /* list of known 64-bit aware filesystems */
58     static const uint32_t  known64[] = {
59         EXT2_SUPER_MAGIC,
60         UFS_MAGIC,
61         REISERFS_SUPER_MAGIC,
62         XFS_SUPER_MAGIC,
63         SMB_SUPER_MAGIC,
64         UDF_SUPER_MAGIC,
65         JFS_SUPER_MAGIC,
66         NTFS_SB_MAGIC,
67         VXFS_SUPER_MAGIC,
68         EOL_MAGIC
69     };
70     int  nn = 0;
71 
72     for (; known64[nn] != EOL_MAGIC; ++nn) {
73         if (known64[nn] == s->f_type) {
74             return 64;
75         }
76     }
77     return 32;
78 }
79 
80 
81 static long
__link_max(struct statfs * s)82 __link_max( struct statfs*  s )
83 {
84     // These constant values were taken from kernel headers.
85     // They're not available in uapi headers.
86     static const struct { uint32_t  type; int  max; }  knownMax[] =
87     {
88         { EXT2_SUPER_MAGIC, 32000 },
89         { EXT3_SUPER_MAGIC, 32000 },
90         { MINIX_SUPER_MAGIC, 250 },
91         { MINIX2_SUPER_MAGIC, 65530 },
92         { REISERFS_SUPER_MAGIC, 0xffff - 1000 },
93         { UFS_MAGIC, 32000 },
94         { EOL_MAGIC, 0 }
95     };
96     int   nn = 0;
97 
98     for (; knownMax[nn].type != EOL_MAGIC; ++nn) {
99         if (knownMax[nn].type == s->f_type) {
100             return knownMax[nn].max;
101         }
102     }
103     return LINK_MAX;
104 }
105 
106 static long
__2_symlinks(struct statfs * s)107 __2_symlinks( struct statfs*  s )
108 {
109     /* list of know filesystems that don't support symlinks */
110     static const uint32_t  knownNoSymlinks[] = {
111         ADFS_SUPER_MAGIC, BFS_MAGIC, CRAMFS_MAGIC,
112         EFS_SUPER_MAGIC, MSDOS_SUPER_MAGIC, NTFS_SB_MAGIC,
113         QNX4_SUPER_MAGIC,
114         EOL_MAGIC
115     };
116     int  nn = 0;
117 
118     for (; knownNoSymlinks[nn] != EOL_MAGIC; ++nn) {
119         if (knownNoSymlinks[nn] == s->f_type) {
120             return 0;
121         }
122     }
123     return 1;
124 }
125 
126 static long
__name_max(struct statfs * s)127 __name_max( struct statfs*  s )
128 {
129     return s->f_namelen;
130 }
131 
132 long
pathconf(const char * path,int name)133 pathconf(const char *path, int name)
134 {
135     struct statfs  buf;
136     int            ret = statfs( path, &buf );
137 
138     if (ret < 0)
139         return -1;
140 
141     switch (name) {
142     case _PC_FILESIZEBITS:
143         return __filesizebits(&buf);
144 
145     case _PC_LINK_MAX:
146         return __link_max(&buf);
147 
148     case _PC_MAX_CANON:
149         return MAX_CANON;
150 
151     case _PC_MAX_INPUT:
152         return MAX_INPUT;
153 
154     case _PC_NAME_MAX:
155         return __name_max(&buf);
156 
157     case _PC_PATH_MAX:
158         return PATH_MAX;
159 
160     case _PC_PIPE_BUF:
161         return PIPE_BUF;
162 
163     case _PC_2_SYMLINKS:
164         return __2_symlinks(&buf);
165 
166 #if 0  /* don't know what to do there, the specs are really weird */
167     case _PC_ALLOC_SIZE_MIN:
168     case _PC_REC_INCR_XFER_SIZE:
169     case _PC_REC_MAX_XFER_SIZE:
170     case _PC_REC_MIN_XFER_SIZE:
171     case _PC_REC_XFER_ALIGN:
172 #endif
173 
174     case _PC_SYMLINK_MAX:
175         return -1;  /* no limit */
176 
177     case _PC_CHOWN_RESTRICTED:
178         return _POSIX_CHOWN_RESTRICTED;
179 
180     case _PC_NO_TRUNC:
181         return _POSIX_NO_TRUNC;
182 
183     case _PC_VDISABLE:
184         return _POSIX_VDISABLE;
185 
186     case _PC_ASYNC_IO:
187         return _POSIX_ASYNC_IO;
188 
189     case _PC_PRIO_IO:
190         return _POSIX_PRIO_IO;
191 
192     case _PC_SYNC_IO:
193         return _POSIX_SYNC_IO;
194 
195     default:
196         errno = EINVAL;
197         return -1;
198     }
199 }
200 
fpathconf(int fildes,int name)201 long fpathconf(int fildes, int name)
202 {
203     struct statfs  buf;
204     int            ret = fstatfs(fildes, &buf);
205 
206     if (ret < 0)
207         return -1;
208 
209     switch (name) {
210     case _PC_FILESIZEBITS:
211         return __filesizebits(&buf);
212 
213     case _PC_LINK_MAX:
214         return __link_max(&buf);
215 
216     case _PC_MAX_CANON:
217         return MAX_CANON;
218 
219     case _PC_MAX_INPUT:
220         return MAX_INPUT;
221 
222     case _PC_NAME_MAX:
223         return __name_max(&buf);
224 
225     case _PC_PATH_MAX:
226         return PATH_MAX;
227 
228     case _PC_PIPE_BUF:
229         return PIPE_BUF;
230 
231     case _PC_2_SYMLINKS:
232         return __2_symlinks(&buf);
233 
234 #if 0  /* don't know what to do there, the specs are really weird */
235     case _PC_ALLOC_SIZE_MIN:
236     case _PC_REC_INCR_XFER_SIZE:
237     case _PC_REC_MAX_XFER_SIZE:
238     case _PC_REC_MIN_XFER_SIZE:
239     case _PC_REC_XFER_ALIGN:
240 #endif
241 
242     case _PC_SYMLINK_MAX:
243         return -1;  /* no limit */
244 
245     case _PC_CHOWN_RESTRICTED:
246         return _POSIX_CHOWN_RESTRICTED;
247 
248     case _PC_NO_TRUNC:
249         return _POSIX_NO_TRUNC;
250 
251     case _PC_VDISABLE:
252         return _POSIX_VDISABLE;
253 
254     case _PC_ASYNC_IO:
255         return _POSIX_ASYNC_IO;
256 
257     case _PC_PRIO_IO:
258         return _POSIX_PRIO_IO;
259 
260     case _PC_SYNC_IO:
261         return _POSIX_SYNC_IO;
262 
263     default:
264         errno = EINVAL;
265         return -1;
266     }
267 }
268