1#include <fcntl.h> 2#include <sys/types.h> 3#ifdef OS2 4#define INCL_DOSFILEMGR 5#include <os2.h> 6#else 7#include <dirent.h> 8#include <unistd.h> 9#endif 10#include <string.h> 11#include <stdlib.h> 12#include <sys/stat.h> 13 14#include "bon_file.h" 15#include "bon_time.h" 16 17CPCCHAR rand_chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 18 19 20COpenTest::COpenTest(int chunk_size, bool use_sync, bool *doExit) 21 : m_chunk_size(chunk_size) 22 , m_number(0) 23 , m_number_directories(1) 24 , m_max(0) 25 , m_min(0) 26 , m_size_range(0) 27 , m_dirname(NULL) 28 , m_file_name_buf(NULL) 29 , m_file_names(NULL) 30 , m_sync(use_sync) 31 , m_directoryHandles(NULL) 32 , m_dirIndex(NULL) 33 , m_buf(new char[m_chunk_size]) 34 , m_exit(doExit) 35 , m_sync_dir(true) 36{ 37} 38 39void COpenTest::random_sort() 40{ 41 for(int i = 0; i < m_number; i++) 42 { 43 char *tmp = m_file_names[i]; 44 int newind = rand() % m_number; 45 m_file_names[i] = m_file_names[newind]; 46 m_file_names[newind] = tmp; 47 if(m_dirIndex) 48 { 49 int tmpInd = m_dirIndex[i]; 50 m_dirIndex[i] = m_dirIndex[newind]; 51 m_dirIndex[newind] = tmpInd; 52 } 53 if(*m_exit) return; 54 } 55} 56 57COpenTest::~COpenTest() 58{ 59 int i; 60 if(m_dirname) 61 { 62 fprintf(stderr, "Cleaning up test directory after error.\n"); 63 if(m_file_names) 64 { 65 for(i = 0; i < m_number; i++) 66 unlink(m_file_names[i]); 67 } 68 if(m_number_directories > 1) 69 { 70 char buf[6]; 71 for(i = 0; i < m_number_directories; i++) 72 { 73 sprintf(buf, "%05d", i); 74 if(rmdir(buf)) 75 io_error("rmdir"); 76 } 77 } 78 if(chdir("..") || rmdir(m_dirname)) 79 io_error("rmdir"); 80 delete m_dirname; 81 } 82 if(m_directoryHandles) 83 { 84 for(i = 0; i < m_number_directories; i++) 85 close(m_directoryHandles[i]); 86 delete m_directoryHandles; 87 } 88 delete m_file_name_buf; 89 delete m_file_names; 90 delete m_dirIndex; 91 delete m_buf; 92} 93 94void COpenTest::make_names(bool do_random) 95{ 96 delete m_file_name_buf; 97 delete m_file_names; 98 int names_per_directory = m_number / m_number_directories; 99 int names_in_dir = 0; 100 int directory_num = 0; 101 if(!m_dirIndex && m_sync) 102 m_dirIndex = new int[m_number]; 103 if(m_number_directories == 1) 104 { 105 m_file_name_buf = new char[(MaxNameLen + 1) * m_number]; 106 } 107 else 108 { 109 m_file_name_buf = new char[(MaxNameLen + 1 + 6) * m_number]; 110 } 111 m_file_names = new PCHAR[m_number]; 112 PCHAR buf = m_file_name_buf; 113 for(int i = 0; i < m_number; i++) 114 { 115 if(*m_exit) 116 { 117 delete m_file_names; 118 m_file_names = NULL; 119 return; 120 } 121 char rand_buf[RandExtraLen + 1]; 122 int len = rand() % (RandExtraLen + 1); 123 int j; 124 for(j = 0; j < len; j++) 125 { 126 rand_buf[j] = rand_chars[rand() % strlen(rand_chars)]; 127 } 128 rand_buf[j] = '\0'; 129 m_file_names[i] = buf; 130 if(m_number_directories != 1) 131 { 132 sprintf(buf, "%05d/", directory_num); 133 buf += strlen(buf); 134 } 135 if(m_sync) 136 m_dirIndex[i] = directory_num; 137 names_in_dir++; 138 if(names_in_dir > names_per_directory) 139 { 140 names_in_dir = 0; 141 directory_num++; 142 } 143 if(do_random) 144 { 145 sprintf(buf, "%s%07d", rand_buf, i); 146 } 147 else 148 { 149 sprintf(buf, "%07d%s", i, rand_buf); 150 } 151 buf += strlen(buf) + 1; 152 } 153} 154 155int COpenTest::create_a_file(const char *filename, char *buf, int size, int dir) 156{ 157 FILE_TYPE fd = 0; 158#ifdef OS2 159 ULONG action = 0; 160 ULONG rc = DosOpen(filename, &fd, &action, 0, FILE_NORMAL 161 , OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS 162 , OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE 163 , NULL); 164#else 165 fd = creat(filename, S_IRUSR | S_IWUSR); 166#endif 167 if(fd == -1) 168 { 169 fprintf(stderr, "Can't create file %s\n", filename); 170 return -1; 171 } 172 if(m_max) 173 { 174 for(int i = 0; i < size; i += m_chunk_size) 175 { 176 int to_write = size - i; 177 if(to_write > m_chunk_size) to_write = m_chunk_size; 178#ifdef OS2 179 ULONG actual = 0; 180 if(DosWrite(fd, PVOID(buf), to_write, &actual)) 181 { 182 fprintf(stderr, "Can't write data.\n"); 183 return -1; 184 } 185#else 186 if(to_write != write(fd, static_cast<void *>(buf), to_write)) 187 { 188 fprintf(stderr, "Can't write data.\n"); 189 return -1; 190 } 191#endif 192 } 193 } 194 if(m_sync) 195 { 196 if(fsync(fd)) 197 { 198 fprintf(stderr, "Can't sync file.\n"); 199 return -1; 200 } 201 if(m_sync_dir && fsync(m_directoryHandles[dir])) 202 { 203 fprintf(stderr, "Can't sync directory, turning off dir-sync.\n"); 204 m_sync_dir = false; 205 } 206 } 207 file_close(fd); 208 return 0; 209} 210 211int COpenTest::create_a_link(const char *original, const char *filename, int dir) 212{ 213#ifdef OS2 214 fprintf(stderr, "Not supported on OS/2\n"); 215 return -1; 216#else 217 if(m_max == -1) 218 { 219 if(link(original, filename)) 220 { 221 fprintf(stderr, "Can't create link %s\n", filename); 222 return -1; 223 } 224 if(m_sync) 225 { 226 if(fsync(m_directoryHandles[dir])) 227 { 228 fprintf(stderr, "Can't sync file.\n"); 229 return -1; 230 } 231 } 232 } 233 else 234 { 235 if(symlink(original, filename)) 236 { 237 fprintf(stderr, "Can't create symlink %s\n", filename); 238 return -1; 239 } 240 if(m_sync) 241 { 242 if(fsync(m_directoryHandles[dir])) 243 { 244 fprintf(stderr, "Can't sync file.\n"); 245 return -1; 246 } 247 } 248 } 249 return 0; 250#endif 251} 252 253int COpenTest::create(CPCCHAR dirname, BonTimer &timer, int num, int max_size 254 , int min_size, int num_directories, bool do_random) 255{ 256 if(num_directories >= 100000) 257 { 258 fprintf(stderr, "Can't have more than 99,999 directories.\n"); 259 return -1; 260 } 261 262 m_number = num * DirectoryUnit; 263 m_number_directories = num_directories; 264 make_names(do_random); 265 m_max = max_size; 266 m_min = min_size; 267 m_size_range = m_max - m_min; 268 m_dirname = new char[strlen(dirname) + 1]; 269 strcpy(m_dirname, dirname); 270 271 if(make_directory(dirname)) 272 { 273 fprintf(stderr, "Can't make directory %s\n", dirname); 274 return -1; 275 } 276 if(chdir(dirname)) 277 { 278 fprintf(stderr, "Can't change to directory %s\n", dirname); 279 return -1; 280 } 281 int i; 282 if(m_sync) 283 m_directoryHandles = new FILE_TYPE[num_directories]; 284 if(num_directories > 1) 285 { 286 for(i = 0; i < num_directories; i++) 287 { 288 sprintf(m_buf, "%05d", i); 289 if(make_directory(m_buf)) 290 { 291 fprintf(stderr, "Can't make directory %s\n", m_buf); 292 return -1; 293 } 294 if(m_sync) 295 { 296 m_directoryHandles[i] = open(m_buf, O_RDONLY); 297 if(m_directoryHandles[i] == -1) 298 { 299 fprintf(stderr, "Can't get directory handle.\n"); 300 return -1; 301 } 302 } 303 } 304 } 305 else if(m_sync) 306 { 307 m_directoryHandles[0] = open(".", O_RDONLY); 308 if(m_directoryHandles[0] == -1) 309 { 310 fprintf(stderr, "Can't get directory handle.\n"); 311 return -1; 312 } 313 } 314 315 timer.timestamp(); 316 for(i = 0; i < m_number; i++) 317 { 318 if(*m_exit) 319 { 320 return EXIT_CTRL_C; 321 } 322 // m_max < 0 means link or sym-link 323 if(m_max < 0) 324 { 325 if(i == 0) 326 { 327 if(create_a_file(m_file_names[0], m_buf, 0, m_dirIndex ? m_dirIndex[0] : 0)) 328 return -1; 329 } 330 else 331 { 332 // create_a_link() looks at m_max to see what to do 333 if(create_a_link(m_file_names[0], m_file_names[i], m_dirIndex ? m_dirIndex[i] : 0)) 334 return -1; 335 } 336 } 337 else 338 { 339 int size; 340 if(m_size_range) 341 size = m_min + (rand() % (m_size_range + 1)); 342 else 343 size = m_max; 344 if(create_a_file(m_file_names[i], m_buf, size, m_dirIndex ? m_dirIndex[i] : 0)) 345 return -1; 346 } 347 } 348 timer.get_delta_t(do_random ? CreateRand : CreateSeq); 349 return 0; 350} 351 352int COpenTest::delete_random(BonTimer &timer) 353{ 354 random_sort(); 355 timer.timestamp(); 356 int i; 357 for(i = 0; i < m_number; i++) 358 { 359 if(unlink(m_file_names[i])) 360 { 361 fprintf(stderr, "Can't delete file %s\n", m_file_names[i]); 362 return -1; 363 } 364 if(m_sync && m_sync_dir) 365 { 366 if(fsync(m_directoryHandles[m_dirIndex[i]])) 367 { 368 fprintf(stderr, "Can't sync directory, turning off dir-sync.\n"); 369 m_sync_dir = false; 370 } 371 } 372 } 373 if(m_number_directories > 1) 374 { 375 char buf[6]; 376 for(i = 0; i < m_number_directories; i++) 377 { 378 sprintf(buf, "%05d", i); 379 if(m_sync) 380 { 381 close(m_directoryHandles[i]); 382 } 383 if(rmdir(buf)) 384 { 385 io_error("rmdir"); 386 return -1; 387 } 388 } 389 } 390 else 391 { 392 if(m_sync) 393 { 394 close(m_directoryHandles[0]); 395 } 396 } 397 if(chdir("..") || rmdir(m_dirname)) 398 { 399 io_error("rmdir"); 400 return -1; 401 } 402 delete m_dirname; 403 m_dirname = NULL; 404 timer.get_delta_t(DelRand); 405 return 0; 406} 407 408int COpenTest::delete_sequential(BonTimer &timer) 409{ 410 timer.timestamp(); 411 int count = 0; 412 for(int i = 0; i < m_number_directories; i++) 413 { 414 char buf[6]; 415 if(m_number_directories != 1) 416 { 417 sprintf(buf, "%05d", i); 418 if(chdir(buf)) 419 { 420 fprintf(stderr, "Can't change to directory %s\n", buf); 421 return -1; 422 } 423 } 424#ifdef OS2 425 HDIR d = 0; 426 ULONG entries = 1; 427 FILEFINDBUF3 findBuf; 428 ULONG rc = DosFindFirst("*", &d 429 , FILE_ARCHIVED | FILE_SYSTEM | FILE_HIDDEN | FILE_READONLY 430 , &findBuf, sizeof(findBuf), &entries, FIL_STANDARD); 431 if(rc || !entries) 432 { 433 fprintf(stderr, "Can't open directory.\n"); 434 return -1; 435 } 436 do 437 { 438 if(unlink(findBuf.achName)) 439 { 440 fprintf(stderr, "Can't delete file %s\n", findBuf.achName); 441 DosFindClose(d); 442 return -1; 443 } 444 count++; 445 rc = DosFindNext(d, &findBuf, sizeof(findBuf), &entries); 446 } while(!rc && entries == 1); 447 DosFindClose(d); 448#else 449 DIR *d = opendir("."); 450 if(!d) 451 { 452 fprintf(stderr, "Can't open directory.\n"); 453 return -1; 454 } 455 dirent *file_ent; 456 457 while((file_ent = readdir(d)) != NULL) 458 { 459 if(file_ent->d_name[0] != '.') 460 { 461 if(unlink(file_ent->d_name)) 462 { 463 fprintf(stderr, "Can't delete file %s\n", file_ent->d_name); 464 return -1; 465 } 466 467 468 if(m_sync && m_sync_dir) 469 { 470 if(fsync(m_directoryHandles[i])) 471 { 472 fprintf(stderr, "Can't sync directory, turning off dir-sync.\n"); 473 m_sync_dir = false; 474 } 475 } 476 count++; 477 } 478 } 479 closedir(d); 480#endif 481 if(m_sync) 482 { 483 close(m_directoryHandles[i]); 484 } 485 if(m_number_directories != 1) 486 { 487 if(chdir("..") || rmdir(buf)) 488 { 489 io_error("rmdir"); 490 return -1; 491 } 492 } 493 } 494 if(chdir("..") || rmdir(m_dirname)) 495 { 496 io_error("rmdir"); 497 return -1; 498 } 499 delete m_dirname; 500 m_dirname = NULL; 501 if(count != m_number) 502 { 503 fprintf(stderr, "Expected %d files but only got %d\n", m_number, count); 504 return -1; 505 } 506 timer.get_delta_t(DelSeq); 507 return 0; 508} 509 510int COpenTest::stat_file(CPCCHAR file) 511{ 512 struct stat st; 513 if(stat(file, &st)) 514 { 515 fprintf(stderr, "Can't stat file %s\n", file); 516 return -1; 517 } 518 if(st.st_size) 519 { 520 FILE_TYPE fd = 0; 521#ifdef OS2 522 ULONG action = 0; 523 ULONG rc = DosOpen(file, &fd, &action, 0, FILE_NORMAL 524 , OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS 525 , OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE 526 , NULL); 527 if(rc) 528 fd = -1; 529#else 530 fd = open(file, O_RDONLY); 531#endif 532 if(fd == -1) 533 { 534 fprintf(stderr, "Can't open file %s\n", file); 535 return -1; 536 } 537 for(int i = 0; i < st.st_size; i += m_chunk_size) 538 { 539 int to_read = st.st_size - i; 540 if(to_read > m_chunk_size) to_read = m_chunk_size; 541#ifdef OS2 542 ULONG actual = 0; 543 rc = DosRead(fd, PVOID(m_buf), to_read, &actual); 544 if(to_read != actual || rc) 545#else 546 if(to_read != read(fd, static_cast<void *>(m_buf), to_read)) 547#endif 548 { 549 fprintf(stderr, "Can't read data.\n"); 550 return -1; 551 } 552 } 553 file_close(fd); 554 } 555 return 0; 556} 557 558int COpenTest::stat_random(BonTimer &timer) 559{ 560 random_sort(); 561 timer.timestamp(); 562 563 int i; 564 for(i = 0; i < m_number; i++) 565 { 566 if(-1 == stat_file(m_file_names[i])) 567 return -1; 568 } 569 timer.get_delta_t(StatRand); 570 return 0; 571} 572 573int COpenTest::stat_sequential(BonTimer &timer) 574{ 575 timer.timestamp(); 576 int count = 0; 577 for(int i = 0; i < m_number_directories; i++) 578 { 579 char buf[6]; 580 if(m_number_directories != 1) 581 { 582 sprintf(buf, "%05d", i); 583 if(chdir(buf)) 584 { 585 fprintf(stderr, "Can't change to directory %s\n", buf); 586 return -1; 587 } 588 } 589#ifdef OS2 590 HDIR d = 0; 591 ULONG entries = 1; 592 FILEFINDBUF3 findBuf; 593 ULONG rc = DosFindFirst("*", &d 594 , FILE_ARCHIVED | FILE_SYSTEM | FILE_HIDDEN | FILE_READONLY 595 , &findBuf, sizeof(findBuf), &entries, FIL_STANDARD); 596 if(rc || !entries) 597 { 598 fprintf(stderr, "Can't open directory.\n"); 599 if(m_number_directories != 1) 600 { 601 if(chdir("..")) 602 fprintf(stderr, "Can't chdir().\n"); 603 } 604 return -1; 605 } 606 do 607 { 608 if(*m_exit) 609 { 610 return EXIT_CTRL_C; 611 } 612 if(findBuf.achName[0] != '.') // our files do not start with a dot 613 { 614 if(-1 == stat_file(findBuf.achName)) 615 { 616 if(m_number_directories != 1) 617 { 618 if(chdir("..")) 619 fprintf(stderr, "Can't chdir().\n"); 620 } 621 return -1; 622 } 623 count++; 624 } 625 rc = DosFindNext(d, &findBuf, sizeof(findBuf), &entries); 626 } while(!rc && entries == 1); 627 DosFindClose(d); 628#else 629 DIR *d = opendir("."); 630 if(!d) 631 { 632 fprintf(stderr, "Can't open directory.\n"); 633 if(m_number_directories != 1) 634 { 635 if(chdir("..")) 636 fprintf(stderr, "Can't chdir().\n"); 637 } 638 return -1; 639 } 640 dirent *file_ent; 641 while((file_ent = readdir(d)) != NULL) 642 { 643 if(*m_exit) 644 { 645 if(m_number_directories != 1 && chdir("..")) 646 { 647 fprintf(stderr, "Can't change to directory ..\n"); 648 return -1; 649 } 650 return EXIT_CTRL_C; 651 } 652 if(file_ent->d_name[0] != '.') // our files do not start with a dot 653 { 654 if(-1 == stat_file(file_ent->d_name)) 655 { 656 if(m_number_directories != 1) 657 { 658 if(chdir("..")) 659 fprintf(stderr, "Can't chdir().\n"); 660 } 661 return -1; 662 } 663 count++; 664 } 665 } 666 closedir(d); 667#endif 668 if(m_number_directories != 1 && chdir("..")) 669 { 670 fprintf(stderr, "Can't change to directory ..\n"); 671 return -1; 672 } 673 } 674 if(count != m_number) 675 { 676 fprintf(stderr, "Expected %d files but only got %d\n", m_number, count); 677 return -1; 678 } 679 timer.get_delta_t(StatSeq); 680 return 0; 681} 682 683