tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */