bigfile.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "prio.h"
  6. #include "prmem.h"
  7. #include "prprf.h"
  8. #include "prinit.h"
  9. #include "prerror.h"
  10. #include "prthread.h"
  11. #include "plerror.h"
  12. #include "plgetopt.h"
  13. #define DEFAULT_COUNT 10
  14. #define DEFAULT_FILESIZE 1
  15. #define BUFFER_SIZE 1000000
  16. typedef enum {v_silent, v_whisper, v_shout} Verbosity;
  17. static void Verbose(Verbosity, const char*, const char*, PRIntn);
  18. #define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__)
  19. static PRIntn test_result = 2;
  20. static PRFileDesc *output = NULL;
  21. static PRIntn verbose = v_silent;
  22. static PRIntn filesize = DEFAULT_FILESIZE;
  23. static PRIntn Usage(void)
  24. {
  25. PR_fprintf(output, "Bigfile test usage:\n");
  26. PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s <n>] <filename>\n");
  27. PR_fprintf(output, "\td\tdebug mode (equivalent to -vvv)\t(false)\n");
  28. PR_fprintf(output, "\tv\tAdditional levels of output\t(none)\n");
  29. PR_fprintf(output, "\tk\tKeep data file after exit\t(false)\n");
  30. PR_fprintf(output, "\ts <n>\tFile size in megabytes\t\t(1 megabyte)\n");
  31. PR_fprintf(output, "\t<filename>\tName of test file\t(none)\n");
  32. return 2; /* nothing happened */
  33. } /* Usage */
  34. static PRStatus DeleteIfFound(const char *filename)
  35. {
  36. PRStatus rv;
  37. VERBOSE(v_shout, "Checking for existing file");
  38. rv = PR_Access(filename, PR_ACCESS_WRITE_OK);
  39. if (PR_SUCCESS == rv)
  40. {
  41. VERBOSE(v_shout, "Deleting existing file");
  42. rv = PR_Delete(filename);
  43. if (PR_FAILURE == rv) {
  44. VERBOSE(v_shout, "Cannot delete big file");
  45. }
  46. }
  47. else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) {
  48. VERBOSE(v_shout, "Cannot access big file");
  49. }
  50. else {
  51. rv = PR_SUCCESS;
  52. }
  53. return rv;
  54. } /* DeleteIfFound */
  55. static PRIntn Error(const char *msg, const char *filename)
  56. {
  57. PRInt32 error = PR_GetError();
  58. if (NULL != msg)
  59. {
  60. if (0 == error) {
  61. PR_fprintf(output, msg);
  62. }
  63. else {
  64. PL_FPrintError(output, msg);
  65. }
  66. }
  67. (void)DeleteIfFound(filename);
  68. if (v_shout == verbose) {
  69. PR_Abort();
  70. }
  71. return 1;
  72. } /* Error */
  73. static void Verbose(
  74. Verbosity level, const char *msg, const char *file, PRIntn line)
  75. {
  76. if (level <= verbose) {
  77. PR_fprintf(output, "[%s : %d]: %s\n", file, line, msg);
  78. }
  79. } /* Verbose */
  80. static void PrintInfo(PRFileInfo64 *info, const char *filename)
  81. {
  82. PRExplodedTime tm;
  83. char ctime[40], mtime[40];
  84. static const char *types[] = {"FILE", "DIRECTORY", "OTHER"};
  85. PR_fprintf(
  86. output, "[%s : %d]: File info for %s\n",
  87. __FILE__, __LINE__, filename);
  88. PR_fprintf(
  89. output, " type: %s, size: %llu bytes,\n",
  90. types[info->type - 1], info->size);
  91. PR_ExplodeTime(info->creationTime, PR_GMTParameters, &tm);
  92. (void)PR_FormatTime(ctime, sizeof(ctime), "%c GMT", &tm);
  93. PR_ExplodeTime(info->modifyTime, PR_GMTParameters, &tm);
  94. (void)PR_FormatTime(mtime, sizeof(mtime), "%c GMT", &tm);
  95. PR_fprintf(
  96. output, " creation: %s,\n modify: %s\n", ctime, mtime);
  97. } /* PrintInfo */
  98. int main(int argc, char **argv)
  99. {
  100. PRStatus rv;
  101. char *buffer;
  102. PLOptStatus os;
  103. PRInt32 loop, bytes;
  104. PRFileInfo small_info;
  105. PRFileInfo64 big_info;
  106. PRBool keep = PR_FALSE;
  107. PRFileDesc *file = NULL;
  108. const char *filename = NULL;
  109. PRIntn count = DEFAULT_COUNT;
  110. PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment;
  111. PRInt64 sevenFox = LL_INIT(0,0x7fffffff);
  112. PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:");
  113. output = PR_GetSpecialFD(PR_StandardError);
  114. PR_STDIO_INIT();
  115. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  116. {
  117. if (PL_OPT_BAD == os) {
  118. continue;
  119. }
  120. switch (opt->option)
  121. {
  122. case 0:
  123. filename = opt->value;
  124. break;
  125. case 'd': /* debug mode */
  126. verbose = v_shout;
  127. break;
  128. case 'k': /* keep file */
  129. keep = PR_TRUE;
  130. break;
  131. case 'v': /* verbosity */
  132. if (v_shout > verbose) {
  133. verbose += 1;
  134. }
  135. break;
  136. case 'c': /* loop counter */
  137. count = atoi(opt->value);
  138. break;
  139. case 's': /* filesize */
  140. filesize = atoi(opt->value);
  141. break;
  142. case 'h': /* confused */
  143. default:
  144. return Usage();
  145. }
  146. }
  147. PL_DestroyOptState(opt);
  148. if (0 == count) {
  149. count = DEFAULT_COUNT;
  150. }
  151. if (0 == filesize) {
  152. filesize = DEFAULT_FILESIZE;
  153. }
  154. if (NULL == filename)
  155. {
  156. #define FILE_NAME "bigfile.dat"
  157. if (DEFAULT_FILESIZE != filesize) {
  158. return Usage();
  159. }
  160. else {
  161. filename = FILE_NAME;
  162. }
  163. }
  164. if (PR_FAILURE == DeleteIfFound(filename)) {
  165. return 1;
  166. }
  167. test_result = 0;
  168. LL_I2L(zero_meg, 0);
  169. LL_I2L(one_meg, 1000000);
  170. LL_I2L(filesize64, filesize);
  171. buffer = (char*)PR_MALLOC(BUFFER_SIZE);
  172. LL_I2L(big_fragment, BUFFER_SIZE);
  173. LL_MUL(filesize64, filesize64, one_meg);
  174. for (loop = 0; loop < BUFFER_SIZE; ++loop) {
  175. buffer[loop] = (char)loop;
  176. }
  177. VERBOSE(v_whisper, "Creating big file");
  178. file = PR_Open(filename, PR_CREATE_FILE | PR_WRONLY, 0666);
  179. if (NULL == file) {
  180. return Error("PR_Open()", filename);
  181. }
  182. VERBOSE(v_whisper, "Testing available space in empty file");
  183. big_answer = file->methods->available64(file);
  184. if (!LL_IS_ZERO(big_answer)) {
  185. return Error("empty available64()", filename);
  186. }
  187. LL_SUB(big_size, filesize64, one_meg);
  188. VERBOSE(v_whisper, "Creating sparse big file by seeking to end");
  189. big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET);
  190. if (!LL_EQ(big_answer, big_size)) {
  191. return Error("seek", filename);
  192. }
  193. VERBOSE(v_whisper, "Writing block at end of sparse file");
  194. bytes = file->methods->write(file, buffer, BUFFER_SIZE);
  195. if (bytes != BUFFER_SIZE) {
  196. return Error("write", filename);
  197. }
  198. VERBOSE(v_whisper, "Testing available space at end of sparse file");
  199. big_answer = file->methods->available64(file);
  200. if (!LL_IS_ZERO(big_answer)) {
  201. return Error("eof available64()", filename);
  202. }
  203. VERBOSE(v_whisper, "Getting big info on sparse big file");
  204. rv = file->methods->fileInfo64(file, &big_info);
  205. if (PR_FAILURE == rv) {
  206. return Error("fileInfo64()", filename);
  207. }
  208. if (v_shout <= verbose) {
  209. PrintInfo(&big_info, filename);
  210. }
  211. VERBOSE(v_whisper, "Getting small info on sparse big file");
  212. rv = file->methods->fileInfo(file, &small_info);
  213. if (LL_CMP(sevenFox, <, filesize64) && (PR_SUCCESS == rv))
  214. {
  215. VERBOSE(v_whisper, "Should have failed and didn't");
  216. return Error("fileInfo()", filename);
  217. }
  218. else if (LL_CMP(sevenFox, >, filesize64) && (PR_FAILURE == rv))
  219. {
  220. VERBOSE(v_whisper, "Should have succeeded and didn't");
  221. return Error("fileInfo()", filename);
  222. }
  223. VERBOSE(v_whisper, "Rewinding big file");
  224. big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET);
  225. if (!LL_IS_ZERO(big_answer)) {
  226. return Error("rewind seek64()", filename);
  227. }
  228. VERBOSE(v_whisper, "Establishing available space in rewound file");
  229. big_answer = file->methods->available64(file);
  230. if (LL_NE(filesize64, big_answer)) {
  231. return Error("bof available64()", filename);
  232. }
  233. VERBOSE(v_whisper, "Closing big file");
  234. rv = file->methods->close(file);
  235. if (PR_FAILURE == rv) {
  236. return Error("close()", filename);
  237. }
  238. VERBOSE(v_whisper, "Reopening big file");
  239. file = PR_Open(filename, PR_RDWR, 0666);
  240. if (NULL == file) {
  241. return Error("open failed", filename);
  242. }
  243. VERBOSE(v_whisper, "Checking available data in reopened file");
  244. big_answer = file->methods->available64(file);
  245. if (LL_NE(filesize64, big_answer)) {
  246. return Error("reopened available64()", filename);
  247. }
  248. big_answer = zero_meg;
  249. VERBOSE(v_whisper, "Rewriting every byte of big file data");
  250. do
  251. {
  252. bytes = file->methods->write(file, buffer, BUFFER_SIZE);
  253. if (bytes != BUFFER_SIZE) {
  254. return Error("write", filename);
  255. }
  256. LL_ADD(big_answer, big_answer, big_fragment);
  257. } while (LL_CMP(big_answer, <, filesize64));
  258. VERBOSE(v_whisper, "Checking position at eof");
  259. big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_CUR);
  260. if (LL_NE(big_answer, filesize64)) {
  261. return Error("file size error", filename);
  262. }
  263. VERBOSE(v_whisper, "Testing available space at eof");
  264. big_answer = file->methods->available64(file);
  265. if (!LL_IS_ZERO(big_answer)) {
  266. return Error("eof available64()", filename);
  267. }
  268. VERBOSE(v_whisper, "Rewinding full file");
  269. big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET);
  270. if (!LL_IS_ZERO(big_answer)) {
  271. return Error("bof seek64()", filename);
  272. }
  273. VERBOSE(v_whisper, "Testing available space in rewound file");
  274. big_answer = file->methods->available64(file);
  275. if (LL_NE(big_answer, filesize64)) {
  276. return Error("bof available64()", filename);
  277. }
  278. VERBOSE(v_whisper, "Seeking to end of big file");
  279. big_answer = file->methods->seek64(file, filesize64, PR_SEEK_SET);
  280. if (LL_NE(big_answer, filesize64)) {
  281. return Error("eof seek64()", filename);
  282. }
  283. VERBOSE(v_whisper, "Getting info on big file while it's open");
  284. rv = file->methods->fileInfo64(file, &big_info);
  285. if (PR_FAILURE == rv) {
  286. return Error("fileInfo64()", filename);
  287. }
  288. if (v_shout <= verbose) {
  289. PrintInfo(&big_info, filename);
  290. }
  291. VERBOSE(v_whisper, "Closing big file");
  292. rv = file->methods->close(file);
  293. if (PR_FAILURE == rv) {
  294. return Error("close()", filename);
  295. }
  296. VERBOSE(v_whisper, "Getting info on big file after it's closed");
  297. rv = PR_GetFileInfo64(filename, &big_info);
  298. if (PR_FAILURE == rv) {
  299. return Error("fileInfo64()", filename);
  300. }
  301. if (v_shout <= verbose) {
  302. PrintInfo(&big_info, filename);
  303. }
  304. VERBOSE(v_whisper, "Deleting big file");
  305. rv = PR_Delete(filename);
  306. if (PR_FAILURE == rv) {
  307. return Error("PR_Delete()", filename);
  308. }
  309. PR_DELETE(buffer);
  310. return test_result;
  311. } /* main */
  312. /* bigfile.c */