1 /**
2  * Copyright: Copyright (c) 2011 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Jan 16, 2011
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dvm.io.Path;
8 
9 import std.conv;
10 
11 import tango.core.Exception;
12 public import tango.io.Path;
13 version (Posix) import tango.stdc.posix.sys.stat;
14 import tango.sys.Common;
15 
16 import mambo.core..string;
17 import dvm.dvm.Options;
18 import dvm.util.Util;
19 
20 bool isSymlink (string path)
21 {
22     version (Windows)
23         return false;
24 
25     else
26     {
27         stat_t buffer;
28         int status;
29 
30         if (lstat(path.ptr, &buffer) == -1)
31             return false;
32 
33         return S_ISLNK(buffer.st_mode);
34     }
35 }
36 
37 int remove (string path, bool recursive = false)
38 {
39     alias tango.io.Path.remove removePath;
40 
41     if (!recursive)
42         return removePath(path) ? 1 : 0;
43 
44     int result;
45 
46     foreach (info ; children(path))
47     {
48         string fullPath = (info.path ~ info.name).assumeUnique;
49 
50         if (isSymlink(fullPath))
51             continue;
52 
53         if (info.folder)
54             result += remove(fullPath, true);
55 
56         else
57             result += removePath(fullPath) ? 1 : 0;
58     }
59 
60     return removePath(path) ? result + 1 : result;
61 }
62 
63 void copy (string source, string destination)
64 {
65     copyMoveImpl(source, destination, false);
66 }
67 
68 void move (string source, string destination)
69 {
70     copyMoveImpl(source, destination, true);
71 }
72 
73 private void copyMoveImpl (string source, string destination, bool doMove)
74 {
75     auto options = Options.instance;
76 
77     verbose(options.indentation, "source: ", source);
78     verbose(options.indentation, "destination: ", destination, '\n');
79 
80     if (exists(destination))
81         remove(destination, true);
82 
83     bool createParentOnly = false;
84 
85     if (isFile(source))
86         createParentOnly = true;
87 
88     version (Windows)
89         createParentOnly = true;
90 
91     if (createParentOnly)
92         createPath(parse(destination).path);
93 
94     else
95         createPath(destination);
96 
97     if (doMove)
98         rename(source, destination);
99     else
100         tango.io.Path.copy(source, destination);
101 }
102 
103 void validatePath (string path)
104 {
105     if (!exists(path))
106         throw new IOException("File not found \"" ~ path ~ "\"");
107 }
108 
109 string join (const(char)[][] paths ...)
110 {
111     return tango.io.Path.join(paths).assumeUnique;
112 }
113 
114 string native (const(char)[] path)
115 {
116     return tango.io.Path.native(path.toMutable).assumeUnique;
117 }
118 
119 string normalize (const(char)[] path)
120 {
121     return tango.io.Path.normalize(path).assumeUnique;
122 }
123 
124 string standard (const(char)[] path)
125 {
126     return tango.io.Path.standard(path.toMutable).assumeUnique;
127 }
128 
129 version (Posix):
130 
131 enum Owner
132 {
133     Read = S_IRUSR,
134     Write = S_IWUSR,
135     Execute = S_IXUSR,
136     All = S_IRWXU
137 }
138 
139 enum Group
140 {
141     Read = S_IRGRP,
142     Write = S_IWGRP,
143     Execute = S_IXGRP,
144     All = S_IRWXG
145 }
146 
147 enum Others
148 {
149     Read = S_IROTH,
150     Write = S_IWOTH,
151     Execute = S_IXOTH,
152     All = S_IRWXO
153 }
154 
155 void permission (string path, ushort mode)
156 {
157     if (chmod((path ~ '\0').ptr, mode) == -1)
158         throw new IOException(path ~ ": " ~ SysError.lastMsg.assumeUnique);
159 }
160 
161 private template permissions (alias reference)
162 {
163     enum permissions = "if (add)
164     {
165         if (read) m |= " ~ reference.stringof ~ ".Read;
166         if (write) m |= " ~ reference.stringof ~ ".Write;
167         if (execute) m |= " ~ reference.stringof ~ ".Execute;
168     }
169 
170     else if (remove)
171     {
172         if (read) m &= ~" ~ reference.stringof ~ ".Read;
173         if (write) m &= ~" ~ reference.stringof ~ ".Write;
174         if (execute) m &= ~" ~ reference.stringof ~ ".Execute;
175     }
176 
177     else if (assign)
178     {
179         m = 0;
180 
181         if (read) m |= " ~ reference.stringof ~ ".Read;
182         if (write) m |= " ~ reference.stringof ~ ".Write;
183         if (execute) m |= " ~ reference.stringof ~ ".Execute;
184     }";
185 }
186 
187 void permission (string path, string mode)
188 {
189     ushort m = permission(path);
190 
191     bool owner;
192     bool group;
193     bool others;
194     bool all = true;
195 
196     bool add;
197     bool remove;
198     bool assign;
199 
200     bool read;
201     bool write;
202     bool execute;
203 
204     foreach (c ; mode)
205     {
206         switch (c)
207         {
208             case 'u':
209                 owner = true;
210                 all = false;
211             continue;
212 
213             case 'g':
214                 group = true;
215                 all = false;
216             continue;
217 
218             case 'o':
219                 others = true;
220                 all = false;
221             continue;
222 
223             case 'a': all = true; continue;
224 
225             case 'r': read = true; continue;
226             case 'w': write = true; continue;
227             case 'x': execute = true; continue;
228 
229             case '+': add = true; continue;
230             case '-': remove = true; continue;
231             case '=': assign = true; continue;
232 
233             default: continue;
234         }
235     }
236 
237     if (owner) mixin(permissions!(Owner));
238     if (group) mixin(permissions!(Group));
239     if (others) mixin(permissions!(Others));
240 
241     if (all)
242     {
243         mixin(permissions!(Owner));
244         mixin(permissions!(Group));
245         mixin(permissions!(Others));
246     }
247 
248     permission(path, m);
249 }
250 
251 private ushort permission (string path)
252 {
253     int status;
254     stat_t buffer;
255 
256     if (stat((path ~ '\0').ptr, &buffer) == -1)
257         throw new IOException(path ~ ": " ~ SysError.lastMsg.assumeUnique);
258 
259     return buffer.st_mode & octal!(777);
260 }