/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <pathconf.h> #include <sys/vfs.h> #include <sys/limits.h> #include <linux/ext2_fs.h> #include <linux/ext3_fs.h> #include <errno.h> /* these may not be defined yet by our headers */ #ifndef _POSIX_VDISABLE #define _POSIX_VDISABLE -1 #endif #ifndef _POSIX_SYNC_IO #define _POSIX_SYNC_IO -1 #endif #ifndef _POSIX_PRIO_IO #define _POSIX_PRIO_IO -1 #endif #ifndef _POSIX_ASYNC_IO #define _POSIX_ASYNC_IO -1 #endif static long __filesizebits( struct statfs* s ) { #define EOL_MAGIC 0x0000U /* list of known 64-bit aware filesystems */ static const uint32_t known64[] = { EXT2_SUPER_MAGIC, UFS_MAGIC, REISERFS_SUPER_MAGIC, XFS_SUPER_MAGIC, SMB_SUPER_MAGIC, UDF_SUPER_MAGIC, JFS_SUPER_MAGIC, NTFS_SB_MAGIC, VXFS_SUPER_MAGIC, EOL_MAGIC }; int nn = 0; for (;;) { if ( known64[nn] == EOL_MAGIC ) return 32; if ( known64[nn] == s->f_type ) return 64; } } static long __link_max( struct statfs* s ) { /* constant values were taken from official kernel headers. * I don't think this justified bringing in <linux/minix_fs.h> et al * into our cleaned-up kernel three */ static const struct { uint32_t type; int max; } knownMax[] = { { EXT2_SUPER_MAGIC, EXT2_LINK_MAX }, { EXT3_SUPER_MAGIC, EXT3_LINK_MAX }, { MINIX_SUPER_MAGIC, 250 }, { MINIX2_SUPER_MAGIC, 65530 }, { REISERFS_SUPER_MAGIC, 0xffff - 1000 }, { UFS_MAGIC, 32000 }, { EOL_MAGIC, 0 } }; int nn = 0; for (;;) { if ( knownMax[nn].type == EOL_MAGIC ) return LINK_MAX; if ( knownMax[nn].type == s->f_type ) return knownMax[nn].max; } return LINK_MAX; } static long __2_symlinks( struct statfs* s ) { /* list of know filesystems that don't support symlinks */ static const uint32_t knownNoSymlinks[] = { ADFS_SUPER_MAGIC, BFS_MAGIC, CRAMFS_MAGIC, EFS_SUPER_MAGIC, MSDOS_SUPER_MAGIC, NTFS_SB_MAGIC, QNX4_SUPER_MAGIC, EOL_MAGIC }; int nn = 0; for (;;) { if (knownNoSymlinks[nn] == 0) return 1; if (knownNoSymlinks[nn] == s->f_type) return 0; } } static long __name_max( struct statfs* s ) { return s->f_namelen; } long pathconf(const char *path, int name) { struct statfs buf; int ret = statfs( path, &buf ); if (ret < 0) return -1; switch (name) { case _PC_FILESIZEBITS: return __filesizebits(&buf); case _PC_LINK_MAX: return __link_max(&buf); case _PC_MAX_CANON: return MAX_CANON; case _PC_MAX_INPUT: return MAX_INPUT; case _PC_NAME_MAX: return __name_max(&buf); case _PC_PATH_MAX: return PATH_MAX; case _PC_PIPE_BUF: return PIPE_BUF; case _PC_2_SYMLINKS: return __2_symlinks(&buf); #if 0 /* don't know what to do there, the specs are really weird */ case _PC_ALLOC_SIZE_MIN: case _PC_REC_INCR_XFER_SIZE: case _PC_REC_MAX_XFER_SIZE: case _PC_REC_MIN_XFER_SIZE: case _PC_REC_XFER_ALIGN: #endif case _PC_SYMLINK_MAX: return -1; /* no limit */ case _PC_CHOWN_RESTRICTED: return _POSIX_CHOWN_RESTRICTED; case _PC_NO_TRUNC: return _POSIX_NO_TRUNC; case _PC_VDISABLE: return _POSIX_VDISABLE; case _PC_ASYNC_IO: return _POSIX_ASYNC_IO; case _PC_PRIO_IO: return _POSIX_PRIO_IO; case _PC_SYNC_IO: return _POSIX_SYNC_IO; default: errno = EINVAL; return -1; } } long fpathconf(int fildes, int name) { struct statfs buf; int ret = fstatfs(fildes, &buf); if (ret < 0) return -1; switch (name) { case _PC_FILESIZEBITS: return __filesizebits(&buf); case _PC_LINK_MAX: return __link_max(&buf); case _PC_MAX_CANON: return MAX_CANON; case _PC_MAX_INPUT: return MAX_INPUT; case _PC_NAME_MAX: return __name_max(&buf); case _PC_PATH_MAX: return PATH_MAX; case _PC_PIPE_BUF: return PIPE_BUF; case _PC_2_SYMLINKS: return __2_symlinks(&buf); #if 0 /* don't know what to do there, the specs are really weird */ case _PC_ALLOC_SIZE_MIN: case _PC_REC_INCR_XFER_SIZE: case _PC_REC_MAX_XFER_SIZE: case _PC_REC_MIN_XFER_SIZE: case _PC_REC_XFER_ALIGN: #endif case _PC_SYMLINK_MAX: return -1; /* no limit */ case _PC_CHOWN_RESTRICTED: return _POSIX_CHOWN_RESTRICTED; case _PC_NO_TRUNC: return _POSIX_NO_TRUNC; case _PC_VDISABLE: return _POSIX_VDISABLE; case _PC_ASYNC_IO: return _POSIX_ASYNC_IO; case _PC_PRIO_IO: return _POSIX_PRIO_IO; case _PC_SYNC_IO: return _POSIX_SYNC_IO; default: errno = EINVAL; return -1; } }