00001 #include <assert.h>
00002 #include <string.h>
00003 #include <stdlib.h>
00004 #include <time.h>
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include <stdio.h>
00008 #include <limits.h>
00009
00010 #include "FdStream.H"
00011
00012 #include <iostream>
00013 #include <fstream>
00014
00015 #if !defined(__sun__)
00016 extern "C" {
00017 #include <getopt.h>
00018 }
00019 #endif
00020
00021 using std::cout;
00022 using std::cerr;
00023 using std::endl;
00024 using std::ios;
00025 using std::hex;
00026 using std::dec;
00027 using std::ifstream;
00028 using std::fstream;
00029 using FS::IFdStream;
00030 using FS::FdStream;
00031
00032 void print_stream_state(std::ostream &out, unsigned int state)
00033 {
00034 bool first = true;
00035 if(state & ios::eofbit)
00036 {
00037 out << "eof";
00038 state &= ~((unsigned int) ios::eofbit);
00039 first = false;
00040 }
00041 if(state & ios::failbit)
00042 {
00043 if(!first)
00044 out << "|";
00045 out << "fail";
00046 state &= ~((unsigned int) ios::failbit);
00047 first = false;
00048 }
00049 if(state & ios::badbit)
00050 {
00051 if(!first)
00052 out << "|";
00053 out << "bad";
00054 state &= ~((unsigned int) ios::badbit);
00055 first = false;
00056 }
00057 if(state != 0)
00058 {
00059 if(!first)
00060 out << "|";
00061 out << "0x" << hex << state << dec;
00062 }
00063 }
00064
00065 void print_state_if_not_good(const ios &stream,
00066 const char *name, const char *marker)
00067 {
00068 if(!stream.good())
00069 {
00070 cout << name << " state (" << marker << "): ";
00071 print_stream_state(cout, stream.rdstate());
00072 cout << endl;
00073 }
00074 }
00075
00076 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
00077 #define MIN(a, b) (((a) > (b)) ? (b) : (a))
00078
00079 #define MAX_READ_SIZE (BUFSIZ*2)
00080
00081 static bool verbose_read = false, verbose_write = false;
00082
00083 void random_read_test(const char *fname,
00084 unsigned int count)
00085 {
00086 ifstream test_fstream(fname);
00087 IFdStream test_fdstream(fname);
00088
00089 struct stat stat_buf;
00090 if(fstat(test_fdstream.fd(), &stat_buf) != 0)
00091 {
00092 cerr << "fstat of \"" << fname << "\"" << endl;
00093 exit(1);
00094 }
00095
00096 for(unsigned int i = 0; i < count; i++)
00097 {
00098 switch(random() % 2)
00099 {
00100 case 0:
00101
00102
00103 {
00104 char f_buf[MAX_READ_SIZE], fd_buf[MAX_READ_SIZE];
00105
00106 unsigned int rand_read_size = (random() % MAX_READ_SIZE)+1;
00107
00108 if(verbose_read)
00109 cout << "R[" << i << "]: Read " << rand_read_size
00110 << " bytes at offset " << test_fstream.tellg() << endl;
00111
00112 test_fstream.read(f_buf, rand_read_size);
00113 long f_count = test_fstream.gcount();
00114 test_fdstream.read(fd_buf, rand_read_size);
00115 long fd_count = test_fdstream.gcount();
00116 assert(f_count == fd_count);
00117 assert(memcmp(f_buf, fd_buf, f_count) == 0);
00118 }
00119 break;
00120 case 1:
00121 {
00122 unsigned int rand_file_pos = (random() % stat_buf.st_size);
00123
00124 if(verbose_read)
00125 cout << "R[" << i << "]: Seek to " << rand_file_pos
00126 << endl;
00127
00128 test_fstream.seekg(rand_file_pos);
00129 long f_pos = test_fstream.tellg();
00130 test_fdstream.seekg(rand_file_pos);
00131 long fd_pos = test_fdstream.tellg();
00132 assert(f_pos == fd_pos);
00133 }
00134 break;
00135 }
00136 }
00137 }
00138
00139 void compare_files(const char *fname1, const char *fname2)
00140 {
00141 struct stat stat_buf1, stat_buf2;
00142 if(stat(fname1, &stat_buf1) != 0)
00143 {
00144 cerr << "stat of \"" << fname1 << "\"" << endl;
00145 exit(1);
00146 }
00147 if(stat(fname2, &stat_buf2) != 0)
00148 {
00149 cerr << "stat of \"" << fname2 << "\"" << endl;
00150 exit(1);
00151 }
00152 assert(stat_buf1.st_size == stat_buf2.st_size);
00153
00154 ifstream stream1(fname1), stream2(fname2);
00155
00156 while(!stream1.eof())
00157 {
00158 char buf1[MAX_READ_SIZE], buf2[MAX_READ_SIZE];
00159 stream1.read(buf1, MAX_READ_SIZE);
00160 int count1 = stream1.gcount();
00161 stream2.read(buf2, MAX_READ_SIZE);
00162 int count2 = stream2.gcount();
00163 assert(count1 == count2);
00164 if(memcmp(buf1, buf2, count1) != 0)
00165 {
00166 cerr << "Files \"" << fname1 << "\" and \"" << fname2 << "\" differ"
00167 << endl;
00168 for(unsigned int i = 0; i < count1; i++)
00169 {
00170 if(buf1[i] != buf2[i])
00171 {
00172 cerr << "Differences start at offset "
00173 << (((int) stream1.tellg()) - count1 + i) << endl;
00174 abort();
00175 }
00176 }
00177 }
00178 }
00179 assert(stream2.eof());
00180 }
00181
00182 void random_read_write_test(const char *source_fname,
00183 const char *dest_fname_base,
00184 unsigned int count)
00185 {
00186 ifstream source(source_fname);
00187 struct stat stat_buf;
00188 if(stat(source_fname, &stat_buf) != 0)
00189 {
00190 cerr << "stat of \"" << source_fname << "\"" << endl;
00191 exit(1);
00192 }
00193
00194 char fname_buf[FILENAME_MAX];
00195 sprintf(fname_buf, "%s.fstream_rw", dest_fname_base);
00196 char fdname_buf[FILENAME_MAX];
00197 sprintf(fdname_buf, "%s.fdstream_rw", dest_fname_base);
00198
00199 {
00200 fstream test_fstream(fname_buf, ios::in|ios::out|ios::trunc);
00201 FdStream test_fdstream(fdname_buf, ios::in|ios::out|ios::trunc);
00202
00203
00204 unsigned long max_written = 0;
00205
00206
00207 unsigned long current_pos = 0;
00208
00209 enum { op_seek, op_read, op_write } last_op = op_seek;
00210
00211 for(unsigned int i = 0; i < count; i++)
00212 {
00213 bool f_good = test_fstream.good(), fd_good = test_fdstream.good();
00214 if((f_good && !fd_good) || (!f_good && fd_good))
00215 {
00216 cerr << "RW[" << i << "]: only one stream is 'good'" << endl
00217 << " fstream : ";
00218 print_stream_state(cerr, test_fstream.rdstate());
00219 cerr << endl
00220 << " fdstream : ";
00221 print_stream_state(cerr, test_fdstream.rdstate());
00222 cerr << endl;
00223 abort();
00224 }
00225
00226
00227 unsigned int random_op = random() % 3;
00228 switch(random_op)
00229 {
00230 case 0:
00231
00232
00233 {
00234
00235
00236 unsigned long max_read_size =
00237 MIN(MAX_READ_SIZE,
00238 max_written - current_pos);
00239
00240 if(max_read_size > 0)
00241 {
00242 unsigned int rand_read_size = (random() % max_read_size)+1;
00243
00244 if(verbose_write)
00245 cout << "RW[" << i << "]: Read " << rand_read_size
00246 << " bytes at offset " << current_pos
00247 << endl;
00248
00249 char f_buf[MAX_READ_SIZE], fd_buf[MAX_READ_SIZE];
00250
00251 if(last_op == op_write)
00252 test_fstream.seekg(test_fstream.tellg());
00253 test_fstream.read(f_buf, rand_read_size);
00254 int f_count = test_fstream.gcount();
00255 test_fdstream.read(fd_buf, rand_read_size);
00256 int fd_count = test_fdstream.gcount();
00257 assert(f_count == fd_count);
00258 if(memcmp(f_buf, fd_buf, f_count) != 0)
00259 {
00260 cerr << "RW[" << i << "]: " << rand_read_size
00261 << " bytes read at offset " << current_pos
00262 << " don't match."
00263 << endl;
00264 for(unsigned int i = 0; i < f_count; i++)
00265 {
00266 if(f_buf[i] != fd_buf[i])
00267 {
00268 cerr
00269 << "Differences in this read start at offset "
00270 << (current_pos + i)
00271 << ":" << endl
00272 << " fstream[" << (current_pos + i) << "] == "
00273 << hex << (((unsigned int) f_buf[i]) & 0x00ff) << dec << endl
00274 << " fdstream[" << (current_pos + i) << "] == "
00275 << hex << (((unsigned int) fd_buf[i]) & 0x00ff) << dec << endl
00276 << "(Actual differences may start earlier.)"
00277 << endl;
00278 abort();
00279 }
00280 }
00281 }
00282
00283
00284 current_pos += fd_count;
00285
00286 last_op = op_read;
00287
00288 break;
00289 }
00290 }
00291
00292 case 1:
00293 if(max_written > 0)
00294 {
00295
00296 unsigned int rand_file_pos = (random() % max_written);
00297 if(verbose_write)
00298 {
00299 cout << "RW[" << i << "]: Seek to " << rand_file_pos
00300 << endl;
00301 }
00302 test_fstream.seekg(rand_file_pos);
00303 test_fdstream.seekg(rand_file_pos);
00304 test_fstream.seekp(rand_file_pos);
00305 test_fdstream.seekp(rand_file_pos);
00306
00307
00308 current_pos = rand_file_pos;
00309
00310 last_op = op_seek;
00311
00312 break;
00313 }
00314
00315 case 2:
00316 {
00317
00318
00319 char read_buf[MAX_READ_SIZE];
00320
00321 unsigned int rand_read_size = (random() % MAX_READ_SIZE)+1;
00322 unsigned long rand_read_start = (random() %
00323 (stat_buf.st_size - rand_read_size));
00324 source.seekg(rand_read_start);
00325 source.read(read_buf, rand_read_size);
00326 int read_count = source.gcount();
00327
00328 if(verbose_write)
00329 {
00330 cout << "RW[" << i << "]: Write " << read_count
00331 << " bytes from source offset " << rand_read_start
00332 << " at offset " << current_pos << endl;
00333 }
00334
00335 if(last_op == op_read)
00336 test_fstream.seekp(test_fstream.tellp());
00337 test_fstream.write(read_buf, read_count);
00338 test_fdstream.write(read_buf, read_count);
00339
00340
00341 current_pos += read_count;
00342
00343
00344 if(current_pos > max_written)
00345 max_written = current_pos;
00346 }
00347
00348 last_op = op_write;
00349
00350 break;
00351 }
00352
00353
00354
00355
00356
00357 unsigned int random_compare = random() % 2;
00358 switch(random_compare)
00359 {
00360 case 0:
00361 {
00362 if(verbose_write)
00363 cout << "RW[" << i << "]: Check get position" << endl;
00364 unsigned long fd_pos = test_fdstream.tellg();
00365 assert(fd_pos == current_pos);
00366 }
00367 break;
00368 case 1:
00369 {
00370 if(verbose_write)
00371 cout << "RW[" << i << "]: Check put position" << endl;
00372 unsigned long fd_pos = test_fdstream.tellp();
00373 assert(fd_pos == current_pos);
00374 }
00375 break;
00376 }
00377 }
00378 }
00379
00380
00381 compare_files(fname_buf, fdname_buf);
00382 }
00383
00384 int main(int argc, char* argv[])
00385 {
00386 unsigned int seed = time(0);
00387 unsigned int count = 10000;
00388 for (;;)
00389 {
00390 char* slash;
00391 int c = getopt(argc, argv, "s:c:vRW");
00392 if (c == EOF) break;
00393 switch (c)
00394 {
00395 case 's':
00396 seed = strtoul(optarg, NULL, 0);
00397 break;
00398 case 'c':
00399 count = strtoul(optarg, NULL, 0);
00400 break;
00401 case 'v':
00402 verbose_read = true;
00403 verbose_write = true;
00404 break;
00405 case 'R':
00406 verbose_read = true;
00407 break;
00408 case 'W':
00409 verbose_write = true;
00410 break;
00411 }
00412 }
00413
00414 cout << "To reproduce: -s " << seed
00415 << " -c " << count << endl;
00416 srandom(seed);
00417
00418 for(unsigned int i = optind; i < argc; i++)
00419 {
00420 random_read_test(argv[i], count);
00421 random_read_write_test(argv[i],
00422 argv[i],
00423 count);
00424 }
00425
00426 return 0;
00427 }