1
0

NXFileObject.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. #ifndef WIN32_LEAN_AND_MEAN
  2. #define WIN32_LEAN_AND_MEAN
  3. #endif
  4. #include <windows.h>
  5. #include "NXFileObject.h"
  6. #include "nx/nxfile.h"
  7. #include "nu/nodelist.h"
  8. #include "foundation/atomics.h"
  9. #include "nu/nodelist.h"
  10. #include <errno.h>
  11. #include <new>
  12. /* Windows implementation
  13. note: for now, we're using FILE. We will eventually replace with better buffering
  14. TODO: deal with files opened in "append" mode */
  15. NXFileObject::NXFileObject()
  16. {
  17. nodelist_init(&region_stack);
  18. region.start = 0;
  19. region.end = 0xFFFFFFFFFFFFFFFFULL;
  20. position=0;
  21. reference_count=1;
  22. uri=0;
  23. memset(&file_stats, 0, sizeof(file_stats));
  24. }
  25. NXFileObject::~NXFileObject()
  26. {
  27. NXURIRelease(uri);
  28. NXFileRegion *region = (NXFileRegion *)region_stack.head;
  29. while (region)
  30. {
  31. NXFileRegion *next = (NXFileRegion *)region->Next;
  32. free(region);
  33. region = next;
  34. }
  35. }
  36. ns_error_t NXFileObject::Initialize(nx_uri_t _uri)
  37. {
  38. uri = NXURIRetain(_uri);
  39. return NErr_Success;
  40. }
  41. size_t NXFileObject::Retain()
  42. {
  43. return nx_atomic_inc(&reference_count);
  44. }
  45. size_t NXFileObject::Release()
  46. {
  47. if (!reference_count)
  48. {
  49. return reference_count;
  50. }
  51. size_t r = nx_atomic_dec_release(&reference_count);
  52. if (!r)
  53. {
  54. delete(this);
  55. }
  56. return r;
  57. }
  58. ns_error_t NXFileObject::LockRegion(uint64_t start, uint64_t end)
  59. {
  60. // save the old region data
  61. NXFileRegion *old_region = (NXFileRegion *)calloc(1, sizeof(NXFileRegion));
  62. if (!old_region)
  63. {
  64. return NErr_OutOfMemory;
  65. }
  66. old_region->start = region.start;
  67. old_region->end = region.end;
  68. nodelist_push_front(&region_stack, old_region);
  69. // if we're already locked, Lock within our current region.
  70. // The weird way the logic is done prevents overflow
  71. if (start > region.end - region.start)
  72. {
  73. start = region.end;
  74. }
  75. else
  76. {
  77. start = region.start + start;
  78. }
  79. if (end > region.end - region.start)
  80. {
  81. end = region.end;
  82. }
  83. else
  84. {
  85. end = region.start + end;
  86. }
  87. region.start = start;
  88. region.end = end;
  89. return NErr_Success;
  90. }
  91. ns_error_t NXFileObject::UnlockRegion()
  92. {
  93. NXFileRegion *new_region = (NXFileRegion *)nodelist_pop_front(&region_stack);
  94. if (new_region)
  95. {
  96. region.start = new_region->start;
  97. region.end = new_region->end;
  98. free(new_region);
  99. return NErr_Success;
  100. }
  101. else
  102. {
  103. return NErr_NoAction;
  104. }
  105. }
  106. ns_error_t NXFileObject::Stat(nx_file_stat_t out_stats)
  107. {
  108. *out_stats = file_stats;
  109. return NErr_Success;
  110. }
  111. ns_error_t NXFileObject::Length(uint64_t *length)
  112. {
  113. *length = region.end - region.start;
  114. return NErr_Success;
  115. }
  116. ns_error_t NXFileObject::EndOfFile()
  117. {
  118. if (position >= region.end)
  119. {
  120. return NErr_True;
  121. }
  122. else
  123. {
  124. return NErr_False;
  125. }
  126. }
  127. /* ----------------------------------------- */
  128. class NXFileObject_FILE : public NXFileObject
  129. {
  130. public:
  131. NXFileObject_FILE();
  132. ~NXFileObject_FILE();
  133. ns_error_t Initialize(nx_uri_t uri, FILE *f, bool writable);
  134. private:
  135. FILE *f;
  136. bool writable;
  137. ns_error_t Read(void *buffer, size_t bytes_requested, size_t *bytes_read);
  138. ns_error_t Write(const void *buffer, size_t bytes);
  139. ns_error_t Seek(uint64_t position);
  140. ns_error_t Tell(uint64_t *position);
  141. ns_error_t PeekByte(uint8_t *byte);
  142. ns_error_t Sync();
  143. ns_error_t Truncate();
  144. };
  145. NXFileObject_FILE::NXFileObject_FILE()
  146. {
  147. f = 0;
  148. writable = false;
  149. }
  150. NXFileObject_FILE::~NXFileObject_FILE()
  151. {
  152. if (f)
  153. {
  154. fclose(f);
  155. }
  156. }
  157. ns_error_t NXFileObject_FILE::Initialize(nx_uri_t uri, FILE *_f, bool _writable)
  158. {
  159. writable = _writable;
  160. ns_error_t ret = NXFileObject::Initialize(uri);
  161. if (ret != NErr_Success)
  162. {
  163. return ret;
  164. }
  165. ret = NXFile_statFILE(_f, &file_stats);
  166. if (ret != NErr_Success)
  167. {
  168. return ret;
  169. }
  170. region.end = file_stats.file_size;
  171. f = _f;
  172. return NErr_Success;
  173. }
  174. ns_error_t NXFileObject_FILE::Read(void *buffer, size_t bytes_requested, size_t *bytes_read)
  175. {
  176. // if it's an "empty" read, we need to determine whether or not we're at the end of the file
  177. if (bytes_requested == 0)
  178. {
  179. if (region.end == position || feof(f))
  180. {
  181. return NErr_EndOfFile;
  182. }
  183. else
  184. {
  185. return NErr_Success;
  186. }
  187. }
  188. // don't read into any data after the locked region
  189. if ((uint64_t)bytes_requested > region.end - position)
  190. {
  191. bytes_requested = (size_t)(region.end - position);
  192. }
  193. if (bytes_requested == 0)
  194. {
  195. return NErr_EndOfFile;
  196. }
  197. if (buffer == 0)
  198. {
  199. uint64_t old_position=position;
  200. Seek(position+bytes_requested);
  201. if (bytes_read)
  202. {
  203. *bytes_read = (size_t)(position - old_position);
  204. }
  205. return NErr_Success;
  206. }
  207. else
  208. {
  209. size_t results = fread(buffer, 1, bytes_requested, f);
  210. if (results == 0)
  211. {
  212. if (feof(f))
  213. {
  214. return NErr_EndOfFile;
  215. }
  216. else
  217. {
  218. return NErr_Error;
  219. }
  220. }
  221. if (bytes_read)
  222. {
  223. *bytes_read = results;
  224. }
  225. position+=results;
  226. return NErr_Success;
  227. }
  228. }
  229. ns_error_t NXFileObject_FILE::Write(const void *buffer, size_t bytes)
  230. {
  231. // TODO: review this in relation to locked regions
  232. size_t results = fwrite(buffer, 1, bytes, f);
  233. if (results == 0)
  234. {
  235. return NErr_Error;
  236. }
  237. position += results;
  238. if (region.end < position)
  239. {
  240. region.end = position;
  241. }
  242. return NErr_Success;
  243. }
  244. ns_error_t NXFileObject_FILE::PeekByte(uint8_t *byte)
  245. {
  246. if (position == region.end)
  247. {
  248. return NErr_EndOfFile;
  249. }
  250. int read_byte = fgetc(f);
  251. if (read_byte != EOF)
  252. {
  253. ungetc(read_byte, f);
  254. }
  255. else
  256. {
  257. return NErr_EndOfFile;
  258. }
  259. *byte = (uint8_t)read_byte;
  260. return NErr_Success;
  261. }
  262. ns_error_t NXFileObject_FILE::Seek(uint64_t new_position)
  263. {
  264. if (!writable)
  265. {
  266. // doing it this way will prevent integer overflow
  267. if (new_position > (region.end - region.start))
  268. {
  269. new_position = region.end - region.start;
  270. }
  271. }
  272. if (_fseeki64(f, region.start+new_position, SEEK_SET) == 0)
  273. {
  274. position = region.start+new_position;
  275. return NErr_Success;
  276. }
  277. else
  278. {
  279. return NErr_Error;
  280. }
  281. }
  282. ns_error_t NXFileObject_FILE::Tell(uint64_t *out_position)
  283. {
  284. *out_position = position - region.start;
  285. return NErr_Success;
  286. }
  287. ns_error_t NXFileObject_FILE::Sync()
  288. {
  289. fflush(f);
  290. return NErr_Success;
  291. }
  292. ns_error_t NXFileObject_FILE::Truncate()
  293. {
  294. int fd = _fileno(f);
  295. _chsize_s(fd, position);
  296. return NErr_Success;
  297. }
  298. /* ----------------------------------------- */
  299. ns_error_t NXFileOpenFile(nx_file_t *out_file, nx_uri_t filename, nx_file_FILE_flags_t flags)
  300. {
  301. FILE *f = NXFile_fopen(filename, flags);
  302. if (!f)
  303. {
  304. if (errno == ENOENT)
  305. {
  306. return NErr_FileNotFound;
  307. }
  308. else
  309. {
  310. return NErr_Error;
  311. }
  312. }
  313. NXFileObject_FILE *file_object = new (std::nothrow) NXFileObject_FILE;
  314. if (!file_object)
  315. {
  316. fclose(f);
  317. return NErr_OutOfMemory;
  318. }
  319. ns_error_t ret = file_object->Initialize(filename, f, !!(flags & nx_file_FILE_writable_mask));
  320. if (ret != NErr_Success)
  321. {
  322. fclose(f);
  323. delete file_object;
  324. return ret;
  325. }
  326. *out_file = (nx_file_t)file_object;
  327. return NErr_Success;
  328. }
  329. nx_file_t NXFileRetain(nx_file_t _f)
  330. {
  331. if (!_f)
  332. {
  333. return 0;
  334. }
  335. NXFileObject *f = (NXFileObject *)_f;
  336. f->Retain();
  337. return _f;
  338. }
  339. void NXFileRelease(nx_file_t _f)
  340. {
  341. if (_f)
  342. {
  343. NXFileObject *f = (NXFileObject *)_f;
  344. f->Release();
  345. }
  346. }
  347. ns_error_t NXFileRead(nx_file_t _f, void *buffer, size_t bytes_requested, size_t *bytes_read)
  348. {
  349. if (!_f)
  350. {
  351. return NErr_BadParameter;
  352. }
  353. NXFileObject *f = (NXFileObject *)_f;
  354. return f->Read(buffer, bytes_requested, bytes_read);
  355. }
  356. ns_error_t NXFileSeek(nx_file_t _f, uint64_t position)
  357. {
  358. if (!_f)
  359. {
  360. return NErr_BadParameter;
  361. }
  362. NXFileObject *f = (NXFileObject *)_f;
  363. return f->Seek(position);
  364. }
  365. ns_error_t NXFileTell(nx_file_t _f, uint64_t *position)
  366. {
  367. if (!_f)
  368. {
  369. return NErr_BadParameter;
  370. }
  371. NXFileObject *f = (NXFileObject *)_f;
  372. return f->Tell(position);
  373. }
  374. ns_error_t NXFileLockRegion(nx_file_t _f, uint64_t start_position, uint64_t end_position)
  375. {
  376. if (!_f)
  377. {
  378. return NErr_BadParameter;
  379. }
  380. NXFileObject *f = (NXFileObject *)_f;
  381. return f->LockRegion(start_position, end_position);
  382. }
  383. ns_error_t NXFileUnlockRegion(nx_file_t _f)
  384. {
  385. if (!_f)
  386. {
  387. return NErr_BadParameter;
  388. }
  389. NXFileObject *f = (NXFileObject *)_f;
  390. return f->UnlockRegion();
  391. }
  392. ns_error_t NXFileStat(nx_file_t _f, nx_file_stat_t file_stats)
  393. {
  394. if (!_f)
  395. {
  396. return NErr_BadParameter;
  397. }
  398. NXFileObject *f = (NXFileObject *)_f;
  399. return f->Stat(file_stats);
  400. }
  401. ns_error_t NXFileLength(nx_file_t _f, uint64_t *length)
  402. {
  403. if (!_f)
  404. {
  405. return NErr_BadParameter;
  406. }
  407. NXFileObject *f = (NXFileObject *)_f;
  408. return f->Length(length);
  409. }
  410. ns_error_t NXFileEndOfFile(nx_file_t _f)
  411. {
  412. if (!_f)
  413. {
  414. return NErr_BadParameter;
  415. }
  416. NXFileObject *f = (NXFileObject *)_f;
  417. return f->EndOfFile();
  418. }
  419. ns_error_t NXFilePeekByte(nx_file_t _f, uint8_t *byte)
  420. {
  421. if (!_f)
  422. {
  423. return NErr_BadParameter;
  424. }
  425. NXFileObject *f = (NXFileObject *)_f;
  426. return f->PeekByte(byte);
  427. }
  428. ns_error_t NXFileWrite(nx_file_t _f, const void *buffer, size_t bytes)
  429. {
  430. if (!_f)
  431. {
  432. return NErr_BadParameter;
  433. }
  434. NXFileObject *f = (NXFileObject *)_f;
  435. return f->Write(buffer, bytes);
  436. }
  437. ns_error_t NXFileSync(nx_file_t _f)
  438. {
  439. if (!_f)
  440. {
  441. return NErr_BadParameter;
  442. }
  443. NXFileObject *f = (NXFileObject *)_f;
  444. return f->Sync();
  445. }
  446. ns_error_t NXFileTruncate(nx_file_t _f)
  447. {
  448. if (!_f)
  449. {
  450. return NErr_BadParameter;
  451. }
  452. NXFileObject *f = (NXFileObject *)_f;
  453. return f->Truncate();
  454. }