📄 tables.c
字号:
bad: warn(1, "Unable to fix truncated inode/device field when storing %s", arcn->name); warn(0, "Archive may create improper hard links when extracted"); return(0);}/* * directory access/mod time reset table routines (for directories READ by pax) * * The pax -t flag requires that access times of archive files to be the same * before being read by pax. For regular files, access time is restored after * the file has been copied. This database provides the same functionality for * directories read during file tree traversal. Restoring directory access time * is more complex than files since directories may be read several times until * all the descendants in their subtree are visited by fts. Directory access * and modification times are stored during the fts pre-order visit (done * before any descendants in the subtree is visited) and restored after the * fts post-order visit (after all the descendants have been visited). In the * case of premature exit from a subtree (like from the effects of -n), any * directory entries left in this database are reset during final cleanup * operations of pax. Entries are hashed by inode number for fast lookup. *//* * atdir_start() * create the directory access time database for directories READ by pax. * Return: * 0 is created ok, -1 otherwise. */#if __STDC__intatdir_start(void)#elseintatdir_start()#endif{ if (atab != NULL) return(0); if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) { warn(1,"Cannot allocate space for directory access time table"); return(-1); } return(0);}/* * atdir_end() * walk through the directory access time table and reset the access time * of any directory who still has an entry left in the database. These * entries are for directories READ by pax */#if __STDC__voidatdir_end(void)#elsevoidatdir_end()#endif{ register ATDIR *pt; register int i; if (atab == NULL) return; /* * for each non-empty hash table entry reset all the directories * chained there. */ for (i = 0; i < A_TAB_SZ; ++i) { if ((pt = atab[i]) == NULL) continue; /* * remember to force the times, set_ftime() looks at pmtime * and patime, which only applies to things CREATED by pax, * not read by pax. Read time reset is controlled by -t. */ for (; pt != NULL; pt = pt->fow) set_ftime(pt->name, pt->mtime, pt->atime, 1); }}/* * add_atdir() * add a directory to the directory access time table. Table is hashed * and chained by inode number. This is for directories READ by pax */#if __STDC__voidadd_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime)#elsevoidadd_atdir(fname, dev, ino, mtime, atime) char *fname; dev_t dev; ino_t ino; time_t mtime; time_t atime;#endif{ register ATDIR *pt; register u_int indx; if (atab == NULL) return; /* * make sure this directory is not already in the table, if so just * return (the older entry always has the correct time). The only * way this will happen is when the same subtree can be traversed by * different args to pax and the -n option is aborting fts out of a * subtree before all the post-order visits have been made). */ indx = ((unsigned)ino) % A_TAB_SZ; if ((pt = atab[indx]) != NULL) { while (pt != NULL) { if ((pt->ino == ino) && (pt->dev == dev)) break; pt = pt->fow; } /* * oops, already there. Leave it alone. */ if (pt != NULL) return; } /* * add it to the front of the hash chain */ if ((pt = (ATDIR *)malloc(sizeof(ATDIR))) != NULL) { if ((pt->name = strdup(fname)) != NULL) { pt->dev = dev; pt->ino = ino; pt->mtime = mtime; pt->atime = atime; pt->fow = atab[indx]; atab[indx] = pt; return; } (void)free((char *)pt); } warn(1, "Directory access time reset table ran out of memory"); return;}/* * get_atdir() * look up a directory by inode and device number to obtain the access * and modification time you want to set to. If found, the modification * and access time parameters are set and the entry is removed from the * table (as it is no longer needed). These are for directories READ by * pax * Return: * 0 if found, -1 if not found. */#if __STDC__intget_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime)#elseintget_atdir(dev, ino, mtime, atime) dev_t dev; ino_t ino; time_t *mtime; time_t *atime;#endif{ register ATDIR *pt; register ATDIR **ppt; register u_int indx; if (atab == NULL) return(-1); /* * hash by inode and search the chain for an inode and device match */ indx = ((unsigned)ino) % A_TAB_SZ; if ((pt = atab[indx]) == NULL) return(-1); ppt = &(atab[indx]); while (pt != NULL) { if ((pt->ino == ino) && (pt->dev == dev)) break; /* * no match, go to next one */ ppt = &(pt->fow); pt = pt->fow; } /* * return if we did not find it. */ if (pt == NULL) return(-1); /* * found it. return the times and remove the entry from the table. */ *ppt = pt->fow; *mtime = pt->mtime; *atime = pt->atime; (void)free((char *)pt->name); (void)free((char *)pt); return(0);}/* * directory access mode and time storage routines (for directories CREATED * by pax). * * Pax requires that extracted directories, by default, have their access/mod * times and permissions set to the values specified in the archive. During the * actions of extracting (and creating the destination subtree during -rw copy) * directories extracted may be modified after being created. Even worse is * that these directories may have been created with file permissions which * prohibits any descendants of these directories from being extracted. When * directories are created by pax, access rights may be added to permit the * creation of files in their subtree. Every time pax creates a directory, the * times and file permissions specified by the archive are stored. After all * files have been extracted (or copied), these directories have their times * and file modes reset to the stored values. The directory info is restored in * reverse order as entries were added to the data file from root to leaf. To * restore atime properly, we must go backwards. The data file consists of * records with two parts, the file name followed by a DIRDATA trailer. The * fixed sized trailer contains the size of the name plus the off_t location in * the file. To restore we work backwards through the file reading the trailer * then the file name. *//* * dir_start() * set up the directory time and file mode storage for directories CREATED * by pax. * Return: * 0 if ok, -1 otherwise */#if __STDC__intdir_start(void)#elseintdir_start()#endif{ char *pt; if (dirfd != -1) return(0); if ((pt = tempnam((char *)NULL, (char *)NULL)) == NULL) return(-1); /* * unlink the file so it goes away at termination by itself */ (void)unlink(pt); if ((dirfd = open(pt, O_RDWR|O_CREAT, 0600)) >= 0) { (void)unlink(pt); return(0); } warn(1, "Unable to create temporary file for directory times: %s", pt); return(-1);}/* * add_dir() * add the mode and times for a newly CREATED directory * name is name of the directory, psb the stat buffer with the data in it, * frc_mode is a flag that says whether to force the setting of the mode * (ignoring the user set values for preserving file mode). Frc_mode is * for the case where we created a file and found that the resulting * directory was not writeable and the user asked for file modes to NOT * be preserved. (we have to preserve what was created by default, so we * have to force the setting at the end. this is stated explicitly in the * pax spec) */#if __STDC__voidadd_dir(char *name, int nlen, struct stat *psb, int frc_mode)#elsevoidadd_dir(name, nlen, psb, frc_mode) char *name; int nlen; struct stat *psb; int frc_mode;#endif{ DIRDATA dblk; if (dirfd < 0) return; /* * get current position (where file name will start) so we can store it * in the trailer */ if ((dblk.npos = lseek(dirfd, 0L, SEEK_CUR)) < 0) { warn(1,"Unable to store mode and times for directory: %s",name); return; } /* * write the file name followed by the trailer */ dblk.nlen = nlen + 1; dblk.mode = psb->st_mode & 0xffff; dblk.mtime = psb->st_mtime; dblk.atime = psb->st_atime; dblk.frc_mode = frc_mode; if ((write(dirfd, name, dblk.nlen) == dblk.nlen) && (write(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) { ++dircnt; return; } warn(1,"Unable to store mode and times for created directory: %s",name); return;}/* * proc_dir() * process all file modes and times stored for directories CREATED * by pax */#if __STDC__voidproc_dir(void)#elsevoidproc_dir()#endif{ char name[PAXPATHLEN+1]; DIRDATA dblk; u_long cnt; if (dirfd < 0) return; /* * read backwards through the file and process each directory */ for (cnt = 0; cnt < dircnt; ++cnt) { /* * read the trailer, then the file name, if this fails * just give up. */ if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0) break; if (read(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; if (read(dirfd, name, dblk.nlen) != dblk.nlen) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; /* * frc_mode set, make sure we set the file modes even if * the user didn't ask for it (see file_subs.c for more info) */ if (pmode || dblk.frc_mode) set_pmode(name, dblk.mode); if (patime || pmtime) set_ftime(name, dblk.mtime, dblk.atime, 0); } (void)close(dirfd); dirfd = -1; if (cnt != dircnt) warn(1,"Unable to set mode and times for created directories"); return;}/* * database independent routines *//* * st_hash() * hashes filenames to a u_int for hashing into a table. Looks at the tail * end of file, as this provides far better distribution than any other * part of the name. For performance reasons we only care about the last * MAXKEYLEN chars (should be at LEAST large enough to pick off the file * name). Was tested on 500,000 name file tree traversal from the root * and gave almost a perfectly uniform distribution of keys when used with * prime sized tables (MAXKEYLEN was 128 in test). Hashes (sizeof int) * chars at a time and pads with 0 for last addition. * Return: * the hash value of the string MOD (%) the table size. */#if __STDC__u_intst_hash(char *name, int len, int tabsz)#elseu_intst_hash(name, len, tabsz) char *name; int len; int tabsz;#endif{ register char *pt; register char *dest; register char *end; register int i; register u_int key = 0; register int steps; register int res; u_int val; /* * only look at the tail up to MAXKEYLEN, we do not need to waste * time here (remember these are pathnames, the tail is what will * spread out the keys) */ if (len > MAXKEYLEN) { pt = &(name[len - MAXKEYLEN]); len = MAXKEYLEN; } else pt = name; /* * calculate the number of u_int size steps in the string and if * there is a runt to deal with */ steps = len/sizeof(u_int); res = len % sizeof(u_int); /* * add up the value of the string in unsigned integer sized pieces * too bad we cannot have unsigned int aligned strings, then we * could avoid the expensive copy. */ for (i = 0; i < steps; ++i) { end = pt + sizeof(u_int); dest = (char *)&val; while (pt < end) *dest++ = *pt++; key += val; } /* * add in the runt padded with zero to the right */ if (res) { val = 0; end = pt + res; dest = (char *)&val; while (pt < end) *dest++ = *pt++; key += val; } /* * return the result mod the table size */ return(key % tabsz);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -