gzlog.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
- /*
- * gzlog.c
- * Copyright (C) 2004 Mark Adler
- * For conditions of distribution and use, see copyright notice in gzlog.h
- * version 1.0, 26 Nov 2004
- *
- */
- #include <string.h> /* memcmp() */
- #include <stdlib.h> /* malloc(), free(), NULL */
- #include <sys/types.h> /* size_t, off_t */
- #include <unistd.h> /* read(), close(), sleep(), ftruncate(), */
- /* lseek() */
- #include <fcntl.h> /* open() */
- #include <sys/file.h> /* flock() */
- #include "zlib.h" /* deflateInit2(), deflate(), deflateEnd() */
- #include "gzlog.h" /* interface */
- #define local static
- /* log object structure */
- typedef struct {
- int id; /* object identifier */
- int fd; /* log file descriptor */
- off_t extra; /* offset of extra "ap" subfield */
- off_t mark_off; /* offset of marked data */
- off_t last_off; /* offset of last block */
- unsigned long crc; /* uncompressed crc */
- unsigned long len; /* uncompressed length (modulo 2^32) */
- unsigned stored; /* length of current stored block */
- } gz_log;
- #define GZLOGID 19334 /* gz_log object identifier */
- #define LOCK_RETRY 1 /* retry lock once a second */
- #define LOCK_PATIENCE 1200 /* try about twenty minutes before forcing */
- /* acquire a lock on a file */
- local int lock(int fd)
- {
- int patience;
- /* try to lock every LOCK_RETRY seconds for LOCK_PATIENCE seconds */
- patience = LOCK_PATIENCE;
- do {
- if (flock(fd, LOCK_EX + LOCK_NB) == 0)
- return 0;
- (void)sleep(LOCK_RETRY);
- patience -= LOCK_RETRY;
- } while (patience > 0);
- /* we've run out of patience -- give up */
- return -1;
- }
- /* release lock */
- local void unlock(int fd)
- {
- (void)flock(fd, LOCK_UN);
- }
- /* release a log object */
- local void log_clean(gz_log *log)
- {
- unlock(log->fd);
- (void)close(log->fd);
- free(log);
- }
- /* read an unsigned long from a byte buffer little-endian */
- local unsigned long make_ulg(unsigned char *buf)
- {
- int n;
- unsigned long val;
- val = (unsigned long)(*buf++);
- for (n = 8; n < 32; n += 8)
- val += (unsigned long)(*buf++) << n;
- return val;
- }
- /* read an off_t from a byte buffer little-endian */
- local off_t make_off(unsigned char *buf)
- {
- int n;
- off_t val;
- val = (off_t)(*buf++);
- for (n = 8; n < 64; n += 8)
- val += (off_t)(*buf++) << n;
- return val;
- }
- /* write an unsigned long little-endian to byte buffer */
- local void dice_ulg(unsigned long val, unsigned char *buf)
- {
- int n;
- for (n = 0; n < 4; n++) {
- *buf++ = val & 0xff;
- val >>= 8;
- }
- }
- /* write an off_t little-endian to byte buffer */
- local void dice_off(off_t val, unsigned char *buf)
- {
- int n;
- for (n = 0; n < 8; n++) {
- *buf++ = val & 0xff;
- val >>= 8;
- }
- }
- /* initial, empty gzip file for appending */
- local char empty_gz[] = {
- 0x1f, 0x8b, /* magic gzip id */
- 8, /* compression method is deflate */
- 4, /* there is an extra field */
- 0, 0, 0, 0, /* no modification time provided */
- 0, 0xff, /* no extra flags, no OS */
- 20, 0, 'a', 'p', 16, 0, /* extra field with "ap" subfield */
- 32, 0, 0, 0, 0, 0, 0, 0, /* offset of uncompressed data */
- 32, 0, 0, 0, 0, 0, 0, 0, /* offset of last block */
- 1, 0, 0, 0xff, 0xff, /* empty stored block (last) */
- 0, 0, 0, 0, /* crc */
- 0, 0, 0, 0 /* uncompressed length */
- };
- /* initialize a log object with locking */
- void *gzlog_open(char *path)
- {
- unsigned xlen;
- unsigned char temp[20];
- unsigned sub_len;
- int good;
- gz_log *log;
- /* allocate log structure */
- log = malloc(sizeof(gz_log));
- if (log == NULL)
- return NULL;
- log->id = GZLOGID;
- /* open file, creating it if necessary, and locking it */
- log->fd = open(path, O_RDWR | O_CREAT, 0600);
- if (log->fd < 0) {
- free(log);
- return NULL;
- }
- if (lock(log->fd)) {
- close(log->fd);
- free(log);
- return NULL;
- }
- /* if file is empty, write new gzip stream */
- if (lseek(log->fd, 0, SEEK_END) == 0) {
- if (write(log->fd, empty_gz, sizeof(empty_gz)) != sizeof(empty_gz)) {
- log_clean(log);
- return NULL;
- }
- }
- /* check gzip header */
- (void)lseek(log->fd, 0, SEEK_SET);
- if (read(log->fd, temp, 12) != 12 || temp[0] != 0x1f ||
- temp[1] != 0x8b || temp[2] != 8 || (temp[3] & 4) == 0) {
- log_clean(log);
- return NULL;
- }
- /* process extra field to find "ap" sub-field */
- xlen = temp[10] + (temp[11] << 8);
- good = 0;
- while (xlen) {
- if (xlen < 4 || read(log->fd, temp, 4) != 4)
- break;
- sub_len = temp[2];
- sub_len += temp[3] << 8;
- xlen -= 4;
- if (memcmp(temp, "ap", 2) == 0 && sub_len == 16) {
- good = 1;
- break;
- }
- if (xlen < sub_len)
- break;
- (void)lseek(log->fd, sub_len, SEEK_CUR);
- xlen -= sub_len;
- }
- if (!good) {
- log_clean(log);
- return NULL;
- }
- /* read in "ap" sub-field */
- log->extra = lseek(log->fd, 0, SEEK_CUR);
- if (read(log->fd, temp, 16) != 16) {
- log_clean(log);
- return NULL;
- }
- log->mark_off = make_off(temp);
- log->last_off = make_off(temp + 8);
- /* get crc, length of gzip file */
- (void)lseek(log->fd, log->last_off, SEEK_SET);
- if (read(log->fd, temp, 13) != 13 ||
- memcmp(temp, "