| 1104 | | |
|---|
| 1105 | | |
|---|
| 1106 | | /******************************************************************************* |
|---|
| 1107 | | |
|---|
| 1108 | | Wraps the O/S specific calls with a D API. Note that these accept |
|---|
| 1109 | | null-terminated strings only, which is why it is a private struct |
|---|
| 1110 | | |
|---|
| 1111 | | *******************************************************************************/ |
|---|
| 1112 | | |
|---|
| 1113 | | private struct FS |
|---|
| 1114 | | { |
|---|
| 1115 | | /*********************************************************************** |
|---|
| 1116 | | |
|---|
| 1117 | | TimeStamp information. Accurate to whatever the OS supports |
|---|
| 1118 | | |
|---|
| 1119 | | ***********************************************************************/ |
|---|
| 1120 | | |
|---|
| 1121 | | struct Stamps |
|---|
| 1122 | | { |
|---|
| 1123 | | Time created, /// time created |
|---|
| 1124 | | accessed, /// last time accessed |
|---|
| 1125 | | modified; /// last time modified |
|---|
| 1126 | | } |
|---|
| 1127 | | |
|---|
| 1128 | | /*********************************************************************** |
|---|
| 1129 | | |
|---|
| 1130 | | Passed around during file-scanning |
|---|
| 1131 | | |
|---|
| 1132 | | ***********************************************************************/ |
|---|
| 1133 | | |
|---|
| 1134 | | struct FileInfo |
|---|
| 1135 | | { |
|---|
| 1136 | | char[] path, |
|---|
| 1137 | | name; |
|---|
| 1138 | | ulong bytes; |
|---|
| 1139 | | bool folder; |
|---|
| 1140 | | } |
|---|
| 1141 | | |
|---|
| 1142 | | /*********************************************************************** |
|---|
| 1143 | | |
|---|
| 1144 | | Throw an exception using the last known error |
|---|
| 1145 | | |
|---|
| 1146 | | ***********************************************************************/ |
|---|
| 1147 | | |
|---|
| 1148 | | static void exception (char[] filename) |
|---|
| 1149 | | { |
|---|
| 1150 | | throw new IOException (filename[0..$-1] ~ ": " ~ SysError.lastMsg); |
|---|
| 1151 | | } |
|---|
| 1152 | | |
|---|
| 1153 | | /*********************************************************************** |
|---|
| 1154 | | |
|---|
| 1155 | | Returns the time of the last modification. Accurate |
|---|
| 1156 | | to whatever the OS supports, and in a format dictated |
|---|
| 1157 | | by the file-system. For example NTFS keeps UTC time, |
|---|
| 1158 | | while FAT timestamps are based on the local time. |
|---|
| 1159 | | |
|---|
| 1160 | | ***********************************************************************/ |
|---|
| 1161 | | |
|---|
| 1162 | | static Time modified (char[] name) |
|---|
| 1163 | | { |
|---|
| 1164 | | return timeStamps(name).modified; |
|---|
| 1165 | | } |
|---|
| 1166 | | |
|---|
| 1167 | | /*********************************************************************** |
|---|
| 1168 | | |
|---|
| 1169 | | Returns the time of the last access. Accurate to |
|---|
| 1170 | | whatever the OS supports, and in a format dictated |
|---|
| 1171 | | by the file-system. For example NTFS keeps UTC time, |
|---|
| 1172 | | while FAT timestamps are based on the local time. |
|---|
| 1173 | | |
|---|
| 1174 | | ***********************************************************************/ |
|---|
| 1175 | | |
|---|
| 1176 | | static Time accessed (char[] name) |
|---|
| 1177 | | { |
|---|
| 1178 | | return timeStamps(name).accessed; |
|---|
| 1179 | | } |
|---|
| 1180 | | |
|---|
| 1181 | | /*********************************************************************** |
|---|
| 1182 | | |
|---|
| 1183 | | Returns the time of file creation. Accurate to |
|---|
| 1184 | | whatever the OS supports, and in a format dictated |
|---|
| 1185 | | by the file-system. For example NTFS keeps UTC time, |
|---|
| 1186 | | while FAT timestamps are based on the local time. |
|---|
| 1187 | | |
|---|
| 1188 | | ***********************************************************************/ |
|---|
| 1189 | | |
|---|
| 1190 | | static Time created (char[] name) |
|---|
| 1191 | | { |
|---|
| 1192 | | return timeStamps(name).created; |
|---|
| 1193 | | } |
|---|
| 1194 | | |
|---|
| 1195 | | /*********************************************************************** |
|---|
| 1196 | | |
|---|
| 1197 | | Win32 API code |
|---|
| 1198 | | |
|---|
| 1199 | | ***********************************************************************/ |
|---|
| 1200 | | |
|---|
| 1201 | | version (Win32) |
|---|
| 1202 | | { |
|---|
| 1203 | | /*************************************************************** |
|---|
| 1204 | | |
|---|
| 1205 | | return a wchar[] instance of the path |
|---|
| 1206 | | |
|---|
| 1207 | | ***************************************************************/ |
|---|
| 1208 | | |
|---|
| 1209 | | private static wchar[] toString16 (wchar[] tmp, char[] path) |
|---|
| 1210 | | { |
|---|
| 1211 | | auto i = MultiByteToWideChar (CP_UTF8, 0, |
|---|
| 1212 | | path.ptr, path.length, |
|---|
| 1213 | | tmp.ptr, tmp.length); |
|---|
| 1214 | | return tmp [0..i]; |
|---|
| 1215 | | } |
|---|
| 1216 | | |
|---|
| 1217 | | /*************************************************************** |
|---|
| 1218 | | |
|---|
| 1219 | | return a char[] instance of the path |
|---|
| 1220 | | |
|---|
| 1221 | | ***************************************************************/ |
|---|
| 1222 | | |
|---|
| 1223 | | private static char[] toString (char[] tmp, wchar[] path) |
|---|
| 1224 | | { |
|---|
| 1225 | | auto i = WideCharToMultiByte (CP_UTF8, 0, path.ptr, path.length, |
|---|
| 1226 | | tmp.ptr, tmp.length, null, null); |
|---|
| 1227 | | return tmp [0..i]; |
|---|
| 1228 | | } |
|---|
| 1229 | | |
|---|
| 1230 | | /*************************************************************** |
|---|
| 1231 | | |
|---|
| 1232 | | Get info about this path |
|---|
| 1233 | | |
|---|
| 1234 | | ***************************************************************/ |
|---|
| 1235 | | |
|---|
| 1236 | | private static bool fileInfo (char[] name, inout WIN32_FILE_ATTRIBUTE_DATA info) |
|---|
| 1237 | | { |
|---|
| 1238 | | version (Win32SansUnicode) |
|---|
| 1239 | | { |
|---|
| 1240 | | if (! GetFileAttributesExA (name.ptr, GetFileInfoLevelStandard, &info)) |
|---|
| 1241 | | return false; |
|---|
| 1242 | | } |
|---|
| 1243 | | else |
|---|
| 1244 | | { |
|---|
| 1245 | | wchar[MAX_PATH] tmp = void; |
|---|
| 1246 | | if (! GetFileAttributesExW (toString16(tmp, name).ptr, GetFileInfoLevelStandard, &info)) |
|---|
| 1247 | | return false; |
|---|
| 1248 | | } |
|---|
| 1249 | | |
|---|
| 1250 | | return true; |
|---|
| 1251 | | } |
|---|
| 1252 | | |
|---|
| 1253 | | /*************************************************************** |
|---|
| 1254 | | |
|---|
| 1255 | | Get info about this path |
|---|
| 1256 | | |
|---|
| 1257 | | ***************************************************************/ |
|---|
| 1258 | | |
|---|
| 1259 | | private static DWORD getInfo (char[] name, inout WIN32_FILE_ATTRIBUTE_DATA info) |
|---|
| 1260 | | { |
|---|
| 1261 | | if (! fileInfo (name, info)) |
|---|
| 1262 | | exception (name); |
|---|
| 1263 | | return info.dwFileAttributes; |
|---|
| 1264 | | } |
|---|
| 1265 | | |
|---|
| 1266 | | /*************************************************************** |
|---|
| 1267 | | |
|---|
| 1268 | | Get flags for this path |
|---|
| 1269 | | |
|---|
| 1270 | | ***************************************************************/ |
|---|
| 1271 | | |
|---|
| 1272 | | private static DWORD getFlags (char[] name) |
|---|
| 1273 | | { |
|---|
| 1274 | | WIN32_FILE_ATTRIBUTE_DATA info = void; |
|---|
| 1275 | | |
|---|
| 1276 | | return getInfo (name, info); |
|---|
| 1277 | | } |
|---|
| 1278 | | |
|---|
| 1279 | | /*************************************************************** |
|---|
| 1280 | | |
|---|
| 1281 | | Return whether the file or path exists |
|---|
| 1282 | | |
|---|
| 1283 | | ***************************************************************/ |
|---|
| 1284 | | |
|---|
| 1285 | | static bool exists (char[] name) |
|---|
| 1286 | | { |
|---|
| 1287 | | WIN32_FILE_ATTRIBUTE_DATA info = void; |
|---|
| 1288 | | |
|---|
| 1289 | | return fileInfo (name, info); |
|---|
| 1290 | | } |
|---|
| 1291 | | |
|---|
| 1292 | | /*************************************************************** |
|---|
| 1293 | | |
|---|
| 1294 | | Return the file length (in bytes) |
|---|
| 1295 | | |
|---|
| 1296 | | ***************************************************************/ |
|---|
| 1297 | | |
|---|
| 1298 | | static ulong fileSize (char[] name) |
|---|
| 1299 | | { |
|---|
| 1300 | | WIN32_FILE_ATTRIBUTE_DATA info = void; |
|---|
| 1301 | | |
|---|
| 1302 | | getInfo (name, info); |
|---|
| 1303 | | return (cast(ulong) info.nFileSizeHigh << 32) + |
|---|
| 1304 | | info.nFileSizeLow; |
|---|
| 1305 | | } |
|---|
| 1306 | | |
|---|
| 1307 | | /*************************************************************** |
|---|
| 1308 | | |
|---|
| 1309 | | Is this file writable? |
|---|
| 1310 | | |
|---|
| 1311 | | ***************************************************************/ |
|---|
| 1312 | | |
|---|
| 1313 | | static bool isWritable (char[] name) |
|---|
| 1314 | | { |
|---|
| 1315 | | return (getFlags(name) & FILE_ATTRIBUTE_READONLY) == 0; |
|---|
| 1316 | | } |
|---|
| 1317 | | |
|---|
| 1318 | | /*************************************************************** |
|---|
| 1319 | | |
|---|
| 1320 | | Is this file actually a folder/directory? |
|---|
| 1321 | | |
|---|
| 1322 | | ***************************************************************/ |
|---|
| 1323 | | |
|---|
| 1324 | | static bool isFolder (char[] name) |
|---|
| 1325 | | { |
|---|
| 1326 | | return (getFlags(name) & FILE_ATTRIBUTE_DIRECTORY) != 0; |
|---|
| 1327 | | } |
|---|
| 1328 | | |
|---|
| 1329 | | /*************************************************************** |
|---|
| 1330 | | |
|---|
| 1331 | | Return timestamp information |
|---|
| 1332 | | |
|---|
| 1333 | | Timstamps are returns in a format dictated by the |
|---|
| 1334 | | file-system. For example NTFS keeps UTC time, |
|---|
| 1335 | | while FAT timestamps are based on the local time |
|---|
| 1336 | | |
|---|
| 1337 | | ***************************************************************/ |
|---|
| 1338 | | |
|---|
| 1339 | | static Stamps timeStamps (char[] name) |
|---|
| 1340 | | { |
|---|
| 1341 | | static Time convert (FILETIME time) |
|---|
| 1342 | | { |
|---|
| 1343 | | return Time (TimeSpan.Epoch1601 + *cast(long*) &time); |
|---|
| 1344 | | } |
|---|
| 1345 | | |
|---|
| 1346 | | WIN32_FILE_ATTRIBUTE_DATA info = void; |
|---|
| 1347 | | Stamps time = void; |
|---|
| 1348 | | |
|---|
| 1349 | | getInfo (name, info); |
|---|
| 1350 | | time.modified = convert (info.ftLastWriteTime); |
|---|
| 1351 | | time.accessed = convert (info.ftLastAccessTime); |
|---|
| 1352 | | time.created = convert (info.ftCreationTime); |
|---|
| 1353 | | return time; |
|---|
| 1354 | | } |
|---|
| 1355 | | |
|---|
| 1356 | | /*************************************************************** |
|---|
| 1357 | | |
|---|
| 1358 | | Transfer the content of another file to this one. |
|---|
| 1359 | | Returns a reference to this class on success, or |
|---|
| 1360 | | throws an IOException upon failure. |
|---|
| 1361 | | |
|---|
| 1362 | | ***************************************************************/ |
|---|
| 1363 | | |
|---|
| 1364 | | static void copy (char[] src, char[] dst) |
|---|
| 1365 | | { |
|---|
| 1366 | | version (Win32SansUnicode) |
|---|
| 1367 | | { |
|---|
| 1368 | | if (! CopyFileA (src.ptr, dst.ptr, false)) |
|---|
| 1369 | | exception (src); |
|---|
| 1370 | | } |
|---|
| 1371 | | else |
|---|
| 1372 | | { |
|---|
| 1373 | | wchar[MAX_PATH+1] tmp1 = void; |
|---|
| 1374 | | wchar[MAX_PATH+1] tmp2 = void; |
|---|
| 1375 | | |
|---|
| 1376 | | if (! CopyFileW (toString16(tmp1, src).ptr, toString16(tmp2, dst).ptr, false)) |
|---|
| 1377 | | exception (src); |
|---|
| 1378 | | } |
|---|
| 1379 | | } |
|---|
| 1380 | | |
|---|
| 1381 | | /*************************************************************** |
|---|
| 1382 | | |
|---|
| 1383 | | Remove the file/directory from the file-system |
|---|
| 1384 | | |
|---|
| 1385 | | ***************************************************************/ |
|---|
| 1386 | | |
|---|
| 1387 | | static void remove (char[] name) |
|---|
| 1388 | | { |
|---|
| 1389 | | if (isFolder(name)) |
|---|
| 1390 | | { |
|---|
| 1391 | | version (Win32SansUnicode) |
|---|
| 1392 | | { |
|---|
| 1393 | | if (! RemoveDirectoryA (name.ptr)) |
|---|
| 1394 | | exception (name); |
|---|
| 1395 | | } |
|---|
| 1396 | | else |
|---|
| 1397 | | { |
|---|
| 1398 | | wchar[MAX_PATH] tmp = void; |
|---|
| 1399 | | if (! RemoveDirectoryW (toString16(tmp, name).ptr)) |
|---|
| 1400 | | exception (name); |
|---|
| 1401 | | } |
|---|
| 1402 | | } |
|---|
| 1403 | | else |
|---|
| 1404 | | version (Win32SansUnicode) |
|---|
| 1405 | | { |
|---|
| 1406 | | if (! DeleteFileA (name.ptr)) |
|---|
| 1407 | | exception (name); |
|---|
| 1408 | | } |
|---|
| 1409 | | else |
|---|
| 1410 | | { |
|---|
| 1411 | | wchar[MAX_PATH] tmp = void; |
|---|
| 1412 | | if (! DeleteFileW (toString16(tmp, name).ptr)) |
|---|
| 1413 | | exception (name); |
|---|
| 1414 | | } |
|---|
| 1415 | | } |
|---|
| 1416 | | |
|---|
| 1417 | | /*************************************************************** |
|---|
| 1418 | | |
|---|
| 1419 | | change the name or location of a file/directory, and |
|---|
| 1420 | | adopt the provided Path |
|---|
| 1421 | | |
|---|
| 1422 | | ***************************************************************/ |
|---|
| 1423 | | |
|---|
| 1424 | | static void rename (char[] src, char[] dst) |
|---|
| 1425 | | { |
|---|
| 1426 | | const int Typical = MOVEFILE_REPLACE_EXISTING + |
|---|
| 1427 | | MOVEFILE_COPY_ALLOWED + |
|---|
| 1428 | | MOVEFILE_WRITE_THROUGH; |
|---|
| 1429 | | |
|---|
| 1430 | | int result; |
|---|
| 1431 | | version (Win32SansUnicode) |
|---|
| 1432 | | result = MoveFileExA (src.ptr, dst.ptr, Typical); |
|---|
| 1433 | | else |
|---|
| 1434 | | { |
|---|
| 1435 | | wchar[MAX_PATH] tmp1 = void; |
|---|
| 1436 | | wchar[MAX_PATH] tmp2 = void; |
|---|
| 1437 | | result = MoveFileExW (toString16(tmp1, src).ptr, toString16(tmp2, dst).ptr, Typical); |
|---|
| 1438 | | } |
|---|
| 1439 | | |
|---|
| 1440 | | if (! result) |
|---|
| 1441 | | exception (src); |
|---|
| 1442 | | } |
|---|
| 1443 | | |
|---|
| 1444 | | /*************************************************************** |
|---|
| 1445 | | |
|---|
| 1446 | | Create a new file |
|---|
| 1447 | | |
|---|
| 1448 | | ***************************************************************/ |
|---|
| 1449 | | |
|---|
| 1450 | | static void createFile (char[] name) |
|---|
| 1451 | | { |
|---|
| 1452 | | HANDLE h; |
|---|
| 1453 | | |
|---|
| 1454 | | version (Win32SansUnicode) |
|---|
| 1455 | | h = CreateFileA (name.ptr, GENERIC_WRITE, |
|---|
| 1456 | | 0, null, CREATE_ALWAYS, |
|---|
| 1457 | | FILE_ATTRIBUTE_NORMAL, cast(HANDLE) 0); |
|---|
| 1458 | | else |
|---|
| 1459 | | { |
|---|
| 1460 | | wchar[MAX_PATH] tmp = void; |
|---|
| 1461 | | h = CreateFileW (toString16(tmp, name).ptr, GENERIC_WRITE, |
|---|
| 1462 | | 0, null, CREATE_ALWAYS, |
|---|
| 1463 | | FILE_ATTRIBUTE_NORMAL, cast(HANDLE) 0); |
|---|
| 1464 | | } |
|---|
| 1465 | | |
|---|
| 1466 | | if (h == INVALID_HANDLE_VALUE) |
|---|
| 1467 | | exception (name); |
|---|
| 1468 | | |
|---|
| 1469 | | if (! CloseHandle (h)) |
|---|
| 1470 | | exception (name); |
|---|
| 1471 | | } |
|---|
| 1472 | | |
|---|
| 1473 | | /*************************************************************** |
|---|
| 1474 | | |
|---|
| 1475 | | Create a new directory |
|---|
| 1476 | | |
|---|
| 1477 | | ***************************************************************/ |
|---|
| 1478 | | |
|---|
| 1479 | | static void createFolder (char[] name) |
|---|
| 1480 | | { |
|---|
| 1481 | | version (Win32SansUnicode) |
|---|
| 1482 | | { |
|---|
| 1483 | | if (! CreateDirectoryA (name.ptr, null)) |
|---|
| 1484 | | exception (name); |
|---|
| 1485 | | } |
|---|
| 1486 | | else |
|---|
| 1487 | | { |
|---|
| 1488 | | wchar[MAX_PATH] tmp = void; |
|---|
| 1489 | | if (! CreateDirectoryW (toString16(tmp, name).ptr, null)) |
|---|
| 1490 | | exception (name); |
|---|
| 1491 | | } |
|---|
| 1492 | | } |
|---|
| 1493 | | |
|---|
| 1494 | | /*************************************************************** |
|---|
| 1495 | | |
|---|
| 1496 | | List the set of filenames within this folder. |
|---|
| 1497 | | |
|---|
| 1498 | | Each path and filename is passed to the provided |
|---|
| 1499 | | delegate, along with the path prefix and whether |
|---|
| 1500 | | the entry is a folder or not. |
|---|
| 1501 | | |
|---|
| 1502 | | Returns the number of files scanned. |
|---|
| 1503 | | |
|---|
| 1504 | | ***************************************************************/ |
|---|
| 1505 | | |
|---|
| 1506 | | static int list (char[] folder, int delegate(ref FileInfo) dg) |
|---|
| 1507 | | { |
|---|
| 1508 | | HANDLE h; |
|---|
| 1509 | | int ret; |
|---|
| 1510 | | char[] prefix; |
|---|
| 1511 | | char[MAX_PATH+1] tmp = void; |
|---|
| 1512 | | FIND_DATA fileinfo = void; |
|---|
| 1513 | | |
|---|
| 1514 | | int next() |
|---|
| 1515 | | { |
|---|
| 1516 | | version (Win32SansUnicode) |
|---|
| 1517 | | return FindNextFileA (h, &fileinfo); |
|---|
| 1518 | | else |
|---|
| 1519 | | return FindNextFileW (h, &fileinfo); |
|---|
| 1520 | | } |
|---|
| 1521 | | |
|---|
| 1522 | | static T[] padded (T[] s, T[] ext) |
|---|
| 1523 | | { |
|---|
| 1524 | | if (s.length is 0 || s[$-1] != '\\') |
|---|
| 1525 | | return s ~ "\\" ~ ext; |
|---|
| 1526 | | return s ~ ext; |
|---|
| 1527 | | } |
|---|
| 1528 | | |
|---|
| 1529 | | version (Win32SansUnicode) |
|---|
| 1530 | | h = FindFirstFileA (padded(folder[0..$-1], "*\0").ptr, &fileinfo); |
|---|
| 1531 | | else |
|---|
| 1532 | | { |
|---|
| 1533 | | wchar[MAX_PATH] host = void; |
|---|
| 1534 | | h = FindFirstFileW (padded(toString16(host, folder[0..$-1]), "*\0").ptr, &fileinfo); |
|---|
| 1535 | | } |
|---|
| 1536 | | |
|---|
| 1537 | | if (h is INVALID_HANDLE_VALUE) |
|---|
| 1538 | | exception (folder); |
|---|
| 1539 | | |
|---|
| 1540 | | scope (exit) |
|---|
| 1541 | | FindClose (h); |
|---|
| 1542 | | |
|---|
| 1543 | | prefix = FilePath.padded (folder[0..$-1]); |
|---|
| 1544 | | do { |
|---|
| 1545 | | version (Win32SansUnicode) |
|---|
| 1546 | | { |
|---|
| 1547 | | auto len = strlen (fileinfo.cFileName.ptr); |
|---|
| 1548 | | auto str = fileinfo.cFileName.ptr [0 .. len]; |
|---|
| 1549 | | } |
|---|
| 1550 | | else |
|---|
| 1551 | | { |
|---|
| 1552 | | auto len = wcslen (fileinfo.cFileName.ptr); |
|---|
| 1553 | | auto str = toString (tmp, fileinfo.cFileName [0 .. len]); |
|---|
| 1554 | | } |
|---|
| 1555 | | |
|---|
| 1556 | | // skip hidden/system files |
|---|
| 1557 | | if ((fileinfo.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)) is 0) |
|---|
| 1558 | | { |
|---|
| 1559 | | FileInfo info = void; |
|---|
| 1560 | | info.name = str; |
|---|
| 1561 | | info.path = prefix; |
|---|
| 1562 | | info.bytes = (cast(ulong) fileinfo.nFileSizeHigh << 32) + fileinfo.nFileSizeLow; |
|---|
| 1563 | | info.folder = (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; |
|---|
| 1564 | | |
|---|
| 1565 | | // skip "..." names |
|---|
| 1566 | | if (str.length > 3 || str != "..."[0 .. str.length]) |
|---|
| 1567 | | if ((ret = dg(info)) != 0) |
|---|
| 1568 | | break; |
|---|
| 1569 | | } |
|---|
| 1570 | | } while (next); |
|---|
| 1571 | | |
|---|
| 1572 | | return ret; |
|---|
| 1573 | | } |
|---|
| 1574 | | } |
|---|
| 1575 | | |
|---|
| 1576 | | /*********************************************************************** |
|---|
| 1577 | | |
|---|
| 1578 | | Posix-specific code |
|---|
| 1579 | | |
|---|
| 1580 | | ***********************************************************************/ |
|---|
| 1581 | | |
|---|
| 1582 | | version (Posix) |
|---|
| 1583 | | { |
|---|
| 1584 | | /*************************************************************** |
|---|
| 1585 | | |
|---|
| 1586 | | Get info about this path |
|---|
| 1587 | | |
|---|
| 1588 | | ***************************************************************/ |
|---|
| 1589 | | |
|---|
| 1590 | | private static uint getInfo (char[] name, inout stat_t stats) |
|---|
| 1591 | | { |
|---|
| 1592 | | if (posix.stat (name.ptr, &stats)) |
|---|
| 1593 | | exception (name); |
|---|
| 1594 | | |
|---|
| 1595 | | return stats.st_mode; |
|---|
| 1596 | | } |
|---|
| 1597 | | |
|---|
| 1598 | | /*************************************************************** |
|---|
| 1599 | | |
|---|
| 1600 | | Return whether the file or path exists |
|---|
| 1601 | | |
|---|
| 1602 | | ***************************************************************/ |
|---|
| 1603 | | |
|---|
| 1604 | | static bool exists (char[] name) |
|---|
| 1605 | | { |
|---|
| 1606 | | stat_t stats = void; |
|---|
| 1607 | | return posix.stat (name.ptr, &stats) is 0; |
|---|
| 1608 | | } |
|---|
| 1609 | | |
|---|
| 1610 | | /*************************************************************** |
|---|
| 1611 | | |
|---|
| 1612 | | Return the file length (in bytes) |
|---|
| 1613 | | |
|---|
| 1614 | | ***************************************************************/ |
|---|
| 1615 | | |
|---|
| 1616 | | static ulong fileSize (char[] name) |
|---|
| 1617 | | { |
|---|
| 1618 | | stat_t stats = void; |
|---|
| 1619 | | |
|---|
| 1620 | | getInfo (name, stats); |
|---|
| 1621 | | return cast(ulong) stats.st_size; // 32 bits only |
|---|
| 1622 | | } |
|---|
| 1623 | | |
|---|
| 1624 | | /*************************************************************** |
|---|
| 1625 | | |
|---|
| 1626 | | Is this file writable? |
|---|
| 1627 | | |
|---|
| 1628 | | ***************************************************************/ |
|---|
| 1629 | | |
|---|
| 1630 | | static bool isWritable (char[] name) |
|---|
| 1631 | | { |
|---|
| 1632 | | stat_t stats = void; |
|---|
| 1633 | | |
|---|
| 1634 | | return (getInfo(name, stats) & O_RDONLY) == 0; |
|---|
| 1635 | | } |
|---|
| 1636 | | |
|---|
| 1637 | | /*************************************************************** |
|---|
| 1638 | | |
|---|
| 1639 | | Is this file actually a folder/directory? |
|---|
| 1640 | | |
|---|
| 1641 | | ***************************************************************/ |
|---|
| 1642 | | |
|---|
| 1643 | | static bool isFolder (char[] name) |
|---|
| 1644 | | { |
|---|
| 1645 | | stat_t stats = void; |
|---|
| 1646 | | |
|---|
| 1647 | | return (getInfo(name, stats) & S_IFDIR) != 0; |
|---|
| 1648 | | } |
|---|
| 1649 | | |
|---|
| 1650 | | /*************************************************************** |
|---|
| 1651 | | |
|---|
| 1652 | | Return timestamp information |
|---|
| 1653 | | |
|---|
| 1654 | | Timstamps are returns in a format dictated by the |
|---|
| 1655 | | file-system. For example NTFS keeps UTC time, |
|---|
| 1656 | | while FAT timestamps are based on the local time |
|---|
| 1657 | | |
|---|
| 1658 | | ***************************************************************/ |
|---|
| 1659 | | |
|---|
| 1660 | | static Stamps timeStamps (char[] name) |
|---|
| 1661 | | { |
|---|
| 1662 | | static Time convert (timeval* tv) |
|---|
| 1663 | | { |
|---|
| 1664 | | return Time.epoch1970 + |
|---|
| 1665 | | TimeSpan.seconds(tv.tv_sec) + |
|---|
| 1666 | | TimeSpan.micros(tv.tv_usec); |
|---|
| 1667 | | } |
|---|
| 1668 | | |
|---|
| 1669 | | stat_t stats = void; |
|---|
| 1670 | | Stamps time = void; |
|---|
| 1671 | | |
|---|
| 1672 | | getInfo (name, stats); |
|---|
| 1673 | | |
|---|
| 1674 | | time.modified = convert (cast(timeval*) &stats.st_mtime); |
|---|
| 1675 | | time.accessed = convert (cast(timeval*) &stats.st_atime); |
|---|
| 1676 | | time.created = convert (cast(timeval*) &stats.st_ctime); |
|---|
| 1677 | | return time; |
|---|
| 1678 | | } |
|---|
| 1679 | | |
|---|
| 1680 | | /*********************************************************************** |
|---|
| 1681 | | |
|---|
| 1682 | | Transfer the content of another file to this one. Returns a |
|---|
| 1683 | | reference to this class on success, or throws an IOException |
|---|
| 1684 | | upon failure. |
|---|
| 1685 | | |
|---|
| 1686 | | ***********************************************************************/ |
|---|
| 1687 | | |
|---|
| 1688 | | static void copy (char[] source, char[] dest) |
|---|
| 1689 | | { |
|---|
| 1690 | | auto src = posix.open (source.ptr, O_RDONLY, 0640); |
|---|
| 1691 | | scope (exit) |
|---|
| 1692 | | if (src != -1) |
|---|
| 1693 | | posix.close (src); |
|---|
| 1694 | | |
|---|
| 1695 | | auto dst = posix.open (dest.ptr, O_CREAT | O_RDWR, 0660); |
|---|
| 1696 | | scope (exit) |
|---|
| 1697 | | if (dst != -1) |
|---|
| 1698 | | posix.close (dst); |
|---|
| 1699 | | |
|---|
| 1700 | | if (src is -1 || dst is -1) |
|---|
| 1701 | | exception (source); |
|---|
| 1702 | | |
|---|
| 1703 | | // copy content |
|---|
| 1704 | | ubyte[] buf = new ubyte [16 * 1024]; |
|---|
| 1705 | | int read = posix.read (src, buf.ptr, buf.length); |
|---|
| 1706 | | while (read > 0) |
|---|
| 1707 | | { |
|---|
| 1708 | | auto p = buf.ptr; |
|---|
| 1709 | | do { |
|---|
| 1710 | | int written = posix.write (dst, p, read); |
|---|
| 1711 | | p += written; |
|---|
| 1712 | | read -= written; |
|---|
| 1713 | | if (written is -1) |
|---|
| 1714 | | exception (dest); |
|---|
| 1715 | | } while (read > 0); |
|---|
| 1716 | | read = posix.read (src, buf.ptr, buf.length); |
|---|
| 1717 | | } |
|---|
| 1718 | | if (read is -1) |
|---|
| 1719 | | exception (source); |
|---|
| 1720 | | |
|---|
| 1721 | | // copy timestamps |
|---|
| 1722 | | stat_t stats; |
|---|
| 1723 | | if (posix.stat (source.ptr, &stats)) |
|---|
| 1724 | | exception (source); |
|---|
| 1725 | | |
|---|
| 1726 | | utimbuf utim; |
|---|
| 1727 | | utim.actime = stats.st_atime; |
|---|
| 1728 | | utim.modtime = stats.st_mtime; |
|---|
| 1729 | | if (utime (dest.ptr, &utim) is -1) |
|---|
| 1730 | | exception (dest); |
|---|
| 1731 | | } |
|---|
| 1732 | | |
|---|
| 1733 | | /*************************************************************** |
|---|
| 1734 | | |
|---|
| 1735 | | Remove the file/directory from the file-system |
|---|
| 1736 | | |
|---|
| 1737 | | ***************************************************************/ |
|---|
| 1738 | | |
|---|
| 1739 | | static void remove (char[] name) |
|---|
| 1740 | | { |
|---|
| 1741 | | if (isFolder (name)) |
|---|
| 1742 | | { |
|---|
| 1743 | | if (posix.rmdir (name.ptr)) |
|---|
| 1744 | | exception (name); |
|---|
| 1745 | | } |
|---|
| 1746 | | else |
|---|
| 1747 | | if (tango.stdc.stdio.remove (name.ptr) == -1) |
|---|
| 1748 | | exception (name); |
|---|
| 1749 | | } |
|---|
| 1750 | | |
|---|
| 1751 | | /*************************************************************** |
|---|
| 1752 | | |
|---|
| 1753 | | change the name or location of a file/directory, and |
|---|
| 1754 | | adopt the provided FilePath |
|---|
| 1755 | | |
|---|
| 1756 | | ***************************************************************/ |
|---|
| 1757 | | |
|---|
| 1758 | | static void rename (char[] src, char[] dst) |
|---|
| 1759 | | { |
|---|
| 1760 | | if (tango.stdc.stdio.rename (src.ptr, dst.ptr) == -1) |
|---|
| 1761 | | exception (src); |
|---|
| 1762 | | } |
|---|
| 1763 | | |
|---|
| 1764 | | /*************************************************************** |
|---|
| 1765 | | |
|---|
| 1766 | | Create a new file |
|---|
| 1767 | | |
|---|
| 1768 | | ***************************************************************/ |
|---|
| 1769 | | |
|---|
| 1770 | | static void createFile (char[] name) |
|---|
| 1771 | | { |
|---|
| 1772 | | int fd; |
|---|
| 1773 | | |
|---|
| 1774 | | fd = posix.open (name.ptr, O_CREAT | O_WRONLY | O_TRUNC, 0660); |
|---|
| 1775 | | if (fd == -1) |
|---|
| 1776 | | exception (name); |
|---|
| 1777 | | |
|---|
| 1778 | | if (posix.close(fd) == -1) |
|---|
| 1779 | | exception (name); |
|---|
| 1780 | | } |
|---|
| 1781 | | |
|---|
| 1782 | | /*************************************************************** |
|---|
| 1783 | | |
|---|
| 1784 | | Create a new directory |
|---|
| 1785 | | |
|---|
| 1786 | | ***************************************************************/ |
|---|
| 1787 | | |
|---|
| 1788 | | static void createFolder (char[] name) |
|---|
| 1789 | | { |
|---|
| 1790 | | if (posix.mkdir (name.ptr, 0777)) |
|---|
| 1791 | | exception (name); |
|---|
| 1792 | | } |
|---|
| 1793 | | /*************************************************************** |
|---|
| 1794 | | |
|---|
| 1795 | | List the set of filenames within this folder. |
|---|
| 1796 | | |
|---|
| 1797 | | Each path and filename is passed to the provided |
|---|
| 1798 | | delegate, along with the path prefix and whether |
|---|
| 1799 | | the entry is a folder or not. |
|---|
| 1800 | | |
|---|
| 1801 | | Returns the number of files scanned. |
|---|
| 1802 | | |
|---|
| 1803 | | ***************************************************************/ |
|---|
| 1804 | | |
|---|
| 1805 | | static int list (char[] folder, int delegate(ref FileInfo) dg) |
|---|