/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "prio.h" #include "prmem.h" #include "prprf.h" #include "prinit.h" #include "prerror.h" #include "prthread.h" #include "plerror.h" #include "plgetopt.h" #define DEFAULT_COUNT 10 #define DEFAULT_FILESIZE 1 #define BUFFER_SIZE 1000000 typedef enum {v_silent, v_whisper, v_shout} Verbosity; static void Verbose(Verbosity, const char*, const char*, PRIntn); #define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__) static PRIntn test_result = 2; static PRFileDesc *output = NULL; static PRIntn verbose = v_silent; static PRIntn filesize = DEFAULT_FILESIZE; static PRIntn Usage(void) { PR_fprintf(output, "Bigfile test usage:\n"); PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s ] \n"); PR_fprintf(output, "\td\tdebug mode (equivalent to -vvv)\t(false)\n"); PR_fprintf(output, "\tv\tAdditional levels of output\t(none)\n"); PR_fprintf(output, "\tk\tKeep data file after exit\t(false)\n"); PR_fprintf(output, "\ts \tFile size in megabytes\t\t(1 megabyte)\n"); PR_fprintf(output, "\t\tName of test file\t(none)\n"); return 2; /* nothing happened */ } /* Usage */ static PRStatus DeleteIfFound(const char *filename) { PRStatus rv; VERBOSE(v_shout, "Checking for existing file"); rv = PR_Access(filename, PR_ACCESS_WRITE_OK); if (PR_SUCCESS == rv) { VERBOSE(v_shout, "Deleting existing file"); rv = PR_Delete(filename); if (PR_FAILURE == rv) { VERBOSE(v_shout, "Cannot delete big file"); } } else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) { VERBOSE(v_shout, "Cannot access big file"); } else { rv = PR_SUCCESS; } return rv; } /* DeleteIfFound */ static PRIntn Error(const char *msg, const char *filename) { PRInt32 error = PR_GetError(); if (NULL != msg) { if (0 == error) { PR_fprintf(output, msg); } else { PL_FPrintError(output, msg); } } (void)DeleteIfFound(filename); if (v_shout == verbose) { PR_Abort(); } return 1; } /* Error */ static void Verbose( Verbosity level, const char *msg, const char *file, PRIntn line) { if (level <= verbose) { PR_fprintf(output, "[%s : %d]: %s\n", file, line, msg); } } /* Verbose */ static void PrintInfo(PRFileInfo64 *info, const char *filename) { PRExplodedTime tm; char ctime[40], mtime[40]; static const char *types[] = {"FILE", "DIRECTORY", "OTHER"}; PR_fprintf( output, "[%s : %d]: File info for %s\n", __FILE__, __LINE__, filename); PR_fprintf( output, " type: %s, size: %llu bytes,\n", types[info->type - 1], info->size); PR_ExplodeTime(info->creationTime, PR_GMTParameters, &tm); (void)PR_FormatTime(ctime, sizeof(ctime), "%c GMT", &tm); PR_ExplodeTime(info->modifyTime, PR_GMTParameters, &tm); (void)PR_FormatTime(mtime, sizeof(mtime), "%c GMT", &tm); PR_fprintf( output, " creation: %s,\n modify: %s\n", ctime, mtime); } /* PrintInfo */ int main(int argc, char **argv) { PRStatus rv; char *buffer; PLOptStatus os; PRInt32 loop, bytes; PRFileInfo small_info; PRFileInfo64 big_info; PRBool keep = PR_FALSE; PRFileDesc *file = NULL; const char *filename = NULL; PRIntn count = DEFAULT_COUNT; PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment; PRInt64 sevenFox = LL_INIT(0,0x7fffffff); PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:"); output = PR_GetSpecialFD(PR_StandardError); PR_STDIO_INIT(); while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { if (PL_OPT_BAD == os) { continue; } switch (opt->option) { case 0: filename = opt->value; break; case 'd': /* debug mode */ verbose = v_shout; break; case 'k': /* keep file */ keep = PR_TRUE; break; case 'v': /* verbosity */ if (v_shout > verbose) { verbose += 1; } break; case 'c': /* loop counter */ count = atoi(opt->value); break; case 's': /* filesize */ filesize = atoi(opt->value); break; case 'h': /* confused */ default: return Usage(); } } PL_DestroyOptState(opt); if (0 == count) { count = DEFAULT_COUNT; } if (0 == filesize) { filesize = DEFAULT_FILESIZE; } if (NULL == filename) { #define FILE_NAME "bigfile.dat" if (DEFAULT_FILESIZE != filesize) { return Usage(); } else { filename = FILE_NAME; } } if (PR_FAILURE == DeleteIfFound(filename)) { return 1; } test_result = 0; LL_I2L(zero_meg, 0); LL_I2L(one_meg, 1000000); LL_I2L(filesize64, filesize); buffer = (char*)PR_MALLOC(BUFFER_SIZE); LL_I2L(big_fragment, BUFFER_SIZE); LL_MUL(filesize64, filesize64, one_meg); for (loop = 0; loop < BUFFER_SIZE; ++loop) { buffer[loop] = (char)loop; } VERBOSE(v_whisper, "Creating big file"); file = PR_Open(filename, PR_CREATE_FILE | PR_WRONLY, 0666); if (NULL == file) { return Error("PR_Open()", filename); } VERBOSE(v_whisper, "Testing available space in empty file"); big_answer = file->methods->available64(file); if (!LL_IS_ZERO(big_answer)) { return Error("empty available64()", filename); } LL_SUB(big_size, filesize64, one_meg); VERBOSE(v_whisper, "Creating sparse big file by seeking to end"); big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET); if (!LL_EQ(big_answer, big_size)) { return Error("seek", filename); } VERBOSE(v_whisper, "Writing block at end of sparse file"); bytes = file->methods->write(file, buffer, BUFFER_SIZE); if (bytes != BUFFER_SIZE) { return Error("write", filename); } VERBOSE(v_whisper, "Testing available space at end of sparse file"); big_answer = file->methods->available64(file); if (!LL_IS_ZERO(big_answer)) { return Error("eof available64()", filename); } VERBOSE(v_whisper, "Getting big info on sparse big file"); rv = file->methods->fileInfo64(file, &big_info); if (PR_FAILURE == rv) { return Error("fileInfo64()", filename); } if (v_shout <= verbose) { PrintInfo(&big_info, filename); } VERBOSE(v_whisper, "Getting small info on sparse big file"); rv = file->methods->fileInfo(file, &small_info); if (LL_CMP(sevenFox, <, filesize64) && (PR_SUCCESS == rv)) { VERBOSE(v_whisper, "Should have failed and didn't"); return Error("fileInfo()", filename); } else if (LL_CMP(sevenFox, >, filesize64) && (PR_FAILURE == rv)) { VERBOSE(v_whisper, "Should have succeeded and didn't"); return Error("fileInfo()", filename); } VERBOSE(v_whisper, "Rewinding big file"); big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); if (!LL_IS_ZERO(big_answer)) { return Error("rewind seek64()", filename); } VERBOSE(v_whisper, "Establishing available space in rewound file"); big_answer = file->methods->available64(file); if (LL_NE(filesize64, big_answer)) { return Error("bof available64()", filename); } VERBOSE(v_whisper, "Closing big file"); rv = file->methods->close(file); if (PR_FAILURE == rv) { return Error("close()", filename); } VERBOSE(v_whisper, "Reopening big file"); file = PR_Open(filename, PR_RDWR, 0666); if (NULL == file) { return Error("open failed", filename); } VERBOSE(v_whisper, "Checking available data in reopened file"); big_answer = file->methods->available64(file); if (LL_NE(filesize64, big_answer)) { return Error("reopened available64()", filename); } big_answer = zero_meg; VERBOSE(v_whisper, "Rewriting every byte of big file data"); do { bytes = file->methods->write(file, buffer, BUFFER_SIZE); if (bytes != BUFFER_SIZE) { return Error("write", filename); } LL_ADD(big_answer, big_answer, big_fragment); } while (LL_CMP(big_answer, <, filesize64)); VERBOSE(v_whisper, "Checking position at eof"); big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_CUR); if (LL_NE(big_answer, filesize64)) { return Error("file size error", filename); } VERBOSE(v_whisper, "Testing available space at eof"); big_answer = file->methods->available64(file); if (!LL_IS_ZERO(big_answer)) { return Error("eof available64()", filename); } VERBOSE(v_whisper, "Rewinding full file"); big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); if (!LL_IS_ZERO(big_answer)) { return Error("bof seek64()", filename); } VERBOSE(v_whisper, "Testing available space in rewound file"); big_answer = file->methods->available64(file); if (LL_NE(big_answer, filesize64)) { return Error("bof available64()", filename); } VERBOSE(v_whisper, "Seeking to end of big file"); big_answer = file->methods->seek64(file, filesize64, PR_SEEK_SET); if (LL_NE(big_answer, filesize64)) { return Error("eof seek64()", filename); } VERBOSE(v_whisper, "Getting info on big file while it's open"); rv = file->methods->fileInfo64(file, &big_info); if (PR_FAILURE == rv) { return Error("fileInfo64()", filename); } if (v_shout <= verbose) { PrintInfo(&big_info, filename); } VERBOSE(v_whisper, "Closing big file"); rv = file->methods->close(file); if (PR_FAILURE == rv) { return Error("close()", filename); } VERBOSE(v_whisper, "Getting info on big file after it's closed"); rv = PR_GetFileInfo64(filename, &big_info); if (PR_FAILURE == rv) { return Error("fileInfo64()", filename); } if (v_shout <= verbose) { PrintInfo(&big_info, filename); } VERBOSE(v_whisper, "Deleting big file"); rv = PR_Delete(filename); if (PR_FAILURE == rv) { return Error("PR_Delete()", filename); } PR_DELETE(buffer); return test_result; } /* main */ /* bigfile.c */