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 }