bigfile.c (9979B)
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 6 #include "prio.h" 7 #include "prmem.h" 8 #include "prprf.h" 9 #include "prinit.h" 10 #include "prerror.h" 11 #include "prthread.h" 12 13 #include "plerror.h" 14 #include "plgetopt.h" 15 16 #define DEFAULT_COUNT 10 17 #define DEFAULT_FILESIZE 1 18 #define BUFFER_SIZE 1000000 19 20 typedef enum { v_silent, v_whisper, v_shout } Verbosity; 21 static void Verbose(Verbosity, const char*, const char*, PRIntn); 22 23 #define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__) 24 25 static PRIntn test_result = 2; 26 static PRFileDesc* output = NULL; 27 static PRIntn verbose = v_silent; 28 static PRIntn filesize = DEFAULT_FILESIZE; 29 30 static PRIntn Usage(void) { 31 PR_fprintf(output, "Bigfile test usage:\n"); 32 PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s <n>] <filename>\n"); 33 PR_fprintf(output, "\td\tdebug mode (equivalent to -vvv)\t(false)\n"); 34 PR_fprintf(output, "\tv\tAdditional levels of output\t(none)\n"); 35 PR_fprintf(output, "\tk\tKeep data file after exit\t(false)\n"); 36 PR_fprintf(output, "\ts <n>\tFile size in megabytes\t\t(1 megabyte)\n"); 37 PR_fprintf(output, "\t<filename>\tName of test file\t(none)\n"); 38 return 2; /* nothing happened */ 39 } /* Usage */ 40 41 static PRStatus DeleteIfFound(const char* filename) { 42 PRStatus rv; 43 VERBOSE(v_shout, "Checking for existing file"); 44 rv = PR_Access(filename, PR_ACCESS_WRITE_OK); 45 if (PR_SUCCESS == rv) { 46 VERBOSE(v_shout, "Deleting existing file"); 47 rv = PR_Delete(filename); 48 if (PR_FAILURE == rv) { 49 VERBOSE(v_shout, "Cannot delete big file"); 50 } 51 } else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) { 52 VERBOSE(v_shout, "Cannot access big file"); 53 } else { 54 rv = PR_SUCCESS; 55 } 56 return rv; 57 } /* DeleteIfFound */ 58 59 static PRIntn Error(const char* msg, const char* filename) { 60 PRInt32 error = PR_GetError(); 61 if (NULL != msg) { 62 if (0 == error) { 63 PR_fprintf(output, msg); 64 } else { 65 PL_FPrintError(output, msg); 66 } 67 } 68 (void)DeleteIfFound(filename); 69 if (v_shout == verbose) { 70 PR_Abort(); 71 } 72 return 1; 73 } /* Error */ 74 75 static void Verbose(Verbosity level, const char* msg, const char* file, 76 PRIntn line) { 77 if (level <= verbose) { 78 PR_fprintf(output, "[%s : %d]: %s\n", file, line, msg); 79 } 80 } /* Verbose */ 81 82 static void PrintInfo(PRFileInfo64* info, const char* filename) { 83 PRExplodedTime tm; 84 char ctime[40], mtime[40]; 85 static const char* types[] = {"FILE", "DIRECTORY", "OTHER"}; 86 PR_fprintf(output, "[%s : %d]: File info for %s\n", __FILE__, __LINE__, 87 filename); 88 PR_fprintf(output, " type: %s, size: %llu bytes,\n", types[info->type - 1], 89 info->size); 90 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 96 PR_fprintf(output, " creation: %s,\n modify: %s\n", ctime, mtime); 97 } /* PrintInfo */ 98 99 int main(int argc, char** argv) { 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 113 PLOptState* opt = PL_CreateOptState(argc, argv, "dtvhs:"); 114 115 output = PR_GetSpecialFD(PR_StandardError); 116 117 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 118 if (PL_OPT_BAD == os) { 119 continue; 120 } 121 switch (opt->option) { 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 149 if (0 == count) { 150 count = DEFAULT_COUNT; 151 } 152 if (0 == filesize) { 153 filesize = DEFAULT_FILESIZE; 154 } 155 if (NULL == filename) { 156 #define FILE_NAME "bigfile.dat" 157 if (DEFAULT_FILESIZE != filesize) { 158 return Usage(); 159 } else { 160 filename = FILE_NAME; 161 } 162 } 163 164 if (PR_FAILURE == DeleteIfFound(filename)) { 165 return 1; 166 } 167 168 test_result = 0; 169 170 LL_I2L(zero_meg, 0); 171 LL_I2L(one_meg, 1000000); 172 LL_I2L(filesize64, filesize); 173 buffer = (char*)PR_MALLOC(BUFFER_SIZE); 174 LL_I2L(big_fragment, BUFFER_SIZE); 175 LL_MUL(filesize64, filesize64, one_meg); 176 177 for (loop = 0; loop < BUFFER_SIZE; ++loop) { 178 buffer[loop] = (char)loop; 179 } 180 181 VERBOSE(v_whisper, "Creating big file"); 182 file = PR_Open(filename, PR_CREATE_FILE | PR_WRONLY, 0666); 183 if (NULL == file) { 184 return Error("PR_Open()", filename); 185 } 186 187 VERBOSE(v_whisper, "Testing available space in empty file"); 188 big_answer = file->methods->available64(file); 189 if (!LL_IS_ZERO(big_answer)) { 190 return Error("empty available64()", filename); 191 } 192 193 LL_SUB(big_size, filesize64, one_meg); 194 VERBOSE(v_whisper, "Creating sparse big file by seeking to end"); 195 big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET); 196 if (!LL_EQ(big_answer, big_size)) { 197 return Error("seek", filename); 198 } 199 200 VERBOSE(v_whisper, "Writing block at end of sparse file"); 201 bytes = file->methods->write(file, buffer, BUFFER_SIZE); 202 if (bytes != BUFFER_SIZE) { 203 return Error("write", filename); 204 } 205 206 VERBOSE(v_whisper, "Testing available space at end of sparse file"); 207 big_answer = file->methods->available64(file); 208 if (!LL_IS_ZERO(big_answer)) { 209 return Error("eof available64()", filename); 210 } 211 212 VERBOSE(v_whisper, "Getting big info on sparse big file"); 213 rv = file->methods->fileInfo64(file, &big_info); 214 if (PR_FAILURE == rv) { 215 return Error("fileInfo64()", filename); 216 } 217 if (v_shout <= verbose) { 218 PrintInfo(&big_info, filename); 219 } 220 221 VERBOSE(v_whisper, "Getting small info on sparse big file"); 222 rv = file->methods->fileInfo(file, &small_info); 223 if (LL_CMP(sevenFox, <, filesize64) && (PR_SUCCESS == rv)) { 224 VERBOSE(v_whisper, "Should have failed and didn't"); 225 return Error("fileInfo()", filename); 226 } else if (LL_CMP(sevenFox, >, filesize64) && (PR_FAILURE == rv)) { 227 VERBOSE(v_whisper, "Should have succeeded and didn't"); 228 return Error("fileInfo()", filename); 229 } 230 231 VERBOSE(v_whisper, "Rewinding big file"); 232 big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); 233 if (!LL_IS_ZERO(big_answer)) { 234 return Error("rewind seek64()", filename); 235 } 236 237 VERBOSE(v_whisper, "Establishing available space in rewound file"); 238 big_answer = file->methods->available64(file); 239 if (LL_NE(filesize64, big_answer)) { 240 return Error("bof available64()", filename); 241 } 242 243 VERBOSE(v_whisper, "Closing big file"); 244 rv = file->methods->close(file); 245 if (PR_FAILURE == rv) { 246 return Error("close()", filename); 247 } 248 249 VERBOSE(v_whisper, "Reopening big file"); 250 file = PR_Open(filename, PR_RDWR, 0666); 251 if (NULL == file) { 252 return Error("open failed", filename); 253 } 254 255 VERBOSE(v_whisper, "Checking available data in reopened file"); 256 big_answer = file->methods->available64(file); 257 if (LL_NE(filesize64, big_answer)) { 258 return Error("reopened available64()", filename); 259 } 260 261 big_answer = zero_meg; 262 VERBOSE(v_whisper, "Rewriting every byte of big file data"); 263 do { 264 bytes = file->methods->write(file, buffer, BUFFER_SIZE); 265 if (bytes != BUFFER_SIZE) { 266 return Error("write", filename); 267 } 268 LL_ADD(big_answer, big_answer, big_fragment); 269 } while (LL_CMP(big_answer, <, filesize64)); 270 271 VERBOSE(v_whisper, "Checking position at eof"); 272 big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_CUR); 273 if (LL_NE(big_answer, filesize64)) { 274 return Error("file size error", filename); 275 } 276 277 VERBOSE(v_whisper, "Testing available space at eof"); 278 big_answer = file->methods->available64(file); 279 if (!LL_IS_ZERO(big_answer)) { 280 return Error("eof available64()", filename); 281 } 282 283 VERBOSE(v_whisper, "Rewinding full file"); 284 big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); 285 if (!LL_IS_ZERO(big_answer)) { 286 return Error("bof seek64()", filename); 287 } 288 289 VERBOSE(v_whisper, "Testing available space in rewound file"); 290 big_answer = file->methods->available64(file); 291 if (LL_NE(big_answer, filesize64)) { 292 return Error("bof available64()", filename); 293 } 294 295 VERBOSE(v_whisper, "Seeking to end of big file"); 296 big_answer = file->methods->seek64(file, filesize64, PR_SEEK_SET); 297 if (LL_NE(big_answer, filesize64)) { 298 return Error("eof seek64()", filename); 299 } 300 301 VERBOSE(v_whisper, "Getting info on big file while it's open"); 302 rv = file->methods->fileInfo64(file, &big_info); 303 if (PR_FAILURE == rv) { 304 return Error("fileInfo64()", filename); 305 } 306 if (v_shout <= verbose) { 307 PrintInfo(&big_info, filename); 308 } 309 310 VERBOSE(v_whisper, "Closing big file"); 311 rv = file->methods->close(file); 312 if (PR_FAILURE == rv) { 313 return Error("close()", filename); 314 } 315 316 VERBOSE(v_whisper, "Getting info on big file after it's closed"); 317 rv = PR_GetFileInfo64(filename, &big_info); 318 if (PR_FAILURE == rv) { 319 return Error("fileInfo64()", filename); 320 } 321 if (v_shout <= verbose) { 322 PrintInfo(&big_info, filename); 323 } 324 325 VERBOSE(v_whisper, "Deleting big file"); 326 rv = PR_Delete(filename); 327 if (PR_FAILURE == rv) { 328 return Error("PR_Delete()", filename); 329 } 330 331 PR_DELETE(buffer); 332 return test_result; 333 } /* main */ 334 335 /* bigfile.c */