File.cpp 37 KB

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