forked from matildeopbravo/shafa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fsize_.h
136 lines (117 loc) · 5.18 KB
/
fsize_.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <stdio.h>
#include <stdlib.h>
size_t fsize(FILE *fp_in, char const *filename, size_t *the_block_size,
size_t *size_of_last_block);
/*
Function fsize() to get the size of files and the number of blocks contained
in the file (for a given block size).
The function works for files already opened (and pointed by <fp_in>) and also
for files not already opened (in this case the file is identified by
<filename>).
This function works on files of any size and on any operating system and on
any machine architecture. Bear in mind that for files larger than 2 GBytes the
function is very slow. Block size of FSIZE_DEFAULT_BLOCK_SIZE should yield
the best results in terms of execution time but it may be dependent of the
operating system and/or machine architecture/hardware.
The function returns directly the number of blocks contained in the file of
a given block size in <*the_block_size>. It also returns, indirectly, the
actual block size used in <*the_block_size>, which may be different than
the original size in <*the_block_size>. If the original value of
<*the_block_size> is smaller than FSIZE_MIN_BLOCK_SIZE then
FSIZE_MIN_BLOCK_SIZE is used. Also, if the original value of <*the_block_size>
is bigger than FSIZE_MAX_BLOCK_SIZE then FSIZE_MAX_BLOCK_SIZE is used. If the
original value of
<*the_block_size> is equal to 0 (zero) then FSIZE_DEFAULT_BLOCK_SIZE is used.
Bear in mind that the last block may have a smaller size and its value is
returned in <*size_of_last_block>.
If n_blocks is the returned number of blocks then:
total_file_size = n_blocks * <*the_block_size> + <*size_of_last_block>
Arguments:
FILE *fp_in - a file pointer (if NULL, then the file is identified by
<filename>) unsigned char *filename - if NULL then file must be identified by
< *fp> unsigned long *the_block_size - this is used to pass the intended size
for each block and to receive the actual block size used long
*size_of_last_block - this is used to receive the size of the last block
This code is open source and free to use as long as the original author is
identified.
(c) 2020, Bruno A.F. Dias - University of Minho, Informatics Department
*/
#define FSIZE_DEFAULT_BLOCK_SIZE 524288 // Default block size = 512 KBytes
#define FSIZE_MIN_BLOCK_SIZE 512 // Min block size = 512 Bytes
#define FSIZE_MAX_BLOCK_SIZE 67108864 // Max block size = 64 MBytes
#define FSIZE_MAX_NUMBER_OF_BLOCKS \
4294967296 // Max number of blocks that can be returned = 2^32 blocks
#define FSIZE_MAX_SIZE_FSEEK \
2147483648 // Max size permitted in fseek/ftell functions = 2 GBytes
#define FSIZE_ERROR_BLOCK_SIZE -1 // Error: Block size is larger than max value
#define FSIZE_ERROR_NUMBER_OF_BLOCKS \
-2 // Error: Number of Blocks exceeds max value permitted
#define FSIZE_ERROR_IN_FILE -3 // Error: Opening or reading file
#define FSIZE_ERROR_IN_FTELL -1L // Error: When using ftell()
size_t fsize(FILE *fp_in, char const *filename, size_t *the_block_size,
size_t *size_of_last_block) {
size_t total;
size_t n_blocks;
size_t n_read, block_size;
unsigned char *temp_buffer;
int fseek_error;
FILE *fp;
block_size = *the_block_size;
if (block_size > FSIZE_MAX_BLOCK_SIZE)
return (FSIZE_ERROR_BLOCK_SIZE);
if (block_size == 0UL)
block_size = FSIZE_DEFAULT_BLOCK_SIZE;
if (block_size < FSIZE_MIN_BLOCK_SIZE)
block_size = FSIZE_MIN_BLOCK_SIZE;
*the_block_size = block_size;
if (filename == NULL || *filename == 0)
fp = fp_in;
else {
fp = fopen(filename, "rb");
if (fp == NULL)
return (FSIZE_ERROR_IN_FILE);
}
fseek_error = fseek(fp, 0L, SEEK_SET);
if (fseek_error)
return (FSIZE_ERROR_IN_FILE);
fseek_error = fseek(fp, 0L, SEEK_END);
if (!fseek_error) {
total = ftell(fp);
if (total == (size_t)FSIZE_ERROR_IN_FTELL)
return (FSIZE_ERROR_IN_FILE);
n_blocks = total / block_size;
if (n_blocks * block_size == total)
*size_of_last_block = block_size;
else {
*size_of_last_block = total - n_blocks * block_size;
n_blocks++;
}
return (n_blocks);
}
n_blocks = FSIZE_MAX_SIZE_FSEEK / block_size -
1; // In reality fseek() can't handle FSIZE_MAX_SIZE_FSEEK of
// 2GBytes, so let's use a smaller size
fseek_error = fseek(fp, n_blocks * block_size, SEEK_SET);
if (fseek_error)
return (FSIZE_ERROR_IN_FILE);
temp_buffer = malloc(sizeof(unsigned char) * block_size);
do {
n_blocks++;
n_read = fread(temp_buffer, sizeof(unsigned char), block_size, fp);
} while (n_read == block_size && n_blocks <= FSIZE_MAX_NUMBER_OF_BLOCKS);
free(temp_buffer);
if (n_blocks > FSIZE_MAX_NUMBER_OF_BLOCKS)
return (FSIZE_ERROR_NUMBER_OF_BLOCKS);
if (n_read == 0L) {
*size_of_last_block = block_size;
n_blocks--;
} else
*size_of_last_block = n_read;
if (filename == NULL || *filename == 0) {
fseek_error = fseek(fp, 0L, SEEK_SET);
if (fseek_error)
return (FSIZE_ERROR_IN_FILE);
} else
fclose(fp);
return (n_blocks);
}