51 broke -E logic completely, rewise it
[tfcrypt.git] / tfc_misc.c
1 /*
2  * tfcrypt -- high security Threefish encryption tool.
3  *
4  * tfcrypt is copyrighted:
5  * Copyright (C) 2012-2019 Andrey Rys. All rights reserved.
6  *
7  * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files (the
11  * "Software"), to deal in the Software without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28
29 #include "tfcrypt.h"
30
31 size_t blk_len_adj(tfc_fsize filelen, tfc_fsize read_already, size_t blklen)
32 {
33         if (filelen == NOFSIZE) return blklen;
34         return ((filelen - read_already) >= blklen) ? blklen : (filelen - read_already);
35 }
36
37 tfc_yesno xor_shrink(void *dst, size_t szdst, const void *src, size_t szsrc)
38 {
39         unsigned char *udst = dst;
40         const unsigned char *usrc = src;
41         size_t x, y;
42
43         if ((szsrc % szdst) != 0) return NO;
44         if (szdst >= szsrc) {
45                 if (szdst == szsrc) {
46                         memmove(dst, src, szsrc);
47                         return YES;
48                 }
49                 return NO;
50         }
51
52         memset(dst, 0, szdst);
53         for (x = 0; x < (szsrc / szdst); x++) {
54                 for (y = 0; y < szdst; y++) udst[y] ^= usrc[(x*szdst)+y];
55         }
56
57         return YES;
58 }
59
60 tfc_yesno str_empty(const char *str)
61 {
62         if (!*str) return YES;
63         return NO;
64 }
65
66 int xxopen(tfc_yesno noerr, const char *pathname, int flags)
67 {
68         int r;
69
70         if ((flags & O_WRONLY || flags & O_RDWR)) {
71                 if (read_only == YES) flags = O_RDONLY;
72                 else flags |= write_flags;
73         }
74
75         flags |= O_LARGEFILE;
76         r = open(pathname, flags, 0666);
77         if (noerr == NO && r == -1) xerror(NO, NO, YES, "%s", pathname);
78         return r;
79 }
80
81 int xopen(const char *pathname, int flags)
82 {
83         return xxopen(NO, pathname, flags);
84 }
85
86 void xclose(int fd)
87 {
88         if (fd < 3) return;
89         if (close(fd) == -1) xerror(YES, NO, NO, "close(%d)", fd);
90 }
91
92 const char *tfc_modename(int mode)
93 {
94         switch (mode) {
95                 case TFC_MODE_CTR: return "CTR";
96                 case TFC_MODE_STREAM: return "STREAM";
97                 case TFC_MODE_XTS: return "XTS";
98                 case TFC_MODE_ECB: return "ECB";
99                 case TFC_MODE_CBC: return "CBC";
100                 case TFC_MODE_PCBC: return "PCBC";
101         }
102
103         return NULL;
104 }
105
106 tfc_yesno tfc_is_freestream(int mode)
107 {
108         switch (mode) {
109                 case TFC_MODE_PLAIN:
110                 case TFC_MODE_XOR:
111                 case TFC_MODE_STREAM: return YES;
112         }
113
114         return NO;
115 }
116
117 void tfc_getcurtime(tfc_useconds *tx)
118 {
119         struct timespec t;
120         memset(&t, 0, sizeof(t));
121
122         clock_gettime(CLOCK_MONOTONIC, &t);
123         *tx = (tfc_useconds)t.tv_sec * 1000000 + (t.tv_nsec / 1000);
124
125         memset(&t, 0, sizeof(t));
126 }
127
128 char *tfc_format_time(tfc_useconds t)
129 {
130         tfc_useconds secs, dsecs;
131         unsigned days, hours, minutes, seconds;
132         static char r[128];
133
134         secs = (tfc_useconds)TFC_UTODSECS(t);
135         dsecs = (tfc_useconds)(t - (secs * 1000000));
136
137         days = secs / 86400;
138         hours = (secs / 3600) % 24;
139         minutes = (secs / 60) % 60;
140         seconds = secs % 60;
141
142         if (days > 0) sprintf(r, "%ud,%02u:%02u:%02u.%04u", days, hours, minutes, seconds, (unsigned)(dsecs / 100));
143         else if (hours > 0) sprintf(r, "%02u:%02u:%02u.%04u", hours, minutes, seconds, (unsigned)(dsecs / 100));
144         else if (minutes > 0) sprintf(r, "%02u:%02u.%04u", minutes, seconds, (unsigned)(dsecs / 100));
145         else sprintf(r, "%02u.%04u", seconds, (unsigned)(dsecs / 100));
146
147         return r;
148 }
149
150 char *tfc_format_pid(const char *str)
151 {
152         static char r[128];
153         size_t n;
154
155         n = xstrlcpy(r, str, sizeof(r));
156         if (show_pid == YES && sizeof(r)-n >= 22) sprintf(r+n, "[%lu]", (unsigned long)progpid);
157
158         return r;
159 }
160
161 tfc_fsize tfc_fdsize(int fd)
162 {
163         off_t l, cur;
164
165         cur = lseek(fd, 0L, SEEK_CUR);
166         l = lseek(fd, 0L, SEEK_SET);
167         if (l == -1) return NOFSIZE;
168         l = lseek(fd, 0L, SEEK_END);
169         if (l == -1) return NOFSIZE;
170         lseek(fd, cur, SEEK_SET);
171
172         return (tfc_fsize)l;
173 }
174
175 tfc_fsize tfc_fdgetpos(int fd)
176 {
177         off_t t;
178
179         t = lseek(fd, 0L, SEEK_CUR);
180         if (t == (off_t)-1) return NOFSIZE;
181         return (tfc_fsize)t;
182 }
183
184 tfc_fsize tfc_fnamesize(char *fname, tfc_yesno noexit)
185 {
186         int fnmfd;
187         tfc_fsize ret;
188         char *s, T[2];
189
190         if (!fname) return 0;
191
192         s = strchr(fname, ':');
193         if (s && s[1] && (s[1] == '+' || s[1] == '-' || s[1] == '*' || s[1] == '/')) {
194                 memcpy(T, s, 2);
195                 memset(s, 0, 2);
196         }
197
198         fnmfd = xxopen(YES, fname, O_RDONLY);
199         if (s) memcpy(s, T, 2);
200         if (fnmfd == -1) {
201                 xerror(noexit, NO, YES, "%s", fname);
202                 return NOFSIZE;
203         }
204         ret = tfc_fdsize(fnmfd);
205         if (ret == NOFSIZE) {
206                 xerror(noexit, NO, YES, "%s: not a seekable file", fname);
207                 return ret;
208         }
209         xclose(fnmfd);
210
211         return ret;
212 }
213
214 tfc_fsize tfc_modifysize(tfc_fsize szmodify, const char *szspec)
215 {
216         tfc_fsize t;
217         const char *s;
218         char *stoi, c;
219
220         if (szmodify == NOFSIZE) return NOFSIZE;
221         if (!szspec) return szmodify;
222         s = szspec;
223
224         if (*s != ':') return szmodify;
225         s++;
226         if (!(*s == '+' || *s == '-' || *s == '*' || *s == '/')) return szmodify;
227         c = *s;
228         s++;
229         if (strchr(s, '/') || strchr(s, '.')) return szmodify;
230
231         t = tfc_humanfsize(s, &stoi);
232         if (!str_empty(stoi)) return szmodify;
233
234         switch (c) {
235                 case '+': szmodify += t; break;
236                 case '-': szmodify -= t; break;
237                 case '*': szmodify *= t; break;
238                 case '/': szmodify /= t; break;
239                 default: break;
240         }
241
242         return szmodify;
243 }
244
245 void fcopy_matime(int fd, const struct stat *st)
246 {
247         struct timeval times[2];
248
249         times[1].tv_sec = times[0].tv_sec = st->st_mtime;
250         times[1].tv_usec = times[0].tv_usec = 0;
251         if (futimes(fd, times) == -1) xerror(YES, NO, YES, "futimes(%d)", fd);
252 }
253
254 static void char_to_nul(char *s, size_t l, int c)
255 {
256         while (*s && l) { if (*s == c) { *s = 0; break; } s++; l--; }
257 }
258
259 tfc_yesno xfgets(char *s, size_t n, FILE *f)
260 {
261         memset(s, 0, n);
262
263         if (fgets(s, (int)n, f) == s) {
264                 char_to_nul(s, n, '\n');
265                 return YES;
266         }
267
268         return NO;
269 }
270
271 tfc_yesno isbase64(const char *s)
272 {
273         while (*s) {
274                 if (*s >= 'g' && *s <= 'z') return YES;
275                 if (*s >= 'G' && *s <= 'Z') return YES;
276                 if (*s == '+' || *s == '/' || *s == '=') return YES;
277                 s++;
278         }
279         return NO;
280 }
281
282 static int chrbin(char x)
283 {
284         if (x >= '0' && x <= '9')
285                 return x - '0';
286         if (x >= 'A' && x <= 'F')
287                 return x - 'A' + 10;
288         if (x >= 'a' && x <= 'f')
289                 return x - 'a' + 10;
290         return 0;
291 }
292
293 void hex2bin(void *d, const char *s)
294 {
295         const char *S = s;
296         char *D = d;
297         int x = 0;
298
299         while (*s) {
300                 if ((s-S) % 2) {
301                         x = (x << 4) ^ chrbin(*s);
302                         *D = x; D++;
303                 }
304                 else x = chrbin(*s);
305                 s++;
306         }
307 }