PageRenderTime 24ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/chromium/base/platform_file_posix.cc

https://gitlab.com/f3822/qtwebengine-chromium
C++ | 465 lines | 371 code | 80 blank | 14 comment | 69 complexity | 808fcf3d87d8665ea5d6f848f3da97e7 MD5 | raw file
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/platform_file.h"
  5. #include <fcntl.h>
  6. #include <errno.h>
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. #include "base/files/file_path.h"
  10. #include "base/logging.h"
  11. #include "base/metrics/sparse_histogram.h"
  12. #include "base/posix/eintr_wrapper.h"
  13. #include "base/strings/utf_string_conversions.h"
  14. #include "base/threading/thread_restrictions.h"
  15. #if defined(OS_ANDROID)
  16. #include "base/os_compat_android.h"
  17. #endif
  18. namespace base {
  19. // Make sure our Whence mappings match the system headers.
  20. COMPILE_ASSERT(PLATFORM_FILE_FROM_BEGIN == SEEK_SET &&
  21. PLATFORM_FILE_FROM_CURRENT == SEEK_CUR &&
  22. PLATFORM_FILE_FROM_END == SEEK_END, whence_matches_system);
  23. namespace {
  24. #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
  25. typedef struct stat stat_wrapper_t;
  26. static int CallFstat(int fd, stat_wrapper_t *sb) {
  27. base::ThreadRestrictions::AssertIOAllowed();
  28. return fstat(fd, sb);
  29. }
  30. #else
  31. typedef struct stat64 stat_wrapper_t;
  32. static int CallFstat(int fd, stat_wrapper_t *sb) {
  33. base::ThreadRestrictions::AssertIOAllowed();
  34. return fstat64(fd, sb);
  35. }
  36. #endif
  37. // NaCl doesn't provide the following system calls, so either simulate them or
  38. // wrap them in order to minimize the number of #ifdef's in this file.
  39. #if !defined(OS_NACL)
  40. static bool IsOpenAppend(PlatformFile file) {
  41. return (fcntl(file, F_GETFL) & O_APPEND) != 0;
  42. }
  43. static int CallFtruncate(PlatformFile file, int64 length) {
  44. return HANDLE_EINTR(ftruncate(file, length));
  45. }
  46. static int CallFsync(PlatformFile file) {
  47. return HANDLE_EINTR(fsync(file));
  48. }
  49. static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
  50. #ifdef __USE_XOPEN2K8
  51. // futimens should be available, but futimes might not be
  52. // http://pubs.opengroup.org/onlinepubs/9699919799/
  53. timespec ts_times[2];
  54. ts_times[0].tv_sec = times[0].tv_sec;
  55. ts_times[0].tv_nsec = times[0].tv_usec * 1000;
  56. ts_times[1].tv_sec = times[1].tv_sec;
  57. ts_times[1].tv_nsec = times[1].tv_usec * 1000;
  58. return futimens(file, ts_times);
  59. #else
  60. return futimes(file, times);
  61. #endif
  62. }
  63. static PlatformFileError CallFctnlFlock(PlatformFile file, bool do_lock) {
  64. struct flock lock;
  65. lock.l_type = F_WRLCK;
  66. lock.l_whence = SEEK_SET;
  67. lock.l_start = 0;
  68. lock.l_len = 0; // Lock entire file.
  69. if (HANDLE_EINTR(fcntl(file, do_lock ? F_SETLK : F_UNLCK, &lock)) == -1)
  70. return ErrnoToPlatformFileError(errno);
  71. return PLATFORM_FILE_OK;
  72. }
  73. #else // defined(OS_NACL)
  74. static bool IsOpenAppend(PlatformFile file) {
  75. // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
  76. // standard and always appends if the file is opened with O_APPEND, just
  77. // return false here.
  78. return false;
  79. }
  80. static int CallFtruncate(PlatformFile file, int64 length) {
  81. NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate.
  82. return 0;
  83. }
  84. static int CallFsync(PlatformFile file) {
  85. NOTIMPLEMENTED(); // NaCl doesn't implement fsync.
  86. return 0;
  87. }
  88. static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
  89. NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
  90. return 0;
  91. }
  92. static PlatformFileError CallFctnlFlock(PlatformFile file, bool do_lock) {
  93. NOTIMPLEMENTED(); // NaCl doesn't implement flock struct.
  94. return PLATFORM_FILE_ERROR_INVALID_OPERATION;
  95. }
  96. #endif // defined(OS_NACL)
  97. } // namespace
  98. // NaCl doesn't implement system calls to open files directly.
  99. #if !defined(OS_NACL)
  100. // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
  101. PlatformFile CreatePlatformFileUnsafe(const FilePath& name,
  102. int flags,
  103. bool* created,
  104. PlatformFileError* error) {
  105. base::ThreadRestrictions::AssertIOAllowed();
  106. int open_flags = 0;
  107. if (flags & PLATFORM_FILE_CREATE)
  108. open_flags = O_CREAT | O_EXCL;
  109. if (created)
  110. *created = false;
  111. if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
  112. DCHECK(!open_flags);
  113. open_flags = O_CREAT | O_TRUNC;
  114. }
  115. if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
  116. DCHECK(!open_flags);
  117. DCHECK(flags & PLATFORM_FILE_WRITE);
  118. open_flags = O_TRUNC;
  119. }
  120. if (!open_flags && !(flags & PLATFORM_FILE_OPEN) &&
  121. !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
  122. NOTREACHED();
  123. errno = EOPNOTSUPP;
  124. if (error)
  125. *error = PLATFORM_FILE_ERROR_FAILED;
  126. return kInvalidPlatformFileValue;
  127. }
  128. if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) {
  129. open_flags |= O_RDWR;
  130. } else if (flags & PLATFORM_FILE_WRITE) {
  131. open_flags |= O_WRONLY;
  132. } else if (!(flags & PLATFORM_FILE_READ) &&
  133. !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) &&
  134. !(flags & PLATFORM_FILE_APPEND) &&
  135. !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
  136. NOTREACHED();
  137. }
  138. if (flags & PLATFORM_FILE_TERMINAL_DEVICE)
  139. open_flags |= O_NOCTTY | O_NDELAY;
  140. if (flags & PLATFORM_FILE_APPEND && flags & PLATFORM_FILE_READ)
  141. open_flags |= O_APPEND | O_RDWR;
  142. else if (flags & PLATFORM_FILE_APPEND)
  143. open_flags |= O_APPEND | O_WRONLY;
  144. COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
  145. int mode = S_IRUSR | S_IWUSR;
  146. #if defined(OS_CHROMEOS)
  147. mode |= S_IRGRP | S_IROTH;
  148. #endif
  149. int descriptor =
  150. HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
  151. if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
  152. if (descriptor < 0) {
  153. open_flags |= O_CREAT;
  154. if (flags & PLATFORM_FILE_EXCLUSIVE_READ ||
  155. flags & PLATFORM_FILE_EXCLUSIVE_WRITE) {
  156. open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
  157. }
  158. descriptor = HANDLE_EINTR(
  159. open(name.value().c_str(), open_flags, mode));
  160. if (created && descriptor >= 0)
  161. *created = true;
  162. }
  163. }
  164. if (created && (descriptor >= 0) &&
  165. (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)))
  166. *created = true;
  167. if ((descriptor >= 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
  168. unlink(name.value().c_str());
  169. }
  170. if (error) {
  171. if (descriptor >= 0)
  172. *error = PLATFORM_FILE_OK;
  173. else
  174. *error = ErrnoToPlatformFileError(errno);
  175. }
  176. return descriptor;
  177. }
  178. FILE* FdopenPlatformFile(PlatformFile file, const char* mode) {
  179. return fdopen(file, mode);
  180. }
  181. #endif // !defined(OS_NACL)
  182. bool ClosePlatformFile(PlatformFile file) {
  183. base::ThreadRestrictions::AssertIOAllowed();
  184. return !IGNORE_EINTR(close(file));
  185. }
  186. int64 SeekPlatformFile(PlatformFile file,
  187. PlatformFileWhence whence,
  188. int64 offset) {
  189. base::ThreadRestrictions::AssertIOAllowed();
  190. if (file < 0 || offset < 0)
  191. return -1;
  192. return lseek(file, static_cast<off_t>(offset), static_cast<int>(whence));
  193. }
  194. int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
  195. base::ThreadRestrictions::AssertIOAllowed();
  196. if (file < 0 || size < 0)
  197. return -1;
  198. int bytes_read = 0;
  199. int rv;
  200. do {
  201. rv = HANDLE_EINTR(pread(file, data + bytes_read,
  202. size - bytes_read, offset + bytes_read));
  203. if (rv <= 0)
  204. break;
  205. bytes_read += rv;
  206. } while (bytes_read < size);
  207. return bytes_read ? bytes_read : rv;
  208. }
  209. int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) {
  210. base::ThreadRestrictions::AssertIOAllowed();
  211. if (file < 0 || size < 0)
  212. return -1;
  213. int bytes_read = 0;
  214. int rv;
  215. do {
  216. rv = HANDLE_EINTR(read(file, data, size));
  217. if (rv <= 0)
  218. break;
  219. bytes_read += rv;
  220. } while (bytes_read < size);
  221. return bytes_read ? bytes_read : rv;
  222. }
  223. int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
  224. char* data, int size) {
  225. base::ThreadRestrictions::AssertIOAllowed();
  226. if (file < 0)
  227. return -1;
  228. return HANDLE_EINTR(pread(file, data, size, offset));
  229. }
  230. int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
  231. char* data, int size) {
  232. base::ThreadRestrictions::AssertIOAllowed();
  233. if (file < 0 || size < 0)
  234. return -1;
  235. return HANDLE_EINTR(read(file, data, size));
  236. }
  237. int WritePlatformFile(PlatformFile file, int64 offset,
  238. const char* data, int size) {
  239. base::ThreadRestrictions::AssertIOAllowed();
  240. if (IsOpenAppend(file))
  241. return WritePlatformFileAtCurrentPos(file, data, size);
  242. if (file < 0 || size < 0)
  243. return -1;
  244. int bytes_written = 0;
  245. int rv;
  246. do {
  247. rv = HANDLE_EINTR(pwrite(file, data + bytes_written,
  248. size - bytes_written, offset + bytes_written));
  249. if (rv <= 0)
  250. break;
  251. bytes_written += rv;
  252. } while (bytes_written < size);
  253. return bytes_written ? bytes_written : rv;
  254. }
  255. int WritePlatformFileAtCurrentPos(PlatformFile file,
  256. const char* data, int size) {
  257. base::ThreadRestrictions::AssertIOAllowed();
  258. if (file < 0 || size < 0)
  259. return -1;
  260. int bytes_written = 0;
  261. int rv;
  262. do {
  263. rv = HANDLE_EINTR(write(file, data, size));
  264. if (rv <= 0)
  265. break;
  266. bytes_written += rv;
  267. } while (bytes_written < size);
  268. return bytes_written ? bytes_written : rv;
  269. }
  270. int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
  271. const char* data, int size) {
  272. base::ThreadRestrictions::AssertIOAllowed();
  273. if (file < 0 || size < 0)
  274. return -1;
  275. return HANDLE_EINTR(write(file, data, size));
  276. }
  277. bool TruncatePlatformFile(PlatformFile file, int64 length) {
  278. base::ThreadRestrictions::AssertIOAllowed();
  279. return ((file >= 0) && !CallFtruncate(file, length));
  280. }
  281. bool FlushPlatformFile(PlatformFile file) {
  282. base::ThreadRestrictions::AssertIOAllowed();
  283. return !CallFsync(file);
  284. }
  285. bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
  286. const base::Time& last_modified_time) {
  287. base::ThreadRestrictions::AssertIOAllowed();
  288. if (file < 0)
  289. return false;
  290. timeval times[2];
  291. times[0] = last_access_time.ToTimeVal();
  292. times[1] = last_modified_time.ToTimeVal();
  293. return !CallFutimes(file, times);
  294. }
  295. bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
  296. if (!info)
  297. return false;
  298. stat_wrapper_t file_info;
  299. if (CallFstat(file, &file_info))
  300. return false;
  301. info->is_directory = S_ISDIR(file_info.st_mode);
  302. info->is_symbolic_link = S_ISLNK(file_info.st_mode);
  303. info->size = file_info.st_size;
  304. #if defined(OS_LINUX)
  305. const time_t last_modified_sec = file_info.st_mtim.tv_sec;
  306. const int64 last_modified_nsec = file_info.st_mtim.tv_nsec;
  307. const time_t last_accessed_sec = file_info.st_atim.tv_sec;
  308. const int64 last_accessed_nsec = file_info.st_atim.tv_nsec;
  309. const time_t creation_time_sec = file_info.st_ctim.tv_sec;
  310. const int64 creation_time_nsec = file_info.st_ctim.tv_nsec;
  311. #elif defined(OS_ANDROID)
  312. const time_t last_modified_sec = file_info.st_mtime;
  313. const int64 last_modified_nsec = file_info.st_mtime_nsec;
  314. const time_t last_accessed_sec = file_info.st_atime;
  315. const int64 last_accessed_nsec = file_info.st_atime_nsec;
  316. const time_t creation_time_sec = file_info.st_ctime;
  317. const int64 creation_time_nsec = file_info.st_ctime_nsec;
  318. #elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
  319. const time_t last_modified_sec = file_info.st_mtimespec.tv_sec;
  320. const int64 last_modified_nsec = file_info.st_mtimespec.tv_nsec;
  321. const time_t last_accessed_sec = file_info.st_atimespec.tv_sec;
  322. const int64 last_accessed_nsec = file_info.st_atimespec.tv_nsec;
  323. const time_t creation_time_sec = file_info.st_ctimespec.tv_sec;
  324. const int64 creation_time_nsec = file_info.st_ctimespec.tv_nsec;
  325. #else
  326. // TODO(gavinp): Investigate a good high resolution option for OS_NACL.
  327. const time_t last_modified_sec = file_info.st_mtime;
  328. const int64 last_modified_nsec = 0;
  329. const time_t last_accessed_sec = file_info.st_atime;
  330. const int64 last_accessed_nsec = 0;
  331. const time_t creation_time_sec = file_info.st_ctime;
  332. const int64 creation_time_nsec = 0;
  333. #endif
  334. info->last_modified =
  335. base::Time::FromTimeT(last_modified_sec) +
  336. base::TimeDelta::FromMicroseconds(last_modified_nsec /
  337. base::Time::kNanosecondsPerMicrosecond);
  338. info->last_accessed =
  339. base::Time::FromTimeT(last_accessed_sec) +
  340. base::TimeDelta::FromMicroseconds(last_accessed_nsec /
  341. base::Time::kNanosecondsPerMicrosecond);
  342. info->creation_time =
  343. base::Time::FromTimeT(creation_time_sec) +
  344. base::TimeDelta::FromMicroseconds(creation_time_nsec /
  345. base::Time::kNanosecondsPerMicrosecond);
  346. return true;
  347. }
  348. PlatformFileError LockPlatformFile(PlatformFile file) {
  349. return CallFctnlFlock(file, true);
  350. }
  351. PlatformFileError UnlockPlatformFile(PlatformFile file) {
  352. return CallFctnlFlock(file, false);
  353. }
  354. PlatformFileError ErrnoToPlatformFileError(int saved_errno) {
  355. switch (saved_errno) {
  356. case EACCES:
  357. case EISDIR:
  358. case EROFS:
  359. case EPERM:
  360. return PLATFORM_FILE_ERROR_ACCESS_DENIED;
  361. #if !defined(OS_NACL) // ETXTBSY not defined by NaCl.
  362. case ETXTBSY:
  363. return PLATFORM_FILE_ERROR_IN_USE;
  364. #endif
  365. case EEXIST:
  366. return PLATFORM_FILE_ERROR_EXISTS;
  367. case ENOENT:
  368. return PLATFORM_FILE_ERROR_NOT_FOUND;
  369. case EMFILE:
  370. return PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
  371. case ENOMEM:
  372. return PLATFORM_FILE_ERROR_NO_MEMORY;
  373. case ENOSPC:
  374. return PLATFORM_FILE_ERROR_NO_SPACE;
  375. case ENOTDIR:
  376. return PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
  377. default:
  378. #if !defined(OS_NACL) // NaCl build has no metrics code.
  379. UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
  380. saved_errno);
  381. #endif
  382. return PLATFORM_FILE_ERROR_FAILED;
  383. }
  384. }
  385. } // namespace base