📄 tests.c
字号:
CHECK(fd != -1); actual_size = tests_fill_file(fd, file_size); CHECK(close(fd) != -1); if (file_size != 0 && actual_size == 0) tests_delete_file(file_name); else tests_sync_directory(file_name); return actual_size;}/* Calculate: free_space * numerator / denominator */uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator){ if (denominator == 0) denominator = 1; if (numerator > denominator) numerator = denominator; return numerator * (tests_get_free_space() / denominator);}/* Create file "fragment_n" where n is the file_number, and unlink it */int tests_create_orphan(unsigned file_number){ int fd; int flags; mode_t mode; char file_name[256]; sprintf(file_name, "fragment_%u", file_number); flags = O_CREAT | O_TRUNC | O_RDWR | tests_maybe_sync_flag(); mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; fd = open(file_name, flags, mode); if (fd == -1 && (errno == ENOSPC || errno == EMFILE)) return fd; /* File system full or too many open files */ CHECK(fd != -1); tests_sync_directory(file_name); CHECK(unlink(file_name) != -1); return fd;}/* Write size bytes at offset to the file "fragment_n" where n is the file_number and file_number also determines the random data written i.e. seed for random numbers */unsigned tests_write_fragment_file(unsigned file_number, int fd, off_t offset, unsigned size){ int i, d; uint64_t u; ssize_t written; off_t pos; char buf[WRITE_BUFFER_SIZE]; if (size > WRITE_BUFFER_SIZE) size = WRITE_BUFFER_SIZE; pos = lseek(fd, 0, SEEK_END); CHECK(pos != (off_t) -1); if (offset > pos) offset = pos; pos = lseek(fd, offset, SEEK_SET); CHECK(pos != (off_t) -1); CHECK(pos == offset); srand(file_number); while (offset--) rand(); u = RAND_MAX; u += 1; u /= 256; d = (int) u; for (i = 0; i < size; ++i) buf[i] = rand() / d; written = write(fd, buf, size); if (written <= 0) { CHECK(errno == ENOSPC); /* File system full */ errno = 0; written = 0; } tests_maybe_sync(fd); return (unsigned) written;}/* Write size bytes to the end of file descriptor fd using file_number to determine the random data written i.e. seed for random numbers */unsigned tests_fill_fragment_file(unsigned file_number, int fd, unsigned size){ off_t offset; offset = lseek(fd, 0, SEEK_END); CHECK(offset != (off_t) -1); return tests_write_fragment_file(file_number, fd, offset, size);}/* Write size bytes to the end of file "fragment_n" where n is the file_number and file_number also determines the random data written i.e. seed for random numbers */unsigned tests_append_to_fragment_file(unsigned file_number, unsigned size, int create){ int fd; int flags; mode_t mode; unsigned actual_growth; char file_name[256]; sprintf(file_name, "fragment_%u", file_number); if (create) flags = O_CREAT | O_EXCL | O_WRONLY | tests_maybe_sync_flag(); else flags = O_WRONLY | tests_maybe_sync_flag(); mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; fd = open(file_name, flags, mode); if (fd == -1 && errno == ENOSPC) { errno = 0; return 0; /* File system full */ } CHECK(fd != -1); actual_growth = tests_fill_fragment_file(file_number, fd, size); CHECK(close(fd) != -1); if (create && !actual_growth) tests_delete_fragment_file(file_number); return actual_growth;}/* Write size bytes at offset to the file "fragment_n" where n is the file_number and file_number also determines the random data written i.e. seed for random numbers */unsigned tests_overwite_fragment_file( unsigned file_number, off_t offset, unsigned size){ int fd; unsigned actual_size; char file_name[256]; sprintf(file_name, "fragment_%u", file_number); fd = open(file_name, O_RDWR | tests_maybe_sync_flag()); if (fd == -1 && errno == ENOSPC) { errno = 0; return 0; /* File system full */ } CHECK(fd != -1); actual_size = tests_write_fragment_file(file_number, fd, offset, size); CHECK(close(fd) != -1); return actual_size;}/* Delete file "fragment_n" where n is the file_number */void tests_delete_fragment_file(unsigned file_number){ char file_name[256]; sprintf(file_name, "fragment_%u", file_number); tests_delete_file(file_name);}/* Check the random data in file "fragment_n" is what is expected */void tests_check_fragment_file_fd(unsigned file_number, int fd){ ssize_t sz, i; int d; uint64_t u; char buf[8192]; CHECK(lseek(fd, 0, SEEK_SET) == 0); srand(file_number); u = RAND_MAX; u += 1; u /= 256; d = (int) u; for (;;) { sz = read(fd, buf, 8192); if (sz == 0) break; CHECK(sz >= 0); for (i = 0; i < sz; ++i) CHECK(buf[i] == (char) (rand() / d)); }}/* Check the random data in file "fragment_n" is what is expected */void tests_check_fragment_file(unsigned file_number){ int fd; ssize_t sz, i; int d; uint64_t u; char file_name[256]; char buf[8192]; sprintf(file_name, "fragment_%u", file_number); fd = open(file_name, O_RDONLY); CHECK(fd != -1); srand(file_number); u = RAND_MAX; u += 1; u /= 256; d = (int) u; for (;;) { sz = read(fd, buf, 8192); if (sz == 0) break; CHECK(sz >= 0); for (i = 0; i < sz; ++i) CHECK(buf[i] == (char) (rand() / d)); } CHECK(close(fd) != -1);}/* Central point to decide whether to use fsync */void tests_maybe_sync(int fd){ if (tests_ok_to_sync) CHECK(fsync(fd) != -1);}/* Return O_SYNC if ok to sync otherwise return 0 */int tests_maybe_sync_flag(void){ if (tests_ok_to_sync) return O_SYNC; return 0;}/* Return random number from 0 to n - 1 */size_t tests_random_no(size_t n){ uint64_t a, b; if (!n) return 0; if (n - 1 <= RAND_MAX) { a = rand(); b = RAND_MAX; b += 1; } else { const uint64_t u = 1 + (uint64_t) RAND_MAX; a = rand(); a *= u; a += rand(); b = u * u; CHECK(n <= b); } if (RAND_MAX <= UINT32_MAX && n <= UINT32_MAX) return a * n / b; else /*if (RAND_MAX <= UINT64_MAX && n <= UINT64_MAX)*/ { uint64_t x, y; if (a < n) { x = a; y = n; } else { x = n; y = a; } return (x * (y / b)) + ((x * (y % b)) / b); }}/* Make a directory empty */void tests_clear_dir(const char *dir_name){ DIR *dir; struct dirent *entry; char buf[4096]; dir = opendir(dir_name); CHECK(dir != NULL); CHECK(getcwd(buf, 4096) != NULL); CHECK(chdir(dir_name) != -1); for (;;) { errno = 0; entry = readdir(dir); if (entry) { if (strcmp(".",entry->d_name) != 0 && strcmp("..",entry->d_name) != 0) { if (entry->d_type == DT_DIR) { tests_clear_dir(entry->d_name); CHECK(rmdir(entry->d_name) != -1); } else CHECK(unlink(entry->d_name) != -1); } } else { CHECK(errno == 0); break; } } CHECK(chdir(buf) != -1); CHECK(closedir(dir) != -1);}/* Create an empty sub-directory or small file in the current directory */int64_t tests_create_entry(char *return_name){ int fd; char name[256]; for (;;) { sprintf(name, "%u", (unsigned) tests_random_no(10000000)); fd = open(name, O_RDONLY); if (fd == -1) break; close(fd); } if (return_name) strcpy(return_name, name); if (tests_random_no(2)) { return tests_create_file(name, tests_random_no(4096)); } else { if (mkdir(name, 0777) == -1) { CHECK(errno == ENOSPC); errno = 0; return 0; } return TESTS_EMPTY_DIR_SIZE; }}/* Remove a random file of empty sub-directory from the current directory */int64_t tests_remove_entry(void){ DIR *dir; struct dirent *entry; unsigned count = 0, pos; int64_t result = 0; dir = opendir("."); CHECK(dir != NULL); for (;;) { errno = 0; entry = readdir(dir); if (entry) { if (strcmp(".",entry->d_name) != 0 && strcmp("..",entry->d_name) != 0) ++count; } else { CHECK(errno == 0); break; } } pos = tests_random_no(count); count = 0; rewinddir(dir); for (;;) { errno = 0; entry = readdir(dir); if (!entry) { CHECK(errno == 0); break; } if (strcmp(".",entry->d_name) != 0 && strcmp("..",entry->d_name) != 0) { if (count == pos) { if (entry->d_type == DT_DIR) { tests_clear_dir(entry->d_name); CHECK(rmdir(entry->d_name) != -1); result = TESTS_EMPTY_DIR_SIZE; } else { struct stat st; CHECK(stat(entry->d_name, &st) != -1); result = st.st_size; CHECK(unlink(entry->d_name) != -1); } } ++count; } } CHECK(closedir(dir) != -1); return result;}/* Read mount information from /proc/mounts or /etc/mtab */int tests_get_mount_info(struct mntent *info){ FILE *f; struct mntent *entry; int found = 0; f = fopen("/proc/mounts", "rb"); if (!f) f = fopen("/etc/mtab", "rb"); CHECK(f != NULL); while (!found) { entry = getmntent(f); if (entry) { if (strcmp(entry->mnt_dir, tests_file_system_mount_dir) == 0) { found = 1; *info = *entry; } } else break; } CHECK(fclose(f) == 0); return found;}/* Un-mount and re-mount test file system */void tests_remount(void){ struct mntent mount_info; char *source; char *target; char *filesystemtype; unsigned long mountflags; void *data; char cwd[4096]; CHECK(tests_get_mount_info(&mount_info)); if (strcmp(mount_info.mnt_dir,"/") == 0) return; CHECK(getcwd(cwd, 4096) != NULL); CHECK(chdir("/") != -1); CHECK(umount(tests_file_system_mount_dir) != -1); source = mount_info.mnt_fsname; target = tests_file_system_mount_dir; filesystemtype = tests_file_system_type; mountflags = 0; data = mount_info.mnt_opts; if (data) { if (strcmp(data, "rw") == 0) data = NULL; else if (strncmp(data, "rw,", 3) == 0) data += 3; } CHECK(mount(source, target, filesystemtype, mountflags, data) != -1); CHECK(chdir(cwd) != -1);}/* Un-mount or re-mount test file system */static void tests_mnt(int mnt){ static struct mntent mount_info; char *source; char *target; char *filesystemtype; unsigned long mountflags; void *data; static char cwd[4096]; if (mnt == 0) { CHECK(tests_get_mount_info(&mount_info)); if (strcmp(mount_info.mnt_dir,"/") == 0) return; CHECK(getcwd(cwd, 4096) != NULL); CHECK(chdir("/") != -1); CHECK(umount(tests_file_system_mount_dir) != -1); } else { source = mount_info.mnt_fsname; target = tests_file_system_mount_dir; filesystemtype = tests_file_system_type; mountflags = 0; data = NULL; CHECK(mount(source, target, filesystemtype, mountflags, data) != -1); CHECK(chdir(cwd) != -1); }}/* Unmount test file system */void tests_unmount(void){ tests_mnt(0);}/* Mount test file system */void tests_mount(void){ tests_mnt(1);}/* Check whether the test file system is also the root file system */int tests_fs_is_rootfs(void){ struct stat f_info; struct stat root_f_info; CHECK(stat(tests_file_system_mount_dir, &f_info) != -1); CHECK(stat("/", &root_f_info) != -1); if (f_info.st_dev == root_f_info.st_dev) return 1; else return 0;}/* Try to make a directory empty */void tests_try_to_clear_dir(const char *dir_name){ DIR *dir; struct dirent *entry; char buf[4096]; dir = opendir(dir_name); if (dir == NULL) return; if (getcwd(buf, 4096) == NULL || chdir(dir_name) == -1) { closedir(dir); return; } for (;;) { errno = 0; entry = readdir(dir); if (entry) { if (strcmp(".",entry->d_name) != 0 && strcmp("..",entry->d_name) != 0) { if (entry->d_type == DT_DIR) { tests_try_to_clear_dir(entry->d_name); rmdir(entry->d_name); } else unlink(entry->d_name); } } else { CHECK(errno == 0); break; } } chdir(buf); closedir(dir);}/* Check whether the test file system is also the current file system */int tests_fs_is_currfs(void){ struct stat f_info; struct stat curr_f_info; CHECK(stat(tests_file_system_mount_dir, &f_info) != -1); CHECK(stat(".", &curr_f_info) != -1); if (f_info.st_dev == curr_f_info.st_dev) return 1; else return 0;}#define PID_BUF_SIZE 64/* Concatenate a pid to a string in a signal safe way */void tests_cat_pid(char *buf, const char *name, pid_t pid){ char *p; unsigned x; const char digits[] = "0123456789"; char pid_buf[PID_BUF_SIZE]; x = (unsigned) pid; p = pid_buf + PID_BUF_SIZE; *--p = '\0'; if (x) while (x) { *--p = digits[x % 10]; x /= 10; } else *--p = '0'; buf[0] = '\0'; strcat(buf, name); strcat(buf, p);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -