/* POSIX crc32/adler32 checksum program; requires zlib (a.k.a. libz)
 * Compile:    cc -o zsum32 zsum32.c -lz
 */

//#define _FILE_OFFSET_BITS 64
#include "config.h"
#include </usr/include/zlib.h>

#include </usr/include/errno.h>
#include </usr/include/stdio.h>
#include </usr/include/string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

//#define BUFSIZE     (8192*4)
#define BUFSIZE     (8*4096*1024)

//osv
//#define IOBUF_SIZE (1024*1024)
//#include <fcntl.h>
//#include <malloc.h>
#define MYEOF 0
#define SWAB_ALIGN_OFFSET 2
#define INPUT_BLOCK_SLOP (2 * SWAB_ALIGN_OFFSET + 2 * page_size - 1)

static inline void *
ptr_align (void const *ptr, size_t alignment)
{
  char const *p0 = ptr;
  char const *p1 = p0 + alignment - 1;
  return (void *) (p1 - (size_t) p1 % alignment);
}

int main(int argc, char **argv) {
	int estat = 0, erri = 0, i;
	int myfile;
	FILE *seek_f=0;
	uLong adler, crc;
	off_t bsize=0;
	off_t bsize_tmp=0;
	off_t tsz=0;
	int seek_from_block=-1;
	const char *errs = NULL;
	//static char buffer[BUFSIZE];
	char *buffer;
	char *real_buf;
	char flush_str[4096];
	ssize_t rb = -1;
	static size_t page_size;
	page_size = getpagesize();
	real_buf = malloc(BUFSIZE+INPUT_BLOCK_SLOP);
	buffer = real_buf;
	buffer += SWAB_ALIGN_OFFSET;  /* allow space for swab */
	buffer = ptr_align (buffer, page_size);
	for(i=0;i<4096;i++){
		flush_str[i]='-';
	}
	flush_str[4095]='\000';
	flush_str[1]=' ';
	if (argc < 3) {
		erri = EINVAL;
		errs = "Usage adlermap.c FILE bsize seek_file";
		goto jerror_noc;
	}

	if (argc >= 3) {
		++argv;
		myfile = open(*argv, O_RDONLY);//, O_DIRECT|O_NOATIME);
		if (myfile < 0) {
			fprintf( stderr,  "open %s failed", *argv);
			return 1;
		}
		{
		//суки O_DIRECT не работает через open, только через fcntl
		int old_flags = fcntl (myfile, F_GETFL);
		int new_flags = old_flags | O_DIRECT;
		fcntl (myfile, F_SETFL, new_flags);
		old_flags = fcntl (myfile, F_GETFL);
		}
	}
	
	if (argc >= 3) {
		++argv;
		bsize=atoi(*argv);
		if (bsize<=0) {
			bsize=1024*1024;
		}
	}

	/*	if (argc >= 4) {
			++argv;
			seek_from_block = atoi(*argv);
			fseek(f, bsize*seek_from_block, SEEK_SET);
		}*/
	if (argc >= 4) {
		++argv;
		seek_f = fopen(*argv, "rb");
		if (seek_f == NULL) {
			fprintf( stderr,  "fopen %s failed", *argv);
			return 1;
		}
		seek_from_block = 1;
	}
/*
//OSV МЕДЛЕННЕЙ!!!    
{
int IOBUF_SIZE=16000;
char *iobuf = (char *) malloc(IOBUF_SIZE);
setvbuf(stdout, iobuf, _IOFBF, IOBUF_SIZE);
}*/
setvbuf(stdout,NULL,_IONBF,0);

	while (1) {
		if (seek_f) {
			fscanf(seek_f,"%d\n", &seek_from_block);
			lseek(myfile, bsize*seek_from_block, SEEK_SET);
		}
		tsz=0;
		adler = adler32(0L, Z_NULL, 0);
		bsize_tmp = bsize;
		//читаем один блок
		for (;;) {
			rb = read(myfile, buffer, bsize_tmp);
			tsz=tsz+rb;
			//printf("tsz=%d bs=%d rb=%d bsize_tmp=%d %.8lx\n", tsz, bsize, rb, bsize_tmp, (unsigned long)adler);

			if (rb > 0){
				//если прочитали меньше, чем надо, то дочитаем потом
				if (rb < bsize)
					bsize_tmp=bsize_tmp-rb;
				adler = adler32(adler, (const Bytef*)buffer, (uInt)rb);
				//crc = crc32(crc, (const Bytef*)buffer, (uInt)rb);
				//rb<4096 это значит конец файла
				if (tsz==bsize || (rb % 4096 != 0) ){
					//printf("%.8lx %s\n", (unsigned long)adler, flush_str);
					printf("%.8lx\n", (unsigned long)adler);
					fflush(stdout);
					/*for(i=0;i<1;i++){
						printf("%s\n", flush_str);
						fflush(stdout);
					}*/
					break;
				}
				continue;
			}
			if (rb==MYEOF ){
				if (tsz!=0){
					printf("%.8lx\n", (unsigned long)adler);
					fflush(stdout);
				}
				break;
			}
			erri = errno;
			errs = "fread the file failed";
			goto jerror;
		}
		if (seek_f && feof(seek_f))
			break;
		if (rb==MYEOF || (rb % 4096 != 0) /*odirectEOF*/)
			  break;
	}
//    printf("%.8lx\n",
//           (unsigned long)adler);

	(void)close(myfile);
	if (seek_f) (void)fclose(seek_f);
jleave:
	return estat;

jerror:
	(void)close(myfile);
	if (seek_f) (void)fclose(seek_f);
jerror_noc:
	fprintf(stderr, "%s: %s\n", errs, strerror(erri));
	estat = 1;
	goto jleave;
}

