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