mirror of
https://github.com/xroche/httrack.git
synced 2026-07-26 18:49:39 +03:00
Compare commits
5 Commits
pt-readfie
...
warnfix-li
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
018826d70e | ||
|
|
237468cb57 | ||
|
|
6b590fa6d9 | ||
|
|
230ebd0a70 | ||
|
|
272373f64c |
@@ -629,8 +629,8 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
||||
// File exists on disk with declared cache name (this is expected!)
|
||||
if (fexist_utf8(fconv(catbuff, sizeof(catbuff), previous_save))) { // un fichier existe déja
|
||||
// Expected size ?
|
||||
const size_t fsize =
|
||||
fsize_utf8(fconv(catbuff, sizeof(catbuff), previous_save));
|
||||
const LLint fsize = fsize_utf8(
|
||||
fconv(catbuff, sizeof(catbuff), previous_save));
|
||||
if (fsize == r.size) {
|
||||
// Target name is the previous name, and the file looks good: nothing to do!
|
||||
if (strcmp(previous_save, target_save) == 0) {
|
||||
@@ -666,7 +666,8 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
||||
// Suppose a broken mirror, with a file being renamed: OK
|
||||
else if (fexist_utf8(fconv(catbuff, sizeof(catbuff), target_save))) {
|
||||
// Expected size ?
|
||||
const size_t fsize = fsize_utf8(fconv(catbuff, sizeof(catbuff), target_save));
|
||||
const LLint fsize =
|
||||
fsize_utf8(fconv(catbuff, sizeof(catbuff), target_save));
|
||||
|
||||
if (fsize == r.size) {
|
||||
// So far so good
|
||||
|
||||
@@ -696,17 +696,19 @@ int httpmirror(char *url1, httrackp * opt) {
|
||||
// copier adresse(s) dans liste des adresses
|
||||
{
|
||||
char *a = url1;
|
||||
int primary_len = 8192;
|
||||
|
||||
if (StringNotEmpty(opt->filelist)) {
|
||||
primary_len += max(0, fsize_utf8(StringBuff(opt->filelist)) * 2);
|
||||
}
|
||||
primary_len += (int) strlen(url1) * 2;
|
||||
const LLint list_sz = StringNotEmpty(opt->filelist)
|
||||
? fsize_utf8(StringBuff(opt->filelist))
|
||||
: 0;
|
||||
/* two bytes reserved per list byte; -1 makes an undoublable size refused */
|
||||
const LLint list_room =
|
||||
list_sz > 0 ? (list_sz <= INT64_MAX / 2 ? list_sz * 2 : -1) : 0;
|
||||
const size_t primary_len =
|
||||
llint_grow_size_t(8192 + strlen(url1) * 2, list_room, 0);
|
||||
|
||||
// création de la première page, qui contient les liens de base à scanner
|
||||
// c'est plus propre et plus logique que d'entrer à la main les liens dans la pile
|
||||
// on bénéficie ainsi des vérifications et des tests du robot pour les liens "primaires"
|
||||
primary = (char *) malloct(primary_len);
|
||||
primary = primary_len != (size_t) -1 ? (char *) malloct(primary_len) : NULL;
|
||||
if (!primary) {
|
||||
printf("PANIC! : Not enough memory [%d]\n", __LINE__);
|
||||
XH_extuninit;
|
||||
@@ -887,7 +889,7 @@ int httpmirror(char *url1, httrackp * opt) {
|
||||
}
|
||||
|
||||
if (filelist_buff != NULL) {
|
||||
int filelist_ptr = 0;
|
||||
size_t filelist_ptr = 0;
|
||||
int n = 0;
|
||||
char BIGSTK line[HTS_URLMAXSIZE * 2];
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
int argv_url = -1; // ==0 : utiliser cache et doit.log
|
||||
char *argv_firsturl = NULL; // utilisé pour nommage par défaut
|
||||
char *url = NULL; // URLS séparées par un espace
|
||||
int url_sz = 65535;
|
||||
size_t url_sz = 65535;
|
||||
|
||||
// the parametres
|
||||
int httrack_logmode = 3; // ONE log file
|
||||
@@ -224,21 +224,22 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
|
||||
/* create x_argvblk buffer for transformed command line */
|
||||
{
|
||||
int current_size = 0;
|
||||
int size;
|
||||
size_t current_size = 0;
|
||||
const LLint size = fsize("config");
|
||||
size_t blk_size;
|
||||
int na;
|
||||
|
||||
for(na = 0; na < argc; na++)
|
||||
current_size += (int) (strlen(argv[na]) + 1);
|
||||
if ((size = fsize("config")) > 0)
|
||||
current_size += size;
|
||||
x_argvblk = (char *) malloct(current_size + 32768);
|
||||
current_size += strlen(argv[na]) + 1;
|
||||
/* a huge file named "config" must saturate, not wrap, the capacity */
|
||||
blk_size = llint_grow_size_t(current_size, size > 0 ? size : 0, 32768);
|
||||
x_argvblk = blk_size != (size_t) -1 ? (char *) malloct(blk_size) : NULL;
|
||||
if (x_argvblk == NULL) {
|
||||
HTS_PANIC_PRINTF("Error, not enough memory");
|
||||
htsmain_free();
|
||||
return -1;
|
||||
}
|
||||
x_argvblk_size = (size_t) (current_size + 32768);
|
||||
x_argvblk_size = blk_size;
|
||||
x_argvblk[0] = '\0';
|
||||
x_ptr = 0;
|
||||
|
||||
@@ -1456,20 +1457,29 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
FILE *fp = FOPEN(argv[na], "rb");
|
||||
|
||||
if (fp != NULL) {
|
||||
int cl = (int) strlen(url);
|
||||
size_t cl = strlen(url);
|
||||
const size_t fzs = llint_to_size_t(fz);
|
||||
const size_t capa = llint_grow_size_t(cl, fz, 8192);
|
||||
|
||||
ensureUrlCapacity(url, url_sz, cl + fz + 8192);
|
||||
if (capa == (size_t) -1) {
|
||||
fclose(fp);
|
||||
HTS_PANIC_PRINTF("File url list too large");
|
||||
htsmain_free();
|
||||
return -1;
|
||||
}
|
||||
ensureUrlCapacity(url, url_sz, capa);
|
||||
if (cl > 0) { /* don't stick! (3.43) */
|
||||
url[cl] = ' ';
|
||||
cl++;
|
||||
}
|
||||
if (fread(url + cl, 1, fz, fp) != fz) {
|
||||
if (fread(url + cl, 1, fzs, fp) != fzs) {
|
||||
fclose(fp);
|
||||
HTS_PANIC_PRINTF("File url list could not be read");
|
||||
htsmain_free();
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
*(url + cl + fz) = '\0';
|
||||
*(url + cl + fzs) = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2296,8 +2306,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
|
||||
} else { // URL/filters
|
||||
char catbuff[CATBUFF_SIZE];
|
||||
const int urlSize = (int) strlen(argv[na]);
|
||||
const int capa = (int) (strlen(url) + urlSize + 32);
|
||||
const size_t urlSize = strlen(argv[na]);
|
||||
const size_t capa = strlen(url) + urlSize + 32;
|
||||
|
||||
assertf(urlSize < HTS_URLMAXSIZE);
|
||||
if (urlSize < HTS_URLMAXSIZE) {
|
||||
|
||||
@@ -336,16 +336,20 @@ typedef int INTsys;
|
||||
#endif
|
||||
|
||||
/* Socket-handle type. An unsigned integer wide enough for a Windows SOCKET;
|
||||
a plain int file descriptor on POSIX. */
|
||||
a plain int file descriptor on POSIX. T_SOCP is its printf conversion,
|
||||
'%' included: unsigned __int64 on Win64 must not be printed with "%d". */
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN64)
|
||||
|
||||
typedef unsigned __int64 T_SOC;
|
||||
#define T_SOCP "%" PRIu64
|
||||
#else
|
||||
typedef unsigned __int32 T_SOC;
|
||||
#define T_SOCP "%" PRIu32
|
||||
#endif
|
||||
#else
|
||||
typedef int T_SOC;
|
||||
#define T_SOCP "%d"
|
||||
#endif
|
||||
|
||||
/* Buffer size for a printed network address (IPv4 or IPv6, NUL included). */
|
||||
|
||||
@@ -2598,13 +2598,15 @@ void deletesoc(T_SOC soc) {
|
||||
if (closesocket(soc) != 0) {
|
||||
int err = WSAGetLastError();
|
||||
|
||||
fprintf(stderr, "* error closing socket %d: %s\n", soc, strerror(err));
|
||||
fprintf(stderr, "* error closing socket " T_SOCP ": %s\n", soc,
|
||||
strerror(err));
|
||||
}
|
||||
#else
|
||||
if (close(soc) != 0) {
|
||||
const int err = errno;
|
||||
|
||||
fprintf(stderr, "* error closing socket %d: %s\n", soc, strerror(err));
|
||||
fprintf(stderr, "* error closing socket " T_SOCP ": %s\n", soc,
|
||||
strerror(err));
|
||||
}
|
||||
#endif
|
||||
#if HTS_WIDE_DEBUG
|
||||
|
||||
15
src/htslib.h
15
src/htslib.h
@@ -607,6 +607,21 @@ static HTS_UNUSED size_t llint_to_size_t(LLint o) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Capacity for @p used bytes plus @p extra more plus @p slack spare;
|
||||
(size_t) -1 if the total exceeds (size_t) -2 or @p extra is negative
|
||||
(llint_to_size_t() would map that to a huge valid-looking size). */
|
||||
static HTS_UNUSED size_t llint_grow_size_t(size_t used, LLint extra,
|
||||
size_t slack) {
|
||||
const size_t max = (size_t) -2; /* (size_t) -1 is the error value */
|
||||
const size_t e = extra >= 0 ? llint_to_size_t(extra) : (size_t) -1;
|
||||
|
||||
if (e == (size_t) -1 || used > max || slack > max - used ||
|
||||
e > max - used - slack) {
|
||||
return (size_t) -1;
|
||||
}
|
||||
return used + e + slack;
|
||||
}
|
||||
|
||||
/* dirent() compatibility */
|
||||
#ifdef _WIN32
|
||||
/* Holds a UTF-8 d_name: MAX_PATH (260) UTF-16 units expand to <=3 bytes each.
|
||||
|
||||
@@ -2023,6 +2023,77 @@ static int st_fsize(httrackp *opt, int argc, char **argv) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 4GB+100KB wraps to ~108KB through an int, and needs 33 unsigned bits. A
|
||||
macro, not a static const: MSVC's C mode (/TC) rejects a const object
|
||||
used inside another object's static initializer below (C2099). */
|
||||
#define HTS_ST_GROWSIZE_OVER32 (4LL * 1024 * 1024 * 1024 + 100 * 1024)
|
||||
|
||||
/* llint_grow_size_t() sizes the buffer holding a whole -%S list file: the
|
||||
result must be the exact 64-bit sum or a clean refusal, never a short one. */
|
||||
static int st_growsize(httrackp *opt, int argc, char **argv) {
|
||||
enum { REFUSE, ACCEPT, WIDTH };
|
||||
|
||||
static const struct {
|
||||
size_t used;
|
||||
LLint extra;
|
||||
size_t slack;
|
||||
int want;
|
||||
} cases[] = {
|
||||
{0, 0, 0, ACCEPT},
|
||||
{10, 100, 8192, ACCEPT},
|
||||
{(size_t) -2 - 8, 4, 4, ACCEPT}, /* exact fit, no room to spare */
|
||||
{(size_t) -2, 0, 0, ACCEPT}, /* largest representable capacity */
|
||||
{0, -1, 0, REFUSE}, /* fsize() failure */
|
||||
/* -1 already maps to SIZE_MAX; only this exercises the negative guard */
|
||||
{0, -4096, 0, REFUSE},
|
||||
{(size_t) -1, 1, 0, REFUSE},
|
||||
{(size_t) -2, 0, 1, REFUSE}, /* slack alone overruns */
|
||||
{(size_t) -1 - 8, 4, 4, REFUSE}, /* total would be the error value */
|
||||
{(size_t) -1 - 8, 4, 8, REFUSE},
|
||||
{0, HTS_ST_GROWSIZE_OVER32, 8192,
|
||||
WIDTH}, /* 32-bit size_t can't hold these */
|
||||
{10, HTS_ST_GROWSIZE_OVER32, 8192, WIDTH},
|
||||
};
|
||||
|
||||
size_t k;
|
||||
int rc = 0;
|
||||
|
||||
(void) opt;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
for (k = 0; k < sizeof(cases) / sizeof(cases[0]); k++) {
|
||||
const size_t used = cases[k].used, slack = cases[k].slack;
|
||||
const LLint extra = cases[k].extra;
|
||||
const size_t got = llint_grow_size_t(used, extra, slack);
|
||||
const hts_boolean refused = got == (size_t) -1 ? HTS_TRUE : HTS_FALSE;
|
||||
const hts_boolean exact =
|
||||
!refused && extra >= 0 && got - used - slack == (size_t) extra;
|
||||
hts_boolean ok;
|
||||
|
||||
switch (cases[k].want) {
|
||||
case ACCEPT:
|
||||
ok = exact;
|
||||
break;
|
||||
case REFUSE:
|
||||
ok = refused;
|
||||
break;
|
||||
default:
|
||||
ok = sizeof(size_t) >= sizeof(LLint) ? exact : refused;
|
||||
break;
|
||||
}
|
||||
if (!ok) {
|
||||
fprintf(stderr,
|
||||
"growsize: grow(" LLintP ", " LLintP ", " LLintP ") = " LLintP
|
||||
" (want %s)\n",
|
||||
(LLint) used, extra, (LLint) slack, (LLint) got,
|
||||
cases[k].want == REFUSE ? "refusal" : "exact sum");
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
printf("growsize self-test %s\n", rc == 0 ? "OK" : "FAILED");
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int st_savename(httrackp *opt, int argc, char **argv) {
|
||||
lien_adrfilsave afs;
|
||||
cache_back cache;
|
||||
@@ -4868,6 +4939,8 @@ static const struct selftest_entry {
|
||||
{"sniff", "<content-type> <hex:..|text>", "MIME magic consistency",
|
||||
st_sniff},
|
||||
{"fsize", "<dir>", "file size past the 2GB signed-32-bit wrap", st_fsize},
|
||||
{"growsize", "", "buffer capacity for a 64-bit file size (no int wrap)",
|
||||
st_growsize},
|
||||
{"cache", "<dir>", "cache read/write round-trip self-test", st_cache},
|
||||
{"cacheindex", "", "cache-index (.ndx) parse must stay in bounds",
|
||||
st_cacheindex},
|
||||
|
||||
25
tests/01_engine-growsize.test
Normal file
25
tests/01_engine-growsize.test
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Buffer capacity for a 64-bit file size ('httrack -#test=growsize'): a -%S list
|
||||
# file past 4GB must size its buffer exactly or be refused, never wrap.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
out=$(httrack -#test=growsize)
|
||||
echo "$out"
|
||||
test "$out" == "growsize self-test OK"
|
||||
|
||||
tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_growsize.XXXXXX")
|
||||
trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM
|
||||
|
||||
echo '<html><body>hi</body></html>' >"$tmp/index.html"
|
||||
printf -- '-*/zzmarker*\n' >"$tmp/rules.txt"
|
||||
|
||||
# the rules file lands in the URL/filter string, echoed back by the banner
|
||||
run=$(httrack -O "$tmp/out" --quiet -n "-%S" "$tmp/rules.txt" \
|
||||
"file://$tmp/index.html" 2>&1) || true
|
||||
printf '%s\n' "$run" | grep -q 'zzmarker' || {
|
||||
echo "FAIL: -%S rules file was not loaded"
|
||||
printf '%s\n' "$run"
|
||||
exit 1
|
||||
}
|
||||
@@ -64,6 +64,7 @@ TESTS = \
|
||||
01_engine-reconcile.test \
|
||||
01_engine-expandhome.test \
|
||||
01_engine-fsize.test \
|
||||
01_engine-growsize.test \
|
||||
01_engine-redirect.test \
|
||||
01_engine-longpath-io.test \
|
||||
01_engine-mirror-io.test \
|
||||
|
||||
Reference in New Issue
Block a user