Line data Source code
1 : /* Compute CRC32 checksum of file contents.
2 : Copyright (C) 2006 Red Hat, Inc.
3 : This file is part of elfutils.
4 :
5 : This file is free software; you can redistribute it and/or modify
6 : it under the terms of either
7 :
8 : * the GNU Lesser General Public License as published by the Free
9 : Software Foundation; either version 3 of the License, or (at
10 : your option) any later version
11 :
12 : or
13 :
14 : * the GNU General Public License as published by the Free
15 : Software Foundation; either version 2 of the License, or (at
16 : your option) any later version
17 :
18 : or both in parallel, as here.
19 :
20 : elfutils is distributed in the hope that it will be useful, but
21 : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : General Public License for more details.
24 :
25 : You should have received copies of the GNU General Public License and
26 : the GNU Lesser General Public License along with this program. If
27 : not, see <http://www.gnu.org/licenses/>. */
28 :
29 : #ifdef HAVE_CONFIG_H
30 : # include <config.h>
31 : #endif
32 :
33 : #include "libeu.h"
34 : #include <errno.h>
35 : #include <unistd.h>
36 : #include <sys/stat.h>
37 : #include <sys/mman.h>
38 : #include "system.h"
39 :
40 : int
41 61 : crc32_file (int fd, uint32_t *resp)
42 : {
43 61 : unsigned char buffer[1024 * 8];
44 61 : uint32_t crc = 0;
45 61 : off_t off = 0;
46 61 : ssize_t count;
47 :
48 61 : struct stat st;
49 61 : if (fstat (fd, &st) == 0)
50 : {
51 : /* Try mapping in the file data. */
52 61 : size_t mapsize = st.st_size;
53 61 : void *mapped = mmap (NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
54 61 : if (mapped == MAP_FAILED && errno == ENOMEM)
55 : {
56 0 : const size_t pagesize = sysconf (_SC_PAGESIZE);
57 0 : mapsize = ((mapsize / 2) + pagesize - 1) & -pagesize;
58 0 : while (mapsize >= pagesize
59 0 : && (mapped = mmap (NULL, mapsize, PROT_READ, MAP_PRIVATE,
60 0 : fd, 0)) == MAP_FAILED && errno == ENOMEM)
61 0 : mapsize /= 2;
62 : }
63 61 : if (mapped != MAP_FAILED)
64 : {
65 61 : do
66 : {
67 61 : if (st.st_size <= (off_t) mapsize)
68 : {
69 61 : *resp = crc32 (crc, mapped, st.st_size);
70 61 : munmap (mapped, mapsize);
71 61 : return 0;
72 : }
73 0 : crc = crc32 (crc, mapped, mapsize);
74 0 : off += mapsize;
75 0 : st.st_size -= mapsize;
76 0 : } while (mmap (mapped, mapsize, PROT_READ, MAP_FIXED|MAP_PRIVATE,
77 0 : fd, off) == mapped);
78 0 : munmap (mapped, mapsize);
79 : }
80 : }
81 :
82 0 : while ((count = TEMP_FAILURE_RETRY (pread (fd, buffer, sizeof buffer,
83 : off))) > 0)
84 : {
85 0 : off += count;
86 0 : crc = crc32 (crc, buffer, count);
87 : }
88 :
89 0 : *resp = crc;
90 :
91 0 : return count == 0 ? 0 : -1;
92 : }
|