📄 xdelta3-main.h
字号:
get_errno (void){#ifndef _WIN32 if (errno == 0) { XPR(NT "you found a bug: expected errno != 0\n"); errno = XD3_INTERNAL; } return errno;#else DWORD errNum = GetLastError(); if (errNum == NO_ERROR) { errNum = XD3_INTERNAL; } return errNum;#endif}const char*xd3_mainerror(int err_num) {#ifndef _WIN32 const char* x = xd3_strerror (err_num); if (x != NULL) { return x; } return strerror(err_num);#else static char err_buf[256]; const char* x = xd3_strerror (err_num); if (x != NULL) { return x; } memset (err_buf, 0, 256); FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err_num, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), err_buf, 256, NULL); return err_buf;#endif}static longget_millisecs_now (void){#ifndef _WIN32 struct timeval tv; gettimeofday (& tv, NULL); return (tv.tv_sec) * 1000L + (tv.tv_usec) / 1000;#else SYSTEMTIME st; FILETIME ft; __int64 *pi = (__int64*)&ft; GetLocalTime(&st); SystemTimeToFileTime(&st, &ft); return (long)((*pi) / 10000);#endif}/* Always >= 1 millisec, right? */static longget_millisecs_since (void){ static long last = 0; long now = get_millisecs_now(); long diff = now - last; last = now; return diff;}static char*main_format_bcnt (xoff_t r, char *buf){ static const char* fmts[] = { "B", "KB", "MB", "GB" }; usize_t i; for (i = 0; i < SIZEOF_ARRAY(fmts); i += 1) { if (r <= (10 * 1024) || i == (-1 + (int)SIZEOF_ARRAY(fmts))) { sprintf (buf, "%"Q"u %s", r, fmts[i]); break; } r /= 1024; } return buf;}static char*main_format_rate (xoff_t bytes, long millis, char *buf){ xoff_t r = (xoff_t)(1.0 * bytes / (1.0 * millis / 1000.0)); static char lbuf[32]; main_format_bcnt (r, lbuf); sprintf (buf, "%s/sec", lbuf); return buf;}static char*main_format_millis (long millis, char *buf){ if (millis < 1000) { sprintf (buf, "%lu ms", millis); } else if (millis < 10000) { sprintf (buf, "%.1f sec", millis / 1000.0); } else { sprintf (buf, "%lu sec", millis / 1000L); } return buf;}/* A safe version of strtol for xoff_t. */static intmain_strtoxoff (const char* s, xoff_t *xo, char which){ char *e; xoff_t x; XD3_ASSERT(s && *s != 0); { /* Should check LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX? */#if SIZEOF_XOFF_T == 4 long xx = strtol (s, &e, 0);#else long long xx = strtoll (s, &e, 0);#endif if (xx < 0) { XPR(NT "-%c: negative integer: %s\n", which, s); return EXIT_FAILURE; } x = xx; } if (*e != 0) { XPR(NT "-%c: invalid integer: %s\n", which, s); return EXIT_FAILURE; } (*xo) = x; return 0;}static intmain_atou (const char* arg, usize_t *xo, usize_t low, usize_t high, char which){ xoff_t x; int ret; if ((ret = main_strtoxoff (arg, & x, which))) { return ret; } if (x < low) { XPR(NT "-%c: minimum value: %u\n", which, low); return EXIT_FAILURE; } if (high == 0) { high = USIZE_T_MAX; } if (x > high) { XPR(NT "-%c: maximum value: %u\n", which, high); return EXIT_FAILURE; } (*xo) = (usize_t)x; return 0;}/****************************************************************** FILE BASICS ******************************************************************//* With all the variation in file system-call semantics, arguments, * return values and error-handling for the POSIX and STDIO file APIs, * the insides of these functions make me sick, which is why these * wrappers exist. */#define XOPEN_OPNAME (xfile->mode == XO_READ ? "read" : "write")#define XOPEN_STDIO (xfile->mode == XO_READ ? "rb" : "wb")#define XOPEN_POSIX (xfile->mode == XO_READ ? \ O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC)#define XOPEN_MODE (xfile->mode == XO_READ ? 0 : 0666)#define XF_ERROR(op, name, ret) \ do { if (!option_quiet) { XPR(NT "file %s failed: %s: %s: %s\n", (op), \ XOPEN_OPNAME, (name), xd3_mainerror (ret)); } } while (0)#if XD3_STDIO#define XFNO(f) fileno(f->file)#define XSTDOUT_XF(f) { (f)->file = stdout; (f)->filename = "/dev/stdout"; }#define XSTDIN_XF(f) { (f)->file = stdin; (f)->filename = "/dev/stdin"; }#elif XD3_POSIX#define XFNO(f) f->file#define XSTDOUT_XF(f) \ { (f)->file = STDOUT_FILENO; (f)->filename = "/dev/stdout"; }#define XSTDIN_XF(f) \ { (f)->file = STDIN_FILENO; (f)->filename = "/dev/stdin"; }#elif XD3_WIN32#define XFNO(f) -1#define XSTDOUT_XF(f) { \ (f)->file = GetStdHandle(STD_OUTPUT_HANDLE); \ (f)->filename = "(stdout)"; \ }#define XSTDIN_XF(f) { \ (f)->file = GetStdHandle(STD_INPUT_HANDLE); \ (f)->filename = "(stdin)"; \ }#endifstatic voidmain_file_init (main_file *xfile){ memset (xfile, 0, sizeof (*xfile));#if XD3_POSIX xfile->file = -1;#endif#if XD3_WIN32 xfile->file = INVALID_HANDLE_VALUE;#endif}static intmain_file_isopen (main_file *xfile){#if XD3_STDIO return xfile->file != NULL;#elif XD3_POSIX return xfile->file != -1;#elif XD3_WIN32 return xfile->file != INVALID_HANDLE_VALUE;#endif}static intmain_file_close (main_file *xfile){ int ret = 0; if (! main_file_isopen (xfile)) { return 0; }#if XD3_STDIO ret = fclose (xfile->file); xfile->file = NULL;#elif XD3_POSIX ret = close (xfile->file); xfile->file = -1;#elif XD3_WIN32 if (!CloseHandle(xfile->file)) { ret = get_errno (); } xfile->file = INVALID_HANDLE_VALUE;#endif if (ret != 0) { XF_ERROR ("close", xfile->filename, ret = get_errno ()); } return ret;}static voidmain_file_cleanup (main_file *xfile){ XD3_ASSERT (xfile != NULL); if (main_file_isopen (xfile)) { main_file_close (xfile); } if (xfile->snprintf_buf != NULL) { main_free(xfile->snprintf_buf); xfile->snprintf_buf = NULL; } if (xfile->filename_copy != NULL) { main_free(xfile->filename_copy); xfile->filename_copy = NULL; }}static intmain_file_open (main_file *xfile, const char* name, int mode){ int ret = 0; xfile->mode = mode; XD3_ASSERT (name != NULL); XD3_ASSERT (! main_file_isopen (xfile)); if (name[0] == 0) { XPR(NT "invalid file name: empty string\n"); return XD3_INVALID; }#if XD3_STDIO xfile->file = fopen (name, XOPEN_STDIO); ret = (xfile->file == NULL) ? get_errno () : 0;#elif XD3_POSIX if ((ret = open (name, XOPEN_POSIX, XOPEN_MODE)) < 0) { ret = get_errno (); } else { xfile->file = ret; ret = 0; }#elif XD3_WIN32 xfile->file = CreateFile(name, (mode == XO_READ) ? GENERIC_READ : GENERIC_WRITE, FILE_SHARE_READ, NULL, (mode == XO_READ) ? OPEN_EXISTING : (option_force ? CREATE_ALWAYS : CREATE_NEW), FILE_ATTRIBUTE_NORMAL, NULL); if (xfile->file == INVALID_HANDLE_VALUE) { ret = get_errno (); }#endif if (ret) { XF_ERROR ("open", name, ret); } else { xfile->realname = name; xfile->nread = 0; } return ret;}static intmain_file_stat (main_file *xfile, xoff_t *size, int err_ifnoseek){ int ret = 0;#if XD3_WIN32# if (_WIN32_WINNT >= 0x0500) LARGE_INTEGER li; if (GetFileSizeEx(xfile->file, &li) == 0) { ret = get_errno (); } else { *size = li.QuadPart; }# else DWORD filesize = GetFileSize(xfile->file, NULL); if (filesize == INVALID_FILE_SIZE) { ret = GetLastError(); if (ret != NO_ERROR) return ret; } *size = filesize;# endif#else struct stat sbuf; if (fstat (XFNO (xfile), & sbuf) < 0) { ret = get_errno (); if (err_ifnoseek) { XF_ERROR ("stat", xfile->filename, ret); } return ret; } if (! S_ISREG (sbuf.st_mode)) { if (err_ifnoseek) { XPR(NT "source file must be seekable: %s\n", xfile->filename); } return ESPIPE; } (*size) = sbuf.st_size;#endif return ret;}static intmain_file_exists (main_file *xfile){ struct stat sbuf; return stat (xfile->filename, & sbuf) == 0 && S_ISREG (sbuf.st_mode);}#if (XD3_POSIX || EXTERNAL_COMPRESSION)/* POSIX-generic code takes a function pointer to read() or write(). * This calls the function repeatedly until the buffer is full or EOF. * The NREAD parameter is not set for write, NULL is passed. Return * is signed, < 0 indicate errors, otherwise byte count. */typedef int (xd3_posix_func) (int fd, uint8_t *buf, usize_t size);static intxd3_posix_io (int fd, uint8_t *buf, usize_t size, xd3_posix_func *func, usize_t *nread){ int ret; usize_t nproc = 0; while (nproc < size) { int result = (*func) (fd, buf + nproc, size - nproc); if (result < 0) { ret = get_errno (); if (ret != EAGAIN && ret != EINTR) { return ret; } result = 0; } if (nread != NULL && result == 0) { break; } nproc += result; } if (nread != NULL) { (*nread) = nproc; } return 0;}#endif/* POSIX is unbuffered, while STDIO is buffered. main_file_read() * should always be called on blocks. */static intmain_file_read (main_file *ifile, uint8_t *buf, usize_t size, usize_t *nread, const char *msg){ int ret = 0;#if XD3_STDIO usize_t result; result = fread (buf, 1, size, ifile->file); if (result < size && ferror (ifile->file)) { ret = get_errno (); } else { *nread = result; }#elif XD3_POSIX ret = xd3_posix_io (ifile->file, buf, size, (xd3_posix_func*) &read, nread);#elif XD3_WIN32 DWORD nread2; if (ReadFile (ifile->file, buf, size, &nread2, NULL) == 0) { ret = get_errno(); } else { *nread = (usize_t)nread2; }#endif if (ret) { XPR(NT "%s: %s: %s\n", msg, ifile->filename, xd3_mainerror (ret)); } else { if (option_verbose > 3) { XPR(NT "main read: %s: %u\n", ifile->filename, (*nread)); } ifile->nread += (*nread); } return ret;}static intmain_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg){ int ret = 0;#if XD3_STDIO usize_t result; result = fwrite (buf, 1, size, ofile->file); if (result != size) { ret = get_errno (); }#elif XD3_POSIX ret = xd3_posix_io (ofile->file, buf, size, (xd3_posix_func*) &write, NULL);#elif XD3_WIN32 DWORD nwrite; if (WriteFile(ofile->file, buf, size, &nwrite, NULL) == 0) { ret = get_errno (); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -