📄 tfs_dirs.c
字号:
first_sub_layer); } for (i = first_sub_layer; i <= MAX_SUB_LAYER; i++) { if (front_pnodes[i] == NULL) { continue; } if (write_backlist(front_pnodes[i], backlists[i])) { nse_log_message( "warning: can't write .tfs_backfiles"); print_pnode_path(front_pnodes[i]); } }error: for (i = 0; i <= MAX_SUB_LAYER; i++) { nse_hash_destroy(backhashs[i], (Nse_voidfunc) free, (Nse_voidfunc) NULL); if (ro_pnodes[i] != NULL) { free_pnode(ro_pnodes[i]); } } destroy_backlists(ro_backlists); return (result);}static bool_tbuild_backlist_one_layer(pp, sub_layer, backhashs, backlist) struct pnode *pp; int sub_layer; Hash *backhashs; Nse_list backlist;{ DIR *dirp; struct direct *dp; dirp = tfs_opendir(pp); if (dirp == NULL) { return (FALSE); } dp = readdir(dirp); while (dp != NULL) { if (good_name(dp->d_name)) { (void) add_to_backlist_unique(backlist, backhashs, dp->d_name, 1, sub_layer, 0L); } dp = readdir(dirp); } tfs_closedir(dirp); return (TRUE);}/* * Add the directory with pnode 'pp' to 'backlist'. This routine exists * solely to prevent the runtime stack of build_backlists() from getting * too large in case we have to recurse a number of times. Note that * we always put the directory names of the first read-only layer into the * backlist. These directory names are needed by read_and_verify_backlists() * to determine whether or not a backlist is valid; and by * tfs_set_searchlink() to determine whether or not a new searchlink * is different from the one already set. */static voidadd_dir_to_backlist(pp, backlist) struct pnode *pp; Nse_list backlist;{ char pn[MAXPATHLEN]; ptopn(pp, pn); add_to_backlist(backlist, pn, 1, 0L);}static bool_thave_all_ro_backlists(ro_pnodes, ro_backlists, first_sub_layer) struct pnode **ro_pnodes; Nse_list *ro_backlists; unsigned first_sub_layer;{ int i; for (i = first_sub_layer; i <= MAX_SUB_LAYER; i++) { if (ro_pnodes[i] == NULL || ro_backlists[i] == NULL) { return (FALSE); } } return (TRUE);}/* * Copy entries from backlists in sub-layers of the first read-only layer. */static voidcopy_backlists(backlists, backhashs, ro_backlists, first_sub_layer) Nse_list *backlists; Hash *backhashs; Nse_list *ro_backlists; unsigned first_sub_layer;{ bool_t file_added; int i; file_added = FALSE; for (i = first_sub_layer; i <= MAX_SUB_LAYER; i++) { nse_list_iterate(ro_backlists[i], copy_backlist_entry, backlists[i], backhashs, i, &file_added); }}static voidcopy_backlist_entry(fl, backlist, backhashs, sub_layer, new_file) Filelist fl; Nse_list backlist; Hash *backhashs; int sub_layer; bool_t *new_file;{ if (!IS_DIRNAME(fl)) { if (add_to_backlist_unique(backlist, backhashs, fl->fname, fl->layer + 1, sub_layer, fl->mtime)) { *new_file = TRUE; } } else { if (*new_file) { add_to_backlist(backlist, fl->fname, fl->layer + 1, fl->mtime); } *new_file = FALSE; }}/* * Returns TRUE if 'fname' is added to the backlist; FALSE if the name * is already in the backlist. Note that if 'fname' is in a variant * sub-layer, we must also make sure that 'fname' hasn't been added to * the shared-source backlist. */static bool_tadd_to_backlist_unique(backlist, backhashs, fname, layer, sub_layer, mtime) Nse_list backlist; Hash *backhashs; char *fname; int layer; int sub_layer; long mtime;{ char *file_name; int i; if (sub_layer < MAX_SUB_LAYER) { for (i = MAX_SUB_LAYER; i > sub_layer; i--) { if (nse_hash_lookup(backhashs[i], fname)) { return (FALSE); } } } file_name = NSE_STRDUP(fname); if (nse_hash_insert(backhashs[sub_layer], file_name, HASH_VALUE)) { free(file_name); return (FALSE); } add_to_backlist(backlist, fname, layer, mtime); return (TRUE);}/* * 'backlists' is a list containing backlists for each of the sub-layers. * Convert the file and directory names in the backlists into child vnodes * and directory pnodes for the directory vnode 'pvp'. * 'pp' is the pnode of the last writeable layer. */static voidreaddir_backlists(pvp, pp, backlists, layer) struct vnode *pvp; struct pnode *pp; Nse_list *backlists; int layer;{ Flist_iter_rec flist[MAX_SUB_LAYER + 1]; struct pnode *next_pp; unsigned first_sub_layer = FIRST_SUBL(pvp); int max_sub_layer = MAX_SUB_LAYER; int min_layer; unsigned sub_layer; int i; for (i = first_sub_layer; i <= MAX_SUB_LAYER; i++) { if (backlists[i] == NULL) { max_sub_layer = i - 1; break; } flist[i].end = nse_list_end(backlists[i]); flist[i].elem = nse_list_first_elem(backlists[i]); flist[i].entry = (Filelist) nse_listelem_data(flist[i].elem); } while (1) { layer++; min_layer = INFINITY; /* * Select the sub-layer with the minimum absolute layer #. */ for (i = first_sub_layer; i <= max_sub_layer; i++) { if (!END_OF_LIST(flist[i]) && flist[i].entry->layer < min_layer) { min_layer = flist[i].entry->layer; sub_layer = i; } } if (min_layer == INFINITY) { break; } /* * flist[sub_layer] now points to a series of file entries * followed by an entry for the directory in which the files * can be found. */ while (!IS_DIRNAME(flist[sub_layer].entry)) { (void) create_child_vnode(pvp, flist[sub_layer].entry->fname, layer, flist[sub_layer].entry->mtime); get_next_entry(&flist[sub_layer]); } /* * flist[sub_layer] now points to a directory entry. If * layer == 0, then this is an extra directory name for * the first layer. (Extra directory names used to exist * in the .tfs_backfiles of the frontmost sub-layer in * rev 3 backfiles.) * XXX remove this check when BACKF_VERSION changed. */ if (flist[sub_layer].entry->layer > 0) { next_pp = path_to_pnode(flist[sub_layer].entry->fname, sub_layer); set_next_pnode(pvp, pp, next_pp, layer - 1); pp = next_pp; } else { layer--; } get_next_entry(&flist[sub_layer]); } set_next_pnode(pvp, pp, (struct pnode *) NULL, layer - 1);}static voidget_next_entry(flist) Flist_iter flist;{ flist->elem = nse_listelem_next(flist->elem); flist->entry = (Filelist) nse_listelem_data(flist->elem);}static voiddestroy_backlists(backlists) Nse_list *backlists;{ int i; for (i = 0; i <= MAX_SUB_LAYER; i++) { if (backlists[i] != NULL) { nse_list_destroy(backlists[i]); } }}/* * File 'name' has been seen in directory 'pvp' at layer # 'layer'. Create * a vnode for the file if it hasn't been seen yet. */static struct vnode *create_child_vnode(pvp, name, layer, mtime) struct vnode *pvp; char *name; int layer; long mtime;{ struct vnode *vp; vp = find_vnode(pvp, name); if (vp == NULL) { vp = create_vnode(pvp, name, (long) 0); } if (vp->v_layer == INVALID_LAYER) { vp->v_layer = layer; } else if (vp->v_back_layer == INVALID_LAYER) { vp->v_back_layer = layer; } vp->v_mtime = mtime; return (vp);}/* * Create white-out vnodes for each of the entries in the whiteout list * 'wp'. */static voidcreate_whiteout_vnodes(pvp, layer, wp) struct vnode *pvp; int layer; Nse_whiteout wp;{ struct vnode *vp; while (wp != NULL) { vp = find_vnode(pvp, wp->name); if (vp == NULL) { vp = create_vnode(pvp, wp->name, (long) 0); } if (vp->v_layer == INVALID_LAYER) { vp->v_whited_out = TRUE; vp->v_layer = layer; } else if (vp->v_back_layer == INVALID_LAYER) { vp->v_back_whited_out = TRUE; vp->v_back_layer = layer; } wp = wp->next; }}/* * Insert the entries in the whiteout list 'wp' into the readdir hash table. */static voidinsert_whiteout_into_hash(readdir_hash, wp) Hash readdir_hash; Nse_whiteout wp;{ char *file_name; while (wp != NULL) { file_name = NSE_STRDUP(wp->name); if (nse_hash_insert(readdir_hash, file_name, HASH_VALUE)) { free(file_name); } wp = wp->next; }}intchange_backlist_mtime(pp, name, mtime) struct pnode *pp; char *name; long mtime;{ return modify_backlist(pp, name, change_mtime, (char *) mtime);}/* ARGSUSED */static voidchange_mtime(list, fl, mtime) Nse_list list; Filelist fl; long mtime;{ fl->mtime = mtime;}/* * Change the name of the entry named 'name' to 'newname' in the backlist * of directory 'pp'. If 'name' was the first directory entry in the * backlist, then insert the old name at the front of the backlist. */intchange_backlist_name(pp, name, newname) struct pnode *pp; char *name; char *newname;{ return modify_backlist(pp, name, change_name, newname);}static voidchange_name(list, fl, newname) Nse_list list; Filelist fl; char *newname;{ Nse_listelem elem; Filelist fl_new; if (fl->layer == 1 && IS_DIRNAME(fl)) { elem = nse_list_create_elem(list); fl_new = (Filelist) nse_listelem_data(elem); fl_new->fname = NSE_STRDUP(fl->fname); fl_new->layer = 1; fl_new->mtime = fl->mtime; nse_list_insert_head(list, elem); } free(fl->fname); fl->fname = NSE_STRDUP(newname);}/* * Modify the backlist entry for 'name' in the backlist for directory 'pp'. * 'modify_func' is the function to be used to change the entry, and 'arg' * is the argument to 'modify_func'. */static intmodify_backlist(pp, name, modify_func, arg) struct pnode *pp; char *name; void (*modify_func)(); char *arg;{ Nse_list backlist; Filelist fl; int result = 0; backlist = read_backlist(pp); if (backlist == NULL) { return ENOENT; } fl = (Filelist) nse_list_search(backlist, backlist_name_eq, name); if (fl == NULL) { result = ENOENT; goto error; } modify_func(backlist, fl, arg); result = write_backlist(pp, backlist);error: nse_list_destroy(backlist); return result;}static Nse_listread_backlist(pp) struct pnode *pp;{ char path[MAXPATHLEN]; FILE *file; Nse_list list; Filelist fl; int count; int version; bool_t eof = FALSE; Nse_err err; ptoname_or_pn(pp, path); nse_pathcat(path, NSE_TFS_BACK_FILE); file = open_tfs_file(path, "r", (Nse_err *) NULL); if (file == NULL) { return (NULL); } /* * Make sure that the version # in the file is correct. */ err = nse_fscanf(path, &count, file, NSE_TFS_VERSION_FORMAT, &version); if (err || count != 1 || version != NSE_TFS_BACKF_VERSION) { if (err) { nse_log_err_print(err); } fclose(file); return (NULL); } list = filelist_create(); err = read_backlist_entry(file, path, &fl, &eof); while (!eof) { (void) nse_list_add_new_data(list, (Nse_opaque) fl); err = read_backlist_entry(file, path, &fl, &eof); } if (err) { nse_log_err_print(err); } fclose(file); return (list);}static intwrite_backlist(pp, list) struct pnode *pp; Nse_list list;{ char path[MAXPATHLEN]; FILE *file; Nse_err err; ptoname_or_pn(pp, path); nse_pathcat(path, NSE_TFS_BACK_FILE); file = open_tfs_file(path, "w", (Nse_err *) NULL); if (file == NULL) { return (errno); } if ((err = nse_fprintf(path, file, NSE_TFS_VERSION_FORMAT, NSE_TFS_BACKF_VERSION)) || (err = (Nse_err) nse_list_iterate_or(list, write_backlist_entry, file, path)) || (err = nse_fclose(path, file))) { nse_log_err_print(err); fclose(file); (void) unlink(path); return (err->code); } return (0);}#define BACK_FILE_FORMAT "%s %d %ld\n"static Nse_errread_backlist_entry(file, path, entryp, eofp) FILE *file; char *path; Filelist *entryp; bool_t *eofp;{ Filelist fl; char line[MAXPATHLEN]; char name[MAXPATHLEN]; int layer; long mtime; int nitems; Nse_err err; /* * Can't use fscanf() because if there is no mtime on the current * line and the name of the file on the next line is a number, * fscanf() would read the next filename in as the mtime. */ err = nse_fgets(path, line, MAXPATHLEN, file, eofp); if (*eofp) { return err; } nitems = sscanf(line, BACK_FILE_FORMAT, name, &layer, &mtime); if (nitems < 2) { *eofp = TRUE; return NULL; } fl = NSE_NEW(Filelist); fl->fname = NSE_STRDUP(name); fl->layer = layer; if (nitems == 3) { fl->mtime = mtime; } *entryp = fl; return NULL;}static Nse_errwrite_backlist_entry(fl, file, path) Filelist fl; FILE *file; char *path;{ if (fl->mtime != 0) { return nse_fprintf(path, file, BACK_FILE_FORMAT, fl->fname, fl->layer, fl->mtime); } else { return nse_fprintf(path, file, "%s %d\n", fl->fname, fl->layer); }}static voidadd_to_backlist(list, name, layer, mtime) Nse_list list; char *name; int layer; long mtime;{ Filelist fl; fl = (Filelist) nse_list_add_new_elem(list); fl->fname = NSE_STRDUP(name); fl->layer = layer; fl->mtime = mtime;}static Hashinit_dir_hash(){ return (nse_hash_create(HASH_SIZE, NULL, (Nse_boolfunc) _nse_streq_func, _nse_hash_string, (Nse_intfunc) NULL, NULL, (Nse_intfunc) NULL, 7));}static bool_tgood_name(name) char *name;{ return (!NSE_STREQ(name, ".") && !NSE_STREQ(name, "..") && !is_tfs_special_file(name));}/* * Filelist routines */static bool_tbacklist_is_dir(fl) Filelist fl;{ return (IS_DIRNAME(fl));}static bool_tbacklist_name_eq(fl, name) Filelist fl; char *name;{ return (NSE_STREQ(fl->fname, name));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -