📄 integck.c
字号:
/* * Copyright (C) 2007 Nokia Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Author: Adrian Hunter */#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <stdint.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <limits.h>#include <dirent.h>#include <sys/mman.h>#include "tests.h"/* Structures to store data written to the test file system, so that we can check whether the file system is correct. */struct write_info /* Record of random data written into a file */{ struct write_info *next; off_t offset; /* Where in the file the data was written */ size_t size; /* Number of bytes written */ unsigned random_seed; /* Seed for rand() to create random data */ off_t random_offset; /* Call rand() this number of times first */ int trunc; /* Records a truncation (raw_writes only) */};struct dir_entry_info;struct file_info /* Each file has one of these */{ char *name; /* Original name */ struct write_info *writes; /* Record accumulated writes to the file */ struct write_info *raw_writes; /* Record in order all writes to the file */ struct fd_info *fds; /* All open file descriptors for this file */ struct dir_entry_info *links; int link_count; off_t length; int deleted; /* File has been deleted but is still open */ int no_space_error; /* File has incurred a ENOSPC error */ uint64_t check_run_no; /* Run number used when checking */};struct symlink_info /* Each symlink has one of these */{ char *target_pathname; struct dir_entry_info *entry; /* dir entry of this symlink */};struct dir_info /* Each directory has one of these */{ char *name; struct dir_info *parent; /* Parent directory or null for our top directory */ unsigned number_of_entries; struct dir_entry_info *first; struct dir_entry_info *entry; /* Dir entry of this dir */};struct dir_entry_info /* Each entry in a directory has one of these */{ struct dir_entry_info *next; /* List of entries in directory */ struct dir_entry_info *prev; /* List of entries in directory */ struct dir_entry_info *next_link; /* List of hard links for same file */ struct dir_entry_info *prev_link; /* List of hard links for same file */ char *name; struct dir_info *parent; /* Parent directory */ char type; /* f => file, d => dir, s => symlink */ int checked; /* Temporary flag used when checking */ union entry_ { struct file_info *file; struct dir_info *dir; struct symlink_info *symlink; void *target; } entry;};struct fd_info /* We keep a number of files open */{ struct fd_info *next; struct file_info *file; int fd;};struct open_file_info /* We keep a list of open files */{ struct open_file_info *next; struct fd_info *fdi;};static struct dir_info *top_dir = NULL; /* Our top directory */static struct open_file_info *open_files = NULL; /* We keep a list of open files */static size_t open_files_count = 0;static int grow = 1; /* Should we try to grow files and directories */static int shrink = 0; /* Should we try to shrink files and directories */static int full = 0; /* Flag that the file system is full */static uint64_t operation_count = 0; /* Number of operations used to fill up the file system */static uint64_t initial_free_space = 0; /* Free space on file system when test starts */static unsigned log10_initial_free_space = 0; /* log10 of initial_free_space */static int check_nospc_files = 0; /* Also check data in files that incurred a "no space" error */static int can_mmap = 0; /* Can write via mmap */static long mem_page_size; /* Page size for mmap */static uint64_t check_run_no;static char *copy_string(const char *s){ char *str; if (!s) return NULL; str = (char *) malloc(strlen(s) + 1); CHECK(str != NULL); strcpy(str, s); return str;}static char *cat_strings(const char *a, const char *b){ char *str; size_t sz; if (a && !b) return copy_string(a); if (b && !a) return copy_string(b); if (!a && !b) return NULL; sz = strlen(a) + strlen(b) + 1; str = (char *) malloc(sz); CHECK(str != NULL); strcpy(str, a); strcat(str, b); return str;}static char *cat_paths(const char *a, const char *b){ char *str; size_t sz; int as, bs; size_t na, nb; if (a && !b) return copy_string(a); if (b && !a) return copy_string(b); if (!a && !b) return NULL; as = 0; bs = 0; na = strlen(a); nb = strlen(b); if (na && a[na - 1] == '/') as = 1; if (nb && b[0] == '/') bs = 1; if ((as && !bs) || (!as && bs)) return cat_strings(a, b); if (as && bs) return cat_strings(a, b + 1); sz = na + nb + 2; str = (char *) malloc(sz); CHECK(str != NULL); strcpy(str, a); strcat(str, "/"); strcat(str, b); return str;}static char *dir_path(struct dir_info *parent, const char *name){ char *parent_path; char *path; if (!parent) return cat_paths(tests_file_system_mount_dir, name); parent_path = dir_path(parent->parent, parent->name); path = cat_paths(parent_path, name); free(parent_path); return path;}static void open_file_add(struct fd_info *fdi){ struct open_file_info *ofi; size_t sz; sz = sizeof(struct open_file_info); ofi = (struct open_file_info *) malloc(sz); CHECK(ofi != NULL); memset(ofi, 0, sz); ofi->next = open_files; ofi->fdi = fdi; open_files = ofi; open_files_count += 1;}static void open_file_remove(struct fd_info *fdi){ struct open_file_info *ofi; struct open_file_info **prev; prev = &open_files; for (ofi = open_files; ofi; ofi = ofi->next) { if (ofi->fdi == fdi) { *prev = ofi->next; free(ofi); open_files_count -= 1; return; } prev = &ofi->next; } CHECK(0); /* We are trying to remove something that is not there */}static struct fd_info *add_fd(struct file_info *file, int fd){ struct fd_info *fdi; size_t sz; sz = sizeof(struct fd_info); fdi = (struct fd_info *) malloc(sz); CHECK(fdi != NULL); memset(fdi, 0, sz); fdi->next = file->fds; fdi->file = file; fdi->fd = fd; file->fds = fdi; open_file_add(fdi); return fdi;}static void add_dir_entry(struct dir_info *parent, char type, const char *name, void *target){ struct dir_entry_info *entry; size_t sz; sz = sizeof(struct dir_entry_info); entry = (struct dir_entry_info *) malloc(sz); CHECK(entry != NULL); memset(entry, 0, sz); entry->type = type; entry->name = copy_string(name); entry->parent = parent; entry->next = parent->first; if (parent->first) parent->first->prev = entry; parent->first = entry; parent->number_of_entries += 1; if (entry->type == 'f') { struct file_info *file = target; entry->entry.file = file; entry->next_link = file->links; if (file->links) file->links->prev_link = entry; file->links = entry; file->link_count += 1; } else if (entry->type == 'd') { struct dir_info *dir = target; entry->entry.dir = dir; dir->entry = entry; dir->name = copy_string(name); dir->parent = parent; } else if (entry->type == 's') { struct symlink_info *symlink = target; entry->entry.symlink = symlink; symlink->entry = entry; }}static void remove_dir_entry(struct dir_entry_info *entry){ entry->parent->number_of_entries -= 1; if (entry->parent->first == entry) entry->parent->first = entry->next; if (entry->prev) entry->prev->next = entry->next; if (entry->next) entry->next->prev = entry->prev; if (entry->type == 'f') { struct file_info *file = entry->entry.file; if (entry->prev_link) entry->prev_link->next_link = entry->next_link; if (entry->next_link) entry->next_link->prev_link = entry->prev_link; if (file->links == entry) file->links = entry->next_link; file->link_count -= 1; if (file->link_count == 0) file->deleted = 1; } free(entry->name); free(entry);}static struct dir_info *dir_new(struct dir_info *parent, const char *name){ struct dir_info *dir; size_t sz; char *path; path = dir_path(parent, name); if (mkdir(path, 0777) == -1) { CHECK(errno == ENOSPC); full = 1; free(path); return NULL; } free(path); sz = sizeof(struct dir_info); dir = (struct dir_info *) malloc(sz); CHECK(dir != NULL); memset(dir, 0, sz); dir->name = copy_string(name); dir->parent = parent; if (parent) add_dir_entry(parent, 'd', name, dir); return dir;}static void file_delete(struct file_info *file);static void file_unlink(struct dir_entry_info *entry);static void symlink_remove(struct symlink_info *symlink);static void dir_remove(struct dir_info *dir){ char *path; /* Remove directory contents */ while (dir->first) { struct dir_entry_info *entry; entry = dir->first; if (entry->type == 'd') dir_remove(entry->entry.dir); else if (entry->type == 'f') file_unlink(entry); else if (entry->type == 's') symlink_remove(entry->entry.symlink); else CHECK(0); /* Invalid struct dir_entry_info */ } /* Remove entry from parent directory */ remove_dir_entry(dir->entry); /* Remove directory itself */ path = dir_path(dir->parent, dir->name); CHECK(rmdir(path) != -1); free(dir);}static struct file_info *file_new(struct dir_info *parent, const char *name){ struct file_info *file = NULL; char *path; mode_t mode; int fd; size_t sz; CHECK(parent != NULL); path = dir_path(parent, name); mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; fd = open(path, O_CREAT | O_EXCL | O_RDWR, mode); if (fd == -1) { CHECK(errno == ENOSPC); free(path); full = 1; return NULL; } free(path); sz = sizeof(struct file_info); file = (struct file_info *) malloc(sz); CHECK(file != NULL); memset(file, 0, sz); file->name = copy_string(name); add_dir_entry(parent, 'f', name, file); add_fd(file, fd); return file;}static void link_new(struct dir_info *parent, const char *name, struct file_info *file){ struct dir_entry_info *entry; char *path, *target; int ret; if (!file) return; entry = file->links; if (!entry) return; path = dir_path(parent, name); target = dir_path(entry->parent, entry->name); ret = link(target, path); if (ret == -1) { CHECK(errno == ENOSPC); free(target); free(path); full = 1; return; } free(target); free(path); add_dir_entry(parent, 'f', name, file);}static void file_close(struct fd_info *fdi);static void file_close_all(struct file_info *file){ struct fd_info *fdi = file->fds; while (fdi) { struct fd_info *next = fdi->next; file_close(fdi); fdi = next; }}static void file_unlink(struct dir_entry_info *entry){ struct file_info *file = entry->entry.file; char *path; path = dir_path(entry->parent, entry->name); /* Remove file entry from parent directory */ remove_dir_entry(entry); /* Unlink the file */ CHECK(unlink(path) != -1); free(path); /* Free struct file_info if file is not open and not linked */ if (!file->fds && !file->links) { struct write_info *w, *next; free(file->name); w = file->writes; while (w) { next = w->next; free(w); w = next; } free(file); } else if (!file->links) file->deleted = 1;}static struct dir_entry_info *pick_entry(struct file_info *file){ struct dir_entry_info *entry; size_t r; if (!file->link_count) return NULL; r = tests_random_no(file->link_count); entry = file->links; while (entry && r--) entry = entry->next_link; return entry;}static void file_unlink_file(struct file_info *file)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -