/* * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef PATH_MAX #define PATH_MAX 256 #endif #ifndef SSIZE_MAX #define SSIZE_MAX LONG_MAX #endif unsigned long UtilServerTs(void) { struct timeval tv; unsigned long ts; gettimeofday(&tv, NULL); ts = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); return ts; } unsigned long UtilLastModified(char *path) { struct stat st; unsigned long ts; if (stat(path, &st) == 0) { ts = (st.st_mtim.tv_sec * 1000) + (st.st_mtim.tv_nsec / 1000000); return ts; } else { return 0; } } int UtilMkdir(const char *dir, const mode_t mode) { char tmp[PATH_MAX]; char *p = NULL; struct stat st; size_t len; len = strnlen(dir, PATH_MAX); if (!len || len == PATH_MAX) { errno = ENAMETOOLONG; return -1; } memcpy(tmp, dir, len); tmp[len] = '\0'; if (tmp[len - 1] == '/') { tmp[len - 1] = '\0'; } if (stat(tmp, &st) == 0 && S_ISDIR(st.st_mode)) { return 0; } for (p = tmp + 1; *p; p++) { if (*p == '/') { *p = 0; if (stat(tmp, &st) != 0) { if (mkdir(tmp, mode) < 0) { /* errno already set by mkdir() */ return -1; } } else if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; return -1; } *p = '/'; } } if (stat(tmp, &st) != 0) { if (mkdir(tmp, mode) < 0) { /* errno already set by mkdir() */ return -1; } } else if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; return -1; } return 0; } int UtilSleepMillis(long ms) { struct timespec ts; int res; ts.tv_sec = ms / 1000; ts.tv_nsec = (ms % 1000) * 1000000; res = nanosleep(&ts, &ts); return res; } size_t UtilParseBytes(char *str) { size_t bytes = 0; while (*str) { if (isdigit((unsigned char) *str)) { bytes *= 10; bytes += *str - '0'; } else { switch (*str) { case 'K': bytes *= 1024; break; case 'M': bytes *= pow(1024, 2); break; case 'G': bytes *= pow(1024, 3); break; case 'k': bytes *= 1000; break; case 'm': bytes *= pow(1000, 2); break; case 'g': bytes *= pow(1000, 3); break; default: return 0; } if (*(str + 1)) { return 0; } } str++; } return bytes; } ssize_t UtilGetDelim(char **linePtr, size_t * n, int delim, FILE * stream) { char *curPos, *newLinePtr; size_t newLinePtrLen; int c; if (!linePtr || !n || !stream) { errno = EINVAL; return -1; } if (*linePtr == NULL) { *n = 128; if (!(*linePtr = Malloc(*n))) { errno = ENOMEM; return -1; } } curPos = *linePtr; while (1) { c = fgetc(stream); if (ferror(stream) || (c == EOF && curPos == *linePtr)) { return -1; } if (c == EOF) { break; } if ((*linePtr + *n - curPos) < 2) { if (SSIZE_MAX / 2 < *n) { #ifdef EOVERFLOW errno = EOVERFLOW; #else errno = ERANGE; #endif return -1; } newLinePtrLen = *n * 2; if (!(newLinePtr = Realloc(*linePtr, newLinePtrLen))) { errno = ENOMEM; return -1; } curPos = newLinePtr + (curPos - *linePtr); *linePtr = newLinePtr; *n = newLinePtrLen; } *curPos++ = (char) c; if (c == delim) { break; } } *curPos = '\0'; return (ssize_t) (curPos - *linePtr); } ssize_t UtilGetLine(char **linePtr, size_t * n, FILE * stream) { return UtilGetDelim(linePtr, n, '\n', stream); } size_t UtilStreamCopy(FILE * in, FILE * out) { size_t bytes = 0; int c; while (1) { c = fgetc(in); if (feof(in)) { break; } if (ferror(in)) { if (errno == EAGAIN) { clearerr(in); continue; } else { break; } } fputc(c, out); bytes++; } return bytes; }