The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

497 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "linuxincludes.h"
  24. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  25. #include <sys/stat.h>
  26. #include <sys/dir.h>
  27. #include <sys/ptrace.h>
  28. #include <sys/vfs.h> // for statfs
  29. #include <sys/wait.h>
  30. #include <unistd.h>
  31. #include <fnmatch.h>
  32. #include <utime.h>
  33. #include <pwd.h>
  34. #include <fcntl.h>
  35. #define U_ISOFS_SUPER_MAGIC (short) 0x9660 // linux/iso_fs.h
  36. #define U_MSDOS_SUPER_MAGIC (short) 0x4d44 // linux/msdos_fs.h
  37. #define U_NFS_SUPER_MAGIC (short) 0x6969 // linux/nfs_fs.h
  38. #define U_SMB_SUPER_MAGIC (short) 0x517B // linux/smb_fs.h
  39. BEGIN_JUCE_NAMESPACE
  40. #include "../../../src/juce_core/io/files/juce_FileInputStream.h"
  41. #include "../../../src/juce_core/io/files/juce_FileOutputStream.h"
  42. #include "../../../src/juce_core/basics/juce_SystemStats.h"
  43. #include "../../../src/juce_core/basics/juce_Time.h"
  44. #include "../../../src/juce_core/basics/juce_Random.h"
  45. #include "../../../src/juce_core/io/network/juce_URL.h"
  46. #include "../../../src/juce_core/io/files/juce_NamedPipe.h"
  47. #include "../../../src/juce_core/threads/juce_InterProcessLock.h"
  48. #include "../../../src/juce_core/threads/juce_Thread.h"
  49. //==============================================================================
  50. /*
  51. Note that a lot of methods that you'd expect to find in this file actually
  52. live in juce_posix_SharedCode.h!
  53. */
  54. #include "../../macosx/platform_specific_code/juce_posix_SharedCode.h"
  55. //==============================================================================
  56. static File executableFile;
  57. //==============================================================================
  58. void juce_getFileTimes (const String& fileName,
  59. int64& modificationTime,
  60. int64& accessTime,
  61. int64& creationTime) throw()
  62. {
  63. modificationTime = 0;
  64. accessTime = 0;
  65. creationTime = 0;
  66. struct stat info;
  67. const int res = stat (fileName.toUTF8(), &info);
  68. if (res == 0)
  69. {
  70. modificationTime = (int64) info.st_mtime * 1000;
  71. accessTime = (int64) info.st_atime * 1000;
  72. creationTime = (int64) info.st_ctime * 1000;
  73. }
  74. }
  75. bool juce_setFileTimes (const String& fileName,
  76. int64 modificationTime,
  77. int64 accessTime,
  78. int64 creationTime) throw()
  79. {
  80. struct utimbuf times;
  81. times.actime = (time_t) (accessTime / 1000);
  82. times.modtime = (time_t) (modificationTime / 1000);
  83. return utime (fileName.toUTF8(), &times) == 0;
  84. }
  85. bool juce_setFileReadOnly (const String& fileName, bool isReadOnly) throw()
  86. {
  87. struct stat info;
  88. const int res = stat (fileName.toUTF8(), &info);
  89. if (res != 0)
  90. return false;
  91. info.st_mode &= 0777; // Just permissions
  92. if( isReadOnly )
  93. info.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
  94. else
  95. // Give everybody write permission?
  96. info.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
  97. return chmod (fileName.toUTF8(), info.st_mode) == 0;
  98. }
  99. bool juce_copyFile (const String& s, const String& d) throw()
  100. {
  101. const File source (s), dest (d);
  102. FileInputStream* in = source.createInputStream();
  103. bool ok = false;
  104. if (in != 0)
  105. {
  106. if (dest.deleteFile())
  107. {
  108. FileOutputStream* const out = dest.createOutputStream();
  109. if (out != 0)
  110. {
  111. const int bytesCopied = out->writeFromInputStream (*in, -1);
  112. delete out;
  113. ok = (bytesCopied == source.getSize());
  114. if (! ok)
  115. dest.deleteFile();
  116. }
  117. }
  118. delete in;
  119. }
  120. return ok;
  121. }
  122. const StringArray juce_getFileSystemRoots() throw()
  123. {
  124. StringArray s;
  125. s.add (T("/"));
  126. return s;
  127. }
  128. //==============================================================================
  129. bool File::isOnCDRomDrive() const throw()
  130. {
  131. struct statfs buf;
  132. if (statfs (getFullPathName().toUTF8(), &buf) == 0)
  133. return (buf.f_type == U_ISOFS_SUPER_MAGIC);
  134. // Assume not if this fails for some reason
  135. return false;
  136. }
  137. bool File::isOnHardDisk() const throw()
  138. {
  139. struct statfs buf;
  140. if (statfs (getFullPathName().toUTF8(), &buf) == 0)
  141. {
  142. switch (buf.f_type)
  143. {
  144. case U_ISOFS_SUPER_MAGIC: // CD-ROM
  145. case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
  146. case U_NFS_SUPER_MAGIC: // Network NFS
  147. case U_SMB_SUPER_MAGIC: // Network Samba
  148. return false;
  149. default:
  150. // Assume anything else is a hard-disk (but note it could
  151. // be a RAM disk. There isn't a good way of determining
  152. // this for sure)
  153. return true;
  154. }
  155. }
  156. // Assume so if this fails for some reason
  157. return true;
  158. }
  159. bool File::isOnRemovableDrive() const throw()
  160. {
  161. jassertfalse // xxx not implemented for linux!
  162. return false;
  163. }
  164. bool File::isHidden() const throw()
  165. {
  166. return getFileName().startsWithChar (T('.'));
  167. }
  168. //==============================================================================
  169. const File File::getSpecialLocation (const SpecialLocationType type)
  170. {
  171. switch (type)
  172. {
  173. case userHomeDirectory:
  174. {
  175. const char* homeDir = getenv ("HOME");
  176. if (homeDir == 0)
  177. {
  178. struct passwd* const pw = getpwuid (getuid());
  179. if (pw != 0)
  180. homeDir = pw->pw_dir;
  181. }
  182. return File (String::fromUTF8 ((const uint8*) homeDir));
  183. }
  184. case userDocumentsDirectory:
  185. case userMusicDirectory:
  186. case userMoviesDirectory:
  187. case userApplicationDataDirectory:
  188. return File ("~");
  189. case userDesktopDirectory:
  190. return File ("~/Desktop");
  191. case commonApplicationDataDirectory:
  192. return File ("/var");
  193. case globalApplicationsDirectory:
  194. return File ("/usr");
  195. case tempDirectory:
  196. {
  197. File tmp ("/var/tmp");
  198. if (! tmp.isDirectory())
  199. {
  200. tmp = T("/tmp");
  201. if (! tmp.isDirectory())
  202. tmp = File::getCurrentWorkingDirectory();
  203. }
  204. return tmp;
  205. }
  206. case currentExecutableFile:
  207. case currentApplicationFile:
  208. // if this fails, it's probably because juce_setCurrentExecutableFileName()
  209. // was never called to set the filename - this should be done by the juce
  210. // main() function, so maybe you've hacked it to use your own custom main()?
  211. jassert (executableFile.exists());
  212. return executableFile;
  213. default:
  214. jassertfalse // unknown type?
  215. break;
  216. }
  217. return File::nonexistent;
  218. }
  219. //==============================================================================
  220. void juce_setCurrentExecutableFileName (const String& filename) throw()
  221. {
  222. executableFile = File::getCurrentWorkingDirectory().getChildFile (filename);
  223. }
  224. //==============================================================================
  225. const File File::getCurrentWorkingDirectory() throw()
  226. {
  227. char buf [2048];
  228. return File (String::fromUTF8 ((const uint8*) getcwd (buf, sizeof (buf))));
  229. }
  230. bool File::setAsCurrentWorkingDirectory() const throw()
  231. {
  232. return chdir (getFullPathName().toUTF8()) == 0;
  233. }
  234. //==============================================================================
  235. const String File::getVersion() const throw()
  236. {
  237. return String::empty; // xxx not yet implemented
  238. }
  239. //==============================================================================
  240. const File File::getLinkedTarget() const throw()
  241. {
  242. char buffer [4096];
  243. size_t numChars = readlink ((const char*) getFullPathName().toUTF8(),
  244. buffer, sizeof (buffer));
  245. if (numChars > 0 && numChars <= sizeof (buffer))
  246. return File (String::fromUTF8 ((const uint8*) buffer, (int) numChars));
  247. return *this;
  248. }
  249. //==============================================================================
  250. bool File::moveToTrash() const throw()
  251. {
  252. if (! exists())
  253. return true;
  254. File trashCan (T("~/.Trash"));
  255. if (! trashCan.isDirectory())
  256. trashCan = T("~/.local/share/Trash/files");
  257. if (! trashCan.isDirectory())
  258. return false;
  259. return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
  260. getFileExtension()));
  261. }
  262. //==============================================================================
  263. struct FindFileStruct
  264. {
  265. String parentDir, wildCard;
  266. DIR* dir;
  267. bool getNextMatch (String& result, bool* const isDir, bool* const isHidden, int64* const fileSize,
  268. Time* const modTime, Time* const creationTime, bool* const isReadOnly) throw()
  269. {
  270. const char* const wildcardUTF8 = wildCard.toUTF8();
  271. for (;;)
  272. {
  273. struct dirent* const de = readdir (dir);
  274. if (de == 0)
  275. break;
  276. if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
  277. {
  278. result = String::fromUTF8 ((const uint8*) de->d_name);
  279. const String path (parentDir + result);
  280. if (isDir != 0 || fileSize != 0)
  281. {
  282. struct stat info;
  283. const bool statOk = (stat (path.toUTF8(), &info) == 0);
  284. if (isDir != 0)
  285. *isDir = path.isEmpty() || (statOk && ((info.st_mode & S_IFDIR) != 0));
  286. if (isHidden != 0)
  287. *isHidden = (de->d_name[0] == '.');
  288. if (fileSize != 0)
  289. *fileSize = statOk ? info.st_size : 0;
  290. }
  291. if (modTime != 0 || creationTime != 0)
  292. {
  293. int64 m, a, c;
  294. juce_getFileTimes (path, m, a, c);
  295. if (modTime != 0)
  296. *modTime = m;
  297. if (creationTime != 0)
  298. *creationTime = c;
  299. }
  300. if (isReadOnly != 0)
  301. *isReadOnly = ! juce_canWriteToFile (path);
  302. return true;
  303. }
  304. }
  305. return false;
  306. }
  307. };
  308. // returns 0 on failure
  309. void* juce_findFileStart (const String& directory, const String& wildCard, String& firstResultFile,
  310. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime,
  311. Time* creationTime, bool* isReadOnly) throw()
  312. {
  313. DIR* d = opendir (directory.toUTF8());
  314. if (d != 0)
  315. {
  316. FindFileStruct* ff = new FindFileStruct();
  317. ff->parentDir = directory;
  318. if (!ff->parentDir.endsWithChar (File::separator))
  319. ff->parentDir += File::separator;
  320. ff->wildCard = wildCard;
  321. if (wildCard == T("*.*"))
  322. ff->wildCard = T("*");
  323. ff->dir = d;
  324. if (ff->getNextMatch (firstResultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly))
  325. {
  326. return ff;
  327. }
  328. else
  329. {
  330. firstResultFile = String::empty;
  331. isDir = false;
  332. isHidden = false;
  333. closedir (d);
  334. delete ff;
  335. }
  336. }
  337. return 0;
  338. }
  339. bool juce_findFileNext (void* handle, String& resultFile,
  340. bool* isDir, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly) throw()
  341. {
  342. FindFileStruct* const ff = (FindFileStruct*) handle;
  343. if (ff != 0)
  344. return ff->getNextMatch (resultFile, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
  345. return false;
  346. }
  347. void juce_findFileClose (void* handle) throw()
  348. {
  349. FindFileStruct* const ff = (FindFileStruct*) handle;
  350. if (ff != 0)
  351. {
  352. closedir (ff->dir);
  353. delete ff;
  354. }
  355. }
  356. bool juce_launchFile (const String& fileName,
  357. const String& parameters) throw()
  358. {
  359. String cmdString (fileName);
  360. cmdString << " " << parameters;
  361. if (URL::isProbablyAWebsiteURL (fileName)
  362. || URL::isProbablyAnEmailAddress (fileName))
  363. {
  364. // create a command that tries to launch a bunch of likely browsers
  365. const char* const browserNames[] = { "/etc/alternatives/x-www-browser", "firefox", "mozilla", "konqueror", "opera" };
  366. StringArray cmdLines;
  367. for (int i = 0; i < numElementsInArray (browserNames); ++i)
  368. cmdLines.add (String (browserNames[i]) + T(" ") + cmdString.trim().quoted());
  369. cmdString = cmdLines.joinIntoString (T(" || "));
  370. }
  371. if (cmdString.startsWithIgnoreCase (T("file:")))
  372. cmdString = cmdString.substring (5);
  373. const char* const argv[4] = { "/bin/sh", "-c", (const char*) cmdString.toUTF8(), 0 };
  374. const int cpid = fork();
  375. if (cpid == 0)
  376. {
  377. setsid();
  378. // Child process
  379. execve (argv[0], (char**) argv, environ);
  380. exit (0);
  381. }
  382. return cpid >= 0;
  383. }
  384. END_JUCE_NAMESPACE