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
52static long
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
81static long
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
106static long
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
126static long
127__name_max( struct statfs*  s )
128{
129    return s->f_namelen;
130}
131
132long
133pathconf(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
201long 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