diff -Nru apt-cacher-ng-0.9.1/ChangeLog apt-cacher-ng-3.3.1/ChangeLog --- apt-cacher-ng-0.9.1/ChangeLog 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/ChangeLog 2020-01-08 19:58:26.000000000 +0000 @@ -1,3 +1,274 @@ +apt-cacher-ng (3.3.1) A-LITTLE-BUGFIX-FOR-A-MAN; urgency=medium + + * POTENTIAL SECURITY ISSUE (CVE-2020-5202): + - in certain situations, the maint job run by acngtool could leak the + administrator credentials from apt-cacher-ng configuration. This is only + likely if the attacker is able to impersonate the daemon with an own + server listening on the same port. + - The mitigation path for this is: + - SocketPath option is configured by default + - By default, acngtool only attempts to run the maint job through the + Unix Domain Socket. If SocketPath is not set but admin credentials are + configured, the operation is denied. + - For non-standard cases where acngtool is used to run special arbitrary + commands (ACNG_REQ variable) and the operation through SocketPath is not + possible (i.e. missing permissions or the tool is run on a different + host), the operation through TCP can be enforced with ACNG_INSECURE + environment variable + * Support .zst compressed packages (reference: + https://www.archlinux.org/news/now-using-zstandard-instead-of-xz-for-package-compression/ ) + * Added global cancelation points for the daemon shutdown phase, now + terminating sooner especially when a maintenance jobs runs in background + + -- Eduard Bloch Wed, 08 Jan 2020 20:47:37 +0100 + +apt-cacher-ng (3.3) THE-CLAMPS-ARE-MARCHING; urgency=low + + [ POSSIBLY BREAKING CHANGES ] + * the setting of cachedir and logdir in the built-in defaults is now + configurable at build time (-DACNG_CACHE_DIR=... -DACNG_LOG_DIR=...) + and this settings are also propagated into generated configuration examples + * Dropping support for CMake prior to v3.1, dropped most custom variables + for target locations, now relying on public CMake variables from + GNUInstallDirs module; for details, see + https://cmake.org/cmake/help/v3.2/module/GNUInstallDirs.html + * Dropping support for OpenSSL before 1.0.2 + + [ FEATURES AND IMPROVEMENTS ] + * Change of default network timeout to 40 seconds + * Reduced automatic retries on remote disconnects to two + * Alternative fallback scheme for non-primary target connection attempts + (with default timeout value of 4s, see FastTimeout setting). By default, + this should help with unstable (blocking) IPv6 routing where IPv4 is still + operational (Debian bug #942122) + * Refactored DNS resolution&caching code, potential fix of rate connection + problems + * RequiresMountsFor directive in systemd service file example with + additional remarks on keeping this in sync with the config (as in Debian + bug #929035 and partly suggested in #942355) + * PFilePattern extensions for Fedora 29 and 30, by Alan Jenkins, Debian + bug #928270 (thanks!) + * VFilePattern extension for Centos8, by Andy Lowther, Debian bug #944143 + (thanks!) + * added very explicit explanation on what "default value" means in the + acng.conf example (Debian bug #855995) and also how to print it + (with acngtool, Debian bug #914746) + * Mirror database update + * Configurable timeout for forced client disconnect on the last portion of + data + + [ BUGFIXES ] + * increased size of the decompression line buffer for config file reading + (Debian bug #942634) + * fixes potential data race in DNS resolution + * Typo in INSTALL file (Debian bug #913593) + * In Arch Linux database mirror list, rewrite https URLs to http since the + official JSON query only returns https versions, also add a different + source (from Debian bug #942844) + * Generation of Sourceforge mirror redirectors list is fixed + * Fixed an ancient bug where there last answered request might have been + delayed in processing due to incorrect selection of MSG_MORE flag + * Potential crash on shutdown prevented (misordered destructor sequence, + insufficient tracking of remaining active tasks) + * Correct shutdown of blocked incoming connection on daemon shutdown + * Limit of simultaneous DNS resolver requests to 8 due to observed + instability of glibc (probably + https://sourceware.org/ml/libc-alpha/2015-10/msg00865.html ) + + [ INTERNAL REFACTORING ] + * Overhauling code deployment, using a shared library (reducing installed + file size by up to 20%) + * dropped rfc2553emu code from old APT, using the platform abstraction from + libevent instead + * partial redesign for more singlethreaded IO operation + * Disabled LTO by default, still crashing gold linker with certain option + combinations + * Moved lingering on CLOSE_WAIT sockets to the single main thread + + -- Eduard Bloch Sun, 10 Nov 2019 18:59:08 +0100 + +apt-cacher-ng (3.2) MY-NAME-IS-ANYBODY; urgency=medium + + * Maintenance release + * Basic support for FlatPak repositories + * Added flat by-hash structure to file patterns + * Allowing some Debian and Ubuntu services in default PassThroughPattern + * Various fixes in manpage and configuration examples + * Mirror database update + + -- Eduard Bloch Fri, 07 Sep 2018 12:55:46 +0200 + +apt-cacher-ng (3.1) SPACE-COWBOYS-FOREVER; urgency=low + + * Hide credentials in acngtool in some corner cases (by astian) + * Dropped references to distkill.pl script which was superseeded by acngtool + * Made default PassThroughPattern setting (bugs.d.o) stricter + * Mirror database update + + [ Carlos Maddela ] + * Avoid expiration failure when some index files are missing + + -- Eduard Bloch Sun, 05 Nov 2017 20:28:09 +0100 + +apt-cacher-ng (3) THIS-IS-NOT-THE-END; urgency=medium + + * NOTE: this release tackles multiple issues that might be considered + security related in certain environments. + * FIX: Making sure to truncate the file in case its download is aborted. + This is needed in order to avoid hidden filesystem space allocation + (Debian bug #856635). Also more delicate use of fallocate calls on Linux + due to the potentially syscall execution delay. By default, limit the + requested size to the first megabyte of a file. + * FIX: detection of incorrectly allocated files and automated trimming in + expiration run + * FIX: acngtool shrink function now uses allocated space for calculation, + not the visible size. Also more user friendly verbose output and little + performance optimization. + * FIX: acngtool shrink function now also considers unknown files as junk + * FIX: compilation with GCC7, also warning fixes with Clang4 + * FIX: better checking of possibly invalid remote certificate configuration + in SSL client code + * FIX: added workaround code for OpenSSL certificate validation even with + ancient SSL versions like the one found in Ubuntu 14 LTS; borrowed from + libevent examples (originally from ssl-conservatory and cURL) + * FIX: no printing of requested file name in the 403 HTTP status line + * FIX: typo/wording in manual, iptables examples + * FIX: in file truncation wizard (cleanup task), don't truncate the + associated .head files (because they might contain the best download + source information) + * NEW: better index deletion wizard, offering to remove all related files in + the same run. This can help to avoid accidental recreation of "incomplete" + files later. + * Database update + + -- Eduard Bloch Tue, 14 Mar 2017 16:23:20 +0100 + +apt-cacher-ng (2) THE-LAST-JOB-FILMS-LTD; urgency=medium + + * Minor refactoring (DNS cache with fewer mutexes) + * FIX: communication for maint jobs now properly considers possible + addresses from daemon's configuration. Communication via UDS remains + broken which is subject to repairs in the next update of core code + * FIX: Correct parsing of unix suffixes for ExStartTradeOff option + * FIX: fixes for compilation errors with GCC 5.4 (by Bob Ham) + * FIX: try to link with libatomic, some architectures require it + + -- Eduard Bloch Tue, 22 Nov 2016 21:29:54 +0100 + +apt-cacher-ng (1) LOGAN-VS-BLADE-RUNNER-3D; urgency=low + + * The version numbers change to plain integer. The minor numbers were + already hardly used for differentiation between bugfix and feature + releases. If this becomes ever needed, the version might be extended to + x.y scheme. + * FIX: typo in option name ExThreshold, and also hiding obsolete options + in configuration dump + * FIX: correct display of errors in acngtool curl operation + * FIX: strict SSL hostname validation even with peers not supporting SNI + (Debian bug #839751) + * NEW: simple "live" download statistics display on the maintenance page + * NEW: storage of simple download statistics across service restart (until + the expiration run) + * NEW: default method to abort expiration runs if not much data has been + downloaded though the proxy since the last expiration run. + * NEW: special command in acngtool ("shrink") to files until + the wanted size of the cache directory is reached (considering file type + and creation dates). The default strategy is keeping least recently + downloaded files in cache. + * NEW: optional tagging of used package files which can influence the + "shrink" command operation to keep least recently USED files instead of + least recently downloaded files. + * CHANGE: remote errors now printed as E states in the logging code + * Database update + + -- Eduard Bloch Wed, 19 Oct 2016 22:07:06 +0200 + +apt-cacher-ng (0.9.3.2) PAINT-IT-AEROGLAZE-Z306; urgency=low + + * FIX: avoid endless looping on startup when a new (not existing) directory + was specified as CacheDir + * FIX: build failure on non-Linux POSIX systems (Debian bug #830736, now + moved namespace tag to general scope) + * FIX: Stop printing bogus "error" summary on the end of every maintenance + task execution + * NEW: allow for omission of CacheDir setting; continues operation in + degraded mode with only harmless features which are not needing local + storage (HTTPS pass-through, local web server) + * Mirror database update + + -- Eduard Bloch Tue, 12 Jul 2016 21:56:15 +0200 + +apt-cacher-ng (0.9.3.1) KLENDATHU-AIRLINES-FLIGHT-931; urgency=low + + * This is a minor bugfix release, there are more changes to expect soon + * FIX: attaching to monitor the output of background maintenance task in the + browser working properly + * Extended workaround for the fake Content-Location "redirect", setting + "Accept: octet/stream" header which seems to be the only way to tell + Apache and nginx that we really want THAT data and not some compressed + version (no matter whether it's gzip or xz or cewwlCrzyCompression3000 or + whatever their authors consider suitable for everybody by default) + * Better handling of error situations in expiration task, printing a summary + at the bottom. + * extended metadata (changelogs) download filters for Tanglu + * Added documentation on how to use multilines with RequestAppendix option + + -- Eduard Bloch Wed, 08 Jun 2016 23:07:52 +0200 + +apt-cacher-ng (0.9.3) HAVE-SOME-LIGHT-BALLS; urgency=medium + + * FIX: Cope with removal of SHA1 checksums from Debian/Ubuntu (In)Release files + * FIX: Overhaul of pdiff based update code, actually repairing pdiff code in + some environments which has been silently broken for about 2-3 months. The + old code was designed for the situation a half decade ago when + information like compressed version's checksum was not available in the + patch index. + * FIX: reduction of volatile data whitelist - now expiring deprecated + Translations*/* data + * Small review of expiration (index file updating) code, replaced some + cruft to make analysis with less syscalls and attempt to get more likely + available of remote files in some cases. + * Better handling of by-hash type files: + + Moved internal storage of Release files' tracking snapshots to a private + namespace of the cache + + Proper detection of caches where by-hash data has been downloaded by + previous versions without tracking snapshots and work around this + situation + + in case that by-hash directory has a better version of the reference + file (matching the latest InRelease's signature), the reference file + contents is replaced with that correct version + + correct handling for expiration with or without strict path checking + * WORKAROUND: + + detecting a situation when remote attempts to foist uncompressed version + on the proxy and returning a 500 code to user instead; otherwise that data + would be handled incorrectly and eventually poison the cache + + -- Eduard Bloch Sun, 29 May 2016 18:34:45 +0200 + +apt-cacher-ng (0.9.2) HERE-COMES-JASON; urgency=medium + + * Added regexps for Debian, by-hash index files and changelog data on + ftp-master.debian.org + * FIX: expiration of orphaned Packages.bz2 (and similar) files in + Debian/Ubuntu repositories + * Added deb.debian.conf to Debian mirror list (Debian bug #820813) + * Database update + * Enabling LTO on GCC 5+ as default (working around suspected pthread issues + by switching to std classes instead of custom pthread access), also fixing + some GCC 6 specific warnings + * FIX: default regex for .asc suffix, for Debian's new source files' PGP + signatures, since dpkg-dev 1.18.5 + * FIX: parse option suffixes with hypens (like Remap-x-y) correctly + * FIX: on systems where volatile files are accessed ONLY through files named + by hash value (actually only Ubuntu Xenial), + attempt to extract the original file names from seen InRelease files and + restore tracking of original files. + This is a stop-gap solution (and there will better integration of + Acquire-By-Hash feature in future releases) but it's needed to be + deployed ASAP to avoid cache damages on existing systems. + + -- Eduard Bloch Fri, 13 May 2016 19:37:53 +0200 + apt-cacher-ng (0.9.1) THE-DARK-NIGHT; urgency=low * FIX: correct human error message printing with recent glibc diff -Nru apt-cacher-ng-0.9.1/client/client.cc apt-cacher-ng-3.3.1/client/client.cc --- apt-cacher-ng-0.9.1/client/client.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/client/client.cc 2020-01-08 19:58:26.000000000 +0000 @@ -9,13 +9,15 @@ #include #include -namespace acfg +namespace acng{ +namespace cfg { int nettimeout=60; } - +} int main(int argc, char **argv) { + using namespace acng; signal(SIGPIPE, SIG_IGN); acbuf bufToD, bufFromD; diff -Nru apt-cacher-ng-0.9.1/client/CMakeLists.txt apt-cacher-ng-3.3.1/client/CMakeLists.txt --- apt-cacher-ng-0.9.1/client/CMakeLists.txt 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/client/CMakeLists.txt 2020-01-08 19:58:26.000000000 +0000 @@ -1,6 +1,6 @@ PROJECT(ACNG CXX C) ADD_EXECUTABLE(in.acng client.cc) -SET_TARGET_PROPERTIES(in.acng PROPERTIES COMPILE_FLAGS "${ACNG_CXXFLAGS_COMMON} -DMINIBUILD") +SET_TARGET_PROPERTIES(in.acng PROPERTIES COMPILE_FLAGS "${ACNG_COMPFLAGS} ${ACNG_CXXFLAGS} -DMINIBUILD") TARGET_LINK_LIBRARIES(in.acng ${NetworkLibs} ${EXTRA_LIBS_INETD}) INSTALL(TARGETS in.acng DESTINATION ${LIBDIR}) diff -Nru apt-cacher-ng-0.9.1/CMakeLists.txt apt-cacher-ng-3.3.1/CMakeLists.txt --- apt-cacher-ng-0.9.1/CMakeLists.txt 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/CMakeLists.txt 2020-01-08 19:58:26.000000000 +0000 @@ -1,20 +1,20 @@ -cmake_minimum_required(VERSION 2.6.2) +cmake_minimum_required(VERSION 3.1) -set(CMAKE_LEGACY_CYGWIN_WIN32 0) # don't care for now... just expecting POSIX +# enforce minimal C++ language level +set(CMAKE_CXX_STANDARD 14) +# let it take the lowest version, we need some precursor of C++14x +#set(CMAKE_CXX_STANDARD_REQUIRED on) -# we want the old policy to support cmake 2.x -IF(POLICY CMP0056) # added in CMake 3.2 - cmake_policy (SET CMP0056 OLD) -ENDIF() -IF (POLICY CMP0053) # added in CMake 3.1 - cmake_policy (SET CMP0053 OLD) # use old-style @VAR@ expansion -ENDIF (POLICY CMP0053) +# don't care for now... just expecting POSIX +set(CMAKE_LEGACY_CYGWIN_WIN32 0) + +set(PACKAGE "apt-cacher-ng") -PROJECT(ACNG CXX C) +PROJECT(${PACKAGE} CXX C) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) -set(CMAKE_SKIP_BUILD_RPATH on) # no -rdynamic needed ever +#set(CMAKE_SKIP_BUILD_RPATH on) # no -rdynamic needed ever INCLUDE(CheckIncludeFiles) INCLUDE(CheckCXXSourceCompiles) @@ -22,41 +22,42 @@ INCLUDE(CheckTypeSize) INCLUDE(TestBigEndian) INCLUDE(CheckLibraryExists) +INCLUDE(CheckSymbolExists) INCLUDE(FindPkgConfig) +INCLUDE(GNUInstallDirs) -set(PACKAGE "apt-cacher-ng") IF(NOT DEFINED(CMAKE_INSTALL_PREFIX)) set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE STRING "Target file space") ENDIF() -IF(NOT DEFINED(DATADIR)) - set(DATADIR "${CMAKE_INSTALL_PREFIX}/share" CACHE STRING "Shared data files directory") -ENDIF() IF(NOT DEFINED(LIBDIR)) set(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib/${PACKAGE}" CACHE STRING "Location of ${PACKAGE} extra files") ENDIF() -IF(NOT DEFINED(DOCDIR)) - set(DOCDIR "${DATADIR}/doc/${PACKAGE}" CACHE STRING "Location of documentation files") -ENDIF() - -IF(NOT DEFINED(SYSCONFDIR)) - if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr") - set(SYSCONFDIR /etc) - else() - set(SYSCONFDIR ${CMAKE_INSTALL_PREFIX}/etc) - endif() -ENDIF() - if(NOT DEFINED(CFGDIR)) -set(CFGDIR "${SYSCONFDIR}/${PACKAGE}") + set(CFGDIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/${PACKAGE}") endif() - -if(NOT DEFINED(SBINDIR)) -set(SBINDIR "${CMAKE_INSTALL_PREFIX}/sbin") -endif() - if(NOT DEFINED(RUNDIR)) set(RUNDIR "/run") endif() +set(SOCKET_PATH "${RUNDIR}/${PACKAGE}/socket") + + +IF(NOT DEFINED(ACNG_CACHE_DIR)) + set(ACNG_CACHE_DIR "/var/tmp" CACHE STRING "Cache folder for examples and default configuration") +ENDIF() + +IF(NOT DEFINED(ACNG_LOG_DIR)) + set(ACNG_LOG_DIR "/var/tmp" CACHE STRING "Log file folder for examples and default configuration") +ENDIF() + +# carefully splicing of command line arguments, even from lists +macro(_append varname) + string(REPLACE ";" " " _apx "${ARGN}") + if(NOT DEFINED ${varname}) + set(${varname} "${_apx}") + else() + set(${varname} "${${varname}} ${_apx}") + endif() +endmacro() INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "include") @@ -75,84 +76,90 @@ # those are appended later via COMPILER_FLAGS. $CXXFLAGS and CMAKE_CXX_FLAGS # also influence it, need to be adjusted carefully by user. -SET(ACNG_CXXFLAGS_COMMON "-D_FILE_OFFSET_BITS=64") +SET(ACNG_COMPFLAGS "-D_FILE_OFFSET_BITS=64") -foreach(cxxarg -pthread -Wall -Wextra -Wno-unused-parameter -fvisibility-inlines-hidden) +find_package(Threads REQUIRED) +if(THREADS_HAVE_PTHREAD_ARG) + _append(CFLAGS_PTHREAD -pthread) +endif() + +foreach(cxxarg -Wall -Wextra -Wno-unused-parameter -fvisibility=hidden) STRING(REGEX REPLACE "=|-|," "" optname "${cxxarg}") - CHECK_CXX_COMPILER_FLAG("${cxxarg}" "CXX_${optname}") - if(CXX_${optname}) - SET(ACNG_CXXFLAGS_COMMON "${ACNG_CXXFLAGS_COMMON} ${cxxarg}") - endif() + CHECK_CXX_COMPILER_FLAG("${cxxarg}" "COPT_${optname}") + if(COPT_${optname}) + _append(ACNG_COMPFLAGS ${cxxarg}) + endif() endforeach() -foreach(linkarg -Wl,--as-needed -Wl,-O1 -Wl,--discard-all -Wl,--no-undefined -Wl,--build-id=sha1) +CHECK_CXX_COMPILER_FLAG(-fvisibility-inlines-hidden CXX_VIHI) +if(CXX_VIHI) + _append(ACNG_CXXFLAGS -fvisibility-inlines-hidden) +endif() + +foreach(linkarg -Wl,--as-needed -Wl,-O1 -Wl,--discard-all -Wl,--no-undefined -Wl,--build-id=sha1 -Wl,-fuse-ld=gold) STRING(REGEX REPLACE "=|-|," "" optname "${linkarg}") set(CMAKE_REQUIRED_FLAGS "${linkarg}") CHECK_CXX_COMPILER_FLAG("" "LD_${optname}") if(LD_${optname}) - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${linkarg}") + _append(CMAKE_EXE_LINKER_FLAGS ${linkarg}) endif() set(CMAKE_REQUIRED_FLAGS "") endforeach(linkarg) +set(CMAKE_REQUIRED_FLAGS "-Wl,-fuse-ld=gold -Wl,--threads") +CHECK_CXX_COMPILER_FLAG("" LD_MULTITHREADED) +if(LD_MULTITHREADED) + _append(CMAKE_EXE_LINKER_FLAGS "-Wl,-fuse-ld=gold -Wl,--threads") +endif() +set(CMAKE_REQUIRED_FLAGS "") + option(USE_SSL "Use OpenSSL library for TLS and other crypto functionality" on) -# option(USE_LTO "Enable Link Time Optimization (requires modern compilers)" on) IF(CMAKE_SYSTEM MATCHES "Darwin") - SET(ACNG_CXXFLAGS_COMMON " ${ACNG_CXXFLAGS_COMMON} -D_DARWIN_C_SOURCE ") -ENDIF(CMAKE_SYSTEM MATCHES "Darwin") + _append(ACNG_COMPFLAGS -D_DARWIN_C_SOURCE) +ENDIF() IF(CMAKE_SYSTEM MATCHES "CYGWIN") - set(USE_LTO off) - SET(ACNG_CXXFLAGS_COMMON " ${ACNG_CXXFLAGS_COMMON} -U__STRICT_ANSI__ -DNOMINMAX ") + set(USE_LTO_DEFAULT off) + _append(ACNG_COMPFLAGS -U__STRICT_ANSI__ -DNOMINMAX) ELSE() - + if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION MATCHES "^[56789]") + set(USE_LTO_DEFAULT on) + endif() ENDIF() +# set the default to OFF for now because gold is still too buggy +set(USE_LTO_DEFAULT off) + if(CMAKE_BUILD_TYPE MATCHES Debug) - set(USE_LTO off) - set(ACNG_CXXFLAGS_COMMON "-DDEBUG ${ACNG_CXXFLAGS_COMMON}") + set(USE_LTO_DEFAULT off) + _append(ACNG_COMPFLAGS -DDEBUG) else() set(CMAKE_REQUIRED_FLAGS "-Wl,--gc-sections") CHECK_CXX_COMPILER_FLAG("-Os -fdata-sections -ffunction-sections -Wl,--gc-sections" GC_SECTIONS) if(GC_SECTIONS) - SET(ACNG_CXXFLAGS_COMMON "${ACNG_CXXFLAGS_COMMON} -fdata-sections -ffunction-sections") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + _append(ACNG_COMPFLAGS -fdata-sections -ffunction-sections) + _append(CMAKE_EXE_LINKER_FLAGS -Wl,--gc-sections) + _append(CMAKE_SHARED_LINKER_FLAGS -Wl,--gc-sections) endif() set(CMAKE_REQUIRED_FLAGS "") endif() -FILE(READ test/build/testcxx11.cc CXX11_TESTSRC) -# prefer that style if possible since since Cygwin seems to have an old bug with missing definitions, http://cygwin.com/ml/cygwin/2012-04/msg00140.html -CHECK_CXX_COMPILER_FLAG(-std=gnu++11 COMPILER_SUPPORTS_GNU11) -if(COMPILER_SUPPORTS_GNU11) - set(ACNG_CXXFLAGS_COMMON "${ACNG_CXXFLAGS_COMMON} -std=gnu++11") -else() - CHECK_CXX_COMPILER_FLAG(-std=c++11 COMPILER_SUPPORTS_CXX11) - if(COMPILER_SUPPORTS_CXX11) - set(ACNG_CXXFLAGS_COMMON "${ACNG_CXXFLAGS_COMMON} -std=c++11") - else() - CHECK_CXX_COMPILER_FLAG(-std=c++0x COMPILER_SUPPORTS_CXX0X) - if(COMPILER_SUPPORTS_CXX0X) - set(ACNG_CXXFLAGS_COMMON "${ACNG_CXXFLAGS_COMMON} -std=c++0x") - else() - message(FATAL_ERROR "!! Error: failed to configure compiler for C++11 support. For GCC, version 4.7 or newer is required.") - endif() - endif() -endif() +option(USE_LTO "Enable Link Time Optimization (requires modern compilers)" ${USE_LTO_DEFAULT}) if(USE_LTO) - SET(LDFLAGS_NOLTO "${CMAKE_EXE_LINKER_FLAGS}") - SET(CMAKE_REQUIRED_FLAGS "${ACNG_CXXFLAGS_COMMON} -flto -flto-partition=none") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto -flto-partition=none") - CHECK_CXX_SOURCE_COMPILES("${CXX11_TESTSRC}" HAS_LTO) - if(HAS_LTO) - SET(ACNG_CXXFLAGS_COMMON ${CMAKE_REQUIRED_FLAGS}) - else() - SET(CMAKE_REQUIRED_FLAGS "${ACNG_CXXFLAGS_COMMON}") - SET(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS_NOLTO}") - message(WARNING "Link Time Optimization support broken, disabling it.") - endif() + SET(LDFLAGS_BACKUP "${CMAKE_EXE_LINKER_FLAGS}") + SET(CMAKE_REQUIRED_FLAGS "${ACNG_COMPFLAGS} -flto") + _append(CMAKE_EXE_LINKER_FLAGS -flto) + CHECK_CXX_SOURCE_COMPILES("int main() {return 0;}" HAS_LTO) + if(HAS_LTO) + SET(ACNG_COMPFLAGS ${CMAKE_REQUIRED_FLAGS}) + else() + SET(CMAKE_REQUIRED_FLAGS "${ACNG_COMPFLAGS}") + SET(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS_BACKUP}") + message(WARNING "Link Time Optimization support broken, disabling it.") + set(USE_LTO off) + endif() endif() FIND_LIBRARY(HAVE_SOCKETLIB socket) # separate socket lib looks like Solaris-like environment @@ -160,9 +167,6 @@ LIST(APPEND BaseNetworkLibs socket nsl) endif(HAVE_SOCKETLIB) -# explicit linking needed for global locks in dlcon -list(APPEND BaseNetworkLibs pthread) - SET(CMAKE_REQUIRED_LIBRARIES wrap ${BaseNetworkLibs}) FILE(READ test/build/HAVE_LIBWRAP.cc TESTSRC) CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_LIBWRAP) @@ -174,6 +178,14 @@ ENDIF(HAVE_LIBWRAP) SET(CMAKE_REQUIRED_LIBRARIES "") +# lib is not in the standard path so FIND_LIBRARY is not reliable +set(CMAKE_REQUIRED_FLAGS "-latomic") +CHECK_CXX_COMPILER_FLAG("" LD_ATOMIC) +if(LD_ATOMIC) +_append(BaseNetworkLibs atomic) +endif() +set(CMAKE_REQUIRED_FLAGS "") + if(CYGWIN) message("!! Not using wordexp on Cygwin, not reliable") set(HAVE_WORDEXP off) @@ -205,8 +217,8 @@ FILE(READ test/build/HAVE_LINUX_EVENTFD.cc TESTSRC) CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_LINUX_EVENTFD) - FILE(READ test/build/HAVE_LINUX_SPLICE.cc TESTSRC) - CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_LINUX_SPLICE) + # FILE(READ test/build/HAVE_LINUX_SPLICE.cc TESTSRC) + # CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_LINUX_SPLICE) endif() FILE(READ test/build/HAVE_PREAD.cc TESTSRC) @@ -216,27 +228,21 @@ CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_DAEMON) pkg_check_modules(lsd "libsystemd>=209") +# either part of the big library nowadays or in the helper library on older systems if(NOT lsd_FOUND) pkg_check_modules(lsd libsystemd-daemon) endif() -string(REPLACE ";" " " lsd_LDFLAGS "${lsd_LDFLAGS}") -string(REPLACE ";" " " lsd_CFLAGS "${lsd_CFLAGS}") +_append(CFLAGS_DAEMON ${lsd_CFLAGS}) +_append(LDFLAGS_DAEMON ${lsd_LDFLAGS}) set(HAVE_SD_NOTIFY ${lsd_FOUND}) -SET(CMAKE_REQUIRED_FLAGS ${ACNG_CXXFLAGS_COMMON}) -FILE(READ test/build/HAVE_MEMORY_SPTR.cc TESTSRC) -CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_MEMORY_SPTR) -if(NOT HAVE_MEMORY_SPTR) - message(FATAL_ERROR "Could not find a working smart pointer implementation.") -endif() - SET(CMAKE_REQUIRED_LIBRARIES dl) FILE(READ test/build/HAVE_DLOPEN.cc TESTSRC) CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_DLOPEN) # XXX: convert the compressor stuff to pkgconfig usage and print an overview of enabled/found values in one final message and collect and process cflags too -SET(CMAKE_REQUIRED_FLAGS ${ACNG_CXXFLAGS_COMMON}) +SET(CMAKE_REQUIRED_FLAGS ${ACNG_COMPFLAGS}) #INCLUDE(FindZLIB) # broken, hangs for 10 seconds # header check should be enough, gzip should be everywhere nowadays #CHECK_INCLUDE_FILES("gzip.h" HAVE_ZLIB) @@ -258,7 +264,7 @@ message("!! apt-cacher-ng requires bzip2 library and development files for bz2 format support") endif (BZIP2_FOUND) -SET(CMAKE_REQUIRED_FLAGS ${ACNG_CXXFLAGS_COMMON}) +SET(CMAKE_REQUIRED_FLAGS ${ACNG_COMPFLAGS}) SET(CMAKE_REQUIRED_LIBRARIES lzma) FILE(READ test/build/HAVE_LZMA.cc TESTSRC) CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_LZMA) @@ -272,12 +278,29 @@ set(HAVE_CHECKSUM on) +pkg_check_modules(libevent libevent) +if(NOT libevent_FOUND) + message(FATAL_ERROR "!! Error: proper libevent installation is required") +else() + string(REPLACE ";" " " ACNG_COMPFLAGS "${ACNG_COMPFLAGS} ${libevent_CFLAGS}") + LIST(APPEND BaseNetworkLibs ${libevent_LDFLAGS}) +endif() + + +pkg_check_modules(libevent_pthreads libevent_pthreads) +if(NOT libevent_pthreads_FOUND) + message(FATAL_ERROR "!! Error: proper libevent_pthreads installation is required") +else() + string(REPLACE ";" " " ACNG_COMPFLAGS "${ACNG_COMPFLAGS} ${libevent_pthreads_CFLAGS}") + LIST(APPEND BaseNetworkLibs ${libevent_pthreads_LDFLAGS}) +endif() + if(USE_SSL) - pkg_check_modules(openssl openssl) + pkg_check_modules(openssl "openssl>=1.0.2") if(openssl_FOUND) set(HAVE_SSL on) - string(REPLACE ";" " " ACNG_CXXFLAGS_COMMON "${ACNG_CXXFLAGS_COMMON} ${openssl_CFLAGS}") - string(REPLACE ";" " " SSL_LIB_LIST "${openssl_LDFLAGS}") + _append(ACNG_COMPFLAGS ${openssl_CFLAGS}) + _append(SSL_LIB_LIST ${openssl_LDFLAGS}) else() message(WARNING "OpenSSL not found, disabling TLS connection support") set(HAVE_SSL off) @@ -298,8 +321,8 @@ if(tomcrypt_FOUND) set(HAVE_TOMCRYPT on) # with workaround, http://clang.debian.net/logs/2015-03-25/libtomcrypt_1.17-6_unstable_clang.log - string(REPLACE ";" " " ACNG_CXXFLAGS_COMMON "${ACNG_CXXFLAGS_COMMON} ${tomcrypt_CFLAGS} -DLTC_NO_ROLC -DLTC_BASE64") - string(REPLACE ";" " " SSL_LIB_LIST "${tomcrypt_LDFLAGS}") + _append(ACNG_COMPFLAGS ${tomcrypt_CFLAGS} -DLTC_NO_ROLC -DLTC_BASE64) + _append(SSL_LIB_LIST ${tomcrypt_LDFLAGS}) else() set(HAVE_TOMCRYPT off) message(WARNING "Could not find LibTomCrypt or use OpenSSL. Some important functionality will be disabled.") @@ -315,11 +338,17 @@ # server process. # Needs HAVE_WL_AS_NEEDED! -message("Compiler flags: ${CMAKE_CXX_FLAGS} ${ACNG_CXXFLAGS_COMMON}") +message("Build settings:") +message("Compiler flags (common): ${ACNG_COMPFLAGS}") +message("Compiler flags (C++ only): ${ACNG_CXXFLAGS}") +message("Compiler flags (environment): ${CMAKE_CXX_FLAGS}") message("Linker flags: ${CMAKE_EXE_LINKER_FLAGS}") +message("LTO use: ${USE_LTO} +") -SET(CMAKE_REQUIRED_LIBRARIES "") -SET(CMAKE_REQUIRED_FLAGS ${ACNG_CXXFLAGS_COMMON}) +# unset everything, only use as needed +SET(CMAKE_REQUIRED_LIBRARIES ) +SET(CMAKE_REQUIRED_FLAGS ) # I don't need -rdynamic, thanks! SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") @@ -340,19 +369,13 @@ ### ### Extra install rules for static files ### -if(NOT DEFINED(HTMLDIR)) - set(HTMLDIR ${DOCDIR}/html) -endif() -if(NOT DEFINED(MANDIR)) - set(MANDIR ${DATADIR}/man) -endif() -install(FILES doc/README doc/apt-cacher-ng.pdf DESTINATION ${DOCDIR}) -install(DIRECTORY doc/html/ DESTINATION ${HTMLDIR} +install(FILES doc/README doc/${PACKAGE}.pdf DESTINATION ${CMAKE_INSTALL_DOCDIR}) +install(DIRECTORY doc/html/ DESTINATION ${CMAKE_INSTALL_DOCDIR}/html FILES_MATCHING PATTERN "*.*") -install(DIRECTORY doc/man/ DESTINATION ${MANDIR}/man8 +install(DIRECTORY doc/man/ DESTINATION ${CMAKE_INSTALL_MANDIR}/man8 FILES_MATCHING PATTERN "*.8") if(NOT DEFINED(AVAHIDIR)) - set(AVAHIDIR "${SYSCONFDIR}/avahi/services") + set(AVAHIDIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/avahi/services") endif() install(FILES contrib/apt-cacher-ng.service DESTINATION ${AVAHIDIR}) @@ -360,10 +383,7 @@ PACKAGE: ${PACKAGE} VERSION: ${ACVERSION} CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX} -DATADIR: ${DATADIR} +CMAKE_INSTALL_FULL_SYSCONFDIR: ${CMAKE_INSTALL_FULL_SYSCONFDIR} LIBDIR: ${LIBDIR} -DOCDIR: ${DOCDIR} -SYSCONFDIR: ${SYSCONFDIR} -CFGDIR: ${CFGDIR} -SBINDIR: ${SBINDIR} +AVAHIDIR: ${AVAHIDIR} ") diff -Nru apt-cacher-ng-0.9.1/conf/acng.conf.in apt-cacher-ng-3.3.1/conf/acng.conf.in --- apt-cacher-ng-0.9.1/conf/acng.conf.in 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/acng.conf.in 2020-01-08 19:58:26.000000000 +0000 @@ -11,19 +11,25 @@ # software package downloads. It's supposed to be in a directory specified by # the -c option of apt-cacher-ng, see apt-cacher-ng(8) for details. # RULES: -# Letter case in variable names does not matter, names and values should be -# separated with colons. For boolean variables, zero number is considered false, -# non-zero considered true. If a default value is not explicitly mentioned in -# the description, the commented value assignments mostly represent the default -# values of the particular variables. +# - letter case in variable names does not matter +# - names and values are separated by colon or equals sign +# - for boolean variables, zero means false, non-zero means true +# - "default value" means built-in (!) defaults, i.e. something which the +# program uses if the option is not set here or in other config files. +# That value might be explicitly mentioned in the description. Where it is +# not, there is no reason to assume any of the examples to be the default +# value! In doubt, use acngtool to query the value of the particular variable. # Storage directory for downloaded data and related maintenance activity. # -CacheDir: /var/cache/apt-cacher-ng +# Note: When the value for CacheDir is changed, change the file +# /lib/systemd/system/apt-cacher-ng.service too +# +CacheDir: @ACNG_CACHE_DIR@ # Log file directory, can be set empty to disable logging # -LogDir: /var/log/apt-cacher-ng +LogDir: @ACNG_LOG_DIR@ # A place to look for additional configuration and resource files if they are not # found in the configuration directory @@ -31,7 +37,8 @@ SupportDir: @LIBDIR@ # TCP server port for incoming http (or HTTP proxy) connections. -# Can be set to 9999 to emulate apt-proxy. +# Can be set to 9999 to emulate apt-proxy. Value of 0 turns off TCP server +# (SocketPath must be set in this case). # # Port:3142 @@ -67,11 +74,7 @@ Remap-epel: file:epel_mirrors # Fedora EPEL Remap-slrep: file:sl_mirrors # Scientific Linux Remap-gentoo: file:gentoo_mirrors.gz /gentoo ; file:backends_gentoo # Gentoo Archives - -# This is usually not needed for security.debian.org because it's always the -# same DNS hostname. However, it might be enabled in order to use hooks -# or ForceManaged mode or special flags in this context. Not set by default. -# Remap-secdeb: security.debian.org +Remap-secdeb: security.debian.org ; security.debian.org deb.debian.org/debian-security # Virtual page accessible in a web browser to see statistics and status # information, i.e. under http://localhost:3142/acng-report.html @@ -84,10 +87,12 @@ ReportPage: acng-report.html # Socket file for accessing through local UNIX socket instead of TCP/IP. Can be -# used with inetd bridge or cron client. -# Default: not set, UNIX socket bridge is disabled. +# used with inetd (via bridge tool in.acng from apt-cacher-ng package), is also +# used internally for administrative purposes. +# +# Default: @SOCKET_PATH@ # -# SocketPath:/var/run/apt-cacher-ng/socket +# SocketPath: /var/run/apt-cacher-ng/socket # If set to 1, makes log files be written to disk on every new line. Default # is 0, buffers are flushed after the client disconnects. Technically, @@ -125,7 +130,23 @@ # available for some days (mirror downtime) then there is a risk of removal of # still useful package files. # -ExTreshold: 4 +ExThreshold: 4 + +# If the expiration is run daily, it sometimes does not make much sense to do +# it because the expected changes (i.e. removal of expired files) don't justify +# the extra processing time or additional downloads for expiration operation +# itself. This discrepancy might be especially worse if the local client +# installations are small or are rarely updated but the daily changes of +# the remote archive metadata are heavy. +# +# The following option enables a possible trade-off: the expiration run is +# suppressed until a certain amount of data has been downloaded through +# apt-cacher-ng since the last expiration execution (which might indicate that +# packages were replaced with newer versions). +# +# The number can have a suffix (k,K,m,M for Kb,KiB,Mb,MiB) +# +# ExStartTradeOff: 500m # Stop expiration when a critical problem appears, issue like a failed update # of an index file in the preparation step. @@ -140,7 +161,7 @@ # before the (day) count is reached. Might be useful with whacky internet # connections. # -# Default: a guessed value, 1 if ExTreshold is 5 or more, 0 otherwise. +# Default: a guessed value, 1 if ExThreshold is 5 or more, 0 otherwise. # # ExSuppressAdminNotification: 1 @@ -175,6 +196,17 @@ # is refused when this value is reached (below zero = unlimited). # MaxConThreads: -1 # +# Timeout for a forced disconnect in cases where a client connection is about +# to be closed but remote refuses to confirm the disconnect request. Setting +# this to a lower value mitigates the effects of resource starvation in case of +# a DOS attack but increases the risk of failing to flush the remaining portion +# of data. +# DisconnectTimeout: 15 + +# By default, if a remote suddenly reconnects, ACNG tries at least two times to +# redownload from the same or different location (if known). +# DlMaxRetries: 2 + # Pigeonholing files (like static vs. volatile contents) is done by (extended) # regular expressions. # @@ -214,7 +246,7 @@ # log writing. Non-zero value triggers at least faster log file flushing. # # Some higher bits only working with a special debug build of apt-cacher-ng, -# see the manual for details. The setting has an alias named UnbufferLogs. +# see the manual for details. # # WARNING: this can write significant amount of data into apt-cacher.err logfile. # @@ -259,7 +291,13 @@ # Network timeout for outgoing connections, in seconds. # -# NetworkTimeout: 60 +# NetworkTimeout: 40 + +# Fast fallback timeout, in seconds. This is the time to wait before +# alternative target addresses for a client connection are tried, which can be +# usefull for quick fallback to IPv4 in case of whacky IPv6 configuration. +# +# FastTimeout = 4 # Sometimes it makes sense to not store the data in cache and just return the # package data to client while it comes in. The following DontCache* parameters @@ -309,7 +347,7 @@ # between them or explicitly create them. # # LocalDirs: woo /data/debarchive/woody ; hamm /data/debarchive/hamm -LocalDirs: acng-doc @DOCDIR@ +LocalDirs: acng-doc @CMAKE_INSTALL_FULL_DOCDIR@ # Precache a set of files referenced by specified index files. This can be used # to create a partial mirror usable for offline work. There are certain limits @@ -402,8 +440,8 @@ # PassThroughPattern: private-ppa\.launchpad\.net:443$ # PassThroughPattern: .* # this would allow CONNECT to everything # -# Default: -# PassThroughPattern: ^bugs.debian.org:443$ +# Default: ^(bugs\.debian\.org|changelogs\.ubuntu\.com):443$ +# PassThroughPattern: ^(bugs\.debian\.org|changelogs\.ubuntu\.com):443$ # It's possible that an evil client requests a volatile file but does not # retrieve the response and keeps the connection effectively stuck over @@ -495,8 +533,8 @@ # # BadRedirDetectMime: text/html -# When a BUS signal is received (typically IO issues), a shell command can be -# execute before the daemon is terminated. +# When a BUS signal is received (typically on IO errors), a shell command can be +# executed before the daemon is terminated. # Example: # BusAction: ls -l /proc/$PPID/ | mail -s SIGBUS! root @@ -505,3 +543,20 @@ # differrent meaning in the future. # # NoSSLChecks: 0 + +# Setting this value means: on file downloads from/via cache, tag relevant +# files. And when acngtool runs the shrink command, it will look at the day +# when the file was retrieved from cache last time (and not when it was +# originally downloaded). +# +# TrackFileUse: 0 + +# Controls preallocation of file system space where this feature is supported. +# This might reduce disk fragmentation and therefore improve later read +# performance. However, write performance can be reduced which could be +# exploited by malicious users. +# The value defines a size limit of how much to report to the OS as expected +# file size (starting from the beginning of the file). +# Set to zero to disable this feature completely. Default: one megabyte +# +# ReserveSpace: 1048576 diff -Nru apt-cacher-ng-0.9.1/conf/archlx_mirrors apt-cacher-ng-3.3.1/conf/archlx_mirrors --- apt-cacher-ng-0.9.1/conf/archlx_mirrors 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/archlx_mirrors 2020-01-08 19:58:26.000000000 +0000 @@ -1,99 +1,320 @@ +http://appuals.com/archlinux/ +http://arch-mirror.cloud.louifox.house/ +http://arch-mirror.wtako.net/ +http://arch.eckner.net/archlinux/ +http://arch.jensgutermuth.de/ +http://arch.midov.pl/arch/ +http://arch.mirror.constant.com/ +http://arch.mirror.far.fi/ +http://arch.mirror.square-r00t.net/ +http://arch.mirrors.pair.com/ +http://arch.nimukaito.net/ +http://arch.nixlab.pl/ +http://arch.petarmaric.com/ +http://arch.serverspace.co.uk/arch/ +http://arch.softver.org.mk/archlinux/ +http://arch.unixpeople.org/ +http://archimonde.ts.si/archlinux/ +http://archlinux.beccacervello.it/archlinux/ http://archlinux.c3sl.ufpr.br/ -http://archlinux.goodsoft.lv/ -http://archlinux.kz/ -http://archlinux.limun.org/ -http://archlinux.mirror.dkm.cz/pub/archlinux/ +http://archlinux.cs.nctu.edu.tw/ +http://archlinux.cu.be/ +http://archlinux.de-labrusse.fr/ +http://archlinux.dynamict.se/ +http://archlinux.grena.ge/ +http://archlinux.honkgong.info/ +http://archlinux.ip-connect.vn.ua/ +http://archlinux.iskon.hr/ +http://archlinux.koyanet.lv/archlinux/ +http://archlinux.mailtunnel.eu/ +http://archlinux.melbourneitmirror.net/ +http://archlinux.mirror.ba/ +http://archlinux.mirror.colo-serv.net/ +http://archlinux.mirror.digitalpacific.com.au/ +http://archlinux.mirror.garr.it/archlinux/ +http://archlinux.mirror.iphh.net/ http://archlinux.mirror.kangaroot.net/ +http://archlinux.mirror.liquidtelecom.com/ +http://archlinux.mirror.liteserver.nl/ +http://archlinux.mirror.pcextreme.nl/ +http://archlinux.mirror.py/archlinux/ +http://archlinux.mirror.rafal.ca/ http://archlinux.mirror.root.lu/ +http://archlinux.mirror.wearetriple.com/ +http://archlinux.mirrors.benatherton.com/ +http://archlinux.mirrors.linux.ro/ http://archlinux.mirrors.ovh.net/archlinux/ http://archlinux.mirrors.uk2.net/ +http://archlinux.mivzakim.net/ http://archlinux.nautile.nc/archlinux/ +http://archlinux.olanfa.rocks/ http://archlinux.polymorf.fr/ -http://archlinux.puzzle.ch/ -http://archlinux.supsec.org/ +http://archlinux.pop-es.rnp.br/ +http://archlinux.rezopole.net/ +http://archlinux.surlyjake.com/archlinux/ +http://archlinux.thaller.ws/ +http://archlinux.uib.no/ +http://archlinux.uk.mirror.allworldit.com/archlinux/ +http://archlinux.vi-di.fr/ +http://archlinux.za.mirror.allworldit.com/archlinux/ +http://archlinux.zepto.cloud/ +http://archmirror.hbit.sztaki.hu/archlinux/ +http://archmirror.lavatech.top/ +http://arlm.tyzoid.com/ http://artfiles.org/archlinux.org/ -http://cake.lib.fit.edu/archlinux/ -http://cosmos.cites.illinois.edu/pub/archlinux/ -http://distrib-coffee.ipsl.jussieu.fr/pub/linux/archlinux/ +http://br.mirror.archlinux-br.org/ +http://ca.us.mirror.archlinux-br.org/ +http://dfw.mirror.rackspace.com/archlinux/ +http://dist-mirror.fem.tu-ilmenau.de/archlinux/ +http://distro.ibiblio.org/archlinux/ +http://download.nus.edu.sg/mirror/archlinux/ +http://f.archlinuxvn.org/archlinux/ +http://foss.aueb.gr/mirrors/linux/archlinux/ http://ftp-stud.hs-esslingen.de/pub/Mirrors/archlinux/ +http://ftp.acc.umu.se/mirror/archlinux/ http://ftp.byfly.by/pub/archlinux/ http://ftp.cc.uoc.gr/mirrors/linux/archlinux/ -http://ftp.ds.hj.se/pub/os/linux/archlinux/ -http://ftp.eenet.ee/pub/archlinux/ +http://ftp.energia.mta.hu/pub/mirrors/ftp.archlinux.org/ +http://ftp.fau.de/archlinux/ +http://ftp.fi.muni.cz/pub/linux/arch/ +http://ftp.gwdg.de/pub/linux/archlinux/ http://ftp.halifax.rwth-aachen.de/archlinux/ +http://ftp.harukasan.org/archlinux/ http://ftp.heanet.ie/mirrors/ftp.archlinux.org/ http://ftp.hosteurope.de/mirror/ftp.archlinux.org/ +http://ftp.icm.edu.pl/pub/Linux/dist/archlinux/ http://ftp.iinet.net.au/pub/archlinux/ http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/ http://ftp.kaist.ac.kr/ArchLinux/ -http://ftp.linux.kiev.ua/pub/Linux/ArchLinux/ +http://ftp.lanet.kr/pub/archlinux/ +http://ftp.linux.cz/pub/linux/arch/ http://ftp.linux.org.tr/archlinux/ http://ftp.lysator.liu.se/pub/archlinux/ -http://ftp.nluug.nl/pub/os/Linux/distr/archlinux/ +http://ftp.myrveln.se/pub/linux/archlinux/ +http://ftp.nluug.nl/os/Linux/distr/archlinux/ http://ftp.ntua.gr/pub/linux/archlinux/ http://ftp.osuosl.org/pub/archlinux/ http://ftp.otenet.gr/linux/archlinux/ -http://ftp.portlane.com/pub/os/linux/archlinux/ -http://ftp.rnl.ist.utl.pt/pub/archlinux/ -http://ftp.roedu.net/mirrors/archlinux.org/ +http://ftp.rediris.es/mirror/archlinux/ +http://ftp.rnl.tecnico.ulisboa.pt/pub/archlinux/ +http://ftp.sh.cvut.cz/arch/ +http://ftp.snt.utwente.nl/pub/os/linux/archlinux/ http://ftp.spline.inf.fu-berlin.de/mirrors/archlinux/ +http://ftp.swin.edu.au/archlinux/ http://ftp.tku.edu.tw/Linux/ArchLinux/ +http://ftp.tsukuba.wide.ad.jp/Linux/archlinux/ http://ftp.tu-chemnitz.de/pub/linux/archlinux/ +http://ftp.u-strasbg.fr/linux/distributions/archlinux/ +http://ftp.uni-bayreuth.de/linux/archlinux/ +http://ftp.uni-hannover.de/archlinux/ http://ftp.uni-kl.de/pub/linux/archlinux/ -http://ftp5.gwdg.de/pub/linux/archlinux/ -http://less.cogeco.net/pub/archlinux/ -http://linux.cs.nctu.edu.tw/archlinux/ +http://ftp.vectranet.pl/archlinux/ +http://ftp.wrz.de/pub/archlinux/ +http://ftp.yzu.edu.tw/Linux/archlinux/ +http://ger.mirror.pkgbuild.com/ +http://glua.ua.pt/pub/archlinux/ +http://gluttony.sin.cvut.cz/arch/ +http://hkg.mirror.rackspace.com/archlinux/ +http://iad.mirror.rackspace.com/archlinux/ +http://iad.mirrors.misaka.one/archlinux/ +http://il.us.mirror.archlinux-br.org/ +http://ind.mirror.pkgbuild.com/ +http://jpn.mirror.pkgbuild.com/ +http://linorg.usp.br/archlinux/ +http://linux.rz.rub.de/archlinux/ +http://lon.mirror.rackspace.com/archlinux/ +http://mex.mirror.pkgbuild.com/ http://mir.archlinux.fr/ -http://mir1.archlinux.fr/archlinux/ -http://miroir.ezvan.fr/archlinux/ +http://mirror-archlinux.webruimtehosting.nl/ +http://mirror-hk.koddos.net/archlinux/ +http://mirror.0x.sg/archlinux/ +http://mirror.23media.com/archlinux/ http://mirror.aarnet.edu.au/pub/archlinux/ -http://mirror.academica.fi/archlinux/ -http://mirror.ancl.hawaii.edu/linux/archlinux/ -http://mirror.archlinux.fi/archlinux/ +http://mirror.adct.be/arch/ +http://mirror.aktkn.sg/archlinux/ +http://mirror.ams1.nl.leaseweb.net/archlinux/ +http://mirror.archlinux.cl/ +http://mirror.archlinux.ikoula.com/archlinux/ http://mirror.archlinux.no/ -http://mirror.archlinux.ro/archlinux/ -http://mirror.bjtu.edu.cn/archlinux/ -http://mirror.cinosure.com/archlinux/ +http://mirror.arizona.edu/archlinux/ +http://mirror.bethselamin.de/ +http://mirror.bytemark.co.uk/archlinux/ +http://mirror.cc.columbia.edu/pub/linux/archlinux/ +http://mirror.cedia.org.ec/archlinux/ +http://mirror.cedille.club/archlinux/ +http://mirror.chaoticum.net/arch/ +http://mirror.checkdomain.de/archlinux/ +http://mirror.cs.pitt.edu/archlinux/ +http://mirror.cs.vt.edu/pub/ArchLinux/ http://mirror.csclub.uwaterloo.ca/archlinux/ http://mirror.cse.iitk.ac.in/archlinux/ -http://mirror.de.leaseweb.net/archlinux/ -http://mirror.devnu11.net/archlinux/ -http://mirror.ece.vt.edu/archlinux/ -http://mirror.ihost.md/archlinux/ +http://mirror.cyberbits.eu/archlinux/ +http://mirror.dal10.us.leaseweb.net/archlinux/ +http://mirror.datacenter.by/pub/archlinux/ +http://mirror.dc02.hackingand.coffee/arch/ +http://mirror.digitalnova.at/archlinux/ +http://mirror.dkm.cz/archlinux/ +http://mirror.easyname.at/archlinux/ +http://mirror.edatel.net.co/archlinux/ +http://mirror.es.its.nyu.edu/archlinux/ +http://mirror.espoch.edu.ec/archlinux/ +http://mirror.f4st.host/archlinux/ +http://mirror.fra10.de.leaseweb.net/archlinux/ +http://mirror.fsmg.org.nz/archlinux/ +http://mirror.gnomus.de/ +http://mirror.host.ag/archlinux/ +http://mirror.i3d.net/pub/archlinux/ +http://mirror.ibcp.fr/pub/archlinux/ +http://mirror.init7.net/archlinux/ http://mirror.internode.on.net/pub/archlinux/ +http://mirror.is.co.za/mirror/archlinux.org/ http://mirror.isoc.org.il/pub/archlinux/ http://mirror.its.dal.ca/archlinux/ -http://mirror.lividpenguin.com/pub/archlinux/ +http://mirror.kaminski.io/archlinux/ +http://mirror.kku.ac.th/archlinux/ +http://mirror.koddos.net/archlinux/ +http://mirror.labkom.id/archlinux/ +http://mirror.lagoon.nc/pub/archlinux/ +http://mirror.lastmikoi.net/archlinux/ +http://mirror.librelabucm.org/archlinux/ +http://mirror.lnx.sk/pub/linux/archlinux/ +http://mirror.lty.me/archlinux/ http://mirror.lzu.edu.cn/archlinux/ -http://mirror.mocker.org/archlinux/ -http://mirror.netglobalis.net/archlinux/ -http://mirror.nl.leaseweb.net/archlinux/ -http://mirror.optus.net/archlinux/ -http://mirror.rit.edu/archlinux/ +http://mirror.math.princeton.edu/pub/archlinux/ +http://mirror.metalgamer.eu/archlinux/ +http://mirror.metrocast.net/archlinux/ +http://mirror.mia11.us.leaseweb.net/archlinux/ +http://mirror.mijn.host/archlinux/ +http://mirror.mikrogravitation.org/archlinux/ +http://mirror.mirohost.net/archlinux/ +http://mirror.nak-mci.ir/arch/ +http://mirror.neostrada.nl/archlinux/ +http://mirror.netcologne.de/archlinux/ +http://mirror.netweaver.uk/archlinux/ +http://mirror.neuf.no/archlinux/ +http://mirror.nus.edu.sg/archlinux/ +http://mirror.oldsql.cc/archlinux/ +http://mirror.one.com/archlinux/ +http://mirror.onet.pl/pub/mirrors/archlinux/ +http://mirror.onevip.mk/archlinux/ +http://mirror.orbit-os.com/archlinux/ +http://mirror.osbeck.com/archlinux/ +http://mirror.pit.teraswitch.com/archlinux/ +http://mirror.pkgbuild.com/ +http://mirror.pmf.kg.ac.rs/archlinux/ +http://mirror.poliwangi.ac.id/archlinux/ +http://mirror.premi.st/archlinux/ +http://mirror.ps.kz/archlinux/ +http://mirror.pseudoform.org/ +http://mirror.puzzle.ch/archlinux/ +http://mirror.rackspace.com/archlinux/ +http://mirror.reisenbauer.ee/archlinux/ +http://mirror.rise.ph/archlinux/ +http://mirror.rol.ru/archlinux/ +http://mirror.scd31.com/arch/ http://mirror.selfnet.de/archlinux/ +http://mirror.sergal.org/archlinux/ +http://mirror.sfo12.us.leaseweb.net/archlinux/ +http://mirror.siena.edu/archlinux/ +http://mirror.smith.geek.nz/archlinux/ +http://mirror.srv.fail/archlinux/ +http://mirror.stephen304.com/archlinux/ +http://mirror.system.is/arch/ +http://mirror.t-home.mk/archlinux/ +http://mirror.terrahost.no/linux/archlinux/ +http://mirror.thekinrar.fr/archlinux/ +http://mirror.truenetwork.ru/archlinux/ +http://mirror.ubrco.de/archlinux/ +http://mirror.ufam.edu.br/archlinux/ +http://mirror.ufro.cl/archlinux/ +http://mirror.ufscar.br/archlinux/ +http://mirror.umd.edu/archlinux/ +http://mirror.ungleich.ch/mirror/packages/archlinux/ +http://mirror.united-gameserver.de/archlinux/ +http://mirror.uta.edu.ec/archlinux/ +http://mirror.veriteknik.net.tr/archlinux/ http://mirror.vpsfree.cz/archlinux/ +http://mirror.vtti.vt.edu/archlinux/ +http://mirror.wdc1.us.leaseweb.net/archlinux/ +http://mirror.wormhole.eu/archlinux/ +http://mirror.wtnet.de/arch/ +http://mirror.xeonbd.com/archlinux/ +http://mirror.xtom.com.hk/archlinux/ http://mirror.yandex.ru/archlinux/ -http://mirror.yellowfiber.net/archlinux/ -http://mirror.yongbok.net/archlinux/ -http://mirror6.bjtu.edu.cn/archlinux/ +http://mirror2.totbb.net/archlinux/ http://mirrors.163.com/archlinux/ -http://mirrors.adnettelecom.ro/archlinux/ -http://mirrors.cat.pdx.edu/archlinux/ +http://mirrors.acm.wpi.edu/archlinux/ +http://mirrors.advancedhosters.com/archlinux/ +http://mirrors.aggregate.org/archlinux/ +http://mirrors.arnoldthebat.co.uk/archlinux/ +http://mirrors.atviras.lt/archlinux/ +http://mirrors.cat.net/archlinux/ +http://mirrors.celianvdb.fr/archlinux/ +http://mirrors.cqu.edu.cn/archlinux/ http://mirrors.dotsrc.org/archlinux/ +http://mirrors.eric.ovh/arch/ +http://mirrors.evowise.com/archlinux/ http://mirrors.gigenet.com/archlinux/ -http://mirrors.lax1.thegcloud.com/arch// -http://mirrors.mithril.org.ua/linux/archlinux/ +http://mirrors.ims.nksc.lt/archlinux/ +http://mirrors.kernel.org/archlinux/ +http://mirrors.kurnode.com/archlinux/ +http://mirrors.liquidweb.com/archlinux/ +http://mirrors.lug.mtu.edu/archlinux/ +http://mirrors.m247.ro/archlinux/ +http://mirrors.manchester.m247.com/arch-linux/ +http://mirrors.mirjamali.ir/archlinux/ +http://mirrors.myaegean.gr/linux/archlinux/ http://mirrors.n-ix.net/archlinux/ +http://mirrors.nav.ro/archlinux/ +http://mirrors.netix.net/archlinux/ +http://mirrors.neusoft.edu.cn/archlinux/ +http://mirrors.nic.cz/archlinux/ +http://mirrors.nix.org.ua/linux/archlinux/ +http://mirrors.niyawe.de/archlinux/ +http://mirrors.nxthost.com/archlinux/ +http://mirrors.ocf.berkeley.edu/archlinux/ +http://mirrors.phx.ms/arch/ +http://mirrors.pidginhost.com/arch/ http://mirrors.prometeus.net/archlinux/ +http://mirrors.rit.edu/archlinux/ http://mirrors.rutgers.edu/archlinux/ -http://mirrors.st.uz/archlinux/ +http://mirrors.sjtug.sjtu.edu.cn/archlinux/ +http://mirrors.sonic.net/archlinux/ +http://mirrors.standaloneinstaller.com/archlinux/ +http://mirrors.tuna.tsinghua.edu.cn/archlinux/ +http://mirrors.udenar.edu.co/archlinux/ +http://mirrors.ukfast.co.uk/sites/archlinux.org/ +http://mirrors.uni-plovdiv.net/archlinux/ +http://mirrors.ustc.edu.cn/archlinux/ +http://mirrors.xjtu.edu.cn/archlinux/ +http://mirrors.xmission.com/archlinux/ +http://mirrors.xtom.com/archlinux/ +http://mirrors.xtom.nl/archlinux/ +http://mirrors.zju.edu.cn/archlinux/ +http://muug.ca/mirror/archlinux/ +http://nova.quantum-mirror.hu/mirrors/pub/archlinux/ +http://ord.mirror.rackspace.com/archlinux/ +http://osl.ugr.es/archlinux/ +http://packages.oth-regensburg.de/archlinux/ +http://pet.inf.ufsc.br/mirrors/archlinux/ http://piotrkosoft.net/pub/mirrors/ftp.archlinux.org/ -http://repo.ukdw.ac.id/archlinux/ -http://schlunix.org/archlinux/ +http://pkg.adfinis-sygroup.ch/archlinux/ +http://quantum-mirror.hu/mirrors/pub/archlinux/ +http://reflector.luehm.com/arch/ +http://repo.ialab.dsu.edu/archlinux/ +http://repo.iut.ac.ir/repo/archlinux/ +http://repo.miserver.it.umich.edu/archlinux/ +http://repo.sadjad.ac.ir/arch/ +http://sgp.mirror.pkgbuild.com/ http://shadow.ind.ntou.edu.tw/archlinux/ -http://sunsite.rediris.es/mirror/archlinux/ -http://www.bitwave.com.br/downloads/archlinux/ +http://sharing.thelinuxsect.com/archlinux/ +http://super.quantum-mirror.hu/mirrors/pub/archlinux/ +http://suro.ubaya.ac.id/archlinux/ +http://syd.mirror.rackspace.com/archlinux/ +http://tux.rainside.sk/archlinux/ +http://www.caco.ic.unicamp.br/archlinux/ http://www.gtlib.gatech.edu/pub/archlinux/ -http://www.laqee.unal.edu.co/archlinux/ -http://www.las.ic.unicamp.br/pub/archlinux/ -http://www2.itti.ifce.edu.br/archlinux/ +http://www.gutscheindrache.com/mirror/archlinux/ +http://www.mirrorservice.org/sites/ftp.archlinux.org/ +http://www.ratenzahlung.de/mirror/archlinux/ +http://za.mirror.archlinux-br.org/ diff -Nru apt-cacher-ng-0.9.1/conf/CMakeLists.txt apt-cacher-ng-3.3.1/conf/CMakeLists.txt --- apt-cacher-ng-0.9.1/conf/CMakeLists.txt 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/CMakeLists.txt 2020-01-08 19:58:26.000000000 +0000 @@ -2,9 +2,9 @@ CONFIGURE_FILE("acng.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/acng.conf") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/acng.conf" DESTINATION ${CFGDIR}) -install(DIRECTORY ./ DESTINATION ${CFGDIR} - FILES_MATCHING PATTERN "*.conf") -install(DIRECTORY ./ DESTINATION ${LIBDIR} - FILES_MATCHING REGEX "mirrors$|mirrors.gz$|html$|css$|default$") +install(FILES security.conf DESTINATION ${CFGDIR}) +file(GLOB OTHER_DATA "*mirrors" "*mirrors.gz" "*.html" "*.css" "*default") +install(FILES ${OTHER_DATA} DESTINATION ${LIBDIR}) +#message("${OTHER_DATA} goes to ${LIBDIR}") diff -Nru apt-cacher-ng-0.9.1/conf/cygwin_mirrors apt-cacher-ng-3.3.1/conf/cygwin_mirrors --- apt-cacher-ng-0.9.1/conf/cygwin_mirrors 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/cygwin_mirrors 2020-01-08 19:58:26.000000000 +0000 @@ -1,60 +1,50 @@ -http://artfiles.org/cygwin.org/pub/cygwin/ -http://bo.mirror.garr.it/mirrors/sourceware.org/cygwin/ -http://cygwin.asis.io/ -http://cygwin.cybermirror.org/ -http://cygwin.jpacheco.net/ +http://cygwin.cathedral-networks.org/ +http://cygwin.mbwarez.dk/ http://cygwin.mirror.constant.com/ -http://cygwin.mirror.gtcomm.net/ +http://cygwin.mirror.globo.tech/ http://cygwin.mirror.rafal.ca/ -http://cygwin.mirrors.hoobly.com/ -http://cygwin.mirrors.pair.com/ http://cygwin.mirror.uk.sargasso.net/ +http://cygwin.mirrors.hoobly.com/ http://cygwin.osuosl.org/ -http://cygwin.parentingamerica.com/ -http://cygwin.refractal.net/ -http://cygwin.skazkaforyou.com/ -http://download.nus.edu.sg/mirror/cygwin/ -http://ftp.cc.uoc.gr/mirrors/cygwin/ -http://ftp.eq.uc.pt/software/pc/prog/cygwin/ +http://cygwin.uib.no/ +http://cygwin.viem-it.no/ +http://ftp-stud.hs-esslingen.de/pub/Mirrors/sources.redhat.com/cygwin/ +http://ftp.acc.umu.se/mirror/cygwin/ +http://ftp.cse.yzu.edu.tw/pub/cygwin/ +http://ftp.fau.de/cygwin/ http://ftp.fsn.hu/pub/cygwin/ -http://ftp.gwdg.de/pub/linux/sources.redhat.com/cygwin/ -http://ftp.hawo.stw.uni-erlangen.de/cygwin/ -http://ftp.heanet.ie/pub/cygwin/ http://ftp.iij.ad.jp/pub/cygwin/ -http://ftp.inf.tu-dresden.de/software/windows/cygwin32/ http://ftp.jaist.ac.jp/pub/cygwin/ http://ftp.rnl.tecnico.ulisboa.pt/pub/cygwin/ http://ftp.snt.utwente.nl/pub/software/cygwin/ -http://ftp-stud.hs-esslingen.de/pub/Mirrors/sources.redhat.com/cygwin/ http://ftp.yz.yamagata-u.ac.jp/pub/cygwin/ -http://gd.tuwien.ac.at/gnu/cygwin/ +http://ftp.yzu.edu.tw/cygwin/ http://linorg.usp.br/cygwin/ http://linux.rz.ruhr-uni-bochum.de/download/cygwin/ -http://lug.mtu.edu/cygwin/ +http://mirror.checkdomain.de/cygwin/ +http://mirror.clarkson.edu/cygwin/ http://mirror.cs.vt.edu/pub/cygwin/cygwin/ +http://mirror.csclub.uwaterloo.ca/cygwin/ +http://mirror.datacenter.by/pub/mirrors/cygwin/ http://mirror.easyname.at/cygwin/ +http://mirror.homelab.no/cygwin/ http://mirror.internode.on.net/pub/cygwin/ -http://mirror.lagoon.nc/pub/cygwin/ -http://mirror.nexcess.net/cygwin/ -http://mirror.pkill.info/cygwin/ -http://mirrors.163.com/cygwin/ -http://mirrors.chauf.net/cygwin/ -http://mirrors.fe.up.pt/pub/cygwin/ -http://mirrors.go-parts.com/cygwin/ +http://mirror.isoc.org.il/pub/cygwin/ +http://mirror.koddos.net/cygwin/ +http://mirror.rise.ph/cygwin/cygwin/ +http://mirror.steadfast.net/cygwin/ +http://mirror.team-cymru.com/cygwin/ +http://mirrors.dotsrc.org/cygwin/ http://mirrors.kernel.org/sourceware/cygwin/ http://mirrors.koehn.com/cygwin/cygwin-ftp/ -http://mirrors-ru.go-parts.com/cygwin/ +http://mirrors.metapeer.com/cygwin/ +http://mirrors.netix.net/cygwin/ http://mirrors.sonic.net/cygwin/ http://mirrors.syringanetworks.net/cygwin/ -http://mirror.steadfast.net/cygwin/ -http://mirrors-uk.go-parts.com/cygwin/ -http://mirrors-usa.go-parts.com/cygwin/ -http://mirrors.ustc.edu.cn/cygwin/ -http://mirror.switch.ch/ftp/mirror/cygwin/ http://mirrors.xmission.com/cygwin/ -http://mirror.team-cymru.org/cygwin/ -http://piotrkosoft.net/pub/mirrors/cygwin/ +http://muug.ca/mirror/cygwin/ http://sourceware.mirrors.tds.net/pub/sourceware.org/cygwin/ http://ucmirror.canterbury.ac.nz/cygwin/ -http://www.gtlib.gatech.edu/pub/cygwin/ +http://www.gutscheinrausch.de/mirror/cygwin/ http://www.mirrorservice.org/sites/sourceware.org/pub/cygwin/ +http://www.pirbot.com/mirrors/cygwin/ Binary files /tmp/tmpkjulcxzb/ruXzwKbog_/apt-cacher-ng-0.9.1/conf/deb_mirrors.gz and /tmp/tmpkjulcxzb/I6ezfHM2L0/apt-cacher-ng-3.3.1/conf/deb_mirrors.gz differ diff -Nru apt-cacher-ng-0.9.1/conf/epel_mirrors apt-cacher-ng-3.3.1/conf/epel_mirrors --- apt-cacher-ng-0.9.1/conf/epel_mirrors 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/epel_mirrors 2020-01-08 19:58:26.000000000 +0000 @@ -1,140 +1,206 @@ -http://anorien.csc.warwick.ac.uk/mirrors/epel/ -http://buaya.klas.or.id/epel/ -http://epel.mirror.net.in/epel/ -http://epel.mirrors.ovh.net/epel/ -http://epel.vpsnet.lt/epel/ +http://centos.anexia.at/epel/ +http://dfw.mirror.rackspace.com/epel/ +http://download-ib01.fedoraproject.org/pub/epel/ +http://epel.blizoo.mk/epel/ +http://epel.mirror.angkasa.id/pub/epel/ +http://epel.mirror.liquidtelecom.com/epel/ +http://espejito.fder.edu.uy/fedora/epel/ +http://fedora-epel.koyanet.lv/epel/ http://fedora-epel.mirrors.tds.net/fedora-epel/ -http://fedora-mirror01.rbc.ru/pub/epel/ -http://fedora.aau.at/epel/ +http://fedora-mirror.zerocopy.io/epel/ +http://fedora-mirror02.rbc.ru/pub/epel/ +http://fedora.cs.nctu.edu.tw/epel/ http://fedora.cu.be/epel/ -http://fedora.ip-connect.vn.ua/fedora-epel/ http://fedora.is.co.za/epel/ +http://fedora.melbourneitmirror.net/epel/ +http://fedora.mirror.ac.za/epel/ +http://fedora.mirror.garr.it/epel/ http://fedora.mirror.serversaustralia.com.au/epel/ http://fedora.mirrors.pair.com/epel/ http://fedora.mirrors.telekom.ro/pub/epel/ -http://fedora.skyggnir.is/epel/ -http://fedora.uberglobalmirror.com/epel/ +http://fedora.nyherji.is/epel/ +http://fedora.tu-chemnitz.de/pub/linux/fedora-epel/ http://fedora.uib.no/epel/ http://fedora.westmancom.com/epel/ http://fr2.rpmfind.net/linux/epel/ http://ftp-stud.hs-esslingen.de/pub/epel/ http://ftp.acc.umu.se/mirror/fedora/epel/ +http://ftp.arnes.si/mirrors/epel/ http://ftp.cica.es/epel/ -http://ftp.colocall.net/pub/epel/ -http://ftp.crc.dk/fedora-epel/ +http://ftp.cse.buffalo.edu/pub/epel/ http://ftp.cuhk.edu.hk/pub/linux/fedora-epel/ http://ftp.fau.de/epel/ +http://ftp.fi.muni.cz/pub/linux/fedora/epel/ http://ftp.icm.edu.pl/pub/Linux/fedora/linux/epel/ -http://ftp.iij.ad.jp/pub/linux/fedora/epel/ +http://ftp.iij.ad.jp/pub/linux/Fedora/epel/ http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/ -http://ftp.kddilabs.jp/Linux/packages/fedora/epel/ -http://ftp.linux.ncsu.edu/pub/epel/ -http://ftp.linux.org.tr/epel/ http://ftp.lysator.liu.se/pub/epel/ http://ftp.nluug.nl/pub/os/Linux/distr/fedora-epel/ -http://ftp.osuosl.org/pub/fedora-epel/ -http://ftp.rediris.es/mirror/fedora-epel/ +http://ftp.plusline.net/epel/ http://ftp.riken.jp/Linux/fedora/epel/ +http://ftp.uma.es/mirror/epel/ http://ftp.uni-bayreuth.de/linux/fedora-epel/ +http://ftp.uni-kl.de/pub/linux/fedora-epel/ http://ftp.uni-stuttgart.de/epel/ -http://ftp.uninett.no/linux/epel/ -http://ftp.up.pt/fedora-epel/ http://ftp.upjs.sk/pub/mirrors/epel/ +http://ftp.wcss.pl/pub/linux/epel/ http://ftp.wrz.de/pub/fedora-epel/ +http://ftp.yz.yamagata-u.ac.jp/pub/linux/fedora-projects/epel/ +http://ftp.yzu.edu.tw/Linux/Fedora-EPEL/ +http://hk.mirrors.thegigabit.com/epel/ +http://hkg.mirror.rackspace.com/epel/ +http://iad.mirror.rackspace.com/epel/ http://kartolo.sby.datautama.net.id/EPEL/ -http://kdeforge2.unl.edu/mirrors/epel/ -http://linux.mirrors.es.net/fedora-epel/ -http://lug.mtu.edu/epel/ +http://lon.mirror.rackspace.com/epel/ http://mir01.syntis.net/epel/ -http://mirror.23media.de/epel/ -http://mirror.awanti.com/epel/ -http://mirror.bjtu.edu.cn/fedora-epel/ +http://mirror.23media.com/epel/ +http://mirror.aarnet.edu.au/pub/epel/ +http://mirror.arizona.edu/fedora-epel/ +http://mirror.as24220.net/pub/epel/ +http://mirror.atl.genesisadaptive.com/epel/ +http://mirror.bacloud.com/epel/ http://mirror.bytemark.co.uk/fedora/epel/ +http://mirror.cedia.org.ec/epel/ +http://mirror.cherryservers.com/epel/ http://mirror.chpc.utah.edu/pub/epel/ -http://mirror.ci.ifes.edu.br/epel/ -http://mirror.clarkson.edu/epel/ -http://mirror.cogentco.com/pub/linux/epel/ +http://mirror.clarkson.edu/fedora-epel/ +http://mirror.coastal.edu/epel/ http://mirror.compevo.com/epel/ http://mirror.cs.pitt.edu/epel/ +http://mirror.cs.princeton.edu/pub/mirrors/epel/ http://mirror.csclub.uwaterloo.ca/fedora/epel/ +http://mirror.dal.nexril.net/fedora-epel/ +http://mirror.datacenter.by/pub/fedoraproject.org/epel/ +http://mirror.datto.com/fedora/epel/ http://mirror.de.leaseweb.net/epel/ -http://mirror.dgn.net.tr/epel/ -http://mirror.digmia.com/epel/ -http://mirror.dionipe.net/fedora/epel/ -http://mirror.duomenucentras.lt/epel/ -http://mirror.espoch.edu.ec/fedora-epel/ +http://mirror.dst.ca/epel/ +http://mirror.ehost.vn/epel/ +http://mirror.epn.edu.ec/epel/ +http://mirror.etf.bg.ac.rs/epel/ http://mirror.euserv.net/linux/fedora-epel/ -http://mirror.fraunhofer.de/dl.fedoraproject.org/epel/ +http://mirror.freethought-internet.co.uk/epel/ http://mirror.globo.com/epel/ +http://mirror.grid.uchicago.edu/pub/linux/epel/ +http://mirror.hoster.kz/fedora/epel/ http://mirror.hosting90.cz/epel/ +http://mirror.hostnet.nl/epel/ http://mirror.i3d.net/pub/fedora-epel/ -http://mirror.ibcp.fr/pub/epel/ http://mirror.imt-systems.com/epel/ +http://mirror.in2p3.fr/pub/epel/ +http://mirror.infonline.de/epel/ +http://mirror.init7.net/fedora/epel/ http://mirror.inode.at/epel/ +http://mirror.intergrid.com.au/epel/ +http://mirror.its.dal.ca/pub/epel/ http://mirror.karneval.cz/pub/linux/fedora/epel/ http://mirror.kinamo.be/epel/ http://mirror.lagoon.nc/pub/epel/ -http://mirror.liquidtelecom.com/fedora/epel/ +http://mirror.linux-ia64.org/epel/ http://mirror.logol.ru/epel/ +http://mirror.lzu.edu.cn/epel/ +http://mirror.marwan.ma/fedora/epel/ +http://mirror.math.princeton.edu/pub/epel/ http://mirror.metrocast.net/fedora/epel/ -http://mirror.nexcess.net/epel/ +http://mirror.mrjester.net/fedora/epel/ +http://mirror.neostrada.nl/epel/ +http://mirror.netcologne.de/fedora-epel/ +http://mirror.netsite.dk/epel/ +http://mirror.netweaver.uk/epel/ +http://mirror.nextlayer.at/epel/ http://mirror.nl.leaseweb.net/epel/ +http://mirror.nodesdirect.com/epel/ http://mirror.nonstop.co.il/epel/ http://mirror.nsc.liu.se/fedora-epel/ -http://mirror.omnilance.com/epel/ -http://mirror.onet.pl/pub/mirrors/fedora/linux/epel/ +http://mirror.optus.net/epel/ http://mirror.oss.ou.edu/epel/ http://mirror.overthewire.com.au/pub/epel/ -http://mirror.pmf.kg.ac.rs/fedora/epel/ -http://mirror.premi.st/epel/ -http://mirror.proserve.nl/fedora-epel/ +http://mirror.pit.teraswitch.com/fedora/epel/ +http://mirror.poliwangi.ac.id/epel/ +http://mirror.pregi.net/epel/ +http://mirror.pregi.net/pub/Linux/Fedora/epel/ +http://mirror.prgmr.com/pub/epel/ +http://mirror.ps.kz/epel/ +http://mirror.realcompute.io/epel/ +http://mirror.redium.net/pub/linux/epel/ http://mirror.rise.ph/fedora-epel/ -http://mirror.seas.harvard.edu/epel/ -http://mirror.serverbeheren.nl/epel/ +http://mirror.rnet.missouri.edu/epel/ +http://mirror.sax.uk.as61049.net/epel/ +http://mirror.serverion.com/epel/ http://mirror.sfo12.us.leaseweb.net/epel/ +http://mirror.siena.edu/epel/ +http://mirror.sjc02.svwh.net/fedora-epel/ http://mirror.slu.cz/epel/ -http://mirror.smartmedia.net.id/epel/ -http://mirror.steadfast.net/epel/ -http://mirror.symnds.com/distributions/fedora-epel/ +http://mirror.steadfastnet.com/epel/ +http://mirror.szerverem.hu/epel/ +http://mirror.t-home.mk/epel/ +http://mirror.team-cymru.com/epel/ +http://mirror.twinlakes.net/epel/ +http://mirror.uic.edu/EPEL/ http://mirror.umd.edu/fedora/epel/ -http://mirror.unl.edu/epel/ -http://mirror.us.leaseweb.net/epel/ -http://mirror.utexas.edu/epel/ +http://mirror.upb.edu.co/epel/ +http://mirror.us-midwest-1.nexcess.net/epel/ +http://mirror.uta.edu.ec/epel/ http://mirror.uv.es/mirror/fedora-epel/ -http://mirror.vit.com.tr/mirror/Epel/ -http://mirror.vutbr.cz/epel/ -http://mirror.wanxp.id/epel/ -http://mirror.wbs.co.za/fedora-epel/ +http://mirror.vcu.edu/pub/gnu+linux/epel/ +http://mirror.veriteknik.net.tr/epel/ +http://mirror.vpsnet.com/epel/ +http://mirror.webtastix.net/fedora/epel/ +http://mirror.xeonbd.com/fedora-epel/ +http://mirror.xnet.co.nz/pub/epel/ http://mirror.yandex.ru/epel/ -http://mirror0.babylon.network/epel/ +http://mirror.zetup.net/fedora-epel/ http://mirror01.idc.hinet.net/EPEL/ -http://mirror1.babylon.network/epel/ +http://mirror1.ku.ac.th/fedora/epel/ +http://mirror2.totbb.net/epel/ +http://mirrors.aliyun.com/epel/ +http://mirrors.bangmodhosting.com/epel/ http://mirrors.bestthaihost.com/epel/ -http://mirrors.cat.pdx.edu/epel/ +http://mirrors.bytes.ua/epel/ +http://mirrors.colocall.net/epel/ http://mirrors.coreix.net/fedora-epel/ -http://mirrors.digipower.vn/fedora/epel/ -http://mirrors.hustunique.com/epel/ +http://mirrors.daticum.com/epel/ +http://mirrors.dotsrc.org/fedora-buffet/epel/ +http://mirrors.glesys.net/fedora/epel/ http://mirrors.ircam.fr/pub/fedora/epel/ -http://mirrors.isu.net.sa/pub/fedora/fedora-epel/ http://mirrors.kernel.org/fedora-epel/ +http://mirrors.liquidweb.com/fedora-epel/ +http://mirrors.lug.mtu.edu/epel/ http://mirrors.mit.edu/epel/ +http://mirrors.mivocloud.com/epel/ http://mirrors.n-ix.net/fedora-epel/ +http://mirrors.nav.ro/epel/ http://mirrors.nayatel.com/epel/ http://mirrors.neterra.net/epel/ -http://mirrors.neusoft.edu.cn/epel/ +http://mirrors.netix.net/epel/ http://mirrors.nic.cz/epel/ -http://mirrors.opencas.cn/epel/ -http://mirrors.rit.edu/fedora/epel/ +http://mirrors.njupt.edu.cn/epel/ +http://mirrors.piconets.webwerks.in/fedora-mirror/epel/ +http://mirrors.powernet.com.ru/fedora/epel/ +http://mirrors.sonic.net/epel/ http://mirrors.syringanetworks.net/fedora-epel/ -http://mirrors.telianet.dk/epel/ http://mirrors.thzhost.com/epel/ -http://mirrors.tummy.com/pub/fedora.redhat.com/epel/ +http://mirrors.tuna.tsinghua.edu.cn/epel/ +http://mirrors.ucr.ac.cr/epel/ http://mirrors.ukfast.co.uk/sites/dl.fedoraproject.org/pub/epel/ http://mirrors.uni-ruse.bg/epel/ +http://mirrors.up.pt/fedora-epel/ +http://mirrors.xmission.com/fedora-epel/ http://mirrors.yun-idc.com/epel/ +http://muug.ca/mirror/fedora-epel/ +http://my.fedora.ipserverone.com/epel/ +http://my.mirrors.thegigabit.com/epel/ +http://ord.mirror.rackspace.com/epel/ +http://pkg.adfinis-sygroup.ch/epel/ +http://pubmirror1.math.uh.edu/fedora-buffet/epel/ +http://pubmirror2.math.uh.edu/fedora-buffet/epel/ http://reflector.westga.edu/repos/Fedora-EPEL/ http://repo.boun.edu.tr/epel/ -http://vesta.informatik.rwth-aachen.de/ftp/pub/Linux/fedora-epel/ +http://repos.del.extreme-ix.org/epel/ +http://scientificlinux.physik.uni-muenchen.de/mirror/epel/ +http://sg.fedora.ipserverone.com/epel/ +http://syd.mirror.rackspace.com/epel/ +http://ucmirror.canterbury.ac.nz/linux/fedora/fedora-epel/ http://www.fedora.is/fedora/epel/ +http://www.ftp.ne.jp/Linux/distributions/fedora/epel/ http://www.mirrorservice.org/sites/dl.fedoraproject.org/pub/epel/ -http://www.muug.mb.ca/pub/epel/ +http://www.nic.funet.fi/pub/mirrors/fedora.redhat.com/pub/epel/ diff -Nru apt-cacher-ng-0.9.1/conf/fedora_mirrors apt-cacher-ng-3.3.1/conf/fedora_mirrors --- apt-cacher-ng-0.9.1/conf/fedora_mirrors 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/fedora_mirrors 2020-01-08 19:58:26.000000000 +0000 @@ -1,175 +1,116 @@ http://archive.linux.duke.edu/pub/fedora/linux/ -http://buaya.klas.or.id/fedora/linux/ http://download.fedoraproject.org/pub/fedora/linux/ -http://download.polytechnic.edu.na/pub/fedora/linux/ -http://fedora-mirror01.rbc.ru/pub/fedora/linux/ -http://fedora.aau.at/linux/ -http://fedora.bhs.mirrors.ovh.net/linux/ +http://espejito.fder.edu.uy/fedora/fedora/linux/ +http://fedora-mirror.zerocopy.io/fedora/linux/ +http://fedora-mirror02.rbc.ru/pub/fedora/linux/ http://fedora.blizoo.mk/fedora/linux/ -http://fedora.c3sl.ufpr.br/linux/ -http://fedora.dcc.fc.up.pt/linux/ -http://fedora.inode.at/fedora/linux/ -http://fedora.ip-connect.vn.ua/linux/ http://fedora.is.co.za/linux/ -http://fedora.linux.ee/pub/fedora/linux/ -http://fedora.linuxman.biz/linux/ -http://fedora.mirror.constant.com/linux/ +http://fedora.mirror.angkasa.id/pub/fedora/linux/ http://fedora.mirror.digitalpacific.com.au/linux/ -http://fedora.mirror.garr.it/mirrors/fedora/linux/ +http://fedora.mirror.garr.it/fedora/linux/ +http://fedora.mirror.iweb.com/linux/ +http://fedora.mirror.liteserver.nl/linux/ http://fedora.mirror.root.lu/ -http://fedora.mirrors.ovh.net/linux/ http://fedora.mirrors.pair.com/linux/ http://fedora.mirrors.telekom.ro/pub/fedora/linux/ -http://fedora.osuosl.org/linux/ http://fedora.tu-chemnitz.de/pub/linux/fedora/linux/ -http://fedora.uberglobalmirror.com/fedora/linux/ http://fedora.uib.no/fedora/linux/ -http://fedora.xfree.com.ar/linux/ http://fr2.rpmfind.net/linux/fedora/linux/ http://free.nchc.org.tw/fedora/linux/ http://ftp-stud.hs-esslingen.de/pub/fedora/linux/ http://ftp.acc.umu.se/mirror/fedora/linux/ -http://ftp.astral.ro/mirrors/fedora/pub/fedora/linux/ -http://ftp.byfly.by/pub/fedoraproject.org/linux/ -http://ftp.cc.uoc.gr/pub/fedora/linux/ -http://ftp.cica.es/fedora/linux/ -http://ftp.colocall.net/pub/fedora/linux/ http://ftp.cse.buffalo.edu/pub/fedora/linux/ http://ftp.fau.de/fedora/linux/ http://ftp.fi.muni.cz/pub/linux/fedora/linux/ -http://ftp.free.fr/mirrors/fedora.redhat.com/fedora/linux/ -http://ftp.freepark.org/pub/linux/distributions/fedora/linux/ -http://ftp.gts.lug.ro/fedora/linux/ -http://ftp.halifax.rwth-aachen.de/fedora/linux/ -http://ftp.heanet.ie/pub/fedora/linux/ http://ftp.icm.edu.pl/pub/Linux/fedora/linux/ -http://ftp.isu.edu.tw/pub/Linux/Fedora/linux/ -http://ftp.itu.edu.tr/Mirror/Fedora/linux/ +http://ftp.iij.ad.jp/pub/linux/Fedora/fedora/linux/ http://ftp.jaist.ac.jp/pub/Linux/Fedora/ http://ftp.linux.cz/pub/linux/fedora/linux/ -http://ftp.linux.ncsu.edu/pub/fedora/linux/ http://ftp.lip6.fr/ftp/pub/linux/distributions/fedora/ http://ftp.lysator.liu.se/pub/fedora/linux/ -http://ftp.ncnu.edu.tw/Linux/Fedora/linux/ http://ftp.nluug.nl/pub/os/Linux/distr/fedora/linux/ -http://ftp.ntua.gr/pub/linux/fedora/linux/ -http://ftp.pbone.net/pub/fedora/linux/ -http://ftp.ps.pl/pub/Linux/fedora-linux/ -http://ftp.sjtu.edu.cn/fedora/linux/ -http://ftp.swin.edu.au/fedora/linux/ -http://ftp.tsukuba.wide.ad.jp/Linux/fedora-archive/fedora/linux/ -http://ftp.tsukuba.wide.ad.jp/Linux/fedora/linux/ -http://ftp.tudelft.nl/download.fedora.redhat.com/linux/ -http://ftp.udl.es/pub/fedora/linux/ +http://ftp.plusline.net/fedora/linux/ http://ftp.uma.es/mirror/fedora/linux/ http://ftp.uni-bayreuth.de/linux/fedora/linux/ http://ftp.uni-kl.de/pub/linux/fedora/linux/ -http://ftp.uni-koeln.de/mirrors/fedora/linux/ http://ftp.uni-stuttgart.de/epel/ http://ftp.upjs.sk/pub/fedora/linux/ -http://ftp.usf.edu/pub/fedora/linux/ -http://ftp.ussg.iu.edu/linux/fedora/linux/ -http://ftp.wcss.pl/pub/linux/fedora/linux/ -http://ftp.yz.yamagata-u.ac.jp/pub/linux/fedora/linux/ +http://ftp.yz.yamagata-u.ac.jp/pub/linux/fedora-projects/fedora/linux/ http://ftp.yzu.edu.tw/Linux/Fedora/linux/ -http://ftp6.sjtu.edu.cn/fedora/linux/ -http://gd.tuwien.ac.at/opsys/linux/fedora/linux/ -http://kdeforge2.unl.edu/mirrors/fedora/linux/ -http://linus.iyte.edu.tr/linux/fedora/linux/ http://linux.mirrors.es.net/fedora/ -http://lug.mtu.edu/fedora/linux/ -http://mir01.syntis.net/fedora/linux/ -http://mirror.1000mbps.com/fedora/linux/ -http://mirror.as24220.net/pub/fedora/linux/ +http://mirror.23media.com/fedora/linux/ +http://mirror.aarnet.edu.au/pub/fedora/linux/ +http://mirror.arizona.edu/fedora/linux/ http://mirror.bytemark.co.uk/fedora/epel/ http://mirror.bytemark.co.uk/fedora/linux/ -http://mirror.bytemark.co.uk/fedora/linux/development/24/Everything/armhfp/os/ -http://mirror.bytemark.co.uk/fedora/linux/development/24/Everything/i386/os/ -http://mirror.bytemark.co.uk/fedora/linux/development/24/Everything/x86_64/os/ -http://mirror.cc.vt.edu/pub/fedora/linux/ -http://mirror.cedia.org.ec/fedora/ +http://mirror.bytemark.co.uk/fedora/linux/development/31/Everything/aarch64/os/ +http://mirror.bytemark.co.uk/fedora/linux/development/31/Everything/armhfp/os/ +http://mirror.bytemark.co.uk/fedora/linux/development/31/Everything/x86_64/os/ +http://mirror.cedia.org.ec/fedora/linux/ http://mirror.chpc.utah.edu/pub/fedora/linux/ http://mirror.clarkson.edu/fedora/linux/ -http://mirror.cogentco.com/pub/linux/fedora/linux/ -http://mirror.cpsc.ucalgary.ca/mirror/fedora/linux/ http://mirror.cs.pitt.edu/fedora/linux/ +http://mirror.cs.princeton.edu/pub/mirrors/fedora/linux/ http://mirror.csclub.uwaterloo.ca/fedora/linux/ http://mirror.datacenter.by/pub/fedoraproject.org/linux/ http://mirror.de.leaseweb.net/fedora/linux/ -http://mirror.dhakacom.com/fedora/linux/ -http://mirror.digitalnova.at/fedora/linux/ http://mirror.easyspeedy.com/fedora/ +http://mirror.epn.edu.ec/fedora/linux/ http://mirror.euserv.net/linux/fedora/linux/ -http://mirror.fedora.delta-net.ge/pub/fedora/linux/ -http://mirror.fraunhofer.de/dl.fedoraproject.org/fedora/linux/ http://mirror.globo.com/fedora/linux/ -http://mirror.hmc.edu/fedora/linux/ +http://mirror.hoster.kz/fedora/fedora/linux/ http://mirror.i3d.net/pub/fedora/linux/ +http://mirror.in2p3.fr/pub/fedora/linux/ +http://mirror.infonline.de/fedora/linux/ +http://mirror.init7.net/fedora/fedora/linux/ http://mirror.its.dal.ca/pub/fedora/linux/ http://mirror.karneval.cz/pub/linux/fedora/linux/ http://mirror.lagoon.nc/pub/fedora/linux/ +http://mirror.linux-ia64.org/fedora/linux/ http://mirror.metrocast.net/fedora/linux/ -http://mirror.nbtelecom.com.br/fedora/linux/ +http://mirror.mrjester.net/fedora/linux/ http://mirror.netcologne.de/fedora/linux/ +http://mirror.netsite.dk/fedora/linux/ http://mirror.nexcess.net/fedora/ http://mirror.nl.leaseweb.net/fedora/linux/ http://mirror.nonstop.co.il/fedora/linux/ -http://mirror.nus.edu.sg/fedora/linux/ -http://mirror.onet.pl/pub/mirrors/fedora/linux/ http://mirror.optus.net/fedora/linux/ -http://mirror.ox.ac.uk/sites/download.fedora.redhat.com/pub/fedora/linux/ -http://mirror.pmf.kg.ac.rs/fedora/linux/ -http://mirror.pnl.gov/fedora/linux/ http://mirror.prgmr.com/pub/fedora/linux/ -http://mirror.proserve.nl/fedora/linux/ +http://mirror.realcompute.io/fedora/linux/ http://mirror.rise.ph/fedora/linux/ -http://mirror.seas.harvard.edu/fedora/linux/ +http://mirror.rnet.missouri.edu/fedora/linux/ http://mirror.sfo12.us.leaseweb.net/fedora/linux/ +http://mirror.siena.edu/fedora/linux/ http://mirror.slu.cz/fedora/linux/ -http://mirror.smartmedia.net.id/fedora/linux/ -http://mirror.sov.uk.goscomb.net/fedora/linux/ -http://mirror.squ.edu.om/fedora/linux/ -http://mirror.steadfast.net/epel/ http://mirror.steadfast.net/fedora/ -http://mirror.steadfast.net/fedora/development/24/Everything/armhfp/os/ -http://mirror.steadfast.net/fedora/development/24/Everything/i386/os/ -http://mirror.steadfast.net/fedora/development/24/Everything/x86_64/os/ -http://mirror.switch.ch/ftp/mirror/fedora/linux/ -http://mirror.symnds.com/distributions/fedora/ -http://mirror.t-home.mk/fedora/linux/ +http://mirror.steadfastnet.com/epel/ +http://mirror.szerverem.hu/fedora/linux/ http://mirror.umd.edu/fedora/linux/ -http://mirror.unl.edu/fedora/linux/ -http://mirror.uoregon.edu/fedora/linux/ -http://mirror.us.leaseweb.net/fedora/linux/ -http://mirror.utexas.edu/fedora/linux/ +http://mirror.upb.edu.co/fedora/linux/ +http://mirror.uta.edu.ec/fedora/linux/ http://mirror.uv.es/mirror/fedora/linux/ -http://mirror.vorboss.net/fedora/linux/ -http://mirror.vutbr.cz/fedora/ -http://mirror.wanxp.id/fedora/linux/ +http://mirror.veriteknik.net.tr/fedora/linux/ +http://mirror.vpsnet.com/fedora/linux/ http://mirror.yandex.ru/fedora/linux/ -http://mirror.zetup.net/fedora-enchilada/linux/ -http://mirror2.hs-esslingen.de/fedora/linux/ -http://mirrors.cat.pdx.edu/fedora/linux/ +http://mirror2.totbb.net/fedora/linux/ +http://mirrors.dotsrc.org/fedora-buffet/fedora/linux/ http://mirrors.ircam.fr/pub/fedora/linux/ -http://mirrors.isu.net.sa/pub/fedora/fedora-linux/ http://mirrors.kernel.org/fedora/ -http://mirrors.linux.edu.lv/ftp.redhat.com/pub/fedora/linux/ +http://mirrors.lug.mtu.edu/fedora/linux/ http://mirrors.mit.edu/fedora/linux/ http://mirrors.n-ix.net/fedora/linux/ +http://mirrors.nav.ro/fedora/linux/ http://mirrors.nic.cz/fedora/linux/ -http://mirrors.ptd.net/fedora/linux/ -http://mirrors.rit.edu/fedora/fedora/linux/ -http://mirrors.tummy.com/pub/fedora.redhat.com/fedora/linux/ +http://mirrors.piconets.webwerks.in/fedora-mirror/fedora/linux/ +http://mirrors.syringanetworks.net/fedora/linux/ http://mirrors.uni-ruse.bg/fedora/linux/ -http://mirrors.ustc.edu.cn/fedora/linux/ http://mirrors.xmission.com/fedora/linux/ +http://muug.ca/mirror/fedora/linux/ +http://my.fedora.ipserverone.com/fedora/linux/ http://opensource.nchc.org.tw/fedora/linux/ -http://repo.atlantic.net/fedora/linux/ +http://pubmirror1.math.uh.edu/fedora-buffet/fedora/linux/ +http://pubmirror2.math.uh.edu/fedora-buffet/fedora/linux/ +http://sg.fedora.ipserverone.com/fedora/linux/ http://ucmirror.canterbury.ac.nz/linux/fedora/linux/ -http://vesta.informatik.rwth-aachen.de/ftp/pub/Linux/fedora/linux/ -http://www.ftp.saix.net/linux/distributions/fedora/linux/ -http://www.las.ic.unicamp.br/pub/fedora/linux/ http://www.mirrorservice.org/sites/dl.fedoraproject.org/pub/fedora/linux/ -http://www.muug.mb.ca/pub/fedora/linux/ http://www.nic.funet.fi/pub/mirrors/fedora.redhat.com/pub/fedora/linux/ -http://www.webhostingjams.com/mirror/fedora/linux/ Binary files /tmp/tmpkjulcxzb/ruXzwKbog_/apt-cacher-ng-0.9.1/conf/gentoo_mirrors.gz and /tmp/tmpkjulcxzb/I6ezfHM2L0/apt-cacher-ng-3.3.1/conf/gentoo_mirrors.gz differ diff -Nru apt-cacher-ng-0.9.1/conf/maint.html apt-cacher-ng-3.3.1/conf/maint.html --- apt-cacher-ng-0.9.1/conf/maint.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/maint.html 2020-01-08 19:58:26.000000000 +0000 @@ -31,8 +31,9 @@ function copycheck(src, clname) { var nodes=document.getElementsByClassName(clname); + var isChecked = src.checked; for(var i=0; i diff -Nru apt-cacher-ng-0.9.1/conf/report.html apt-cacher-ng-3.3.1/conf/report.html --- apt-cacher-ng-0.9.1/conf/report.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/report.html 2020-01-08 19:58:26.000000000 +0000 @@ -14,6 +14,30 @@

Transfer statistics

+ + + + + + + + + + + + + + + +
Since startupRecent history
Data fetched: ${dataInHuman} ${dataHistInHuman}
Data served: ${dataOutHuman} ${dataHistOutHuman}
+

Log analysis

+ @@ -51,7 +75,7 @@ -

Index update and processing options

+

Shared processing options

Temporary options for the general behavour and index update configuration can set in this user interface. They are only relevant to expiration and import features triggered below. @@ -64,6 +88,7 @@
+

Expiration

@@ -73,11 +98,9 @@ needed when Stable system distribution is used by the clients, but use of unstable branches with high fluctuation requires to clean up the local cache from time to time. ACNG includes helper code to identify - unreferenced files automatically (executed with the button below). -
- Warning: this operation may redownload all index files. The current - implementation does not support delta-based reconstruction of index files - ("pdiff" mechanism). + unreferenced files automatically and optionally check the cache and + verify data against file information in the index files, where + available.

Scan and semi-automatic expiration

@@ -94,6 +117,8 @@ \n"; for(auto it=sorted.rbegin(); it!=sorted.rend(); ++it) { - bool xNew; m_fmtHelper << "" + << AddLookupGetKey(*(it->second), "") << ">" "\n"; @@ -2217,7 +2290,7 @@ } SendFmt << "
Period Cache efficiency
+ +

@@ -187,8 +212,6 @@

- -

diff -Nru apt-cacher-ng-0.9.1/conf/sfnet_mirrors apt-cacher-ng-3.3.1/conf/sfnet_mirrors --- apt-cacher-ng-0.9.1/conf/sfnet_mirrors 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/sfnet_mirrors 2020-01-08 19:58:26.000000000 +0000 @@ -0,0 +1,19 @@ +http://astuteinternet.dl.sourceforge.net/project/ +http://ayera.dl.sourceforge.net/project/ +http://cfhcable.dl.sourceforge.net/project/ +http://freefr.dl.sourceforge.net/project/ +http://gigenet.dl.sourceforge.net/project/ +http://iweb.dl.sourceforge.net/project/ +http://jaist.dl.sourceforge.net/project/ +http://liquidtelecom.dl.sourceforge.net/project/ +http://managedway.dl.sourceforge.net/project/ +http://nchc.dl.sourceforge.net/project/ +http://netcologne.dl.sourceforge.net/project/ +http://netix.dl.sourceforge.net/project/ +http://newcontinuum.dl.sourceforge.net/project/ +http://phoenixnap.dl.sourceforge.net/project/ +http://razaoinfo.dl.sourceforge.net/project/ +http://tenet.dl.sourceforge.net/project/ +http://ufpr.dl.sourceforge.net/project/ +http://versaweb.dl.sourceforge.net/project/ +http://vorboss.dl.sourceforge.net/project/ diff -Nru apt-cacher-ng-0.9.1/conf/sl_mirrors apt-cacher-ng-3.3.1/conf/sl_mirrors --- apt-cacher-ng-0.9.1/conf/sl_mirrors 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/sl_mirrors 2020-01-08 19:58:26.000000000 +0000 @@ -1,45 +1,34 @@ -http://anorien.csc.warwick.ac.uk/mirrors/scientific/ +http://ba.mirror.garr.it/mirrors/scientific/ http://distrib-coffee.ipsl.jussieu.fr/pub/linux/scientific-linux/ http://ftp-stud.hs-esslingen.de/pub/Mirrors/scientific/ -http://ftp.cc.uoc.gr/mirrors/linux/scientific/ http://ftp.fau.de/scientific/ http://ftp.halifax.rwth-aachen.de/scientificlinux/ -http://ftp.heanet.ie/pub/scientific/ http://ftp.icm.edu.pl/pub/Linux/dist/scientific/ -http://ftp.itb.ac.id/pub/ScientificLinux/ http://ftp.jaist.ac.jp/pub/Linux/scientific/ http://ftp.kddilabs.jp/Linux/packages/scientificlinux/ http://ftp.linux.org.tr/scientific/ http://ftp.lip6.fr/pub/linux/distributions/scientific/ -http://ftp.nluug.nl/os/Linux/distr/scientific/ -http://ftp.plusline.de/pub/scientific/ http://ftp.riken.jp/Linux/scientific/ http://ftp.rrzn.uni-hannover.de/scientific/ http://ftp.scientificlinux.org/linux/scientific/ http://ftp.tsukuba.wide.ad.jp/Linux/scientific/ -http://ftp.twaren.net/Linux/scientific/ -http://ftp.yz.yamagata-u.ac.jp/pub/linux/scientific/ http://ftp.yzu.edu.tw/Linux/scientific/ http://ftp1.scientificlinux.org/linux/scientific/ http://ftp2.scientificlinux.org/linux/scientific/ http://linux.cs.uu.nl/scientific/ http://linuxsoft.cern.ch/scientific/ -http://mirror.23media.de/scientific/ +http://mirror.1000mbps.com/scientific/ http://mirror.aarnet.edu.au/pub/scientific/ -http://mirror.ancl.hawaii.edu/linux/scientific/ http://mirror.cedia.org.ec/scientific/ -http://mirror.crazynetwork.it/scientificlinux/ http://mirror.digmia.com/scientific/ -http://mirror.imbg.org.ua/pub/linux/scientific/ +http://mirror.host.ag/scientific/ http://mirror.karneval.cz/pub/linux/scientific/ -http://mirror.lstn.net/scientific/ +http://mirror.math.princeton.edu/pub/scientific/ http://mirror.mephi.ru/scientific/ -http://mirror.pmf.kg.ac.rs/scientific/ -http://mirror.squ.edu.om/scientificlinux/ -http://mirror.switch.ch/ftp/mirror/scientificlinux/ -http://mirrors.200p-sf.sonic.net/scientific/ http://mirrors.ircam.fr/pub/scientificlinux/scientific/ +http://mirrors.up.pt/pub/scientific/ http://scientificlinux.physik.uni-muenchen.de/mirror/scientific/ http://wftp.tu-chemnitz.de/pub/linux/scientific/ +http://www.gtlib.gatech.edu/pub/scientific/ http://www.mirrorservice.org/sites/ftp.scientificlinux.org/linux/scientific/ http://www.nic.funet.fi/pub/Linux/INSTALL/scientific/ diff -Nru apt-cacher-ng-0.9.1/conf/ubuntu_mirrors apt-cacher-ng-3.3.1/conf/ubuntu_mirrors --- apt-cacher-ng-0.9.1/conf/ubuntu_mirrors 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/ubuntu_mirrors 2020-01-08 19:58:26.000000000 +0000 @@ -11,13 +11,13 @@ http://aq.archive.ubuntu.com/ubuntu/ http://ar.archive.ubuntu.com/ubuntu/ http://archive.linux.duke.edu/ubuntu/ -http://archive.mirror.blix.com/ubuntu/ -http://archive.ubuntu.com.ba/ubuntu/ +http://archive.raptus-net.de/ubuntu/ http://archive.ubuntu.com/ubuntu/ http://archive.ubuntu.csg.uzh.ch/ubuntu/ -http://archive.ubuntu.mirror.dkm.cz/ +http://archive.ubuntu.mirror.ba/ubuntu/ http://archive.ubuntu.mirror.rafal.ca/ubuntu/ http://archive.ubuntu.nautile.nc/ubuntu/ +http://archive.ubuntu.petiak.ir/ubuntu/ http://archive.ubuntumirror.dei.uc.pt/ubuntu/ http://artfiles.org/ubuntu.com/ http://as.archive.ubuntu.com/ubuntu/ @@ -26,6 +26,7 @@ http://aw.archive.ubuntu.com/ubuntu/ http://ax.archive.ubuntu.com/ubuntu/ http://az.archive.ubuntu.com/ubuntu/ +http://aze.archive.ubuntu.com/ubuntu/ http://ba.archive.ubuntu.com/ubuntu/ http://bb.archive.ubuntu.com/ubuntu/ http://bd.archive.ubuntu.com/ubuntu/ @@ -39,12 +40,10 @@ http://bm.archive.ubuntu.com/ubuntu/ http://bn.archive.ubuntu.com/ubuntu/ http://bo.archive.ubuntu.com/ubuntu/ -http://bouyguestelecom.ubuntu.lafibre.info/ubuntu/ http://bq.archive.ubuntu.com/ubuntu/ http://br.archive.ubuntu.com/ubuntu/ http://bs.archive.ubuntu.com/ubuntu/ http://bt.archive.ubuntu.com/ubuntu/ -http://buaya.klas.or.id/ubuntu/ http://bv.archive.ubuntu.com/ubuntu/ http://bw.archive.ubuntu.com/ubuntu/ http://by.archive.ubuntu.com/ubuntu/ @@ -61,7 +60,6 @@ http://cm.archive.ubuntu.com/ubuntu/ http://cn.archive.ubuntu.com/ubuntu/ http://co.archive.ubuntu.com/ubuntu/ -http://cosmos.cites.illinois.edu/pub/ubuntu/ http://cr.archive.ubuntu.com/ubuntu/ http://cu.archive.ubuntu.com/ubuntu/ http://cv.archive.ubuntu.com/ubuntu/ @@ -70,22 +68,22 @@ http://cy.archive.ubuntu.com/ubuntu/ http://cz.archive.ubuntu.com/ubuntu/ http://de.archive.ubuntu.com/ubuntu/ -http://de2.archive.ubuntu.com/ubuntu/ http://deb-mirror.habari.co.tz/ubuntu/ http://debian.charite.de/ubuntu/ -http://dist1.800hosting.com/ubuntu/ http://distrib-coffee.ipsl.jussieu.fr/pub/linux/ubuntu/ http://dj.archive.ubuntu.com/ubuntu/ http://dk.archive.ubuntu.com/ubuntu/ http://dm.archive.ubuntu.com/ubuntu/ http://do.archive.ubuntu.com/ubuntu/ http://download.nus.edu.sg/mirror/ubuntu/ +http://download.nust.na/pub/ubuntu/ubuntu/ http://dz.archive.ubuntu.com/ubuntu/ http://ec.archive.ubuntu.com/ubuntu/ http://ee.archive.ubuntu.com/ubuntu/ http://eg.archive.ubuntu.com/ubuntu/ http://eh.archive.ubuntu.com/ubuntu/ http://er.archive.ubuntu.com/ubuntu/ +http://es-mirrors.evowise.com/ubuntu/ http://es.archive.ubuntu.com/ubuntu/ http://et.archive.ubuntu.com/ubuntu/ http://eu.archive.ubuntu.com/ubuntu/ @@ -100,43 +98,42 @@ http://ftp.acc.umu.se/ubuntu/ http://ftp.agh.edu.pl/ubuntu/ http://ftp.arnes.si/pub/mirrors/ubuntu/ -http://ftp.astral.ro/mirrors/ubuntu.com/ubuntu/ -http://ftp.availo.se/ubuntu/ +http://ftp.aso.ee/ubuntu/ +http://ftp.belnet.be/ubuntu/ http://ftp.byfly.by/ubuntu/ http://ftp.caliu.cat/pub/distribucions/ubuntu/archive/ http://ftp.cc.uoc.gr/mirrors/linux/ubuntu/packages/ http://ftp.citylink.co.nz/ubuntu/ http://ftp.cuhk.edu.hk/pub/Linux/ubuntu/ http://ftp.cvut.cz/ubuntu/ -http://ftp.ds.karen.hj.se/ubuntu/ -http://ftp.energotel.sk/pub/linux/ubuntu/archive/ +http://ftp.daum.net/ubuntu/ +http://ftp.energotel.sk/pub/linux/ubuntu/ +http://ftp.estpak.ee/ubuntu/ http://ftp.fau.de/ubuntu/ -http://ftp.freepark.org/ubuntu/ -http://ftp.gts.lug.ro/ubuntu/ +http://ftp.fsn.hu/ubuntu/ http://ftp.halifax.rwth-aachen.de/ubuntu/ -http://ftp.hawo.stw.uni-erlangen.de/ubuntu/ +http://ftp.harukasan.org/ubuntu/ http://ftp.heanet.ie/pub/ubuntu/ http://ftp.hosteurope.de/mirror/archive.ubuntu.com/ http://ftp.icm.edu.pl/pub/Linux/ubuntu/ -http://ftp.iitm.ac.in/ubuntu/ -http://ftp.info.uvt.ro/ubuntu/ +http://ftp.iinet.net.au/pub/ubuntu/ http://ftp.jaist.ac.jp/pub/Linux/ubuntu/ -http://ftp.kfki.hu/linux/ubuntu/ -http://ftp.klid.dk/ftp/ubuntu/ +http://ftp.lanet.kr/ubuntu/ http://ftp.leg.uct.ac.za/ubuntu/ http://ftp.linux.org.tr/ubuntu/ http://ftp.litnet.lt/ubuntu/ http://ftp.lysator.liu.se/ubuntu/ -http://ftp.mtu.ru/pub/ubuntu/archive/ http://ftp.neowiz.com/ubuntu/ http://ftp.nluug.nl/os/Linux/distr/ubuntu/ -http://ftp.nsysu.edu.tw/Ubuntu/ubuntu/ http://ftp.ntou.edu.tw/ubuntu/ http://ftp.ntua.gr/ubuntu/ http://ftp.oleane.net/ubuntu/ +http://ftp.rezopole.net/ubuntu/ http://ftp.riken.jp/Linux/ubuntu/ +http://ftp.rnl.tecnico.ulisboa.pt/pub/ubuntu/archive/ http://ftp.rrzn.uni-hannover.de/pub/mirror/linux/ubuntu/ http://ftp.rz.tu-bs.de/pub/mirror/ubuntu-packages/ +http://ftp.sh.cvut.cz/ubuntu/ http://ftp.sjtu.edu.cn/ubuntu/ http://ftp.snt.utwente.nl/pub/os/linux/ubuntu/ http://ftp.stw-bonn.de/ubuntu/ @@ -149,14 +146,14 @@ http://ftp.tu-ilmenau.de/mirror/ubuntu/ http://ftp.tudelft.nl/archive.ubuntu.com/ http://ftp.u-picardie.fr/mirror/ubuntu/ubuntu/ -http://ftp.ubuntu-tw.net/mirror/ubuntu/ +http://ftp.ubuntu-tw.net/ubuntu/ http://ftp.udc.es/ubuntu/ http://ftp.uni-bayreuth.de/linux/ubuntu/ubuntu/ -http://ftp.uni-kassel.de/ubuntu/ubuntu/ http://ftp.uni-kl.de/pub/linux/ubuntu/ http://ftp.uni-mainz.de/ubuntu/ http://ftp.uni-stuttgart.de/ubuntu/ http://ftp.uninett.no/ubuntu/ +http://ftp.upcnet.ro/mirrors/ubuntu.com/ubuntu/ http://ftp.usf.edu/pub/ubuntu/ http://ftp.ussg.iu.edu/linux/ubuntu/ http://ftp.utexas.edu/ubuntu/ @@ -166,7 +163,6 @@ http://ga.archive.ubuntu.com/ubuntu/ http://gb.archive.ubuntu.com/ubuntu/ http://gd.archive.ubuntu.com/ubuntu/ -http://gd.tuwien.ac.at/opsys/linux/ubuntu/archive/ http://ge.archive.ubuntu.com/ubuntu/ http://gf.archive.ubuntu.com/ubuntu/ http://gg.archive.ubuntu.com/ubuntu/ @@ -174,6 +170,7 @@ http://gi.archive.ubuntu.com/ubuntu/ http://giano.com.dist.unige.it/ubuntu/ http://gl.archive.ubuntu.com/ubuntu/ +http://glua.ua.pt/pub/ubuntu/ http://gm.archive.ubuntu.com/ubuntu/ http://gn.archive.ubuntu.com/ubuntu/ http://gp.archive.ubuntu.com/ubuntu/ @@ -186,6 +183,7 @@ http://gw.archive.ubuntu.com/ubuntu/ http://gy.archive.ubuntu.com/ubuntu/ http://hk.archive.ubuntu.com/ubuntu/ +http://hk.mirrors.thegigabit.com/ubuntu/ http://hm.archive.ubuntu.com/ubuntu/ http://hn.archive.ubuntu.com/ubuntu/ http://hr.archive.ubuntu.com/ubuntu/ @@ -199,33 +197,37 @@ http://io.archive.ubuntu.com/ubuntu/ http://iq.archive.ubuntu.com/ubuntu/ http://ir.archive.ubuntu.com/ubuntu/ +http://ir.ubuntu.sindad.cloud/ubuntu/ http://is.archive.ubuntu.com/ubuntu/ +http://it-mirrors.evowise.com/ubuntu/ http://it.archive.ubuntu.com/ubuntu/ http://je.archive.ubuntu.com/ubuntu/ http://jm.archive.ubuntu.com/ubuntu/ http://jo.archive.ubuntu.com/ubuntu/ http://jp.archive.ubuntu.com/ubuntu/ -http://kadignaz.de/ubuntu/ http://kambing.ui.ac.id/ubuntu/ http://kartolo.sby.datautama.net.id/ubuntu/ http://ke.archive.ubuntu.com/ubuntu/ http://kebo.pens.ac.id/ubuntu/ +http://kebo.vlsm.org/ubuntu/ http://kg.archive.ubuntu.com/ubuntu/ http://kh.archive.ubuntu.com/ubuntu/ http://ki.archive.ubuntu.com/ubuntu/ http://km.archive.ubuntu.com/ubuntu/ http://kn.archive.ubuntu.com/ubuntu/ +http://kozyatagi.mirror.guzel.net.tr/ubuntu/ http://kp.archive.ubuntu.com/ubuntu/ http://kr.archive.ubuntu.com/ubuntu/ http://kw.archive.ubuntu.com/ubuntu/ http://ky.archive.ubuntu.com/ubuntu/ http://kz.archive.ubuntu.com/ubuntu/ +http://la-mirrors.evowise.com/ubuntu/ http://la.archive.ubuntu.com/ubuntu/ http://lb.archive.ubuntu.com/ubuntu/ http://lc.archive.ubuntu.com/ubuntu/ http://li.archive.ubuntu.com/ubuntu/ -http://linux.nsu.ru/ubuntu/ -http://linux.psu.ru/ubuntu/ +http://linux.darkpenguin.net/distros/ubuntu-archive/ +http://linux.yz.yamagata-u.ac.jp/ubuntu/ http://lk.archive.ubuntu.com/ubuntu/ http://lr.archive.ubuntu.com/ubuntu/ http://ls.archive.ubuntu.com/ubuntu/ @@ -241,116 +243,186 @@ http://mf.archive.ubuntu.com/ubuntu/ http://mg.archive.ubuntu.com/ubuntu/ http://mh.archive.ubuntu.com/ubuntu/ -http://mirror-fpt-telecom.fpt.net/ubuntu/ +http://miroir.univ-lorraine.fr/ubuntu/ +http://mirror.0-1.cloud/ubuntu/ +http://mirror.0x.sg/ubuntu/ http://mirror.1000mbps.com/ubuntu/ -http://mirror.23media.de/ubuntu/ +http://mirror.23media.com/ubuntu/ http://mirror.aarnet.edu.au/pub/ubuntu/archive/ -http://mirror.adminbannok.com/ubuntu/ +http://mirror.aktkn.sg/ubuntu/ +http://mirror.aminidc.com/ubuntu/ http://mirror.amsiohosting.net/archive.ubuntu.com/ http://mirror.ancl.hawaii.edu/linux/ubuntu/ http://mirror.aptus.co.tz/pub/ubuntuarchive/ +http://mirror.arizona.edu/ubuntu/ +http://mirror.armaghan.net/ubuntu/ http://mirror.as24220.net/pub/ubuntu-archive/ http://mirror.as24220.net/pub/ubuntu/ http://mirror.as29550.net/archive.ubuntu.com/ http://mirror.as43289.net/ubuntu/ http://mirror.atlantic.net/ubuntu/ -http://mirror.blizoo.mk/ubuntu/ +http://mirror.biznetgio.com/ubuntu/ http://mirror.bytemark.co.uk/ubuntu/ http://mirror.cc.columbia.edu/pub/linux/ubuntu/archive/ http://mirror.cc.vt.edu/pub2/ubuntu/ http://mirror.cedia.org.ec/ubuntu/ +http://mirror.cedille.club/ubuntu/ http://mirror.clarkson.edu/ubuntu/ +http://mirror.clearsky.vn/ubuntu/ http://mirror.clibre.uqam.ca/ubuntu/ http://mirror.cogentco.com/pub/linux/ubuntu/ http://mirror.corbina.net/ubuntu/ http://mirror.crazynetwork.it/ubuntu/archive/ +http://mirror.cs.jmu.edu/pub/ubuntu/ http://mirror.cs.pitt.edu/ubuntu/archive/ +http://mirror.cs.unm.edu/archive/ http://mirror.csclub.uwaterloo.ca/ubuntu/ http://mirror.cse.iitk.ac.in/ubuntu/ http://mirror.datacenter.az/ubuntu/ http://mirror.datacenter.by/ubuntu/ +http://mirror.datacenter.mn/ubuntu/ +http://mirror.dataone.nl/ubuntu-archive/ http://mirror.de.leaseweb.net/ubuntu/ +http://mirror.deace.id/ubuntu/ http://mirror.dhakacom.com/ubuntu-archive/ http://mirror.dhakacom.com/ubuntu/ -http://mirror.digistar.vn/ubuntu/ -http://mirror.earthlink.iq/ubuntu/ +http://mirror.dkm.cz/ubuntu/ +http://mirror.docker.ru/ubuntu/ +http://mirror.easyname.at/ubuntu-archive/ http://mirror.easyspeedy.com/ubuntu/ http://mirror.edatel.net.co/ubuntu/ +http://mirror.ehost.vn/ubuntu/ +http://mirror.enzu.com/ubuntu/ http://mirror.espol.edu.ec/ubuntu/ http://mirror.fairway.ne.jp/ubuntu/ +http://mirror.freethought-internet.co.uk/ubuntu/ +http://mirror.fsmg.org.nz/ubuntu/ +http://mirror.funkfreundelandshut.de/ubuntu/ +http://mirror.genesisadaptive.com/ubuntu/ http://mirror.globo.com/ubuntu/archive/ http://mirror.greennet.gl/ubuntu/ -http://mirror.hmc.edu/ubuntu/ -http://mirror.htnshost.com/ubuntu/ +http://mirror.hostdime.com.br/ubuntu/ +http://mirror.hoster.kz/ubuntu/ +http://mirror.hostnet.nl/ubuntu/archive/ http://mirror.i3d.net/pub/ubuntu/ http://mirror.idealhosting.net.tr/ubuntu/ +http://mirror.init7.net/ubuntu/ +http://mirror.intergrid.com.au/ubuntu/ http://mirror.internode.on.net/pub/ubuntu/ubuntu/ -http://mirror.iranserver.com/ubuntu/ +http://mirror.iodc.dk/ubuntu/ +http://mirror.ipb.de/ubuntu/ http://mirror.isoc.org.il/pub/ubuntu/ http://mirror.it.ubc.ca/ubuntu/ http://mirror.its.dal.ca/ubuntu/ http://mirror.its.sfu.ca/mirror/ubuntu/ -http://mirror.jmu.edu/pub/ubuntu/ -http://mirror.kavalinux.com/ubuntu/ +http://mirror.kakao.com/ubuntu/ +http://mirror.kamp.de/ubuntu/ http://mirror.kku.ac.th/ubuntu/ +http://mirror.kumi.systems/ubuntu/ +http://mirror.labkom.id/ubuntu/ +http://mirror.launtel.net.au/ubuntu/ +http://mirror.lcsee.wvu.edu/ubuntu/ +http://mirror.library.ucy.ac.cy/linux/ubuntu/archive/ +http://mirror.linux-ia64.org/ubuntu/ +http://mirror.linux.pizza/ubuntu/ +http://mirror.lnx-solutions.com/ubuntu/ http://mirror.lstn.net/ubuntu/ +http://mirror.lzu.edu.cn/ubuntu/ +http://mirror.marwan.ma/ubuntu/ +http://mirror.math.princeton.edu/pub/ubuntu/ http://mirror.math.ucdavis.edu/ubuntu/ http://mirror.metrocast.net/ubuntu/ http://mirror.mirohost.net/ubuntu/ +http://mirror.mrjester.net/ubuntu/archive/ +http://mirror.muvhost.com/ubuntu/ http://mirror.mythic-beasts.com/ubuntu/ http://mirror.neolabs.kz/ubuntu/ http://mirror.netcologne.de/ubuntu/ -http://mirror.network32.net/ubuntu/ -http://mirror.neu.edu.cn/ubuntu/ -http://mirror.nexcess.net/ubuntu/ +http://mirror.netsite.dk/ubuntu/archive/ +http://mirror.netspace.net.au/pub/ubuntu/ http://mirror.nforce.com/pub/linux/ubuntu/ http://mirror.ni.net.tr/ubuntu/ +http://mirror.niif.hu/ubuntu/ +http://mirror.nl.datapacket.com/ubuntu/ http://mirror.nl.leaseweb.net/ubuntu/ -http://mirror.nus.edu.sg/ubuntu/ +http://mirror.nodesdirect.com/ubuntu/ +http://mirror.nwlab.tk/ubuntu/ http://mirror.one.com/ubuntu/ http://mirror.onet.pl/pub/mirrors/ubuntu/ -http://mirror.optus.net/ubuntu/ +http://mirror.onevip.mk/ubuntu/ +http://mirror.operationtulip.com/ubuntu/ http://mirror.os6.org/ubuntu/ http://mirror.overthewire.com.au/ubuntu/ http://mirror.ox.ac.uk/sites/archive.ubuntu.com/ubuntu/ -http://mirror.picosecond.org/ubuntu/ +http://mirror.pit.teraswitch.com/ubuntu/ http://mirror.plusserver.com/ubuntu/ubuntu/ +http://mirror.plustech.de/ubuntu/ http://mirror.pnl.gov/ubuntu/ http://mirror.poliwangi.ac.id/ubuntu/ http://mirror.pregi.net/ubuntu/ -http://mirror.premi.st/ubuntu/ +http://mirror.previder.nl/ubuntu/ +http://mirror.ps.kz/ubuntu/ +http://mirror.rasanegar.com/ubuntu/archive/ +http://mirror.ratiokontakt.de/mirror/ubuntu/ +http://mirror.realcompute.io/ubuntu/ +http://mirror.redium.net/pub/linux/ubuntu/ +http://mirror.renu.ac.ug/ubuntu/ +http://mirror.retentionrange.co.bw/ubuntu/ http://mirror.rise.ph/ubuntu/ -http://mirror.rol.ru/ubuntu/ -http://mirror.scalabledns.com/ubuntu/ -http://mirror.soften.ktu.lt/ubuntu/ +http://mirror.sax.uk.as61049.net/ubuntu/ +http://mirror.serverion.com/ubuntu/ +http://mirror.serverius.net/ubuntu/ +http://mirror.serverloft.eu/ubuntu/ubuntu/ +http://mirror.siena.edu/ubuntu/ +http://mirror.sjc02.svwh.net/ubuntu/ +http://mirror.solnode.io/ubuntu/releases/ http://mirror.sov.uk.goscomb.net/ubuntu/ -http://mirror.squ.edu.om/ubuntuarchive/ -http://mirror.steadfast.net/ubuntu/ +http://mirror.steadfastnet.com/ubuntu/ http://mirror.stw-aachen.de/ubuntu/ -http://mirror.switch.ch/ftp/mirror/ubuntu/ -http://mirror.symnds.com/ubuntu/ http://mirror.t-home.mk/ubuntu/ +http://mirror.tcc.wa.edu.au/ubuntu/ +http://mirror.team-cymru.com/ubuntu/ http://mirror.team-cymru.org/ubuntu/ +http://mirror.tedra.es/ubuntu/ http://mirror.telepoint.bg/ubuntu/ +http://mirror.thaidns.co.th/ubuntu/ http://mirror.timeweb.ru/ubuntu/ http://mirror.tocici.com/ubuntu/ http://mirror.transip.net/ubuntu/ubuntu/ +http://mirror.truenetwork.ru/ubuntu/ +http://mirror.ubuntu.ikoula.com/ http://mirror.ubuntu.ikoula.com/ubuntu/ +http://mirror.ubuntu.serverforge.org/ http://mirror.uchile.cl/ubuntu/ +http://mirror.ufam.edu.br/ubuntu/ +http://mirror.ufca.edu.br/mirror/ubuntu-archive/ +http://mirror.ufscar.br/ubuntu/ http://mirror.umd.edu/ubuntu/ http://mirror.unej.ac.id/ubuntu/ -http://mirror.unesp.br/ubuntu/ +http://mirror.unimagdalena.edu.co/ubuntu/ http://mirror.unix-solutions.be/ubuntu/ http://mirror.uoregon.edu/ubuntu/ +http://mirror.upb.edu.co/ubuntu/ +http://mirror.us-midwest-1.nexcess.net/ubuntu/ http://mirror.us.leaseweb.net/ubuntu/ +http://mirror.usetelecom.com.br/ubuntu/ +http://mirror.vcu.edu/pub/gnu+linux/ubuntu/ +http://mirror.vnet.sk/ubuntu/ http://mirror.vorboss.net/ubuntu-archive/ -http://mirror.vutbr.cz/ubuntu/archive/ +http://mirror.vpgrp.io/ubuntu/ +http://mirror.vpsnet.com/ubuntu/ http://mirror.waia.asn.au/ubuntu/ +http://mirror.wiru.co.za/ubuntu/ +http://mirror.wtnet.de/ubuntu/ +http://mirror.xaas.ir/ubuntu/ +http://mirror.xeonbd.com/ubuntu-archive/ +http://mirror.xtom.com.hk/ubuntu/ http://mirror.yandex.ru/ubuntu/ +http://mirror.yongbok.net/ubuntu/ http://mirror.zetup.net/ubuntu/ -http://mirror.zol.co.zw/ubuntu/ http://mirror01.idc.hinet.net/ubuntu/ http://mirror1.ku.ac.th/ubuntu/ +http://mirror1.totbb.net/ubuntu/ http://mirror2.tuxinator.org/ubuntu/ http://mirrordenver.fdcservers.net/ubuntu/ http://mirrors.accretive-networks.net/ubuntu/ @@ -358,55 +430,78 @@ http://mirrors.aliyun.com/ubuntu/ http://mirrors.arpnetworks.com/Ubuntu/ http://mirrors.asnet.am/ubuntu/ +http://mirrors.bangmod.cloud/ubuntu/ http://mirrors.bloomu.edu/ubuntu/ http://mirrors.cat.pdx.edu/ubuntu/ -http://mirrors.ccs.neu.edu/ubuntu/ -http://mirrors.coopvgg.com.ar/ubuntu/ +http://mirrors.cloud.linets.cl/ubuntu/ +http://mirrors.cn99.com/ubuntu/ +http://mirrors.coreix.net/ubuntu/ http://mirrors.cqu.edu.cn/ubuntu/ +http://mirrors.daticum.com/ubuntu/archive/ http://mirrors.dotsrc.org/ubuntu/ -http://mirrors.eastera.tj/ubuntu/ http://mirrors.easynews.com/linux/ubuntu/ -http://mirrors.fe.up.pt/ubuntu/ http://mirrors.gigenet.com/ubuntuarchive/ +http://mirrors.huaweicloud.com/repository/ubuntu/ http://mirrors.ircam.fr/pub/ubuntu/archive/ +http://mirrors.isu.net.sa/pub/ubuntu-releases/ +http://mirrors.liquidweb.com/ubuntu/ +http://mirrors.lug.mtu.edu/ubuntu/ http://mirrors.maine.edu/ubuntu/ http://mirrors.melbourne.co.uk/ubuntu/ http://mirrors.mit.edu/ubuntu/ +http://mirrors.mivocloud.com/ubuntu/ http://mirrors.namecheap.com/ubuntu/ +http://mirrors.nav.ro/ubuntu/ http://mirrors.nayatel.com/ubuntu/ http://mirrors.nhanhoa.com/ubuntu/ http://mirrors.nic.funet.fi/ubuntu/ -http://mirrors.nl.eu.kernel.org/ubuntu/ -http://mirrors.noction.com/ubuntu/archive/ +http://mirrors.nju.edu.cn/ubuntu/ +http://mirrors.njupt.edu.cn/ubuntu/ +http://mirrors.nxthost.com/ubuntu/ http://mirrors.ocf.berkeley.edu/ubuntu/ +http://mirrors.piconets.webwerks.in/ubuntu-mirror/ubuntu/ http://mirrors.pidginhost.com/ubuntu/ +http://mirrors.powernet.com.ru/ubuntu/ http://mirrors.psu.ac.th/ubuntu/ +http://mirrors.ptisp.pt/ubuntu/ http://mirrors.rit.edu/ubuntu/ -http://mirrors.se.eu.kernel.org/ubuntu/ -http://mirrors.skyshe.cn/ubuntu/ +http://mirrors.sohu.com/ubuntu/ http://mirrors.sonic.net/ubuntu/ +http://mirrors.sth.sze.hu/ubuntu/ http://mirrors.syringanetworks.net/ubuntu-archive/ -http://mirrors.telianet.dk/ubuntu/ http://mirrors.tripadvisor.com/ubuntu/ http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ +http://mirrors.ukfast.co.uk/sites/archive.ubuntu.com/ +http://mirrors.up.pt/ubuntu/ http://mirrors.us.kernel.org/ubuntu/ http://mirrors.usinternet.com/ubuntu/archive/ http://mirrors.ustc.edu.cn/ubuntu/ +http://mirrors.vcea.wsu.edu/ubuntu/ +http://mirrors.vhost.vn/ubuntu/ +http://mirrors.wikimedia.org/ubuntu/ http://mirrors.xmission.com/ubuntu/ +http://mirrors.xservers.ro/ubuntu/ +http://mirrors.xtom.com/ubuntu/ +http://mirrors.xtom.nl/ubuntu/ +http://mirrors.yun-idc.com/ubuntu/ http://mk.archive.ubuntu.com/ubuntu/ http://ml.archive.ubuntu.com/ubuntu/ http://mm.archive.ubuntu.com/ubuntu/ +http://mn.archive.ubuntu.com/ubuntu/ http://mo.archive.ubuntu.com/ubuntu/ +http://mozart.ee.ic.ac.uk/ubuntu-archive/ http://mp.archive.ubuntu.com/ubuntu/ http://mq.archive.ubuntu.com/ubuntu/ http://mr.archive.ubuntu.com/ubuntu/ http://ms.archive.ubuntu.com/ubuntu/ http://mt.archive.ubuntu.com/ubuntu/ http://mu.archive.ubuntu.com/ubuntu/ +http://muug.ca/mirror/ubuntu/ http://mv.archive.ubuntu.com/ubuntu/ http://mw.archive.ubuntu.com/ubuntu/ http://mx.archive.ubuntu.com/ubuntu/ http://my.archive.ubuntu.com/ubuntu/ +http://my.mirrors.thegigabit.com/ubuntu/ http://mz.archive.ubuntu.com/ubuntu/ http://na.archive.ubuntu.com/ubuntu/ http://nc.archive.ubuntu.com/ubuntu/ @@ -417,14 +512,17 @@ http://nl.archive.ubuntu.com/ubuntu/ http://nl3.archive.ubuntu.com/ubuntu/ http://no.archive.ubuntu.com/ubuntu/ +http://no.mirrors.blix.com/ubuntu/ http://np.archive.ubuntu.com/ubuntu/ http://nr.archive.ubuntu.com/ubuntu/ http://nu.archive.ubuntu.com/ubuntu/ +http://ny-mirrors.evowise.com/ubuntu/ http://nz.archive.ubuntu.com/ubuntu/ http://om.archive.ubuntu.com/ubuntu/ http://opensource.xtdv.net/ubuntu/ http://osmirror.rug.nl/ubuntu/ http://pa.archive.ubuntu.com/ubuntu/ +http://packages.oth-regensburg.de/ubuntu/ http://pe.archive.ubuntu.com/ubuntu/ http://pf.archive.ubuntu.com/ubuntu/ http://pg.archive.ubuntu.com/ubuntu/ @@ -442,14 +540,25 @@ http://pw.archive.ubuntu.com/ubuntu/ http://py.archive.ubuntu.com/ubuntu/ http://qa.archive.ubuntu.com/ubuntu/ +http://quantum-mirror.hu/mirrors/pub/ubuntu/ http://re.archive.ubuntu.com/ubuntu/ http://reflector.westga.edu/repos/Ubuntu/archive/ +http://rep-ubuntu-il.upress.io/ubuntu/ http://repo.bigstepcloud.com/ubuntu/ +http://repo.ialab.dsu.edu/ubuntu/ +http://repo.inara.pk/ubuntu/ +http://repo.isra.edu.pk/ubuntu/ +http://repo.iut.ac.ir/repo/Ubuntu/ +http://repo.miserver.it.umich.edu/ubuntu/ http://repo.unpatti.ac.id/ubuntu/ +http://repos.del.extreme-ix.org/ubuntu/ +http://repos.forethought.net/ubuntu/ +http://repos.interior.edu.uy/ubuntu/ +http://repositorio.nti.ufal.br/ubuntu/ +http://ro-mirrors.evowise.com/ubuntu/ http://ro.archive.ubuntu.com/ubuntu/ http://rs.archive.ubuntu.com/ubuntu/ http://ru.archive.ubuntu.com/ubuntu/ -http://run.hit.edu.cn/ubuntu/ http://rw.archive.ubuntu.com/ubuntu/ http://sa.archive.ubuntu.com/ubuntu/ http://sb.archive.ubuntu.com/ubuntu/ @@ -497,31 +606,30 @@ http://tw.archive.ubuntu.com/ubuntu/ http://tz.archive.ubuntu.com/ubuntu/ http://ua.archive.ubuntu.com/ubuntu/ -http://ubnt-archive.xfree.com.ar/ubuntu/ http://ubuntu-arch.linux.edu.lv/ubuntu/ http://ubuntu-archive.locaweb.com.br/ubuntu/ -http://ubuntu-archive.mirror.liquidtelecom.com/ubuntu/ -http://ubuntu-archive.mirror.nucleus.be/ http://ubuntu-archive.mirror.serveriai.lt/ +http://ubuntu-archive.mirrors.estointernet.in/ http://ubuntu-ashisuto.ubuntulinux.jp/ubuntu/ -http://ubuntu-mirror.neocom.org.ua/ubuntu/ -http://ubuntu-mirror.telesys.org.ua/ubuntu/ -http://ubuntu-mirror.totbb.net/ubuntu/ -http://ubuntu.01link.hk/ -http://ubuntu.asis.io/ -http://ubuntu.bhs.mirrors.ovh.net/ftp.ubuntu.com/ubuntu/ +http://ubuntu-mirror.netzyp.com/ubuntu/ +http://ubuntu.anexia.at/ubuntu/ +http://ubuntu.archive.kw.zain.com/ +http://ubuntu.bhs.mirrors.ovh.net/ubuntu/ http://ubuntu.c3sl.ufpr.br/ubuntu/ +http://ubuntu.ca-west.mirror.fullhost.io/ubuntu/ http://ubuntu.cica.es/ubuntu/ +http://ubuntu.colocall.net/ubuntu/ +http://ubuntu.connesi.it/ubuntu/ http://ubuntu.cs.nctu.edu.tw/ubuntu/ http://ubuntu.cs.utah.edu/ubuntu/ -http://ubuntu.cybercomhosting.com/ubuntu/ -http://ubuntu.dcc.fc.up.pt/ +http://ubuntu.cybertips.info/ubuntu/ +http://ubuntu.dts.mg/ubuntu/ http://ubuntu.ethz.ch/ubuntu/ -http://ubuntu.fastbull.org/ubuntu/ http://ubuntu.grena.ge/ubuntu/ http://ubuntu.grn.cat/ubuntu/ +http://ubuntu.hbcse.tifr.res.in/ubuntu/ +http://ubuntu.hostiran.ir/ubuntuarchive/ http://ubuntu.hysing.is/ubuntu/ -http://ubuntu.ictvalleumbra.it/ubuntu/ http://ubuntu.inode.at/ubuntu/ http://ubuntu.ip-connect.vn.ua/ http://ubuntu.ipacct.com/ubuntu/ @@ -529,51 +637,53 @@ http://ubuntu.koyanet.lv/ubuntu/ http://ubuntu.lagis.at/ubuntu/ http://ubuntu.lagoon.nc/ubuntu/ -http://ubuntu.laps.ufpa.br/ubuntu/ -http://ubuntu.lionlike.com/ubuntu/ -http://ubuntu.localmsp.org/ubuntu/ +http://ubuntu.man.lodz.pl/ubuntu/ +http://ubuntu.melbourneitmirror.net/archive/ http://ubuntu.mirror.ac.ke/ubuntu/ http://ubuntu.mirror.cambrium.nl/ubuntu/ http://ubuntu.mirror.constant.com/ +http://ubuntu.mirror.datamossa.io/ubuntu/ http://ubuntu.mirror.digitalpacific.com.au/archive/ http://ubuntu.mirror.frontiernet.net/ubuntu/ +http://ubuntu.mirror.ftn.uns.ac.rs/archive/ http://ubuntu.mirror.garr.it/ubuntu/ +http://ubuntu.mirror.globo.tech/ +http://ubuntu.mirror.iodc.dk/ubuntu/ http://ubuntu.mirror.iweb.ca/ -http://ubuntu.mirror.jahanserver.com/ http://ubuntu.mirror.lrz.de/ubuntu/ -http://ubuntu.mirror.neology.co.za/ubuntu/ +http://ubuntu.mirror.myduniahost.com/ubuntu/ http://ubuntu.mirror.rafal.ca/ubuntu/ http://ubuntu.mirror.root.lu/ubuntu/ +http://ubuntu.mirror.serverloft.de/ubuntu/ http://ubuntu.mirror.serversaustralia.com.au/ubuntu/ -http://ubuntu.mirror.su.se/ubuntu/ +http://ubuntu.mirror.snu.edu.in/ubuntu/ http://ubuntu.mirror.tn/ubuntu/ +http://ubuntu.mirror.true.nl/ubuntu/ http://ubuntu.mirror.tudos.de/ubuntu/ http://ubuntu.mirror.vu.lt/ubuntu/ http://ubuntu.mirrors.linux.ro/archive/ -http://ubuntu.mirrors.ovh.net/ftp.ubuntu.com/ubuntu/ +http://ubuntu.mirrors.omnilance.com/ubuntu/ +http://ubuntu.mirrors.ovh.net/ubuntu/ http://ubuntu.mirrors.pair.com/archive/ -http://ubuntu.mirrors.skynet.be/pub/ubuntu.com/ubuntu/ -http://ubuntu.mirrors.skynet.be/ubuntu/ http://ubuntu.mirrors.tds.net/pub/ubuntu/ +http://ubuntu.mirrors.theom.nz/ http://ubuntu.mirrors.uk2.net/ubuntu/ -http://ubuntu.mirrors.wvstateu.edu/ -http://ubuntu.org.ua/ubuntu/ +http://ubuntu.netforce.hosting/ubuntu/ +http://ubuntu.ntc.net.np/ubuntu/ http://ubuntu.osuosl.org/ubuntu/ http://ubuntu.otenet.gr/ +http://ubuntu.parspack.net/ubuntu/ http://ubuntu.positive-internet.com/ubuntu/ -http://ubuntu.retrosnub.co.uk/ubuntu/ +http://ubuntu.repo.cure.edu.uy/mirror/ http://ubuntu.saglayici.com/ubuntu/ -http://ubuntu.saix.net/ubuntu-archive/ http://ubuntu.securedservers.com/ http://ubuntu.snet.uz/ubuntu/ -http://ubuntu.sth.sze.hu/ubuntu/ http://ubuntu.stu.edu.tw/ubuntu/ http://ubuntu.task.gda.pl/ubuntu/ -http://ubuntu.trumpetti.atm.tut.fi/ubuntu/ +http://ubuntu.turhost.com/ubuntu/ http://ubuntu.tuxuri.com/ubuntu/ -http://ubuntu.uberglobalmirror.com/archive/ +http://ubuntu.uc3m.es/ubuntu/ http://ubuntu.ucr.ac.cr/ubuntu/ -http://ubuntu.uhost.hk/ http://ubuntu.uib.no/archive/ http://ubuntu.unc.edu.ar/ubuntu/ http://ubuntu.uni-klu.ac.at/ubuntu/ @@ -581,23 +691,22 @@ http://ubuntu.unitedcolo.de/ubuntu/ http://ubuntu.univ-nantes.fr/ubuntu/ http://ubuntu.univ-reims.fr/ubuntu/ +http://ubuntu.vargonen.com/ubuntu/ http://ubuntu.volia.net/ubuntu-archive/ -http://ubuntu.wallawalla.edu/ubuntu/ -http://ubuntu.wikimedia.org/ubuntu/ -http://ubuntuarchive.mirror.nac.net/ http://ubuntutym.u-toyama.ac.jp/ubuntu/ http://ucho.ignum.cz/ubuntu/ http://ucmirror.canterbury.ac.nz/ubuntu/ http://ug.archive.ubuntu.com/ubuntu/ +http://uk-mirrors.evowise.com/ubuntu/ http://uk.archive.ubuntu.com/ubuntu/ http://um.archive.ubuntu.com/ubuntu/ http://us.archive.ubuntu.com/ubuntu/ +http://us.mirror.nsec.pt/ubuntu/ http://uy.archive.ubuntu.com/ubuntu/ http://uz.archive.ubuntu.com/ubuntu/ http://va.archive.ubuntu.com/ubuntu/ http://vc.archive.ubuntu.com/ubuntu/ http://ve.archive.ubuntu.com/ubuntu/ -http://vesta.informatik.rwth-aachen.de/ftp/pub/Linux/ubuntu/ubuntu/ http://vg.archive.ubuntu.com/ubuntu/ http://vi.archive.ubuntu.com/ubuntu/ http://vn.archive.ubuntu.com/ubuntu/ @@ -609,8 +718,8 @@ http://www.ftp.ne.jp/Linux/packages/ubuntu/archive/ http://www.gtlib.gatech.edu/pub/ubuntu/ http://www.mirrorservice.org/sites/archive.ubuntu.com/ubuntu/ -http://www.nic.funet.fi/pub/mirrors/archive.ubuntu.com/ -http://wwwftp.ciril.fr/pub/linux/ubuntu/archives/ +http://www.ubuntu.com/getubuntu/download/ +http://www.ubuntu.com/partners/ http://ye.archive.ubuntu.com/ubuntu/ http://yt.archive.ubuntu.com/ubuntu/ http://za.archive.ubuntu.com/ubuntu/ diff -Nru apt-cacher-ng-0.9.1/conf/userinfo.html apt-cacher-ng-3.3.1/conf/userinfo.html --- apt-cacher-ng-0.9.1/conf/userinfo.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/conf/userinfo.html 2020-01-08 19:58:26.000000000 +0000 @@ -46,7 +46,7 @@ becomes:

deb http://${serverip}:${cfg:port}/ftp.debian.org/debian stable main contrib non-free
deb-src http://${serverip}:${cfg:port}/ftp.debian.org/debian stable main contrib non-free
- deb http://${serverip}:${cfg:port}//HTTPS///get.docker.com/ubuntu docker main

+ deb http://${serverip}:${cfg:port}/HTTPS///get.docker.com/ubuntu docker main

Depending on the configuration, it might be possible to use a shortcut for the base URLs without knowing the mirror, for example:

deb http://${serverip}:${cfg:port}/debian stable main contrib non-free

diff -Nru apt-cacher-ng-0.9.1/COPYING apt-cacher-ng-3.3.1/COPYING --- apt-cacher-ng-0.9.1/COPYING 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/COPYING 2020-01-08 19:58:26.000000000 +0000 @@ -2,22 +2,16 @@ Copyright: -apt-cacher-ng: (C) 2006-2012 Eduard Bloch -md5 add-on: (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. -getaddrinfo emulation: (C) 2001, Jason Gunthorpe -sha1 add-on: (C) 2006, The Bitzi Corporation -sha2 add-on: (C) 2005, 2007 Olivier Gay +apt-cacher-ng: (C) 2006-2019 Eduard Bloch License: The source files in this package are provided for use and distribution under the terms listed under I unless specified otherwise in the beginning of the -particular file. The package includes md5 checksumming implementation provided -under the terms listed under II, getaddrinfo/freeaddrinfo/getnameinfo emulation -code released under the terms listed under III, and sha1 implementation -released under the terms listed under IV. +particular file. The package includes additional code from external source, +covered by the following licenses. -I. Apt-Cacher NG +I. Apt-Cacher NG (all files except where specified otherwise) Copyright (c) 2007-2012 Eduard Bloch. All rights reserved. @@ -48,19 +42,3 @@ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -II. - -// $Id: rfc2553emu.cc,v 1.8 2001/02/20 07:03:18 jgg Exp $ -/* ###################################################################### - - RFC 2553 Emulation - Provides emulation for RFC 2553 getaddrinfo, - freeaddrinfo and getnameinfo - - This is really C code, it just has a .cc extensions to play nicer with - the rest of APT. - - Originally written by Jason Gunthorpe and placed into - the Public Domain, do with it what you will. - - ##################################################################### */ - diff -Nru apt-cacher-ng-0.9.1/dbgen/extra/deb_mirrors apt-cacher-ng-3.3.1/dbgen/extra/deb_mirrors --- apt-cacher-ng-0.9.1/dbgen/extra/deb_mirrors 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/dbgen/extra/deb_mirrors 2020-01-08 19:58:26.000000000 +0000 @@ -3,3 +3,4 @@ http://cdn.debian.net/debian/ http://http.debian.net/debian/ http://httpredir.debian.org/debian/ +http://deb.debian.org/debian/ diff -Nru apt-cacher-ng-0.9.1/dbgen/Makefile apt-cacher-ng-3.3.1/dbgen/Makefile --- apt-cacher-ng-0.9.1/dbgen/Makefile 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/dbgen/Makefile 2020-01-08 19:58:26.000000000 +0000 @@ -1,8 +1,19 @@ +# Mirror list/database update instructions +# This Make hackery runs either directly on web input or uses multiple steps in +# case where the input data is uncertain and the validity needs to be +# double-checked (by probing/crawling). To avoid pointless scans, the data is +# fingerprinted and the fingerprints are stored in the repository. +# +# XXX: this actually became too wild and most code should be moved into regular shell scripts. +# DBTMP=tmp export DBTMP CONFDIR=conf export CONFDIR +DEBMASTERLIST=https://salsa.debian.org/mirror-team/masterlist/raw/master/Mirrors.masterlist +ARCHJSON=https://www.archlinux.de/mirrors/datatables + # Main rule to be called to update all databases. Does two things, first get # and pre-filter raw data, second: check the sources and generate final lists, @@ -23,8 +34,8 @@ # the get_* targets are intended to fetch data, but only change the key file (prerequisite for other rules) if the data has really changed # this is the first stage of the gendbs target. get_deb_input: $(DBTMP) - wget -q -O $(DBTMP)/dsnap_raw 'http://anonscm.debian.org/viewvc/webwml/webwml/english/mirror/Mirrors.masterlist?view=markup' - grep file.line.text $(DBTMP)/dsnap_raw | sed -e 's,.*>,,' > $(DBTMP)/dsnap + wget -q -O $(DBTMP)/dsnap '$(DEBMASTERLIST)' + #grep file.line.text $(DBTMP)/dsnap_raw | sed -e 's,.*>,,' > $(DBTMP)/dsnap md5sum $(DBTMP)/dsnap > $(DBTMP)/sig-debian cmp sig-debian $(DBTMP)/sig-debian 2>/dev/null || cp $(DBTMP)/sig-debian sig-debian @@ -52,12 +63,11 @@ md5sum $(DBTMP)/slsnap > $(DBTMP)/sig-slsnap cmp sig-slsnap $(DBTMP)/sig-slsnap 2>/dev/null || cp $(DBTMP)/sig-slsnap sig-slsnap -get_sfnet_input: - wget -q -O $(DBTMP)/sf_raw http://sourceforge.net/p/forge/documentation/Mirrors/ - perl -ne 'next if !/^

([a-z]+)<\/td>/; print "http://$$1.dl.sourceforge.net/project/\n"' > $(DBTMP)/sfsnap <$(DBTMP)/sf_raw - md5sum $(DBTMP)/sfsnap > $(DBTMP)/sig-sfsnap - cmp sig-sfsnap $(DBTMP)/sig-sfsnap 2>/dev/null || cp $(DBTMP)/sig-sfsnap sig-sfsnap +get_sfnet_input: $(CONFDIR)/sfnet_mirrors +$(CONFDIR)/sfnet_mirrors: $(CONFDIR) + wget -q -O $(DBTMP)/sf_raw http://sourceforge.net/p/forge/documentation/Mirrors/ + perl -pe 's,[a-z]\+<' | sed -e 's,,http://,;s,<.*,.dl.sourceforge.net/project/,' > $(CONFDIR)/sfnet_mirrors # the $(CONFDIR)/* targets are intended to check the raw data got in the first step and # generate the final lists, skipping dead mirrors. this is the second stage of the gendbs target. @@ -72,12 +82,6 @@ $(CONFDIR)/sl_mirrors: sig-slsnap ubuntuscan.sh bash ubuntuscan.sh $@ $(DBTMP)/slsnap $(DBTMP) "/" "5rolling\|6rolling\|7rolling\|8rolling\|9rolling" -$(CONFDIR)/sfnet_mirrors: sig-sfsnap - > $(DBTMP)/sfnet_mirrors.tmp - for u in $$(cat $(DBTMP)/sfsnap) ; do echo Testing "$$u"; wget --timeout=10 --tries=1 -q -O- $$u | grep -qi "all.*rights" && echo "$$u" >> $(DBTMP)/sfnet_mirrors.tmp; done - mkdir -p "$(CONFDIR)" - cp -f $(DBTMP)/sfnet_mirrors.tmp $@ - $(CONFDIR)/ubuntu_mirrors: sig-ubuntu ubuntuscan.sh bash ubuntuscan.sh $@ $(DBTMP)/usnap $(DBTMP) "/pool/" "main" @@ -86,8 +90,13 @@ grep ^http: $(DBTMP)/cyg_raw | cut -f1 -d\; | sort -u > $(CONFDIR)/cygwin_mirrors $(CONFDIR)/archlx_mirrors: - wget -q --no-check-certificate -O $(DBTMP)/arch_raw 'https://archlinux.de/?page=MirrorStatus' - grep nofollow $(DBTMP)/arch_raw | cut -f2 -d'"' | grep ^http: | sort -u > $(CONFDIR)/archlx_mirrors + wget -q -O $(DBTMP)/arch_raw '$(ARCHJSON)' +# jq '.data[]' $(DBTMP)/arch_raw | jq .url -r | sort -u > $(CONFDIR)/archlx_mirrors + jq '.data[]' $(DBTMP)/arch_raw | jq .url -r | sed -e 's,https://,http://,' > $(DBTMP)/archlx_mirrors + wget -q -O- https://www.archlinux.org/mirrorlist/all/http/ \ + | grep 'http://' \ + | sed -e 's/.* = //' -e 's/\$$repo.*//' >> $(DBTMP)/archlx_mirrors + sort -u < $(DBTMP)/archlx_mirrors > $(CONFDIR)/archlx_mirrors $(CONFDIR)/deb_mirrors.gz: sig-debian deburlgen.pl perl deburlgen.pl Archive-http < $(DBTMP)/dsnap > $(DBTMP)/dsnap.urls @@ -109,17 +118,17 @@ else TARARGS += --mtime=@$(SOURCE_DATE_EPOCH) endif -ifneq ($(shell tar --help | grep clamp-mtime),) +ifneq ($(shell LANG=C tar --help | grep clamp-mtime),) TARARGS += --clamp-mtime endif -ifneq ($(shell tar --help | grep "sort.*name"),) +ifneq ($(shell LANG=C tar --help | grep "sort.*name"),) TARARGS += --sort=name endif package: $(DBTMP) - rm -rf $(TGTDIR) && mkdir $(TGTDIR) && cp -l Makefile deburlgen.pl gentoo_mirrors.sh ubuntuscan.sh sig-* $(TGTDIR) && tar -f- -c $(TARARGS) $(TGTDIR) | xz -9 > $(DBGENERATOR).tar.xz + rm -rf $(TGTDIR) && mkdir $(TGTDIR) && cp -l Makefile deburlgen.pl *.sh sig-* $(TGTDIR) && tar -f- -c $(TARARGS) $(TGTDIR) | xz -9 > $(DBGENERATOR).tar.xz install: cp conf/*mirrors* /usr/lib/apt-cacher-ng/ -.PHONY: $(CONFDIR)/gentoo_mirrors.gz +.PHONY: $(CONFDIR)/gentoo_mirrors.gz $(CONFDIR)/archlx_mirrors $(CONFDIR)/sfnet_mirrors diff -Nru apt-cacher-ng-0.9.1/dbgen/sig-debian apt-cacher-ng-3.3.1/dbgen/sig-debian --- apt-cacher-ng-0.9.1/dbgen/sig-debian 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/dbgen/sig-debian 2020-01-08 19:58:26.000000000 +0000 @@ -1 +1 @@ -4e381296068164faf08daa995fb0579a tmp/dsnap +3904658da9c9dd2338b772bd01fbc11e tmp/dsnap diff -Nru apt-cacher-ng-0.9.1/dbgen/sig-fsnap apt-cacher-ng-3.3.1/dbgen/sig-fsnap --- apt-cacher-ng-0.9.1/dbgen/sig-fsnap 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/dbgen/sig-fsnap 2020-01-08 19:58:26.000000000 +0000 @@ -1 +1 @@ -0ddeda810c2f8453fd5c214f85ff6ff4 tmp/fsnap +31d338dac4c6f5267c404befa13a05a2 tmp/fsnap diff -Nru apt-cacher-ng-0.9.1/dbgen/sig-sfsnap apt-cacher-ng-3.3.1/dbgen/sig-sfsnap --- apt-cacher-ng-0.9.1/dbgen/sig-sfsnap 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/dbgen/sig-sfsnap 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -d41d8cd98f00b204e9800998ecf8427e tmp/sfsnap diff -Nru apt-cacher-ng-0.9.1/dbgen/sig-slsnap apt-cacher-ng-3.3.1/dbgen/sig-slsnap --- apt-cacher-ng-0.9.1/dbgen/sig-slsnap 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/dbgen/sig-slsnap 2020-01-08 19:58:26.000000000 +0000 @@ -1 +1 @@ -6ae76ee2f73bc6271a2f95a9a60967c1 tmp/slsnap +e1eb89e6a535a25ec0443a53bf5a72ed tmp/slsnap diff -Nru apt-cacher-ng-0.9.1/dbgen/sig-ubuntu apt-cacher-ng-3.3.1/dbgen/sig-ubuntu --- apt-cacher-ng-0.9.1/dbgen/sig-ubuntu 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/dbgen/sig-ubuntu 2020-01-08 19:58:26.000000000 +0000 @@ -1 +1 @@ -912e6e5c82a0fe4331c83dcc1aaedd48 tmp/usnap +ba36b438e7e9f7bcb37da1106b0e568f tmp/usnap diff -Nru apt-cacher-ng-0.9.1/dbgen/ubuntuscan.sh apt-cacher-ng-3.3.1/dbgen/ubuntuscan.sh --- apt-cacher-ng-0.9.1/dbgen/ubuntuscan.sh 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/dbgen/ubuntuscan.sh 2020-01-08 19:58:26.000000000 +0000 @@ -25,7 +25,7 @@ tempdir=${3:-$(mktemp -d)} sfx=${4:-/dists} # Debian is easy, Ubuntu is bad... no symbolic name. Try to match well known release names -testkey=${5:-'updates\|stable\|unstable\|security\|backports\|feisty\|gutsy\|hardy\|intrepid\|jaunty\|karmic\|lucid\|maverick\|depper\|natty\|oneiric\|dapper\|edgy\|precise\|quantal\|raring\|saucy\|trusty\|vivid\|wily'} +testkey=${5:-'updates\|stable\|unstable\|security\|backports\|feisty\|gutsy\|hardy\|intrepid\|jaunty\|karmic\|lucid\|maverick\|depper\|natty\|oneiric\|dapper\|edgy\|precise\|quantal\|raring\|saucy\|trusty\|vivid\|wily\|xenial\|yakkety\|zesty\|artful\|bionic\|cosmic\|disco'} mkdir -p $tempdir rm -f $tempdir/url.* $tempdir/log.* diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.config apt-cacher-ng-3.3.1/debian/apt-cacher-ng.config --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.config 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.config 2020-01-19 20:24:09.000000000 +0000 @@ -6,6 +6,6 @@ db_input low apt-cacher-ng/proxy || true db_input low apt-cacher-ng/cachedir || true db_input low apt-cacher-ng/bindaddress || true -db_input low apt-cacher-ng/port || true -db_input low apt-cacher-ng/tunnelenable || true +db_input medium apt-cacher-ng/port || true +db_input high apt-cacher-ng/tunnelenable || true db_go diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.cron.daily apt-cacher-ng-3.3.1/debian/apt-cacher-ng.cron.daily --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.cron.daily 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.cron.daily 2020-01-19 20:24:09.000000000 +0000 @@ -7,4 +7,19 @@ # export HOSTNAME test -x /usr/lib/apt-cacher-ng/acngtool || exit 0 + +if test -e /etc/default/apt-cacher-ng +then + . /etc/default/apt-cacher-ng + test -z "$NO_CRON_RUN" || exit 0 +fi + +rpage=$(/usr/lib/apt-cacher-ng/acngtool -c /etc/apt-cacher-ng 2>/dev/null printvar ReportPage) +if test 0 = $(echo "$rpage" | wc -w) +then + echo Warning: ReportPage setting of apt-cacher-ng was disabled by administrator. >&2 + echo See /usr/share/doc/apt-cacher-ng/README.Debian for details. >&2 + exit 42 +fi + /usr/lib/apt-cacher-ng/acngtool maint -c /etc/apt-cacher-ng SocketPath=/var/run/apt-cacher-ng/socket diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.default apt-cacher-ng-3.3.1/debian/apt-cacher-ng.default --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.default 2016-04-05 19:40:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.default 2020-01-19 20:24:09.000000000 +0000 @@ -1,14 +1,10 @@ -# Defaults for apt-cacher-ng initscript -# sourced by /etc/init.d/apt-cacher-ng -# installed at /etc/default/apt-cacher-ng by the maintainer scripts +# Defaults for apt-cacher-ng +# sourced by /etc/init.d/apt-cacher-ng and the cron job script # # This is a POSIX shell fragment # -# Set to non-empty value to disable the start of the service at boot time -# DISABLED=1 - # See umask(2) or chmod(1) for details. # 002 would make new files writable by group. # @@ -16,3 +12,6 @@ # Additional options that are passed to the Daemon. DAEMON_OPTS=" -c /etc/apt-cacher-ng " + +# variable can be set to disable the daily cron job +# NO_CRON_RUN= diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.init apt-cacher-ng-3.3.1/debian/apt-cacher-ng.init --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.init 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.init 2020-01-19 20:24:09.000000000 +0000 @@ -29,8 +29,6 @@ . /etc/default/apt-cacher-ng fi -test -z "$DISABLED" || exit 0 - # our runtime state files directory, will be purged on startup! RUNDIR="/var/run/$NAME" diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.lintian-overrides apt-cacher-ng-3.3.1/debian/apt-cacher-ng.lintian-overrides --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.lintian-overrides 2016-04-05 19:40:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.lintian-overrides 2020-01-19 20:24:09.000000000 +0000 @@ -1 +1,3 @@ apt-cacher-ng: possible-gpl-code-linked-with-openssl +apt-cacher-ng: package-name-doesnt-match-sonames libsupacng +apt-cacher-ng: shlib-without-versioned-soname diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.logrotate apt-cacher-ng-3.3.1/debian/apt-cacher-ng.logrotate --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.logrotate 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.logrotate 2020-01-19 20:24:09.000000000 +0000 @@ -19,6 +19,7 @@ /var/log/apt-cacher-ng/apt-cache*.err { su apt-cacher-ng apt-cacher-ng daily + notifempty missingok rotate 7 compress diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.postinst apt-cacher-ng-3.3.1/debian/apt-cacher-ng.postinst --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.postinst 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.postinst 2020-01-19 20:24:09.000000000 +0000 @@ -92,32 +92,40 @@ fi fi + check_sane_data="grep -q http:// $tmpfile" + # may hit a local mirror which also hosts Debian, use it then sed -e 's,\([a-z]\)/.*,\1,' < $CFG/backends_debian | xargs -n1 -i grep "{}" $DDIR/ubuntu_mirrors > $tmpfile || true # mirror suggestions from Ubuntu's service might be a good candidate - if ! test -s $tmpfile ; then + if ! $check_sane_data ; then mirurl=http://mirrors.ubuntu.com/mirrors.txt - wget -q -O- $mirurl >> $tmpfile 2>/dev/null || curl -s $mirurl >> $tmpfile 2>/dev/null || $TOOL curl $mirurl $BINPATH >> $tmpfile 2>/dev/null || true + if which wget > /dev/null 2>&1 ; then + wget --timeout=15 -q -O- $mirurl >> $tmpfile 2>/dev/null || true + elif which curl > /dev/null 2>&1 ; then + curl -m 15 --fail -s $mirurl >> $tmpfile 2>/dev/null || true + else + $TOOL NetworkTimeout:15 curl $mirurl $BINPATH >> $tmpfile 2>/dev/null || true + fi fi # still nothing. Sneak more information from Debian backend configuration? - if ! test -s $tmpfile ; then # ok, go by Debian TLD + if ! $check_sane_data ; then # ok, go by Debian TLD grep debian.org/ /etc/apt-cacher-ng/backends_debian | \ sed -e 's,^http://ftp[2-3]\?\.\([a-z][a-z]\).*,http://\1.archive.ubuntu.com/,' | \ sort -u | xargs -n1 -i grep "{}" $DDIR/ubuntu_mirrors > $tmpfile || true fi - if ! test -s $tmpfile ; then # ok, then try just any TLD + if ! $check_sane_data ; then # ok, then try just any TLD sed -e 's,^http://\([^\/]\+\).*,\1,;s,.*\.\(.*\),http://\1.archive.ubuntu.com/,' < $CFG/backends_debian | \ sort -u | xargs -n1 -i grep "{}" $DDIR/ubuntu_mirrors > $tmpfile || true fi - if ! test -s $tmpfile ; then + if ! $check_sane_data ; then echo http://archive.ubuntu.com/ubuntu/ > $tmpfile || true fi - if test -s $tmpfile ; then + if $check_sane_data ; then echo "$def_file_header" > $udefault cat $tmpfile >> $udefault fi @@ -137,20 +145,8 @@ db_get $NAME/cachedir case "$RET" in keep|"") - # but making sure that it's really set to something sensible in the - # config, otherwise replace with the default - if ! TESTPATH=$($TOOL printvar CacheDir -c $CFG 2>/dev/null) ; then - # ok, some IO trouble is bad but in this case just behave like it - # did in the former times with a static /v/c/a-c-n folder setting - CDIR=/var/cache/$NAME - CDIRCONF="# CacheDir not set, having trouble reading config files" - elif test -d "$TESTPATH" ; then - CDIR="$TESTPATH" - CDIRCONF="# CacheDir not set by debconf" - else - CDIR=/var/cache/$NAME - CDIRCONF="CacheDir: $CDIR # default or overridden since '$TESTPATH' directory didn't exist" - fi + # maybe never displayed to user + CDIRCONF='# CacheDir set to "keep", not overriding here' ;; *) # ok, configured by debconf, will be created as needed @@ -159,6 +155,14 @@ ;; esac + if test -z "$CDIR" ; then + CDIR=$($TOOL printvar CacheDir -c $CFG 2>/dev/null) + if test -z "$CDIR" ; then + # unlikely... but even if PEBCAK, prepare the correct folder now + CDIR=/var/cache/$NAME + fi + fi + # user should exist. adduser sometimes fails (system range issue) but that's ok adduser --quiet --system --group --no-create-home --home "$CDIR" $NAME || id $NAME # also setup permissions ASAP @@ -166,7 +170,6 @@ dpkg-statoverride --update --add root $NAME 640 $CFG/security.conf fi - # be sure about that even if the user messed it up for x in "$CDIR" $LDIR ; do if [ ! -d "$x" ]; then install -d -g $NAME -o $NAME -m2755 "$x" @@ -207,7 +210,7 @@ if [ x"$BINDADDRESS" = x"all" ] ; then # just for backwards compatibility BINDADDRESS='BindAddress: ' elif [ x"$BINDADDRESS" = x"keep" ] ; then - BINDADDRESS='# BindAddress is set by other config file(s)' + BINDADDRESS='# BindAddress set to "keep", not overriding here' else BINDADDRESS="BindAddress: $BINDADDRESS" fi @@ -215,7 +218,7 @@ db_get $NAME/port PORT="$RET" if [ x"$PORT" = x"keep" ] || [ x"$PORT" = x ] ; then - PORT='# Port is set by other config file(s)' + PORT='# Port set to "keep", not overriding here' else PORT="Port: $PORT" fi @@ -225,7 +228,7 @@ if [ x"$PROXY" = x ] ; then PROXY='Proxy:' elif [ x"$PROXY" = x"keep" ] ; then - PROXY='# Proxy set by other config files(s)' + PROXY='# Proxy set to "keep", not overriding here' else if echo "$PROXY" |grep -q '@' ; then # well, there are credentials which is bad. This better goes into a file with restricted permissions. diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.postrm apt-cacher-ng-3.3.1/debian/apt-cacher-ng.postrm --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.postrm 2016-04-05 19:40:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.postrm 2020-01-19 20:24:09.000000000 +0000 @@ -8,7 +8,7 @@ CFG=/etc/$NAME if [ "$1" = "purge" ]; then - rm -rf "$CDIR" + rm -rf "$CDIR" ||: rm -f $LDIR/apt-cacher.err.* $LDIR/apt-cacher.err $LDIR/apt-cacher.log $LDIR/apt-cacher.log.* $LDIR/maint_*.log rmdir $LDIR 2>/dev/null || true rm -rf /var/lib/apt-cacher-ng diff -Nru apt-cacher-ng-0.9.1/debian/apt-cacher-ng.triggers apt-cacher-ng-3.3.1/debian/apt-cacher-ng.triggers --- apt-cacher-ng-0.9.1/debian/apt-cacher-ng.triggers 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/apt-cacher-ng.triggers 2020-01-19 20:24:09.000000000 +0000 @@ -0,0 +1 @@ +activate-noawait ldconfig diff -Nru apt-cacher-ng-0.9.1/debian/changelog apt-cacher-ng-3.3.1/debian/changelog --- apt-cacher-ng-0.9.1/debian/changelog 2016-04-19 19:17:57.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/changelog 2021-05-07 16:34:48.000000000 +0000 @@ -1,9 +1,232 @@ -apt-cacher-ng (0.9.1-1ubuntu1) xenial; urgency=medium +apt-cacher-ng (3.3.1-2~16.04.sav0) xenial; urgency=high - * Merge from Debian unstable (LP: #1561829). Remaining changes: - - debian/patches/by-hash.patch: Consider by-hash files as static data. + * Backport to Xenial - -- Logan Rosen Tue, 19 Apr 2016 19:15:51 +0000 + -- Rob Savoury Fri, 07 May 2021 09:34:48 -0700 + +apt-cacher-ng (3.3.1-2) unstable; urgency=high + + * Fixes FTBFS on mipsel/mips64el + * Fixes missing last-minute changes in actual upstream version 3.3.1 + + -- Eduard Bloch Sun, 19 Jan 2020 21:24:09 +0100 + +apt-cacher-ng (3.3.1-1) unstable; urgency=medium + + * Bugfix upstream release update + + (CVE-2020-5202) Enforce secured call to the server in maint job triggering + + Allow .zst compression for tarballs (closes: Bug#948259, thanks + to Arnaud Rebillout) + + Added branch information to Vcs-Git control line (closes: #913594) + + Hint about not set (by debconf) CacheDir variable in zz_debconf.conf + (closes: #929031) + + -- Eduard Bloch Wed, 08 Jan 2020 21:01:26 +0100 + +apt-cacher-ng (3.3-2) unstable; urgency=low + + * Upload to Sid + + -- Eduard Bloch Thu, 14 Nov 2019 13:56:58 +0100 + +apt-cacher-ng (3.3-1) experimental; urgency=low + + * New upstream version v3.3 + Contains a good number of internal changes, including: + - Alternative fallback scheme for non-primary target connection + attempts (with default timeout value of 4s, see FastTimeout + setting). By default, this should help with unstable (blocking) IPv6 + routing where IPv4 is still operational (closes: #942122) + - RequiresMountsFor directive in systemd service file example with + additional remarks on keeping this in sync with the config + (closes: #929035, #942355) + - PFilePattern extensions for Fedora 29 and 30, by Alan Jenkins, + closes: #928270, thanks!) + - VFilePattern extension for Centos8, by Andy Lowther, + closes: #944143 (thanks!) + - added very explicit explanation on what "default value" means in the + acng.conf example (closes: #855995) and also how to print it (with + acngtool, closes: #914746) + - Typo in INSTALL file (closes: #913593) + - In Arch Linux database mirror list, rewrite https URLs to http since + the official JSON query only returns https versions, also add a + different source (closes: #942844, thanks!) + * Make errors on purging of cache folder non-fatal (closes: #915082) + * Recommends: ca-certificates (closes: #926282) + + -- Eduard Bloch Sun, 10 Nov 2019 19:00:40 +0100 + +apt-cacher-ng (3.2-3) unstable; urgency=medium + + * Increase decompression line buffer size (closes: #942634) + + -- Eduard Bloch Mon, 28 Oct 2019 22:14:46 +0100 + +apt-cacher-ng (3.2-2) unstable; urgency=medium + + * Fix for incorrect assumption of some existing SHA256SUMS files in Debian + repositories which makes the expiration task fail without a proper way + for the end user to recover from it. Now ignore a download error in this + case (similar handling as for other guesses), assuming that permanent + 404ing for other reasons than removal of remote content can be considered + unlikely (closes: #928957) + + -- Eduard Bloch Fri, 17 May 2019 22:59:21 +0200 + +apt-cacher-ng (3.2-1) unstable; urgency=low + + * New upstream version + + Allow tunnel mode per default for some Debian and Ubuntu services + closes: #906113 + + Adding remap config for security.d.o + closes: #900325 + + Fix incorrect -C option in manpage and other minor errors + closes: #901292, #901294, #901295 + + Remove obsolete option from config output + closes: #859680 + * Removed the DISABLED flag from the init script (current Debian policy, + section 9.3.3.1) + * Raised the debconf priority to high for the question about proxy tunnel + permissions (like HTTPS) since there is no perfect default. + closes: #814359 + + -- Eduard Bloch Fri, 07 Sep 2018 11:30:33 +0200 + +apt-cacher-ng (3.1-1) unstable; urgency=low + + * New upstream version + + removed doc references to distkill.pl (closes: #877703, LP: #1635029) + + includes fix for rare expiration failure on missing index files + (closes: #872830) + + fixes credential printing in logs (closes: #877135) + + hardens default pass-through mask for bugs.debian.org (closes: #874349) + * Portuguese translation update (by Traduz, closes: #874609) + * Policy definition and build-deps update (no related changes) + + -- Eduard Bloch Sun, 05 Nov 2017 20:55:20 +0100 + +apt-cacher-ng (3-5) unstable; urgency=low + + * Moving RequiresMountsFor to Unit section (closes: #859520) + + -- Eduard Bloch Thu, 27 Apr 2017 20:12:02 +0200 + +apt-cacher-ng (3-4) unstable; urgency=medium + + * Made cron.daily tolerant to removal of config files (closes: #858952) + + -- Eduard Bloch Sun, 02 Apr 2017 10:05:38 +0200 + +apt-cacher-ng (3-3) unstable; urgency=medium + + * Updated debian/copyright to match the upstream version (now really) + + -- Eduard Bloch Tue, 28 Mar 2017 21:01:49 +0200 + +apt-cacher-ng (3-2) unstable; urgency=medium + + * Updated debian/copyright to match the upstream version + + -- Eduard Bloch Tue, 28 Mar 2017 20:09:54 +0200 + +apt-cacher-ng (3-1) unstable; urgency=medium + + * New upstream version + + GCC7 compilation fixes (closes: #853315) + + fixes hidden space allocation issue (closes: #856635) + + smarter manual index deletion wizard which covers related files too + (probably closes: #789706) + * Spanish translation update (by Matías A. Bellone, closes: #853105) + * Instructions on how to work around cron job execution and "special needs" + of some users to disable the admin page (closes: #855996) + * Added RequiresMountsFor to systemd service description (closes: #855618, + only in Debian patch for now) + + -- Eduard Bloch Wed, 22 Mar 2017 20:30:21 +0100 + +apt-cacher-ng (2-1) unstable; urgency=low + + * New upstream version + + Fix for incorrect compilation with gcc-5.4 (closes: #843417, #843410) + + Fixes communication of cron job runner on systems where public address + was guessed incorrectly and/or connection was not possible + (closes: #843834, #841633) + + Fix ExStartTradeOff computation with unit suffix (closes: #845245) + + Linking libatomic where possible (closes: #841431, now really) + * Not rotating apt-cacher.err log when file is empty (notifempty option, + closes: #832882) + + -- Eduard Bloch Tue, 22 Nov 2016 21:39:43 +0100 + +apt-cacher-ng (1-2) unstable; urgency=low + + [ Dejan Latinovic ] + * Fixing FTBFS on MIPS (extra libatomic dependency, closes: #841431) + + [Eduard Bloch] + * Extended mips/mipsel FTBFS patch to powerpcspe and m68k + + -- Eduard Bloch Thu, 20 Oct 2016 20:25:39 +0200 + +apt-cacher-ng (1-1) unstable; urgency=low + + * New upstream version + + Better TLS hostname checks (closes: #839751) + + Making build reproducible again (closes: #834755) + + -- Eduard Bloch Wed, 19 Oct 2016 22:14:15 +0200 + +apt-cacher-ng (0.9.3.2-1) unstable; urgency=low + + * New upstream version + + Fix FTBFS with non-Linux kernels (closes: #830736) + * Better sanity check of data retrieved when looking for Ubuntu mirrors and + correct checking of curl return code (prevents accidental inclusion of + garbage from error messages of intermediate proxies into backend mirror + configuration). Also sets shorter timeouts when fetching mirrors.txt + (which closes: #827721 even while upgrading from very old versions) + * In postinst, dropped some "smart" code which was trying to setup the + default cache directory in case when clueless user deleted the related + configuration line. That guessing was probably helping less often than it + might have broken things; it contained a bug which (only on the very first + installation) could incorrectly add a forced setting of CacheDir + (closes: #830578) + * Giving the question about pass-through higher debconf priority since some + people seem to care a lot about HTTPS forwarding (#813359) + + -- Eduard Bloch Tue, 12 Jul 2016 22:03:27 +0200 + +apt-cacher-ng (0.9.3.1-1) unstable; urgency=low + + * New upstream version + * Sync with standards 0.9.8 + * Not stopping daemon on upgrade (closes: #825154) + + -- Eduard Bloch Wed, 08 Jun 2016 23:34:30 +0200 + +apt-cacher-ng (0.9.3-1) unstable; urgency=medium + + * New upstream version + + handling for removal of SHA1 signature lists in recent Release/InRelease + files (closes: #824293) + + better support of by-hash storage (now really closes: #819852 apart from + some corner cases) + + better links in error reporting mails (closes: #825640) + + -- Eduard Bloch Sun, 29 May 2016 18:30:24 +0200 + +apt-cacher-ng (0.9.2-1) unstable; urgency=low + + * New upstream version + + basic support for by-hash index files (closes: #819852) including some + precaution in cache cleanup routines + + supports .asc signatures for source (closes: #823733) + + supports repo names with hyphens again (closes: #823570) + + supports deb.debian.org by default (closes: #820813) + * Japanese Debconf template update from Takuma Yamada included + (closes: #815527) + + -- Eduard Bloch Fri, 13 May 2016 20:04:32 +0200 apt-cacher-ng (0.9.1-1) unstable; urgency=low @@ -17,12 +240,6 @@ -- Eduard Bloch Mon, 01 Feb 2016 19:50:49 +0100 -apt-cacher-ng (0.8.9-1ubuntu1) xenial; urgency=medium - - * Consider by-hash files as static data (closes: #819852). - - -- Colin Watson Tue, 05 Apr 2016 14:52:21 +0100 - apt-cacher-ng (0.8.9-1) unstable; urgency=medium * New upstream version (avoids use of Proxy in cron jobs, closes: #811350) diff -Nru apt-cacher-ng-0.9.1/debian/control apt-cacher-ng-3.3.1/debian/control --- apt-cacher-ng-0.9.1/debian/control 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/control 2020-01-19 20:24:09.000000000 +0000 @@ -1,19 +1,19 @@ Source: apt-cacher-ng Section: net Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Eduard Bloch -Build-Depends: debhelper (>= 9), cmake (>= 2.6.2), libbz2-dev, zlib1g-dev, liblzma-dev, libfuse-dev [!hurd-i386], pkg-config, libwrap0-dev, lsb-base (>> 3.0-6), dh-systemd (>= 1.5), po-debconf, libssl-dev, libsystemd-dev (>= 210) [linux-any] | libsystemd-daemon-dev [linux-any] -Standards-Version: 3.9.6 +Maintainer: Eduard Bloch +Build-Depends: debhelper (>= 9), cmake (>= 2.6.2), libbz2-dev, zlib1g-dev, liblzma-dev, libfuse-dev [!hurd-i386], pkg-config, libwrap0-dev, lsb-base (>> 3.0-6), debhelper (>= 9.20160709) | dh-systemd (>= 1.5), po-debconf, libssl-dev, libsystemd-dev (>= 210) [linux-any] | libsystemd-daemon-dev [linux-any], libpthread-stubs0-dev, libevent-dev +Standards-Version: 4.1.1 Homepage: http://www.unix-ag.uni-kl.de/~bloch/acng/ -Vcs-Git: https://alioth.debian.org/anonscm/git/apt-cacher-ng/apt-cacher-ng.git -Vcs-Browser: https://alioth.debian.org/scm/browser.php?group_id=100566 +Vcs-Git: https://salsa.debian.org/blade/apt-cacher-ng.git -b debian/sid_v3.3.x +Vcs-Browser: https://salsa.debian.org/blade/apt-cacher-ng/tree/debian/sid Package: apt-cacher-ng Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, adduser +Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lsb-base (>= 3.0-6) Pre-Depends: dpkg (>= 1.15.6) Conflicts: logrotate (<< 3.8.0) +Recommends: ca-certificates Suggests: doc-base, libfuse2 (>= 2.5), avahi-daemon Description: caching proxy server for software repositories Apt-Cacher NG is a caching proxy for downloading packages from Debian-style diff -Nru apt-cacher-ng-0.9.1/debian/copyright apt-cacher-ng-3.3.1/debian/copyright --- apt-cacher-ng-0.9.1/debian/copyright 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/copyright 2020-01-19 20:24:09.000000000 +0000 @@ -5,25 +5,24 @@ Upstream Author: -Eduard Bloch +Author: Eduard Bloch Copyright: -apt-cacher-ng: (C) 2006-2009 Eduard Bloch -md5 add-on: (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. +apt-cacher-ng: (C) 2006-2012 Eduard Bloch getaddrinfo emulation: (C) 2001, Jason Gunthorpe -sha1 add-on: (C) 2006, The Bitzi Corporation +Alternative SSL host validation: +Copyright (C) 2012, iSEC Partners. +Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. License: The source files in this package are provided for use and distribution under the terms listed under I unless specified otherwise in the beginning of the -particular file. The package includes md5 checksumming implementation provided -under the terms listed under II, getaddrinfo/freeaddrinfo/getnameinfo emulation -code released under the terms listed under III, and sha1 implementation -released under the terms listed under IV. +particular file. The package includes additional code from external source, +covered by the following licenses. -I. Apt-Cacher NG +I. Apt-Cacher NG (all files except for specified below) Copyright (c) 2007-2012 Eduard Bloch. All rights reserved. @@ -54,33 +53,7 @@ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -II. MD5 implementation - -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ - -III. +II. */rfc2553emu.* // $Id: rfc2553emu.cc,v 1.8 2001/02/20 07:03:18 jgg Exp $ /* ###################################################################### @@ -96,97 +69,49 @@ ##################################################################### */ -IV. +III. oldssl-workaround/openssl* (alternative OpenSSL hostname validation code) +/* +Copyright (C) 2012, iSEC Partners. -/* (PD) 2006 The Bitzi Corporation - * - * 1. Authorship. This work and others bearing the above - * label were created by, or on behalf of, the Bitzi - * Corporation. Often other public domain material by - * other authors is incorporated; this should be clear - * from notations in the source code. If other non- - * public-domain code or libraries are included, this is - * is done under those works' respective licenses. - * - * 2. Release. The Bitzi Corporation places its portion - * of these labelled works into the public domain, - * disclaiming all rights granted us by copyright law. - * - * Bitzi places no restrictions on your freedom to copy, - * use, redistribute and modify this work, though you - * should be aware of points (3), (4), and (5) below. - * - * 3. Trademark Advisory. The Bitzi Corporation reserves - * all rights with regard to any of its trademarks which - * may appear herein, such as "Bitzi", "Bitcollider", or - * "Bitpedia". Please take care that your uses of this - * work do not infringe on our trademarks or imply our - * endorsement. For example, you should change labels - * and identifier strings in your derivative works where - * appropriate. - * - * 4. Licensed portions. Some code and libraries may be - * incorporated in this work in accordance with the - * licenses offered by their respective rightsholders. - * Further copying, use, redistribution and modification - * of these third-party portions remains subject to - * their original licenses. - * - * 5. Disclaimer. THIS SOFTWARE IS PROVIDED BY THE AUTHOR - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Please see http://bitzi.com/publicdomain or write - * info@bitzi.com for more info. +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. */ -V. +IV. oldssl-workaround/hostcheck* -/* - * FIPS 180-2 SHA-224/256/384/512 implementation - * Last update: 02/02/2007 - * Issue date: 04/30/2005 - * - * Copyright (C) 2005, 2007 Olivier Gay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ +COPYRIGHT AND PERMISSION NOTICE +Copyright (c) 1996 - 2013, Daniel Stenberg, . -The Debian packaging is (C) 2007, Eduard Bloch and -is licensed under the GPL, see `/usr/share/common-licenses/GPL-2'. +All rights reserved. +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +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 OF THIRD PARTY RIGHTS. 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. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. diff -Nru apt-cacher-ng-0.9.1/debian/gbp.conf apt-cacher-ng-3.3.1/debian/gbp.conf --- apt-cacher-ng-0.9.1/debian/gbp.conf 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/gbp.conf 2020-01-19 20:24:09.000000000 +0000 @@ -1,4 +1,4 @@ [DEFAULT] -upstream-branch = upstream/sid -debian-branch = debian/sid +upstream-branch = upstream/sid_v3.3.x +debian-branch = debian/sid_v3.3.x diff -Nru apt-cacher-ng-0.9.1/debian/patches/by-hash.patch apt-cacher-ng-3.3.1/debian/patches/by-hash.patch --- apt-cacher-ng-0.9.1/debian/patches/by-hash.patch 2016-04-05 13:52:06.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/patches/by-hash.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -Description: Consider by-hash files as static data -Author: Colin Watson -Bug-Debian: https://bugs.debian.org/819852 - -Index: b/source/acfg_defaults.cc -=================================================================== ---- a/source/acfg_defaults.cc -+++ b/source/acfg_defaults.cc -@@ -30,6 +30,7 @@ - "|[a-f0-9]+-(susedata|updateinfo|primary|deltainfo).xml.gz" //opensuse, index data, hash in filename - "|fonts/(final/)?[a-z]+32.exe(\\?download.*)?" // msttcorefonts, fonts/final/comic32.exe /corefonts/comic32.exe plus SF's parameters - "|/dists/.*/installer-[^/]+/[0-9][^/]+/images/.*" // d-i stuff with revision -+ "|/dists/.*/by-hash/.*" - "|/[[:alpha:]]{1,2}/[a-f0-9]{64}(-[a-f0-9]{64})?(\\.gz)?" // FreeBSD, after https://alioth.debian.org/tracker/?func=detail&atid=413111&aid=315254&group_id=100566 - ")$"); - diff -Nru apt-cacher-ng-0.9.1/debian/patches/debian-changes apt-cacher-ng-3.3.1/debian/patches/debian-changes --- apt-cacher-ng-0.9.1/debian/patches/debian-changes 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/patches/debian-changes 2021-05-07 16:34:48.000000000 +0000 @@ -0,0 +1,70 @@ +Description: + TODO: Put a short summary on the line above and replace this paragraph + with a longer explanation of this change. Complete the meta-information + with other relevant fields (see below for details). To make it easier, the + information below has been extracted from the changelog. Adjust it or drop + it. + . + apt-cacher-ng (3.3.1-2) unstable; urgency=high + . + * Fixes FTBFS on mipsel/mips64el + * Fixes missing last-minute changes in actual upstream version 3.3.1 +Author: Eduard Bloch + +--- +The information above should follow the Patch Tagging Guidelines, please +checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here +are templates for supplementary fields that you might want to add: + +Origin: , +Bug: +Bug-Debian: https://bugs.debian.org/ +Bug-Ubuntu: https://launchpad.net/bugs/ +Forwarded: +Reviewed-By: +Last-Update: 2020-01-19 + +--- apt-cacher-ng-3.3.1.orig/CMakeLists.txt ++++ apt-cacher-ng-3.3.1/CMakeLists.txt +@@ -96,7 +96,26 @@ if(CXX_VIHI) + _append(ACNG_CXXFLAGS -fvisibility-inlines-hidden) + endif() + +-foreach(linkarg -Wl,--as-needed -Wl,-O1 -Wl,--discard-all -Wl,--no-undefined -Wl,--build-id=sha1 -Wl,-fuse-ld=gold) ++option(USE_GOLD "Attempt to use the GOLD linker" ON) ++option(USE_GOLD_MT "Attempt to use the GOLD linker with multi-threading" ON) ++if(${USE_GOLD}) ++ if(${USE_GOLD_MT}) ++ set(CMAKE_REQUIRED_FLAGS "-Wl,-fuse-ld=gold -Wl,--threads") ++ CHECK_CXX_COMPILER_FLAG("" LD_MULTITHREADED) ++ endif() ++ if(LD_MULTITHREADED) ++ _append(CMAKE_EXE_LINKER_FLAGS "-Wl,-fuse-ld=gold -Wl,--threads") ++ else() # ok, just gold? ++ set(CMAKE_REQUIRED_FLAGS "-Wl,-fuse-ld=gold") ++ CHECK_CXX_COMPILER_FLAG("" LD_GOLD) ++ if(LD_GOLD) ++ _append(CMAKE_EXE_LINKER_FLAGS "-Wl,-fuse-ld=gold") ++ endif() ++ endif() ++ set(CMAKE_REQUIRED_FLAGS "") ++endif() ++ ++foreach(linkarg -Wl,--as-needed -Wl,-O1 -Wl,--discard-all -Wl,--no-undefined -Wl,--build-id=sha1) + STRING(REGEX REPLACE "=|-|," "" optname "${linkarg}") + set(CMAKE_REQUIRED_FLAGS "${linkarg}") + CHECK_CXX_COMPILER_FLAG("" "LD_${optname}") +@@ -106,13 +125,6 @@ foreach(linkarg -Wl,--as-needed -Wl,-O1 + set(CMAKE_REQUIRED_FLAGS "") + endforeach(linkarg) + +-set(CMAKE_REQUIRED_FLAGS "-Wl,-fuse-ld=gold -Wl,--threads") +-CHECK_CXX_COMPILER_FLAG("" LD_MULTITHREADED) +-if(LD_MULTITHREADED) +- _append(CMAKE_EXE_LINKER_FLAGS "-Wl,-fuse-ld=gold -Wl,--threads") +-endif() +-set(CMAKE_REQUIRED_FLAGS "") +- + option(USE_SSL "Use OpenSSL library for TLS and other crypto functionality" on) + + IF(CMAKE_SYSTEM MATCHES "Darwin") diff -Nru apt-cacher-ng-0.9.1/debian/patches/series apt-cacher-ng-3.3.1/debian/patches/series --- apt-cacher-ng-0.9.1/debian/patches/series 2016-04-05 13:49:59.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/patches/series 2020-01-19 20:24:09.000000000 +0000 @@ -1 +1 @@ -by-hash.patch +debian-changes diff -Nru apt-cacher-ng-0.9.1/debian/po/es.po apt-cacher-ng-3.3.1/debian/po/es.po --- apt-cacher-ng-0.9.1/debian/po/es.po 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/po/es.po 2020-01-19 20:24:09.000000000 +0000 @@ -7,7 +7,7 @@ # Omar Campagne , 2009, 2010 # # - Updates -# Matías A. Bellone , 2013 +# Matías A. Bellone , 2013, 2015 # # Traductores, si no conocen el formato PO, merece la pena leer la # de gettext, especialmente las secciones dedicadas a este @@ -32,7 +32,7 @@ "Project-Id-Version: 0.4-1\n" "Report-Msgid-Bugs-To: apt-cacher-ng@packages.debian.org\n" "POT-Creation-Date: 2015-03-17 19:19+0100\n" -"PO-Revision-Date: 2014-02-09 13:04-0300\n" +"PO-Revision-Date: 2015-11-16 00:32-0300\n" "Last-Translator: Matías Bellone \n" "Language-Team: Debian l10n Spanish \n" "Language: es\n" @@ -74,12 +74,12 @@ "URL remapping can be set up automatically, using a configuration based on " "the current state of /etc/apt/sources.list." msgstr "" -"Apt-Cacher NG puede descargar paquetes desde otros repositorios distintos a " -"los solicitados por los clientes. Esto le permite almacenar el contenido " +"Apt-Cacher NG puede descargar paquetes desde otros repositorios distintos " +"a los solicitados por los clientes. Esto le permite almacenar el contenido " "eficientemente y facilitar al administrador cambiar a otra réplica más " -"adelante. Se puede configurar automáticamente el remapeo de URLs utilizando " -"una configuración basada en el estado actual del archivo «/etc/apt/sources." -"list»." +"adelante. Se puede configurar automáticamente el remapeo de direcciones " +"URL utilizando una configuración basada en el estado actual del archivo " +"«/etc/apt/sources.list»." #. Type: select #. Description @@ -107,7 +107,7 @@ #. Description #: ../apt-cacher-ng.templates:3001 msgid "Listening address(es) for Apt-Cacher NG:" -msgstr "Dirección(es) en la(s) que escuchará Apt-Cacher NG:" +msgstr "Direcciones en las que escuchará Apt-Cacher NG:" #. Type: string #. Description @@ -116,8 +116,8 @@ "Please specify the local addresses that Apt-Cacher NG should listen on " "(multiple entries must be separated by spaces)." msgstr "" -"Indique la(s) dirección(es) local(es) en la(s) que debe escuchar Apt-Cacher " -"NG (debe separar las direcciones con espacios)." +"Indique las direcciones locales en las que debe escuchar Apt-Cacher NG " +"(debe separar las direcciones con espacios)." #. Type: string #. Description @@ -179,7 +179,7 @@ "If this field is left empty, the value from the current configuration " "remains unchanged." msgstr "" -"Si deja este campo vacío no se modificará el valor actual de laconfiguración." +"Si deja este campo vacío no se modificará el valor actual de la configuración." #. Type: string #. Description @@ -205,8 +205,8 @@ "If this field is left empty, the value from the current configuration " "remains unchanged or is set to the default of /var/cache/apt-cacher-ng." msgstr "" -"Si deja este campo vacío se mantendrá el valor acual de la configuración o " -"se utilizará el valor predeterminado: «/var/cache/apt-cacher-ng»." +"Si deja este campo vacío se mantendrá el valor actual de la configuración " +"o se utilizará el valor predeterminado: «/var/cache/apt-cacher-ng»." #. Type: string #. Description @@ -244,7 +244,7 @@ #. Description #: ../apt-cacher-ng.templates:7001 msgid "Allow HTTP tunnels through Apt-Cacher NG?" -msgstr "" +msgstr "¿Desea permitir túneles HTTP a través de Apt-Cacher NG?" #. Type: boolean #. Description @@ -254,6 +254,9 @@ "can be used to access remote servers that might otherwise be blocked by (for " "instance) a firewall filtering HTTPS connections." msgstr "" +"Puede configurar Apt-Cacher NG para permitir a los usuarios crear túneles " +"HTTP que pueden ser utilizados para acceder a servidores remotos posiblemente " +"bloqueados, por ejemplo, por un cortafuegos que filtre conexiones HTTPS." #. Type: boolean #. Description @@ -262,6 +265,8 @@ "This feature is usually disabled for security reasons; enable it only for " "trusted LAN environments." msgstr "" +"Esta opción generalmente se encuentra desactivada por cuestiones de " +"seguridad; actívela sólo en entornos LAN en los que confíe." # N.t: update = actualización de la lista de paquetes..., ya que «actualizar» # en este contexto puede sugerir la instalación de versiones nuevas de paquetes diff -Nru apt-cacher-ng-0.9.1/debian/po/ja.po apt-cacher-ng-3.3.1/debian/po/ja.po --- apt-cacher-ng-0.9.1/debian/po/ja.po 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/po/ja.po 2020-01-19 20:24:09.000000000 +0000 @@ -1,7 +1,7 @@ -# Copyright (C) 2009 Eduard Bloch -# This file is distributed under the same license as apt-cacher-ng package. -# Hideki Yamane (Debian-JP) , 2009. -# +# Copyright (C) 2009 Eduard Bloch +# This file is distributed under the same license as apt-cacher-ng package. +# Hideki Yamane (Debian-JP) , 2009. +# msgid "" msgstr "" "Project-Id-Version: apt-cacher-ng 0.4-2\n" @@ -212,7 +212,7 @@ #. Description #: ../apt-cacher-ng.templates:7001 msgid "Allow HTTP tunnels through Apt-Cacher NG?" -msgstr "" +msgstr "Apt-Cacher NG 経由㮠HTTP トンãƒãƒ«ã‚’許å¯ã—ã¾ã™ã‹?" #. Type: boolean #. Description @@ -222,6 +222,10 @@ "can be used to access remote servers that might otherwise be blocked by (for " "instance) a firewall filtering HTTPS connections." msgstr "" +"Apt-Cacher NG ã¯ã€ãƒ¦ãƒ¼ã‚¶ãŒ HTTP トンãƒãƒ« を作æˆã§ãるよã†ã«è¨­å®šã™ã‚‹ã“ã¨ãŒã§ã" +"ã¾ã™ã€‚リモートサーãƒã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ãŒã€ä¾‹ãˆã° " +"HTTPS 接続をフィルタリングã™ã‚‹ãƒ•ã‚¡ã‚¤ã‚¢ã‚¦ã‚©ãƒ¼ãƒ«ãªã©ã€ä»–ã®æ‰‹æ®µã§é®æ–­ã•ã‚Œã‚‹å¯èƒ½" +"性ãŒã‚ã‚Šã¾ã™ã€‚" #. Type: boolean #. Description @@ -230,3 +234,5 @@ "This feature is usually disabled for security reasons; enable it only for " "trusted LAN environments." msgstr "" +"ã“ã®æ©Ÿèƒ½ã¯ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ä¸Šã®ç†ç”±ã‹ã‚‰é€šå¸¸ã¯ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚ä¿¡é ¼ã§ãã‚‹ " +"LAN 環境ã®å ´åˆã«ã®ã¿ã€æ©Ÿèƒ½ã‚’有効ã«ã—ã¾ã™ã€‚" diff -Nru apt-cacher-ng-0.9.1/debian/po/pt.po apt-cacher-ng-3.3.1/debian/po/pt.po --- apt-cacher-ng-0.9.1/debian/po/pt.po 2016-04-05 19:40:01.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/po/pt.po 2020-01-19 20:24:09.000000000 +0000 @@ -1,20 +1,21 @@ # Portuguese translation or apt-cacher-ng debconf messages # Copyright (C) 2009, The apt-cacher-ng's authors # This file is distributed under the same license as the apt-cacher-ng package. -# Pedro Ribeiro . +# 2017, Pedro Ribeiro . # msgid "" msgstr "" -"Project-Id-Version: apt-cacher-ng_0.4-2\n" +"Project-Id-Version: apt-cacher-ng_3-5\n" "Report-Msgid-Bugs-To: apt-cacher-ng@packages.debian.org\n" "POT-Creation-Date: 2015-03-17 19:19+0100\n" -"PO-Revision-Date: 2014-02-12 22:00+0000\n" -"Last-Translator: Pedro Ribeiro\n" -"Language-Team: Portuguese\n" -"Language: \n" +"PO-Revision-Date: 2017-09-07 22:09+0100\n" +"Last-Translator: Pedro Ribeiro \n" +"Language-Team: Portuguese \n" +"Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #. Type: select #. Choices @@ -50,11 +51,12 @@ "URL remapping can be set up automatically, using a configuration based on " "the current state of /etc/apt/sources.list." msgstr "" -"O Apt-Cacher NG pode fazer o download de pacotes de repositórios além dos " -"pedidos pelos clientes. Isto permite fazer a cache de conteúdos mais " -"eficientemente e facilita a mudança posterior de mirror por parte de um " -"administrador. O mapeamento de URL pode ser configurado automaticamente, " -"através duma configuração baseada no estado actual do /etc/apt/sources.list." +"O Apt-Cacher NG pode fazer o download de pacotes a partir de outros " +"repositórios além dos pedidos pelos clientes. Isto permite fazer a cache de " +"conteúdos mais eficientemente e facilita a mudança posterior de mirror por " +"parte de um administrador. O mapeamento de URL pode ser configurado " +"automaticamente, através duma configuração baseada no estado actual do /etc/" +"apt/sources.list." #. Type: select #. Description @@ -104,7 +106,8 @@ msgstr "" "Cada entrada tem que ser um endereço IP ou nome de máquina associado com uma " "interface de rede local. Endereços genéricos específicos de protocolo são " -"também suportados, como por exemplo 0.0.0.0 para interfaces com IPv4." +"também suportados, como por exemplo 0.0.0.0 para escutar em todas as " +"interfaces com IPv4." #. Type: string #. Description @@ -180,8 +183,7 @@ "remains unchanged or is set to the default of /var/cache/apt-cacher-ng." msgstr "" "Se este campo for deixado em branco, o valor configurado actualmente " -"permanece inalterado ou conforme o que estiver definido em /var/cache/apt-" -"cacher-ng." +"permanece inalterado ou é definido para /var/cache/apt-cacher-ng." #. Type: string #. Description @@ -219,7 +221,7 @@ #. Description #: ../apt-cacher-ng.templates:7001 msgid "Allow HTTP tunnels through Apt-Cacher NG?" -msgstr "" +msgstr "Permitir túneis HTTP para o Apt-Cacher NG?" #. Type: boolean #. Description @@ -229,6 +231,9 @@ "can be used to access remote servers that might otherwise be blocked by (for " "instance) a firewall filtering HTTPS connections." msgstr "" +"O Apt-Cacher NG pode ser configurado para permitir a criação de túneis HTTP, " +"que podem ser usados para aceder a servidores remotos que seriam bloqueados " +"por firewalls que filtrem ligações HTTPS, por exemplo." #. Type: boolean #. Description @@ -237,6 +242,8 @@ "This feature is usually disabled for security reasons; enable it only for " "trusted LAN environments." msgstr "" +"Esta funcionalidade está normalmente desabilitada por razões de segurança; " +"active-a apenas em ambientes LAN de confiança." #~ msgid "" #~ "This remapping of URLs can be configured now in an automated way based on " diff -Nru apt-cacher-ng-0.9.1/debian/README.Debian apt-cacher-ng-3.3.1/debian/README.Debian --- apt-cacher-ng-0.9.1/debian/README.Debian 2016-04-05 19:40:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/README.Debian 2020-01-19 20:24:09.000000000 +0000 @@ -28,6 +28,29 @@ access mode of /etc/apt-cacher-ng/security.conf is explicitly changed to restrict access to members of the apt-cacher-ng group. +CRON JOB PITFALLS +----------------- + +The current version of apt-cacher-ng requires the internal report +and administration page to be enabled and accessible for the daily cron job. +Therefore, wild west way of system administration (i.e. turning it off +ReportPage setting and also disabling TCP service for localhost) will make the +expiration tasks fail, either invisibly or visibly (complaining via cron mails +after a while). + +If the execution of cron job for expiration is really supposed to be disabled +without further complaints, one might create and set the NO_CRON_RUN variable +in /etc/default/apt-cacher-ng file. + +This constraint might change in future versions of apt-cacher-ng with a +dedicated admin control socket or some other channel for delicate communication. + +As of now, the best way to create obstacles for evil local users while keeping +the cron job execution alive is currently only working through obfuscation, +changing reportpage to something secret, optionally making the configuration +files not readable for local users, and also setting admin credentials (see +above). + REMOTE MIRROR CONFIGURATION --------------------------- diff -Nru apt-cacher-ng-0.9.1/debian/rules apt-cacher-ng-3.3.1/debian/rules --- apt-cacher-ng-0.9.1/debian/rules 2016-04-05 19:40:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/debian/rules 2020-01-19 20:24:09.000000000 +0000 @@ -11,11 +11,23 @@ CFLAGS += $(CPPFLAGS) CXXFLAGS += $(CPPFLAGS) +DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) + +# libatomic provides 8-bytes atomic operation for 32-bit MIPS +ifneq (,$(filter $(DEB_HOST_ARCH), mips mipsel)) + EXTRA_LIBS="-DEXTRA_LIBS_ACNG=-latomic" +endif + +# gold with --threads crashes there, maybe not enough stack size on those architectures +ifneq (,$(filter $(DEB_HOST_ARCH), mipsel mips64el)) + EXTRA_LIBS="-DUSE_GOLD_MT=off" +endif + %: dh $@ --parallel --with systemd override_dh_auto_configure: - dh_auto_configure -- -DSDINSTALL=on + dh_auto_configure -- -DSDINSTALL=on -DACNG_CACHE_DIR=/var/cache/apt-cacher-ng -DACNG_LOG_DIR=/var/log/apt-cacher-ng -DUSE_LTO=off $(EXTRA_LIBS) # needs extra build deps and internet -> ignore override_dh_auto_test: @@ -30,7 +42,7 @@ test -r debian/apt-cacher-ng/etc/apt-cacher-ng/backends_ubuntu.default || mv debian/apt-cacher-ng/usr/lib/apt-cacher-ng/backends_ubuntu.default debian/apt-cacher-ng/etc/apt-cacher-ng/ override_dh_installinit: - dh_installinit -- defaults 18 + dh_installinit --no-restart-on-upgrade --restart-after-upgrade -- defaults 18 override_dh_compress: dh_compress -X.pdf diff -Nru apt-cacher-ng-0.9.1/doc/apt-cacher-ng.pdf apt-cacher-ng-3.3.1/doc/apt-cacher-ng.pdf --- apt-cacher-ng-0.9.1/doc/apt-cacher-ng.pdf 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/apt-cacher-ng.pdf 2020-01-08 19:58:26.000000000 +0000 @@ -4,7 +4,7 @@ 1 0 obj << /Title (Apt-Cacher-NG User Manual) -/Producer (Halibut, version 1.1) +/Producer (Halibut, version 1.2) >> endobj 2 0 obj @@ -19,16 +19,17 @@ 3 0 obj << /Type /Outlines -/First 93 0 R -/Last 93 0 R +/First 91 0 R +/Last 91 0 R /Count 13 >> endobj 4 0 obj << /Type /Pages -/Count 35 +/Count 34 /Kids [ +49 0 R 50 0 R 51 0 R 52 0 R @@ -36,7 +37,6 @@ 54 0 R 55 0 R 56 0 R -57 0 R ] /Resources 5 0 R /MediaBox 14 0 R @@ -274,89 +274,86 @@ 15 0 obj << /Type /Page -/Parent 50 0 R -/Contents 58 0 R +/Parent 49 0 R +/Contents 57 0 R >> endobj 16 0 obj << /Type /Page -/Parent 50 0 R -/Contents 59 0 R +/Parent 49 0 R +/Contents 58 0 R /Annots [ <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> -<> ] @@ -365,12 +362,12 @@ 17 0 obj << /Type /Page -/Parent 50 0 R -/Contents 60 0 R +/Parent 49 0 R +/Contents 59 0 R /Annots [ <> +/Dest[31 0 R/XYZ null null null]>> <> @@ -379,7 +376,7 @@ /Dest[32 0 R/XYZ null null null]>> <> +/Dest[32 0 R/XYZ null null null]>> <> @@ -388,102 +385,102 @@ /Dest[34 0 R/XYZ null null null]>> <> +/Dest[34 0 R/XYZ null null null]>> <> <> +/Dest[36 0 R/XYZ null null null]>> <> +/Dest[37 0 R/XYZ null null null]>> <> +/Dest[38 0 R/XYZ null null null]>> <> +/Dest[38 0 R/XYZ null null null]>> <> <> +/Dest[39 0 R/XYZ null null null]>> <> +/Dest[39 0 R/XYZ null null null]>> <> +/Dest[39 0 R/XYZ null null null]>> <> <> +/Dest[40 0 R/XYZ null null null]>> <> +/Dest[40 0 R/XYZ null null null]>> <> +/Dest[40 0 R/XYZ null null null]>> <> +/Dest[41 0 R/XYZ null null null]>> <> +/Dest[41 0 R/XYZ null null null]>> <> +/Dest[43 0 R/XYZ null null null]>> <> +/Dest[43 0 R/XYZ null null null]>> <> +/Dest[43 0 R/XYZ null null null]>> <> +/Dest[44 0 R/XYZ null null null]>> <> +/Dest[44 0 R/XYZ null null null]>> <> +/Dest[44 0 R/XYZ null null null]>> <> +/Dest[45 0 R/XYZ null null null]>> <> +/Dest[45 0 R/XYZ null null null]>> ] >> endobj 18 0 obj << /Type /Page -/Parent 50 0 R -/Contents 61 0 R +/Parent 49 0 R +/Contents 60 0 R /Annots [ <> +/Dest[46 0 R/XYZ null null null]>> <> +/Dest[47 0 R/XYZ null null null]>> <> +/Dest[48 0 R/XYZ null null null]>> ] >> endobj 19 0 obj << /Type /Page -/Parent 51 0 R -/Contents 62 0 R +/Parent 50 0 R +/Contents 61 0 R /Annots [ <> endobj 22 0 obj << /Type /Page -/Parent 51 0 R -/Contents 65 0 R +/Parent 50 0 R +/Contents 64 0 R /Annots [ <> +/Dest[37 0 R/XYZ null null null]>> ] >> endobj 23 0 obj << /Type /Page -/Parent 52 0 R -/Contents 66 0 R +/Parent 51 0 R +/Contents 65 0 R /Annots [ <> ] >> @@ -537,11 +534,11 @@ 24 0 obj << /Type /Page -/Parent 52 0 R -/Contents 67 0 R +/Parent 51 0 R +/Contents 66 0 R /Annots [ <> ] >> @@ -549,11 +546,11 @@ 25 0 obj << /Type /Page -/Parent 52 0 R -/Contents 68 0 R +/Parent 51 0 R +/Contents 67 0 R /Annots [ <> ] >> @@ -561,27 +558,27 @@ 26 0 obj << /Type /Page -/Parent 52 0 R -/Contents 69 0 R -/Annots [ -<> -] +/Parent 51 0 R +/Contents 68 0 R >> endobj 27 0 obj << /Type /Page /Parent 52 0 R -/Contents 70 0 R +/Contents 69 0 R +/Annots [ +<> +] >> endobj 28 0 obj << /Type /Page -/Parent 53 0 R -/Contents 71 0 R +/Parent 52 0 R +/Contents 70 0 R /Annots [ <> <> +/Dest[40 0 R/XYZ null null null]>> ] >> endobj 29 0 obj << /Type /Page -/Parent 53 0 R -/Contents 72 0 R +/Parent 52 0 R +/Contents 71 0 R >> endobj 30 0 obj << /Type /Page -/Parent 53 0 R -/Contents 73 0 R +/Parent 52 0 R +/Contents 72 0 R >> endobj 31 0 obj << /Type /Page -/Parent 53 0 R -/Contents 74 0 R +/Parent 52 0 R +/Contents 73 0 R >> endobj 32 0 obj << /Type /Page -/Parent 54 0 R -/Contents 75 0 R +/Parent 53 0 R +/Contents 74 0 R >> endobj 33 0 obj << /Type /Page -/Parent 54 0 R -/Contents 76 0 R +/Parent 53 0 R +/Contents 75 0 R >> endobj 34 0 obj << /Type /Page -/Parent 54 0 R -/Contents 77 0 R +/Parent 53 0 R +/Contents 76 0 R >> endobj 35 0 obj << /Type /Page -/Parent 54 0 R -/Contents 78 0 R -/Annots [ -<> -] +/Parent 53 0 R +/Contents 77 0 R >> endobj 36 0 obj << /Type /Page -/Parent 55 0 R -/Contents 79 0 R +/Parent 54 0 R +/Contents 78 0 R /Annots [ <> ] >> @@ -664,39 +656,39 @@ 37 0 obj << /Type /Page -/Parent 55 0 R -/Contents 80 0 R +/Parent 54 0 R +/Contents 79 0 R /Annots [ <> +/Rect[316.741 339.362 398.4 351.362]/Border[0 0 0] +/A<>>> +<> ] >> endobj 38 0 obj << /Type /Page -/Parent 55 0 R -/Contents 81 0 R +/Parent 54 0 R +/Contents 80 0 R /Annots [ <>>> -<> +/Rect[465.091 632 519.004 644]/Border[0 0 0] +/Dest[21 0 R/XYZ null null null]>> ] >> endobj 39 0 obj << /Type /Page -/Parent 55 0 R -/Contents 82 0 R +/Parent 54 0 R +/Contents 81 0 R /Annots [ <> +/Rect[222.156 429 274.152 441]/Border[0 0 0] +/Dest[39 0 R/XYZ null null null]>> ] >> endobj @@ -704,50 +696,48 @@ << /Type /Page /Parent 55 0 R -/Contents 83 0 R +/Contents 82 0 R /Annots [ <> +/Rect[348.85 657.028 409.988 669.028]/Border[0 0 0] +/Dest[26 0 R/XYZ null null null]>> ] >> endobj 41 0 obj << /Type /Page -/Parent 56 0 R -/Contents 84 0 R -/Annots [ -<> -] +/Parent 55 0 R +/Contents 83 0 R >> endobj 42 0 obj << /Type /Page -/Parent 56 0 R -/Contents 85 0 R +/Parent 55 0 R +/Contents 84 0 R /Annots [ <>>> <> +<> ] >> endobj 43 0 obj << /Type /Page -/Parent 56 0 R -/Contents 86 0 R +/Parent 55 0 R +/Contents 85 0 R /Annots [ <> +/Rect[451.715 502.244 504.859 514.244]/Border[0 0 0] +/Dest[45 0 R/XYZ null null null]>> ] >> endobj @@ -755,38 +745,26 @@ << /Type /Page /Parent 56 0 R -/Contents 87 0 R -/Annots [ -<> -] +/Contents 86 0 R >> endobj 45 0 obj << /Type /Page -/Parent 57 0 R -/Contents 88 0 R ->> -endobj -46 0 obj -<< -/Type /Page -/Parent 57 0 R -/Contents 89 0 R +/Parent 56 0 R +/Contents 87 0 R /Annots [ <> +/Dest[43 0 R/XYZ null null null]>> ] >> endobj -47 0 obj +46 0 obj << /Type /Page -/Parent 57 0 R -/Contents 90 0 R +/Parent 56 0 R +/Contents 88 0 R /Annots [ <> endobj -48 0 obj +47 0 obj << /Type /Page -/Parent 57 0 R -/Contents 91 0 R +/Parent 56 0 R +/Contents 89 0 R /Annots [ <> +/Dest[37 0 R/XYZ null null null]>> ] >> endobj -49 0 obj +48 0 obj << /Type /Page -/Parent 57 0 R -/Contents 92 0 R +/Parent 56 0 R +/Contents 90 0 R /Annots [ <>>> -<>>> ] >> endobj -50 0 obj +49 0 obj << /Type /Pages /Parent 4 0 R @@ -843,7 +818,7 @@ ] >> endobj -51 0 obj +50 0 obj << /Type /Pages /Parent 4 0 R @@ -856,26 +831,26 @@ ] >> endobj -52 0 obj +51 0 obj << /Type /Pages /Parent 4 0 R -/Count 5 +/Count 4 /Kids [ 23 0 R 24 0 R 25 0 R 26 0 R -27 0 R ] >> endobj -53 0 obj +52 0 obj << /Type /Pages /Parent 4 0 R -/Count 4 +/Count 5 /Kids [ +27 0 R 28 0 R 29 0 R 30 0 R @@ -883,7 +858,7 @@ ] >> endobj -54 0 obj +53 0 obj << /Type /Pages /Parent 4 0 R @@ -896,48 +871,47 @@ ] >> endobj -55 0 obj +54 0 obj << /Type /Pages /Parent 4 0 R -/Count 5 +/Count 4 /Kids [ 36 0 R 37 0 R 38 0 R 39 0 R -40 0 R ] >> endobj -56 0 obj +55 0 obj << /Type /Pages /Parent 4 0 R /Count 4 /Kids [ +40 0 R 41 0 R 42 0 R 43 0 R -44 0 R ] >> endobj -57 0 obj +56 0 obj << /Type /Pages /Parent 4 0 R /Count 5 /Kids [ +44 0 R 45 0 R 46 0 R 47 0 R 48 0 R -49 0 R ] >> endobj -58 0 obj +57 0 obj << /Filter/FlateDecode /Length 435 @@ -947,43 +921,42 @@ 'X¶ƒLC~ÐÇs›0úQŒ§´Öž‰”BâÛ KÄîž¾Hõ諲XÒ©û%?+0 dMI’=Y.É(á÷ë,Ëz®›0c5î{˜gïnosX¹_pU{ÅY”׋ª8ªƒ^ð_kSÔ‹vËêÒ1‘Ó«=9UêrÎïM_­¹Ý}1¶»õÞ<‹{†·ÐêtÉSZšÐz³GݺÖ8³.jeMhBŒ+ï†úÆxÛ q/ŒçTû¡L…ÁìO:Æ£"ø$åwÆ9§ëq!â,²Žš¦ëœ6Ê¢?C"ùÅ”zªÏb÷‹Ñ½ÓY5¢wŽŽOãÃ@·á;ZiÕv~Ù œà¢Y§ã·µwÝ¡žC=óyý§3,ùGòÂÙŸbÃW³ÊàÂyøMIËÆ€-Üs“Ì8$‚.LÒãÎøï§AŸà6$B¬s’äœã@”3ù{õ,ÿlÕé¯ endstream endobj -59 0 obj +58 0 obj << /Filter/FlateDecode -/Length 836 +/Length 795 >> stream xœÝ˜Ír›0…÷y --aaŠ$ÄOw‰“Τ“™vlÒ.Ú.0ÈŽG0âäí{…ˆÄNÓEœñ wáÏçèÜ+ù>u¨O‘Ç0¢Hq´<:‰>,}D\/F.|0Ò¥AДÆ7Èšæ²â²*íø7CÑÅ.šÐÈ!4Bq†~XÓ«¤¨¸²'„¹¶­È¶Îe¥ò¬N+‘K{‚}L,ÇžPp@—ŸF©Åì_ñç# &ÄqÃp51Ô³ZJ!W漞ØVš¤WPE\ ¾èW˜†ÞÈyýï.•©á=IJ‘š'à”ŸÄëZ%­æŒ„#åà .ñúú¢ck;眫[3ëÿ)¬Eã†ÝÉ<Ø “yº°ð÷áïq'C{žöŒ§³[›0+‘)ÏÌ‹¿«þ £¾[Q½Ž¿Ù˜DVž& Hõ:Q÷ðë£ÑÒ?Ã2Úëz¨š–R?Yss_ݼÔK™±CDîÉMä/òRT¹¬éI²õôåìÂÜÜ$EÑ´,ºoibL* »;Óx‹µõòw%ªm¯qà€ë8Žy>]£Ñk“àgõÙs^ðT$ëÖ„J¤×C±’,Ö\>ɼ2N%Ñ+#“£^øLŽ2“£sžÖ ‘BèëüÎÿÊîíŒWÖ±äqšò²Ü&àV°Å½¹ž5WSµZÚ¤M!}°ÇÂÑ¢”u»—s#ª+s·‹J -->Ï迱'%})¢¼‚Š©ŒpÈÉöK齘³¨’ź ùcgìiÉÆØa¡)‡ÖŠ·#m‘«ª34áƒÐÈw,»ÑŸk}ǧ¢„Þbæ¾Çù§Ô½Gÿí.NH¨2»v­7#oËçïŒ\¿¹§|!9n ¦¬j}ô0vQ´ƒÅêwr÷KÁåür~¦§™ð06`/Bíéjò÷Ïr•9§¹ÒM’‘w„ÜS·b•¶‰{!d}§EöÉû!î‰l‚yž×*å˼ævC"”ÊÛì‚»ÑSR®®›F²'«oö÷«]¶¦“Òƒ2ó7دiÐà^ˆQ=œœp}lrWˆÇc2"/LƒCo8ý΄1œ†ŸÅ?„Êi +-aaŠ$„¡»ÄIgÒÉL;6imdG#1âúí{…ˆ‹ò·h‚3^€áŽ‡ÏçèÜ+Æ…,ò‰QÀ0¢Hs´8:IŽ>,BD|”,F>|02¥cÒ”&7È™(YqY•nòŠ¡€˜bìùðSIŽ~8“«´¨¸vG„ùvÈuÎe¥U^g•PÒáÇsGc(8 CD©G)u˜û+ù|Ô„xã°šXèi-¥K{ n\'K³+¨"¾_Ì-L£`à¸áS¸Ô➤¥ÈìðÉOàe­ÓVqF¢bîÑŽZìà¡ç/æŒë[3çŽþ>«ÇÃfíEö{ˆICÎo]ÂœTf<·7žÖ>‡`ŒûLtLüÍÅ$vT–ÎMÕ«ToàáãÁfÑ‹Ù[7³¸ËÞÚy_4£¤¹²âö¼Ú¼4똱DÞQ›6ÄS^¨RTJ ÃÕt#Ù:úrzaOnÒ¢hšŽü·´0¦ ”ƒý‡=ÜãïZTÛ&;å€Õó<{!»¿@ã×Á©³uå¬à™HW­µÈ®÷¥JóP•¼+’ª²6%ñ+¡Aôp„2¡3žÕ Bèë<æEú\É:~<Î2^–[÷ÁØÛÊ5ßØãùW{0Jë…‹AØ ‚,§ßƒIÇ\‹êÊž­Ä|­ÓÂHφ3î?ƒ>—PH^ÁâÄÔ†o“õµCË<›³¨Òùª ‡gÜ‘’5ˆ‰Á*Ó.Žœ%oÙBéªÓú›à‚hà»”~òG‡ÙÐ&ñ©(¡«ØqïßØSš®cþ€vã&$TÙmºQ›‘·Å ûÒ6ì¤í)Ÿ‹TîÏ4–RVµyÕ0tI÷`ýV¹_ +.g—³33ÄD‡±çz1©ÞO> stream -xœÝ™Ks£FÇïþ¡*Âóॽ¤œu{c—˜$‡8‡ŒäÉCñ°w÷Ó§‡°¤­SeÙrÊ! äùñïþw÷ðC|t¼D&V¼´°…à[!±B?²âÜúË~ÇʆWÎŒøÈûåØ—L /X‘pg†éÛ®3 áû·ð‚)¥.¥6Žœ¿ãGijf„¸¦Vœ/ ºŽ8ß³äŽkò$ã¬hK¸<ðþ¸Þî} œ,ÓÔÜÁ¾ý©k„,àÇ<ä8 šæ#ßIÛÈœ5<5ÂŽiì‘C "è[D´#úÅ!¾Íy)Š•ɯnôñ½’W5èWëOärKÜþV”,ùÈVæfÜg.ÁÁ—]­ -ßPau&ϬgaÎ>:XuÝ»…0€©>·È$3ü5¯DŸ Ku «»†½€ìY·mÒ`š4š&í Œ:>u+m"ïeKíâ†ûÌw Â,¦ŠÊ -ºtþtR#9k˜jÐ!èˆÑ4¥îV»â™´=g"óú%ùà¡æ›¡‹bË¡éZÉ!•e‘‰‚¯Äž{{ÑíÎt¬¼Øä€ÿüÙäVÉ¡¼!yÔ±ÒI–ðmé®õkYÉF&2ëÂG{'ÜAE¦åaÊ6¿Q$ίï=}t»v¨’¯Ž x˜KJY×b‘u -‘€¾ î[~ïÞôÜöOFµÑÜÉÖ8JÝÈjˆ)–eë9ÕýÀƒè¶H¼poŽ2ÁµaX÷.W¥›ú±ªæ¹€2Íô8,’ Ñ :Žè u9P´C(mœ¨Ñ3]Šª2Š`‚ÑË,øyywÏs=7Æjl¬d RßIÙhâyôFP)çk“â)׃þj¥ÙPø¦æÃÜh [{ëu%AÓüV[7i¼4Å å™PÖkFÈÁxR¦ê¹qÝÇ}z¯ŠG×ñè^¥Û–6c&º··;WMÖ÷zÀÒ6Ê`ܘ- »ëúiò,›TO+ä ˜‰Gj›¦|¨î²¹(ÔFÜwúƒL® -½è®þ™–Œ+ãÒ‘¿7„àëž_· "« ž>òÕ®ëöõ5­9/‡Y_Äðìà9£jP° ¤Î;^Ró4#ð]„ãùÕµ#‰ë½“7d;Ñšá|<ûùäRO¸­•–E—ž‚LÆe$ZFŒ`K`GÜÄg[³Mƒ‚øž8:¡Tr$\tŽ¼&ðV5P=é‹Q7Ò¸ŠÔ•D|7I +)•÷ fh„Î'&¾”Ê°ÃÀß ”?(¨S!ÊÝfæô“ƒeTW nS=¶È5ü5«x Ky ­•‘c¸Ï¬ÛHÃqÒÎeåù‰CýÇÉ–TgW&žyñ,µ‰ÈËæ›Ä ÷‰v BC"“Ë +JUöxR#9m¨¬Ð!è8‡Ô›*è’¶ÃLDžCÍ`0 ÔüÒWtÙ+ÑG²(2^°ïUGþN0Žƒ‘i–!fŠM˜Àa%K¸tˆä^ÍJ‡Z¶œëcY‰F$"S‹GÏ Ò.*<®•æù/©âl~KôÙõØm ¿<¿ƒbn)E]óE¦„rï¥uõò{7ñ¦k’à±6ªÝñæF´ÆWêFTýÒ¢Y¶Yêî¸Ú- á³ùÊ׆…`]Á\–²ƒè:Œšå’5Õ!OFD3è8ò^¨ÖéÂB‘µÊºjxÇtÁ«Ê(‚]Œ^fÂûåÝÝBÍt ˪-DH}#D£‰gÑ[A 6M³µ¦é„éžwµÒl(|S­ÒNn4„­­g^ Ð4§ÕÖ¥+M2HYÆ¥õšÝÞxR*³ºqÝû- 7$¯Šç­ãyx•.^ÚŒšÕ½½ó¦\5Yßö7JÛ2ƒqcº€OUÕî^ök<4®@0}6Ô6MYŸÝ!ds^È=©ïô™XõzÒ*ÿ™ÂŒIãÒm‘ÿlþÁÃÊ_— <«ïž>ó‘§O¦Ói—ÿhÓšq9tüº-†{\U»€‚M 9îxé™W?EˆÀÛ uƒîSW¬1£º¾7íÇ,+ƾv¥T#ÅÃGÔÝ}œù®»O\¬ÓÆÑ” A‡TMÏ&+ŽžÂ¹±QUmÙo /¾òÒí|Euz¡-™­G6ÅÖăé§HüÏÑñ7e ºÏ endstream endobj -61 0 obj +60 0 obj << /Filter/FlateDecode -/Length 292 +/Length 293 >> stream -xœÝ’1OÃ0…÷þ -«Óy°‰Ï±›t£ 00xC &qÛ 6AŽ«ŠÏQ·* ¨ÊwÎ=¿wY¸Éͪ` -™[1Å -z«-›™Š¹{†šƒäPq`žâ𺠻9q÷dÓ'›5±$§kÉàß“àÐøf"‰~}ê>©­¬ðÜÃj?†‘ ´•ÔZC.zL>¦KyèÒæRMoÛ6†ñ›ÕocðíÇqœPeQ–L('u=ušhÜ” …Z—˜ÑÉ•¼e@9€Ö9Úˆ@ÌðË m%Äœ€*8Ìi›ýÀÑÀáÌb¿³ò}›Åc·ë’OÝÐÓ…3óðÊ#^ñœÊpË¡O¾¡¿GÕå_^û׸戋ˆÒ0aÑ|1CÉÝÛäÎ}˜àË +xœÝ’1Oó0†÷þ +«“=ØøÎqšt£ 00xûô ¦qÛ 6AŽ«ŠÏ· + eÈ{ν:?ïeåf7[Í™Û2`š`uɶbîÈþñZp%x%8ü)öχp\Šÿîžlæb+­B,Èé2ø×$ßøÍ>DÝîÒ}R—ªÂks ÛÓ!±¬”1†§~ÒCò1Må¹Mû©šß6M Ã'«?Äà›·qœ„•. +&ÁäImGVs7ÐqÉü‘P”7˜ HÄ ¿ÞÓVBÌ €|IÛ|èz–Ÿ/Á¬N»!+ß5Y<¶Ç6ùÔö}\Ø߀gF<ýd¸uß%¿¡¿êâ'¯ýmÜbÄEDe™,Ñ~0óB¸—Ù{•ÏËŠ endstream endobj -62 0 obj +61 0 obj << /Filter/FlateDecode /Length 1717 @@ -999,7 +972,7 @@ ŽQ˜šoå«1ð¹®ö=d°ÁG'ýô?ׂŒ„nŽ¿\Ò„Ñ!Ïa‚‹ív4¬oqHÿåø/ »ûÊ endstream endobj -63 0 obj +62 0 obj << /Filter/FlateDecode /Length 605 @@ -1009,7 +982,7 @@ 6߶[Ž5Ø’')+öïG‰vl·r°E>ò‘TvŒEF²A©7[àÄŒªçHC¹]¥ºRááMc¼qjÊ…+ïæÜzVx%.¼­€^ ûZ’TVÖâŽXlϨù¡Iç—†#¦_´qÇlŸçäIñ šªêÇ$*­ßå´OQ’Ó°•‡tš³ò¼]()TÒŽ·¸W×.,ÂùŒƒÑieÄÐÄz¶à,n¦€ÕçᙌØÊó2‰Z°tÂá×µ» ªµXÐ(í^w†íÃAúØåPÿêiMßQÛâÅÿ;ŽÆñÆ %ÎaÇd»žcl›“MÆB-´ð·ËU endstream endobj -64 0 obj +63 0 obj << /Filter/FlateDecode /Length 1961 @@ -1022,7 +995,7 @@ hG2ÖYn†v¯dÜPßy¦ôIËƦVËVâÑEc`3·^.õÓ7ÁjhYÞ…q ­™‘ýf“C™„µ¾È±„V¦„~<ý´‚§ endstream endobj -65 0 obj +64 0 obj << /Filter/FlateDecode /Length 717 @@ -1031,94 +1004,99 @@ xœmU;oÛ0Þó+4R@¬èaÇj;µH—"íÐ(S–i›)E <ºIþ})¥£À€ÀïÞok®nöyR”I³OŠ$÷¿"Y—ÉzU'M—üaÍQ¤‹¢®³õŠíí„a'ÜÑìÞÞ®™bKj­Ñé2gÿÒbÅ„–B;Ò©[’”ç'®Ô[äkr Éz›rYN–;é½MR/i‘3cÿ~!Ñ£IKÏÃ#²Cp×éSóã*OE•4;Ÿ÷J¹\ŽQu½’6Ü‘×I+T°ì?\“T«0ïI°·æ`y³€Ћ6’pCáÓK¿¾ „sR(½#æ HOFööÖt3Ãe”OëC³\—€)ÓŽÕÌÒæy —%Væ§|EçŸêlžuõ¾Gˆ §7õybõ@nUdv›–9;9"h3ö"}.‘§³x€wqtS&G؃w×ฟÊÌKV묪*vg0ãCÿÚ°Ã9{‰ÐÔ»;³„¾þº#€ ÀŽsôb¥sBùñ÷=lÒØ×8~äkË·*rç;²ì^äˆUZWÃ,€°a>Ï´±¢øÜ p‹”µÄ5ëª:3à}h?ºØp$…°& ¤*ìŸØ-ÇÔ›ýü䤨|! ùyÕÐëfŠ2¦'ú<Ô‹ô)e/–—Y1^¢Ý˜`€¸SŒåoÌ<€p`Î*ô‘œã6-jviy=¶22„ (ºNÚMëx¾\¦‹Lã.ைQx|pƒ.³Éë ²Ã®heø¸¥«|ŠÈ¿žOàðµÒåRe“þt7 ¸§îááþ¦¹ BÜ®@Ú0™;æ±÷}t®➬Â9XÂ,ÉbD×"PÂúX,TõåqVŽ£ -בŒˆÔaeÔ©S–¥¬º¬˜ÿ/Äšì„ó,IY–Ù*Y¬–ëñ„ÖÃéüÞüÀÙðè +בŒˆÔaeÔ©S–¥¬¼¬˜ÿ/Äšì„ó,IY–Ù*Y¬–ëñ„ÖÃéüÞüÀœðç endstream endobj -66 0 obj +65 0 obj << /Filter/FlateDecode -/Length 2117 +/Length 2104 >> stream -xœ…ËŽã6ò>_aôe¤…­‘dËv÷žv& ‹ Ì8¹¤÷@K´ÍDµ"5=½_¿U¬")?zƒܬ«Èz±J›r¶^çÙr3[UÅl9äìðîãî݇ÃzVæ³ÝaVÌrø+fȹY!çî<û=ùt½•Cº(7Ûd•&Oé*Ofiò&-ªä[Zæ‰èjÙÃWä,òä›ßñIwÏåª8Žƒ°Jwé¿wÿr:‹5ê\,WY¹š-V o]Ìv (YšébSåÉoécžèZìQÏØ -’þÊbà¸%Ša)e™UùŠ¤ìNʤ‹åvmª¤öw`XuvÐÍXËÈbôYxϪӭ>¾ÜËIÕ§(!îì¤lðú~¯˱kä`¬è&ÔkÙ.—Éaìj4Šh•¥+å³E±ÌòŠM¡)˜¦ÊVÅ&,Ò¤õ .Æ ;þèpûÞøõ k}>ËΊPx(ZMÏäE+ë©{yЃôP­;«ºQuGyQödž£h *Žƒé=ð(fYºûãÝúÒ[@/Á³xüᣨÿLÁÉp‡'¢G§Á/¬Ä°ûn=Œ’[ÉÐv‰ÊŒ2Ö™8ЈWBZàˆ["ÃY ƒ<ôë—Ïf¤t%½ L­ -„ä9j8;3ÆCû–îÌSl/ýüå§OÛ²¶Š®[Áà‹³°´Æ€Ãÿ¢5šVfì{=XÙ<§a~5. i'£¾|¦Å Ï¢ï• ·[²#] @¹·Ä_<çú–Ÿ~K‹ò1Ñ-8°Ì×Y±Þ°C ºî -F‚ììŽÎa';;ÙÄuéSˆñFßЮ.¹½ôÓÅÈ¢²¿Ðp)Dœe»ðßû=Ÿ1ºVÂÊ ;—ÇAD xŽ%æNÀ¶Î  ˆRA £ÀžÆó¾ª%PaÅþË21±"Úû¢@”ËuöXL -„GØ“«{K*‚‘HFì Þ€C°ìNĆOÍ$ æ"ø`t«šbDÓLÎñÃ_ƒ*ôôÝjœc®Q½¥5¨SªIG<'™…6¦ª’ìøßy@g>b¦(S?§ cVÒ#;(=Fͱ*0‚û†Täì´ k3îÿ€ºϬ£WŽï†‡8P#nE †ß&xX¤€Ð©ùIñ¯ Ź{cB•Æ{ÿuÐ\w‹¢Z»VŸ[Œ»gÙ*a+/™#¤&bÜÉp=û!rÜ=ë<Òyp¦ã­P]o½R-ôi4ºat³"öä¡—ÿ ³ØwZþÌ ¸Nÿf^Ýå@,V"‚5H×PSS™†2ï«e,’&¬QAüøÒÃì®ižÜ®f¾ë…+?}7¥8Â<…Â餰ÿ–ÁpÍr¹¡d³ 'Ý]=&°nˆ®[¦e(¼ž÷æ(ÌHdÒõš¸GE6hs\dÒ‡@xàV {ܧ€¥èmGùp'lz¡p0|8É]l¹´ð@lùƒ§;ƒOu­Gˆ‡9YAfGþèòr’“执Õꪓë¡ò¸¡b‘k¨¯êþ™EÓJøve/j¬¶ÐÞ¿Ñ3—¡†º=Ë|Å_·ŒøÛ.ýôî ¥Aöô¹^(îôkvHù©ÔLˆÂQá0Q!†½‚¡4¬«døµ_¹ž -#Ëo0ãeßÿLæ>ºæ¹ûv:ÈÿŒ»MQñkbœ[é,~‡h&$² ‘TW·#}Äer‘KŸUˆZ;˜ùMÀ=rGàé·¥‘™â{ÄœA1R1ÐÝM·Y_ÃK÷Áô¿þ¸û¾-1· +xœ…]oã6ò}…‘—H[±$枺Û‡Ã(²n_.÷@K´ÅVu"µÙܯ¿¿œh¯àp†Ãr¾>´/»í>+‡Åf›/ÊÅÈ—O.»E±^œ.‹|±†¿|¤ûÜžºÅ¿’O 4ÓU±?$›4yL7ëd‘&?Ôi¾M¾¦Å:a}Åk"ø‚”ù:ùêN|’ýs±É¯ÓÈ´}úïÓ?Ð|‡BWå&+6‹Õf›mö€©A ÈÈÒ$OWûí:ù==®Y±3Ê™ZFÜ_-¸ol,—¢ÈŽùž¸œ¡ÒUyØeûmR¹7XXôz”õTñ@¢dÇ=´èe+¯¯÷Òˆª ÂÉžóŸïÎJ¿œúšJ³>Úm¬”CY&—©¯P)¬šž´^¬ò2[ z„¼¤« ê&ß'ð‚UšT¬jà!  úëßiî£ï•[¼’]Ç{s+Bá¥hßɱÚížùEŽÜA•ìµè'Ñ_æEèÆól¥§?>ìnÍû˜6“ß}dÕŸ)X^p÷^t4"ÜBsô»oÚÁȹå:”(L ¥Í¥‰µø†I áH èÄ8ÊÑA¿=}VKÏ¥„ ܵÂo$ÏABgô.Õ -]Üè'?Xåôü§Ÿ?ŠLÚ +z:U€1:¦i‡ÿY«$­Ô4 rÔ¼~N3Âü¦LÒI‹zúL‹‘wl„ñsš[!Š'$€‚¯Ä_¼ç +/ú=;ýžæÅ1‘- P®wY¾Û[ƒ(4ÝT@9³¿ƒy xïut/ˆëÂÅÅ+>~E½šèvÜ›› ‘Fùp#á– ë¸g»±‘ ÆçDd<{ X‡ó%„5½¶yR + u é n¬æÎüŒo£'"_aè5Kì¸f5Ó,?ÔLôþe…Í?´ ØõÝÍÔ\ªQr)ªDô´^ƒ÷²°/’ak¬±OFÆ]íºj™R…; æhDqoêˆu¥û,lœ£‰×Xb$eRkÛh÷^@~£8ó8ûêû€ù³—xç—ø·Z±qù+²"-šL°)M8‘ÓXÝ`žxË™âæ×Z\PÈ% Œ€¼Çá]Ð/çHèØëÙ‘»øwtJÉJ0Í#r› GPä5Äà9$™?€c½B;@¥”@W…n¦îÜ3Ñ(0Ó¢ÿe¢ˆ´ˆ +¿IE¹ÃC!E8„nLæ+)0òGÚRò¢_ðÖk½Ý°ØÛ[Û- êx§d+ê;"DÕD÷øñ§Æ®^Zz>„¯1Ú(åÒä‰U#§æÇ!ž“LC+³Ý&Ùõ¿KÎœËÄ(U=§Ƹ¤B; +9É!/X„íU,$e/µ_«éü¤þpg¤˜Œ<ëìBÍ Ø0*[ž ¶p¾SÙªâ + +9º)3>Qã»ÿÚkÞvŽ«|»3í +V\t›Êì¹°å·Äs3TßFVÎâ‹iåiõ=1Âî`vè\a„ûƒ‰X x·®…ZöŠ1îP˜<ÝúeDåG›øæhŸzgª‘S[ÏËru`N‹Èœš#‘2ï·kR³Þu‚3F +.£0çïìL „E¿Ib—ÒŽ9”ºõî£ vžOü?WúÐO_‹oØx†©!_[2ð»4°¶mU@tS eÉ<Сl¶ Ä º* ´>ÓuWE¾1·¼-Á|€Ò®…£ÉÚ3ôú´¬y+:¡ã Š¦©íæ ]ˆ(jè +š¦Þ…Nh¾†µ~l{ð‡«è¨‡šš_L&- ¹sÝ•¸®fÇ—ÀEÀО÷N=›vèýíÄ݆xå[ ‡$ÕYòa”בuaW¦º¡ÍÊ–˜Ù PN‘;B£AÂlCw± ˜œ~ù ªž…4‡T6Žé)EZ@éWàÖp®ƒPªe–ÀÕ2Ϫ=èǫ́ýwœœ¿¹i@L7ôçÙtÖnØ (¡aƒæж#³ŸÉinÛÆr„©¹ L3«ÙÆ-í¶Ž™ƒy4ØÂy®#¿ŠÙ».ÃþÈ/Fuö(æ\ä +–ïžMÜÉj‚‘Z³0*ùë3ÌÈßhù#Ì•£° ×SºÎħ»Û|´B˜_X Üt©TÔꧾô¶–˜b–nIƒï$Àl«Úú<£›Gs¡7£xŽä‹_¼¼wå1\B=úbsù[gÀ6e¹§pö# *Í[Ý&t± ÝÚoš”IKßü9ÚwW±„”B¢YD…3"ÑØFk¯‘¼ø;[ZpòxôXrßvâws~301‚…á‹ÖÚx— „IÌ"àƒ€¹ í< ùHQ¡ÓÍXTÔpÄtoub7|÷bYÏ&ᙜ +–°b—Ó·'“ØFIÄ€ðy@¿vf'ȸY±vhØ™kQ±6ð•cm’HL–#®€ÍÉ5È¡¨4K—d2‡ð³36½ÏÙè&Š11ì×fø£o!{Ûû¥;ÔÒ2ÔMˤÔ†9[À-ôè¹á».JâÌC\\ÊQÀ‡f'2VÜHö&Ï-­Í7ŸiÄŽ«üx4ƒX\Ö–´OåÖn“ÃNÅú°sŽ¨:ƒ·!AçÁv-ìÉÞÌèÈX,Ù5ƒ¯ +[ã ¨áS,ä5 ¾-ÇÙUUr‡X’xvµŸÃ^M!ö3e³JH>f˜g´iÔ%vWjQµ¾*êÛ/˜p¡$mçGèpá{6}ñ> stream -xœ}YYã¸~ß_Ñè—‘ݲ%Ù²= L.,‚YÌ:Ùé<ÐÝfFWtLOÿûÔÅC²w1ƒÕÁ"Y,~UEÿþôÝú²yHÒ‡Óå!yØÀŸäá˜?ìw‡‡Sýðï¨h›Q™fõœî6Q©FÅ_–Ó6Z>.üÿxÆ¥­ªv•î¢7Ó¼ZV_«qø¸úÏé/ßåÏ)ÌZÂ/é6]=' ¨ ¦î*´°ÙÆ0vÔ«d}™‘ä{ÔM*=873^½”—Ã’|þ«tºw‚ÊX-2(K¾3h¸¶SU:Yך&XÉØúe^ƒg5x{¥éu1¶ý{°Æ í?9<<';@œvˆ7‡,êu׆Æä»è‰8Pǯ±§¯ãØ}\¯/c—þžjâ¶_%‡èuÍäúñe ùä'á} -¿ž†ÑSèú€ %“Ò6~ª)ùˆËà[[¦5±‰$z†J W²ñŒn¸ -âkwØÄ9ÌùùÏ8¤éó -îË*»^ÄõÄŒ½+Ńœìvô‡ŸÌ¨?:…ß^ÛalT­÷ÁëÐÎDá羸Œé¯––Dþ¸9Ï5ÆÀÚýº½¬ý©®?À‘ìiô÷n4m£*¢èT0¸uUÒšÓHõÚ‹T5´Ìž]z>^DäŽW3xn¯kÕuxñUê¡è M êY¶wÈü¥ÊR>ÁFÝâü,€µæ\i/ýŠnP=Ùè ½DŸ*£†'K¥ £þ.û'¾¬ì0„;oÆb º‡ÝÀsª¶ý2uòm ¨)Ķ©±l÷÷ ÿç*IÜA;¹ä˜rðO]×bø#à áe°û-èÓ:¬€ǾN½Bo{Á›>{E÷ŒKUè'o -Ã0˜ÆÇ®å|C°* -S/»Žu[ÇÙ½oÝÞ¿¸àI§ -÷º?âé¹¹Mö,“M‹cŽùC[kÏ|`K¾woìµÖÍèÅìF’Ó¹9ÁlQ»èªVé&úJŪ°×y9*\úðæj"B´áÛ&š»iºà”ßâ[tÚî»B á¢ò-„_¥0†NæòÎ Œã ¶­½‚*ä -Z…·«)®^^ Z⬽'Dº9Å4Ò©ˆÖÔµM0aÛ4š&0º„µe~qÎÚ®KrÌÑÇ'ÊNB\´'B -¦ÂaS2òåöpä󪫎 HÆCM9Îjt¡Õ;øK|®a…ØÌmìU2h4…ŸÆ-vKnÛä€<%m­g¿!¨j š}ˆ­â‰KEϪC”vŠ«Y£c˜OxBÕAéÅJ&ÚEgDÅÉTp4µL$»´º2,XJp5úÞ”Ú)Ù;w`‹NX_iœ;¢ŸøªüÑô«Óƒ¶b·ó} -ŠA„ÀŠ åÅ×FZ L:Tþn¤ºY˜g‡[‚ÞJ”´êñ$C–­`,f­/ùC’ãòž D6Öy'ùë?ÛºÍPÓ±?È:áƒkhøk-¿í €^makÖ—¶¶q#Ÿ¥|”[4ƒùÉl7BýT¨A bj¶d˜àŒPs¢ -f ê 'oüwÛ—¦Q.JóÃéô£Ûõí·,ä¨Ip¥kP˜ánrØ2”À²ùú‚ÚYÛÜÞNýjÇà!Š?_1-å“- ãŠC$½þߤ1C<±ÐC¢Õ˜©—Üž6U«r6]9õÐvÝŽ7µ¨½ß‡³[ºó]rQ€…Š²L‰OõŒÖh‚mi@ú¦©10”¿ß¨pœ]Tz?ðδ¿d=F†Ížaœ³Œ\Å¥{¨!¨u¶”pÈ7cÈn˜ytϺѸóÂ`?ƒR*Îí¶B4Æ6>V¡Ÿ*;U8DÏ.SO9z‰Åó8Ãú ‹í>…åÖ™¿Ñ§ôÅ‘Ùž83A}åÕèX©Ó/¨±:Ç.þÓšRQ§d‡aæWä'ƒÃžŠ@è <^îc€“v¥HžÁ@:Cú´`b Oi†G† jÞ=}ð÷T¯ñ˜xT¸¯áRœgIÍwoeŸ~<Í·&w$äŒ „!OR,¦G*P궤›åæ²¾6B¼Böª"ì·òy•^r´FºM­g # -¡Ç+ÿ“@{&Оwñn—sJ‹þ¦ûWıyÒËâÞÐX㇤ÎÀ5;þ³–œ82³}Œ¤M¸º yÞnÃN†;†,ɸ£ nˆ}XûP+ø¢ BUÿÈf5©Ÿiº¦Æ›N‘¶ðNoLnï.¾/6ç*‚ØOAÕÑÍ&b…aO]G¶ÝÐ<á3Z-¸)P[@üŽL§Á½DúgKéhjè §\JúÒ!—Æq,v–k¡.hYÉȤAGuÖòêËŽ n²±´ÊöiÍëÇEh=¢>î´#i¶¡H¥‡Wù6MÑּɌ^¬$Õ ^…Ñ›¥àÂ/Ù%,0MI,¦³®‡‹ØßV¢!ùÓÒ½$¦á¦¢ i—c`<â|È,Øe ÐîöDNÈ%•ˆà‘qt’Ž5™ åŠ–Bî’EŠŒKÀ•oLTà<0ÓÞ_?Iˆ$´G‡—¯㥠lÁs FÄ_»'ÇäG?ÊÒ#åS‘ -þ[Šg ôoüªÈ¹Br?$jc`£šìÂœ';  S«Ú)ÝL{ÕÓíëÞíMË9€¡û/žCÁÁÁ ¬è\E -MÁÈWA„*0öHQdÆw/Æ·…Ç™qüÝcnafýþ´ò:)xìâVûÎS,‡I’Ó“üh ÔüŽ%9@Š«ÐçX›$‡øpØ ÖÎ~ßìosô¥#ŽÙ/å§äÓ[£P>S"ʶ™Kà_*˜lÝMç5¼·OßîN©0ÞŠ=„BZ$|f©:ʇˆœ}O•%Öá.—>y.×H'$:©¢²×’”ñ’eµ#B)mðå8œ”aÃÒ¾+@E—§Yˆ÷ìÏprýù»ø¸XÇéâTÂN-M°Ž).ü¿£íLy®-Þ/i'Ûè)>è:tD^"ö ‹l]Tciq9v¶~ñmצïuš‹—Mk~»|°Mí•Ä…^ÓMŒÒ"¯i—[¿I°4ä,$p¢e>äü¥œ¦6òqáÿ‡«0.MU5«d¿|¥U2«»åCÿ‘æÈë$á9`QÉjÇ ÒÛ[‹§˜€óaì@.ü60#΂ ˆÆ«®^ÊËa …Ÿ +ZÓ9AeU‹ Ê’ßÔ_›±*¬ml¬dhü2¯ÁsÞ{{%EÁñìÖx¹‹$qÚ1ÚNïG( +p ‰^"O=\‡¡ý¸Ù\†6* ü=Û¼Žšn—/&7Ï«`È'? ïSø·ï˜Rýw)J&G E±s|eª‰íR¢§¯òþJ6Öè†wâq½?n£ æüü§?“d½‚ƒû²ŠÁ®qD=2ã Ñ R<èÞÉîGøÙæ£SøíµéŽß}ð:´3Qøð©+®cú+†¥%‘?îÎsƒ1°qg¿i.ª›p$ûc²ü[‹w¡(: nS•´æ„áBEyÕ7Ì{DåãEDîpµ½ç®æm‹ovP¥é‹ÎÒÄ陿ò²”O°qk®Hkïí¹2^úÝwdƒ3ô¼üTÙ¼Tš(ãhõOpÙ¯8ñy¥ÃÈdތ٠t{#º!æTMóelå…Ø.ñ!–ºìôUǸƒfsñSÂÁ?¶mƒá =Âe°û•‚ôƒi*¹ƒ`¼š³'QLwÁ¸Ì óèMaÓøØUÎ÷QÑ«¢0õ²ëp«"uœî}çöþ=ÀO:V¸×ÓϮLî4]±L6-Œ9æ÷ÍÍx~Œ(ðä[ò)¿­`¯7S^Ìn$9'|Lµ_^óU²]~¥Œ¢*ìu^N.}xw5!š‘ðm»œºI’}tNûÀ}W4\T¶#ð«—7f`±ÍÍ+ä…\AUx½Úâê嘉q6^"ÝœbèTDkl›:˜°©kC“õžºsÈó²7r}zQ!‚¢…ï Ôtš¿ù£4PT=&rS²ónúá[aZ,Ù’=&ÀK‡ÛF"…j#‚…\<)~{tÚ·¦îÄž±Ae‘Ðù¹AO08#ä;U9ÿ} ´K§Nð§ë©óŒ„Ïò)ýÝ$˜eTW1&Aå[uníéW[UžBÔòÙÉ"+· Õر—é„\nª”n£°1O´ééþéàÐèdåmgoX+;ÆÖæùÅ9j¸.ñS†>>Qvâbòa$¤`:!ÖTù +G>¯¦j™@€d<4”ãT£ ­¾ƒ¿ÄçVÍLc¯zs$”Aƒ-ü„4n¶[rÛ6ä)á(hkû˜AUSÐìس°"u,*žT‡(ms®fYŒŽa>á U¥ç2Ñ~yFTm{“‰d—* Û!Â¥W£ëliœ’Ø™[tÂæKèܱü™¯Êm·:ý'è÷‡(;$ DHP¬Rž} i¥•À¤CåïVª›yyv¸%è‹’É;<É¥ŒbÖæ’-â —·~Š!²±FÈ‚< ÈGXÿYë6KMÇá(ë„®¡á#¬µü¶Sh\üeµƒ­©/µ¶q#ŸR¾ ÊÍÃ`~t'ÛP?y 15[2LpF(È9Q3õ…“×þ»éJ[ç.Jóãéô“Ž…^ôÛrÔÄG¸Ò7P˜àn|ÜI· … ]_P;ÍíÍØ­ö ¢øËÃQ)ŸlÒÚ«›pƒâ‘…Uc¢^r{ZWMÎsÔtåÔCÛôR1Û¦Þo‰ÃÉ-Ýû.¹¨,À EY¦Ä§F=£5Z`›¾i¬- åïW*\gg•Þ¼3ã/Y‡Ñ‡as`ç,#WqÉjj]…-%òí²kfžݳ© NPJŹN å + É°Úø¨B7V:U8ÄL.cG9zŽÅÓ8Ãú ‹Ý!åÖ™¿Ñ§ôÅ‘Ùž83A}åÕèX©Ó/¨V%Ç.þÓØ2§NI‡aæWä'ƒÃ‹@¿o¡<žïNÞ—hWPŠd) ¤3¤O%<¤$¨yóôÀßSðJUé¨p#^Ã¥8Ï’šï½•}úé4ÝšÜ H3‚†î´#Iʸô𚺇ãæÆ›LéÅJRMïU½YJ.ü’]ÂØ”äÀ‚~<+˜p=4[Äá¾ }éWC¦“ÄÔßµQt£!ír ô€Gœ™;¢ÌÚ}ÅžÈ ¹¤<2NÒò£&´\ÑrCþç•éo +ΕoLTð~ßfš÷ÁO" íÉ3=ô;C4w©à¿Rz.×HÇ$:iNe¯’”ñâyµ#B)mðå8œT~ÅÚw¨èò4 éWC´?ÁÉYlð4 üì@/ÆWjõ…’‚É3\ÛãYÜUIhVE‹€1kKWœfì{J¸”È“a±â˜6XMð÷ ‡³Æo?¿ñ[þ9,Û/à‘b$Þbˆüpú³Eû† endstream endobj -68 0 obj +67 0 obj << /Filter/FlateDecode -/Length 2537 +/Length 2608 >> stream -xœÙŽã¸ñ}¿ÂO‰ ´eëòÑû´‹ìb'H&ÁÄ‹}˜ Z¢ÛÌè -)MwÿýÖEQò¸1I0À4ë`‰ÅºéOßm.ÛEœ,N—E¼Ø¿x±Oûü°8Õ‹ËKkWëd·‹iºÔ«8_¾¨º«4#ñ~©ª*º)Móv<›þ¨›á¼J¶Ë¡é‡MÀÎ>1¸AMäý:n¸ÚX;Ýò뇿¸(ß]ÂÚêÒX]ô¦m¿q¡iû N—«žþüÝv±ŽÓh›f‹S wðii"_Hóh{H—ýÕOóe¯ì*>,ŸtÏ0œ„•q}à§V×]ÿúi%{½Öš'ÓÒ´ñbÛšÑEetÓÿQYýŸA˼tÚ@°ø–ÿŽg¿Wª^E¤ææ‹åAá$‰Ò,G…—t×:Ó·öõquú÷ÄAfl—?¬Öûô×S¨âªQ1í¸›àñF‡À…izmIé‘¥ͧ$‹µežç«)®¼,uQ)«]`%¹¢íF¡Î›YË4?˜uùWmáÞŸ6&>2Ó6Q»ƒ‚´u.äªÑ‹à8 ëÀ@¥øya?¡V® ÜhʺÀíC ª'P{ lª øpƒCV •×þ謯˜Ë gÖM³Ë—Þ v‹nä²Xgi§;°q6ßÏVÀ·Léÿxµ>äû(ÎÒåoÖôèûøK­º5°D#Š¶AC> Vѵòwü½ŽŸ™¸ÒoWº“(g7f`·ÛƒZ ïAÎÂXk@´ã<Ö…›­$ÀÄÅÊ C5å„?,§~ìyÅ4^ÞäXŵ›>˜ÔéY6U‹¶îÚ†íŸf y+ÓÏp·=^"büNƒÑìÉ·—;²‰ú«$_~ÁD­'pªØ`ž›3³§‹ •cÏ“/mUµ(ø9°ôW}/Y:#å!ß.ÝkÓ«—GÏ6K1ô=Š7žé>:·Izw>Ìí6:ßã\Æ.JÁµ¶ÓÇò0ßH"ÿ™ïßÞ~R’ç×»÷ù·÷þ­CÓ¨êçJ=Ýl_§q>÷ýºK£,ž{DZ×!ÄÙÞã•Gº×úÜV¦¸¿ÅÛRHîÚUàóÈÈ>(¸åe¨*9JΡrONN…ôŽ7 ð,fáªy¸cP] }=¯â-ø~é ®Ö‚_ÙgãÆ”y‰¥+pÖæéÚ{ÒYC\ŒPO‹B;gΕ(uÈi¨ž:BƒaªÀxëÚb( »ŠrÑáÂÖÜõV=¥@c˜pz«!:Z;cpº6„#FÓ×n¶;FYî3Ž?Ö̽røX2æðpX/|£â%`¸IõŸ´ÊT<÷ÆUÊ])†Eu’(ÐL¶6mXCååÇ£u 1Ûïæ–­Lmð.á©i/×)ÏQÜß2Šÿ#ÙÓ0š…$í’§üÂq£Ã´gWÙo[ø¹Ùn¨¹¥:ÃM@Ãäç¨ÇòL†Þ—Fê¤Á:9v7ô÷lÚ@C“Å1_M®òñ0üN†NcíÉ’°Â~™î=‚'’Õßž¼qaÙ‚Iøò2M0€•È<-…íáHt‚Û#q{ì™{ïîÄqe>ãhsëîI õÃ×Ê‹©ôã`+÷'j)"úð<µfÐfcr5ë5õ qB_§\k:—ñ6„g•'¡©°t° g$ÏÁ‚OžüA¡o=çÏw}Ó²ÄÓéèýyP_‡fêí¶¾Où8IäÒîSq࿵y!/¥DоY…ø™‡TÚ=¾ŽHZç§^¢r·_©Úö³§²ÑßxÍfM)ïy÷øuá¼ûÌq›"õzÐÇ(³]^ú.*uÄ­eÔÚ§ /™*i™T‡iÞÆÞ<ÑòkY–û9—?u{<¾¯=Š«ùAŸhWš©=©6oZ‡q·¤=ÓU†&´˜gåèiPX™@¡)aÖ1Uo!KÇÃ×˳<µ ‹×;1)1Í]¤?8v7BQn$ür:ý= ö¼øé\ÞobÂÃÇÔ1J¶èཡ -¤’Á\¡(á -O‡ã~¾,¡Ñá·ë)…qw+³îÆ_hÀ{}«Æ® ¸Ë+ù‰áAB‘~…áöz,'>ÞðÑY"Ÿgpe$ÊFƒ -„(Z:í]`Ú1z‘¹è‰Èÿ7$‡3þÌäC’’óy€»Œ*t0D~Ïbxáw‡(ÞGIºéÆ* Ó|ÑKÂÉlÃËÿ*F÷ã«êH”20Æ)ƒcœ2è#•¡ÛH !V÷ÔÂÝÆ*³Áƒ…5íàröCœà¼£ˆOþ­Ñ#ø DŒT~à¯Î]I|ŒàE4MÈí"»Ø ’I0ÑbM/ýj*z]bÐ]YêÆÖ=k8ñâú‹bWÃi™¬CÝ+…Î>1øÁLøý:PXåºnz)úÃY×`½ô®©•Þy%¨›^7è·ÌåóÂE¿nØ>ñy`33TÜÃMxQ:ß+=} ¶jû7´O:˜4ƒW"¡',èà¹k*祳5y(î:ûŸÁÊw:@0û†ÿŽw¿W˜ÞDb7±œ$Ë»ødÛÆ;4Úǹ骘ÕòÃòa—@;¹@¹pÛ§i?*qt\€÷ÛŽdI +Ïa̱ÓˆŸá²°yi:ë•|ääó¦™*žÏcöªÁ9VŸ&&2“6VÛT<剂€h®3Ù´-¼O!&BFØO°¥otúI@X¯Ôámˆ 6Õd‡a!™ZáªÁ¡W ‘ÂÕgV쇓F£ífl`{g(ïC–Fqº…7ÎÄžÙÈ)ý/öˆ«Yºø­s½“ÝÌ¥2íD4wÒ*&¨uüÊÄ’~»XíD6bÞl!ÆåÆ㻇-Ç +!¬,»>ãÜÓ…šI6 +”‡©‹ ½.§fhåe¿ÉµòKOz¯xQooÅ’¼©ZHôüi–±Ò5ÃætÛ£:ÀŸr£ ¯•;’‰øš[&ð¨$Ý +5Ç倗'T,»^@Ÿ›²lñ‹’„Üs%žw’6ë…«{óúȦ†>GÞ6f®]t8$’–4}D•ÏÝr½ŽöB÷8ç±R°¬Yî£ä9;¿O¢ð™ïß?~4DÎoOï6¿öo-¾Œ).ÍóÕq¨L6sÓç +f›FY<7ºc£Ã‡ú7èߪSSºüö‘ð”‚ò—f( ÝŸFB6aÅä`•ç¡,å*ö”[|6”Eo2Ïbfnêgt;Þš3¯—e¼Ó/ü½€±Ž³ê^œRdä%æ-¥¬Ü󥨓· !™æ¹õÞJ«(rÈm(™ú°…ê•JøŽe£×•ŠöõÚ°áʨïLÞSt0Õ•u¡4çhº·•ƒØY™ÊžRâòxâƒyFÜë±þâ&7ñ}ÇÑ80½p² xN/‚Dãð­Éo +)åÚ![€5ô¼¢¼qV€3)Ú[FLÊÜùîÎ ¦×åe¨Ù`ùQ¢*Óækœÿ‘Oæ”ôh!yéjãû·Û ûd¿£8lÏ·Îp9ÒÇ.Ú‰!‚`È‚;Y%ÃÊó+þ×KJîræš[¥®ÕƒAd!ã Te +Ý ­Iy'Ÿ+[p’rº²AÙ7DåÍœ;°âý3ɲ(!'#û£ aøÜ?@ñq¯[£ËY†˜d8Ùºaþ\+ î4¡3Þ7¹3lØ£úóÖG©d‘~2º%åOÜh`È[o´Q›ç¦)tGê¼*øbhf¤z3]~)]=¼‚âPð«¢dšTî¯#ûvڥžœ©Ë&!æiá’Êúo¸Õïˆp2$ÁööíÒdMßžV­g[4‰,3ŽÀ¯²c•ß;‚ø__m÷ö‡ëºâ=!@ì“8­LÒe«S¨7ûßË™ÚGí´P‰@¬=¤0¹1ëFÒ¦B 5µ×n¼Ýí»…û~ƒ…†|¯°>ï±VÆæÔ`¼æ:éó2R 6a=2¨¦N` ÉÜDµÿÃ'NRÉÁ»©5ïBA»#!Â18Ò p0båäDa‘[mýÈÍßð¢ÐeœCËX™|KjHá·S„y£ôÑö/M÷åè*Û ýu1–¿y’\RíÇ1Eá»â‚ÅIXž¬T•øÜ·;­Ÿ?6”6ã(D7Øc{ÝRåù¦{(”{ãêÙá)¹K”% Óä4eHŠ£ :mÄRÂp£A“2š¶ô§Ýôb½oÄ;xª†óLfðG/‡K°à‚%€•Ö„÷ÒWÜ÷ã_T.Ö:À/}ß>®V¼Ëõ d\áSJOº9K£ØÎVðŽ·¤˜µ˜húàèLßZÙöe›pµæ£*øX2†p½là &ŽNñª®QÃ';ãJîzâKãiV7Ò“‹É& HAGqBÙºÉѺÑ5$^=ijÝv®“ÒUu c¦¨SFQ\Þ2rÿ 9àЙ%ÕRÀüÂn3™#vËlÚz®u…RnaN  ¨—À<•Xˆ§¿#vRߌW\»nÖû Ô34Eä E£»ào +áî°¡Ë뀖x¥ç¥·M$Ëž1a9‚1øü¦i&xƒ‰ÈåÌ•ô¸^‰np}%®ŽqÝÝ -”î v6×æžÄ>Bª<»Ò>]éÿDEDžGÖ +ÀlŒ­®ö½¥r!NèëêaM÷ +ã˜à‡¤2@œÑ¥‡C<§gBpsô'ƒ¶õ¢Ž?u}U±ÄàÓéÜúYTœ Íă ¶Ô#O“@.Õ>åþ[¹W2ðB2›5Ð?sJ§g?Z „& ¼DᮿR6Í—€åG{üƒÑ±$å#¿M›“RI‡×Òž }\‚,ëŹo£ÂF\XFM÷¼â%c%*"‘éoÍ‹Øù]yR–mBËŒ‡ÜŽ³µGÅøŠGù„»PCP5Ô¨¨îÇÓ¡‹Dé˜ð½ÈFcA!Ñ;Žó0¡áòŽ‘cà9wŠô0l(U0#h* …[¡âÖp<Ïʵá¸bø—‘¹Ò`uíøÛ o¨ÓØ4`jéx%?.Ü‹#Òï/\Ü@%‚É$xΛÅÏx6ƒ+'>6>¨PP?ˆü  ÖÁ¦åb°¹‘þ|×!ßñGÑÌpŸ—‚?R`>  É¨DóBà÷ü'†Ùn¼ÝGðãb’®Ú¡¹‰°¹t_mÄœ°)[ñòÊA“øÁø/å Å1^æ§ã#¨¾Ò endstream endobj -69 0 obj +68 0 obj << /Filter/FlateDecode -/Length 3061 +/Length 3105 >> stream -xœZÝÛ6ï_±ÈKm`WkIþÚ}H{W\W´H]ÜCöh‰»V#K>QjêÿþæSC9Zà á|gșߌóýá›Ç—Õ]šÝ^îÒ»üIïvÙÝn³¿;œï>-†ã2[-†sÕ-7›ER‡þy¹|ÈW«dµÏUcãþäAi$C;t…I]…Þ¸ÏÙ:­}0†kJ#†à™H·»…+š×H/šóÃáW£.]û×u¹…3Þ‡º6¢óÿ|èãM»hŸÎ—Uç‹Þ—ËÿþùÍêî!Í“ÕÓÝ¡„ã÷íò!Û®y– Á]ÛvÐ1ØÁˆÇË`ïÓvWcµ/6í9šY·…«£]qªŸçß'?ÙÕõ_iG¢Ïh—Ùfñ¥¹7Ö®qe嚉R6Áe8ÖUº›Õ"øîÏeºYøŽiZþÇ•ÂiBï]™ÐJ/Û»tWëa'i¾½{ÈÖÉ“w½Ÿ-rú;[>ì7»$]ç‹ß.¾¨èì»ý¢ï`o¸ŸÓt_hP.Ó˜´¯ÚF•›¶‡»Å;ë¥7Î=Ñáäé<¥|Ñ”«°„¨Î—ÚŸ}Ó;Üdd—¾wUFúyqq]_\_mQfúëR;pC9ªºc‹|¶!=$á7åü'mƒOæuèø¾¾¡íâ‡Î×®WWÐÝ%æ¥ •Ü;rbßWÍ«LùrªŠ“NíPËä£çñø°¾®©ÇªŠª¯åÕÉ7M 'Èž’<Ç·ÑûŽ\¤œng¤= eõ^Úºæ;"•x‰ß?þˈè½ë]{~cfQWpÂHwh >Eô¹-+tÁlx8ÒSÞ&xCýÙ].`Xcu¬•ý#Zã3(v=,¡¿ÖÞØ·^:Þ “8Ãx€Ñ²¡*ý½‘UƒÁ'ð„¾à_îñÇ•q›SúÆÁ•œ ½vûd·‘9<Ðaø'‰ï‡~W¶Âè ¡]Q#f6p—ŒFרÃà™¥“ ŬºúŒ§ŒVˆ>u_‡Ú™úÞÜÃxÆÈ2g€!¿ó|Ez~=|˜|Jw’™FR½Jï^fôÄU£êãé ”9EóâY•ºHsr?+ÑC?&F~hJSw½ úS£…'|?w|ùÞÕA&TG¼ÆȠõ£P2;ó£—"b0M軡à$ýÕl½ -*ê ^Ò‹fqçÏøMŒ©S‚¢h@›|Ø)"øÞÍ,>œ¬dÛ”¡”Þ…fѺ…L4r9Ò¨¾3AŽ“ôÏ\Nÿ¢üÆ¥Õgò¸R§¾¿ØT»ñÏËÄ”äF¥â±˜›°–Fqmµ!÷Lƒ-wI4ß#æ«ÇñlàG?š¾ ›A‡!†`‚Q"Aq&Ï%“gO{À{€¨ð‹Ÿ}÷Šrø#Jö›,ÙïXáÓ‚‘ç¸^kûÔ>\¨šH£nýoÒd·ÛOmsãxHŠât¡[Þ?>"t5Ÿ¼a¡$IxÒÅõ§0I£š^~’èHn¨ûêR{ãÐ3z0º¨Œ|Ñf Tˆ áÜl›î7í¶bÛ†&æÝ¡Òh_ÂMãšÚ8OÞ¿±-\ºÞ"üˆ~e|lûSŸ0¡“ ²í*Ùîò© г_ø#¨tËt¿xõå¬)Á«µÙRJ  Ôš‚':¤ØļÆ÷”Ûîs¸76%RYäì®&8Fë5Þ—ñZ Ãx’oÀ+E¤Ì‚‚¤d™vgêѸM¼0g)ÂÂùéeºòÔÇ“7¾ø?ägÀý`±©—ŸÀâ›L½ÌøÂåfÍp.Øä½QmCX¨… ‡ºŒ° qv=½2Ú#ÚOà°Prçôx”©Ñlò‘t{ä(Ó¨®`ò›òlØW÷áh`H^¯·19^ t¼ŽÕñJãyu̸™âA1ôÑ$gÃp…@y6ºhÏg* l3¸=Ñ\8w1…Ü3·iá;¨Tf‹:)Á;)”€špŒùüæ è à”ĸœNæô-õ+ˆjBm¡ ÃšÃäpÑ"_* ã$Äõ‹òJ_Ø¡,?L*•ÓtüÐn;N_D:Óá΄ -)•JŒèñ&f®÷I¾ÚHÌ´¯$´ib‹ŸÙíŸp%¨ðuÁ˜ö vüµó¿_îUü7IrJs*ª*<,s,’};Œ;hm™(ƒ–}¼Yn¯-R¹yºyMÕ5šÝ¸YŸL¶—È~òØùAc 7 „`°ªÔp±Y¡÷q@Öùå¹j ×€á)™î£ˆ.sÏn¬,D†.¢¤/#T3™‰Ut;DU´e4µšHÈ]ó=*ngdùZœç‚ hk`ó¡„=57_(С|3ÎôAV´wªÂ²%”2,ŠFváª×†°Ü·H£„æÄU¦28d~‘„gœý54æΓ¤ÀÕâ7/XàâŠÏט(Ûbˆš8ØZé_9aD6°ë´S¢/†ÞFiO -v`ðQ:Š¼0°?D£/Ë"\÷Dy‘G´븦Å;ÿÍ–ÿeÈ ˜~fvÕÜ|_Û•²Ž¢°¹âçrña›‚é†UEåÑÂ@UÙ½IÌ° ÖFï õ6ƒû‡,×"SŽÞñܘ›ï#Ŧ4ÅÐFz§xuëm±æ1^1^ž-ûF]¤t¿³Æ€oŒwb•wÆ:{‡¾F*ÑW&v6„¬ÛQüÝi¥¡ZñþÑä¦m°|ì !JcYã…º;UMAIuñFè˜Í$ÚÑé-ôÉÜù?€vklL¾[¯Ö#ñ#U×BpTàñK;4廑„öÂì$l@«ãþ³ÆcéJUSØ–\´}kËA1!=rKûÞ¦©6¶ ? `ÈÙž€6U!Ÿy(×G£ä Ï,Fñ«±Ea¡Dë—F»µÜΧ¥]£Á«Ò:gL Üœ=9ŒƒV\»â:EÏnV}ÅÀL˜¢nO -meº¸XLPÇÀÃ=ó¹ÉF÷„)ºl—Ûõîápyø4;5íüi¹Ú&éf;ëÎÞ€>D@î‚o`¸¸ª2ðÜ\"ÞÚw_æébÖ´Ÿ£ªÒ×]`Äb—ÍÎn¾\Ìþœ§ëY4ùÏùr=smÙôÁ¿‘µ¯»Þp—²m›6bz™}9—ùÙ®Ö­ÊÐùÂv/ëù¿ÿfñð”fÉbÿp(@=ïKÏ×ëYR…îe>Ê 2ŒARÀ4€¡éÛ܇w1ìËr•V>ÂÕ…$_è¬yýñEsþv8üjеmþºÍ7p8Ã}@U(Ðú÷>tñ¦m´O닲õ9Š"¾~Ê÷ïÐfÅÓlÈ¢6¡c6ž¯½¼QÓÞ ÕœlØfªšÜUÑŽ.?—µO óϳí꺯¸£†è ZÔ—úÑP?¸Ú¥«§DpíU™ïz1 ¾eól¦eá/h®L V劄Vz>mÒ>´§U–¤Ùæ¬-Ù«q­æ ´YF¿—ó§Ý s•Í~»ú¼¤»ow³®…½Á?†É`hPà‹*Ê®lje®›Œ‹wÖ'>l¼´gO&°OíY ba%P^®•¿À#u¸Ë€.|çÊ* ðËìêÚŽ\ÝlQrúëZ9ÐC1°ºcƒx"=%Á×Åôò¦ÆGóÚ·|† 5W¤ˆ&Z_¹N•AÖKÈkJ±ú‹»^A´†j{X,1øG”ûF{šÏBw«¼¡ï?t¼“àFˆ²ð–]46¥À3¢èän~X·97¡«Xå”õ¡Ûî’íZæðX4@VÃPP2ß÷Ý0.m ‰ »<'MLlà®ì¨E‰©#GŨªüŒ·ŒVˆ‹¼¯}åŒ}pñîÀ^лL  ¤ï,[߇_ß÷éVÂÓªVééËŒŽ¹r”]<ýžÂ§p^] G«TqŽî âw%|¨ÇÄÀuaì®3Bw.ãk4ð†§®/ç]¬PhàfByD3F]®ˆÞ½!ƒhB×ö9Gê¯f«)(©—IOšÉ­¿€ó72†Oq‹Ânnt°s°ÝM]$Þ_0cYnR~”¤ô.4’V D£Ë®FùB¥Œå@˜ß0ja}!+tM5‹™'Æt 5*ÍÁü¿¶X“úF›GÅ÷Œ!ëy¸Û3èèÏÆ/YÍ K C0 +¥RBAq4Ï$š/÷;ˆ1;HÚጳŸ}ûŠ9üüõ2Ùm™á%¹ÑzíSùˆpƒlÕHê…pë§l&Ûín,›;ÅCX¥ÃÕòþùóWÓÉJ’„']]w“ô'ñŽ”ÖõUW^+ozFOWmOêÁ,1 ¨;7Ù¦»5„»Èö£å #ñn‘i/Wº&&n(ßØŒ®3?dÀ2>6Ý™!ªq ¢“ +–›E²Ùfc f%áCPªÒÎÓÝìÕ“¢üMk½¡˜.É6@+rž¨\'ÆEE[x44RYäânF8FëÕÞñZœˆñ$_ƒVòˆ™$טldÚž©GáÖñÂRó%†ùé4^y¬ãÑŸýˆùrØXË{øz©Zæ ÜåzÅù\°1ä’55åÀEi˜`ȡ˘36.®§WD{DûIF,ØüŒ"Õ›IÖ#W{uÍ&ß°”ß`î¿WAòzIñ + âu¬ŠWï«cÎœÉä}Mr6 7p”ƒóær¡ÚÀ6ë‰æ½kð)¤ž©MsßB±2Y7H‘ÚI¡ Ôð€cŒ' 7…_¥$†åp2Åo¡_1@”ÂhEVÆ —‹ùR¢&!®`Wø’ŠòÓ™IBårš§¡1$ÚMËá‹@g<ÜžPfJ…Cöxç3W»$[¬ÅgÚ))[½¨ú ·>Í’sÓPEKkSÈ£»9ÍÅáëj€Ð–N uTØû$…#dñfv»=®U¾ÁÓÂŽ¿¶þ÷룒ÿO‚œÂ\£ +«ó ëdßôÃZ]&Š eŸï–Ûi†XîÞ†nDZSvõf㕾˜åNûÙS#nÇ.ûp®ªPµYä w±?ÖùÅ¥¬!Ô€Ü)–î"‡.s/n(,„ú6‚¤5#P=š‰e47ö„œ7E4µQH[oô©¸£±ÌVrã,“ Šö4ßJÐcq³AÅ›a¦²¢½S% e@âh@ç®×9¡|­){‹8 +hOÜd*''B€Èï#á‰{~s÷IBàbö›—\àêòÏ×(š¼ú8”°5ÒÃr‚ˆdÉ®Ó^‰¾T²{x;KÛk²ƒÒVäý-" y(30-Êëö)ሖãô*®iqÅÖŸ|+KAª3`ú…Ñe}w¾¦-dͦŠŸëÕƒ‡­sr¤kfå,*ã®wOUÙ£Q%™a2 +¬¥\“­³ÜCÌ´Ã^Äõ©…16?FŒuaŒ¡‰øÎñêÖÝbÎc¼b¼˜FÇ +²¦áÃ0¢°*{cbäiËÄ&œå*&¨ò<õ +‰QòoJ0Þ»q¼DìÉûcÀÂtg¶áÒ•Ê„èk"0]¦êSÆߨèáVï@³o¢X*Mtm|¼2·ú’Ä•yM¶Á8ÀPý½ËËÖZ3\ Š¢èèIB㮆+|€(­Ô5tüA11Ê.²£7‚$YB‰rO¡Sã#²¦ÆHÚŠö7F´›hÎćý¥ábtIÿ™® útÊžÚá×X)rÁ¥ý>*ŽÎ…6ÿÛM÷=®l“©ÓûÁÚáèRà»Ç𮀳]ðFáî•ýðYø¨Ç%„;O&ؤðG:×0GòÄxçh3r$ÚÍÂCÄs.}ëZp<äRSˆ\ôLäˆâÛpÇfm7PnÍ•™âÚÔ/fKùh2ý³Çhåh¯¡S§RãÛÈ ï· ó`œÌG¡–ã^C† /ùªÀXÎýKïc+D +¿@”. #/Ð +¬É®‚m%3œ<'Á²U:þN­FŃtŸy7uw±Ò=dðü—d¾)Ùõÿþv”Í endstream endobj -70 0 obj +69 0 obj << /Filter/FlateDecode -/Length 792 +/Length 825 >> stream -xœ…UKoÛ8¾çWpoÒb­êaÙJ‚\6(Ð.ö”zO颠¤±Í†"’ŠëþúEQdƒE€h†ó̓ÃoÆnÞsR”äp$Éñ¯ û†ì높|.·ezøŠ ÊƒÄz’ŒJ~»>ÌÿõC­¡Š"kª[}N¥ÀHÅiR ÓMUÜf·Å>¡"’¹%¨aiY'¯iQ'Œs’ þ÷ôoP.gÖƒ*­«óWŠõq:s¶!Ë<9qÙRžþøçfã Ý•+uÉUÖy¢Á&NNaÂ}ç(Vè¤0`}3î@=‚i')¥fFªkº«“Ì>Ò%R k'À0š%µ‘îÛ3M[¾£Ò&MO¹+”[²)ËŸ½œË£ÃÈánƆg̽Oò7=´Xí92Ä¢òe`JIõgvúNîÝiK»½þ‚fF¹·OžûÎ%„¸ZäÃp V=CŸù±¦N>bÛª¢É¶ë¡R[æJ¯ºr¼vTrð²-+-ð²¡4o:I÷þ.ø…ñÞ[¨XEfRbÁÕÉ6ß‹¥Ð>¦ @੺â‹#Mlƒ×v<ۻ؇Þ5YUU mv®x³˜;,ˆõÔD ,—@Y& }ÔÒÖr‰+J·yòWpÆá‘ÿBÐÅxŠ ˆÌêf².ÌT@)è'ÑSÑÙók8·=zÓ‰”¡v~ª¢Ìêƒ -m(ç8íÒ5~96A}d²óàeÛ -/ÛVíÂÌ9hUðGP?É!r´ôâ‘n®#DùÐ5R8_ZÜÿ¾¢iý 6Ì„+›&Û#ùFãäÆ6·ˆ‘„:œ!Y˜ -ðVƒè 2Ë wg*N‘ù8èØ™¦¸ï^™TA£D¶ËŽKÎà Òü¢®A«Ïrâ}Ð¥à×  Ôà~siÃæ+vYnÈ-kT“¥4Ï*<™i·Aã Ã-=›”ä+¨wB5;ØE9Ž@u­BÄLrü"MåÔšãÄœá¸u3ÿfÞÝ6¼û´J.;åí•4(?cµ]éÖ\âLM6uYÏ‹°¨ì®{øs°õU +xœ…UMÛ6½çW07)ˆUQ²¼r‚½4(Ð9mÝÓ6XPÒÈf—"’ήûë;)‘Y( Øó8o>83ÿ|z÷ÓXZ‘ÓH()ñCÉñ@îš–œ&ò˜€|W5% +½åJzÐæY‘gtïѨ´°Œ SäßN¿¿ÛÑ–ì*t<ì¯j_姿1V½Æj1”SÍZ½Þî—o3CïY[F”m}ôÔÇ싒艞¯L¾«é±8Ò»ŒÉD´d–çU“}Ïi“AT.A"üóák/Þ_"TÎÔÛk͇4œ½8—U™…ê˜w ‰îhíS ±|å¬åòì\¼8¡WÒ‚ ôjýW7^Ò0+íҷüÐ`á—Ã/,xê¶0Í6„¶*4†Ö‰@LR»v†Ð®j¿¶+:8\ÒcÓ,àÓÂm,·?ÀÄæÝfû‰Œ¹ž&®µÒŠó?ä³?íXÿ r0O¨æL’Ï®ååZ¹Œò 7ǼÌÀ† ´øq>¶ðÙoX¶š¶Å~k‚ÆMÕƮЧ³¢Q«i•]Z9ÅËÆÔVÕYùþ{ç/\ «†ÉMÔ`¯Z^“íË}Ô˜YI³úhü{ñ"Ä9Õ7ì8Ž‰+ðVŽGw×èC[ÔuÆæà3‘qn‚ºÇ„øÀlBÂtE$t‰æj`("üU¹\^ÒŒò}™}ŒÆøFDb4(G`X€Dݳ$o>áÔÅ7Y†«˜ìÝù-ž»½©D×ËÒ•ªhZt*eBàkW¾ðáØFY ‰Ê½‡Uv¥XeWŠˆ^¸½DÔ3 ï#üCM‰¡/‘`{›!‰‡¦ "”xøÿŒ&nÌLÃ2pUÛw8|³õrë +Œ[DÏ8„&žá°péÙC¢VQî/Lž_ý a–ã¾ûΕŽ –rUö³ä-üCZ:ê t¹æ¢®bˆXIq‹hb×ð›K{.=¥k_Ö³Ú:Ux²Œ] ‚Á;[Ž[zQi%6Òà…èj1p‹ržiæK…ŒeÈñÇT];;^E¤s|n= ÿ‹ÈYv·sï:­ÂNy{%z}c[éN]áLCvMé!­Ý®ûåô/î_ž endstream endobj -71 0 obj +70 0 obj << /Filter/FlateDecode /Length 2528 @@ -1137,24 +1115,28 @@ ‚Û9„^ KmMF«n©ÄVi¡Xˆ—L7odê3žØóÆÍT¢$yŒÇð Q·~t\ìzIÛ{Ù‘ãßA¢L¯‰u»âÞ퉴1*ˆ¤%Êøb^Ð4Ò×xådG eT)~bVKk­Ý„Oš4£‘ÈdÜ'«Ä†ý£NT¬l‰áûãñ… Ôp_Gy ‘[©ÎÃñÆ—,JúR.Í##).a¤é@äoòÚÖ+»‡mŸ³ÈpB·k;XzhQc‘ŒÌ÷w¦q轕œŽÓ €"x¢ÿ0ÔÝ8£ O‰3Npëš*A²{ÔÌGÜvíÐÃóñM_qI»¹)oäG¼ûdøËÅr–ïœ>ç%{885Yðá3¯ž*1Yç§XçuímX(ôm—‘õ®SCG B#G9xýõþå@„Aè6)ÇÄþGo2÷ëDKŽp%EDkõ¯&g€ë V¡ @ÆßÙè´‰,[ClwÃï!ô¦¸¾™~éG³h+’©Õ$g¾· ²*˜3rã19]R÷–mñ¤&¤<EH-*T8ªâžªLgOëköåèò²—Ý+“Æ£ =äq`Ë(•„K*¤¬Pð>«vl´i -æ+oÑN 'yG)¬q(!B†„™d›w†fHwót¿ÍV¿Ád4+Z½Ã ë×íÛ”u¹Ò2½v¥&_XþÀ@6&ŒNIáýL—e»ºìúÖ¬¼ã6E0ù m{²5‘áî§iîrÅÇZí¥€ÓõäùÄ“tppS/tÿkÐM¯h˜3R)[d8²E¹†Ñlø‚×éd$ôÙw«fª£@.êÒfˆf»Áµ6ísà;×ûöe³\.vR´ÿÝ[nÞVìÏL‘´Õì ëõKåâ+ÒšjR^v}ååÿ %-îëùî%à7Ë—_;É2ú¾Œ½Cö]6‹»3ÐlOñàZO pŠ—Ljz^¿§Àºjåø£7LO uÖëŠbŸË—õâpPuñ.•´ìÞqîÊ›P@ÆŽ pZç Á×åâŠ1ã”6ÓøöÓ®õ¡TÿJa–i§íG«ë@^›Â#ã¬T@xýõþå@„Aè6)ÇÄþGo2÷ëDKŽp%EDkõ¯&g€ë V¡ @ÆßÙè´‰,[ClwÃï!ô¦¸¾™~éG³h+’©Õ$g¾· ²*˜3rã19]R÷–mñ¤&¤<EH-*T8ªâžªLgOëköåèò²—Ý+“Æ£ =äq`ËX* —THY¡à}(VíØhÓ0@[ÌWÞ¢Nò ŽRXãP2B„ 3ÿÈ7ï, Íîæé~›/¬~ƒ/ÈhV0´z‡AÖ¯Û?¶)ër¥e&{íJL¾ °ü€lL*’ + ú™8.ËvuÙõ!­!YyÇmŠ`òÚödk0"ÃÝOÓÜ劵ÚK§ëÉóˆ'éàà¦^èþ× ›^Ñ0g¤"R¶Èpd‹r £Ùð¯ÓÉHè³ïVÍTG\Ô¥Í8ÍvƒkmÚçÀw®÷íËf¹\ì¤hÿ»·8ܼ­ØŸ™"i«ØÖë—4ÊÅ56V6¤5Õ¤¼ìúÊËÿAJZ$Ü×óÝ9JÀo–/¿v’-dô}{‡ì»lwg ÙžâÁµžà//õ¼„OuÕÊñFo˜žê¬×Å>—/ëÅá êâ9\*iÙ½ãÜ•7¡€Œà´ÎAƒ¯ËÅcÆ)m¦ñí§]ëC©þ'”Â,ÒNÛV!×¼6…9FÆY©€xÞl3F1¨1„½9I@Ö“î2$ƒž +öÿf¯Å–'.rJš)Ì £|å/tïΉCõåA[Ÿ¾H*OnŸKv¿*aq—TY”4Ì?ÿA+Ì( endstream endobj -72 0 obj +71 0 obj << /Filter/FlateDecode -/Length 1922 +/Length 1920 >> stream -xœ¥XKã8¾÷¯0æ²PqâW}«-Ôb{ÐX¶3§ÎG‰Õå؆%OMýû!EÊRR™ÙlÕ!’HQ)ÿ}÷iqZFiíNQ-á?ÖY´.7Ñî}wµœÍ³m™äy7êð6ˆÞ/ì³"mŒT{ö‹iêîèçµÐ~"BiÆ4ôã fi¿DõêW«îÒ‹AòLˆÃÓ[aÔ,+ã_q»Ô‰'_i_wÚrkY½êÙv?ZFó4vG¸.œ,å2®DÓØCa¬ZúÕpÍFÎg±©)ŽŽ\u­‘xôo†Dë(‚wŠ#¯èîÂ4âLƒS7Р3µä¡jáÚdT: ••Q] wC…§U”®Ðeó¼H²"šg+Ò¿œÅÉ,Îgó5ì{¬*©ÑöëUr˜epJC oÊÔ4R­4G–ëBÁ‰ÍHì¸GžÉ6]ó¦™2£°ª=àb >Ô1\…ˆ[<¼sÕ(Ù¿þåe^jQÆu®ú!8¹í,¡ŒõØ÷Ý`ÐŽvT¬áSÀÀ7nFKÛÈX&«Õš½Îçž‚§5ÜÎ/PøÑxÔÁF²ã]>—5|œóËNÑ°JTWJXщŸÿí L­•Ðò!ÙÞ*ycŽ£—™Š4Y—±Cä×µê{é¼ÀqCœÆæSzÈ[qÞjUÕ~z¯³t z;Ù’'ÝÉMÕ§-}§µ:42ñô/­6­6 -ýjx‰c×ÊÛ;»¤>uMÓ!z¼Mù¦ìõg·Áå@ -GYš`Ø&)„.žÛ{à…ÀI‡AÏg‡ùçXRm"ªöüÓÃÄ NÓиc BÎûD´Wr“=¡çpîr¸\':h/F=,¾6¾v?>͉:™ƒ"BŒp «"Ù°”ý,±{íÒd˜ }‘§ñóQ!æK›‚W ¸cEÿM+ âÂyœ×x×’£='@?=+Á#“ fÅ¥oä~Æ „¶Ì ¥áU¿Ö ±·²,GƒÑù -X’ˆ*PMÜFÐÛ Œ84Œç9Ýð>[•ñ­5Š"žf˜£Ÿo|Ä×·®z•æ”ý¼øU ‹al¡­Úrݸ(’'t;F iªšuv]¢¦Êt'ØE#Nzäïû¡ë% “غ0BÔÖ7âwO/Ìý‡—ó´È£HˆñKAÂGm÷&”‰"@…!²Ñ«ª] Dƒ“âˆÿ(Ä;(ÜÄʹ]“Mé ¢îÚ±;æùÚzžléfX t"œµ°¡ ;® ¸NÁ¤= ± >¤'>ΊeüôÕ²o(Z íGËh«@¹oÒ -ØX˜ÜÇ›ýÌÓX« 1€Gù÷/¢í±ÙiS#rߊ¥ªáÆ#0PÉö^Äv+¶¦³L[Úà—ÀÝ&îtn>Rh´·w¥±ƒëi,ðÐá‰B¤ú_:¥â¯uJ=$ ÿ ´Ð6Ô7ˆ0€T§©{Cý÷GZVnDnºO6¤ÆÆêö¶íz`y©{ÿCÙȶ9yö»ïàP¿°‹»Qc/ ŽšïPj Œ«Š -€W†’µîTÅÊY( µ5hˆM|¶6à ®{{GÞÏC1 Ö‚š·Jƒâ¦†ú½,)7üÙÀ­ž\›‰ÿ¹Û½øëÁ3¨²K,0ÓÂŽ^_<»ç–¾ÜQ£§Ä'Ülƒ,ªqcL+Ö\wu3#|h‚3±êߤ»VÕ®èѨJu#—hì°h$*Æqe”üXñŸ°w‚0Ýt̾P(p¶œóË¥í ‹ÑÖ†{Z?&P˜OÁ&ÀhFbFhÏåÍ!EjâO_QÁ¦}¬áÅꔃ}ð™ K 4PÀRsGâûà©ytÚýv|!½lôá‰SºGBP,?ùñc[Ô¸'Eaoß‚\æq^pOéÆÕeçâymîˆl¶‰Ýá&XTÝ&ê*”®ÑâÓ)õÐçúþQ8‡l„×b|ðÀª{Y)ÛÐXKØ'd–n“2šo×–#-qíy÷;úçr +xœ¥XKã8¾÷¯0æ²6PqâG^}«-Ôb{ÐX¶3§ÎG‰Õå؆%OMýû!EÊRR™Á ¶êI¤(Š”ÿ¹û4?-¢,v§(‹ðŸEë2Û[%oÌqòÒÙXÈÒõ2¶¢`h \«¾'óÒq›ˆLé!ÁÅ9Xx«UUûéE¼&Ù2ùþv²%Oº“›ª?N[úNkuhdêé_Zm ­m¸úÕðÇ®•·wvÙꚦC˜y›SÙëÏnƒK– Ž,ó,V/…Çs{#q0é0¨ã9àì0QëOªMEÕžz˜ÔiÚ@w¬¢AlzŸˆöJn²'Øãd/\²/×i ÈÚÇóQsÀù¹¯ÝO3¢Næ ˆƒÐ#\cƪL7,eŸ¤v¯]š “£/Š,~>*ÌÌb‘n³›@€²¢ÿ¡‰` Áã<Îk¼kÉÑžS Ÿˆ•p”É„ÇâÒ7rŸ0Á23hixÕ¯õÂFì­,Ë‘Å`Ft~ ¢š$¢ +T·ô6(# ?ÁN7¼'«eü@k¢ˆ§æèçñõ­«^¥ye?ÏÃ|ÛyhDkÀ¹¶\7. +¤)Æ΀Ñ\šjN‚fM®kÙTÂîäA»hÄIü}?tý „a[FˆàúFüîé…Ù¥ÿðòq‘•Ei1~‰"Hø¨íÞ„2Q¨0D6zõAµsÄ‚cpòCñ…xžX9·¢+c²)½!AÔ];–`Ç¢X[Ï“-Ý ‹•N…³6taÇÁ×)˜´§!Ö#Ág€ôÄǤ\ÄO_-û†¢Õ‘Ð~´Œ¶ +”û&­€…É}¼Ù'žÆZm ˆ<ʸmˆÍN›:–Ó8øžå(P w(–hOáEl[c‹>Ë´¥ ~ ÜmðàN‹ç#…F{{W;¸žöPÀ.‘(Dª¿ÒR•¯¥ê!á1£Ñ¥ÚY}íºWîžA3ÛŸÂÍä6£W\ù6PšØóp# w;¡I+nž`á Ió{¤¶Dµ?l,èö +0±MoÑÝ8Tt,5dð뚤£N7qBÞ[¯¨,ï~‡y±h³^\¯èB²ªE«ôÅöîÀèÛ˜ÐÝaðUµão~AæÐÊæèÈà—Ún‚3*€ jÿ€à<µ"O‘]˜qÓ‚‹]ceNyJ­Iñ™„Ÿí 0Ò ðîY4TꜮEÆ+©‰¸¡“›&à”fì‰MWÜÉ“öÜ@CgТ*Á¹ªU#oü£‹_#r¾H7®ØÛº1T©…ÔkœÜéjj >͉˜eY™–S{0y"š=F_þóòË.šõág³#¦z9žÃ„„¬SˆÃt1?¢Ç§§ç—Ý5àÿ]‰Û<ÍV+ àÿŠ»ÿûüóógƒü†A‡œ0×® ü9è, tvÉü= ÷ °Ð6Ð7ˆ€0€D§©{fý…·Ürër À}²56N··M×ËËÜg(ù¶ ¿~÷ýêöp7j¬ñ]Á1ó + qUü{e(UëNU¬œ’P[ƒ†ØÄgkÞà*°·wä ðh1Á`-¨x«,(mj¨ÛËíЂ¦[)<¹6/þ{·{ñ3ÖƒgPcX^¦…½½xv5†/-}P¸£FOiO¨Ù'XL㶘V¬¹îêfFøˆÐgbÍ¿Iv­.ª\Ï/¢Q•êF.ÐØ_ÑHTŒâÊ(ù±Þ?açaº¥7µ8‡ ΀r~Ùb´€a1ÚÚpOëÇ©s¢â)ØäàÍHÌèí9°¸¹1d ±8MœàéK *Ø´5¼Wr°¾Fa!öéTjîG|ò S sû1¼ÂI™ýö&þó æ{7ñ ÃU ¥]òÆ×Π=üfÆç¢ir°‘ "Ê}+³ß-²tŸ@™Ê3SgÓJ×ׇ?[œ’2 endstream endobj -74 0 obj +73 0 obj << /Filter/FlateDecode /Length 907 @@ -1182,7 +1164,7 @@ »Ü‹ss™÷žuŠØíg)Ãzñøçáÿkõ°‡®¬!ÿz¦àF3¿{òì.©¢]yW¹ç kìKðCû!FWÈ endstream endobj -75 0 obj +74 0 obj << /Filter/FlateDecode /Length 2273 @@ -1202,7 +1184,7 @@ óZ¶‡w{ÏÄ;¦V\8ç®á{Ë Q|Ê£wl¡><G‹æ×Z§c½—\ ;-„lΗÁ@^¸d‰^i8-_¡Êšhûÿ¡Ã÷ˆ?ž²¢<Áür•Ÿùóùz¤á endstream endobj -76 0 obj +75 0 obj << /Filter/FlateDecode /Length 2243 @@ -1218,7 +1200,7 @@ ‹ÒÝßôÅñD"i£q¼7Ñ™Ïwuñ½‘d["ÞÐê$¬Ê”¥Câ`Ž4É1©ƒ3> +stream +xœuTMoÛ0 ½çW=É@âÙjœ´×½ìXø¶î [J£U– IY–ýúQ_‘ã´(Râ£øH?ò{·úv¨‹Ý¡hŠþšb‹}ûTtcñÍÊ ÞãjÛìÑÞ6’qÉW” f -R2»ì1†¶È0ý§lZÄ´Yß"¼Í`ç˜ÈðAÞgÌÿ¸&–§-:s!2ÆX¢mr jœá’Ë÷Œ8(}%¤FVþê~¬êbÓ<…R)¹ð·5z‹tÀ¼Ë wP3¹¼•á@$ †’¾/`ź‚_œuŽ'©Ùi&F3@°˜?Vã5•cºH«ÄãÀ½+Ÿ€A¹ivÏUýôˆÌÄÜËpD§)ü·Gn‚5i50ã¾D‚{žÎ%Ô@D0 ¡ÆBå®oîj 2ÇÜRJ9¢Á% Çku)XJDºÔ¥ä}‰¡K¾å‹¯¤Apĸ¶lŸ«Ý¾ªVc8µ©’ä"z8ò'ŽU†½pꌼ†ù7Ô´)‘`9RdäÃk ðñ±ºu)½³gä ÏG%f´gÍ»M1£¨´ó“Ö„dðC¤ Ò ªc`ÚÂH$Aù*Ì—JÂíÎÍH>ÊÆÍ¿i£Œ¢MÌG²á5ÝÖh¡L_ãrIˆtàNn)ב‰ÉïÍÑröh2(A:yß³qúºÃP½e’ÀÔ-[7Áº©²<_Or94#¤ +ìæ>áGré£áý^$ÛE˜ pŒ+°W†ÛËläbÏ8©@Ë-šMIÑÉ,'îÌÿM—u©å"ꕵ~^ÜÆ:,œB½c +Û×ù¼ê¸ç“W[>œ‰Âšë5¯² ,Ü€`‹M»÷„nÊî÷ê¥ûË׶C +endstream +endobj 78 0 obj << /Filter/FlateDecode -/Length 775 +/Length 2144 >> stream -xœuUKsÛ ¾çW¨>I3±*)–í\;“C{lukzÀŽ©hÕõ¿ï (N=™qöñ±Ï‡¾tŸUV7YwÌꬂ¿:Û5Ù®Ýgݘý̉¢ÅºÙ5å¦Þå¯Í¦„ók ”SC/hs)’Êœði›kªþu›S¥ßÞ&°UL¤?“·…€ÚÇ'¦ˆaÁE›_ç £ Q&¨z9Nœ0ÁÄ[B¥ŠÉ‘¿ºoU¶®Ÿ²n€TrÕ o«üÃòƒgAÎäúZx†ˆÁR¸º…yy --.*ì,=REEO‡àýcb@ð½¢£´‘ø*eˆ½i|ì]±‡»*«ýS®'ê,#;O‰6'¦7)ÙSíºõ41\ö„'– #ÔT¨†«%Š{"ó>Ô;vÁBOaÈã ä˜F½…a³®Ù¡h ‚®7T0ŒDÛ×›çr ŽJŽžk£aTÕŸXÑ„8Ë{aT Ÿ9rZ9§é%OÈÕwÀ*ᱯ $UÒ.̈;/'Éa31ø‘¼u±QQ(íJãÁÆ•ß zª ¬‹g°Œúþ”Õ5ìÐHÎEm7y,O}4ØbPÏM•? Äê fCø*ðºWl2ž³+ ÓÇÝ ;­íÿv£œx%—úĦ)a/ÐÅèn2дžô¶¯0<Àˆ·2h¿.ü©Y|(†Â¸šÅ´Ào[›N½ß•;ˆÂDRÃ2èȹV"¯òS´‡=ºF‰»%–¶žÕT˜dË.’‹S˜kì%))®4-( Ãâs³}­çjxSc{¾kËg[!Š%‘[KÙ.f'ª;<óž³¥²@8<. 6¸;€Zâ•p¾GXQèqáÑDo7·õî¼;!F ¶¬¼M­ :Nž¥Oræx˜Ãžu8Õ8Yñã5ÔÃçò“'Ð`š?ûBÈ›âýöy;>YøÆCøÏ ~äl¦Ùøè›ö<[·Ûʦ7uÑý~xéþÙ.  +xœËŽã¸ñ¾_!Ìe% ­¶$K¶û6™L’ ÉŽ‘=¤ƒ€–hKÛ²hˆÒt;_Ÿzðe¯'4àf=X,Ö‹UZçQUér»ŽVeÑ(£ÃØýðx¨¢|íQ-á/‹u½&ÖÝ)úgü¡çIŽÉ"_oâM?%«e%ñ_>'å2þe‡àgÍd14¼øS²YÆï‘ô÷ä_»¿Ò1Y…Ç,ŠUš¯¢ÅªH‹bí8¤¦Iœ%‹5Hü’ËXÔI¾Œ_D’-ãc²€_É‚»ÓY¡.Ëx2‚Aç¹yžfyÅrß÷£Í%Y”ëeºÍÖ $+ã·NOÝpôس¨_ÄQj©Å€@ï¥GÒÑ“lÌ0)™ l­[°(Àpü‘¤fŒŽTªåè eNu ‹-£EûáU•äeü:ôJ4¤|¦šZyJy¹ƒC%/…]hu2«Qêiìê©Sƒ~"ñÕµ¥2ô™ÿjøq‚]ÛM<³PüŸ-@ët¹)@ïZνœ$ÓŸóUÖK2*¡¹/žÿµë{¦íÍŽQf&E@ƒ<é¹ávÝÈ”Z “&m 1 *P„ᕲ͵ÉÀàõ ÉGÓ2hlg>k±ºíоßPaƒ<ÉI4b) _ ôÐb¹³Ø§lØTiV¡_µîö½|`ˆlŒ=r4üúrÚ«¾«Cß /d@?²FƒßÑÑ iõà¹&o{CmÕÜ7dû9¥!‰œÍKbÆ»¶5žfKE»ÆX ¢÷Ú¶&ðÉ̃q„ÔgYw¢ï/ ³6¸K)t0-¯Nš‡Æâñ.…-(½YAãSï~ jDY¤†Õ²žÄxUÆÆÉŶH«ÍMBW”Xè²Müù:{ÊÛìù›àˆC·±ž9· ­ +nïW "Q,·‚®º…Pˆ¾#“mÁÆ /«ð¾n°™é*[ÈÄ.dÕ7¬X^l¸|ã”zþÖru_ü(}*x5vÇvz07!Ðwr0Œƒ”¾vvXÚn¥Mí¨æckÄ}Ït TŽ°Ô(§Ð}PZñH>ÊÊ ž#ª9Ðräô=ŽbØj¸í--¼'%PzñòÉ_NŠ wz@y%ÞÙ¹õ^öœ÷Þ}rrK¯X^Ôø" /†Æ”­Uþ½·éëD1˜ç9¼¡çŽîšgÔtP¥üEͣǦÜë‡VÐé$Ƥ„*yü‘ò8MSÏCÅ ˜èTŽ ùN¥^æi•ç¿S©—•«ÕzÞûríß;dQk(áÕM+€5ƒžÇ5ï¤baáF½*K¡¶g?~ã# x ŸG£ûãM/š£V@p¶Dð5Ü Nââ}ÀIM‚p=_3ßnÓ”¼Jè&ˆnšAk 1<ÙU£ð$^S8óò$&ìíÑ·õK‹í†Ý5H'ìªünºqOg¤]×)ÂM­ÒpW64åuHóø 9‘ã ú{éáʇ)þß6¤O7]†ù×MäŠaw%4>½@¬Ex[ãiïç™l×çhÑ‹±ŸGõv 6F7¡óÿˆkÕë-~¾>þé +ú¾j>}»jÊáJÂ?’ +Z6¡‘Wejë.¡øŽÒ4¨>Ã`d¹3hŽGjÆ,‰ñ]®! z—®XGÊ@âþ@}ú9¤Žžû‰ +ñöJ¬\ ð Ì < ÷Þ9Ž¶Žž¤Ö8ìݶõÆN+ß°ZE¶±Eý:¦pv[—ÿ³†ÁDš—¿í7I&>\v IÝ1ï1™,Ùe‹Ó›HK­¹¡74,–Íø0u¸[z¡=ôGàxÃÛ_ŒA–ë4¿¶ÞoÇ£"£Ì´#’Ǹ1£à¶dPžÖ«ÆÐö¤É<†DCŽ'ÙÞÔ`Z@¨ ‹£1É*2×5xú0óax§ãþtð<ôšÝ)5ÞEaZõP ‹e5,ÔËÃÒZèU<‚GTÂʃ"ìç™Mƒé`S´°NéRL6wH7µþ„wAU¿ºµñý™¦ScÿUF{àñÇ5vCóHÉe¨t'L aô|Òž‰•° §¦ò£nEÿ=×_I¸‰c¾/£Ú‹}¨‡U‡âȃºÿhp fP9*‚3 ¦‚…!ÜlŒò¹Ów¸€y²ãF@¿?§Xò¯3~€°GH í(Bñ’zÆ©Óç} To›ÈPÖ=†“Vϵ™xÙy4XFÃœæðº;u½ˆÐ:GíaSš™Û´˜V|»=Zf¶ïÂÚW–m”üýÉÐ̳À4ÿÀ0¬Îr¤> ½çï¯râ~yá-C¾fÄÛ+x/ é^ˆ`L?2ØE1½WoC¹w|#;ÁÍ +ø?føùÏ2àKóŒÙM‰m‰¢×ÊC­ìÏ÷œêféN×A ¾•ðp.…&=aí&‹€ +ã ÏºšÎ©CNüBÐÕ3G@é>Ò˜7õö3ìOŸqÜ}|æÍ’®ÈóvÐ2ø3x¼À$ég-‡#ý »©À8væ³(3Íà éãų‡_´ã}m;[ ÄÆ7NþsS…[Q³G÷ͳmZÂwmî󛀻ÿ±©Æ endstream endobj 79 0 obj << /Filter/FlateDecode -/Length 2060 +/Length 2926 >> stream -xœ…X[¯Û¸~ß_!äe%àXGË—¼¥iÚ¦@›tctš¢ %ÚÒI4D*‰ûëw.¤H{]À‡sáp8~3Ô¶ˆ6Õ&Í×Ѻʣ2šdtúáO‡žO›¨È¢Ã)Ê£ þò5·j†è?ñÛV\Œœ’U±ÝÅ»$~¬³8Jâ¿}Hª,þù€äÍb16<øK²Ëâ7(úWòßÃßi•|ƒ«¬ÊuZ¬£ÕºJ÷ëmth` °š&qž¬¶`ñcRf±¨“"‹_D’gñ9YÁ¯dÃÝpQèKk\.аµ[”i¶/Øî›~’¢¹&« -ö³Ï·`$¯âo6ÝxöÜ‹¨_ÄYjϩňD¥gÒÒF6g4ÊS¦USë¢1ž$«9³ƒ%•êC;Ú€£¬©N´±,Zåešg{ÞJ£’¢Š¿Ž½ 9_@¨L+‡”‡XTòP¸VƒMR›©«M§FýšÌon#•ã Pøÿ¬Æ ÌÚïb3]í@ñŽÓlW‚ßµ.½4’埋uÞK2.a¸¯^ÿk×÷,;Ú“<ÍCŠ„{ÒkÃ%µ¶”G¸ÆpKùî6dðúˆìc`ÎI ö>±ºí0¾_Ðaˤ0"%ã+´F¬X"öþvpµ6x®ZwÇ^>1 L66žL-´úú:UßÕ‹Bß/@&ß±G£ŸÑÓœ Liõ䵌½•¶jî›…äø-NC"/":l*03=Œ­=iŽD´klÔ {ockŸÂ<Úƒú"ëNôý•iög)k…¦áÍJóØ8>.ÀP:ÈÁéÝ0 \ŒÿgC}ø%ÀˆªL­nT7ÉÚ(ÈñMÛC.÷eºÙÝ¡]Y!Ðå»øÃííÉïoÏ?gú¸õÌWqÞ -Úâþ1Jˆr¹´Õ=¤"€è; -ÙbÜ0x1D…çu£[È®H+8ìá&v¡ª¾SEhxqéôEL&õúÄru“vßgéoÒÀ£©;·æÉž·Í€¾“£U¥lôíY‡ÈvoÍ´“šÏ­5÷½Èw!žÔ$ÿà¤Þªƒx¦#Ê«<-K‚Oh9ñí›Çús ·WÃD.”°ºå!Uþ·ÿü«W‚MÌvIÊðü¸Wµ §ƒUOoœtú½DOŠõ&ÝÑÞýÕÖ¶ -ë3ÞËÐE&j¡é1eøš0 žìôù„ÖkŒˆ·OçµX‘áLO(ïÄ›‡e|”=߀GeŸ9¸K_]Ôô"à^ŒE­uñ½³þd(Ëup^«K‡Ûµ$B51®jžAÚÈ£~ò¤‚K1%çÿ?ùiiš.jXÜw"–‹¸ä´Aö6Í6ùïBö:­²­m==n/†a†oÀ÷js—8tX¸±ôxòt‡°±ã{»<Íw;·öó1=“犞­ÛÏwýhý®Ikl©!Z[Ü1qõÄ1Ф–€-(®ÆÐùlɳ›B/Aªˆ¾E‘®A¿Q”Þ–â<.8fƒ0ØÕã‘zŸ[j5¬ -´.20vƒ¿‹’íé¬ÎpUŽkZ¥¥Ÿâ‹—“+/ìL °¥!B8¢öJl!x÷M`oúúîL³° ÄuùcÅÄ»¹ñðÙáÆyÛ«ñüdiè@\_¢U/N¤}™Ô·k0/ºËß³f—®[õuŒV?Ý®þ}_|âùVÕF¦\ðàßÉÚ5ÝalªÔy'i›SK_àQä¹w³hÎgJÇXÌø׊¥Õ‰j5i¿¥ýrGϽ¡t&Ý^©@•‘ÑŸA¹šð G‘Óä0tZã;ï¾£·škß°We¾s€~›CølÛV€ZEQý¶Õ$›X´Ü[$]–yƒ÷ȉt°>`ÿè¤5÷òVÆXÁèÃGÓálé„ö -ÐAü¡~7žw¼Ú€dÛ´¸ ÞoFeÎ÷Ü>ŽÚñ'iøS_QúÈUÃ¾îŽ - -âճẗ"˜Ì¢œ>ªožCy´|`gü‹Ÿ±&üðç°ÂÒSÆΦ‹í„¢×ÊS­ì/ºžåÝé:€¸à# ?Ë¥Ðä&Œ—7E …¯pÐTݼ˗H‡šøi «gN€jù:ÃÁÏ÷à*|à¥gH\Xß~A8Ôl +xœËrã6òž¯PùiʦEêiç4;“lfk*ëÊ(•C¼ˆ„$Ä©åÃçë·_@C2lMÕ¨_hFw£él¾¹ÝMGi6ÚìFéh +ÿÒÑ*­ëÑæ8úm¼-]ULnÒå2I—«qW3<]ÏÆm}´Š5¶´“l1~ÆÿLÕ)ç1›§¥m¥¼ŸÌ§ã?ýS)Gó4I§cÛ¾¥Þt=žºˆ/eßÛ6fÎv¬»/ëÜt®®"ùz­Äµ­-&ÿÙüë›éè&%Óéj´)À㪆meË4¹KWã¢Æ~­ÊÚ¶xœ(G6Œ„l¼dÓqƒÅµVуí×v.ù£yQæb\y­$ÛžlîLY’X6®+åUuu3´[g"jûÒ‚íÐþ(ÿëÁVC»csg³y²\Æ[‚i"îÉ6GSÙª£EÑí«º±ÅµRòƒÍŸ¥S *š:§3ó„ºïNd&Áwu£ÈDÍþl=Û:–>ÓÝŸ +ÓE8ïÀ†&)8jþ„zo¿Ô}““÷Ý¥±¥á&Þ ØbØùEîÄ3Ä£™p,YÖsÑû\µWl¬±×*M¸²]´d£RÛ¦ïìÍЮÁ¬9ŸƒQ»CwûnÆΆG;Ðí/ìºU׫LßÚ†¦œóýÓ¡^+,Ð5ʉoÉëq|Q˜—β٘Ѻ’íçãÍd=×ge"Ó]+¹é«{Úðín&ñ ¶žeÉt•âÖÇÍqtûlšÛÜ€_ÞšSwûŽÀdëªÉæ÷sCéÒmI¶„;ÚÞ¾{‡ýß#¼g¼FÚ³•ýÆwx1/À›ƒˆ5ÿžúf’®Ç{yÿ°ù¶eÐUm*SÊXÜÔ5Ãc·h–9 –bð +– ñboe&¾7WaDGÀ]ŽÒ%®ûnT6‡Å/uñëÉ8™Œ³ÉÍ +W•Ë­^­yáðûåËçÛÍç/Œp4‰Çñ›ÍÈ<7Ÿ%2Ñ'J(àÝìòÍáÐO5\—mi=sóÝ÷oyàÛ*o^N-TÌÈŠ_+ÐÄœÖѲ=óÙÏ¡=Dkjê®ÎëÒ³¿ºî+ÍÙщǫkZŸŽXf8^ñaÑé6¸3@0PdÙ‚üßí^Ï$ÿyÆ¿O¶‚#PnÛŸNuÓ©ÄWÊ2­JØÊ€Q •02óúxre4AçŽxW=ÿG¾ñi‘ìÁEó”ÖšÛ¦3n8;A<˜Ü̳d +w¨{gs,„Fž.0®°t’å¿ ä¢WxÎ<(¹2]ß(ŠuÁ€”x˜­ª`)0W ëÂbÎÔu +ÊŠq»XM lU}:›ßq¨6y!-ÔF*¥S@8ÚÂq*„n=¡=Žm²OT ºå/ÞüÇ 7BؾD ;XÚšc4YÓsùp±R„ùBøahLÜËó‚JšBT÷Mé𫎨 xÛ5Žl¨ìÐaþf,®Æ"t+bPrœ‡oÐeÞ¸"¬³™d¾ìþ@ÄÃ0e[GØ b¤ÆP¦”ÓŒ|~ÿS4¬8ºJa|`WPxøb]ÔEó⺞TÁÙLÁ}Â2L„¹nðÞHü¥çSˆíj&$_pö+EµÁ±T_-_…|/àÚXqéGaxïJ©^û[«Ä÷ié +^r?œ+¬¼g‹TÎ#»Ås”;º¢(#ÜÇ4ó+Ô‡žAlž àü +†D:#g÷¤ÊÚã -ú@}¬È Y"ïÛ®Æ`¸Æʪ®¬€ëøh… Ž%ø«;õ¥Ï4¾o{yc‹Pô‚ïk…{d¹œŽ—Fo£|¸^‹÷ð0²äzYpzVÆ›[óæ¼SÜeŸ†î`…k±^k•BogÃî¼@2·H\—'¿N¥‰2ß—¥j;™¦‹gß),Ÿ`íAâ› ÜFM¸^Xï5dÏù’®Q0oz,=*¶Ì—žÃ>V}Û)ikƒhaÛ¼qÛx~[{ŒâœÀ……Ê´LÂàO¯GŽÑ°Ú7ju™¹†£Ø·P%Býjì(Ùœ +gïÀ•jˆégIDh»¾¢àdJ×½ð˜G©ïY€+¡³ç‡2§É:I'×JÁã-EÑÖ榧þÕ™®yÔÚzµ³p \‘'øþ«\ö sò݆Fh—€qÓ¶ý‘{)^ÚDlÁ\bÁ:Òâ_€WÐ?í E‰à±ñu é÷‡7Õ)Æáy¹_æ5'e·]$yÂ](`ܹYÅŽÌ(XÊ–ÎW:Hz„MØ7ÿŠmZ÷äNø’P2xƒËKûÆô|SÚÇI¢\œx,†üjËr°eõTI­ Ž¶Êø9A׸M_Á³Ê¸aX(©ˆïn‰”¦Æ]§¢ð^䎄è£ç‰ð¤-Ê, ´…ïña‰sXPe$^aŒ*¯ê7^×`Ç ›Î)ÁÑ¥8óŠ†öŒ \˜†l^\ÜOpÚ'ƒTý½VêËXHsÍ#Ñ7×B¡’AxõÀP…p*»¾ (÷^¾2(é‚Lí*p¾g×ÔÂV9|>ƒ—ãX§´ÖæÐSÇÐç)Q=Ü^+ÙußFŠ¹>öØÁ4…b]Ä«:·‹Ô!Òæ®î£º´Lù@e6æØ)ÆïŒ(PH0Â-plð•%=–ö°Õ£ñïhB¯{Ôô8¸ì˜} ËÞÁ“øù +·£¬Þ—¼®¿¾ñ¸“ðQ»‰†¦ÜQk`¾n~ŸÒ² ûƒ”•üÍÿ×´”Bóèa ÈN¥(Ov¥„Ù{Aד½hô^/(Ÿ‹Àe­î&šjß{C¢f ×" ÝÚ¹¾»/—ƒˆØ5àb†¢>ì,[‡f+ ²H—œäé}SÒ§Aår_•hB¯·è@Ï褜Ê×¾lTìL6&¤Ý çÓNcÿÛ;iì|î mÞ6ÐãÃ÷àûŒ,¦ó}ÆEdêиáAõI>رÙWTxÕTh&:äÜ.› ¹á›a[Ó†Y¹~†ðK× ¨ +kŠF n° —~…ðÝ1châO9‚+øj§žQ:ÿÌò\Ìå‡Ëç9|E ¼Ïé,îï]wjïïÅq–Sèðüôó÷6Wß]4ØiC™h@{bE +3Î_uX­ô1|@â×— /ŸH¨Ðïh|0iÃóþ‚0g$½]ß`DbÄU@?Ê#äï{!< ¥Ò«-¾Ц½øEùÊÕ€…–{¥¾ˆÀ~›Ñµo•ë ÉAé¨óCLùž ²>o‹<´ ÛÁŠ wíËmˆxNA¢ú’)}DžF¡P¤ä™pßâ ìJrS8äoŠÒŠu!µŽ:? ïcŠº +¾R›B]|‘‡0ÎÉ.္H‚ÞBÛg´;qÆßûVò¯Þ3R…åõ¥_ »U:ŸNÌH¥Á?øêNùHßD\õ"OA‹z{r©<é‘®–Çàs2ÆEÌ­ž¤MãcnÖ±¹ÆðBÚ°g=à_P4ÕùwÈt–%wóµ$gÁ&Ø䤯wÜÅú?ÌÃðOà 7qU4öb]sx!fK 8É»‹e¬’•®BŠû0µî;óÍWôúic˜O“eð±2£Ù²ÎöýæÍkâ endstream endobj 80 0 obj << /Filter/FlateDecode -/Length 1327 +/Length 2269 >> stream -xœ¥VKsÛ6¾çW`ÒCÉŒD‰ÔÓ¾tÒ4Í´×S«“CÜD.-ÔÀ@Ëú÷]%W¥ói²y™Ž‹õ4[.WÉÛë#V‹„©Ào%h}DPßó¼dÀõÀ<¨Ó´˜&æG°Šñ»A©ãÊ”¢òÔ+‘‹äÀA+5èv¬Ü TI#ÿ{zŸæÓ)V­ÇôßÍŸ¯¦dœÏ²é ó¯0ÛmÃx•Žóå2ËÑ…n=]Ï%ö( ˜x0~tl2ì%&éT8oMß]}œ>4õœ{ª5ì[ÉãPî:,N$Ú¶:¢QRÍôEE”‚ê¤3WŠÛ„ spË<»ÈOËÕm$>aÃ(’­9Ï.²ÃàrdJ³Òëïé1kSÊšQ`j¡d´i¬Záäe\ðqšü[F#®:*¬©¿Ñÿ¸~.;Wîb6·P )x•‘´¹§alƒðLvÇ…„j8åÊû@ÚS\Ha¢Ó­-“§k!±7Ø¿;‰g+bíß][QÑx¼g¾NsjyoüNnD'K‹¾‹<.@8¶påщÔâ<ø½^ëvˆ £Œ­­l/5è³ß301 £ mé fQÈ4hme§a|.k,kiíçXT½¦·/fl¦âFà4ùÇA—ë.èt -¤Ýrîú/˜ö^1@&ƒ$î’§v®Q‘Y6n*öÅ*°µŸ'›tñģ߈êQ`ËŽ_Ú„'õÌOoL½(2—y"÷dò@夤Ë mõä]f[ÆÓͧu´¶µº ¶¨š¼¹öx!_mÑ õõöÉuðbê1Œ‹¾–)ÜÛÉ4_'w^oœŸ•[2®ArÚx[“ÓÈ­©™ÜÞ³ßCÖÉ-_c”8-îÀïäºæõ`!ñ\=—$_š°ÇØOÅc_f³â¿N“,MŠt¼B«w´4Ëæ±Zã¡™û ðŸi¸ƒ÷Ù—¢wÊÑŸw‘_¸Ùnô Ë-U¬ ¤0ÞÌH³—A]$­ÃÚÕÙ¶^)°š\«Ñ3êžê=kš¬mS•’µQn„÷aFÖØ=UȈd -Js+YF²òU=ßÀîˆ*Ðx3¨ÏŽú`o Éqˆ¨ìKýð™tj€ëØÖAŽùÝ$Nñ ÊoðAa|ÖKÁ|DÚ¨r LgYöÔÅï¢ã1»H¶íìM|ùT+ψ¼q«ÛdIð¤f8’ñ¦´í3%)2‚ÃhΞWuŽg]îÆg÷ Z̦/YÌÅWé.P÷¯G¶GQã1]¼d´ÌHœöê%åUF:®4Ý6€úùú%ƒ5Ö¦WÏÏ'€ =].­öÇ·_ýqõá’lv@ÌÓé³ šä º¦"ÖÁË—vVL"r…d8M÷Pfðñ4 Ò¢2rƒg©IE´ -Л5TÄŒÏìLxæu{ciã„_0Á«n¿9B¨#™¡olïS¾$ÕS·¿EI þΠ’X^ž¹ȳm1©`+¡µÍ¥&=²ÏxpHþFçæIÛ(ÝÕµßÀ4Ã÷‡÷ŒµïƒoŒ­ÖmVÙ¶œ¨kf¯™vOóÌp{Ú;ãø³†ú‘ªŸ4æ7}~ã8¸ñ¯>K—šÝÐ5õ÷ü¬}4~¤ Ãùn°Å'ø%oà rá†ëßÜ~ |Xø1>3Ò÷›ÿ¿»K +xœXKs㸾ï¯`9‡¥R6%êmå4³Þ$ÞÚªÚQ²‡8ˆ%Œ)BÀñøߧÝ(ÙÚ<Êeè×× ~Ü~7n&Y9ͶMVfø)³ûe¶Z¬³í1ûGÞ[9º›M׿\åâäîFy%ªƒ4£é$¢ÛØ–Æ‹ü¯Ûí§42úÛk`‰®NœVº0ªVÉÎÙÁ„î:Y¥Å:±ÎâÁûõçÁ®›t£Þö¢½)FÿÜþôÝ$»+gÙ¶õ>ë#;-WÅd=Ë[uTNÖ~"U%­¥1ïŒnÓÊJtÄÙÉ°ú ähºÈ¿ŽÊEÎ2üRw0ºßxYý¥·îÊ­›áB–e$ÊØ÷­04áéo'÷Qº»Ôá)/þ릥—r’”À{OˤŒÑf~®Ci¯iÇA[XõÛ5ùIw›–«®jûZ¡ã‘;ŸÏhÐhCï§Q‘¶<'ˆ§ø2æ#}0ñ©oU#“,&¹•† kF‹ENn¼+×ìc#LçÓÑ]YÂÚ­¤å¤X.!œl[ˆÓ£„?/üª{Œ\‰ç†uG麾٤¸M»¡H +ÎD[UËÛ$]«æõÊÞà@s¼.Ø5CÅ‚ ªƒèöh…ɪX ·(Ü齊cÏHóäJ&N½ «È¢‚€ïÃÕr«{ö+Ze¡ª]«7☕`3áœx¥A«õ3tw7ºm È0E‘*Ž§VRõ73n»À¡ŽåµÜe ±‹÷Òµ®ž¥)*}÷»¾s}F3ÙQ¨n´ý’tÈÿ=6šŒ v×í3e3h`µïÁî™°™GœLuÙ‡OÛÛ Ã=K›)w)ÌB VXë¤é03§ý íæÊÕÎ% U·Çª°™•óéÿ¯ÞÇRpq™aeØSe˜1åÞñÜ¡ »©“‰É‚ÙZZ'Eé&³’¦ðîd¯7›eV.½×fóÂ;nI¡³ö½Ð +¼ýÓã_~ǯÖ:Cᣀ\:î ƒ›˜GŠÓ嚪¶†vo‡HŒ3¾•Ðiìó°ôZŠðZŠùD3¸ðf +[f}QûZÃvÔÁlïa—”d¼q˸͋İÔX3åkŸJö"çàttÌ»|·³Ðp‚¨Õº$¸½iœQÆhciâÚe(‘éÍ@ÊCWÁ€&Óo°È[ ‘T ÒŸ<²ö çïÎN¥ò65F߶vµ:B­) G”è +M¥¬¶žùéÒ°mŸF·DΨxc×ã.sDœ=(_,yÛÈ*mñ‘Ĭ]š|PJƒ‡çp–N×H³¶¯qž<˜/ù¦•ï-õ« ÖjQh¼¡hWc£.N'<ž™\è€.>Ed<’ Ñxb`QƒÈDÂbûîéºñ8¯°Ÿ Ò}z|£ø_(B BzMï,¾Šýr +”â‚ë‡/ô¹åŽåPÑÄ‚ª=—˜‚ßË +Ùï¾…®Ã|É™‚‘TÌ•À²ý ~‰[8 ÕKxXà517ÂJx¶(xvZ|m^x„ඓ‰_„û^z|¢vòM^ñsYQ—Vxò]3Φ×9Ú“’- gR†!âhhJ 5ÿGŇoÏ!lô·[,Á¿a4Àn | +-–¾Ñnü³g/ f—q…m9A‚ˆ=¯ÁOôm© Âµ&máŒä¦ØÛÑ”¡1Å""üÞ÷ 7 <Ú.âÝ:a8ÙtðDe}ÀÚ!þWÕ‚Ô@¤æ§q'Ði¨ ÇÔc¼£…òpÇU¬¯øêé =%`䟅Cïà—#z&°$¼a¯¡Ä÷ѵ҄ñ°yŽßÒ·Na!¬Ûk139é|ª1öÉ`üE¢á¯Áš×_Ó˨ÿ©a›SÃöýýu4ƒQ¾q“4ðO?øEŸ_ ìi@T>b@-l`ý :ßþ~û‡#:J~«ø²>„ℯ´„›DÑ',&<ÈÐ0¾‰ä^Œˆðý ðàãU$¨ø·¯ïɬõûò:ÝÈQ0pFt^xoÞÏðy ã¾bE0ž> ðLBz˜ð5ˆ‘Ì? Ë!À4¼¸¦Œ‘¾ºòD*¼á÷׿hÇS0ŹÏÜù6ç…¶älJ×€+;Žé£0g0Ô„CÖ§qôà aá®,òÝBû"n8Ç#Àœ¢œ¯O“Æuc†¿ðæêšsÐ)§ÓbÎK}[>x©ÎgËb1­Fþ¡úW·Þlð5·Ù|Bsm6ÂÀÇ¥¯²üÞ|Ënýñ‡í͟Ο`ã±6Ù/%»Æ^ŠÞ/ìOnÎ/?-:]o:GîÛÀ‹¯% endstream endobj 81 0 obj << /Filter/FlateDecode -/Length 2807 +/Length 2354 >> stream -xœ9KsãFÎ÷ü -–/‘¶lZ¤$KvN³ylfk*_*ã­â=´È–ÕŠÔ²I;Þ_ÿ  Ñ²édÇU# F?ðhüûýW×ûeV”Ùý>+²üÙ¦Ì6ëmvÌfYvýdúëÊT{mNÃU€ú«öñº¶»Þž®kçí³kl6¿ÿý«EvU,óÅ -ÔÙì‡nlë ™z·×µþŽ¹Ê›|q» \¿~øå§?ýã.»?ج·ÇîÉ4™©={îƦΞÝÉfÝ8dχª]o«¡ëõYÕµƒq­kß.ŸÉ?×Öölïëóì³m`vVgC—y Ò,hl5°Ï¥\ïo²â/åj¹ÊËüÜæë%\Sý6ÛÎgù|¶œ_mÖ‹Ù‡ª²ÞϯÊÍv6tôûùó§ëûOŸ Áó –9f?Þßÿüùa>ÿ÷ý?a™ß=¯R–ùj»¢U>ó«â¦È×3ç Z›Ù©óÞÁ] —ÚÁÌËÅìi^¬g‘nÛª9 ¶V6Ã;~+€¶*ﶅøäŒPÂ’=õÝÐU]#äg7R¡•mãYhw½GKPžnîC”wK7€7Ÿ‘ÉáÉ%Ã%­ó[˜äöo—ËÙp°Jø¿“mAJõãéÔõƒr<Ï‹ÅÌxå°-p­fPbÕO`JÜÑæJÿ±›—pj‹ÿóùÞƒKÖi¬©´²=ÚîÙáƒåþ·_ÊËõ2߀À=ÊÞƒÕú8fÚ:¸ÃÆU&8Ø7q¸UêYÀƒ·f{EAS\¬ð¸ZÛÚàqèØÕ¶¹Œ¨äãqÛn˜:ªÚt¹ºÍon6äH CHOðz»„ Ðq׶?ÚÚ™!ãm¯úే™Ís•‚æ…±#2€5ÿñv/ÉÆV§zsLëÇÆú·;E˜B¦áeÞ…{¸9÷ø‡rU‚OUØ|‹ üÖƒŠ|Ä1–†;!”Oè`vAI¨Mŵ=tž%àþZÃöh„{»ïz{‡^º1•iQ‚šºVX—þ×/ŸT>¨[lÏýÛwc¡(Ç° ̇'´kAŽæ ºªÕÐÀQ±SšOˆÂxÆ–TTÄ0£ËTA錩¥\Ü­¥HM^Þ6I6X5ÎÊ–`â!²à“5eè—øã¾jÞÜæ‹-G.@4øŒ¡7aéh´ã(Ðgbõ'Óð´HN.‚¥„_ºaN.€È;Œ¸ãð§KM1\10]Ñð>óGÀõ²ºc¶ÑÛ:¯ÐdÞq‘{ -¬Ë%¿2ädþ0ˆÊ0ïì1Ò&sÂÂDÚ/#Ÿ>ü”L«®ÕI¾;Ú™‚òMkEt—¬‹ûú¢ÎVŠæ·aÌ “~Ãñ—»‰±A} ‰—Ï8Ù•`QÅïÌ5M\! ùÂà|*¸s4/éôòµð¤Šô÷vÙt•,dE+¹›~Û*¼L…*N»E½Mò]]7 .1Mð}È$ôLŠ ë‰Î]0n ‘™» µÖ&½Ð,ħ‚ÌÔMT£: †[̬ºÖ2¸MUËlXŒ½ºÓØÈkæ~4MÐ 3Å@Ïøc§ðˆ$Wõ†Ù»d")W¤ˆ…Ç™ åËŒ£?M%b·eˆO|ˆ1((0_ó:Òõ -ÇÓ C_næx¥.~û”æJüÐ4*ídú!]}¯0'|ŒùÇ7ž¸›Œšà^˜ïõá>W7Á Œ‚U?b2((ß`’ -…l¬ýzС¬µõ”aé"øÔ+âÃTåqòÇ„FîQ —ÉnßÉÕyåT1¡dN$ K„üÕÉPÊUHœÅ€ÊÙŸ="<¶ÛœL㆚óÀù=1P&tV~(q‘oóâa~©#¨Þ†íleàEz-‹`°*?¡Ñ¨PÊÈCMùgoÙG|“oo54 -"Þ#¸ñ~<†ª,r›„ìƒKÊØ%R¤\A)íI ãéåë Ò?Þ§…ç›õìòü]c/pœáÅÆh$hBƒô”½1¦ðŠŒ ¨lã$ÓÁ¡8„}gò¯óÕbæ¾@³¡Õ.ƒ5¸ª±ï,Ožâæ¹2Pr"X -øl›æjÊ-¾´œk‚¡mJ*'‚›Þô –Õ¼€‡a¢¤,G;:åÒ'€p7(+Ô‹Ô‘`y¡°×!™~¦Ù‡ÖÀänrÎn.¥ ðdåQãÿàzžÐõ*) ¹À¥¥Å.tàJA²^@ÐôøìÅê%½0Ü4É>À7ñªG¹H”lÁ-Iêd¡nb;ˆð} ÜÌTÔ§€]–Û¸Ãr£AÇùM’ñ±o|®(×À÷ìBŠÆãÝ è ”žò­¤ÊƒÉÞ$“´ì¤}¦ôö?£ã6ÌFÞþÉÐ&w=>LpÒg„xd!±0ƒô×ÉUÇÆ MêNÁs…/Ü/‹Ñ!ÑÌuÊx\º2¤~gwΈÄÙÎø¸*åÏ~ƒDQqOɬÉ̼•Fq»ŒÝ114…§VpßœT“2KFp3Tù%ß&0}^Á牰ƒUÐÅÝÝaNþîŽ çf±˜]|÷ñ—�¿øæUƒ=¨d xŸ˜‘…Š«sýA&›Ãn¹!‰ª+^78„?çPÇÄÏ „}–`âcù }AXƒÞ~ì1"âZ?rò×½Z%<¥;¬ðN9zQEùÆÔ€„–;e }†å˜‰Û{¥J"9Ét~‘¿'(¯¼ÛÌ-C?!@ôn¨•@s© ‘®ÉH’ŸÂczI …ÌÅeJÄ¥ÅÉ­N¤þ&S‚½)v¬étÖ¹ -˜ûœ ¿ký`M­“¦¿‚àšdøüŽr€8è­µ}NÇÆøûèùýU? ¢0½þíªX-9>IqÞÛÿBâI ¸ RÕŒd¯T`l6²WÉÐCð-Áz‹õz« ©Å&ËHÐMBÙµÌ~†éžLëg3ÀW–>èI (–e~ ¼J(ÐÂ¥`—3|¾£~(U$‚¡ŸžRêâ*k¼ÙWûZA‰XÞpÄÉÿöj›|£»àì>.­ç.¥ûŠ€úŸv†)º…´¬,ÏÝ&¼½ËrKf<]ŸG²'˜>õè¸4Ô‰¾81¥Á‡ˆÆ©/Æãqq€Z‡‘¹S»È™„t¡; -¶z‘OùÆgªUà2IGGk¡_9KÚWÌIŽ~j…ûà’ïwµ²j˜ -ÁŠû…|PØh#ÙL ÕÓ·ý!y}‡‰œá휰’Nð)Ë5—…ž`JŠ¤âàñsŽä,ç<ð™¤.•:¨ÍHO5RW«%œq¤˜PÐÊ8@£L¡ÞM¡ñàWÇc5%ûž×ë©´Û]Ãöðq}V®ÐO¾¿ÿ!Ò„© +xœ•X_oä¸ ï§ì“ÈxìñüKö)mZt‹wÀ݇Ûb¡±5±6¶å³ä¤AÑï^’¢,Mâ¤WÈ%Ñ"ù#¥?Þÿa}Þ/òýâþ¼Èüå‹âö‹Ãn»¸o¿&Çe’.“ÝruØeÉír›%OË"K´ª–«Íᘔ¢\æYR«îÁ ÎË <*‘È+Tç$•n6Žy_íÛf›7ÒÑö¥—fùÏû¿µ`á­-¶éf»XmŠt³A–þ¢[iU ª«";¦»¤l”ììÄZí©J/7»ä¹k´¨Xv,[z|¨½’èíj‰ŸWƒq`0ø‰nð„’ÑÆ“å´º°ÂÓ¦Mã™NGN“¾±zÞŽDw—‹âgg‹U^¤¹ÿÐZ U¥Ìãr•__§(ês ÉÏ9<-ó]Ÿ°Û#§ûå¼øi£ìU`F#ßYüNwöOx>AT©A–Váñº}ÃÐ70&b%ÿK´}ƒóÒ3FÄ´˜„xhÌ·e´dr%1HºÙ#2c ŽÜ@Ⱥ@2)Çö• C ê{êÕhà3G v¿­xä˜<)÷Êéq,¡Î\Ið³0ÎþýØ-8v_ÚÞêöfå×äûÛ@–ºm1,}vô^µ¯°Ÿë} ”p?xôÔh]B¤”¬F®ƒ_ê/ +MÔ>ºY1nÿ jpMˆñÉ Nò¬ý±Ô#é`â÷·b‡Z1È-Í—'¸C·üãîÕÍâË/?y}ŽÁîù׉¿¨Á`ŒÍ8Aš ´ö¡©ï›yª´ƒc1mŸ)¿§EL “e´ˆ¿Ÿ8l ò +"; ì—.Ðz¨ä0¿–'<¶‡Ü©ÔÓ‹òQ<ÈÈ&‡ª~ 1WiùœÙ£î˜1äZXðÊgu ¨Ö]f—‰ƒÈùšþÏ´2÷Þ`ªÚ¡óõ¢gÊDÏ‘Èv!¯ý …Œøh zì¾Q%†r:­€{þ5êò<3ÝçÈ´±ÇÕ½Caö)šg㯠B8©ažÁ-ŸÆYÔ0-£×1½›.U½üõ€uZ]EkÑ%Ë3°O›†è¸'EHí1¶¢±=É0 Á@]£›ììFV©.L§öwæÎ#[@ñ©e˜ñ¸>Û[ÌFÒWÎDª$Î÷®¸MÍ2 :×ñ:>d­SO2ïY$&ÊÝ~5–;?Õ‡'stF¥,,<šiM‡6aèYž&:Fd¡s¯ÂL¼e¿©=!“¿ëR4wnËûBWqM:)ð%šÇ%M÷!WÏ>áùnþËól“f³`~ü̬¨þo(w2ztùŸ˜þ%E>îsÐñÇ"ºêzFÇMèh£§ÙËŽ!<4ÓF*Z’áÃ1-=Xx®RðŠ—H§.RrøÎt™;š/"aSº¹nÞ¢éI†ÒèäZS~´¹ð5<×Ùa$Ä6—™Å%᧎§„TBŽjñ²œo2^µ]~Ü·ò!|óc–Âk$Åfò¿í"vwEÊã¿Æ9H óÔ‹³¬…þÞN› +MÏð¦mƒÏ,Òë‹(J4±Ò‹Fë~±®äÓº¬ >ë'1¬ Š°m\9PZuëY«_ÁÓíÙú6k»îí­ß—/—“—~ Oô.ˆÞˆ8ñÐHvK.Éîzˆ›Á=#¸~þ=îHûbçî0“‹Qâ[øAqÅqBŒº[Ÿçðµ ¬øõ<>|ÅϵÓ4pÆUÌòÝÑøãxlú8æOÑØsÓ~6šHo^ªa“^(¼óÊj:ïa+€´?¾Ë>nÓýqÿ!|Óãnó@>_®:1Ñ'Mδ‘9á8¢pòsEqÄ­èâ¯ÈæU¾-Ò]q¼üÜV¼à +GHJ$09ð—n©gØÿD¼{Xï,‚»æ)ú¯°åÄ®´žtº Ä;Ašž44ÆŽÃŒ *v³)Fž#ü:îa€~]`‚¯‡i°¦Ä§dœ-‡P Ÿ^§Q]Pxëõb W˜b÷¡Û¯¡?ð¡l€Îj› h.ì[|ÕÏ‹ë} +Aê¯û¯KV¶ ©ä >t¦øÐ…äºíìš²èû x*¿gùº×ºááË:òª¯ÉómšÃ­ÙU£Í-þóýÖ]3Ö endstream endobj 82 0 obj << /Filter/FlateDecode -/Length 2234 +/Length 2965 >> stream -xœXKs#¹ ¾ï¯èrÛª²[j½­œfÖ›Ä[©Ú©%{Xç@uSÇ­¦ÒdWÿ~|H–’IÊe Äã#Ø×ß ·£¬gëmVf#ø)³Å2[Ì–Ùúý–¿Œ§ãÁCYÎFùz/“ù¨˜Ïù•Mó0Èþ¼í……'ÝÃßVÊ:®;H»×õÝ*Žè6Ò6UY5J¶6òFÕò>Ѥkµ=ÝU%‰ü?~ù{‰¶ükýÓwå2{('Ùº†ƒU{Ñî@Ãx´(fËI¾·öh"k5Ón"Ž£ªÀ{ëW9kü¸±jw‘¿ûÛzýéóp8¼óË7Ò¾IÙžo¿¯mt®{¯\+²ðë~LG¹²{wÖQ<ªÝ+<ÙtF'ëTõzÏ<ëvdodçi /ô¦šÆÏy_¿Spìôï§(Ó¨×A9ÊÃôN“S³Õa/EzÓ‹°:ÍÓµŒgù[ÛhQ9ŽêÙIa·òqZŒ0:d°l>RÞx¿ÈKä|Zßg˜Î èUšLÙKe±ÚÃZ+»9³ÚYhV7L;×HTío…Õ¤œŽÿÿã}ô%†Ë (ûÒ›aÅdThã¹ ì¾sàq¡ J'ë$ V œÒX)êLo3#im'(<Üγrî¢6™.psJ¥« éàaÑþéù¯O?CàK)‚ð‰Y@¡÷Œ×á‚ÿ[þLy:_Ò­­QDbq­„Ž4€Y\z«Dx-å|ä\X˜Ò–§¾¨]­A5í-!윊Œ׌ۼH¤ŒÑ‡„kÔAYWJæ¢æ`w Ì -;žHÚ9£Z´}±, nE‹¥tJFT×éÎÐÀc¹ÀK8L¶ÚFPº -4œü"çÈÒm˜hqÈâ§Ú~E‹°KJv¥ëÕ m;}xßÚÕêwM5¢D[hºjÁkˉ»"m$›æepOì„îçlšu¸Ë3"Œî•»,yÛÈ*Š¸Lâ©M|P\ žý^:šGM_íÃ8E N¾íÁÐÚê!#¼o¨E!z#*BѶÆF]¸=Opaº\úaâ¹Ì¸ŒÆý5ˆÌD,6Ww×[‡ó -û9¯ Ч?@_Iàqê\Òke ‘o€b?=§øÂ÷§’ç¹g ËzèÒÄ+="Ts®1&¿Ó% \dξÌ«+Ås ¦s®ÌläB­ø)Óº³q¶°n/á`ׄÚðk(²kPð:ì´Øl^x€äL6ÛÈ8匭“¹Ððßã·‘ïêŠîÚ£¢.¼ðâºf¥JåaW”ìIØ“* GCSÒ­ù?œ› çï¶?:ëfs£Ão ìΕÐlîí­{vâèÔÂã2JPêÈ -Dìx $…Ôä}üæø¨í¢W$7E0½,á0DS.â&ÂÞGŒf¶‹|7Vtœž—¨c…ÿîA܇maè||´ºh{FÑçz磑f¾CÈÝ°( -ü…ÕOÿ|‚¿eAÕu~±&ÊuÐ@Æ’%~±Ñ¸QþäôÍ®ƒ'*Ÿ¼í³á=š?5±ùÙÚ#œ)=‘Cê1®œB9¸c[¬¯Øô2ü”Ê= Óè@Óm虜`‰ÃÞB‰ïCheçé´y.|¢x×N~!\X÷·r&9iÝ-’#IöQ0Îàø[°æΊ¯é¹/Ôÿְͨaû€ñþ:˜@(L׸I"ÜÓþ‡M1æÃôyÀT.càXØÀº ¾ùÏíßgÌ.uüVq׶û¾Áî¦%Ü$Ž>a1ã@†ÈðB$–{1bü÷?¯C—sº¦³Ö×õµº'P €°h ¼ðÞ½Ÿáó@Ë}Å‚`<~à‘ˆô0àî ~DòüQN ¤áŵ°"¢†? Ä‹×B·Éï“)Œ}æ·°;/NKÁ¦rõ¸²áœ>ˆî †¶þŠ!ï"˜,ØÊ*¯ö²ØAàsŠrº‚ ‡ºË¾]Kv5¼]\VØŸÜ}Ë«l~³È}5«o¬âZã“Ôs{™ÿ„†´=å·þd´ Ÿ5‹eHÔù÷E7¶L’ÝHjš E…eÐîJˆh³ ÷Œë ½À&¬7ðÕOz;èƒy¢ô²&DWà ê½||t «§ù›%1pãP£æ;?á»ÏCÛ…ÍŒgz_Uþ ~þL†¨òT|ÊÅ)þnæÙä3Ž‰£®„ƒ2 yиO¡aÿÄäZbr´äžqùXÌ i©šÆ3Læ×Ê­ +xœ]ã¶ñ½¿b‘—³‹]ْ対—´A®8‡Ä‡EÚ«» œ93äpÈùäè¾?üeqZÝÅÉÝátß-á/¾Û&wÛõîîPßý>˳übº‡ù¬9/þSÖ­íúÅü߇Á²¥.KöÑ +˜ÿ8æ«e2;\ Üpt濃iz‚£ån5ûŽ9}Ç3lkº¬/mã'¸‹ª‚Ém™?yÊÐ2¶þ<ýµ®ÊæÉ‘d,ÐC¼Š–)K•5À+Y/g¹mú² Cƒ+›3]Í£Ìñ/3¤aéz“ {âßÇ$+á“Û¶4.’{ÙÜż—‡U%éÝC²‰ÒåšÙÍgÑ|¶Ÿ?laÙOv¯g/Àc»›õ– â¾ÌãåÌäCo™Ûº†38†Žæ4O@’N¨|:œzÓñðlùh0´ ÅüýFk*\ÂmX¸ ¡$ÞE›ÍŽìÇ­u®<ÒaCÂÂx wWŠwqº`B>¸ÞÖì Ë^.e~ñ²pµÞÁšï ð«àè6œIV0ÊÜÀñÓ_ÉÖ˜œL O¿¼6Š¾7u‹V ö²·|#Àw¹ZExlnº>+ƃٖvzI^Y¶-¥±¹*—Q¬ˆ§®©zW´yŽv *Ë™æi²šu¦ÎÚ–@ЫHÜ ‘tZ‘xáT†ÔÈuZ⛬6¼ZCeBSq +£Ñc˜œõžîE|«â4¹‰£íœñ‰\BŒX#ÖzśǞYaŽi£‹µà·‡?[ßí£ušÈ40 ¦Ža˜¬R `¿ \ï˜ÛÓìÀ•ub4 +÷«1<Þ­ ‰½ˆ”\~Eÿ&óÙýÍö«h·E68øiñ×?=ªîêéjm n_ÃbpÝÂ]À‚…ÍYÛù€n¾du[7ny"’íÖÉ$â Ò 0à ÕDàÛ.áJ7S¡/^rìûˆ1µ¹}¨Ðç_r­ÉKÜ7g˜¼û”åF¢ •H÷áÿ¶ÅÞ涺=Iºy‚h÷¹!/ˆ„â”Ç +åPÔVe^ö¦zoÖ A¢¢n9üÈTgºgŠYŸPÑ1ƒ]è¬BÌ=®ùˆhèpL~)û‹_õáÓsêi¶»¢l<¥íø."?á0ßÁ M8\QºŒü>¦Àél@”ó`Ì·t÷ž48Òn4Nãh¥fû}Ùï‹¢Ãk¿6î$-ͶuÊJ²–JÃtNáX'dž†Wï zâø)X@âøãÚ!IÒhyãG™s6/3NDÛU´VàøµY×—ùPeÇAzAEÚîÉ#¯ôK·HÜœ{Ìs¯~ìZ˜yø· ;.åÛ +vpÁ:Ê„ô~‘„û·VpeÀà£|€æ]Ï`¥.‹å’åߌթ‘AƒÚž +,Ê&¯†ÂH)Rt&RABßC}ˆ·;q£ºì„xÛÛq A¡vuÊqï×¢ÇÊX„÷Ìĺt5ģבxôëZXEå¬Àh€º&䯻KZ÷ +üeB>çÑeÅ{(u# dËǹ觬*U Ý\*Ø3]”«ÈhkZt =¤à8d)…¥ªÈ³®ð˜À•CóôÊYƒ°Ÿ>˜Ug=Ö‰žE Áµ?›^…rÅRÚ·¸»òV ñU‡ZYFô7¿Î‹¢ß$Å1müåJNŒ¿ñÈ÷<‡ŠÏ–Ræ³f1žøWRŒƒ´ø¼!Cñ :¹–ÇTožWYR²ögÔ¹Ï{©Dӡ׆`.Öõ΃\Χo³´C +V2…·Ô'ð.3.n‚uw§Vö}cx÷PÐKƒ@/t(æàÅ +‘¹ V¸ -¡ƒä1Q_ƒ9e‘Ñ»lÉOg‘±¼déb–âß4k?C¬µ¬Ê¾¤¨ÉÓQptŸ²9YzCëJ<©t¼É–cPTb~Éšs@º„+æ’a¥ô\‚©¤KR«ð|4€8CåKí§²e(†[“‚Chdyž’zH²ŠƒTå¦ç÷Ýë×Øo¸q†jhD°•È +ÉuBboy#NÌ\À¡ÂÇ#(ož¬Eà`?vžË\1cå†_˜Ûñº8ÅZÅI';­z~àC~@R—·÷ÌÍ>Úúò ·nžuˆä‚•ëú71(IÖÑr=]˜'„>kpa—ð…5† /R›£B `^úÝØl øŒp’L½à-ýyA~(•l£DŒ†±TuŒ=›<¬ò$Ö®yæ<ƒÏ.=\Ž'zù…zå!#–‚-¯xÿéàñ¡ \è[ëñúŒ‹Ê8Á}¨³3ôe¦R©KÚJŠBª‚àg[û*”^~è*‹Vü›€«EK´¼ ¨ÿŸ<ýˆ‡gí¾a]ÛÜÄÃoê\Š?¡Ë +î‘ÃËÿÛòFîa²“Ñ÷øR¥üÓ…ýöñýÏÂʃ|Mᜎ +PiéAÔ‘ŽIG +˜Æg*/bŽoXk{²” ÖÇ ¬£™«½=P°&šÊf…7‚}ž²³¼:®Õ¯ž<Ök•Í3)ôPQRˆh±1×z–°æƒ|g¨oí¹q énÔMÖ€ïa&”Jp¶ÊÍ;€Y¡Šú³Ž›S2“_eÆUµtÕ©oO.؇{æ<×_℆M}4J²_’íg§L(ó¸›ø·Å“?ÿòÑÓË`g‡žv¦ªÓoYciñKcêky[dLÐä¸FaBcâ†BÍüP³‚?ð*y wVƒ«êãÄSÀÀQ_Òã+¬OÊQ,ˆ”¦¸i¼†7ïÍæ|ºé¹Bž„Ÿ2R´Zzlˆ/l²N‰Ò24E‡š^6ãÊÌB&ûç<"(ª‡NWP‘ lW˜‘@õ‹L ­Õ^¶^“Å…u«Ðu~Ç~ËM×õÝ÷ЪqÃq粈ãŠä¦ÕÆG6ƒJA†[JJÓJY\\òìcÇvàÂZ[qyãç¨l.e ¶é+©í¯ÄPw”5 ˆ‰@IÑ)Y®Éh‚F `°"¥"Ù§“ãßóWŠ‹<)¤$Dm-0S]•®TŸ-~,Uh¬Ve-7ÏtO(µ·é,BšÞʶ0wÍŸn¿$j©Ã_hbýÄ£µäŠ?ΑÉÊxœŠ€¼e!GWOÅÀϽ$åÓø±xÛSN½÷Ì(X + ,¸p_a {ÿ—ô ®ÿ&£ÉìÑÁÿÌ(;mÈ ÌॠÍ.ë{ ¾Al§%€RÓùæãBø0¹ÈCÅ6°@ød_Q÷‘}C#>0&×’ Æ´þÌ ˜ endstream endobj 83 0 obj << /Filter/FlateDecode -/Length 2349 +/Length 2608 >> stream -xœ•]oã¸ñ½¿ÂÈ“ IJ$&ûPl±-ºE;à‚îÃm± %:âF_'RIƒCÿ{ç‹"mgƒ+D3Ã!9œoÒyøÓê”β|öpše³þ²Ù>Ÿí·‡ÙC3ûunÇ¢Z,óm:ÿšo²ZÛdñï‡À¤Ý,Ûá¤åz“ä›Ù2¬„ ‡ÅVÓÖ½[.æ…**8nžÎ—tæt¶ÌÖ|Êô•r`}ÍÈ&ÛÏ¿ÖL°Rõ)`xJžßÚê6šcÚ»*ZšÄIþ±v s˜H´E–λáÉ?2\Aò"½ ‰C®"ãý¨+…'y6Ý8x–˜Áš¦¯1=xB?PAx6¥.ÚÊE{U"îöGÂËh¡ÚËÓV`m+ º#ý’Û ú·Qc2•QÀ¿ ‚L1 œ½é!ŽZ¯VêÞU{7q«@•°{ ”ÊI#EcðýüËOž_¡1°tƒIìû-ÖßÌ`é:=pÚr¶ÐÔeÀ1Oz¸¨µÅð|¡8ž±Ƽ«£EðT~V¼` ^œôsàn(õðö -X~Pe˜%b©"¤WÅ“zÔ‘Lœ9ýê2xD¿bEqV/ºY‹Ýú¨¢NÙÚóH²±ã°ïðÿE{òà¥j:XOz¡ˆóÉ€È~â×’›¸Æ WîkS ë&Ó -¸7¨î5°QÇ摶‹³c«{CÂìc4Ïŧ "7±a ¾P¯Ù4ªø«ÚvkƦšDýOoßâ OÓ•ÑZ'”©Õh’°©zb„0c)È. G&B°P³ªZom¤ÊÒœKeÚ0ZÙ œFÙ|BÉ -âóö›ý•÷|‘¨£ -Áöæ¢55½Bh¹seÄåÉw©2õu®ÎÒƦ<ç (Ÿ‡Å²ŒPγÓF&ZRÒ# =,x¬4't»„N1qþ¸ŠÄ툉°)%´ËÎîï”$£spȹ½$_º°¯i­FÊÈö*Š~j…=„ bÔ«×ÅÛMÃEûäÇ}\5;¤Évþ8ÿ&g:óÕí:‘ñ_ãx£…eꥅÖ@î¦ÎË„&f¸j¿–ùzÜMž3ŸÑÜÙ²›Õ]×ÏV¥~^%øÄlõ¬†¥lý–œx–íãêM‰ã¶îä|»4Œm{};÷e‰cïÜvá -oìCØÙp”¡‘dÖRfùJ‡›Áý ˜ûúÞ÷šÝzË÷ŽÉ¬Hñ­÷`¤’05-,ÌFyо6Ц>MK?TaIÎ <†Q;<ÍÔ­yäa„4 L¾W…kÏØHÊÚC k ½ !æ›(C Ô•'¾H…há6FeŒîTr0›&ø1›ülÚÏEé=êŒ5lÒwÞx‰À®¹ØjXÚöj;ÕÃ&Ùv黎CrØæW‰âÃùªg2¢‹Ä ªˆÜÈÏUe„AÐ6ª…~K2/³Í:Ù®á¨zÅÙpy -0ðK7Êì}$œÔKa‚Ãan&"á=¦'&s¹þ0ñ´Iv‚°8Ч—#DL®­½ÞÀÕc½}×ÜwPó=G( À³Ü¤{p–p¢¯ñu<[ßípJ%¿,Gé6T›B.âÐ]â‚«¦u+Ššoß5äMý-ÍV}×Õ2|^'Ä!hͳ¸x`ÇêËÇꢡÉr蓽_t'Éýe(‡ÛÆÑâ‹ w 9)ñ†WºaŽ©’†p[ÍáÕ¦x -#cÏTi6„]²¹ -)Ê—È¿à+£¯E6®o”$©Ñ¼š”m.†§¸að«öæ] ®²õî²ÛÌÒÅÛM¾‘¡‹Ñ7øËœ@šNx¤À?TÎgC@J7€ {Ôßbþ|a°I4ß‚bEÏÂEÓÃQ %’`¹IQ'Îwa( šÑC¦Çƒô2 ^Áé4‹n©ñ -زÊ0kzœÉ¢Kê$3=[kw&›ìÁ£Óo7ðXÃS¾ÃÀûëÃÿ]å'Ò +xœ•YK“㶾ûW¨öbɵÃ!©çø¶ÙØÙMÅötË䑈,E0 ¹³Ê¯w¿ðFS©ÔTºÑW£ûëø—ýÇ|V”³ýqVÌrø+fÛr¶]ïfûóìŸó]½xX•OÙªØΟËUÑ©¶½,6ëù{n_ÏUw:ž™uÒž©TçÉCh´ýhÎæ¿ZÆ]ÏÖÅ)Z[©6Œ\Uz2ÏîæyYùܺ¯¡á ‡ÑÓæ話 óöÎ~¿,þµÿûùì¡XfE±žíkØb­ôÙv0вÜÑÜ”r¶‹4 ç™AÆtIƒJÆPÛ(ðhÕdP—öK™fêj§ët9ÇH÷ªú +æN¤£e¢¯Õ¨ïí÷¥1-LQeVløP[=\†QŸ¹5ß-Åô‘¯ì0&,-Ò3°ëb=?µæd­Î¢à“NÕÈx~Ö +Ì•Èjãt5ZwIfDçñÌ!Ñz]\5ºo4‰²X;Ýú†·Þ+‡6j7€÷–Ežm6rȬy‘]™1JNš À±ZóÚKT9:{¾8ŠÂîY†þêE¨Ö¼D©ØZzÚsßÂÚD¡¶‹"¢k­ªu²ÜØ=·Ý¸¯u>oÔ¢ÌçßpBÍ-ß°Á¶jd–Êv£îFCëñ¸™¡5³‡Œ¹ÜÌÊmV¬W<ön1Ïób¹xØB×? Ô- ´ÝÍ}6‹¹šF{†ñ+nÍ:6þöŽ–°Xæs‰×ˆPaÊeœòC?¨Ñ¢€#Ån•=A üþ7¦wË¥x”5š^8XŒb/²aÅ^n{í`µ^ëlk áØÿXµéNQÎÜkÑFÃ<Ç( ÞßÁ)¯æ}®žñDÐýN „ûrMžñbÆ&rï¾`ÿw±aÐã‹{^d±mOp&L­ˆ©jjÇ؈;M8­…¥y†pIè±Qɼ“ÀÜ{’IdÓ dQÜâ†;.<„l±ÿ7JÉ–l‘Oìÿÿ³/»Å*ÇU–ë  €Dàáóö;h~3Îvgtò(iÍW4G¢ûÂÐ $‰Ž[æ°‰LE²·nT‡6†‘ö}l`dæÝÔ£Óêü.ã•+œ Úùý‚sÈAdç|ÞY²&…¸àù%tämÐo;ƒ©=>PÀ2Rÿøð;€H*‹š¿âøTsØ &i¤3N9ï£*çº;^M ·*žØ+"¨D€¦­¤{uB&:!k€Ãj ¬‰$!ûMŠˆ•ª¹;¡x  Ïu:QÒ¢_Ä.ŠëÚ€Ü9®·d†W_Èd¾GêÙPAQl)·‹ bhÞo娤f[ŸçC®ø¼]ÌYÓÒ½ ?ôh§dÆgDp’ýb ÖHz¬# $+l šUä2U²Ú³â€ +‹V÷lÄÉ‘mµ¢<ßÛÈEF¢~LŽ#…ôáJMdq¯ÒpÐì÷¢LÇÜ;7$ÚÎòһ؅cÊà,êí¬ðjo¢9U´›‚# 8¾š)D-ø•ò –Èy‚…øËá†Tj%ßmê ³XÉ<„’/owñÃQPÀ/îð å5àˆ]gQûóñÞ!z¯ùØèêëg4®8ºüS¶\ò4HS!†÷ 8ªÖ‘=è–ÑýÌ7J‘¸t0€»î” Ê ÃÁPGÜrÌQL™)™#ô*ãp«×g +õ©ê®Ò”/TàŒ©F)79¥øÐØðä×*ôØ8;š¨­¢¬š†‘jKá1¸uÛ’‰DêÄ3¶¢óIId¢I5®H &×%«&¼ã/}¾Hô$Ç'¹ãëèÚTw/ñˆ¶x1TýAÚ“bÀ3R•/“Ã&nM^ Vž;$ªNCŽ‹¬í¸l–1É›7Bh,ú¾oØß[Ôh଼ËùÞƒ!ÙÏ_˜o„ã ED Uh´ÂÒª(¥ž©v wÆa}H¼ŒQI˜ß>`õó1(öÖ¶÷`nZå‚æèTuµØc5w|59¸Û%AâMé•E ßó‘C¤•<ÅÏ×øò‘-Îï»øî\a6áàÑzýÃ%ÑðQê…|%¸_‰¿ tœÅT ×ÇÇi0',lá‚’Çì’þ&Ñõþò +~ø† jQÆP EBØÏ]Ôº=0ï¶Pì#ÂaÄB"x˜¿ÂÂ<?Œ¶¤„ÕdP W É™i­#ðø ²ðÏ!Û¸kaÈj”=˜—û—püPÀ4¿4ÛódêÐÀ$a:ÛÁ­ïá\Äûîr#6” +¸Ñg$æÔÁbÚàÜÁˆËí ¶[2©w¢;NÃ!‡×Ó[Óu7†æÂ)*¼Ifù÷Äjì³rBƽ ½9•åóVõ£í™üuÿ×5~Å×ø/xÇàËŒÆ_ç3Žoêgýß÷ôÏû`Ÿ B÷vðÝ(¶à.=]ÁUcLd*é[§Õøy;ôìˆf žoܯ‘;g2(=©¥ +°@COS\íyÁ˜KÃE ¾¿…ÚÓìÔoåªÄÄ4LôÀJ<âÑ×N^wb“ŠêP´F7΢ʇHB +o"ç"ýùö1µuÔÀRS™t:Ê®ÂÄw/@0 AðEWTÉYýXª”6ì3Kñ™Û !=ëÐC™â•‹=\CÒˆ‚F€WòÔ†Á’\—‰ŸŒ¿›§!ÓONš,g ˜¾¥§] "¡ZÁ•‹ó{ +\¹cœä¬Š ë9ÓÕ\ÑǦ`ܨÇýà(W÷¬lò¶½4¹šjaù¦È#ÖºjùµY„áþƬ7—Ò ³‡ûy„<Žn ÅŽh?6ÖT=»R^ÂJ˜¬•Ó1j‡iQ Öläñ­ôëõŠ§ºªy+è‚ðÀ7:X¯MÐp­8ØÉùuÁ#Œ~3VË¿Iy‡Éd¿ÒÞG„Ï Ò‡|±3º«(ɲЌ?Ê to àøzN~9eúÔÚC`Ø­ /½[¾îëaÕÏ#o³õ¥Sgx™½³o¸úQ¶[’õý€€°§¦ Ö±dÃÛECóÝ(K¢ +·º¾…6õÙŸ}¯øu€¯ …`¸ŸJ†ôÏY¾†êׇM†¼÷P£$|*Ömw ÅU,1ÇË-äX(u«±£oWŒZE¹ó_¾+|Íÿ/‹W@˜¾}±pÝ¿ZåÑ&Ï!•k8‘á¾Uˆ=þôåŽr|b?×›Õãù:ôÓ½jëõ¨¾` Y§þ3©Z5™u§dìð½½ÙÃtfè}òÏ/èžã3Ͻ!§Š«§ðà“–˜ÒKê·§ðÓ `¥ú>,‚zœú¨áë8ao +¹÷±ß«4-n‘&K8æô³ ·p¦â¯ú`¼ÅtTÁ¡…¢Øg:/!¯° +[^Õ…þTÄE ôØÏJâõ >’w•[ô«_öÝ„ endstream endobj 84 0 obj << /Filter/FlateDecode -/Length 3047 +/Length 787 >> stream -xœÙŽãÆñÝ_1o–‚J$uæ%X; vÃXØZøÁ“ŠjIôðPØÔÌN¾>uvµf9ë`€U×ÑÕG]ÜvßÍŽó»4»ÛïÒ»9ü¥wëìn½ÜÜíš»ß'Å0¸æ2Lïól›lÓõ¤hp\`>Ÿ†-]?UËø‹ë«n|JYw¾jOFÎ.’Òµ­+‡ªkfßÝR›¶âeñ>"í»+íðC7ý÷î_ßÍïîÓ<™/à”<Óô~‘å“Þ5ÅåB@Ö{ÈééÚ¸(#é´0H曜·³2„ÃÚ[åßãÙzhªbEFwG%ƒÑm‹ñ1r>†îâÝô>[¥Éz9©«Çi:Ÿ8âžsÑër¤«T Ó&·ïÝ%9wÝ£ŸîþˆÔ¿Ù&K¸"f;v=SUH -BòSŸü‚»ŸŠ4Y/Z%1 ›ûÕ9oò|âY³†XLu’Ó¿ÙtòîÕ¶y²Ù¦²78øqö—?=êîæ÷‹]oÄ‘šj`"îÐ…a&…êÕyºw6}VƲy&楳!"½âÞæ]`–km?h:'–¯«k·þLø˘6,íÑm¥Û,™'ËæSQPUתº ¹U°oFÊ -”›à©ëV¹©­ÈR`üŒ®ÆÃKç}µÇÔîoßÊ”¢ÿϨtË} ¨×áÔQ©˜sço •®`À)JPiXÉá–7`N&·Ñ< ½c3Àéfr¢¸·ˆb½Ð¡ ëú!ÞDáGDá44…òÇXu -Û©®{Î>Og‘q勉ébæâá6ãs­êj¨(n2Ûný§jÝÃ4± ”™©ò†f=Ö.É^„Xž‹ö‘Îñ̽;X-=U`*‹9©Uä'ãC“h(±v÷Õ…¡®Mª¡‘éea$éÊóýË[bíÉdª¢€`3‘’ï„ÄîòÕ¾±ð‘„¢I Ú›fKÙp´nväÑõT• ôˆk0ü4À¼Èyš-Õâ(Í’â€T>?ò!?J ±Ë Ï\sµMÖ[)¥~§”ƒ‚¿zÜ!’«V.î¿ -BY¶LæËñê<ç(ôY£ û„U׃¾HŽŽA€?t=Û<Æ+JJ0/)DÐ3ÞÒŸÇš„©ldbí0L¥²cìɵàbµ‘X»”…7Ï&. ..€lŽmÿB½q‘€¥hË3ÞÚ>Þ(×:"¶3<¤†á -ÆE¥œà>6Å©jÝè[^Ê5pÊ®–Ê*!xÇuƒ­¥7… }Ý¡?GÄ6’ãQ-¯Ä<¾ÇÓ³z¿Ýtðƒ¿*v)Å>+¸0þ–å…üýXØ& ¾W)…§tc¿ýôþgƒ°ø gSĸc¨¼4•¤cR’®í®'ª0RpXpYªHíaÎÆhAîfm¬‰¶îŠƒ‚u‹“<=^]}9ÔluWR졦¤Ñz#TØz˜¸îƒ”‡h^ ¼^N=ì‡jäáJýhø8¡\‚“\ê⪩09š¡è¿è¹I%œü6cÉA‰Ÿ2× -Bi¨zbwTnxèAÅíà ~Ï1qö„×[ô3jn`£cVôå9ŠâѺ‡ª«ì ×¼‘ærhQÉSR‡ œ‰êEüüÏ_  K4¯¡ä¨!Õs/0·:Cˆ:P¯Š±ý»øȾüKSWí£!¸öShïmèôÐîÇB v½Œv%@W ~K'’\M1بݲÖ&$tõ•£bØfèŦôEëÔG E)8fÒ`ãÚ>‡sï¢ Uó†—qi-oÞÅjC¯(ž%†}>vV¶'PŽ×N ø¦:·&pÏTJcÌCMSA—×¾>—£Ö9Wø"b^»Å‘ó¹f︓휬¿à! -l‡E¬’þ¹ûdD±i¥é‚BåâJ!zà)çÞEBôQåâxcà¶â_g3#þå'£WÑ*¾»öð†H° 1Z¢~ˉ–À4¦—Y#c¢fÇ- -“‹GjaC‰Í -~Øá]òxÎ`Å8ÃÛ1ˆ‰ú²˜ -©7kä (ž2…‘ó#®’ï s=…°åìá*~ƳẳÍ"X0Ä›ç Âx*>ÿFQÌĽ+ )®Yà`4½½h n¨¯T.ºŒ ñÛI=Ú Ò/’Ôx@ñ CÓHé=æü gáÞQïB ‘c½‹¨ãJQ2|¤q‘d>I˜ÛÚX¿!*,Ê1¾J¹‘¢Â Òã+¬/Ë°-–îðª{s…ðîlOÇWíW(ijø³Æí–0â ­W¢´‡… ýÑkCœÀ@éYÈäß{CDµõµ×T)C×\ P#×@—u¥—d3Baå*t›ä±ïòª¥ë‡þZÐÂÚqÅ¡çï2‰åŠäîÕÊ‚ŽA§ Aǽ%¥i½¬.1™{ß³!øx†Ãa)®q ¡ŽJ‘REûÂŽ}-þÍ6Ô!e(b,VR€ÊæK2›¨ã,L©›Hê¥Áø÷üÉâ,/ é Q{ ,Ô¬Ò•ŠãS‡ŸN -5«Ìå.š® ÷z1‰v! p;| ‡-ßø®(ŸkRýÞ£eÎ_êÈfeX—¢LäkTŒýÜTR9­ÅÝLyõ £x)40áƒc !ðý_»ÿãê‡o -M ½ûϵêµ7:™Ñ{Aº^0–‚€Âobö7B(µŸ_}gˆßGAŠYH¡ -Øyh-\JZɽ3 ¥ÎØ©†Gî‰>¸˜mXV% 6Zô> +R¹$À>â½)€YEÌrÛcŸà‹`ã ÇÐgÂtnOK¢/zB¢@"è#{£Ø·{!ó ¨–cß57‚NÏ4´W%!Ÿ|ÀªÜµÌì°Ô¡¯æ¶ô«FH˜ØŽ¾^öíQ*-?©ÛŠI(*­5(rxÈRð%øÏôØdk¬yþ±û‡ -^3 +xœmUËnÛ:Ýç+´¤€Xõ°å}ã]êê¦(hi,3‘D•¤âäïËÇHd| ÏÌp8g^þ½¹{8ç -’æœÐ$7?šŠäP“fLþ#Í$¤»¢>f5á +OÇ’°A‰€Ô2ÏBêÕð,dÐSš¦4D²§¢¢Ãæw™;¦!hŧ>ÀÍÔýj­ 2ýNN=·½m.jÆ•¥¡sã÷û"yú­ùt—';Z&MgHýòÙZåd„Is1Aç¡^“‘“  S(uyÈÉ U¬ëÖ M<Ùz$fëÔñÉW6öÐZ±UJ²””î[xòÊ+Œº(|Ôž[A3º?˜7@2ô‡"W=ÌL©«]Èèªù7bí¶ë[Ë®*ÛO*À‘÷½YûQ1}ÁÂ#$ÂyÆÙGº.D³ç›ç»‚>fu²«÷NQ­ð¯æ'Ó < endstream endobj 85 0 obj << /Filter/FlateDecode -/Length 2657 ->> -stream -xœ}YYsã¸~ϯPÍK¨-K¦NËû6qöpj©”ò´N¥ ±¦$Ç㟾pH¢SS5BF÷×Ýðßö¹?n'‹ídœ,&9ü[L–»ùn»ž™-Vó|#ç}É -Û¼,׋Óàt9­V›ùvû½™¾ŠÔ§/8ÿSdtºïas/Óyäíqž(õqºÈázê>2ñ¤ ¥šÁ“t"Oà‰ü¸¯T²Ÿ$Gë"¡ê:®©×g·*'xàFt óéþO”’lÙ"?Ûér“½iüÿ+agwàOË͘¦ááí@÷í)Ý æWãlsÖMßEIm^щî[¥“uÜÐ4tÙò ›ÈT¶ÖõêP'Ëtï]¯Ïw‘A^â‰OCÛõN«ó§dW ³üwêüyÁˆyvVdççrT[EîKÖUàŠ/Ó0Åœ5mÝk|ÅðQõ|ñœ€d?]5’›(É+ƒf¹9·u²Û³â€ -›Vc6b 25!Ûz=߀ÓÄðg¹HAÔö ãØSÈ -*/‹gÆA³ß‹2]sëtº\—h;Ë[oâŽÉíÒ]ÐÛW:ÙáÅ>Ds¼ÃõvÁ‹¸¾’GˆZðKq&è%O°£9Üp”ZÉOšÞÔ,VòBÉ·§øå((à÷ ùWwˆc¦«t9ÚÏDZKô^óTéâõ+Î….ÿ8_­ø38FÏOŠ8ªÖ‘<èšÑýÌ3{Fâ@¥‹Ü5§dT–:â‘c®ˆbÊLÉ7’E/2nP·º½Ó¬kUs‘¦|¡wL5Êr›SŠŒG¿W÷•³Ã©ŠÚ*ÊŠ¡€Œ4·®k2‘hö|&øó:³8”D&šˆ—^!0¸&ÙE7à‡º&o¿‹óØ@¢'9>9Ȉ¯£kãÀƒ|¶x3TýíI1à Þ¼ü-!âÑ„ñf°ŠðÔ!Qur\$mƒ€¾ÀˆÈ8ìZ]¼p|ê@cÑ÷=c?¶©‘h଼Ë)—C•Z¼Fòù Ááº{GQB•± -ZakE”ÒÌT»,e)™ƒ@âeŒJBüú«Ÿ§ ØZ[oÀÜÔÊÍÞ©âb³Ç(ªF|18¸+‚Ä«Òk%{ -h¤i%ÏDñË%¾<±åÑùý?+ÌÎ&T@¼Z¯xO4|”z!·cûò1ÐqV{P1¼¸¼>Nƒ9aaÅ”,8f“Ì7‰®÷–…PðËW\P‹2†‚H(æ|n¢Ö†Å>"F,Ô)‚‡ù æ!øaÈhKJXM•ÐZHÎLkùÞÏ…¿Gyˆ§‚¬FÙƒié¿„*TÆü¶çƒihÌàIˆÆ6Ð5Psï§W -»Ï¯†R3}FbJ,¦ ÎŒ¸Ìg°} “z'1+‡¶§×¦k® Í…7Ž¨ð&™åßgL¨±ÏÊÉ0žíÍ©,ÏjÕö¶å1à¯ëØö±“Ÿ…žzïBÚø ·ñ_°ÇàËôÆ·ó¿ǺïþŸ>]jÙgŒ}°OP·¶ë u(žƒ§ôãZ>‘©d"vãµ-Rò D3Í÷í"Òs&‹¯ê”0œ† šÞ:_íyÁø–†F ?BéÇìÔ#@B®¾^b1t„ð;ÓˆG¯ £CY*ªCÑÝxU>Ç!¤ð*RÞ(2Ÿ»¡.£–šÊ¤Ÿ£ì*†~­ã8\ô Ap£+ªä¬~ ,Õƒ@Jö™•øÌuCHÏ:x2í`pãb×0‡t¢ Ãá -W`IÚe¢ã{ó4dZ@6YÎðù$‡ÐŒvpaüž­ W`Œ“ÌÁª¦v‘2MÉ}dãF¸^ïG¸º'å×Óè¥É•TÉ"¯Xꢦ¾Û CÿƤ·Ò “‡ñ"4x•>ä‹ÑMAI–…¦ÿ«|úÆŽ·ßä—SŸj{»@Ì¥wËÛ¹Výwäm¶|oÔ^fG0 -Z?ªÑv+²£ l੆ÇëX²a7BQãßÐü4Ê’¨×­.»°…‡MD}ög?‹_e‚é~Ãý§dIÿœå§aЪ~¯qÙdɱZUI.>øT¬ëz éE,1Ç÷kȱPê}ö÷ÙvA.FöÃ7o$ú{l/€0Í›_`-Ü÷ÖAy´Ísˆd¥ûn¤»jÌõýw÷Pî(÷ŽOìçr»¾ÿ©¬ûn¬Úº]UŸUÑÍõßA•ªš[wJÖ¾ßëζë†3Cï£~AŸðo˜i~è 95èP\=†Ÿ´Ä”YR¿=†˜–€\h+Õ¶aìÔýÐF _Ç yUÈÝÅy7iZŽ™&K¸æRsm•p8SÂàïú`¼IE!…1†Q(Š}Æ¡û’áV!ç¦.ô·".J 7ZQïé±´vP{pe¾ã£SOä©nhñ•Ú+Ê®XÆu{Dzð½úЖŒ$":ÉÁL–ºîUwçµåm‡e`%'Ÿ ßÆW]¨( €‚ûítÝÿ ÎŒ]Ô¿þù K€@oðÞ^ȵ.åJ|<û`‡öÙOP¢Â§pSÜJÑ!'ÂA_u×T@¯èÿ%³Âm‡“_Ù”@™šjÿ§§ÈòÙ‡ZygN'i±„åï5ÒÕÞô!Y{U¾Ü|ÏÙ:†äC|Þ”áâÞÍùj—üW#O1š -A®7reœ@×Üã^†¿péòæ‘S1ñôÓs$øú…8é­˜®„í~²j"pÒ¹»ß o:ê(¨ëtYÁ'¡ü[ŸW®ÿû’|xÔ €Œš³éVŠ>Ω[LÚÚÃ] ÈdÌ ŸrIàqò£¡ -£ïýjá_1ðƒ ºÂ™–³=ÑáåRè¤ecFx‡šËe/¤£GRñcʪÆÍd¶ZR*\î0 þ°ÿ{º -endstream -endobj -86 0 obj -<< -/Filter/FlateDecode -/Length 394 ->> -stream -xœURMÛ ½ï¯àRÍãäÚª­Ú³oÝXgb³ †i¶ÿ¾ÇÆ‘%Ëoæ½7oFþÜ?=ŸKÄ*ÔŸCe|ê*Ô5Ôkô ¿)*ÞÒšu8L@~÷?£‚ߜѶm£¨?E.|Xé  xJ£VÝéÛv %ïV¾œ´añçœc?Iká”^e˜öã¥ÏÈŠá]ŒÕ/ØUbóøy_¾ÿÈt+œÐÀù[È‚ÕGÚ•Œ/éÂäÌeLó«š6fR—ø¯tfÖ0‡OK=Ùz€•äaÒ̹×L f·wEð ¡+õa 6.S¤ÊxQbW Æ(¿J”|'¬ÄÛ×ÂÚÝ{ §î ›h¬A¿ÂÞuÚyÌOžNPæÝÍ™œÕ´k🋠bY*Uñtb>eWv0¤èÿ6Í*Oý‹÷l…÷הݸô$‚ȨØäƒÑúaFúŸ|†ZŽSØØ·³}Xã!3â‚z‡LþV&š=®{‹è)éßž*v¤ *ÚziTÇTüÚÿþýÎó -endstream -endobj -87 0 obj -<< -/Filter/FlateDecode /Length 2055 >> stream -xœ}XÝoã¸ß¿B¸—J@¬µ$ËŽô!ím{(Š»Öm6} %:f#‰*Im6ýë;Ãá—cï!Ìùàpf8üq¨]mÛ}ÙT÷Ù¦­²&S<;}øÓáÃÇÓ6«×Ùá”UÙþª UwU=ŒÙ×üÏg6®ŠU½»Ï÷EþPlÖyVä‡â~«¢^çr9Õ:¸>KiÄô\üûð7k¹Ú¢åU³)ëM¶ÚlÊ]»Ë=XCe‘WÅj×®óŸùí,Ïhæ9wj4àæ×u¹miúgÅ1Š‰©7p LŒœM0Q%Oô {6BN4Öܘ8)þ`Ý^,óToêbUU ±~ Í_%ýö—¦g%¦úÚ©®¬TÎÊߥ›²jà4&ƒ§¢nóWѳ Ù,úÌ{"O˜+¦qgÒ%¯V¬ÝŠ_äè ±¾˜6-¦“T#‹©aóÌ™_ÿU˜³p‚E/~’QlÒàåG®”TÄ$¤ó÷ãß 7ȶ»œU›C‘•&Õ±.½f{ßäBG…W%ŒáSd¡tWEÞ±î yjÛ¼w£æSÎ-&v„*ŽÓi’•lU¹ñE6„Òq›8;«ª)×~?f Õ–šMK>ŸÑaO]8 á…dÅ»6?º*÷Ú"±CÙƒ Ú¸]QžäÓ³:9aÍ=/Êæô.ÌÔœG-Í;ʸgÐyÝmØ¿Õ1PXÏ01觢8üçÃêÝ™µ€áNO'GˆË¤93S\Ê»P©^ƒîä¢ä%wôw § ®@G®5{ì©5Z¤Ç Vo¯OÐ_ÉÒýåpøL£3g}8š'%W´ƒÏÜ…ñŠgSª§7ˆd„h…&¬ùxjÀ]k leËÜ3ó•Ìǖ燇Çî¿‹¤zøŘùF-ó| ´õ6ÄAûVÎ~&¸vh=âYLá|Ö4ìU¿qE#ÍFf1Ž/З0KÿH»ƒÿéq[êí«F¸á}ÓØ<Á(†O“XÆ»¨¡²Œ€ jèÏ3ºáU¼+^Á¢¥ö¡ôu$lZthÛ¢™ 0 mt“¤8¥Ë5Ãæü!j„ëÓ+½Á81œ"…Tj^¦r V‚³7â(óhïf×gK0øíKy6'tñíL•WlÛêy³®èb|çDÚ’>›(H!Xj€5™ ÅÍÚ7t† ¢/ƒàŸEUïs9À0$ÆC5\ûˆ[{³ø]}Yl »Ñæ -Æn¾Û]ëÏí¢¦Ü/jjTˆ8-fQ‘LOt²^(9gÁ@X] CÍ'>Ñ}A4K€+)œ!¸Ý™M;7¢_fëú¶*a$¸+bÑÅã -015Ää¦ñÀJÃÔq:9J*ŠëeäýíuèºásYÔ¤Šñªï0òúJ?r¸ê»à¢y×Öý»Áñç¾JàÎÕ‘F°÷c9¥Óz¡;‰Iqi·H -2<²Ç™ïaáÄÓPɮ˼C:±RtËÀT´îÑ#eS$Ž‰`3Þ/Í­ _7*ÃTDš=u¢vƒ‘œääO”Ë­ À«=†99€h`; –v,þD¡ôólu—̊Ñiíµ" ’ bè^‚y‚/;†u'ÎoVÏWjÆ× Ùà‘æHí8ÄV­ŒjÁ¤2Ë9§œÜ%³T˜Çâð̇™ú2gD„…Â>Ø¥ðn…†qêxª µCï©ÀŽŽçl1 Q‚ËõA™•ìl ÉI¹l|«¶*×°à“2w‘þ&´0‘¤:wÄ+tðÀKSÉ!2ÞyîÙ¶ÖÂ$ÚÁ›ÖéA¬ÆÉuu•ëêê=´u÷÷СRG÷} -÷‡d—`[—ûíÞ«¦_Êhù“íÒàùˆÖ …ÝJí.«_ðÌÚ"~ѳqD‡IsÌ™™³}©mË -_Töàˆ -ƾš=è¶ *:5לÜEUc_lNn7ðz*y¸D¼Oü¹u"°šò»í4õ¡Ú~¹²ÏWË@,Ԣ瑴âÆn?3T‹“%í¿gÙÜ{âèu]î=ßHxsàwœÀq_d¼üœ,âñp}–Òˆé¹ø÷áoÖrÕ¢åÕf[ÖÛlµÝ–»f—z° +†Ê"¯ŠÕ®Yç?ó#ÚYžÑÌs4îÔhÀͯë²mhúgÅ1Š‰©7p LŒœM0Q%Oô {6BN4Öܘ8)þ`m/–yª·u±ª*ÐX?毒~ûKÓ³S}íŒTWV*gåïÒÍY5p“ÁSQ7ù‰«èYÐÜ,úÌ{"O˜+¦qgÒ%¯V¬ÝŠ_äè ±¾˜6-¦“T#‹©aóÌ™_ÿU˜³p‚E/~’QlÒàåG®”TÄ$¤ó÷ãߢ7ÈÚ]΋ªÉ¿ƒ¡ÈJ“êX—Þ³¹ßäBG…W%ŒáSd¡tWEÞ±î yjš¼w£æSÎ-&v„*ŽÓi’•lU¹ñE6„Òq›8;«jS®ý~̪,m¶ ù|F‡=uá$„’ïšüèªÜk‹ÄeK &hãvEy’OÏêä„5÷¼(›Ó»0Ssµ4ï(ãžAçµ Ú°)~«c °žabÐOEqøχջ3kÞNŽ—+Hsf¦¸8”w¡R½Ý)ÈEÉKïè'îN\Ž\köØSj´H¬Þ^Ÿ ¿’'¤ûËáð™FgÎúp4OJ:¯hŸ¹ ãϦT/No/ÈÑ +MXóñ´qwq`¬5°•-sÏ ÏV2[ž»ÿ.êácæ?µpÌó5ÐÖmˆƒö­&œýLpíÐzij˜þÂù¬iت~ãŠGšÌb2_ '.a–þvÿÓ7<â¶Ô›5VpÃûÍÆæ!F1 |šÄ2ÞE eldPCžÑ ¯â]ñ +-½°—¥¯Ó aÓú CÛÝàA¢¹"U”ÛÊ „â×Uÿ5×F*\ ÚomˆÕ~Sî«ÙF¦=Ûe|‰‘¡x`ÿ{‹Â‘XÀ¿­3ÏDìAÕê#sfÊ؉[ð¬; —Hf*>ˆKVmfÝ d0JC=ÃÈm,õzK;ÃÆ„š…peÇDi/üÆ'Ô†´.£b’§t¹fØœ?Dp}z¥7¸Ç †S¤£°“J-ÐËôAŽÁJpöF¼eíÝìú r ¿})oÀÆã„.¾©òŠ¶É¡ž·ëŠ.&ÀwN¤-ù糉Âc”tLcõgYüÆRꃂ¥FX“¹PŒÐ¬}CgØ ú2þYTõ>—ÜCbðÜ.jÊ-ñ’¡¦F…ˆÓbÉôD'ë…’s „Õ2Ô|âÝD³d¸’ÂRÛÙ„°s#úe¶®·U ó ùóÀ]Ñ‹.o ãQCLn¬4L§“£¤¢¸^FÞß^‡®>é‘EMª¯ú#¯¯ô#‡«° .šwmÝ?°î«îAPi{?–S:­º“˜—v‹¤ Ã#{ü‘ùnN< •ì:¼È;¤+E· LEë=‚Q6Eâ˜Ù1ãý²ÑLÑ +úu£2ìAE¤ÙS'j7ÈÉ™A@þD¹lm^í1ÌÉDÛáH°´cñ' +¥Ÿg{¨»dVŽLk¯•dC÷ÌxÙ1¬;q~³z¾R3¾Þ­iŽôØŽClÕʨö A*³LsÊÉ]2K…y,Ï|˜©/sFDX(ìƒ] +ïVh§Ž§ºP;ôž +ìèxÎ#á%ظ\”YÉÎ’œ”ËÆ·jªr ë>)séoB IªsG¼B¼4•"ãçžmk-L¢¼iÄ:aœ\WW¹®®ÞC[w*utßg¡pèAvÙ6u¹o÷^Õ0ýRFËŸl—þ?ÈG´-ìPjwYEøÚ€gV‹øEÏÆy&Í1gfÎö¥Ö–¾¨ìÁ!}5;5zе *:5לÜEUc_lNn7ðz* íéB’A ø˜\­íßÓ–xÊéÎ>¾‡œä‹ïcÃ’IhÞ”Œsá&‡{ííË@ž”6OEXl |òp‰xŸøsëD`5åwÿÚÙÔ[„jûåÊ>_-±P‹žGÒˆs¸üÌP-N–´ÿžes×u¹÷|#áÍßqÇ}‘ñòs²ˆÇó4¾–â‹™Ftn2uè±')ZG"G «es{8¾}E^ë@;÷mea@©¤x‚Þn…¤Á+“tmì$¤bðá¯fËÝ•?ÿu |ɨí¥Zïñ:ýtø?¹wçu endstream endobj -88 0 obj +86 0 obj << /Filter/FlateDecode /Length 2807 @@ -1429,31 +1393,30 @@ öÌE› ôRJ&ÆÑo8´òµ–ð°9,Wxj½ÎøÛ50r[5qبiÌvRÀ cwÇ0ò† ív¢Þ›Y¨¤“h=#™¤#tRpù\äökϘ÷b¯~Àê;A‡JtÝ&6S§ïøÉ#h÷¨„âðF¾_€Å5ÎÙeÓÿP†¡Àà~KZ»™¡TS’Û®Kˆç¯‚Úñ& ”ÆJµÝw~ãyý#WÝÔe:@Ìæº@KXåK¨k8F½]‚ýçµïg07Z;Zˆä|0'Ÿš™ÇÐ\h‹?l˜yþ×öô~Eº*­VÛäÑÉŽìÏIô#f˶©‚õ;ÐÌòG¡“ÀÇÞÝØ´0¢o®V46&ß„uh ÀKiˆîSøÝ—)^ž[Ö|›ËQßêÃxº>i¾Kó­;«Ëûá­+¶å ­_*¿:›››ððDµÃ)j 飞‰ u! w–­’<‹¯ ¼sVp‚›ÆéWó•/ÎC•§÷7ÞÃÒ°óa·ÃïÈM¦0Ra'h–=+*D0„¯* ?ž|:¹Îç„^•Ð -BQ Õ„Ã$~’œ$ã#ÿ]¼…e†Ù—ÏŸgxêwûÿôhB +BQ Õ„Ã$~’œ$ã#ÿ]¼…e†Ù—ÏŸ§xêwûÿôhA endstream endobj -89 0 obj +87 0 obj << /Filter/FlateDecode -/Length 1592 +/Length 1586 >> stream xœ¥WooÛ8¿OAlxðØ·Ú‰Än tÀmÝÝõ^ · w‡vÀ)¶kµ%C’tŸþ¨?Ž4Ý0\ -4ER$Eþȼ]½˜l¦¤°Ú@SüK O!_\ª» MCxFi6§—³@Q=ljö&Ó€]15b®DW„K1æôbI–Z²âa8|XßÐ5#|òi¦Ó ãº©Tš6êb ¥º†ñíø22˜ÔõpéVŠ® ?¯~1…(™ÅÓ™æñb‘¢“VÔÜ[Ì%ÇÖ_“'q6¿ì¹6’Ò¯ad2Ì„5¿ öån…©„°çµ ¥{p$úÈz¥}^GÉ|/³qxï‚¢î4üʽÉ/L*}៪¢Åƒs Z8!ÔŸ¢=‰@Û{ÉÔƒO––}.pŸ4Œ‹ÒÓ:E¶} -'ŸäË8]úøåÆEÿP™óxî.ÜI/—õ±B‘(›N +;ñ時ûÐGélgx×Qï‹á1j‘NWBºµeü 5é]R®™©»‚˜üˆy^¢€¯’¾ÂJñðÕAtÄàà}T‚BC‹p¿–câ‹&ºiÏé0àƒÐ -Ó¡ ð,p&'üëŽÕeTÒöû"xûOôÓ9Cò@áC5%°9ÁÍû·Ÿ~½NÎéœP]Lg:.‘”gOø¢Â)9¦Öb[2ym¢!©i‹¼¼N ¤ën{Ÿ³åÜ#ÊëChdÇ‹ýš5TtZÁ—NiئáÍH§ (âH© -=}Xã`æAIA8ì™®à–uôîGÃA¤>o5Ž3­Ä&msc$S)1mÄh±àsÿŒ­ÿ¹5Ø|”÷wÁÊ^²HmÕîL=“ºs¤@lÜ7>‹…¶n[>ˆ¬=¯•Œ–noàÂ|CS/U²áßP‰ÅÕ+0,r-Yég?¯^õÍ ×àFÄb¹EƒÙäVŒ#±±qD©Ö˜0nï̶¦ÃÀUcêÄ'ÃósI~28Æš?$m-ø!vùù£Rv­6a5ÛõWÖ¦nYMNç¯íxîxlZ-œþœÚf6s m .V«d߯±ÜFì¶/»­¡/ -Éâ+ €û½ýÎu4¿)EL?ÃÝŸÄŽÝ ¢¤ÄéþêSÔ°Z®àŸ¶ž-Îû€pRfE”ìA•ÅçàÂ}nyÛiØ°šÂ5¢§Ò8¶Þ‡ˆ˜>=@Ò$1±“ùÌjºÕÀ´oÂŒPI´ÅËþ~ZZ-¨â>„Šì(¬m†ÁgmüÔ¿¿E!€¿y¬²Hïv ZS©qtÓ#¿Å;sQÙ{TüÔÄSmÿØðá'±£òÿ€£ÃV’Æ¢+f!V‚Yú㧶™š‚ `C" ¾ªh =ʘrðëY{Þ#¬û°´¿#cœk -³©¤¨›sÒƇÔ9úœ{ÒÝ:BgÌï=Ÿg’ê‡fìûÜgGƒ?¾gêžr€…4YÆ .§k–šÓ÷«êjEe +4"ER$Eþļ]½˜l¦¤°Ú@SüK O!_\ª» MCxFi6§—³@Q=5{“i@Ž®˜ W¢«GÊ¥Kzµ$Ë-Yñ0ì >¬oèš>ù´ÓiÐqÝÌ?*Mu1pˆR]Ãøv| 9Lêz8t+E׆ŸW¿¿˜B”ÌâižÀªÄ ;E¥‰b1"Àµ¤eaºva²°A#s/™öKRTy=-üwå7 RôËûtžÔT]Ù£'›™O?:‘¦qžÌ•ØsˆþÒêÈjˈo¯Ž(˜ìˆœXrr´®¾‚J{{(­½×ò¯‹ík¹¿èðß7ML6$™q.šÍãtŽf½‡wÁ2 â0ÈÂ(Ç >Hs?bmꡦMÜÜë'Ó<^,R Òªš“Â`‹µäÄúcò$Îæ—½ÔFRú5ŒL…™´æ—Á¾¢Ü­°”ðö¼¤tŽLŸYo´¯ë(™Ïãe6Nï]ðQÔf‚_¹;ù…I¥/üUU´xpôJ §„öSô'1 +è›/™zðÅÒ’¢¯qQz^§È¶/àäò“|§KŸŸ Ü¸ì:sÏýÖ…Ûéõ²>W¨eÓi€ie'ñϼPpå(-â Ï:ÊÇ(´[®©ä¦Ïót_ÎfˆœÓ¤kà™ +?¬Mi÷„¤Ð#Zaƒ(G.“C_Kaºh¯è‘…f vŒ Äo«Õ‡0I ýÀ£ñ6LîžaŠÀÄ\7s¥u{5™lt?ŠN†‹E7LJ!1F!²u=ºå[Lešgˆf®´² ¢uk‹03¾Ú"Ì4h[òèE‰i…HÓnAqÕ +è¹¼V+ÅÇûŠ•[2jEd9h[|1¾Hb—¥Ë*飰ÒÆÏ38×÷¯{bxŒZ¤Ó•nmA¿GMy—”kfú® ¦>bÇ^…—¨àûã…¤ï°R|ü@u1xx• …ÐÐ"Üï¦e$˜xÁ¢„‰nÚs6 ø ô€Âr((< œÉ‰üºcu•´ý¾ +ž~$ýtΑxbMƪ‚›÷o?ýzÎÒ„êbÂ8ÓqyŒÏ ´8žµY2y"ÎÖ1·[½6©‚Ô¼‰¼¼N ¤ën{ŸséÜ#ÄëC^dÇ‹ýš5TtZÁ—NiئáÍH§ (‚H©=½U `ÙAI>8ì™®à–uôîG³B¤>ï5Î2­ÄÚÆH-¦R6úˆÿÐc-Àþ_ÿó»<óQÑß+ÓuÉ"µ-»3ÍLêα±qßx-vÚ:² |PY{Y§*-m°Â|ãR¯U²‘ßP‰Õ0"r-Vë?o^õ/AoÁ͉ÛÅ"r‹«É­Gfcáá…R? ¬±`.Ü Ñ²¦Ã´UcéÄ'ÓÂóCI~2~8Á>$m-ò!pùá£Rv­6i5äú+kS·,‰&§C‡·vH¤Á[5m¡GWq=ëÏ{„u?ý•öGdŒCm!ðÉÃj*)ÚÅÇ“9iãCé}Î]éÇna0æÇž¯3Iu‡3>úÜWGS?Þgê®r€…4YÆ .gk–˜Ý÷«gõD¿ endstream endobj -90 0 obj +88 0 obj << /Filter/FlateDecode -/Length 1293 +/Length 1292 >> stream xœ}WÝoÛ6ï_!äe2«¢dÙrß²6:`[ÐxOËh‰Š¸H¤@Rq¼¿~Ç/‘v›¥@ûûïŽ÷¥ü|øð±ËT$‡.AIÿP²«“]U'‡1ù+}*6ÅjP•§‡žÊÕzƒvÙíÒ‘>÷*G¢ÏuÊ LÞ…óݤ~2êu: ~Èd'ªz+¢LÎØD %,º¾Ç¬({¾¾»N‰\ÈÛ  Éœ,¥ÖùûðëT'kT&‡b¢¬áã4®–e• D.´âöX–ezü—NÅ"ál9N‚ŒXÍ‚lÃ#¢J1R†5/[˜ßˆç ¦úàÊ<µ8ò 8ªL0yˆÅ¥¡€üœV(O¹xÉ f­#. @@ -1463,379 +1426,395 @@ 6¹v`hÊ52ÓÂ3ÜûS3H°Ï¯U% Ãã··m:l!Éø†Ž#i©éGh L¸ò&°ž í‚’D ¨‹ÈB§Éëüõ¤y±e=jß•êi•Yâ‘8®ôF»Uš­Räþ7¬Îx‡–(LiÂÇn› ­žóë &˦ÃÖßåzµÞ΃éI~ÔɆ"ýät7N¡RVÞ0ªq/Û>¾4…Ê"Û¢ÊÃé +õ¨¡´ËÚÌY}.wU*Ö~CøAî6ƒ£nîZíV M)í+ò}VìKxÈshä_7Ю¶5 ¿ÁîsÎï»< Èh*VY Y’D¼ÒÆ_p;Ô'ª -Ћ&‹f¡à¶–»Aéù¾“<­ SÃÞ‰l¹Ž[˜i$ÏÄìêòNgÕ¾°ç?Ù*÷ä¥Ë×_~™6ƒþ›ÂLÐÜÍÉÜ5r¼s™ù„;YâÝyœ/s@ |H¶ÐÅÃYgDÛ/Ð>«’u¹ÝÛ-uÉÝþ2zÑ +Ћ&‹f¡à¶–»Aéù¾“<­ SÃÞ‰l¹Ž[˜i$ÏÄìêòNgÕ¾°ç?Ù*÷ä¥Ë×_~™6ƒþ›ÂLÐÜÍÉÜ5r¼s™ù„;YâÝyœ/s@ |H¶ÐÅÃYgDÛ/Ð>«’u¹ÝÛ5%ø+zÐ endstream endobj -91 0 obj +89 0 obj << /Filter/FlateDecode -/Length 1001 +/Length 1000 >> stream -xœ}VIoÛ8¾çW9Q@¬X‹·¹MÒ`Ú™ .`ÝÆs EÚb+‘I5Í¿ŸÇMTÒÀÈ!oß¾'oŠd½®’j•'e"ir¾y¨oîÏë¤X&õ9É“%üå‰QÛl“ºOþE-4•é¢ØlQ¾LÑiµDIŠþá"ÍWè…;ÑÃxQŽÂœ8â™õLcÍWéõßœ&Ð:Y”»¤&àÿXTEºÈóÕíy÷ -–@é–:âö+ÖÜzîëàÙâìþ®ëoŽ¤øåñæ\³Æ†v<¦Ü5ƒš¯ªßÅëE¦6Ûe²(Š+9ÆØŸŸþüäýqïø¯§Úè{àúðXÒó€ì*Áóz…²+Ñ÷_¿>=‚ër•geY¢#: Ÿ­Öƒº?žïëçƒcWùé‘sÚ©c5MC=K&XœÒb‰Fu8¥df¢ÅL—F>åøÔG†qzŠhpg«Ë·É"/]y˜ôŒ3¥%ÖBª;ßE›8Åm -ÝA¥{Ø A¨Æ¬s+¶0ž?hÜ·ýÁ d—gËíTpdØõ:_o¤ kÜl¼Ü”h€Ã"Edìšt™Ùb›¬š)sòqÐqgw)Hû¡£fûæñÌDYßúG°ÆÐãrc• +/in60~qüPÊt• ávkœ¬¥˜P9“bΆ±³èÉ&­/ç¨ aF -Ó b¿ a×ËIÁaùe””ÜM\ƒ8¿ç¡¦c{‹b¹ËVPû ëºø2[hðÄ$õ#ò<;"C{0{¶Aé!>š“E¥r+å™öšXÓ0ÑŒÐÃ<ƒ.å[t‰ªŠÊŸ¬¡w‘Ã2šÍäÐ覵÷Ɉ÷eN·f³=ù=¶xÐT¦‹b»Cù2E¤«%JRôi¾F/܉Æ‹ræÄϬgk&¸Jÿ«þ†@à¼06É¢Ü'ÿ§bU¤‹<_/Ñw¯` ”n©#n°bͭ羞-Îîÿçªúæ¨AŠ_Þ`Î5klhÇcÊýWã0©)ñªú]¼^ô`j³]&‹¢¸’cŒýùéÏOÞ÷Žÿzªш¾®%ý0È~ :ö*ß"=rN;uJ£¦iH gÉ‹:-–hÔQ‡SJf&ZÌtiäSŽë.82Œú5*v¢Á­.ß%‹¼tåaÒ3Δ–X ©î|hhmâw)tîa 7¡³Î­ØÂxþ qßG3}ž-wSÁ‘a×è|³E’B.¬q³ñrSn ‹u±kÒef‹m²j¦ÌÉÇQ@sÄÝ¥ 퇎ší›Æ3e5~ëÁCË­U‚®¼¤¹Ù4ÂøÅñ @)ÓmT‚†Û­q²–bBåLŠ9Æ΢'›´¾œ£&„)L3ˆ=þ‚†]/'i‡Aä—QRr7q âüž‡BšŽì-Šå>[Cí/¬ëâËlY Á“ÔÈóìˆ íÁìÙ¥ÇøüiN•Ê­”gÚkbMÃD3Bk†y]ÊwèU•?YCï"‡e4›É¡ÑMk;ï“ïËœnÍf{x¨n…¿§¸þ¸¶GÖ¥ ø½¶ãUZ®‘Ä\ pf¸¿l³»Ø â½rá¥ow¯ôÚñ«lê«]MȻݠ1>Ó ¼sÌ/ü.j娀è‡ÙÕ™Sj +ý50n7èi¬~˜Óeh¬5í­¢…;H.#UÞ±ë05@ù7¼(1J›L¹r“/Ël×iªÀ¿k¬lWŒl!Ù…ÙÍœèнö¡0wGÀK›QúéLq×…7Zh< ß-Ñpï·ÙðyºÇ€g* +´¤s³Œ^÷lOë‹æÒEX‚7NäÈãOÖ·PWCÉm”‘šãÂ;ÉÇ90NÜL'/¦®Žª¨¢[)ÆK;gÌry¡õûâÍFIWJC¯BâpT><Àl +þÛâÎzƒ›n!\xX›oPðü«Ó‹ð-—neÐ|ø&³"/³5üÚYÁ,’ ²L«ï7OÕÿœˆ endstream endobj -92 0 obj +90 0 obj << /Filter/FlateDecode -/Length 514 +/Length 498 >> stream -xœeRËrÛ Ýû+èª0S»Y~dÕ4iݤ íš,°„,\.ºÊÄ_Hh’ÑBç>8ç¾ö ív[´-(Ê‘¨Y}/W_›b*DQæ>Š|Úþ€ÊýÁ-¿‚°dÍöL)Áwd›aDðƒÑÀ+ /å/Gáž1O‘¡u~Deí^–­ kºÏ7GºÇWŵur4‚Ã`EŸ<Ü.ò•ìa™.uÀ‡<Ç°$~f[ªvIè?=>m’ëÑèÏÌVô8,Þ€IäUl+—j|€ÖØEYMÂ73$+¸R·q8n$4#ÑÂ÷ÄŠ ÷¦ÐJ}¦6@cSœ°Ÿˆ‡|òT\ -ð›¯Ôó³(!+ð« +ἦ™™l@VüD›©XÆæýÍú3P½‰(ü®ÃIÉ*àŽK5wäø®ø(Ë´¼úK¨kÀö#Ë\¹®fÇÃO*Jš÷}Ý+i òÖ\D)¯ü,þÐÇý¨Oá®x_’yòš$GXÄ”,\ö]²!T°üŠ+DŠùšp܉»î>9ãÀ£u¶$ õ‚átKܵÑ.>Î2Fy‚}çnkéÜÍ,ª7y:£Çb>\â«Œ üíÃü~*øžC7þºjùíܽmjñLâ:âÕ\†i“?ˆ^ ŸF%F›­·ÇQç)/«åÚn, +xœeR»rœ0í÷+ÔEšÉ$`®âØiÒ8]ìB —EŽ6Bx¼ icç>tÎ}íÚíJTVÈê6?êÍ·n‡XŽêQ”»"Ÿ¶? z@ðCÏ/ Ù²ýSJð)sŒ~ÐÊòÆ’—ú—£pϘ§ÈѶ8¢ºu/ëÈ–î‹ìH÷ø"¹RÐ&GÜNÆäáf•/Åh×éB|( +l×ÄϬ¤reׄðÓãS–\Z}±Éìa–ÛÕ«yÛJÁµŸl¯Íª¬.á«ž.åuŽ -ÂHøžX•ãQ`{¡ÎÁTÚÐéIÅ'ì'â!¿ùf ®B+üîÆ+Ôò,Ja~óq0Â^ƒWw “ ÈÀ¿ F›ÝŠelÙߢ¿9êˆÂï2¤h¸KG~ŠB±LÛ¿„ºÌxcd¹+×ÕìxøIFIý±¯{)´í£¼Ñ¯ÐDÊ ?ÁŸú¸Ÿõé!Üí×dž¼æd“#,â– .û.Ù€ –_qgRÌßРǸë“3> endobj -94 0 obj +92 0 obj << /Title (Contents) -/Parent 93 0 R +/Parent 91 0 R /Dest[16 0 R/XYZ null null null] -/Next 95 0 R +/Next 93 0 R >> endobj -95 0 obj +93 0 obj << /Title (Chapter 1: Introduction) -/Parent 93 0 R +/Parent 91 0 R /Dest[19 0 R/XYZ null null null] -/Prev 94 0 R -/Next 96 0 R +/Prev 92 0 R +/Next 94 0 R >> endobj -96 0 obj +94 0 obj << /Title (Chapter 2: Running apt-cacher-ng) -/Parent 93 0 R +/Parent 91 0 R /Dest[20 0 R/XYZ null null null] -/Prev 95 0 R -/Next 97 0 R +/Prev 93 0 R +/Next 95 0 R >> endobj -97 0 obj +95 0 obj << /Title (Chapter 3: Basic Configuration) -/Parent 93 0 R +/Parent 91 0 R /Dest[21 0 R/XYZ null null null] -/Prev 96 0 R -/First 98 0 R -/Last 99 0 R +/Prev 94 0 R +/First 96 0 R +/Last 97 0 R /Count -2 -/Next 100 0 R +/Next 98 0 R >> endobj -98 0 obj +96 0 obj << /Title (3.1 Server Configuration) -/Parent 97 0 R +/Parent 95 0 R /Dest[21 0 R/XYZ null null null] -/Next 99 0 R +/Next 97 0 R >> endobj -99 0 obj +97 0 obj << /Title (3.2 Client Configuration) -/Parent 97 0 R +/Parent 95 0 R /Dest[21 0 R/XYZ null null null] -/Prev 98 0 R +/Prev 96 0 R >> endobj -100 0 obj +98 0 obj << /Title (Chapter 4: Advanced Server Configuration) -/Parent 93 0 R +/Parent 91 0 R /Dest[23 0 R/XYZ null null null] -/Prev 97 0 R -/First 101 0 R -/Last 103 0 R +/Prev 95 0 R +/First 99 0 R +/Last 101 0 R /Count -3 -/Next 106 0 R +/Next 104 0 R >> endobj -101 0 obj +99 0 obj << /Title (4.1 Vocabulary) -/Parent 100 0 R +/Parent 98 0 R /Dest[23 0 R/XYZ null null null] -/Next 102 0 R +/Next 100 0 R >> endobj -102 0 obj +100 0 obj << /Title (4.2 Configuration file types) -/Parent 100 0 R +/Parent 98 0 R /Dest[23 0 R/XYZ null null null] -/Prev 101 0 R -/Next 103 0 R +/Prev 99 0 R +/Next 101 0 R >> endobj -103 0 obj +101 0 obj << /Title (4.3 Repositories and URL mapping) -/Parent 100 0 R +/Parent 98 0 R /Dest[24 0 R/XYZ null null null] -/Prev 102 0 R -/First 104 0 R -/Last 105 0 R +/Prev 100 0 R +/First 102 0 R +/Last 103 0 R /Count -2 >> endobj -104 0 obj +102 0 obj << /Title (4.3.1 Writing Remap-... configuration) -/Parent 103 0 R +/Parent 101 0 R /Dest[25 0 R/XYZ null null null] -/Next 105 0 R +/Next 103 0 R >> endobj -105 0 obj +103 0 obj << /Title (4.3.2 Special tricks and additional notes) -/Parent 103 0 R +/Parent 101 0 R /Dest[26 0 R/XYZ null null null] -/Prev 104 0 R +/Prev 102 0 R >> endobj -106 0 obj +104 0 obj << /Title (Chapter 5: Security) -/Parent 93 0 R +/Parent 91 0 R /Dest[28 0 R/XYZ null null null] -/Prev 100 0 R -/First 107 0 R -/Last 111 0 R +/Prev 98 0 R +/First 105 0 R +/Last 109 0 R /Count -5 -/Next 112 0 R +/Next 110 0 R >> endobj -107 0 obj +105 0 obj << /Title (5.1 Access control by IP interface) -/Parent 106 0 R +/Parent 104 0 R /Dest[28 0 R/XYZ null null null] -/Next 108 0 R +/Next 106 0 R >> endobj -108 0 obj +106 0 obj << /Title (5.2 Access control with libwrap) -/Parent 106 0 R +/Parent 104 0 R /Dest[28 0 R/XYZ null null null] -/Prev 107 0 R -/Next 109 0 R +/Prev 105 0 R +/Next 107 0 R >> endobj -109 0 obj +107 0 obj << /Title (5.3 Access control with inetd) -/Parent 106 0 R +/Parent 104 0 R /Dest[29 0 R/XYZ null null null] -/Prev 108 0 R -/Next 110 0 R +/Prev 106 0 R +/Next 108 0 R >> endobj -110 0 obj +108 0 obj << /Title (5.4 Access control with iptables) -/Parent 106 0 R +/Parent 104 0 R /Dest[29 0 R/XYZ null null null] -/Prev 109 0 R -/Next 111 0 R +/Prev 107 0 R +/Next 109 0 R >> endobj -111 0 obj +109 0 obj << /Title (5.5 Target port filter) -/Parent 106 0 R +/Parent 104 0 R /Dest[29 0 R/XYZ null null null] -/Prev 110 0 R +/Prev 108 0 R >> endobj -112 0 obj +110 0 obj << /Title (Chapter 6: Distribution specific instructions) -/Parent 93 0 R +/Parent 91 0 R /Dest[30 0 R/XYZ null null null] -/Prev 106 0 R -/First 113 0 R -/Last 119 0 R +/Prev 104 0 R +/First 111 0 R +/Last 117 0 R /Count -7 -/Next 120 0 R +/Next 118 0 R >> endobj -113 0 obj +111 0 obj << /Title (6.1 Debian and Ubuntu) -/Parent 112 0 R +/Parent 110 0 R /Dest[30 0 R/XYZ null null null] -/Next 114 0 R +/Next 112 0 R >> endobj -114 0 obj +112 0 obj << /Title (6.2 OpenSUSE) -/Parent 112 0 R +/Parent 110 0 R /Dest[30 0 R/XYZ null null null] -/Prev 113 0 R -/Next 115 0 R +/Prev 111 0 R +/Next 113 0 R >> endobj -115 0 obj +113 0 obj << /Title (6.3 Fedora Core) -/Parent 112 0 R +/Parent 110 0 R /Dest[30 0 R/XYZ null null null] -/Prev 114 0 R -/Next 116 0 R +/Prev 112 0 R +/Next 114 0 R >> endobj -116 0 obj +114 0 obj << /Title (6.4 Arch Linux) -/Parent 112 0 R +/Parent 110 0 R /Dest[30 0 R/XYZ null null null] -/Prev 115 0 R -/Next 117 0 R +/Prev 113 0 R +/Next 115 0 R >> endobj -117 0 obj +115 0 obj << /Title (6.5 Sourceforge mirror network) -/Parent 112 0 R +/Parent 110 0 R /Dest[30 0 R/XYZ null null null] -/Prev 116 0 R -/Next 118 0 R +/Prev 114 0 R +/Next 116 0 R >> endobj -118 0 obj +116 0 obj << /Title (6.6 Cygwin mirrors) -/Parent 112 0 R +/Parent 110 0 R /Dest[31 0 R/XYZ null null null] -/Prev 117 0 R -/Next 119 0 R +/Prev 115 0 R +/Next 117 0 R >> endobj -119 0 obj +117 0 obj << /Title (6.7 Limited expiration) -/Parent 112 0 R +/Parent 110 0 R /Dest[31 0 R/XYZ null null null] -/Prev 118 0 R +/Prev 116 0 R >> endobj -120 0 obj +118 0 obj << /Title (Chapter 7: Maintenance) -/Parent 93 0 R +/Parent 91 0 R /Dest[32 0 R/XYZ null null null] -/Prev 112 0 R -/First 121 0 R -/Last 125 0 R +/Prev 110 0 R +/First 119 0 R +/Last 123 0 R /Count -2 -/Next 126 0 R +/Next 124 0 R >> endobj -121 0 obj +119 0 obj << /Title (7.1 Cache cleanup) -/Parent 120 0 R +/Parent 118 0 R /Dest[32 0 R/XYZ null null null] -/First 122 0 R -/Last 124 0 R +/First 120 0 R +/Last 122 0 R /Count -3 -/Next 125 0 R +/Next 123 0 R >> endobj -122 0 obj +120 0 obj << /Title (7.1.1 Manual expiration) -/Parent 121 0 R +/Parent 119 0 R /Dest[32 0 R/XYZ null null null] -/Next 123 0 R +/Next 121 0 R >> endobj -123 0 obj +121 0 obj << /Title (7.1.2 Automated cache cleanup) -/Parent 121 0 R +/Parent 119 0 R /Dest[34 0 R/XYZ null null null] -/Prev 122 0 R -/Next 124 0 R +/Prev 120 0 R +/Next 122 0 R >> endobj -124 0 obj +122 0 obj << /Title (7.1.3 Keeping latest versions of expired package files) -/Parent 121 0 R +/Parent 119 0 R /Dest[34 0 R/XYZ null null null] -/Prev 123 0 R +/Prev 121 0 R >> endobj -125 0 obj +123 0 obj << /Title (7.2 Removal of distribution releases) -/Parent 120 0 R +/Parent 118 0 R /Dest[34 0 R/XYZ null null null] -/Prev 121 0 R +/Prev 119 0 R >> endobj -126 0 obj +124 0 obj << /Title (Chapter 8: HOWTOs and FAQ) -/Parent 93 0 R +/Parent 91 0 R /Dest[36 0 R/XYZ null null null] -/Prev 120 0 R -/First 127 0 R -/Last 141 0 R -/Count -15 -/Next 142 0 R +/Prev 118 0 R +/First 125 0 R +/Last 138 0 R +/Count -14 +/Next 139 0 R >> endobj -127 0 obj +125 0 obj << /Title (8.1 Package import) -/Parent 126 0 R +/Parent 124 0 R /Dest[36 0 R/XYZ null null null] +/Next 126 0 R +>> +endobj +126 0 obj +<< +/Title (8.2 Access to SSL/TLS remotes \(HTTPS\)) +/Parent 124 0 R +/Dest[37 0 R/XYZ null null null] +/Prev 125 0 R +/Next 127 0 R +>> +endobj +127 0 obj +<< +/Title (8.3 JIGDO usage) +/Parent 124 0 R +/Dest[38 0 R/XYZ null null null] +/Prev 126 0 R /Next 128 0 R >> endobj 128 0 obj << -/Title (8.2 Cache overview) -/Parent 126 0 R -/Dest[37 0 R/XYZ null null null] +/Title (8.4 Avoid use of apt-cacher-ng for certain hosts) +/Parent 124 0 R +/Dest[38 0 R/XYZ null null null] /Prev 127 0 R /Next 129 0 R >> endobj 129 0 obj << -/Title (8.3 Access to SSL/TLS remotes \(HTTPS\)) -/Parent 126 0 R -/Dest[38 0 R/XYZ null null null] +/Title (8.5 Avoid caching for certain domains or certain file types) +/Parent 124 0 R +/Dest[39 0 R/XYZ null null null] /Prev 128 0 R /Next 130 0 R >> endobj 130 0 obj << -/Title (8.4 JIGDO usage) -/Parent 126 0 R +/Title (8.6 How to make big download series faster) +/Parent 124 0 R /Dest[39 0 R/XYZ null null null] /Prev 129 0 R /Next 131 0 R @@ -1843,8 +1822,8 @@ endobj 131 0 obj << -/Title (8.5 Avoid use of apt-cacher-ng for certain hosts) -/Parent 126 0 R +/Title (8.7 How to import DVDs or ISO images) +/Parent 124 0 R /Dest[39 0 R/XYZ null null null] /Prev 130 0 R /Next 132 0 R @@ -1852,8 +1831,8 @@ endobj 132 0 obj << -/Title (8.6 Avoid caching for certain domains or certain file types) -/Parent 126 0 R +/Title (8.8 How to integrate DVDs or ISO image data) +/Parent 124 0 R /Dest[39 0 R/XYZ null null null] /Prev 131 0 R /Next 133 0 R @@ -1861,8 +1840,8 @@ endobj 133 0 obj << -/Title (8.7 How to make big download series faster) -/Parent 126 0 R +/Title (8.9 How to execute commands before and after going online?) +/Parent 124 0 R /Dest[40 0 R/XYZ null null null] /Prev 132 0 R /Next 134 0 R @@ -1870,8 +1849,8 @@ endobj 134 0 obj << -/Title (8.8 How to import DVDs or ISO images) -/Parent 126 0 R +/Title (8.10 Listen to only specific interfaces or IP protocols) +/Parent 124 0 R /Dest[40 0 R/XYZ null null null] /Prev 133 0 R /Next 135 0 R @@ -1879,8 +1858,8 @@ endobj 135 0 obj << -/Title (8.9 How to integrate DVDs or ISO image data) -/Parent 126 0 R +/Title (8.11 How to avoid use of IPv4 \(or IPv6\) where possible?) +/Parent 124 0 R /Dest[40 0 R/XYZ null null null] /Prev 134 0 R /Next 136 0 R @@ -1888,8 +1867,8 @@ endobj 136 0 obj << -/Title (8.10 How to execute commands before and after going online?) -/Parent 126 0 R +/Title (8.12 Use the proxy without storing all data twice) +/Parent 124 0 R /Dest[40 0 R/XYZ null null null] /Prev 135 0 R /Next 137 0 R @@ -1897,8 +1876,8 @@ endobj 137 0 obj << -/Title (8.11 Listen to only specific interfaces or IP protocols) -/Parent 126 0 R +/Title (8.13 Optional semi-automatic use of proxy) +/Parent 124 0 R /Dest[41 0 R/XYZ null null null] /Prev 136 0 R /Next 138 0 R @@ -1906,63 +1885,63 @@ endobj 138 0 obj << -/Title (8.12 How to avoid use of IPv4 \(or IPv6\) where possible?) -/Parent 126 0 R +/Title (8.14 Partial Mirroring) +/Parent 124 0 R /Dest[41 0 R/XYZ null null null] /Prev 137 0 R -/Next 139 0 R >> endobj 139 0 obj << -/Title (8.13 Use the proxy without storing all data twice) -/Parent 126 0 R -/Dest[41 0 R/XYZ null null null] -/Prev 138 0 R -/Next 140 0 R +/Title (Chapter 9: Troubleshooting) +/Parent 91 0 R +/Dest[43 0 R/XYZ null null null] +/Prev 124 0 R +/First 140 0 R +/Last 147 0 R +/Count -8 +/Next 148 0 R >> endobj 140 0 obj << -/Title (8.14 Optional semi-automatic use of proxy) -/Parent 126 0 R -/Dest[42 0 R/XYZ null null null] -/Prev 139 0 R +/Title (9.1 Debugging) +/Parent 139 0 R +/Dest[43 0 R/XYZ null null null] /Next 141 0 R >> endobj 141 0 obj << -/Title (8.15 Partial Mirroring) -/Parent 126 0 R -/Dest[42 0 R/XYZ null null null] +/Title (9.2 Problem: keeps delivering damaged files) +/Parent 139 0 R +/Dest[43 0 R/XYZ null null null] /Prev 140 0 R +/Next 142 0 R >> endobj 142 0 obj << -/Title (Chapter 9: Troubleshooting) -/Parent 93 0 R +/Title (9.3 Problem: regular expiration action reproducibly aborts) +/Parent 139 0 R /Dest[44 0 R/XYZ null null null] -/Prev 126 0 R -/First 143 0 R -/Last 150 0 R -/Count -8 -/Next 151 0 R +/Prev 141 0 R +/Next 143 0 R >> endobj 143 0 obj << -/Title (9.1 Debugging) -/Parent 142 0 R +/Title (9.4 Problem: cacher suddenly terminates, log reports IO errors) +/Parent 139 0 R /Dest[44 0 R/XYZ null null null] +/Prev 142 0 R /Next 144 0 R >> endobj 144 0 obj << -/Title (9.2 Problem: keeps delivering damaged files) -/Parent 142 0 R +/Title (9.5 Problem: download fails with 503 ... status message) +/Parent 139 0 R /Dest[44 0 R/XYZ null null null] /Prev 143 0 R /Next 145 0 R @@ -1970,8 +1949,8 @@ endobj 145 0 obj << -/Title (9.3 Problem: regular expiration action reproducibly aborts) -/Parent 142 0 R +/Title (9.6 Problem: 'apt-get' freezes when downloading files) +/Parent 139 0 R /Dest[45 0 R/XYZ null null null] /Prev 144 0 R /Next 146 0 R @@ -1979,8 +1958,8 @@ endobj 146 0 obj << -/Title (9.4 Problem: cacher suddenly terminates, log reports IO errors) -/Parent 142 0 R +/Title (9.7 'apt-get' reports corrupted bzip2 data) +/Parent 139 0 R /Dest[45 0 R/XYZ null null null] /Prev 145 0 R /Next 147 0 R @@ -1988,58 +1967,31 @@ endobj 147 0 obj << -/Title (9.5 Problem: download fails with 503 ... status message) -/Parent 142 0 R -/Dest[45 0 R/XYZ null null null] +/Title (9.8 Problem: 'apt-cacher-ng' refuses to start with "Address already in use") +/Parent 139 0 R +/Dest[46 0 R/XYZ null null null] /Prev 146 0 R -/Next 148 0 R >> endobj 148 0 obj << -/Title (9.6 Problem: 'apt-get' freezes when downloading files) -/Parent 142 0 R -/Dest[46 0 R/XYZ null null null] -/Prev 147 0 R +/Title (Chapter 10: Known Bugs and Limitations) +/Parent 91 0 R +/Dest[47 0 R/XYZ null null null] +/Prev 139 0 R /Next 149 0 R >> endobj 149 0 obj << -/Title (9.7 'apt-get' reports corrupted bzip2 data) -/Parent 142 0 R -/Dest[46 0 R/XYZ null null null] -/Prev 148 0 R -/Next 150 0 R ->> -endobj -150 0 obj -<< -/Title (9.8 Problem: 'apt-cacher-ng' refuses to start with "Address already in use") -/Parent 142 0 R -/Dest[47 0 R/XYZ null null null] -/Prev 149 0 R ->> -endobj -151 0 obj -<< -/Title (Chapter 10: Known Bugs and Limitations) -/Parent 93 0 R -/Dest[48 0 R/XYZ null null null] -/Prev 142 0 R -/Next 152 0 R ->> -endobj -152 0 obj -<< /Title (Chapter 11: Contact) -/Parent 93 0 R -/Dest[49 0 R/XYZ null null null] -/Prev 151 0 R +/Parent 91 0 R +/Dest[48 0 R/XYZ null null null] +/Prev 148 0 R >> endobj xref -0 153 +0 150 0000000000 65535 f 0000000066 00000 n 0000000155 00000 n @@ -2057,148 +2009,145 @@ 0000005232 00000 n 0000005262 00000 n 0000005328 00000 n -0000007769 00000 n -0000010677 00000 n -0000011016 00000 n -0000011264 00000 n -0000011437 00000 n -0000011503 00000 n -0000011673 00000 n -0000011854 00000 n -0000012027 00000 n -0000012209 00000 n -0000012382 00000 n -0000012448 00000 n -0000012813 00000 n -0000012879 00000 n -0000012945 00000 n -0000013011 00000 n -0000013077 00000 n -0000013143 00000 n -0000013209 00000 n -0000013382 00000 n -0000013564 00000 n -0000013742 00000 n -0000014052 00000 n -0000014226 00000 n -0000014400 00000 n -0000014581 00000 n -0000014878 00000 n -0000015052 00000 n -0000015234 00000 n -0000015300 00000 n -0000015482 00000 n -0000015655 00000 n -0000015829 00000 n -0000016526 00000 n -0000016622 00000 n -0000016718 00000 n -0000016821 00000 n -0000016917 00000 n -0000017013 00000 n -0000017116 00000 n -0000017212 00000 n -0000017315 00000 n -0000017822 00000 n -0000018730 00000 n -0000020023 00000 n -0000020387 00000 n -0000022177 00000 n -0000022854 00000 n -0000024888 00000 n -0000025677 00000 n -0000027867 00000 n -0000030604 00000 n -0000033214 00000 n -0000036348 00000 n -0000037212 00000 n -0000039813 00000 n -0000041808 00000 n -0000043848 00000 n -0000044827 00000 n -0000047173 00000 n -0000049489 00000 n -0000052269 00000 n -0000053116 00000 n -0000055249 00000 n -0000056649 00000 n -0000059529 00000 n -0000061836 00000 n -0000064258 00000 n -0000067378 00000 n -0000070108 00000 n -0000070574 00000 n -0000072702 00000 n -0000075582 00000 n -0000077247 00000 n -0000078613 00000 n -0000079687 00000 n -0000080273 00000 n -0000080415 00000 n -0000080516 00000 n -0000080645 00000 n -0000080783 00000 n -0000080957 00000 n -0000081074 00000 n -0000081191 00000 n -0000081378 00000 n -0000081488 00000 n -0000081626 00000 n -0000081793 00000 n -0000081926 00000 n -0000082063 00000 n -0000082230 00000 n -0000082360 00000 n -0000082501 00000 n -0000082640 00000 n -0000082782 00000 n -0000082900 00000 n -0000083093 00000 n -0000083210 00000 n -0000083332 00000 n -0000083457 00000 n -0000083581 00000 n -0000083721 00000 n -0000083849 00000 n -0000083967 00000 n -0000084137 00000 n -0000084289 00000 n -0000084408 00000 n -0000084547 00000 n -0000084697 00000 n -0000084829 00000 n -0000085003 00000 n -0000085117 00000 n -0000085245 00000 n -0000085394 00000 n -0000085519 00000 n -0000085677 00000 n -0000085846 00000 n -0000085998 00000 n -0000086144 00000 n -0000086297 00000 n -0000086466 00000 n -0000086631 00000 n -0000086798 00000 n -0000086957 00000 n -0000087108 00000 n -0000087226 00000 n -0000087400 00000 n -0000087509 00000 n -0000087662 00000 n -0000087830 00000 n -0000088002 00000 n -0000088167 00000 n -0000088330 00000 n -0000088482 00000 n -0000088653 00000 n -0000088800 00000 n +0000007660 00000 n +0000010568 00000 n +0000010907 00000 n +0000011155 00000 n +0000011328 00000 n +0000011394 00000 n +0000011564 00000 n +0000011745 00000 n +0000011918 00000 n +0000012100 00000 n +0000012166 00000 n +0000012339 00000 n +0000012704 00000 n +0000012770 00000 n +0000012836 00000 n +0000012902 00000 n +0000012968 00000 n +0000013034 00000 n +0000013100 00000 n +0000013166 00000 n +0000013348 00000 n +0000013658 00000 n +0000013832 00000 n +0000014006 00000 n +0000014187 00000 n +0000014253 00000 n +0000014632 00000 n +0000014814 00000 n +0000014880 00000 n +0000015062 00000 n +0000015235 00000 n +0000015409 00000 n +0000015980 00000 n +0000016076 00000 n +0000016172 00000 n +0000016268 00000 n +0000016371 00000 n +0000016467 00000 n +0000016563 00000 n +0000016659 00000 n +0000016762 00000 n +0000017269 00000 n +0000018136 00000 n +0000019430 00000 n +0000019795 00000 n +0000021585 00000 n +0000022262 00000 n +0000024296 00000 n +0000025085 00000 n +0000027262 00000 n +0000029991 00000 n +0000032672 00000 n +0000035850 00000 n +0000036747 00000 n +0000039348 00000 n +0000041341 00000 n +0000043381 00000 n +0000044360 00000 n +0000046706 00000 n +0000049022 00000 n +0000051802 00000 n +0000052524 00000 n +0000054741 00000 n +0000057740 00000 n +0000060082 00000 n +0000062509 00000 n +0000065547 00000 n +0000068228 00000 n +0000069087 00000 n +0000071215 00000 n +0000074095 00000 n +0000075754 00000 n +0000077119 00000 n +0000078192 00000 n +0000078762 00000 n +0000078904 00000 n +0000079005 00000 n +0000079134 00000 n +0000079272 00000 n +0000079445 00000 n +0000079562 00000 n +0000079679 00000 n +0000079864 00000 n +0000079972 00000 n +0000080108 00000 n +0000080274 00000 n +0000080407 00000 n +0000080544 00000 n +0000080710 00000 n +0000080840 00000 n +0000080981 00000 n +0000081120 00000 n +0000081262 00000 n +0000081380 00000 n +0000081573 00000 n +0000081690 00000 n +0000081812 00000 n +0000081937 00000 n +0000082061 00000 n +0000082201 00000 n +0000082329 00000 n +0000082447 00000 n +0000082617 00000 n +0000082769 00000 n +0000082888 00000 n +0000083027 00000 n +0000083177 00000 n +0000083309 00000 n +0000083483 00000 n +0000083597 00000 n +0000083746 00000 n +0000083871 00000 n +0000084029 00000 n +0000084198 00000 n +0000084350 00000 n +0000084496 00000 n +0000084649 00000 n +0000084817 00000 n +0000084982 00000 n +0000085149 00000 n +0000085308 00000 n +0000085459 00000 n +0000085577 00000 n +0000085751 00000 n +0000085860 00000 n +0000086013 00000 n +0000086181 00000 n +0000086353 00000 n +0000086518 00000 n +0000086681 00000 n +0000086833 00000 n +0000087004 00000 n +0000087151 00000 n trailer << -/Size 153 +/Size 150 /Root 2 0 R /Info 1 0 R >> startxref -88914 +87265 %%EOF diff -Nru apt-cacher-ng-0.9.1/doc/html/bugs.html apt-cacher-ng-3.3.1/doc/html/bugs.html --- apt-cacher-ng-0.9.1/doc/html/bugs.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/bugs.html 2020-01-08 19:58:26.000000000 +0000 @@ -19,7 +19,7 @@ Only HTTP HEAD and GET commands are supported properly.
  • -CONNECT (for https/SSL/TLS tunnels) is supported but needs to be enabled by local administrators, see section 8.3 for details +CONNECT (for https/SSL/TLS tunnels) is supported but needs to be enabled by local administrators, see section 8.2 for details
  • POST support is restricted to apt-listbugs actions and is actually implemented as simple data forwarding with minor header manipulation. If additional proxy is configured, the client will be redirected to the HTTPS version of bugs.debian.org service, i.e. switching to the CONNECT method (see above) diff -Nru apt-cacher-ng-0.9.1/doc/html/config-serv.html apt-cacher-ng-3.3.1/doc/html/config-serv.html --- apt-cacher-ng-0.9.1/doc/html/config-serv.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/config-serv.html 2020-01-08 19:58:26.000000000 +0000 @@ -39,7 +39,7 @@ "Package files": files that contain software packages and other "solid" data: DEBs, source files for their creation (.tar.gz, .diff, .dsc), various metadata which is not subject to change after first appearance on the server.
  • -"Configuration line": one single line in the configuration file. Some examples in this chapter may contain wrapped lines but should be stored as a single line in the configuration. +"Configuration line": one single line in the configuration file. Some examples in this chapter may be displayed as wrapped lines but should be stored as a single line in the configuration. Some variables (like RequestAppendix) support multiline data which needs to be separated with \n delimiter.
  • 4.2 Configuration file types

    @@ -174,7 +174,7 @@ keyfile=... The meaning of this setting is: if any real download error (status code 400 and higher) happens on a file which path ends with the specified string then the target server is blacklisted (considered faulty) immediately and this download (and subsequent ones requested by this client connection) are retried from other servers (see TargetURLs description above). Can be used multiple times to define a list. See below for documented example.
  • -deltasrc=URL Configures the base URL used to download .debdelta files. The path hierarchy below this URL should correspond to the source URLs and file paths in the cache. Only one URL can be specified at the moment. It is used for explicit mirroring operations, see section 8.15 for details. +deltasrc=URL Configures the base URL used to download .debdelta files. The path hierarchy below this URL should correspond to the source URLs and file paths in the cache. Only one URL can be specified at the moment. It is used for explicit mirroring operations, see section 8.14 for details.
  • proxy=proxyspec Configures an alternative proxy URL which overrides the global proxy setting in the context of this repository. Can be set empty to disable proxy usage. diff -Nru apt-cacher-ng-0.9.1/doc/html/config-servquick.html apt-cacher-ng-3.3.1/doc/html/config-servquick.html --- apt-cacher-ng-0.9.1/doc/html/config-servquick.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/config-servquick.html 2020-01-08 19:58:26.000000000 +0000 @@ -69,7 +69,7 @@ Mixing the configuration methods is usually possible but not within the same client program instance. Doing that (going with proxy mode AND use rewritten URLs) will probably confuse the server: in best-case, the connection will be slower because of a little transport loop on the server side, and in the worst-case, the target URL will eventually become not resolvable and the downloads will just fail.

    -Using SSL/TLS transport (i.e. https urls) is also possible with some restrictions, see section 8.3 for details. +Using SSL/TLS transport (i.e. https urls) is also possible with some restrictions, see section 8.2 for details.


    Comments to blade@debian.org diff -Nru apt-cacher-ng-0.9.1/doc/html/cont.html apt-cacher-ng-3.3.1/doc/html/cont.html --- apt-cacher-ng-0.9.1/doc/html/cont.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/cont.html 2020-01-08 19:58:26.000000000 +0000 @@ -18,7 +18,7 @@ There are also a public mailing list and request trackers available on the Alioth project page.

    -And last, but not least: feel free to express your gratitude by donating a small amount of money via PayPal (to edi@gmx.de) or just Flattr it! +And last, but not least: feel free to express your gratitude by donating a small amount of money via PayPal (to edi@gmx.de).


    Comments to blade@debian.org diff -Nru apt-cacher-ng-0.9.1/doc/html/howtos.html apt-cacher-ng-3.3.1/doc/html/howtos.html --- apt-cacher-ng-0.9.1/doc/html/howtos.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/howtos.html 2020-01-08 19:58:26.000000000 +0000 @@ -16,20 +16,19 @@
  • Chapter 8: HOWTOs and FAQ
  • Chapter 8: HOWTOs and FAQ

    @@ -59,11 +58,11 @@
  • -Store copies of your .debs, .orig.tar.gz, ... somewhere in the _import subdirectory in the cache, ie. in /var/cache/apt-cacher/_import/. The files may be links or symlinks, does not matter. When done, apt-cacher will move those files to its own internal locations. Example: +Store copies of your .debs, .orig.tar.gz, ... somewhere in the _import subdirectory in the cache, ie. in /var/cache/apt-cacher-ng/_import/. The files may be links or symlinks, it does not matter. When done, apt-cacher will move those files to its own internal locations. Example:
    cd /var/cache
     mkdir apt-cacher-ng/_import
     cp -laf apt-proxy apt-cacher /var/cache/apt-cacher-ng/_import
    -chown -R apt-cacher-ng apt-cacher-ng/_import
    +chown -R apt-cacher-ng:apt-cacher-ng apt-cacher-ng/_import
     
  • @@ -84,52 +83,7 @@

    on the client to purge APT's internal cache, and then rerun "apt-get update" there.

    -

    8.2 Cache overview

    -

    -To get a basic overview of the cache contents, the distkill.pl script may be used. See section 7.2 for details and warnings. -

    -
    # /usr/lib/apt-cacher-ng/distkill.pl
    -Scanning /var/cache/apt-cacher-ng, please wait...
    -Found distributions:
    -	1. testing (6 index files)
    -	2. sid (63 index files)
    -	3. etch-unikl (30 index files)
    -	4. etch (30 index files)
    -	5. experimental (505 index files)
    -	6. lenny (57 index files)
    -	7. unstable (918 index files)
    -	8. stable (10 index files)
    -
    -WARNING: The removal action would wipe out whole directories containing
    -         index files. Select d to see detailed list.
    -
    -Which distribution to remove? (Number, 0 to exit, d for details): d
    -
    -Directories to remove:
    - 1. testing: 
    -  /var/cache/apt-cacher-ng/debrep/dists/testing 
    - 2. sid: 
    -  /var/cache/apt-cacher-ng/localstuff/dists/sid 
    -  /var/cache/apt-cacher-ng/debrep/dists/sid 
    - 4. etch: 
    -  /var/cache/apt-cacher-ng/ftp.debian-unofficial.org/debian/dists/etch 
    - 5. experimental: 
    -  /var/cache/apt-cacher-ng/debrep/dists/experimental 
    - 6. lenny: 
    -  /var/cache/apt-cacher-ng/security.debian.org/dists/lenny 
    -  /var/cache/apt-cacher-ng/debrep/dists/lenny 
    - 7. unstable: 
    -  /var/cache/apt-cacher-ng/debrep/dists/unstable 
    -  /var/cache/apt-cacher-ng/localstuff/debian/dists/unstable 
    - 8. stable: 
    -  /var/cache/apt-cacher-ng/debrep/dists/stable 
    -Found distributions:
    -
    -WARNING: The removal action would wipe out whole directories containing
    -         index files. Select d to see detailed list.
    -
    -
    -

    8.3 Access to SSL/TLS remotes (HTTPS)

    +

    8.2 Access to SSL/TLS remotes (HTTPS)

    It is possible to have encrypted access to remote sites via HTTPS protocol with recent versions of apt-cacher-ng if the OpenSSL support was enabled at compile time. However this leads certain side effects and complications; due to the nature of the HTTPS connection model, it is not possible to act as an intermediate server (e.g. caching proxy) by the same rules as with HTTP:

    @@ -147,7 +101,7 @@ Considering these difficulties, there are three (and a half) methods to use SSL.

    • -First, the "half method" - not using the proxy at all, configuring each client to not use the HTTP proxy for HTTPS urls. This will obviously disable central caching and requires the client has separated configuration options to set this. For Debian based distros, this can be done by adding a configuration like this: Acquire::https::proxy "DIRECT"; to apt.conf or one of the apt.conf.d files. See section 8.5 for further information. +First, the "half method" - not using the proxy at all, configuring each client to not use the HTTP proxy for HTTPS urls. This will obviously disable central caching and requires the client has separated configuration options to set this. For Debian based distros, this can be done by adding a configuration like this: Acquire::https::proxy "DIRECT"; to apt.conf or one of the apt.conf.d files. See section 8.4 for further information.
    • The "backend configuration method": if the clients access the remote sites through URLs remapped on the server, the cacher admin can add https URLs to backend lists instead of http urls. Data will be cached just like usual. @@ -166,7 +120,7 @@ # Basically the same just with access to apt-cacher-ng through # URL rewritting instead of setting http proxy. -

      8.4 JIGDO usage

      +

      8.3 JIGDO usage

      It's possible to use apt-cacher-ng source with the jigdo-lite utility. There are some limitations, though:

      @@ -195,18 +149,18 @@

      That's all, jigdo-lite will fetch the package files using apt-cacher-ng proxy.

      -

      8.5 Avoid use of apt-cacher-ng for certain hosts

      +

      8.4 Avoid use of apt-cacher-ng for certain hosts

      Sometimes clients might need to access some remote side directly to do some non-file-transfer oriented work but still passing the data through configured apt-cacher-ng proxy. Such remote hosts can be marked for direct access in apt configuration, e.g. in /etc/apt/apt.conf:

      Acquire::HTTP::Proxy::archive.example.org "DIRECT";
       //or Acquire::HTTP::Proxy::archive.example.org  "other.proxy:port"
       
      -

      8.6 Avoid caching for certain domains or certain file types

      +

      8.5 Avoid caching for certain domains or certain file types

      Sometimes clients to download through apt-cacher-ng but the data shall not be stored on the harddisk of the server. To get it, use the DontCache directive (see examples for details) to define such files.

      -

      8.7 How to make big download series faster

      +

      8.6 How to make big download series faster

      Symptom: A common situation is a periodic download of hundreds of files through apt-cacher-ng where just a half is present in the cache. Although caching works fine, there are visible delays on some files during the download.

      @@ -219,9 +173,9 @@

      there is a higher chance to get the server connection "preheated" before a stall occurs.

      -

      8.8 How to import DVDs or ISO images

      +

      8.7 How to import DVDs or ISO images

      -First, it should be clear what is needed to be done. In order to integrate the packages from a DVD or ISO image, read on in section 8.9. +First, it should be clear what is needed to be done. In order to integrate the packages from a DVD or ISO image, read on in section 8.8.

      The situation with ISO files import is complicated. They are not supported by the cache and there is also no expiration mode for them. The feature might be considered for addition in some future release of apt-cacher-ng. @@ -229,7 +183,7 @@

      What is possible now is publishing a directory with ISO files using its web server mode, see LocalDirs config option for details.

      -

      8.9 How to integrate DVDs or ISO image data

      +

      8.8 How to integrate DVDs or ISO image data

      Integrating package files from DVD or ISO images is not much different to the usual import operation, see above for instructions.

      @@ -244,11 +198,11 @@

      A possible variation is import via symlinks. This can make sense where the space consumption must be reduced and the ISO image should stay on the server for a long time. To achive this, the image should be mounted at some mount point outside of the _import directory; the mounted state should be made permanent, maybe via an /etc/fstab entry with the loop option; then a symbolic link tree pointing to the mountpoint location should be created in the _import directory (something like cp -as /mnt/image_jessie_01/pool /var/cache/apt-cacher-ng/_import/). The subsequent "import" operation should pick up the symlinks and continue using them as links istead of file copies.

      -

      8.10 How to execute commands before and after going online?

      +

      8.9 How to execute commands before and after going online?

      It is possible to configure custom commands which are executed before the internet connection attempt and after a certain period after closing the connection. The commands are bound to a remapping configuration and the config file is named after the name of that remapping config, like debrep.hooks for Remap-debrep. See section 4.3.2, conf/*.hooks and /usr/share/doc/apt-cacher-ng/examples/*.hooks files for details.

      -

      8.11 Listen to only specific interfaces or IP protocols

      +

      8.10 Listen to only specific interfaces or IP protocols

      Unless configured explicitely, the server listens to any interface with IPv4 or IPv6 protocol. To disable some of this, use the BindAddress option. It should contain a list of IP adresseses associated with particular network interfaces, separated by space. When option is set then the server won't listen to addresses or protocols not included there.

      @@ -258,11 +212,11 @@

      The usual wildcard addresses can also be used to match all interfaces configured for the specific protocol, like 0.0.0.0 for IPv4.

      -

      8.12 How to avoid use of IPv4 (or IPv6) where possible?

      +

      8.11 How to avoid use of IPv4 (or IPv6) where possible?

      Usually, outgoing hosts are accessed by the protocol and with the target IP reported as the first candidate by operating system facilities (getaddrinfo). It is possible to change this behavior, i.e. to skip IPv6 or IPv4 versions or try IPv6 connection first and then use IPv4 as alternative (or vice versa). See option ConnectProto in configuration examples.

      -

      8.13 Use the proxy without storing all data twice

      +

      8.12 Use the proxy without storing all data twice

      There is a general use case where the data storing behavior of APT is not so fortunate. Imagine an old laptop with a slow and small harddisk but a modern network connection (i.e. Cardbus-attached WLAN card). But there is not enough space for APT to store the downloaded packages on the local disk, or not enough to perform the upgrade afterwards.

      @@ -275,7 +229,7 @@

      And finally, angfs usage can be optimized for local access. This works best if the proxy daemons runs on the same machine as acngfs and there are hundreds of packages to update while filesystem access costs are negligible. Here the cache directory can be specified in acngfs parameters, and then it gets files directly from the cache if they are completely downloaded and don't have volatile contents.

      -

      8.14 Optional semi-automatic use of proxy

      +

      8.13 Optional semi-automatic use of proxy

      Apt-Cacher NG daemon has some optional operations modes regading the use of external proxy (configured with "Proxy" setting). The default mode means use of that proxy for all remote connections.

      @@ -291,7 +245,7 @@

      Hint: this special modes can be combined with non-caching behavior (see above) and another ACNG proxy in the home LAN to get smart caching for laptop users.

      -

      8.15 Partial Mirroring

      +

      8.14 Partial Mirroring

      It is possible to create a partial local mirror of a remote package repository. The method to do this is usually known as pre-caching. A such mirror would contain all files available to apt through apt-cacher-ng, making the cache server suitable for pure off-line use.

      diff -Nru apt-cacher-ng-0.9.1/doc/html/index.html apt-cacher-ng-3.3.1/doc/html/index.html --- apt-cacher-ng-0.9.1/doc/html/index.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/index.html 2020-01-08 19:58:26.000000000 +0000 @@ -56,20 +56,19 @@
    • Chapter 8: HOWTOs and FAQ
    • Chapter 9: Troubleshooting
        diff -Nru apt-cacher-ng-0.9.1/doc/html/maint.html apt-cacher-ng-3.3.1/doc/html/maint.html --- apt-cacher-ng-0.9.1/doc/html/maint.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/maint.html 2020-01-08 19:58:26.000000000 +0000 @@ -144,10 +144,10 @@ After all, if the old release is no longer used by local cache users then the extra disk usage becomes a problem. This problem will go away after many months when the old release files are finally deleted on the servers, then the package expiration will start complaining for some days (the expiration delay) and only then the finally unreferenced files will be removed.

        -To speed up this process, the local administrator can remove the traces of the old distribution release from the archive. Either the top-level "Release" files, or even the whole index file trees relevant for certain releases. +To speed up this process, the local administrator can remove the index files of the old distribution release from the archive. Either the top-level "Release" files, or even the whole index file trees relevant for certain releases.

        -To make this task easier, a "brutal" script called distkill.pl is shipped with apt-cacher-ng. It runs interactively, it scans the package directory and presents an overview of index file trees assumed to represent distro releases. Then it provides a command promt to remove some immediately. The script should be used with extreme care! See section 8.2 for example of its output. +To make this task easier, there is a special helper mode in the cleanup task of the maintenance page. Run this manually (and maybe enable extra verbosity on the main page) and use the wizard on the bottom of the log page to delete particular index files.


        Comments to blade@debian.org diff -Nru apt-cacher-ng-0.9.1/doc/html/secure.html apt-cacher-ng-3.3.1/doc/html/secure.html --- apt-cacher-ng-0.9.1/doc/html/secure.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/secure.html 2020-01-08 19:58:26.000000000 +0000 @@ -40,7 +40,7 @@

        5.1 Access control by IP interface

        -A simple control method for incoming connections is listening only to network interfaces which are inside a secure perimeter, e.g. belong to the local network. See section 8.11 for details on this configuration parameter. The default setting is listening to all interfaces. +A simple control method for incoming connections is listening only to network interfaces which are inside a secure perimeter, e.g. belong to the local network. See section 8.10 for details on this configuration parameter. The default setting is listening to all interfaces.

        5.2 Access control with libwrap

        @@ -54,7 +54,7 @@

        5.3 Access control with inetd

        -In some situations, access filtering by client IP/hostname might be not supported directly or there are other reasons to use inetd to wrap access to apt-cacher inetd. For this case, an inetd daemon is shipped with the package which makes the use of tcpd possible. Installation is done in following steps: +In some situations, access filtering by client IP or hostname might be not supported directly or there are other reasons to use inetd to wrap access to apt-cacher inetd. For this case, an inetd daemon is shipped with the package which makes the use of tcpd possible. Installation is done in following steps:

        1. compile the inetd bridge tool "in.acng", if not already done (check /usr/lib/apt-cacher-ng). @@ -82,7 +82,7 @@ Looking at performance, the most efficient way to estables access control by source IP is the use of system's native mechanisms. For the Linux kernel, it can be created with iptables rules like in the following example, usually stored in system's firewall setup script (or any init script like /etc/rc.local):

        iptables -A INPUT -p tcp --dport 3142 --source 127.0.0.0/8 -j ACCEPT
        -iptables -A INPUT -p tcp --dport 3142 --source 192.168.0.0.0/16 -j ACCEPT
        +iptables -A INPUT -p tcp --dport 3142 --source 192.168.0.0/16 -j ACCEPT
         iptables -A INPUT -p tcp --dport 3142  -j REJECT --reject-with tcp-reset
         

        5.5 Target port filter

        diff -Nru apt-cacher-ng-0.9.1/doc/html/troublefaq.html apt-cacher-ng-3.3.1/doc/html/troublefaq.html --- apt-cacher-ng-0.9.1/doc/html/troublefaq.html 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/html/troublefaq.html 2020-01-08 19:58:26.000000000 +0000 @@ -125,9 +125,9 @@ apt-get source apt-cacher-ng apt-get build-dep apt-cacher-ng cd apt-cacher-ng-* - make distclean all DEBUG=1 + ./build.sh DEBUG /etc/init.d/apt-cacher-ng stop - ./apt-cacher-ng -c /etc/apt-cacher-ng logdir=/tmp foreground=1 debug=7 + builddir/apt-cacher-ng -c /etc/apt-cacher-ng logdir=/tmp foreground=1 debug=7 # (let apt-get run now, on timeouts just wait >> 20 seconds) # stop the daemon with Ctrl-C /etc/init.d/apt-cacher-ng start diff -Nru apt-cacher-ng-0.9.1/doc/man/apt-cacher-ng.8 apt-cacher-ng-3.3.1/doc/man/apt-cacher-ng.8 --- apt-cacher-ng-0.9.1/doc/man/apt-cacher-ng.8 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/man/apt-cacher-ng.8 2020-01-08 19:58:26.000000000 +0000 @@ -17,16 +17,22 @@ .PP The command-line options supported by \fBapt-cacher-ng\fP are: .IP "\fB-c\fP \fIconfdir\fP" -Scan the specified configuration directory and interpret configuration files find there. +Scan the specified configuration directory and interpret configuration files found there. .IP "\fB-h\fP" Short option summary +.IP "\fB-i\fP" +Ignore some non-critical configuration errors on startup. Regular operation with this switch is not recommended. +.IP "\fB-v\fP" +Enable additional verbosity in log output. +.IP "\fB-e\fP" +Invoke expiration task immediately after startup. This option exists for legacy compatibility and can be dangerous to use due to filesystem permission issues (i.e. danger to cause them). Using acngtool to control such operations instead is advisable. .IP "\fIvarname=varopt\fP" The options from the configuration can be passed on the command line as key=value pairs. .SH "CONFIGURATION" .PP -Apt-Cacher NG is configured by a multi-config directory, i.e. the configuration is split into many configuration files having names with suffix \fI.conf\fP and stored in a single directory. Variables can override previously configured settings from other files, sometimes that settings are merged (depending on the variable). +Apt-Cacher NG is configured by a multi-config directory, i.e. the configuration is split into many configuration files having names with suffix \fI.conf\fP and stored in a single directory. Variables can override previously configured settings from other files, sometimes those settings are merged (depending on the variable). .PP -The configuration directory is typically \fI/etc/apt-cacher-ng\fP but it can be adjusted with the -C option (see systemd service file for details or wherever the init system starts the daemon). +The configuration directory is typically \fI/etc/apt-cacher-ng\fP but it can be adjusted with the -c option (see systemd service file for details or wherever the init system starts the daemon). .PP On Debian systems, there are at least three files installed by default: acng.conf (containing documented examples), security.conf (containing sensible data and only readable for special users) and zz_debconf.conf (containing popular settings which are set by the Debian Configuration mechanism). .SH "SIGNALS" diff -Nru apt-cacher-ng-0.9.1/doc/README apt-cacher-ng-3.3.1/doc/README --- apt-cacher-ng-0.9.1/doc/README 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/README 2020-01-08 19:58:26.000000000 +0000 @@ -142,7 +142,7 @@ eventually become not resolvable and the downloads will just fail. Using SSL/TLS transport (i.e. https urls) is also possible with some - restrictions, see section 8.3 for details. + restrictions, see section 8.2 for details. Chapter 4: Advanced Server Configuration ---------------------------------------- @@ -171,8 +171,10 @@ after first appearance on the server. - "Configuration line": one single line in the configuration file. - Some examples in this chapter may contain wrapped lines but - should be stored as a single line in the configuration. + Some examples in this chapter may be displayed as wrapped lines + but should be stored as a single line in the configuration. Some + variables (like `RequestAppendix') support multiline data which + needs to be separated with \n delimiter. 4.2 Configuration file types @@ -404,7 +406,7 @@ .debdelta files. The path hierarchy below this URL should correspond to the source URLs and file paths in the cache. Only one URL can be specified at the moment. It is used for explicit - mirroring operations, see section 8.15 for details. + mirroring operations, see section 8.14 for details. - `proxy=proxyspec' Configures an alternative proxy URL which overrides the global proxy setting in the context of this @@ -471,7 +473,7 @@ A simple control method for incoming connections is listening only to network interfaces which are inside a secure perimeter, e.g. - belong to the local network. See section 8.11 for details on this + belong to the local network. See section 8.10 for details on this configuration parameter. The default setting is listening to all interfaces. @@ -494,7 +496,7 @@ 5.3 Access control with inetd - In some situations, access filtering by client IP/hostname might + In some situations, access filtering by client IP or hostname might be not supported directly or there are other reasons to use inetd to wrap access to apt-cacher inetd. For this case, an inetd daemon is shipped with the package which makes the use of tcpd possible. @@ -529,7 +531,7 @@ (or any init script like `/etc/rc.local'): iptables -A INPUT -p tcp --dport 3142 --source 127.0.0.0/8 -j ACCEPT - iptables -A INPUT -p tcp --dport 3142 --source 192.168.0.0.0/16 -j ACCEPT + iptables -A INPUT -p tcp --dport 3142 --source 192.168.0.0/16 -j ACCEPT iptables -A INPUT -p tcp --dport 3142 -j REJECT --reject-with tcp-reset 5.5 Target port filter @@ -814,16 +816,14 @@ finally unreferenced files will be removed. To speed up this process, the local administrator can remove the - traces of the old distribution release from the archive. Either + index files of the old distribution release from the archive. Either the top-level "Release" files, or even the whole index file trees relevant for certain releases. - To make this task easier, a "brutal" script called distkill.pl is - shipped with apt-cacher-ng. It runs interactively, it scans the - package directory and presents an overview of index file trees - assumed to represent distro releases. Then it provides a command - promt to remove some immediately. The script should be used with - extreme care! See section 8.2 for example of its output. + To make this task easier, there is a special helper mode in the + cleanup task of the maintenance page. Run this manually (and maybe + enable extra verbosity on the main page) and use the wizard on the + bottom of the log page to delete particular index files. Chapter 8: HOWTOs and FAQ ------------------------- @@ -856,14 +856,14 @@ 2. Store copies of your .debs, .orig.tar.gz, ... somewhere in the `_import' subdirectory in the cache, ie. in `/var/cache/apt- - cacher/_import/'. The files may be links or symlinks, does not - matter. When done, apt-cacher will move those files to its own - internal locations. Example: + cacher-ng/_import/'. The files may be links or symlinks, it does + not matter. When done, apt-cacher will move those files to its + own internal locations. Example: cd /var/cache mkdir apt-cacher-ng/_import cp -laf apt-proxy apt-cacher /var/cache/apt-cacher-ng/_import - chown -R apt-cacher-ng apt-cacher-ng/_import + chown -R apt-cacher-ng:apt-cacher-ng apt-cacher-ng/_import 3. Visit the report page and trigger the import action there. Check the results, look for (red) error messages. @@ -898,53 +898,7 @@ on the client to purge APT's internal cache, and then rerun "apt-get update" there. - 8.2 Cache overview - - To get a basic overview of the cache contents, the distkill.pl - script may be used. See section 7.2 for details and warnings. - - # /usr/lib/apt-cacher-ng/distkill.pl - Scanning /var/cache/apt-cacher-ng, please wait... - Found distributions: - 1. testing (6 index files) - 2. sid (63 index files) - 3. etch-unikl (30 index files) - 4. etch (30 index files) - 5. experimental (505 index files) - 6. lenny (57 index files) - 7. unstable (918 index files) - 8. stable (10 index files) - - WARNING: The removal action would wipe out whole directories containing - index files. Select d to see detailed list. - - Which distribution to remove? (Number, 0 to exit, d for details): d - - Directories to remove: - 1. testing: - /var/cache/apt-cacher-ng/debrep/dists/testing - 2. sid: - /var/cache/apt-cacher-ng/localstuff/dists/sid - /var/cache/apt-cacher-ng/debrep/dists/sid - 4. etch: - /var/cache/apt-cacher-ng/ftp.debian-unofficial.org/debian/dists/etch - 5. experimental: - /var/cache/apt-cacher-ng/debrep/dists/experimental - 6. lenny: - /var/cache/apt-cacher-ng/security.debian.org/dists/lenny - /var/cache/apt-cacher-ng/debrep/dists/lenny - 7. unstable: - /var/cache/apt-cacher-ng/debrep/dists/unstable - /var/cache/apt-cacher-ng/localstuff/debian/dists/unstable - 8. stable: - /var/cache/apt-cacher-ng/debrep/dists/stable - Found distributions: - - WARNING: The removal action would wipe out whole directories containing - index files. Select d to see detailed list. - - - 8.3 Access to SSL/TLS remotes (HTTPS) + 8.2 Access to SSL/TLS remotes (HTTPS) It is possible to have encrypted access to remote sites via HTTPS protocol with recent versions of apt-cacher-ng if the OpenSSL @@ -990,7 +944,7 @@ the client has separated configuration options to set this. For Debian based distros, this can be done by adding a configuration like this: `Acquire::https::proxy "DIRECT";' to apt.conf or - one of the apt.conf.d files. See section 8.5 for further + one of the apt.conf.d files. See section 8.4 for further information. - The "backend configuration method": if the clients access the @@ -1026,7 +980,7 @@ # Basically the same just with access to apt-cacher-ng through # URL rewritting instead of setting http proxy. - 8.4 JIGDO usage + 8.3 JIGDO usage It's possible to use apt-cacher-ng source with the jigdo-lite utility. There are some limitations, though: @@ -1058,7 +1012,7 @@ That's all, jigdo-lite will fetch the package files using apt- cacher-ng proxy. - 8.5 Avoid use of apt-cacher-ng for certain hosts + 8.4 Avoid use of apt-cacher-ng for certain hosts Sometimes clients might need to access some remote side directly to do some non-file-transfer oriented work but still passing the @@ -1069,14 +1023,14 @@ Acquire::HTTP::Proxy::archive.example.org "DIRECT"; //or Acquire::HTTP::Proxy::archive.example.org "other.proxy:port" - 8.6 Avoid caching for certain domains or certain file types + 8.5 Avoid caching for certain domains or certain file types Sometimes clients to download through apt-cacher-ng but the data shall not be stored on the harddisk of the server. To get it, use the DontCache directive (see examples for details) to define such files. - 8.7 How to make big download series faster + 8.6 How to make big download series faster Symptom: A common situation is a periodic download of hundreds of files through apt-cacher-ng where just a half is present in the @@ -1098,11 +1052,11 @@ there is a higher chance to get the server connection "preheated" before a stall occurs. - 8.8 How to import DVDs or ISO images + 8.7 How to import DVDs or ISO images First, it should be clear what is needed to be done. In order to integrate the packages from a DVD or ISO image, read on in section - 8.9. + 8.8. The situation with ISO files import is complicated. They are not supported by the cache and there is also no expiration mode for @@ -1112,7 +1066,7 @@ What is possible now is publishing a directory with ISO files using its web server mode, see `LocalDirs' config option for details. - 8.9 How to integrate DVDs or ISO image data + 8.8 How to integrate DVDs or ISO image data Integrating package files from DVD or ISO images is not much different to the usual import operation, see above for instructions. @@ -1137,7 +1091,7 @@ up the symlinks and continue using them as links istead of file copies. - 8.10 How to execute commands before and after going online? + 8.9 How to execute commands before and after going online? It is possible to configure custom commands which are executed before the internet connection attempt and after a certain period @@ -1147,7 +1101,7 @@ section 4.3.2, `conf/*.hooks' and `/usr/share/doc/apt-cacher- ng/examples/*.hooks' files for details. - 8.11 Listen to only specific interfaces or IP protocols + 8.10 Listen to only specific interfaces or IP protocols Unless configured explicitely, the server listens to any interface with IPv4 or IPv6 protocol. To disable some of this, use the @@ -1164,7 +1118,7 @@ interfaces configured for the specific protocol, like 0.0.0.0 for IPv4. - 8.12 How to avoid use of IPv4 (or IPv6) where possible? + 8.11 How to avoid use of IPv4 (or IPv6) where possible? Usually, outgoing hosts are accessed by the protocol and with the target IP reported as the first candidate by operating system @@ -1173,7 +1127,7 @@ and then use IPv4 as alternative (or vice versa). See option ConnectProto in configuration examples. - 8.13 Use the proxy without storing all data twice + 8.12 Use the proxy without storing all data twice There is a general use case where the data storing behavior of APT is not so fortunate. Imagine an old laptop with a slow and small @@ -1210,7 +1164,7 @@ acngfs parameters, and then it gets files directly from the cache if they are completely downloaded and don't have volatile contents. - 8.14 Optional semi-automatic use of proxy + 8.13 Optional semi-automatic use of proxy Apt-Cacher NG daemon has some optional operations modes regading the use of external proxy (configured with "Proxy" setting). The default @@ -1243,7 +1197,7 @@ (see above) and another ACNG proxy in the home LAN to get smart caching for laptop users. - 8.15 Partial Mirroring + 8.14 Partial Mirroring It is possible to create a partial local mirror of a remote package repository. The method to do this is usually known as pre-caching. A @@ -1431,9 +1385,9 @@ apt-get source apt-cacher-ng apt-get build-dep apt-cacher-ng cd apt-cacher-ng-* - make distclean all DEBUG=1 + ./build.sh DEBUG /etc/init.d/apt-cacher-ng stop - ./apt-cacher-ng -c /etc/apt-cacher-ng logdir=/tmp foreground=1 debug=7 + builddir/apt-cacher-ng -c /etc/apt-cacher-ng logdir=/tmp foreground=1 debug=7 # (let apt-get run now, on timeouts just wait >> 20 seconds) # stop the daemon with Ctrl-C /etc/init.d/apt-cacher-ng start @@ -1501,7 +1455,7 @@ - Only HTTP HEAD and GET commands are supported properly. - CONNECT (for https/SSL/TLS tunnels) is supported but needs to be - enabled by local administrators, see section 8.3 for details + enabled by local administrators, see section 8.2 for details - POST support is restricted to apt-listbugs actions and is actually implemented as simple data forwarding with minor header @@ -1531,7 +1485,6 @@ on the Alioth project page. And last, but not least: feel free to express your gratitude by - donating a small amount of money via PayPal (to edi@gmx.de) or just - Flattr it! + donating a small amount of money via PayPal (to edi@gmx.de). [Eduard Bloch, Sun, 19 Apr 2015 10:25:49 +0200] diff -Nru apt-cacher-ng-0.9.1/doc/src/manpage.but apt-cacher-ng-3.3.1/doc/src/manpage.but --- apt-cacher-ng-0.9.1/doc/src/manpage.but 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/src/manpage.but 2020-01-08 19:58:26.000000000 +0000 @@ -28,12 +28,24 @@ \dt \cw{-c} \e{confdir} \dd Scan the specified configuration directory and interpret configuration - files find there. + files found there. \dt \cw{-h} \dd Short option summary +\dt \cw{-i} + +\dd Ignore some non-critical configuration errors on startup. Regular operation with this switch is not recommended. + +\dt \cw{-v} + +\dd Enable additional verbosity in log output. + +\dt \cw{-e} + +\dd Invoke expiration task immediately after startup. This option exists for legacy compatibility and can be dangerous to use due to filesystem permission issues (i.e. danger to cause them). Using acngtool to control such operations instead is advisable. + \dt \e{varname=varopt} \dd The options from the configuration can be passed on the command line as key=value pairs. @@ -43,11 +55,11 @@ Apt-Cacher NG is configured by a multi-config directory, i.e. the configuration is split into many configuration files having names with suffix \e{.conf} and stored in a single directory. Variables can override previously configured -settings from other files, sometimes that settings are merged (depending on the +settings from other files, sometimes those settings are merged (depending on the variable). The configuration directory is typically \e{/etc/apt-cacher-ng} but it can be -adjusted with the -C option (see systemd service file for details or wherever +adjusted with the -c option (see systemd service file for details or wherever the init system starts the daemon). On Debian systems, there are at least three files installed by default: diff -Nru apt-cacher-ng-0.9.1/doc/src/README.but apt-cacher-ng-3.3.1/doc/src/README.but --- apt-cacher-ng-0.9.1/doc/src/README.but 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/doc/src/README.but 2020-01-08 19:58:26.000000000 +0000 @@ -178,7 +178,8 @@ \b "Configuration line": one single line in the configuration file. Some examples in this chapter may -contain wrapped lines but should be stored as a single line in the configuration. +be displayed as wrapped lines but should be stored as a single line in the configuration. +Some variables (like \c{RequestAppendix}) support multiline data which needs to be separated with \\n delimiter. \H{cfgfiles} Configuration file types @@ -469,7 +470,7 @@ \H{acl-inetd} Access control with inetd -In some situations, access filtering by client IP/hostname might be not +In some situations, access filtering by client IP or hostname might be not supported directly or there are other reasons to use inetd to wrap access to apt-cacher inetd. For this case, an inetd daemon is shipped with the package which makes the use of tcpd possible. Installation is done in following steps: @@ -502,7 +503,7 @@ \c{/etc/rc.local}): \c iptables -A INPUT -p tcp --dport 3142 --source 127.0.0.0/8 -j ACCEPT -\c iptables -A INPUT -p tcp --dport 3142 --source 192.168.0.0.0/16 -j ACCEPT +\c iptables -A INPUT -p tcp --dport 3142 --source 192.168.0.0/16 -j ACCEPT \c iptables -A INPUT -p tcp --dport 3142 -j REJECT --reject-with tcp-reset \H{acl-tgtports} Target port filter @@ -769,16 +770,14 @@ package expiration will start complaining for some days (the expiration delay) and only then the finally unreferenced files will be removed. -To speed up this process, the local administrator can remove the traces of the +To speed up this process, the local administrator can remove the index files of the old distribution release from the archive. Either the top-level "Release" files, or even the whole index file trees relevant for certain releases. -To make this task easier, a "brutal" script called distkill.pl is shipped with -apt-cacher-ng. It runs interactively, it scans the package directory and -presents an overview of index file trees assumed to represent distro releases. -Then it provides a command promt to remove some immediately. The script should -be used with extreme care! See -\k{cache-overview} for example of its output. +To make this task easier, there is a special helper mode in the cleanup task of +the maintenance page. Run this manually (and maybe enable extra verbosity on +the main page) and use the wizard on the bottom of the log page to delete +particular index files. \C{howtos} HOWTOs and FAQ @@ -811,15 +810,15 @@ \n Store copies of your .debs, .orig.tar.gz, ... somewhere in the \c{_import} -subdirectory in the cache, ie. in \c{/var/cache/apt-cacher/_import/}. The files may -be links or symlinks, does not matter. When done, apt-cacher will move those +subdirectory in the cache, ie. in \c{/var/cache/apt-cacher-ng/_import/}. The files may +be links or symlinks, it does not matter. When done, apt-cacher will move those files to its own internal locations. Example: \lcont{ \c cd /var/cache \c mkdir apt-cacher-ng/_import \c cp -laf apt-proxy apt-cacher /var/cache/apt-cacher-ng/_import -\c chown -R apt-cacher-ng apt-cacher-ng/_import +\c chown -R apt-cacher-ng:apt-cacher-ng apt-cacher-ng/_import } \n Visit the report page and trigger the import action there. @@ -848,51 +847,6 @@ on the client to purge APT's internal cache, and then rerun "apt-get update" there. -\H{cache-overview}Cache overview - -To get a basic overview of the cache contents, the distkill.pl script may be used. See \k{distkill} for details and warnings. - -\c # /usr/lib/apt-cacher-ng/distkill.pl -\c Scanning /var/cache/apt-cacher-ng, please wait... -\c Found distributions: -\c 1. testing (6 index files) -\c 2. sid (63 index files) -\c 3. etch-unikl (30 index files) -\c 4. etch (30 index files) -\c 5. experimental (505 index files) -\c 6. lenny (57 index files) -\c 7. unstable (918 index files) -\c 8. stable (10 index files) -\c -\c WARNING: The removal action would wipe out whole directories containing -\c index files. Select d to see detailed list. -\c -\c Which distribution to remove? (Number, 0 to exit, d for details): d -\c -\c Directories to remove: -\c 1. testing: -\c /var/cache/apt-cacher-ng/debrep/dists/testing -\c 2. sid: -\c /var/cache/apt-cacher-ng/localstuff/dists/sid -\c /var/cache/apt-cacher-ng/debrep/dists/sid -\c 4. etch: -\c /var/cache/apt-cacher-ng/ftp.debian-unofficial.org/debian/dists/etch -\c 5. experimental: -\c /var/cache/apt-cacher-ng/debrep/dists/experimental -\c 6. lenny: -\c /var/cache/apt-cacher-ng/security.debian.org/dists/lenny -\c /var/cache/apt-cacher-ng/debrep/dists/lenny -\c 7. unstable: -\c /var/cache/apt-cacher-ng/debrep/dists/unstable -\c /var/cache/apt-cacher-ng/localstuff/debian/dists/unstable -\c 8. stable: -\c /var/cache/apt-cacher-ng/debrep/dists/stable -\c Found distributions: -\c -\c WARNING: The removal action would wipe out whole directories containing -\c index files. Select d to see detailed list. -\c - \H{ssluse}Access to SSL/TLS remotes (HTTPS) It is possible to have encrypted access to remote sites via HTTPS protocol with @@ -1308,9 +1262,9 @@ \c apt-get source apt-cacher-ng \c apt-get build-dep apt-cacher-ng \c cd apt-cacher-ng-* -\c make distclean all DEBUG=1 +\c ./build.sh DEBUG \c /etc/init.d/apt-cacher-ng stop -\c ./apt-cacher-ng -c /etc/apt-cacher-ng logdir=/tmp foreground=1 debug=7 +\c builddir/apt-cacher-ng -c /etc/apt-cacher-ng logdir=/tmp foreground=1 debug=7 \c # (let apt-get run now, on timeouts just wait >> 20 seconds) \c # stop the daemon with Ctrl-C \c /etc/init.d/apt-cacher-ng start @@ -1394,7 +1348,6 @@ available on the \W{http://alioth.debian.org/projects/apt-cacher-ng/}{Alioth project page}. And last, but not least: feel free to express your gratitude by donating a -small amount of money via \W{https://www.paypal.com}{PayPal} (to edi@gmx.de) or just -\W{https://flattr.com/thing/51105/Apt-Cacher-NG}{Flattr it!} +small amount of money via \W{https://www.paypal.com}{PayPal} (to edi@gmx.de). \versionid Eduard Bloch, Sun, 19 Apr 2015 10:25:49 +0200 diff -Nru apt-cacher-ng-0.9.1/fs/CMakeLists.txt apt-cacher-ng-3.3.1/fs/CMakeLists.txt --- apt-cacher-ng-0.9.1/fs/CMakeLists.txt 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/fs/CMakeLists.txt 2020-01-08 19:58:26.000000000 +0000 @@ -1,5 +1,3 @@ -PROJECT(ACNG CXX C) - ############################################ ## Attempt to build acngfs where possible ## @@ -7,33 +5,31 @@ pkg_check_modules(fuse fuse) -string(REPLACE ";" " " acngfs_cflags "${ACNG_CXXFLAGS_COMMON};-DMINIBUILD;${fuse_CFLAGS}") +_append(acngfs_cflags ${fuse_CFLAGS} ${CFLAGS_PTHREAD}) # double-check and make sure it compiles FILE(READ ../test/build/HAVE_FUSE_25.cc TESTSRC) -SET(CMAKE_REQUIRED_FLAGS "${ACNG_CXXFLAGS_COMMON} ${acngfs_cflags}") +SET(CMAKE_REQUIRED_FLAGS "${ACNG_COMPFLAGS} ${acngfs_cflags}") CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_FUSE_25) if(fuse_FOUND AND HAVE_FUSE_25) - list(APPEND fsSRCS httpfs.cc ../source/lockable.cc ../source/header.cc ../source/caddrinfo.cc ../source/acbuf.cc ../source/acfg.cc ../source/acfg_defaults.cc ../source/tcpconnect.cc ../source/dlcon.cc ../source/fileitem.cc ../source/meta.cc) + # not linking acngstuff lib, too many dependencies, so building a custom variant with MINIBUILD flag + list(APPEND fsSRCS httpfs.cc) - if(CMAKE_BUILD_TYPE MATCHES Debug) - list(APPEND fsSRCS ../source/aclogger.cc) - endif() - - ADD_EXECUTABLE(acngfs ${fsSRCS}) - INSTALL(TARGETS acngfs DESTINATION ${LIBDIR}) - - #message("uhm: ${fuse_CFLAGS} -- ${acngfs_cflags} -- ${fuse_LDFLAGS} -- ${HAVE_DLOPEN}") - SET_TARGET_PROPERTIES(acngfs PROPERTIES COMPILE_FLAGS "${acngfs_cflags}" ) - if(HAVE_DLOPEN) - TARGET_LINK_LIBRARIES(acngfs dl pthread ${BaseNetworkLibs} ${SSL_LIB_LIST} ${EXTRA_LIBS_ACNGFS}) - else(HAVE_DLOPEN) - TARGET_LINK_LIBRARIES(acngfs ${fuse_LDFLAGS} ${BaseNetworkLibs} ${SSL_LIB_LIST} ${EXTRA_LIBS_ACNGFS}) - endif(HAVE_DLOPEN) + if(CMAKE_BUILD_TYPE MATCHES Debug) + list(APPEND fsSRCS ../source/aclogger.cc) + endif() + + ADD_EXECUTABLE(acngfs ${fsSRCS}) + SET_TARGET_PROPERTIES(acngfs PROPERTIES COMPILE_FLAGS "${ACNG_COMPFLAGS} ${ACNG_CXXFLAGS} ${acngfs_cflags}") + INSTALL(TARGETS acngfs DESTINATION ${LIBDIR}) + if(HAVE_DLOPEN) + _append(EXTRA_LIBS_ACNGFS dl) + endif() + TARGET_LINK_LIBRARIES(acngfs supacng ${fuse_LDFLAGS} ${BaseNetworkLibs} ${SSL_LIB_LIST} ${EXTRA_LIBS_ACNGFS} ${CMAKE_THREAD_LIBS_INIT}) else(fuse_FOUND AND HAVE_FUSE_25) - message("- FUSE not found or not compatible, not building acngfs") + message("- FUSE not found or not compatible, not building acngfs") endif(fuse_FOUND AND HAVE_FUSE_25) diff -Nru apt-cacher-ng-0.9.1/fs/httpfs.cc apt-cacher-ng-3.3.1/fs/httpfs.cc --- apt-cacher-ng-0.9.1/fs/httpfs.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/fs/httpfs.cc 2020-01-08 19:58:26.000000000 +0000 @@ -8,8 +8,6 @@ #define LOCAL_DEBUG #include "debug.h" -#include "acsyscap.h" - #include "meta.h" #include "header.h" #include "caddrinfo.h" @@ -22,9 +20,8 @@ #include "fileitem.h" #include "dlcon.h" +#include "fileio.h" -#include -#include #ifdef HAVE_SYS_MOUNT_H #include #include @@ -33,19 +30,6 @@ #include #endif -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - #define FUSE_USE_VERSION 25 #include @@ -59,8 +43,7 @@ #endif using namespace std; - -const string sEmptyString; +using namespace acng; #ifdef SPAM #define _cerr(x) cerr << x @@ -79,8 +62,6 @@ static mstring altPath; bool g_bGoodServer=true; -cmstring sDefPortHTTP("3142"), sDefPortHTTPS("80"); - struct tDlDesc { cmstring m_path; @@ -157,7 +138,7 @@ tFileId(off_t a, mstring b) : m_size(a), m_ctime(b) {}; bool operator!=(tFileId other) const { return m_size != other.m_size || m_ctime != other.m_ctime;} }; -static class : public lockable, public map +static class : public base_with_mutex, public map {} remote_info_cache; struct tDlDescRemote : public tDlDesc @@ -172,7 +153,6 @@ { // expire the caches every time, should not cost much anyway g_tcp_con_factory.BackgroundCleanup(); - CAddrInfo::BackgroundCleanup(); }; int Read(char *retbuf, const char *path, off_t pos, size_t len) @@ -307,14 +287,14 @@ tFitem *pFi = new tFitem(retbuf, len, pos, fid, bIsFirst); tFileItemPtr spFi(static_cast(pFi)); - dler.AddJob(spFi, &uri, 0, 0, 0); + dler.AddJob(spFi, &uri, 0, 0, 0, cfg::REDIRMAX_DEFAULT); dler.WorkLoop(); int nHttpCode(100); pFi->WaitForFinish(&nHttpCode); bIsFirst=false; - if (m_ftype == rechecks::FILE_SOLID && fidOrig != fid) + if (m_ftype == rex::FILE_SOLID && fidOrig != fid) { lockguard g(remote_info_cache); remote_info_cache[m_path] = fid; @@ -380,7 +360,7 @@ } }; auto probe(make_shared()); - dler.AddJob(probe, &uri, 0, 0, 0); + dler.AddJob(probe, &uri, 0, 0, 0, cfg::REDIRMAX_DEFAULT); dler.WorkLoop(); int nHttpCode(100); fileitem::FiStatus res = probe->WaitForFinish(&nHttpCode); @@ -392,7 +372,7 @@ return -EIO; else if (nHttpCode == 200) { - if (m_ftype == rechecks::FILE_SOLID) // not caching volatile stuff + if (m_ftype == rex::FILE_SOLID) // not caching volatile stuff { lockguard g(remote_info_cache); remote_info_cache[m_path] = @@ -415,9 +395,9 @@ if(!path) return -1; - rechecks::eMatchType type = rechecks::GetFiletype(path); + rex::eMatchType type = rex::GetFiletype(path); _cerr( "type: " << type); - if (type == rechecks::FILE_SOLID || type == rechecks::FILE_VOLATILE) + if (type == rex::FILE_SOLID || type == rex::FILE_VOLATILE) { if(0 == tDlDescLocal(path, type).Stat(*stbuf)) return 0; @@ -541,12 +521,12 @@ tDlDesc *p(nullptr); struct stat stbuf; - rechecks::eMatchType ftype = rechecks::GetFiletype(path); + rex::eMatchType ftype = rex::GetFiletype(path); - MYTRY + try { // ok... if that is a remote object, can we still use local access instead? - if(!altPath.empty() && rechecks::FILE_SOLID == ftype) + if(!altPath.empty() && rex::FILE_SOLID == ftype) { p = new tDlDescLocal(path, ftype); if(p) @@ -568,7 +548,7 @@ return -EIO; } } - MYCATCH(std::bad_alloc&) + catch(std::bad_alloc&) { return -EIO; } @@ -652,6 +632,7 @@ int main(int argc, char *argv[]) { + using namespace acng; memset(&acngfs_oper, 0, sizeof(acngfs_oper)); acngfs_oper.getattr = acngfs_getattr; @@ -690,12 +671,12 @@ if(argc<4) barf("Not enough arguments, try --help.\n"); - acfg::agentname = "ACNGFS"; - acfg::agentheader="User-Agent: ACNGFS\r\n"; - acfg::requestapx = "User-Agent: ACNGFS\r\nX-Original-Source: 42\r\n"; + cfg::agentname = "ACNGFS"; + cfg::agentheader="User-Agent: ACNGFS\r\n"; + cfg::requestapx = "User-Agent: ACNGFS\r\nX-Original-Source: 42\r\n"; #ifdef SPAM - acfg::debug=0xff; - acfg::verboselog=1; + cfg::debug=0xff; + cfg::verboselog=1; #endif if(argv[1] && baseUrl.SetHttpUrl(argv[1])) @@ -726,7 +707,7 @@ // all parameters processed, forwarded to fuse call below - ::rechecks::CompileExpressions(); + acng::rex::CompileExpressions(); #if 0//def SPAM { @@ -747,8 +728,6 @@ nMyArgCount=3; altPath = argv[3]; } - - // test mount point const char *mpoint = argv[nMyArgCount+1]; @@ -765,8 +744,9 @@ } #ifndef DEBUG +namespace acng { // for the uber-clever GNU linker and should be removed by strip again -namespace aclog +namespace log { void flush() {}; void misc(const string &s, const char ) @@ -784,4 +764,5 @@ }; } +} #endif diff -Nru apt-cacher-ng-0.9.1/include/acbuf.h apt-cacher-ng-3.3.1/include/acbuf.h --- apt-cacher-ng-0.9.1/include/acbuf.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/acbuf.h 2020-01-08 19:58:26.000000000 +0000 @@ -7,11 +7,14 @@ #include #include "meta.h" +namespace acng +{ + /*! \brief Helper class to maintain a memory buffer, i.e. a continuous block of bytes. * It also encapsulates some typical operations on it. */ -class acbuf +class ACNG_API acbuf { public: inline acbuf() : r(0), w(0), m_nCapacity(0), m_buf(nullptr) {}; @@ -52,14 +55,14 @@ * \param maxlen Maximum amount of data to write * \return Number of written bytes, negative on failures, see write(2) */ - int syswrite(int fd, unsigned int maxlen=MAX_VAL(uint)); + int syswrite(int fd, unsigned int maxlen=MAX_VAL(unsigned int)); /* * Reads from a file descriptor and append to buffered data, update position indexes. * \param fd File descriptor * \return Number of read bytes, negative on failures, see read(2) */ - int sysread(int fd, unsigned int maxlen=MAX_VAL(uint)); + int sysread(int fd, unsigned int maxlen=MAX_VAL(unsigned int)); protected: @@ -77,7 +80,7 @@ * What it also makes possible: use itself as a string, use alternative add() operators * for strings which can also specify the length, and it runs faster with zero-terminated strings. */ -class tSS : public acbuf +class ACNG_API tSS : public acbuf { public: // map char array to buffer pointer and size @@ -85,7 +88,7 @@ inline tSS & operator<<(cmstring& val) { return add(val); }; inline tSS & operator<<(const acbuf& val) { return add(val.rptr(), val.size()); }; -#define __tss_nbrfmt(x, h, y) { add(fmtbuf, sprintf(fmtbuf, m_fmtmode == hex ? h : x, y)); return *this; } +#define __tss_nbrfmt(x, h, y) { reserve_atleast(22); got(sprintf(wptr(), m_fmtmode == hex ? h : x, y)); return *this; } inline tSS & operator<<(int val) __tss_nbrfmt("%d", "%x", val); inline tSS & operator<<(unsigned int val) __tss_nbrfmt("%u", "%x", val); inline tSS & operator<<(long val) __tss_nbrfmt("%ld", "%lx", val); @@ -96,7 +99,7 @@ inline tSS & operator<<(void* val) __tss_nbrfmt("ptr:%llu", "ptr:0x%llx", (long long unsigned) val); #endif - enum fmtflags { hex, dec }; + enum fmtflags : bool { hex, dec }; inline tSS & operator<<(fmtflags mode) { m_fmtmode=mode; return *this;} operator mstring() const { return mstring(rptr(), size()); } @@ -124,8 +127,8 @@ inline tSS & add(cmstring& val) { return add((const char*) val.data(), (size_t) val.size());} protected: - char fmtbuf[22]; fmtflags m_fmtmode; + /// make sure to have at least minWriteCapa bytes extra available for writing inline void reserve_atleast(size_t minWriteCapa) { if(w+minWriteCapa+1 < m_nCapacity) return; @@ -135,6 +138,6 @@ inline tSS & appDosNL() { return add("\r\n", 2);} }; -cmstring& GetFooter(); +} #endif diff -Nru apt-cacher-ng-0.9.1/include/acfg.h apt-cacher-ng-3.3.1/include/acfg.h --- apt-cacher-ng-0.9.1/include/acfg.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/acfg.h 2020-01-08 19:58:26.000000000 +0000 @@ -5,14 +5,13 @@ #include "config.h" #include "meta.h" #include -#include -static const int RESERVED_DEFVAL = -4223; #define NUM_PBKDF2_ITERATIONS 1 // 1757961 #define ACNG_DEF_PORT "3142" -#define ACFG_REDIRMAX_DEFAULT 5 +namespace acng +{ struct ltstring { bool operator()(const mstring &s1, const mstring &s2) const { @@ -22,10 +21,13 @@ typedef std::map NoCaseStringMap; -namespace acfg +namespace cfg { +static const int RESERVED_DEFVAL = -4223; -extern mstring cachedir, logdir, confdir, fifopath, user, group, pidfile, suppdir, +static const int REDIRMAX_DEFAULT = 5; + +extern mstring cachedir, logdir, confdir, udspath, user, group, pidfile, suppdir, reportpage, vfilepat, pfilepat, wfilepat, agentname, adminauth, adminauthB64, bindaddr, port, sUmask, tmpDontcacheReq, tmpDontcachetgt, tmpDontcache, mirrorsrcs, requestapx, @@ -33,11 +35,13 @@ extern mstring pfilepatEx, vfilepatEx, wfilepatEx, spfilepatEx, svfilepatEx; // for customization by user -extern int debug, numcores, offlinemode, foreground, verbose, stupidfs, forcemanaged, keepnver, +extern ACNG_API int debug, numcores, offlinemode, foreground, verbose, stupidfs, forcemanaged, keepnver, verboselog, extreshhold, exfailabort, tpstandbymax, tpthreadmax, dnscachetime, dlbufsize, usewrap, exporigin, logxff, oldupdate, recompbz2, nettimeout, updinterval, forwardsoap, dirperms, fileperms, maxtempdelay, redirmax, vrangeops, stucksecs, persistoutgoing, pipelinelen, exsupcount, -optproxytimeout, patrace, maxdlspeed, maxredlsize, nsafriendly; +optproxytimeout, patrace, maxdlspeed, maxredlsize, dlretriesmax, nsafriendly, trackfileuse, exstarttradeoff, +fasttimeout, discotimeout; +extern int allocspace; // processed config settings extern const tHttpUrl* GetProxyInfo(); @@ -46,14 +50,14 @@ extern int conprotos[2]; -extern std::atomic_bool degraded; - -bool SetOption(const mstring &line, NoCaseStringMap *pDupeChecker); -void dump_config(bool includingDelicateValues=false); -void ReadConfigDirectory(const char*, bool bReadErrorIsFatal=true); +bool ACNG_API SetOption(const mstring &line, NoCaseStringMap *pDupeChecker); +void ACNG_API dump_config(bool includingDelicateValues=false); +void ACNG_API ReadConfigDirectory(const char*, bool bReadErrorIsFatal=true); //! Prepare various things resulting from variable combinations, etc. -void PostProcConfig(); +void ACNG_API PostProcConfig(); + +bool DegradedMode(); struct tRepoData { @@ -98,16 +102,19 @@ extern mstring cacheDirSlash; // guaranteed to have a trailing path separator void dump_trace(); -int * GetIntPtr(LPCSTR key); -mstring * GetStringPtr(LPCSTR key); +ACNG_API int * GetIntPtr(LPCSTR key); +ACNG_API mstring * GetStringPtr(LPCSTR key); int CheckAdminAuth(LPCSTR auth); extern bool g_bQuiet, g_bNoComplex; +static const cmstring privStoreRelSnapSufix("_xstore/rsnap"); +static const cmstring privStoreRelQstatsSfx("_xstore/qstats"); + } // namespace acfg -namespace rechecks +namespace rex { enum NOCACHE_PATTYPE : bool @@ -116,7 +123,7 @@ NOCACHE_TGT }; -enum eMatchType +enum eMatchType : int8_t { FILE_INVALID = -1, FILE_SOLID = 0, FILE_VOLATILE, FILE_WHITELIST, @@ -132,8 +139,9 @@ bool CompileUncExpressions(NOCACHE_PATTYPE type, cmstring& pat); bool CompileExpressions(); } +LPCSTR ACNG_API ReTest(LPCSTR s); -#define CACHE_BASE (acfg::cacheDirSlash) +#define CACHE_BASE (acng::cfg::cacheDirSlash) #define CACHE_BASE_LEN (CACHE_BASE.length()) // where the relative paths begin #define SZABSPATH(x) (CACHE_BASE+(x)).c_str() #define SABSPATH(x) (CACHE_BASE+(x)) @@ -141,7 +149,7 @@ bool AppendPasswordHash(mstring &stringWithSalt, LPCSTR plainPass, size_t passLen); // XXX: find a better place for this, shared between server and acngtool -enum ControLineType +enum ControLineType : uint8_t { NotForUs = 0, BeforeError = 1, @@ -149,4 +157,6 @@ }; #define maark "41d_a6aeb8-26dfa" // random enough to not match anything existing *g* +} + #endif diff -Nru apt-cacher-ng-0.9.1/include/aclogger.h apt-cacher-ng-3.3.1/include/aclogger.h --- apt-cacher-ng-0.9.1/include/aclogger.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/aclogger.h 2020-01-08 19:58:26.000000000 +0000 @@ -5,10 +5,8 @@ #include "meta.h" #include "acbuf.h" -#define LOG_FLUSH 1 -#define LOG_MORE 2 -#define LOG_DEBUG 4 - +namespace acng +{ #ifdef DEBUG @@ -17,7 +15,7 @@ t_logger(const char *szFuncName, const void * ptr); // starts the logger, shifts stack depth ~t_logger(); tSS & GetFmter(); - void Write(const char *pFile=nullptr, unsigned int nLine=0); + void Write(const char *pFile = nullptr, unsigned int nLine = 0); private: tSS m_strm; pthread_t m_id; @@ -31,52 +29,77 @@ #define USRDBG(msg) LOG(msg) #else // print some extra things when user wants debug with non-debug build -#define USRDBG(msg) { if(acfg::debug & LOG_DEBUG) {aclog::err( tSS()< GetCurrentCountersInOut(); +void ResetOldCounters(); +std::pair GetOldCountersInOut(bool calcIncomming = true, bool calcOutgoing = true); + +bool ACNG_API open(); +void ACNG_API close(bool bReopen); +void transfer(uint64_t bytesIn, uint64_t bytesOut, cmstring& sClient, cmstring& sPath, + bool bAsError); +void err(const char *msg, const char *client = nullptr); +void misc(const mstring & sLine, const char cLogType = 'M'); +inline void err(cmstring &msg) +{ + err(msg.c_str()); +} +inline void err(const tSS& msg) { + err(msg.c_str()); +} +void flush(); + +void GenerateReport(mstring &); - bool open(); - void close(bool bReopen); - void transfer(char cLogType, uint64_t nCount, const char *szClient, const char *szPath); - void err(const char *msg, const char *client=nullptr); - void misc(const mstring & sLine, const char cLogType='M'); - inline void err(cmstring &msg) { err(msg.c_str()); } - inline void err(const tSS& msg) { err(msg.c_str()); } - void flush(); - - void GenerateReport(mstring &); - - class tRowData - { - public: - uint64_t byteIn, byteOut; - unsigned long reqIn, reqOut; - time_t from, to; - tRowData() : byteIn(0), byteOut(0), reqIn(0), reqOut(0), from(0), to(0) - {}; - /* - tRowData(const tRowData &a) : - byteIn(a.byteIn), byteOut(a.byteOut), - reqIn(a.reqIn), reqOut(a.reqOut), - from(a.from), to(a.to) - { - }; - */ - private: - // tRowData & operator=(const tRowData &a); - }; +class tRowData +{ +public: + uint64_t byteIn, byteOut; + unsigned long reqIn, reqOut; + time_t from, to; + tRowData() : + byteIn(0), byteOut(0), reqIn(0), reqOut(0), from(0), to(0) + { + } + ; + /* + tRowData(const tRowData &a) : + byteIn(a.byteIn), byteOut(a.byteOut), + reqIn(a.reqIn), reqOut(a.reqOut), + from(a.from), to(a.to) + { + }; + */ +private: + // tRowData & operator=(const tRowData &a); +}; - mstring GetStatReport(); +mstring GetStatReport(); } //#define TIMEFORMAT "%a %d/%m" #define TIMEFORMAT "%Y-%m-%d %H:%M" +} #endif - - diff -Nru apt-cacher-ng-0.9.1/include/acsyscap.h.in apt-cacher-ng-3.3.1/include/acsyscap.h.in --- apt-cacher-ng-0.9.1/include/acsyscap.h.in 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/acsyscap.h.in 2020-01-08 19:58:26.000000000 +0000 @@ -1,4 +1,6 @@ -/* Generated by CMake build scripts, manual changes will be lost */ +/* + * WARNING: Generated by CMake build scripts, manual changes will be lost! + */ #cmakedefine HAVE_ZLIB #cmakedefine HAVE_LIBBZ2 @@ -24,9 +26,13 @@ #cmakedefine HAVE_SD_NOTIFY #cmakedefine HAVE_LINUX_EVENTFD #cmakedefine ACVERSION "@ACVERSION@" -#cmakedefine CFGDIR "@CFGDIR@" -#cmakedefine LIBDIR "@LIBDIR@" -#cmakedefine DOCDIR "@DOCDIR@" -#cmakedefine BINDIR "@BINDIR@" -#cmakedefine SBINDIR "@SBINDIR@" +#cmakedefine CFGDIR "@CFGDIR@" +#cmakedefine LIBDIR "@LIBDIR@" +#define DOCDIR "@CMAKE_INSTALL_FULL_DOCDIR@" +#define BINDIR "@CMAKE_INSTALL_FULL_BINDIR@" +#define SBINDIR "@CMAKE_INSTALL_FULL_SBINDIR@" #cmakedefine HAVE_CHECKSUM +#define CACHEDIR "@ACNG_CACHE_DIR@" +#define LOGDIR "@ACNG_LOG_DIR@" +#define UDSPATH "@SOCKET_PATH@" + diff -Nru apt-cacher-ng-0.9.1/include/bgtask.h apt-cacher-ng-3.3.1/include/bgtask.h --- apt-cacher-ng-0.9.1/include/bgtask.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/bgtask.h 2020-01-08 19:58:26.000000000 +0000 @@ -13,6 +13,9 @@ #include #include +namespace acng +{ + class tSpecOpDetachable : public tSpecialRequest { public: @@ -51,38 +54,19 @@ // counter. Originally written with some uber-protective considerations in mind like // not letting a listener block the work of an operator by any means. - // notification of attached processes - class tProgressTracker : public condition - { - public: - off_t nEndSize; - time_t id; - tProgressTracker() : nEndSize(-1), id(0) {}; - void SetEnd(off_t); - }; - typedef SHARED_PTR tProgTrackPtr; - static WEAK_PTR g_pTracker; - tProgTrackPtr m_pTracker; - protected: // value is an ID number assigned to the string (key) in the moment of adding it - std::map m_delCboxFilter; + struct pathMemEntry { mstring msg; unsigned id;}; + std::map m_pathMemory; // generates a lookup blob as hidden form parameter mstring BuildCompressedDelFileCatalog(); -}; -struct tRemoteFileInfo; -// helper to make the code more robust -class ifileprocessor -{ -public: - virtual void HandlePkgEntry(const tRemoteFileInfo &entry) = 0; - virtual ~ifileprocessor() {}; + static base_with_condition g_StateCv; + static bool g_sigTaskAbort; + // to watch the log file + int m_logFd = -1; }; -extern pthread_mutex_t abortMx; -extern bool bSigTaskAbort; - #ifdef DEBUG class tBgTester : public tSpecOpDetachable { @@ -96,4 +80,6 @@ }; #endif // DEBUG +} + #endif /* BGTASK_H_ */ diff -Nru apt-cacher-ng-0.9.1/include/cacheman.h apt-cacher-ng-3.3.1/include/cacheman.h --- apt-cacher-ng-0.9.1/include/cacheman.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/cacheman.h 2020-01-08 19:58:26.000000000 +0000 @@ -11,12 +11,19 @@ #include "bgtask.h" #include "fileitem.h" #include +#include // #define USEDUPEFILTER +namespace acng +{ + class dlcon; + +// XXX: specific declarations, maybe move to a namespace class tDlJobHints; -struct foo; +class tFileGroups; +struct tContentKey; static cmstring sAbortMsg("Found errors during processing, " "aborting as requested."); @@ -24,30 +31,24 @@ static cmstring sIndex("Index"); static cmstring sslIndex("/Index"); -struct tPatchEntry -{ - string patchName; - tFingerprint fprState, fprPatch; -}; -typedef deque::const_iterator tPListConstIt; +bool CompDebVerLessThan(cmstring &s1, cmstring s2); +extern time_t m_gMaintTimeNow; void DelTree(const string &what); - -class tCacheOperation : +class cacheman : public IFileHandler, public tSpecOpDetachable { public: - tCacheOperation(const tSpecialRequest::tRunParms& parms); - virtual ~tCacheOperation(); + cacheman(const tSpecialRequest::tRunParms& parms); + virtual ~cacheman(); -protected: enum enumMetaType - : uint_least8_t + : uint8_t { - EIDX_UNSUPPORTED = 0, + EIDX_NOTREFINDEX = 0, EIDX_RELEASE, EIDX_PACKAGES, EIDX_SOURCES, @@ -57,41 +58,55 @@ EIDX_SUSEREPO, EIDX_XMLRPMLIST, EIDX_RFC822WITHLISTS, - EIDX_TRANSIDX, + EIDX_TRANSIDX, // XXX: in the old times, there were special i18n/Index files, are they gone for good now? EIDX_MD5DILIST, EIDX_SHA256DILIST }; struct tIfileAttribs { bool vfile_ondisk:1, uptodate:1, parseignore:1, hideDlErrors:1, - forgiveDlErrors:1, alreadyparsed:1, - guessed:1; // file is not on disk, the name is pure calculation from pdiff mechanism - enumMetaType eIdxType = EIDX_UNSUPPORTED; - const tStrDeq *bros = nullptr; + forgiveDlErrors:1, alreadyparsed:1; + enumMetaType eIdxType = EIDX_NOTREFINDEX; + tIfileAttribs *bro; // point to a related descriptor, circled single-linked list off_t space = 0; inline tIfileAttribs() : vfile_ondisk(false), uptodate(false), parseignore(false), hideDlErrors(false), - forgiveDlErrors(false), alreadyparsed(false), - guessed(false) - {}; + forgiveDlErrors(false), alreadyparsed(false) + { + bro = this; + }; +#if defined(DEBUG) || defined(DEBUGIDX) + inline tSS toString() const + { + return tSS() << alreadyparsed << "|" + << forgiveDlErrors << "|" + << hideDlErrors << "|" + << parseignore << "|" + << space << "|" + << uptodate << "|" + << vfile_ondisk; + } +#endif }; - // this is not unordered because sometimes it might need modification - // while an iterator still works on it - std::map m_metaFilesRel; // helpers to keep the code cleaner and more readable const tIfileAttribs &GetFlags(cmstring &sPathRel) const; - tIfileAttribs &SetFlags(cmstring &sPathRel); - void SetCommonUserFlags(cmstring &cmd); +protected: + // this is not unordered because sometimes we make use of iterator references while + // doing modification of the map + std::map m_metaFilesRel; + tIfileAttribs &SetFlags(cmstring &sPathRel); + // evil shortcut, might point to read-only dummy... to be used with care + tIfileAttribs &GetRWFlags(cmstring &sPathRel); void UpdateVolatileFiles(); void _BusyDisplayLogs(); void _Usermsg(mstring m); bool AddIFileCandidate(const mstring &sFileRel); - // NOOP, implemented here for convinience + // NOOP, implemented here for convenience bool ProcessOthers(const mstring &sPath, const struct stat &); bool ProcessDirAfter(const mstring &sPath, const struct stat &); @@ -106,7 +121,7 @@ * * */ - void ProcessSeenMetaFiles(ifileprocessor &pkgHandler); + void ProcessSeenIndexFiles(std::function pkgHandler); void StartDlder(); @@ -118,11 +133,12 @@ }; bool Download(cmstring& sFilePathRel, bool bIsVolatileFile, eDlMsgPrio msgLevel, tFileItemPtr pForcedItem=tFileItemPtr(), - const tHttpUrl *pForcedURL=nullptr, unsigned hints=0); + const tHttpUrl *pForcedURL=nullptr, unsigned hints=0, cmstring* sGuessedFrom = nullptr); #define DL_HINT_GUESS_REPLACEMENT 0x1 +#define DL_HINT_NOTAG 0x2 - // internal helper variables - bool m_bErrAbort, m_bVerbose, m_bForceDownload; + // common helper variables + bool m_bErrAbort, m_bVerbose, m_bForceDownload, m_bSkipIxUpdate = false; bool m_bScanInternals, m_bByPath, m_bByChecksum, m_bSkipHeaderChecks; bool m_bTruncateDamaged; int m_nErrorCount; @@ -133,8 +149,11 @@ void TellCount(unsigned nCount, off_t nSize); - bool ParseAndProcessMetaFile(ifileprocessor &output_receiver, - const mstring &sPath, enumMetaType idxType); + /** + * @param collectAllCsTypes If set, will send callbacks for all identified checksum types. In addition, will set the value of Acquire-By-Hash to the pointed boolean. + */ + bool ParseAndProcessMetaFile(std::function output_receiver, + const mstring &sPath, enumMetaType idxType, bool byHashMode = false); std::unordered_map m_forceKeepInTrash; @@ -146,56 +165,97 @@ mstring m_processedIfile; void ProgTell(); - void AddDelCbox(cmstring &sFileRel, bool bExtraFile = false); - - typedef std::pair tContId; - struct tClassDesc {tStrDeq paths; tContId diffIdxId, bz2VersContId;}; - typedef std::map tContId2eqClass; + void AddDelCbox(cmstring &sFileRel, cmstring& reason, bool bExtraFile = false); // add certain files to the kill bill, to be removed after the activity is done virtual void MarkObsolete(cmstring&) {}; // for compressed map of special stuff - inline mstring AddLookupGetKey(cmstring &sFilePathRel, bool& isNew) - { - unsigned id = m_delCboxFilter.size(); - auto it = m_delCboxFilter.find(sFilePathRel); - isNew = it==m_delCboxFilter.end(); - if(isNew) - m_delCboxFilter[sFilePathRel] = id; - else - id = it->second; - char buf[30]; - return mstring(buf, snprintf(buf, sizeof(buf), " name=\"kf\" value=\"%x\"", id)); - } + mstring AddLookupGetKey(cmstring &sFilePathRel, cmstring& errorReason); + + // stuff in those directories must be managed by some top-level index files + // whitelist patterns do not apply there! + tStrSet m_managedDirs; private: - tContId2eqClass m_eqClasses; - bool Propagate(cmstring &donorRel, tContId2eqClass::iterator eqClassIter, - cmstring *psTmpUnpackedAbs=nullptr); - void InstallBz2edPatchResult(tContId2eqClass::iterator &eqClassIter); - tCacheOperation(const tCacheOperation&); - tCacheOperation& operator=(const tCacheOperation&); - bool PatchFile(cmstring &srcRel, cmstring &patchIdxLocation, - tPListConstIt pit, tPListConstIt itEnd, - const tFingerprint *verifData); - dlcon *m_pDlcon; + void ExtractAllRawReleaseDataFixStrandedPatchIndex(tFileGroups& ret, const tStrDeq& releaseFilesRel); + void FilterGroupData(tFileGroups& idxGroups); + void SortAndInterconnectGroupData(tFileGroups& idxGroups); + + /** + * Adjust the configuration of related paths (relative to updatePath) to prevent + * smart downloads later, how exactly depends on current execution mode. + * + * If strict path checks are used the content may also be copied over. + */ + void SyncSiblings(cmstring &srcPathRel, const tStrDeq& targets); + + cacheman(const cacheman&); + cacheman& operator=(const cacheman&); + + dlcon *m_pDlcon = nullptr; + cmstring& GetFirstPresentPath(const tFileGroups& groups, const tContentKey& ckey); + + /* + * Analyze patch base candidate, fetch patch files as suggested by index, patch, distribute result + */ + void PatchOne(cmstring& pindexPathRel, const tStrDeq& patchBaseCandidates); + void ParseGenericRfc822File(filereader& reader, cmstring& sExtListFilter, + map >& contents); + bool ParseDebianIndexLine(tRemoteFileInfo& info, cmstring& fline); +protected: + bool CalculateBaseDirectories(cmstring& sPath, enumMetaType idxType, mstring& sBaseDir, mstring& sBasePkgDir); bool IsDeprecatedArchFile(cmstring &sFilePathRel); - + /** + * @brief Process key:val type files, handling multiline values as lists + * @param ixInflatedChecksum Pass through as struct attribute to ret callback + * @param sExtListFilter If set to non-empty, will only extract value(s) for that key + * @param byHashMode Return without calbacks if AcquireByHash is not set to yes. Not setting list filter also makes sense in this mode. + */ + bool ParseDebianRfc822Index(filereader& reader, std::function &ret, + cmstring& sCurFilesReferenceDirRel, + cmstring& sPkgBaseDir, + enumMetaType ixType, CSTYPES csType, + cmstring& sExtListFilter, + bool byHashMode); const tIfileAttribs attr_dummy_pure = tIfileAttribs(); tIfileAttribs attr_dummy; -}; + /* Little helper to check existence of specific name on disk, either in cache or replacement directory, depending on what the srcPrefix defines */ + virtual bool _checkSolidHashOnDisk(cmstring& hexname, const tRemoteFileInfo &entry, + cmstring& srcPrefix); + + // "can return false negatives" thing + // to be implemented in subclasses + virtual bool _QuickCheckSolidFileOnDisk(cmstring& /* sFilePathRel */) { return false; } + void BuildCacheFileList(); + /** + * This is supposed to restore references to files that are no longer + * downloaded by apt directly but via semi-static files identified by hash + * value in their name. + * + * Without this link, the index processing would not be able to parse the + * lists correctly and expiration would eventually "expire" good data. + * + * The code identify the original location of the index + * file by Release file analysis. */ + bool FixMissingByHashLinks(std::unordered_set &oldReleaseFiles); + + /** + * If the specified (In)Release file has By-Hash enabled, look for paths that match + * the hash reference and if found, restore the data contents on the location of the + * file that the by-hash blobs originated from. + * @param releasePathRel cache-relative location of InRelease file + * @param stripPrefix Optional prefix to prepend to releasePathRel but not to referenced files + */ + bool ProcessByHashReleaseFileRestoreFiles(cmstring& releasePathRel, cmstring& stripPrefix); -static cmstring compSuffixes[] = { ".xz", ".bz2", ".gz", ".lzma"}; -static cmstring compSuffixesAndEmpty[] = { ".xz", ".bz2", ".gz", ".lzma", ""}; -static cmstring compSuffixesAndEmptyByLikelyhood[] = { "", ".xz", ".bz2", ".gz", ".lzma",}; -static cmstring compSuffixesAndEmptyByRatio[] = { ".xz", ".lzma", ".bz2", ".gz", ""}; -static cmstring compSuffixesByRatio[] = { ".xz", ".lzma", ".bz2", ".gz"}; + // simple helper for use by others as well, and let compiler do RVO + tStrDeq GetGoodReleaseFiles(); +}; -bool CompDebVerLessThan(cmstring &s1, cmstring s2); -extern time_t m_gMaintTimeNow; +} #endif /*_CACHEMAN_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/caddrinfo.h apt-cacher-ng-3.3.1/include/caddrinfo.h --- apt-cacher-ng-0.9.1/include/caddrinfo.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/caddrinfo.h 2020-01-08 19:58:26.000000000 +0000 @@ -2,47 +2,55 @@ #define CADDRINFO_H_ #include "meta.h" -#include "rfc2553emu.h" #include "lockable.h" - -#ifndef HAVE_GETADDRINFO -#warning Not sure about gai_strerror, and this define check is stupid/incorrect too -#warning but most likely it is missing too -> fake it +#include +#include "sockio.h" -#ifndef gai_strerror -#define gai_strerror(x) "Generic DNS error" -#endif +namespace acng +{ -#endif +class CAddrInfo +{ + // not to be copied ever + CAddrInfo(const CAddrInfo&) = delete; + CAddrInfo operator=(const CAddrInfo&) = delete; -class CAddrInfo; + // some hints for cached entries + std::unique_ptr m_sError; + time_t m_expTime = MAX_VAL(time_t); + + // raw returned data from getaddrinfo + evutil_addrinfo * m_rawInfo = nullptr; + // shortcut for iterators, first in the list with TCP target + evutil_addrinfo * m_tcpAddrInfo = nullptr; -class CAddrInfo : public lockable -{ public: - time_t m_nExpTime=0; - struct addrinfo * m_addrInfo=nullptr; - CAddrInfo() =default; - bool Resolve(const mstring & sHostname, const mstring &sPort, mstring & sErrorBuf); + CAddrInfo() = default; + // blocking DNS resolution. Supposed to be called only once! + bool ResolveTcpTarget(const mstring & sHostname, const mstring &sPort, mstring & sErrorBuf, + const evutil_addrinfo* hints, + bool & bTransientError); + + void Reset(); + ~CAddrInfo(); - typedef SHARED_PTR SPtr; - static SPtr CachedResolve(const mstring & sHostname, const mstring &sPort, + static SHARED_PTR CachedResolve(const mstring & sHostname, const mstring &sPort, mstring &sErrorMsgBuf); - static time_t BackgroundCleanup(); + //tDnsIterator getIterator(int pf_filter) const { return tDnsIterator(pf_filter, this); } + /** + * Return a pre-located pointer which points on the first TCP compatible address or nullptr + * if no such found. + */ + const evutil_addrinfo *getTcpAddrInfo() const { return m_tcpAddrInfo; } +}; -protected: - struct addrinfo * m_resolvedInfo=nullptr; // getaddrinfo excrements, to cleanup +typedef SHARED_PTR CAddrInfoPtr; -private: - // not to be copied ever - CAddrInfo(const CAddrInfo&); - CAddrInfo operator=(const CAddrInfo&); - -}; +} #endif /*CADDRINFO_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/cleaner.h apt-cacher-ng-3.3.1/include/cleaner.h --- apt-cacher-ng-0.9.1/include/cleaner.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/cleaner.h 2020-01-08 19:58:26.000000000 +0000 @@ -12,6 +12,9 @@ #include #include +namespace acng +{ + /** * @brief Primitive task scheduler for internal helper functions * @@ -19,30 +22,38 @@ * b) called method return the next time they want to be called * c) called method can be run at any time without side-effects * (they have to check the need of their internal work by themselves) + * + * The implementation comes from a trade-off. Data size is not big enough to justify use of priority_queue, + * and it also makes not much sense since time points need to be adjusted for specific usecases without + * need to invalidate previous entries sitting in the prio-queue. + * */ -class cleaner : public condition +class ACNG_API cleaner : public base_with_condition { public: - cleaner(); void Init(); virtual ~cleaner(); void WorkLoop(); void Stop(); - enum eType + enum eType : char { - TYPE_EXFILEITEM, TYPE_ACFGHOOKS, TYPE_EXDNS, TYPE_EXCONNS, - TYPE_STOPSCHED, ETYPE_MAX + TYPE_EXFILEITEM, TYPE_ACFGHOOKS, /* TYPE_EXDNS,*/ TYPE_EXCONNS, + ETYPE_MAX }; void ScheduleFor(time_t when, eType what); void dump_status(); + static cleaner& GetInstance(bool initAsNoop=false); private: + cleaner(bool noop=false); pthread_t m_thr; time_t stamps[cleaner::ETYPE_MAX]; + bool m_terminating = false; + bool m_noop=false; }; -extern cleaner g_victor; // ... down to the nap +} #endif /* CLEANER_H_ */ diff -Nru apt-cacher-ng-0.9.1/include/config.h apt-cacher-ng-3.3.1/include/config.h --- apt-cacher-ng-0.9.1/include/config.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/config.h 2020-01-08 19:58:26.000000000 +0000 @@ -22,19 +22,14 @@ // added in Makefile... #define _FILE_OFFSET_BITS 64 +namespace acng +{ + #define SHARED_PTR std::shared_ptr #define INTRUSIVE_PTR std::intrusive_ptr #define WEAK_PTR std::weak_ptr #define SCOPED_PTR std::auto_ptr -#ifdef NO_EXCEPTIONS -#define MYTRY -#define MYCATCH(x) if(false) -#else -#define MYTRY try -#define MYCATCH catch -#endif - #ifndef PATH_MAX #define PATH_MAX 4096 #endif @@ -53,4 +48,33 @@ #define SSL_OPT_ARG(x) #endif +#if defined _WIN32 || defined __CYGWIN__ + #define ACNG_SO_IMPORT __declspec(dllimport) + #define ACNG_SO_EXPORT __declspec(dllexport) + #define ACNG_SO_LOCAL +#else + #if __GNUC__ >= 4 + #define ACNG_SO_IMPORT __attribute__ ((visibility ("default"))) + #define ACNG_SO_EXPORT __attribute__ ((visibility ("default"))) + #define ACNG_SO_LOCAL __attribute__ ((visibility ("hidden"))) + #else + #define ACNG_SO_IMPORT + #define ACNG_SO_EXPORT + #define ACNG_SO_LOCAL + #endif +#endif + +#ifdef ACNG_CORE_IN_SO + #ifdef supacng_EXPORTS // defined by cmake for shared lib project + #define ACNG_API ACNG_SO_EXPORT + #else + #define ACNG_API ACNG_SO_IMPORT + #endif // ACNG_DLL_EXPORTS + #define ACNG_LOCAL ACNG_SO_LOCAL +#else // ACNG_DLL is not defined, code is built in as usual + #define ACNG_API + #define ACNG_LOCAL +#endif // ACNG_DLL + +} #endif // __CONFIG_H diff -Nru apt-cacher-ng-0.9.1/include/conn.h apt-cacher-ng-3.3.1/include/conn.h --- apt-cacher-ng-0.9.1/include/conn.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/conn.h 2020-01-08 19:58:26.000000000 +0000 @@ -1,76 +1,74 @@ - #ifndef _CON_H #define _CON_H #include "config.h" #include "lockable.h" - +#include "header.h" +#include "sockio.h" #include #include +#include #define RBUFLEN 16384 +namespace acng +{ + class dlcon; class job; class header; -class con; -typedef SHARED_PTR tConPtr; +class conn; +typedef SHARED_PTR tConPtr; -class con // : public tRunable +class conn // : public tRunable { - public: - con(int fdId, const char *client); - virtual ~con(); - - void WorkLoop(); - - void LogDataCounts(const mstring & file, - const char *xff, - off_t countIn, off_t countOut, bool bFileIsError); - - private: - con& operator=(const con&);// { /* ASSERT(!"Don't copy con objects"); */ }; - con(const con&);// { /* ASSERT(!"Don't copy con objects"); */ }; - - //! Terminate the connection descriptors gracefully - void ShutDown(); +public: + conn(unique_fd fdId, const char *client); + virtual ~conn(); + + void WorkLoop(); +private: + conn& operator=(const conn&); // { /* ASSERT(!"Don't copy con objects"); */ }; + conn(const conn&); // { /* ASSERT(!"Don't copy con objects"); */ }; + unique_fd m_fd; + int m_confd; + bool m_badState = false; + + std::list m_jobs2send; - int m_confd; - - std::list m_jobs2send; - #ifdef KILLABLE // to awake select with dummy data int wakepipe[2]; #endif - - bool m_bStopActivity; - - pthread_t m_dlerthr; - - // for jobs - friend class job; - bool SetupDownloader(const char *xff); - dlcon * m_pDlClient; - mstring m_sClientHost; - header *m_pTmpHead; - - struct __tlogstuff - { - mstring file, client; - off_t sumIn, sumOut; - bool bFileIsError; - void write(); - void reset(const mstring &pNewFile, const mstring &pNewClient, bool bIsError); - inline __tlogstuff() : sumIn(0), sumOut(0), bFileIsError(false) {} - } logstuff; + + std::thread m_dlerthr; + + // for jobs + friend class job; + bool SetupDownloader(const char *xff); + std::shared_ptr m_pDlClient; + mstring m_sClientHost; + + // some accounting + mstring logFile, logClient; + off_t fileTransferIn = 0, fileTransferOut = 0; + bool m_bLogAsError = false; + void writeAnotherLogRecord(const mstring &pNewFile, + const mstring &pNewClient); + + // This method collects the logged data counts for certain file. + // Since the user might restart the transfer again and again, the counts are accumulated (for each file path) + void LogDataCounts(cmstring &file, const char *xff, off_t countIn, + off_t countOut, bool bAsError); #ifdef DEBUG unsigned m_nProcessedJobs; #endif }; +} + #endif diff -Nru apt-cacher-ng-0.9.1/include/conserver.h apt-cacher-ng-3.3.1/include/conserver.h --- apt-cacher-ng-0.9.1/include/conserver.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/conserver.h 2020-01-08 19:58:26.000000000 +0000 @@ -1,16 +1,30 @@ #ifndef CONSERVER_H_ #define CONSERVER_H_ +#include "meta.h" + +namespace acng +{ + namespace conserver { /*! Prepares the connection handlers and internal things, binds, listens, etc. - * @return Nothing, uses exit to abort + * @return Number of created listeners. */ -void Setup(); +int Setup(); /// Start the service int Run(); /// Stop all running connections sanely and threads if possible -void Shutdown(); +ACNG_API void Shutdown(); + +void HandleOverload(); + +/** + * Return connection handle for proper closing. + */ +ACNG_API void FinishConnection(int fd); + +} } diff -Nru apt-cacher-ng-0.9.1/include/csmapping.h apt-cacher-ng-3.3.1/include/csmapping.h --- apt-cacher-ng-0.9.1/include/csmapping.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/csmapping.h 2020-01-08 19:58:26.000000000 +0000 @@ -9,7 +9,10 @@ // XXX: allocate this dynamically? #define MAXCSLEN 64 -typedef enum { +namespace acng +{ + +typedef enum : char { CSTYPE_INVALID=0, CSTYPE_MD5=1, CSTYPE_SHA1=2, @@ -50,6 +53,17 @@ default: return "Other"; } } +inline LPCSTR GetCsNameReleaseFile(CSTYPES csType) +{ + switch(csType) + { + case CSTYPE_MD5: return "MD5Sum"; + case CSTYPE_SHA1: return "SHA1"; + case CSTYPE_SHA256: return "SHA256"; + case CSTYPE_SHA512: return "SHA512"; + default: return "Other"; + } +} class csumBase { @@ -72,6 +86,14 @@ { memcpy(csum, a.csum, sizeof(csum)); }; + tFingerprint & operator=(const tFingerprint& a) + { + if(this == &a) return *this; + size = a.size; + csType = a.csType; + memcpy(csum, a.csum, sizeof(csum)); + return *this; + } bool SetCs(const mstring & hexString, CSTYPES eCstype = CSTYPE_INVALID) { @@ -104,8 +126,37 @@ return false; size=newsize; return true; + } - bool ScanFile(const mstring & path, const CSTYPES eCstype, bool bUnpack, FILE *fDump=nullptr) + + /** + * Reads first two tokens from splitter, first considered checksum, second the size. + * Keeps the splitter pointed at last token, expects splitter be set at previous position. + * @return false if data is crap or wantedType was set but does not fit what's in the first token. + */ + inline bool Set(const tSplitWalk & splitInput, CSTYPES wantedType = CSTYPE_INVALID) + { + if(!splitInput.Next()) + return false; + if(!SetCs(splitInput.str(), wantedType)) + return false; + if(!splitInput.Next()) + return false; + size = atoofft(splitInput.str().c_str(), -1); + if(size < 0) + return false; + return true; + } +#if 0 + /** + * Warning: this function only exists to work around C++ stupidity. + * The const modifier is void, it will still modify splitter state. + */ + inline bool Set(const tSplitWalk & splitInput, CSTYPES wantedType = CSTYPE_INVALID) + { return Set(std::move(splitInput), wantedType); } +#endif + + bool ScanFile(const mstring & path, const CSTYPES eCstype, bool bUnpack = false, FILE *fDump=nullptr) { if(! GetCSTypeLen(eCstype)) return false; // unsupported @@ -139,7 +190,7 @@ { return !(other == *this); } - bool CheckFile(cmstring & sFile) + bool CheckFile(cmstring & sFile) const { if(size != GetFileSize(sFile, -2)) return false; @@ -161,14 +212,12 @@ struct tRemoteFileInfo { tFingerprint fpr; - bool bInflateForCs = false; mstring sDirectory, sFileName; inline void SetInvalid() { sFileName.clear(); sDirectory.clear(); fpr.csType=CSTYPE_INVALID; fpr.size=-1; - bInflateForCs = false; } inline bool IsUsable() { return (!sFileName.empty() && fpr.csType!=CSTYPE_INVALID && fpr.size>0); @@ -233,5 +282,6 @@ typedef std::map tFprCacheMap; +} #endif /*CSMAPPING_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/debug.h apt-cacher-ng-3.3.1/include/debug.h --- apt-cacher-ng-0.9.1/include/debug.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/debug.h 2020-01-08 19:58:26.000000000 +0000 @@ -8,9 +8,14 @@ #include #include - #ifdef DEBUG #include +#endif + +namespace acng +{ + +#ifdef DEBUG #define ASSERT(x) assert(x) #else #define ASSERT(x) @@ -23,6 +28,7 @@ #define dbgline #define ASSERT(x) #define LOG(x) +#define LOGSTARTFUNC #define LOGSTART(x) #define LOGSTARTs(x) #define LOGSTART2(x,y) @@ -33,20 +39,21 @@ #else -#define LOGLVL(n, x) if(acfg::debug&n){ __logobj.GetFmter() << x; __logobj.Write(__FILE__,__LINE__); } -#define LOG(x) LOGLVL(LOG_DEBUG, x) +#define LOGLVL(n, x) if(acng::cfg::debug&n){ __logobj.GetFmter() << x; __logobj.Write(__FILE__,__LINE__); } +#define LOG(x) LOGLVL(log::LOG_DEBUG, x) +#define LOGSTARTFUNC t_logger __logobj(__func__, this); #define LOGSTART(x) t_logger __logobj(x, this); #define LOGSTARTs(x) t_logger __logobj(x, nullptr); -#define LOGSTART2(x, y) t_logger __logobj(x, this); LOGLVL(LOG_DEBUG, y /* << "@" __FILE__ ":" << __LINE__ */ ) -#define LOGSTART2s(x, y) t_logger __logobj(x, nullptr); LOGLVL(LOG_DEBUG, y /*<< "@" __FILE__ ":" << __LINE__ */ ) +#define LOGSTART2(x, y) t_logger __logobj(x, this); LOGLVL(log::LOG_DEBUG, y /* << "@" __FILE__ ":" << __LINE__ */ ) +#define LOGSTART2s(x, y) t_logger __logobj(x, nullptr); LOGLVL(log::LOG_DEBUG, y /*<< "@" __FILE__ ":" << __LINE__ */ ) #define dbgprint(x) std::cerr << x << std::endl; #define ldbg(x) LOG(x) #define dbgline ldbg("mark") -#define DBGQLOG(x) {aclog::err(tSS()<< x);} +#define DBGQLOG(x) {log::err(tSS()<< x);} #define dump_proc_status dump_proc_status_always #endif @@ -64,5 +71,6 @@ } }; +} #endif // __DEBUG_H__ diff -Nru apt-cacher-ng-0.9.1/include/dirwalk.h apt-cacher-ng-3.3.1/include/dirwalk.h --- apt-cacher-ng-0.9.1/include/dirwalk.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/dirwalk.h 2020-01-08 19:58:26.000000000 +0000 @@ -6,19 +6,26 @@ #include -class IFileHandler +namespace acng +{ + +class ACNG_API IFileHandler { public: virtual bool ProcessRegular(const std::string &sPath, const struct stat &) =0; virtual bool ProcessOthers(const std::string &sPath, const struct stat &)=0; virtual bool ProcessDirAfter(const std::string &sPath, const struct stat &)=0; virtual ~IFileHandler() {}; -}; - -bool DirectoryWalk(const mstring & sRootDir, IFileHandler *h, bool bFilterDoubleDirVisit=true, - bool bFollowSymlinks=true); + typedef std::function output_receiver; + static bool DirectoryWalk(const mstring & sRootDir, IFileHandler *h, bool bFilterDoubleDirVisit=true, + bool bFollowSymlinks=true); + // similar, but returns only files, and just using a function pointer for that + static bool FindFiles(const mstring & sRootDir, IFileHandler::output_receiver callBack, bool bFilterDoubleDirVisit=true, + bool bFollowSymlinks=true); +}; +} #endif /*DIRWALK_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/dlcon.h apt-cacher-ng-3.3.1/include/dlcon.h --- apt-cacher-ng-0.9.1/include/dlcon.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/dlcon.h 2020-01-08 19:58:26.000000000 +0000 @@ -16,11 +16,30 @@ #include "acfg.h" #include "acbuf.h" +namespace acng +{ + struct tDlJob; -typedef SHARED_PTR tDlJobPtr; +typedef std::shared_ptr tDlJobPtr; typedef std::list tDljQueue; -class dlcon : public lockable +/** + * dlcon is a basic connection broker for download processes. + * It's defacto a slave of the conn class, the active thread is spawned by conn when needed + * and it's finished by its destructor. However, the life time is prolonged if the usage count + * is not down to zero, i.e. when there are more users registered as reader for the file + * downloaded by the agent here then it will continue downloading and block the conn dtor + * until that download is finished or the other client detaches. If a download is active and parent + * conn object calls Stop... then the download will be aborted ASAP. + * + * Internally, a queue of download job items is maintained. Each contains a reference either to + * a full target URL or to a tupple of a list of mirror descriptions (url prefix) and additional + * path suffix for the required file. + * + * In addition, there is a local blacklist which is applied to all download jobs in the queue, + * i.e. remotes marked as faulty there are no longer considered by the subsequent download jobs. + */ +class ACNG_API dlcon : public base_with_mutex { public: dlcon(bool bManualExecution, mstring *xff=nullptr, @@ -32,8 +51,9 @@ void SignalStop(); bool AddJob(tFileItemPtr m_pItem, const tHttpUrl *pForcedUrl, - const acfg::tRepoData *pRepoDesc, - cmstring *sPatSuffix, LPCSTR reqHead); + const cfg::tRepoData *pRepoDesc, + cmstring *sPatSuffix, LPCSTR reqHead, + int nMaxRedirection); mstring m_sXForwardedFor; @@ -95,10 +115,11 @@ unsigned m_nLastDlCount=0; void wake(); + void awaken_check(); }; #define IS_REDIRECT(st) (st == 301 || st == 302 || st == 307) -#endif - +} +#endif diff -Nru apt-cacher-ng-0.9.1/include/dnsiter.h apt-cacher-ng-3.3.1/include/dnsiter.h --- apt-cacher-ng-0.9.1/include/dnsiter.h 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/dnsiter.h 2020-01-08 19:58:26.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * dnsiter.h + * + * Created on: 29.10.2019 + * Author: Eduard Bloch + * + * Help structures to iterate over addrinfo results picking only specific protocols. + */ + +#ifndef INCLUDE_DNSITER_H_ +#define INCLUDE_DNSITER_H_ + +#include + +namespace acng +{ + +// produce a sequence of entries filtered by family type (ipv4, ipv6, or unspec) +struct tDnsIterator +{ + tDnsIterator(int pf_filter, const evutil_addrinfo* par); + tDnsIterator() = default; + const evutil_addrinfo* next(); +private: + const evutil_addrinfo* m_cur = nullptr; + int m_pf = 0, m_just_created = true; +}; + +// returns an alternating sequence for different families, starting with the preferred one +struct tAlternatingDnsIterator +{ + tDnsIterator m_iters[2]; + bool m_idx, m_toggle; + + const evutil_addrinfo* next(); + tAlternatingDnsIterator(const evutil_addrinfo*); +}; + +} + + + +#endif /* INCLUDE_DNSITER_H_ */ diff -Nru apt-cacher-ng-0.9.1/include/evabase.h apt-cacher-ng-3.3.1/include/evabase.h --- apt-cacher-ng-0.9.1/include/evabase.h 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/evabase.h 2020-01-08 19:58:26.000000000 +0000 @@ -0,0 +1,38 @@ +#ifndef __EVABASE_H__ +#define __EVABASE_H__ + +#include "config.h" + +struct event_base; +#include +#include + +namespace acng +{ + +class socket_activity_base; + +/** + * Event lib abstraction - destructible event base + */ +class ACNG_API evabase +{ + std::unordered_set m_weak_ref_users; + +public: + event_base *base; + static std::atomic in_shutdown; + /** Share the global instance created by main() */ + static std::shared_ptr instance; + evabase(); + ~evabase(); + + // add a "free running" activity reference to the collection, for later shutdown + void register_activity(socket_activity_base*); + void unregister_activity(socket_activity_base*); + void invoke_shutdown_activities(); +}; + +} + +#endif diff -Nru apt-cacher-ng-0.9.1/include/evasocket.h apt-cacher-ng-3.3.1/include/evasocket.h --- apt-cacher-ng-0.9.1/include/evasocket.h 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/evasocket.h 2020-01-08 19:58:26.000000000 +0000 @@ -0,0 +1,87 @@ +#ifndef __evasocket_h__ +#define __evasocket_h__ + +#include +#include + +#include "meta.h" + +struct event; + +namespace acng +{ + +class evabase; + +/** + * Event lib abstraction - destructible socket wrapper + * + * Auto-closer for a socket descriptor + */ +class evasocket +{ + evutil_socket_t m_fd; + evasocket(evutil_socket_t fd); +public: + ~evasocket(); + evutil_socket_t fd() { return m_fd; } + static std::shared_ptr create(evutil_socket_t fd); +}; + +/** + * Reference-counting-friendly helper which binds an event to a socket. + */ +class event_socket +{ + struct event * m_event = nullptr; + std::shared_ptr m_evbase; + std::shared_ptr m_sock; + std::function& sock, short)> m_parent_action; + +public: + event_socket(std::shared_ptr ev_base, + std::shared_ptr sock, + short create_flags, + std::function& sock, short)> action); + ~event_socket(); + + // activate the event once (does not make sense with EV_PERSIST) + void enable(const struct timeval *tv = nullptr); + // disable a previously enabled event (does not make much sense with EV_PERSIST unless suppressing one known pending execution is needed) + void disable(); + + // interface to libevent callbacks + static void on_io(evutil_socket_t, short what, void *uptr); + +private: + event_socket(const event_socket&) = delete; + // subtle moving to different location is just as bad because the pointer argument in the event pool becomes wild + event_socket(event_socket&&) = delete; +}; + +/** + * A free running activity tracker for interaction with a single socket. + * Will notify the parent about its destruction. + */ +class socket_activity_base +{ + // keep us alive + std::shared_ptr m_selfref; +protected: + std::shared_ptr m_evbase; +public: + socket_activity_base(std::shared_ptr m_evbase); + // release the back reference from the main base if it was registered there + virtual ~socket_activity_base(); + + // interface towards evabase: + + /** + * Tell all outstanding activities inside to stop and eventually release the object. + */ + virtual void invoke_shutdown() { delete this; } +}; + +} + +#endif diff -Nru apt-cacher-ng-0.9.1/include/expiration.h apt-cacher-ng-3.3.1/include/expiration.h --- apt-cacher-ng-0.9.1/include/expiration.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/expiration.h 2020-01-08 19:58:26.000000000 +0000 @@ -5,6 +5,9 @@ #include #include +namespace acng +{ + // caching all relevant file identity data and helper flags in such entries struct tDiskFileInfo { @@ -15,15 +18,16 @@ tFingerprint fpr; }; -class expiration : public tCacheOperation, public ifileprocessor +class expiration : public cacheman { public: // XXX: g++ 4.7 is not there yet... using tCacheOperation::tCacheOperation; - inline expiration(const tRunParms& parms) : tCacheOperation(parms) {}; + inline expiration(const tRunParms& parms) : cacheman(parms) {}; protected: std::unordered_map> m_trashFile2dir2Info; + tStrVec m_oversizedFiles; void RemoveAndStoreStatus(bool bPurgeNow); void LoadPreviousData(bool bForceInsert); @@ -32,9 +36,7 @@ virtual void Action() override; // for FileHandler virtual bool ProcessRegular(const mstring &sPath, const struct stat &) override; - - // for ifileprocessor - virtual void HandlePkgEntry(const tRemoteFileInfo &entry) override; + void HandlePkgEntry(const tRemoteFileInfo &entry); void LoadHints(); @@ -48,9 +50,18 @@ void MarkObsolete(cmstring&) override; tStrVec m_killBill; + virtual bool _checkSolidHashOnDisk(cmstring& hexname, const tRemoteFileInfo &entry, + cmstring& srcPrefix) override; + virtual bool _QuickCheckSolidFileOnDisk(cmstring& /* sFilePathRel */) override; private: int m_nPrevFailCount =0; bool CheckAndReportError(); + + void HandleDamagedFiles(); + void ListExpiredFiles(); + void TrimFiles(); }; +} + #endif /*EXPIRATION_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/fileio.h apt-cacher-ng-3.3.1/include/fileio.h --- apt-cacher-ng-0.9.1/include/fileio.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/fileio.h 2020-01-08 19:58:26.000000000 +0000 @@ -24,6 +24,9 @@ #define O_BINARY 0 // ignore on Unix #endif +namespace acng +{ + int falloc_helper(int fd, off_t start, off_t len); ssize_t sendfile_generic(int out_fd, int in_fd, off_t *offset, size_t count); @@ -53,8 +56,19 @@ void set_nb(int fd); void set_block(int fd); -#define forceclose(fd) { while(0 != ::close(fd)) { if(errno != EINTR) break; }; fd=-1; } -#define checkforceclose(fd) if(fd>=0){ while(0 != ::close(fd)) { if(errno != EINTR) break; }; fd=-1; } +inline void forceclose(int& fd) { while(0 != ::close(fd)) { if(errno != EINTR) break; }; fd=-1; } +inline void justforceclose(int fd) { while(0 != ::close(fd)) { if(errno != EINTR) break; }; } +inline void checkforceclose(int &fd) +{ + if (fd == -1) + return; + while (0 != ::close(fd)) + { + if (errno != EINTR) + break; + }; + fd = -1; +} inline void checkForceFclose(FILE* &fh) @@ -70,6 +84,7 @@ } } +// more efficient than tDtorEx with lambda struct FILE_RAII { FILE *p = nullptr; @@ -82,7 +97,8 @@ FILE_RAII operator=(const FILE_RAII&); }; - +void mkdirhier(cmstring& path); +bool xtouch(cmstring &wanted); void mkbasedir(const mstring & path); /* @@ -99,4 +115,8 @@ }; */ +using unique_fd = auto_raii; + +} + #endif /* FILEIO_H_ */ diff -Nru apt-cacher-ng-0.9.1/include/fileitem.h apt-cacher-ng-3.3.1/include/fileitem.h --- apt-cacher-ng-0.9.1/include/fileitem.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/fileitem.h 2020-01-08 19:58:26.000000000 +0000 @@ -9,17 +9,20 @@ #include "header.h" #include +namespace acng +{ + class fileitem; -typedef SHARED_PTR tFileItemPtr; +typedef std::shared_ptr tFileItemPtr; typedef std::unordered_multimap tFiGlobMap; //! Base class containing all required data and methods for communication with the download sources -class fileitem : public condition +class ACNG_API fileitem : public base_with_condition { public: // Life cycle (process states) of a file description item - enum FiStatus + enum FiStatus : char { FIST_FRESH, FIST_INITED, FIST_DLPENDING, FIST_DLGOTHEAD, FIST_DLRECEIVING, @@ -72,6 +75,8 @@ /// mark the item as complete as-is, assuming that sizeseen is correct void SetupComplete(); + void UpdateHeadTimestamp(); + uint64_t m_nIncommingCount; off_t m_nSizeSeen; off_t m_nRangeLimit; @@ -91,6 +96,7 @@ FiStatus m_status; mstring m_sPathRel; time_t m_nTimeDlStarted, m_nTimeDlDone; + virtual int Truncate2checkedSize() {return 0;}; private: // helper data for global registration control. Access is synchronized by the global lock, @@ -106,6 +112,7 @@ inline fileitem_with_storage(cmstring &s) {m_sPathRel=s;}; inline fileitem_with_storage(cmstring &s, int nUsers) {m_sPathRel=s; usercount=nUsers; }; virtual ~fileitem_with_storage(); + int Truncate2checkedSize() override; // send helper like wrapper for sendfile. Just declare virtual here to make it better customizable later. virtual ssize_t SendData(int confd, int filefd, off_t &nSendPos, size_t nMax2SendNow) override; virtual bool DownloadStartedStoreHeader(const header & h, size_t hDataLen, @@ -115,8 +122,10 @@ inline static mstring NormalizePath(cmstring &sPathRaw) { - return acfg::stupidfs ? DosEscape(sPathRaw) : sPathRaw; + return cfg::stupidfs ? DosEscape(sPathRaw) : sPathRaw; } +protected: + int MoveRelease2Sidestore(); }; #ifndef MINIBUILD @@ -128,7 +137,7 @@ public: // public constructor wrapper, get a unique object from the map or a new one - bool PrepageRegisteredFileItemWithStorage(cmstring &sPathUnescaped, bool bConsiderAltStore); + bool PrepareRegisteredFileItemWithStorage(cmstring &sPathUnescaped, bool bConsiderAltStore); // related to GetRegisteredFileItem but used for registration of custom file item // implementations created elsewhere (which still need to obey regular work flow) @@ -145,12 +154,12 @@ // when copied around, invalidates the original reference ~fileItemMgmt(); inline fileItemMgmt() {} - inline tFileItemPtr get() {return m_ptr;} + inline tFileItemPtr getFiPtr() {return m_ptr;} inline operator bool() const {return (bool) m_ptr;} + tFileItemPtr m_ptr; private: - tFileItemPtr m_ptr; void Unreg(); fileItemMgmt(const fileItemMgmt &src); @@ -163,7 +172,5 @@ #define fileItemMgmt void #endif // not MINIBUILD +} #endif - - - diff -Nru apt-cacher-ng-0.9.1/include/filelocks.h apt-cacher-ng-3.3.1/include/filelocks.h --- apt-cacher-ng-0.9.1/include/filelocks.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/filelocks.h 2020-01-08 19:58:26.000000000 +0000 @@ -8,6 +8,9 @@ #include #include +namespace acng +{ + struct TFileShrinkGuard { static std::unique_ptr Acquire(const struct stat&); @@ -19,5 +22,6 @@ TFileShrinkGuard() =default; }; +} #endif /* FILELOCKS_H_ */ diff -Nru apt-cacher-ng-0.9.1/include/filereader.h apt-cacher-ng-3.3.1/include/filereader.h --- apt-cacher-ng-0.9.1/include/filereader.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/filereader.h 2020-01-08 19:58:26.000000000 +0000 @@ -7,6 +7,9 @@ #include "fileio.h" #include "filelocks.h" +namespace acng +{ + class IDecompressor; @@ -16,7 +19,7 @@ * Could use boost::iostream templates for most of that, but Boost became such a monster nowadays. * And for my work, my class behaves smarter. */ -class filereader { +class ACNG_API filereader { public: filereader(); @@ -97,5 +100,6 @@ bool Bz2compressFile(const char *pathIn, const char*pathOut); -#endif // __FILEREADER_H +} +#endif // __FILEREADER_H diff -Nru apt-cacher-ng-0.9.1/include/header.h apt-cacher-ng-3.3.1/include/header.h --- apt-cacher-ng-0.9.1/include/header.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/header.h 2020-01-08 19:58:26.000000000 +0000 @@ -5,11 +5,15 @@ #include #include #include "meta.h" +#include "acbuf.h" -class header { +namespace acng +{ +class ACNG_API header { public: - enum eHeadType { + enum eHeadType : char + { INVALID, HEAD, GET, @@ -17,7 +21,8 @@ CONNECT, ANSWER }; - enum eHeadPos { + enum eHeadPos : char + { CONNECTION, // 0 CONTENT_LENGTH, IF_MODIFIED_SINCE, @@ -46,21 +51,12 @@ inline header(){}; ~header(); header(const header &); + header(header &&); header& operator=(const header&); static mstring GenInfoHeaders(); static bool ParseDate(const char *, struct tm*); - /*! - * Read buffer to parse one string. Optional offset where to begin to - * scan. - * - * return: - * 0: incomplete, needs more data - * <0: error - * >0: length of the processed data - */ - int LoadFromBuf(const char *src, unsigned length); int LoadFromFile(const mstring & sPath); //! returns byte count or negative errno value @@ -70,6 +66,7 @@ void set(eHeadPos, const char *val); void set(eHeadPos, const char *s, size_t len); void set(eHeadPos, off_t nValue); + void prep(eHeadPos, size_t length); void del(eHeadPos); inline void copy(const header &src, eHeadPos pos) { set(pos, src.h[pos]); }; @@ -81,11 +78,20 @@ tSS ToString() const; static std::vector GetKnownHeaders(); - - //@param pNotForUs unsorted map, key is header name, value is the rest of the line starting - // with colon and ending with \r\n. In case of multiline, extending lines are appended to - // the value string as-is - int Load(const char *src, unsigned length, tLPS *pNotForUs=nullptr); + /** + * Read buffer to parse one string. Optional offset where to begin to + * scan. + * + * @param src Pointer to raw input + * @param length Maximum considered input length + * @param unkFunc Optional callback for ignored headers (called with key name and rest of the line including CRLF) + * @return Length of processed data, + * 0: incomplete, needs more data + * <0: error + * >0: length of the processed data + */ + // XXX: maybe redesign the unkFunc to just use pointer and length instead of strings + int Load(const char *src, unsigned length, const std::function &unkFunc = std::function()); }; inline bool BODYFREECODE(int status) @@ -94,4 +100,6 @@ return (304 == status || (status>=100 && status<200) || 204==status); } +} + #endif diff -Nru apt-cacher-ng-0.9.1/include/job.h apt-cacher-ng-3.3.1/include/job.h --- apt-cacher-ng-0.9.1/include/job.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/job.h 2020-01-08 19:58:26.000000000 +0000 @@ -9,19 +9,22 @@ #include "fileitem.h" #include "maintenance.h" -class con; +namespace acng +{ + +class conn; class job { public: - typedef enum + typedef enum : char { R_DONE = 0, R_AGAIN = 1, R_DISCON = 2, R_NOTFORUS = 3 } eJobResult; - typedef enum { + typedef enum : char { STATE_SEND_MAIN_HEAD, STATE_HEADER_SENT, STATE_SEND_PLAIN_DATA, @@ -34,7 +37,7 @@ STATE_FINISHJOB } eJobState; - job(header *h, con *pParent); + job(header &&h, conn *pParent); ~job(); // __attribute__((externally_visible)) @@ -43,12 +46,12 @@ /* * Start or continue returning the file. */ - eJobResult SendData(int confd); + eJobResult SendData(int confd, bool haveMoreJobs); private: int m_filefd; - con *m_pParentCon; + conn *m_pParentCon; bool m_bChunkMode; bool m_bClientWants2Close; @@ -62,14 +65,14 @@ tSpecialRequest::eMaintWorkType m_eMaintWorkType = tSpecialRequest::workNotSpecial; mstring m_sOrigUrl; // local SAFE copy of the originating source - header *m_pReqHead; // copy of users requests header + header m_reqHead; // copy of users requests header fileItemMgmt m_pItem; off_t m_nSendPos, m_nCurrentRangeLast; off_t m_nAllDataCount; unsigned long m_nChunkRemainingBytes; - rechecks::eMatchType m_type; + rex::eMatchType m_type; job(const job&); job & operator=(const job&); @@ -77,7 +80,7 @@ const char * BuildAndEnqueHeader(const fileitem::FiStatus &fistate, const off_t &nGooddataSize, header& respHead); fileitem::FiStatus _SwitchToPtItem(); void SetErrorResponse(const char * errorLine, const char *szLocation=nullptr, const char *bodytext=nullptr); - void HandleLocalDownload(const mstring &visPath, + void PrepareLocalDownload(const mstring &visPath, const mstring &fsBase, const mstring &fsSubpath); bool ParseRange(); @@ -86,9 +89,11 @@ }; -class tTraceData: public tStrSet, public lockable { +class tTraceData: public tStrSet, public base_with_mutex { public: static tTraceData& getInstance(); }; +} + #endif diff -Nru apt-cacher-ng-0.9.1/include/jsonstats.h apt-cacher-ng-3.3.1/include/jsonstats.h --- apt-cacher-ng-0.9.1/include/jsonstats.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/jsonstats.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -#ifndef SOURCE_JSONSTATS_H_ -#define SOURCE_JSONSTATS_H_ - -#include - -class jsonstats: public expiration -{ -public: - jsonstats(const tRunParms & parms);// : public expiration(parms) {}; - virtual ~jsonstats(); - void Run() override; - void Action() override; -protected: - void PrintJson(); -}; - -#endif /* SOURCE_JSONSTATS_H_ */ diff -Nru apt-cacher-ng-0.9.1/include/lockable.h apt-cacher-ng-3.3.1/include/lockable.h --- apt-cacher-ng-0.9.1/include/lockable.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/lockable.h 2020-01-08 19:58:26.000000000 +0000 @@ -1,167 +1,51 @@ #ifndef _LOCKABLE_H #define _LOCKABLE_H -#include +#include -/* - * This is a custom implementation of synchronization objects for flexible use in different - * parts of ACNG, including RAII style helper objects. - * - * The implementation is somewhat similar to what's available in Boost and C++11 now - * but only because it was driven by the same ideas and needs, and it was developed long - * before C++11 and explicitly avoiding the requirement of a Boost installation. - */ - -class lockguard; - -#ifdef DEBUG_never -#include -#define __lock_yell(x) std::cerr <<"### " x "\n"; -#else -#define __lock_yell(x) -#endif +#include +#include -class lockable +namespace acng { -public: - inline lockable() - { - pthread_mutex_init(&m_obj_mutex, nullptr); - } - virtual ~lockable() - { - pthread_mutex_destroy(&m_obj_mutex); - } - inline void lock() - { - pthread_mutex_lock(&m_obj_mutex); - } - bool tryLock(); - inline void unlock() - { - pthread_mutex_unlock(&m_obj_mutex); - } - -protected: - friend class lockguard; - pthread_mutex_t m_obj_mutex; -}; -class lockguard +typedef std::mutex acmutex; + +struct base_with_mutex { -public: + std::mutex m_obj_mutex; +}; - // lock() helper sets the bool flag, no need to pre-initialize here - inline lockguard(pthread_mutex_t *m, bool bInitiallyLock = true) : - l(*m), bLocked(false) - { - if (bInitiallyLock) - lock(); - } - inline lockguard(pthread_mutex_t &m, bool bInitiallyLock = true) : - l(m), bLocked(false) - { - if (bInitiallyLock) - lock(); - } - inline lockguard(lockable & cl, bool bInitiallyLock = true) : - l(cl.m_obj_mutex), bLocked(false) - { - if (bInitiallyLock) - lock(); - } - - inline lockguard(lockable *cl, bool bInitiallyLock = true) : - l(cl->m_obj_mutex), bLocked(false) - { - if (bInitiallyLock) - lock(); - } - inline void unLock() - { - if (bLocked) - { - pthread_mutex_unlock(&l); - bLocked = false; - __lock_yell ("LOCK RELEASED"); - } - } - inline void reLock() - { - if (!bLocked) - lock(); - } - ~lockguard() - { - unLock(); - } - -private: - pthread_mutex_t& l; - bool bLocked; - - inline void lock() - { - pthread_mutex_lock(&l); - bLocked = true; - __lock_yell ("LOCK SET"); - } - - // not to be copied ever - lockguard(const lockguard&); - lockguard& operator=(const lockguard&); +// little adapter for more convenient use +struct lockguard { + std::lock_guard _guard; + lockguard(std::mutex& mx) : _guard(mx) {} + lockguard(std::mutex* mx) : _guard(*mx) {} + lockguard(base_with_mutex& mbase) : _guard(mbase.m_obj_mutex) {} + lockguard(base_with_mutex* mbase) : _guard(mbase->m_obj_mutex) {} }; -//#define setLockGuard ldbgvl(DBGSPAM, "Locking @" << __LINE__); lockguard __lockguard(&__mutex); -#define setLockGuard lockguard local_helper_lockguard(&m_obj_mutex); +struct lockuniq { + std::unique_lock _guard; + lockuniq(std::mutex& mx) : _guard(mx) {} + lockuniq(base_with_mutex& mbase) : _guard(mbase.m_obj_mutex) {} + lockuniq(base_with_mutex* mbase) : _guard(mbase->m_obj_mutex) {} + void unLock() { _guard.unlock();} + void reLock() { _guard.lock(); } + void reLockSafe() { if(!_guard.owns_lock()) _guard.lock(); } +}; -// more sophisticated condition class, includes the required mutex -class condition: public lockable +struct ACNG_API base_with_condition : public base_with_mutex { + std::condition_variable m_obj_cond; + void notifyAll() { m_obj_cond.notify_all(); } + void wait(lockuniq& uli) { m_obj_cond.wait(uli._guard); } + bool wait_until(lockuniq& uli, time_t nUTCsecs, long msec); + bool wait_for(lockuniq& uli, long secs, long msec); +}; -protected: - pthread_cond_t m_obj_cond; - -public: - inline condition() : - lockable() - { - pthread_cond_init(&m_obj_cond, nullptr); - } - ~condition() - { - pthread_cond_destroy(&m_obj_cond); - } - inline void wait() - { - pthread_cond_wait(&m_obj_cond, &m_obj_mutex); - } - -#if 0 - /** \brief Waits for the specified period of time or a signal or external notification - * @return true if awaken by another thread or signal, false if run into timeout. - * @param secs Seconds to wait - * @param msecs Extra milliseconds to wait, optional value - */ - bool wait(time_t secs, long msecs=0); -#endif +#define setLockGuard std::lock_guard local_helper_lockguard(m_obj_mutex); - /** \brief Waits until the specified moment is reached or a signal - * or external notification happened - * - * @return true waited to the end, false when awaken prematurely - * @param secs Seconds to wait - * @param msecs Extra milliseconds to wait, optional value - */ - bool wait_until(time_t nUTCsecs, long msec); - inline void notifyAll() - { - pthread_cond_broadcast(&m_obj_cond); - } - void notify() - { - pthread_cond_signal(&m_obj_cond); - } -}; +} #endif diff -Nru apt-cacher-ng-0.9.1/include/maintenance.h apt-cacher-ng-3.3.1/include/maintenance.h --- apt-cacher-ng-0.9.1/include/maintenance.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/maintenance.h 2020-01-08 19:58:26.000000000 +0000 @@ -6,9 +6,11 @@ #include "sockio.h" #include "acbuf.h" +static const std::string sBRLF("
        \n"); + #ifdef DEBUG -#define MTLOGDEBUG(x) { SendFmt << x << "\n
        \n"; } -#define MTLOGASSERT(x, y) {if(!(x)) SendFmt << "
        " << y << "
        \n
        \n";} +#define MTLOGDEBUG(x) { SendFmt << x << sBRLF; } +#define MTLOGASSERT(x, y) {if(!(x)) SendFmt << "
        " << y << "
        \n" << sBRLF;} //#define MTLOGVERIFY(x, y) MTLOGASSERT(x, y) #else #define MTLOGASSERT(x, y) {} @@ -18,10 +20,12 @@ #define MAINT_PFX "maint_" -class tSpecialRequest +namespace acng +{ +class ACNG_API tSpecialRequest { public: - enum eMaintWorkType : int + enum eMaintWorkType : char { workNotSpecial =0, @@ -45,7 +49,7 @@ workSTYLESHEET, workTraceStart, workTraceEnd, - workJStats, +// workJStats, // disabled, probably useless workTRUNCATE, workTRUNCATECONFIRM }; @@ -125,4 +129,11 @@ static tSpecialRequest* MakeMaintWorker(const tRunParms& parms); }; +std::string to_base36(unsigned int val); +static const string relKey("/Release"), inRelKey("/InRelease"); +static cmstring sfxXzBz2GzLzma[] = { ".xz", ".bz2", ".gz", ".lzma"}; +static cmstring sfxXzBz2GzLzmaNone[] = { ".xz", ".bz2", ".gz", ".lzma", ""}; +static cmstring sfxMiscRelated[] = { "", ".xz", ".bz2", ".gz", ".lzma", ".gpg", ".diff/Index"}; +} + #endif /*MAINTENANCE_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/meta.h apt-cacher-ng-3.3.1/include/meta.h --- apt-cacher-ng-0.9.1/include/meta.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/meta.h 2020-01-08 19:58:26.000000000 +0000 @@ -16,10 +16,11 @@ #include #include #include -#include #include #include #include +#include +#include #include #include @@ -29,11 +30,34 @@ #define EXTREME_MEMORY_SAVING false + +#ifdef _MSC_VER +#define __func__ __FUNCTION__ +#endif + + +// little STFU helper +#if __GNUC__ >= 7 +#define __just_fall_through [[fallthrough]] +#else +#define __just_fall_through +#endif + +#define STRINGIFY(a) STR(a) +#define STR(a) #a + +namespace acng +{ + class acbuf; typedef std::string mstring; typedef const std::string cmstring; +typedef std::pair tStrPair; +typedef std::vector tStrVec; +typedef std::set tStrSet; +typedef std::deque tStrDeq; typedef mstring::size_type tStrPos; const static tStrPos stmiss(cmstring::npos); typedef unsigned short USHORT; @@ -46,7 +70,8 @@ #define SZPATHSEPUNIX "/" #define CPATHSEPWIN '\\' #define SZPATHSEPWIN "\\" -extern cmstring sPathSep, sPathSepUnix, sDefPortHTTP, sDefPortHTTPS; +extern std::string sDefPortHTTP, sDefPortHTTPS; +extern cmstring sPathSep, sPathSepUnix, hendl; extern cmstring FAKEDATEMARK; @@ -77,17 +102,23 @@ #error "Unknown how to configure non-blocking mode (O_NONBLOCK) on this system" #endif -#include -#ifndef SO_MAXCONN -#define SO_MAXCONN 250 -#endif - //#define PATHSEP "/" int getUUID(); #define SPACECHARS " \f\n\r\t\v" +#ifdef COMPATGCC47 +class tStrMap : public std::map +{ +public: + void emplace(cmstring& key, cmstring& value) + { + EMPLACE_PAIR_COMPAT(*this, key, value); + } +}; +#else typedef std::map tStrMap; +#endif inline void trimFront(mstring &s, LPCSTR junk=SPACECHARS) { @@ -124,6 +155,9 @@ mstring GetBaseName(cmstring &in); mstring GetDirPart(cmstring &in); +tStrPair SplitDirPath(cmstring& in); + +LPCSTR GetTypeSuffix(cmstring& s); void trimProto(mstring & sUri); tStrPos findHostStart(const mstring & sUri); @@ -135,8 +169,6 @@ #define WITHLEN(x) x, (_countof(x)-1) #define MAKE_PTR_0_LEN(x) x, 0, (_countof(x)-1) -//extern mstring sPathSep, sPathSepUnix, sCR, sCRLF; - // there is memchr and strpbrk but nothing like the last one acting on specified RAW memory range static inline LPCSTR mempbrk (LPCSTR membuf, char const * const needles, size_t len) { @@ -147,12 +179,11 @@ return nullptr; } -typedef std::vector tStrVec; -typedef std::set tStrSet; -typedef std::deque tStrDeq; +#define ELVIS(x, y) (x ? x : y) +#define OPTSET(x, y) if(!x) x = y // Sometimes I miss Perl... -tStrVec::size_type Tokenize(const mstring &in, LPCSTR sep, tStrVec & out, bool bAppend=false, mstring::size_type nStartOffset=0); +tStrVec::size_type Tokenize(cmstring &in, const char* sep, tStrVec & out, bool bAppend=false, mstring::size_type nStartOffset=0); /*inline void Join(mstring &out, const mstring & sep, const tStrVec & tokens) {out.clear(); if(tokens.empty()) return; for(const auto& tok: tokens)out+=(sep + tok);} */ @@ -164,7 +195,7 @@ extern cmstring PROT_PFX_HTTPS, PROT_PFX_HTTP; -class tHttpUrl +class ACNG_API tHttpUrl { private: @@ -180,9 +211,17 @@ { return bSSL ? PROT_PFX_HTTPS : PROT_PFX_HTTP; } - + tHttpUrl(const acng::tHttpUrl& a) + { + sHost = a.sHost; + sPort = a.sPort; + sPath = a.sPath; + sUserPass = a.sUserPass; + bSSL = a.bSSL; + } tHttpUrl & operator=(const tHttpUrl &a) { + if(&a == this) return *this; sHost = a.sHost; sPort = a.sPort; sPath = a.sPath; @@ -223,8 +262,8 @@ #define POKE(x) for(;;) { ssize_t n=write(x, "", 1); if(n>0 || (EAGAIN!=errno && EINTR!=errno)) break; } -#define MIN_VAL(x) (std::numeric_limits::min()) -#define MAX_VAL(x) (std::numeric_limits::max()) +#define MIN_VAL(x) (std::numeric_limits< x >::min()) +#define MAX_VAL(x) (std::numeric_limits< x >::max()) void appendLong(mstring &s, long val); @@ -259,23 +298,15 @@ #endif // let the compiler optimize and keep best variant -inline off_t atoofft(LPCSTR p) -{ - using namespace std; - if(sizeof(long long) == sizeof(off_t)) - return atoll(p); - if(sizeof(int) == sizeof(off_t)) - return atoi(p); - return atol(p); -} +off_t atoofft(LPCSTR p); inline off_t atoofft(LPCSTR p, off_t nDefVal) { return p ? atoofft(p) : nDefVal; } -mstring offttosH(off_t n); - +ACNG_API mstring offttosH(off_t n); +ACNG_API mstring offttosHdotted(off_t n); tStrDeq ExpandFilePattern(cmstring& pattern, bool bSorted=false, bool bQuiet=false); //void MakeAbsolutePath(mstring &dirToFix, const mstring &reldir); @@ -285,21 +316,12 @@ void UrlEscapeAppend(cmstring &s, mstring &sTarget); bool UrlUnescapeAppend(cmstring &from, mstring & to); // Decode with result as return value, no error reporting -inline mstring UrlUnescape(cmstring &from) -{ - mstring ret; // let the compiler optimize - UrlUnescapeAppend(from, ret); - return ret; -} +mstring UrlUnescape(cmstring &from); mstring DosEscape(cmstring &s); // just the bare minimum to make sure the string does not break HTML formating -inline mstring html_sanitize(cmstring& in) -{ - mstring ret; - for(auto c:in) - ret += ( strchr("<>'\"&;", (unsigned) c) ? '_' : c); - return ret; -} +mstring html_sanitize(cmstring& in); + +ACNG_API mstring UserinfoEscape(cmstring &s); #define pathTidy(s) { if(startsWithSz(s, "." SZPATHSEP)) s.erase(0, 2); tStrPos n(0); \ for(n=0;stmiss!=n;) { n=s.find(SZPATHSEP SZPATHSEP, n); if(stmiss!=n) s.erase(n, 1);}; \ @@ -311,62 +333,34 @@ #define StrHas(haystack, needle) (haystack.find(needle) != stmiss) #define StrHasFrom(haystack, needle, startpos) (haystack.find(needle, startpos) != stmiss) +#define StrEraseEnd(s,len) (s).erase((s).size() - len) off_t GetFileSize(cmstring & path, off_t defret); -inline mstring offttos(off_t n) -{ - char buf[21]; - int len=snprintf(buf, 21, OFF_T_FMT, n); - return mstring(buf, len); -} - -inline mstring ltos(long n) -{ - char buf[21]; - int len=snprintf(buf, 21, "%ld", n); - return mstring(buf, len); -} +ACNG_API mstring offttos(off_t n); +ACNG_API mstring ltos(long n); +ACNG_API mstring offttosH(off_t n); -inline mstring offttosH(off_t n) -{ - LPCSTR pref[]={"", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB"}; - for(unsigned i=0;i<_countof(pref)-1; i++) - { - if(n<1024) - return ltos(n)+pref[i]; - if(n<10000) - return ltos(n/1000)+"."+ltos((n%1000)/100)+pref[i+1]; +//template +ACNG_API off_t strsizeToOfft(const char *sizeString); // XXX: if needed... charp sizeString, charp *next) - n/=1024; - } - return "INF"; -} -inline void replaceChars(mstring &s, LPCSTR szBadChars, char goodChar) -{ - for(mstring::iterator p=s.begin();p!=s.end();p++) - for(LPCSTR b=szBadChars;*b;b++) - if(*b==*p) - { - *p=goodChar; - break; - } -} +void replaceChars(mstring &s, LPCSTR szBadChars, char goodChar); extern cmstring sEmptyString; -//! split-and-extract helper for strings, for convenient use with for-loops +//! iterator-like helper for string splitting, for convenient use with for-loops +// Works exactly once! class tSplitWalk { cmstring &s; - mstring::size_type start, len, oob; + mutable mstring::size_type start, len, oob; LPCSTR m_seps; public: inline tSplitWalk(cmstring *line, LPCSTR separators=SPACECHARS, unsigned begin=0) : s(*line), start(begin), len(stmiss), oob(line->size()), m_seps(separators) {} - inline bool Next() + inline bool Next() const { if(len != stmiss) // not initial state, find the next position start = start + len + 1; @@ -393,9 +387,25 @@ return true; } - inline mstring str(){ return s.substr(start, len); } - inline operator mstring() { return str(); } - inline LPCSTR remainder() { return s.c_str() + start; } + inline mstring str() const { return s.substr(start, len); } + inline operator mstring() const { return str(); } + inline LPCSTR remainder() const { return s.c_str() + start; } + + struct iterator + { + tSplitWalk* _walker = nullptr; + // default is end sentinel + bool bEol = true; + iterator() {} + iterator(tSplitWalk& walker) : _walker(&walker) { bEol = !walker.Next(); } + // just good enough for basic iteration and end detection + bool operator==(const iterator& other) const { return (bEol && other.bEol); } + bool operator!=(const iterator& other) const { return !(other == *this); } + iterator operator++() { bEol = !_walker->Next(); return *this; } + std::string operator*() { return _walker->str(); } + }; + iterator begin() {return iterator(*this); } + iterator end() { return iterator(); } }; //bool CreateDetachedThread(void *(*threadfunc)(void *)); @@ -404,48 +414,7 @@ bool IsAbsolute(cmstring &dirToFix); - - -inline char unEscape(const char p) -{ - switch (p) - { - case '0': - return '\0'; - case 'a': - return '\a'; - case 'b': - return '\b'; - case 't': - return '\t'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 'v': - return '\v'; - case 'f': - return '\f'; - default: - return p; - } -} - -inline mstring unEscape(cmstring &s) -{ - mstring ret; - for(cmstring::const_iterator it=s.begin();it!=s.end();++it) - { - if(*it=='\\') - { - ++it; - ret+=unEscape(*it); - } - else - ret+=*it; - } - return ret; -} +mstring unEscape(cmstring &s); std::string BytesToHexString(const uint8_t sum[], unsigned short lengthBin); //bool HexToString(const char *a, mstring& ret); @@ -462,21 +431,13 @@ static const time_t END_OF_TIME(MAX_VAL(time_t)-2); -static inline unsigned FormatTime(char *buf, const time_t cur) -{ - struct tm tmp; - gmtime_r(&cur, &tmp); - asctime_r(&tmp, buf); - //memcpy(buf + 24, " GMT", 4); // wrong, only needed for rfc-822 format, not for asctime's - //return 28; - return 24; -} +unsigned FormatTime(char *buf, size_t bufLen, const time_t cur); struct tCurrentTime { char buf[30]; unsigned len; - inline tCurrentTime() { len=FormatTime(buf, time(nullptr)); } + inline tCurrentTime() { len=FormatTime(buf, sizeof(buf), time(nullptr)); } inline operator mstring() { return mstring(buf, len); } }; @@ -490,14 +451,14 @@ inline extended_bool(bool val, Textra xtra = defval) : value(val), xdata(xtra) {}; }; -void DelTree(cmstring &what); +void ACNG_API DelTree(cmstring &what); -struct tErrnoFmter: public mstring +struct ACNG_API tErrnoFmter: public mstring { tErrnoFmter(LPCSTR prefix = nullptr); }; -mstring EncodeBase64Auth(cmstring &sPwdString); +ACNG_API mstring EncodeBase64Auth(cmstring &sPwdString); mstring EncodeBase64(LPCSTR data, unsigned len); #if defined(HAVE_SSL) || defined(HAVE_TOMCRYPT) @@ -505,14 +466,113 @@ bool DecodeBase64(LPCSTR pAscii, size_t len, acbuf& binData); #endif -#if __GNUC__ == 4 && __GNUC_MINOR__ < 8 && !defined(__clang__) -#define COMPATGCC47 -#define EMPLACE_PAIR(M,K,V) if(M.find(K) == M.end()) M.insert(std::make_pair(K,V)) +typedef std::deque> tLPS; + +#ifdef __GNUC__ +#define AC_LIKELY(x) __builtin_expect(!!(x), true) +#define AC_UNLIKELY(x) __builtin_expect(!!(x), false) #else -#define EMPLACE_PAIR(M,K,V) M.emplace(K,V) +#define AC_LIKELY(x) x +#define AC_UNLIKELY(x) x #endif -typedef std::vector> tLPS; +// shortcut for the non-invasive lookup and copy of stuff from maps +#define ifThereStoreThere(x,y,z) { auto itFind = (x).find(y); if(itFind != (x).end()) z = itFind->second; } +#define ifThereStoreThereAndBreak(x,y,z) { auto itFind = (x).find(y); if(itFind != (x).end()) { z = itFind->second; break; } } + +bool scaseequals(cmstring& a, cmstring& b); + +// dirty little RAII helper +struct tDtorEx { + std::function _action; + inline tDtorEx(decltype(_action) action) : _action(action) {} + inline ~tDtorEx() { _action(); } +}; + +// unique_ptr semantics on a very custom type +template +struct auto_raii +{ + T m_p; + auto_raii(T xp) : m_p(xp) {} + ~auto_raii() { if (m_p != inval_default) TFreeFunc(m_p); } + T release() { auto ret=m_p; m_p = inval_default; return ret;} + T get() const { return m_p; } + auto_raii() = delete; + auto_raii(const auto_raii&) = delete; + auto_raii(auto_raii && other) + { + m_p = other.m_p; + other.m_p = inval_default; + } + operator bool() const { return inval_default != m_p;} +}; + +// from bgtask.cc +cmstring GetFooter(); + +template +std::pair pairSum(const std::pair& a, const std::pair& b) +{ + return std::pair(a.first+b.first, a.second + b.second); +} + +#define RET_SWITCH(label) switch(label) { +#define RET_CASE(label) case label : goto label; +#define RET_SWITCH_END } + +#define setLockGuardX(x) std::lock_guard local_helper_lockguard(x); + +namespace cfg +{ +extern int nettimeout; +} +struct CTimeVal +{ + struct timeval tv = {0,23}; +public: + // calculates for relative time (span) + struct timeval* For(time_t tExpSec, suseconds_t tExpUsec = 23) + { + tv.tv_sec = tExpSec; + tv.tv_usec = tExpUsec; + return &tv; + } + struct timeval* ForNetTimeout() + { + tv.tv_sec = cfg::nettimeout; + tv.tv_usec = 23; + return &tv; + } + // calculates for absolute time + struct timeval* Until(time_t tExpWhen, suseconds_t tExpUsec = 23) + { + tv.tv_sec = GetTime() + tExpWhen; + tv.tv_usec = tExpUsec; + return &tv; + } + // like above but with error checking + struct timeval* SetUntil(time_t tExpWhen, suseconds_t tExpUsec = 23) + { + auto now(GetTime()); + if(now >= tExpWhen) + return nullptr; + tv.tv_sec = now + tExpWhen; + tv.tv_usec = tExpUsec; + return &tv; + } + // calculates for a timespan with max. length until tExpSec + struct timeval* Remaining(time_t tExpSec, suseconds_t tExpUsec = 23) + { + auto exp = tExpSec - GetTime(); + tv.tv_sec = exp < 0 ? 0 : exp; + tv.tv_usec = tExpUsec; + return &tv; + } +}; + +extern std::atomic g_global_shutdown; +} #endif // _META_H diff -Nru apt-cacher-ng-0.9.1/include/mirror.h apt-cacher-ng-3.3.1/include/mirror.h --- apt-cacher-ng-0.9.1/include/mirror.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/mirror.h 2020-01-08 19:58:26.000000000 +0000 @@ -10,12 +10,14 @@ #include "cacheman.h" -class pkgmirror: public tCacheOperation, ifileprocessor +namespace acng +{ +class pkgmirror: public cacheman { public: // XXX: for c++11... using tCacheOperation::tCacheOperation; inline pkgmirror(const tSpecialRequest::tRunParms& parms) - : tCacheOperation(parms) {}; + : cacheman(parms) {}; virtual ~pkgmirror() {}; void Action() override; @@ -23,11 +25,10 @@ protected: // FileHandler bool ProcessRegular(const mstring &sPath, const struct stat &) override; - virtual void HandlePkgEntry(const tRemoteFileInfo &entry) override; + void HandlePkgEntry(const tRemoteFileInfo &entry); void _LoadKeyCache(const mstring & sFileName); - bool m_bCalcSize=false, m_bSkipIxUpdate =false, - m_bDoDownload=false, m_bAsNeeded=false, m_bUseDelta=false; + bool m_bCalcSize=false, m_bDoDownload=false, m_bAsNeeded=false, m_bUseDelta=false; off_t m_totalSize=0, m_totalHave=0; tStrSet m_pathFilter; @@ -36,4 +37,5 @@ bool ConfigDelta(cmstring &sPathRel); }; +} #endif /* MIRROR_H_ */ diff -Nru apt-cacher-ng-0.9.1/include/pkgimport.h apt-cacher-ng-3.3.1/include/pkgimport.h --- apt-cacher-ng-0.9.1/include/pkgimport.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/pkgimport.h 2020-01-08 19:58:26.000000000 +0000 @@ -8,13 +8,15 @@ #include #include "csmapping.h" -class pkgimport : public tCacheOperation, ifileprocessor +namespace acng +{ +class pkgimport : public cacheman { public: // XXX: c++11 using tCacheOperation::tCacheOperation; inline pkgimport(const tSpecialRequest::tRunParms& parms) - : tCacheOperation(parms) {}; + : cacheman(parms) {}; void Action() override; @@ -22,8 +24,8 @@ // FileHandler bool ProcessRegular(const mstring &sPath, const struct stat &) override; //bool ProcessOthers(const mstring &sPath, const struct stat &); - virtual void HandlePkgEntry(const tRemoteFileInfo &entry) override; void _LoadKeyCache(); + void HandlePkgEntry(const tRemoteFileInfo &entry); private: @@ -48,5 +50,5 @@ }; - +} #endif /*PKGIMPORT_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/rfc2553emu.h apt-cacher-ng-3.3.1/include/rfc2553emu.h --- apt-cacher-ng-0.9.1/include/rfc2553emu.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/rfc2553emu.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -// -*- mode: cpp; mode: fold -*- -// Description /*{{{*/ -// $Id: rfc2553emu.h,v 1.4 2000/06/18 06:04:45 jgg Exp $ -/* ###################################################################### - - RFC 2553 Emulation - Provides emulation for RFC 2553 getaddrinfo, - freeaddrinfo and getnameinfo - - These functions are necessary to write portable protocol independent - networking. They transparently support IPv4, IPv6 and probably many - other protocols too. This implementation is needed when the host does - not support these standards. It implements a simple wrapper that - basically supports only IPv4. - - Perfect emulation is not provided, but it is passable.. - - Originally written by Jason Gunthorpe and placed into - the Public Domain, do with it what you will. - - ##################################################################### */ - /*}}}*/ -#ifndef RFC2553EMU_H -#define RFC2553EMU_H - -#include -#include -#include - -// Autosense getaddrinfo -#if defined(AI_PASSIVE) && defined(EAI_NONAME) -#define HAVE_GETADDRINFO -#endif - -// Autosense getnameinfo -#if defined(NI_NUMERICHOST) -#define HAVE_GETNAMEINFO -#endif - -// getaddrinfo support? -#ifndef HAVE_GETADDRINFO - // Renamed to advoid type clashing.. (for debugging) - struct addrinfo_emu - { - int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ - int ai_family; /* PF_xxx */ - int ai_socktype; /* SOCK_xxx */ - int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ - size_t ai_addrlen; /* length of ai_addr */ - char *ai_canonname; /* canonical name for nodename */ - struct sockaddr *ai_addr; /* binary address */ - struct addrinfo_emu *ai_next; /* next structure in linked list */ - }; - #define addrinfo addrinfo_emu - - int getaddrinfo(const char *nodename, const char *servname, - const struct addrinfo *hints, - struct addrinfo **res); - void freeaddrinfo(struct addrinfo *ai); - - #ifndef AI_PASSIVE - #define AI_PASSIVE (1<<1) - #endif - - #ifndef EAI_NONAME - #define EAI_NONAME -1 - #define EAI_AGAIN -2 - #define EAI_FAIL -3 - #define EAI_NODATA -4 - #define EAI_FAMILY -5 - #define EAI_SOCKTYPE -6 - #define EAI_SERVICE -7 - #define EAI_ADDRFAMILY -8 - #define EAI_SYSTEM -10 - #define EAI_MEMORY -11 - #endif - - /* If we don't have getaddrinfo then we probably don't have - sockaddr_storage either (same RFC) so we definately will not be - doing any IPv6 stuff. Do not use the members of this structure to - retain portability, cast to a sockaddr. */ - #define sockaddr_storage sockaddr_in -#endif - -// getnameinfo support (glibc2.0 has getaddrinfo only) -#ifndef HAVE_GETNAMEINFO - - int getnameinfo(const struct sockaddr *sa, socklen_t salen, - char *host, size_t hostlen, - char *serv, size_t servlen, - int flags); - - #ifndef NI_MAXHOST - #define NI_MAXHOST 1025 - #define NI_MAXSERV 32 - #endif - - #ifndef NI_NUMERICHOST - #define NI_NUMERICHOST (1<<0) - #define NI_NUMERICSERV (1<<1) -// #define NI_NOFQDN (1<<2) - #define NI_NAMEREQD (1<<3) - #define NI_DATAGRAM (1<<4) - #endif - - #define sockaddr_storage sockaddr_in -#endif - -// Glibc 2.0.7 misses this one -#ifndef AI_NUMERICHOST -#define AI_NUMERICHOST 0 -#endif - -#endif diff -Nru apt-cacher-ng-0.9.1/include/showinfo.h apt-cacher-ng-3.3.1/include/showinfo.h --- apt-cacher-ng-0.9.1/include/showinfo.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/showinfo.h 2020-01-08 19:58:26.000000000 +0000 @@ -4,6 +4,8 @@ #include "maintenance.h" #include +namespace acng +{ class tMarkupFileSend : public tSpecialRequest { public: @@ -21,8 +23,7 @@ // uses fallback lookup map, can be feed with data in subclass constructor virtual void SendProp(cmstring &key); - // XXX: could make this virtual and customizable, if needed - int CheckCondition(LPCSTR key, size_t len); // 0: true, 1: false, <0: unknown condition + virtual int CheckCondition(LPCSTR key, size_t len); // 0: true, 1: false, <0: unknown condition private: tMarkupFileSend(const tMarkupFileSend&) =delete; @@ -41,9 +42,12 @@ std::set files; tSS sHidParms; mstring sVisualMode; // Truncat or Delet + tStrDeq extraFiles; public: tDeleter(const tRunParms& parms, cmstring& vmode); virtual void SendProp(cmstring &key) override; + //virtual int CheckCondition(LPCSTR key, size_t len) override; // 0: true, 1: false, <0: unknown condition + }; struct tShowInfo : public tMarkupFileSend @@ -57,4 +61,5 @@ tMaintPage(const tRunParms& parms); virtual void SendProp(cmstring &key) override; }; +} #endif /*SHOWINFO_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/sockio.h apt-cacher-ng-3.3.1/include/sockio.h --- apt-cacher-ng-0.9.1/include/sockio.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/sockio.h 2020-01-08 19:58:26.000000000 +0000 @@ -2,7 +2,7 @@ #define SOCKIO_H_ #include "meta.h" - +#include "fileio.h" #include #include #include @@ -15,6 +15,9 @@ #include #include +#include +#include + using namespace std; @@ -33,8 +36,20 @@ #define MSG_MORE 0 #endif -void termsocket(int); -inline void termsocket_quick(int fd) +#ifndef SO_MAXCONN +#define SO_MAXCONN 250 +#endif + +namespace acng +{ + +#ifdef HAVE_SSL +void globalSslInit(); +#endif + +void termsocket_async(int, event_base*); + +inline void termsocket_quick(int& fd) { if(fd<0) return; @@ -55,5 +70,21 @@ return (1 == select(fd + 1, &rfds, nullptr, nullptr, &tv) && FD_ISSET(fd, &rfds)); } +struct select_set_t +{ + int m_max = -1; + fd_set fds; + void add(int n) { if(m_max == -1 ) FD_ZERO(&fds); if(n>m_max) m_max = n; FD_SET(n, &fds); } + bool is_set(int fd) { return FD_ISSET(fd, &fds); } + int nfds() { return m_max + 1; } + operator bool() const { return m_max != -1; } +}; + +std::string formatIpPort(const evutil_addrinfo *info); + +// common flags for a CONNECTING socket +void set_connect_sock_flags(evutil_socket_t fd); + +} #endif /*SOCKIO_H_*/ diff -Nru apt-cacher-ng-0.9.1/include/tcpconnect.h apt-cacher-ng-3.3.1/include/tcpconnect.h --- apt-cacher-ng-0.9.1/include/tcpconnect.h 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/include/tcpconnect.h 2020-01-08 19:58:26.000000000 +0000 @@ -9,7 +9,7 @@ #define TCPCONNECT_H_ #include - +#include #include "meta.h" #include "sockio.h" @@ -20,11 +20,14 @@ #include "acbuf.h" #endif +namespace acng +{ + class tcpconnect; class fileitem; typedef std::shared_ptr tDlStreamHandle; -class tcpconnect +class ACNG_API tcpconnect { public: virtual ~tcpconnect(); @@ -41,7 +44,7 @@ protected: tcpconnect operator=(const tcpconnect&); tcpconnect(const tcpconnect&) =default; - tcpconnect(acfg::tRepoData::IHookHandler *pStateReport); + tcpconnect(cfg::tRepoData::IHookHandler *pStateReport); int m_conFd =-1; mstring m_sHostName, m_sPort; @@ -58,7 +61,7 @@ private: bool _Connect(mstring &sErrOut, int timeout); - acfg::tRepoData::IHookHandler *m_pStateObserver=nullptr; + cfg::tRepoData::IHookHandler *m_pStateObserver=nullptr; protected: #ifdef HAVE_SSL @@ -80,7 +83,7 @@ virtual tDlStreamHandle CreateConnected(cmstring &sHostname, cmstring &sPort, mstring &sErrOut, bool *pbSecondHand, - acfg::tRepoData::IHookHandler *pStateTracker + cfg::tRepoData::IHookHandler *pStateTracker ,bool ssl ,int timeout ,bool mustbevirgin @@ -88,7 +91,7 @@ virtual ~IDlConFactory() {}; }; -class dl_con_factory : public IDlConFactory +class ACNG_API dl_con_factory : public IDlConFactory { public: /// Moves the connection handle to the reserve pool (resets the specified sptr). @@ -97,7 +100,7 @@ virtual tDlStreamHandle CreateConnected(cmstring &sHostname, cmstring &sPort, mstring &sErrOut, bool *pbSecondHand, - acfg::tRepoData::IHookHandler *pStateTracker + cfg::tRepoData::IHookHandler *pStateTracker ,bool ssl ,int timeout ,bool mustbevirgin @@ -130,5 +133,6 @@ unsigned int GetInstCount(unsigned type) { return m_instCount.load();} }; */ +} #endif /* TCPCONNECT_H_ */ diff -Nru apt-cacher-ng-0.9.1/INSTALL apt-cacher-ng-3.3.1/INSTALL --- apt-cacher-ng-0.9.1/INSTALL 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/INSTALL 2020-01-08 19:58:26.000000000 +0000 @@ -1,13 +1,13 @@ Requirements: - Linux or mostly POSIX.1-2001 compliant environment - - CMake 2.6.2 or newer, probably also GNU make + - CMake 3.1 or newer, probably also GNU make - gcc 4.7 or newer or clang 3.0 or newer and latest libstdc++ or Boost headers - on Linux systems, kernel 2.6.22 or newer and glibc 2.8 or newer - pkg-config and zlib (and development components) Extra requirements for optional features: - - libbz2, liblzma (from XZ), OpenSSL and their development components + - libbz2, liblzma (from XZ), OpenSSL (>= 1.0.2) and their development parts - LibTomCrypt can serve as replacement for some parts of functionality if OpenSSL is not available. See LibTomCrypt notes below! - recent FUSE library and its development files for the "virtual mirror" @@ -31,15 +31,25 @@ - the build system makes use of pkg-config to locate required software components. For locally built packages, you might need to adjust its path settings; see manpage for details. - - Link Time Optimization may be broken with some compilers. if a GCC "internal - compiler error" appears, first try -DUSE_LTO=off - - -DCMAKE_INSTALL_PREFIX=... specificies main directory to install (/usr/local is default) - - -DCFGDIR=... (config directory, default is "etc" under CMAKE_INSTALL_PREFIX - or just /etc if CMAKE_INSTALL_PREFIX is /usr) - - -DDOCDIR=... and -DLIBDIR=... specify target directories for docs resp. - supplementary files - - see CMakeLists.txt for more paths that can be customized - - Install halibut tool to rebuild the documentation, if needed + - Link Time Optimization may be broken with some compilers. If a GCC "internal + compiler error" appears, first try -DUSE_LTO=off. Some installations also + have a broken GNU linker, disabling LTO or installing gold (and restarting + build process) might be advisable. + - CMAKE_INSTALL_... type of variables is used for most of the target directory + resolution, see + https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html for details + - -DCMAKE_INSTALL_PREFIX=... specificies main directory to install (/usr/local + is default) + - -DCFGDIR=... for custom config directory, default is apt-cacher-ng under + CMAKE_INSTALL_SYSCONFDIR) + - -DLIBDIR=... for directory with utilities and supplementary files, default + is lib/apt-cacher-ng under $CMAKE_INSTALL_PREFIX + - see CMakeLists.txt for more variables that can be customized + - NOTE: install halibut tool to rebuild the documentation, if needed + - If an update of remote mirror data is required, this can be achieved with + "make -C dbgen". The result ends in dbgen/conf/ and needs to be checked + carefully before installing it because of the evolution of mirrors (the + scripts might not keep up with the remote changes). Configure to run on system startup: @@ -66,7 +76,7 @@ - visit Command-and-Control web interface of apt-cacher-ng, link can be found among other instructions at http://yourHostName:portNumber/ , which might be http://localhost:3142/ with the default configuration - - for apt clients, there is a config snipped in contrib/10-apt-cacher-ng.conf + - for apt clients, there is a config snippet in contrib/10-apt-cacher-ng.conf which might be installed into /etc/apt/apt.conf.d/. Developer notes: diff -Nru apt-cacher-ng-0.9.1/README apt-cacher-ng-3.3.1/README --- apt-cacher-ng-0.9.1/README 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/README 2020-01-08 19:58:26.000000000 +0000 @@ -142,7 +142,7 @@ eventually become not resolvable and the downloads will just fail. Using SSL/TLS transport (i.e. https urls) is also possible with some - restrictions, see section 8.3 for details. + restrictions, see section 8.2 for details. Chapter 4: Advanced Server Configuration ---------------------------------------- @@ -171,8 +171,10 @@ after first appearance on the server. - "Configuration line": one single line in the configuration file. - Some examples in this chapter may contain wrapped lines but - should be stored as a single line in the configuration. + Some examples in this chapter may be displayed as wrapped lines + but should be stored as a single line in the configuration. Some + variables (like `RequestAppendix') support multiline data which + needs to be separated with \n delimiter. 4.2 Configuration file types @@ -404,7 +406,7 @@ .debdelta files. The path hierarchy below this URL should correspond to the source URLs and file paths in the cache. Only one URL can be specified at the moment. It is used for explicit - mirroring operations, see section 8.15 for details. + mirroring operations, see section 8.14 for details. - `proxy=proxyspec' Configures an alternative proxy URL which overrides the global proxy setting in the context of this @@ -471,7 +473,7 @@ A simple control method for incoming connections is listening only to network interfaces which are inside a secure perimeter, e.g. - belong to the local network. See section 8.11 for details on this + belong to the local network. See section 8.10 for details on this configuration parameter. The default setting is listening to all interfaces. @@ -494,7 +496,7 @@ 5.3 Access control with inetd - In some situations, access filtering by client IP/hostname might + In some situations, access filtering by client IP or hostname might be not supported directly or there are other reasons to use inetd to wrap access to apt-cacher inetd. For this case, an inetd daemon is shipped with the package which makes the use of tcpd possible. @@ -529,7 +531,7 @@ (or any init script like `/etc/rc.local'): iptables -A INPUT -p tcp --dport 3142 --source 127.0.0.0/8 -j ACCEPT - iptables -A INPUT -p tcp --dport 3142 --source 192.168.0.0.0/16 -j ACCEPT + iptables -A INPUT -p tcp --dport 3142 --source 192.168.0.0/16 -j ACCEPT iptables -A INPUT -p tcp --dport 3142 -j REJECT --reject-with tcp-reset 5.5 Target port filter @@ -814,16 +816,14 @@ finally unreferenced files will be removed. To speed up this process, the local administrator can remove the - traces of the old distribution release from the archive. Either + index files of the old distribution release from the archive. Either the top-level "Release" files, or even the whole index file trees relevant for certain releases. - To make this task easier, a "brutal" script called distkill.pl is - shipped with apt-cacher-ng. It runs interactively, it scans the - package directory and presents an overview of index file trees - assumed to represent distro releases. Then it provides a command - promt to remove some immediately. The script should be used with - extreme care! See section 8.2 for example of its output. + To make this task easier, there is a special helper mode in the + cleanup task of the maintenance page. Run this manually (and maybe + enable extra verbosity on the main page) and use the wizard on the + bottom of the log page to delete particular index files. Chapter 8: HOWTOs and FAQ ------------------------- @@ -856,14 +856,14 @@ 2. Store copies of your .debs, .orig.tar.gz, ... somewhere in the `_import' subdirectory in the cache, ie. in `/var/cache/apt- - cacher/_import/'. The files may be links or symlinks, does not - matter. When done, apt-cacher will move those files to its own - internal locations. Example: + cacher-ng/_import/'. The files may be links or symlinks, it does + not matter. When done, apt-cacher will move those files to its + own internal locations. Example: cd /var/cache mkdir apt-cacher-ng/_import cp -laf apt-proxy apt-cacher /var/cache/apt-cacher-ng/_import - chown -R apt-cacher-ng apt-cacher-ng/_import + chown -R apt-cacher-ng:apt-cacher-ng apt-cacher-ng/_import 3. Visit the report page and trigger the import action there. Check the results, look for (red) error messages. @@ -898,53 +898,7 @@ on the client to purge APT's internal cache, and then rerun "apt-get update" there. - 8.2 Cache overview - - To get a basic overview of the cache contents, the distkill.pl - script may be used. See section 7.2 for details and warnings. - - # /usr/lib/apt-cacher-ng/distkill.pl - Scanning /var/cache/apt-cacher-ng, please wait... - Found distributions: - 1. testing (6 index files) - 2. sid (63 index files) - 3. etch-unikl (30 index files) - 4. etch (30 index files) - 5. experimental (505 index files) - 6. lenny (57 index files) - 7. unstable (918 index files) - 8. stable (10 index files) - - WARNING: The removal action would wipe out whole directories containing - index files. Select d to see detailed list. - - Which distribution to remove? (Number, 0 to exit, d for details): d - - Directories to remove: - 1. testing: - /var/cache/apt-cacher-ng/debrep/dists/testing - 2. sid: - /var/cache/apt-cacher-ng/localstuff/dists/sid - /var/cache/apt-cacher-ng/debrep/dists/sid - 4. etch: - /var/cache/apt-cacher-ng/ftp.debian-unofficial.org/debian/dists/etch - 5. experimental: - /var/cache/apt-cacher-ng/debrep/dists/experimental - 6. lenny: - /var/cache/apt-cacher-ng/security.debian.org/dists/lenny - /var/cache/apt-cacher-ng/debrep/dists/lenny - 7. unstable: - /var/cache/apt-cacher-ng/debrep/dists/unstable - /var/cache/apt-cacher-ng/localstuff/debian/dists/unstable - 8. stable: - /var/cache/apt-cacher-ng/debrep/dists/stable - Found distributions: - - WARNING: The removal action would wipe out whole directories containing - index files. Select d to see detailed list. - - - 8.3 Access to SSL/TLS remotes (HTTPS) + 8.2 Access to SSL/TLS remotes (HTTPS) It is possible to have encrypted access to remote sites via HTTPS protocol with recent versions of apt-cacher-ng if the OpenSSL @@ -990,7 +944,7 @@ the client has separated configuration options to set this. For Debian based distros, this can be done by adding a configuration like this: `Acquire::https::proxy "DIRECT";' to apt.conf or - one of the apt.conf.d files. See section 8.5 for further + one of the apt.conf.d files. See section 8.4 for further information. - The "backend configuration method": if the clients access the @@ -1026,7 +980,7 @@ # Basically the same just with access to apt-cacher-ng through # URL rewritting instead of setting http proxy. - 8.4 JIGDO usage + 8.3 JIGDO usage It's possible to use apt-cacher-ng source with the jigdo-lite utility. There are some limitations, though: @@ -1058,7 +1012,7 @@ That's all, jigdo-lite will fetch the package files using apt- cacher-ng proxy. - 8.5 Avoid use of apt-cacher-ng for certain hosts + 8.4 Avoid use of apt-cacher-ng for certain hosts Sometimes clients might need to access some remote side directly to do some non-file-transfer oriented work but still passing the @@ -1069,14 +1023,14 @@ Acquire::HTTP::Proxy::archive.example.org "DIRECT"; //or Acquire::HTTP::Proxy::archive.example.org "other.proxy:port" - 8.6 Avoid caching for certain domains or certain file types + 8.5 Avoid caching for certain domains or certain file types Sometimes clients to download through apt-cacher-ng but the data shall not be stored on the harddisk of the server. To get it, use the DontCache directive (see examples for details) to define such files. - 8.7 How to make big download series faster + 8.6 How to make big download series faster Symptom: A common situation is a periodic download of hundreds of files through apt-cacher-ng where just a half is present in the @@ -1098,11 +1052,11 @@ there is a higher chance to get the server connection "preheated" before a stall occurs. - 8.8 How to import DVDs or ISO images + 8.7 How to import DVDs or ISO images First, it should be clear what is needed to be done. In order to integrate the packages from a DVD or ISO image, read on in section - 8.9. + 8.8. The situation with ISO files import is complicated. They are not supported by the cache and there is also no expiration mode for @@ -1112,7 +1066,7 @@ What is possible now is publishing a directory with ISO files using its web server mode, see `LocalDirs' config option for details. - 8.9 How to integrate DVDs or ISO image data + 8.8 How to integrate DVDs or ISO image data Integrating package files from DVD or ISO images is not much different to the usual import operation, see above for instructions. @@ -1137,7 +1091,7 @@ up the symlinks and continue using them as links istead of file copies. - 8.10 How to execute commands before and after going online? + 8.9 How to execute commands before and after going online? It is possible to configure custom commands which are executed before the internet connection attempt and after a certain period @@ -1147,7 +1101,7 @@ section 4.3.2, `conf/*.hooks' and `/usr/share/doc/apt-cacher- ng/examples/*.hooks' files for details. - 8.11 Listen to only specific interfaces or IP protocols + 8.10 Listen to only specific interfaces or IP protocols Unless configured explicitely, the server listens to any interface with IPv4 or IPv6 protocol. To disable some of this, use the @@ -1164,7 +1118,7 @@ interfaces configured for the specific protocol, like 0.0.0.0 for IPv4. - 8.12 How to avoid use of IPv4 (or IPv6) where possible? + 8.11 How to avoid use of IPv4 (or IPv6) where possible? Usually, outgoing hosts are accessed by the protocol and with the target IP reported as the first candidate by operating system @@ -1173,7 +1127,7 @@ and then use IPv4 as alternative (or vice versa). See option ConnectProto in configuration examples. - 8.13 Use the proxy without storing all data twice + 8.12 Use the proxy without storing all data twice There is a general use case where the data storing behavior of APT is not so fortunate. Imagine an old laptop with a slow and small @@ -1210,7 +1164,7 @@ acngfs parameters, and then it gets files directly from the cache if they are completely downloaded and don't have volatile contents. - 8.14 Optional semi-automatic use of proxy + 8.13 Optional semi-automatic use of proxy Apt-Cacher NG daemon has some optional operations modes regading the use of external proxy (configured with "Proxy" setting). The default @@ -1243,7 +1197,7 @@ (see above) and another ACNG proxy in the home LAN to get smart caching for laptop users. - 8.15 Partial Mirroring + 8.14 Partial Mirroring It is possible to create a partial local mirror of a remote package repository. The method to do this is usually known as pre-caching. A @@ -1431,9 +1385,9 @@ apt-get source apt-cacher-ng apt-get build-dep apt-cacher-ng cd apt-cacher-ng-* - make distclean all DEBUG=1 + ./build.sh DEBUG /etc/init.d/apt-cacher-ng stop - ./apt-cacher-ng -c /etc/apt-cacher-ng logdir=/tmp foreground=1 debug=7 + builddir/apt-cacher-ng -c /etc/apt-cacher-ng logdir=/tmp foreground=1 debug=7 # (let apt-get run now, on timeouts just wait >> 20 seconds) # stop the daemon with Ctrl-C /etc/init.d/apt-cacher-ng start @@ -1501,7 +1455,7 @@ - Only HTTP HEAD and GET commands are supported properly. - CONNECT (for https/SSL/TLS tunnels) is supported but needs to be - enabled by local administrators, see section 8.3 for details + enabled by local administrators, see section 8.2 for details - POST support is restricted to apt-listbugs actions and is actually implemented as simple data forwarding with minor header @@ -1531,7 +1485,6 @@ on the Alioth project page. And last, but not least: feel free to express your gratitude by - donating a small amount of money via PayPal (to edi@gmx.de) or just - Flattr it! + donating a small amount of money via PayPal (to edi@gmx.de). [Eduard Bloch, Sun, 19 Apr 2015 10:25:49 +0200] diff -Nru apt-cacher-ng-0.9.1/source/acbuf.cc apt-cacher-ng-3.3.1/source/acbuf.cc --- apt-cacher-ng-0.9.1/source/acbuf.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/acbuf.cc 2020-01-08 19:58:26.000000000 +0000 @@ -7,7 +7,10 @@ #include "acbuf.h" #include "fileio.h" #include +#include "sockio.h" +namespace acng +{ bool acbuf::setsize(unsigned int c) { if(m_nCapacity==c) return true; @@ -95,11 +98,10 @@ { if (EINTR == errno || EAGAIN == errno) { - struct timeval tv{acfg::nettimeout, 0}; fd_set wfds; FD_ZERO(&wfds); FD_SET(nConFd, &wfds); - auto r=::select(nConFd + 1, nullptr, &wfds, nullptr, &tv); + auto r=::select(nConFd + 1, nullptr, &wfds, nullptr, CTimeVal().ForNetTimeout()); if(!r && errno != EINTR) { if(sErrorStatus) @@ -124,12 +126,10 @@ bool tSS::recv(int nConFd, mstring* sErrorStatus) { - struct timeval tv - { acfg::nettimeout, 0 }; fd_set rfds; FD_ZERO(&rfds); FD_SET(nConFd, &rfds); - auto r = ::select(nConFd + 1, &rfds, nullptr, nullptr, &tv); + auto r = ::select(nConFd + 1, &rfds, nullptr, nullptr, CTimeVal().ForNetTimeout()); if (!r) { if(errno == EINTR) @@ -176,3 +176,5 @@ return *this; } */ + +} diff -Nru apt-cacher-ng-0.9.1/source/acfg.cc apt-cacher-ng-3.3.1/source/acfg.cc --- apt-cacher-ng-0.9.1/source/acfg.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/acfg.cc 2020-01-08 19:58:26.000000000 +0000 @@ -5,6 +5,7 @@ #include "meta.h" #include "filereader.h" #include "fileio.h" +#include "sockio.h" #include "lockable.h" #include "cleaner.h" @@ -16,10 +17,12 @@ #include #include #include - +#include using namespace std; +namespace acng +{ // hint to use the main configuration excluding the complex directives //bool g_testMode=false; @@ -28,15 +31,17 @@ #define BARF(x) {if(!g_bQuiet) { cerr << x << endl;} exit(EXIT_FAILURE); } #define BADSTUFF_PATTERN "\\.\\.($|%|/)" -namespace rechecks +namespace rex { bool CompileExpressions(); } -namespace acfg { +namespace cfg { + +bool ACNG_API g_bQuiet=false, g_bNoComplex=false; -bool g_bQuiet=false, g_bNoComplex=false; +extern std::atomic_bool degraded; // internal stuff: string sPopularPath("/debian/"); @@ -44,7 +49,7 @@ int optProxyCheckInt = 99; tStrMap localdirs; -static class : public lockable, public NoCaseStringMap {} mimemap; +static class : public base_with_mutex, public NoCaseStringMap {} mimemap; std::bitset *pUserPorts = nullptr; @@ -59,6 +64,7 @@ { const char *name; int *ptr; const char *warn; uint8_t base; + uint8_t hidden; // just a hint }; struct tProperty @@ -68,8 +74,6 @@ std::function get; // returns a string value. A string starting with # tells to skip the output }; -#ifndef MINIBUILD - // predeclare some void _ParseLocalDirs(cmstring &value); void AddRemapInfo(bool bAsBackend, const string & token, const string &repname); @@ -89,7 +93,7 @@ ,{ "CacheDir", &cachedir} ,{ "LogDir", &logdir} ,{ "SupportDir", &suppdir} - ,{ "SocketPath", &fifopath} + ,{ "SocketPath", &udspath} ,{ "PidFile", &pidfile} ,{ "ReportPage", &reportpage} ,{ "VfilePattern", &vfilepat} @@ -119,46 +123,53 @@ }; MapNameToInt n2iTbl[] = { - { "Debug", &debug, nullptr, 10} - ,{ "OfflineMode", &offlinemode, nullptr, 10} - ,{ "ForeGround", &foreground, nullptr, 10} - ,{ "ForceManaged", &forcemanaged, nullptr, 10} - ,{ "StupidFs", &stupidfs, nullptr, 10} - ,{ "VerboseLog", &verboselog, nullptr, 10} - ,{ "ExTreshold", &extreshhold, nullptr, 10} - ,{ "MaxStandbyConThreads", &tpstandbymax, nullptr, 10} - ,{ "MaxConThreads", &tpthreadmax, nullptr, 10} - ,{ "DnsCacheSeconds", &dnscachetime, nullptr, 10} - ,{ "UnbufferLogs", &debug, nullptr, 10} - ,{ "ExAbortOnProblems", &exfailabort, nullptr, 10} - ,{ "ExposeOrigin", &exporigin, nullptr, 10} - ,{ "LogSubmittedOrigin", &logxff, nullptr, 10} - ,{ "RecompBz2", &recompbz2, nullptr, 10} - ,{ "NetworkTimeout", &nettimeout, nullptr, 10} - ,{ "MinUpdateInterval", &updinterval, nullptr, 10} - ,{ "ForwardBtsSoap", &forwardsoap, nullptr, 10} - ,{ "KeepExtraVersions", &keepnver, nullptr, 10} - ,{ "UseWrap", &usewrap, nullptr, 10} - ,{ "FreshIndexMaxAge", &maxtempdelay, nullptr, 10} - ,{ "RedirMax", &redirmax, nullptr, 10} - ,{ "VfileUseRangeOps", &vrangeops, nullptr, 10} - ,{ "ResponseFreezeDetectTime", &stucksecs, nullptr, 10} - ,{ "ReuseConnections", &persistoutgoing, nullptr, 10} - ,{ "PipelineDepth", &pipelinelen, nullptr, 10} - ,{ "ExSuppressAdminNotification", &exsupcount, nullptr, 10} - ,{ "OptProxyTimeout", &optproxytimeout, nullptr, 10} - ,{ "MaxDlSpeed", &maxdlspeed, nullptr, 10} - ,{ "MaxInresponsiveDlSize", &maxredlsize, nullptr, 10} - - ,{ "DirPerms", &dirperms, nullptr, 8} - ,{ "FilePerms", &fileperms, nullptr, 8} - - ,{ "Verbose", nullptr, "Option is deprecated, ignoring the value." , 10} - ,{ "MaxSpareThreadSets",&tpstandbymax, "Deprecated option name, mapped to MaxStandbyConThreads", 10} - ,{ "OldIndexUpdater", &oldupdate, "Option is deprecated, ignoring the value." , 10} - ,{ "Patrace", &patrace, "Don't use in config files!" , 10} - ,{ "NoSSLchecks", &nsafriendly, "Disable SSL security checks" , 10} - ,{ "OptProxyCheckInterval", &optProxyCheckInt, nullptr, 10} + { "Debug", &debug, nullptr, 10, false} + ,{ "OfflineMode", &offlinemode, nullptr, 10, false} + ,{ "ForeGround", &foreground, nullptr, 10, false} + ,{ "ForceManaged", &forcemanaged, nullptr, 10, false} + ,{ "StupidFs", &stupidfs, nullptr, 10, false} + ,{ "VerboseLog", &verboselog, nullptr, 10, false} + ,{ "ExThreshold", &extreshhold, nullptr, 10, false} + ,{ "ExTreshold", &extreshhold, nullptr, 10, true} // wrong spelling :-( + ,{ "MaxStandbyConThreads", &tpstandbymax, nullptr, 10, false} + ,{ "MaxConThreads", &tpthreadmax, nullptr, 10, false} + ,{ "DlMaxRetries", &dlretriesmax, nullptr, 10, false} + ,{ "DnsCacheSeconds", &dnscachetime, nullptr, 10, false} + ,{ "UnbufferLogs", &debug, nullptr, 10, false} + ,{ "ExAbortOnProblems", &exfailabort, nullptr, 10, false} + ,{ "ExposeOrigin", &exporigin, nullptr, 10, false} + ,{ "LogSubmittedOrigin", &logxff, nullptr, 10, false} + ,{ "RecompBz2", &recompbz2, nullptr, 10, false} + ,{ "NetworkTimeout", &nettimeout, nullptr, 10, false} + ,{ "FastTimeout", &fasttimeout, nullptr, 10, false} + ,{ "DisconnectTimeout", &discotimeout, nullptr, 10, false} + ,{ "MinUpdateInterval", &updinterval, nullptr, 10, false} + ,{ "ForwardBtsSoap", &forwardsoap, nullptr, 10, false} + ,{ "KeepExtraVersions", &keepnver, nullptr, 10, false} + ,{ "UseWrap", &usewrap, nullptr, 10, false} + ,{ "FreshIndexMaxAge", &maxtempdelay, nullptr, 10, false} + ,{ "RedirMax", &redirmax, nullptr, 10, false} + ,{ "VfileUseRangeOps", &vrangeops, nullptr, 10, false} + ,{ "ResponseFreezeDetectTime", &stucksecs, nullptr, 10, false} + ,{ "ReuseConnections", &persistoutgoing, nullptr, 10, false} + ,{ "PipelineDepth", &pipelinelen, nullptr, 10, false} + ,{ "ExSuppressAdminNotification", &exsupcount, nullptr, 10, false} + ,{ "OptProxyTimeout", &optproxytimeout, nullptr, 10, false} + ,{ "MaxDlSpeed", &maxdlspeed, nullptr, 10, false} + ,{ "MaxInresponsiveDlSize", &maxredlsize, nullptr, 10, false} + ,{ "OptProxyCheckInterval", &optProxyCheckInt, nullptr, 10, false} + ,{ "TrackFileUse", &trackfileuse, nullptr, 10, false} + ,{ "ReserveSpace", &allocspace, nullptr , 10, false} + + // octal base interpretation of UNIX file permissions + ,{ "DirPerms", &dirperms, nullptr, 8, false} + ,{ "FilePerms", &fileperms, nullptr, 8, false} + + ,{ "Verbose", nullptr, "Option is deprecated, ignoring the value." , 10, true} + ,{ "MaxSpareThreadSets",&tpstandbymax, "Deprecated option name, mapped to MaxStandbyConThreads", 10, true} + ,{ "OldIndexUpdater", &oldupdate, "Option is deprecated, ignoring the value." , 10, true} + ,{ "Patrace", &patrace, "Don't use in config files!" , 10, false} + ,{ "NoSSLchecks", &nsafriendly, "Disable SSL security checks" , 10, false} }; @@ -301,6 +312,15 @@ { return "#"; // TOP SECRET"; } } +, +{ "ExStartTradeOff", [](cmstring& key, cmstring& value) -> bool +{ + exstarttradeoff = strsizeToOfft(value.c_str()); + return true; +}, [](bool) -> string +{ + return ltos(exstarttradeoff); +} } #if SUPPWHASH bIsHashedPwd=false; @@ -335,21 +355,23 @@ return nullptr; } -tProperty* GetPropPtr(LPCSTR key) +tProperty* GetPropPtr(cmstring& key) { - auto sep = strrchr(key, '-'); + auto sep = key.find('-'); + auto szkey = key.c_str(); for (auto &ent : n2pTbl) { - if (0 == strcasecmp(key, ent.name)) + if (0 == strcasecmp(szkey, ent.name)) return &ent; - // identified as prefix? - if(sep && 0 == ent.name[sep-key+1] && 0==strncasecmp(key, ent.name, sep-key+1)) + // identified as prefix, with matching length? + if(sep != stmiss && 0==strncasecmp(szkey, ent.name, sep) && 0 == ent.name[sep+1]) return &ent; } return nullptr; } -int * GetIntPtr(LPCSTR key) { +int * GetIntPtr(LPCSTR key) +{ for(auto &ent : n2iTbl) if(0==strcasecmp(key, ent.name)) return ent.ptr; @@ -383,12 +405,17 @@ inline bool qgrep(cmstring &needle, cmstring &file) { - for(acfg::tCfgIter itor(file); itor.Next();) + for(cfg::tCfgIter itor(file); itor.Next();) if(StrHas(itor.sLine, needle)) return true; return false; } +bool DegradedMode() +{ + return degraded.load(); +} + inline void _FixPostPreSlashes(string &val) { // fix broken entries @@ -457,6 +484,9 @@ if(key.empty()) return false; // weird + if(endsWithSzAr(val, "\\")) + cerr << "Warning: multilines are not supported, consider using \\n." <second; } // try some educated guess... assume binary if we are sure, text if we are almost sure @@ -792,7 +822,7 @@ return false; } } - else if ( nullptr != (ppTarget = GetPropPtr(key.c_str()))) + else if ( nullptr != (ppTarget = GetPropPtr(key))) { return ppTarget->set(key, value); } @@ -864,7 +894,7 @@ while(itor.Next()) { - if(debug & LOG_DEBUG) + if(debug & log::LOG_DEBUG) cerr << "Backend URL: " << itor.sLine < vecReqPatters, vecTgtPatterns; -bool CompileExpressions() +bool ACNG_API CompileExpressions() { auto compat = [](regex_t* &re, LPCSTR ps) { @@ -1396,7 +1431,7 @@ std::cerr << buf << ": " << ps << std::endl; return false; }; - using namespace acfg; + using namespace cfg; return (compat(rex[FILE_SOLID].pat, pfilepat.c_str()) && compat(rex[FILE_VOLATILE].pat, vfilepat.c_str()) && compat(rex[FILE_WHITELIST].pat, wfilepat.c_str()) @@ -1431,7 +1466,7 @@ || (type == FILE_VOLATILE && MatchType(in, FILE_SPECIAL_VOLATILE)); } -eMatchType GetFiletype(const string & in) +ACNG_API eMatchType GetFiletype(const string & in) { if (MatchType(in, FILE_SPECIAL_VOLATILE)) return FILE_VOLATILE; @@ -1458,10 +1493,10 @@ } else if(!bRecursiveCall) // don't go further than one level { - tStrDeq srcs = acfg::ExpandFileTokens(token); + tStrDeq srcs = cfg::ExpandFileTokens(token); for(const auto& src: srcs) { - acfg::tCfgIter itor(src); + cfg::tCfgIter itor(src); if(!itor) { cerr << "Error opening pattern file: " << src <0) - mkdir(path.substr(0,pos).c_str(), acfg::dirperms); - } -} #ifndef MINIBUILD LPCSTR ReTest(LPCSTR s) { - static LPCSTR names[rechecks::ematchtype_max] = + static LPCSTR names[rex::ematchtype_max] = { "FILE_SOLID", "FILE_VOLATILE", "FILE_WHITELIST", "NASTY_PATH", "PASSTHROUGH", "FILE_SPECIAL_SOLID" }; - auto t = rechecks::GetFiletype(s); - if(t<0 || t>=rechecks::ematchtype_max) + auto t = rex::GetFiletype(s); + if(t<0 || t>=rex::ematchtype_max) return "NOMATCH"; return names[t]; } #endif + +} diff -Nru apt-cacher-ng-0.9.1/source/acfg_defaults.cc apt-cacher-ng-3.3.1/source/acfg_defaults.cc --- apt-cacher-ng-0.9.1/source/acfg_defaults.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/acfg_defaults.cc 2020-01-08 19:58:26.000000000 +0000 @@ -5,18 +5,23 @@ #include "config.h" #include "meta.h" #include "acfg.h" +#include "sockio.h" + +#include using namespace std; -namespace acfg +namespace acng +{ +namespace cfg { -string cachedir("/var/tmp"), logdir("/var/tmp"), fifopath, pidfile, reportpage, +string ACNG_API cachedir(CACHEDIR), logdir(LOGDIR), udspath(UDSPATH), pidfile, reportpage, confdir, adminauth, adminauthB64, bindaddr, mirrorsrcs, suppdir(LIBDIR), capath("/etc/ssl/certs"), cafile, badredmime("text/html"); #define INFOLDER "(^|.*/)" -#define COMPRLIST "(\\.gz|\\.bz2|\\.lzma|\\.xz)" +#define COMPRLIST "(\\.gz|\\.bz2|\\.lzma|\\.xz|\\.zst)" #define ALXPATTERN ".*\\.(db|files|abs)(\\.tar" COMPRLIST ")?" #define COMPOPT COMPRLIST"?" //#define COMPONENT_OPTIONAL "(-[a-z0-9-])" @@ -31,12 +36,18 @@ "|fonts/(final/)?[a-z]+32.exe(\\?download.*)?" // msttcorefonts, fonts/final/comic32.exe /corefonts/comic32.exe plus SF's parameters "|/dists/.*/installer-[^/]+/[0-9][^/]+/images/.*" // d-i stuff with revision "|/[[:alpha:]]{1,2}/[a-f0-9]{64}(-[a-f0-9]{64})?(\\.gz)?" // FreeBSD, after https://alioth.debian.org/tracker/?func=detail&atid=413111&aid=315254&group_id=100566 + "|/by-hash/(SHA|MD)[0-9]+/.*" // support Debian/Ubuntu by-hash index files + "|\\.asc$" // all remaining PGP signatures. Assuming that volatile ones are matched below. + "|changelogs/pool/.*/changelog.txt$" // packages.ultimediaos.com + "|/objects/.*/.*\\.(dirtree|filez|commit|commitmeta)|/repo/deltas/.*" // FlatPak + // for Fedora 29 and 30 , https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=928270 + "|[a-f0-9]+-modules.yaml.gz|[a-f0-9]+-(primary|filelists|comps-[^.]*.[^.]*|updateinfo|prestodelta).xml(|.gz|.xz|.zck)" ")$"); string svfilepat("/development/rawhide/.*" // more stuff for ubuntu dist-upgrader "|dists/.*dist-upgrader.*/current/.*" // /dists/xenial/main/dist-upgrader-all/current/xenial.tar.gz - "|changelogs.ubuntu.com/.*" // changelogs.ubuntu.com/meta-release-lts-development + "|changelogs.ubuntu.com/meta.*" // changelogs.ubuntu.com/meta-release-lts-development // XXX: signature might change afterwards... any better solution than this location? "|" INFOLDER ".*(\\.(d|u)?deb|\\.rpm|\\.drpm|\\.dsc|\\.tar" COMPRLIST ")\\.gpg$" ); @@ -52,7 +63,7 @@ "|filelists\\.xml\\.gz|filelists\\.sqlite\\.bz2|repomd\\.xml" // SL, http://ra.khe.sh/computers/linux/apt-cacher-ng-with-yum.html "|packages\\.[a-zA-Z][a-zA-Z]\\.gz|info\\.txt|license\\.tar\\.gz|license\\.zip" //opensuse "|" ALXPATTERN // Arch Linux - "|metalink\\?repo|.*prestodelta\\.xml\\.gz|repodata/.*\\.(xml|sqlite)" COMPOPT // CentOS + "|metalink\\?repo|.*prestodelta\\.xml\\.gz|repodata/.*\\.(yaml|yml|xml|sqlite)" COMPOPT // CentOS "|\\.treeinfo|vmlinuz|(initrd|product|squashfs|updates)\\.img" // Fedora "|\\.o" // https://bugs.launchpad.net/ubuntu/+source/apt-cacher-ng/+bug/1078224 "|Components-.*yml" COMPOPT // DEP-11 aka AppStream" @@ -67,6 +78,8 @@ "|connectivity-check.html|ubiquity/.*update|getubuntu/releasenotes" // Ubuntu installer network check, etc. "|wiki.ubuntu.com/.*/ReleaseNotes" // this is actually for an internal check and therefore contains the hostname "|ubuntu/dists/.*\\.html" // http://archive.ubuntu.com/ubuntu/dists/vivid-updates/main/dist-upgrader-all/current/ReleaseAnnouncement.html + "|metadata.(ftp-master.debian|tanglu).org/changelogs/.*" // some of them are not static + "|/refs/heads/app.*|/repo/(summary|config)(\\.sig)?|/Service/News$" // FlatPak ); //string wfilepat( VPATPREFIX "(Release|Release\\.gpg|release|meta-release|Translation[^/]*\\.bz2)$"); @@ -74,7 +87,6 @@ string wfilepat(INFOLDER "(Release|InRelease|.*\\.gpg" "|(Packages|Sources)" COMPRLIST "?" // hm... private repos without Release file :-( - "|Translation[^/]*" COMPRLIST "?" // to be checked, but they should never really go anywhere "|.*\\.xml" // SUSE "|setup\\.bz2(.sig)?" // Cygwin "|" ALXPATTERN // Arch Linux @@ -86,13 +98,14 @@ string pfilepatEx, spfilepatEx, vfilepatEx, svfilepatEx, wfilepatEx; // for customization by user int offlinemode(false), verboselog(true), stupidfs(false), forcemanaged(false), extreshhold(20), tpstandbymax(8), tpthreadmax(-1), dirperms(00755), fileperms(00664), -keepnver(0), maxtempdelay(27), vrangeops(1); +keepnver(0), maxtempdelay(27), vrangeops(1), dlretriesmax(2); int dlbufsize(70000), exfailabort(1), exporigin(false), numcores(1), -logxff(false), oldupdate(false), recompbz2(false), nettimeout(60), updinterval(0), +logxff(false), oldupdate(false), recompbz2(false), nettimeout(40), updinterval(0), forwardsoap(RESERVED_DEFVAL), usewrap(RESERVED_DEFVAL), redirmax(RESERVED_DEFVAL), stucksecs(500), persistoutgoing(1), pipelinelen(10), exsupcount(RESERVED_DEFVAL), -optproxytimeout(-1), patrace(false), maxredlsize(1<<16), nsafriendly(false); +optproxytimeout(-1), patrace(false), maxredlsize(1<<16), nsafriendly(false), +trackfileuse(false), exstarttradeoff(500000000), fasttimeout(4), discotimeout(15); int maxdlspeed(RESERVED_DEFVAL); @@ -105,25 +118,30 @@ int dnscachetime(1800); #endif -string agentname("Debian Apt-Cacher-NG/" ACVERSION); -string remoteport("80"), port(ACNG_DEF_PORT); -string agentheader; +string ACNG_API agentname("Debian Apt-Cacher-NG/" ACVERSION); +string ACNG_API remoteport("80"), port(ACNG_DEF_PORT); +string ACNG_API agentheader; -string requestapx; +string ACNG_API requestapx; string sigbuscmd; mstring connectPermPattern("~~~"); #ifdef DEBUG int debug(3), foreground(true); -//string cachedir("/var/cache/acng"), logdir("/var/log/acng"), fifopath, pidfile; +//string cachedir("/var/cache/acng"), logdir("/var/log/acng"), udspath, pidfile; #else int debug(0), foreground(false); #endif -string cacheDirSlash; // guaranteed to have a trailing path separator +string ACNG_API cacheDirSlash; // guaranteed to have a trailing path separator +// If second == unspec -> first applies as filter, if first unspec -> not filtered int conprotos[2] = { PF_UNSPEC, PF_UNSPEC }; std::atomic_bool degraded(false); +int allocspace = 1024*1024; + +} + } diff -Nru apt-cacher-ng-0.9.1/source/aclogger.cc apt-cacher-ng-3.3.1/source/aclogger.cc --- apt-cacher-ng-0.9.1/source/aclogger.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/aclogger.cc 2020-01-08 19:58:26.000000000 +0000 @@ -1,42 +1,142 @@ #include "meta.h" +#include #include #include +#include +#include #include "debug.h" - #include "aclogger.h" #include "acfg.h" #include "lockable.h" #include "filereader.h" - #include "fileio.h" -#include #include #include -#include #include #include +#include using namespace std; -namespace aclog +namespace acng +{ +namespace log { ofstream fErr, fStat; -static pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; +static acmutex mx; + +#ifndef DEBUG +bool logIsEnabled = false; +#else +bool logIsEnabled = true; +#endif + +std::atomic totalIn(0), totalOut(0); + +std::pair GetCurrentCountersInOut() + { + return std::make_pair(totalIn.load(), totalOut.load()); + } + +std::pair oldCounters(0,0); + +void ResetOldCounters() +{ + char lbuf[600]; + // safe some cycles an snprintf + auto xl = (CACHE_BASE.size() + cfg::privStoreRelQstatsSfx.size()); + if (xl > 550) + return; // heh? + memcpy(lbuf, CACHE_BASE.data(), CACHE_BASE.size()); + memcpy(lbuf + CACHE_BASE.size(), cfg::privStoreRelQstatsSfx.data(), + cfg::privStoreRelQstatsSfx.size()); + + for (char foldNam : + { 'i', 'o' }) + { + lbuf[xl] = 0; + auto xoff = sprintf(lbuf + xl, "/%c/", foldNam); + auto lptr = lbuf + xl + xoff; + auto dirp = opendir(lbuf); + if (!dirp) + continue; + while (true) + { + auto ent = readdir(dirp); + if (!ent) + break; + auto llen = strlen(ent->d_name); + if (llen > 25 || llen < 4) + continue; + memcpy(lptr, ent->d_name, llen + 1); + unlink(lbuf); + } + closedir(dirp); + } + oldCounters = decltype(oldCounters)(); +} + +decltype(oldCounters) GetOldCountersInOut(bool calcIncomming, bool calcOutgoing) +{ +#ifndef MINIBUILD + // needs to do first reading of old stats? + char lbuf[600]; + // safe some cycles an snprintf + auto xl=(CACHE_BASE.size() + cfg::privStoreRelQstatsSfx.size()); + if(xl > 550) + return oldCounters; // heh? + memcpy(lbuf, CACHE_BASE.data(), CACHE_BASE.size()); + memcpy(lbuf+CACHE_BASE.size(), cfg::privStoreRelQstatsSfx.data(), cfg::privStoreRelQstatsSfx.size()); + if (!oldCounters.first && !oldCounters.second) + { + auto rfunc = [&lbuf, xl](off_t& pRet, char foldNam) + { + lbuf[xl]=0; + auto xoff=sprintf(lbuf+xl, "/%c/", foldNam); + auto lptr = lbuf+xl+xoff; + auto dirp = opendir(lbuf); + if(!dirp) + return; + char buf[30]; + while(true) + { + auto ent = readdir(dirp); + if(!ent) break; + auto llen=strlen(ent->d_name); + if(llen > 25 || llen<4) continue; + memcpy(lptr, ent->d_name, llen+1); + auto tpos=readlink(lbuf, buf, _countof(buf)-1); + if(tpos < 1) continue; + buf[tpos]=0; + pRet += acng::strsizeToOfft(buf); + } + closedir(dirp); + }; + if(calcIncomming) + rfunc(oldCounters.first, 'i'); + if(calcOutgoing) + rfunc(oldCounters.second, 'o'); + } +#endif + return oldCounters; +} bool open() { // only called in the beginning or when reopening, already locked... // lockguard g(&mx); - if(acfg::logdir.empty()) + if(cfg::logdir.empty()) return true; - string apath(acfg::logdir+"/apt-cacher.log"), epath(acfg::logdir+"/apt-cacher.err"); + logIsEnabled = true; + + string apath(cfg::logdir+"/apt-cacher.log"), epath(cfg::logdir+"/apt-cacher.err"); mkbasedir(apath); @@ -51,41 +151,68 @@ return fStat.is_open() && fErr.is_open(); } - -void transfer(char cLogType, uint64_t nCount, const char *szClient, const char *szPath) +void transfer(uint64_t bytesIn, + uint64_t bytesOut, + cmstring& sClient, + cmstring& sPath, + bool bAsError) { + totalIn.fetch_add(bytesIn); + totalOut.fetch_add(bytesOut); + + if(!logIsEnabled) + return; + lockguard g(&mx); + if(!fStat.is_open()) return; - fStat << time(0) << '|' << cLogType << '|' << nCount; - if(acfg::verboselog) - fStat << '|' << szClient << '|' << szPath; - fStat << '\n'; - if(acfg::debug&LOG_FLUSH) fStat.flush(); + auto tNow=GetTime(); + if (bytesIn) + { + fStat << tNow << "|I|" << bytesIn; + if (cfg::verboselog) + fStat << '|' << sClient << '|' << sPath; + fStat << '\n'; // not endl, it might flush + } + if (bytesOut) + { + fStat << tNow << (bAsError ? "|E|" : "|O|") << bytesOut; + if (cfg::verboselog) + fStat << '|' << sClient << '|' << sPath; + fStat << '\n'; // not endl, it might flush + } + + if(cfg::debug & LOG_FLUSH) fStat.flush(); } void misc(const string & sLine, const char cLogType) { + if(!logIsEnabled) + return; + lockguard g(&mx); if(!fStat.is_open()) return; fStat << time(0) << '|' << cLogType << '|' << sLine << '\n'; - if(acfg::debug&LOG_FLUSH) + if(cfg::debug & LOG_FLUSH) fStat.flush(); } -void err(const char *msg, const char *client) +void ACNG_API err(const char *msg, const char *client) { + if(!logIsEnabled) + return; + lockguard g(&mx); if(!fErr.is_open()) { -/*#ifdef DEBUG +#ifdef DEBUG // basic debugging of acngtool cerr << msg <=LOG_MORE) cerr << (bReopen ? "Reopening logs...\n" : "Closing logs...\n"); + // let's try to store a snapshot of the current stats + auto snapIn = offttos(totalIn.exchange(0)); + auto snapOut = offttos(totalOut.exchange(0)); + timeval tp; + gettimeofday(&tp, 0); + auto inLinkPath = CACHE_BASE + cfg::privStoreRelQstatsSfx + "/i/" + + acng::offttos(tp.tv_sec) + "." + acng::ltos(tp.tv_usec); + auto outLinkPath = CACHE_BASE + cfg::privStoreRelQstatsSfx + "/o/" + + acng::offttos(tp.tv_sec) + "." + acng::ltos(tp.tv_usec); + ignore_value(symlink(snapIn.c_str(), inLinkPath.c_str())); + ignore_value(symlink(snapOut.c_str(), outLinkPath.c_str())); + + + if(!logIsEnabled) + return; + + lockguard g(mx); + if(cfg::debug >= LOG_MORE) cerr << (bReopen ? "Reopening logs...\n" : "Closing logs...\n"); fErr.close(); fStat.close(); if(bReopen) - aclog::open(); + log::open(); } @@ -131,7 +277,7 @@ #ifndef MINIBUILD inline deque GetStats() { - string sDataFile=acfg::cachedir+SZPATHSEP"_stats_dat"; + string sDataFile=cfg::cachedir+SZPATHSEP"_stats_dat"; deque out; time_t now = time(nullptr); @@ -144,14 +290,14 @@ out.emplace_back(d); } - for (auto& log : ExpandFilePattern(acfg::logdir + SZPATHSEP "apt-cacher*.log", false)) + for (auto& log : ExpandFilePattern(cfg::logdir + SZPATHSEP "apt-cacher*.log", false)) { - if (acfg::debug >= LOG_MORE) + if (cfg::debug >= LOG_MORE) cerr << "Reading log file: " << log << endl; filereader reader; if (!reader.OpenFile(log)) { - aclog::err("Error opening a log file"); + log::err("Error opening a log file"); continue; } string sLine; @@ -200,7 +346,7 @@ { string ret; vector buf(1024); - for (auto& entry : aclog::GetStats()) + for (auto& entry : log::GetStats()) { auto reqMax = std::max(entry.reqIn, entry.reqOut); auto dataMax = std::max(entry.byteIn, entry.byteOut); @@ -290,8 +436,8 @@ #ifdef DEBUG -static class : public lockable, public std::map -{} stackDepths; +static struct : public base_with_mutex, public std::map +{} indentPerThread; t_logger::t_logger(const char *szFuncName, const void * ptr) { @@ -299,8 +445,8 @@ m_szName = szFuncName; callobj = uintptr_t(ptr); { - lockguard __lockguard(stackDepths); - m_nLevel = stackDepths[m_id]++; + lockguard __lockguard(indentPerThread); + m_nLevel = indentPerThread[m_id]++; } // writing to the level of parent since it's being "created there" GetFmter() << ">> " << szFuncName << " [T:"< #include +#include #include -#ifdef HAVE_SSL -#include -#endif - #include #include #include @@ -26,21 +23,19 @@ #include #include #include - +#include #include #include #include #include +#include #include "debug.h" #include "dlcon.h" #include "fileio.h" #include "fileitem.h" - -using namespace std; - +#include "sockio.h" #ifdef HAVE_SSL -/* OpenSSL headers */ #include "openssl/bio.h" #include "openssl/ssl.h" #include "openssl/err.h" @@ -48,26 +43,29 @@ #include #include #endif - #include "filereader.h" #include "csmapping.h" #include "cleaner.h" +using namespace std; +using namespace acng; + bool g_bVerbose = false; -// dummies to satisfy references to cleaner callbacks -cleaner::cleaner() : m_thr(pthread_t()) {} -cleaner::~cleaner() {} -void cleaner::ScheduleFor(time_t, cleaner::eType) {} -cleaner g_victor; +// from sockio.cc in more recent versions +bool isUdsAccessible(cmstring& path) +{ + Cstat s(path); + return s && S_ISSOCK(s.st_mode) && 0 == access(path.c_str(), W_OK); +} -struct IFitemFactory +struct ACNG_API IFitemFactory { virtual SHARED_PTR Create() =0; virtual ~IFitemFactory() =default; }; -struct CPrintItemFactory : public IFitemFactory +struct ACNG_API CPrintItemFactory : public IFitemFactory { virtual SHARED_PTR Create() { @@ -90,6 +88,9 @@ bool, bool&) override { m_head = h; + auto opt_dbg=getenv("ACNGTOOL_DEBUG_DOWNLOAD"); + if(opt_dbg && *opt_dbg) + std::cerr << (std::string) h.ToString() << std::endl; return true; } virtual bool StoreFileData(const char *data, unsigned int size) override @@ -108,6 +109,54 @@ } }; +// That is relevant to push the download agent logics correctly and are shown in logs; +// not relevant for the actual connection since it's rerouted through TUdsFactory +#define FAKE_UDS_HOSTNAME "UNIX-DOMAIN-SOCKET" + +SHARED_PTR CreateStdoutItem() +{ + class tPrintItem: public fileitem + { + public: + tPrintItem() + { + m_bAllowStoreData = false; + m_nSizeChecked = m_nSizeSeen = 0; + } + virtual FiStatus Setup(bool) override + { + m_nSizeChecked = m_nSizeSeen = 0; + return m_status = FIST_INITED; + } + virtual int GetFileFd() override + { + return 1; + } + ; // something, don't care for now + virtual bool DownloadStartedStoreHeader(const header &h, size_t, const char*, bool, bool&) + override + { + m_head = h; + auto opt_dbg = getenv("ACNGTOOL_DEBUG_DOWNLOAD"); + if (opt_dbg && *opt_dbg) + std::cerr << (std::string) h.ToString() << std::endl; + return true; + } + virtual bool StoreFileData(const char *data, unsigned int size) override + { + if (!size) + m_status = FIST_COMPLETE; + + return (size == fwrite(data, sizeof(char), size, stdout)); + } + ssize_t SendData(int, int, off_t&, size_t) override + { + return 0; + } + }; + return make_shared(); +} + struct verbprint { int cnt = 0; @@ -136,107 +185,133 @@ } } vprint; -struct CReportItemFactory : public IFitemFactory +/** + * Create a special processor which looks for error markers in the download stream and + * reports the result only then. + */ +SHARED_PTR CreateReportItem() { - virtual SHARED_PTR Create() + class tRepItem: public fileitem { - class tRepItem : public fileitem + acbuf lineBuf; + string m_key = maark; + tStrVec m_errMsg; + + public: + tRepItem() + { + m_bAllowStoreData = false; + m_nSizeChecked = m_nSizeSeen = 0; + lineBuf.setsize(1 << 16); + memset(lineBuf.wptr(), 0, 1 << 16); + } + ; + virtual FiStatus Setup(bool) override { - acbuf lineBuf; - string m_key = maark; - tStrVec m_errMsg; - - public: - - tRepItem() - { - m_bAllowStoreData=false; - m_nSizeChecked = m_nSizeSeen = 0; - lineBuf.setsize(1<<16); - memset(lineBuf.wptr(), 0, 1<<16); - }; - virtual FiStatus Setup(bool) override - { - m_nSizeChecked = m_nSizeSeen = 0; - return m_status = FIST_INITED; - } - virtual int GetFileFd() override - { return 1;}; // something, don't care for now - virtual bool DownloadStartedStoreHeader(const header &h, size_t, const char *, - bool, bool&) override + m_nSizeChecked = m_nSizeSeen = 0; + return m_status = FIST_INITED; + } + virtual int GetFileFd() override + { + return 1; + } + ; // something, don't care for now + virtual bool DownloadStartedStoreHeader(const header &h, size_t, const char*, bool, bool&) + override + { + m_head = h; + return true; + } + virtual bool StoreFileData(const char *data, unsigned int size) override + { + if (!size) { - m_head = h; - return true; + m_status = FIST_COMPLETE; + vprint.fin(); } - virtual bool StoreFileData(const char *data, unsigned int size) override - { - if(!size) + auto consumed = std::min(size, lineBuf.freecapa()); + memcpy(lineBuf.wptr(), data, consumed); + lineBuf.got(consumed); + for (;;) + { + LPCSTR p = lineBuf.rptr(); + auto end = mempbrk(p, "\r\n", lineBuf.size()); + if (!end) + break; + string s(p, end - p); + lineBuf.drop(s.length() + 1); + vprint.dot(); + if (startsWith(s, m_key)) { - m_status = FIST_COMPLETE; - vprint.fin(); - } - auto consumed = std::min(size, lineBuf.freecapa()); - memcpy(lineBuf.wptr(), data, consumed); - lineBuf.got(consumed); - for(;;) - { - LPCSTR p = lineBuf.rptr(); - auto end = mempbrk(p, "\r\n", lineBuf.size()); - if(!end) + // that's for us... " content\n" + char *endchar = nullptr; + p = s.c_str(); + auto val = strtoul(p + m_key.length(), &endchar, 10); + if (!endchar || !*endchar) + continue; // heh? shall not finish here + switch (ControLineType(val)) + { + case ControLineType::BeforeError: + m_errMsg.emplace_back(endchar, s.size() - (endchar - p)); + vprint.msg(m_errMsg.back()); break; - string s(p, end-p); - lineBuf.drop(s.length()+1); - vprint.dot(); - if(startsWith(s, m_key)) + case ControLineType::Error: { - // that's for us... " content\n" - char *endchar = nullptr; - p = s.c_str(); - auto val = strtoul(p + m_key.length(), &endchar, 10); - if(!endchar || !*endchar) - continue; // heh? shall not finish here - switch(ControLineType(val)) - { - case ControLineType::BeforeError: - m_errMsg.emplace_back(endchar, s.size() - (endchar - p)); - vprint.msg(m_errMsg.back()); - break; - case ControLineType::Error: - { - if(!g_bVerbose) // printed before - for(auto l : m_errMsg) - cerr << l << endl; - m_errMsg.clear(); - string msg(endchar, s.size() - (endchar - p)); - vprint.fin(); - cerr << msg << endl; - break; - } - default: - continue; - } + if (!g_bVerbose) // printed before + for (auto l : m_errMsg) + cerr << l << endl; + m_errMsg.clear(); + string msg(endchar, s.size() - (endchar - p)); + vprint.fin(); + cerr << msg << endl; + break; + } + default: + continue; } } - return true; } - ssize_t SendData(int , int, off_t &, size_t ) override - { - return 0; - } - }; - return make_shared(); - } -}; + return true; + } + ssize_t SendData(int, int, off_t&, size_t) override + { + return 0; + } + }; + return make_shared(); +} +void DownloadItem(const tHttpUrl &url, IDlConFactory &pDlconFac, const SHARED_PTR &fi) +{ + dlcon dl("", nullptr, &pDlconFac); + std::thread dlThread([&]() {dl.WorkLoop();}); + dl.AddJob(fi, &url, nullptr, nullptr, 0, cfg::REDIRMAX_DEFAULT); + int st; + auto fistatus = fi->WaitForFinish(&st); + // just be sure to set a proper error code + if(fistatus != fileitem::FIST_COMPLETE && fi->GetHeader().getStatus() < 400) + fi->GetHeader().frontLine = "909 Incomplete download"; + dl.SignalStop(); + dlThread.join(); +} int wcat(LPCSTR url, LPCSTR proxy, IFitemFactory*, IDlConFactory *pdlconfa = &g_tcp_con_factory); -LPCSTR ReTest(LPCSTR); - -static void usage(int retCode = 0) +static void usage(int retCode = 0, LPCSTR cmd = nullptr) { - (retCode ? cout : cerr) << + if(cmd) + { + if(0 == strcmp(cmd, "shrink")) + cerr << "USAGE: acngtool shrink numberX [-f | -n] [-x] [-v] [variable assignments...]" < other.lastDate; + } +}; + +int shrink(off_t wantedSize, bool dryrun, bool apply, bool verbose, bool incIfiles) +{ + if(!dryrun && !apply) + { + cerr << "Error: needs -f or -n options" << endl; + return 97; + } + if(dryrun && apply) + { + cerr << "Error: -f and -n are mutually exclusive" <, cmpLessDate */ > delQ; + std::unordered_map > related; + + blkcnt_t totalBlocks = 0; + + IFileHandler::FindFiles(cfg::cachedir, + [&delQ, &totalBlocks, &related, &incIfiles](cmstring & path, const struct stat& finfo) -> bool + { + // reference date used in the prioqueue heap + auto dateLatest = max(finfo.st_ctim.tv_sec, finfo.st_mtim.tv_sec); + auto isHead = endsWithSzAr(path, ".head"); + string pkgPath, otherName; + if(isHead) + { + pkgPath = path.substr(0, path.length()-5); + otherName = pkgPath; + } + else + { + pkgPath = path; + otherName = path + ".head"; + } + auto ftype = rex::GetFiletype(pkgPath); + if((ftype==rex::FILE_SPECIAL_VOLATILE || ftype == rex::FILE_VOLATILE) && !incIfiles) + return true; + // anything else is considered junk + + auto other = related.find(otherName); + if(other == related.end()) + { + // the related file will appear soon + related.insert(make_pair(path, make_pair(dateLatest, finfo.st_blocks))); + return true; + } + // care only about stamps on .head files (track mode) + // or ONLY about data file's timestamp (not-track mode) + if( (cfg::trackfileuse && !isHead) || (!cfg::trackfileuse && isHead)) + dateLatest = other->second.first; + + auto bothBlocks = (finfo.st_blocks + other->second.second); + related.erase(other); + + totalBlocks += bothBlocks; + delQ.push({pkgPath, dateLatest, bothBlocks}); + + return true; + } + , true, false); + + // there might be some unmatched remains... + for(auto kv: related) + delQ.push({kv.first, kv.second.first, kv.second.second}); + related.clear(); + + auto foundSizeString = offttosHdotted(totalBlocks*512); + blkcnt_t wantedBlocks = wantedSize / 512; + + if(totalBlocks < wantedBlocks) + { + if(verbose) + cout << "Requested size smaller than current size, nothing to do." << endl; + return 0; + } + + if(verbose) + { + cout << "Found " << foundSizeString << " bytes of relevant data, reducing to " + << offttosHdotted(wantedSize) << " (~"<< (wantedBlocks*100/totalBlocks) << "%)" + << endl; + } + while(!delQ.empty()) + { + bool todel = (totalBlocks > wantedBlocks); + if(todel) + totalBlocks -= delQ.top().blocks; + const char *msg = 0; + if(verbose || dryrun) + msg = (todel ? "Delete: " : "Keep: " ); + auto& delpath(delQ.top().path); + if(msg) + cout << msg << delpath << endl << msg << delpath << ".head" << endl; + if(todel && apply) + { + unlink(delpath.c_str()); + unlink(mstring(delpath + ".head").c_str()); + } + delQ.pop(); + } + if(verbose) + { + cout << "New size: " << offttosHdotted(totalBlocks*512) << " (before: " + << foundSizeString << ")" << endl; + } + return 0; +} #if SUPPWHASH @@ -350,98 +545,147 @@ return true; } -int maint_job() +/** + * Helper which implements a custom connection class that runs through a specified Unix Domain + * Socket (see base class for the name). + */ +struct TUdsFactory : public ::acng::IDlConFactory { - acfg::SetOption("proxy=", nullptr); - LPCSTR envh = getenv("HOSTNAME"); - if (!envh) - envh = "localhost"; - LPCSTR req = getenv("ACNGREQ"); - if (!req) - req = "?doExpire=Start+Expiration&abortOnErrors=aOe"; - - tSS urlPath; - urlPath << "http://"; - if(!acfg::adminauth.empty()) - urlPath << acfg::adminauth << "@"; - urlPath << envh << ":" << acfg::port; - - if(acfg::reportpage.empty()) - return -1; - if(acfg::reportpage[0] != '/') - urlPath << '/'; - urlPath << acfg::reportpage << req; - - CReportItemFactory fac; - - int s = -1; - if (!acfg::fifopath.empty()) + void RecycleIdleConnection(tDlStreamHandle &handle) override { -#ifdef DEBUG - cerr << "Socket path: " << acfg::fifopath << endl; -#endif - s = socket(PF_UNIX, SOCK_STREAM, 0); - if (s >= 0) + // keep going, no recycling/restoring + } + tDlStreamHandle CreateConnected(cmstring&, cmstring&, mstring& sErrorOut, bool*, + cfg::tRepoData::IHookHandler*, bool, int, bool) override + { + struct udsconnection: public tcpconnect { - struct sockaddr_un addr; - addr.sun_family = PF_UNIX; - strcpy(addr.sun_path, acfg::fifopath.c_str()); - socklen_t adlen = acfg::fifopath.length() + 1 + offsetof(struct sockaddr_un, sun_path); - if (0 != connect(s, (struct sockaddr*) &addr, adlen)) - { - s = -1; -#ifdef DEBUG - perror("connect"); -#endif - } - else + bool failed = false; + udsconnection() : tcpconnect(nullptr) { - //identify myself + // some static and dummy parameters, and invalidate SSL for sure + m_ssl = nullptr; + m_bio = nullptr; + m_sHostName = FAKE_UDS_HOSTNAME; + m_sPort = cfg::port; + + m_conFd = socket(PF_UNIX, SOCK_STREAM, 0); + if (m_conFd < 0) + { + failed = true; + return; + } + struct sockaddr_un addr; + addr.sun_family = PF_UNIX; + strcpy(addr.sun_path, cfg::udspath.c_str()); + socklen_t adlen = cfg::udspath.length() + 1 + offsetof(struct sockaddr_un, sun_path); + if (connect(m_conFd, (struct sockaddr*) &addr, adlen)) + { + DBGQLOG(tErrnoFmter("connect result: ")); + checkforceclose(m_conFd); + failed = true; + return; + } + // basic identification needed tSS ids; ids << "GET / HTTP/1.0\r\nX-Original-Source: localhost\r\n\r\n"; - if (!ids.send(s)) - s = -1; + if (!ids.send(m_conFd)) + { + failed = true; + return; + } } - } + }; + auto ret = make_shared(); + // mimic regular processing of a bad result here! + if(ret && ret->failed) ret.reset(); + if(!ret) sErrorOut = "912 Cannot establish control connection"; + return ret; } +}; - if(s>=0) // use hot unix socket +int maint_job() +{ + if (cfg::reportpage.empty()) { - struct udsFac: public IDlConFactory - { - int m_sockfd = -1; - udsFac(int n) : m_sockfd(n) {} + cerr << "ReportPage is not configured in the server config, aborting..." <(m_sockfd); - } - } udsfac(s); - wcat(urlPath.c_str(), nullptr, &fac, &udsfac); + auto isInsecForced = []() { auto se = getenv("ACNG_INSECURE"); return se && *se; }; + + // by default, use the socket connection; if credentials require it -> enforce it + bool have_cred = !url.sUserPass.empty(), + have_uds = !cfg::udspath.empty(), + try_tcp = !have_cred; + bool uds_ok = have_uds && isUdsAccessible(cfg::udspath); + + if(have_cred) + { + if(isInsecForced()) // so try TCP anyway + { + try_tcp = true; + } + else if(have_uds && !uds_ok) + { + cerr << "This operation transmits credentials but the socket (" << cfg::udspath + << ") is currently not accessible!" << endl; + return EXIT_FAILURE; + } + else if(!have_uds) + { + cerr << "This operation transmits credentials but SocketPath is not configured to a safe location in the server configuration. " + "Please set SocketPath to a safe location, or set ACNG_INSECURE environment variable to override this check." + <GetHeader().getStatus() == 200; + DBGQLOG("UDS result: " << response_ok) + } + if(!response_ok && try_tcp) + { + DBGQLOG("Trying TCP path") + // never use a proxy here (insecure?), those are most likely local IPs + cfg::SetOption("Proxy=", nullptr); + cfg::nettimeout = 30; + vector hostips; + Tokenize(cfg::bindaddr, SPACECHARS, hostips, false); + if(hostips.empty()) + hostips.emplace_back("127.0.0.1"); + for (const auto &tgt : hostips) + { + url.sHost = tgt; + auto fi = CreateReportItem(); + DownloadItem(url, g_tcp_con_factory, fi); + response_ok = fi->GetHeader().getStatus() == 200; + if (response_ok) + break; + } } - else // ok, try the TCP path + if(!response_ok) { - wcat(urlPath.c_str(), getenv("http_proxy"), &fac); + cerr << "Could not make a valid request to the server. Please visit " + << url.ToURI(false) << " and check special conditions." < f; }; @@ -552,6 +796,7 @@ { LPCSTR szCfgDir=CFGDIR; std::vector validargs, nonoptions; + bool ignoreCfgErrors = false; for (auto p=argv; p '0' && *p<='9') + wantedSize = strsizeToOfft(p); + else if(*p == '-') + { + for(++p;*p;++p) + { + if(*p == 'f') apply = true; + else if(*p == 'n') dryrun = true; + else if (*p == 'x') incIfiles = true; + else if (*p == 'v') verbose = true; + } + } + } + } + } }; int main(int argc, const char **argv) { + using namespace acng; + // ensure a harmless object just in case any activity wants to run anything there + cleaner::GetInstance(false).notifyAll(); + string exe(argv[0]); unsigned aOffset=1; if(endsWithSzAr(exe, "expire-caller.pl")) @@ -772,8 +1055,8 @@ aOffset=0; argv[0] = "maint"; } - acfg::g_bQuiet = true; - acfg::g_bNoComplex = true; // no DB for just single variables + cfg::g_bQuiet = false; + cfg::g_bNoComplex = true; // no DB for just single variables parm* parm = nullptr; LPCSTR mode = nullptr; @@ -800,52 +1083,57 @@ }); if(!mode || !parm) usage(3); +#ifdef DEBUG + log::open(); +#endif if(!xargCount) // should run the code at least once? { if(parm->minArg) // uh... needs argument(s) - usage(4); + usage(4, mode); parm->f(nullptr); } + else if(parm->maxArg == UINT_MAX) // or needs to terminate it? + parm->f(nullptr); return g_exitCode; } int wcat(LPCSTR surl, LPCSTR proxy, IFitemFactory* fac, IDlConFactory *pDlconFac) { - acfg::dnscachetime=0; - acfg::persistoutgoing=0; - acfg::badredmime.clear(); - acfg::redirmax=10; + cfg::dnscachetime=0; + cfg::persistoutgoing=0; + cfg::badredmime.clear(); + cfg::redirmax=10; if(proxy) - if(acfg::SetOption(string("proxy:")+proxy, nullptr)) + if(cfg::SetOption(string("proxy:")+proxy, nullptr)) return -1; tHttpUrl url; if(!surl) return 2; string xurl(surl); - if(!url.SetHttpUrl(xurl)) + if(!url.SetHttpUrl(xurl, false)) return -2; dlcon dl(true, nullptr, pDlconFac); auto fi=fac->Create(); - dl.AddJob(fi, &url, nullptr, nullptr, 0); + dl.AddJob(fi, &url, nullptr, nullptr, 0, cfg::REDIRMAX_DEFAULT); dl.WorkLoop(); - if(fi->GetStatus() == fileitem::FIST_COMPLETE) - { - auto hh=fi->GetHeaderUnlocked(); - auto st=hh.getStatus(); - if(st == 200) - return EXIT_SUCCESS; - // don't reveal passwords - auto xpos=xurl.find('@'); - if(xpos!=stmiss) - xurl.erase(0, xpos+1); - cerr << "Error: cannot fetch " << xurl <<", " << hh.frontLine << endl; - if (st>=500) - return EIO; - if (st>=400) - return EACCES; - } + auto fistatus = fi->GetStatus(); + header hh = fi->GetHeader(); + int st=hh.getStatus(); + + if(fistatus == fileitem::FIST_COMPLETE && st == 200) + return EXIT_SUCCESS; + + // don't reveal passwords + auto xpos=xurl.find('@'); + if(xpos!=stmiss) + xurl.erase(0, xpos+1); + cerr << "Error: cannot fetch " << xurl <<", " << hh.frontLine << endl; + if (st>=500) + return EIO; + if (st>=400) + return EACCES; return EXIT_FAILURE; } @@ -862,7 +1150,7 @@ if (argc < 2) return -1; - acfg::tHostInfo hi; + acng::cfg:tHostInfo hi; cout << "Parsing " << argv[1] << ", result: " << hi.SetUrl(argv[1]) << endl; cout << "Host: " << hi.sHost << ", Port: " << hi.sPort << ", Path: " << hi.sPath << endl; @@ -962,18 +1250,18 @@ if (cmd == "benchmark") { dump_proc_status_always(); - acfg::g_bQuiet = true; - acfg::g_bNoComplex = false; + cfg::g_bQuiet = true; + cfg::g_bNoComplex = false; parse_options(argc - 2, argv + 2, true); - acfg::PostProcConfig(); + cfg::PostProcConfig(); string s; tHttpUrl u; int res=0; /* - acfg::tRepoResolvResult hm; + acng::cfg:tRepoResolvResult hm; tHttpUrl wtf; wtf.SetHttpUrl(non_opt_args.front()); - acfg::GetRepNameAndPathResidual(wtf, hm); + acng::cfg:GetRepNameAndPathResidual(wtf, hm); */ while(cin) { @@ -981,8 +1269,8 @@ s += "/xtest.deb"; if(u.SetHttpUrl(s)) { - acfg::tRepoResolvResult xdata; - acfg::GetRepNameAndPathResidual(u, xdata); + cfg::tRepoResolvResult xdata; + cfg::GetRepNameAndPathResidual(u, xdata); cout << s << " -> " << (xdata.psRepoName ? "matched" : "not matched") << endl; diff -Nru apt-cacher-ng-0.9.1/source/apt-cacher.cc apt-cacher-ng-3.3.1/source/apt-cacher.cc --- apt-cacher-ng-0.9.1/source/apt-cacher.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/apt-cacher.cc 2020-01-08 19:58:26.000000000 +0000 @@ -32,16 +32,6 @@ #include #include -#ifdef HAVE_SSL -#include -#include "openssl/bio.h" -#include "openssl/ssl.h" -#include "openssl/err.h" -#include -#include -#include -#endif - #include "filereader.h" #include "csmapping.h" #ifdef DEBUG @@ -49,18 +39,25 @@ #endif #include "maintenance.h" +#include "evabase.h" +#include +#include + +namespace acng +{ static void usage(int nRetCode=0); static void SetupCacheDir(); -void sig_handler(int signum); -void log_handler(int signum); -void dump_handler(int signum); +void term_handler(evutil_socket_t fd, short what, void *arg); +void log_handler(evutil_socket_t fd, short what, void *arg); +void dump_handler(evutil_socket_t fd, short what, void *arg); +void noop_handler(evutil_socket_t fd, short what, void *arg); void handle_sigbus(); void check_algos(); -typedef struct sigaction tSigAct; +extern mstring sReplDir; -cleaner g_victor; +typedef struct sigaction tSigAct; #ifdef HAVE_DAEMON inline bool fork_away() @@ -96,12 +93,17 @@ bool bExtraVerb=false; LPCSTR szCfgDir=nullptr; std::vector cmdvars; + bool ignoreCfgErrors = false; for (auto p=argv+1; pbase; + auto what = EV_SIGNAL|EV_PERSIST; +#define REGSIG(x,y) event_add(::event_new(ebase, x, what, & y, 0), nullptr); + for(int snum : {SIGBUS, SIGTERM, SIGINT, SIGQUIT}) REGSIG(snum, term_handler); + REGSIG(SIGUSR1, log_handler); + REGSIG(SIGUSR2, dump_handler); + REGSIG(SIGPIPE, noop_handler); #ifdef SIGIO - sigaction(SIGIO, &act, nullptr); + REGSIG(SIGIO, noop_handler); #endif #ifdef SIGXFSZ - sigaction(SIGXFSZ, &act, nullptr); -#endif -} - -int main(int argc, const char **argv) -{ - -#ifdef HAVE_SSL - SSL_load_error_strings(); - ERR_load_BIO_strings(); - ERR_load_crypto_strings(); - ERR_load_SSL_strings(); - OpenSSL_add_all_algorithms(); - SSL_library_init(); + REGSIG(SIGXFSZ, noop_handler); #endif - - bool bRunCleanup=false; - - parse_options(argc, argv, bRunCleanup); - - if(!aclog::open()) - { - cerr << "Problem creating log files. Check permissions of the log directory, " - << acfg::logdir<base); + break; } default: return; } } + +void CloseAllCachedConnections(); + +struct tAppStartStop +{ + tAppStartStop(int argc, const char**argv) + { + evthread_use_pthreads(); + + #ifdef HAVE_SSL + acng::globalSslInit(); + #endif + + bool bRunCleanup=false; + + parse_options(argc, argv, bRunCleanup); + + if(!log::open()) + { + cerr << "Problem creating log files. Check permissions of the log directory, " + << cfg::logdir<(); + + setup_sighandler(); + + SetupCacheDir(); + + DelTree(cfg::cacheDirSlash+sReplDir); + + if(conserver::Setup() <= 0) + { + cerr << "No listening socket(s) could be created/prepared. " + "Check the network, check or unset the BindAddress directive.\n"; + exit(EXIT_FAILURE); + } + + if (bRunCleanup) + { + tSpecialRequest::RunMaintWork(tSpecialRequest::workExExpire, + cfg::reportpage + "?abortOnErrors=aOe&doExpire=Start", + fileno(stdout)); + exit(0); + } + + if (!cfg::foreground && !fork_away()) + { + tErrnoFmter ef("Failed to change to daemon mode"); + cerr << ef << endl; + exit(43); + } + + if (!cfg::pidfile.empty()) + { + mkbasedir(cfg::pidfile); + FILE *PID_FILE = fopen(cfg::pidfile.c_str(), "w"); + if (PID_FILE != nullptr) + { + fprintf(PID_FILE, "%d", getpid()); + checkForceFclose(PID_FILE); + } + } + } + ~tAppStartStop() + { + cleaner::GetInstance().Stop(); + if (!cfg::pidfile.empty()) + unlink(cfg::pidfile.c_str()); + conserver::Shutdown(); + CloseAllCachedConnections(); + log::close(false); + } +}; + +} + +int main(int argc, const char **argv) +{ + using namespace acng; + tAppStartStop app(argc, argv); + return conserver::Run(); + +} diff -Nru apt-cacher-ng-0.9.1/source/bgtask.cc apt-cacher-ng-3.3.1/source/bgtask.cc --- apt-cacher-ng-0.9.1/source/bgtask.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/bgtask.cc 2020-01-08 19:58:26.000000000 +0000 @@ -12,6 +12,7 @@ #include "acfg.h" #include "meta.h" #include "filereader.h" +#include "evabase.h" #include #include @@ -27,34 +28,40 @@ "" #define LOG_DECO_END "" -bool bSigTaskAbort=false; -pthread_mutex_t abortMx=PTHREAD_MUTEX_INITIALIZER; +namespace acng +{ + +// for start/stop and abort hint +base_with_condition tSpecOpDetachable::g_StateCv; +bool tSpecOpDetachable::g_sigTaskAbort=false; +// not zero if a task is active +time_t nBgTimestamp = 0; tSpecOpDetachable::~tSpecOpDetachable() { - if(m_pTracker) - m_pTracker->SetEnd(m_reportStream.is_open() ? off_t(m_reportStream.tellp()) : off_t(0)); - if(m_reportStream.is_open()) { m_reportStream << LOG_DECO_END; m_reportStream.close(); } + checkforceclose(m_logFd); } -// the obligatory definition of static members :-( -WEAK_PTR tSpecOpDetachable::g_pTracker; +cmstring GetFooter() +{ + return mstring("
        Server: ") + cfg::agentname + + "  |  Donate!" + "  |  Apt-Cacher NG homepage
        "; +} -cmstring& GetFooter() +std::string to_base36(unsigned int val) { - static mstring footer; - if(footer.empty()) - { - footer = string("
        Server: ") + acfg::agentname + - "  |  Flattr this!" - "  |  Apt-Cacher NG homepage
        "; - } - return footer; + static std::string base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + std::string result; + do { + result.insert(0, 1, base36[val % 36]); + } while (val /= 36); + return result; } /* @@ -66,8 +73,9 @@ if (m_parms.cmd.find("&sigabort")!=stmiss) { - lockguard g(&abortMx); - bSigTaskAbort=true; + lockguard g(g_StateCv); + g_sigTaskAbort=true; + g_StateCv.notifyAll(); tStrPos nQuest=m_parms.cmd.find("?"); if(nQuest!=stmiss) { @@ -84,9 +92,9 @@ tSS deco; const char *mark(nullptr); if(m_szDecoFile && - ( deco.initFromFile((acfg::confdir+SZPATHSEP+m_szDecoFile).c_str()) - || (!acfg::suppdir.empty() && - deco.initFromFile((acfg::suppdir+SZPATHSEP+m_szDecoFile).c_str())))) + ( deco.initFromFile((cfg::confdir+SZPATHSEP+m_szDecoFile).c_str()) + || (!cfg::suppdir.empty() && + deco.initFromFile((cfg::suppdir+SZPATHSEP+m_szDecoFile).c_str())))) { mark=::strchr(deco.rptr(), '~'); if(mark) @@ -105,67 +113,59 @@ tSS logPath; - tProgTrackPtr pTracked; + time_t other_id=0; { // this is locked just to make sure that only one can register as master - lockguard guard(abortMx); - pTracked=g_pTracker.lock(); - if(!pTracked) // ok, not running yet -> become the log source then + lockguard guard(g_StateCv); + if(0 == nBgTimestamp) // ok, not running yet -> become the log source then { - m_pTracker = make_shared(); - time_t nMaintId=time(0); + auto id = time(0); logPath.clear(); - logPath<id = nMaintId; - g_pTracker=m_pTracker; + nBgTimestamp = id; } else { + nBgTimestamp = 0; SendChunk("Failed to create the log file, aborting."); return; } } + else other_id = nBgTimestamp; } - if(pTracked) + if(other_id) { SendChunkSZ("A maintenance task is already running!\n"); SendFmtRemote << " (Cancel)"; SendChunkSZ("
        Attempting to attach to the log output...
        \n"); - off_t nSent(0); - int fd(0); - acbuf xx; + tSS sendbuf(4096); + lockuniq g(g_StateCv); for(;;) { - lockguard g(*pTracked); - - if(!pTracked->id && pTracked->nEndSize==off_t(-1)) - break; // error? source is gone but end mark not set? - // otherwise: end known OR sorce active - - if(nSent==pTracked->nEndSize) - break; // DONE! - - if(!fd) + if(other_id != nBgTimestamp) + { + // task is gone or replaced by another? + SendChunkSZ("
        End of log output. Please reload to run again.\n"); + goto finish_action; + } + if(m_logFd < 0) { logPath.clear(); - logPath<id << ".log.html"; - fd=open(logPath.c_str(), O_RDONLY); + logPath<=0) - { - set_nb(fd); + if(m_logFd>=0) SendChunk("ok:
        \n"); - } else { SendChunk("Failed to open log output, please retry later.
        \n"); @@ -173,19 +173,21 @@ } } - tSS msg; - msg.sysread(fd); // can be more than tracker reported. checks need to consider this - SendChunk(msg.data(), msg.length()); - nSent+=msg.length(); - msg.clear(); - - /* when file is truncated (disk full), the end size might be unreachable - * -> detect the time out - */ - if(pTracked->wait_until(GetTime()+33, 1)) - break; + while(true) + { + int r = sendbuf.sysread(m_logFd); + if(r < 0) + goto finish_action; + if(r == 0) + { + g_StateCv.wait_for(g, 10, 1); + break; + } + SendChunkRemoteOnly(sendbuf.rptr(), sendbuf.size()); + sendbuf.clear(); + } } - checkforceclose(fd); + // unreachable goto finish_action; } else @@ -193,14 +195,14 @@ /***************************************************** * This is the worker part *****************************************************/ - { - lockguard g(&abortMx); - bSigTaskAbort=false; - } + lockuniq g(&g_StateCv); + g_sigTaskAbort=false; + tDtorEx cleaner([&](){g.reLockSafe(); nBgTimestamp = 0; g_StateCv.notifyAll();}); + g.unLock(); SendFmt << "Maintenance task " << GetTaskName() << ", apt-cacher-ng version: " ACVERSION; - string link = "http://" + GetHostname() + ":" + acfg::port + "/" + m_parms.cmd; + string link = "http://" + GetHostname() + ":" + cfg::port + "/" + cfg::reportpage; SendFmtRemote << " (Cancel)" << "\n\n" -// << "\n" - ; + << "Server control address: " << link + << "\n-->\n"; string xlink = "
        \nServer link: " + link + "
        \n"; SendChunkLocalOnly(xlink.data(), xlink.size()); SendFmt << "
        \n"; @@ -220,8 +220,43 @@ Action(); - if (!m_delCboxFilter.empty()) + + if (!m_pathMemory.empty()) { + bool unchint=false; + bool ehprinted=false; + + for(const auto& err: m_pathMemory) + { + if(err.second.msg.empty()) + continue; + + if(!ehprinted) + { + ehprinted=true; + SendChunkRemoteOnly(WITHLEN( + "
        Error summary:
        ")); + } + + unchint = unchint + ||endsWithSzAr(err.first, "Packages") + ||endsWithSzAr(err.first, "Sources"); + + SendFmtRemote << err.first << ":
    " << title << "
    second), xNew) << ">" << html_sanitize(offttosH(it->first)) << "" << *(it->second) << "
    "; - if(m_delCboxFilter.empty()) + if(m_pathMemory.empty()) { SendFmtRemote << "
    Action(s):
    " "void { + cout << "Dir: " << entry.sDirectory << endl << "File: " << entry.sFileName << endl + << "Checksum-" << GetCsName(entry.fpr.csType) << ": " << entry.fpr.GetCsAsString() + << endl; + }, file, GuessMetaTypeFromURL(file)); } virtual bool ProcessRegular(const mstring &, const struct stat &) override {return true;} virtual bool ProcessOthers(const mstring &, const struct stat &) override {return true;} @@ -2258,7 +2329,7 @@ #endif -void tCacheOperation::ProgTell() +void cacheman::ProgTell() { if (++m_nProgIdx == m_nProgTell) { @@ -2267,3 +2338,167 @@ m_nProgTell*=2; } } + +bool cacheman::_checkSolidHashOnDisk(cmstring& hexname, + const tRemoteFileInfo &entry, + cmstring& srcPrefix + ) +{ + string solidPath = CACHE_BASE + entry.sDirectory.substr(srcPrefix.length()) + "by-hash/" + + GetCsNameReleaseFile(entry.fpr.csType) + '/' + hexname; + return ! ::access(solidPath.c_str(), F_OK); +} + +void cacheman::BuildCacheFileList() +{ + //dump_proc_status(); + IFileHandler::DirectoryWalk(cfg::cachedir, this); + //dump_proc_status(); +} + +bool cacheman::ProcessByHashReleaseFileRestoreFiles(cmstring& releasePathRel, cmstring& stripPrefix) +{ + int errors = 0; + + return ParseAndProcessMetaFile([this, &errors, &stripPrefix](const tRemoteFileInfo &entry) -> void + { + // ignore, those files are empty and are likely to report false positives + if(entry.fpr.size < 29) + return; + + auto hexname(BytesToHexString(entry.fpr.csum, GetCSTypeLen(entry.fpr.csType))); + // ok, getting all hash versions... + if(!_checkSolidHashOnDisk(hexname, entry, stripPrefix)) + return; // not for us + + auto wantedPathRel = entry.sDirectory.substr(stripPrefix.size()) + + entry.sFileName; + auto wantedPathAbs = SABSPATH(wantedPathRel); +#ifdef DEBUGIDX + SendFmt << entry.sDirectory.substr(stripPrefix.size()) + "by-hash/" + + GetCsNameReleaseFile(entry.fpr.csType) + '/' + hexname + << " was " << wantedPathAbs << hendl; +#endif + Cstat wantedState(wantedPathAbs); + string solidPathRel, solidPathAbs; + // lazy construction for the check below + if(!wantedState || wantedState.st_size != entry.fpr.size) + { + solidPathRel = entry.sDirectory.substr(stripPrefix.size()) + "by-hash/" + + GetCsNameReleaseFile(entry.fpr.csType) + '/' + hexname; + solidPathAbs = SABSPATH(solidPathRel); + } + + bool contentMatch(false); + // either target file is missing or is an older(?) version of different size + // and our version fits better + if(!wantedState || (wantedState.st_size != entry.fpr.size + && (contentMatch = entry.fpr.CheckFile(solidPathAbs)))) + { + if(m_bVerbose) + SendFmt << "Restoring virtual file " << wantedPathRel + << " (equal to " << solidPathRel << ")" << hendl; + + // return with increased count if error happens + errors++; + + header h; + // load by-hash header, check URL, rewrite URL, copy the stuff over + if(!h.LoadFromFile(SABSPATH(solidPathRel) + ".head") || ! h.h[header::XORIG]) + { + if(m_bVerbose) + SendFmt << "Couldn't read " << SABSPATH(solidPathRel) << ".head
    "; + return; + } + string origin(h.h[header::XORIG]); + tStrPos pos = origin.rfind("by-hash/"); + if(pos == stmiss) + { + if(m_bVerbose) + SendFmt << SABSPATH(solidPathRel) << " is not from by-hash folder
    "; + return; + } + h.set(header::XORIG, origin.substr(0, pos) + entry.sFileName); + // most servers report crap type on by-hash files, use generic one + h.set(header::CONTENT_TYPE, "octet/stream"); + // should be ok h.set(header::CONTENT_LENGTH, entry.fpr.size) + if(!Inject(solidPathRel, wantedPathRel, false, &h, false)) + { + if(m_bVerbose) + SendChunk("Couldn't install
    "); + return; + } + auto& flags = SetFlags(wantedPathRel); + if(flags.vfile_ondisk) + flags.uptodate = true; + + errors--; + } + }, + stripPrefix + releasePathRel, enumMetaType::EIDX_RELEASE, true) && errors == 0; +} + +bool cacheman::FixMissingByHashLinks(std::unordered_set &oldReleaseFiles) +{ + bool ret = true; + + // path of side store with trailing slash relativ to cache folder + auto srcPrefix(cfg::privStoreRelSnapSufix + sPathSep); + + for(const auto& snapPathInXstore: oldReleaseFiles) + { + if(endsWithSzAr(snapPathInXstore, ".upgrayedd")) + continue; + // path relative to cache folder + if(!ProcessByHashReleaseFileRestoreFiles(snapPathInXstore, srcPrefix)) + { + SendFmt << "There were error(s) processing " << snapPathInXstore << ", ignoring..."<< hendl; + if(!m_bVerbose) + SendChunk("Enable verbosity to see more"); + return ret; + } +#ifdef DEBUGIDX + SendFmt << "Purging " << SABSPATH(srcPrefix + snapPathInXstore) << hendl; +#endif + unlink(SABSPATH(srcPrefix + snapPathInXstore).c_str()); + } + return ret; +} + +tStrDeq cacheman::GetGoodReleaseFiles() +{ + tStrMap t; + for (const auto& kv : m_metaFilesRel) + { + bool inr; + if(endsWith(kv.first, inRelKey)) + inr=true; + else if(endsWith(kv.first, relKey)) + inr=false; + else + continue; + if(!kv.second.vfile_ondisk) + continue; + auto df=SplitDirPath(kv.first); + string& fn = t[df.first]; + + if(inr) // always wins + { + if(!fn.empty()) // there was Release already... crap + SetFlags(kv.first).parseignore = true; + fn = df.second; + } + else + { + if(fn.empty()) + fn = df.second; + else + SetFlags(kv.first).parseignore = true; + } + } + tStrDeq ret; + for(const auto& kv: t) ret.emplace_back(kv.first+kv.second); + return ret; +} + +} diff -Nru apt-cacher-ng-0.9.1/source/caddrinfo.cc apt-cacher-ng-3.3.1/source/caddrinfo.cc --- apt-cacher-ng-0.9.1/source/caddrinfo.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/caddrinfo.cc 2020-01-08 19:58:26.000000000 +0000 @@ -7,138 +7,196 @@ #include "lockable.h" #include "cleaner.h" -#include - +#include +#include +#include using namespace std; -static class : public unordered_map, public lockable {} mapDnsCache; +#define DNS_MAX_PAR 8 -bool CAddrInfo::Resolve(const string & sHostname, const string &sPort, - string & sErrorBuf) +namespace acng { - LOGSTART2("CAddrInfo::Resolve", "Resolving " << sHostname); +static const unsigned DNS_CACHE_MAX=255; - LPCSTR port = sPort.empty() ? nullptr : sPort.c_str(); +static string make_dns_key(const string & sHostname, const string &sPort) +{ + return sHostname + "/" + sPort; +} - static struct addrinfo hints = - { - // we provide numbers, no resolution needed; only supported addresses - (port ? AI_NUMERICSERV:0) | AI_ADDRCONFIG, - PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, - 0, nullptr, nullptr, nullptr }; +base_with_condition dnsCacheCv; - // if only one family is specified, filter on this earlier - if(acfg::conprotos[0] != PF_UNSPEC && acfg::conprotos[1] == PF_UNSPEC) - hints.ai_family = acfg::conprotos[0]; +map dnsCache; +deque dnsAddSeq; - if (m_resolvedInfo) - { - freeaddrinfo(m_resolvedInfo); - m_resolvedInfo=nullptr; - } +bool CAddrInfo::ResolveTcpTarget(const string & sHostname, const string &sPort, + string & sErrorBuf, + const evutil_addrinfo* pHints, + bool & bTransientError) +{ + LOGSTART2("CAddrInfo::Resolve", "Resolving " << sHostname); - int r=getaddrinfo(sHostname.c_str(), port, &hints, &m_resolvedInfo); + sErrorBuf.clear(); + auto filter_specific = (cfg::conprotos[0] != PF_UNSPEC && cfg::conprotos[1] == PF_UNSPEC); + evutil_addrinfo default_connect_hints = + { + // we provide plain port numbers, no resolution needed + // also return only probably working addresses + AI_NUMERICSERV | AI_ADDRCONFIG, + filter_specific ? cfg::conprotos[0] : PF_UNSPEC, + SOCK_STREAM, IPPROTO_TCP, + 0, nullptr, nullptr, nullptr + }; - if (0!=r) - { - sErrorBuf=(tSS()<<"503 DNS error for hostname "<ai_next) + static atomic_int dns_overload_limiter(0); + while(dns_overload_limiter > DNS_MAX_PAR) + this_thread::sleep_for(1s); + dns_overload_limiter++; + int r = evutil_getaddrinfo(sHostname.empty() ? nullptr : sHostname.c_str(), + sPort.empty() ? nullptr : sPort.c_str(), + pHints ? pHints : &default_connect_hints, + &m_rawInfo); + dns_overload_limiter--; + + switch(r) + { + case 0: break; + case EAI_AGAIN: + case EAI_MEMORY: + case EAI_SYSTEM: + bTransientError = true; + __just_fall_through; + default: + return ret_error("If this refers to a configured cache repository, please check the corresponding configuration file", r); + } +#ifdef DEBUG + for(auto p=m_rawInfo; p; p=p->ai_next) + std::cerr << formatIpPort(p) << std::endl; +#endif + // find any suitable-looking entry and keep a pointer to it faster lookup + for (auto pCur=m_rawInfo; pCur; pCur = pCur->ai_next) { - if (pCur->ai_socktype == SOCK_STREAM&& pCur->ai_protocol == IPPROTO_TCP) - { - m_addrInfo=pCur; - return true; - } + if (pCur->ai_socktype != SOCK_STREAM || pCur->ai_protocol != IPPROTO_TCP) + continue; + m_tcpAddrInfo = pCur; + return true; } - LOG("couldn't find working DNS config"); - sErrorBuf="500 DNS resolution error"; + return ret_error("no suitable target service", EAI_SYSTEM); +} - // TODO: remove me from the map - return false; +void CAddrInfo::Reset() +{ + if (m_rawInfo) + evutil_freeaddrinfo(m_rawInfo); + m_tcpAddrInfo = m_rawInfo = nullptr; } CAddrInfo::~CAddrInfo() { - if (m_resolvedInfo) - freeaddrinfo(m_resolvedInfo); + Reset(); } - -CAddrInfo::SPtr CAddrInfo::CachedResolve(const string & sHostname, const string &sPort, string &sErrorMsgBuf) +CAddrInfoPtr CAddrInfo::CachedResolve(const string & sHostname, const string &sPort, string &sErrorMsgBuf) { - //time_t timeExpired=time(nullptr)+acfg::dnscachetime; - time_t now(time(0)); - mstring dnsKey=sHostname+":"+sPort; + bool dummy_run = sHostname.empty() && sPort.empty(); + bool bTransientError = false; + auto resolve_now = [&]() + { + auto ret = make_shared(); + if(! ret->ResolveTcpTarget(sHostname, sPort, sErrorMsgBuf, nullptr, bTransientError)) + ret.reset(); + return ret; + }; + if (!cfg::dnscachetime && !dummy_run) + return resolve_now(); + + auto dnsKey = make_dns_key(sHostname, sPort); + auto now(GetTime()); - SPtr p; + lockuniq lg(dnsCacheCv); + + // clean all expired entries + unsigned n(0); + while(!dnsAddSeq.empty() && dnsAddSeq.front()->second && dnsAddSeq.front()->second->m_expTime <= now) { - lockguard g(mapDnsCache); - SPtr localEntry; - SPtr & cand = acfg::dnscachetime>0 ? mapDnsCache[dnsKey] : localEntry; - if(cand && cand->m_nExpTime >= now) - return cand; - cand.reset(new CAddrInfo); - p=cand; - // lock the internal class and keep it until we are done with preparations - p->lock(); + // just to be safe in case anyone waits for it + if(!dnsAddSeq.front()->second->m_sError) + dnsAddSeq.front()->second->m_sError.reset(new string("504 DNS Cache Timeout")); + dnsCache.erase(dnsAddSeq.front()); + dnsAddSeq.pop_front(); + ++n; } + if(n) dnsCacheCv.notifyAll(); - if(!p) - return SPtr(); // weird... + if (dummy_run) + return CAddrInfoPtr(); - if (p->Resolve(sHostname, sPort, sErrorMsgBuf)) + if (dnsCache.size() >= DNS_CACHE_MAX) { - p->m_nExpTime = time(0) + acfg::dnscachetime; -#ifndef MINIBUILD - g_victor.ScheduleFor(p->m_nExpTime, cleaner::TYPE_EXDNS); -#endif - p->unlock(); + // something is fishy, too long exp. time? Just pass through then + lg.unLock(); + return resolve_now(); } - else // not good, remove from the cache again + + auto insres = dnsCache.emplace(dnsKey, make_shared()); + auto p = insres.first->second; + auto is_ours(insres.second); + if (is_ours) { - aclog::err( (tSS()<<"Error resolving "<unlock(); - p.reset(); + dnsAddSeq.push_back(insres.first); + p->m_expTime = now + cfg::dnscachetime; } - - return p; -} - -time_t CAddrInfo::BackgroundCleanup() -{ - lockguard g(mapDnsCache); - time_t now(GetTime()), ret(END_OF_TIME); - - for(auto it=mapDnsCache.begin(); it!=mapDnsCache.end(); ) + else // reuse the results from another thread { - if(it->second) + while(true) { - if(it->second->m_nExpTime<=now) + if(p->m_sError) { - mapDnsCache.erase(it++); - continue; + sErrorMsgBuf = * p->m_sError; + return CAddrInfoPtr(); } - else - ret=min(ret, it->second->m_nExpTime); + if(p->m_expTime <= MAX_VAL(time_t)) + return p; + dnsCacheCv.wait(lg); } - - ++it; } - return ret; + lg.unLock(); + auto resret = p->ResolveTcpTarget(sHostname, sPort, sErrorMsgBuf, nullptr, bTransientError); + lg.reLock(); + if(resret) + { + p->m_expTime = now + cfg::dnscachetime; + dnsCacheCv.notifyAll(); + return p; + } + // or handle errors, keep them for observers + p->m_sError.reset(new string(sErrorMsgBuf)); + // for permanent failures, also keep them in cache for a while + if(!bTransientError) + p->m_expTime = now + cfg::dnscachetime; + dnsCacheCv.notifyAll(); + return p; } +#if 0 void DropDnsCache() { - lockguard g(mapDnsCache); - mapDnsCache.clear(); +#warning check all usage + lockguard g(dnsCacheCv); + dnsCleanupQ.clear(); + dnsCache.clear(); +} +#endif + } diff -Nru apt-cacher-ng-0.9.1/source/cleaner.cc apt-cacher-ng-3.3.1/source/cleaner.cc --- apt-cacher-ng-0.9.1/source/cleaner.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/cleaner.cc 2020-01-08 19:58:26.000000000 +0000 @@ -21,7 +21,10 @@ #define TERM_VAL (time_t(-1)) -cleaner::cleaner() : m_thr(0) +namespace acng +{ + +cleaner::cleaner(bool noop) : m_thr(0), m_noop(noop) { Init(); } @@ -39,68 +42,71 @@ { LOGSTART("cleaner::WorkLoop"); + lockuniq g(this); for(;;) { - eType what = TYPE_EXDNS; - time_t now; + // XXX: review the flow, is this always safe? + eType what = TYPE_EXCONNS; + time_t when = END_OF_TIME; + + if(m_terminating) + return; + + // ok, who's next? + for (unsigned i = 0; i < ETYPE_MAX; ++i) { - setLockGuard; - // ok, who's next? - for (unsigned i = 0; i < _countof(stamps); ++i) - if (stamps[i] < stamps[what]) - what = (eType) i; - now=GetTime(); - if(stamps[what] > now) + if (stamps[i] < when) { - wait_until(stamps[what], 112); - continue; + what = (eType) i; + when = stamps[i]; } - stamps[what] = END_OF_TIME; - // good, do the work now } + + auto now=GetTime(); + if(when > now) + { + // work around buggy STL: add some years on top and hope it will be fixed then + if(when == END_OF_TIME) + when = now | 0x3ffffffe; + wait_until(g, when, 111); + continue; + } + stamps[what] = END_OF_TIME; + g.unLock(); + + // good, do the work now time_t time_nextcand=END_OF_TIME; switch(what) { case TYPE_ACFGHOOKS: - time_nextcand = acfg::BackgroundCleanup(); - USRDBG("acfg::ExecutePostponed, nextRunTime now: " << time_nextcand); + time_nextcand = cfg::BackgroundCleanup(); + USRDBG("acng::cfg:ExecutePostponed, nextRunTime now: " << time_nextcand); break; case TYPE_EXCONNS: time_nextcand = g_tcp_con_factory.BackgroundCleanup(); USRDBG("tcpconnect::ExpireCache, nextRunTime now: " << time_nextcand); break; - - case TYPE_EXDNS: - time_nextcand = CAddrInfo::BackgroundCleanup(); - USRDBG("CAddrInfo::ExpireCache, nextRunTime now: " << time_nextcand); - break; - case TYPE_EXFILEITEM: time_nextcand = fileItemMgmt::BackgroundCleanup(); USRDBG("fileitem::DoDelayedUnregAndCheck, nextRunTime now: " << time_nextcand); break; - default: - return; + case ETYPE_MAX: + return; // heh? } if(time_nextcand <= now || time_nextcand < 1) { - aclog::err(tSS() << "ERROR: looping bug candidate on " << what + log::err(tSS() << "ERROR: looping bug candidate on " << (int) what << ", value: " << time_nextcand); time_nextcand=GetTime()+60; } - setLockGuard; + g.reLock(); if (time_nextcand < stamps[what]) stamps[what] = time_nextcand; - - // ok, who's next? - for (unsigned i = 0; i < _countof(stamps); ++i) - if (stamps[i] < stamps[what]) - what = (eType) i; }; } @@ -112,6 +118,8 @@ void cleaner::ScheduleFor(time_t when, eType what) { + if(m_noop) return; + setLockGuard; if(m_thr == 0) { @@ -140,7 +148,7 @@ if(!m_thr) return; - stamps[cleaner::TYPE_STOPSCHED] = 1; + m_terminating = true; notifyAll(); } pthread_join(m_thr, nullptr); @@ -154,16 +162,23 @@ setLockGuard; tSS msg; msg << "Cleanup schedule:\n"; - for(int i=0; i ${SRCS} apt-cacher.cc) -TARGET_LINK_LIBRARIES(apt-cacher-ng ${BaseNetworkLibs} ${ServerLibs} ${CompLibs} ${SSL_LIB_LIST} ${lsd_LDFLAGS} ${EXTRA_LIBS_ACNG}) -# I'd like this method more but apparently LINK_FLAGS is always prepended, no way to append it -#SET_TARGET_PROPERTIES(apt-cacher-ng PROPERTIES LINK_FLAGS "${lsd_LDFLAGS}") -SET_TARGET_PROPERTIES(apt-cacher-ng PROPERTIES COMPILE_FLAGS "${ACNG_CXXFLAGS_COMMON} ${lsd_CFLAGS}") -INSTALL(TARGETS apt-cacher-ng DESTINATION ${SBINDIR}) - -ADD_EXECUTABLE(acngtool acngtool.cc $) -SET_TARGET_PROPERTIES(acngtool PROPERTIES COMPILE_FLAGS "${ACNG_CXXFLAGS_COMMON}") -TARGET_LINK_LIBRARIES(acngtool ${BaseNetworkLibs} ${CompLibs} ${SSL_LIB_LIST} ${EXTRA_LIBS_ACNGTOOL}) +set(SHAREDSRCS sockio.cc acbuf.cc acfg.cc acfg_defaults.cc aclogger.cc caddrinfo.cc dirwalk.cc dlcon.cc fileio.cc fileitem.cc filelocks.cc filereader.cc header.cc meta.cc tcpconnect.cc cleaner.cc job.cc bgtask.cc cacheman.cc conn.cc conserver.cc expiration.cc lockable.cc maintenance.cc mirror.cc pkgimport.cc showinfo.cc evabase.cc evasocket.cc dnsiter.cc) +set(ACNG_SRCS apt-cacher.cc) +add_definitions(-DACNG_CORE_IN_SO) + +ADD_LIBRARY(supacng SHARED ${SHAREDSRCS}) +SET_TARGET_PROPERTIES(supacng PROPERTIES COMPILE_FLAGS "${ACNG_COMPFLAGS} ${ACNG_CXXFLAGS} ${CFLAGS_DAEMON} ${CFLAGS_PTHREAD}") +TARGET_LINK_LIBRARIES(supacng ${BaseNetworkLibs} ${ServerLibs} ${CompLibs} ${SSL_LIB_LIST} ${LDFLAGS_DAEMON} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBS_ACNG}) +INSTALL(TARGETS supacng LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +ADD_EXECUTABLE(apt-cacher-ng ${ACNG_SRCS} apt-cacher.cc) +TARGET_LINK_LIBRARIES(apt-cacher-ng supacng ${BaseNetworkLibs} ${ServerLibs} ${CompLibs} ${SSL_LIB_LIST} ${LDFLAGS_DAEMON} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBS_ACNG}) +SET_TARGET_PROPERTIES(apt-cacher-ng PROPERTIES COMPILE_FLAGS "${ACNG_COMPFLAGS} ${ACNG_CXXFLAGS} ${CFLAGS_DAEMON} ${CFLAGS_PTHREAD}") +INSTALL(TARGETS apt-cacher-ng DESTINATION ${CMAKE_INSTALL_SBINDIR}) + +ADD_EXECUTABLE(acngtool acngtool.cc) +SET_TARGET_PROPERTIES(acngtool PROPERTIES COMPILE_FLAGS "${ACNG_COMPFLAGS} ${ACNG_CXXFLAGS} ${CFLAGS_PTHREAD}") +TARGET_LINK_LIBRARIES(acngtool supacng ${BaseNetworkLibs} ${CompLibs} ${SSL_LIB_LIST} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBS_ACNGTOOL}) INSTALL(TARGETS acngtool DESTINATION ${LIBDIR}) diff -Nru apt-cacher-ng-0.9.1/source/conn.cc apt-cacher-ng-3.3.1/source/conn.cc --- apt-cacher-ng-0.9.1/source/conn.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/conn.cc 2020-01-08 19:58:26.000000000 +0000 @@ -10,6 +10,7 @@ #include "acbuf.h" #include "tcpconnect.h" #include "cleaner.h" +#include "conserver.h" #include #include @@ -19,52 +20,42 @@ using namespace std; +#define SHORT_TIMEOUT 4 -con::con(int fdId, const char *c) : - m_confd(fdId), - m_bStopActivity(false), - m_dlerthr(0), - m_pDlClient(nullptr), - m_pTmpHead(nullptr) +namespace acng +{ + +conn::conn(unique_fd fd, const char *c) : + m_fd(move(fd)), + m_confd(m_fd.get()) { if(c) // if nullptr, pick up later when sent by the wrapper m_sClientHost=c; - LOGSTART2("con::con", "fd: " << fdId << ", clienthost: " << c); + LOGSTART2("con::con", "fd: " << m_confd << ", clienthost: " << c); #ifdef DEBUG - m_nProcessedJobs=0; + m_nProcessedJobs=0; #endif }; -con::~con() { +conn::~conn() { LOGSTART("con::~con (Destroying connection...)"); - termsocket(m_confd); // our user's connection is released but the downloader task created here may still be serving others // tell it to stop when it gets the chance and delete it then - std::list::iterator jit; - for (jit=m_jobs2send.begin(); jit!=m_jobs2send.end(); jit++) - delete *jit; - - logstuff.write(); - - if(m_pDlClient) - { - m_pDlClient->SignalStop(); - pthread_join(m_dlerthr, nullptr); - - delete m_pDlClient; - m_pDlClient=nullptr; - } - if(m_pTmpHead) - { - delete m_pTmpHead; - m_pTmpHead=nullptr; - } - aclog::flush(); + for (auto jit : m_jobs2send) delete jit; + + writeAnotherLogRecord(sEmptyString, sEmptyString); + + if(m_pDlClient) + m_pDlClient->SignalStop(); + if(m_dlerthr.joinable()) + m_dlerthr.join(); + log::flush(); + conserver::FinishConnection(m_confd); } namespace RawPassThrough @@ -101,32 +92,32 @@ tHttpUrl url; if (!url.SetHttpUrl(uri)) return; - auto proxy = acfg::GetProxyInfo(); + auto proxy = cfg::GetProxyInfo(); if (!proxy) { direct_connect: m_spOutCon = g_tcp_con_factory.CreateConnected(url.sHost, url.GetPort(), sErr, 0, 0, - false, acfg::nettimeout, true); + false, cfg::nettimeout, true); } else { // switch to HTTPS tunnel in order to get a direct connection through the proxy m_spOutCon = g_tcp_con_factory.CreateConnected(proxy->sHost, proxy->GetPort(), - sErr, 0, 0, false, acfg::optproxytimeout > 0 ? - acfg::optproxytimeout : acfg::nettimeout, + sErr, 0, 0, false, cfg::optproxytimeout > 0 ? + cfg::optproxytimeout : cfg::nettimeout, true); if (m_spOutCon) { if (!m_spOutCon->StartTunnel(tHttpUrl(url.sHost, url.GetPort(), - true), sErr, & proxy->sUserPass, false)) + true), sErr, & proxy->sUserPass, false)) { m_spOutCon.reset(); } } - else if(acfg::optproxytimeout > 0) // ok... try without + else if(cfg::optproxytimeout > 0) // ok... try without { - acfg::MarkProxyFailure(); + cfg::MarkProxyFailure(); goto direct_connect; } } @@ -193,82 +184,87 @@ } } -void con::WorkLoop() { +void conn::WorkLoop() { LOGSTART("con::WorkLoop"); - + signal(SIGPIPE, SIG_IGN); - - acbuf inBuf; - inBuf.setsize(32*1024); - - int maxfd=m_confd; - while(!m_bStopActivity) { - fd_set rfds, wfds; - FD_ZERO(&wfds); - FD_ZERO(&rfds); - - FD_SET(m_confd, &rfds); - if(inBuf.freecapa()==0) - return; // shouldn't even get here - - job *pjSender(nullptr); - - if ( !m_jobs2send.empty()) + + acbuf inBuf; + inBuf.setsize(32*1024); + + // define a much shorter timeout than network timeout in order to be able to disconnect bad clients quickly + auto client_timeout(GetTime() + cfg::nettimeout); + + int maxfd=m_confd; + while(!g_global_shutdown && !m_badState) { + fd_set rfds, wfds; + FD_ZERO(&wfds); + FD_ZERO(&rfds); + + FD_SET(m_confd, &rfds); + if(inBuf.freecapa()==0) + return; // shouldn't even get here + + job *pjSender(nullptr); + bool hasMoreJobs = m_jobs2send.size()>1; + + if ( !m_jobs2send.empty()) { pjSender=m_jobs2send.front(); FD_SET(m_confd, &wfds); } - - - ldbg("select con"); - - struct timeval tv; - tv.tv_sec = acfg::nettimeout; - tv.tv_usec = 23; - int ready = select(maxfd+1, &rfds, &wfds, nullptr, &tv); - - if(ready == 0) - { - USRDBG("Timeout occurred, apt client disappeared silently?"); - return; - } + + ldbg("select con"); + int ready = select(maxfd+1, &rfds, &wfds, nullptr, CTimeVal().For(SHORT_TIMEOUT)); + + if(g_global_shutdown) + break; + + if(ready == 0) + { + USRDBG("Timeout occurred, apt client disappeared silently?"); + if(GetTime() > client_timeout) + return; // yeah, time to leave + continue; + } else if (ready<0) { if (EINTR == errno) continue; - + ldbg("select error in con, errno: " << errno); return; // FIXME: good error message? } - - ldbg("select con back"); + else + { + // ok, something is still flowing, increase deadline + client_timeout = GetTime() + cfg::nettimeout; + } + + ldbg("select con back"); + + if(FD_ISSET(m_confd, &rfds)) { + int n=inBuf.sysread(m_confd); + ldbg("got data: " << n <<", inbuf size: "<< inBuf.size()); + if(n<=0) // error, incoming junk overflow or closed connection + { + if(n==-EAGAIN) + continue; + else + { + ldbg("client closed connection"); + return; + } + } + } - if(FD_ISSET(m_confd, &rfds)) { - int n=inBuf.sysread(m_confd); - ldbg("got data: " << n <<", inbuf size: "<< inBuf.size()); - if(n<=0) // error, incoming junk overflow or closed connection - { - if(n==-EAGAIN) - continue; - else - { - ldbg("client closed connection"); - return; - } - } - } - - // split new data into requests - while(inBuf.size()>0) { - MYTRY - { - if(!m_pTmpHead) - m_pTmpHead = new header(); - if(!m_pTmpHead) - return; // no resources? whatever - - int nHeadBytes=m_pTmpHead->LoadFromBuf(inBuf.rptr(), inBuf.size()); + // split new data into requests + while(inBuf.size()>0) { + try + { + header h; + int nHeadBytes=h.Load(inBuf.rptr(), inBuf.size()); ldbg("header parsed how? " << nHeadBytes); if(nHeadBytes == 0) { // Either not enough data received, or buffer full; make space and retry @@ -282,13 +278,13 @@ } // also must be identified before - if (m_pTmpHead->type == header::POST) + if (h.type == header::POST) { - if (acfg::forwardsoap && !m_sClientHost.empty()) + if (cfg::forwardsoap && !m_sClientHost.empty()) { - if (RawPassThrough::CheckListbugs(*m_pTmpHead)) + if (RawPassThrough::CheckListbugs(h)) { - tSplitWalk iter(&m_pTmpHead->frontLine); + tSplitWalk iter(&h.frontLine); if(iter.Next() && iter.Next()) RawPassThrough::RedirectBto2https(m_confd, iter); } @@ -303,16 +299,16 @@ return; } - if(m_pTmpHead->type == header::CONNECT) + if(h.type == header::CONNECT) { inBuf.drop(nHeadBytes); - tSplitWalk iter(&m_pTmpHead->frontLine); + tSplitWalk iter(& h.frontLine); if(iter.Next() && iter.Next()) { cmstring tgt(iter); - if(rechecks::Match(tgt, rechecks::PASSTHROUGH)) + if(rex::Match(tgt, rex::PASSTHROUGH)) RawPassThrough::PassThrough(inBuf, m_confd, tgt); else { @@ -324,27 +320,30 @@ } return; } - + if (m_sClientHost.empty()) // may come from wrapper... MUST identify itself { inBuf.drop(nHeadBytes); - if(m_pTmpHead->h[header::XORIG] && *(m_pTmpHead->h[header::XORIG])) + if(h.h[header::XORIG] && * h.h[header::XORIG]) { - m_sClientHost=m_pTmpHead->h[header::XORIG]; + m_sClientHost=h.h[header::XORIG]; continue; // OK } else return; } - ldbg("Parsed REQUEST:" << m_pTmpHead->frontLine); + ldbg("Parsed REQUEST:" << h.frontLine); ldbg("Rest: " << (inBuf.size()-nHeadBytes)); { - job * j = new job(m_pTmpHead, this); + job * j = new job(std::move(h), this); j->PrepareDownload(inBuf.rptr()); + + if(m_badState) return; + inBuf.drop(nHeadBytes); m_jobs2send.emplace_back(j); @@ -352,59 +351,54 @@ m_nProcessedJobs++; #endif } - - m_pTmpHead=nullptr; // owned by job now } - MYCATCH(bad_alloc&) - { - return; - } - } - - if(inBuf.freecapa()==0) - return; // cannot happen unless being attacked + catch(bad_alloc&) + { + return; + } + } + + if(inBuf.freecapa()==0) + return; // cannot happen unless being attacked if(FD_ISSET(m_confd, &wfds) && pjSender) { - switch(pjSender->SendData(m_confd)) + switch(pjSender->SendData(m_confd, hasMoreJobs)) { - case(job::R_DISCON): + case(job::R_DISCON): { ldbg("Disconnect advise received, stopping connection"); return; } - case(job::R_DONE): + case(job::R_DONE): { - m_jobs2send.pop_front(); + m_jobs2send.pop_front(); delete pjSender; pjSender=nullptr; - + ldbg("Remaining jobs to send: " << m_jobs2send.size()); break; } - case(job::R_AGAIN): - break; - default: - break; + case(job::R_AGAIN): + break; + default: + break; } - } + } } } -void * _StartDownloader(void *pVoidDler) +bool conn::SetupDownloader(const char *pszOrigin) { - static_cast(pVoidDler) -> WorkLoop(); - return nullptr; -} + if(m_badState) + return false; -bool con::SetupDownloader(const char *pszOrigin) -{ if (m_pDlClient) return true; - MYTRY + try { - if(acfg::exporigin) + if(cfg::exporigin) { string sXff; if(pszOrigin) @@ -413,44 +407,33 @@ sXff += ", "; } sXff+=m_sClientHost; - m_pDlClient=new dlcon(false, &sXff); + m_pDlClient.reset(new dlcon(false, &sXff)); } else - m_pDlClient=new dlcon(false); - + m_pDlClient.reset(new dlcon(false)); + if(!m_pDlClient) return false; + auto pin = m_pDlClient; + m_dlerthr = move(thread([pin](){ + pin->WorkLoop(); + })); + m_badState = false; + return true; } - MYCATCH(bad_alloc&) + catch(...) { + m_badState = true; + m_pDlClient.reset(); return false; } - - if (0==pthread_create(&m_dlerthr, nullptr, _StartDownloader, - (void *)m_pDlClient)) - { - return true; - } - delete m_pDlClient; - m_pDlClient=nullptr; - return false; } -void con::__tlogstuff::write() +void conn::LogDataCounts(cmstring & sFile, const char *xff, off_t nNewIn, + off_t nNewOut, bool bAsError) { - if (sumIn>0) - aclog::transfer('I', sumIn, client.c_str(), file.c_str()); - - if(sumOut>0) - aclog::transfer(bFileIsError ? 'E' : 'O', sumOut, client.c_str(), file.c_str()); -} - -void con::LogDataCounts(const std::string & sFile, const char *xff, off_t nNewIn, - off_t nNewOut, bool bFileIsError) -{ - LOGSTART("con::LogDataCounts"); string sClient; - if (!acfg::logxff || !xff) // not to be logged or not available + if (!cfg::logxff || !xff) // not to be logged or not available sClient=m_sClientHost; else if (xff) { @@ -460,22 +443,21 @@ if (pos!=stmiss) sClient.erase(0, pos+1); } - if(sFile != logstuff.file || sClient != logstuff.client) - { - logstuff.write(); - logstuff.reset(sFile, sClient, bFileIsError); - } - LOG("heh? state now: " << logstuff.sumIn << " " << logstuff.sumOut); - logstuff.sumIn+=nNewIn; - logstuff.sumOut+=nNewOut; - + if(sFile != logFile || sClient != logClient) + writeAnotherLogRecord(sFile, sClient); + fileTransferIn += nNewIn; + fileTransferOut += nNewOut; + if(bAsError) m_bLogAsError = true; } -void con::__tlogstuff::reset(const std::string &pNewFile, const std::string &pNewClient, bool bIsError) +// sends the stats to logging and replaces file/client identities with the new context +void conn::writeAnotherLogRecord(const mstring &pNewFile, const mstring &pNewClient) { - bFileIsError=bIsError; - file=pNewFile; - client=pNewClient; - sumIn=0; - sumOut=0; + log::transfer(fileTransferIn, fileTransferOut, logClient, logFile, m_bLogAsError); + fileTransferIn = fileTransferOut = 0; + m_bLogAsError = false; + logFile = pNewFile; + logClient = pNewClient; +} + } diff -Nru apt-cacher-ng-0.9.1/source/conserver.cc apt-cacher-ng-3.3.1/source/conserver.cc --- apt-cacher-ng-0.9.1/source/conserver.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/conserver.cc 2020-01-08 19:58:26.000000000 +0000 @@ -1,22 +1,24 @@ +#include #include "conserver.h" #include "meta.h" #include "lockable.h" #include "conn.h" -#include "rfc2553emu.h" #include "acfg.h" - +#include "caddrinfo.h" #include "sockio.h" #include "fileio.h" +#include "evabase.h" +#include "evasocket.h" +#include "dnsiter.h" #include #include #include - #include #include -#include #include +#include #include #include // std::min_element, std::max_element @@ -28,6 +30,8 @@ #include #endif +#include + #include "debug.h" using namespace std; @@ -37,316 +41,373 @@ #define AF_INET6 23 /* IP version 6 */ #endif +namespace acng +{ + namespace conserver { int yes(1); +vector > g_vecSocks; + +base_with_condition g_thread_push_cond_var; +deque> g_freshConQueue; +unsigned g_nStandbyThreads = 0, g_nTotalThreads=0; -int g_sockunix(-1); -vector g_vecSocks; +bool g_suspended = false; // temporary suspended operation +SHARED_PTR g_resumer; -condition g_ThreadPoolCondition; -list g_freshConQueue; -int g_nStandbyThreads(0); -int g_nAllConThreadCount(0); -bool bTerminationMode(false); +void SetupConAndGo(unique_fd fd, const char *szClientName); +void do_resume(); // safety mechanism, detect when the number of incoming connections // is growing A LOT faster than it can be processed #define MAX_BACKLOG 200 -void * ThreadAction(void *) +void do_accept(const std::shared_ptr& soc) { - lockguard g(g_ThreadPoolCondition); - list & Qu = g_freshConQueue; + LOGSTART2s("do_accept", soc->fd()); + + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + + int fd = -1; + while(true) + { + fd = accept(soc->fd(), (struct sockaddr*) &addr, &addrlen); + + if (fd != -1) + break; + + switch (errno) + { + case EAGAIN: + case EINTR: + continue; + case EMFILE: + case ENFILE: + case ENOBUFS: + case ENOMEM: + // resource exhaustion, might recover when another connection handler has stopped, disconnect this one for now + conserver::HandleOverload(); + return; + default: + return; + } + } + + unique_fd man_fd(fd); + + evutil_make_socket_nonblocking(fd); + if (addr.ss_family == AF_UNIX) + { + USRDBG("Detected incoming connection from the UNIX socket"); + SetupConAndGo(move(man_fd), nullptr); + } + else + { + USRDBG("Detected incoming connection from the TCP socket"); + char hbuf[NI_MAXHOST]; + if (getnameinfo((struct sockaddr*) &addr, addrlen, hbuf, sizeof(hbuf), + nullptr, 0, NI_NUMERICHOST)) + { + log::err("ERROR: could not resolve hostname for incoming TCP host"); + return; + } + + if (cfg::usewrap) + { +#ifdef HAVE_LIBWRAP + // libwrap is non-reentrant stuff, call it from here only + request_info req; + request_init(&req, RQ_DAEMON, "apt-cacher-ng", RQ_FILE, fd, 0); + fromhost(&req); + if (!hosts_access(&req)) + { + log::err("ERROR: access not permitted by hosts files", hbuf); + return; + } +#else + log::err( + "WARNING: attempted to use libwrap which was not enabled at build time"); +#endif + } + SetupConAndGo(move(man_fd), hbuf); + } +} + + +auto ThreadAction = []() +{ + lockuniq g(g_thread_push_cond_var); while (true) { - while (Qu.empty() && !bTerminationMode) - g_ThreadPoolCondition.wait(); + while (g_freshConQueue.empty() && !g_global_shutdown) + g_thread_push_cond_var.wait(g); - if (bTerminationMode) + if (g_global_shutdown) break; - con *c=Qu.front(); - Qu.pop_front(); + auto c = move(g_freshConQueue.front()); + g_freshConQueue.pop_front(); g_nStandbyThreads--; + g.unLock(); - c->WorkLoop(); - delete c; - + c.reset(); g.reLock(); + g_nStandbyThreads++; - if (g_nStandbyThreads >= acfg::tpstandbymax) + if (int(g_nStandbyThreads) >= cfg::tpstandbymax || g_global_shutdown) break; } - - g_nAllConThreadCount--; - g_nStandbyThreads--; - - return nullptr; -} - -bool CreateDetachedThread(void *(*__start_routine)(void *)) -{ - pthread_t thr; - pthread_attr_t attr; // be detached from the beginning - if (pthread_attr_init(&attr)) - return false; - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - bool bOK = (0 == pthread_create(&thr, &attr, __start_routine, nullptr)); - pthread_attr_destroy(&attr); - return bOK; -} + // remove from global pool + g_nStandbyThreads--; + g_nTotalThreads--; + g_thread_push_cond_var.notifyAll(); +}; //! pushes waiting thread(s) and create threads for each waiting task if needed -inline bool SpawnThreadsAsNeeded() +auto SpawnThreadsAsNeeded = []() { - lockguard g(g_ThreadPoolCondition); - list & Qu = g_freshConQueue; - // check the kill-switch - if(g_nAllConThreadCount+1>=acfg::tpthreadmax || bTerminationMode) + if(int(g_nTotalThreads+1)>=cfg::tpthreadmax || g_global_shutdown) return false; - int nNeeded = Qu.size()-g_nStandbyThreads; - - while (nNeeded-- > 0) - { - if (!CreateDetachedThread(ThreadAction)) - return false; - g_nStandbyThreads++; - g_nAllConThreadCount++; - } - - g_ThreadPoolCondition.notifyAll(); - - return true; -} - + // need a custom one + if(g_nStandbyThreads == 0) + { + try + { + thread thr(ThreadAction); + // if thread was started w/o exception it will decrement those in the end + g_nStandbyThreads++; + g_nTotalThreads++; + thr.detach(); + } + catch(...) + { + return false; + } + } + g_thread_push_cond_var.notifyAll(); + return true; + }; -void SetupConAndGo(int fd, const char *szClientName=nullptr) +void SetupConAndGo(unique_fd man_fd, const char *szClientName) { - LOGSTART2s("SetupConAndGo", fd); + LOGSTART2s("SetupConAndGo", man_fd.get()); - if(!szClientName) - szClientName=""; - - USRDBG( "Client name: " << szClientName); - con *c(nullptr); - - { - // thread pool control, and also see Shutdown(), protect from - // interference of OS on file descriptor management - lockguard g(g_ThreadPoolCondition); + if (!szClientName) + szClientName = ""; - // DOS prevention - if (g_freshConQueue.size() > MAX_BACKLOG) - { - USRDBG( "Worker queue overrun"); - goto local_con_failure; - } - try - { - c = new con(fd, szClientName); - if (!c) - { -#ifdef NO_EXCEPTIONS - USRDBG( "Out of memory"); -#endif - goto local_con_failure; - } + USRDBG("Client name: " << szClientName); - g_freshConQueue.emplace_back(c); - LOG("Connection to backlog, total count: " << g_freshConQueue.size()); + lockguard g(g_thread_push_cond_var); + // DOS prevention + if (g_freshConQueue.size() > MAX_BACKLOG) + { + USRDBG("Worker queue overrun"); + return; + } - } catch (std::bad_alloc&) - { - USRDBG( "Out of memory"); - goto local_con_failure; - } + try + { + g_freshConQueue.emplace_back(make_unique(move(man_fd), szClientName)); + LOG("Connection to backlog, total count: " << g_freshConQueue.size()); } - + catch (const std::bad_alloc&) + { + USRDBG("Out of memory"); + return; + } + if (!SpawnThreadsAsNeeded()) { - tErrnoFmter fer("Cannot start threads, cleaning up. Reason: "); + tErrnoFmter fer( + "Cannot start threads, cleaning up, aborting all incoming connections. Reason: "); USRDBG(fer); - lockguard g(g_ThreadPoolCondition); - while(!g_freshConQueue.empty()) - { - delete g_freshConQueue.back(); - g_freshConQueue.pop_back(); - } + g_freshConQueue.clear(); } +} + +bool bind_and_listen(shared_ptr mSock, const evutil_addrinfo *pAddrInfo) + { + LOGSTART2s("bind_and_listen", formatIpPort(pAddrInfo)); + if ( ::bind(mSock->fd(), pAddrInfo->ai_addr, pAddrInfo->ai_addrlen)) + { + log::flush(); + perror("Couldn't bind socket"); + cerr.flush(); + if(EADDRINUSE == errno) + { + if(pAddrInfo->ai_family == PF_UNIX) + cerr << "Error creating or binding the UNIX domain socket - please check permissions!" <fd(), SO_MAXCONN)) + { + perror("Couldn't listen on socket"); + return false; + } - return; + g_vecSocks.emplace_back( + make_shared(evabase::instance, + mSock, + EV_READ | EV_PERSIST, + [](const std::shared_ptr& sock, short) {do_accept(sock);}) + ); + // and activate it once + g_vecSocks.back()->enable(); + return true; + }; - local_con_failure: - if (c) - delete c; - USRDBG( "Connection setup error"); - termsocket_quick(fd); -} +std::string scratchBuf; -void CreateUnixSocket() { - string & sPath=acfg::fifopath; - auto addr_unx = sockaddr_un(); - - size_t size = sPath.length()+1+offsetof(struct sockaddr_un, sun_path); - - auto die=[]() { - cerr << "Error creating Unix Domain Socket, "; - cerr.flush(); - perror(acfg::fifopath.c_str()); - cerr << "Check socket file and directory permissions" <sizeof(addr_unx.sun_path)) + CAddrInfo resolver; + auto hints = evutil_addrinfo(); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF_UNSPEC; + bool ignored; + if(!resolver.ResolveTcpTarget(addi ? addi : sEmptyString, port, scratchBuf, &hints, ignored)) { - errno=ENAMETOOLONG; - die(); + log::flush(); + perror("Error resolving address for binding"); + return 0; } - - addr_unx.sun_family = AF_UNIX; - strncpy(addr_unx.sun_path, sPath.c_str(), sPath.length()); - - mkbasedir(sPath); - unlink(sPath.c_str()); - - g_sockunix = socket(PF_UNIX, SOCK_STREAM, 0); - setsockopt(g_sockunix, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); - if (g_sockunix<0) - die(); - - if (::bind(g_sockunix, (struct sockaddr *)&addr_unx, size) < 0) - die(); - - if (0==listen(g_sockunix, SO_MAXCONN)) - g_vecSocks.emplace_back(g_sockunix); -} + std::unordered_set dedup; + tDnsIterator iter(PF_UNSPEC, resolver.getTcpAddrInfo()); + unsigned res(0); + for(const evutil_addrinfo *p; !!(p=iter.next());) + { + // no fit or or seen before? + if(!dedup.emplace((const char*) p->ai_addr, p->ai_addrlen).second) + continue; + int nSockFd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (nSockFd == -1) + { + // STFU on lag of IPv6? + switch(errno) + { + case EAFNOSUPPORT: + case EPFNOSUPPORT: + case ESOCKTNOSUPPORT: + case EPROTONOSUPPORT: + continue; + default: + perror("Error creating socket"); + continue; + } + } + auto mSock = evasocket::create(nSockFd); + // if we have a dual-stack IP implementation (like on Linux) then + // explicitly disable the shadow v4 listener. Otherwise it might be + // bound or maybe not, and then just sometimes because of configurable + // dual-behavior, or maybe because of real errors; + // we just cannot know for sure but we need to. +#if defined(IPV6_V6ONLY) && defined(SOL_IPV6) + if(p->ai_family==AF_INET6) + setsockopt(mSock->fd(), SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)); +#endif + setsockopt(mSock->fd(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + res += bind_and_listen(mSock, p); + } + return res; +}; -void Setup() +int ACNG_API Setup() { LOGSTART2s("Setup", 0); - using namespace acfg; - if (fifopath.empty() && port.empty()) + if (cfg::udspath.empty() && cfg::port.empty()) { cerr << "Neither TCP nor UNIX interface configured, cannot proceed.\n"; exit(EXIT_FAILURE); } - - if (atoi(port.c_str())>0) - { - auto hints = addrinfo(); - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - hints.ai_family = 0; - - auto conaddr = [hints](LPCSTR addi) - { - LOGSTART2s("Setup::ConAddr", 0); - struct addrinfo *res, *p; - if(0!=getaddrinfo(addi, port.c_str(), &hints, &res)) - { - perror("Error resolving address for binding"); - return; - } - - for(p=res; p; p=p->ai_next) - { - int nSockFd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (nSockFd<0) - goto error_socket; - - // if we have a dual-stack IP implementation (like on Linux) then - // explicitly disable the shadow v4 listener. Otherwise it might be - // bound or maybe not, and then just sometimes because of configurable - // dual-behavior, or maybe because of real errors; - // we just cannot know for sure but we need to. -#if defined(IPV6_V6ONLY) && defined(SOL_IPV6) - if(p->ai_family==AF_INET6) - setsockopt(nSockFd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)); -#endif - setsockopt(nSockFd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); - - if (::bind(nSockFd, p->ai_addr, p->ai_addrlen)) - goto error_bind; - if (listen(nSockFd, SO_MAXCONN)) - goto error_listen; - - USRDBG( "created socket, fd: " << nSockFd);// << ", for bindaddr: "<(evabase::instance, evasocket::create(-1), 0, + [](const std::shared_ptr&, short) + { do_resume();}); + } + unsigned nCreated = 0; - error_listen: - perror("Couldn't listen on socket"); - goto close_socket; + if (cfg::udspath.empty()) + log::err("Not creating Unix Domain Socket, fifo_path not specified"); + else + { + string & sPath = cfg::udspath; + auto addr_unx = sockaddr_un(); - error_bind: - perror("Couldn't bind socket"); - cerr.flush(); - if(EADDRINUSE == errno) - cerr << "Port " << port << " is busy, see the manual (Troubleshooting chapter) for details." < sizeof(addr_unx.sun_path)) { - do - { - conaddr(sp.str().c_str()); - } - while(sp.Next()); + errno = ENAMETOOLONG; + die(); } - else - conaddr(nullptr); - if(g_vecSocks.empty()) - { - cerr << "No socket(s) could be created/prepared. " - "Check the network, check or unset the BindAddress directive.\n"; - exit(EXIT_FAILURE); - } + addr_unx.sun_family = AF_UNIX; + strncpy(addr_unx.sun_path, sPath.c_str(), sPath.length()); + + mkbasedir(sPath); + unlink(sPath.c_str()); + + auto sockFd = socket(PF_UNIX, SOCK_STREAM, 0); + if(sockFd < 0) die(); + + evutil_addrinfo ai; + ai.ai_addr =(struct sockaddr *) &addr_unx; + ai.ai_addrlen = size; + ai.ai_family = PF_UNIX; + + nCreated += bind_and_listen(evasocket::create(sockFd), &ai); } - else - aclog::err("Not creating TCP listening socket, no valid port specified!"); - if ( !acfg::fifopath.empty() ) - CreateUnixSocket(); + if (atoi(cfg::port.c_str()) <= 0) + log::err("Not creating TCP listening socket, no valid port specified!"); else - aclog::err("Not creating Unix Domain Socket, fifo_path not specified"); + { + bool custom_listen_ip = false; + for(const auto& sp: tSplitWalk(&cfg::bindaddr)) + { + nCreated += setup_tcp_listeners(sp.c_str(), cfg::port); + custom_listen_ip = true; + } + // just TCP_ANY if none was specified + if(!custom_listen_ip) + nCreated += setup_tcp_listeners(nullptr, cfg::port); + } + return nCreated; } -int Run() +int ACNG_API Run() { LOGSTART2s("Run", "GoGoGo"); @@ -354,119 +415,63 @@ sd_notify(0, "READY=1"); #endif - fd_set rfds, wfds; - int maxfd = 1 + *max_element(g_vecSocks.begin(), g_vecSocks.end()); - USRDBG( "Listening to incoming connections..."); - - while (1) - { // main accept() loop - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - for(auto soc: g_vecSocks) FD_SET(soc, &rfds); - - //cerr << "Polling..." <base, EVLOOP_NO_EXIT_ON_EMPTY); +} - if(g_sockunix == soc) - { - int fd = accept(g_sockunix, nullptr, nullptr); - if (fd>=0) - { - set_nb(fd); - USRDBG( "Detected incoming connection from the UNIX socket"); - SetupConAndGo(fd); - } - else if(errno == EMFILE || errno == ENOMEM || ENOBUFS == errno) - { - // play nicely, give it a break - sleep(1); - } - } - else - { - struct sockaddr_storage addr; +void Shutdown() +{ + DBGQLOG("Closing listening sockets\n"); + // terminate activities + g_vecSocks.clear(); + g_resumer.reset(); - socklen_t addrlen = sizeof(addr); - int fd=accept(soc,(struct sockaddr *)&addr, &addrlen); -//fd_accepted: - if (fd>=0) - { - set_nb(fd); - char hbuf[NI_MAXHOST]; - USRDBG( "Detected incoming connection from the TCP socket"); - - if (getnameinfo((struct sockaddr*) &addr, addrlen, hbuf, sizeof(hbuf), - nullptr, 0, NI_NUMERICHOST)) - { - aclog::err("ERROR: could not resolve hostname for incoming TCP host"); - termsocket_quick(fd); - sleep(1); - continue; - } + { + lockuniq g(g_thread_push_cond_var); + // global hint to all conn objects + g_global_shutdown = true; + DBGQLOG("Notifying worker threads\n"); + g_thread_push_cond_var.notifyAll(); + while(g_nTotalThreads) + g_thread_push_cond_var.wait(g); + } +} - if (acfg::usewrap) - { -#ifdef HAVE_LIBWRAP - // libwrap is non-reentrant stuff, call it from here only - request_info req; - request_init(&req, RQ_DAEMON, "apt-cacher-ng", RQ_FILE, fd, 0); - fromhost(&req); - if (!hosts_access(&req)) - { - aclog::err("ERROR: access not permitted by hosts files", hbuf); - termsocket_quick(fd); - continue; - } -#else - aclog::err("WARNING: attempted to use libwrap which was not enabled at build time"); -#endif - } +const struct timeval g_resumeTimeout { 2, 11 }; - SetupConAndGo(fd, hbuf); - } - else if(errno == EMFILE || errno == ENOMEM || ENOBUFS == errno) - { - // play nicely, give it a break - sleep(1); - } - } - } +void HandleOverload() +{ + lockguard g(g_thread_push_cond_var); + g_suspended = true; + for(auto& it: g_vecSocks) + { + it->disable(); } - return 0; + g_resumer->enable(&g_resumeTimeout); } -void Shutdown() +void do_resume() { - lockguard g(g_ThreadPoolCondition); - - if(bTerminationMode) - return; // double SIGWHATEVER? Prevent it. - - //for (map::iterator it=mConStatus.begin(); it !=mConStatus.end(); it++) - // it->first->SignalStop(); - // TODO: maybe call shutdown on all? - //printf("Signaled stop to all cons\n"); - - bTerminationMode=true; - printf("Notifying waiting threads\n"); - g_ThreadPoolCondition.notifyAll(); - - printf("Closing listening sockets\n"); - for(auto soc: g_vecSocks) termsocket_quick(soc); + lockguard g(g_thread_push_cond_var); + if(!g_suspended) return; + if(!g_resumer) return; // already in shutdown phase + g_resumer->disable(); + for(auto& it: g_vecSocks) + { + it->enable(); + } + g_suspended = false; +} + +void FinishConnection(int fd) +{ + if(fd == -1) + return; + + termsocket_async(fd, evabase::instance->base); + // there is a good chance that more resources are available now + do_resume(); +} + } } diff -Nru apt-cacher-ng-0.9.1/source/dirwalk.cc apt-cacher-ng-3.3.1/source/dirwalk.cc --- apt-cacher-ng-0.9.1/source/dirwalk.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/dirwalk.cc 2020-01-08 19:58:26.000000000 +0000 @@ -11,7 +11,11 @@ #include "dirwalk.h" using namespace std; -namespace acfg + +namespace acng +{ + +namespace cfg { extern int stupidfs; } @@ -53,12 +57,12 @@ if(r) { /* errnoFmter f; - aclog::err(tSS() << sPath << + log::err(tSS() << sPath << " IO error [" << f<<"]"); */ return true; // slight risk of missing information here... bug ignoring is safer } - // dangling symlink? + // yeah, and we ignore symlinks here if(S_ISLNK(m_stinfo.st_mode)) return true; } @@ -110,7 +114,7 @@ if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) { childbuf.sPath=sPath+sPathSepUnix; - if(acfg::stupidfs) + if(cfg::stupidfs) UrlUnescapeAppend(dp->d_name, childbuf.sPath); else childbuf.sPath+=dp->d_name; @@ -131,7 +135,7 @@ -bool DirectoryWalk(const string & sRoot, IFileHandler *h, bool bFilterDoubleDirVisit, +bool IFileHandler::DirectoryWalk(const string & sRoot, IFileHandler *h, bool bFilterDoubleDirVisit, bool bFollowSymlinks) { dnode root(nullptr); @@ -140,3 +144,20 @@ return root.Walk(h, bFilterDoubleDirVisit ? &filter : nullptr, bFollowSymlinks); } +// XXX: create some shortcut? wasting CPU cycles for virtual call PLUS std::function wrapper +bool IFileHandler::FindFiles(const mstring & sRootDir, IFileHandler::output_receiver callBack, bool bFilterDoubleDirVisit, + bool bFollowSymlinks) +{ + struct tFileGrabber : public IFileHandler + { + IFileHandler::output_receiver &m_cb; + bool ProcessRegular(cmstring &sPath, const struct stat &st) override { return m_cb(sPath, st);} + bool ProcessOthers(cmstring &sPath, const struct stat &) override {return true;}; + bool ProcessDirAfter(cmstring &sPath, const struct stat &) override {return true;}; + tFileGrabber(IFileHandler::output_receiver &ret) : m_cb(ret) {} + } cb(callBack); + return DirectoryWalk(sRootDir, &cb, bFilterDoubleDirVisit, bFollowSymlinks); +} + + +} diff -Nru apt-cacher-ng-0.9.1/source/dlcon.cc apt-cacher-ng-3.3.1/source/dlcon.cc --- apt-cacher-ng-0.9.1/source/dlcon.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/dlcon.cc 2020-01-08 19:58:26.000000000 +0000 @@ -2,6 +2,7 @@ #include #include #include +#include #define LOCAL_DEBUG #include "debug.h" @@ -13,6 +14,7 @@ #include "fileitem.h" #include "fileio.h" #include "sockio.h" +#include "evabase.h" #ifdef HAVE_LINUX_EVENTFD #include @@ -23,10 +25,21 @@ // evil hack to simulate random disconnects //#define DISCO_FAILURE -#define MAX_RETRY 11 +#define MAX_RETRY cfg::dlretriesmax + +namespace acng +{ static cmstring sGenericError("567 Unknown download error occured"); +// those are not allowed to be forwarded +static const auto taboo = +{ + string("Host"), string("Cache-Control"), + string("Proxy-Authorization"), string("Accept"), + string("User-Agent") +}; + std::atomic_uint g_nDlCons(0); dlcon::dlcon(bool bManualExecution, string *xff, IDlConFactory *pConFactory) : @@ -36,8 +49,10 @@ { LOGSTART("dlcon::dlcon"); #ifdef HAVE_LINUX_EVENTFD - m_wakeventfd=eventfd(0, 0); - if(m_wakeventfd>=0) + m_wakeventfd = eventfd(0, 0); + if(m_wakeventfd == -1) + m_bStopASAP = true; + else set_nb(m_wakeventfd); #else if (0 == pipe(m_wakepipe)) @@ -45,6 +60,11 @@ set_nb(m_wakepipe[0]); set_nb(m_wakepipe[1]); } + else + { + m_wakepipe[0] = m_wakepipe[1] = -1; + m_bStopASAP = true; + } #endif if (xff) m_sXForwardedFor = *xff; @@ -73,7 +93,7 @@ #define HINT_KILL_LAST_FILE 128 #define HINT_TGTCHANGE 256 - const acfg::tRepoData * m_pRepoDesc=nullptr; + const cfg::tRepoData * m_pRepoDesc=nullptr; /*! * Returns a reference to http url where host and port and protocol match the current host @@ -84,12 +104,12 @@ return m_pCurBackend ? *m_pCurBackend : m_remoteUri; } - inline acfg::tRepoData::IHookHandler * GetConnStateTracker() + inline cfg::tRepoData::IHookHandler * GetConnStateTracker() { return m_pRepoDesc ? m_pRepoDesc->m_pHooks : nullptr; } - typedef enum + typedef enum : char { STATE_GETHEADER, STATE_REGETHEADER, STATE_PROCESS_DATA, STATE_GETCHUNKHEAD, STATE_PROCESS_CHUNKDATA, STATE_GET_CHUNKTRAILER, @@ -112,7 +132,7 @@ inline tDlJob(dlcon *p, tFileItemPtr pFi, const tHttpUrl *pUri, - const acfg::tRepoData * pRepoData, + const cfg::tRepoData * pRepoData, const std::string *psPath, int redirmax) : m_pStorage(pFi), @@ -138,6 +158,7 @@ ~tDlJob() { + LOGSTART("tDlJob::~tDlJob"); if (m_pStorage) m_pStorage->DecDlRefCount(sErrorMsg.empty() ? sGenericError : sErrorMsg); } @@ -147,24 +168,19 @@ if(!reqHead) return; header h; - tLPS cheaders; - h.Load(reqHead, std::numeric_limits::max(), &cheaders); - if(cheaders.empty()) - return; - for(const auto& ch: cheaders) - { - // some headers are reserved (actually all starting with those prefixes - if(strncasecmp(ch.first.c_str(), WITHLEN("Host")) && - strncasecmp(ch.first.c_str(), WITHLEN("Proxy-Authorization")) && - strncasecmp(ch.first.c_str(), WITHLEN("Cache-Control")) && - strncasecmp(ch.first.c_str(), WITHLEN("Accept")) && - strncasecmp(ch.first.c_str(), WITHLEN("User-Agent")) - ) - { - m_extraHeaders += ch.first; - m_extraHeaders += ch.second; - } - } + bool forbidden=false; + h.Load(reqHead, (unsigned) std::numeric_limits::max(), + [this, &forbidden](cmstring& key, cmstring& rest) + { + // heh, continuation of ignored stuff or without start? + if(key.empty() && (m_extraHeaders.empty() || forbidden)) + return; + forbidden = taboo.end() != std::find_if(taboo.begin(), taboo.end(), + [&key](cmstring &x){return scaseequals(x,key);}); + if(!forbidden) + m_extraHeaders += key + rest; + } + ); } inline string RemoteUri(bool bUrlEncoded) @@ -298,7 +314,7 @@ ldbg(RemoteUri(true)); - head << " HTTP/1.1\r\n" << acfg::agentheader << "Host: " << GetPeerHost().sHost << "\r\n"; + head << " HTTP/1.1\r\n" << cfg::agentheader << "Host: " << GetPeerHost().sHost << "\r\n"; if (proxy) // proxy stuff, and add authorization if there is any { @@ -310,7 +326,7 @@ } // Proxy-Connection is a non-sensical copy of Connection but some proxy // might listen only to this one so better add it - head << (acfg::persistoutgoing ? "Proxy-Connection: keep-alive\r\n" + head << (cfg::persistoutgoing ? "Proxy-Connection: keep-alive\r\n" : "Proxy-Connection: close\r\n"); } @@ -336,12 +352,12 @@ { if (pHead.h[header::LAST_MODIFIED]) { - if (acfg::vrangeops > 0) + if (cfg::vrangeops > 0) { bSetIfRange = true; bSetRange = true; } - else if(acfg::vrangeops == 0) + else if(cfg::vrangeops == 0) { head << "If-Modified-Since: " << pHead.h[header::LAST_MODIFIED] << "\r\n"; } @@ -388,13 +404,15 @@ if (m_pStorage->m_bCheckFreshness) head << "Cache-Control: no-store,no-cache,max-age=0\r\n"; - if (acfg::exporigin && !xff.empty()) + if (cfg::exporigin && !xff.empty()) head << "X-Forwarded-For: " << xff << "\r\n"; - head << acfg::requestapx + head << cfg::requestapx << m_extraHeaders - << "Accept: */*\r\nAccept-Encoding: identity\r\nConnection: " - << (acfg::persistoutgoing ? "keep-alive\r\n\r\n" : "close\r\n\r\n"); + << "Accept: application/octet-stream\r\n" + "Accept-Encoding: identity\r\n" + "Connection: " + << (cfg::persistoutgoing ? "keep-alive\r\n\r\n" : "close\r\n\r\n"); #ifdef SPAM //head.syswrite(2); @@ -447,7 +465,7 @@ for (;;) // returned by explicit error (or get-more) return { - ldbg("switch: " << m_DlState); + ldbg("switch: " << (int)m_DlState); if (STATE_GETHEADER == m_DlState || STATE_REGETHEADER == m_DlState) { @@ -459,7 +477,12 @@ bool bHotItem = (m_DlState == STATE_REGETHEADER); dbgline; - auto hDataLen = h.LoadFromBuf(inBuf.rptr(), inBuf.size()); + auto hDataLen = h.Load(inBuf.rptr(), inBuf.size(), + [&h](cmstring& key, cmstring& rest) + { if(scaseequals(key, "Content-Location")) + h.frontLine = "HTTP/1.1 500 Apt-Cacher NG does not like that data"; + }); + if (0 == hDataLen) return HINT_MORE; if (hDataLen<0) @@ -471,7 +494,7 @@ } ldbg("contents: " << std::string(inBuf.rptr(), hDataLen)); - inBuf.drop(hDataLen); + inBuf.drop((unsigned long) hDataLen); if (h.type != header::ANSWER) { dbgline; @@ -483,7 +506,7 @@ int st = h.getStatus(); - if (acfg::redirmax) // internal redirection might be disabled + if (cfg::redirmax) // internal redirection might be disabled { if (IS_REDIRECT(st)) { @@ -534,7 +557,7 @@ m_DlState = STATE_FINISHJOB; } // the only case where we expect a 304 - else if(st == 304 && acfg::vrangeops == 0) + else if(st == 304 && cfg::vrangeops == 0) { m_pStorage->SetupComplete(); m_DlState = STATE_FINISHJOB; @@ -564,11 +587,11 @@ bool bDoRetry(false); // detect bad auto-redirectors (auth-pages, etc.) by the mime-type of their target - if(acfg::redirmax - && !acfg::badredmime.empty() - && acfg::redirmax != m_nRedirRemaining + if(cfg::redirmax + && !cfg::badredmime.empty() + && cfg::redirmax != m_nRedirRemaining && h.h[header::CONTENT_TYPE] - && strstr(h.h[header::CONTENT_TYPE], acfg::badredmime.c_str()) + && strstr(h.h[header::CONTENT_TYPE], cfg::badredmime.c_str()) && h.getStatus() < 300) // contains the final data/response { if(m_pStorage->m_bCheckFreshness) @@ -580,8 +603,9 @@ { // this was redirected and the destination is BAD! h.frontLine="HTTP/1.1 501 Redirected to invalid target"; - void DropDnsCache(); - DropDnsCache(); + // XXX: not sure this is the right attribution + //void DropDnsCache(); + //DropDnsCache(); } } @@ -684,20 +708,52 @@ tDlJob & operator=(const tDlJob&); }; -void dlcon::wake() +#ifdef HAVE_LINUX_EVENTFD +inline void dlcon::wake() { - if (fdWakeWrite<0) + LOGSTART("dlcon::wake"); + if(fdWakeWrite == -1) return; -#ifdef HAVE_LINUX_EVENTFD - while(eventfd_write(fdWakeWrite, 1)<0) ; + while(true) + { + auto r=eventfd_write(fdWakeWrite, 1); + if(r == 0 || (errno != EINTR && errno != EAGAIN)) + break; + } + +} + +void ACNG_API dlcon::awaken_check() +{ + eventfd_t xtmp; + for(int i=0; i < 1000 ; ++i) + { + auto tmp = eventfd_read(fdWakeRead, &xtmp); + if(tmp == 0) + return; + if(errno != EAGAIN) + return; + } +} + #else +void dlcon::wake() +{ + LOGSTART("dlcon::wake"); POKE(fdWakeWrite); -#endif } +inline void dlcon::awaken_check() +{ + LOGSTART("dlcon::awaken_check"); + for (char tmp; ::read(m_wakepipe[0], &tmp, 1) > 0;) ; +} + +#endif bool dlcon::AddJob(tFileItemPtr m_pItem, const tHttpUrl *pForcedUrl, - const acfg::tRepoData *pBackends, - cmstring *sPatSuffix, LPCSTR reqHead) + const cfg::tRepoData *pBackends, + cmstring *sPatSuffix, LPCSTR reqHead, + int nMaxRedirection) { if(!pForcedUrl) { @@ -707,6 +763,8 @@ return false; } setLockGuard; + if(m_bStopASAP || evabase::in_shutdown) + return false; /* ASSERT( todo->m_pStorage->m_nRangeLimit < 0 @@ -715,8 +773,7 @@ LOGSTART2("dlcon::EnqJob", todo->m_remoteUri.ToURI(false)); */ m_qNewjobs.emplace_back( - make_shared(this, m_pItem, pForcedUrl, pBackends, sPatSuffix, - m_bManualMode ? ACFG_REDIRMAX_DEFAULT : acfg::redirmax)); + make_shared(this, m_pItem, pForcedUrl, pBackends, sPatSuffix,nMaxRedirection)); m_qNewjobs.back()->ExtractCustomHeaders(reqHead); @@ -732,7 +789,6 @@ // stop all activity as soon as possible m_bStopASAP=true; m_qNewjobs.clear(); - wake(); } @@ -755,7 +811,6 @@ << m_sendBuf.size() << ", inbuf size: " << m_inBuf.size()); fd_set rfds, wfds; - struct timeval tv; int r = 0; int fd = con ? con->GetFD() : -1; FD_ZERO(&rfds); @@ -794,8 +849,6 @@ } ldbg("select dlcon"); - tv.tv_sec = acfg::nettimeout; - tv.tv_usec = 0; // jump right into data processing but only once if(bReEntered) @@ -804,10 +857,14 @@ goto proc_data; } - r=select(nMaxFd + 1, &rfds, &wfds, nullptr, &tv); + r=select(nMaxFd + 1, &rfds, &wfds, nullptr, CTimeVal().ForNetTimeout()); ldbg("returned: " << r << ", errno: " << errno); + if(m_bStopASAP || evabase::in_shutdown) + { + return HINT_DISCON; + } - if (r < 0) + if (r == -1) { if (EINTR == errno) continue; @@ -823,6 +880,8 @@ else if (r == 0) // looks like a timeout { sErrorMsg = "500 Connection timeout"; + LOG(sErrorMsg); + // was there anything to do at all? if(inpipe.empty()) return HINT_SWITCH; @@ -835,18 +894,7 @@ if (FD_ISSET(fdWakeRead, &rfds)) { - dbgline; -#ifdef HAVE_LINUX_EVENTFD - eventfd_t xtmp; - int tmp; - do { - tmp = eventfd_read(fdWakeRead, &xtmp); - } while (tmp < 0 && (errno == EINTR || errno == EAGAIN)); - -#else - for (int tmp; read(m_wakepipe[0], &tmp, 1) > 0;) - ; -#endif + awaken_check(); return HINT_SWITCH; } @@ -898,7 +946,7 @@ #endif )) { - if(acfg::maxdlspeed != RESERVED_DEFVAL) + if(cfg::maxdlspeed != cfg::RESERVED_DEFVAL) { auto nCntNew=g_nDlCons.load(); if(m_nLastDlCount != nCntNew) @@ -906,7 +954,7 @@ m_nLastDlCount=nCntNew; // well, split the bandwidth - auto nSpeedNowKib = uint(acfg::maxdlspeed) / nCntNew; + auto nSpeedNowKib = uint(cfg::maxdlspeed) / nCntNew; auto nTakesPerSec = nSpeedNowKib / 32; if(!nTakesPerSec) nTakesPerSec=1; @@ -952,7 +1000,7 @@ } if( fakeFail-- < 0) { -// LOGLVL(LOG_DEBUG, "\n#################\nFAKING A FAILURE\n###########\n"); +// LOGLVL(log::LOG_DEBUG, "\n#################\nFAKING A FAILURE\n###########\n"); r=0; fakeFail=rand()%123; errno = EROFS; @@ -1078,18 +1126,20 @@ string sErrorMsg; m_inBuf.clear(); - if (!m_inBuf.setsize(acfg::dlbufsize)) + if (!m_inBuf.setsize(cfg::dlbufsize)) { - aclog::err("500 Out of memory"); + log::err("500 Out of memory"); return; } if(fdWakeRead<0 || fdWakeWrite<0) { - aclog::err("Error creating pipe file descriptors"); + log::err("Error creating pipe file descriptors"); return; } + tDtorEx allJobReleaser([&](){ m_qNewjobs.clear(); }); + tDljQueue inpipe; tDlStreamHandle con; unsigned loopRes=0; @@ -1116,7 +1166,7 @@ { return cjob->m_pRepoDesc->m_pProxy; } - return acfg::GetProxyInfo(); + return cfg::GetProxyInfo(); }; while(true) // outer loop: jobs, connection handling @@ -1126,7 +1176,7 @@ setLockGuard; LOG("New jobs: " << m_qNewjobs.size()); - if(m_bStopASAP) + if(m_bStopASAP || evabase::in_shutdown) { /* The no-more-users checking logic will purge orphaned items from the inpipe * queue. When the connection is dirty after that, it will be closed in the @@ -1172,7 +1222,6 @@ bool bUsed = false; ASSERT(!m_qNewjobs.empty()); - auto doconnect = [&](const tHttpUrl& tgt, int timeout, bool fresh) { return m_pConFactory->CreateConnected(tgt.sHost, @@ -1193,8 +1242,8 @@ { if(proxy) { - con = doconnect(*proxy, acfg::optproxytimeout > 0 ? - acfg::optproxytimeout : acfg::nettimeout, false); + con = doconnect(*proxy, cfg::optproxytimeout > 0 ? + cfg::optproxytimeout : cfg::nettimeout, false); if(con) { if(!con->StartTunnel(peerHost, sErrorMsg, & proxy->sUserPass, true)) @@ -1202,27 +1251,27 @@ } } else - con = doconnect(peerHost, acfg::nettimeout, false); + con = doconnect(peerHost, cfg::nettimeout, false); } else #endif { if(proxy) { - con = doconnect(*proxy, acfg::optproxytimeout > 0 ? - acfg::optproxytimeout : acfg::nettimeout, false); + con = doconnect(*proxy, cfg::optproxytimeout > 0 ? + cfg::optproxytimeout : cfg::nettimeout, false); } else - con = doconnect(peerHost, acfg::nettimeout, false); + con = doconnect(peerHost, cfg::nettimeout, false); } - if(!con && proxy && acfg::optproxytimeout>0) + if(!con && proxy && cfg::optproxytimeout>0) { ldbg("optional proxy broken, disable"); m_bProxyTot = true; proxy = nullptr; - acfg::MarkProxyFailure(); - con = doconnect(peerHost, acfg::nettimeout, false); + cfg::MarkProxyFailure(); + con = doconnect(peerHost, cfg::nettimeout, false); } ldbg("connection valid? " << bool(con) << " was fresh? " << !bUsed); @@ -1249,7 +1298,7 @@ // connection should be stable now, prepare all jobs and/or move to pipeline while(!bStopRequesting && !m_qNewjobs.empty() - && int(inpipe.size()) <= acfg::pipelinelen) + && int(inpipe.size()) <= cfg::pipelinelen) { tDlJobPtr &cjob = m_qNewjobs.front(); @@ -1301,8 +1350,8 @@ } } } - ldbg("Request(s) cooked, buffer contents: " << m_sendBuf); + ASSERT(!m_sendBuf.empty()); go_select: @@ -1314,6 +1363,8 @@ // inner loop: plain communication until something happens. Maybe should use epoll here? loopRes=ExchangeData(sErrorMsg, con, inpipe); ldbg("loopRes: "<< loopRes); + if(m_bStopASAP || evabase::in_shutdown) + return; /* check whether we have a pipeline stall. This may happen because a) we are done or * b) because of the remote hostname change or c) the client stopped sending tasks. @@ -1378,7 +1429,7 @@ // trying to resume that job secretly, unless user disabled the use of range (we // cannot resync the sending position ATM, throwing errors to user for now) - if (acfg::vrangeops <= 0 && inpipe.front()->m_pStorage->m_bCheckFreshness) + if (cfg::vrangeops <= 0 && inpipe.front()->m_pStorage->m_bCheckFreshness) loopRes |= EFLAG_JOB_BROKEN; else inpipe.front()->m_DlState = tDlJob::STATE_REGETHEADER; @@ -1447,3 +1498,5 @@ } } + +} diff -Nru apt-cacher-ng-0.9.1/source/dnsiter.cc apt-cacher-ng-3.3.1/source/dnsiter.cc --- apt-cacher-ng-0.9.1/source/dnsiter.cc 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/dnsiter.cc 2020-01-08 19:58:26.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * dnsiter.cc + * + * Created on: 29.10.2019 + * Author: Eduard Bloch + */ + +#include "acfg.h" +#include "dnsiter.h" +#include + +#include + +namespace acng +{ + +tDnsIterator::tDnsIterator(int pf_filter, const evutil_addrinfo* par) : m_cur(par) +{ + m_pf = pf_filter; +} + +const evutil_addrinfo* tDnsIterator::next() +{ + while(m_cur) + { + if(!m_just_created) + m_cur = m_cur->ai_next; + m_just_created = false; + if(!m_cur) return nullptr; + // this isn't normal since prefiltered before and is not allowed + if (m_cur->ai_socktype != SOCK_STREAM || m_cur->ai_protocol != IPPROTO_TCP) + return nullptr; + if(m_pf == PF_UNSPEC || m_cur->ai_family == m_pf) + return m_cur; + } + return nullptr; +} + +const evutil_addrinfo* tAlternatingDnsIterator::next() +{ + if (m_toggle) + { + auto ret = m_iters[!m_idx].next(); + // EOF at alternative, staying here then + if(!ret) + { + m_toggle = false; + return next(); + } + m_idx = !m_idx; + return ret; + } + return m_iters[m_idx].next(); +} + +tAlternatingDnsIterator::tAlternatingDnsIterator(const evutil_addrinfo* parObj) : + m_idx(false), m_toggle(false) +{ + if(cfg::conprotos[0] == PF_UNSPEC) + { + m_idx = 0; + m_iters[0] = tDnsIterator(PF_UNSPEC, parObj); + } + else if(cfg::conprotos[1] == PF_UNSPEC) + { + m_idx = 0; + m_iters[0] = tDnsIterator(cfg::conprotos[0], parObj); + } + else + { + m_toggle = true; + m_idx = 1; // will toggle at start + m_iters[0] = tDnsIterator(cfg::conprotos[0], parObj); + m_iters[1] = tDnsIterator(cfg::conprotos[1], parObj); + } +} +} + + diff -Nru apt-cacher-ng-0.9.1/source/evabase.cc apt-cacher-ng-3.3.1/source/evabase.cc --- apt-cacher-ng-0.9.1/source/evabase.cc 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/evabase.cc 2020-01-08 19:58:26.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * evabase.cc + * + * Created on: 14.03.2019 + * Author: EB + */ + +#include "evabase.h" +#include "evasocket.h" + +#include "meta.h" +#include + +namespace acng +{ + +std::shared_ptr evabase::instance; +std::atomic evabase::in_shutdown = ATOMIC_VAR_INIT(false); + +evabase::evabase() : base (event_base_new()) +{ +} + +evabase::~evabase() +{ + event_base_free(base); +} + +void acng::evabase::register_activity(socket_activity_base* p) +{ + m_weak_ref_users.insert(p); +} + +void acng::evabase::unregister_activity(socket_activity_base* p) +{ + m_weak_ref_users.erase(p); +} + +void evabase::invoke_shutdown_activities() +{ + auto snapshot = m_weak_ref_users; + for(const auto& opfer: snapshot) + if(opfer) opfer->invoke_shutdown(); +} + +} diff -Nru apt-cacher-ng-0.9.1/source/evasocket.cc apt-cacher-ng-3.3.1/source/evasocket.cc --- apt-cacher-ng-0.9.1/source/evasocket.cc 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/evasocket.cc 2020-01-08 19:58:26.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * evasocket.cc + * + * Created on: 15.03.2019 + * Author: EB + */ + +#include "evasocket.h" +#include "evabase.h" + +#include "fileio.h" +#include +#include + +acng::evasocket::evasocket(int fd) : m_fd(fd) +{ +} + +acng::evasocket::~evasocket() +{ + checkforceclose(m_fd); +} + +std::shared_ptr acng::evasocket::create(int fd) +{ + return std::shared_ptr(new evasocket(fd)); +} + +acng::event_socket::event_socket(std::shared_ptr ev_base, std::shared_ptr sock, + short create_flags, + std::function & sock, short)> action) +: m_evbase(ev_base), m_sock(sock), m_parent_action(action) +{ + m_event = event_new(ev_base->base, sock->fd(), create_flags, event_socket::on_io, this); +} + +acng::event_socket::~event_socket() +{ + if(m_event) + event_free(m_event); +} + +void acng::event_socket::on_io(evutil_socket_t, short what, void* uptr) +{ + auto es = (event_socket*) uptr; + es->m_parent_action(es->m_sock, what); +} + +void acng::event_socket::enable(const struct timeval *tv) +{ + if(m_event) + event_add(m_event, tv); +} + +void acng::event_socket::disable() +{ + if(m_event) + event_del(m_event); +} +/* +acng::event_socket::event_socket(event_socket&& o) +{ + m_evbase.swap(o.m_evbase); + m_sock.swap(o.m_sock); + m_parent_action.swap(o.m_parent_action); + m_event = o.m_event; + o.m_event = nullptr; +} +*/ + +acng::socket_activity_base::socket_activity_base(std::shared_ptr evbase) +: m_evbase(evbase) +{ + m_evbase->register_activity(this); +} + +acng::socket_activity_base::~socket_activity_base() +{ + m_evbase->unregister_activity(this); +} +/* +std::shared_ptr acng::socket_activity_base::self_lock() +{ + m_selfref = std::shared_from_this(this); + m_evbase->register_activity(m_selfref); + return m_selfref; +} + +std::shared_ptr acng::socket_activity_base::release_self_lock() +{ + decltype(m_selfref) ret; + if(m_selfref) + { + m_evbase->unregister_activity(m_selfref); + ret.swap(m_selfref); + } + return ret; +} +*/ diff -Nru apt-cacher-ng-0.9.1/source/expiration.cc apt-cacher-ng-3.3.1/source/expiration.cc --- apt-cacher-ng-0.9.1/source/expiration.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/expiration.cc 2020-01-08 19:58:26.000000000 +0000 @@ -1,4 +1,3 @@ - //#define LOCAL_DEBUG #include "debug.h" @@ -25,18 +24,27 @@ #warning Unlinking parts defused #endif -#define TIMEEXPIRED(t) (t < (m_gMaintTimeNow-acfg::extreshhold*86400)) -#define TIME_AGONY (m_gMaintTimeNow-acfg::extreshhold*86400) +#define TIMEEXPIRED(t) (t < (m_gMaintTimeNow-acng::cfg::extreshhold*86400)) +#define TIME_AGONY (m_gMaintTimeNow-acng::cfg::extreshhold*86400) #define FNAME_PENDING "_expending_dat" #define FNAME_DAMAGED "_expending_damaged" #define sFAIL_INI SABSPATH("_exfail_cnt") #define FAIL_INI sFAIL_INI.c_str() +namespace acng +{ + +// represents the session's current incomming data count at the moment when expr. was run last time +// it's needed to correct the considerations based on the active session's download stats +off_t lastCurrentDlCount(0); + void expiration::HandlePkgEntry(const tRemoteFileInfo &entry) { - LOGSTART2("expiration::_HandlePkgEntry:", +#ifdef DEBUGSPAM + LOGSTART2("expiration::HandlePkgEntry:", "\ndir:" << entry.sDirectory << "\nname: " << entry.sFileName << "\nsize: " << entry.fpr.size << "\ncsum: " << entry.fpr.GetCsAsString()); +#endif #define ECLASS "ERROR: " #define WCLASS "WARNING: " @@ -55,11 +63,11 @@ string sPathAbs(CACHE_BASE+sPathRel); // end line ending starting from a class and add checkbox as needed - auto finish_bad = [&]()->bool + auto finish_bad = [&](cmstring& reason)->bool { if (m_damageList.is_open()) m_damageList << sPathRel << "\n"; SendChunk(" (treating as damaged file...) "); - AddDelCbox(sPathRel); + AddDelCbox(sPathRel, reason); SendChunk(CLASSEND); return true; }; @@ -87,7 +95,7 @@ if(m_bVerbose) { SendFmt << WCLASS << sPathRel << " (invalid but volatile, ignoring...) "; - AddDelCbox(sPathRel); + AddDelCbox(sPathRel, "Bad file state while containing volatile index data"); SendChunk(CLASSEND); } ADDSPACE(size); @@ -114,15 +122,11 @@ // Basic header checks. Skip if the file was forcibly updated/reconstructed before. if (m_bSkipHeaderChecks || descHave.bNoHeaderCheck) { - LOG("Skipped header check for " << sPathRel); - } - else if(entry.bInflateForCs) - { - LOG("Skipped header check for " << sPathRel << ", cannot compare sizes"); +// LOG("Skipped header check for " << sPathRel); } else if(entry.fpr.size>=0) { - LOG("Doing basic header checks"); +// LOG("Doing basic header checks"); header h; auto sHeadAbs(sPathAbs+".head"); if (0=0) + if(entry.fpr.size>=0) { if(lenFromStat > entry.fpr.size) goto report_oversize; if(lenFromStat < entry.fpr.size) goto handle_incomplete; @@ -173,8 +176,7 @@ if(!m_bByChecksum) return report_good(lenFromStat); //knowing the expected and real size, try a shortcut without scanning - if(!entry.bInflateForCs// if we can check quickly with the file size - && entry.fpr.size >= 0) + if(entry.fpr.size >= 0) { if(lenFromStat<0) lenFromStat=GetFileSize(sPathAbs, -123); if(lenFromStat >=0 && lenFromStat < entry.fpr.size) @@ -185,16 +187,13 @@ } if(entry.fpr.csType != descHave.fpr.csType && - !descHave.fpr.ScanFile(sPathAbs, entry.fpr.csType, entry.bInflateForCs)) + !descHave.fpr.ScanFile(sPathAbs, entry.fpr.csType)) { // IO error? better keep it for now, not sure how to deal with it SendFmt << ECLASS "An error occurred while checksumming " << sPathRel << ", leaving as-is for now."; - if(entry.bInflateForCs) - SendFmt << " NOTE: this can be caused by the incomplete compression" - " header if the download was not finished."; - aclog::err(tSS() << "Error reading " << sPathAbs ); - AddDelCbox(sPathRel); + log::err(tSS() << "Error reading " << sPathAbs ); + AddDelCbox(sPathRel, "IO error"); SendFmt<second.erase(it++); }; - // needs to match the exact file location. + // needs to match the exact file location if requested. // And for "Index" files, they have always to be at a well defined location, this // constraint is also needed to expire deprecated files - if(m_bByPath || entry.sFileName == sIndex) + // and in general, all kinds of index files shall be checked at the particular location since + // there are too many identical names spread between different repositories + bool byPath = (m_bByPath || entry.sFileName == sIndex || + rex::Match(entry.sDirectory + entry.sFileName, rex::FILE_VOLATILE)); + if(byPath) { // compare full paths (physical vs. remote) with their real paths auto cleanPath(entry.sDirectory); @@ -301,12 +304,12 @@ // of gaps in the "package history" when proceeded in linear fashion. inline void expiration::DropExceptionalVersions() { - if(m_trashFile2dir2Info.empty() || !acfg::keepnver) + if(m_trashFile2dir2Info.empty() || !cfg::keepnver) return; if(system("dpkg --version >/dev/null 2>&1")) { SendFmt << "dpkg not available on this system, cannot identify latest versions to keep " - "only " << acfg::keepnver << " of them."; + "only " << cfg::keepnver << " of them."; return; } struct tPkgId @@ -348,9 +351,9 @@ auto procGroup = [&]() { // if more than allowed, keep the highest versions for sure, others are expired as usual - if(version2trashGroup.size() > (uint) acfg::keepnver) + if(version2trashGroup.size() > (uint) cfg::keepnver) std::sort(version2trashGroup.begin(), version2trashGroup.end()); - for(unsigned i=0; i\n"; #ifdef ENABLED - ::unlink(sPathAbs.c_str()); - ::unlink((sPathAbs + ".head").c_str()); + SendFmt << "Removing " << sPathRel; + if(::unlink(sPathAbs.c_str())) + SendChunk(tErrnoFmter(" [ERROR] ")+""); + SendFmt << sBRLF << "Removing " << sPathRel << ".head"; + if(::unlink((sPathAbs + ".head").c_str())) + SendChunk(tErrnoFmter(" [ERROR] ")+""); + SendChunk(sBRLF); ::rmdir(SZABSPATH(dir_props.first)); #endif } @@ -441,7 +452,7 @@ SendFmt << "Tagging " << sPathRel; if (m_bVerbose) SendFmt << " (t-" << (m_gMaintTimeNow - desc.nLostAt) / 3600 << "h)"; - SendChunk("
    \n"); + SendChunk(sBRLF); nCount++; tagSpace += desc.fpr.size; @@ -467,82 +478,41 @@ } if (m_parms.type==workExList) { - LoadPreviousData(true); - off_t nSpace(0); - unsigned cnt(0); - for (auto& i : m_trashFile2dir2Info) - { - for (auto& j : i.second) - { - auto rel = (j.first + i.first); - auto abspath = SABSPATH(rel); - off_t sz = GetFileSize(abspath, -2); - if (sz < 0) - continue; - - cnt++; - SendChunk(rel + "
    \n"); - nSpace += sz; - - sz = GetFileSize(abspath + ".head", -2); - if (sz >= 0) - { - nSpace += sz; - SendChunk(rel + ".head
    \n"); - } - } - } - TellCount(cnt, nSpace); - - mstring delURL(m_parms.cmd); - StrSubst(delURL, "justShow", "justRemove"); - SendFmtRemote << "Delete all listed files " - "(no further confirmation)
    \n"; + ListExpiredFiles(); return; } - if(m_parms.type==workExPurgeDamaged || m_parms.type==workExListDamaged || m_parms.type==workExTruncDamaged) { - filereader f; - if(!f.OpenFile(SABSPATH(FNAME_DAMAGED))) + HandleDamagedFiles(); + return; + } + + bool tradeOffCheck = cfg::exstarttradeoff && !StrHas(m_parms.cmd, "ignoreTradeOff") && !m_bByChecksum; + + off_t newLastIncommingOffset = 0; + + if(tradeOffCheck) + { + newLastIncommingOffset = log::GetCurrentCountersInOut().first; + + auto haveIncomming = newLastIncommingOffset - lastCurrentDlCount + + log::GetOldCountersInOut(true).first; + if(haveIncomming < cfg::exstarttradeoff) { - SendChunk(WITHLEN("List of damaged files not found")); + SendFmt << "Expiration suppressed due to costs-vs.-benefit considerations " + "(see exStartTradeOff setting, " << offttosH(haveIncomming) << + " vs. " << offttosH(cfg::exstarttradeoff) + << " (m_parms.cmd << "&ignoreTradeOff=iTO\">Override this check now)" + << sBRLF; return; } - mstring s; - while(f.GetOneLine(s)) - { - if(s.empty()) - continue; - - if(m_parms.type == workExPurgeDamaged) - { - SendFmt << "Removing " << s << "
    \n"; - ::unlink(SZABSPATH(s)); - ::unlink(SZABSPATH(s+".head")); - } - else if(m_parms.type == workExTruncDamaged) - { - SendFmt << "Truncating " << s << "
    \n"; - ignore_value(::truncate(SZABSPATH(s), 0)); - } - else - SendFmt << s << "
    \n"; - } - return; } - SetCommonUserFlags(m_parms.cmd); - m_bIncompleteIsDamaged=StrHas(m_parms.cmd, "incomAsDamaged"); m_bScanVolatileContents=StrHas(m_parms.cmd, "scanVolatile"); SendChunk("Locating potentially expired files in the cache...
    \n"); - - //dump_proc_status(); - DirectoryWalk(acfg::cachedir, this); - //dump_proc_status(); - + BuildCacheFileList(); if(CheckStopSignal()) goto save_fail_count; SendFmt<<"Found "<\n"; @@ -550,7 +520,7 @@ #if 0 //def DEBUG for(auto& i: m_trashFile2dir2Info) { - SendFmt << "
    File: " << i.first <<"
    \n"; + SendFmt << "
    File: " << i.first <\n"; } @@ -572,7 +542,28 @@ m_damageList.open(SZABSPATH(FNAME_DAMAGED), ios::out | ios::trunc); SendChunk(WITHLEN("Validating cache contents...
    \n")); - ProcessSeenMetaFiles(*this); + + // by-hash stuff needs special handling... + for(const auto& sPathRel : GetGoodReleaseFiles()) + { + auto func = [this](const tRemoteFileInfo &e) { + auto hexname(BytesToHexString(e.fpr.csum, GetCSTypeLen(e.fpr.csType))); + auto hit = m_trashFile2dir2Info.find(hexname); + if(hit == m_trashFile2dir2Info.end()) + return; // unknown + if(!m_bByPath) + { + m_trashFile2dir2Info.erase(hit); + return; + } + auto sdir = e.sDirectory + "by-hash/" + GetCsNameReleaseFile(e.fpr.csType) + '/'; + hit->second.erase(sdir); + }; + ParseAndProcessMetaFile(func, sPathRel, EIDX_RELEASE, true); + } + + ProcessSeenIndexFiles([this](const tRemoteFileInfo &e) { + HandlePkgEntry(e); }); if(CheckAndReportError() || CheckStopSignal()) goto save_fail_count; @@ -586,9 +577,17 @@ DelTree(CACHE_BASE+"_actmp"); + TrimFiles(); + PrintStats("Allocated disk space"); - SendChunk("
    Done."); + SendChunk("
    Done.
    "); + + if(tradeOffCheck) + { + lastCurrentDlCount = newLastIncommingOffset; + log::ResetOldCounters(); + } save_fail_count: @@ -622,15 +621,114 @@ } +void expiration::ListExpiredFiles() +{ + LoadPreviousData(true); + off_t nSpace(0); + unsigned cnt(0); + for (auto& i : this->m_trashFile2dir2Info) + { + for (auto& j : i.second) + { + auto rel = (j.first + i.first); + auto abspath = SABSPATH(rel); + off_t sz = GetFileSize(abspath, -2); + if (sz < 0) + continue; + + cnt++; + this->SendChunk(rel + sBRLF); + nSpace += sz; + + sz = GetFileSize(abspath + ".head", -2); + if (sz >= 0) + { + nSpace += sz; + this->SendChunk(rel + ".head
    \n"); + } + } + } + this->TellCount(cnt, nSpace); + + mstring delURL(this->m_parms.cmd); + StrSubst(delURL, "justShow", "justRemove"); + SendFmtRemote << "Delete all listed files " + "(no further confirmation)
    \n"; + return; +} + +void expiration::TrimFiles() +{ + if(m_oversizedFiles.empty()) + return; + auto now=GetTime(); + SendFmt << "Trimming cache files (" << m_oversizedFiles.size() <<")" << sBRLF; + for(const auto& fil: m_oversizedFiles) + { + // still there and not changed? + Cstat stinfo(fil); + if(!stinfo) + continue; + if(now - 86400 > stinfo.st_mtim.tv_sec) + { +// SendFmt << "let's truncate " << fil << " to " << stinfo.st_size << "
    "; + // it's unlikely to be accessed but better protect it + fileItemMgmt item; + item.PrepareRegisteredFileItemWithStorage(fil, true); + if(!item) + continue; + lockguard g(item.m_ptr.get()); + off_t nix; + if(item.m_ptr->GetStatusUnlocked(nix) >= fileitem::FIST_DLGOTHEAD) + continue; + + if(0 != truncate(fil.c_str(), stinfo.st_size)) + SendFmt << "Error at " << fil << " (" << tErrnoFmter() << ")" << sBRLF; + + } + } +} + +void expiration::HandleDamagedFiles() +{ + filereader f; + if(!f.OpenFile(SABSPATH(FNAME_DAMAGED))) + { + this->SendChunk(WITHLEN("List of damaged files not found")); + return; + } + mstring s; + while(f.GetOneLine(s)) + { + if(s.empty()) + continue; + + if(this->m_parms.type == workExPurgeDamaged) + { + SendFmt << "Removing " << s << sBRLF; + unlink(SZABSPATH(s)); + unlink(SZABSPATH(s+".head")); + } + else if(this->m_parms.type == workExTruncDamaged) + { + SendFmt << "Truncating " << s << sBRLF; + ignore_value(truncate(SZABSPATH(s), 0)); + } + else + SendFmt << s << sBRLF; + } + return; +} + void expiration::PurgeMaintLogs() { - tStrDeq logs = ExpandFilePattern(acfg::logdir + SZPATHSEP MAINT_PFX "*.log*"); + tStrDeq logs = ExpandFilePattern(cfg::logdir + SZPATHSEP MAINT_PFX "*.log*"); if (logs.size() > 2) SendChunk(WITHLEN( "Found required cleanup tasks: purging maintenance logs...
    \n")); for (const auto &s: logs) { - time_t id = atoofft(s.c_str() + acfg::logdir.size() + 7); + time_t id = atoofft(s.c_str() + cfg::logdir.size() + 7); //cerr << "id ist: "<< id<\n")); for(const auto &s: m_killBill) { - SendChunk(s+"
    \n"); + SendChunk(s+sBRLF); ::unlink(SZABSPATH(s)); } } @@ -661,6 +759,27 @@ return false; ProgTell(); + auto diffMoreThan = [&stinfo](blkcnt_t diff){ + return stinfo.st_blocks > diff && stinfo.st_size/512 < (stinfo.st_blocks - diff); + }; + + // detect invisible holes at the end of files (side effect of properly incorrect hidden allocation) + // allow some tolerance of about 10kb, should cover all page alignment effects + if(diffMoreThan(20)) + { + auto now=GetTime(); + if(now - 86400 > stinfo.st_mtim.tv_sec) + { + m_oversizedFiles.emplace_back(sPathAbs); + + // don't spam unless the user wants it and the size is really large + if(m_bVerbose || diffMoreThan(40)) + { + SendFmt << "Trailing allocated space on " << sPathAbs << " (" << stinfo.st_blocks << + " blocks, expected: ~" << (stinfo.st_size/512 + 1) <<"), will be trimmed later
    "; + } + } + } string sPathRel(sPathAbs, CACHE_BASE_LEN); DBGQLOG(sPathRel); @@ -687,6 +806,13 @@ flags.eIdxType = EIDX_SHA256DILIST; flags.vfile_ondisk = true; flags.uptodate = false; + + // the original source context will probably provide a viable source for + // this URL - it might go 404 if the whole folder is missing but then the + // referenced content would also be outdated/gone and not worth keeping + // in the cache anyway + + flags.forgiveDlErrors = true; } // and last but not least - care only about the modern version of that index m_metaFilesRel.erase(idir + "MD5SUMS"); @@ -700,7 +826,7 @@ attr.space += stinfo.st_size; attr.forgiveDlErrors = endsWith(sPathRel, sslIndex); } - else if (rechecks::Match(sPathRel, rechecks::FILE_VOLATILE)) + else if (rex::Match(sPathRel, rex::FILE_VOLATILE)) return true; // cannot check volatile files properly so don't care // ok, split to dir/file and add to the list @@ -720,9 +846,9 @@ void expiration::LoadHints() { filereader reader; - if(!reader.OpenFile(acfg::confdir+SZPATHSEP+"ignore_list")) + if(!reader.OpenFile(cfg::confdir+SZPATHSEP+"ignore_list")) { - if(acfg::suppdir.empty() || !reader.OpenFile(acfg::suppdir+SZPATHSEP+"ignore_list")) + if(cfg::suppdir.empty() || !reader.OpenFile(cfg::suppdir+SZPATHSEP+"ignore_list")) return; } string sTmp; @@ -792,8 +918,8 @@ char buf[200]; // map to to wait - int nMax=acfg::extreshhold-((now-oldest)/86400); - int nMin=acfg::extreshhold-((now-newest)/86400); + int nMax=cfg::extreshhold-((now-oldest)/86400); + int nMin=cfg::extreshhold-((now-newest)/86400); snprintf(buf, _countof(buf), "Previously detected: %lu rotten package file(s), " "to be deleted in about %d-%d day(s)
    \n", @@ -810,7 +936,7 @@ if (m_nErrorCount > 0 && m_bErrAbort) { SendFmt << sAbortMsg; - if(m_nPrevFailCount+(m_nErrorCount>0) > acfg::exsupcount) + if(m_nPrevFailCount+(m_nErrorCount>0) > cfg::exsupcount) SendFmt << "\n\n"; return true; } @@ -821,3 +947,23 @@ { m_killBill.emplace_back(sPathRel); } + +bool expiration::_checkSolidHashOnDisk(cmstring& hexname, const tRemoteFileInfo& entry, + cmstring& srcPrefix) +{ + if(m_trashFile2dir2Info.find(hexname) == m_trashFile2dir2Info.end()) + return false; + return cacheman::_checkSolidHashOnDisk(hexname, entry, srcPrefix); +} + +bool expiration::_QuickCheckSolidFileOnDisk(cmstring& sPathRel) +{ + auto dir=GetDirPart(sPathRel); + auto nam=sPathRel.substr(dir.size()); + auto it = m_trashFile2dir2Info.find(nam); + if(it == m_trashFile2dir2Info.end()) + return false; + return it->second.find(dir) != it->second.end(); +} + +} diff -Nru apt-cacher-ng-0.9.1/source/fileio.cc apt-cacher-ng-3.3.1/source/fileio.cc --- apt-cacher-ng-0.9.1/source/fileio.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/fileio.cc 2020-01-08 19:58:26.000000000 +0000 @@ -6,10 +6,18 @@ #include "config.h" #include "fileio.h" #include "acbuf.h" - +#include "acfg.h" +#include #ifdef HAVE_LINUX_FALLOCATE #include -#include +#endif + +using namespace std; + +namespace acng +{ + +#ifdef HAVE_LINUX_FALLOCATE int falloc_helper(int fd, off_t start, off_t len) { @@ -122,7 +130,9 @@ return -1; while(count>0) { - auto readcount=read(in_fd, buf, std::min(count, sizeof(buf))); + auto maxlen=sizeof(buf); + if(count0) + mkdir(path.substr(0,pos).c_str(), cfg::dirperms); + } +} + +void ACNG_API mkdirhier(cmstring& path) +{ + if(0==mkdir(path.c_str(), cfg::dirperms) || EEXIST == errno) + return; // should succeed in most cases + if(path.empty()) + return; + for(cmstring::size_type pos = path[0] == '/' ? 1 : 0;pos < path.size();pos++) + { + pos = path.find('/', pos); + mkdir(path.substr(0,pos).c_str(), cfg::dirperms); + if(pos == stmiss) break; + } +} + +} diff -Nru apt-cacher-ng-0.9.1/source/fileitem.cc apt-cacher-ng-3.3.1/source/fileitem.cc --- apt-cacher-ng-0.9.1/source/fileitem.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/fileitem.cc 2020-01-08 19:58:26.000000000 +0000 @@ -14,13 +14,21 @@ #include #include +#include +#include +#include + using namespace std; -#define MAXTEMPDELAY acfg::maxtempdelay // 27 -mstring sReplDir("_altStore" SZPATHSEP); +namespace acng +{ +#define MAXTEMPDELAY acng::cfg::maxtempdelay // 27 +mstring ACNG_API sReplDir("_altStore" SZPATHSEP); static tFiGlobMap mapItems; -static lockable mapItemsMx; +#ifndef MINIBUILD +static acmutex mapItemsMx; +#endif header const & fileitem::GetHeaderUnlocked() { @@ -36,28 +44,28 @@ } fileitem::fileitem() : - condition(), - m_nIncommingCount(0), - m_nSizeSeen(0), - m_nRangeLimit(-1), - m_bCheckFreshness(true), - m_bHeadOnly(false), - m_bAllowStoreData(true), - m_nSizeChecked(0), - m_filefd(-1), - m_nDlRefsCount(0), - usercount(0), - m_status(FIST_FRESH), - m_nTimeDlStarted(0), - m_nTimeDlDone(END_OF_TIME), - m_globRef(mapItems.end()) + m_nIncommingCount(0), + m_nSizeSeen(0), + m_nRangeLimit(-1), + m_bCheckFreshness(true), + m_bHeadOnly(false), + m_bAllowStoreData(true), + m_nSizeChecked(0), + m_filefd(-1), + m_nDlRefsCount(0), + usercount(0), + m_status(FIST_FRESH), + m_nTimeDlStarted(0), + m_nTimeDlDone(END_OF_TIME), + m_globRef(mapItems.end()) { } fileitem::~fileitem() { //setLockGuard; -// m_head.clear(); + // m_head.clear(); + Truncate2checkedSize(); checkforceclose(m_filefd); } @@ -70,13 +78,13 @@ void fileitem::DecDlRefCount(const string &sReason) { setLockGuard; - + notifyAll(); m_nDlRefsCount--; if(m_nDlRefsCount>0) return; // someone will care... - + // ... otherwise: the last downloader disappeared, needing to tell observers if (m_status=0) @@ -122,7 +131,6 @@ return (0==::stat(path.c_str(), &stbuf)) ? stbuf.st_size : defret; } - void fileitem::ResetCacheState() { setLockGuard; @@ -144,14 +152,14 @@ m_status=FIST_INITED; m_bCheckFreshness = bCheckFreshness; - + cmstring sPathAbs(CACHE_BASE+m_sPathRel); if(m_head.LoadFromFile(sPathAbs+".head") >0 && m_head.type==header::ANSWER ) { if(200 != m_head.getStatus()) goto error_clean; - + LOG("good head"); @@ -166,7 +174,7 @@ LOG("check freshness, last modified: " << p ); // that will cause check by if-mo-only later, needs to be sure about the size here - if(acfg::vrangeops == 0 + if(cfg::vrangeops == 0 && m_nSizeSeen != atoofft(m_head.h[header::CONTENT_LENGTH], -17)) { m_nSizeSeen = 0; @@ -179,14 +187,13 @@ if(pContLen) { off_t nContLen=atoofft(pContLen); // if it's 0 then we assume it's 0 - + // file larger than it could ever be? if(nContLen < m_nSizeSeen) goto error_clean; - LOG("Content-Length has a sane range"); - + m_nSizeChecked=m_nSizeSeen; // is it complete? and 0 value also looks weird, try to verify later @@ -207,15 +214,15 @@ if(!bCheckFreshness) m_nSizeSeen=GetFileSize(sPathAbs, 0); } - LOG("resulting status: " << m_status); + LOG("resulting status: " << (int) m_status); return m_status; error_clean: - ::unlink((sPathAbs+".head").c_str()); - m_head.clear(); - m_nSizeSeen=0; - m_status=FIST_INITED; - return m_status; // unuseable, to be redownloaded + ::unlink((sPathAbs+".head").c_str()); + m_head.clear(); + m_nSizeSeen=0; + m_status=FIST_INITED; + return m_status; // unuseable, to be redownloaded } bool fileitem::CheckUsableRange_unlocked(off_t nRangeLastByte) @@ -254,9 +261,9 @@ cmstring sPathAbs(SABSPATH(m_sPathRel)); cmstring sPathHead(sPathAbs+".head"); // header allowed to be lost in process... -// if(unlink(sPathHead.c_str())) -// ::ignore_value(::truncate(sPathHead.c_str(), 0)); - ::ignore_value(::truncate(sPathAbs.c_str(), 0)); + // if(unlink(sPathHead.c_str())) + // ::ignore_value(::truncate(sPathHead.c_str(), 0)); + acng::ignore_value(::truncate(sPathAbs.c_str(), 0)); Cstat stf(sPathAbs); if(stf && stf.st_size>0) return false; // didn't work. Permissions? Anyhow, too dangerous to act on this now @@ -268,8 +275,8 @@ h.del(header::XFORWARDEDFOR); h.del(header::CONTENT_RANGE); h.StoreToFile(sPathHead); -// if(0==stat(sPathHead.c_str(), &stf) && stf.st_size >0) -// return false; // that's weird too, header still exists with real size + // if(0==stat(sPathHead.c_str(), &stf) && stf.st_size >0) + // return false; // that's weird too, header still exists with real size m_head.clear(); m_nSizeSeen=m_nSizeChecked=0; @@ -284,11 +291,18 @@ m_status = FIST_COMPLETE; } +void fileitem::UpdateHeadTimestamp() +{ + if(m_sPathRel.empty()) + return; + utimes(SZABSPATH(m_sPathRel + ".head"), nullptr); +} + fileitem::FiStatus fileitem::WaitForFinish(int *httpCode) { - setLockGuard; + lockuniq g(this); while(m_status= FIST_COMPLETE) { @@ -335,7 +348,7 @@ // conflict with another thread's download attempt? Deny, except for a forced restart if (m_status > FIST_DLPENDING && !bForcedRestart) return false; - + if(m_bCheckFreshness) m_nTimeDlStarted = GetTime(); @@ -343,7 +356,7 @@ // optional optimization: hints for the filesystem resp. kernel off_t hint_start(0), hint_length(0); - + // status will change, most likely... ie. return withError action notifyAll(); @@ -351,13 +364,14 @@ string sHeadPath=sPathAbs + ".head"; auto withErrorAndKillFile = [&](LPCSTR x) - { + { SETERROR(x); if(m_filefd>=0) { #if _POSIX_SYNCHRONIZED_IO > 0 fsync(m_filefd); #endif + Truncate2checkedSize(); forceclose(m_filefd); } @@ -368,7 +382,7 @@ m_status=FIST_DLERROR; m_nTimeDlDone=GetTime(); return false; - }; + }; int serverStatus = h.getStatus(); #if 0 @@ -432,7 +446,7 @@ int n=sscanf(p, "bytes " OFF_T_FMT "-" OFF_T_FMT "/" OFF_T_FMT, &myfrom, &myto, &mylen); if(n<=0) n=sscanf(p, "bytes=" OFF_T_FMT "-" OFF_T_FMT "/" OFF_T_FMT, &myfrom, &myto, &mylen); - + ldbg("resuming? n: "<< n << " und myfrom: " < kill cached file ASAP + // -> kill cached file ASAP m_bAllowStoreData=false; m_head.copy(h, header::XORIG); return withErrorAndKillFile("503 Server disagrees on file size, cleaning up"); @@ -513,51 +530,53 @@ return withError(h.getCodeMessage()); } - m_bAllowStoreData=false; + m_bAllowStoreData = false; // have a clean header with just the error message - m_head.frontLine=h.frontLine; + m_head.frontLine = h.frontLine; m_head.set(header::CONTENT_LENGTH, "0"); - if(m_status>FIST_DLGOTHEAD) + if(m_status > FIST_DLGOTHEAD) { // oh shit. Client may have already started sending it. Prevent such trouble in future. unlink(sHeadPath.c_str()); } } - if(acfg::debug&LOG_MORE) - aclog::misc(string("Download of ")+m_sPathRel+" started"); + if(cfg::debug & log::LOG_MORE) + log::misc(string("Download of ")+m_sPathRel+" started"); if(m_bAllowStoreData) { // using adaptive Delete-Or-Replace-Or-CopyOnWrite strategy - - // First opening the file first to be sure that it can be written. Header storage is the critical point, + + MoveRelease2Sidestore(); + + // First opening the file to be sure that it can be written. Header storage is the critical point, // every error after that leads to full cleanup to not risk inconsistent file contents - + int flags = O_WRONLY | O_CREAT | O_BINARY; struct stat stbuf; - + mkbasedir(sPathAbs); - m_filefd=open(sPathAbs.c_str(), flags, acfg::fileperms); + m_filefd = open(sPathAbs.c_str(), flags, cfg::fileperms); ldbg("file opened?! returned: " << m_filefd); - + // self-recovery from cache poisoned with files with wrong permissions - if (m_filefd<0) + if (m_filefd < 0) { - if(m_nSizeChecked>0) // OOOH CRAP! CANNOT APPEND HERE! Do what's still possible. + if(m_nSizeChecked > 0) // OOOH CRAP! CANNOT APPEND HERE! Do what's still possible. { - string temp=sPathAbs+".tmp"; - if(FileCopy(sPathAbs, temp) && 0==unlink(sPathAbs.c_str()) ) + string temp = sPathAbs + ".tmp"; + if(FileCopy(sPathAbs, temp) && 0 == unlink(sPathAbs.c_str()) ) { if(0!=rename(temp.c_str(), sPathAbs.c_str())) return withError("503 Cannot rename files"); - + // be sure about that if(0!=stat(sPathAbs.c_str(), &stbuf) || stbuf.st_size!=m_nSizeSeen) return withError("503 Cannot copy file parts, filesystem full?"); - - m_filefd=open(sPathAbs.c_str(), flags, acfg::fileperms); + + m_filefd=open(sPathAbs.c_str(), flags, cfg::fileperms); ldbg("file opened after copying around: "); } else @@ -567,11 +586,11 @@ else { unlink(sPathAbs.c_str()); - m_filefd=open(sPathAbs.c_str(), flags, acfg::fileperms); + m_filefd=open(sPathAbs.c_str(), flags, cfg::fileperms); ldbg("file force-opened?! returned: " << m_filefd); } } - + if (m_filefd<0) { tErrnoFmter efmt("503 Cache storage error - "); @@ -581,22 +600,22 @@ return withError(efmt.c_str()); #endif } - - if(0!=fstat(m_filefd, &stbuf) || !S_ISREG(stbuf.st_mode)) + + if(0 != fstat(m_filefd, &stbuf) || !S_ISREG(stbuf.st_mode)) return withErrorAndKillFile("503 Not a regular file"); // this makes sure not to truncate file while it's mmaped auto tempLock = TFileShrinkGuard::Acquire(stbuf); - + // crop, but only if the new size is smaller. MUST NEVER become larger (would fill with zeros) - if(m_nSizeChecked <= m_nSizeSeen) + if(m_nSizeSeen != 0 && m_nSizeChecked <= m_nSizeSeen) { - if(0==ftruncate(m_filefd, m_nSizeChecked)) - { + if(0==Truncate2checkedSize()) + { #if ( (_POSIX_C_SOURCE >= 199309L || _XOPEN_SOURCE >= 500) && _POSIX_SYNCHRONIZED_IO > 0) fdatasync(m_filefd); #endif - } + } else return withErrorAndKillFile("503 Cannot change file size"); } @@ -604,29 +623,31 @@ return withErrorAndKillFile("503 Internal error on size checking"); // else... nothing to fix since the expectation==reality - falloc_helper(m_filefd, hint_start, hint_length); - /* - * double-check the docs, this is probably not relevant for writting + // falloc_helper(m_filefd, hint_start, hint_length); + if(m_nSizeSeen < (off_t) cfg::allocspace) + falloc_helper(m_filefd, 0, min(hint_start+hint_length, (off_t)cfg::allocspace)); + /* + * double-check the docs, this is probably not relevant for writting #ifdef HAVE_FADVISE // optional, experimental posix_fadvise(m_filefd, hint_start, hint_length, POSIX_FADV_SEQUENTIAL); #endif -*/ - ldbg("Storing header as "+sHeadPath); + */ + ldbg("Storing header as " + sHeadPath); int count=m_head.StoreToFile(sHeadPath); if(count<0) - return withErrorAndKillFile( (-count!=ENOSPC + return withErrorAndKillFile( (-count != ENOSPC ? "503 Cache storage error" : "503 OUT OF DISK SPACE")); - + // double-check the sane state - if(0!=fstat(m_filefd, &stbuf) || stbuf.st_size!=m_nSizeChecked) + if(0 != fstat(m_filefd, &stbuf) || stbuf.st_size != m_nSizeChecked) return withErrorAndKillFile("503 Inconsistent file state"); - - if(m_nSizeChecked!=lseek(m_filefd, m_nSizeChecked, SEEK_SET)) + + if(m_nSizeChecked != lseek(m_filefd, m_nSizeChecked, SEEK_SET)) return withErrorAndKillFile("503 IO error, positioning"); } - + m_status=FIST_DLGOTHEAD; return true; } @@ -635,20 +656,20 @@ { setLockGuard; - LOGSTART2("fileitem::StoreFileData", "status: " << m_status << ", size: " << size); + LOGSTART2("fileitem::StoreFileData", "status: " << (int) m_status << ", size: " << size); // something might care, most likely... also about BOUNCE action notifyAll(); - m_nIncommingCount+=size; - + m_nIncommingCount += size; + if(m_status > FIST_COMPLETE || m_status < FIST_DLGOTHEAD) { - ldbg("StoreFileData rejected, status: " << m_status) + ldbg("StoreFileData rejected, status: " << (int) m_status) return false; } - - if (size==0) + + if (size == 0) { if(FIST_COMPLETE == m_status) { @@ -657,10 +678,10 @@ else { m_status = FIST_COMPLETE; - m_nTimeDlDone=GetTime(); + m_nTimeDlDone = GetTime(); - if (acfg::debug & LOG_MORE) - aclog::misc(tSS() << "Download of " << m_sPathRel << " finished"); + if (cfg::debug & log::LOG_MORE) + log::misc(tSS() << "Download of " << m_sPathRel << " finished"); // we are done! Fix header from chunked transfers? if (m_filefd >= 0 && !m_head.h[header::CONTENT_LENGTH]) @@ -674,26 +695,26 @@ { m_status = FIST_DLRECEIVING; - if (m_bAllowStoreData && m_filefd>=0) + if (m_bAllowStoreData && m_filefd >= 0) { - while(size>0) + while(size > 0) { - int r=write(m_filefd, data, size); - if(r<0) + int r = write(m_filefd, data, size); + if(r < 0) { - if(EINTR==errno || EAGAIN==errno) + if(EINTR == errno || EAGAIN == errno) continue; tErrnoFmter efmt("HTTP/1.1 503 "); m_head.frontLine = efmt; m_status=FIST_DLERROR; // message will be set by the caller - m_nTimeDlDone=GetTime(); + m_nTimeDlDone = GetTime(); _LogWithErrno(efmt.c_str(), m_sPathRel); return false; } - m_nSizeChecked+=r; - size-=r; - data+=r; + m_nSizeChecked += r; + size -= r; + data += r; } } } @@ -731,16 +752,16 @@ { if(m_ptr->m_status < fileitem::FIST_COMPLETE && m_ptr->m_status != fileitem::FIST_INITED) { - ldbg("usercount dropped to zero while downloading?: " << m_ptr->m_status); + ldbg("usercount dropped to zero while downloading?: " << (int) m_ptr->m_status); } // some file items will be held ready for some time time_t when(0); if (MAXTEMPDELAY && m_ptr->m_bCheckFreshness && m_ptr->m_status == fileitem::FIST_COMPLETE && - ((when=m_ptr->m_nTimeDlStarted+MAXTEMPDELAY) > GetTime())) + ((when = m_ptr->m_nTimeDlStarted+MAXTEMPDELAY) > GetTime())) { - g_victor.ScheduleFor(when, cleaner::TYPE_EXFILEITEM); + cleaner::GetInstance().ScheduleFor(when, cleaner::TYPE_EXFILEITEM); return; } @@ -759,22 +780,22 @@ } -bool fileItemMgmt::PrepageRegisteredFileItemWithStorage(cmstring &sPathUnescaped, bool bConsiderAltStore) +bool fileItemMgmt::PrepareRegisteredFileItemWithStorage(cmstring &sPathUnescaped, bool bConsiderAltStore) { LOGSTART2("fileitem::GetFileItem", sPathUnescaped); - MYTRY + try { mstring sPathRel(fileitem_with_storage::NormalizePath(sPathUnescaped)); lockguard lockGlobalMap(mapItemsMx); - tFiGlobMap::iterator it=mapItems.find(sPathRel); - if(it!=mapItems.end()) + auto it = mapItems.find(sPathRel); + if(it != mapItems.end()) { if (bConsiderAltStore) { // detect items that got stuck somehow time_t now(GetTime()); - time_t extime(now - acfg::stucksecs); + time_t extime(now - cfg::stucksecs); if (it->second->m_nTimeDlDone < extime) { // try to find its sibling which is in good state? @@ -791,7 +812,7 @@ // ok, then create a modded name version in the replacement directory mstring sPathRelMod(sPathRel); replaceChars(sPathRelMod, "/\\", '_'); - sPathRelMod.insert(0, sReplDir + ltos(getpid()) + "_" + ltos(now)+"_"); + sPathRelMod.insert(0, sReplDir + ltos(getpid()) + "_" + ltos(now) + "_"); LOG("Registering a new REPLACEMENT file item..."); auto sp(make_shared(sPathRelMod, 1)); sp->m_globRef = mapItems.insert(make_pair(sPathRel, sp)); @@ -811,7 +832,7 @@ m_ptr = sp; return true; } - MYCATCH(std::bad_alloc&) + catch(std::bad_alloc&) { } return false; @@ -834,7 +855,7 @@ spCustomFileItem->m_globRef = mapItems.emplace(spCustomFileItem->m_sPathRel, spCustomFileItem); - spCustomFileItem->usercount=1; + spCustomFileItem->usercount = 1; m_ptr = spCustomFileItem; return true; } @@ -847,22 +868,21 @@ } -// this method is supposed to be awaken periodically and detect items with ref count manipulated by +// this method is supposed to be awaken periodically and detects items with ref count manipulated by // the request storm prevention mechanism. Items shall be be dropped after some time if no other // thread but us is using them. time_t fileItemMgmt::BackgroundCleanup() { LOGSTART2s("fileItemMgmt::BackgroundCleanup", GetTime()); lockguard lockGlobalMap(mapItemsMx); - tFiGlobMap::iterator it, here; - time_t now=GetTime(); + time_t now = GetTime(); time_t oldestGet = END_OF_TIME; time_t expBefore = now - MAXTEMPDELAY; - for(it=mapItems.begin(); it!=mapItems.end();) + for(auto it = mapItems.begin(); it != mapItems.end();) { - here=it++; + auto here = it++; // became busy again? Ignore this entry, it's new master will take care of the deletion ASAP if(here->second->usercount >0) @@ -893,7 +913,7 @@ ldbg(oldestGet); // preserving a few seconds to catch more of them in the subsequent run - return std::max(oldestGet + MAXTEMPDELAY, GetTime()+8); + return std::max(oldestGet + MAXTEMPDELAY, GetTime() + 8); } ssize_t fileitem_with_storage::SendData(int out_fd, int in_fd, off_t &nSendPos, size_t count) @@ -903,17 +923,17 @@ #else ssize_t r=sendfile(out_fd, in_fd, &nSendPos, count); - if(r<0 && (errno==ENOSYS || errno==EINVAL)) + if(r<0 && (errno == ENOSYS || errno == EINVAL)) return sendfile_generic(out_fd, in_fd, &nSendPos, count); - else - return r; + + return r; #endif } void fileItemMgmt::dump_status() { tSS fmt; - aclog::err("File descriptor table:\n"); + log::err("File descriptor table:\n"); for(const auto& item : mapItems) { fmt.clear(); @@ -927,20 +947,22 @@ { fmt << "\t" << item.second->m_sPathRel << "\n\tDlRefCount: " << item.second->m_nDlRefsCount - << "\n\tState: " << item.second->m_status + << "\n\tState: " << (int) item.second->m_status << "\n\tFilePos: " << item.second->m_nIncommingCount << " , " << item.second->m_nRangeLimit << " , " << item.second->m_nSizeChecked << " , " << item.second->m_nSizeSeen << "\n\tGotAt: " << item.second->m_nTimeDlStarted << "\n\n"; } - aclog::err(fmt.c_str(), nullptr); + log::err(fmt.c_str(), nullptr); } - aclog::flush(); + log::flush(); } fileitem_with_storage::~fileitem_with_storage() { + Truncate2checkedSize(); + if(startsWith(m_sPathRel, sReplDir)) { ::unlink(SZABSPATH(m_sPathRel)); @@ -948,4 +970,34 @@ } } +int fileitem_with_storage::Truncate2checkedSize() +{ + if(m_filefd == -1 || m_nSizeChecked<0) + return -1; + return ftruncate(m_filefd, m_nSizeChecked); +} + +// special file? When it's rewritten from start, save the old version instead +int fileitem_with_storage::MoveRelease2Sidestore() +{ + if(m_nSizeChecked) + return 0; + if(!endsWithSzAr(m_sPathRel, "/InRelease") && !endsWithSzAr(m_sPathRel, "/Release")) + return 0; + auto srcAbs = CACHE_BASE + m_sPathRel; + Cstat st(srcAbs); + if(st) + { + auto tgtDir = CACHE_BASE + cfg::privStoreRelSnapSufix + sPathSep + GetDirPart(m_sPathRel); + mkdirhier(tgtDir); + auto sideFileAbs = tgtDir + ltos(st.st_ino) + ltos(st.st_mtim.tv_sec) + + ltos(st.st_mtim.tv_nsec); + return FileCopy(srcAbs, sideFileAbs); + //return rename(srcAbs.c_str(), sideFileAbs.c_str()); + } + return 0; +} + #endif // MINIBUILD + +} diff -Nru apt-cacher-ng-0.9.1/source/filelocks.cc apt-cacher-ng-3.3.1/source/filelocks.cc --- apt-cacher-ng-0.9.1/source/filelocks.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/filelocks.cc 2020-01-08 19:58:26.000000000 +0000 @@ -7,7 +7,9 @@ using namespace std; -condition g_mmapLocksMx; +namespace acng +{ +base_with_condition g_mmapLocksMx; decltype(TFileShrinkGuard::g_mmapLocks) TFileShrinkGuard::g_mmapLocks; @@ -21,7 +23,7 @@ unique_ptr TFileShrinkGuard::Acquire(const struct stat& info) { - lockguard g(g_mmapLocksMx); + lockuniq g(g_mmapLocksMx); while(true) { #ifdef COMPATGCC47 auto res = g_mmapLocks.insert(make_pair(info.st_dev, info.st_ino)); @@ -34,6 +36,8 @@ ret->m_it = res.first; return unique_ptr(ret); } - g_mmapLocksMx.wait(); + g_mmapLocksMx.wait(g); } } + +} diff -Nru apt-cacher-ng-0.9.1/source/filereader.cc apt-cacher-ng-3.3.1/source/filereader.cc --- apt-cacher-ng-0.9.1/source/filereader.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/filereader.cc 2020-01-08 19:58:26.000000000 +0000 @@ -16,6 +16,7 @@ #include "debug.h" #include +#include #ifdef HAVE_SSL #include @@ -30,7 +31,7 @@ // must be something sensible, ratio impacts stack size by inverse power of 2 #define BUFSIZEMIN 4095 // makes one page on i386 and should be enough for typical index files -#define BUFSIZEMAX 16*4096 +#define BUFSIZEMAX 256*1024 #ifdef MINIBUILD @@ -41,6 +42,8 @@ using namespace std; +namespace acng +{ // to make sure not to deal with incomplete operations from a signal handler class tMmapEntry { @@ -429,20 +432,20 @@ std::atomic_int g_nThreadsToKill; -void handle_sigbus() +void ACNG_API handle_sigbus() { - if (!acfg::sigbuscmd.empty()) + if (!cfg::sigbuscmd.empty()) { /*static char buf[21]; sprintf(buf, "%u", (unsigned) getpid()); setenv("ACNGPID", buf, 1); */ - ::ignore_value(system(acfg::sigbuscmd.c_str())); + acng::ignore_value(system(cfg::sigbuscmd.c_str())); } else { - aclog::err( + log::err( "FATAL ERROR: apparently an IO error occurred, while reading files. " "Please check your system logs for related errors reports. Also consider " "using the BusAction option, see Apt-Cacher NG Manual for details"); @@ -454,7 +457,7 @@ { if (!x.valid.load()) continue; - aclog::err(string("FATAL ERROR: probably IO error occurred, probably while reading the file ") + log::err(string("FATAL ERROR: probably IO error occurred, probably while reading the file ") +x.path+" . Please check your system logs for related errors."); } #endif @@ -475,7 +478,7 @@ { if (!x.valid.load()) continue; - aclog::err( + log::err( string("FATAL ERROR: probably IO error occurred, probably while reading the file ") + x.path + " . Please check your system logs for related errors."); @@ -491,7 +494,7 @@ if (!metoo) return; - suicid: aclog::err("FATAL ERROR: SIGBUS, probably caused by an IO error. " + suicid: log::err("FATAL ERROR: SIGBUS, probably caused by an IO error. " "Please check your system logs for related errors."); g_nThreadsToKill.fetch_add(-1); @@ -750,7 +753,7 @@ } // test checksum wrapper classes and their algorithms, also test conversion methods -void check_algos() +void ACNG_API check_algos() { #ifdef HAVE_CHECKSUM const char testvec[]="abc"; @@ -818,3 +821,5 @@ } #endif + +} diff -Nru apt-cacher-ng-0.9.1/source/header.cc apt-cacher-ng-3.3.1/source/header.cc --- apt-cacher-ng-0.9.1/source/header.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/header.cc 2020-01-08 19:58:26.000000000 +0000 @@ -20,6 +20,8 @@ using namespace std; +namespace acng +{ struct eHeadPos2label { header::eHeadPos pos; @@ -78,6 +80,14 @@ h[i] = s.h[i] ? strdup(s.h[i]) : nullptr; } +header::header(header &&s) +:type(s.type) +{ + frontLine.swap(s.frontLine); + swap(h, s.h); +} + + header& header::operator=(const header& s) { type=s.type; @@ -112,7 +122,7 @@ } int header::Load(LPCSTR const in, unsigned maxlen, - std::vector> *pNotForUs) + const std::function &unkHandler) { if(maxlen<9) return 0; @@ -172,12 +182,8 @@ if(lastLineIdx == HEADPOS_NOTFORUS) { - if(pNotForUs) - { - if(pNotForUs->empty()) // heh? - return -4; - pNotForUs->back().second.append(szBegin, nlen+2); - } + if(unkHandler) + unkHandler("", string(szBegin, nlen+2)); continue; } else if(lastLineIdx == HEADPOS_MAX || !h[lastLineIdx]) @@ -217,22 +223,13 @@ h[xh.pos][l]='\0'; break; } - if(pNotForUs && lastLineIdx == HEADPOS_NOTFORUS) - pNotForUs->emplace_back(string(key,keyLen), + if(unkHandler && lastLineIdx == HEADPOS_NOTFORUS) + unkHandler(string(key,keyLen), string(szBegin+keyLen, end+2-(szBegin+keyLen))); } return -2; } -int header::LoadFromBuf(const char * const in, unsigned maxlen) -{ - clear(); - int ret=Load(in, maxlen); - if(ret<0) - clear(); - return ret; -} - int header::LoadFromFile(const string &sPath) { clear(); @@ -243,7 +240,7 @@ acbuf buf; if(!buf.initFromFile(sPath.c_str())) return -1; - return LoadFromBuf(buf.rptr(), buf.size()); + return Load(buf.rptr(), buf.size()); } @@ -274,7 +271,7 @@ } } -void header::set(eHeadPos key, cmstring &value) +void header::set(eHeadPos key, const mstring &value) { string::size_type l=value.size()+1; h[key]=(char*) realloc(h[key], l); @@ -282,6 +279,11 @@ memcpy(h[key], value.c_str(), l); } +void header::prep(eHeadPos key, size_t len) +{ + h[key]=(char*) malloc(len); +} + void header::set(eHeadPos key, off_t nValue) { char buf[3*sizeof(off_t)]; @@ -304,7 +306,7 @@ { int nByteCount(0); const char *szPath=sPath.c_str(); - int fd=open(szPath, O_WRONLY|O_CREAT|O_TRUNC, acfg::fileperms); + int fd=open(szPath, O_WRONLY|O_CREAT|O_TRUNC, cfg::fileperms); if(fd<0) { fd=-errno; @@ -312,7 +314,7 @@ if(::unlink(szPath)) return fd; - fd=open(szPath, O_WRONLY|O_CREAT|O_TRUNC, acfg::fileperms); + fd=open(szPath, O_WRONLY|O_CREAT|O_TRUNC, cfg::fileperms); if(fd<0) return -errno; } @@ -372,3 +374,5 @@ return false; } + +} diff -Nru apt-cacher-ng-0.9.1/source/job.cc apt-cacher-ng-3.3.1/source/job.cc --- apt-cacher-ng-0.9.1/source/job.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/job.cc 2020-01-08 19:58:26.000000000 +0000 @@ -6,6 +6,7 @@ #include #include #include +#include using namespace std; #include "conn.h" @@ -27,18 +28,22 @@ #define CHUNKDEFAULT false #endif + +namespace acng +{ + mstring sHttp11("HTTP/1.1"); #define SPECIAL_FD -42 inline bool IsValidFD(int fd) { return fd>=0 || SPECIAL_FD == fd; } tTraceData traceData; -void acfg::dump_trace() +void cfg::dump_trace() { - aclog::err("Paths with uncertain content types:"); + log::err("Paths with uncertain content types:"); lockguard g(traceData); for (const auto& s : traceData) - aclog::err(s); + log::err(s); } tTraceData& tTraceData::getInstance() { @@ -83,9 +88,9 @@ } virtual bool StoreFileData(const char *data, unsigned int size) override { - setLockGuard; + lockuniq g(this); - LOGSTART2("tPassThroughFitem::StoreFileData", "status: " << m_status); + LOGSTART2("tPassThroughFitem::StoreFileData", "status: " << (int) m_status); // something might care, most likely... also about BOUNCE action notifyAll(); @@ -107,7 +112,7 @@ m_nConsumable=size; m_nConsumed=0; while(0 == m_nConsumed && m_status <= FIST_COMPLETE) - wait(); + wait(g); dbgline; // let the downloader abort? @@ -123,12 +128,12 @@ } ssize_t SendData(int out_fd, int, off_t &nSendPos, size_t nMax2SendNow) override { - setLockGuard; + lockuniq g(this); while(0 == m_nConsumable && m_status<=FIST_COMPLETE && ! (m_nSizeChecked==0 && m_status==FIST_COMPLETE)) { - wait(); + wait(g); } if (m_status >= FIST_DLERROR || !m_pData) return -1; @@ -151,7 +156,7 @@ m_nConsumed+=r; nSendPos+=r; } - notify(); + notifyAll(); return r; } }; @@ -197,7 +202,7 @@ header & HeadRef() { return m_head; } }; -job::job(header *h, con *pParent) : +job::job(header &&h, conn *pParent) : m_filefd(-1), m_pParentCon(pParent), m_bChunkMode(CHUNKDEFAULT), @@ -206,39 +211,41 @@ m_bNoDownloadStarted(false), m_state(STATE_SEND_MAIN_HEAD), m_backstate(STATE_TODISCON), - m_pReqHead(h), + m_reqHead(std::move(h)), m_nSendPos(0), m_nCurrentRangeLast(MAX_VAL(off_t)-1), m_nAllDataCount(0), m_nChunkRemainingBytes(0), - m_type(rechecks::FILE_INVALID), + m_type(rex::FILE_INVALID), m_nReqRangeFrom(-1), m_nReqRangeTo(-1) { - LOGSTART2("job::job", "job creating, " << m_pReqHead->frontLine << " and this: " << uintptr_t(this)); + LOGSTART2("job::job", "job creating, " << h.frontLine << " and this: " << uintptr_t(this)); } -string miscError("(HTTP error page)"); +static const string miscError(" [HTTP error, code: "); job::~job() { LOGSTART("job::~job"); + int stcode = 200; + if(m_pItem) stcode = m_pItem.getFiPtr()->GetHeader().getStatus(); + + bool bErr=m_sFileLoc.empty() || stcode >= 400; - bool bErr=m_sFileLoc.empty(); m_pParentCon->LogDataCounts( - ( bErr ? (m_pItem ? m_pItem.get()->GetHttpMsg() : miscError ) : m_sFileLoc ), - m_pReqHead->h[header::XFORWARDEDFOR], - (m_pItem ? m_pItem.get()->GetTransferCount() : 0), + m_sFileLoc + (bErr ? (miscError + ltos(stcode) + ']') : sEmptyString), + m_reqHead.h[header::XFORWARDEDFOR], + (m_pItem ? m_pItem.getFiPtr()->GetTransferCount() : 0), m_nAllDataCount, bErr); checkforceclose(m_filefd); - delete m_pReqHead; } -inline void job::HandleLocalDownload(const string &visPath, +inline void job::PrepareLocalDownload(const string &visPath, const string &fsBase, const string &fsSubpath) { - string absPath = fsBase+SZPATHSEP+fsSubpath; + mstring absPath = fsBase+SZPATHSEP+fsSubpath; Cstat stbuf(absPath); if (!stbuf) { @@ -268,25 +275,6 @@ } return; } -/* - // simplified version, just converts a string into a page - class bufferitem : public tPassThroughFitem, private string - { - public: - bufferitem(const string &sId, const string &sData) - : tPassThroughFitem(sId), string(sData) - { - status = FIST_COMPLETE; - m_pData=c_str(); - m_nConsumable=length(); - m_nSizeChecked=m_nConsumable; - m_head.frontLine.assign(_SZ2PS("HTTP/1.1 200 OK")); - m_head.set(header::CONTENT_LENGTH, length()); - m_head.set(header::CONTENT_TYPE, _SZ2PS("text/html") ); - m_head.type=header::ANSWER; - } - }; -*/ if(S_ISDIR(stbuf.st_mode)) { @@ -322,7 +310,8 @@ m_pItem.RegisterFileitemLocalOnly(p); // assign to smart pointer ASAP, operations might throw tSS & page = p->m_data; - page << "\nIndex of " << visPath << "" + page << "\nIndex of " + << visPath << "" "

    Index of " << visPath << "

    " "" ""; @@ -332,12 +321,11 @@ page<<"ERROR READING DIRECTORY"; else { - // quick hack, good enough - tStrMap sortMap; - for(struct dirent dp, *pEndTest; - 0==readdir_r(dir, &dp, &pEndTest) && pEndTest; ) + // quick hack with sorting by custom keys, good enough here + priority_queue, std::greater> sortHeap; + for(struct dirent *pdp(0);0!=(pdp=readdir(dir));) { - if (0!=::stat((absPath+SZPATHSEP+dp.d_name).c_str(), &stbuf)) + if (0!=::stat(mstring(absPath+SZPATHSEP+pdp->d_name).c_str(), &stbuf)) continue; bool bDir=S_ISDIR(stbuf.st_mode); @@ -347,29 +335,35 @@ strftime(datestr, sizeof(datestr)-1, "%d-%b-%Y %H:%M", localtime_r(&stbuf.st_mtime, &tmtimebuf)); - tSS line; - if(bDir) - line << "[DIR]"; - else if(startsWithSz(acfg::GetMimeType(dp.d_name), "image/")) - line << "[IMG]"; - else - line << "[   ]"; - line << "\r\n"; + while(!sortHeap.empty()) + { + page.add(WITHLEN("\r\n")); + sortHeap.pop(); + } + } - cmstring& GetFooter(); - page << "
     NameLast modifiedSize

    " : "\">" ) << dp.d_name - << "" << datestr << ""; + string line; if(bDir) - line << "-"; + line += "[DIR]"; + else if(startsWithSz(cfg::GetMimeType(pdp->d_name), "image/")) + line += "[IMG]"; else - line << offttosH(stbuf.st_size); - sortMap[string(bDir?"a":"b")+dp.d_name] = line; + line += "[   ]"; + line += string("d_name + + (bDir? "/\">" : "\">" ) + + pdp->d_name + +"" + + datestr + + "" + + (bDir ? string("-") : offttosH(stbuf.st_size)); + sortHeap.push(make_pair(string(bDir?"a":"b")+pdp->d_name, line)); + //dbgprint((mstring)line); } closedir(dir); - for(tStrMap::const_iterator it=sortMap.begin(); it!=sortMap.end(); it++) - page << "
    " << it->second << "
    ")); + page << sortHeap.top().second; + page.add(WITHLEN("
    " - <
    "; + page << "" <"; p->seal(); return; } @@ -396,7 +390,10 @@ m_head.type=header::ANSWER; m_head.frontLine="HTTP/1.1 200 OK"; m_head.set(header::CONTENT_LENGTH, stdata.st_size); - cmstring &sMimeType=acfg::GetMimeType(sLocalPath); + m_head.prep(header::LAST_MODIFIED, 26); + if(m_head.h[header::LAST_MODIFIED]) + FormatTime(m_head.h[header::LAST_MODIFIED], 26, stdata.st_mtim.tv_sec); + cmstring &sMimeType=cfg::GetMimeType(sLocalPath); if(!sMimeType.empty()) m_head.set(header::CONTENT_TYPE, sMimeType); }; @@ -424,10 +421,10 @@ * Content-Range: bytes 453291-7725119/7725120 */ - const char *pRange = m_pReqHead->h[header::RANGE]; + const char *pRange = m_reqHead.h[header::RANGE]; // working around a bug in old curl versions if (!pRange) - pRange = m_pReqHead->h[header::CONTENT_RANGE]; + pRange = m_reqHead.h[header::CONTENT_RANGE]; if (pRange) { int nRangeItems = sscanf(pRange, "bytes=" OFF_T_FMT @@ -452,22 +449,22 @@ LOGSTART("job::PrepareDownload"); #ifdef DEBUGLOCAL - acfg::localdirs["stuff"]="/tmp/stuff"; - aclog::err(m_pReqHead->ToString()); + cfg::localdirs["stuff"]="/tmp/stuff"; + log::err(m_pReqHead->ToString()); #endif string sReqPath, sPathResidual; tHttpUrl theUrl; // parsed URL // resolve to an internal repo location and maybe backends later - acfg::tRepoResolvResult repoMapping; + cfg::tRepoResolvResult repoMapping; fileitem::FiStatus fistate(fileitem::FIST_FRESH); bool bPtMode(false); bool bForceFreshnessChecks(false); // force update of the file, i.e. on dynamic index files? - tSplitWalk tokenizer(& m_pReqHead->frontLine, SPACECHARS); + tSplitWalk tokenizer(& m_reqHead.frontLine, SPACECHARS); - if(m_pReqHead->type!=header::GET && m_pReqHead->type!=header::HEAD) + if(m_reqHead.type!=header::GET && m_reqHead.type!=header::HEAD) goto report_invpath; if(!tokenizer.Next() || !tokenizer.Next()) // at path... goto report_invpath; @@ -481,16 +478,16 @@ // a sane default? normally, close-mode for http 1.0, keep for 1.1. // But if set by the client then just comply! m_bClientWants2Close =!m_bIsHttp11; - if(m_pReqHead && m_pReqHead->h[header::CONNECTION]) - m_bClientWants2Close = !strncasecmp(m_pReqHead->h[header::CONNECTION], "close", 5); + if(m_reqHead.h[header::CONNECTION]) + m_bClientWants2Close = !strncasecmp(m_reqHead.h[header::CONNECTION], "close", 5); // "clever" file system browsing attempt? - if(rechecks::Match(sReqPath, rechecks::NASTY_PATH) + if(rex::Match(sReqPath, rex::NASTY_PATH) || stmiss != sReqPath.find(MAKE_PTR_0_LEN("/_actmp")) || startsWithSz(sReqPath, "/_")) goto report_notallowed; - MYTRY + try { if (startsWithSz(sReqPath, "/HTTPS///")) sReqPath.replace(0, 6, PROT_PFX_HTTPS); @@ -516,9 +513,9 @@ goto report_invport; } - if(acfg::pUserPorts) + if(cfg::pUserPorts) { - if(!acfg::pUserPorts->test(nPort)) + if(!cfg::pUserPorts->test(nPort)) goto report_invport; } else if(nPort != 80) @@ -528,14 +525,15 @@ for(tStrPos pos=0; stmiss != (pos = theUrl.sPath.find("//", pos, 2)); ) theUrl.sPath.erase(pos, 1); - bPtMode=rechecks::MatchUncacheable(theUrl.ToURI(false), rechecks::NOCACHE_REQ); + bPtMode=rex::MatchUncacheable(theUrl.ToURI(false), rex::NOCACHE_REQ); - LOG("input uri: "<h[header::AUTHORIZATION]); + m_reqHead.h[header::AUTHORIZATION]); if(m_eMaintWorkType != tSpecialRequest::workNotSpecial) { m_sFileLoc = sReqPath; @@ -543,13 +541,14 @@ } } - using namespace rechecks; + using namespace rex; { - tStrMap::const_iterator it = acfg::localdirs.find(theUrl.sHost); - if (it != acfg::localdirs.end()) + tStrMap::const_iterator it = cfg::localdirs.find(theUrl.sHost); + if (it != cfg::localdirs.end()) { - HandleLocalDownload(sReqPath, it->second, theUrl.sPath); + PrepareLocalDownload(sReqPath, it->second, theUrl.sPath); + ParseRange(); return; } } @@ -566,8 +565,12 @@ if ( m_type == FILE_INVALID ) { - if(!acfg::patrace) + if(!cfg::patrace) + { + // just for the log + m_sFileLoc = theUrl.sPath; goto report_notallowed; + } // ok, collect some information helpful to the user m_type = FILE_VOLATILE; @@ -576,19 +579,19 @@ } // got something valid, has type now, trace it - USRDBG("Processing new job, "<frontLine); + USRDBG("Processing new job, "<empty()) m_sFileLoc=*repoMapping.psRepoName+SZPATHSEP+repoMapping.sRestPath; else m_sFileLoc=theUrl.sHost+theUrl.sPath; - bForceFreshnessChecks = ( ! acfg::offlinemode && m_type == FILE_VOLATILE); - m_pItem.PrepageRegisteredFileItemWithStorage(m_sFileLoc, bForceFreshnessChecks); + bForceFreshnessChecks = ( ! cfg::offlinemode && m_type == FILE_VOLATILE); + m_pItem.PrepareRegisteredFileItemWithStorage(m_sFileLoc, bForceFreshnessChecks); } - MYCATCH(std::out_of_range&) // better safe... + catch(std::out_of_range&) // better safe... { goto report_invpath; } @@ -598,15 +601,22 @@ USRDBG("Error creating file item for " << m_sFileLoc); goto report_overload; } + + if(cfg::DegradedMode()) + goto report_degraded; - fistate = m_pItem.get()->Setup(bForceFreshnessChecks); - LOG("Got initial file status: " << fistate); + fistate = m_pItem.getFiPtr()->Setup(bForceFreshnessChecks); + LOG("Got initial file status: " << (int) fistate); if (bPtMode && fistate != fileitem::FIST_COMPLETE) fistate = _SwitchToPtItem(); ParseRange(); + // might need to update the filestamp because nothing else would trigger it + if(cfg::trackfileuse && fistate >= fileitem::FIST_DLGOTHEAD && fistate < fileitem::FIST_DLERROR) + m_pItem.getFiPtr()->UpdateHeadTimestamp(); + if(fistate==fileitem::FIST_COMPLETE) return; // perfect, done here @@ -614,11 +624,11 @@ // no matter whether the file is complete or not // handles different cases: GET with range, HEAD with range, HEAD with no range if((m_nReqRangeFrom>=0 && m_nReqRangeTo>=0) - || (m_pReqHead->type==header::HEAD && 0!=(m_nReqRangeTo=-1))) + || (m_reqHead.type==header::HEAD && 0!=(m_nReqRangeTo=-1))) { - auto p(m_pItem.get()); + auto p(m_pItem.getFiPtr()); lockguard g(p.get()); - if(m_pItem.get()->CheckUsableRange_unlocked(m_nReqRangeTo)) + if(m_pItem.getFiPtr()->CheckUsableRange_unlocked(m_nReqRangeTo)) { LOG("Got a partial request for incomplete download; range is available"); m_bNoDownloadStarted=true; @@ -626,7 +636,7 @@ } } - if(acfg::offlinemode) { // make sure there will be no problems later in SendData or prepare a user message + if(cfg::offlinemode) { // make sure there will be no problems later in SendData or prepare a user message // error or needs download but freshness check was disabled, so it's really not complete. goto report_offlineconf; } @@ -634,18 +644,18 @@ if( fistate < fileitem::FIST_DLGOTHEAD) // needs a downloader { dbgline; - if(!m_pParentCon->SetupDownloader(m_pReqHead->h[header::XFORWARDEDFOR])) + if(!m_pParentCon->SetupDownloader(m_reqHead.h[header::XFORWARDEDFOR])) { USRDBG( "Error creating download handler for "<m_backends.empty()); - if (acfg::forcemanaged && !bHaveRedirects) + if (cfg::forcemanaged && !bHaveRedirects) goto report_notallowed; if (!bPtMode) @@ -655,14 +665,15 @@ ? repoMapping.repodata->m_backends.front().ToURI(false) + repoMapping.sRestPath : theUrl.ToURI(false); - if (rechecks::MatchUncacheable(testUri, rechecks::NOCACHE_TGT)) + if (rex::MatchUncacheable(testUri, rex::NOCACHE_TGT)) fistate = _SwitchToPtItem(); } - if (m_pParentCon->m_pDlClient->AddJob(m_pItem.get(), + if (m_pParentCon->m_pDlClient->AddJob(m_pItem.getFiPtr(), bHaveRedirects ? nullptr : &theUrl, repoMapping.repodata, bHaveRedirects ? &repoMapping.sRestPath : nullptr, - (LPCSTR) ( bPtMode ? headBuf : nullptr))) + (LPCSTR) ( bPtMode ? headBuf : nullptr), + cfg::redirmax)) { ldbg("Download job enqueued for " << m_sFileLoc); } @@ -672,7 +683,7 @@ goto report_overload; } } - MYCATCH(std::bad_alloc&) // OOM, may this ever happen here? + catch(std::bad_alloc&) // OOM, may this ever happen here? { USRDBG( "Out of memory"); goto report_overload; @@ -686,9 +697,7 @@ return ; report_notallowed: - SetErrorResponse((tSS() << "403 Forbidden file type or location: " << sReqPath).c_str(), - nullptr, "403 Forbidden file type or location"); -// USRDBG( sRawUriPath + " -- ACCESS FORBIDDEN"); + SetErrorResponse("403 Forbidden file type or location"); return ; report_offlineconf: @@ -699,19 +708,17 @@ SetErrorResponse("403 Invalid path specification"); return ; +report_degraded: + SetErrorResponse("403 Cache server in degraded mode"); + return ; + report_invport: SetErrorResponse("403 Configuration error (confusing proxy mode) or prohibited port (see AllowUserPorts)"); return ; -/* -report_doubleproxy: - SetErrorResponse("403 URL seems to be made for proxy but contains apt-cacher-ng port. " - "Inconsistent apt configuration?"); - return ; -*/ } #define THROW_ERROR(x) { if(m_nAllDataCount) return R_DISCON; SetErrorResponse(x); return R_AGAIN; } -job::eJobResult job::SendData(int confd) +job::eJobResult job::SendData(int confd, bool haveMoreJobs) { LOGSTART("job::SendData"); @@ -730,16 +737,16 @@ if (m_pItem) { - lockguard g(m_pItem.get().get()); + lockuniq g(m_pItem.getFiPtr().get()); for(;;) { - fistate=m_pItem.get()->GetStatusUnlocked(nGoodDataSize); + fistate=m_pItem.getFiPtr()->GetStatusUnlocked(nGoodDataSize); - LOG(fistate); + LOG((int) fistate); if (fistate > fileitem::FIST_COMPLETE) { - const header &h = m_pItem.get()->GetHeaderUnlocked(); + const header &h = m_pItem.getFiPtr()->GetHeaderUnlocked(); g.unLock(); // item lock must be released in order to replace it! if(m_nAllDataCount) return R_DISCON; @@ -765,17 +772,17 @@ break; } // or wait for the dl source to get data at the position we need to start from - LOG("sendstate: " << fistate << " , sendpos: " << m_nSendPos << nGoodDataSize); + LOG("sendstate: " << (int) fistate << " , sendpos: " << m_nSendPos << nGoodDataSize); if(fistate==fileitem::FIST_COMPLETE || (m_nSendPos < nGoodDataSize && fistate>=fileitem::FIST_DLGOTHEAD)) break; dbgline; - m_pItem.get()->wait(); + m_pItem.getFiPtr()->wait(g); dbgline; } - respHead = m_pItem.get()->GetHeaderUnlocked(); + respHead = m_pItem.getFiPtr()->GetHeaderUnlocked(); if(respHead.h[header::XORIG]) m_sOrigUrl=respHead.h[header::XORIG]; @@ -786,10 +793,12 @@ ASSERT(!"no FileItem assigned and no sensible way to continue"); return R_DISCON; } +#define returnSomething(msg) { LOG(msg); if(m_bClientWants2Close) return R_DISCON; \ + LOG("Reporting job done"); return R_DONE; }; for(;;) // left by returning { - MYTRY // for bad_alloc in members + try // for bad_alloc in members { switch(m_state) { @@ -815,11 +824,11 @@ return R_AGAIN; } - m_filefd=m_pItem.get()->GetFileFd(); + m_filefd=m_pItem.getFiPtr()->GetFileFd(); if(!IsValidFD(m_filefd)) THROW_ERROR("503 IO error"); m_state=m_bChunkMode ? STATE_SEND_CHUNK_HEADER : STATE_SEND_PLAIN_DATA; - ldbg("next state will be: " << m_state); + ldbg("next state will be: " << (int) m_state); continue; } case(STATE_SEND_PLAIN_DATA): @@ -838,7 +847,7 @@ size_t nMax2SendNow=min(nGoodDataSize-m_nSendPos, m_nCurrentRangeLast+1-m_nSendPos); ldbg("~sendfile: on "<< m_nSendPos << " up to : " << nMax2SendNow); - int n = m_pItem.get()->SendData(confd, m_filefd, m_nSendPos, nMax2SendNow); + int n = m_pItem.getFiPtr()->SendData(confd, m_filefd, m_nSendPos, nMax2SendNow); ldbg("~sendfile: " << n << " new m_nSendPos: " << m_nSendPos); if(n>0) @@ -876,7 +885,7 @@ if(m_nChunkRemainingBytes==0) GOTOENDE; // done - int n = m_pItem.get()->SendData(confd, m_filefd, m_nSendPos, m_nChunkRemainingBytes); + int n = m_pItem.getFiPtr()->SendData(confd, m_filefd, m_nSendPos, m_nChunkRemainingBytes); if(n<0) THROW_ERROR("400 Client error"); m_nChunkRemainingBytes-=n; @@ -895,11 +904,11 @@ /* Sends data from the local buffer, used for page or chunk headers. * -> DELICATE STATE, should not be interrupted by exception or throw * to another state path uncontrolled. */ - MYTRY + try { ldbg("prebuf sending: "<< m_sendbuf.c_str()); auto r=send(confd, m_sendbuf.rptr(), m_sendbuf.size(), - m_backstate == STATE_TODISCON ? 0 : MSG_MORE); + (haveMoreJobs && m_backstate != STATE_TODISCON) ? MSG_MORE : 0); if (r<0) { if (errno==EAGAIN || errno==EINTR || errno == ENOBUFS) @@ -910,40 +919,29 @@ m_sendbuf.drop(r); if(m_sendbuf.empty()) { - USRDBG("Returning to last state, " << m_backstate); + USRDBG("Returning to last state, " << (int) m_backstate); m_state=m_backstate; continue; } } - MYCATCH(...) + catch(...) { return R_DISCON; } return R_AGAIN; } - case(STATE_ALLDONE): - LOG("State: STATE_ALLDONE?"); - // no break + returnSomething("STATE_ALLDONE?"); case (STATE_ERRORCONT): - LOG("or STATE_ERRORCONT?"); - // no break + returnSomething("STATE_ERRORCONT?"); case(STATE_FINISHJOB): - LOG("or STATE_FINISHJOB"); - { - if(m_bClientWants2Close) - return R_DISCON; - LOG("Reporting job done") - return R_DONE; - } - break; + returnSomething("STATE_FINISHJOB?"); case(STATE_TODISCON): - // no break default: return R_DISCON; } } - MYCATCH(bad_alloc&) { + catch(bad_alloc&) { // TODO: report memory failure? return R_DISCON; } @@ -1001,13 +999,13 @@ // Handle If-Modified-Since and Range headers; // we deal with them equally but need to know which to use - const char *pIfmo = m_pReqHead->h[header::RANGE] ? - m_pReqHead->h[header::IFRANGE] : m_pReqHead->h[header::IF_MODIFIED_SINCE]; + const char *pIfmo = m_reqHead.h[header::RANGE] ? + m_reqHead.h[header::IFRANGE] : m_reqHead.h[header::IF_MODIFIED_SINCE]; const char *pLastMo = respHead.h[header::LAST_MODIFIED]; // consider contents "fresh" for non-volatile data, or when "our" special client is there, or the client simply doesn't care - bool bDataIsFresh = (m_type != rechecks::FILE_VOLATILE - || m_pReqHead->h[header::ACNGFSMARK] || !pIfmo); + bool bDataIsFresh = (m_type != rex::FILE_VOLATILE + || m_reqHead.h[header::ACNGFSMARK] || !pIfmo); auto tm1=tm(), tm2=tm(); bool bIfModSeenAndChecked=false; @@ -1033,7 +1031,7 @@ bool bPermitPartialStart = ( fistate >= fileitem::FIST_DLGOTHEAD && fistate <= fileitem::FIST_COMPLETE - && nGooddataSize >= ( m_nReqRangeFrom - acfg::maxredlsize)); + && nGooddataSize >= ( m_nReqRangeFrom - cfg::maxredlsize)); /* * make sure that our client doesn't just hang here while the download thread is @@ -1043,7 +1041,7 @@ if(fistate==fileitem::FIST_COMPLETE // or can start sending within this range (positive range-from) || bPermitPartialStart // don't care since found special hint from acngfs (kludge...) - || m_pReqHead->h[header::ACNGFSMARK] ) + || m_reqHead.h[header::ACNGFSMARK] ) { // detect errors, out-of-range case if(m_nReqRangeFrom>=nContLen || m_nReqRangeTotype==header::HEAD) + if(m_reqHead.type==header::HEAD) m_backstate=STATE_ALLDONE; // simulated head is prepared but don't send stuff return 0; @@ -1115,7 +1113,7 @@ LOGSTART("job::_SwitchToPtItem"); // exception-safe sequence m_pItem.RegisterFileitemLocalOnly(new tPassThroughFitem(m_sFileLoc)); - return m_pItem.get()->Setup(true); + return m_pItem.getFiPtr()->Setup(true); } @@ -1145,3 +1143,5 @@ //aclog::err(tSS() << "fileitem is now " << uintptr_t(m_pItem.get())); m_state=STATE_SEND_MAIN_HEAD; } + +} diff -Nru apt-cacher-ng-0.9.1/source/jsonstats.cc apt-cacher-ng-3.3.1/source/jsonstats.cc --- apt-cacher-ng-0.9.1/source/jsonstats.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/jsonstats.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -#include - -jsonstats::jsonstats(const tRunParms & parms) : expiration(parms) -{ -} - -jsonstats::~jsonstats() -{ -} - -#define CHECKABORT if(CheckStopSignal()) return; - -void jsonstats::Run() -{ - auto origFD = m_parms.fd; - m_parms.fd = -1; // no printing until we say so - SetCommonUserFlags(m_parms.cmd); - m_bIncompleteIsDamaged=StrHas(m_parms.cmd, "incomAsDamaged"); - DirectoryWalk(acfg::cachedir, this); - CHECKABORT - ProcessSeenMetaFiles(*this); - CHECKABORT - m_parms.fd = origFD; - SendChunkedPageHeader("200", "application/json"); - PrintJson(); -} - - -void jsonstats::PrintJson() -{ - SendChunk("{\n\t\"assignedSpace\": {\n"); - off_t total=0; - for(auto &f: m_metaFilesRel) - { - if(f.second.space<=0) - continue; - if(total != 0) - SendChunk(",\n"); - - total += f.second.space; - SendFmt << "\t\t\"" << f.first << "\": " << f.second.space; - } - SendFmt<< "\n\t},\n\t\"total\": " << total << "\n}"; -} - - -void jsonstats::Action() -{ -} diff -Nru apt-cacher-ng-0.9.1/source/lockable.cc apt-cacher-ng-3.3.1/source/lockable.cc --- apt-cacher-ng-0.9.1/source/lockable.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/lockable.cc 2020-01-08 19:58:26.000000000 +0000 @@ -1,49 +1,25 @@ -#define LOCAL_DEBUG #include "debug.h" #include #include "lockable.h" -#include -#include -#include -#include -bool lockable::tryLock() { - return EBUSY!=pthread_mutex_trylock(&m_obj_mutex); +#include + +namespace acng +{ +bool base_with_condition::wait_until(lockuniq& uli, time_t nUTCsecs, long msec) +{ + auto tpUTC = std::chrono::system_clock::from_time_t(nUTCsecs); + tpUTC += std::chrono::milliseconds(msec); + auto r = m_obj_cond.wait_until(uli._guard, tpUTC); + return std::cv_status::timeout == r; } -bool condition::wait_until(time_t nUTCsecs, long msec) +bool base_with_condition::wait_for(lockuniq& uli, long secs, long msec) { - if(nUTCsecs < 0 || msec < 0) - return false; // looks suspicious, report timeout, immediately - if(msec>=1000) - { - nUTCsecs += (msec/1000); - msec %=1000; - } - struct timespec timeout = {nUTCsecs, msec*1000}; - auto r = pthread_cond_timedwait(&m_obj_cond, &m_obj_mutex, &timeout); - -#ifdef _DARWIN_C_SOURCE - // From: Andrew Sharpe - // Date: Sat, 29 Dec 2012 19:21:11 +1000 - // ... - // kludge to work around what looks like wrapping issues - - // I'd like to know the implementation of pthread_cond_timedwait - // to get a definitive solution to this, as tracing through the - // headers on OSX lead me to believe that timespec.tv_sec is of - // type __darwin_time_t and that can handle values up to - // 9223372036854775807 (on this machine), however this - // implementation breaks with any value greater than - // 2147483647 (std::numeric_limits::max()) - - if (r==ETIMEDOUT && nUTCsecs == END_OF_TIME) - { - timeout.tv_sec = MAX_VAL(int); - r=pthread_cond_timedwait(&m_obj_cond, &m_obj_mutex, &timeout); - } -#endif + auto r = m_obj_cond.wait_for(uli._guard, std::chrono::milliseconds(msec + secs*1000)); + return std::cv_status::timeout == r; +} - return r==ETIMEDOUT; } diff -Nru apt-cacher-ng-0.9.1/source/maintenance.cc apt-cacher-ng-3.3.1/source/maintenance.cc --- apt-cacher-ng-0.9.1/source/maintenance.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/maintenance.cc 2020-01-08 19:58:26.000000000 +0000 @@ -7,7 +7,6 @@ #include "expiration.h" #include "pkgimport.h" #include "showinfo.h" -#include "jsonstats.h" #include "mirror.h" #include "aclogger.h" #include "filereader.h" @@ -29,6 +28,8 @@ #define MAINT_HTML_DECO "maint.html" +namespace acng { + tSpecialRequest::tSpecialRequest(const tRunParms& parms) : m_parms(parms) { @@ -198,7 +199,7 @@ case workTRUNCATECONFIRM: return "Manual File Truncation (Confirmed)"; case workCOUNTSTATS: return "Status Report With Statistics"; case workSTYLESHEET: return "CSS"; - case workJStats: return "Stats"; + // case workJStats: return "Stats"; } return "SpecialOperation"; } @@ -227,7 +228,7 @@ return workSTYLESHEET; // not starting like the maint page? - if(cmd.compare(spos, wlen, acfg::reportpage)) + if(cmd.compare(spos, wlen, cfg::reportpage)) return workNotSpecial; // ok, filename identical, also the end, or having a parameter string? @@ -238,7 +239,7 @@ // means needs authorization // all of the following need authorization if configured, enforce it - switch(acfg::CheckAdminAuth(auth)) + switch(cfg::CheckAdminAuth(auth)) { case 0: #ifdef HAVE_CHECKSUM @@ -268,7 +269,7 @@ {"doCount=", workCOUNTSTATS}, {"doTraceStart=", workTraceStart}, {"doTraceEnd=", workTraceEnd}, - {"doJStats", workJStats} +// {"doJStats", workJStats} }; for(auto& needle: matches) if(StrHasFrom(cmd, needle.trigger, epos)) @@ -314,21 +315,28 @@ return new tDeleter(parms, "Truncat"); case workSTYLESHEET: return new tStyleCss(parms); +#if 0 case workJStats: return new jsonstats(parms); +#endif } return nullptr; } void tSpecialRequest::RunMaintWork(eMaintWorkType jobType, cmstring& cmd, int fd) { - MYTRY { + if(cfg::DegradedMode() && jobType != workSTYLESHEET) + jobType = workUSERINFO; + + try { SHARED_PTR p; p.reset(MakeMaintWorker({fd, jobType, cmd})); if(p) p->Run(); } - MYCATCH(...) + catch(...) { } } + +} diff -Nru apt-cacher-ng-0.9.1/source/meta.cc apt-cacher-ng-3.3.1/source/meta.cc --- apt-cacher-ng-0.9.1/source/meta.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/meta.cc 2020-01-08 19:58:26.000000000 +0000 @@ -18,17 +18,22 @@ #ifdef HAVE_TOMCRYPT #include #endif + using namespace std; +namespace acng +{ cmstring sPathSep(SZPATHSEP); cmstring sPathSepUnix(SZPATHSEPUNIX); #ifndef MINIBUILD -cmstring sDefPortHTTP("80"); -cmstring sDefPortHTTPS("443"); +std::string ACNG_API sDefPortHTTP = "80", sDefPortHTTPS = "443"; #endif cmstring PROT_PFX_HTTPS(WITHLEN("https://")), PROT_PFX_HTTP(WITHLEN("http://")); cmstring FAKEDATEMARK(WITHLEN("Sat, 26 Apr 1986 01:23:39 GMT+3")); +cmstring hendl("
    \n"); + +std::atomic g_global_shutdown; /* int getUUID() { @@ -121,7 +126,7 @@ /*! * \brief Simple split function, outputs resulting tokens into a string vector, with or without purging the previous contents */ -tStrVec::size_type Tokenize(const string & in, const char *sep, +ACNG_API tStrVec::size_type Tokenize(const string & in, const char *sep, tStrVec & out, bool bAppend, std::string::size_type nStartOffset) { if(!bAppend) @@ -170,7 +175,7 @@ */ string::size_type pos = sOutVal.find(":"); - if (pos==string::npos) + if (AC_UNLIKELY(pos == 0 || pos==string::npos)) { //cerr << "Bad configuration directive found, looking for: " << szKey << ", found: "<< sOut << endl; return false; @@ -205,7 +210,7 @@ else if(0==strncasecmp(url.c_str(), "https://", 8)) { #ifndef HAVE_SSL - aclog::err("E_NOTIMPLEMENTED: SSL"); + log::err("E_NOTIMPLEMENTED: SSL"); return false; #else hStart=8; @@ -248,11 +253,11 @@ sHost=url.substr(hStart, hEndSuc-hStart); - // credentials might in there, strip them of + // credentials might be in there, strip them off l=sHost.rfind('@'); if(l!=mstring::npos) { - sUserPass=sHost.substr(0, l); + sUserPass = UrlUnescape(sHost.substr(0, l)); sHost.erase(0, l+1); } @@ -271,16 +276,22 @@ strip_ipv6_junk: + bool host_appears_to_be_ipv6 = false; if(sHost[0]=='[') { + host_appears_to_be_ipv6 = true; bCheckBrac=true; sHost.erase(0,1); } - if(sHost[sHost.length()-1]==']') + if (sHost[sHost.length()-1] == ']') { + bCheckBrac = !bCheckBrac; sHost.erase(sHost.length()-1); - else if(bCheckBrac) // must have been present here + } + if (bCheckBrac) // Unmatched square brackets. return false; + if (!host_appears_to_be_ipv6) + sHost = UrlUnescape(sHost); return true; @@ -315,7 +326,7 @@ #if defined(HAVE_WORDEXP) || defined(HAVE_GLOB) -tStrDeq ExpandFilePattern(cmstring& pattern, bool bSorted, bool bQuiet) +ACNG_API tStrDeq ExpandFilePattern(cmstring& pattern, bool bSorted, bool bQuiet) { tStrDeq srcs; #ifdef HAVE_WORDEXP @@ -575,6 +586,63 @@ return ret; } +/* From RFC3986 [0]: + * + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + * + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * + * authority = [ userinfo "@" ] host [ ":" port ] + * + * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + * + * 0: https://www.ietf.org/rfc/rfc3986.txt + */ +static bool is_allowed_unencoded_userinfo_char(char c) +{ + switch (c) { + // unreserved: + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': + case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': case '.': case '_': case '~': + // sub-delims: + case '!': case '$': case '&': case '\'': case '(': case ')': + case '*': case '+': case ',': case ';': case '=': + // colon: + case ':': + return true; + default: + return false; + } +} + +mstring UserinfoEscape(cmstring &s) +{ + mstring ret; + ret.reserve(s.size()); + + for (const auto& c : s) { + if (is_allowed_unencoded_userinfo_char(c)) { + ret += c; + } else { + char pct_encoded[4] = { '%', h2t_map[uint8_t(c) >> 4], + h2t_map[uint8_t(c) & 0x0f], '\0'}; + ret += pct_encoded; + } + } + + return ret; +} + mstring DosEscape(cmstring &s) { mstring ret; @@ -652,6 +720,9 @@ unsigned char_count=0; char alphabet[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; string out; + //int newLineAfter = textWidth * 3 / 4; + //int linePos=0; + for(auto p=data; p 0 && linePos++ >= newLineAfter) + { + linePos = 0; + out+='\n'; + } + */ } if (char_count != 0) { @@ -721,3 +799,198 @@ } #endif #endif + +mstring GetDirPart(cmstring &in) +{ + if(in.empty()) + return sEmptyString; + + tStrPos end = in.find_last_of(CPATHSEP); + if(end == stmiss) // none? don't care then + return sEmptyString; + + return in.substr(0, end+1); +} + +std::pair SplitDirPath(cmstring& in) + { +auto dir=GetDirPart(in); +return std::pair(dir, in.substr(dir.length())); + } + + +LPCSTR GetTypeSuffix(cmstring& s) +{ + auto pos = s.find_last_of("/."); + auto p = s.c_str(); + return pos == stmiss ? p + s.length() : p + pos; +} + +off_t ACNG_API atoofft(LPCSTR p) +{ + using namespace std; + if(sizeof(long long) == sizeof(off_t)) + return atoll(p); + if(sizeof(int) == sizeof(off_t)) + return atoi(p); + return atol(p); +} + +mstring UrlUnescape(cmstring &from) +{ + mstring ret; // let the compiler optimize + UrlUnescapeAppend(from, ret); + return ret; +} +//mstring DosEscape(cmstring &s); +// just the bare minimum to make sure the string does not break HTML formating +mstring html_sanitize(cmstring& in) +{ + mstring ret; + for(auto c:in) + ret += ( strchr("<>'\"&;", (unsigned) c) ? '_' : c); + return ret; +} + +mstring offttos(off_t n) +{ + char buf[21]; + int len=snprintf(buf, 21, OFF_T_FMT, n); + return mstring(buf, len); +} + +mstring ltos(long n) +{ + char buf[21]; + int len=snprintf(buf, 21, "%ld", n); + return mstring(buf, len); +} + +/** + * Human friendly presentation of numbers, with units and only few bytes after comma + */ +mstring offttosH(off_t n) +{ + LPCSTR pref[]={"", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB"}; + for(unsigned i=0;i<_countof(pref)-1; i++) + { + if(n<1024) + return ltos(n)+pref[i]; + if(n<10000) + return ltos(n/1000)+"."+ltos((n%1000)/100)+pref[i+1]; + + n/=1024; + } + return "INF"; +} + +mstring offttosHdotted(off_t n) +{ + mstring ret(to_string(n)); + auto pos = ret.size()-1; + for(unsigned i=1; pos > 0; ++i, --pos) + if(0 == i%3) + ret.insert(pos, "."); + return ret; +} + + +//template +off_t strsizeToOfft(const char *sizeString) // XXX: if needed... charp sizeString, charp *next) +{ + char *inext(0); + auto val = strtoull(sizeString, &inext, 10); + if(!val) return 0; + if(!*inext) return val; // full length + // trim + while(*inext && isspace((unsigned)*inext)) ++inext; + switch(*inext) + { + case 'k': return val * 1000; + case 'm': return val * 1000000; + case 'g': return val * 1000000*1000; + case 'p': return val * 1000000*1000000; + + case 'K': return val * 1024; + case 'M': return val * 1024*1024; + case 'G': return val * 1024*1024*1024; + case 'P': return val * 1024*1024*1024*1024; + } + return val; +} + +void replaceChars(mstring &s, LPCSTR szBadChars, char goodChar) +{ + for(mstring::iterator p=s.begin();p!=s.end();p++) + for(LPCSTR b=szBadChars;*b;b++) + if(*b==*p) + { + *p=goodChar; + break; + } +} + +void addUnEscaped(mstring& s, const char p) +{ + switch (p) + { + case '0': + s += '\0'; break; + case 'a': + s += '\a'; break; + case 'b': + s += '\b'; break; + case 't': + s += '\t'; break; + case 'n': + s += '\n'; break; + case 'r': + s += '\r'; break; + case 'v': + s += '\v'; break; + case 'f': + s += '\f'; break; + case '\\': + s += '\\'; break; + default: + s += '\\'; s += p; break; + } +} + +mstring unEscape(cmstring &s) +{ + mstring ret; + for(cmstring::const_iterator it=s.begin();it!=s.end();++it) + { + if(*it != '\\') ret+= *it; + else if(++it == s.end()) { ret+='\\'; break; } + else addUnEscaped(ret, *it); + } + return ret; +} + +unsigned FormatTime(char *buf, size_t bufLen, const time_t cur) +{ + if(bufLen < 26) + return 0; + struct tm tmp; + gmtime_r(&cur, &tmp); + asctime_r(&tmp, buf); + //memcpy(buf + 24, " GMT", 4); // wrong, only needed for rfc-822 format, not for asctime's + //return 28; + buf[24]=0; + return 24; +} + +bool scaseequals(cmstring& a, cmstring& b) +{ + auto len = a.size(); + if (b.size() != len) + return false; + for (unsigned i = 0; i < len; ++i) + if (tolower((unsigned) a[i]) != tolower((unsigned)b[i])) + return false; + return true; +} + +} diff -Nru apt-cacher-ng-0.9.1/source/mirror.cc apt-cacher-ng-3.3.1/source/mirror.cc --- apt-cacher-ng-0.9.1/source/mirror.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/mirror.cc 2020-01-08 19:58:26.000000000 +0000 @@ -21,6 +21,8 @@ using namespace std; +namespace acng +{ bool pkgmirror::ProcessRegular(const string &sPath, const struct stat &) { if (endsWithSzAr(sPath, ".head")) @@ -62,7 +64,7 @@ void pkgmirror::Action() { - if(acfg::mirrorsrcs.empty()) + if(cfg::mirrorsrcs.empty()) { SendChunk("PrecacheFor not set, check configuration!
    \n"); return; @@ -70,12 +72,8 @@ SendChunk("Locating index files, scanning...
    \n"); - SetCommonUserFlags(m_parms.cmd); - m_bErrAbort=false; // does not f...ing matter, do what we can - m_bCalcSize=(m_parms.cmd.find("calcSize=cs")!=stmiss); m_bDoDownload=(m_parms.cmd.find("doDownload=dd")!=stmiss); - m_bSkipIxUpdate=(m_parms.cmd.find("skipIxUp=si")!=stmiss); m_bAsNeeded=(m_parms.cmd.find("asNeeded=an")!=stmiss); m_bUseDelta=(m_parms.cmd.find("useDebDelta=ud")!=stmiss); @@ -95,7 +93,7 @@ if(m_bUseDelta) StartDlder(); - DirectoryWalk(acfg::cachedir, this); + BuildCacheFileList(); if(CheckStopSignal()) return; @@ -117,29 +115,21 @@ // prepare wildcard matching and collecting tStrSet srcs; - class __srcpicker : public ifileprocessor - { - public: - tStrSet *pSrcs; - tStrVec matchList; - __srcpicker(tStrSet *x) : pSrcs(x) - { - Tokenize(acfg::mirrorsrcs, SPACECHARS, matchList); - }; - void TryAdd(cmstring &s) - { - for(const auto& match : matchList) - if(0==fnmatch(match.c_str(), s.c_str(), FNM_PATHNAME)) - { - pSrcs->insert(s); - break; - } - } - void HandlePkgEntry(const tRemoteFileInfo &entry) - { - TryAdd(entry.sDirectory+entry.sFileName); - } - } picker(&srcs); + tStrVec matchList; + Tokenize(cfg::mirrorsrcs, SPACECHARS, matchList); + auto TryAdd = [&matchList, &srcs](cmstring &s) + { + for(const auto& match : matchList) + if(0==fnmatch(match.c_str(), s.c_str(), FNM_PATHNAME)) + { +#ifdef COMPATGCC47 + srcs.insert(s); +#else + srcs.emplace(s); +#endif + break; + } + }; mstring sErr; @@ -151,24 +141,26 @@ { if(!m_bSkipIxUpdate && !GetFlags((cmstring)path2x.first).uptodate) Download((cmstring)path2x.first, true, eMsgShow); - ParseAndProcessMetaFile(picker, (cmstring) path2x.first, EIDX_RELEASE); + ParseAndProcessMetaFile([&TryAdd](const tRemoteFileInfo &entry) { + TryAdd(entry.sDirectory+entry.sFileName); }, + (cmstring) path2x.first, EIDX_RELEASE); } else - picker.TryAdd((cmstring)path2x.first); + TryAdd((cmstring)path2x.first); } SendChunk("Identifying more index files in cache...
    "); // unless found in release files, get the from the local system - for (const auto& match: picker.matchList) + for (const auto& match: matchList) for(const auto& path : ExpandFilePattern(CACHE_BASE+match, false)) - picker.TryAdd(path); + TryAdd(path); auto delBros = [&srcs](cmstring& mine) { string base; int nDeleted = 0; cmstring* pMySuf=nullptr; - for(const auto& suf: compSuffixesAndEmpty) + for(const auto& suf: sfxXzBz2GzLzmaNone) { if(endsWith(mine, suf)) { @@ -177,7 +169,7 @@ break; } } - for(const auto& suf : compSuffixesAndEmpty) + for(const auto& suf : sfxXzBz2GzLzmaNone) { if(&suf == pMySuf) continue; @@ -199,7 +191,7 @@ // now there may still be something like Sources and Sources.bz2 if they // were added by Release file scan. Choose the preferred one simply by extension. restart_clean2: // start over if the set changed while having a hot iterator - for (const auto& s: compSuffixesAndEmptyByRatio) + for (const auto& s: sfxXzBz2GzLzma) for (const auto& src : srcs) if (endsWith(src, s)&& delBros(src)) // this is the one goto restart_clean2; @@ -232,12 +224,13 @@ for (auto& src : srcs) { #ifdef DEBUG - if(LOG_MORE&acfg::debug) + if(log::LOG_MORE & cfg::debug) SendFmt << "mirror check: " << src; #endif off_t needBefore=(m_totalSize-m_totalHave); - ParseAndProcessMetaFile(*this, src, GuessMetaTypeFromURL(src)); + ParseAndProcessMetaFile([this](const tRemoteFileInfo &e) { + HandlePkgEntry(e); }, src, GuessMetaTypeFromURL(src)); SendFmt << src << ": " << offttosH((m_totalSize-m_totalHave)-needBefore) @@ -267,7 +260,8 @@ if(CheckStopSignal()) return; ConfigDelta(src); - ParseAndProcessMetaFile(*this, src, GuessMetaTypeFromURL(src)); + ParseAndProcessMetaFile([this](const tRemoteFileInfo &e) { + HandlePkgEntry(e); }, src, GuessMetaTypeFromURL(src)); } } } @@ -288,9 +282,9 @@ if (m_repCutLen != stmiss) { vname.resize(m_repCutLen); - const acfg::tRepoData *pRepo = acfg::GetRepoData(vname); + const cfg::tRepoData *pRepo = cfg::GetRepoData(vname); #ifdef DEBUG - if(acfg::debug & LOG_MORE) + if(cfg::debug & log::LOG_MORE) { if(!pRepo) SendFmt << "hm, no delta provider for " << sPathRel; @@ -480,3 +474,5 @@ } } } + +} diff -Nru apt-cacher-ng-0.9.1/source/pkgimport.cc apt-cacher-ng-3.3.1/source/pkgimport.cc --- apt-cacher-ng-0.9.1/source/pkgimport.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/pkgimport.cc 2020-01-08 19:58:26.000000000 +0000 @@ -23,6 +23,8 @@ #define SCACHEFILE (CACHE_BASE+"_impkeycache") #define FMTSIG "FMT5" +namespace acng +{ /* * Algorithm: * @@ -46,14 +48,10 @@ } */ -bool pkgimport::ProcessRegular(cmstring &sPath, const struct stat &stinfo) +bool pkgimport::ProcessRegular(const mstring &sPath, const struct stat &stinfo) { + if(CheckStopSignal()) return false; - { - lockguard g(&abortMx); - if(bSigTaskAbort) - return false; - } if(endsWithSzAr(sPath, ".head")) return true; @@ -69,7 +67,7 @@ AddIFileCandidate(sPath.substr(CACHE_BASE_LEN)); } - else if(rechecks::FILE_INVALID != rechecks::GetFiletype(sPath)) + else if(rex::FILE_INVALID != rex::GetFiletype(sPath)) { // get a fingerprint by checksumming if not already there from the fpr cache @@ -179,9 +177,7 @@ m_sSrcPath=CACHE_BASE+"_import"; SendFmt << "Importing from " << m_sSrcPath << " directory.
    Scanning local files...
    "; - - SetCommonUserFlags(m_parms.cmd); - m_bErrAbort=false; // does not f...ing matter, do what we can + m_bByPath=true; // should act on all locations _LoadKeyCache(); @@ -191,13 +187,9 @@ <<" from the fingerprint cache
    \n"); m_bLookForIFiles=true; - DirectoryWalk(acfg::cachedir, this, true); - { - lockguard g(&abortMx); - if(bSigTaskAbort) - return; - } + BuildCacheFileList(); + if(CheckStopSignal()) return; if(m_metaFilesRel.empty()) { @@ -207,12 +199,7 @@ UpdateVolatileFiles(); - - { - lockguard g(&abortMx); - if(bSigTaskAbort) - return; - } + if(CheckStopSignal()) return; if(m_bErrAbort && m_nErrorCount>0) { @@ -223,12 +210,7 @@ m_bLookForIFiles=false; DBGQLOG("building contents map for " << m_sSrcPath); DirectoryWalk(m_sSrcPath, this, true); - - { - lockguard g(&abortMx); - if(bSigTaskAbort) - return; - } + if(CheckStopSignal()) return; if(m_importMap.empty()) { @@ -236,13 +218,10 @@ return; } - ProcessSeenMetaFiles(*this); + ProcessSeenIndexFiles([this](const tRemoteFileInfo &e) { + HandlePkgEntry(e); }); - { - lockguard g(&abortMx); - if(bSigTaskAbort) - return; - } + if(CheckStopSignal()) return; ofstream fList; fList.open(SCACHEFILE.c_str(), ios::out | ios::trunc); @@ -308,7 +287,7 @@ return; string sDestAbs=CACHE_BASE; - if(acfg::stupidfs) + if(cfg::stupidfs) sDestAbs+=DosEscape(entry.sDirectory+entry.sFileName); else sDestAbs+=(entry.sDirectory+entry.sFileName); @@ -366,7 +345,7 @@ h.type=header::ANSWER; if (h.StoreToFile(sDestAbs+".head")<=0) { - aclog::err("Unable to store generated header"); + log::err("Unable to store generated header"); return; // junk may remain but that's a job for cleanup later } hit->second.bFileUsed=true; @@ -462,3 +441,5 @@ } */ + +} diff -Nru apt-cacher-ng-0.9.1/source/rfc2553emu.cc apt-cacher-ng-3.3.1/source/rfc2553emu.cc --- apt-cacher-ng-0.9.1/source/rfc2553emu.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/rfc2553emu.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -// -*- mode: cpp; mode: fold -*- -// Description /*{{{*/ -// $Id: rfc2553emu.cc,v 1.8 2001/02/20 07:03:18 jgg Exp $ -/* ###################################################################### - - RFC 2553 Emulation - Provides emulation for RFC 2553 getaddrinfo, - freeaddrinfo and getnameinfo - - This is really C code, it just has a .cc extensions to play nicer with - the rest of APT. - - Originally written by Jason Gunthorpe and placed into - the Public Domain, do with it what you will. - - ##################################################################### */ - /*}}}*/ -#include "rfc2553emu.h" -#include -#include -#include -#include -#include - -#ifndef HAVE_GETADDRINFO -// getaddrinfo - Resolve a hostname /*{{{*/ -// --------------------------------------------------------------------- -/* */ -int getaddrinfo(const char *nodename, const char *servname, - const struct addrinfo *hints, - struct addrinfo **res) -{ - struct addrinfo **Result = res; - hostent *Addr; - unsigned int Port; - int Proto; - const char *End; - char **CurAddr; - - // Try to convert the service as a number - Port = htons(strtol(servname,(char **)&End,0)); - Proto = SOCK_STREAM; - - if (hints != 0 && hints->ai_socktype != 0) - Proto = hints->ai_socktype; - - // Not a number, must be a name. - if (End != servname + strlen(servname)) - { - struct servent *Srv = 0; - - // Do a lookup in the service database - if (hints == 0 || hints->ai_socktype == SOCK_STREAM) - Srv = getservbyname(servname,"tcp"); - if (hints != 0 && hints->ai_socktype == SOCK_DGRAM) - Srv = getservbyname(servname,"udp"); - if (Srv == 0) - return EAI_NONAME; - - // Get the right protocol - Port = Srv->s_port; - if (strcmp(Srv->s_proto,"tcp") == 0) - Proto = SOCK_STREAM; - else - { - if (strcmp(Srv->s_proto,"udp") == 0) - Proto = SOCK_DGRAM; - else - return EAI_NONAME; - } - - if (hints != 0 && hints->ai_socktype != Proto && - hints->ai_socktype != 0) - return EAI_SERVICE; - } - - // Hostname lookup, only if this is not a listening socket - if (hints != 0 && (hints->ai_flags & AI_PASSIVE) != AI_PASSIVE) - { - Addr = gethostbyname(nodename); - if (Addr == 0) - { - if (h_errno == TRY_AGAIN) - return EAI_AGAIN; - if (h_errno == NO_RECOVERY) - return EAI_FAIL; - return EAI_NONAME; - } - - // No A records - if (Addr->h_addr_list[0] == 0) - return EAI_NONAME; - - CurAddr = Addr->h_addr_list; - } - else - CurAddr = (char **)&End; // Fake! - - // Start constructing the linked list - *res = 0; - for (; *CurAddr != 0; CurAddr++) - { - // New result structure - *Result = (struct addrinfo *)calloc(sizeof(**Result),1); - if (*Result == 0) - { - freeaddrinfo(*res); - return EAI_MEMORY; - } - if (*res == 0) - *res = *Result; - - (*Result)->ai_family = AF_INET; - (*Result)->ai_socktype = Proto; - - // If we have the IPPROTO defines we can set the protocol field - #ifdef IPPROTO_TCP - if (Proto == SOCK_STREAM) - (*Result)->ai_protocol = IPPROTO_TCP; - if (Proto == SOCK_DGRAM) - (*Result)->ai_protocol = IPPROTO_UDP; - #endif - - // Allocate space for the address - (*Result)->ai_addrlen = sizeof(struct sockaddr_in); - (*Result)->ai_addr = (struct sockaddr *)calloc(sizeof(sockaddr_in),1); - if ((*Result)->ai_addr == 0) - { - freeaddrinfo(*res); - return EAI_MEMORY; - } - - // Set the address - ((struct sockaddr_in *)(*Result)->ai_addr)->sin_family = AF_INET; - ((struct sockaddr_in *)(*Result)->ai_addr)->sin_port = Port; - - if (hints != 0 && (hints->ai_flags & AI_PASSIVE) != AI_PASSIVE) - ((struct sockaddr_in *)(*Result)->ai_addr)->sin_addr = *(in_addr *)(*CurAddr); - else - { - // Already zerod by calloc. - break; - } - - Result = &(*Result)->ai_next; - } - - return 0; -} - /*}}}*/ -// freeaddrinfo - Free the result of getaddrinfo /*{{{*/ -// --------------------------------------------------------------------- -/* */ -void freeaddrinfo(struct addrinfo *ai) -{ - struct addrinfo *Tmp; - while (ai != 0) - { - free(ai->ai_addr); - Tmp = ai; - ai = ai->ai_next; - free(ai); - } -} - /*}}}*/ -#endif // HAVE_GETADDRINFO - -#ifndef HAVE_GETNAMEINFO -// getnameinfo - Convert a sockaddr to a string /*{{{*/ -// --------------------------------------------------------------------- -/* */ -int getnameinfo(const struct sockaddr *sa, socklen_t salen, - char *host, size_t hostlen, - char *serv, size_t servlen, - int flags) -{ - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - // This routine only supports internet addresses - if (sa->sa_family != AF_INET) - return EAI_ADDRFAMILY; - - if (host != 0) - { - // Try to resolve the hostname - if ((flags & NI_NUMERICHOST) != NI_NUMERICHOST) - { - struct hostent *Ent = gethostbyaddr((char *)&sin->sin_addr,sizeof(sin->sin_addr), - AF_INET); - if (Ent != 0) - strncpy(host,Ent->h_name,hostlen); - else - { - if ((flags & NI_NAMEREQD) == NI_NAMEREQD) - { - if (h_errno == TRY_AGAIN) - return EAI_AGAIN; - if (h_errno == NO_RECOVERY) - return EAI_FAIL; - return EAI_NONAME; - } - - flags |= NI_NUMERICHOST; - } - } - - // Resolve as a plain numberic - if ((flags & NI_NUMERICHOST) == NI_NUMERICHOST) - { - strncpy(host,inet_ntoa(sin->sin_addr),hostlen); - } - } - - if (serv != 0) - { - // Try to resolve the hostname - if ((flags & NI_NUMERICSERV) != NI_NUMERICSERV) - { - struct servent *Ent; - if ((flags & NI_DATAGRAM) == NI_DATAGRAM) - Ent = getservbyport(ntohs(sin->sin_port),"udp"); - else - Ent = getservbyport(ntohs(sin->sin_port),"tcp"); - - if (Ent != 0) - strncpy(serv,Ent->s_name,servlen); - else - { - if ((flags & NI_NAMEREQD) == NI_NAMEREQD) - return EAI_NONAME; - - flags |= NI_NUMERICSERV; - } - } - - // Resolve as a plain numberic - if ((flags & NI_NUMERICSERV) == NI_NUMERICSERV) - { - snprintf(serv,servlen,"%u",ntohs(sin->sin_port)); - } - } - - return 0; -} - /*}}}*/ -#endif // HAVE_GETNAMEINFO diff -Nru apt-cacher-ng-0.9.1/source/showinfo.cc apt-cacher-ng-3.3.1/source/showinfo.cc --- apt-cacher-ng-0.9.1/source/showinfo.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/showinfo.cc 2020-01-08 19:58:26.000000000 +0000 @@ -22,6 +22,12 @@ #undef SendFmtRemote #endif +#define SCALEFAC 250 + + +namespace acng +{ + static cmstring sReportButton("
    " "
    " "" @@ -48,8 +54,8 @@ const char *pr(nullptr), *pend(nullptr); if(!m_bFatalError) { - m_bFatalError = ! ( fr.OpenFile(acfg::confdir+SZPATHSEP+m_sFileName, true) || - (!acfg::suppdir.empty() && fr.OpenFile(acfg::suppdir+SZPATHSEP+m_sFileName, true))); + m_bFatalError = ! ( fr.OpenFile(cfg::confdir+SZPATHSEP+m_sFileName, true) || + (!cfg::suppdir.empty() && fr.OpenFile(cfg::suppdir+SZPATHSEP+m_sFileName, true))); } if(m_bFatalError) { @@ -131,6 +137,8 @@ return; } + auto del = (m_parms.type == workDELETE); + mstring params(m_parms.cmd, qpos+1); mstring blob; for(tSplitWalk split(¶ms, "&"); split.Next();) @@ -139,7 +147,7 @@ if(startsWithSz(tok, "kf=")) { char *end(0); - auto val = strtoul(tok.c_str()+3, &end, 16); + auto val = strtoul(tok.c_str()+3, &end, 36); if(*end == 0 || *end=='&') #ifdef COMPATGCC47 files.insert(val); @@ -151,11 +159,14 @@ tok.swap(blob); } sHidParms << "\n"; tStrDeq filePaths; acbuf buf; + mstring redoLink; + #ifdef HAVE_DECB64 // this page isn't accessible with crippled configuration anyway if (!blob.empty()) { @@ -189,7 +200,9 @@ buf.drop(sizeof(unsigned)); if(slen > buf.size()) // looks fishy return; - if(ContHas(files, id)) + if(redoLink.empty()) // don't care about id in the first line + redoLink.assign(buf.rptr(), slen); + else if(ContHas(files, id)) filePaths.emplace_back(buf.rptr(), slen); buf.drop(slen); } @@ -198,39 +211,81 @@ for(const auto& path : filePaths) { if(path.find_first_of(BADCHARS)!=stmiss // what the f..., XSS attempt? - || rechecks::Match(path, rechecks::NASTY_PATH)) + || rex::Match(path, rex::NASTY_PATH)) { m_bFatalError=true; return; } } + // XXX: this is wasting some CPU cycles but is good enough for this case + for (const auto& path : filePaths) + { + mstring bname(path); + for(const auto& sfx: sfxXzBz2GzLzma) + if(endsWith(path, sfx)) + bname = path.substr(0, path.size()-sfx.size()); + auto tryAdd=[this,&bname,&path](cmstring& sfx) + { + auto cand = bname+sfx; + if(cand == path || ::access(SZABSPATH(cand), F_OK)) + return; + extraFiles.push_back(cand); + }; + for(const auto& sfx: sfxMiscRelated) + tryAdd(sfx); + if(endsWith(path, relKey)) + tryAdd(path.substr(0, path.size()-relKey.size())+inRelKey); + if(endsWith(path, inRelKey)) + tryAdd(path.substr(0, path.size()-inRelKey.size())+relKey); + } + + if (m_parms.type == workDELETECONFIRM || m_parms.type == workTRUNCATECONFIRM) { for (const auto& path : filePaths) sHidParms << html_sanitize(path) << "
    \n"; for (const auto& pathId : files) - sHidParms << "\n" << tSS::fmtflags::dec; + sHidParms << "\n"; + if(m_parms.type == workDELETECONFIRM && !extraFiles.empty()) + { + sHidParms << sBRLF << "Extra files found" << sBRLF + << "

    It's recommended to delete the related files (see below) as well, otherwise " + << "the removed files might be resurrected by recovery mechanisms later.

    " + << "" + << "Yes, please remove all related files

    Example list:

    "; + for (const auto& path : extraFiles) + sHidParms << path << sBRLF; + } } else { - auto del = (m_parms.type == workDELETE); for (const auto& path : filePaths) { - for (auto suf : - { "", ".head" }) - { - sHidParms << (del ? "Deleting " : "Truncating ") << path << suf << "
    \n"; - auto p = acfg::cacheDirSlash + path + suf; - int r = del ? unlink(p.c_str()) : truncate(p.c_str(), 0); - if (r && errno != ENOENT) + auto doFile=[this, &del](cmstring& path) + { + for (auto suf : { "", ".head" }) { - tErrnoFmter ferrno("[ error: "); - sHidParms << ferrno << " ]
    \n"; + sHidParms << (del ? "Deleting " : "Truncating ") << path << suf << "
    \n"; + auto p = cfg::cacheDirSlash + path + suf; + int r = del ? unlink(p.c_str()) : truncate(p.c_str(), 0); + if (r && errno != ENOENT) + { + tErrnoFmter ferrno("[ error: "); + sHidParms << ferrno << " ]" << sBRLF; + } + if(!del) + break; } - } + }; + doFile(path); + if(StrHas(m_parms.cmd, "cleanRelated=")) + for (const auto& path : extraFiles) + doFile(path); + } + sHidParms << "
    Repeat the last action
    " << sBRLF; } } @@ -239,9 +294,9 @@ { if(StrHas(parms.cmd, "doTraceStart")) - acfg::patrace=true; + cfg::patrace=true; else if(StrHas(parms.cmd, "doTraceStop")) - acfg::patrace=false; + cfg::patrace=false; else if(StrHas(parms.cmd, "doTraceClear")) { auto& tr(tTraceData::getInstance()); @@ -260,12 +315,12 @@ if(PFXCMP(id, len, "cfg:")) { string key(id+4, len-4); - auto p=acfg::GetIntPtr(key.c_str()); + auto p=cfg::GetIntPtr(key.c_str()); if(p) return ! *p; - if(key == "degraded") - return acfg::degraded.load(); - return -1; + if(key == "degraded") + return cfg::DegradedMode(); + return -1; } if(RAWEQ(id, len, "delConfirmed")) return m_parms.type != workDELETE && m_parms.type != workTRUNCATE; @@ -303,11 +358,11 @@ { if(!StrHas(m_parms.cmd, "doCount")) return SendChunk(sReportButton); - return SendChunk(aclog::GetStatReport()); + return SendChunk(log::GetStatReport()); } static cmstring defStringChecked("checked"); if(key == "aOeDefaultChecked") - return SendChunk(acfg::exfailabort ? defStringChecked : sEmptyString); + return SendChunk(cfg::exfailabort ? defStringChecked : sEmptyString); if(key == "curPatTraceCol") { m_fmtHelper.clear(); @@ -349,10 +404,10 @@ if (startsWithSz(key, "cfg:")) { auto ckey=key.c_str() + 4; - auto ps(acfg::GetStringPtr(ckey)); + auto ps(cfg::GetStringPtr(ckey)); if(ps) return SendChunk(*ps); - auto pi(acfg::GetIntPtr(ckey)); + auto pi(cfg::GetIntPtr(ckey)); if(pi) return SendChunk(m_fmtHelper.clean() << *pi); return; @@ -371,4 +426,57 @@ } if(key=="random") return SendChunk(m_fmtHelper.clean() << rand()); + if(key=="dataInHuman") + { + auto stats = log::GetCurrentCountersInOut(); + return SendChunk(offttosH(stats.first)); + } + if(key=="dataOutHuman") + { + auto stats = log::GetCurrentCountersInOut(); + return SendChunk(offttosH(stats.second)); + } + if(key=="dataIn") + { + auto stats = log::GetCurrentCountersInOut(); + auto statsMax = std::max(stats.first, stats.second); + auto pixels = statsMax ? (stats.first * SCALEFAC / statsMax) : 0; + return SendChunk(m_fmtHelper.clean() << pixels); + } + if(key=="dataOut") + { + auto stats = log::GetCurrentCountersInOut(); + auto statsMax = std::max(stats.second, stats.first); + auto pixels = statsMax ? (SCALEFAC * stats.second / statsMax) : 0; + return SendChunk(m_fmtHelper.clean() << pixels); + } + + if (key == "dataHistInHuman") + { + auto stats = pairSum(log::GetCurrentCountersInOut(), log::GetOldCountersInOut()); + return SendChunk(offttosH(stats.first)); + } + if (key == "dataHistOutHuman") + { + auto stats = pairSum(log::GetCurrentCountersInOut(), log::GetOldCountersInOut()); + return SendChunk(offttosH(stats.second)); + } + if (key == "dataHistIn") + { + auto stats = pairSum(log::GetCurrentCountersInOut(), log::GetOldCountersInOut()); + auto statsMax = std::max(stats.second, stats.first); + auto pixels = statsMax ? (stats.first * SCALEFAC / statsMax) : 0; + return SendChunk(m_fmtHelper.clean() << pixels); + } + if (key == "dataHistOut") + { + auto stats = pairSum(log::GetCurrentCountersInOut(), log::GetOldCountersInOut()); + auto statsMax = std::max(stats.second, stats.first); + auto pixels = statsMax ? (SCALEFAC * stats.second/statsMax) : 0; + return SendChunk(m_fmtHelper.clean() << pixels); + } + + +} + } diff -Nru apt-cacher-ng-0.9.1/source/sockio.cc apt-cacher-ng-3.3.1/source/sockio.cc --- apt-cacher-ng-0.9.1/source/sockio.cc 1970-01-01 00:00:00.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/sockio.cc 2020-01-08 19:58:26.000000000 +0000 @@ -0,0 +1,96 @@ + +#include "meta.h" +#include "sockio.h" +#include "debug.h" +#include + +namespace acng +{ +using namespace std; + +// those data structures are used by main thread only +// helper structure with metadata which can be passed around +unordered_map g_discoTimeouts; +char crapbuf[40]; + +void termsocket_now(int fd, void *p = nullptr) +{ + ::shutdown(fd, SHUT_RD); + forceclose(fd); + g_discoTimeouts.erase(fd); + if(p) event_free((event*)p); +} + +void linger_read(int fd, short what, void *p) +{ + if ((what & EV_TIMEOUT) || !(what & EV_READ)) + return termsocket_now(fd, p); + // ok, have to read junk or terminating zero-read + while (true) + { + int r = recv(fd, crapbuf, sizeof(crapbuf), MSG_WAITALL); + if (0 == r) + return termsocket_now(fd, p); + if (r < 0) + { + if (errno == EAGAIN) + { + // come again later + CTimeVal exp; + event_add((event*) p, exp.Remaining(g_discoTimeouts[fd])); + return; + } + if (errno == EINTR) + continue; + // some other error? Kill it + return termsocket_now(fd, p); + } + } +} + +/*! \brief Helper to flush data stream contents reliable and close the connection then + * DUDES, who write TCP implementations... why can this just not be done easy and reliable? Why do we need hacks like the method below? + For details, see: http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable + * Using SO_LINGER is also dangerous, see https://www.nybek.com/blog/2015/04/29/so_linger-on-non-blocking-sockets + * + */ +void termsocket_async(int fd, event_base* base) +{ + event* ev(nullptr); + try + { + LOGSTART2s("::termsocket", fd); + if (!fd) + return; + // initiate shutdown, i.e. sending FIN and giving the remote some time to confirm + ::shutdown(fd, SHUT_WR); + int r = read(fd, crapbuf, sizeof(crapbuf)); + if (r == 0) // fine, we are done + return termsocket_now(fd, nullptr); + LOG("waiting for peer to react"); + auto ev = event_new(base, fd, EV_READ, linger_read, + event_self_cbarg()); + g_discoTimeouts[fd] = GetTime() + cfg::discotimeout; + struct timeval tmout { cfg::discotimeout, 42 }; + if (ev && 0 == event_add(ev, &tmout)) + return; // will cleanup in the callbacks + } catch (...) + { + } + // error cleanup... EOM? + if (ev) + event_free(ev); + justforceclose(fd); +} + +void set_connect_sock_flags(evutil_socket_t fd) +{ +#ifndef NO_TCP_TUNNING + int yes(1); + ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); +#endif + evutil_make_socket_nonblocking(fd); +} + +} diff -Nru apt-cacher-ng-0.9.1/source/tcpconnect.cc apt-cacher-ng-3.3.1/source/tcpconnect.cc --- apt-cacher-ng-0.9.1/source/tcpconnect.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/source/tcpconnect.cc 2020-01-08 19:58:26.000000000 +0000 @@ -19,6 +19,8 @@ #include "fileio.h" #include "fileitem.h" #include "cleaner.h" +#include "dnsiter.h" +#include "evabase.h" #include using namespace std; @@ -32,17 +34,26 @@ #endif #ifdef HAVE_SSL -#include -#include -#include +#include +#include "openssl/bio.h" +#include "openssl/ssl.h" +#include "openssl/err.h" +#include +#include +#include +#include +#include #endif -std::atomic_uint dl_con_factory::g_nconns(0); -dl_con_factory g_tcp_con_factory; +namespace acng +{ + +ACNG_API std::atomic_uint dl_con_factory::g_nconns(0); +ACNG_API dl_con_factory g_tcp_con_factory; -tcpconnect::tcpconnect(acfg::tRepoData::IHookHandler *pObserver) : m_pStateObserver(pObserver) +tcpconnect::tcpconnect(cfg::tRepoData::IHookHandler *pObserver) : m_pStateObserver(pObserver) { - if(acfg::maxdlspeed != RESERVED_DEFVAL) + if(cfg::maxdlspeed != cfg::RESERVED_DEFVAL) dl_con_factory::g_nconns.fetch_add(1); if(pObserver) pObserver->OnAccess(); @@ -52,7 +63,7 @@ { LOGSTART("tcpconnect::~tcpconnect, terminating outgoing connection class"); Disconnect(); - if(acfg::maxdlspeed != RESERVED_DEFVAL) + if(cfg::maxdlspeed != cfg::RESERVED_DEFVAL) dl_con_factory::g_nconns.fetch_add(-1); #ifdef HAVE_SSL if(m_ctx) @@ -69,112 +80,11 @@ } } -/*! \brief Helper to flush data stream contents reliable and close the connection then - * DUDES, who write TCP implementations... why can this just not be done easy and reliable? Why do we need hacks like the method below? - For details, see: http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable - * - */ -void termsocket(int fd) -{ - LOGSTART2s("::termsocket", fd); - if (fd < 0) - return; - - fcntl(fd, F_SETFL, ~O_NONBLOCK & fcntl(fd, F_GETFL)); - ::shutdown(fd, SHUT_WR); - char buf[40]; - LOG("waiting for peer to react"); - while(true) - { - int r=recv(fd, buf, 40, MSG_WAITALL); - if(0 == r) - break; - if(r < 0) - { - if(errno == EINTR) - continue; - break; // XXX error case, actually - } - } - - while (0 != ::close(fd)) - { - if (errno != EINTR) - break; - }; -} - -static int connect_timeout(int sockfd, const struct sockaddr *addr, socklen_t addrlen, time_t timeout, bool bAssumeNonBlock) -{ - long stflags; - struct timeval tv; - fd_set wfds; - int res; - - tv.tv_sec = timeout; - tv.tv_usec = 0; - - if(!bAssumeNonBlock) - { - if ((stflags = fcntl(sockfd, F_GETFL, nullptr)) < 0) - return -1; - - // Set to non-blocking mode. - if (fcntl(sockfd, F_SETFL, stflags | O_NONBLOCK) < 0) - return -1; - } - res = connect(sockfd, addr, addrlen); - if (res < 0) { - if (EINPROGRESS == errno) - { - for (;;) { - // Wait for connection. - FD_ZERO(&wfds); - FD_SET(sockfd, &wfds); - res = select(sockfd+1, nullptr, &wfds, nullptr, &tv); - if (res < 0) - { - if (EINTR != errno) - return -1; - } - else if (res > 0) - { - // Socket selected for writing. - int err; - socklen_t optlen = sizeof(err); - - if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &optlen) < 0) - return -1; - - if (err) - { - errno = err; - return -1; - } - - break; - } else { - // Timeout. - errno = ETIMEDOUT; - return -1; - } - } - } else { - return -1; - } - } - - if(!bAssumeNonBlock && fcntl(sockfd, F_SETFL, stflags) < 0) // Set back to original mode - return -1; - - return 0; -} - inline bool tcpconnect::_Connect(string & sErrorMsg, int timeout) { LOGSTART2("tcpconnect::_Connect", "hostname: " << m_sHostName); - CAddrInfo::SPtr dns = CAddrInfo::CachedResolve(m_sHostName, m_sPort, sErrorMsg); + auto dns = CAddrInfo::CachedResolve(m_sHostName, m_sPort, sErrorMsg); if(!dns) { @@ -184,65 +94,250 @@ ::signal(SIGPIPE, SIG_IGN); - // always consider first family, afterwards stop when no more specified - for (unsigned i=0; i< _countof(acfg::conprotos) && (0==i || acfg::conprotos[i]!=PF_UNSPEC); ++i) - { - for (auto pInfo = dns->m_addrInfo; pInfo; pInfo = pInfo->ai_next) - { - if (acfg::conprotos[i] != PF_UNSPEC && acfg::conprotos[i] != pInfo->ai_family) - continue; + Disconnect(); + auto time_start(GetTime()); - ldbg("Creating socket for " << m_sHostName); + enum ePhase { + NO_ALTERNATIVES, + NOT_YET, + PICK_ADDR, + ADDR_PICKED, + SELECT_CONN, // shall do select on connection + HANDLE_ERROR, // transient error state, to be continued into some recovery or ERROR_STOP; expects a useful errno value! + ERROR_STOP // basically a non-recoverable error state + }; + struct tConData { + ePhase state; + int fd; + time_t tmexp; + const evutil_addrinfo *dns; + ~tConData() { checkforceclose(fd); } + //! prepare and start connection + //! @return true if connection happened even here, false otherwise (state is then adjusted for further processing) + bool init_con(time_t time_exp) + { + checkforceclose(fd); + tmexp = time_exp; + fd = ::socket(dns->ai_family, dns->ai_socktype, dns->ai_protocol); + if(fd == -1) + { + state = HANDLE_ERROR; + return false; + } + set_connect_sock_flags(fd); +#if DEBUG + log::err(string("Connecting: ") + formatIpPort(dns)); +#endif + while (true) + { + auto res = connect(fd, dns->ai_addr, dns->ai_addrlen); + if (res != -1) + return true; + if (errno == EINTR) + continue; + if (errno == EINPROGRESS) + { + errno = 0; + state = SELECT_CONN; + } + else + // interpret that errno + state = HANDLE_ERROR; + return false; - if (pInfo->ai_socktype != SOCK_STREAM || pInfo->ai_protocol != IPPROTO_TCP) + } + } + }; + auto iter = tAlternatingDnsIterator(dns->getTcpAddrInfo()); + tConData prim {ADDR_PICKED, -1, time_start + timeout, iter.next() }; + tConData alt {NO_ALTERNATIVES, -1, time_start + cfg::fasttimeout, nullptr }; + CTimeVal tv; + // pickup the first and/or probably the best errno code which can be reported to user + int error_prim = 0; + + auto retGood = [&](int& fd) { std::swap(fd, m_conFd); return true; }; + auto retError = [&](const std::string &errStr) { sErrorMsg = errStr; return false; }; + auto withErrnoError = [&]() { return retError(tErrnoFmter("500 Connection failure: ")); }; + auto withThisErrno = [&withErrnoError](int myErr) { errno = myErr; return withErrnoError(); }; + + // ok, initial condition, one target should be always there, iterator would also hop to the next fallback if allowed + if(!prim.dns) + return withThisErrno(EAFNOSUPPORT); + if (cfg::fasttimeout > 0) + { + alt.dns = iter.next(); + alt.state = alt.dns ? NOT_YET : NO_ALTERNATIVES; + } + + for(auto op_max=0; op_max < 30000; ++op_max) // fail-safe switch, in case of any mistake here + { + LOG("state a: " << prim.state << ", state b: " << alt.state ); + switch(prim.state) + { + case PICK_ADDR: + case NO_ALTERNATIVES: + case NOT_YET: + // XXX: not reachable + break; + case ADDR_PICKED: + if(prim.init_con(time_start + cfg::nettimeout)) + return retGood(prim.fd); + OPTSET(error_prim, errno); + __just_fall_through; + case SELECT_CONN: + { + if(GetTime() >= prim.tmexp) + { + OPTSET(error_prim, ELVIS(errno, ETIMEDOUT)); + prim.state = HANDLE_ERROR; continue; + } + break; + } + case HANDLE_ERROR: + { + // error on primary, what now? prefer the first seen error code or remember errno + OPTSET(error_prim, ELVIS(errno, EINVAL)); + // can work around? + switch(alt.state) + { + case NO_ALTERNATIVES: + case ERROR_STOP: + return withThisErrno(error_prim); + case NOT_YET: + prim.state = ERROR_STOP; + // push it sooner + alt.tmexp -= cfg::fasttimeout; + break; + default: + // some intermediate state there? Let it continue + prim.state = ERROR_STOP; + break; + } + break; + } + case ERROR_STOP: + checkforceclose(prim.fd); + break; + default: // this should be unreachable + return retError("500 Internal error at " STRINGIFY(__LINE__)); + } - Disconnect(); - - m_conFd = ::socket(pInfo->ai_family, pInfo->ai_socktype, pInfo->ai_protocol); - if (m_conFd < 0) + switch(alt.state) + { + case NO_ALTERNATIVES: + break; + case NOT_YET: + if (GetTime() < alt.tmexp) + break; + // first DNS info was preselected before + ASSERT(alt.dns); + alt.state = ADDR_PICKED; + __just_fall_through; + case ADDR_PICKED: + { + if(alt.init_con(GetTime() + cfg::fasttimeout)) + return retGood(alt.fd); + continue; + } + case PICK_ADDR: + { + alt.dns = iter.next(); + alt.state = alt.dns ? ADDR_PICKED : ERROR_STOP; + continue; + } + case SELECT_CONN: + { + auto now(GetTime()); + if(now >= prim.tmexp) + { + alt.state = ERROR_STOP; continue; - -#ifndef NO_TCP_TUNNING + } + if(now >= alt.tmexp) { - int yes(1); - ::setsockopt(m_conFd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); - ::setsockopt(m_conFd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); + alt.state = HANDLE_ERROR; + continue; } -#endif - set_nb(m_conFd); - if (::connect_timeout(m_conFd, pInfo->ai_addr, pInfo->ai_addrlen, timeout, true) < 0) + break; + } + case HANDLE_ERROR: + { + alt.state = PICK_ADDR; + continue; + } + case ERROR_STOP: + { + // came here because: + // - no more alternative DNS info + // - fatal socket/connect errors + // - exceeded maximal network timeout + if(prim.state == ERROR_STOP) { - if(errno==ETIMEDOUT) - sErrorMsg="Connection timeout"; -#ifndef MINIBUILD - USRDBG(tErrnoFmter("Outgoing connection for ") << m_sHostName << ", Port: " << m_sPort ); -#endif + // reconsider final error state there + prim.state = HANDLE_ERROR; continue; } -#ifdef DEBUG - nConCount.fetch_add(1); -#endif - ldbg("connect() ok"); + break; + } + default: // this should be unreachable + return retError("500 Internal error at " STRINGIFY(__LINE__)); + } - return true; + select_set_t selset; + auto time_inter = prim.tmexp; + if(prim.state == SELECT_CONN) + selset.add(prim.fd); + if(alt.state == SELECT_CONN) + selset.add(alt.fd); + if(alt.state == NOT_YET || alt.state == SELECT_CONN) + { + if(alt.tmexp < time_inter) + time_inter = alt.tmexp; } - } -#ifdef MINIBUILD - sErrorMsg = "500 Connection failure"; -#else - // format the last available error message for the user - sErrorMsg=tErrnoFmter("500 Connection failure: "); -#endif - ldbg("Force reconnect, con. failure"); - Disconnect(); - return false; + auto res = select(selset.nfds(), nullptr, &selset.fds, nullptr, tv.Remaining(time_inter)); + if(evabase::in_shutdown) + return withThisErrno(ETIMEDOUT); + if (res < 0) + { + if (EINTR != errno) + return withErrnoError(); + } + else if (res > 0) + { + for(auto p: {&alt, &prim}) + { + // Socket selected for writing. + int err; + socklen_t optlen = sizeof(err); + if(p->state == SELECT_CONN && selset.is_set(p->fd) + && getsockopt(p->fd, SOL_SOCKET, SO_ERROR, (void*) &err, &optlen) == 0) + { + if(err) + { + OPTSET(error_prim, err); + prim.state = HANDLE_ERROR; + } + else + return retGood(p->fd); + } + } + } + else + { + // Timeout. + errno = ETIMEDOUT; + continue; + } + + } + return withThisErrno(ELVIS(error_prim, EINVAL)); } void tcpconnect::Disconnect() { - LOGSTART("tcpconnect::_Disconnect"); + LOGSTART2("tcpconnect::_Disconnect", m_sHostName); #ifdef DEBUG nDisconCount.fetch_add(m_conFd >=0); @@ -257,12 +352,18 @@ termsocket_quick(m_conFd); } -lockable spareConPoolMx; +acmutex spareConPoolMx; multimap, std::pair > spareConPool; +ACNG_API void CloseAllCachedConnections() +{ + lockguard g(spareConPoolMx); + spareConPool.clear(); +} + tDlStreamHandle dl_con_factory::CreateConnected(cmstring &sHostname, cmstring &sPort, - mstring &sErrOut, bool *pbSecondHand, acfg::tRepoData::IHookHandler *pStateTracker + mstring &sErrOut, bool *pbSecondHand, cfg::tRepoData::IHookHandler *pStateTracker ,bool bSsl, int timeout, bool nocache) { LOGSTART2s("tcpconnect::CreateConnected", "hostname: " << sHostname << ", port: " << sPort @@ -272,7 +373,7 @@ #ifndef HAVE_SSL if(bSsl) { - aclog::err("E_NOTIMPLEMENTED: SSL"); + log::err("E_NOTIMPLEMENTED: SSL"); return p; } #endif @@ -355,7 +456,7 @@ handle->m_pStateObserver = nullptr; } - if(! acfg::persistoutgoing) + if(! cfg::persistoutgoing) { ldbg("not caching outgoing connections, drop " << handle.get()); handle.reset(); @@ -383,10 +484,10 @@ // a DOS? if (spareConPool.size() < 50) { - EMPLACE_PAIR(spareConPool, make_tuple(host, handle->GetPort() + spareConPool.emplace(make_tuple(host, handle->GetPort() SSL_OPT_ARG(handle->m_bio) ), make_pair(handle, now)); #ifndef MINIBUILD - g_victor.ScheduleFor(now + TIME_SOCKET_EXPIRE_CLOSE, cleaner::TYPE_EXCONNS); + cleaner::GetInstance().ScheduleFor(now + TIME_SOCKET_EXPIRE_CLOSE, cleaner::TYPE_EXCONNS); #endif } #endif @@ -418,10 +519,7 @@ } } // if they have to send something, that must the be the CLOSE signal - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1; - int r=select(nMaxFd + 1, &rfds, nullptr, nullptr, &tv); + int r=select(nMaxFd + 1, &rfds, nullptr, nullptr, CTimeVal().For(0, 1)); // on error, also do nothing, or stop when r fds are processed for (auto it = spareConPool.begin(); r>0 && it != spareConPool.end(); r--) { @@ -468,42 +566,63 @@ << " , reuse: " << nReuseCount.load() << "\n"; #endif - aclog::err(msg); + log::err(msg); } #ifdef HAVE_SSL bool tcpconnect::SSLinit(mstring &sErr, cmstring &sHostname, cmstring &sPort) { SSL * ssl(nullptr); - int hret(0); - LPCSTR perr(0); mstring ebuf; + auto withSslError = [&sErr](const char *perr) + { + sErr="500 SSL error: "; + sErr+=(perr?perr:"Generic SSL failure"); + return false; + }; + auto withLastSslError = [&withSslError]() + { + return withSslError(ERR_reason_error_string(ERR_get_error())); + }; + auto withRetCode = [&withSslError, &ssl](int hret) + { + return withSslError(ERR_reason_error_string(SSL_get_error(ssl, hret))); + }; + // cleaned up in the destructor on EOL if(!m_ctx) { m_ctx = SSL_CTX_new(SSLv23_client_method()); - if (!m_ctx) - goto ssl_init_fail; + if (!m_ctx) return withLastSslError(); SSL_CTX_load_verify_locations(m_ctx, - acfg::cafile.empty() ? nullptr : acfg::cafile.c_str(), - acfg::capath.empty() ? nullptr : acfg::capath.c_str()); + cfg::cafile.empty() ? nullptr : cfg::cafile.c_str(), + cfg::capath.empty() ? nullptr : cfg::capath.c_str()); } ssl = SSL_new(m_ctx); - if(!ssl) - goto ssl_init_fail; + if (!m_ctx) return withLastSslError(); + // for SNI SSL_set_tlsext_host_name(ssl, sHostname.c_str()); + { + auto param = SSL_get0_param(ssl); + /* Enable automatic hostname checks */ + X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + X509_VERIFY_PARAM_set1_host(param, sHostname.c_str(), 0); + /* Configure a non-zero callback if desired */ + SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); + } + // mark it connected and prepare for non-blocking mode SSL_set_connect_state(ssl); SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); - if((hret=SSL_set_fd(ssl, m_conFd)) != 1) - goto ssl_init_fail_retcode; + auto hret=SSL_set_fd(ssl, m_conFd); + if(hret != 1) return withRetCode(hret); while(true) { @@ -511,7 +630,7 @@ if(hret == 1 ) break; if(hret == 0) - goto ssl_init_fail_retcode; + return withRetCode(hret); fd_set rfds, wfds; FD_ZERO(&rfds); @@ -525,35 +644,23 @@ FD_SET(m_conFd, &wfds); break; default: - goto ssl_init_fail_retcode; + return withRetCode(hret); } - struct timeval tv; - tv.tv_sec = acfg::nettimeout; - tv.tv_usec = 0; - int nReady=select(m_conFd+1, &rfds, &wfds, nullptr, &tv); - if(!nReady) - { - perr="Socket timeout"; - goto ssl_init_fail; - } + int nReady=select(m_conFd+1, &rfds, &wfds, nullptr, CTimeVal().ForNetTimeout()); + if(!nReady) return withSslError("Socket timeout"); if (nReady<0) { #ifndef MINIBUILD ebuf=tErrnoFmter("Socket error"); - perr=ebuf.c_str(); + return withSslError(ebuf.c_str()); #else - perr="Socket error"; + return withSslError("Socket error"); #endif - goto ssl_init_fail; } } - + if(m_bio) BIO_free_all(m_bio); m_bio = BIO_new(BIO_f_ssl()); - if(!m_bio) - { - perr="IO initialization error"; - goto ssl_init_fail; - } + if(!m_bio) return withSslError("IO initialization error"); // not sure we need it but maybe the handshake can access this data BIO_set_conn_hostname(m_bio, sHostname.c_str()); BIO_set_conn_port(m_bio, sPort.c_str()); @@ -563,29 +670,38 @@ BIO_set_nbio(m_bio, 1); set_nb(m_conFd); - if(!acfg::nsafriendly) + if(!cfg::nsafriendly) { + X509* server_cert = nullptr; hret=SSL_get_verify_result(ssl); if( hret != X509_V_OK) - { - perr=X509_verify_cert_error_string(hret); - goto ssl_init_fail; + return withSslError(X509_verify_cert_error_string(hret)); + server_cert = SSL_get_peer_certificate(ssl); + if(server_cert) + { + // XXX: maybe extract the real name to a buffer and report it additionally? + // X509_NAME_oneline(X509_get_subject_name (server_cert), cert_str, sizeof (cert_str)); + X509_free(server_cert); } + else // The handshake was successful although the server did not provide a certificate + return withSslError("Incompatible remote certificate"); } - return true; +} - ssl_init_fail_retcode: - - perr=ERR_reason_error_string(SSL_get_error(ssl, hret)); - - ssl_init_fail: - - if(!perr) - perr=ERR_reason_error_string(ERR_get_error()); - sErr="500 SSL error: "; - sErr+=(perr?perr:"Generic SSL failure"); - return false; +//! Global initialization helper (might be non-reentrant) +void ACNG_API globalSslInit() +{ + static bool inited=false; + if(inited) + return; + inited = true; + SSL_load_error_strings(); + ERR_load_BIO_strings(); + ERR_load_crypto_strings(); + ERR_load_SSL_strings(); + OpenSSL_add_all_algorithms(); + SSL_library_init(); } #endif @@ -627,7 +743,7 @@ } header h; - auto n = h.LoadFromBuf(fmt.rptr(), fmt.size()); + auto n = h.Load(fmt.rptr(), fmt.size()); if(!n) continue; @@ -665,4 +781,17 @@ return true; } +std::string formatIpPort(const evutil_addrinfo *p) +{ + char buf[300], pbuf[30]; + getnameinfo(p->ai_addr, p->ai_addrlen, buf, sizeof(buf), pbuf, sizeof(pbuf), + NI_NUMERICHOST | NI_NUMERICSERV); + return string(p->ai_family == PF_INET6 ? "[" : "") + + buf + + (p->ai_family == PF_INET6 ? "]" : "") + + ":" + pbuf; +} + + +} diff -Nru apt-cacher-ng-0.9.1/systemd/apt-cacher-ng.service.in apt-cacher-ng-3.3.1/systemd/apt-cacher-ng.service.in --- apt-cacher-ng-0.9.1/systemd/apt-cacher-ng.service.in 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/systemd/apt-cacher-ng.service.in 2020-01-08 19:58:26.000000000 +0000 @@ -1,13 +1,18 @@ [Unit] Description=Apt-Cacher NG software download proxy After=network.target +# This can be used to ensure that the service starts only after delayed mount of +# the storage location. +# Note: when the CacheDir folder in configuration file(s) like in +# @CFGDIR@/acng.conf is changed, change the next line too! +RequiresMountsFor=@ACNG_CACHE_DIR@ [Service] # the SocketPath option can be removed if the inetd bridge functionality is not needed -ExecStart=@SBINDIR@/apt-cacher-ng SocketPath=@RUNDIR@/apt-cacher-ng/socket -c @CFGDIR@ ForeGround=1 +ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/apt-cacher-ng -c "@CFGDIR@" ForeGround=1 User=apt-cacher-ng Group=apt-cacher-ng -# this can be changed to notify if the support was enabled at build time +# This can be changed to notify if the support was enabled at build time Type=@SDTYPE@ Restart=on-failure diff -Nru apt-cacher-ng-0.9.1/test/apptests.sh apt-cacher-ng-3.3.1/test/apptests.sh --- apt-cacher-ng-0.9.1/test/apptests.sh 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/test/apptests.sh 2020-01-08 19:58:26.000000000 +0000 @@ -8,3 +8,11 @@ . test/include/start.sh $(mktemp -d) builddir/apt-cacher-ng (cd test/soap && bash -x soaptest.sh) finish_acng + +# build test with all profiles +rm -rf tmp/buildtest-* +for pro in Debug Release MinSizeRel ; do + mkdir -p tmp/buildtest-$pro + (cd tmp/buildtest-$pro && cmake ../.. -DCMAKE_BUILD_TYPE=$pro && make -j$(nproc)) +done + diff -Nru apt-cacher-ng-0.9.1/test/build/HAVE_LINUX_SPLICE.cc apt-cacher-ng-3.3.1/test/build/HAVE_LINUX_SPLICE.cc --- apt-cacher-ng-0.9.1/test/build/HAVE_LINUX_SPLICE.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/test/build/HAVE_LINUX_SPLICE.cc 2020-01-08 19:58:26.000000000 +0000 @@ -1,4 +1,6 @@ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include -int main() { loff_t sin(12), sout(34); return splice(0, &sin, 1, &sout, 12, SPLICE_F_MORE); } +int main() { off_t sin(12), sout(34); return splice(0, &sin, 1, &sout, 12, SPLICE_F_MORE); } diff -Nru apt-cacher-ng-0.9.1/test/build/HAVE_MEMORY_SPTR.cc apt-cacher-ng-3.3.1/test/build/HAVE_MEMORY_SPTR.cc --- apt-cacher-ng-0.9.1/test/build/HAVE_MEMORY_SPTR.cc 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/test/build/HAVE_MEMORY_SPTR.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -#include -int main() { std::shared_ptr x(new int(1)); return *x; } - diff -Nru apt-cacher-ng-0.9.1/TODO apt-cacher-ng-3.3.1/TODO --- apt-cacher-ng-0.9.1/TODO 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/TODO 2020-01-08 19:58:26.000000000 +0000 @@ -1,8 +1,48 @@ +Features: + +DontCache mode might causes hanging when the filter matches some files and some not: + +Fehl:1 http://packages.microsoft.com/repos/vscode stable InRelease + 503 Cache storage error - Permission denied/var/cache/apt-cacher-ng/packages.microsoft.com/repos/vscode/dists/stable/InRelease [IP: ::1 3142] + Holen:2 http://security.debian.org jessie/updates InRelease [63,1 kB] + OK:3 http://ftp2.de.debian.org/debian experimental InRelease + Holen:4 http://security.debian.org jessie/updates/main Sources [222 kB] + Ign:5 http://archive.zfsonlinux.org/debian jessie InRelease + Ign:6 http://www.scootersoftware.com bcompare4 InRelease + Holen:7 http://security.debian.org jessie/updates/main amd64 Packages [444 kB] + Fehl:8 http://www.scootersoftware.com bcompare4 Release + 503 Cache storage error - Permission denied/var/cache/apt-cacher-ng/www.scootersoftware.com/dists/bcompare4/Release [IP: ::1 3142] + Holen:9 http://security.debian.org jessie/updates/main i386 Packages [444 kB] + Fehl:10 http://archive.zfsonlinux.org/debian jessie Release + 404 Not Found [IP: ::1 3142] + 0% [Warten auf Kopfzeilen]^C + TODO: -Move signal handler to signalfd (on Linux) or a pipe fed from a basic signal -handler (replacement for non-Linux). Current solution still has potential for dead-locking. +Redesign the config file format to add sections for remap-stuff instead of pushing everything into the same config line. +Basic idea: git-config extended ini format. + +Better cleanup for orphaned .gpg files + +IDEA: create a special control socket, ACLed by local permissions. Requests +coming from there would be considered as ultimately thrusted and go directly to +the maintenance handlers (i.e. alternative reportpage access only for local +administrator even when report page is disabled). + +IDEA: a special control command for acng/acngtool to rebind local TCP interfaces. +For https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=786717 + +IDEA (for nextgen): pre-fallocate the subsequent block of contiguous space in +chunks of less than 1mb size (repeatedly, when the first region was written) + +Raw pass-throough of Location: addresses as long as they follow the minimum +safety rules, for web services that apply strange rules WRT validation of such +redirections (https://bugs.launchpad.net/bugs/1625928) + +Add a special cleanup page (or just a special mode of Expiration task which +does not abort on errors and does not remove stuff) which focuses on the +distro expiration issue. Add custom job trigger with a command file plus fifo file (for output). This might be triggered by SIGUSR2. @@ -71,6 +111,3 @@ - write installation makefile target -For 1.0: - -list the last error messages in the summary of maint logs diff -Nru apt-cacher-ng-0.9.1/VERSION apt-cacher-ng-3.3.1/VERSION --- apt-cacher-ng-0.9.1/VERSION 2016-02-28 16:19:20.000000000 +0000 +++ apt-cacher-ng-3.3.1/VERSION 2020-01-08 19:58:26.000000000 +0000 @@ -1 +1 @@ -0.9.1 +3.3.1