1 /* an mspack_system implementation which reads one or more files, and
2  * only writes to one file; the file is not actually written to, but
3  * an MD5 sum is computed and is available once the written-to file is
4  * closed. You can use anything for the written-to filename, NULL is
5  * probably the most obvious. The code is not multithreadable.
6  */
7 
8 #include <md5.h>
9 #include <stdio.h>
10 #include <stdarg.h>
11 
12 struct md5_ctx md5_context;
13 char md5_string[33];
14 
15 struct mspack_file_p {
16     FILE *fh;
17 };
18 
m_open(struct mspack_system * self,const char * filename,int mode)19 static struct mspack_file *m_open(struct mspack_system *self, const char *filename, int mode) {
20     struct mspack_file_p *fh;
21     if (mode != MSPACK_SYS_OPEN_WRITE &&
22         mode != MSPACK_SYS_OPEN_READ) return NULL;
23 
24     if ((fh = (struct mspack_file_p *) malloc(sizeof(struct mspack_file_p)))) {
25         if (mode == MSPACK_SYS_OPEN_WRITE) {
26             fh->fh = NULL;
27             md5_init_ctx(&md5_context);
28             return (struct mspack_file *) fh;
29         }
30         else {
31             if ((fh->fh = fopen(filename, "rb")))
32                 return (struct mspack_file *) fh;
33         }
34         /* error - free file handle and return NULL */
35         free(fh);
36     }
37     return NULL;
38 }
39 
m_close(struct mspack_file * file)40 static void m_close(struct mspack_file *file) {
41   struct mspack_file_p *self = (struct mspack_file_p *) file;
42   if (self) {
43       if (self->fh) fclose(self->fh);
44       else {
45           unsigned char md5[16];
46           md5_finish_ctx(&md5_context, (void *) &md5);
47           snprintf(md5_string, sizeof(md5_string),
48                    "%02x%02x%02x%02x%02x%02x%02x%02x"
49                    "%02x%02x%02x%02x%02x%02x%02x%02x",
50                    md5[0],  md5[1],  md5[2],  md5[3],
51                    md5[4],  md5[5],  md5[6],  md5[7],
52                    md5[8],  md5[9],  md5[10], md5[11],
53                    md5[12], md5[13], md5[14], md5[15]);
54       }
55       free(self);
56   }
57 }
58 
m_read(struct mspack_file * file,void * buffer,int bytes)59 static int m_read(struct mspack_file *file, void *buffer, int bytes) {
60   struct mspack_file_p *self = (struct mspack_file_p *) file;
61   if (self && self->fh && buffer && bytes >= 0) {
62       size_t count = fread(buffer, 1, bytes, self->fh);
63       if (!ferror(self->fh)) return (int) count;
64   }
65   return -1;
66 }
67 
m_write(struct mspack_file * file,void * buffer,int bytes)68 static int m_write(struct mspack_file *file, void *buffer, int bytes) {
69     struct mspack_file_p *self = (struct mspack_file_p *) file;
70     if (!self || self->fh || !buffer || bytes < 0) return -1;
71     md5_process_bytes(buffer, bytes, &md5_context);
72     return bytes;
73 }
74 
m_seek(struct mspack_file * file,off_t offset,int mode)75 static int m_seek(struct mspack_file *file, off_t offset, int mode) {
76     struct mspack_file_p *self = (struct mspack_file_p *) file;
77     if (self && self->fh) {
78         switch (mode) {
79         case MSPACK_SYS_SEEK_START: mode = SEEK_SET; break;
80         case MSPACK_SYS_SEEK_CUR:   mode = SEEK_CUR; break;
81         case MSPACK_SYS_SEEK_END:   mode = SEEK_END; break;
82         default: return -1;
83         }
84 #if HAVE_FSEEKO
85         return fseeko(self->fh, offset, mode);
86 #else
87         return fseek(self->fh, offset, mode);
88 #endif
89     }
90     return -1;
91 }
92 
m_tell(struct mspack_file * file)93 static off_t m_tell(struct mspack_file *file) {
94     struct mspack_file_p *self = (struct mspack_file_p *) file;
95 #if HAVE_FSEEKO
96     return (self && self->fh) ? (off_t) ftello(self->fh) : 0;
97 #else
98     return (self && self->fh) ? (off_t) ftell(self->fh) : 0;
99 #endif
100 }
101 
m_msg(struct mspack_file * file,const char * format,...)102 static void m_msg(struct mspack_file *file, const char *format, ...) {
103     va_list ap;
104     va_start(ap, format);
105     vfprintf(stderr, format, ap);
106     va_end(ap);
107     fputc((int) '\n', stderr);
108     fflush(stderr);
109 }
m_alloc(struct mspack_system * self,size_t bytes)110 static void *m_alloc(struct mspack_system *self, size_t bytes) {
111     return malloc(bytes);
112 }
m_free(void * buffer)113 static void m_free(void *buffer) {
114     free(buffer);
115 }
m_copy(void * src,void * dest,size_t bytes)116 static void m_copy(void *src, void *dest, size_t bytes) {
117     memcpy(dest, src, bytes);
118 }
119 
120 static struct mspack_system read_files_write_md5 = {
121     &m_open, &m_close, &m_read, &m_write, &m_seek,
122     &m_tell, &m_msg, &m_alloc, &m_free, &m_copy, NULL
123 };
124