/platform/win/scaffold/directory.d

http://github.com/wilkie/djehuty · D · 495 lines · 240 code · 110 blank · 145 comment · 56 complexity · e4a2856cb602873b51a2198be18c62fb MD5 · raw file

  1. /*
  2. * directory.d
  3. *
  4. * This file implements the Scaffold for platform specific Directory
  5. * traversal in Windows.
  6. *
  7. * Author: Dave Wilkinson
  8. *
  9. */
  10. module scaffold.directory;
  11. pragma(lib, "netapi32.lib");
  12. pragma(lib, "mpr.lib");
  13. import platform.win.common;
  14. import platform.vars.directory;
  15. import core.string;
  16. import core.main;
  17. import core.unicode;
  18. import io.console;
  19. import io.file;
  20. bool DirectoryOpen(ref DirectoryPlatformVars dirVars, ref string path) {
  21. if (DirectoryFileIsDir(path)) {
  22. return true;
  23. }
  24. return false;
  25. }
  26. bool DirectoryCreate(ref DirectoryPlatformVars dirVars, ref string path) {
  27. wchar[] strArr = _ConvertFrameworkPath(Unicode.toUtf16(path));
  28. strArr ~= '\0';
  29. if (DirectoryFileIsDir(path)) {
  30. return false;
  31. }
  32. if(CreateDirectoryW(strArr.ptr,null) != 0){
  33. return true;
  34. }
  35. return false;
  36. }
  37. bool DirectoryClose(ref DirectoryPlatformVars dirVars) {
  38. return false;
  39. }
  40. string DirectoryGetBinary() {
  41. static string cached;
  42. // %PROGRAMFILES%
  43. if (cached is null) {
  44. wchar[] str;
  45. int ret = GetEnvironmentVariableW("PROGRAMFILES\0"w.ptr, null, 0);
  46. str = new wchar[ret];
  47. ret = GetEnvironmentVariableW("PROGRAMFILES\0"w.ptr, str.ptr, ret);
  48. str = _SanitizeWindowsPath(str[0..ret]);
  49. cached = Unicode.toUtf8(str) ~ "/" ~ Djehuty.app.name;
  50. }
  51. return cached;
  52. }
  53. string DirectoryGetAppData() {
  54. static string cached;
  55. // %PROGRAMFILES%
  56. if (cached is null) {
  57. wchar[] str = new wchar[5];
  58. int ret = GetEnvironmentVariableW("PROGRAMFILES\0"w.ptr, str.ptr, 0);
  59. str = new wchar[ret];
  60. ret = GetEnvironmentVariableW("PROGRAMFILES\0"w.ptr, str.ptr, ret);
  61. str = _SanitizeWindowsPath(str[0..ret]);
  62. cached = Unicode.toUtf8(str) ~ "/" ~ Djehuty.app.name;
  63. }
  64. return cached;
  65. }
  66. string DirectoryGetTempData() {
  67. static string cached;
  68. if (cached is null) {
  69. int ret = GetTempPathW(0, null);
  70. ret++;
  71. wchar[] str = new wchar[ret];
  72. ret = GetTempPathW(ret, str.ptr);
  73. str = _SanitizeWindowsPath(str[0..ret]);
  74. cached = Unicode.toUtf8(str) ~ "/dpj" ~ toStr(GetCurrentProcessId());
  75. }
  76. return cached;
  77. }
  78. string DirectoryGetUserData() {
  79. static string cached;
  80. // %APPDATA%
  81. if (cached is null) {
  82. wchar[] str;
  83. int ret = GetEnvironmentVariableW("APPDATA\0"w.ptr, null, 0);
  84. str = new wchar[ret];
  85. ret = GetEnvironmentVariableW("APPDATA\0"w.ptr, str.ptr, ret);
  86. str = _SanitizeWindowsPath(str[0..ret]);
  87. cached = Unicode.toUtf8(str) ~ "/" ~ Djehuty.app.name;
  88. }
  89. return cached;
  90. }
  91. string DirectoryGetApp() {
  92. int size = 512;
  93. int ret = 0;
  94. wchar[] dir;
  95. do {
  96. dir = new wchar[size];
  97. ret = GetModuleFileNameW(null, dir.ptr, size);
  98. size <<= 2;
  99. } while (size == ret)
  100. if (ret > 0) {
  101. dir = dir[0..ret-1];
  102. }
  103. dir = _SanitizeWindowsPath(dir);
  104. dir = _TruncateFileName(dir);
  105. return Unicode.toUtf8(dir);
  106. }
  107. string DirectoryGetCWD() {
  108. int size = GetCurrentDirectoryW(0, null);
  109. wchar[] cwd = new wchar[size];
  110. GetCurrentDirectoryW(size, cwd.ptr);
  111. cwd = cwd[0..$-1];
  112. cwd = _SanitizeWindowsPath(cwd);
  113. return Unicode.toUtf8(cwd);
  114. }
  115. bool DirectoryFileIsDir(string path) {
  116. wchar[] strArr = _ConvertFrameworkPath(Unicode.toUtf16(path));
  117. strArr ~= '\0';
  118. DWORD ret = GetFileAttributesW(strArr.ptr);
  119. return (ret & FILE_ATTRIBUTE_DIRECTORY) > 0;
  120. }
  121. bool DirectoryRename(ref string path, string newName) {
  122. string old = path.dup;
  123. old ~= '\0';
  124. string str;
  125. foreach_reverse(int i, chr; path) {
  126. if (chr == '/') {
  127. // truncate
  128. str = path[0..i];
  129. break;
  130. }
  131. }
  132. if (str is null) {
  133. return false;
  134. }
  135. str ~= '/';
  136. str ~= newName;
  137. str ~= '\0';
  138. wchar[] strArr = _ConvertFrameworkPath(Unicode.toUtf16(str));
  139. wchar[] oldArr = _ConvertFrameworkPath(Unicode.toUtf16(old));
  140. MoveFileW(oldArr.ptr, strArr.ptr);
  141. return true;
  142. }
  143. bool DirectoryMove(ref string path, string newPath) {
  144. string old = path.dup;
  145. old ~= '\0';
  146. string str = newPath.dup;
  147. str ~= '\0';
  148. wchar[] strArr = _ConvertFrameworkPath(Unicode.toUtf16(str));
  149. wchar[] oldArr = _ConvertFrameworkPath(Unicode.toUtf16(old));
  150. MoveFileW(oldArr.ptr, strArr.ptr);
  151. return true;
  152. }
  153. bool DirectoryCopy(ref string path, string newPath) {
  154. string old = path.dup;
  155. old ~= '\0';
  156. string str = newPath.dup;
  157. str ~= '\0';
  158. wchar[] strArr = _ConvertFrameworkPath(Unicode.toUtf16(str));
  159. wchar[] oldArr = _ConvertFrameworkPath(Unicode.toUtf16(old));
  160. CopyFileW(oldArr.ptr, strArr.ptr, 0);
  161. return true;
  162. }
  163. string[] _ReturnSharedFolders(wchar[] serverName) {
  164. // Read all drives on this server
  165. string[] ret;
  166. /*
  167. SHARE_INFO_0* bufptr;
  168. DWORD dwEntriesRead;
  169. DWORD dwTotalEntries;
  170. DWORD dwResumeHandle;
  171. uint MAX_PREFERRED_LENGTH = short.max;
  172. NetShareEnum(serverName.ptr, 0, cast(void**)&bufptr, -1,
  173. &dwEntriesRead, &dwTotalEntries, &dwResumeHandle);
  174. NetApiBufferFree(cast(void*)bufptr);
  175. foreach(shareItem; bufptr[0..dwEntriesRead]) {
  176. wchar[] pcchrs = shareItem.shi0_netname[0..strlen(shareItem.shi0_netname)];
  177. if (pcchrs.length > 0 && pcchrs[$-1] != '$') {
  178. ret ~= new String(Unicode.toUtf8(pcchrs));
  179. }
  180. }
  181. */
  182. return ret;
  183. }
  184. string[] _ReturnNetworkComputers() {
  185. string[] ret;
  186. /*
  187. HANDLE enumWorkgroupHandle;
  188. DWORD bufferSize = 16284;
  189. NETRESOURCEW[16284 / NETRESOURCEW.sizeof] networkResource;
  190. WNetOpenEnumW(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, null, &enumWorkgroupHandle);
  191. DWORD numEntries = -1;
  192. WNetEnumResourceW(enumWorkgroupHandle, &numEntries, cast(void*)networkResource.ptr, &bufferSize);
  193. foreach(item; networkResource[0..numEntries]) {
  194. HANDLE subWorkgroupHandle;
  195. WNetOpenEnumW(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, &item, &subWorkgroupHandle);
  196. DWORD subEntries = -1;
  197. NETRESOURCEW[16284 / NETRESOURCEW.sizeof] subResource;
  198. DWORD subSize = 16284;
  199. WNetEnumResourceW(subWorkgroupHandle, &subEntries, cast(void*)subResource.ptr, &subSize);
  200. foreach(subitem; subResource[0..subEntries]) {
  201. if (subitem.lpRemoteName !is null && subitem.dwDisplayType & RESOURCEDISPLAYTYPE_GROUP) {
  202. // Read all computers on this workgroup
  203. SERVER_INFO_101* bufptr;
  204. DWORD dwEntriesRead;
  205. DWORD dwTotalEntries;
  206. DWORD dwResumeHandle;
  207. uint MAX_PREFERRED_LENGTH = short.max;
  208. NetServerEnum(null, 101, cast(void**)&bufptr, MAX_PREFERRED_LENGTH,
  209. &dwEntriesRead, &dwTotalEntries, SV_TYPE_ALL, subitem.lpRemoteName, &dwResumeHandle);
  210. SERVER_INFO_101* tmpptr = bufptr;
  211. foreach(pcitem; tmpptr[0..dwEntriesRead]) {
  212. wchar[] pcchrs = pcitem.sv101_name[0..strlen(pcitem.sv101_name)];
  213. ret ~= new String(Unicode.toUtf8(pcchrs));
  214. }
  215. NetApiBufferFree(cast(void*)bufptr);
  216. }
  217. }
  218. WNetCloseEnum(subWorkgroupHandle);
  219. }
  220. WNetCloseEnum(enumWorkgroupHandle);
  221. SERVER_INFO_101* bufptr;
  222. DWORD dwEntriesRead;
  223. DWORD dwTotalEntries;
  224. DWORD dwResumeHandle;
  225. uint MAX_PREFERRED_LENGTH = short.max;
  226. NetServerEnum(null, 101, cast(void**)&bufptr, MAX_PREFERRED_LENGTH,
  227. &dwEntriesRead, &dwTotalEntries, SV_TYPE_ALL, null, &dwResumeHandle);
  228. SERVER_INFO_101* tmpptr = bufptr;
  229. foreach(pcitem; tmpptr[0..dwEntriesRead]) {
  230. wchar[] pcchrs = pcitem.sv101_name[0..strlen(pcitem.sv101_name)];
  231. // do not let in a duplicate
  232. String thisPC = new String(Unicode.toUtf8(pcchrs));
  233. bool isThere = false;
  234. foreach(strFound; ret) {
  235. if (strFound == thisPC) {
  236. isThere = true;
  237. break;
  238. }
  239. }
  240. if (!isThere) {
  241. ret ~= thisPC;
  242. }
  243. }
  244. NetApiBufferFree(cast(void*)bufptr);
  245. */
  246. return ret;
  247. }
  248. wchar[] _SanitizeWindowsPath(wchar[] tmp) {
  249. if (tmp.length == 0) { return tmp; }
  250. // Handle networks
  251. if (tmp.length > 1 && tmp[0..2] == "\\\\") {
  252. tmp = "/network" ~ tmp[1..$];
  253. }
  254. // Change C: to /c
  255. if (tmp.length > 1 && tmp[0] != '/') {
  256. tmp[1] = tmp[0];
  257. tmp[0] = '/';
  258. }
  259. // Convert slashes
  260. foreach(int i, chr; tmp) {
  261. if(chr == '\\') {
  262. tmp[i] = '/';
  263. }
  264. }
  265. // Remove final slash
  266. if (tmp[tmp.length-1] == '/') {
  267. tmp = tmp[0..tmp.length-1];
  268. }
  269. return tmp;
  270. }
  271. wchar[] _TruncateFileName(wchar[] tmp) {
  272. if (tmp.length == 0) { return tmp; }
  273. foreach_reverse(int i, chr; tmp) {
  274. if(chr == '/') {
  275. return tmp[0..i];
  276. }
  277. }
  278. return tmp;
  279. }
  280. wchar[] _ConvertFrameworkPath(wchar[] tmp) {
  281. if (tmp.length == 0) { return tmp; }
  282. // Handle networks
  283. if (tmp.length > 9 && tmp[0..9] == "/network/") {
  284. tmp = "\\\\" ~ tmp[9..$];
  285. }
  286. // Change /c to C:
  287. if (tmp.length > 1 && tmp[0] == '/') {
  288. tmp[0] = tmp[1];
  289. tmp[1] = ':';
  290. }
  291. // No need to convert slashes, windows api accepts POSIX paths
  292. return tmp;
  293. }
  294. string[] DirectoryList(ref DirectoryPlatformVars dirVars, string path) {
  295. // trim trailing slash
  296. if (path.length > 0 && path[path.length - 1] == '/' || path[path.length - 1] == '\\') {
  297. path = path[0..path.length-1];
  298. }
  299. string newpath = path.dup;
  300. newpath = Unicode.toUtf8(_ConvertFrameworkPath(Unicode.toUtf16(newpath)));
  301. string[] list;
  302. if (newpath == "") {
  303. // root directory listing
  304. // that is, list the network folder and all drives
  305. int logicaldrives = GetLogicalDrives();
  306. string curDrive = ['a'];
  307. while(logicaldrives != 0) {
  308. if ((logicaldrives & 1) == 1) {
  309. list ~= curDrive;
  310. }
  311. if (curDrive[0] == 'z') { break; }
  312. curDrive[0]++;
  313. logicaldrives >>= 1;
  314. }
  315. list ~= "network";
  316. return list;
  317. }
  318. /*else if (path.length >= 8 && path[0..8] == "/network") {
  319. // Get relative path to /network
  320. if (path.length == 8) {
  321. return _ReturnNetworkComputers;
  322. }
  323. else {
  324. String newPath = path.subString(9);
  325. // find next slash (if there is one)
  326. int pos = newPath.find("/");
  327. if (pos == -1) {
  328. // Just a pcname
  329. return _ReturnSharedFolders(newPath.toUtf16 ~ "\0"w);
  330. }
  331. else {
  332. // Fall through to normal directory listing
  333. }
  334. }
  335. }*/
  336. // regular directory listing
  337. DirectoryOpen(dirVars, newpath);
  338. WIN32_FIND_DATAW ffd;
  339. wstring pn = Unicode.toUtf16(newpath);
  340. pn ~= "/*";
  341. pn ~= '\0';
  342. HANDLE h = FindFirstFileW(pn.ptr, &ffd);
  343. bool cont = true;
  344. while(cont) {
  345. // Caculate Length of d_name
  346. int len;
  347. foreach(chr; ffd.cFileName) {
  348. if (chr == '\0') {
  349. break;
  350. }
  351. len++;
  352. }
  353. // Add to list
  354. if (ffd.cFileName[0..len] != "." && ffd.cFileName[0..len] != "..") {
  355. list ~= Unicode.toUtf8(ffd.cFileName[0..len]);
  356. }
  357. // Retrieve next item in the directory
  358. cont = FindNextFileW(h, &ffd) > 0;
  359. }
  360. DirectoryClose(dirVars);
  361. return list;
  362. }