Back to index

lightning-sunbird  0.9+nobinonly
bigfile.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "prio.h"
00039 #include "prmem.h"
00040 #include "prprf.h"
00041 #include "prinit.h"
00042 #include "prerror.h"
00043 #include "prthread.h"
00044 
00045 #include "plerror.h"
00046 #include "plgetopt.h"
00047 
00048 #define DEFAULT_COUNT 10
00049 #define DEFAULT_FILESIZE 1
00050 #define BUFFER_SIZE 1000000
00051 
00052 typedef enum {v_silent, v_whisper, v_shout} Verbosity;
00053 static void Verbose(Verbosity, const char*, const char*, PRIntn);
00054 
00055 #define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__)
00056 
00057 static PRIntn test_result = 2;
00058 static PRFileDesc *output = NULL;
00059 static PRIntn verbose = v_silent;
00060 static PRIntn filesize = DEFAULT_FILESIZE;
00061 
00062 static PRIntn Usage(void)
00063 {
00064     PR_fprintf(output, "Bigfile test usage:\n");
00065     PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s <n>] <filename>\n");
00066     PR_fprintf(output, "\td\tdebug mode (equivalent to -vvv)\t(false)\n");
00067     PR_fprintf(output, "\tv\tAdditional levels of output\t(none)\n");
00068     PR_fprintf(output, "\tk\tKeep data file after exit\t(false)\n");
00069     PR_fprintf(output, "\ts <n>\tFile size in megabytes\t\t(1 megabyte)\n");
00070     PR_fprintf(output, "\t<filename>\tName of test file\t(none)\n");
00071     return 2;  /* nothing happened */
00072 }  /* Usage */
00073 
00074 static PRStatus DeleteIfFound(const char *filename)
00075 {
00076     PRStatus rv;
00077     VERBOSE(v_shout, "Checking for existing file");
00078     rv = PR_Access(filename, PR_ACCESS_WRITE_OK);
00079     if (PR_SUCCESS == rv)
00080     {
00081         VERBOSE(v_shout, "Deleting existing file");
00082         rv = PR_Delete(filename);
00083         if (PR_FAILURE == rv) VERBOSE(v_shout, "Cannot delete big file");
00084     }
00085     else if (PR_FILE_NOT_FOUND_ERROR !=  PR_GetError())
00086         VERBOSE(v_shout, "Cannot access big file");
00087     else rv = PR_SUCCESS;
00088     return rv;
00089 }  /* DeleteIfFound */
00090 
00091 static PRIntn Error(const char *msg, const char *filename)
00092 {
00093     PRInt32 error = PR_GetError();
00094     if (NULL != msg)
00095     {
00096         if (0 == error) PR_fprintf(output, msg);
00097         else PL_FPrintError(output, msg);
00098     }
00099     (void)DeleteIfFound(filename);
00100     if (v_shout == verbose) PR_Abort();
00101     return 1;
00102 }  /* Error */
00103 
00104 static void Verbose(
00105     Verbosity level, const char *msg, const char *file, PRIntn line)
00106 {
00107     if (level <= verbose)
00108         PR_fprintf(output, "[%s : %d]: %s\n", file, line, msg);
00109 }  /* Verbose */
00110 
00111 static void PrintInfo(PRFileInfo64 *info, const char *filename)
00112 {
00113     PRExplodedTime tm;
00114     char ctime[40], mtime[40];
00115     static const char *types[] = {"FILE", "DIRECTORY", "OTHER"};
00116     PR_fprintf(
00117         output, "[%s : %d]: File info for %s\n",
00118         __FILE__, __LINE__, filename);
00119     PR_fprintf(
00120         output, "    type: %s, size: %llu bytes,\n",
00121         types[info->type - 1], info->size);
00122 
00123     PR_ExplodeTime(info->creationTime, PR_GMTParameters, &tm);
00124     (void)PR_FormatTime(ctime, sizeof(ctime), "%c GMT", &tm);
00125     PR_ExplodeTime(info->modifyTime, PR_GMTParameters, &tm);
00126     (void)PR_FormatTime(mtime, sizeof(mtime), "%c GMT", &tm);
00127 
00128     PR_fprintf(
00129         output, "    creation: %s,\n    modify: %s\n", ctime, mtime);
00130 }  /* PrintInfo */
00131 
00132 PRIntn main(PRIntn argc, char **argv)
00133 {
00134     PRStatus rv;
00135     char *buffer;
00136     PLOptStatus os;
00137     PRInt32 loop, bytes;
00138     PRFileInfo small_info;
00139     PRFileInfo64 big_info;
00140     PRBool keep = PR_FALSE;
00141     PRFileDesc *file = NULL;
00142     const char *filename = NULL;
00143     PRIntn count = DEFAULT_COUNT;
00144     PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment;
00145     PRInt64 sevenFox = LL_INIT(0,0x7fffffff);
00146 
00147     PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:");
00148 
00149     output = PR_GetSpecialFD(PR_StandardError);
00150     PR_STDIO_INIT();
00151 
00152     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00153     {
00154         if (PL_OPT_BAD == os) continue;
00155         switch (opt->option)
00156         {
00157         case 0:
00158             filename = opt->value;
00159             break;
00160         case 'd':  /* debug mode */
00161             verbose = v_shout;
00162             break;
00163         case 'k':  /* keep file */
00164             keep = PR_TRUE;
00165             break;
00166         case 'v':  /* verbosity */
00167             if (v_shout > verbose) verbose += 1;
00168             break;
00169         case 'c':  /* loop counter */
00170             count = atoi(opt->value);
00171             break;
00172         case 's':  /* filesize */
00173             filesize = atoi(opt->value);
00174             break;
00175         case 'h':  /* confused */
00176         default:
00177             return Usage();
00178         }
00179     }
00180     PL_DestroyOptState(opt);
00181 
00182     if (0 == count) count = DEFAULT_COUNT;
00183     if (0 == filesize) filesize = DEFAULT_FILESIZE;
00184     if (NULL == filename)
00185     {
00186         if (DEFAULT_FILESIZE != filesize) return Usage();
00187         else filename = "bigfile.dat";
00188     }
00189 
00190     if (PR_FAILURE == DeleteIfFound(filename)) return 1;
00191 
00192     test_result = 0;
00193 
00194     LL_I2L(zero_meg, 0);
00195     LL_I2L(one_meg, 1000000);
00196     LL_I2L(filesize64, filesize);
00197     buffer = (char*)PR_MALLOC(BUFFER_SIZE);
00198     LL_I2L(big_fragment, BUFFER_SIZE);
00199     LL_MUL(filesize64, filesize64, one_meg); 
00200 
00201     for (loop = 0; loop < BUFFER_SIZE; ++loop) buffer[loop] = (char)loop;
00202 
00203     VERBOSE(v_whisper, "Creating big file");
00204     file = PR_Open(filename, PR_CREATE_FILE | PR_WRONLY, 0666);
00205     if (NULL == file) return Error("PR_Open()", filename);
00206     
00207     VERBOSE(v_whisper, "Testing available space in empty file");
00208     big_answer = file->methods->available64(file);
00209     if (!LL_IS_ZERO(big_answer)) return Error("empty available64()", filename);
00210 
00211        LL_SUB(big_size, filesize64, one_meg);
00212     VERBOSE(v_whisper, "Creating sparse big file by seeking to end");
00213        big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET);
00214     if (!LL_EQ(big_answer, big_size)) return Error("seek", filename);
00215 
00216     VERBOSE(v_whisper, "Writing block at end of sparse file");
00217        bytes = file->methods->write(file, buffer, BUFFER_SIZE);
00218     if (bytes != BUFFER_SIZE) return Error("write", filename);
00219 
00220     VERBOSE(v_whisper, "Testing available space at end of sparse file");
00221     big_answer = file->methods->available64(file);
00222     if (!LL_IS_ZERO(big_answer)) return Error("eof available64()", filename);
00223 
00224     VERBOSE(v_whisper, "Getting big info on sparse big file");
00225     rv = file->methods->fileInfo64(file, &big_info);
00226     if (PR_FAILURE == rv) return Error("fileInfo64()", filename);
00227     if (v_shout <= verbose) PrintInfo(&big_info, filename);
00228 
00229     VERBOSE(v_whisper, "Getting small info on sparse big file");
00230     rv = file->methods->fileInfo(file, &small_info);
00231     if (LL_CMP(sevenFox, <, filesize64) && (PR_SUCCESS == rv))
00232     {
00233         VERBOSE(v_whisper, "Should have failed and didn't");
00234         return Error("fileInfo()", filename);
00235     }
00236     else if (LL_CMP(sevenFox, >, filesize64) && (PR_FAILURE == rv))
00237     {
00238         VERBOSE(v_whisper, "Should have succeeded and didn't");
00239         return Error("fileInfo()", filename);
00240     }
00241 
00242     VERBOSE(v_whisper, "Rewinding big file");
00243     big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET);
00244     if (!LL_IS_ZERO(big_answer)) return Error("rewind seek64()", filename);
00245 
00246     VERBOSE(v_whisper, "Establishing available space in rewound file");
00247     big_answer = file->methods->available64(file);
00248     if (LL_NE(filesize64, big_answer))
00249         return Error("bof available64()", filename);
00250 
00251     VERBOSE(v_whisper, "Closing big file");
00252     rv = file->methods->close(file);
00253     if (PR_FAILURE == rv) return Error("close()", filename);
00254 
00255     VERBOSE(v_whisper, "Reopening big file");
00256     file = PR_Open(filename, PR_RDWR, 0666);
00257     if (NULL == file) return Error("open failed", filename);
00258 
00259     VERBOSE(v_whisper, "Checking available data in reopened file");
00260     big_answer = file->methods->available64(file);
00261     if (LL_NE(filesize64, big_answer))
00262         return Error("reopened available64()", filename);
00263 
00264     big_answer = zero_meg;
00265     VERBOSE(v_whisper, "Rewriting every byte of big file data");
00266     do
00267     {
00268         bytes = file->methods->write(file, buffer, BUFFER_SIZE);
00269         if (bytes != BUFFER_SIZE)
00270             return Error("write", filename);
00271         LL_ADD(big_answer, big_answer, big_fragment);
00272     } while (LL_CMP(big_answer, <, filesize64));
00273 
00274     VERBOSE(v_whisper, "Checking position at eof");
00275     big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_CUR);
00276     if (LL_NE(big_answer, filesize64))
00277         return Error("file size error", filename);
00278 
00279     VERBOSE(v_whisper, "Testing available space at eof");
00280     big_answer = file->methods->available64(file);
00281     if (!LL_IS_ZERO(big_answer))
00282         return Error("eof available64()", filename);
00283 
00284     VERBOSE(v_whisper, "Rewinding full file");
00285     big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET);
00286     if (!LL_IS_ZERO(big_answer)) return Error("bof seek64()", filename);
00287 
00288     VERBOSE(v_whisper, "Testing available space in rewound file");
00289     big_answer = file->methods->available64(file);
00290     if (LL_NE(big_answer, filesize64)) return Error("bof available64()", filename);
00291 
00292     VERBOSE(v_whisper, "Seeking to end of big file");
00293     big_answer = file->methods->seek64(file, filesize64, PR_SEEK_SET);
00294     if (LL_NE(big_answer, filesize64)) return Error("eof seek64()", filename);
00295 
00296     VERBOSE(v_whisper, "Getting info on big file while it's open");
00297     rv = file->methods->fileInfo64(file, &big_info);
00298     if (PR_FAILURE == rv) return Error("fileInfo64()", filename);
00299     if (v_shout <= verbose) PrintInfo(&big_info, filename);
00300 
00301     VERBOSE(v_whisper, "Closing big file");
00302     rv = file->methods->close(file);
00303     if (PR_FAILURE == rv) return Error("close()", filename);
00304 
00305     VERBOSE(v_whisper, "Getting info on big file after it's closed");
00306     rv = PR_GetFileInfo64(filename, &big_info);
00307     if (PR_FAILURE == rv) return Error("fileInfo64()", filename);
00308     if (v_shout <= verbose) PrintInfo(&big_info, filename);
00309 
00310     VERBOSE(v_whisper, "Deleting big file");
00311     rv = PR_Delete(filename);
00312     if (PR_FAILURE == rv) return Error("PR_Delete()", filename);
00313 
00314     PR_DELETE(buffer);
00315     return test_result;
00316 } /* main */
00317 
00318 /* bigfile.c */