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 }