/******************************************************************************* * c0xfilesys.c * Test implementation for the ISO C proposal at: * . * * This code is designed to run reasonably well on Unix and Win32 systems. * * Contains * _fgetfilesys() * _getfilesys() * * Notes * Compile with macro '_unix' defined for Unix systems. * * Compile with macro 'NOTEST' defined if you do not want a test driver * 'main()' function compiled into the object code. * * Acknowledgments * This code was written by David R. Tribble (david@tribble.com), Jan 2004. * It is hereby placed into the public domain, and may be used for all * purposes, both commercial and private. No warranty is provided for this * source code, and the author cannot be held liable for its use in any * way. * * See also * * * */ /* Identification */ static const char REV[] = "@(#)drt/text/stdc/c0xfilesys.c $Revision: 1.1 $ $Date: 2004/01/24 23:25:03 $\n"; static const char PROG[] = "c0xfilesys"; /* System includes */ #include #include #include #include #include #if defined(_unix) #include #include #include #elif defined(_WIN32) #define WIN32_LEAN_AND_MEAN 1 #include #include #include #include #endif /* Local includes */ #include "c0xfilesys.h" /* Local macros */ #ifdef NOTEST #undef NOTEST #define NOTEST 1 #else #define NOTEST 0 #endif /* Local constants */ /* printf() format specifiers */ #if defined(_WIN32) && _MSC_VER < 1300 /* For older versions of MS C */ #define LLONG_FMT "I64d" #define ULLONG_FMT "I64u" #else #define LLONG_FMT "lld" #define ULLONG_FMT "llu" #endif /*------------------------------------------------------------------------------ * _getfilesys() * Retrieve information about a file system. * * @param name * File system name. * The contents and format of this name are implementation-defined. * * @param info * Pointer to a file system information structure. * * @return * Zero if successful and the structure pointed to by 'info' is filled with * information about the named file system; otherwise -1. * * @see * * * @since 1.1, 2004-01-24 */ int _getfilesys(const char *name, struct _filesys *info) { #if defined(_unix) struct statvfs fsi; if (statvfs(name, &fsi) < 0) return (-1); memset(info, '\0', sizeof(*info)); sprintf(info->fs_name, "%lu", (unsigned long) fsi.f_fsid); info->fs_nfiles = fsi.f_files - fsi.f_ffree; info->fs_ndirs = -1; info->fs_total = fsi.f_blocks; info->fs_free = (geteuid() == 0 ? fsi.f_bfree : fsi.f_bavail); info->fs_blocksize = fsi.f_frsize; /* Not fsi.f_bsize */ info->fs_namelen = fsi.f_namemax; info->fs_flags = _FILESYS_SUBDIRS; return (0); #elif defined(_WIN32) struct _diskfree_t fsi; int diskno; if (name[0] == '\0') diskno = 0; else if (name[0] >= 'A' and name[0] <= 'Z') diskno = name[0] - 'A' + 1; else if (name[0] >= 'a' and name[0] <= 'z') diskno = name[0] - 'a' + 1; else if (name[0] >= '0' and name[0] <= '9') diskno = strtol(name, NULL, 10); else return (-1); if (diskno == 0) diskno = _getdrive(); if (_getdiskfree(diskno, &fsi) < 0) return (-1); memset(info, '\0', sizeof(*info)); /* Or: = NTFS_VOLUME_DATA_BUFFER.VolumeSerialNumber */ info->fs_name[0] = diskno + 'A' - 1; info->fs_name[1] = ':'; info->fs_nfiles = -1; info->fs_ndirs = -1; info->fs_total = fsi.total_clusters; info->fs_free = fsi.avail_clusters; info->fs_blocksize = (long)fsi.bytes_per_sector * fsi.sectors_per_cluster; info->fs_namelen = MAX_PATH; info->fs_flags = _FILESYS_SUBDIRS | _FILESYS_IGNORE_CASE; return (0); #else #error Unsupported O/S #endif } /*------------------------------------------------------------------------------ * _fgetfilesys() * Retrieve information the file system used by a given I/O stream. * * @param fp * An I/O stream. * This should not be null, nor should it point to a closed stream. * * @param info * Pointer to a file system information structure. * * @return * Zero if successful and the structure pointed to by 'info' is filled with * information about the stream's file system; otherwise -1. * * @see * * * @since 1.1, 2004-01-24 */ int _fgetfilesys(const FILE *fp, struct _filesys *info) { #if defined(_unix) struct statvfs fsi; if (fstatvfs(fileno(fp), &fsi) < 0) return (-1); memset(info, '\0', sizeof(*info)); sprintf(info->fs_name, "%lu", (unsigned long) fsi.f_fsid); info->fs_nfiles = fsi.f_files - fsi.f_ffree; info->fs_ndirs = -1; info->fs_total = fsi.f_blocks; info->fs_free = (geteuid() == 0 ? fsi.f_bfree : fsi.f_bavail); info->fs_blocksize = fsi.f_frsize; /* Not fsi.f_bsize */ info->fs_namelen = fsi.f_namemax; info->fs_flags = _FILESYS_SUBDIRS; return (0); #elif defined(_WIN32) fprintf(stderr, "$ NOT IMPLEMENTED: _fgetfilesys()\n"); return (-1); #else #error Unsupported O/S #endif } #if !NOTEST /*------------------------------------------------------------------------------ * print_info() * Print information about a file system to stdout. * * @param fsname * Name of a file system. * * @param info * Information about the file system. * * @see * * * @since 1.1, 2004-01-18 */ static void print_info(const char *fsname, const struct _filesys *info) { #if _FILESYS_VERS != 1 #error Struct _fileinfo has changed #endif /* Display the file system ID */ printf("File system: '%s'\n", fsname); printf(" name: %s\n", info->fs_name); if (info->fs_blocksize != -1) printf(" block size: %ld bytes\n", info->fs_blocksize); else printf(" block size: unknown\n"); if (info->fs_total != -1) { ullong_t t; const char * m; printf(" total space: %" LLONG_FMT " blocks", info->fs_total); t = info->fs_total; t *= info->fs_blocksize; if (t >= (ullong_t)10*1024*1024*1024) m = "GB", t /= 1024*1024*1024; else if (t >= (ullong_t)10*1024*1024) m = "MB", t /= 1024*1024; else m = "KB", t /= 1024; printf(", %" LLONG_FMT, t); printf(" %s\n", m); } else printf(" total space: unknown\n"); if (info->fs_free != -1) { ullong_t t; const char * m; printf(" free space: %" LLONG_FMT " blocks", info->fs_free); t = info->fs_free; t *= info->fs_blocksize; if (t >= (ullong_t)10*1024*1024*1024) m = "GB", t /= 1024*1024*1024; else if (t >= (ullong_t)10*1024*1024) m = "MB", t /= 1024*1024; else m = "KB", t /= 1024; printf(", %" LLONG_FMT, t); printf(" %s\n", m); } else printf(" free space: unknown\n"); if (info->fs_nfiles != -1) printf(" files: %" LLONG_FMT "\n", info->fs_nfiles); else printf(" files: unknown\n"); if (info->fs_ndirs != -1) printf(" directories: %" LLONG_FMT "\n", info->fs_ndirs); else printf(" directories: unknown\n"); if (info->fs_namelen != -1) printf(" name length: %d+1\n", info->fs_namelen-1); else printf(" name length: unknown\n"); printf(" dir/file names: %s syntax\n", (info->fs_flags & _FILESYS_DIRNAMES) ? "different" : "same"); printf(" filename case: %s\n", (info->fs_flags & _FILESYS_IGNORE_CASE) ? "ignore" : "sensitive"); printf(" subdirectories: %s\n", (info->fs_flags & _FILESYS_SUBDIRS) ? "supported" : "not supported"); printf("\n"); } #endif /* NOTEST */ #if !NOTEST /*------------------------------------------------------------------------------ * main() * Test driver. * Display information about one or more file systems. * * @usage * c0xfilesys filesys... * * @param argc * Number of command line arguments in 'argv'. * * @param argv * Command line arguments. * * @since 1.1, 2004-01-18 */ int main(int argc, char **argv) { int i; /* Check args */ if (argc < 2) { /* Display a usage message */ printf("Display information about one or more file systems.\n"); printf("\n"); printf("usage: %s filesystem...\n", PROG); printf("\n"); /* Punt */ return (EXIT_FAILURE); } /* Process one or more filename args */ for (i = 1; i < argc; i++) { const char * fsname; struct _filesys info; /* Retrieve info for a filename and print it */ fsname = argv[i]; if (_getfilesys(fsname, &info) < 0) printf("Error (%d): %s: %s\n", errno, strerror(errno), fsname); else print_info(fsname, &info); } return (EXIT_SUCCESS); } #endif /* NOTEST */ /* End c0xfilesys.c */