1 /* $Id: qfits_md5.c,v 1.9 2007/01/10 08:53:45 yjung Exp $
2 *
3 * This file is part of the ESO QFITS Library
4 * Copyright (C) 2001-2004 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 * $Author: yjung $
23 * $Date: 2007/01/10 08:53:45 $
24 * $Revision: 1.9 $
25 * $Name: qfits-6_2_0 $
26 */
27
28 /*-----------------------------------------------------------------------------
29 Includes
30 -----------------------------------------------------------------------------*/
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37
38 #include "qfits_md5.h"
39
40 #include "md5.h"
41 #include "qfits_std.h"
42 #include "qfits_error.h"
43
44 /*-----------------------------------------------------------------------------
45 Defines
46 -----------------------------------------------------------------------------*/
47
48 /* Size of an MD5 hash in bytes (32 bytes are 128 bits) */
49 #define MD5HASHSZ 32
50
51 /*----------------------------------------------------------------------------*/
52 /**
53 * @defgroup qfits_md5 FITS data block MD5 computation routine
54 *
55 * This module offers MD5 computation over all data areas of a FITS file.
56 *
57 */
58 /*----------------------------------------------------------------------------*/
59 /**@{*/
60
61 /*-----------------------------------------------------------------------------
62 Function code
63 -----------------------------------------------------------------------------*/
64
65 /*----------------------------------------------------------------------------*/
66 /**
67 @brief Compute the MD5 hash of data zones in a FITS file.
68 @param filename Name of the FITS file to examine.
69 @return 1 statically allocated character string, or NULL.
70
71 This function expects the name of a FITS file.
72 It will compute the MD5 hash on all data blocks in the main data section
73 and possibly extensions (including zero-padding blocks if necessary) and
74 return it as a string suitable for inclusion into a FITS keyword.
75
76 The returned string is statically allocated inside this function,
77 so do not free it or modify it. This function returns NULL in case
78 of error.
79 */
80 /*----------------------------------------------------------------------------*/
qfits_datamd5(const char * filename)81 const char * qfits_datamd5(const char * filename)
82 {
83 static char datamd5[MD5HASHSZ+1];
84 struct MD5Context ctx;
85 unsigned char digest[16];
86 FILE * in;
87 char buf[FITS_BLOCK_SIZE];
88 char * buf_c;
89 int i;
90 int in_header;
91 int check_fits;
92
93 /* Check entries */
94 if (filename==NULL) return NULL;
95 /* Open input file */
96 if ((in=fopen(filename, "r"))==NULL) {
97 qfits_error("cannot open file %s", filename);
98 return NULL;
99 }
100 /* Initialize all variables */
101 MD5Init(&ctx);
102 in_header=1;
103 check_fits=0;
104 /* Loop over input file */
105 while (fread(buf, 1, FITS_BLOCK_SIZE, in)==FITS_BLOCK_SIZE) {
106 /* First time in the loop: check the file is FITS */
107 if (check_fits==0) {
108 /* Examine first characters in block */
109 if (buf[0]!='S' ||
110 buf[1]!='I' ||
111 buf[2]!='M' ||
112 buf[3]!='P' ||
113 buf[4]!='L' ||
114 buf[5]!='E' ||
115 buf[6]!=' ' ||
116 buf[7]!=' ' ||
117 buf[8]!='=') {
118 qfits_error("file [%s] is not FITS\n", filename);
119 fclose(in);
120 return NULL;
121 } else {
122 check_fits=1;
123 }
124 }
125 if (in_header) {
126 buf_c = buf;
127 for (i=0; i<FITS_NCARDS; i++) {
128 if (buf_c[0]=='E' &&
129 buf_c[1]=='N' &&
130 buf_c[2]=='D' &&
131 buf_c[3]==' ') {
132 in_header=0;
133 break;
134 }
135 buf_c += FITS_LINESZ;
136 }
137 } else {
138 /* If current block is a data block */
139 /* Try to locate an extension header */
140 if (buf[0]=='X' &&
141 buf[1]=='T' &&
142 buf[2]=='E' &&
143 buf[3]=='N' &&
144 buf[4]=='S' &&
145 buf[5]=='I' &&
146 buf[6]=='O' &&
147 buf[7]=='N' &&
148 buf[8]=='=') {
149 in_header=1;
150 buf_c = buf;
151 for (i=0; i<FITS_NCARDS; i++) {
152 /* Try to find an END marker in this block */
153 if (buf_c[0]=='E' &&
154 buf_c[1]=='N' &&
155 buf_c[2]=='D' &&
156 buf_c[3]==' ') {
157 /* Found END marker in same block as XTENSION */
158 in_header=0;
159 break;
160 }
161 buf_c += FITS_LINESZ;
162 }
163 } else {
164 MD5Update(&ctx, (unsigned char *)buf, FITS_BLOCK_SIZE);
165 }
166 }
167 }
168 fclose(in);
169 if (check_fits==0) {
170 /* Never went through the read loop: file is not FITS */
171 qfits_error("file [%s] is not FITS", filename);
172 return NULL;
173 }
174 /* Got to the end of file: summarize */
175 MD5Final(digest, &ctx);
176 /* Write digest into a string */
177 sprintf(datamd5,
178 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
179 digest[ 0],
180 digest[ 1],
181 digest[ 2],
182 digest[ 3],
183 digest[ 4],
184 digest[ 5],
185 digest[ 6],
186 digest[ 7],
187 digest[ 8],
188 digest[ 9],
189 digest[10],
190 digest[11],
191 digest[12],
192 digest[13],
193 digest[14],
194 digest[15]);
195 return datamd5;
196 }
197
198 /**@}*/
199