📄 misc.c
字号:
size_t entrylen; if (! directory) return 0; for (entry = directory; (entrylen = strlen (entry)) != 0; entry += entrylen + 1) { char *file_name_buffer = new_name (file_name, entry); int r = remove_any_file (file_name_buffer, RECURSIVE_REMOVE_OPTION); int e = errno; free (file_name_buffer); if (! r) { free (directory); errno = e; return 0; } } free (directory); return safer_rmdir (file_name) == 0; } } break; } return 0;}/* Check if FILE_NAME already exists and make a backup of it right now. Return success (nonzero) only if the backup is either unneeded, or successful. For now, directories are considered to never need backup. If THIS_IS_THE_ARCHIVE is nonzero, this is the archive and so, we do not have to backup block or character devices, nor remote entities. */boolmaybe_backup_file (const char *file_name, bool this_is_the_archive){ struct stat file_stat; /* Check if we really need to backup the file. */ if (this_is_the_archive && _remdev (file_name)) return true; if (stat (file_name, &file_stat)) { if (errno == ENOENT) return true; stat_error (file_name); return false; } if (S_ISDIR (file_stat.st_mode)) return true; if (this_is_the_archive && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode))) return true; assign_string (&before_backup_name, file_name); /* A run situation may exist between Emacs or other GNU programs trying to make a backup for the same file simultaneously. If theoretically possible, real problems are unlikely. Doing any better would require a convention, GNU-wide, for all programs doing backups. */ assign_string (&after_backup_name, 0); after_backup_name = find_backup_file_name (file_name, backup_type); if (! after_backup_name) xalloc_die (); if (rename (before_backup_name, after_backup_name) == 0) { if (verbose_option) fprintf (stdlis, _("Renaming %s to %s\n"), quote_n (0, before_backup_name), quote_n (1, after_backup_name)); return true; } else { /* The backup operation failed. */ int e = errno; ERROR ((0, e, _("%s: Cannot rename to %s"), quotearg_colon (before_backup_name), quote_n (1, after_backup_name))); assign_string (&after_backup_name, 0); return false; }}/* Try to restore the recently backed up file to its original name. This is usually only needed after a failed extraction. */voidundo_last_backup (void){ if (after_backup_name) { if (rename (after_backup_name, before_backup_name) != 0) { int e = errno; ERROR ((0, e, _("%s: Cannot rename to %s"), quotearg_colon (after_backup_name), quote_n (1, before_backup_name))); } if (verbose_option) fprintf (stdlis, _("Renaming %s back to %s\n"), quote_n (0, after_backup_name), quote_n (1, before_backup_name)); assign_string (&after_backup_name, 0); }}/* Depending on DEREF, apply either stat or lstat to (NAME, BUF). */intderef_stat (bool deref, char const *name, struct stat *buf){ return deref ? stat (name, buf) : lstat (name, buf);}/* Set FD's (i.e., FILE's) access time to TIMESPEC[0]. If that's not possible to do by itself, set its access and data modification times to TIMESPEC[0] and TIMESPEC[1], respectively. */intset_file_atime (int fd, char const *file, struct timespec const timespec[2]){#ifdef _FIOSATIME if (0 <= fd) { struct timeval timeval; timeval.tv_sec = timespec[0].tv_sec; timeval.tv_usec = timespec[0].tv_nsec / 1000; if (ioctl (fd, _FIOSATIME, &timeval) == 0) return 0; }#endif return gl_futimens (fd, file, timespec);}/* A description of a working directory. */struct wd{ char const *name; int saved; struct saved_cwd saved_cwd;};/* A vector of chdir targets. wd[0] is the initial working directory. */static struct wd *wd;/* The number of working directories in the vector. */static size_t wds;/* The allocated size of the vector. */static size_t wd_alloc;/* DIR is the operand of a -C option; add it to vector of chdir targets, and return the index of its location. */intchdir_arg (char const *dir){ if (wds == wd_alloc) { if (wd_alloc == 0) { wd_alloc = 2; wd = xmalloc (sizeof *wd * wd_alloc); } else wd = x2nrealloc (wd, &wd_alloc, sizeof *wd); if (! wds) { wd[wds].name = "."; wd[wds].saved = 0; wds++; } } /* Optimize the common special case of the working directory, or the working directory as a prefix. */ if (dir[0]) { while (dir[0] == '.' && ISSLASH (dir[1])) for (dir += 2; ISSLASH (*dir); dir++) continue; if (! dir[dir[0] == '.']) return wds - 1; } wd[wds].name = dir; wd[wds].saved = 0; return wds++;}/* Change to directory I. If I is 0, change to the initial working directory; otherwise, I must be a value returned by chdir_arg. */voidchdir_do (int i){ static int previous; if (previous != i) { struct wd *prev = &wd[previous]; struct wd *curr = &wd[i]; if (! prev->saved) { int err = 0; prev->saved = 1; if (save_cwd (&prev->saved_cwd) != 0) err = errno; else if (0 <= prev->saved_cwd.desc) { /* Make sure we still have at least one descriptor available. */ int fd1 = prev->saved_cwd.desc; int fd2 = dup (fd1); if (0 <= fd2) close (fd2); else if (errno == EMFILE) { /* Force restore_cwd to use chdir_long. */ close (fd1); prev->saved_cwd.desc = -1; prev->saved_cwd.name = xgetcwd (); } else err = errno; } if (err) FATAL_ERROR ((0, err, _("Cannot save working directory"))); } if (curr->saved) { if (restore_cwd (&curr->saved_cwd)) FATAL_ERROR ((0, 0, _("Cannot change working directory"))); } else { if (i && ! ISSLASH (curr->name[0])) chdir_do (i - 1); if (chdir (curr->name) != 0) chdir_fatal (curr->name); } previous = i; }}voidclose_diag (char const *name){ if (ignore_failed_read_option) close_warn (name); else close_error (name);}voidopen_diag (char const *name){ if (ignore_failed_read_option) open_warn (name); else open_error (name);}voidread_diag_details (char const *name, off_t offset, size_t size){ if (ignore_failed_read_option) read_warn_details (name, offset, size); else read_error_details (name, offset, size);}voidreadlink_diag (char const *name){ if (ignore_failed_read_option) readlink_warn (name); else readlink_error (name);}voidsavedir_diag (char const *name){ if (ignore_failed_read_option) savedir_warn (name); else savedir_error (name);}voidseek_diag_details (char const *name, off_t offset){ if (ignore_failed_read_option) seek_warn_details (name, offset); else seek_error_details (name, offset);}voidstat_diag (char const *name){ if (ignore_failed_read_option) stat_warn (name); else stat_error (name);}voidwrite_fatal_details (char const *name, ssize_t status, size_t size){ write_error_details (name, status, size); fatal_exit ();}/* Fork, aborting if unsuccessful. */pid_txfork (void){ pid_t p = fork (); if (p == (pid_t) -1) call_arg_fatal ("fork", _("child process")); return p;}/* Create a pipe, aborting if unsuccessful. */voidxpipe (int fd[2]){ if (pipe (fd) < 0) call_arg_fatal ("pipe", _("interprocess channel"));}/* Return PTR, aligned upward to the next multiple of ALIGNMENT. ALIGNMENT must be nonzero. The caller must arrange for ((char *) PTR) through ((char *) PTR + ALIGNMENT - 1) to be addressable locations. */static inline void *ptr_align (void *ptr, size_t alignment){ char *p0 = ptr; char *p1 = p0 + alignment - 1; return p1 - (size_t) p1 % alignment;}/* Return the address of a page-aligned buffer of at least SIZE bytes. The caller should free *PTR when done with the buffer. */void *page_aligned_alloc (void **ptr, size_t size){ size_t alignment = getpagesize (); size_t size1 = size + alignment; if (size1 < size) xalloc_die (); *ptr = xmalloc (size1); return ptr_align (*ptr, alignment);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -