📄 util.c
字号:
/* Copyright (C) Andrew Tridgell 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "ccache.h"static FILE *logfile;/* log a message to the CCACHE_LOGFILE location */void cc_log(const char *format, ...){ va_list ap; extern char *cache_logfile; if (!cache_logfile) return; if (!logfile) logfile = fopen(cache_logfile, "a"); if (!logfile) return; va_start(ap, format); vfprintf(logfile, format, ap); va_end(ap); fflush(logfile);}/* something went badly wrong! */void fatal(const char *msg){ cc_log("FATAL: %s\n", msg); exit(1);}/* copy all data from one file descriptor to another */void copy_fd(int fd_in, int fd_out){ char buf[10240]; int n; while ((n = read(fd_in, buf, sizeof(buf))) > 0) { if (write(fd_out, buf, n) != n) { fatal("Failed to copy fd"); } }}/* copy a file - used when hard links don't work the copy is done via a temporary file and atomic rename*/int copy_file(const char *src, const char *dest){ int fd1, fd2; char buf[10240]; int n; char *tmp_name; mode_t mask; x_asprintf(&tmp_name, "%s.XXXXXX", dest); fd1 = open(src, O_RDONLY); if (fd1 == -1) { free(tmp_name); return -1; } fd2 = mkstemp(tmp_name); if (fd2 == -1) { close(fd1); free(tmp_name); return -1; } while ((n = read(fd1, buf, sizeof(buf))) > 0) { if (write(fd2, buf, n) != n) { close(fd2); close(fd1); unlink(tmp_name); free(tmp_name); return -1; } } close(fd1); /* get perms right on the tmp file */ mask = umask(0); fchmod(fd2, 0666 & ~mask); umask(mask); /* the close can fail on NFS if out of space */ if (close(fd2) == -1) { unlink(tmp_name); free(tmp_name); return -1; } unlink(dest); if (rename(tmp_name, dest) == -1) { unlink(tmp_name); free(tmp_name); return -1; } free(tmp_name); return 0;}/* make sure a directory exists */int create_dir(const char *dir){ struct stat st; if (stat(dir, &st) == 0) { if (S_ISDIR(st.st_mode)) { return 0; } errno = ENOTDIR; return 1; } if (mkdir(dir, 0777) != 0 && errno != EEXIST) { return 1; } return 0;}/* this is like asprintf() but dies if the malloc fails note that we use vsnprintf in a rather poor way to make this more portable*/void x_asprintf(char **ptr, const char *format, ...){ va_list ap; *ptr = NULL; va_start(ap, format); vasprintf(ptr, format, ap); va_end(ap); if (!ptr) fatal("out of memory in x_asprintf");}/* this is like strdup() but dies if the malloc fails*/char *x_strdup(const char *s){ char *ret; ret = strdup(s); if (!ret) { fatal("out of memory in strdup\n"); } return ret;}/* this is like malloc() but dies if the malloc fails*/void *x_malloc(size_t size){ void *ret; ret = malloc(size); if (!ret) { fatal("out of memory in malloc\n"); } return ret;}/* this is like realloc() but dies if the malloc fails*/void *x_realloc(void *ptr, size_t size){ void *p2; if (!ptr) return x_malloc(size); p2 = malloc(size); if (!p2) { fatal("out of memory in x_realloc"); } if (ptr) { memcpy(p2, ptr, size); free(ptr); } return p2;}/* revsusive directory traversal - used for cleanup fn() is called on all files/dirs in the tree */void traverse(const char *dir, void (*fn)(const char *, struct stat *)){ DIR *d; struct dirent *de; d = opendir(dir); if (!d) return; while ((de = readdir(d))) { char *fname; struct stat st; if (strcmp(de->d_name,".") == 0) continue; if (strcmp(de->d_name,"..") == 0) continue; if (strlen(de->d_name) == 0) continue; x_asprintf(&fname, "%s/%s", dir, de->d_name); if (lstat(fname, &st)) { if (errno != ENOENT) { perror(fname); } free(fname); continue; } if (S_ISDIR(st.st_mode)) { traverse(fname, fn); } fn(fname, &st); free(fname); } closedir(d);}/* return the base name of a file - caller frees */char *str_basename(const char *s){ char *p = strrchr(s, '/'); if (p) { return x_strdup(p+1); } return x_strdup(s);}/* return the dir name of a file - caller frees */char *dirname(char *s){ char *p; s = x_strdup(s); p = strrchr(s, '/'); if (p) { *p = 0; } return s;}int lock_fd(int fd){ struct flock fl; int ret; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1; fl.l_pid = 0; /* not sure why we would be getting a signal here, but one user claimed it is possible */ do { ret = fcntl(fd, F_SETLKW, &fl); } while (ret == -1 && errno == EINTR); return ret;}/* return size on disk of a file */size_t file_size(struct stat *st){ size_t size = st->st_blocks * 512; if ((size_t)st->st_size > size) { /* probably a broken stat() call ... */ size = (st->st_size + 1023) & ~1023; } return size;}/* a safe open/create for read-write */int safe_open(const char *fname){ int fd = open(fname, O_RDWR); if (fd == -1 && errno == ENOENT) { fd = open(fname, O_RDWR|O_CREAT|O_EXCL, 0666); if (fd == -1 && errno == EEXIST) { fd = open(fname, O_RDWR); } } return fd;}/* display a kilobyte unsigned value in M, k or G */void display_size(unsigned v){ if (v > 1024*1024) { printf("%8.1f Gbytes", v/((double)(1024*1024))); } else if (v > 1024) { printf("%8.1f Mbytes", v/((double)(1024))); } else { printf("%8u Kbytes", v); }}/* return a value in multiples of 1024 give a string that can end in K, M or G*/size_t value_units(const char *s){ char m; double v = atof(s); m = s[strlen(s)-1]; switch (m) { case 'G': case 'g': default: v *= 1024*1024; break; case 'M': case 'm': v *= 1024; break; case 'K': case 'k': v *= 1; break; } return (size_t)v;}/* a sane realpath() function, trying to cope with stupid path limits and a broken API*/char *x_realpath(const char *path){ int maxlen; char *ret, *p;#ifdef PATH_MAX maxlen = PATH_MAX;#elif defined(MAXPATHLEN) maxlen = MAXPATHLEN;#elif defined(_PC_PATH_MAX) maxlen = pathconf(path, _PC_PATH_MAX);#endif if (maxlen < 4096) maxlen = 4096; ret = x_malloc(maxlen);#if HAVE_REALPATH p = realpath(path, ret);#else /* yes, there are such systems. This replacement relies on the fact that when we call x_realpath we only care about symlinks */ { int len = readlink(path, ret, maxlen-1); if (len == -1) { free(ret); return NULL; } ret[len] = 0; p = ret; }#endif if (p) { p = x_strdup(p); free(ret); return p; } free(ret); return NULL;}/* a getcwd that will returns an allocated buffer */char *gnu_getcwd(void){ unsigned size = 128; while (1) { char *buffer = (char *)x_malloc(size); if (getcwd(buffer, size) == buffer) { return buffer; } free(buffer); if (errno != ERANGE) { return 0; } size *= 2; }}#ifndef HAVE_MKSTEMP/* cheap and nasty mkstemp replacement */int mkstemp(char *template){ mktemp(template); return open(template, O_RDWR | O_CREAT | O_EXCL, 0600);}#endif/* create an empty file */int create_empty_file(const char *fname){ int fd; fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0666); if (fd == -1) { return -1; } close(fd); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -