1 // Fuzzy Hashing by Jesse Kornblum
2 // Copyright (C) 2012 Kyrus
3 // Copyright (C) 2008 ManTech International Corporation
4 //
5 // $Id: find-file-size.c 144 2012-04-24 14:59:33Z jessekornblum $
6 //
7
8 #include "main.h"
9
10 #ifndef _WIN32
11
12 // Return the size, in bytes of an open file stream. On error, return 0
13 #if defined (__LINUX__)
14
15
find_file_size(FILE * f)16 off_t find_file_size(FILE *f)
17 {
18 off_t num_sectors = 0, sector_size = 0;
19 int fd = fileno(f);
20 struct stat sb;
21
22 if (fstat(fd,&sb))
23 return 0;
24
25 if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
26 return sb.st_size;
27
28 #ifdef HAVE_SYS_IOCTL_H
29 #ifdef HAVE_SYS_MOUNT_H
30 if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode))
31 {
32 #if defined(_IO) && defined(BLKGETSIZE)
33 if (ioctl(fd, BLKGETSIZE, &num_sectors))
34 {
35 return 0;
36 }
37 #else
38 // If we can't run the ioctl call, we can't do anything here
39 return 0;
40 #endif // ifdefined _IO and BLKGETSIZE
41
42
43 #if defined(_IO) && defined(BLKSSZGET)
44 if (ioctl(fd, BLKSSZGET, §or_size))
45 {
46 return 0;
47 }
48 if (0 == sector_size)
49 sector_size = 512;
50 #else
51 sector_size = 512;
52 #endif // ifdef _IO and BLKSSZGET
53
54 return (num_sectors * sector_size);
55 }
56 #endif // #ifdef HAVE_SYS_MOUNT_H
57 #endif // #ifdef HAVE_SYS_IOCTL_H
58
59 return 0;
60 }
61
62 #elif defined (__APPLE__)
63
find_file_size(FILE * f)64 off_t find_file_size(FILE *f) {
65 struct stat info;
66 off_t total = 0;
67 off_t original = ftello(f);
68 int fd = fileno(f);
69 uint32_t blocksize = 0;
70 uint64_t blockcount = 0;
71
72 // I'd prefer not to use fstat as it will follow symbolic links. We don't
73 // follow symbolic links. That being said, all symbolic links *should*
74 // have been caught before we got here.
75
76 if (fstat(fd, &info))
77 {
78 return 0;
79 }
80
81 #ifdef HAVE_SYS_IOCTL_H
82 // Block devices, like /dev/hda, don't return a normal filesize.
83 // If we are working with a block device, we have to ask the operating
84 // system to tell us the true size of the device.
85 //
86 // This isn't the recommended way to do check for block devices,
87 // but using S_ISBLK(info.stmode) wasn't working.
88 if (info.st_mode & S_IFBLK)
89 {
90 // Get the block size
91 if (ioctl(fd, DKIOCGETBLOCKSIZE,&blocksize) < 0)
92 {
93 return 0;
94 }
95
96 // Get the number of blocks
97 if (ioctl(fd, DKIOCGETBLOCKCOUNT, &blockcount) < 0)
98 {
99 }
100
101 total = blocksize * blockcount;
102 }
103 #endif // ifdef HAVE_IOCTL_H
104
105 else
106 {
107 if ((fseeko(f,0,SEEK_END)))
108 return 0;
109 total = ftello(f);
110 if ((fseeko(f,original,SEEK_SET)))
111 return 0;
112 }
113
114 return (total - original);
115 }
116
117
118 #else // ifdef __APPLE__
119
120 // This is code for general UNIX systems
121 // (e.g. NetBSD, FreeBSD, OpenBSD, etc)
122
123 static off_t
midpoint(off_t a,off_t b,long blksize)124 midpoint (off_t a, off_t b, long blksize)
125 {
126 off_t aprime = a / blksize;
127 off_t bprime = b / blksize;
128 off_t c, cprime;
129
130 cprime = (bprime - aprime) / 2 + aprime;
131 c = cprime * blksize;
132
133 return c;
134 }
135
136
137
find_dev_size(int fd,int blk_size)138 off_t find_dev_size(int fd, int blk_size)
139 {
140
141 off_t curr = 0, amount = 0;
142 void *buf;
143
144 if (blk_size == 0)
145 return 0;
146
147 buf = malloc(blk_size);
148
149 for (;;) {
150 ssize_t nread;
151
152 lseek(fd, curr, SEEK_SET);
153 nread = read(fd, buf, blk_size);
154 if (nread < blk_size)
155 {
156 if (nread <= 0)
157 {
158 if (curr == amount)
159 {
160 free(buf);
161 lseek(fd, 0, SEEK_SET);
162 return amount;
163 }
164 curr = midpoint(amount, curr, blk_size);
165 }
166 else
167 { // 0 < nread < blk_size
168 free(buf);
169 lseek(fd, 0, SEEK_SET);
170 return amount + nread;
171 }
172 }
173 else
174 {
175 amount = curr + blk_size;
176 curr = amount * 2;
177 }
178 }
179
180 free(buf);
181 lseek(fd, 0, SEEK_SET);
182 return amount;
183 }
184
185
find_file_size(FILE * f)186 off_t find_file_size(FILE *f)
187 {
188 int fd = fileno(f);
189 struct stat sb;
190
191 if (fstat(fd,&sb))
192 return 0;
193
194 if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
195 return sb.st_size;
196 else if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode))
197 return find_dev_size(fd,sb.st_blksize);
198
199 return 0;
200 }
201
202 #endif // ifdef __LINUX__
203 #endif // ifndef _WIN32
204
205 #if defined(_WIN32)
find_file_size(FILE * f)206 off_t find_file_size(FILE *f)
207 {
208 off_t total = 0, original = ftello(f);
209
210 // Windows does not support running fstat on block devices,
211 // so there's no point in mucking about with them.
212
213 if ((fseeko(f,0,SEEK_END)))
214 return 0;
215
216 total = ftello(f);
217 if ((fseeko(f,original,SEEK_SET)))
218 return 0;
219
220 return total;
221 }
222 #endif // ifdef _WIN32
223