1 /******************************************************************************* 2 3 Copyright: 4 Copyright (c) 2004 Kris Bell. 5 Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH. 6 All rights reserved. 7 8 License: 9 Tango Dual License: 3-Clause BSD License / Academic Free License v3.0. 10 See LICENSE_TANGO.txt for details. 11 12 Version: 13 Mar 2004: Initial release 14 Feb 2007: Now using mutating paths 15 16 Authors: Kris, Chris Sauls (Win95 file support) 17 18 *******************************************************************************/ 19 20 module ocean.io.FileSystem; 21 22 import ocean.core.ExceptionDefinitions; 23 import ocean.io.device.File; 24 import ocean.io.FilePath; 25 import ocean.io.Path : standard, native; 26 import ocean.meta.types.Qualifiers; 27 import ocean.sys.Common; 28 import Integer = ocean.text.convert.Integer_tango; 29 30 import core.stdc.string; 31 import core.sys.posix.unistd; 32 import core.sys.posix.sys.statvfs; 33 34 35 /******************************************************************************* 36 37 Models an OS-specific file-system. 38 39 Included here are methods to manipulate the current working directory, 40 and to convert a path to its absolute form. 41 42 *******************************************************************************/ 43 44 public struct FileSystem 45 { 46 /*************************************************************************** 47 48 Throws: 49 a new IOException with the provided error message 50 51 ***************************************************************************/ 52 53 private static void exception (istring msg) 54 { 55 throw new IOException(msg); 56 } 57 58 /*************************************************************************** 59 60 List the set of root devices. 61 62 ***************************************************************************/ 63 64 static istring[] roots () 65 { 66 istring path = ""; 67 istring[] list; 68 int spaces; 69 70 auto fc = new File("/etc/mtab"); 71 scope (exit) 72 fc.close; 73 74 auto content = new char[cast(int) fc.length]; 75 fc.input.read (content); 76 77 for(int i = 0; i < content.length; i++) 78 { 79 if(content[i] == ' ') spaces++; 80 else if(content[i] == '\n') 81 { 82 spaces = 0; 83 list ~= path; 84 path = ""; 85 } 86 else if(spaces == 1) 87 { 88 if(content[i] == '\\') 89 { 90 path ~= cast(char) Integer.parse(content[++i..i+3], 8u); 91 i += 2; 92 } 93 else path ~= content[i]; 94 } 95 } 96 97 return list; 98 } 99 100 /*************************************************************************** 101 102 Request how much free space in bytes is available on the disk/mountpoint 103 where folder resides 104 105 If a quota limit exists for this area, that will be taken 106 into account unless superuser is set to true. 107 108 If a user has exceeded the quota, a negative number can 109 be returned. 110 111 Note that the difference between total available space 112 and free space will not equal the combined size of the 113 contents on the file system, since the numbers for the 114 functions here are calculated from the used blocks, 115 including those spent on metadata and file nodes. 116 117 If actual used space is wanted one should use the 118 statistics functionality of ocean.io.vfs. 119 120 See_also: totalSpace() 121 122 ***************************************************************************/ 123 124 static long freeSpace(char[] folder, bool superuser = false) 125 { 126 scope fp = new FilePath(folder); 127 statvfs_t info; 128 int res = statvfs(fp.native.cString.ptr, &info); 129 if (res == -1) 130 exception ("freeSpace->statvfs failed:" 131 ~ SysError.lastMsg); 132 133 if (superuser) 134 return cast(long)info.f_bfree * cast(long)info.f_bsize; 135 else 136 return cast(long)info.f_bavail * cast(long)info.f_bsize; 137 } 138 139 /*************************************************************************** 140 141 Request how large in bytes the disk/mountpoint where folder resides is. 142 143 If a quota limit exists for this area, then that quota can be what will 144 be returned unless superuser is set to true. 145 On Posix systems this distinction is not made though. 146 147 Note: 148 Access to this information when _superuser is set to true may 149 only be available if the program is run in superuser mode. 150 151 See_also: 152 `freeSpace` 153 154 ***************************************************************************/ 155 156 static long totalSpace(char[] folder, bool superuser = false) 157 { 158 scope fp = new FilePath(folder); 159 statvfs_t info; 160 int res = statvfs(fp.native.cString.ptr, &info); 161 if (res == -1) 162 exception ("totalSpace->statvfs failed:" 163 ~ SysError.lastMsg); 164 165 return cast(long)info.f_blocks * cast(long)info.f_frsize; 166 } 167 } 168 169 170 /****************************************************************************** 171 172 ******************************************************************************/ 173 174 debug (FileSystem) 175 { 176 import ocean.io.Stdout; 177 178 static void foo (FilePath path) 179 { 180 Stdout("all: ") (path).newline; 181 Stdout("path: ") (path.path).newline; 182 Stdout("file: ") (path.file).newline; 183 Stdout("folder: ") (path.folder).newline; 184 Stdout("name: ") (path.name).newline; 185 Stdout("ext: ") (path.ext).newline; 186 Stdout("suffix: ") (path.suffix).newline.newline; 187 } 188 189 void main() 190 { 191 Stdout.formatln ("dir: {}", FileSystem.getDirectory); 192 193 auto path = new FilePath ("."); 194 foo (path); 195 196 path.set (".."); 197 foo (path); 198 199 path.set ("..."); 200 foo (path); 201 202 path.set (r"/x/y/.file"); 203 foo (path); 204 205 path.suffix = ".foo"; 206 foo (path); 207 208 path.set ("file.bar"); 209 path.absolute("c:/prefix"); 210 foo(path); 211 212 path.set (r"arf/test"); 213 foo(path); 214 path.absolute("c:/prefix"); 215 foo(path); 216 217 path.name = "foo"; 218 foo(path); 219 220 path.suffix = ".d"; 221 path.name = path.suffix; 222 foo(path); 223 224 } 225 }