/** * This is the same as urn_get_sha1(), only the leading "urn:" part * is missing (typically a URN embedded in a GGEP "u"). * * `buf' MUST start with "sha1:" or "bitprint:" indications. Since the * leading "urn:" part is missing, we cannot be lenient. * * Extract the SHA1 out of it, placing it in the supplied `digest' buffer. * * @return whether we successfully extracted the SHA1. */ bool urn_get_sha1_no_prefix(const char *buf, struct sha1 *sha1) { const char *p; size_t len; /* * We handle both "sha1:" and "bitprint:". In the latter case, * the first 32 bytes of the bitprint is the SHA1. */ if ( NULL == (p = is_strcaseprefix(buf, "sha1:")) && NULL == (p = is_strcaseprefix(buf, "bitprint:")) ) return FALSE; len = clamp_strlen(p, SHA1_BASE32_SIZE); if (parse_base32_sha1(p, len, sha1)) return TRUE; /* * Maybe it was generated by clueless people who use an hexadecimal * representation? */ len = clamp_strlen(p, SHA1_BASE16_SIZE); return parse_base16_sha1(p, len, sha1); }
/** * Remove trailing white space from line held within buffer. * * This is meant to be used to validate the line returned by fgets() and to * remove final "\n", or "\r\n" markers as well as any other trailing white * space. * * @param line buffer where line is held * @param size buffer size * @paran lenptr if non-NULL, the final string length is written there * * @return TRUE if we were facing a line terminated by "\n", FALSE otherwise. */ bool file_line_chomp_tail(char *line, size_t size, size_t *lenptr) { size_t len; char *p; len = clamp_strlen(line, size); if (size == len || 0 == len) return FALSE; /* No NUL found or empty string */ if ('\n' != line[len - 1]) return FALSE; /* Truncated line, reading buffer was too small */ p = &line[len - 1]; do { *p = '\0'; } while (p != line && is_ascii_space(*--p)); if (lenptr != NULL) *lenptr = p - line + ('\0' == *p ? 0 : 1); return TRUE; }
G_GNUC_COLD void upload_stats_load_history(void) { FILE *upload_stats_file; file_path_t fp; char line[FILENAME_MAX + 64]; guint lineno = 0; gcu_upload_stats_gui_freeze(); file_path_set(&fp, settings_config_dir(), ul_stats_file); /* open file for reading */ upload_stats_file = file_config_open_read(ul_stats_what, &fp, 1); if (upload_stats_file == NULL) goto done; /* parse, insert names into ul_stats_clist */ while (fgets(line, sizeof(line), upload_stats_file)) { static const struct ul_stats zero_item; struct ul_stats item; struct sha1 sha1_buf; const char *p; size_t i; lineno++; if (line[0] == '#' || line[0] == '\n') continue; p = strchr(line, '\t'); if (NULL == p) goto corrupted; line[p - line] = '\0'; /* line is now the URL-escaped file name */ p++; /* URL-unescape in-place */ if (!url_unescape(line, TRUE)) goto corrupted; item = zero_item; item.pathname = line; for (i = 0; i < 8; i++) { guint64 v; int error; const char *endptr; p = skip_ascii_spaces(p); /* SVN versions up to 15322 had only 6 fields in the history */ if (5 == i && '\0' == *p) break; switch (i) { case 7: /* We have a SHA1 or '*' if none known */ if ('*' != *p) { size_t len = clamp_strlen(p, SHA1_BASE32_SIZE); error = !parse_base32_sha1(p, len, &sha1_buf); item.sha1 = error ? NULL : &sha1_buf; } else { error = FALSE; } p = skip_ascii_non_spaces(p); v = 0; break; default: v = parse_uint64(p, &endptr, 10, &error); p = deconstify_gchar(endptr); } if (error || !is_ascii_space(*endptr)) goto corrupted; switch (i) { case 0: item.size = v; break; case 1: item.attempts = v; break; case 2: item.complete = v; break; case 3: item.bytes_sent |= ((guint64) (guint32) v) << 32; break; case 4: item.bytes_sent |= (guint32) v; break; case 5: item.rtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); case 6: item.dtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); case 7: break; /* Already stored above */ default: g_assert_not_reached(); goto corrupted; } } /* * We store the filenames UTF-8 encoded but the file might have been * edited or corrupted. */ if (is_absolute_path(item.pathname)) { item.filename = lazy_filename_to_utf8_normalized( filepath_basename(item.pathname), UNI_NORM_NFC); } else { item.filename = lazy_unknown_to_utf8_normalized( filepath_basename(item.pathname), UNI_NORM_NFC, NULL); } if (upload_stats_find(NULL, item.pathname, item.size)) { g_warning("upload_stats_load_history():" " Ignoring line %u due to duplicate file.", lineno); } else if (upload_stats_find(item.sha1, item.pathname, item.size)) { g_warning("upload_stats_load_history():" " Ignoring line %u due to duplicate file.", lineno); } else { upload_stats_add(item.pathname, item.size, item.filename, item.attempts, item.complete, item.bytes_sent, item.rtime, item.dtime, item.sha1); } continue; corrupted: g_warning("upload statistics file corrupted at line %u.", lineno); } /* close file */ fclose(upload_stats_file); done: gcu_upload_stats_gui_thaw(); return; }