File.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  1. #include "il2cpp-config.h"
  2. #if IL2CPP_TARGET_POSIX
  3. #include "FileHandle.h"
  4. #if IL2CPP_USE_POSIX_FILE_PLATFORM_CONFIG
  5. #include "FilePlatformConfig.h"
  6. #endif
  7. #include "os/ConsoleExtension.h"
  8. #include "os/ErrorCodes.h"
  9. #include "os/File.h"
  10. #include "os/Mutex.h"
  11. #include "os/Posix/Error.h"
  12. #include "utils/Expected.h"
  13. #include "utils/Il2CppError.h"
  14. #include "utils/PathUtils.h"
  15. #if IL2CPP_SUPPORT_THREADS
  16. #include "Baselib.h"
  17. #include "Cpp/ReentrantLock.h"
  18. #endif
  19. #include <fcntl.h>
  20. #include <stdint.h>
  21. #include <unistd.h>
  22. #include <utime.h>
  23. #if IL2CPP_TARGET_QNX
  24. #include <errno.h>
  25. #else
  26. #include <sys/errno.h>
  27. #endif
  28. #include <sys/stat.h>
  29. #include <sys/types.h>
  30. #include <string>
  31. #define INVALID_FILE_HANDLE (FileHandle*)-1
  32. #define INVALID_FILE_ATTRIBUTES (UnityPalFileAttributes)((uint32_t)-1)
  33. #define TIME_ZERO 116444736000000000ULL
  34. namespace il2cpp
  35. {
  36. namespace os
  37. {
  38. // Head and tail of linked list.
  39. static FileHandle* s_fileHandleHead = NULL;
  40. static FileHandle* s_fileHandleTail = NULL;
  41. #if IL2CPP_SUPPORT_THREADS
  42. static baselib::ReentrantLock s_fileHandleMutex;
  43. #endif
  44. static void AddFileHandle(FileHandle *fileHandle)
  45. {
  46. #if IL2CPP_SUPPORT_THREADS
  47. FastAutoLock autoLock(&s_fileHandleMutex);
  48. #endif
  49. if (s_fileHandleHead == NULL)
  50. {
  51. IL2CPP_ASSERT(s_fileHandleTail == NULL);
  52. s_fileHandleHead = fileHandle;
  53. s_fileHandleTail = fileHandle;
  54. }
  55. else
  56. {
  57. IL2CPP_ASSERT(s_fileHandleTail != NULL);
  58. IL2CPP_ASSERT(s_fileHandleTail->next == NULL);
  59. s_fileHandleTail->next = fileHandle;
  60. fileHandle->prev = s_fileHandleTail;
  61. s_fileHandleTail = fileHandle;
  62. }
  63. }
  64. static void RemoveFileHandle(il2cpp::os::FileHandle *fileHandle)
  65. {
  66. #if IL2CPP_SUPPORT_THREADS
  67. FastAutoLock autoLock(&s_fileHandleMutex);
  68. #endif
  69. if (s_fileHandleHead == fileHandle)
  70. s_fileHandleHead = fileHandle->next;
  71. if (s_fileHandleTail == fileHandle)
  72. s_fileHandleTail = fileHandle->prev;
  73. if (fileHandle->prev)
  74. fileHandle->prev->next = fileHandle->next;
  75. if (fileHandle->next)
  76. fileHandle->next->prev = fileHandle->prev;
  77. }
  78. static const FileHandle* FindFileHandle(const struct stat& statBuf)
  79. {
  80. #if IL2CPP_SUPPORT_THREADS
  81. FastAutoLock autoLock(&s_fileHandleMutex);
  82. #endif
  83. const dev_t device = statBuf.st_dev;
  84. const ino_t inode = statBuf.st_ino;
  85. for (FileHandle *handle = s_fileHandleHead; handle != NULL; handle = handle->next)
  86. {
  87. if (handle->device == device && handle->inode == inode)
  88. return handle;
  89. }
  90. return NULL;
  91. }
  92. bool File::IsHandleOpenFileHandle(intptr_t lookup)
  93. {
  94. #if IL2CPP_SUPPORT_THREADS
  95. FastAutoLock autoLock(&s_fileHandleMutex);
  96. #endif
  97. for (FileHandle *handle = s_fileHandleHead; handle != NULL; handle = handle->next)
  98. {
  99. if (reinterpret_cast<intptr_t>(handle) == lookup)
  100. return true;
  101. }
  102. return false;
  103. }
  104. // NOTE:
  105. // Checking for file sharing violations only works for the current process.
  106. //
  107. // Mono implements this feature across processes by storing the file handles as
  108. // a look up table in a shared file.
  109. static bool ShareAllowOpen(const struct stat& statBuf, int shareMode, int accessMode)
  110. {
  111. const FileHandle *fileHandle = FindFileHandle(statBuf);
  112. if (fileHandle == NULL) // File is not open
  113. return true;
  114. if (fileHandle->shareMode == kFileShareNone || shareMode == kFileShareNone)
  115. return false;
  116. if (((fileHandle->shareMode == kFileShareRead) && (accessMode != kFileAccessRead)) ||
  117. ((fileHandle->shareMode == kFileShareWrite) && (accessMode != kFileAccessWrite)))
  118. {
  119. return false;
  120. }
  121. return true;
  122. }
  123. static UnityPalFileAttributes StatToFileAttribute(const std::string& path, struct stat& pathStat, struct stat* linkStat)
  124. {
  125. uint32_t fileAttributes = 0;
  126. if (S_ISSOCK(pathStat.st_mode))
  127. pathStat.st_mode &= ~S_IFSOCK; // don't consider socket protection
  128. #if defined(__APPLE__) && defined(__MACH__)
  129. if ((pathStat.st_flags & UF_IMMUTABLE) || (pathStat.st_flags & SF_IMMUTABLE))
  130. fileAttributes |= kFileAttributeReadOnly;
  131. #endif
  132. const std::string filename(il2cpp::utils::PathUtils::Basename(path));
  133. if (S_ISDIR(pathStat.st_mode))
  134. {
  135. fileAttributes = kFileAttributeDirectory;
  136. if (!(pathStat.st_mode & S_IWUSR) && !(pathStat.st_mode & S_IWGRP) && !(pathStat.st_mode & S_IWOTH))
  137. fileAttributes |= kFileAttributeReadOnly;
  138. if (filename[0] == '.')
  139. fileAttributes |= kFileAttributeHidden;
  140. }
  141. else
  142. {
  143. if (!(pathStat.st_mode & S_IWUSR) && !(pathStat.st_mode & S_IWGRP) && !(pathStat.st_mode & S_IWOTH))
  144. {
  145. fileAttributes = kFileAttributeReadOnly;
  146. if (filename[0] == '.')
  147. fileAttributes |= kFileAttributeHidden;
  148. }
  149. else if (filename[0] == '.')
  150. fileAttributes = kFileAttributeHidden;
  151. else
  152. fileAttributes = kFileAttributeNormal;
  153. }
  154. if (linkStat != NULL && S_ISLNK(linkStat->st_mode))
  155. fileAttributes |= kFileAttributeReparse_point;
  156. return (UnityPalFileAttributes)fileAttributes;
  157. }
  158. static int GetStatAndLinkStat(const std::string& path, struct stat& pathStat, struct stat& linkStat)
  159. {
  160. const int statResult = stat(path.c_str(), &pathStat);
  161. if (statResult == -1 && errno == ENOENT && lstat(path.c_str(), &pathStat) != 0) // Might be a dangling symlink...
  162. return PathErrnoToErrorCode(path, errno);
  163. if (lstat(path.c_str(), &linkStat) != 0)
  164. return PathErrnoToErrorCode(path, errno);
  165. return kErrorCodeSuccess;
  166. }
  167. static uint64_t TimeToTicks(time_t timeval)
  168. {
  169. return ((uint64_t)timeval * 10000000) + TIME_ZERO;
  170. }
  171. static time_t TicksToTime(uint64_t ticks)
  172. {
  173. return (ticks - TIME_ZERO) / 10000000;
  174. }
  175. static bool InternalCopyFile(int srcFd, int destFd, const struct stat& srcStat, int *error)
  176. {
  177. const blksize_t preferedBlockSize = srcStat.st_blksize;
  178. const blksize_t bufferSize = preferedBlockSize < 8192 ? 8192 : (preferedBlockSize > 65536 ? 65536 : preferedBlockSize);
  179. char *buffer = new char[bufferSize];
  180. ssize_t readBytes;
  181. while ((readBytes = read(srcFd, buffer, bufferSize)) > 0)
  182. {
  183. char* writeBuffer = buffer;
  184. ssize_t writeBytes = readBytes;
  185. while (writeBytes > 0)
  186. {
  187. const ssize_t writtenBytes = write(destFd, writeBuffer, writeBytes);
  188. if (writtenBytes < 0)
  189. {
  190. if (errno == EINTR)
  191. continue;
  192. delete[] buffer;
  193. *error = FileErrnoToErrorCode(errno);
  194. return false;
  195. }
  196. writeBytes -= writtenBytes;
  197. writeBuffer += writtenBytes;
  198. }
  199. }
  200. delete[] buffer;
  201. if (readBytes < 0)
  202. {
  203. *error = FileErrnoToErrorCode(errno);
  204. return false;
  205. }
  206. IL2CPP_ASSERT(readBytes == 0);
  207. return true;
  208. }
  209. utils::Expected<bool> File::Isatty(FileHandle* fileHandle)
  210. {
  211. return isatty(fileHandle->fd) == 1;
  212. }
  213. #if !IL2CPP_PLATFORM_OVERRIDES_STD_FILE_HANDLES
  214. FileHandle* File::GetStdError()
  215. {
  216. static FileHandle* s_handle = NULL;
  217. if (s_handle)
  218. return s_handle;
  219. s_handle = new FileHandle();
  220. s_handle->fd = 2;
  221. s_handle->type = kFileTypeChar;
  222. s_handle->options = 0;
  223. s_handle->accessMode = kFileAccessReadWrite;
  224. s_handle->shareMode = -1; // Only used for files
  225. return s_handle;
  226. }
  227. FileHandle* File::GetStdInput()
  228. {
  229. static FileHandle* s_handle = NULL;
  230. if (s_handle)
  231. return s_handle;
  232. s_handle = new FileHandle();
  233. s_handle->fd = 0;
  234. s_handle->type = kFileTypeChar;
  235. s_handle->options = 0;
  236. s_handle->accessMode = kFileAccessRead;
  237. s_handle->shareMode = -1; // Only used for files
  238. return s_handle;
  239. }
  240. FileHandle* File::GetStdOutput()
  241. {
  242. static FileHandle* s_handle = NULL;
  243. if (s_handle)
  244. return s_handle;
  245. s_handle = new FileHandle();
  246. s_handle->fd = 1;
  247. s_handle->type = kFileTypeChar;
  248. s_handle->options = 0;
  249. s_handle->accessMode = kFileAccessReadWrite;
  250. s_handle->shareMode = -1; // Only used for files
  251. return s_handle;
  252. }
  253. #endif
  254. utils::Expected<bool> File::CreatePipe(FileHandle** read_handle, FileHandle** write_handle)
  255. {
  256. int error;
  257. return File::CreatePipe(read_handle, write_handle, &error);
  258. }
  259. utils::Expected<bool> File::CreatePipe(FileHandle** read_handle, FileHandle** write_handle, int* error)
  260. {
  261. int fds[2];
  262. const int ret = pipe(fds);
  263. if (ret == -1)
  264. {
  265. *error = FileErrnoToErrorCode(errno);
  266. return false;
  267. }
  268. FileHandle *input = new FileHandle();
  269. input->fd = fds[0];
  270. input->type = kFileTypePipe;
  271. input->options = 0;
  272. input->accessMode = kFileAccessRead;
  273. input->shareMode = -1; // Only used for files
  274. FileHandle *output = new FileHandle();
  275. output->fd = fds[1];
  276. output->type = kFileTypePipe;
  277. output->options = 0;
  278. output->accessMode = kFileAccessReadWrite;
  279. output->shareMode = -1; // Only used for files
  280. *read_handle = input;
  281. *write_handle = output;
  282. return true;
  283. }
  284. UnityPalFileAttributes File::GetFileAttributes(const std::string& path, int *error)
  285. {
  286. struct stat pathStat, linkStat;
  287. *error = GetStatAndLinkStat(path, pathStat, linkStat);
  288. if (*error != kErrorCodeSuccess)
  289. return INVALID_FILE_ATTRIBUTES;
  290. return StatToFileAttribute(path, pathStat, &linkStat);
  291. }
  292. bool File::SetFileAttributes(const std::string& path, UnityPalFileAttributes attributes, int* error)
  293. {
  294. struct stat pathStat;
  295. int ret = stat(path.c_str(), &pathStat);
  296. if (ret != 0)
  297. {
  298. *error = PathErrnoToErrorCode(path, errno);
  299. return false;
  300. }
  301. if (attributes & kFileAttributeReadOnly)
  302. ret = chmod(path.c_str(), pathStat.st_mode & ~(S_IWUSR | S_IWOTH | S_IWGRP));
  303. else
  304. ret = chmod(path.c_str(), pathStat.st_mode | S_IWUSR);
  305. if (ret != 0)
  306. {
  307. *error = PathErrnoToErrorCode(path, errno);
  308. return false;
  309. }
  310. // Mono ignores all other attributes
  311. if (attributes & kFileAttributeInternalMonoExecutable)
  312. {
  313. mode_t exec_mask = 0;
  314. if ((pathStat.st_mode & S_IRUSR) != 0)
  315. exec_mask |= S_IXUSR;
  316. if ((pathStat.st_mode & S_IRGRP) != 0)
  317. exec_mask |= S_IXGRP;
  318. if ((pathStat.st_mode & S_IROTH) != 0)
  319. exec_mask |= S_IXOTH;
  320. ret = chmod(path.c_str(), pathStat.st_mode | exec_mask);
  321. if (ret != 0)
  322. {
  323. *error = PathErrnoToErrorCode(path, errno);
  324. return false;
  325. }
  326. }
  327. return true;
  328. }
  329. bool File::GetFileStat(const std::string& path, il2cpp::os::FileStat * stat, int* error)
  330. {
  331. struct stat pathStat, linkStat;
  332. *error = GetStatAndLinkStat(path, pathStat, linkStat);
  333. if (*error != kErrorCodeSuccess)
  334. return false;
  335. const std::string filename(il2cpp::utils::PathUtils::Basename(path));
  336. const time_t creationTime = pathStat.st_mtime < pathStat.st_ctime ? pathStat.st_mtime : pathStat.st_ctime;
  337. stat->name = filename;
  338. stat->attributes = StatToFileAttribute(path, pathStat, &linkStat);
  339. stat->length = (stat->attributes & kFileAttributeDirectory) > 0 ? 0 : pathStat.st_size;
  340. stat->creation_time = TimeToTicks(creationTime);
  341. stat->last_access_time = TimeToTicks(pathStat.st_atime);
  342. stat->last_write_time = TimeToTicks(pathStat.st_mtime);
  343. return true;
  344. }
  345. FileType File::GetFileType(FileHandle* handle)
  346. {
  347. return ((FileHandle*)handle)->type;
  348. }
  349. bool File::DeleteFile(const std::string& path, int *error)
  350. {
  351. const UnityPalFileAttributes attributes = GetFileAttributes(path, error);
  352. if (*error != kErrorCodeSuccess)
  353. {
  354. return false;
  355. }
  356. if (attributes & kFileAttributeReadOnly)
  357. {
  358. *error = kErrorCodeAccessDenied;
  359. return false;
  360. }
  361. const int ret = unlink(path.c_str());
  362. if (ret == -1)
  363. {
  364. *error = PathErrnoToErrorCode(path, errno);
  365. return false;
  366. }
  367. *error = kErrorCodeSuccess;
  368. return true;
  369. }
  370. bool File::CopyFile(const std::string& src, const std::string& dest, bool overwrite, int* error)
  371. {
  372. const int srcFd = open(src.c_str(), O_RDONLY, 0);
  373. if (srcFd < 0)
  374. {
  375. *error = PathErrnoToErrorCode(src, errno);
  376. return false;
  377. }
  378. struct stat srcStat;
  379. if (fstat(srcFd, &srcStat) < 0)
  380. {
  381. *error = FileErrnoToErrorCode(errno);
  382. close(srcFd);
  383. return false;
  384. }
  385. int destFd;
  386. if (!overwrite)
  387. {
  388. destFd = open(dest.c_str(), O_WRONLY | O_CREAT | O_EXCL, srcStat.st_mode);
  389. }
  390. else
  391. {
  392. destFd = open(dest.c_str(), O_WRONLY | O_TRUNC, srcStat.st_mode);
  393. if (destFd < 0)
  394. destFd = open(dest.c_str(), O_WRONLY | O_CREAT | O_TRUNC, srcStat.st_mode);
  395. else
  396. *error = kErrorCodeAlreadyExists; // Apparently this error is set if we overwrite the dest file
  397. }
  398. if (destFd < 0)
  399. {
  400. *error = FileErrnoToErrorCode(errno);
  401. close(srcFd);
  402. return false;
  403. }
  404. const bool ret = InternalCopyFile(srcFd, destFd, srcStat, error);
  405. close(srcFd);
  406. close(destFd);
  407. return ret;
  408. }
  409. bool File::MoveFile(const std::string& src, const std::string& dest, int* error)
  410. {
  411. struct stat srcStat, destStat;
  412. if (stat(src.c_str(), &srcStat) < 0)
  413. {
  414. *error = PathErrnoToErrorCode(src.c_str(), errno);
  415. return false;
  416. }
  417. // In C# land we check for the existence of src, but not for dest.
  418. // We check it here and return the failure if dest exists and is not
  419. // the same file as src.
  420. if (stat(dest.c_str(), &destStat) == 0) // dest exists
  421. {
  422. if (destStat.st_dev != srcStat.st_dev || destStat.st_ino != srcStat.st_ino)
  423. {
  424. *error = kErrorCodeAlreadyExists;
  425. return false;
  426. }
  427. }
  428. if (!ShareAllowOpen(srcStat, kFileShareNone, kFileAccessWrite))
  429. {
  430. *error = kErrorCodeSuccess;
  431. return false;
  432. }
  433. const int ret = rename(src.c_str(), dest.c_str());
  434. if (ret == -1)
  435. {
  436. if (errno == EEXIST)
  437. {
  438. *error = kErrorCodeAlreadyExists;
  439. return false;
  440. }
  441. else if (errno == EXDEV)
  442. {
  443. if (S_ISDIR(srcStat.st_mode))
  444. {
  445. *error = kErrorCodeNotSameDevice;
  446. return false;
  447. }
  448. if (!CopyFile(src, dest, true, error))
  449. {
  450. // CopyFile sets the error
  451. return false;
  452. }
  453. return DeleteFile(src, error); // DeleteFile sets the error
  454. }
  455. else
  456. {
  457. *error = PathErrnoToErrorCode(src.c_str(), errno);
  458. return false;
  459. }
  460. }
  461. *error = kErrorCodeSuccess;
  462. return true;
  463. }
  464. bool File::ReplaceFile(const std::string& sourceFileName, const std::string& destinationFileName, const std::string& destinationBackupFileName, bool ignoreMetadataErrors, int* error)
  465. {
  466. const bool backupFile = !destinationBackupFileName.empty();
  467. // Open the backup file for read so we can restore the file if an error occurs.
  468. const int backupFd = backupFile ? open(destinationBackupFileName.c_str(), O_RDONLY, 0) : -1;
  469. // dest -> backup
  470. if (backupFile)
  471. {
  472. const int retDest = rename(destinationFileName.c_str(), destinationBackupFileName.c_str());
  473. if (retDest == -1)
  474. {
  475. if (backupFd != -1)
  476. close(backupFd);
  477. *error = PathErrnoToErrorCode(destinationFileName.c_str(), errno);
  478. return false;
  479. }
  480. }
  481. // source -> dest
  482. const int restSource = rename(sourceFileName.c_str(), destinationFileName.c_str());
  483. if (restSource == -1)
  484. {
  485. // backup -> dest
  486. if (backupFile)
  487. rename(destinationBackupFileName.c_str(), destinationFileName.c_str());
  488. // Copy backup data -> dest
  489. struct stat backupStat;
  490. if (backupFd != -1 && fstat(backupFd, &backupStat) == 0)
  491. {
  492. const int destFd = open(destinationBackupFileName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, backupStat.st_mode);
  493. if (destFd != -1)
  494. {
  495. int unusedCopyFileError;
  496. InternalCopyFile(backupFd, destFd, backupStat, &unusedCopyFileError);
  497. close(destFd);
  498. }
  499. }
  500. if (backupFd != -1)
  501. close(backupFd);
  502. *error = PathErrnoToErrorCode(sourceFileName.c_str(), errno);
  503. return false;
  504. }
  505. if (backupFd != -1)
  506. close(backupFd);
  507. *error = kErrorCodeSuccess;
  508. return true;
  509. }
  510. static int ConvertFlags(int fileaccess, int createmode)
  511. {
  512. int flags;
  513. switch (fileaccess)
  514. {
  515. case kFileAccessRead:
  516. flags = O_RDONLY;
  517. break;
  518. case kFileAccessWrite:
  519. flags = O_WRONLY;
  520. break;
  521. case kFileAccessReadWrite:
  522. flags = O_RDWR;
  523. break;
  524. default:
  525. flags = 0;
  526. break;
  527. }
  528. switch (createmode)
  529. {
  530. case kFileModeCreateNew:
  531. flags |= O_CREAT | O_EXCL;
  532. break;
  533. case kFileModeCreate:
  534. flags |= O_CREAT | O_TRUNC;
  535. break;
  536. case kFileModeOpen:
  537. break;
  538. case kFileModeOpenOrCreate:
  539. case kFileModeAppend:
  540. flags |= O_CREAT;
  541. break;
  542. case kFileModeTruncate:
  543. flags |= O_TRUNC;
  544. break;
  545. default:
  546. flags = 0;
  547. break;
  548. }
  549. return flags;
  550. }
  551. #ifndef S_ISFIFO
  552. #define S_ISFIFO(m) ((m & S_IFIFO) != 0)
  553. #endif
  554. FileHandle* File::Open(const std::string& path, int mode, int accessMode, int shareMode, int options, int *error)
  555. {
  556. const int flags = ConvertFlags(accessMode, mode);
  557. /* we don't use sharemode, because that relates to sharing of
  558. * the file when the file is open and is already handled by
  559. * other code, perms instead are the on-disk permissions and
  560. * this is a sane default.
  561. */
  562. const mode_t perms = options & kFileOptionsTemporary ? 0600 : 0666;
  563. int fd = open(path.c_str(), flags, perms);
  564. /* If we were trying to open a directory with write permissions
  565. * (e.g. O_WRONLY or O_RDWR), this call will fail with
  566. * EISDIR. However, this is a bit bogus because calls to
  567. * manipulate the directory (e.g. SetFileTime) will still work on
  568. * the directory because they use other API calls
  569. * (e.g. utime()). Hence, if we failed with the EISDIR error, try
  570. * to open the directory again without write permission.
  571. */
  572. // Try again but don't try to make it writable
  573. if (fd == -1)
  574. {
  575. if (errno == EISDIR)
  576. {
  577. fd = open(path.c_str(), flags & ~(O_RDWR | O_WRONLY), perms);
  578. if (fd == -1)
  579. {
  580. *error = PathErrnoToErrorCode(path, errno);
  581. return INVALID_FILE_HANDLE;
  582. }
  583. }
  584. else
  585. {
  586. *error = PathErrnoToErrorCode(path, errno);
  587. return INVALID_FILE_HANDLE;
  588. }
  589. }
  590. struct stat statbuf;
  591. const int ret = fstat(fd, &statbuf);
  592. if (ret == -1)
  593. {
  594. *error = FileErrnoToErrorCode(errno);
  595. close(fd);
  596. return INVALID_FILE_HANDLE;
  597. }
  598. if (!ShareAllowOpen(statbuf, shareMode, accessMode))
  599. {
  600. *error = kErrorCodeSharingViolation;
  601. close(fd);
  602. return INVALID_FILE_HANDLE;
  603. }
  604. FileHandle* fileHandle = new FileHandle();
  605. fileHandle->fd = fd;
  606. fileHandle->path = path;
  607. fileHandle->options = options;
  608. fileHandle->accessMode = accessMode;
  609. fileHandle->shareMode = shareMode;
  610. fileHandle->device = statbuf.st_dev;
  611. fileHandle->inode = statbuf.st_ino;
  612. // Add to linked list
  613. AddFileHandle(fileHandle);
  614. #ifdef HAVE_POSIX_FADVISE
  615. if (options & kFileOptionsSequentialScan)
  616. posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
  617. if (options & kFileOptionsRandomAccess)
  618. posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);
  619. #endif
  620. if (S_ISFIFO(statbuf.st_mode))
  621. fileHandle->type = kFileTypePipe;
  622. else if (S_ISCHR(statbuf.st_mode))
  623. fileHandle->type = kFileTypeChar;
  624. else
  625. fileHandle->type = kFileTypeDisk;
  626. *error = kErrorCodeSuccess;
  627. return fileHandle;
  628. }
  629. bool File::Close(FileHandle* handle, int *error)
  630. {
  631. if (handle->type == kFileTypeDisk && handle->options & kFileOptionsDeleteOnClose)
  632. unlink(handle->path.c_str());
  633. close(handle->fd);
  634. // Remove from linked list
  635. RemoveFileHandle(handle);
  636. delete handle;
  637. *error = kErrorCodeSuccess;
  638. return true;
  639. }
  640. bool File::SetFileTime(FileHandle* handle, int64_t creation_time, int64_t last_access_time, int64_t last_write_time, int* error)
  641. {
  642. if ((handle->accessMode & kFileAccessWrite) == 0)
  643. {
  644. *error = kErrorCodeAccessDenied;
  645. return false;
  646. }
  647. struct stat statbuf;
  648. const int ret = fstat(handle->fd, &statbuf);
  649. if (ret == -1)
  650. {
  651. *error = kErrorCodeInvalidParameter;
  652. return false;
  653. }
  654. struct utimbuf utbuf;
  655. // Setting creation time is not implemented in Mono and not supported by utime.
  656. if (last_access_time >= 0)
  657. {
  658. if (last_access_time < TIME_ZERO)
  659. {
  660. *error = kErrorCodeInvalidParameter;
  661. return false;
  662. }
  663. utbuf.actime = TicksToTime(last_access_time);
  664. }
  665. else
  666. {
  667. utbuf.actime = statbuf.st_atime;
  668. }
  669. if (last_write_time >= 0)
  670. {
  671. if (last_write_time < TIME_ZERO)
  672. {
  673. *error = kErrorCodeInvalidParameter;
  674. return false;
  675. }
  676. utbuf.modtime = TicksToTime(last_write_time);
  677. }
  678. else
  679. {
  680. utbuf.modtime = statbuf.st_mtime;
  681. }
  682. const int utimeRet = utime(handle->path.c_str(), &utbuf);
  683. if (utimeRet == -1)
  684. {
  685. *error = kErrorCodeInvalidParameter;
  686. return false;
  687. }
  688. *error = kErrorCodeSuccess;
  689. return true;
  690. }
  691. int64_t File::GetLength(FileHandle* handle, int *error)
  692. {
  693. if (handle->type != kFileTypeDisk)
  694. {
  695. *error = kErrorCodeInvalidHandle;
  696. return false;
  697. }
  698. struct stat statbuf;
  699. const int ret = fstat(handle->fd, &statbuf);
  700. if (ret == -1)
  701. {
  702. *error = FileErrnoToErrorCode(errno);
  703. return -1;
  704. }
  705. *error = kErrorCodeSuccess;
  706. return statbuf.st_size;
  707. }
  708. bool File::SetLength(FileHandle* handle, int64_t length, int *error)
  709. {
  710. if (handle->type != kFileTypeDisk)
  711. {
  712. *error = kErrorCodeInvalidHandle;
  713. return false;
  714. }
  715. // Save current position
  716. const off_t currentPosition = lseek(handle->fd, 0, SEEK_CUR);
  717. if (currentPosition == -1)
  718. {
  719. *error = FileErrnoToErrorCode(errno);
  720. return false;
  721. }
  722. const off_t setLength = lseek(handle->fd, length, SEEK_SET);
  723. if (setLength == -1)
  724. {
  725. *error = FileErrnoToErrorCode(errno);
  726. return false;
  727. }
  728. int ret = 0;
  729. do
  730. {
  731. ret = ftruncate(handle->fd, length);
  732. }
  733. while (ret == -1 && errno == EINTR);
  734. if (ret == -1)
  735. {
  736. *error = FileErrnoToErrorCode(errno);
  737. return false;
  738. }
  739. const off_t oldPosition = lseek(handle->fd, currentPosition, SEEK_SET);
  740. if (oldPosition == -1)
  741. {
  742. *error = FileErrnoToErrorCode(errno);
  743. return false;
  744. }
  745. *error = kErrorCodeSuccess;
  746. return true;
  747. }
  748. #if !IL2CPP_USE_GENERIC_FILE
  749. bool File::Truncate(FileHandle* handle, int *error)
  750. {
  751. off_t currentPosition = lseek(handle->fd, (off_t)0, SEEK_CUR);
  752. int32_t ret = 0;
  753. *error = kErrorCodeSuccess;
  754. if (currentPosition == -1)
  755. {
  756. *error = FileErrnoToErrorCode(errno);
  757. return false;
  758. }
  759. do
  760. {
  761. ret = ftruncate(handle->fd, currentPosition);
  762. }
  763. while (ret == -1 && errno == EINTR);
  764. if (ret == -1)
  765. {
  766. *error = FileErrnoToErrorCode(errno);
  767. return false;
  768. }
  769. return true;
  770. }
  771. #endif // IL2CPP_USE_GENERIC_FILE
  772. int64_t File::Seek(FileHandle* handle, int64_t offset, int origin, int *error)
  773. {
  774. if (handle->type != kFileTypeDisk)
  775. {
  776. *error = kErrorCodeInvalidHandle;
  777. return false;
  778. }
  779. int whence;
  780. switch (origin)
  781. {
  782. case kFileSeekOriginBegin:
  783. whence = SEEK_SET;
  784. break;
  785. case kFileSeekOriginCurrent:
  786. whence = SEEK_CUR;
  787. break;
  788. case kFileSeekOriginEnd:
  789. whence = SEEK_END;
  790. break;
  791. default:
  792. {
  793. *error = kErrorCodeInvalidParameter;
  794. return -1;
  795. }
  796. }
  797. const off_t position = lseek(handle->fd, offset, whence);
  798. if (position == -1)
  799. {
  800. *error = FileErrnoToErrorCode(errno);
  801. return -1;
  802. }
  803. *error = kErrorCodeSuccess;
  804. return position;
  805. }
  806. int File::Read(FileHandle* handle, char *dest, int count, int *error)
  807. {
  808. if (handle == NULL || handle == INVALID_FILE_HANDLE)
  809. {
  810. *error = kErrorCodeInvalidHandle;
  811. return 0;
  812. }
  813. if ((handle->accessMode & kFileAccessRead) == 0)
  814. {
  815. *error = kErrorCodeAccessDenied;
  816. return 0;
  817. }
  818. int ret;
  819. do
  820. {
  821. ret = (int)read(handle->fd, dest, count);
  822. }
  823. while (ret == -1 && errno == EINTR);
  824. if (ret == -1)
  825. {
  826. *error = FileErrnoToErrorCode(errno);
  827. return 0;
  828. }
  829. return ret;
  830. }
  831. int32_t File::Write(FileHandle* handle, const char* buffer, int count, int *error)
  832. {
  833. if ((handle->accessMode & kFileAccessWrite) == 0)
  834. {
  835. *error = kErrorCodeAccessDenied;
  836. return -1;
  837. }
  838. int ret;
  839. do
  840. {
  841. ret = (int32_t)write(handle->fd, buffer, count);
  842. }
  843. while (ret == -1 && errno == EINTR);
  844. if (ret == -1)
  845. {
  846. *error = FileErrnoToErrorCode(errno);
  847. return -1;
  848. }
  849. #if IL2CPP_SUPPORTS_CONSOLE_EXTENSION
  850. if (handle == GetStdOutput() || handle == GetStdError())
  851. os::ConsoleExtension::Write(buffer);
  852. #endif
  853. return ret;
  854. }
  855. bool File::Flush(FileHandle* handle, int* error)
  856. {
  857. if (handle->type != kFileTypeDisk)
  858. {
  859. *error = kErrorCodeInvalidHandle;
  860. return false;
  861. }
  862. const int ret = fsync(handle->fd);
  863. if (ret == -1)
  864. {
  865. *error = FileErrnoToErrorCode(errno);
  866. return false;
  867. }
  868. *error = kErrorCodeSuccess;
  869. return true;
  870. }
  871. void File::Lock(FileHandle* handle, int64_t position, int64_t length, int* error)
  872. {
  873. struct flock lock_data;
  874. int ret;
  875. lock_data.l_type = F_WRLCK;
  876. lock_data.l_whence = SEEK_SET;
  877. lock_data.l_start = position;
  878. lock_data.l_len = length;
  879. do
  880. {
  881. ret = fcntl(handle->fd, F_SETLK, &lock_data);
  882. }
  883. while (ret == -1 && errno == EINTR);
  884. if (ret == -1)
  885. {
  886. /*
  887. * if locks are not available (NFS for example),
  888. * ignore the error
  889. */
  890. if (errno == ENOLCK
  891. #ifdef EOPNOTSUPP
  892. || errno == EOPNOTSUPP
  893. #endif
  894. #ifdef ENOTSUP
  895. || errno == ENOTSUP
  896. #endif
  897. )
  898. {
  899. *error = kErrorCodeSuccess;
  900. return;
  901. }
  902. *error = FileErrnoToErrorCode(errno);
  903. return;
  904. }
  905. *error = kErrorCodeSuccess;
  906. }
  907. void File::Unlock(FileHandle* handle, int64_t position, int64_t length, int* error)
  908. {
  909. struct flock lock_data;
  910. int ret;
  911. lock_data.l_type = F_UNLCK;
  912. lock_data.l_whence = SEEK_SET;
  913. lock_data.l_start = position;
  914. lock_data.l_len = length;
  915. do
  916. {
  917. ret = fcntl(handle->fd, F_SETLK, &lock_data);
  918. }
  919. while (ret == -1 && errno == EINTR);
  920. if (ret == -1)
  921. {
  922. /*
  923. * if locks are not available (NFS for example),
  924. * ignore the error
  925. */
  926. if (errno == ENOLCK
  927. #ifdef EOPNOTSUPP
  928. || errno == EOPNOTSUPP
  929. #endif
  930. #ifdef ENOTSUP
  931. || errno == ENOTSUP
  932. #endif
  933. )
  934. {
  935. *error = kErrorCodeSuccess;
  936. return;
  937. }
  938. *error = FileErrnoToErrorCode(errno);
  939. return;
  940. }
  941. *error = kErrorCodeSuccess;
  942. }
  943. utils::Expected<bool> File::DuplicateHandle(FileHandle* source_process_handle, FileHandle* source_handle, FileHandle* target_process_handle,
  944. FileHandle** target_handle, int access, int inhert, int options, int* error)
  945. {
  946. return utils::Il2CppError(utils::NotSupported, "This platform does not support file handle duplication.");
  947. }
  948. utils::Expected<bool> File::IsExecutable(const std::string& path)
  949. {
  950. #if IL2CPP_CAN_CHECK_EXECUTABLE
  951. return access(path.c_str(), X_OK) == 0;
  952. #else
  953. return utils::Il2CppError(utils::NotSupported, "This platform cannot check for executable permissions.");
  954. #endif
  955. }
  956. bool File::Cancel(FileHandle* handle)
  957. {
  958. return false;
  959. }
  960. }
  961. }
  962. #endif