/* * Misc FS utilities * * Copyright (c) 2016-2017 Fabrice Bellard * * 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 substantial 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 "cutils.h" #include "list.h" #include "fs_utils.h" /* last byte is the version */ const uint8_t encrypted_file_magic[4] = { 0xfb, 0xa2, 0xe9, 0x01 }; char *compose_path(const char *path, const char *name) { int path_len, name_len; char *d, *q; if (path[0] == '\0') { d = strdup(name); } else { path_len = strlen(path); name_len = strlen(name); d = malloc(path_len + 1 + name_len + 1); q = d; memcpy(q, path, path_len); q += path_len; if (path[path_len - 1] != '/') *q++ = '/'; memcpy(q, name, name_len + 1); } return d; } char *compose_url(const char *base_url, const char *name) { if (strchr(name, ':')) { return strdup(name); } else { return compose_path(base_url, name); } } void skip_line(const char **pp) { const char *p; p = *pp; while (*p != '\n' && *p != '\0') p++; if (*p == '\n') p++; *pp = p; } char *quoted_str(const char *str) { const char *s; char *q; int c; char *buf; if (str[0] == '\0') goto use_quote; s = str; while (*s != '\0') { if (*s <= ' ' || *s > '~') goto use_quote; s++; } return strdup(str); use_quote: buf = malloc(strlen(str) * 4 + 2 + 1); q = buf; s = str; *q++ = '"'; while (*s != '\0') { c = *(uint8_t *)s; if (c < ' ' || c == 127) { q += sprintf(q, "\\x%02x", c); } else if (c == '\\' || c == '\"') { q += sprintf(q, "\\%c", c); } else { *q++ = c; } s++; } *q++ = '"'; *q = '\0'; return buf; } int parse_fname(char *buf, int buf_size, const char **pp) { const char *p; char *q; int c, h; p = *pp; while (isspace_nolf(*p)) p++; if (*p == '\0') return -1; q = buf; if (*p == '"') { p++; for(;;) { c = *p++; if (c == '\0' || c == '\n') { return -1; } else if (c == '\"') { break; } else if (c == '\\') { c = *p++; switch(c) { case '\'': case '\"': case '\\': goto add_char; case 'n': c = '\n'; goto add_char; case 'r': c = '\r'; goto add_char; case 't': c = '\t'; goto add_char; case 'x': h = from_hex(*p++); if (h < 0) return -1; c = h << 4; h = from_hex(*p++); if (h < 0) return -1; c |= h; goto add_char; default: return -1; } } else { add_char: if (q >= buf + buf_size - 1) return -1; *q++ = c; } } } else { while (!isspace_nolf(*p) && *p != '\0' && *p != '\n') { if (q >= buf + buf_size - 1) return -1; *q++ = *p++; } } *q = '\0'; *pp = p; return 0; } int parse_uint32_base(uint32_t *pval, const char **pp, int base) { const char *p, *p1; p = *pp; while (isspace_nolf(*p)) p++; *pval = strtoul(p, (char **)&p1, base); if (p1 == p) return -1; *pp = p1; return 0; } int parse_uint64_base(uint64_t *pval, const char **pp, int base) { const char *p, *p1; p = *pp; while (isspace_nolf(*p)) p++; *pval = strtoull(p, (char **)&p1, base); if (p1 == p) return -1; *pp = p1; return 0; } int parse_uint64(uint64_t *pval, const char **pp) { return parse_uint64_base(pval, pp, 0); } int parse_uint32(uint32_t *pval, const char **pp) { return parse_uint32_base(pval, pp, 0); } int parse_time(uint32_t *psec, uint32_t *pnsec, const char **pp) { const char *p; uint32_t v, m; p = *pp; if (parse_uint32(psec, &p) < 0) return -1; v = 0; if (*p == '.') { p++; /* XXX: inefficient */ m = 1000000000; v = 0; while (*p >= '0' && *p <= '9') { m /= 10; v += (*p - '0') * m; p++; } } *pnsec = v; *pp = p; return 0; } int parse_file_id(FSFileID *pval, const char **pp) { return parse_uint64_base(pval, pp, 16); } char *file_id_to_filename(char *buf, FSFileID file_id) { sprintf(buf, "%016" PRIx64, file_id); return buf; } void encode_hex(char *str, const uint8_t *buf, int len) { int i; for(i = 0; i < len; i++) sprintf(str + 2 * i, "%02x", buf[i]); } int decode_hex(uint8_t *buf, const char *str, int len) { int h0, h1, i; for(i = 0; i < len; i++) { h0 = from_hex(str[2 * i]); if (h0 < 0) return -1; h1 = from_hex(str[2 * i + 1]); if (h1 < 0) return -1; buf[i] = (h0 << 4) | h1; } return 0; } /* return NULL if no end of header found */ const char *skip_header(const char *p) { p = strstr(p, "\n\n"); if (!p) return NULL; return p + 2; } /* return 0 if OK, < 0 if error */ int parse_tag(char *buf, int buf_size, const char *str, const char *tag) { char tagname[128], *q; const char *p, *p1; int len; p = str; for(;;) { if (*p == '\0' || *p == '\n') break; q = tagname; while (*p != ':' && *p != '\n' && *p != '\0') { if ((q - tagname) < sizeof(tagname) - 1) *q++ = *p; p++; } *q = '\0'; if (*p != ':') return -1; p++; while (isspace_nolf(*p)) p++; p1 = p; p = strchr(p, '\n'); if (!p) len = strlen(p1); else len = p - p1; if (!strcmp(tagname, tag)) { if (len > buf_size - 1) len = buf_size - 1; memcpy(buf, p1, len); buf[len] = '\0'; return 0; } if (!p) break; else p++; } return -1; } int parse_tag_uint64(uint64_t *pval, const char *str, const char *tag) { char buf[64]; const char *p; if (parse_tag(buf, sizeof(buf), str, tag)) return -1; p = buf; return parse_uint64(pval, &p); } int parse_tag_file_id(FSFileID *pval, const char *str, const char *tag) { char buf[64]; const char *p; if (parse_tag(buf, sizeof(buf), str, tag)) return -1; p = buf; return parse_uint64_base(pval, &p, 16); } int parse_tag_version(const char *str) { uint64_t version; if (parse_tag_uint64(&version, str, "Version")) return -1; return version; } BOOL is_url(const char *path) { return (strstart(path, "http:", NULL) || strstart(path, "https:", NULL) || strstart(path, "file:", NULL)); }