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 }