Compare commits

..

160 Commits
v19.1 ... v20.0

Author SHA1 Message Date
Andrey Prygunkov
d9d824631e updated version string to "20.0" 2018-06-06 21:34:34 +02:00
Andrey Prygunkov
2bd765b06f updated ChangeLog for v20.0 2018-06-06 20:09:37 +02:00
Andrey Prygunkov
f51c216417 #550: fixed SIMD status message for ARM CRC 2018-06-04 19:00:34 +02:00
Andrey Prygunkov
78b270d23e #550: workaround for GCC 7 bug on ARM
Fix for GCC 7 needing option “-fpermissive” to compile it’s own file
“arm_acle.h”.
2018-06-02 20:34:29 +02:00
Andrey Prygunkov
a4252a1e79 #549: force terminating remote processors
when terminating remote server to ensure all child threads are
terminated on reload/shutdown, even if connections were not closed as
expected
2018-06-01 23:38:10 +02:00
Andrey Prygunkov
1ac2be47d5 #549: force socket closing in remote server (Windows only)
to fix hanging connection to web-client
2018-06-01 23:27:55 +02:00
Andrey Prygunkov
9437a227ee #548: direct rename and direct unpack active by default
on new installations
2018-05-31 21:50:40 +02:00
Andrey Prygunkov
0d19722881 #547: improved duplicate detection for files with same subjects 2018-05-31 18:31:28 +02:00
Andrey Prygunkov
adfe5eef26 #542: fixed 7zip crashing
on newer Linux systems
2018-05-31 15:12:35 +02:00
Sander
321cddeeba #546: advice for letsencrypt in option descriptions 2018-05-30 23:49:50 +02:00
Andrey Prygunkov
44f08325f9 #438: proper program termination on Windows shutdown/logoff 2018-05-30 18:54:01 +02:00
Andrey Prygunkov
e601e77e5e #542: fixed unrar crashing
on newer Linux systems.
2018-05-28 21:38:10 +02:00
Sander
8e6ccfa8a7 #536: nshow IP address of incoming connection (#536) 2018-05-09 22:31:42 +02:00
Andrey Prygunkov
3eebee20aa #534: fixed logging of IPv6 addresses 2018-05-08 18:27:57 +02:00
Andrey Prygunkov
b83a9b9aff #533: detecting malformed articles and printing a warning 2018-05-06 22:46:25 +02:00
Andrey Prygunkov
05d7a8ede2 #533: fixed crash on malformed articles 2018-05-06 22:43:14 +02:00
Andrey Prygunkov
4d771036e2 #529: fixed missing file unlocking after direct rename
Also made locking more granular to avoid unnecessary locks for files
whose articles are not going to be discarded.
2018-05-01 21:22:34 +02:00
Andrey Prygunkov
7e659d8d97 #532: update make config 2018-04-15 18:34:14 +02:00
Andrey Prygunkov
137ac1a3ee fixed #532: wrong favicon used on Android
Dynamically activate icon targeted for iOS only when running on iOS.
2018-04-15 18:16:46 +02:00
Andrey Prygunkov
3a4e6623db fixed #529: crash when flushing article cache after direct rename 2018-04-03 13:02:57 +02:00
Andrey Prygunkov
c2669b359e fixed #527: deleting of active par-job may crash the program 2018-04-02 21:17:24 +02:00
Andrey Prygunkov
8bffb51974 fixed #528: tests may fails on Windows due to locked files 2018-04-02 20:12:54 +02:00
Andrey Prygunkov
81be21b540 #483: added new images to distribution archive 2018-03-25 18:14:57 +02:00
Andrey Prygunkov
222d6a1f6d #509: fixed incorrect renaming in rar-renamer
Further improved detection of rar-sets.
2018-02-22 00:19:51 +01:00
hatem zidi
cd6bf682f9 #483: optimized mobile touch icon (favicon)
Optimized for desktop and mobile platforms.
2018-02-02 18:40:45 +01:00
Andrey Prygunkov
d93769021a #501: fixed race condition in queue script coordinator 2018-01-29 23:54:30 +01:00
Andrey Prygunkov
cf0d086b57 #485: HttpOnly for cookies
to improve security
2018-01-26 00:08:51 +01:00
Andrey Prygunkov
bf53c6eaa6 #496: don't log passwords for incorrect login attempts 2018-01-26 00:00:41 +01:00
Andrey Prygunkov
9b50760006 #477: dupe check now case insensitive 2018-01-25 23:50:07 +01:00
Andrey Prygunkov
b7102894d7 #498: fixed pp-parameter initialization 2018-01-25 23:47:53 +01:00
Andrey Prygunkov
db102f5a15 #498: fixed wrong case in unpack password parameter 2018-01-25 17:39:18 +01:00
Andrey Prygunkov
d9cb0026bd #498: case insensitive pp-parameters 2018-01-25 17:38:35 +01:00
bket
5893d03f1b #497: added LibreSSL support 2018-01-20 18:17:38 +01:00
Andrey Prygunkov
18d138648b fixed #474: build fails on musl 2017-11-15 22:36:10 +01:00
Andrey Prygunkov
93a43e711f #471: more robust news server connection test
This fixes connection test errors with servers checking message id
format correctness.
2017-11-11 11:50:23 +01:00
Andrey Prygunkov
2b52dc5bfe #468: compatibility with Android 4 and older 2017-11-10 23:59:17 +01:00
Andrey Prygunkov
ce844367e7 #468: DNS resolving on Android 2017-11-07 00:21:58 +01:00
Andrey Prygunkov
64a5a78866 #467: print par2 creator packet
as INFO on par-check start and as part of ERROR message on par-repair
failure
2017-11-06 22:47:16 +01:00
Andrey Prygunkov
6f9fb29595 #466: removed less useful debug messages 2017-11-06 22:20:03 +01:00
Andrey Prygunkov
0ee60ab844 #466: keep log-file longer open
that improve logging performance especially in debug build
2017-11-06 22:18:40 +01:00
Andrey Prygunkov
8dfca2a542 #461, 7deb3c1b68: renamed "LogBuffer" in webui 2017-11-04 13:55:30 +01:00
Andrey Prygunkov
76bdd63e60 #465: fixed decoding errors on ARMv5 2017-11-03 17:37:10 +01:00
Andrey Prygunkov
ef78cbfc74 #464: fixed: x86_64 universal build fails on PaX kernel 2017-11-02 19:23:01 +01:00
Andrey Prygunkov
74768b2183 #454, 801bf1ae7c: reactivated simd-decoder
which got accidentally deactivated
2017-11-01 22:56:27 +01:00
Andrey Prygunkov
801bf1ae7c #454: fixed: missing data in raw article mode
- option “RawArticle”
2017-11-01 21:05:11 +01:00
Andrey Prygunkov
a901deff03 #463: stop static initialisation invasion 2017-10-31 11:30:54 +01:00
Andrey Prygunkov
67245d6ca8 #448, 186da63056: NServ memory cache switch
no longer has memory limit parameter. The parameter wasn’t respected
anyway.
2017-10-29 19:14:43 +01:00
Andrey Prygunkov
2d70e1de21 #462: fixed: backup servers not used on certain article decoding errors 2017-10-29 17:52:39 +01:00
Andrey Prygunkov
7deb3c1b68 #461: renamed option "LogBufferSize" to "LogBuffer"
and removed obsolete options “SaveQueue” and “ReloadQueue” from
config-file
2017-10-29 13:07:00 +01:00
Andrey Prygunkov
d4886ac7d1 #461: removed option "BrokenLog" 2017-10-29 12:51:49 +01:00
Andrey Prygunkov
5b3372107d #461: removed option "AccurateRate" 2017-10-29 12:43:06 +01:00
Andrey Prygunkov
07c54740a7 #461: removed option "TerminateTimeout"
No thread killing anymore. Hanging downloads are gracefully cancelled
after timeout set in “ArticleTimeout” or “UrlTimeout”.
2017-10-29 12:34:16 +01:00
Andrey Prygunkov
af111adbde #461: removed options "SaveQueue" and "ReloadQueue" 2017-10-28 16:17:45 +02:00
Andrey Prygunkov
d31a734a5c #460: better handling broken connections 2017-10-27 19:38:42 +02:00
Andrey Prygunkov
54f14f5efa #459: use glibc instead of uClibc
in universal installer builds for Linux
2017-10-27 00:40:12 +02:00
Andrey Prygunkov
18fbd12f2c #454: better target CPU detection in configure 2017-10-25 21:31:50 +02:00
Andrey Prygunkov
ff671e722d #455: changed default location of log-file 2017-10-23 23:29:40 +02:00
Andrey Prygunkov
15c292653e #458: compiling without libxml2 to test dev environment
new configure-parameter “--disable-libxml2”.
2017-10-22 23:52:13 +02:00
Andrey Prygunkov
c0aed9af48 #454: fixed compiling error on aarch64 2017-10-22 20:35:51 +02:00
Andrey Prygunkov
597e4fd034 #454: removed force-inline
since it’s no longer needed after moving loop into inner functions;
better compatibility with different compilers
2017-10-21 00:04:19 +02:00
Andrey Prygunkov
3c2575bc26 #454: removed option "RateBuffer"
since it’s no longer needed with raw decoder which works on 4KB buffer
already
2017-10-20 20:54:52 +02:00
Andrey Prygunkov
50c1ca588c #454: option "RawArticle" works again 2017-10-20 20:52:42 +02:00
Andrey Prygunkov
da9c8b1138 #454: fixed buffer overrun
and compiler warnings on VC++
2017-10-20 18:07:01 +02:00
Andrey Prygunkov
c59ab2d9dc #454: one-pass simd decoder
updated SIMD decoder, support for end-of-stream detection
2017-10-19 18:27:04 +02:00
Andrey Prygunkov
35fca1479c #454: fixed rare crash in stream end detection 2017-10-16 18:15:21 +02:00
Andrey Prygunkov
54c5a061c8 #454: fixed align issue on Windows 32 bit 2017-10-16 18:14:11 +02:00
Andrey Prygunkov
3a0489a4a9 #435: fixed warnings in 64 bit mode on Windows 2017-10-16 18:13:34 +02:00
Andrey Prygunkov
a31fb733a2 #454: SIMD CRC routines for Intel and ARM 2017-10-12 21:09:24 +02:00
Andrey Prygunkov
2691eff535 #448: speed optimisation in NServ
when using unlimited memory cache (command line switch “-m 0”)
2017-10-10 19:11:40 +02:00
Andrey Prygunkov
37b04c593a #448: don't try deleting files that don't exist
- a small optimisation to reduce disk activity
2017-10-08 21:11:05 +02:00
Andrey Prygunkov
b9b1c76ada #454: using raw-decoder from node-yencode library 2017-10-08 21:08:23 +02:00
Andrey Prygunkov
69a0db63f6 #454: integrated node-yencode library by Anime Tosho
1) integrated the library; 2) splitted units by CPU architecture; 3)
extended makefile and configure script to detect CPU architecture and
use appropriate compiler flags; 4) runtime CPU features detection for
x86 and ARM with dynamic code  dispatching; 5) temporary (for test
purposes) printing info about SIMD support to stdout on program
startup; 6) new SIMD routines are not yet used in the program
2017-10-08 20:49:13 +02:00
Andrey Prygunkov
e9926d92e0 fixed compiler warnings 2017-10-09 13:35:43 +02:00
Andrey Prygunkov
f5aa27979c #448, 186da63056: small speed optimisation in NServ 2017-10-09 13:35:10 +02:00
BernCarney
24a4542c14 #452, #453: proper URL encoding in example pp-scripts
Updated scripts to accept special characters in nzbget password and username.
2017-10-05 19:31:49 +02:00
Andrey Prygunkov
bb95e1f274 #448, 186da63056: corrected file mode 2017-09-29 21:45:52 +02:00
Andrey Prygunkov
186da63056 #448: memory cache in NServ
: new command line switch “-m”
2017-09-28 20:45:06 +02:00
Andrey Prygunkov
1facedb694 #451: speed control in NServ
: new command line switches “-w“ and “-r”
2017-09-28 17:45:14 +02:00
Andrey Prygunkov
54eb8e1291 #448: new option "SkipWrite"
replaces compiler define “SKIP_ARTICLE_WRITING”. 2) renamed option
“Decode” to “RawArticle”. 3) option “CrcCheck” moved from section
“Download Queue “ into section “Check and Repair”
2017-09-28 17:31:47 +02:00
Andrey Prygunkov
80b67383e3 #450: speed up yenc decoder
by optimising main decoding loop
2017-09-24 14:24:10 +02:00
Andrey Prygunkov
406a78218a #448, 71505340d0: allow CRC calculation even if
decoding is disabled via SKIP_ARTICLE_DECODING
2017-09-23 00:29:22 +02:00
Andrey Prygunkov
262df77f74 #449: new option "RateBuffer"
to configure speed meter update rate
2017-09-22 23:45:26 +02:00
Andrey Prygunkov
71505340d0 #448: disable article writing and decoding
Disabling is now possible for test purposes via defines
SKIP_ARTICLE_WRITING and SKIP_ARTICLE_DECODING (nzbget.h)
2017-09-22 20:25:05 +02:00
Andrey Prygunkov
bddb0bb26d #447: better optimisation settings (Windows)
Adjusted Visual Studio project to compile with more aggressive
optimisation settings.
2017-09-21 18:45:30 +02:00
Andrey Prygunkov
d90a40909b #446: faster CRC computation 2017-09-21 18:06:17 +02:00
Andrey Prygunkov
2bdc87c198 fixed #445: program hangs during update on Linux 2017-09-18 17:49:12 +02:00
Andrey Prygunkov
e97a0fde11 #443: functional tests on Travis CI 2017-09-16 09:54:41 +02:00
Andrey Prygunkov
eb18608522 #443: functional tests find 7z and par2 automatically 2017-09-15 20:25:40 +02:00
Andrey Prygunkov
481e7b3d2b refactor: removed updates from article writer 2017-09-13 19:19:01 +02:00
Andrey Prygunkov
8545cb3581 #426: show unpack password as plain field 2017-09-13 18:39:40 +02:00
Andrey Prygunkov
e422fea746 #440: merge branch '440-update-check' into develop 2017-09-11 21:18:53 +02:00
Andrey Prygunkov
2ce9f0df38 #440: notification control from main site
To not update all installations on release day but rather gradually
within several days (as defined in update-info file on web-site).
2017-09-11 21:17:51 +02:00
Andrey Prygunkov
36de095e51 #442: improved volume detection in rar-renamer 2017-09-11 20:56:03 +02:00
Andrey Prygunkov
9b05f779f6 #432, #421, b4bcc82abe: remote-server cleanup
Use “close(socket)” when “accept”-ing connections and use
“shutdown(socket)” otherwise.
2017-09-07 17:59:10 +02:00
Andrey Prygunkov
38efd4a4de #440: help screen for update dialog 2017-09-07 17:48:51 +02:00
Andrey Prygunkov
80b8ee8dfb #440: automatic update check
New option "UpdateCheck”.
2017-09-05 20:31:11 +02:00
Andrey Prygunkov
47b1c1a2dd #49, #260: 9dc2b8c71b: corrected formatting 2017-09-05 20:19:41 +02:00
Andrey Prygunkov
7417160da9 #435: thread memory cleanup when using OpenSSL 2017-09-05 19:51:17 +02:00
Andrey Prygunkov
a41e010165 #438: fixed propagation delay 2017-09-04 20:28:00 +02:00
Andrey Prygunkov
cbe7b1e051 #431: fixed broken SSL in built-in web-server 2017-09-04 20:26:19 +02:00
Andrey Prygunkov
00a5b68d84 #439: Authorized IP not working on IPv6 (fix for Windows) 2017-09-04 20:25:47 +02:00
Andrey Prygunkov
561713dbed #435: using "windows" instead of "win32" in setup file name 2017-09-03 11:27:55 +02:00
Andrey Prygunkov
cce9338909 #435: reorganised Windows setup files 2017-09-02 22:20:29 +02:00
Andrey Prygunkov
515fd9298d fixed #439: Authorized IP not working on IPv6 2017-09-02 19:29:33 +02:00
Andrey Prygunkov
0ee72d2dd7 #438: speed improvement in queue management
when downloading with very large queue (thousands of nzbs).
2017-09-02 11:37:57 +02:00
Andrey Prygunkov
57f932cfab #438: hibernating all file infos in one large disk state file
to greatly improve startup time
2017-09-02 11:36:38 +02:00
Andrey Prygunkov
8f803c2f21 #438: great speed optimization for queue-dir cleanup 2017-09-02 11:34:07 +02:00
Andrey Prygunkov
89bd5d6dfe #435: added build script for Windows into repository 2017-09-01 23:01:56 +02:00
Simon Nicolussi
49a0292053 #437: don't rely on sizes of externally generated files
Tests that try to match exact file sizes are prone to break for unexpected versions of p7zip and par2cmdline.
2017-08-31 22:38:42 +02:00
Andrey Prygunkov
a60d8d1273 #435: fixed compiling error with older OpenSSL versions 2017-08-31 21:03:58 +02:00
Andrey Prygunkov
44ea3d02ab #435: extended Windows setup for 64 bit binaries 2017-08-30 23:21:01 +02:00
Andrey Prygunkov
fe9f208f20 #435: better cleanup when using OpenSLL
To avoid memory leaks report when linking OpenSLL statically.
2017-08-30 23:20:09 +02:00
Andrey Prygunkov
20e8bb6ebc #435: project configuration for 64 bit (Windows)
Now using only static libraries.
2017-08-30 23:18:57 +02:00
Andrey Prygunkov
0709f248ee #435: fixed warnings in 64 bit mode on Windows 2017-08-30 22:22:29 +02:00
Andrey Prygunkov
35d8aa5fa7 #435: fixed compiling error if no regex.h 2017-08-28 21:06:45 +02:00
Andrey Prygunkov
9f80f45fb9 #435: compatibility with windows 64 bit 2017-08-28 21:05:52 +02:00
Andrey Prygunkov
763fe425d6 #433: better username/password validation
when testing connection on settings page
2017-08-27 20:28:15 +02:00
Andrey Prygunkov
9c86dc70bd #421, #434: fixed: filter buttons don't work in history 2017-08-27 17:37:44 +02:00
Andrey Prygunkov
1f6a360de5 #421: fixed status buttons on history tab 2017-08-26 18:10:54 +02:00
Andrey Prygunkov
dcdc41ca9a #421, #422: URL components should not be encoded as JSON 2017-08-26 11:34:36 +02:00
Andrey Prygunkov
6d307a05f8 #431: use remote address in error reporting
for incoming connections
2017-08-25 20:22:55 +02:00
Andrey Prygunkov
83c15b1f05 fixed #431: NServ terminates if client interrupts connection 2017-08-25 20:21:40 +02:00
Andrey Prygunkov
43fc121219 #430: article statistics for par-files after direct rename 2017-08-25 18:56:09 +02:00
Andrey Prygunkov
4b729eb0f0 fixed #430: pause and article statistics after direct rename 2017-08-24 14:53:25 +02:00
Andrey Prygunkov
0158614da2 #421: update downloads table even if no changes
when there are active downloads in order to recalculate estimated time
2017-08-24 13:46:37 +02:00
Andrey Prygunkov
ca7807fa92 #421: fixed missing semicolon in raphael.min.js 2017-08-23 18:07:59 +02:00
Andrey Prygunkov
97018ae102 #424: resume detected non-par2-files
when direct rename is active
2017-08-15 12:51:44 +03:00
Andrey Prygunkov
cbe6c6a340 fixed #426: options formatted as password fields when they shouldn't 2017-08-10 22:22:12 +02:00
Andrey Prygunkov
d84ec5685b #425: cross-compiling for FreeBSD using Clang 2017-08-07 12:31:44 +02:00
Andrey Prygunkov
557e0580a7 #421: 45b5727374: fixed messages filter buttons disappeared 2017-08-05 22:58:20 +02:00
Andrey Prygunkov
43c0bdd9d3 #423: Linux installer compatibility with FreeBSD 2017-08-04 23:57:57 +02:00
Andrey Prygunkov
86bcb7073c #420: support for redirect codes 303, 307 and 308
in web-client for fetching of rss feeds and nzb-files
2017-08-04 21:43:40 +02:00
Andrey Prygunkov
6cf0edd278 #421: added debug logging for etags 2017-08-01 21:36:10 +02:00
Andrey Prygunkov
b4bcc82abe #421: fixed crash when disconnecting web-clients on Windows 2017-08-01 21:35:48 +02:00
Andrey Prygunkov
6fb1ea1cff #421: support keep-alive in all responses 2017-07-31 22:50:26 +02:00
Andrey Prygunkov
3ee9125100 #421: better handling shutdown in remote server 2017-07-31 20:30:24 +02:00
Andrey Prygunkov
fad2be0e0f #421: new option "RemoteTimeout"
to define timeout for incoming connections including timeout for
keep-alive.
2017-07-31 20:24:02 +02:00
Andrey Prygunkov
2763f1a522 #421: support for keep-alive connections in built-in web-server 2017-07-31 19:47:17 +02:00
Andrey Prygunkov
1214c79eab correction in debug logging
which could cause crash on shutdown in debug mode
2017-07-31 18:02:24 +02:00
Andrey Prygunkov
7ee0b60361 #418: fixed variadic macros detection 2017-07-31 17:59:11 +02:00
Andrey Prygunkov
0135e605a8 #421, #422: do not parse json-response if it will not be used
… and small refactorings and fixes for error reporting
2017-07-30 23:40:54 +02:00
schnusch
546324d891 #421, #422: added detection of cached responses in WebUI's RPC 2017-07-30 23:40:47 +02:00
schnusch
43563e8dfb #421, #422: removed remnants of 412 error handling 2017-07-30 23:40:38 +02:00
schnusch
4f5d357e3c #421, #422: use GET requests for safe JsonRPC methods in WebUI 2017-07-30 23:40:30 +02:00
Andrey Prygunkov
a6c120bc82 #421, #422: avoid table updates if no changes 2017-07-30 23:40:29 +02:00
Andrey Prygunkov
18f673e6b3 #421, #422: allow caching for more API methods
1) All safe methods are now cacheable.
2) Corrected debug code, accidentally pushed in previous commit (#ifdef
DISABLE_PARCHECK).
2017-07-30 23:40:29 +02:00
Andrey Prygunkov
5ac7c0398e #421, #422: adjustments in ETag support
1) convert MD5 hash into string using standard method instead of base64;
2) if par2 isn’t available using another hash function from Util-unit;
3) avoid gzipping of response if it isn’t sent;
4) use BString class for header string formatting.
2017-07-30 23:40:29 +02:00
schnusch
0008f040b3 #421, 422: added support for Etag an If-None-Match HTTP headers
The web server now support Etag generation for static files and some RPC
methods. If If-None-Match is given in the request and matches with the Etag
generated for the response than no data is sent and 304 or 412 is returned.

The JavaScript RPC calls also support the new HTTP error code by buffering
Etags and responses and will reuse the previous response if 412 is returned.
2017-07-30 23:40:13 +02:00
Andrey Prygunkov
45b5727374 #421: call multiple API-methods simultaneously 2017-07-28 00:42:25 +02:00
Andrey Prygunkov
f001b0744b #421: reduce number of requests when loading webui
by combining all javascript-files into one and all css-files into one
2017-07-28 00:41:18 +02:00
Andrey Prygunkov
2124a886f8 #418: updated POSIX build files to newer autotools version
- compatibility with newer autotools;
- compatibility with newer platforms such as aarch64.
2017-07-26 23:40:09 +02:00
Andrey Prygunkov
7f4b15b4de #416: fixed wait interval 2017-07-26 18:50:07 +02:00
Andrey Prygunkov
68c74a5a30 #416: better error handling when fetching rss feeds 2017-07-24 21:33:48 +02:00
Stefaan Ghysels
01d4ebb800 #417: fixed linux installer failure on android emulator 2017-07-24 18:57:06 +02:00
Tobias Geerinckx-Rice
f56e01d200 #414: fixed compiler error when building using GnuTLS 2017-07-16 07:24:50 +02:00
Andrey Prygunkov
cdc5c5515f fixed #412: unpack using password file doesn't work on Windows
Also added more debug output for future use.
2017-07-12 20:48:59 +02:00
Andrey Prygunkov
67195e7683 #400: adjustments to unix domain sockets mode 2017-07-09 21:48:46 +02:00
Andrey Prygunkov
499e3d5d8f fixed typo in project file for Visual Studio 2017-07-09 20:11:12 +02:00
schnusch
0ee9083627 #400: support for file sockets (POSIX only)
Option "ControlIP" can be set to local file path to use file sockets instead of network sockets.
2017-07-09 19:52:22 +02:00
Andrey Prygunkov
726a6154be updated version string to "20.0-testing" 2017-07-09 19:53:09 +02:00
132 changed files with 13632 additions and 12799 deletions

8
.gitignore vendored
View File

@@ -26,11 +26,14 @@
# GNU Autotools
.deps/
config.h
config.h.in~
config.log
config.status
Makefile
stamp-h1
autom4te.cache/
.dirstamp
*.o-*
# Visual Studio User-specific files
*.suo
@@ -57,6 +60,10 @@ ipch/
*.svclog
*.scc
*.sln
.vscode/
# macOS
.DS_Store
# NZBGet specific
nzbget
@@ -64,3 +71,4 @@ code_revision.cpp
*.temp
*.pyc
pytest.ini
.cache

View File

@@ -13,6 +13,8 @@ matrix:
packages:
- g++-5
- unrar
- p7zip-full
- par2
env:
- COMPILER=g++-5
@@ -24,6 +26,8 @@ matrix:
packages:
- g++-4.9
- unrar
- p7zip-full
- par2
env:
- COMPILER=g++-4.9
@@ -32,6 +36,8 @@ matrix:
apt:
packages:
- unrar
- p7zip-full
- par2
env:
- COMPILER=g++-4.8
- CXXFLAGS="-std=c++11 -O2 -s"
@@ -46,10 +52,16 @@ matrix:
packages:
- clang-3.6
- unrar
- p7zip-full
- par2
env:
- COMPILER=clang++-3.6
install:
- sudo pip install -U pytest
script:
- $COMPILER --version
- CXX=$COMPILER ./configure $CONFIGUREOPTS --enable-tests && make
- ./nzbget --tests
- cd tests/functional && pytest -v

222
ChangeLog
View File

@@ -1,3 +1,119 @@
nzbget-20.0:
- massive performance optimisations in downloader:
- improved yEnc decoder;
- improved CRC32 calculation;
- processing data in one pass;
- SIMD implementation of decoder and CRC functions on x86 and ARM CPUs;
SIMD code relies on node-yencode library by Anime Tosho
(https://github.com/animetosho/node-yencode);
- overall performance improvement up to +500% on x86 and +250% on ARM
(better speed or less CPU usage);
- using glibc instead of uClibc in universal installer builds for Linux:
- this significantly improves performance;
- compatibility with Android and other systems is hopefully also improved;
- in universal installer glibc is used on x86 and ARM;
- uClibc is still used on MIPS and PPC;
- performance optimisations in web-interface:
- reduced number of requests when loading webui by combining all
javascript-files into one and all css-files into one;
- reduced load time by calling multiple API-methods simultaneously;
- extensive use of browser caching for static files significantly
reduces the amount of data transferred on webui initialisation;
- extensive use of browser caching for API requests reduces the amount
of data transferred during webui status updates, especially when
nzbget is in idle state and there are no changes in download queue or
history;
- avoid work in browser on status updates if there are no changes in
download queue or history;
- support for keep alive connections significantly reduces overhead for
establishing connections on webui status updates, especially when
connecting to nzbget via TLS/SSL (avoiding TLS handshakes);
- a number of performance optimisations for large download queue with
thousands of items:
- much faster loading of queue from disk greatly improves program start
up time;
- improved queue management for faster download speed;
- now offering 64 bit binaries for Windows:
- installer includes 32 and 64 bit nzbget binaries;
- when updating from older versions the 64 bit binary is installed
automatically, although into the old location to keep all your
shortcuts intact;
- using word "windows" instead of "win32" in the setup file name;
- automatic update check:
- new option "UpdateCheck" to check for stable or testing versions (or
disable);
- when a new version is found a notification is shown;
- the update check is enabled by default for stable versions;
- significantly improved logging performance, especially in debug builds;
- par-check prints par2 creator application to help identify creator app
issues;
- added support for Unix domain sockets (POSIX only);
- better error handling when fetching rss feeds;
- updated POSIX build files to newer autotools version:
- compatibility with newer autotools;
- compatibility with newer platforms such as aarch64;
- better username/password validation when testing connection on settings
page;
- improved rar-renamer to better handle certain cases;
- new option "SkipWrite" for easier speed tests;
- support for redirect codes 303, 307 and 308 in web-client for fetching of
rss feeds and nzb-files;
- installer for FreeBSD is now built using Clang instead of GCC; this fixes
incompatibility with FreeBSD 11;
- universal Linux installer can now be used on FreeBSD (via Linux
compatibility mode);
- updated unrar to v5.50;
- more robust news server connection test;
- enhancements in NServ:
- memory cache to reduce disk load during speed tests - new command line
switch "-m";
- speed control - new command line switches "-w" and "-r";
- show IP address of incoming connection;
- changed default location of log-file;
- better handling of broken connections;
- removed obsolete or less useful options "SaveQueue", "ReloadQueue",
"TerminateTimeout", "AccurateRate", "BrokenLog";
- renamed option "LogBufferSize" to "LogBuffer";
- passwords of failed login attempts are no longer printed to log to improve
security;
- cookies in web interface are now saved with "httpOnly" attribute to improve
security;
- titles and duplicate keys in duplicate check are now case insensitive;
- added LibreSSL support;
- web interface now has a better icon for favorites or home screen of mobile
devices;
- improved duplicate detection for obfuscated downloads having files with
same subjects;
- direct rename and direct unpack are now active by default on new
installations, except for slow Linux systems;
- added advice for letsencrypt in option descriptions;
- fixed incorrect renaming in rar-renamer which could cause some downloads to
fail;
- fixed race condition in queue script coordinator which could cause crashes;
- fixed: post-processing parameters were sometimes case sensitive causing
issues;
- fixed DNS resolving issues on Android;
- fixed: backup servers not used on certain article decoding errors;
- fixed: when direct rename was active certain downloads with damaged
par2-files become paused at near completion and required manual resuming;
- fixed: crash when flushing article cache after direct rename;
- fixed: deleting active par-job may crash the program;
- fixed: functional tests may fail on Windows due to locked files;
- fixed: unpack using password file doesn't work on Windows;
- fixed: compiler error when building using GnuTLS;
- fixed: Linux installer failure on android emulator;
- fixed: options formatted as password fields when they shouldn't;
- fixed: slightly off article statistics after direct rename;
- fixed: NServ terminated if client interrupted connection;
- fixed: example pp-scripts may not work properly if nzbget password or
username contained special characters;
- fix in functional tests to not rely on sizes of externally generated files;
- fixed: option AuthorizedIP did not work with IPv6 addresses;
- fixed crash on certain malformed articles;
- fixed crash which could happen on Windows when reloading or terminating the
program;
- fixed logging of IPv6 addresses.
nzbget-19.1:
- proper handling of changing category (and destination path) during direct
unpack; direct unpack now gracefully aborts with cleanup; the files will
@@ -10,66 +126,67 @@ nzbget-19.1:
nzbget-19.0:
- unpack during downloading:
- downloaded files can now be unpacked as soon as every archive part is
downloaded;
- new option "DirectUnpack" to activate direct unpacking;
- direct unpack works even with obfuscated downloads; option "DirectRename"
(see below) must be active for that;
- option "ReorderFiles" (see below) should be also active for optimal file
download order;
- direct unpack works for rar-archives; 7-zip archives and simply splitted
files are processed by default unpack module;
- direct unpack obviously works only for healthy download; if download is
damaged the direct unpack cancels and the download is unpacked during
post-processing stage after files are repaired;
- direct unpack reduces the time needed to complete download and
- downloaded files can now be unpacked as soon as every archive part is
downloaded;
- new option "DirectUnpack" to activate direct unpacking;
- direct unpack works even with obfuscated downloads; option
"DirectRename" (see below) must be active for that;
- option "ReorderFiles" (see below) should be also active for optimal
file download order;
- direct unpack works for rar-archives; 7-zip archives and simply
splitted files are processed by default unpack module;
- direct unpack obviously works only for healthy download; if download
is damaged the direct unpack cancels and the download is unpacked
during post-processing stage after files are repaired;
- direct unpack reduces the time needed to complete download and
post-processing;
- it also allows to start watching of video files during download (requires
compatible video player software);
- it also allows to start watching of video files during download
(requires compatible video player software);
- renaming of obfuscated file names during downloading:
- correct file names for obfuscated downloads are now determined during
download stage (instead of post-processing stage);
- downloaded files are saved into disk directly with correct names;
- direct renaming uses par2-files to restore correct file names;
- new option "DirectRename" to activate direct renaming;
- new queue-event NZB_NAMED, sent after the inner files are renamed;
- correct file names for obfuscated downloads are now determined during
download stage (instead of post-processing stage);
- downloaded files are saved into disk directly with correct names;
- direct renaming uses par2-files to restore correct file names;
- new option "DirectRename" to activate direct renaming;
- new queue-event NZB_NAMED, sent after the inner files are renamed;
- automatic reordering of files:
- inner files within nzb reordered to ensure download of files in archive
parts order;
- the files are reordered when nzb is added to queue;
- if direct renaming is active (option "DirectRename") the files are
- inner files within nzb reordered to ensure download of files in
archive parts order;
- the files are reordered when nzb is added to queue;
- if direct renaming is active (option "DirectRename") the files are
reordered again after the correct names becomes known;
- new option "ReorderFiles";
- new command "GroupSortFiles" in api-method "editqueue";
- new subcommand "SF" of remote command "-E/--edit";
- new option "ReorderFiles";
- new command "GroupSortFiles" in api-method "editqueue";
- new subcommand "SF" of remote command "-E/--edit";
- new option "FileNaming" to control how to name obfuscated files (before they
get renamed by par-rename, rar-rename or direct-rename);
- TLS certificate verification:
- when connecting to a news server (for downloading) or a web server (for
fetching of rss feeds and nzb-files) the authenticity of the server is
validated using server security certificate. If the check fails that means
the connection cannot be trusted and must be closed with an error message
explaining the security issue;
- new options "CertCheck" and "CertStore";
- official NZBGet packages come with activated certificate check;
- when updating from an older NZBGet version the option CertCheck will be
automatically activated when the settings is saved (switch to Settings
page in web-interface and click "Save all changed");
- when connecting to a news server (for downloading) or a web server
(for fetching of rss feeds and nzb-files) the authenticity of the
server is validated using server security certificate. If the check
fails that means the connection cannot be trusted and must be closed
with an error message explaining the security issue;
- new options "CertCheck" and "CertStore";
- official NZBGet packages come with activated certificate check;
- when updating from an older NZBGet version the option CertCheck will
be automatically activated when the settings is saved (switch to
Settings page in web-interface and click "Save all changed");
- authentication via form in web-interface as alternative to HTTP
authentication:
- that must help with password tools having issues with HTTP authentication
dialog;
- new option "FormAuth";
- that must help with password tools having issues with HTTP
authentication dialog;
- new option "FormAuth";
- drop-downs (context menus) for priority, category and status columns:
- quicker changing of priority and category;
- easier access to actions via drop-down (context menu) in status column;
- quicker changing of priority and category;
- easier access to actions via drop-down (context menu) in status
column;
- extensions scripts can now be executed from settings page:
- script authors define custom buttons;
- when clicked the script is executed in a special mode and obtain extra
parameters;
- example script "Email.py" extended with button "Send test e-mail";
- script authors define custom buttons;
- when clicked the script is executed in a special mode and obtain extra
parameters;
- example script "Email.py" extended with button "Send test e-mail";
- on Windows NZBGet can now associate itself with nzb-files:
- use option in Windows installer to register NZBGet for nzb-files;
- use option in Windows installer to register NZBGet for nzb-files;
- unrar shipped within Linux package is now compiled with "fallocate" option
to improve compatibility with media players when watching videos during
downloading and unpacking;
@@ -83,9 +200,6 @@ nzbget-19.0:
- save changes before performing actions in history dialog;
- proper exit code on client command success or failure.
- added host name to all error messages regarding connection issues;
- improved continuos integration with Travis CI:
- added gcc 4.8 to test matrix;
- installing unrar into test system to allow unit tests requiring unrar;
- new button "Volume Statistics" in section "News Servers" of settings page;
shows the same volume data as in global statistics dialog;
- new option "ServerX.Notes" for user comments on news servers;
@@ -96,9 +210,9 @@ nzbget-19.0:
- updated unrar to v5.40;
- clear script execution log before executing script;
- added support for crash dumps on Windows:
- renamed option "DumpCore" to "CrashDump";
- new option "CrashTrace" to make it possible to disable default printing off
call stack in order to produce more relevant crash dumps;
- renamed option "DumpCore" to "CrashDump";
- new option "CrashTrace" to make it possible to disable default
printing off call stack in order to produce more relevant crash dumps;
- fixed: startup scheduler tasks can be executed again;
- fixed: "fatal" messages when compiling from sources.
- fixed: per-nzb download statistics could be wrong if the program was

View File

@@ -58,8 +58,8 @@ nzbget_SOURCES = \
daemon/frontend/LoggableFrontend.h \
daemon/frontend/NCursesFrontend.cpp \
daemon/frontend/NCursesFrontend.h \
daemon/main/CommandLineParser.cpp \
daemon/main/CommandLineParser.h \
daemon/main/CommandLineParser.cpp \
daemon/main/CommandLineParser.h \
daemon/main/DiskService.cpp \
daemon/main/DiskService.h \
daemon/main/Maintenance.cpp \
@@ -214,6 +214,25 @@ nzbget_SOURCES += \
lib/par2/verificationpacket.h
endif
# Simd decoder and Crc32
nzbget_SOURCES += \
lib/yencode/YEncode.h \
lib/yencode/SimdInit.cpp \
lib/yencode/SimdDecoder.cpp \
lib/yencode/ScalarDecoder.cpp \
lib/yencode/Sse2Decoder.cpp \
lib/yencode/Ssse3Decoder.cpp \
lib/yencode/PclmulCrc.cpp \
lib/yencode/NeonDecoder.cpp \
lib/yencode/AcleCrc.cpp \
lib/yencode/SliceCrc.cpp
lib/yencode/Sse2Decoder.$(OBJEXT) : CXXFLAGS+=$(SSE2_CXXFLAGS)
lib/yencode/Ssse3Decoder.$(OBJEXT) : CXXFLAGS+=$(SSSE3_CXXFLAGS)
lib/yencode/PclmulCrc.$(OBJEXT) : CXXFLAGS+=$(PCLMUL_CXXFLAGS)
lib/yencode/NeonDecoder.$(OBJEXT) : CXXFLAGS+=$(NEON_CXXFLAGS)
lib/yencode/AcleCrc.$(OBJEXT) : CXXFLAGS+=$(ACLECRC_CXXFLAGS)
AM_CPPFLAGS = \
-I$(srcdir)/daemon/connect \
-I$(srcdir)/daemon/extension \
@@ -226,7 +245,8 @@ AM_CPPFLAGS = \
-I$(srcdir)/daemon/remote \
-I$(srcdir)/daemon/util \
-I$(srcdir)/daemon/nserv \
-I$(srcdir)/lib/par2
-I$(srcdir)/lib/par2 \
-I$(srcdir)/lib/yencode
if WITH_TESTS
nzbget_SOURCES += \
@@ -283,9 +303,9 @@ windows_FILES = \
windows/resources/trayicon_idle.ico \
windows/resources/trayicon_paused.ico \
windows/resources/trayicon_working.ico \
windows/setup/nzbget-setup.nsi \
windows/setup/install.bmp \
windows/setup/uninstall.bmp
windows/resources/install.bmp \
windows/resources/uninstall.bmp \
windows/nzbget-setup.nsi
osx_FILES = \
osx/App_Prefix.pch \
@@ -369,7 +389,9 @@ webui_FILES = \
webui/img/favicon.ico \
webui/img/download-anim-green-2x.png \
webui/img/download-anim-orange-2x.png \
webui/img/transmit-reload-2x.gif
webui/img/transmit-reload-2x.gif \
webui/img/favicon-256x256-opaque.png \
webui/img/favicon-256x256.png
scripts_FILES = \
scripts/EMail.py \

3118
Makefile.in vendored
View File

File diff suppressed because it is too large Load Diff

1378
aclocal.m4 vendored
View File

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,9 @@
/* Define to 1 to disable gzip-support */
#undef DISABLE_GZIP
/* Define to 1 to not use libxml2, only for development purposes */
#undef DISABLE_LIBXML2
/* Define to 1 to disable par-verification and repair */
#undef DISABLE_PARCHECK
@@ -155,6 +158,9 @@
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
@@ -170,9 +176,10 @@
/* Version number of package */
#undef VERSION
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#undef WORDS_BIGENDIAN
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS

10701
configure vendored
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
#
# This file is part of nzbget. See <http://nzbget.net>.
#
# Copyright (C) 2008-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
# Copyright (C) 2008-2018 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -20,11 +20,11 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(nzbget, 19.1, hugbug@users.sourceforge.net)
AC_PREREQ(2.65)
AC_INIT(nzbget, 20.0, hugbug@users.sourceforge.net)
AC_CONFIG_AUX_DIR(posix)
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([foreign])
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_SRCDIR([daemon/main/nzbget.cpp])
AC_CONFIG_HEADERS([config.h])
AM_MAINTAINER_MODE
@@ -65,8 +65,7 @@ fi
dnl
dnl Checks for header files.
dnl
AC_CHECK_HEADERS(sys/prctl.h)
AC_CHECK_HEADERS(regex.h)
AC_CHECK_HEADERS(sys/prctl.h regex.h endian.h getopt.h)
dnl
@@ -146,7 +145,7 @@ if test "$FOUND" = "no"; then
[ char* szHost; struct hostent hinfobuf; char* strbuf; int h_errnop;
struct hostent* hinfo = gethostbyname_r(szHost, &hinfobuf, strbuf, 1024, &h_errnop); ],
AC_MSG_RESULT([[yes, and it takes 5 arguments]])
FOUND="yes"
FOUND="yes"
AC_DEFINE([HAVE_GETHOSTBYNAME_R_5], 1, [Define to 1 if gethostbyname_r takes 5 arguments]),
FOUND="no")
@@ -196,17 +195,17 @@ AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/socket.h>],[
(void)getsockopt (1, 1, 1, NULL, (size_t*)NULL)],[
AC_MSG_RESULT(size_t)
SOCKLEN_T=size_t],[
AC_TRY_COMPILE([
AC_MSG_RESULT(size_t)
SOCKLEN_T=size_t],[
AC_TRY_COMPILE([
#include <stddef.h>
#include <sys/types.h>
#include <sys/socket.h>],[
(void)getsockopt (1, 1, 1, NULL, (int*)NULL)],[
AC_MSG_RESULT(int)
SOCKLEN_T=int],[
AC_MSG_WARN(could not determine)
SOCKLEN_T=int])])])
AC_MSG_RESULT(int)
SOCKLEN_T=int],[
AC_MSG_WARN(could not determine)
SOCKLEN_T=int])])])
AC_DEFINE_UNQUOTED(SOCKLEN_T, $SOCKLEN_T, [Determine what socket length (socklen_t) data type is])
@@ -238,26 +237,36 @@ AC_TRY_COMPILE(
dnl
dnl checks for libxml2 includes and libraries.
dnl
AC_ARG_WITH(libxml2_includes,
[AS_HELP_STRING([--with-libxml2-includes=DIR], [libxml2 include directory])],
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
[INCVAL="yes"],
[INCVAL="no"])
AC_ARG_WITH(libxml2_libraries,
[AS_HELP_STRING([--with-libxml2-libraries=DIR], [libxml2 library directory])],
[LDFLAGS="${LDFLAGS} -L${withval}"]
[LIBVAL="yes"],
[LIBVAL="no"])
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
PKG_CHECK_MODULES(libxml2, libxml-2.0,
[LIBS="${LIBS} $libxml2_LIBS"]
[CPPFLAGS="${CPPFLAGS} $libxml2_CFLAGS"],
AC_MSG_CHECKING(whether to use libxml2)
AC_ARG_ENABLE(libxml2,
[AS_HELP_STRING([--disable-libxml2], [do not use libxml2 (removes dependency from libxml2-library, only for development purposes)])],
[USELIBXML2=$enableval],
[USELIBXML2=yes] )
AC_MSG_RESULT($USELIBXML2)
if test "$USELIBXML2" = "yes"; then
AC_ARG_WITH(libxml2_includes,
[AS_HELP_STRING([--with-libxml2-includes=DIR], [libxml2 include directory])],
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
[INCVAL="yes"],
[INCVAL="no"])
AC_ARG_WITH(libxml2_libraries,
[AS_HELP_STRING([--with-libxml2-libraries=DIR], [libxml2 library directory])],
[LDFLAGS="${LDFLAGS} -L${withval}"]
[LIBVAL="yes"],
[LIBVAL="no"])
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
PKG_CHECK_MODULES(libxml2, libxml-2.0,
[LIBS="${LIBS} $libxml2_LIBS"]
[CPPFLAGS="${CPPFLAGS} $libxml2_CFLAGS"],
AC_MSG_ERROR("libxml2 library not found"))
fi
AC_CHECK_HEADER(libxml/tree.h,,
AC_MSG_ERROR("libxml2 header files not found"))
AC_SEARCH_LIBS([xmlNewNode], [xml2], ,
AC_MSG_ERROR("libxml2 library not found"))
else
AC_DEFINE([DISABLE_LIBXML2],1,[Define to 1 to not use libxml2, only for development purposes])
fi
AC_CHECK_HEADER(libxml/tree.h,,
AC_MSG_ERROR("libxml2 header files not found"))
AC_SEARCH_LIBS([xmlNewNode], [xml2], ,
AC_MSG_ERROR("libxml2 library not found"))
dnl
@@ -327,11 +336,8 @@ AC_MSG_RESULT($ENABLEPARCHECK)
if test "$ENABLEPARCHECK" = "yes"; then
dnl PAR2 checks.
dnl
dnl Checks for header files.
AC_CHECK_HEADERS([endian.h] [getopt.h])
dnl Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
AC_C_BIGENDIAN
AC_FUNC_FSEEKO
dnl Checks for library functions.
AC_CHECK_FUNCS([stricmp])
@@ -541,6 +547,36 @@ else
fi
dnl
dnl Determine if CPU supports SIMD instructions
dnl
AC_MSG_CHECKING(whether to use SIMD-optimized routines)
USE_SIMD=no
case $host_cpu in
i?86|x86_64)
SSE2_CXXFLAGS="-msse2"
SSSE3_CXXFLAGS="-mssse3"
PCLMUL_CXXFLAGS="-msse4.1 -mpclmul"
USE_SIMD=yes
;;
arm*)
NEON_CXXFLAGS="-mfpu=neon"
ACLECRC_CXXFLAGS="-march=armv8-a+crc -fpermissive"
USE_SIMD=yes
;;
aarch64)
ACLECRC_CXXFLAGS="-march=armv8-a+crc -fpermissive"
USE_SIMD=yes
;;
esac
AC_MSG_RESULT($USE_SIMD)
AC_SUBST([SSE2_CXXFLAGS])
AC_SUBST([SSSE3_CXXFLAGS])
AC_SUBST([PCLMUL_CXXFLAGS])
AC_SUBST([NEON_CXXFLAGS])
AC_SUBST([ACLECRC_CXXFLAGS])
dnl
dnl Some Linux systems require an empty signal handler for SIGCHLD
dnl in order for exit codes to be correctly delivered to parent process.
@@ -599,11 +635,10 @@ dnl
dnl variadic macros
dnl
AC_MSG_CHECKING(for variadic macros)
AC_COMPILE_IFELSE([
#define macro(...) macrofunc(__VA_ARGS__)
int macrofunc(int a, int b) { return a + b; }
int test() { return macro(1, 2); }
],
AC_TRY_COMPILE(
[ #define macro(...) macrofunc(__VA_ARGS__) ]
[ int macrofunc(int a, int b) { return a + b; } ],
[ int a=macro(1, 2); ],
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_VARIADIC_MACROS], 1, Define to 1 if variadic macros are supported),
AC_MSG_RESULT([no]))

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
#include "nzbget.h"
#include "Connection.h"
#include "Log.h"
#include "FileSystem.h"
static const int CONNECTION_READBUFFER_SIZE = 1024;
#ifndef HAVE_GETADDRINFO
@@ -79,6 +80,10 @@ void closesocket_gracefully(SOCKET socket)
closesocket(socket);
}
#ifdef __linux__
CString ResolveAndroidHost(const char* host);
#endif
void Connection::Init()
{
debug("Initializing global connection data");
@@ -131,6 +136,7 @@ Connection::Connection(SOCKET socket, bool tls)
m_tls = tls;
m_status = csConnected;
m_socket = socket;
m_host = GetRemoteAddr();
m_bufAvail = 0;
m_timeout = 60;
m_suppressErrors = true;
@@ -209,91 +215,122 @@ bool Connection::Bind()
return true;
}
#ifdef HAVE_GETADDRINFO
struct addrinfo addr_hints, *addr_list, *addr;
memset(&addr_hints, 0, sizeof(addr_hints));
addr_hints.ai_family = m_ipVersion == ipV4 ? AF_INET : m_ipVersion == ipV6 ? AF_INET6 : AF_UNSPEC;
addr_hints.ai_socktype = SOCK_STREAM,
addr_hints.ai_flags = AI_PASSIVE; // For wildcard IP address
BString<100> portStr("%d", m_port);
int res = getaddrinfo(m_host, portStr, &addr_hints, &addr_list);
if (res != 0)
{
ReportError("Could not resolve hostname %s", m_host, true
#ifndef WIN32
, res != EAI_SYSTEM ? res : 0
, res != EAI_SYSTEM ? gai_strerror(res) : nullptr
#endif
);
return false;
}
m_broken = false;
m_socket = INVALID_SOCKET;
for (addr = addr_list; addr != nullptr; addr = addr->ai_next)
if (m_host && m_host[0] == '/')
{
m_socket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
#ifdef WIN32
SetHandleInformation((HANDLE)m_socket, HANDLE_FLAG_INHERIT, 0);
#endif
if (m_socket != INVALID_SOCKET)
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
if (strlen(m_host) >= sizeof(addr.sun_path))
{
ReportError("Binding socket failed for %s: name too long\n", m_host, false);
return false;
}
strcpy(addr.sun_path, m_host);
m_socket = socket(PF_UNIX, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
ReportError("Socket creation failed for %s", m_host, true);
return false;
}
unlink(m_host);
if (bind(m_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
int opt = 1;
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
res = bind(m_socket, addr->ai_addr, addr->ai_addrlen);
if (res != -1)
{
// Connection established
break;
}
// Connection failed
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
}
else
#endif
{
#ifdef HAVE_GETADDRINFO
struct addrinfo addr_hints, *addr_list, *addr;
freeaddrinfo(addr_list);
memset(&addr_hints, 0, sizeof(addr_hints));
addr_hints.ai_family = m_ipVersion == ipV4 ? AF_INET : m_ipVersion == ipV6 ? AF_INET6 : AF_UNSPEC;
addr_hints.ai_socktype = SOCK_STREAM;
addr_hints.ai_flags = AI_PASSIVE; // For wildcard IP address
BString<100> portStr("%d", m_port);
int res = getaddrinfo(m_host, portStr, &addr_hints, &addr_list);
if (res != 0)
{
ReportError("Could not resolve hostname %s", m_host, true
#ifndef WIN32
, res != EAI_SYSTEM ? res : 0
, res != EAI_SYSTEM ? gai_strerror(res) : nullptr
#endif
);
return false;
}
m_socket = INVALID_SOCKET;
for (addr = addr_list; addr != nullptr; addr = addr->ai_next)
{
m_socket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
#ifdef WIN32
SetHandleInformation((HANDLE)m_socket, HANDLE_FLAG_INHERIT, 0);
#endif
if (m_socket != INVALID_SOCKET)
{
int opt = 1;
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
res = bind(m_socket, addr->ai_addr, addr->ai_addrlen);
if (res != -1)
{
// Connection established
break;
}
// Connection failed
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
}
freeaddrinfo(addr_list);
#else
struct sockaddr_in sSocketAddress;
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
sSocketAddress.sin_family = AF_INET;
if (!m_host || strlen(m_host) == 0)
{
sSocketAddress.sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_host);
if (sSocketAddress.sin_addr.s_addr == INADDR_NONE)
struct sockaddr_in sSocketAddress;
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
sSocketAddress.sin_family = AF_INET;
if (!m_host || strlen(m_host) == 0)
{
sSocketAddress.sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_host);
if (sSocketAddress.sin_addr.s_addr == INADDR_NONE)
{
return false;
}
}
sSocketAddress.sin_port = htons(m_port);
m_socket = socket(PF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
ReportError("Socket creation failed for %s", m_host, true);
return false;
}
}
sSocketAddress.sin_port = htons(m_port);
m_socket = socket(PF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
ReportError("Socket creation failed for %s", m_host, true);
return false;
}
int opt = 1;
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
int opt = 1;
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
int res = bind(m_socket, (struct sockaddr *) &sSocketAddress, sizeof(sSocketAddress));
if (res == -1)
{
// Connection failed
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
int res = bind(m_socket, (struct sockaddr *) &sSocketAddress, sizeof(sSocketAddress));
if (res == -1)
{
// Connection failed
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
#endif
}
if (m_socket == INVALID_SOCKET)
{
@@ -324,7 +361,7 @@ int Connection::WriteLine(const char* buffer)
int res = send(m_socket, buffer, strlen(buffer), 0);
if (res <= 0)
{
m_broken = true;
m_status = csBroken;
}
return res;
@@ -345,7 +382,7 @@ bool Connection::Send(const char* buffer, int size)
int res = send(m_socket, buffer + bytesSent, size-bytesSent, 0);
if (res <= 0)
{
m_broken = true;
m_status = csBroken;
return false;
}
bytesSent += res;
@@ -374,13 +411,17 @@ char* Connection::ReadLine(char* buffer, int size, int* bytesReadOut)
if (bufAvail < 0)
{
ReportError("Could not receive data on socket from %s", m_host, true);
m_broken = true;
m_status = csBroken;
break;
}
else if (bufAvail == 0)
{
break;
}
else
{
m_totalBytesRead += bufAvail;
}
bufPtr = m_readBuf;
m_readBuf[bufAvail] = '\0';
}
@@ -423,8 +464,6 @@ char* Connection::ReadLine(char* buffer, int size, int* bytesReadOut)
*bytesReadOut = bytesRead;
}
m_totalBytesRead += bytesRead;
if (inpBuffer == buffer)
{
return nullptr;
@@ -452,12 +491,14 @@ std::unique_ptr<Connection> Connection::Accept()
return nullptr;
}
InitSocketOpts(socket);
return std::make_unique<Connection>(socket, m_tls);
}
int Connection::TryRecv(char* buffer, int size)
{
debug("Receiving data");
//debug("Receiving data");
memset(buffer, 0, size);
@@ -467,13 +508,17 @@ int Connection::TryRecv(char* buffer, int size)
{
ReportError("Could not receive data on socket from %s", m_host, true);
}
else
{
m_totalBytesRead += received;
}
return received;
}
bool Connection::Recv(char * buffer, int size)
{
debug("Receiving data (full buffer)");
//debug("Receiving data (full buffer)");
memset(buffer, 0, size);
@@ -502,6 +547,7 @@ bool Connection::Recv(char * buffer, int size)
}
bufPtr += received;
NeedBytes -= received;
m_totalBytesRead += received;
}
return true;
}
@@ -511,113 +557,156 @@ bool Connection::DoConnect()
debug("Do connecting");
m_socket = INVALID_SOCKET;
m_broken = false;
#ifdef HAVE_GETADDRINFO
struct addrinfo addr_hints, *addr_list, *addr;
memset(&addr_hints, 0, sizeof(addr_hints));
addr_hints.ai_family = m_ipVersion == ipV4 ? AF_INET : m_ipVersion == ipV6 ? AF_INET6 : AF_UNSPEC;
addr_hints.ai_socktype = SOCK_STREAM;
BString<100> portStr("%d", m_port);
int res = getaddrinfo(m_host, portStr, &addr_hints, &addr_list);
if (res != 0)
{
ReportError("Could not resolve hostname %s", m_host, true
#ifndef WIN32
, res != EAI_SYSTEM ? res : 0
, res != EAI_SYSTEM ? gai_strerror(res) : nullptr
#endif
);
return false;
}
std::vector<SockAddr> triedAddr;
bool connected = false;
for (addr = addr_list; addr != nullptr; addr = addr->ai_next)
if (m_host && m_host[0] == '/')
{
// don't try the same combinations of ai_family, ai_socktype, ai_protocol multiple times
SockAddr sa = { addr->ai_family, addr->ai_socktype, addr->ai_protocol };
if (std::find(triedAddr.begin(), triedAddr.end(), sa) != triedAddr.end())
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
if (strlen(m_host) >= sizeof(addr.sun_path))
{
continue;
ReportError("Connection to %s failed: name too long\n", m_host, false);
return false;
}
triedAddr.push_back(sa);
strcpy(addr.sun_path, m_host);
if (m_socket != INVALID_SOCKET)
{
closesocket(m_socket);
}
m_socket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
#ifdef WIN32
SetHandleInformation((HANDLE)m_socket, HANDLE_FLAG_INHERIT, 0);
#endif
m_socket = socket(PF_UNIX, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
// try another addr/family/protocol
continue;
ReportError("Socket creation failed for %s", m_host, true);
return false;
}
if (ConnectWithTimeout(addr->ai_addr, addr->ai_addrlen))
if (!ConnectWithTimeout(&addr, sizeof(addr)))
{
// Connection established
connected = true;
break;
ReportError("Connection to %s failed", m_host, true);
closesocket(m_socket);
m_socket = INVALID_SOCKET;
return false;
}
}
if (m_socket == INVALID_SOCKET && addr_list)
else
#endif
{
ReportError("Socket creation failed for %s", m_host, true);
}
#ifdef HAVE_GETADDRINFO
struct addrinfo addr_hints, *addr_list, *addr;
if (!connected && m_socket != INVALID_SOCKET)
{
ReportError("Connection to %s failed", m_host, true);
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
memset(&addr_hints, 0, sizeof(addr_hints));
addr_hints.ai_family = m_ipVersion == ipV4 ? AF_INET : m_ipVersion == ipV6 ? AF_INET6 : AF_UNSPEC;
addr_hints.ai_socktype = SOCK_STREAM;
freeaddrinfo(addr_list);
BString<100> portStr("%d", m_port);
if (m_socket == INVALID_SOCKET)
{
return false;
}
int res = getaddrinfo(m_host, portStr, &addr_hints, &addr_list);
debug("getaddrinfo for %s: %i", *m_host, res);
#ifdef __linux__
if (res != 0)
{
CString resolvedHost = ResolveAndroidHost(m_host);
if (!resolvedHost.Empty())
{
res = getaddrinfo(resolvedHost, portStr, &addr_hints, &addr_list);
}
}
#endif
if (res != 0)
{
ReportError("Could not resolve hostname %s", m_host, true
#ifndef WIN32
, res != EAI_SYSTEM ? res : 0
, res != EAI_SYSTEM ? gai_strerror(res) : nullptr
#endif
);
return false;
}
std::vector<SockAddr> triedAddr;
bool connected = false;
for (addr = addr_list; addr != nullptr; addr = addr->ai_next)
{
// don't try the same combinations of ai_family, ai_socktype, ai_protocol multiple times
SockAddr sa = { addr->ai_family, addr->ai_socktype, addr->ai_protocol };
if (std::find(triedAddr.begin(), triedAddr.end(), sa) != triedAddr.end())
{
continue;
}
triedAddr.push_back(sa);
if (m_socket != INVALID_SOCKET)
{
closesocket(m_socket);
}
m_socket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
#ifdef WIN32
SetHandleInformation((HANDLE)m_socket, HANDLE_FLAG_INHERIT, 0);
#endif
if (m_socket == INVALID_SOCKET)
{
// try another addr/family/protocol
continue;
}
if (ConnectWithTimeout(addr->ai_addr, addr->ai_addrlen))
{
// Connection established
connected = true;
break;
}
}
if (m_socket == INVALID_SOCKET && addr_list)
{
ReportError("Socket creation failed for %s", m_host, true);
}
if (!connected && m_socket != INVALID_SOCKET)
{
ReportError("Connection to %s failed", m_host, true);
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
freeaddrinfo(addr_list);
if (m_socket == INVALID_SOCKET)
{
return false;
}
#else
struct sockaddr_in sSocketAddress;
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
sSocketAddress.sin_family = AF_INET;
sSocketAddress.sin_port = htons(m_port);
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_host);
if (sSocketAddress.sin_addr.s_addr == INADDR_NONE)
{
return false;
}
struct sockaddr_in sSocketAddress;
memset(&sSocketAddress, 0, sizeof(sSocketAddress));
sSocketAddress.sin_family = AF_INET;
sSocketAddress.sin_port = htons(m_port);
sSocketAddress.sin_addr.s_addr = ResolveHostAddr(m_host);
if (sSocketAddress.sin_addr.s_addr == INADDR_NONE)
{
return false;
}
m_socket = socket(PF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
ReportError("Socket creation failed for %s", m_host, true);
return false;
}
m_socket = socket(PF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
ReportError("Socket creation failed for %s", m_host, true);
return false;
}
if (!ConnectWithTimeout(&sSocketAddress, sizeof(sSocketAddress)))
{
ReportError("Connection to %s failed", m_host, true);
closesocket(m_socket);
m_socket = INVALID_SOCKET;
return false;
}
if (!ConnectWithTimeout(&sSocketAddress, sizeof(sSocketAddress)))
{
ReportError("Connection to %s failed", m_host, true);
closesocket(m_socket);
m_socket = INVALID_SOCKET;
return false;
}
#endif
}
if (!InitSocketOpts())
if (!InitSocketOpts(m_socket))
{
return false;
}
@@ -632,7 +721,7 @@ bool Connection::DoConnect()
return true;
}
bool Connection::InitSocketOpts()
bool Connection::InitSocketOpts(SOCKET socket)
{
char* optbuf = nullptr;
int optsize = 0;
@@ -647,13 +736,13 @@ bool Connection::InitSocketOpts()
optbuf = (char*)&TimeVal;
optsize = sizeof(TimeVal);
#endif
int err = setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, optbuf, optsize);
int err = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, optbuf, optsize);
if (err != 0)
{
ReportError("Socket initialization failed for %s", m_host, true);
return false;
}
err = setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, optbuf, optsize);
err = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, optbuf, optsize);
if (err != 0)
{
ReportError("Socket initialization failed for %s", m_host, true);
@@ -719,7 +808,7 @@ bool Connection::ConnectWithTimeout(void* address, int address_len)
//connect succeeded right away?
if (ret != 0)
{
ret = select(m_socket + 1, &rset, &wset, nullptr, m_timeout ? &ts : nullptr);
ret = select((int)m_socket + 1, &rset, &wset, nullptr, m_timeout ? &ts : nullptr);
//we are waiting for connect to complete now
if (ret < 0)
{
@@ -780,6 +869,15 @@ bool Connection::DoDisconnect()
{
#ifndef DISABLE_TLS
CloseTls();
#endif
#ifndef WIN32
int is_listening;
socklen_t len = sizeof(is_listening);
if (m_host && m_host[0] == '/'
&& getsockopt(m_socket, SOL_SOCKET, SO_ACCEPTCONN, &is_listening, &len) == 0 && is_listening)
{
unlink(m_host);
}
#endif
if (m_gracefull)
{
@@ -809,10 +907,17 @@ void Connection::Cancel()
if (m_socket != INVALID_SOCKET)
{
m_status = csCancelled;
int r = shutdown(m_socket, SHUT_RDWR);
if (r == -1)
if (m_forceClose)
{
ReportError("Could not shutdown connection for %s", m_host, true);
SOCKET socket = m_socket;
m_socket = INVALID_SOCKET;
shutdown(socket, SHUT_RDWR);
closesocket(socket);
}
else
{
shutdown(m_socket, SHUT_RDWR);
}
}
}
@@ -987,16 +1092,47 @@ in_addr_t Connection::ResolveHostAddr(const char* host)
const char* Connection::GetRemoteAddr()
{
struct sockaddr_in PeerName;
int peerNameLength = sizeof(PeerName);
if (getpeername(m_socket, (struct sockaddr*)&PeerName, (SOCKLEN_T*) &peerNameLength) >= 0)
#ifndef WIN32
if (m_host && m_host[0] == '/')
{
return "-";
}
#endif
m_remoteAddr.Clear();
char peerName[1024];
int peerNameLength = sizeof(peerName);
if (getpeername(m_socket, (sockaddr*)&peerName, (SOCKLEN_T*)&peerNameLength) >= 0)
{
#ifdef WIN32
m_remoteAddr = inet_ntoa(PeerName.sin_addr);
HMODULE module = LoadLibrary("ws2_32.dll");
if (module)
{
using inet_ntop_t = PCTSTR WSAAPI (INT Family, PVOID pAddr, PTSTR pStringBuf, size_t StringBufSize);
inet_ntop_t* inet_ntop = (inet_ntop_t*)GetProcAddress(module, "inet_ntop");
if (inet_ntop)
{
inet_ntop(((sockaddr_in*)&peerName)->sin_family,
((sockaddr_in*)&peerName)->sin_family == AF_INET6 ?
(void*)&((sockaddr_in6*)&peerName)->sin6_addr :
(void*)&((sockaddr_in*)&peerName)->sin_addr,
m_remoteAddr, m_remoteAddr.Capacity());
}
FreeLibrary(module);
}
if (m_remoteAddr.Empty())
{
m_remoteAddr = inet_ntoa(((sockaddr_in*)&peerName)->sin_addr);
}
#else
inet_ntop(AF_INET, &PeerName.sin_addr, m_remoteAddr, m_remoteAddr.Capacity());
m_remoteAddr[m_remoteAddr.Capacity() - 1] = '\0';
inet_ntop(((sockaddr_in*)&peerName)->sin_family,
((sockaddr_in*)&peerName)->sin_family == AF_INET6 ?
(void*)&((sockaddr_in6*)&peerName)->sin6_addr :
(void*)&((sockaddr_in*)&peerName)->sin_addr,
m_remoteAddr, m_remoteAddr.Capacity());
#endif
m_remoteAddr[m_remoteAddr.Capacity() - 1] = '\0';
}
return m_remoteAddr;
@@ -1008,3 +1144,210 @@ int Connection::FetchTotalBytesRead()
m_totalBytesRead = 0;
return total;
}
#ifdef __linux__
//******************************************************************************
// Android resolver proxy from AOSP (reworked):
// https://github.com/aosp-mirror/platform_bionic/blob/6c1d23f059986e4ee6f52c44a4944089aae9181d/libc/dns/net/gethnamaddr.c
#define MAXALIASES 35
#define MAXADDRS 35
#define ALIGNBYTES (sizeof(uintptr_t) - 1)
#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
// This should be synchronized to ResponseCode.h
static const int DnsProxyQueryResult = 222;
FILE* android_open_proxy()
{
const char* cache_mode = getenv("ANDROID_DNS_MODE");
bool use_proxy = (cache_mode == nullptr || strcmp(cache_mode, "local") != 0);
if (!use_proxy) {
return nullptr;
}
int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (s == -1) {
return nullptr;
}
const int one = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
struct sockaddr_un proxy_addr;
memset(&proxy_addr, 0, sizeof(proxy_addr));
proxy_addr.sun_family = AF_UNIX;
strncpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
if (connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr)) != 0) {
close(s);
return nullptr;
}
return fdopen(s, "r+");
}
static struct hostent * android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen)
{
uint32_t size;
char buf[4];
if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return nullptr;
// This is reading serialized data from system/netd/server/DnsProxyListener.cpp
// and changes here need to be matched there.
int result_code = strtol(buf, nullptr, 10);
if (result_code != DnsProxyQueryResult) {
fread(&size, 1, sizeof(size), proxy);
return nullptr;
}
if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return nullptr;
size = ntohl(size);
memset(hp, 0, sizeof(*hp));
char *ptr = hbuf;
char *hbuf_end = hbuf + hbuflen;
if (ptr + size > hbuf_end) {
return nullptr;
}
if (fread(ptr, 1, size, proxy) != size) return nullptr;
hp->h_name = ptr;
ptr += size;
char *aliases_ptrs[MAXALIASES];
char **aliases = &aliases_ptrs[0];
while (1) {
if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return nullptr;
size = ntohl(size);
if (size == 0) {
*aliases = nullptr;
break;
}
if (ptr + size > hbuf_end) {
return nullptr;
}
if (fread(ptr, 1, size, proxy) != size) return nullptr;
if (aliases < &aliases_ptrs[MAXALIASES - 1]) {
*aliases++ = ptr;
}
ptr += size;
}
// Fix alignment after variable-length data.
ptr = (char*)ALIGN(ptr);
int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
if (ptr + aliases_len > hbuf_end) {
return nullptr;
}
hp->h_aliases = (char**)ptr;
memcpy(ptr, aliases_ptrs, aliases_len);
ptr += aliases_len;
if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return nullptr;
hp->h_addrtype = ntohl(size);
if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return nullptr;
hp->h_length = ntohl(size);
char *addr_ptrs[MAXADDRS];
char **addr_p = &addr_ptrs[0];
while (1) {
if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return nullptr;
size = ntohl(size);
if (size == 0) {
*addr_p = nullptr;
break;
}
if (ptr + size > hbuf_end) {
return nullptr;
}
if (fread(ptr, 1, size, proxy) != size) return nullptr;
if (addr_p < &addr_ptrs[MAXADDRS - 1]) {
*addr_p++ = ptr;
}
ptr += size;
}
// Fix alignment after variable-length data.
ptr = (char*)ALIGN(ptr);
int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
if (ptr + addrs_len > hbuf_end) {
return nullptr;
}
hp->h_addr_list = (char**)ptr;
memcpy(ptr, addr_ptrs, addrs_len);
return hp;
}
// very similar in proxy-ness to android_getaddrinfo_proxy
static struct hostent * android_gethostbyname_internal(const char *name, int af,
struct hostent *hp, char *hbuf, size_t hbuflen)
{
FILE* proxy = android_open_proxy();
if (proxy == nullptr) {
return nullptr;
}
// This is writing to system/netd/server/DnsProxyListener.cpp and changes
// here need to be matched there.
if (fprintf(proxy, "gethostbyname %s %s %d",
"^",
name == nullptr ? "^" : name,
af) < 0) {
fclose(proxy);
return nullptr;
}
if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
fclose(proxy);
return nullptr;
}
struct hostent* result = android_read_hostent(proxy, hp, hbuf, hbuflen);
fclose(proxy);
return result;
}
CString ResolveAndroidHost(const char* host)
{
debug("ResolveAndroidHost");
bool android = FileSystem::DirectoryExists("/data/dalvik-cache");
if (!android)
{
debug("Not android");
return nullptr;
}
struct hostent hinfobuf;
char strbuf[1024];
struct hostent* hinfo = android_gethostbyname_internal(host, AF_INET, &hinfobuf, strbuf, sizeof(strbuf));
if (hinfo == nullptr)
{
// trying IPv6
hinfo = android_gethostbyname_internal(host, AF_INET6, &hinfobuf, strbuf, sizeof(strbuf));
}
if (hinfo == nullptr)
{
debug("android_gethostbyname_r failed");
return nullptr;
}
BString<1024> result;
inet_ntop(hinfo->h_addrtype, hinfo->h_addr_list[0], result, result.Capacity());
debug("android_gethostbyname_r returned %s", *result);
return *result;
}
#endif

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,7 +41,8 @@ public:
csConnected,
csDisconnected,
csListening,
csCancelled
csCancelled,
csBroken
};
enum EIPVersion
@@ -79,6 +80,7 @@ public:
const char* GetRemoteAddr();
bool GetGracefull() { return m_gracefull; }
void SetGracefull(bool gracefull) { m_gracefull = gracefull; }
void SetForceClose(bool forceClose) { m_forceClose = forceClose; }
#ifndef DISABLE_TLS
bool StartTls(bool isClient, const char* certFile, const char* keyFile);
#endif
@@ -99,8 +101,8 @@ protected:
bool m_suppressErrors = true;
BString<100> m_remoteAddr;
int m_totalBytesRead = 0;
bool m_broken = false;
bool m_gracefull = false;
bool m_forceClose = false;
struct SockAddr
{
@@ -138,7 +140,7 @@ protected:
virtual void PrintError(const char* errMsg);
bool DoConnect();
bool DoDisconnect();
bool InitSocketOpts();
bool InitSocketOpts(SOCKET socket);
bool ConnectWithTimeout(void* address, int address_len);
#ifndef HAVE_GETADDRINFO
in_addr_t ResolveHostAddr(const char* host);

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2008-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2008-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -198,11 +198,36 @@ void TlsSocket::Final()
#ifdef HAVE_LIBGNUTLS
gnutls_global_deinit();
#endif /* HAVE_LIBGNUTLS */
#ifdef HAVE_OPENSSL
#ifndef LIBRESSL_VERSION_NUMBER
FIPS_mode_set(0);
#endif
#ifdef NEED_CRYPTO_LOCKING
CRYPTO_set_locking_callback(nullptr);
CRYPTO_set_id_callback(nullptr);
#endif
ERR_remove_state(0);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && ! defined (LIBRESSL_VERSION_NUMBER)
SSL_COMP_free_compression_methods();
#endif
//ENGINE_cleanup();
CONF_modules_free();
CONF_modules_unload(1);
COMP_zlib_cleanup();
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#endif /* HAVE_OPENSSL */
}
TlsSocket::~TlsSocket()
{
Close();
#ifdef HAVE_OPENSSL
ERR_remove_state(0);
#endif
}
void TlsSocket::ReportError(const char* errMsg, bool suppressable)
@@ -415,14 +440,14 @@ bool TlsSocket::Start()
return false;
}
if (m_host && !SSL_set_tlsext_host_name((SSL*)m_session, m_host))
if (m_isClient && m_host && !SSL_set_tlsext_host_name((SSL*)m_session, m_host))
{
ReportError("Could not set host name for TLS");
Close();
return false;
}
if (!SSL_set_fd((SSL*)m_session, m_socket))
if (!SSL_set_fd((SSL*)m_session, (int)m_socket))
{
ReportError("Could not set the file descriptor for TLS");
Close();
@@ -515,7 +540,7 @@ bool TlsSocket::ValidateCert()
}
gnutls_datum_t msgdata;
if (gnutls_certificate-verification_status_print(status, GNUTLS_CRT_X509, &msgdata, 0) == 0)
if (gnutls_certificate_verification_status_print(status, GNUTLS_CRT_X509, &msgdata, 0) == 0)
{
PrintError(BString<1024>("TLS certificate verification failed for %s: %s."
" For more info visit http://nzbget.net/certificate-verification", *m_host, msgdata.data));

View File

@@ -441,7 +441,9 @@ WebDownloader::EStatus WebDownloader::CheckResponse(const char* response)
warn("URL %s failed: %s", *m_infoName, hTTPResponse);
return adNotFound;
}
else if (!strncmp(hTTPResponse, "301", 3) || !strncmp(hTTPResponse, "302", 3))
else if (!strncmp(hTTPResponse, "301", 3) || !strncmp(hTTPResponse, "302", 3) ||
!strncmp(hTTPResponse, "303", 3) || !strncmp(hTTPResponse, "307", 3) ||
!strncmp(hTTPResponse, "308", 3))
{
m_redirecting = true;
return adRunning;
@@ -648,21 +650,6 @@ void WebDownloader::Stop()
debug("WebDownloader stopped successfully");
}
bool WebDownloader::Terminate()
{
std::unique_ptr<Connection> connection = std::move(m_connection);
bool terminated = Kill();
if (terminated && connection)
{
debug("Terminating connection");
connection->SetSuppressErrors(true);
connection->Cancel();
connection->Disconnect();
connection.reset();
}
return terminated;
}
void WebDownloader::FreeConnection()
{
if (m_connection)

View File

@@ -50,7 +50,6 @@ public:
virtual void Stop();
EStatus Download();
EStatus DownloadWithRedirects(int maxRedirects);
bool Terminate();
void SetInfoName(const char* infoName) { m_infoName = infoName; }
const char* GetInfoName() { return m_infoName; }
void SetUrl(const char* url);

View File

@@ -409,11 +409,10 @@ void QueueScriptCoordinator::CheckQueue()
return;
}
m_curItem.reset();
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
Guard guard(m_queueMutex);
m_curItem.reset();
NzbInfo* curNzbInfo = nullptr;
Queue::iterator itCurItem;

View File

@@ -87,7 +87,7 @@ void FeedCoordinator::Run()
usleep(20 * 1000);
}
if (g_Options->GetServerMode() && g_Options->GetSaveQueue() && g_Options->GetReloadQueue())
if (g_Options->GetServerMode())
{
Guard guard(m_downloadsMutex);
g_DiskState->LoadFeeds(&m_feeds, &m_feedHistory);
@@ -118,8 +118,9 @@ void FeedCoordinator::Run()
for (FeedInfo* feedInfo : &m_feeds)
{
if (((feedInfo->GetInterval() > 0 &&
(current - feedInfo->GetLastUpdate() >= feedInfo->GetInterval() * 60 ||
current < feedInfo->GetLastUpdate())) ||
(feedInfo->GetNextUpdate() == 0 ||
current >= feedInfo->GetNextUpdate() ||
current < feedInfo->GetNextUpdate() - feedInfo->GetInterval() * 60)) ||
feedInfo->GetFetch()) &&
feedInfo->GetStatus() != FeedInfo::fsRunning)
{
@@ -182,8 +183,7 @@ void FeedCoordinator::Stop()
void FeedCoordinator::ResetHangingDownloads()
{
const int timeout = g_Options->GetTerminateTimeout();
if (timeout == 0)
if (g_Options->GetUrlTimeout() == 0)
{
return;
}
@@ -191,31 +191,15 @@ void FeedCoordinator::ResetHangingDownloads()
Guard guard(m_downloadsMutex);
time_t tm = Util::CurrentTime();
m_activeDownloads.erase(std::remove_if(m_activeDownloads.begin(), m_activeDownloads.end(),
[timeout, tm](FeedDownloader* feedDownloader)
for (FeedDownloader* feedDownloader: m_activeDownloads)
{
if (tm - feedDownloader->GetLastUpdateTime() > g_Options->GetUrlTimeout() + 10 &&
feedDownloader->GetStatus() == FeedDownloader::adRunning)
{
if (tm - feedDownloader->GetLastUpdateTime() > timeout &&
feedDownloader->GetStatus() == FeedDownloader::adRunning)
{
debug("Terminating hanging download %s", feedDownloader->GetInfoName());
if (feedDownloader->Terminate())
{
error("Terminated hanging download %s", feedDownloader->GetInfoName());
feedDownloader->GetFeedInfo()->SetStatus(FeedInfo::fsUndefined);
}
else
{
error("Could not terminate hanging download %s", feedDownloader->GetInfoName());
}
// it's not safe to destroy feedDownloader, because the state of object is unknown
delete feedDownloader;
return true;
}
return false;
}),
m_activeDownloads.end());
error("Cancelling hanging feed download %s", feedDownloader->GetInfoName());
feedDownloader->Stop();
}
}
}
void FeedCoordinator::LogDebugInfo()
@@ -291,6 +275,8 @@ void FeedCoordinator::FeedCompleted(FeedDownloader* feedDownloader)
m_activeDownloads.erase(std::find(m_activeDownloads.begin(), m_activeDownloads.end(), feedDownloader));
}
SchedulerNextUpdate(feedInfo, statusOK);
if (statusOK)
{
if (!feedInfo->GetPreview())
@@ -337,6 +323,30 @@ void FeedCoordinator::FeedCompleted(FeedDownloader* feedDownloader)
}
}
void FeedCoordinator::SchedulerNextUpdate(FeedInfo* feedInfo, bool success)
{
time_t current = Util::CurrentTime();
int interval;
if (success)
{
interval = feedInfo->GetInterval() * 60;
feedInfo->SetLastInterval(0);
}
else
{
// On failure schedule next update sooner:
// starting with 1 minute and increasing, but not greater than FeedX.Interval
interval = feedInfo->GetLastInterval() * 2;
interval = std::max(interval, 60);
interval = std::min(interval, feedInfo->GetInterval() * 60);
feedInfo->SetLastInterval(interval);
}
detail("Scheduling update for feed %s in %i minute(s)", feedInfo->GetName(), interval / 60);
feedInfo->SetNextUpdate(current + interval);
}
void FeedCoordinator::FilterFeed(FeedInfo* feedInfo, FeedItemList* feedItems)
{
debug("Filtering feed %s", feedInfo->GetName());
@@ -588,7 +598,7 @@ std::unique_ptr<FeedFile> FeedCoordinator::parseFeed(FeedInfo* feedInfo)
error("Feed file %s kept for troubleshooting (will be deleted on next successful feed fetch)", feedInfo->GetOutputFilename());
feedFile.reset();
}
return std::move(feedFile);
return feedFile;
}
void FeedCoordinator::DownloadQueueUpdate(Subject* caller, void* aspect)
@@ -620,11 +630,11 @@ bool FeedCoordinator::HasActiveDownloads()
void FeedCoordinator::CheckSaveFeeds()
{
debug("CheckSaveFeeds");
Guard guard(m_downloadsMutex);
if (m_save)
{
if (g_Options->GetSaveQueue() && g_Options->GetServerMode())
debug("CheckSaveFeeds: save");
if (g_Options->GetServerMode())
{
g_DiskState->SaveFeeds(&m_feeds, &m_feedHistory);
}

View File

@@ -121,6 +121,7 @@ private:
void CleanupCache();
void CheckSaveFeeds();
std::unique_ptr<FeedFile> parseFeed(FeedInfo* feedInfo);
void SchedulerNextUpdate(FeedInfo* feedInfo, bool success);
};
extern FeedCoordinator* g_FeedCoordinator;

View File

@@ -360,6 +360,10 @@ bool FeedFile::ParseFeed(IUnknown* nzb)
bool FeedFile::Parse()
{
#ifdef DISABLE_LIBXML2
error("Could not parse rss feed, program was compiled without libxml2 support");
return false;
#else
xmlSAXHandler SAX_handler = {0};
SAX_handler.startElement = reinterpret_cast<startElementSAXFunc>(SAX_StartElement);
SAX_handler.endElement = reinterpret_cast<endElementSAXFunc>(SAX_EndElement);
@@ -378,6 +382,7 @@ bool FeedFile::Parse()
}
return true;
#endif
}
void FeedFile::Parse_StartElement(const char *name, const char **atts)
@@ -566,7 +571,11 @@ void FeedFile::SAX_characters(FeedFile* file, const char * xmlstr, int len)
void* FeedFile::SAX_getEntity(FeedFile* file, const char * name)
{
#ifdef DISABLE_LIBXML2
void* e = nullptr;
#else
xmlEntityPtr e = xmlGetPredefinedEntity((xmlChar* )name);
#endif
if (!e)
{
warn("entity not found");

View File

@@ -897,7 +897,7 @@ void FeedFilter::Rule::ExpandRefValues(FeedItemInfo& feedItemInfo, CString* dest
break; // error
}
curvalue.Replace(dollar - curvalue, 2 + varlen + 1, varvalue);
curvalue.Replace((int)(dollar - curvalue), 2 + varlen + 1, varvalue);
}
*destStr = std::move(curvalue);

View File

@@ -51,6 +51,10 @@ public:
const char* GetExtensions() { return m_extensions; }
time_t GetLastUpdate() { return m_lastUpdate; }
void SetLastUpdate(time_t lastUpdate) { m_lastUpdate = lastUpdate; }
time_t GetNextUpdate() { return m_nextUpdate; }
void SetNextUpdate(time_t nextUpdate) { m_nextUpdate = nextUpdate; }
int GetLastInterval() { return m_lastInterval; }
void SetLastInterval(int lastInterval) { m_lastInterval = lastInterval; }
bool GetPreview() { return m_preview; }
void SetPreview(bool preview) { m_preview = preview; }
EStatus GetStatus() { return m_status; }
@@ -76,6 +80,8 @@ private:
CString m_extensions;
int m_priority;
time_t m_lastUpdate = 0;
time_t m_nextUpdate = 0;
int m_lastInterval = 0;
bool m_preview = false;
EStatus m_status = fsUndefined;
CString m_outputFilename;

View File

@@ -894,7 +894,7 @@ void CommandLineParser::ParseFileIdList(int argc, const char* argv[], int optind
if (p)
{
BString<100> buf;
buf.Set(optarg, p - optarg);
buf.Set(optarg, (int)(p - optarg));
editQueueIdFrom = atoi(buf);
editQueueIdTo = atoi(p + 1);
if (editQueueIdFrom <= 0 || editQueueIdTo <= 0)

View File

@@ -179,7 +179,7 @@ bool Maintenance::ReadPackageInfoStr(const char* key, CString& value)
return false;
}
int len = pend - p;
int len = (int)(pend - p);
if (len >= sizeof(fileName))
{
error("Could not parse file %s", *fileName);

View File

@@ -69,20 +69,18 @@ static const char* OPTION_CERTCHECK = "CertCheck";
static const char* OPTION_AUTHORIZEDIP = "AuthorizedIP";
static const char* OPTION_ARTICLETIMEOUT = "ArticleTimeout";
static const char* OPTION_URLTIMEOUT = "UrlTimeout";
static const char* OPTION_SAVEQUEUE = "SaveQueue";
static const char* OPTION_REMOTETIMEOUT = "RemoteTimeout";
static const char* OPTION_FLUSHQUEUE = "FlushQueue";
static const char* OPTION_RELOADQUEUE = "ReloadQueue";
static const char* OPTION_BROKENLOG = "BrokenLog";
static const char* OPTION_NZBLOG = "NzbLog";
static const char* OPTION_DECODE = "Decode";
static const char* OPTION_RAWARTICLE = "RawArticle";
static const char* OPTION_SKIPWRITE = "SkipWrite";
static const char* OPTION_ARTICLERETRIES = "ArticleRetries";
static const char* OPTION_ARTICLEINTERVAL = "ArticleInterval";
static const char* OPTION_URLRETRIES = "UrlRetries";
static const char* OPTION_URLINTERVAL = "UrlInterval";
static const char* OPTION_TERMINATETIMEOUT = "TerminateTimeout";
static const char* OPTION_CONTINUEPARTIAL = "ContinuePartial";
static const char* OPTION_URLCONNECTIONS = "UrlConnections";
static const char* OPTION_LOGBUFFERSIZE = "LogBufferSize";
static const char* OPTION_LOGBUFFER = "LogBuffer";
static const char* OPTION_INFOTARGET = "InfoTarget";
static const char* OPTION_WARNINGTARGET = "WarningTarget";
static const char* OPTION_ERRORTARGET = "ErrorTarget";
@@ -118,7 +116,6 @@ static const char* OPTION_SCRIPTPAUSEQUEUE = "ScriptPauseQueue";
static const char* OPTION_NZBCLEANUPDISK = "NzbCleanupDisk";
static const char* OPTION_PARTIMELIMIT = "ParTimeLimit";
static const char* OPTION_KEEPHISTORY = "KeepHistory";
static const char* OPTION_ACCURATERATE = "AccurateRate";
static const char* OPTION_UNPACK = "Unpack";
static const char* OPTION_DIRECTUNPACK = "DirectUnpack";
static const char* OPTION_UNPACKCLEANUPDISK = "UnpackCleanupDisk";
@@ -142,6 +139,7 @@ static const char* OPTION_MONTHLYQUOTA = "MonthlyQuota";
static const char* OPTION_QUOTASTARTDAY = "QuotaStartDay";
static const char* OPTION_DAILYQUOTA = "DailyQuota";
static const char* OPTION_REORDERFILES = "ReorderFiles";
static const char* OPTION_UPDATECHECK = "UpdateCheck";
// obsolete options
static const char* OPTION_POSTLOGKIND = "PostLogKind";
@@ -168,6 +166,13 @@ static const char* OPTION_HISTORYCLEANUPDISK = "HistoryCleanupDisk";
static const char* OPTION_SCANSCRIPT = "ScanScript";
static const char* OPTION_QUEUESCRIPT = "QueueScript";
static const char* OPTION_FEEDSCRIPT = "FeedScript";
static const char* OPTION_DECODE = "Decode";
static const char* OPTION_SAVEQUEUE = "SaveQueue";
static const char* OPTION_RELOADQUEUE = "ReloadQueue";
static const char* OPTION_TERMINATETIMEOUT = "TerminateTimeout";
static const char* OPTION_ACCURATERATE = "AccurateRate";
static const char* OPTION_CREATEBROKENLOG = "CreateBrokenLog";
static const char* OPTION_BROKENLOG = "BrokenLog";
const char* BoolNames[] = { "yes", "no", "true", "false", "1", "0", "on", "off", "enable", "disable", "enabled", "disabled" };
const int BoolValues[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
@@ -416,7 +421,7 @@ void Options::InitDefaults()
SetOption(OPTION_QUEUEDIR, "${MainDir}/queue");
SetOption(OPTION_NZBDIR, "${MainDir}/nzb");
SetOption(OPTION_LOCKFILE, "${MainDir}/nzbget.lock");
SetOption(OPTION_LOGFILE, "${DestDir}/nzbget.log");
SetOption(OPTION_LOGFILE, "${MainDir}/nzbget.log");
SetOption(OPTION_SCRIPTDIR, "${MainDir}/scripts");
SetOption(OPTION_REQUIREDDIR, "");
SetOption(OPTION_WRITELOG, "append");
@@ -443,20 +448,18 @@ void Options::InitDefaults()
SetOption(OPTION_AUTHORIZEDIP, "");
SetOption(OPTION_ARTICLETIMEOUT, "60");
SetOption(OPTION_URLTIMEOUT, "60");
SetOption(OPTION_SAVEQUEUE, "yes");
SetOption(OPTION_REMOTETIMEOUT, "90");
SetOption(OPTION_FLUSHQUEUE, "yes");
SetOption(OPTION_RELOADQUEUE, "yes");
SetOption(OPTION_BROKENLOG, "yes");
SetOption(OPTION_NZBLOG, "yes");
SetOption(OPTION_DECODE, "yes");
SetOption(OPTION_RAWARTICLE, "no");
SetOption(OPTION_SKIPWRITE, "no");
SetOption(OPTION_ARTICLERETRIES, "3");
SetOption(OPTION_ARTICLEINTERVAL, "10");
SetOption(OPTION_URLRETRIES, "3");
SetOption(OPTION_URLINTERVAL, "10");
SetOption(OPTION_TERMINATETIMEOUT, "600");
SetOption(OPTION_CONTINUEPARTIAL, "no");
SetOption(OPTION_URLCONNECTIONS, "4");
SetOption(OPTION_LOGBUFFERSIZE, "1000");
SetOption(OPTION_LOGBUFFER, "1000");
SetOption(OPTION_INFOTARGET, "both");
SetOption(OPTION_WARNINGTARGET, "both");
SetOption(OPTION_ERRORTARGET, "both");
@@ -495,7 +498,6 @@ void Options::InitDefaults()
SetOption(OPTION_NZBCLEANUPDISK, "no");
SetOption(OPTION_PARTIMELIMIT, "0");
SetOption(OPTION_KEEPHISTORY, "7");
SetOption(OPTION_ACCURATERATE, "no");
SetOption(OPTION_UNPACK, "no");
SetOption(OPTION_DIRECTUNPACK, "no");
SetOption(OPTION_UNPACKCLEANUPDISK, "no");
@@ -522,6 +524,7 @@ void Options::InitDefaults()
SetOption(OPTION_QUOTASTARTDAY, "1");
SetOption(OPTION_DAILYQUOTA, "0");
SetOption(OPTION_REORDERFILES, "no");
SetOption(OPTION_UPDATECHECK, "none");
}
void Options::InitOptFile()
@@ -694,7 +697,7 @@ void Options::InitOptions()
m_downloadRate = ParseIntValue(OPTION_DOWNLOADRATE, 10) * 1024;
m_articleTimeout = ParseIntValue(OPTION_ARTICLETIMEOUT, 10);
m_urlTimeout = ParseIntValue(OPTION_URLTIMEOUT, 10);
m_terminateTimeout = ParseIntValue(OPTION_TERMINATETIMEOUT, 10);
m_remoteTimeout = ParseIntValue(OPTION_REMOTETIMEOUT, 10);
m_articleRetries = ParseIntValue(OPTION_ARTICLERETRIES, 10);
m_articleInterval = ParseIntValue(OPTION_ARTICLEINTERVAL, 10);
m_urlRetries = ParseIntValue(OPTION_URLRETRIES, 10);
@@ -702,7 +705,7 @@ void Options::InitOptions()
m_controlPort = ParseIntValue(OPTION_CONTROLPORT, 10);
m_securePort = ParseIntValue(OPTION_SECUREPORT, 10);
m_urlConnections = ParseIntValue(OPTION_URLCONNECTIONS, 10);
m_logBufferSize = ParseIntValue(OPTION_LOGBUFFERSIZE, 10);
m_logBuffer = ParseIntValue(OPTION_LOGBUFFER, 10);
m_rotateLog = ParseIntValue(OPTION_ROTATELOG, 10);
m_umask = ParseIntValue(OPTION_UMASK, 8);
m_updateInterval = ParseIntValue(OPTION_UPDATEINTERVAL, 10);
@@ -728,11 +731,9 @@ void Options::InitOptions()
m_quotaStartDay = ParseIntValue(OPTION_QUOTASTARTDAY, 10);
m_dailyQuota = ParseIntValue(OPTION_DAILYQUOTA, 10);
m_brokenLog = (bool)ParseEnumValue(OPTION_BROKENLOG, BoolCount, BoolNames, BoolValues);
m_nzbLog = (bool)ParseEnumValue(OPTION_NZBLOG, BoolCount, BoolNames, BoolValues);
m_appendCategoryDir = (bool)ParseEnumValue(OPTION_APPENDCATEGORYDIR, BoolCount, BoolNames, BoolValues);
m_continuePartial = (bool)ParseEnumValue(OPTION_CONTINUEPARTIAL, BoolCount, BoolNames, BoolValues);
m_saveQueue = (bool)ParseEnumValue(OPTION_SAVEQUEUE, BoolCount, BoolNames, BoolValues);
m_flushQueue = (bool)ParseEnumValue(OPTION_FLUSHQUEUE, BoolCount, BoolNames, BoolValues);
m_dupeCheck = (bool)ParseEnumValue(OPTION_DUPECHECK, BoolCount, BoolNames, BoolValues);
m_parRepair = (bool)ParseEnumValue(OPTION_PARREPAIR, BoolCount, BoolNames, BoolValues);
@@ -740,19 +741,18 @@ void Options::InitOptions()
m_parRename = (bool)ParseEnumValue(OPTION_PARRENAME, BoolCount, BoolNames, BoolValues);
m_rarRename = (bool)ParseEnumValue(OPTION_RARRENAME, BoolCount, BoolNames, BoolValues);
m_directRename = (bool)ParseEnumValue(OPTION_DIRECTRENAME, BoolCount, BoolNames, BoolValues);
m_reloadQueue = (bool)ParseEnumValue(OPTION_RELOADQUEUE, BoolCount, BoolNames, BoolValues);
m_cursesNzbName = (bool)ParseEnumValue(OPTION_CURSESNZBNAME, BoolCount, BoolNames, BoolValues);
m_cursesTime = (bool)ParseEnumValue(OPTION_CURSESTIME, BoolCount, BoolNames, BoolValues);
m_cursesGroup = (bool)ParseEnumValue(OPTION_CURSESGROUP, BoolCount, BoolNames, BoolValues);
m_crcCheck = (bool)ParseEnumValue(OPTION_CRCCHECK, BoolCount, BoolNames, BoolValues);
m_directWrite = (bool)ParseEnumValue(OPTION_DIRECTWRITE, BoolCount, BoolNames, BoolValues);
m_decode = (bool)ParseEnumValue(OPTION_DECODE, BoolCount, BoolNames, BoolValues);
m_rawArticle = (bool)ParseEnumValue(OPTION_RAWARTICLE, BoolCount, BoolNames, BoolValues);
m_skipWrite = (bool)ParseEnumValue(OPTION_SKIPWRITE, BoolCount, BoolNames, BoolValues);
m_crashTrace = (bool)ParseEnumValue(OPTION_CRASHTRACE, BoolCount, BoolNames, BoolValues);
m_crashDump = (bool)ParseEnumValue(OPTION_CRASHDUMP, BoolCount, BoolNames, BoolValues);
m_parPauseQueue = (bool)ParseEnumValue(OPTION_PARPAUSEQUEUE, BoolCount, BoolNames, BoolValues);
m_scriptPauseQueue = (bool)ParseEnumValue(OPTION_SCRIPTPAUSEQUEUE, BoolCount, BoolNames, BoolValues);
m_nzbCleanupDisk = (bool)ParseEnumValue(OPTION_NZBCLEANUPDISK, BoolCount, BoolNames, BoolValues);
m_accurateRate = (bool)ParseEnumValue(OPTION_ACCURATERATE, BoolCount, BoolNames, BoolValues);
m_formAuth = (bool)ParseEnumValue(OPTION_FORMAUTH, BoolCount, BoolNames, BoolValues);
m_secureControl = (bool)ParseEnumValue(OPTION_SECURECONTROL, BoolCount, BoolNames, BoolValues);
m_unpack = (bool)ParseEnumValue(OPTION_UNPACK, BoolCount, BoolNames, BoolValues);
@@ -917,7 +917,7 @@ void Options::SetOption(const char* optname, const char* value)
const char* varvalue = GetOption(variable);
if (varvalue)
{
curvalue.Replace(dollar - curvalue, 2 + varlen + 1, varvalue);
curvalue.Replace((int)(dollar - curvalue), 2 + varlen + 1, varvalue);
}
else
{
@@ -1502,7 +1502,7 @@ bool Options::SplitOptionString(const char* option, CString& optName, CString& o
return false;
}
optName.Set(option, eq - option);
optName.Set(option, (int)(eq - option));
optValue.Set(eq + 1);
ConvertOldOption(optName, optValue);
@@ -1601,7 +1601,13 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
!strcasecmp(optname, OPTION_RELOADPOSTQUEUE) ||
!strcasecmp(optname, OPTION_PARCLEANUPQUEUE) ||
!strcasecmp(optname, OPTION_DELETECLEANUPDISK) ||
!strcasecmp(optname, OPTION_HISTORYCLEANUPDISK))
!strcasecmp(optname, OPTION_HISTORYCLEANUPDISK) ||
!strcasecmp(optname, OPTION_SAVEQUEUE) ||
!strcasecmp(optname, OPTION_RELOADQUEUE) ||
!strcasecmp(optname, OPTION_TERMINATETIMEOUT) ||
!strcasecmp(optname, OPTION_ACCURATERATE) ||
!strcasecmp(optname, OPTION_CREATEBROKENLOG) ||
!strcasecmp(optname, OPTION_BROKENLOG))
{
ConfigWarn("Option \"%s\" is obsolete, ignored", optname);
return true;
@@ -1721,15 +1727,21 @@ void Options::ConvertOldOption(CString& option, CString& value)
option = "ArticleInterval";
}
if (!strcasecmp(option, "CreateBrokenLog"))
{
option = "BrokenLog";
}
if (!strcasecmp(option, "DumpCore"))
{
option = OPTION_CRASHDUMP;
}
if (!strcasecmp(option, OPTION_DECODE))
{
option = OPTION_RAWARTICLE;
value = !strcasecmp(value, "no") ? "yes" : "no";
}
if (!strcasecmp(option, "LogBufferSize"))
{
option = OPTION_LOGBUFFER;
}
}
void Options::CheckOptions()
@@ -1803,11 +1815,16 @@ void Options::CheckOptions()
m_certCheck = false;
}
if (!m_decode)
if (m_rawArticle)
{
m_directWrite = false;
}
if (m_skipWrite)
{
m_directRename = false;
}
// if option "ConfigTemplate" is not set, use "WebDir" as default location for template
// (for compatibility with versions 9 and 10).
if (m_configTemplate.Empty() && !m_noDiskAccess)

View File

@@ -203,7 +203,6 @@ public:
const char* GetConfigTemplate() { return m_configTemplate; }
const char* GetScriptDir() { return m_scriptDir; }
const char* GetRequiredDir() { return m_requiredDir; }
bool GetBrokenLog() const { return m_brokenLog; }
bool GetNzbLog() const { return m_nzbLog; }
EMessageTarget GetInfoTarget() const { return m_infoTarget; }
EMessageTarget GetWarningTarget() const { return m_warningTarget; }
@@ -212,15 +211,15 @@ public:
EMessageTarget GetDetailTarget() const { return m_detailTarget; }
int GetArticleTimeout() { return m_articleTimeout; }
int GetUrlTimeout() { return m_urlTimeout; }
int GetTerminateTimeout() { return m_terminateTimeout; }
bool GetDecode() { return m_decode; };
int GetRemoteTimeout() { return m_remoteTimeout; }
bool GetRawArticle() { return m_rawArticle; };
bool GetSkipWrite() { return m_skipWrite; };
bool GetAppendCategoryDir() { return m_appendCategoryDir; }
bool GetContinuePartial() { return m_continuePartial; }
int GetArticleRetries() { return m_articleRetries; }
int GetArticleInterval() { return m_articleInterval; }
int GetUrlRetries() { return m_urlRetries; }
int GetUrlInterval() { return m_urlInterval; }
bool GetSaveQueue() { return m_saveQueue; }
bool GetFlushQueue() { return m_flushQueue; }
bool GetDupeCheck() { return m_dupeCheck; }
const char* GetControlIp() { return m_controlIp; }
@@ -242,9 +241,8 @@ public:
const char* GetLockFile() { return m_lockFile; }
const char* GetDaemonUsername() { return m_daemonUsername; }
EOutputMode GetOutputMode() { return m_outputMode; }
bool GetReloadQueue() { return m_reloadQueue; }
int GetUrlConnections() { return m_urlConnections; }
int GetLogBufferSize() { return m_logBufferSize; }
int GetLogBuffer() { return m_logBuffer; }
EWriteLog GetWriteLog() { return m_writeLog; }
const char* GetLogFile() { return m_logFile; }
int GetRotateLog() { return m_rotateLog; }
@@ -279,7 +277,6 @@ public:
bool GetNzbCleanupDisk() { return m_nzbCleanupDisk; }
int GetParTimeLimit() { return m_parTimeLimit; }
int GetKeepHistory() { return m_keepHistory; }
bool GetAccurateRate() { return m_accurateRate; }
bool GetUnpack() { return m_unpack; }
bool GetDirectUnpack() { return m_directUnpack; }
bool GetUnpackCleanupDisk() { return m_unpackCleanupDisk; }
@@ -361,19 +358,18 @@ private:
EMessageTarget m_errorTarget = mtScreen;
EMessageTarget m_debugTarget = mtNone;
EMessageTarget m_detailTarget = mtScreen;
bool m_decode = true;
bool m_brokenLog = false;
bool m_skipWrite = false;
bool m_rawArticle = false;
bool m_nzbLog = false;
int m_articleTimeout = 0;
int m_urlTimeout = 0;
int m_terminateTimeout = 0;
int m_remoteTimeout = 0;
bool m_appendCategoryDir = false;
bool m_continuePartial = false;
int m_articleRetries = 0;
int m_articleInterval = 0;
int m_urlRetries = 0;
int m_urlInterval = 0;
bool m_saveQueue = false;
bool m_flushQueue = false;
bool m_dupeCheck = false;
CString m_controlIp;
@@ -395,9 +391,8 @@ private:
CString m_lockFile;
CString m_daemonUsername;
EOutputMode m_outputMode = omLoggable;
bool m_reloadQueue = false;
int m_urlConnections = 0;
int m_logBufferSize = 0;
int m_logBuffer = 0;
EWriteLog m_writeLog = wlAppend;
int m_rotateLog = 0;
CString m_logFile;
@@ -433,7 +428,6 @@ private:
bool m_nzbCleanupDisk = false;
int m_parTimeLimit = 0;
int m_keepHistory = 0;
bool m_accurateRate = false;
bool m_unpack = false;
bool m_directUnpack = false;
bool m_unpackCleanupDisk = false;

View File

@@ -52,6 +52,7 @@
#include "FileSystem.h"
#include "StackTrace.h"
#include "CommandScript.h"
#include "YEncode.h"
#ifdef WIN32
#include "WinService.h"
#include "WinConsole.h"
@@ -112,6 +113,7 @@ int main(int argc, char *argv[], char *argp[])
#endif
Util::Init();
YEncode::init();
g_ArgumentCount = argc;
g_Arguments = (char*(*)[])argv;
@@ -145,7 +147,7 @@ int main(int argc, char *argv[], char *argp[])
InstallUninstallServiceCheck(argc, argv);
#endif
srand(Util::CurrentTime());
srand((unsigned int)Util::CurrentTime());
#ifdef WIN32
for (int i=0; i < argc; i++)
@@ -499,7 +501,11 @@ void NZBGet::StartRemoteServer()
m_remoteServer = std::make_unique<RemoteServer>(false);
m_remoteServer->Start();
if (m_options->GetSecureControl())
if (m_options->GetSecureControl()
#ifndef WIN32
&& !(m_options->GetControlIp() && m_options->GetControlIp()[0] == '/')
#endif
)
{
m_remoteSecureServer = std::make_unique<RemoteServer>(true);
m_remoteSecureServer->Start();
@@ -512,37 +518,55 @@ void NZBGet::StopRemoteServer()
{
debug("stopping RemoteServer");
m_remoteServer->Stop();
int maxWaitMSec = 1000;
while (m_remoteServer->IsRunning() && maxWaitMSec > 0)
{
usleep(100 * 1000);
maxWaitMSec -= 100;
}
if (m_remoteServer->IsRunning())
{
debug("Killing RemoteServer");
m_remoteServer->Kill();
}
debug("RemoteServer stopped");
}
if (m_remoteSecureServer)
{
debug("stopping RemoteSecureServer");
m_remoteSecureServer->Stop();
int maxWaitMSec = 1000;
while (m_remoteSecureServer->IsRunning() && maxWaitMSec > 0)
{
usleep(100 * 1000);
maxWaitMSec -= 100;
}
if (m_remoteSecureServer->IsRunning())
{
debug("Killing RemoteSecureServer");
m_remoteSecureServer->Kill();
}
debug("RemoteSecureServer stopped");
}
int maxWaitMSec = 5000;
while (((m_remoteServer && m_remoteServer->IsRunning()) ||
(m_remoteSecureServer && m_remoteSecureServer->IsRunning())) &&
maxWaitMSec > 0)
{
usleep(100 * 1000);
maxWaitMSec -= 100;
}
if (m_remoteServer && m_remoteServer->IsRunning())
{
m_remoteServer->ForceStop();
}
if (m_remoteSecureServer && m_remoteSecureServer->IsRunning())
{
m_remoteSecureServer->ForceStop();
}
maxWaitMSec = 5000;
while (((m_remoteServer && m_remoteServer->IsRunning()) ||
(m_remoteSecureServer && m_remoteSecureServer->IsRunning())) &&
maxWaitMSec > 0)
{
usleep(100 * 1000);
maxWaitMSec -= 100;
}
if (m_remoteServer && m_remoteServer->IsRunning())
{
debug("Killing RemoteServer");
m_remoteServer->Kill();
}
if (m_remoteSecureServer && m_remoteSecureServer->IsRunning())
{
debug("Killing RemoteSecureServer");
m_remoteSecureServer->Kill();
}
debug("RemoteServer stopped");
}
void NZBGet::StartFrontend()

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -59,9 +59,6 @@ compiled */
/* Define to 1 if variadic macros are supported */
#define HAVE_VARIADIC_MACROS
/* Define to 1 if libpar2 supports cancelling (needs a special patch) */
#define HAVE_PAR2_CANCEL
/* Define to 1 if function GetAddrInfo is supported */
#define HAVE_GETADDRINFO
@@ -69,7 +66,16 @@ compiled */
#define SOCKLEN_T socklen_t
/* Define to 1 if you have the <regex.h> header file. */
#ifndef DISABLE_REGEX
#define HAVE_REGEX_H 1
// Static linking to regex library
#define REGEX_STATIC
#endif
#ifndef DISABLE_GZIP
// Static linking to zlib library
#define ZLIB_WINAPI
#endif
/* Suppress warnings */
#define _CRT_SECURE_NO_DEPRECATE
@@ -77,13 +83,21 @@ compiled */
/* Suppress warnings */
#define _CRT_NONSTDC_NO_WARNINGS
#ifndef _WIN64
#define _USE_32BIT_TIME_T
#endif
#if _WIN32_WINNT < 0x0501
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#ifdef _WIN64
#define __amd64__
#else
#define __i686__
#endif
#ifdef _DEBUG
// detection of memory leaks
#define _CRTDBG_MAP_ALLOC
@@ -154,21 +168,28 @@ using namespace MSXML;
#include <sys/resource.h>
#include <sys/statvfs.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdint.h>
#include <pwd.h>
#include <dirent.h>
#ifndef DISABLE_LIBXML2
#include <libxml/parser.h>
#include <libxml/xmlreader.h>
#include <libxml/xmlerror.h>
#include <libxml/entities.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
#endif
@@ -194,13 +215,19 @@ using namespace MSXML;
#include <list>
#include <set>
#include <map>
#include <unordered_map>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <memory>
#include <functional>
// NOTE: do not include <iostream> in "nzbget.h". <iostream> contains objects requiring
// intialization, causing every unit in nzbget to have initialization routine. This in particular
// is causing fatal problems in SIMD units which must not have static initialization because
// they contain code with runtime CPU dispatching.
//#include <iostream>
#ifdef HAVE_LIBGNUTLS
#ifdef WIN32
#include <BaseTsd.h>
@@ -227,6 +254,7 @@ typedef int pid_t;
#include <openssl/sha.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/comp.h>
#endif /* HAVE_OPENSSL */
#ifdef HAVE_REGEX_H
@@ -295,11 +323,22 @@ typedef int pid_t;
#define FOPEN_WB "wbN"
#define FOPEN_AB "abN"
#define __SSE2__
#define __SSSE3__
#define __PCLMUL__
#ifdef DEBUG
// redefine "exit" to avoid printing memory leaks report when terminated because of wrong command line switches
#define exit(code) ExitProcess(code)
#endif
#ifdef HAVE_OPENSSL
FILE _iob[] = {*stdin, *stdout, *stderr};
extern "C" FILE * __cdecl __iob_func(void) { return _iob; }
// For static linking of OpenSSL libraries:
#pragma comment (lib, "legacy_stdio_definitions.lib")
#endif /* HAVE_OPENSSL */
#else
// POSIX
@@ -345,6 +384,13 @@ typedef unsigned long long uint64;
typedef unsigned char uchar;
// Assume little endian if byte order is not defined
#ifndef __BYTE_ORDER
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#ifdef __GNUC__
#define PRINTF_SYNTAX(strindex) __attribute__ ((format (printf, strindex, strindex+1)))
#define SCANF_SYNTAX(strindex) __attribute__ ((format (scanf, strindex, strindex+1)))

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,7 +33,6 @@ ArticleDownloader::ArticleDownloader()
{
debug("Creating ArticleDownloader");
m_articleWriter.SetOwner(this);
SetLastUpdateTimeNow();
}
@@ -321,7 +320,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
}
// retrieve article
response = m_connection->Request(BString<1024>("ARTICLE %s\r\n", m_articleInfo->GetMessageId()));
response = m_connection->Request(BString<1024>("%s %s\r\n",
g_Options->GetRawArticle() ? "ARTICLE" : "BODY", m_articleInfo->GetMessageId()));
status = CheckResponse(response, "could not fetch article");
if (status != adFinished)
@@ -329,28 +329,16 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
return status;
}
if (g_Options->GetDecode())
{
m_yDecoder.Clear();
m_yDecoder.SetCrcCheck(g_Options->GetCrcCheck());
m_uDecoder.Clear();
}
m_decoder.Clear();
m_decoder.SetCrcCheck(g_Options->GetCrcCheck());
m_decoder.SetRawMode(g_Options->GetRawArticle());
bool body = false;
bool end = false;
CharBuffer lineBuf(1024*10);
status = adRunning;
CharBuffer lineBuf(1024*4);
while (!IsStopped())
while (!IsStopped() && !m_decoder.GetEof())
{
time_t oldTime = m_lastUpdateTime;
SetLastUpdateTimeNow();
if (oldTime != m_lastUpdateTime)
{
AddServerData();
}
// Throttle the bandwidth
// throttle the bandwidth
while (!IsStopped() && (g_Options->GetDownloadRate() > 0.0f) &&
(g_StatMeter->CalcCurrentDownloadSpeed() > g_Options->GetDownloadRate() ||
g_StatMeter->CalcMomentaryDownloadSpeed() > g_Options->GetDownloadRate()))
@@ -359,17 +347,17 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
usleep(10 * 1000);
}
int len = 0;
char* line = m_connection->ReadLine(lineBuf, lineBuf.Size(), &len);
g_StatMeter->AddSpeedReading(len);
if (g_Options->GetAccurateRate())
char* buffer;
int len;
m_connection->ReadBuffer(&buffer, &len);
if (len == 0)
{
AddServerData();
len = m_connection->TryRecv(lineBuf, lineBuf.Size());
buffer = lineBuf;
}
// Have we encountered a timeout?
if (!line)
// have we encountered a timeout?
if (len <= 0)
{
if (!IsStopped())
{
@@ -379,67 +367,25 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
break;
}
//detect end of article
if (!strcmp(line, ".\r\n") || !strcmp(line, ".\n"))
g_StatMeter->AddSpeedReading(len);
time_t oldTime = m_lastUpdateTime;
SetLastUpdateTimeNow();
if (oldTime != m_lastUpdateTime)
{
end = true;
break;
AddServerData();
}
//detect lines starting with "." (marked as "..")
if (!strncmp(line, "..", 2))
{
line++;
len--;
}
if (!body)
{
// detect body of article
if (*line == '\r' || *line == '\n')
{
body = true;
}
// check id of returned article
else if (!strncmp(line, "Message-ID: ", 12))
{
char* p = line + 12;
if (strncmp(p, m_articleInfo->GetMessageId(), strlen(m_articleInfo->GetMessageId())))
{
if (char* e = strrchr(p, '\r')) *e = '\0'; // remove trailing CR-character
detail("Article %s @ %s failed: Wrong message-id, expected %s, returned %s", *m_infoName,
*m_connectionName, m_articleInfo->GetMessageId(), p);
status = adFailed;
break;
}
}
}
if (m_format == Decoder::efUnknown && g_Options->GetDecode())
{
m_format = Decoder::DetectFormat(line, len, body);
if (m_format != Decoder::efUnknown)
{
// sometimes news servers misbehave and send article body without new line separator between headers and body
// if we found decoder signature we know the body is already arrived
body = true;
}
}
// decode article data
len = m_decoder.DecodeBuffer(buffer, len);
// write to output file
if (((body && m_format != Decoder::efUnknown) || !g_Options->GetDecode()) && !Write(line, len))
if (len > 0 && !Write(buffer, len))
{
status = adFatalError;
break;
}
}
if (!end && status == adRunning && !IsStopped())
{
detail("Article %s @ %s failed: article incomplete", *m_infoName, *m_connectionName);
status = adFailed;
}
if (IsStopped())
{
status = adFailed;
@@ -498,57 +444,47 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* response
}
}
bool ArticleDownloader::Write(char* line, int len)
bool ArticleDownloader::Write(char* buffer, int len)
{
const char* articleFilename = nullptr;
int64 articleFileSize = 0;
int64 articleOffset = 0;
int articleSize = 0;
if (g_Options->GetDecode())
if (!m_writingStarted)
{
if (m_format == Decoder::efYenc)
if (!g_Options->GetRawArticle())
{
len = m_yDecoder.DecodeBuffer(line, len);
articleFilename = m_yDecoder.GetArticleFilename();
articleFileSize = m_yDecoder.GetSize();
}
else if (m_format == Decoder::efUx)
{
len = m_uDecoder.DecodeBuffer(line, len);
articleFilename = m_uDecoder.GetArticleFilename();
}
else
{
detail("Decoding %s failed: unsupported encoding", *m_infoName);
return false;
}
if (len > 0 && m_format == Decoder::efYenc)
{
if (m_yDecoder.GetBegin() == 0 || m_yDecoder.GetEnd() == 0)
articleFilename = m_decoder.GetArticleFilename();
if (m_decoder.GetFormat() == Decoder::efYenc)
{
return false;
if (m_decoder.GetBeginPos() == 0 || m_decoder.GetEndPos() == 0)
{
return false;
}
articleFileSize = m_decoder.GetSize();
articleOffset = m_decoder.GetBeginPos() - 1;
articleSize = (int)(m_decoder.GetEndPos() - m_decoder.GetBeginPos() + 1);
if (articleSize <= 0 || articleSize > 1024*1024*1024)
{
warn("Malformed article %s: size %i out of range", *m_infoName, articleSize);
return false;
}
}
articleOffset = m_yDecoder.GetBegin() - 1;
articleSize = (int)(m_yDecoder.GetEnd() - m_yDecoder.GetBegin() + 1);
}
}
if (!m_writingStarted && len > 0)
{
if (!m_articleWriter.Start(m_format, articleFilename, articleFileSize, articleOffset, articleSize))
if (!m_articleWriter.Start(m_decoder.GetFormat(), articleFilename, articleFileSize, articleOffset, articleSize))
{
return false;
}
m_writingStarted = true;
}
bool ok = len == 0 || m_articleWriter.Write(line, len);
bool ok = m_articleWriter.Write(buffer, len);
if (m_contentAnalyzer)
{
m_contentAnalyzer->Append(line, len);
m_contentAnalyzer->Append(buffer, len);
}
return ok;
@@ -556,36 +492,21 @@ bool ArticleDownloader::Write(char* line, int len)
ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
{
if (g_Options->GetDecode())
if (!g_Options->GetRawArticle())
{
Decoder* decoder = nullptr;
if (m_format == Decoder::efYenc)
{
decoder = &m_yDecoder;
}
else if (m_format == Decoder::efUx)
{
decoder = &m_uDecoder;
}
else
{
detail("Decoding %s failed: no binary data or unsupported encoding format", *m_infoName);
return adFailed;
}
Decoder::EStatus status = decoder->Check();
Decoder::EStatus status = m_decoder.Check();
if (status == Decoder::dsFinished)
{
if (decoder->GetArticleFilename())
if (m_decoder.GetArticleFilename())
{
m_articleFilename = decoder->GetArticleFilename();
m_articleFilename = m_decoder.GetArticleFilename();
}
if (m_format == Decoder::efYenc)
if (m_decoder.GetFormat() == Decoder::efYenc)
{
m_articleInfo->SetCrc(g_Options->GetCrcCheck() ?
m_yDecoder.GetCalculatedCrc() : m_yDecoder.GetExpectedCrc());
m_decoder.GetCalculatedCrc() : m_decoder.GetExpectedCrc());
}
return adFinished;
@@ -646,22 +567,6 @@ void ArticleDownloader::Stop()
debug("ArticleDownloader stopped successfully");
}
bool ArticleDownloader::Terminate()
{
NntpConnection* connection = m_connection;
bool terminated = Kill();
if (terminated && connection)
{
debug("Terminating connection");
connection->SetSuppressErrors(true);
connection->Cancel();
connection->Disconnect();
g_StatMeter->AddServerData(connection->FetchTotalBytesRead(), connection->GetNewsServer()->GetId());
g_ServerPool->FreeConnection(connection, true);
}
return terminated;
}
void ArticleDownloader::FreeConnection(bool keepConnected)
{
if (m_connection)

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -56,16 +56,6 @@ public:
adFatalError
};
class ArticleWriterImpl : public ArticleWriter
{
public:
void SetOwner(ArticleDownloader* owner) { m_owner = owner; }
protected:
virtual void SetLastUpdateTimeNow() { m_owner->SetLastUpdateTimeNow(); }
private:
ArticleDownloader* m_owner;
};
ArticleDownloader();
virtual ~ArticleDownloader();
void SetFileInfo(FileInfo* fileInfo) { m_fileInfo = fileInfo; }
@@ -76,7 +66,6 @@ public:
ServerStatList* GetServerStats() { return &m_serverStats; }
virtual void Run();
virtual void Stop();
bool Terminate();
time_t GetLastUpdateTime() { return m_lastUpdateTime; }
void SetLastUpdateTimeNow();
const char* GetArticleFilename() { return m_articleFilename; }
@@ -101,10 +90,8 @@ private:
CString m_connectionName;
CString m_articleFilename;
time_t m_lastUpdateTime;
Decoder::EFormat m_format = Decoder::efUnknown;
YDecoder m_yDecoder;
UDecoder m_uDecoder;
ArticleWriterImpl m_articleWriter;
Decoder m_decoder;
ArticleWriter m_articleWriter;
ServerStatList m_serverStats;
bool m_writingStarted;
int m_downloadedSize = 0;
@@ -115,7 +102,7 @@ private:
void FreeConnection(bool keepConnected);
EStatus CheckResponse(const char* response, const char* comment);
void SetStatus(EStatus status) { m_status = status; }
bool Write(char* line, int len);
bool Write(char* buffer, int len);
void AddServerData();
};

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2014-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2014-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -106,7 +106,7 @@ bool ArticleWriter::Start(Decoder::EFormat format, const char* filename, int64 f
}
// allocate cache buffer
if (g_Options->GetArticleCache() > 0 && g_Options->GetDecode() &&
if (g_Options->GetArticleCache() > 0 && !g_Options->GetRawArticle() &&
(!g_Options->GetDirectWrite() || m_format == Decoder::efYenc))
{
m_articleData = g_ArticleCache->Alloc(m_articleSize);
@@ -147,22 +147,31 @@ bool ArticleWriter::Start(Decoder::EFormat format, const char* filename, int64 f
bool ArticleWriter::Write(char* buffer, int len)
{
if (g_Options->GetDecode())
if (!g_Options->GetRawArticle())
{
m_articlePtr += len;
}
if (g_Options->GetDecode() && m_articleData.GetData())
if (m_articlePtr > m_articleSize)
{
// An attempt to write beyond article border is detected.
// That's an error condition (damaged article).
// We return 'false' since this isn't a fatal disk error and
// article size mismatch will be detected in decoder check anyway.
return true;
}
if (!g_Options->GetRawArticle() && m_articleData.GetData())
{
if (m_articlePtr > m_articleSize)
{
detail("Decoding %s failed: article size mismatch", *m_infoName);
return false;
}
memcpy(m_articleData.GetData() + m_articlePtr - len, buffer, len);
return true;
}
if (g_Options->GetSkipWrite())
{
return true;
}
return m_outFile.Write(buffer, len) > 0;
}
@@ -179,7 +188,7 @@ void ArticleWriter::Finish(bool success)
bool directWrite = (g_Options->GetDirectWrite() || m_fileInfo->GetForceDirectWrite()) && m_format == Decoder::efYenc;
if (g_Options->GetDecode())
if (!g_Options->GetRawArticle())
{
if (!directWrite && !m_articleData.GetData())
{
@@ -189,10 +198,9 @@ void ArticleWriter::Finish(bool success)
"Could not rename file %s to %s: %s", *m_tempFilename, m_resultFilename,
*FileSystem::GetLastErrorMessage());
}
FileSystem::DeleteFile(m_tempFilename);
}
FileSystem::DeleteFile(m_tempFilename);
if (m_articleData.GetData())
{
if (m_articleSize != m_articlePtr)
@@ -224,19 +232,20 @@ void ArticleWriter::Finish(bool success)
/* creates output file and subdirectores */
bool ArticleWriter::CreateOutputFile(int64 size)
{
if (g_Options->GetDirectWrite() && FileSystem::FileExists(m_outputFilename) &&
FileSystem::FileSize(m_outputFilename) == size)
if (FileSystem::FileExists(m_outputFilename))
{
// keep existing old file from previous program session
return true;
if (FileSystem::FileSize(m_outputFilename) == size)
{
// keep existing old file from previous program session
return true;
}
// delete existing old file from previous program session
FileSystem::DeleteFile(m_outputFilename);
}
// delete eventually existing old file from previous program session
FileSystem::DeleteFile(m_outputFilename);
// ensure the directory exist
BString<1024> destDir;
destDir.Set(m_outputFilename, FileSystem::BaseFileName(m_outputFilename) - m_outputFilename);
destDir.Set(m_outputFilename, (int)(FileSystem::BaseFileName(m_outputFilename) - m_outputFilename));
CString errmsg;
if (!FileSystem::ForceDirectories(destDir, errmsg))
@@ -305,7 +314,7 @@ void ArticleWriter::CompleteFileParts()
bool cached = m_fileInfo->GetCachedArticles() > 0;
if (!g_Options->GetDecode())
if (g_Options->GetRawArticle())
{
detail("Moving articles for %s", *infoFilename);
}
@@ -344,7 +353,7 @@ void ArticleWriter::CompleteFileParts()
DiskFile outfile;
BString<1024> tmpdestfile("%s.tmp", *ofn);
if (g_Options->GetDecode() && !directWrite)
if (!g_Options->GetRawArticle() && !directWrite)
{
FileSystem::DeleteFile(tmpdestfile);
if (!outfile.Open(tmpdestfile, DiskFile::omWrite))
@@ -364,7 +373,7 @@ void ArticleWriter::CompleteFileParts()
}
tmpdestfile = *m_outputFilename;
}
else if (!g_Options->GetDecode())
else if (g_Options->GetRawArticle())
{
FileSystem::DeleteFile(tmpdestfile);
if (!FileSystem::CreateDirectory(ofn))
@@ -392,7 +401,7 @@ void ArticleWriter::CompleteFileParts()
CharBuffer buffer;
bool firstArticle = true;
if (g_Options->GetDecode() && !directWrite)
if (!g_Options->GetRawArticle() && !directWrite)
{
buffer.Reserve(1024 * 64);
}
@@ -404,22 +413,27 @@ void ArticleWriter::CompleteFileParts()
continue;
}
if (g_Options->GetDecode() && !directWrite && pa->GetSegmentOffset() > -1 &&
if (!g_Options->GetRawArticle() && !directWrite && pa->GetSegmentOffset() > -1 &&
pa->GetSegmentOffset() > outfile.Position() && outfile.Position() > -1)
{
memset(buffer, 0, buffer.Size());
while (pa->GetSegmentOffset() > outfile.Position() && outfile.Position() > -1 &&
outfile.Write(buffer, std::min((int)(pa->GetSegmentOffset() - outfile.Position()), buffer.Size())));
if (!g_Options->GetSkipWrite())
{
while (pa->GetSegmentOffset() > outfile.Position() && outfile.Position() > -1 &&
outfile.Write(buffer, std::min((int)(pa->GetSegmentOffset() - outfile.Position()), buffer.Size())));
}
}
if (pa->GetSegmentContent())
{
outfile.Seek(pa->GetSegmentOffset());
outfile.Write(pa->GetSegmentContent(), pa->GetSegmentSize());
if (!g_Options->GetSkipWrite())
{
outfile.Seek(pa->GetSegmentOffset());
outfile.Write(pa->GetSegmentContent(), pa->GetSegmentSize());
}
pa->DiscardSegment();
SetLastUpdateTimeNow();
}
else if (g_Options->GetDecode() && !directWrite)
else if (!g_Options->GetRawArticle() && !directWrite && !g_Options->GetSkipWrite())
{
DiskFile infile;
if (pa->GetResultFilename() && infile.Open(pa->GetResultFilename(), DiskFile::omRead))
@@ -429,7 +443,6 @@ void ArticleWriter::CompleteFileParts()
{
cnt = (int)infile.Read(buffer, buffer.Size());
outfile.Write(buffer, cnt);
SetLastUpdateTimeNow();
}
infile.Close();
}
@@ -443,7 +456,7 @@ void ArticleWriter::CompleteFileParts()
(int)m_fileInfo->GetArticles()->size());
}
}
else if (!g_Options->GetDecode())
else if (g_Options->GetRawArticle())
{
BString<1024> dstFileName("%s%c%03i", *ofn, PATH_SEPARATOR, pa->GetPartNumber());
if (!FileSystem::MoveFile(pa->GetResultFilename(), dstFileName))
@@ -456,7 +469,7 @@ void ArticleWriter::CompleteFileParts()
if (m_format == Decoder::efYenc)
{
crc = firstArticle ? pa->GetCrc() : Util::Crc32Combine(crc, pa->GetCrc(), pa->GetSegmentSize());
crc = firstArticle ? pa->GetCrc() : Crc32::Combine(crc, pa->GetCrc(), pa->GetSegmentSize());
firstArticle = false;
}
}
@@ -492,7 +505,7 @@ void ArticleWriter::CompleteFileParts()
{
debug("Checking old dir for: %s", *m_outputFilename);
BString<1024> oldDestDir;
oldDestDir.Set(m_outputFilename, FileSystem::BaseFileName(m_outputFilename) - m_outputFilename);
oldDestDir.Set(m_outputFilename, (int)(FileSystem::BaseFileName(m_outputFilename) - m_outputFilename));
if (FileSystem::DirEmpty(oldDestDir))
{
debug("Deleting old dir: %s", *oldDestDir);
@@ -522,18 +535,6 @@ void ArticleWriter::CompleteFileParts()
"%i of %i article downloads failed for \"%s\"",
m_fileInfo->GetMissedArticles() + m_fileInfo->GetFailedArticles(),
m_fileInfo->GetTotalArticles(), *infoFilename);
if (g_Options->GetBrokenLog())
{
BString<1024> brokenLogName("%s%c_brokenlog.txt", *nzbDestDir, PATH_SEPARATOR);
DiskFile file;
if (file.Open(brokenLogName, DiskFile::omAppend))
{
file.Print("%s (%i/%i)%s", *filename, m_fileInfo->GetSuccessArticles(),
m_fileInfo->GetTotalArticles(), LINE_ENDING);
file.Close();
}
}
}
else
{
@@ -581,10 +582,18 @@ void ArticleWriter::FlushCache()
ArticleCache::FlushGuard flushGuard = g_ArticleCache->GuardFlush();
std::vector<ArticleInfo*> cachedArticles;
cachedArticles.reserve(m_fileInfo->GetArticles()->size());
{
Guard contentGuard = g_ArticleCache->GuardContent();
if (m_fileInfo->GetFlushLocked())
{
return;
}
m_fileInfo->SetFlushLocked(true);
cachedArticles.reserve(m_fileInfo->GetArticles()->size());
for (ArticleInfo* pa : m_fileInfo->GetArticles())
{
if (pa->GetSegmentContent())
@@ -646,7 +655,10 @@ void ArticleWriter::FlushCache()
outfile.Seek(pa->GetSegmentOffset());
}
outfile.Write(pa->GetSegmentContent(), pa->GetSegmentSize());
if (!g_Options->GetSkipWrite())
{
outfile.Write(pa->GetSegmentContent(), pa->GetSegmentSize());
}
flushedSize += pa->GetSegmentSize();
flushedArticles++;
@@ -671,6 +683,7 @@ void ArticleWriter::FlushCache()
{
Guard contentGuard = g_ArticleCache->GuardContent();
m_fileInfo->SetCachedArticles(m_fileInfo->GetCachedArticles() - flushedArticles);
m_fileInfo->SetFlushLocked(false);
}
}
@@ -714,57 +727,6 @@ bool ArticleWriter::MoveCompletedFiles(NzbInfo* nzbInfo, const char* oldDestDir)
}
}
// move brokenlog.txt
if (g_Options->GetBrokenLog())
{
BString<1024> oldBrokenLogName("%s%c_brokenlog.txt", oldDestDir, PATH_SEPARATOR);
if (FileSystem::FileExists(oldBrokenLogName))
{
BString<1024> brokenLogName("%s%c_brokenlog.txt", nzbInfo->GetDestDir(), PATH_SEPARATOR);
detail("Moving file %s to %s", *oldBrokenLogName, *brokenLogName);
if (FileSystem::FileExists(brokenLogName))
{
// copy content to existing new file, then delete old file
DiskFile outfile;
if (outfile.Open(brokenLogName, DiskFile::omAppend))
{
DiskFile infile;
if (infile.Open(oldBrokenLogName, DiskFile::omRead))
{
CharBuffer buffer(1024 * 50);
int cnt = buffer.Size();
while (cnt == buffer.Size())
{
cnt = (int)infile.Read(buffer, buffer.Size());
outfile.Write(buffer, cnt);
}
infile.Close();
FileSystem::DeleteFile(oldBrokenLogName);
}
else
{
nzbInfo->PrintMessage(Message::mkError, "Could not open file %s", *oldBrokenLogName);
}
outfile.Close();
}
else
{
nzbInfo->PrintMessage(Message::mkError, "Could not open file %s", *brokenLogName);
}
}
else
{
// move to new destination
if (!FileSystem::MoveFile(oldBrokenLogName, brokenLogName))
{
nzbInfo->PrintMessage(Message::mkError, "Could not move file %s to %s: %s",
*oldBrokenLogName, *brokenLogName, *FileSystem::GetLastErrorMessage());
}
}
}
}
// delete old directory (if empty)
if (FileSystem::DirEmpty(oldDestDir))
{
@@ -809,7 +771,7 @@ CachedSegmentData ArticleCache::Alloc(int size)
p = malloc(size);
if (p)
{
if (!m_allocated && g_Options->GetSaveQueue() && g_Options->GetServerMode() && g_Options->GetContinuePartial())
if (!m_allocated && g_Options->GetServerMode() && g_Options->GetContinuePartial())
{
g_DiskState->WriteCacheFlag();
}
@@ -829,6 +791,7 @@ bool ArticleCache::Realloc(CachedSegmentData* segment, int newSize)
{
m_allocated += newSize - segment->m_size;
segment->m_size = newSize;
segment->m_data = (char*)p;
}
return p;
@@ -842,7 +805,7 @@ void ArticleCache::Free(CachedSegmentData* segment)
Guard guard(m_allocMutex);
m_allocated -= segment->m_size;
if (!m_allocated && g_Options->GetSaveQueue() && g_Options->GetServerMode() && g_Options->GetContinuePartial())
if (!m_allocated && g_Options->GetServerMode() && g_Options->GetContinuePartial())
{
g_DiskState->DeleteCacheFlag();
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2014-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2014-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,9 +60,6 @@ public:
static bool MoveCompletedFiles(NzbInfo* nzbInfo, const char* oldDestDir);
void FlushCache();
protected:
virtual void SetLastUpdateTimeNow() {}
private:
FileInfo* m_fileInfo;
ArticleInfo* m_articleInfo;

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,22 +22,129 @@
#include "Decoder.h"
#include "Log.h"
#include "Util.h"
#include "YEncode.h"
const char* Decoder::FormatNames[] = { "Unknown", "yEnc", "UU" };
Decoder::Decoder()
{
debug("%s", YEncode::decode_simd ? "SIMD yEnc decoder can be used" : "SIMD yEnc decoder isn't available for this CPU");
debug("%s", YEncode::crc_simd ? "SIMD Crc routine can be used" : "SIMD Crc routine isn't available for this CPU");
Clear();
}
void Decoder::Clear()
{
m_articleFilename.Clear();
m_body = false;
m_begin = false;
m_part = false;
m_end = false;
m_crc = false;
m_eof = false;
m_expectedCRC = 0;
m_crc32.Reset();
m_beginPos = 0;
m_endPos = 0;
m_size = 0;
m_endSize = 0;
m_outSize = 0;
m_state = 0;
m_crcCheck = false;
m_lineBuf.Reserve(1024*8);
m_lineBuf.SetLength(0);
}
Decoder::EFormat Decoder::DetectFormat(const char* buffer, int len, bool inBody)
/* At the beginning of article the processing goes line by line to find '=ybegin'-marker.
* Once the yEnc-data is started switches to blockwise processing.
* At the end of yEnc-data switches back to line by line mode to
* process '=yend'-marker and EOF-marker.
* UU-encoded articles are processed completely in line by line mode.
*/
int Decoder::DecodeBuffer(char* buffer, int len)
{
if (m_rawMode)
{
ProcessRaw(buffer, len);
return len;
}
int outlen = 0;
if (m_body && m_format == efYenc)
{
outlen = DecodeYenc(buffer, buffer, len);
if (m_body)
{
return outlen;
}
}
else
{
m_lineBuf.Append(buffer, len);
}
char* line = (char*)m_lineBuf;
while (char* end = strchr(line, '\n'))
{
int llen = (int)(end - line + 1);
if (line[0] == '.' && line[1] == '\r')
{
m_eof = true;
m_lineBuf.SetLength(0);
return outlen;
}
if (m_format == efUnknown)
{
m_format = DetectFormat(line, llen);
}
if (m_format == efYenc)
{
ProcessYenc(line, llen);
if (m_body)
{
outlen = DecodeYenc(end + 1, buffer, m_lineBuf.Length() - (int)(end + 1 - m_lineBuf));
if (m_body)
{
m_lineBuf.SetLength(0);
return outlen;
}
line = (char*)m_lineBuf;
continue;
}
}
else if (m_format == efUx)
{
outlen += DecodeUx(line, llen);
}
line = end + 1;
}
if (*line)
{
len = m_lineBuf.Length() - (int)(line - m_lineBuf);
memmove((char*)m_lineBuf, line, len);
m_lineBuf.SetLength(len);
}
else
{
m_lineBuf.SetLength(0);
}
return outlen;
}
Decoder::EFormat Decoder::DetectFormat(const char* buffer, int len)
{
if (!strncmp(buffer, "=ybegin ", 8))
{
return efYenc;
}
if (inBody && (len == 62 || len == 63) && (buffer[62] == '\n' || buffer[62] == '\r') && *buffer == 'M')
if ((len == 62 || len == 63) && (buffer[62] == '\n' || buffer[62] == '\r') && *buffer == 'M')
{
return efUx;
}
@@ -64,139 +171,122 @@ Decoder::EFormat Decoder::DetectFormat(const char* buffer, int len, bool inBody)
return efUnknown;
}
/**
* YDecoder: fast implementation of yEnc-Decoder
*/
YDecoder::YDecoder()
void Decoder::ProcessYenc(char* buffer, int len)
{
Clear();
}
void YDecoder::Clear()
{
Decoder::Clear();
m_body = false;
m_begin = false;
m_part = false;
m_end = false;
m_crc = false;
m_expectedCRC = 0;
m_calculatedCRC = 0xFFFFFFFF;
m_beginPos = 0;
m_endPos = 0;
m_size = 0;
m_endSize = 0;
m_crcCheck = false;
}
int YDecoder::DecodeBuffer(char* buffer, int len)
{
if (m_body && !m_end)
if (!strncmp(buffer, "=ybegin ", 8))
{
if (!strncmp(buffer, "=yend ", 6))
m_begin = true;
char* pb = strstr(buffer, " name=");
if (pb)
{
m_end = true;
char* pb = strstr(buffer, m_part ? " pcrc32=" : " crc32=");
if (pb)
{
m_crc = true;
pb += 7 + (int)m_part; //=strlen(" crc32=") or strlen(" pcrc32=")
m_expectedCRC = strtoul(pb, nullptr, 16);
}
pb = strstr(buffer, " size=");
if (pb)
{
pb += 6; //=strlen(" size=")
m_endSize = (int64)atoll(pb);
}
return 0;
pb += 6; //=strlen(" name=")
char* pe;
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++);
m_articleFilename = WebUtil::Latin1ToUtf8(CString(pb, (int)(pe - pb)));
}
char* iptr = buffer;
char* optr = buffer;
while (true)
pb = strstr(buffer, " size=");
if (pb)
{
switch (*iptr)
{
case '=': //escape-sequence
iptr++;
*optr = *iptr - 64 - 42;
optr++;
break;
case '\n': // ignored char
case '\r': // ignored char
break;
case '\0':
goto BreakLoop;
default: // normal char
*optr = *iptr - 42;
optr++;
break;
}
iptr++;
pb += 6; //=strlen(" size=")
m_size = (int64)atoll(pb);
}
BreakLoop:
if (m_crcCheck)
m_part = strstr(buffer, " part=");
if (!m_part)
{
m_calculatedCRC = Util::Crc32m(m_calculatedCRC, (uchar *)buffer, (uint32)(optr - buffer));
}
return optr - buffer;
}
else
{
if (!m_part && !strncmp(buffer, "=ybegin ", 8))
{
m_begin = true;
char* pb = strstr(buffer, " name=");
if (pb)
{
pb += 6; //=strlen(" name=")
char* pe;
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++) ;
m_articleFilename = WebUtil::Latin1ToUtf8(CString(pb, pe - pb));
}
pb = strstr(buffer, " size=");
if (pb)
{
pb += 6; //=strlen(" size=")
m_size = (int64)atoll(pb);
}
m_part = strstr(buffer, " part=");
if (!m_part)
{
m_body = true;
m_beginPos = 1;
m_endPos = m_size;
}
}
else if (m_part && !strncmp(buffer, "=ypart ", 7))
{
m_part = true;
m_body = true;
char* pb = strstr(buffer, " begin=");
if (pb)
{
pb += 7; //=strlen(" begin=")
m_beginPos = (int64)atoll(pb);
}
pb = strstr(buffer, " end=");
if (pb)
{
pb += 5; //=strlen(" end=")
m_endPos = (int64)atoll(pb);
}
m_beginPos = 1;
m_endPos = m_size;
}
}
else if (!strncmp(buffer, "=ypart ", 7))
{
m_part = true;
m_body = true;
char* pb = strstr(buffer, " begin=");
if (pb)
{
pb += 7; //=strlen(" begin=")
m_beginPos = (int64)atoll(pb);
}
pb = strstr(buffer, " end=");
if (pb)
{
pb += 5; //=strlen(" end=")
m_endPos = (int64)atoll(pb);
}
}
else if (!strncmp(buffer, "=yend ", 6))
{
m_end = true;
char* pb = strstr(buffer, m_part ? " pcrc32=" : " crc32=");
if (pb)
{
m_crc = true;
pb += 7 + (int)m_part; //=strlen(" crc32=") or strlen(" pcrc32=")
m_expectedCRC = strtoul(pb, nullptr, 16);
}
pb = strstr(buffer, " size=");
if (pb)
{
pb += 6; //=strlen(" size=")
m_endSize = (int64)atoll(pb);
}
}
return 0;
}
Decoder::EStatus YDecoder::Check()
int Decoder::DecodeYenc(char* buffer, char* outbuf, int len)
{
m_calculatedCRC ^= 0xFFFFFFFF;
const unsigned char* src = (unsigned char*)buffer;
unsigned char* dst = (unsigned char*)outbuf;
int endseq = YEncode::decode(&src, &dst, len, (YEncode::YencDecoderState*)&m_state);
int outlen = (int)((char*)dst - outbuf);
// endseq:
// 0: no end sequence found
// 1: \r\n=y sequence found, src points to byte after 'y'
// 2: \r\n.\r\n sequence found, src points to byte after last '\n'
if (endseq != 0)
{
// switch back to line mode to process '=yend'- or eof- marker
m_lineBuf.SetLength(0);
m_lineBuf.Append(endseq == 1 ? "=y" : ".\r\n");
int rem = len - (int)((const char*)src - buffer);
if (rem > 0)
{
m_lineBuf.Append((const char*)src, rem);
}
m_body = false;
}
if (m_crcCheck)
{
m_crc32.Append((uchar*)outbuf, (uint32)outlen);
}
m_outSize += outlen;
return outlen;
}
Decoder::EStatus Decoder::Check()
{
switch (m_format)
{
case efYenc:
return CheckYenc();
case efUx:
return CheckUx();
default:
return dsUnknownError;
}
}
Decoder::EStatus Decoder::CheckYenc()
{
m_calculatedCRC = m_crc32.Finish();
debug("Expected crc32=%x", m_expectedCRC);
debug("Calculated crc32=%x", m_calculatedCRC);
@@ -209,7 +299,7 @@ Decoder::EStatus YDecoder::Check()
{
return dsArticleIncomplete;
}
else if (!m_part && m_size != m_endSize)
else if ((!m_part && m_size != m_endSize) || (m_endSize != m_outSize))
{
return dsInvalidSize;
}
@@ -222,24 +312,7 @@ Decoder::EStatus YDecoder::Check()
}
/**
* UDecoder: supports UU encoding formats
*/
UDecoder::UDecoder()
{
Clear();
}
void UDecoder::Clear()
{
Decoder::Clear();
m_body = false;
m_end = false;
}
/* DecodeBuffer-function uses portions of code from tool UUDECODE by Clem Dye
/* DecodeUx-function uses portions of code from tool UUDECODE by Clem Dye
* UUDECODE.c (http://www.bastet.com/uue.zip)
* Copyright (C) 1998 Clem Dye
*
@@ -248,7 +321,7 @@ void UDecoder::Clear()
#define UU_DECODE_CHAR(c) (c == '`' ? 0 : (((c) - ' ') & 077))
int UDecoder::DecodeBuffer(char* buffer, int len)
int Decoder::DecodeUx(char* buffer, int len)
{
if (!m_body)
{
@@ -264,7 +337,7 @@ int UDecoder::DecodeBuffer(char* buffer, int len)
// extracting filename
char* pe;
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++) ;
m_articleFilename = WebUtil::Latin1ToUtf8(CString(pb, pe - pb));
m_articleFilename = WebUtil::Latin1ToUtf8(CString(pb, (int)(pe - pb)));
m_body = true;
return 0;
@@ -312,13 +385,13 @@ int UDecoder::DecodeBuffer(char* buffer, int len)
}
}
return optr - buffer;
return (int)(optr - buffer);
}
return 0;
}
Decoder::EStatus UDecoder::Check()
Decoder::EStatus Decoder::CheckUx()
{
if (!m_body)
{
@@ -327,3 +400,50 @@ Decoder::EStatus UDecoder::Check()
return dsFinished;
}
void Decoder::ProcessRaw(char* buffer, int len)
{
switch (m_state)
{
case 1:
m_eof = len >= 4 && buffer[0] == '\n' &&
buffer[1] == '.' && buffer[2] == '\r' && buffer[3] == '\n';
break;
case 2:
m_eof = len >= 3 && buffer[0] == '.' && buffer[1] == '\r' && buffer[2] == '\n';
break;
case 3:
m_eof = len >= 2 && buffer[0] == '\r' && buffer[1] == '\n';
break;
case 4:
m_eof = len >= 1 && buffer[0] == '\n';
break;
}
m_eof |= len >= 5 && strstr(buffer, "\r\n.\r\n");
if (len >= 4 && buffer[len-4] == '\r' && buffer[len-3] == '\n' &&
buffer[len-2] == '.' && buffer[len-1] == '\r')
{
m_state = 4;
}
else if (len >= 3 && buffer[len-3] == '\r' && buffer[len-2] == '\n' && buffer[len-1] == '.')
{
m_state = 3;
}
else if (len >= 2 && buffer[len-2] == '\r' && buffer[len-1] == '\n')
{
m_state = 2;
}
else if (len >= 1 && buffer[len-1] == '\r')
{
m_state = 1;
}
else
{
m_state = 0;
}
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
#define DECODER_H
#include "NString.h"
#include "Util.h"
class Decoder
{
@@ -43,37 +44,26 @@ public:
efUx,
};
static const char* FormatNames[];
virtual ~Decoder() {}
virtual EStatus Check() = 0;
virtual void Clear();
virtual int DecodeBuffer(char* buffer, int len) = 0;
const char* GetArticleFilename() { return m_articleFilename; }
static EFormat DetectFormat(const char* buffer, int len, bool inBody);
protected:
CString m_articleFilename;
};
class YDecoder: public Decoder
{
public:
YDecoder();
virtual EStatus Check();
virtual void Clear();
virtual int DecodeBuffer(char* buffer, int len);
Decoder();
EStatus Check();
void Clear();
int DecodeBuffer(char* buffer, int len);
void SetCrcCheck(bool crcCheck) { m_crcCheck = crcCheck; }
int64 GetBegin() { return m_beginPos; }
int64 GetEnd() { return m_endPos; }
void SetRawMode(bool rawMode) { m_rawMode = rawMode; }
EFormat GetFormat() { return m_format; }
int64 GetBeginPos() { return m_beginPos; }
int64 GetEndPos() { return m_endPos; }
int64 GetSize() { return m_size; }
uint32 GetExpectedCrc() { return m_expectedCRC; }
uint32 GetCalculatedCrc() { return m_calculatedCRC; }
bool GetEof() { return m_eof; }
const char* GetArticleFilename() { return m_articleFilename; }
private:
private:
EFormat m_format = efUnknown;
bool m_begin;
bool m_part;
bool m_body;
bool m_body;
bool m_end;
bool m_crc;
uint32 m_expectedCRC;
@@ -82,20 +72,22 @@ private:
int64 m_endPos;
int64 m_size;
int64 m_endSize;
int64 m_outSize;
bool m_eof;
bool m_crcCheck;
};
char m_state;
bool m_rawMode = false;
CString m_articleFilename;
StringBuilder m_lineBuf;
Crc32 m_crc32;
class UDecoder: public Decoder
{
public:
UDecoder();
virtual EStatus Check();
virtual void Clear();
virtual int DecodeBuffer(char* buffer, int len);
private:
bool m_body;
bool m_end;
EFormat DetectFormat(const char* buffer, int len);
void ProcessYenc(char* buffer, int len);
int DecodeYenc(char* buffer, char* outbuf, int len);
EStatus CheckYenc();
int DecodeUx(char* buffer, int len);
EStatus CheckUx();
void ProcessRaw(char* buffer, int len);
};
#endif

View File

@@ -227,10 +227,7 @@ bool NntpConnection::Disconnect()
{
if (m_status == csConnected)
{
if (!m_broken)
{
Request("quit\r\n");
}
Request("quit\r\n");
m_activeGroup = nullptr;
}
return Connection::Disconnect();

View File

@@ -308,8 +308,6 @@ void StatMeter::AddSpeedReading(int bytes)
time_t curTime = Util::CurrentTime();
int nowSlot = (int)curTime / SPEEDMETER_SLOTSIZE;
Guard guard(g_Options->GetAccurateRate() ? &m_speedMutex : nullptr);
if (curTime != m_curSecTime)
{
m_curSecTime = curTime;
@@ -490,7 +488,7 @@ void StatMeter::CalcQuotaUsage(int64& monthBytes, int64& dayBytes)
ServerVolume totalVolume = m_serverVolumes[0];
time_t locTime = Util::CurrentTime() + g_Options->GetLocalTimeOffset();
int daySlot = locTime / 86400 - totalVolume.GetFirstDay();
int daySlot = (int)(locTime / 86400) - totalVolume.GetFirstDay();
dayBytes = 0;
if (daySlot < (int)totalVolume.BytesPerDays()->size())
@@ -534,7 +532,7 @@ int StatMeter::CalcMonthSlots(ServerVolume& volume)
dayparts.tm_mon++;
prevMonth = Util::Timegm(&dayparts);
}
elapsedDays = (locCurTime - prevMonth) / 60 / 60 / 24 + 1;
elapsedDays = (int)(locCurTime - prevMonth) / 60 / 60 / 24 + 1;
}
else
{

View File

@@ -106,7 +106,6 @@ private:
int m_speedBytesIndex;
int m_curSecBytes;
time_t m_curSecTime;
Mutex m_speedMutex;
// time
int64 m_allBytes = 0;

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2016-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,6 +44,10 @@ struct NServOpts
bool generateNzb;
int segmentSize;
bool quit;
int latency;
int speed;
bool memCache;
bool paramError;
NServOpts(int argc, char* argv[], Options::CmdOptList& cmdOpts);
};
@@ -59,7 +63,7 @@ int NServMain(int argc, char* argv[])
Options::CmdOptList cmdOpts;
NServOpts opts(argc, argv, cmdOpts);
if (opts.dataDir.Empty())
if (opts.dataDir.Empty() || opts.paramError)
{
NServPrintUsage(argv[0]);
return 1;
@@ -85,6 +89,10 @@ int NServMain(int argc, char* argv[])
TlsSocket::Init();
#endif
#ifndef WIN32
signal(SIGPIPE, SIG_IGN);
#endif
NServFrontend frontend;
frontend.Start();
@@ -105,11 +113,13 @@ int NServMain(int argc, char* argv[])
}
std::vector<std::unique_ptr<NntpServer>> instances;
NntpCache cache;
for (int i = 0; i < opts.instances; i++)
{
instances.emplace_back(std::make_unique<NntpServer>(i + 1, opts.bindAddress,
opts.firstPort + i, opts.secureCert, opts.secureKey, opts.dataDir, opts.cacheDir));
opts.firstPort + i, opts.secureCert, opts.secureKey, opts.dataDir, opts.cacheDir,
opts.latency, opts.speed, opts.memCache ? &cache : nullptr));
instances.back()->Start();
}
@@ -143,12 +153,15 @@ void NServPrintUsage(const char* com)
" -d <data-dir> - directory whose files will be served\n"
" Optional switches:\n"
" -c <cache-dir> - directory to store encoded articles\n"
" -m - in-memory cache (unlimited, use with care)\n"
" -l <log-file> - write into log-file (disabled by default)\n"
" -i <instances> - number of server instances (default is 1)\n"
" -b <address> - ip address to bind to (default is 0.0.0.0)\n"
" -p <port> - port number for the first instance (default is 6791)\n"
" -s <cert> <key> - paths to SSL certificate and key files\n"
" -v <verbose> - verbosity level 0..3 (default is 2)\n"
" -w <msec> - response latency (in milliseconds)\n"
" -r <KB/s> - speed throttling (in kilobytes per second)\n"
" -z <seg-size> - generate nzbs for all files in data-dir (size in bytes)\n"
" -q - quit after generating nzbs (in combination with -z)\n"
, FileSystem::BaseFileName(com));
@@ -162,9 +175,13 @@ NServOpts::NServOpts(int argc, char* argv[], Options::CmdOptList& cmdOpts)
generateNzb = false;
segmentSize = 500000;
quit = false;
latency = 0;
memCache = false;
speed = 0;
paramError = false;
int verbosity = 2;
char short_options[] = "b:c:d:l:p:i:s:v:z:q";
char short_options[] = "b:c:d:l:p:i:ms:v:w:r:z:q";
optind = 2;
while (true)
@@ -181,6 +198,10 @@ NServOpts::NServOpts(int argc, char* argv[], Options::CmdOptList& cmdOpts)
cacheDir = optind > argc ? nullptr : argv[optind - 1];
break;
case 'm':
memCache = true;
break;
case 'l':
logFile = optind > argc ? nullptr : argv[optind - 1];
break;
@@ -207,6 +228,14 @@ NServOpts::NServOpts(int argc, char* argv[], Options::CmdOptList& cmdOpts)
verbosity = atoi(optind > argc ? "1" : argv[optind - 1]);
break;
case 'w':
latency = atoi(optind > argc ? "0" : argv[optind - 1]);
break;
case 'r':
speed = atoi(optind > argc ? "0" : argv[optind - 1]);
break;
case 'z':
generateNzb = true;
segmentSize = atoi(optind > argc ? "500000" : argv[optind - 1]);
@@ -218,6 +247,11 @@ NServOpts::NServOpts(int argc, char* argv[], Options::CmdOptList& cmdOpts)
}
}
if (optind < argc)
{
paramError = true;
}
if (logFile.Empty())
{
cmdOpts.push_back("WriteLog=none");

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2016-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,9 +28,10 @@ class NntpProcessor : public Thread
{
public:
NntpProcessor(int id, int serverId, const char* dataDir, const char* cacheDir,
const char* secureCert, const char* secureKey) :
const char* secureCert, const char* secureKey, int latency, int speed, NntpCache* cache) :
m_id(id), m_serverId(serverId), m_dataDir(dataDir), m_cacheDir(cacheDir),
m_secureCert(secureCert), m_secureKey(secureKey) {}
m_secureCert(secureCert), m_secureKey(secureKey), m_latency(latency),
m_speed(speed), m_cache(cache) {}
~NntpProcessor() { m_connection->Disconnect(); }
virtual void Run();
void SetConnection(std::unique_ptr<Connection>&& connection) { m_connection = std::move(connection); }
@@ -39,6 +40,8 @@ private:
int m_id;
int m_serverId;
std::unique_ptr<Connection> m_connection;
int m_latency;
int m_speed;
const char* m_dataDir;
const char* m_cacheDir;
const char* m_secureCert;
@@ -49,18 +52,29 @@ private:
int64 m_offset;
int m_size;
bool m_sendHeaders;
int64 m_start;
NntpCache* m_cache;
void ServArticle();
void SendSegment();
bool ServerInList(const char* servList);
void SendData(const char* buffer, int size);
};
void NntpServer::Run()
{
debug("Entering NntpServer-loop");
info("Listening on port %i", m_port);
#ifdef WIN32
if (m_speed > 0)
{
timeBeginPeriod(1);
}
#endif
int num = 1;
while (!IsStopped())
@@ -93,8 +107,8 @@ void NntpServer::Run()
continue;
}
NntpProcessor* commandThread = new NntpProcessor(num++, m_id,
m_dataDir, m_cacheDir, m_secureCert, m_secureKey);
NntpProcessor* commandThread = new NntpProcessor(num++, m_id, m_dataDir,
m_cacheDir, m_secureCert, m_secureKey, m_latency, m_speed, m_cache);
commandThread->SetAutoDestroy(true);
commandThread->SetConnection(std::move(acceptedConnection));
commandThread->Start();
@@ -134,6 +148,7 @@ void NntpProcessor::Run()
}
#endif
info("[%i] Incoming connection from: %s", m_id, m_connection->GetHost() );
m_connection->WriteLine("200 Welcome (NServ)\r\n");
CharBuffer buf(1024);
@@ -199,6 +214,11 @@ void NntpProcessor::ServArticle()
{
detail("[%i] Serving: %s", m_id, m_messageid);
if (m_latency)
{
usleep(1000 * m_latency);
}
bool ok = false;
const char* from = strchr(m_messageid, '?');
@@ -209,7 +229,7 @@ void NntpProcessor::ServArticle()
if (from && off && to && end)
{
m_filename.Set(m_messageid + 1, from - m_messageid - 1);
m_filename.Set(m_messageid + 1, (int)(from - m_messageid - 1));
m_part = atoi(from + 1);
m_offset = atoll(off + 1);
m_size = atoi(to + 1);
@@ -250,14 +270,32 @@ void NntpProcessor::SendSegment()
{
detail("[%i] Sending segment %s (%i=%lli:%i)", m_id, *m_filename, m_part, (long long)m_offset, m_size);
if (m_speed > 0)
{
m_start = Util::GetCurrentTicks();
}
BString<1024> fullFilename("%s/%s", m_dataDir, *m_filename);
BString<1024> cacheFileDir("%s/%s", m_cacheDir, *m_filename);
BString<1024> cacheFileName("%i=%lli-%i", m_part, (long long)m_offset, m_size);
BString<1024> cacheFullFilename("%s/%s", *cacheFileDir, *cacheFileName);
BString<1024> cacheKey("%s/%s", *m_filename, *cacheFileName);
const char* cachedData = nullptr;
int cachedSize;
if (m_cache)
{
m_cache->Find(cacheKey, cachedData, cachedSize);
}
DiskFile cacheFile;
bool readCache = m_cacheDir && cacheFile.Open(cacheFullFilename, DiskFile::omRead);
bool writeCache = m_cacheDir && !readCache;
bool readCache = !cachedData && m_cacheDir && cacheFile.Open(cacheFullFilename, DiskFile::omRead);
bool writeCache = !cachedData && m_cacheDir && !readCache;
StringBuilder cacheMem;
if (m_cache && !cachedData)
{
cacheMem.Reserve((int)(m_size * 1.1));
}
CString errmsg;
if (writeCache && !FileSystem::ForceDirectories(cacheFileDir, errmsg))
@@ -270,23 +308,27 @@ void NntpProcessor::SendSegment()
error("Could not create file %s: %s", *cacheFullFilename, *FileSystem::GetLastErrorMessage());
}
if (!readCache && !FileSystem::FileExists(fullFilename))
if (!cachedData && !readCache && !FileSystem::FileExists(fullFilename))
{
m_connection->WriteLine(CString::FormatStr("430 Article not found\r\n"));
return;
}
YEncoder encoder(fullFilename, m_part, m_offset, m_size,
[con = m_connection.get(), writeCache, &cacheFile](const char* buf, int size)
[proc = this, writeCache, &cacheFile, &cacheMem](const char* buf, int size)
{
if (proc->m_cache)
{
cacheMem.Append(buf);
}
if (writeCache)
{
cacheFile.Write(buf, size);
}
con->Send(buf, size);
proc->SendData(buf, size);
});
if (!readCache && !encoder.OpenFile(errmsg))
if (!cachedData && !readCache && !encoder.OpenFile(errmsg))
{
m_connection->WriteLine(CString::FormatStr("403 %s\r\n", *errmsg));
return;
@@ -300,7 +342,11 @@ void NntpProcessor::SendSegment()
m_connection->WriteLine("\r\n");
}
if (readCache)
if (cachedData)
{
SendData(cachedData, cachedSize);
}
else if (readCache)
{
cacheFile.Seek(0, DiskFile::soEnd);
int size = (int)cacheFile.Position();
@@ -310,12 +356,88 @@ void NntpProcessor::SendSegment()
{
error("Could not read file %s: %s", *cacheFullFilename, *FileSystem::GetLastErrorMessage());
}
m_connection->Send(buf, size);
if (m_cache)
{
cacheMem.Append(buf, size);
}
SendData(buf, size);
}
else
{
encoder.WriteSegment();
}
if (!cachedData && cacheMem.Length() > 0)
{
m_cache->Append(cacheKey, cacheMem, cacheMem.Length());
}
m_connection->WriteLine(".\r\n");
}
void NntpProcessor::SendData(const char* buffer, int size)
{
if (m_speed == 0)
{
m_connection->Send(buffer, size);
return;
}
int64 expectedTime = (int64)1000 * size / (m_speed * 1024) - (Util::GetCurrentTicks() - m_start) / 1000;
int chunkNum = 21;
int chunkSize = size;
int pause = 0;
while (pause < 1 && chunkNum > 1)
{
chunkNum--;
chunkSize = size / chunkNum;
pause = (int)(expectedTime / chunkNum);
}
int sent = 0;
for (int i = 0; i < chunkNum; i++)
{
int len = sent + chunkSize < size ? chunkSize : size - sent;
while (sent + len < size && *(buffer + sent + len) != '\r')
{
len++;
}
m_connection->Send(buffer + sent, len);
int64 now = Util::GetCurrentTicks();
if (now + pause * 1000 < m_start + expectedTime * 1000)
{
usleep(pause * 1000);
}
sent += len;
}
}
void NntpCache::Append(const char* key, const char* data, int len)
{
Guard guard(m_lock);
if (!len)
{
len = strlen(data);
}
m_items.emplace(key, std::make_unique<CacheItem>(key, data, len));
}
bool NntpCache::Find(const char* key, const char*& data, int& size)
{
Guard guard(m_lock);
CacheMap::iterator pos = m_items.find(key);
if (pos != m_items.end())
{
data = (*pos).second->m_data;
size = (*pos).second->m_size;
return true;
}
return false;
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2016-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,14 +23,41 @@
#include "Thread.h"
#include "Connection.h"
#include "Util.h"
class NntpCache
{
public:
void Append(const char* key, const char* data, int len = 0);
bool Find(const char* key, const char*& data, int& size);
private:
class CacheItem
{
public:
CacheItem(const char* key, const char* data, int size) :
m_key(key), m_data(data), m_size(size) {}
CString m_key;
CString m_data;
int m_size = 0;
};
typedef std::unordered_map<std::string, std::unique_ptr<CacheItem>> CacheMap;
CacheMap m_items;
Mutex m_lock;
};
class NntpServer : public Thread
{
public:
NntpServer(int id, const char* host, int port, const char* secureCert,
const char* secureKey, const char* dataDir, const char* cacheDir) :
const char* secureKey, const char* dataDir, const char* cacheDir,
int latency, int speed, NntpCache* cache) :
m_id(id), m_host(host), m_port(port), m_secureCert(secureCert),
m_secureKey(secureKey), m_dataDir(dataDir), m_cacheDir(cacheDir) {}
m_secureKey(secureKey), m_dataDir(dataDir), m_cacheDir(cacheDir),
m_latency(latency), m_speed(speed), m_cache(cache) {}
virtual void Run();
virtual void Stop();
@@ -38,11 +65,14 @@ private:
int m_id;
CString m_host;
int m_port;
int m_latency;
int m_speed;
CString m_dataDir;
CString m_cacheDir;
CString m_secureCert;
CString m_secureKey;
std::unique_ptr<Connection> m_connection;
NntpCache* m_cache;
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2016-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -67,7 +67,7 @@ void YEncoder::WriteSegment()
outbuf.Append(CString::FormatStr("=ybegin part=%i line=128 size=%lli name=%s\r\n", m_part, (long long)m_fileSize, FileSystem::BaseFileName(m_filename)));
outbuf.Append(CString::FormatStr("=ypart begin=%lli end=%lli\r\n", (long long)(m_offset + 1), (long long)(m_offset + m_size)));
uint32 crc = 0xFFFFFFFF;
Crc32 crc;
CharBuffer inbuf(std::min(m_size, 16 * 1024 * 1024));
int lnsz = 0;
char* out = (char*)outbuf + outbuf.Length();
@@ -82,7 +82,7 @@ void YEncoder::WriteSegment()
return; // error;
}
crc = Util::Crc32m(crc, (uchar*)(const char*)inbuf, (int)readBytes);
crc.Append((uchar*)(const char*)inbuf, (int)readBytes);
char* in = inbuf;
while (readBytes > 0)
@@ -122,10 +122,8 @@ void YEncoder::WriteSegment()
}
}
}
crc ^= 0xFFFFFFFF;
m_diskfile.Close();
outbuf.Append(CString::FormatStr("=yend size=%i part=0 pcrc32=%08x\r\n", m_size, (unsigned int)crc));
outbuf.Append(CString::FormatStr("=yend size=%i part=0 pcrc32=%08x\r\n", m_size, (unsigned int)crc.Finish()));
m_writeFunc(outbuf, outbuf.Length());
}

View File

@@ -55,7 +55,7 @@ void DirectUnpack::Run()
m_destDir = nzbInfo->GetDestDir();
m_finalDir = nzbInfo->BuildFinalDirName();
NzbParameter* parameter = nzbInfo->GetParameters()->Find("*Unpack:Password", false);
NzbParameter* parameter = nzbInfo->GetParameters()->Find("*Unpack:Password");
if (parameter)
{
m_password = parameter->GetValue();
@@ -346,7 +346,7 @@ void DirectUnpack::AddMessage(Message::EKind kind, const char* text)
if (!strncmp(text, "Unrar: Insert disk with", 23) && strstr(text, " [C]ontinue, [Q]uit"))
{
BString<1024> filename;
filename.Set(text + 24, strstr(text, " [C]ontinue, [Q]uit") - text - 24);
filename.Set(text + 24, (int)(strstr(text, " [C]ontinue, [Q]uit") - text - 24));
WaitNextVolume(filename);
return;
}
@@ -539,7 +539,7 @@ void DirectUnpack::AddExtraTime(NzbInfo* nzbInfo)
{
if (m_extraStartTime)
{
time_t extraTime = Util::CurrentTime() - m_extraStartTime;
int extraTime = (int)(Util::CurrentTime() - m_extraStartTime);
nzbInfo->SetUnpackSec(nzbInfo->GetUnpackSec() + extraTime);
nzbInfo->SetPostTotalSec(nzbInfo->GetPostTotalSec() + extraTime);
m_extraStartTime = 0;

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -106,6 +106,11 @@ private:
volatile bool m_working = false;
};
class RepairCreatorPacket : public Par2::CreatorPacket
{
friend class ParChecker;
};
Par2::Result Repairer::PreProcess(const char *parFilename)
{
BString<100> memParam("-m%i", g_Options->GetParBuffer());
@@ -368,6 +373,7 @@ int ParChecker::StreamBuf::overflow(int ch)
void ParChecker::Cleanup()
{
Guard guard(m_repairerMutex);
m_repairer.reset();
m_queuedParFiles.clear();
m_processedFiles.clear();
@@ -425,11 +431,6 @@ ParChecker::EStatus ParChecker::RunParCheckAll()
{
allStatus = status;
}
if (g_Options->GetBrokenLog())
{
WriteBrokenLog(status);
}
}
}
@@ -464,6 +465,9 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* parFilename)
return psFailed;
}
CString creator = GetPacketCreator();
info("Recovery files created by: %s", creator.Empty() ? "<unknown program>" : *creator);
m_stage = ptVerifyingSources;
res = GetRepairer()->Process(false);
@@ -580,7 +584,8 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* parFilename)
{
m_errMsg = Par2CmdLineErrStr[res];
}
PrintMessage(Message::mkError, "Repair failed for %s: %s", *m_infoName, *m_errMsg);
PrintMessage(Message::mkError, "Repair failed for %s: %s. Recovery files created by: %s",
*m_infoName, *m_errMsg, creator.Empty() ? "<unknown program>" : *creator);
}
Cleanup();
@@ -594,7 +599,10 @@ int ParChecker::PreProcessPar()
{
Cleanup();
m_repairer = std::make_unique<Repairer>(this);
{
Guard guard(m_repairerMutex);
m_repairer = std::make_unique<Repairer>(this);
}
res = GetRepairer()->PreProcess(m_parFilename);
debug("ParChecker: PreProcess-result=%i", res);
@@ -814,7 +822,7 @@ bool ParChecker::AddSplittedFragments()
DirBrowser dir(m_destDir);
while (const char* filename = dir.Next())
{
if (strcmp(filename, "_brokenlog.txt") && !IsParredFile(filename) && !IsProcessedFile(filename))
if (IsParredFile(filename) && !IsProcessedFile(filename))
{
for (Par2::Par2RepairerSourceFile *sourcefile : GetRepairer()->sourcefiles)
{
@@ -942,8 +950,7 @@ bool ParChecker::AddExtraFiles(bool onlyMissing, bool externalDir, const char* d
DirBrowser dir(directory);
while (const char* filename = dir.Next())
{
if (strcmp(filename, "_brokenlog.txt") &&
(externalDir || (!IsParredFile(filename) && !IsProcessedFile(filename))))
if (externalDir || (!IsParredFile(filename) && !IsProcessedFile(filename)))
{
BString<1024> fullfilename("%s%c%s", directory, PATH_SEPARATOR, filename);
extrafiles.emplace_back(*fullfilename, FileSystem::FileSize(fullfilename));
@@ -1186,49 +1193,14 @@ void ParChecker::CheckEmptyFiles()
void ParChecker::Cancel()
{
GetRepairer()->cancelled = true;
QueueChanged();
}
void ParChecker::WriteBrokenLog(EStatus status)
{
BString<1024> brokenLogName("%s%c_brokenlog.txt", *m_destDir, PATH_SEPARATOR);
if (status != psRepairNotNeeded || FileSystem::FileExists(brokenLogName))
{
DiskFile file;
if (file.Open(brokenLogName, DiskFile::omAppend))
Guard guard(m_repairerMutex);
if (m_repairer)
{
if (status == psFailed)
{
if (IsStopped())
{
file.Print("Repair cancelled for %s\n", *m_infoName);
}
else
{
file.Print("Repair failed for %s: %s\n", *m_infoName, *m_errMsg);
}
}
else if (status == psRepairPossible)
{
file.Print("Repair possible for %s\n", *m_infoName);
}
else if (status == psRepaired)
{
file.Print("Successfully repaired %s\n", *m_infoName);
}
else if (status == psRepairNotNeeded)
{
file.Print("Repair not needed for %s\n", *m_infoName);
}
file.Close();
}
else
{
PrintMessage(Message::mkError, "Could not open file %s", *brokenLogName);
m_repairer->GetRepairer()->cancelled = true;
}
}
QueueChanged();
}
void ParChecker::SaveSourceList()
@@ -1399,7 +1371,7 @@ bool ParChecker::VerifySuccessDataFile(void* diskfile, void* sourcefile, uint32
{
const Par2::FILEVERIFICATIONENTRY* entry = packet->VerificationEntry(i);
Par2::u32 blockCrc = entry->crc;
parCrc = i == 0 ? blockCrc : Util::Crc32Combine(parCrc, blockCrc, (uint32)blocksize);
parCrc = i == 0 ? blockCrc : Crc32::Combine(parCrc, blockCrc, (uint32)blocksize);
}
debug("Block-CRC: %x, filename: %s", parCrc, FileSystem::BaseFileName(sourceFile->GetTargetFile()->FileName().c_str()));
@@ -1477,7 +1449,7 @@ bool ParChecker::VerifyPartialDataFile(void* diskfile, void* sourcefile, Segment
}
const Par2::FILEVERIFICATIONENTRY* entry = packet->VerificationEntry(i);
Par2::u32 blockCrc = entry->crc;
parCrc = blockStart == i ? blockCrc : Util::Crc32Combine(parCrc, blockCrc, (uint32)blocksize);
parCrc = blockStart == i ? blockCrc : Crc32::Combine(parCrc, blockCrc, (uint32)blocksize);
}
else
{
@@ -1537,7 +1509,7 @@ bool ParChecker::SmartCalcFileRangeCrc(DiskFile& file, int64 start, int64 end, S
if (segment.GetOffset() >= start && segment.GetOffset() + segment.GetSize() <= end)
{
downloadCrc = !started ? segment.GetCrc() : Util::Crc32Combine(downloadCrc, segment.GetCrc(), (uint32)segment.GetSize());
downloadCrc = !started ? segment.GetCrc() : Crc32::Combine(downloadCrc, segment.GetCrc(), (uint32)segment.GetSize());
started = true;
}
@@ -1555,7 +1527,7 @@ bool ParChecker::SmartCalcFileRangeCrc(DiskFile& file, int64 start, int64 end, S
return false;
}
downloadCrc = Util::Crc32Combine(downloadCrc, (uint32)partialCrc, (uint32)(end - segment.GetOffset() + 1));
downloadCrc = Crc32::Combine(downloadCrc, (uint32)partialCrc, (uint32)(end - segment.GetOffset() + 1));
break;
}
@@ -1576,21 +1548,37 @@ bool ParChecker::DumbCalcFileRangeCrc(DiskFile& file, int64 start, int64 end, ui
}
CharBuffer buffer(1024 * 64);
uint32 downloadCrc = 0xFFFFFFFF;
Crc32 downloadCrc;
int cnt = buffer.Size();
while (cnt == buffer.Size() && start < end)
{
int needBytes = end - start + 1 > buffer.Size() ? buffer.Size() : (int)(end - start + 1);
cnt = (int)file.Read(buffer, needBytes);
downloadCrc = Util::Crc32m(downloadCrc, (uchar*)(char*)buffer, cnt);
downloadCrc.Append((uchar*)(char*)buffer, cnt);
start += cnt;
}
downloadCrc ^= 0xFFFFFFFF;
*downloadCrcOut = downloadCrc;
*downloadCrcOut = downloadCrc.Finish();
return true;
}
CString ParChecker::GetPacketCreator()
{
Par2::CREATORPACKET* creatorpacket;
if (GetRepairer()->creatorpacket &&
(creatorpacket = (Par2::CREATORPACKET*)(((RepairCreatorPacket*)GetRepairer()->creatorpacket)->packetdata)))
{
int len = (int)(creatorpacket->header.length - sizeof(Par2::PACKET_HEADER));
BString<1024> creator;
if (len > 0)
{
creator.Set((const char*)creatorpacket->client, len);
}
return *creator;
}
return nullptr;
}
#endif

View File

@@ -186,6 +186,7 @@ private:
StreamBuf m_parErrStream{this, Message::mkError};
std::ostream m_parCout{&m_parOutStream};
std::ostream m_parCerr{&m_parErrStream};
Mutex m_repairerMutex;
// "m_repairer" should be of type "Par2::Par2Repairer", however to prevent the
// including of libpar2-headers into this header-file we use an empty abstract class.
@@ -204,7 +205,6 @@ private:
bool AddDupeFiles();
bool AddExtraFiles(bool onlyMissing, bool externalDir, const char* directory);
bool IsProcessedFile(const char* filename);
void WriteBrokenLog(EStatus status);
void SaveSourceList();
void DeleteLeftovers();
void signal_filename(std::string str);
@@ -220,6 +220,7 @@ private:
uint32* downloadCrc);
bool DumbCalcFileRangeCrc(DiskFile& file, int64 start, int64 end, uint32* downloadCrc);
void CheckEmptyFiles();
CString GetPacketCreator();
friend class Repairer;
};

View File

@@ -52,7 +52,7 @@ void PrePostProcessor::Run()
usleep(20 * 1000);
}
if (g_Options->GetServerMode() && g_Options->GetSaveQueue() && g_Options->GetReloadQueue())
if (g_Options->GetServerMode())
{
SanitisePostQueue();
}
@@ -309,7 +309,7 @@ void PrePostProcessor::NzbDownloaded(DownloadQueue* downloadQueue, NzbInfo* nzbI
g_QueueScriptCoordinator->EnqueueScript(nzbInfo, QueueScriptCoordinator::qeNzbDeleted);
}
if (!nzbInfo->GetPostInfo() && g_Options->GetDecode())
if (!nzbInfo->GetPostInfo() && !g_Options->GetRawArticle() && !g_Options->GetSkipWrite())
{
nzbInfo->PrintMessage(Message::mkInfo, "Queueing %s for post-processing", nzbInfo->GetName());
@@ -426,12 +426,12 @@ void PrePostProcessor::DeleteCleanup(NzbInfo* nzbInfo)
}
}
// delete .out.tmp-files and _brokenlog.txt
// delete .out.tmp-files
DirBrowser dir(nzbInfo->GetDestDir());
while (const char* filename = dir.Next())
{
int len = strlen(filename);
if ((len > 8 && !strcmp(filename + len - 8, ".out.tmp")) || !strcmp(filename, "_brokenlog.txt"))
if (len > 8 && !strcmp(filename + len - 8, ".out.tmp"))
{
BString<1024> fullFilename("%s%c%s", nzbInfo->GetDestDir(), PATH_SEPARATOR, filename);
detail("Deleting file %s", filename);
@@ -706,7 +706,7 @@ void PrePostProcessor::StartJob(DownloadQueue* downloadQueue, PostInfo* postInfo
}
#endif
NzbParameter* unpackParameter = postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:", false);
NzbParameter* unpackParameter = postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:");
bool wantUnpack = !(unpackParameter && !strcasecmp(unpackParameter->GetValue(), "no"));
bool unpack = wantUnpack && postInfo->GetNzbInfo()->GetUnpackStatus() == NzbInfo::usNone &&
postInfo->GetNzbInfo()->GetDeleteStatus() == NzbInfo::dsNone;
@@ -927,7 +927,7 @@ void PrePostProcessor::FileDownloaded(DownloadQueue* downloadQueue, NzbInfo* nzb
g_QueueScriptCoordinator->EnqueueScript(nzbInfo, QueueScriptCoordinator::qeFileDownloaded);
}
if (g_Options->GetDirectUnpack() && g_Options->GetDecode())
if (g_Options->GetDirectUnpack() && !g_Options->GetRawArticle() && !g_Options->GetSkipWrite())
{
bool allowPar;
if (nzbInfo->GetDirectUnpackStatus() == NzbInfo::nsNone &&
@@ -935,7 +935,7 @@ void PrePostProcessor::FileDownloaded(DownloadQueue* downloadQueue, NzbInfo* nzb
DirectUnpack::IsArchiveFilename(fileInfo->GetFilename()) &&
CanRunMoreJobs(&allowPar))
{
NzbParameter* unpackParameter = nzbInfo->GetParameters()->Find("*Unpack:", false);
NzbParameter* unpackParameter = nzbInfo->GetParameters()->Find("*Unpack:");
bool wantUnpack = !(unpackParameter && !strcasecmp(unpackParameter->GetValue(), "no"));
if (wantUnpack && nzbInfo->GetFailedArticles() == 0)
{

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2016-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -202,7 +202,8 @@ void RarRenamer::MakeSets()
// find first volumes and create initial incomplete sets
for (RarVolume& volume : m_volumes)
{
if (!volume.GetFiles()->empty() && volume.GetVolumeNo() == 0)
if (!volume.GetFiles()->empty() && volume.GetVolumeNo() == 0 &&
!volume.GetFiles()->front().GetSplitBefore())
{
m_sets.push_back({&volume});
}
@@ -217,6 +218,8 @@ void RarRenamer::MakeSets()
while (found)
{
found = false;
std::vector<RarVolume*> candidates;
RarVolume* lastVolume = set.back();
for (RarVolume& volume : *volumes)
{
@@ -229,12 +232,37 @@ void RarRenamer::MakeSets()
!strcmp(volume.GetFiles()->front().GetFilename(), lastVolume->GetFiles()->back().GetFilename())) ||
(!volume.GetFiles()->front().GetSplitBefore() && !lastVolume->GetFiles()->back().GetSplitAfter())))
{
debug(" adding %s", FileSystem::BaseFileName(volume.GetFilename()));
set.push_back(&volume);
found = true;
break;
debug(" found candidate %s", FileSystem::BaseFileName(volume.GetFilename()));
candidates.push_back(&volume);
}
}
RarVolume* nextVolume = nullptr;
if (candidates.size() > 1)
{
for (RarVolume* volume : candidates)
{
if (SameArchiveName(FileSystem::BaseFileName(set[0]->GetFilename()),
FileSystem::BaseFileName(volume->GetFilename()), set[0]->GetNewNaming()))
{
nextVolume = volume;
break;
}
}
}
if (!nextVolume && !candidates.empty())
{
nextVolume = candidates.front();
}
if (nextVolume)
{
debug(" adding %s", FileSystem::BaseFileName(nextVolume->GetFilename()));
set.push_back(nextVolume);
found = true;
}
}
RarVolume* lastVolume = set.back();
@@ -256,6 +284,42 @@ void RarRenamer::MakeSets()
}
}
bool RarRenamer::SameArchiveName(const char* filename1, const char* filename2, bool newNaming)
{
if (strlen(filename1) != strlen(filename2))
{
return false;
}
const char* ext1 = strrchr(filename1, '.');
const char* ext2 = strrchr(filename2, '.');
if (!(ext1 && ext2 && strlen(ext1) == strlen(ext2)))
{
return false;
}
if (newNaming)
{
if (ext1 == filename1 || ext2 == filename2)
{
return false;
}
BString<1024> name1, name2;
name1.Set(filename1, (int)(ext1 - filename1));
name2.Set(filename2, (int)(ext2 - filename2));
ext1 = strrchr(name1, '.');
ext2 = strrchr(name2, '.');
return ext1 && ext2 && strlen(ext1) == strlen(ext2) &&
!strncmp(ext1, ".part", 5) && !strncmp(ext2, ".part", 5) &&
!strncmp(name1, name2, ext1 - name1);
}
else
{
return !strncmp(filename1, filename2, ext1 - filename1);
}
}
bool RarRenamer::IsSetProperlyNamed(RarVolumeSet& set)
{
RegEx regExPart(".*.part([0-9]+)\\.rar$");

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2016-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -76,6 +76,7 @@ private:
void MakeSets();
bool IsSetProperlyNamed(RarVolumeSet& set);
RarFile* FindMainFile(RarVolumeSet& set);
static bool SameArchiveName(const char* filename1, const char* filename2, bool newNaming);
};
#endif

View File

@@ -137,7 +137,7 @@ void RenameController::ExecRename(const char* destDir, const char* finalDir, con
m_rarRenamer.SetInfoName(nzbName);
m_rarRenamer.SetIgnoreExt(g_Options->GetUnpackIgnoreExt());
NzbParameter* parameter = m_postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:Password", false);
NzbParameter* parameter = m_postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:Password");
if (parameter)
{
m_rarRenamer.SetPassword(parameter->GetValue());

View File

@@ -60,10 +60,10 @@ void UnpackController::Run()
m_finalDir = m_postInfo->GetNzbInfo()->GetFinalDir();
m_name = m_postInfo->GetNzbInfo()->GetName();
NzbParameter* parameter = m_postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:", false);
NzbParameter* parameter = m_postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:");
unpack = !(parameter && !strcasecmp(parameter->GetValue(), "no"));
parameter = m_postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:Password", false);
parameter = m_postInfo->GetNzbInfo()->GetParameters()->Find("*Unpack:Password");
if (parameter)
{
m_password = parameter->GetValue();
@@ -191,7 +191,7 @@ void UnpackController::UnpackArchives(EUnpacker unpacker, bool multiVolumes)
if (!m_unpackOk && m_hasParFiles && !m_unpackPasswordError &&
m_postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped)
{
// for rar4- or 7z-archives try par-check first, before trying password file
debug("For rar4- or 7z-archives try par-check first, before trying password file");
return;
}
}
@@ -218,6 +218,7 @@ void UnpackController::UnpackArchives(EUnpacker unpacker, bool multiVolumes)
(m_unpackDecryptError || m_unpackPasswordError) &&
infile.ReadLine(password, sizeof(password) - 1))
{
debug("Password line: %s", password);
// trim trailing <CR> and <LF>
char* end = password + strlen(password) - 1;
while (end >= password && (*end == '\n' || *end == '\r')) *end-- = '\0';
@@ -304,7 +305,7 @@ void UnpackController::ExecuteUnrar(const char* password)
SetProgressLabel("");
m_unpackOk = exitCode == 0 && m_allOkMessageReceived && !GetTerminated();
m_unpackStartError = exitCode == -1;
m_unpackStartError = exitCode == -1 && !m_autoTerminated;
m_unpackSpaceError = exitCode == 5;
m_unpackPasswordError |= exitCode == 11; // only for rar5-archives
@@ -359,7 +360,7 @@ void UnpackController::ExecuteSevenZip(const char* password, bool multiVolumes)
SetProgressLabel("");
m_unpackOk = exitCode == 0 && m_allOkMessageReceived && !GetTerminated();
m_unpackStartError = exitCode == -1;
m_unpackStartError = exitCode == -1 && !m_autoTerminated;
if (!m_unpackOk && exitCode > 0)
{

View File

@@ -186,7 +186,7 @@ void DirectRenamer::ArticleDownloaded(DownloadQueue* downloadQueue, FileInfo* fi
debug("file: %s; article-hash16k: %s", fileInfo->GetFilename(), fileInfo->GetHash16k());
}
detail("Detected %s %s", (contentAnalyzer->GetParFile() ? "par2-file" : "non-par2-file"), fileInfo->GetFilename());
fileInfo->GetNzbInfo()->PrintMessage(Message::mkDetail, "Detected %s %s", (contentAnalyzer->GetParFile() ? "par2-file" : "non-par2-file"), fileInfo->GetFilename());
if (fileInfo->GetParFile() != contentAnalyzer->GetParFile())
{
@@ -199,8 +199,15 @@ void DirectRenamer::ArticleDownloaded(DownloadQueue* downloadQueue, FileInfo* fi
nzbInfo->SetParCurrentSuccessSize(nzbInfo->GetParCurrentSuccessSize() + fileInfo->GetSuccessSize() * delta);
nzbInfo->SetParCurrentFailedSize(nzbInfo->GetParCurrentFailedSize() +
fileInfo->GetFailedSize() * delta + fileInfo->GetMissedSize() * delta);
nzbInfo->SetParFailedSize(nzbInfo->GetParFailedSize() + fileInfo->GetMissedSize() * delta);
nzbInfo->SetRemainingParCount(nzbInfo->GetRemainingParCount() + 1 * delta);
if (!fileInfo->GetParFile() && fileInfo->GetPaused())
{
fileInfo->GetNzbInfo()->PrintMessage(Message::mkInfo, "Resuming non-par2-file %s", fileInfo->GetFilename());
fileInfo->SetPaused(false);
}
downloadQueue->Save();
}
@@ -314,7 +321,7 @@ void DirectRenamer::UnpausePars(NzbInfo* nzbInfo)
FileInfo* fileInfo = nzbInfo->GetFileList()->Find(parFile.GetId());
if (fileInfo)
{
nzbInfo->PrintMessage(Message::mkDetail, "Increasing priority for par2-file %s", fileInfo->GetFilename());
nzbInfo->PrintMessage(Message::mkInfo, "Increasing priority for par2-file %s", fileInfo->GetFilename());
fileInfo->SetPaused(false);
fileInfo->SetExtraPriority(true);
}

View File

@@ -27,6 +27,10 @@
#include "FileSystem.h"
static const char* FORMATVERSION_SIGNATURE = "nzbget diskstate file version ";
const int DISKSTATE_QUEUE_VERSION = 60;
const int DISKSTATE_FILE_VERSION = 5;
const int DISKSTATE_STATS_VERSION = 3;
const int DISKSTATE_FEEDS_VERSION = 3;
class StateDiskFile : public DiskFile
{
@@ -265,7 +269,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* downloadQueue, bool saveHistory
bool ok = true;
{
StateFile stateFile("queue", 60, true);
StateFile stateFile("queue", DISKSTATE_QUEUE_VERSION, true);
if (!downloadQueue->GetQueue()->empty())
{
StateDiskFile* outfile = stateFile.BeginWrite();
@@ -288,7 +292,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* downloadQueue, bool saveHistory
if (saveHistory)
{
StateFile stateFile("history", 60, true);
StateFile stateFile("history", DISKSTATE_QUEUE_VERSION, true);
if (!downloadQueue->GetHistory()->empty())
{
StateDiskFile* outfile = stateFile.BeginWrite();
@@ -320,7 +324,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* downloadQueue, Servers* servers
int formatVersion = 0;
{
StateFile stateFile("queue", 60, true);
StateFile stateFile("queue", DISKSTATE_QUEUE_VERSION, true);
if (stateFile.FileExists())
{
StateDiskFile* infile = stateFile.BeginRead();
@@ -349,7 +353,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* downloadQueue, Servers* servers
if (formatVersion == 0 || formatVersion >= 57)
{
StateFile stateFile("history", 60, true);
StateFile stateFile("history", DISKSTATE_QUEUE_VERSION, true);
if (stateFile.FileExists())
{
StateDiskFile* infile = stateFile.BeginRead();
@@ -361,6 +365,8 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* downloadQueue, Servers* servers
}
}
LoadAllFileInfos(downloadQueue);
CleanupQueueDir(downloadQueue);
if (!LoadAllFileStates(downloadQueue, servers)) goto error;
@@ -819,19 +825,14 @@ bool DiskState::LoadNzbInfo(NzbInfo* nzbInfo, Servers* servers, StateDiskFile& i
std::unique_ptr<FileInfo> fileInfo = std::make_unique<FileInfo>();
fileInfo->SetId(id);
bool res = LoadFile(fileInfo.get(), true, false);
if (res)
fileInfo->SetPaused(paused);
if (formatVersion < 56)
{
fileInfo->SetPaused(paused);
if (formatVersion < 56)
{
fileInfo->SetTime(time);
}
fileInfo->SetExtraPriority((bool)extraPriority);
fileInfo->SetNzbInfo(nzbInfo);
nzbInfo->GetFileList()->Add(std::move(fileInfo));
fileInfo->SetTime(time);
}
fileInfo->SetExtraPriority((bool)extraPriority);
fileInfo->SetNzbInfo(nzbInfo);
nzbInfo->GetFileList()->Add(std::move(fileInfo));
}
return true;
@@ -884,7 +885,7 @@ bool DiskState::SaveFile(FileInfo* fileInfo)
debug("Saving FileInfo %i to disk", fileInfo->GetId());
BString<100> filename("%i", fileInfo->GetId());
StateFile stateFile(filename, 5, false);
StateFile stateFile(filename, DISKSTATE_FILE_VERSION, false);
StateDiskFile* outfile = stateFile.BeginWrite();
if (!outfile)
@@ -892,10 +893,10 @@ bool DiskState::SaveFile(FileInfo* fileInfo)
return false;
}
return SaveFileInfo(fileInfo, *outfile) && stateFile.FinishWrite();
return SaveFileInfo(fileInfo, *outfile, true) && stateFile.FinishWrite();
}
bool DiskState::SaveFileInfo(FileInfo* fileInfo, StateDiskFile& outfile)
bool DiskState::SaveFileInfo(FileInfo* fileInfo, StateDiskFile& outfile, bool articles)
{
outfile.PrintLine("%s", fileInfo->GetSubject());
outfile.PrintLine("%s", fileInfo->GetFilename());
@@ -918,11 +919,14 @@ bool DiskState::SaveFileInfo(FileInfo* fileInfo, StateDiskFile& outfile)
outfile.PrintLine("%s", *group);
}
outfile.PrintLine("%i", (int)fileInfo->GetArticles()->size());
for (ArticleInfo* articleInfo : fileInfo->GetArticles())
if (articles)
{
outfile.PrintLine("%i,%i", articleInfo->GetPartNumber(), articleInfo->GetSize());
outfile.PrintLine("%s", articleInfo->GetMessageId());
outfile.PrintLine("%i", (int)fileInfo->GetArticles()->size());
for (ArticleInfo* articleInfo : fileInfo->GetArticles())
{
outfile.PrintLine("%i,%i", articleInfo->GetPartNumber(), articleInfo->GetSize());
outfile.PrintLine("%s", articleInfo->GetMessageId());
}
}
return true;
@@ -938,7 +942,7 @@ bool DiskState::LoadFile(FileInfo* fileInfo, bool fileSummary, bool articles)
debug("Loading FileInfo %i from disk", fileInfo->GetId());
BString<100> filename("%i", fileInfo->GetId());
StateFile stateFile(filename, 5, false);
StateFile stateFile(filename, DISKSTATE_FILE_VERSION, false);
StateDiskFile* infile = stateFile.BeginRead();
if (!infile)
@@ -999,10 +1003,9 @@ bool DiskState::LoadFileInfo(FileInfo* fileInfo, StateDiskFile& infile, int form
if (fileSummary) fileInfo->GetGroups()->push_back(buf);
}
if (infile.ScanLine("%i", &size) != 1) goto error;
if (articles)
{
if (infile.ScanLine("%i", &size) != 1) goto error;
for (int i = 0; i < size; i++)
{
int PartNumber, PartSize;
@@ -1030,7 +1033,7 @@ bool DiskState::SaveFileState(FileInfo* fileInfo, bool completed)
debug("Saving FileState %i to disk", fileInfo->GetId());
BString<100> filename("%i%s", fileInfo->GetId(), completed ? "c" : "s");
StateFile stateFile(filename, 5, false);
StateFile stateFile(filename, DISKSTATE_FILE_VERSION, false);
StateDiskFile* outfile = stateFile.BeginWrite();
if (!outfile)
@@ -1073,7 +1076,7 @@ bool DiskState::LoadFileState(FileInfo* fileInfo, Servers* servers, bool complet
debug("Loading FileInfo %i from disk", fileInfo->GetId());
BString<100> filename("%i%s", fileInfo->GetId(), completed ? "c" : "s");
StateFile stateFile(filename, 5, false);
StateFile stateFile(filename, DISKSTATE_FILE_VERSION, false);
StateDiskFile* infile = stateFile.BeginRead();
if (!infile)
@@ -1426,6 +1429,50 @@ void DiskState::CleanupTempDir(DownloadQueue* downloadQueue)
void DiskState::CleanupQueueDir(DownloadQueue* downloadQueue)
{
// Prepare sorted id lists for faster search
std::vector<int> nzbIdList;
std::vector<int> fileIdList;
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
nzbIdList.push_back(nzbInfo->GetId());
for (FileInfo* fileInfo : nzbInfo->GetFileList())
{
fileIdList.push_back(fileInfo->GetId());
}
for (CompletedFile& completedFile : nzbInfo->GetCompletedFiles())
{
fileIdList.push_back(completedFile.GetId());
}
}
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
{
if (historyInfo->GetKind() == HistoryInfo::hkNzb)
{
NzbInfo* nzbInfo = historyInfo->GetNzbInfo();
nzbIdList.push_back(nzbInfo->GetId());
for (FileInfo* fileInfo : nzbInfo->GetFileList())
{
fileIdList.push_back(fileInfo->GetId());
}
for (CompletedFile& completedFile : nzbInfo->GetCompletedFiles())
{
fileIdList.push_back(completedFile.GetId());
}
}
}
std::sort(nzbIdList.begin(), nzbIdList.end());
std::sort(fileIdList.begin(), fileIdList.end());
// Do cleanup
int deletedFiles = 0;
DirBrowser dir(g_Options->GetQueueDir());
@@ -1438,74 +1485,12 @@ void DiskState::CleanupQueueDir(DownloadQueue* downloadQueue)
if ((sscanf(filename, "%i%c", &id, &suffix) == 2 && (suffix == 's' || suffix == 'c')) ||
(sscanf(filename, "%i", &id) == 1 && !strchr(filename, '.')))
{
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
for (FileInfo* fileInfo : nzbInfo->GetFileList())
{
if (fileInfo->GetId() == id)
{
goto next;
}
}
for (CompletedFile& completedFile : nzbInfo->GetCompletedFiles())
{
if (completedFile.GetId() == id)
{
goto next;
}
}
}
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
{
if (historyInfo->GetKind() == HistoryInfo::hkNzb)
{
NzbInfo* nzbInfo = historyInfo->GetNzbInfo();
for (FileInfo* fileInfo : nzbInfo->GetFileList())
{
if (fileInfo->GetId() == id)
{
goto next;
}
}
for (CompletedFile& completedFile : nzbInfo->GetCompletedFiles())
{
if (completedFile.GetId() == id)
{
goto next;
}
}
}
}
del = true;
del = !std::binary_search(fileIdList.begin(), fileIdList.end(), id);
}
if (!del && sscanf(filename, "n%i.log", &id) == 1)
{
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
if (nzbInfo->GetId() == id)
{
goto next;
}
}
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
{
if (historyInfo->GetKind() == HistoryInfo::hkNzb)
{
if (historyInfo->GetNzbInfo()->GetId() == id)
{
goto next;
}
}
}
del = true;
del = !std::binary_search(nzbIdList.begin(), nzbIdList.end(), id);
}
if (del)
@@ -1515,8 +1500,6 @@ void DiskState::CleanupQueueDir(DownloadQueue* downloadQueue)
FileSystem::DeleteFile(fullFilename);
deletedFiles++;
}
next:;
}
if (deletedFiles > 0)
@@ -1534,7 +1517,7 @@ bool DiskState::SaveFeeds(Feeds* feeds, FeedHistory* feedHistory)
{
debug("Saving feeds state to disk");
StateFile stateFile("feeds", 3, true);
StateFile stateFile("feeds", DISKSTATE_FEEDS_VERSION, true);
if (feeds->empty() && feedHistory->empty())
{
@@ -1562,7 +1545,7 @@ bool DiskState::LoadFeeds(Feeds* feeds, FeedHistory* feedHistory)
{
debug("Loading feeds state from disk");
StateFile stateFile("feeds", 3, true);
StateFile stateFile("feeds", DISKSTATE_FEEDS_VERSION, true);
if (!stateFile.FileExists())
{
@@ -1704,6 +1687,119 @@ void DiskState::CalcFileStats(DownloadQueue* downloadQueue, int formatVersion)
}
}
bool DiskState::SaveAllFileInfos(DownloadQueue* downloadQueue)
{
bool ok = true;
StateFile stateFile("files", DISKSTATE_FILE_VERSION, true);
if (!downloadQueue->GetQueue()->empty())
{
StateDiskFile* outfile = stateFile.BeginWrite();
if (!outfile)
{
return false;
}
// save file-infos
int fileCount = 0;
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
fileCount += nzbInfo->GetFileList()->size();
}
outfile->PrintLine("%i", fileCount);
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
for (FileInfo* fileInfo : nzbInfo->GetFileList())
{
outfile->PrintLine("%i", fileInfo->GetId());
SaveFileInfo(fileInfo, *outfile, false);
}
}
// now rename to dest file name
ok = stateFile.FinishWrite();
}
else
{
stateFile.Discard();
}
return ok;
}
bool DiskState::LoadAllFileInfos(DownloadQueue* downloadQueue)
{
if (downloadQueue->GetQueue()->empty())
{
return true;
}
StateFile stateFile("files", DISKSTATE_FILE_VERSION, false);
StateDiskFile* infile = nullptr;
bool useHibernate = false;
if (stateFile.FileExists())
{
infile = stateFile.BeginRead();
useHibernate = infile != nullptr;
if (useHibernate)
{
int fileCount = 0;
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
fileCount += nzbInfo->GetFileList()->size();
}
int size = 0;
useHibernate = infile->ScanLine("%i", &size) == 1 && size == fileCount;
}
if (!useHibernate)
{
stateFile.Discard();
}
}
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
RawFileList brokenFileInfos;
for (FileInfo* fileInfo : nzbInfo->GetFileList())
{
bool res = false;
if (useHibernate)
{
int id = 0;
infile->ScanLine("%i", &id);
if (id == fileInfo->GetId())
{
res = LoadFileInfo(fileInfo, *infile, stateFile.GetFileVersion(), true, false);
}
}
if (!res)
{
res = LoadFile(fileInfo, true, false);
}
if (!res)
{
brokenFileInfos.push_back(fileInfo);
}
}
for (FileInfo* fileInfo : brokenFileInfos)
{
nzbInfo->GetFileList()->Remove(fileInfo);
}
}
return true;
}
void DiskState::DiscardQuickFileInfos()
{
StateFile stateFile("files", DISKSTATE_FILE_VERSION, false);
stateFile.Discard();
}
bool DiskState::LoadAllFileStates(DownloadQueue* downloadQueue, Servers* servers)
{
BString<1024> cacheFlagFilename("%s%c%s", g_Options->GetQueueDir(), PATH_SEPARATOR, "acache");
@@ -1751,7 +1847,7 @@ bool DiskState::SaveStats(Servers* servers, ServerVolumes* serverVolumes)
{
debug("Saving stats to disk");
StateFile stateFile("stats", 3, true);
StateFile stateFile("stats", DISKSTATE_STATS_VERSION, true);
if (servers->empty())
{
@@ -1779,7 +1875,7 @@ bool DiskState::LoadStats(Servers* servers, ServerVolumes* serverVolumes, bool*
{
debug("Loading stats from disk");
StateFile stateFile("stats", 3, true);
StateFile stateFile("stats", DISKSTATE_STATS_VERSION, true);
if (!stateFile.FileExists())
{

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,6 +38,8 @@ public:
bool LoadDownloadQueue(DownloadQueue* downloadQueue, Servers* servers);
bool SaveFile(FileInfo* fileInfo);
bool LoadFile(FileInfo* fileInfo, bool fileSummary, bool articles);
bool SaveAllFileInfos(DownloadQueue* downloadQueue);
void DiscardQuickFileInfos();
bool SaveFileState(FileInfo* fileInfo, bool completed);
bool LoadFileState(FileInfo* fileInfo, Servers* servers, bool completed);
bool LoadArticles(FileInfo* fileInfo);
@@ -55,7 +57,7 @@ public:
void LoadNzbMessages(int nzbId, MessageList* messages);
private:
bool SaveFileInfo(FileInfo* fileInfo, StateDiskFile& outfile);
bool SaveFileInfo(FileInfo* fileInfo, StateDiskFile& outfile, bool articles);
bool LoadFileInfo(FileInfo* fileInfo, StateDiskFile& outfile, int formatVersion, bool fileSummary, bool articles);
bool SaveFileState(FileInfo* fileInfo, StateDiskFile& outfile, bool completed);
bool LoadFileState(FileInfo* fileInfo, Servers* servers, StateDiskFile& infile, int formatVersion, bool completed);
@@ -76,6 +78,7 @@ private:
bool SaveVolumeStat(ServerVolumes* serverVolumes, StateDiskFile& outfile);
bool LoadVolumeStat(Servers* servers, ServerVolumes* serverVolumes, StateDiskFile& infile, int formatVersion);
void CalcFileStats(DownloadQueue* downloadQueue, int formatVersion);
bool LoadAllFileInfos(DownloadQueue* downloadQueue);
bool LoadAllFileStates(DownloadQueue* downloadQueue, Servers* servers);
void SaveServerStats(ServerStatList* serverStatList, StateDiskFile& outfile);
bool LoadServerStats(ServerStatList* serverStatList, Servers* servers, StateDiskFile& infile);

View File

@@ -40,7 +40,7 @@ void NzbParameterList::SetParameter(const char* name, const char* value)
iterator pos = std::find_if(begin(), end(),
[name](NzbParameter& parameter)
{
return !strcmp(parameter.GetName(), name);
return !strcasecmp(parameter.GetName(), name);
});
if (emptyVal && pos != end())
@@ -57,12 +57,11 @@ void NzbParameterList::SetParameter(const char* name, const char* value)
}
}
NzbParameter* NzbParameterList::Find(const char* name, bool caseSensitive)
NzbParameter* NzbParameterList::Find(const char* name)
{
for (NzbParameter& parameter : this)
{
if ((caseSensitive && !strcmp(parameter.GetName(), name)) ||
(!caseSensitive && !strcasecmp(parameter.GetName(), name)))
if (!strcasecmp(parameter.GetName(), name))
{
return &parameter;
}
@@ -376,13 +375,13 @@ void NzbInfo::AddMessage(Message::EKind kind, const char * text)
m_messages.emplace_back(++m_idMessageGen, kind, Util::CurrentTime(), text);
if (g_Options->GetSaveQueue() && g_Options->GetServerMode() && g_Options->GetNzbLog())
if (g_Options->GetServerMode() && g_Options->GetNzbLog())
{
g_DiskState->AppendNzbMessage(m_id, kind, text);
m_messageCount++;
}
while (m_messages.size() > (uint32)g_Options->GetLogBufferSize())
while (m_messages.size() > (uint32)g_Options->GetLogBuffer())
{
m_messages.pop_front();
}
@@ -474,14 +473,14 @@ void NzbInfo::SetActiveDownloads(int activeDownloads)
}
else
{
m_downloadSec = m_downloadStartSec + (Util::CurrentTime() - m_downloadStartTime);
m_downloadSec = m_downloadStartSec + (int)(Util::CurrentTime() - m_downloadStartTime);
m_downloadStartTime = 0;
m_changed = true;
}
}
else if (activeDownloads > 0)
{
m_downloadSec = m_downloadStartSec + (Util::CurrentTime() - m_downloadStartTime);
m_downloadSec = m_downloadStartSec + (int)(Util::CurrentTime() - m_downloadStartTime);
m_changed = true;
}
m_activeDownloads = activeDownloads;
@@ -652,6 +651,7 @@ void NzbInfo::UpdateCurrentStats()
m_currentFailedSize = m_failedSize;
m_parCurrentSuccessSize = m_parSuccessSize;
m_parCurrentFailedSize = m_parFailedSize;
m_extraPriority = 0;
m_currentServerStats.ListOp(&m_serverStats, ServerStatList::soSet);
@@ -662,6 +662,7 @@ void NzbInfo::UpdateCurrentStats()
m_currentFailedArticles += fileInfo->GetFailedArticles();
m_currentSuccessSize += fileInfo->GetSuccessSize();
m_currentFailedSize += fileInfo->GetFailedSize();
m_extraPriority += fileInfo->GetExtraPriority() ? 1 : 0;
if (fileInfo->GetPaused())
{
@@ -685,6 +686,7 @@ void NzbInfo::UpdateCompletedStats(FileInfo* fileInfo)
m_failedSize += fileInfo->GetFailedSize();
m_failedArticles += fileInfo->GetFailedArticles();
m_successArticles += fileInfo->GetSuccessArticles();
m_extraPriority -= fileInfo->GetExtraPriority() ? 1 : 0;
if (fileInfo->GetParFile())
{
@@ -713,6 +715,7 @@ void NzbInfo::UpdateDeletedStats(FileInfo* fileInfo)
m_currentSuccessArticles -= fileInfo->GetSuccessArticles();
m_currentFailedArticles -= fileInfo->GetFailedArticles() + fileInfo->GetMissedArticles();
m_remainingSize -= fileInfo->GetRemainingSize();
m_extraPriority -= fileInfo->GetExtraPriority() ? 1 : 0;
if (fileInfo->GetParFile())
{
@@ -796,6 +799,15 @@ void FileInfo::SetPaused(bool paused)
m_paused = paused;
}
void FileInfo::SetExtraPriority(bool extraPriority)
{
if (m_extraPriority != extraPriority && m_nzbInfo)
{
m_nzbInfo->SetExtraPriority(m_nzbInfo->GetExtraPriority() + (extraPriority ? 1 : -1));
}
m_extraPriority = extraPriority;
}
void FileInfo::MakeValidFilename()
{
m_filename = FileSystem::MakeValidFilename(m_filename);

View File

@@ -177,7 +177,7 @@ public:
bool GetOutputInitialized() { return m_outputInitialized; }
void SetOutputInitialized(bool outputInitialized) { m_outputInitialized = outputInitialized; }
bool GetExtraPriority() { return m_extraPriority; }
void SetExtraPriority(bool extraPriority) { m_extraPriority = extraPriority; }
void SetExtraPriority(bool extraPriority);
int GetActiveDownloads() { return m_activeDownloads; }
void SetActiveDownloads(int activeDownloads);
bool GetDupeDeleted() { return m_dupeDeleted; }
@@ -196,6 +196,8 @@ public:
void SetHash16k(const char* hash16k) { m_hash16k = hash16k; }
const char* GetParSetId() { return m_parSetId; }
void SetParSetId(const char* parSetId) { m_parSetId = parSetId; }
bool GetFlushLocked() { return m_flushLocked; }
void SetFlushLocked(bool flushLocked) { m_flushLocked = flushLocked; }
ServerStatList* GetServerStats() { return &m_serverStats; }
@@ -235,6 +237,7 @@ private:
uint32 m_crc = 0;
CString m_hash16k;
CString m_parSetId;
bool m_flushLocked = false;
static int m_idGen;
static int m_idMax;
@@ -304,7 +307,7 @@ class NzbParameterList : public NzbParameterListBase
{
public:
void SetParameter(const char* name, const char* value);
NzbParameter* Find(const char* name, bool caseSensitive);
NzbParameter* Find(const char* name);
void CopyFrom(NzbParameterList* sourceParameters);
};
@@ -509,6 +512,9 @@ public:
void SetCurrentFailedArticles(int currentFailedArticles) { m_currentFailedArticles = currentFailedArticles; }
int GetPriority() { return m_priority; }
void SetPriority(int priority) { m_priority = priority; }
int GetExtraPriority() { return m_extraPriority; }
void SetExtraPriority(int extraPriority) { m_extraPriority = extraPriority; }
bool HasExtraPriority() { return m_extraPriority > 0; }
bool GetForcePriority() { return m_priority >= FORCE_PRIORITY; }
time_t GetMinTime() { return m_minTime; }
void SetMinTime(time_t minTime) { m_minTime = minTime; }
@@ -664,6 +670,7 @@ private:
time_t m_minTime = 0;
time_t m_maxTime = 0;
int m_priority = 0;
int m_extraPriority = 0;
CompletedFileList m_completedFiles;
EDirectRenameStatus m_directRenameStatus = tsNone;
EPostRenameStatus m_parRenameStatus = rsNone;

View File

@@ -31,8 +31,8 @@ bool DupeCoordinator::SameNameOrKey(const char* name1, const char* dupeKey1,
const char* name2, const char* dupeKey2)
{
bool hasDupeKeys = !Util::EmptyStr(dupeKey1) && !Util::EmptyStr(dupeKey2);
return (hasDupeKeys && !strcmp(dupeKey1, dupeKey2)) ||
(!hasDupeKeys && !strcmp(name1, name2));
return (hasDupeKeys && !strcasecmp(dupeKey1, dupeKey2)) ||
(!hasDupeKeys && !strcasecmp(name1, name2));
}
/**

View File

@@ -87,7 +87,7 @@ void HistoryCoordinator::ServiceWork()
void HistoryCoordinator::DeleteDiskFiles(NzbInfo* nzbInfo)
{
if (g_Options->GetSaveQueue() && g_Options->GetServerMode())
if (g_Options->GetServerMode())
{
// delete parked files
g_DiskState->DiscardFiles(nzbInfo);

View File

@@ -374,7 +374,7 @@ void NzbFile::ProcessFiles()
CalcHashes();
if (g_Options->GetSaveQueue() && g_Options->GetServerMode())
if (g_Options->GetServerMode())
{
for (FileInfo* fileInfo : m_nzbInfo->GetFileList())
{
@@ -595,6 +595,10 @@ bool NzbFile::ParseNzb(IUnknown* nzb)
bool NzbFile::Parse()
{
#ifdef DISABLE_LIBXML2
error("Could not parse rss feed, program was compiled without libxml2 support");
return false;
#else
xmlSAXHandler SAX_handler = {0};
SAX_handler.startElement = reinterpret_cast<startElementSAXFunc>(SAX_StartElement);
SAX_handler.endElement = reinterpret_cast<endElementSAXFunc>(SAX_EndElement);
@@ -623,6 +627,7 @@ bool NzbFile::Parse()
ProcessFiles();
return true;
#endif
}
void NzbFile::Parse_StartElement(const char *name, const char **atts)
@@ -805,7 +810,11 @@ void NzbFile::SAX_characters(NzbFile* file, const char * xmlstr, int len)
void* NzbFile::SAX_getEntity(NzbFile* file, const char * name)
{
#ifdef DISABLE_LIBXML2
void* e = nullptr;
#else
xmlEntityPtr e = xmlGetPredefinedEntity((xmlChar* )name);
#endif
if (!e)
{
file->m_nzbInfo->AddMessage(Message::mkWarning, "entity not found");

View File

@@ -58,9 +58,10 @@ void QueueCoordinator::CoordinatorDownloadQueue::Save()
return;
}
if (g_Options->GetSaveQueue() && g_Options->GetServerMode())
if (g_Options->GetServerMode())
{
g_DiskState->SaveDownloadQueue(this, m_historyChanged);
m_stateChanged = true;
}
for (NzbInfo* nzbInfo : GetQueue())
@@ -102,11 +103,11 @@ void QueueCoordinator::Load()
bool perfectServerMatch = true;
bool queueLoaded = false;
if (g_Options->GetServerMode() && g_Options->GetSaveQueue())
if (g_Options->GetServerMode())
{
statLoaded = g_StatMeter->Load(&perfectServerMatch);
if (g_Options->GetReloadQueue() && g_DiskState->DownloadQueueExists())
if (g_DiskState->DownloadQueueExists())
{
queueLoaded = g_DiskState->LoadDownloadQueue(downloadQueue, g_ServerPool->GetServers());
}
@@ -133,7 +134,7 @@ void QueueCoordinator::Load()
downloadQueue->Save();
// re-save file states into diskstate to update server ids
if (g_Options->GetServerMode() && g_Options->GetSaveQueue())
if (g_Options->GetServerMode())
{
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
@@ -256,12 +257,14 @@ void QueueCoordinator::Run()
}
resetCounter = 0;
g_StatMeter->IntervalCheck();
g_Log->IntervalCheck();
AdjustDownloadsLimit();
}
}
WaitJobs();
SaveAllPartialState();
SaveAllFileState();
debug("Exiting QueueCoordinator-loop");
}
@@ -331,7 +334,7 @@ NzbInfo* QueueCoordinator::AddNzbFileToQueue(std::unique_ptr<NzbInfo> nzbInfo, N
for (FileInfo* fileInfo: nzbInfo->GetFileList())
{
allPaused &= fileInfo->GetPaused();
if (g_Options->GetSaveQueue() && g_Options->GetServerMode())
if (g_Options->GetServerMode())
{
g_DiskState->DiscardFile(fileInfo->GetId(), true, false, false);
}
@@ -398,11 +401,6 @@ void QueueCoordinator::CheckDupeFileInfos(NzbInfo* nzbInfo)
{
debug("CheckDupeFileInfos");
if (!g_Options->GetDupeCheck() || nzbInfo->GetDupeMode() == dmForce)
{
return;
}
RawFileList dupeList;
int index1 = 0;
@@ -419,9 +417,19 @@ void QueueCoordinator::CheckDupeFileInfos(NzbInfo* nzbInfo)
(fileInfo->GetSize() < fileInfo2->GetSize() ||
(fileInfo->GetSize() == fileInfo2->GetSize() && index2 < index1)))
{
warn("File \"%s\" appears twice in collection, adding only the biggest file", fileInfo->GetFilename());
dupe = true;
break;
// If more than two files have same filename we don't filter them out since that
// naming might be intentional and correct filenames must be read from article bodies.
int dupeCount = std::count_if(nzbInfo->GetFileList()->begin(), nzbInfo->GetFileList()->end(),
[fileInfo2](std::unique_ptr<FileInfo>& fileInfo3)
{
return !strcmp(fileInfo3->GetFilename(), fileInfo2->GetFilename());
});
if (dupeCount == 2)
{
warn("File \"%s\" appears twice in collection, adding only the biggest file", fileInfo->GetFilename());
dupe = true;
break;
}
}
}
if (dupe)
@@ -435,7 +443,7 @@ void QueueCoordinator::CheckDupeFileInfos(NzbInfo* nzbInfo)
{
nzbInfo->UpdateDeletedStats(fileInfo);
nzbInfo->GetFileList()->Remove(fileInfo);
if (g_Options->GetSaveQueue() && g_Options->GetServerMode())
if (g_Options->GetServerMode())
{
g_DiskState->DiscardFile(fileInfo->GetId(), true, false, false);
}
@@ -464,8 +472,7 @@ bool QueueCoordinator::GetNextArticle(DownloadQueue* downloadQueue, FileInfo* &f
// if the file doesn't have any articles left for download, we store that fact and search again,
// ignoring all files which were previously marked as not having any articles.
// special case: if the file has ExtraPriority-flag set, it has the highest priority and the
// Paused-flag is ignored.
// special case: if the file has ExtraPriority-flag set, it has the highest priority.
//debug("QueueCoordinator::GetNextArticle()");
@@ -480,20 +487,34 @@ bool QueueCoordinator::GetNextArticle(DownloadQueue* downloadQueue, FileInfo* &f
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
{
for (FileInfo* fileInfo1 : nzbInfo->GetFileList())
bool nzbHigherPriority = fileInfo &&
((nzbInfo->HasExtraPriority() == fileInfo->GetNzbInfo()->HasExtraPriority() &&
nzbInfo->GetPriority() > fileInfo->GetNzbInfo()->GetPriority()) ||
(nzbInfo->HasExtraPriority() > fileInfo->GetNzbInfo()->HasExtraPriority()));
bool nzbPaused = nzbInfo->GetFileList()->size() - nzbInfo->GetPausedFileCount() <= 0;
if ((!fileInfo || nzbHigherPriority) && !nzbPaused &&
(!(g_Options->GetPauseDownload() || g_Options->GetQuotaReached()) || nzbInfo->GetForcePriority()))
{
if ((checkedFiles.empty() ||
std::find(checkedFiles.begin(), checkedFiles.end(), fileInfo1) == checkedFiles.end()) &&
!fileInfo1->GetPaused() && !fileInfo1->GetDeleted() &&
(g_Options->GetPropagationDelay() == 0 ||
(int)fileInfo1->GetTime() < (int)curDate - g_Options->GetPropagationDelay()) &&
(!(g_Options->GetPauseDownload() || g_Options->GetQuotaReached()) || nzbInfo->GetForcePriority()) &&
(!fileInfo ||
(fileInfo1->GetExtraPriority() == fileInfo->GetExtraPriority() &&
fileInfo1->GetNzbInfo()->GetPriority() > fileInfo->GetNzbInfo()->GetPriority()) ||
(fileInfo1->GetExtraPriority() > fileInfo->GetExtraPriority())))
for (FileInfo* fileInfo1 : nzbInfo->GetFileList())
{
fileInfo = fileInfo1;
bool alreadyChecked = !checkedFiles.empty() &&
std::find(checkedFiles.begin(), checkedFiles.end(), fileInfo1) != checkedFiles.end();
bool propagationWait = g_Options->GetPropagationDelay() > 0 &&
(int)fileInfo1->GetTime() + g_Options->GetPropagationDelay() >= (int)curDate;
bool higherPriority = fileInfo &&
((fileInfo1->GetExtraPriority() == fileInfo->GetExtraPriority() &&
fileInfo1->GetNzbInfo()->GetPriority() > fileInfo->GetNzbInfo()->GetPriority()) ||
(fileInfo1->GetExtraPriority() > fileInfo->GetExtraPriority()));
if (!alreadyChecked && !propagationWait && !fileInfo1->GetPaused() &&
!fileInfo1->GetDeleted() && (!fileInfo || higherPriority))
{
fileInfo = fileInfo1;
}
}
}
}
@@ -512,7 +533,7 @@ bool QueueCoordinator::GetNextArticle(DownloadQueue* downloadQueue, FileInfo* &f
return true;
}
if (fileInfo->GetArticles()->empty() && g_Options->GetSaveQueue() && g_Options->GetServerMode())
if (fileInfo->GetArticles()->empty() && g_Options->GetServerMode())
{
g_DiskState->LoadArticles(fileInfo);
LoadPartialState(fileInfo);
@@ -546,7 +567,7 @@ bool QueueCoordinator::GetNextFirstArticle(NzbInfo* nzbInfo, FileInfo* &fileInfo
{
if (!fileInfo1->GetFilenameConfirmed())
{
if (fileInfo1->GetArticles()->empty() && g_Options->GetSaveQueue() && g_Options->GetServerMode())
if (fileInfo1->GetArticles()->empty() && g_Options->GetServerMode())
{
g_DiskState->LoadArticles(fileInfo1);
LoadPartialState(fileInfo1);
@@ -582,7 +603,7 @@ void QueueCoordinator::StartArticleDownload(FileInfo* fileInfo, ArticleInfo* art
articleDownloader->SetArticleInfo(articleInfo);
articleDownloader->SetConnection(connection);
if (articleInfo->GetPartNumber() == 1 && g_Options->GetDirectRename() && g_Options->GetDecode())
if (articleInfo->GetPartNumber() == 1 && g_Options->GetDirectRename() && !g_Options->GetRawArticle())
{
articleDownloader->SetContentAnalyzer(m_directRenamer.MakeArticleContentAnalyzer());
}
@@ -779,7 +800,7 @@ void QueueCoordinator::DeleteFileInfo(DownloadQueue* downloadQueue, FileInfo* fi
fileInfo->GetSuccessArticles() > 0 || fileInfo->GetFailedArticles() > 0 ? CompletedFile::cfPartial :
CompletedFile::cfNone;
if (g_Options->GetSaveQueue() && g_Options->GetServerMode())
if (g_Options->GetServerMode())
{
g_DiskState->DiscardFile(fileInfo->GetId(), fileStatus == CompletedFile::cfSuccess || (fileDeleted && !parking), true, false);
if (fileStatus == CompletedFile::cfPartial && (completed || parking))
@@ -847,7 +868,7 @@ void QueueCoordinator::DiscardTempFiles(FileInfo* fileInfo)
void QueueCoordinator::SaveAllPartialState()
{
if (!(g_Options->GetServerMode() && g_Options->GetSaveQueue()))
if (!g_Options->GetServerMode())
{
return;
}
@@ -906,6 +927,15 @@ void QueueCoordinator::LoadPartialState(FileInfo* fileInfo)
}
}
void QueueCoordinator::SaveAllFileState()
{
if (g_Options->GetServerMode() && m_downloadQueue.m_stateChanged)
{
GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
g_DiskState->SaveAllFileInfos(downloadQueue);
}
}
void QueueCoordinator::CheckHealth(DownloadQueue* downloadQueue, FileInfo* fileInfo)
{
if (g_Options->GetHealthCheck() == Options::hcNone ||
@@ -962,7 +992,7 @@ void QueueCoordinator::LogDebugInfo()
void QueueCoordinator::ResetHangingDownloads()
{
if (g_Options->GetTerminateTimeout() == 0 && g_Options->GetArticleTimeout() == 0)
if (g_Options->GetArticleTimeout() == 0)
{
return;
}
@@ -970,46 +1000,16 @@ void QueueCoordinator::ResetHangingDownloads()
GuardedDownloadQueue guard = DownloadQueue::Guard();
time_t tm = Util::CurrentTime();
m_activeDownloads.erase(std::remove_if(m_activeDownloads.begin(), m_activeDownloads.end(),
[tm](ArticleDownloader* articleDownloader)
for (ArticleDownloader* articleDownloader : m_activeDownloads)
{
if (tm - articleDownloader->GetLastUpdateTime() > g_Options->GetArticleTimeout() + 1 &&
articleDownloader->GetStatus() == ArticleDownloader::adRunning)
{
if (tm - articleDownloader->GetLastUpdateTime() > g_Options->GetArticleTimeout() + 1 &&
articleDownloader->GetStatus() == ArticleDownloader::adRunning)
{
error("Cancelling hanging download %s @ %s", articleDownloader->GetInfoName(),
articleDownloader->GetConnectionName());
articleDownloader->Stop();
}
if (tm - articleDownloader->GetLastUpdateTime() > g_Options->GetTerminateTimeout() &&
articleDownloader->GetStatus() == ArticleDownloader::adRunning)
{
ArticleInfo* articleInfo = articleDownloader->GetArticleInfo();
debug("Terminating hanging download %s", articleDownloader->GetInfoName());
if (articleDownloader->Terminate())
{
error("Terminated hanging download %s @ %s", articleDownloader->GetInfoName(),
articleDownloader->GetConnectionName());
articleInfo->SetStatus(ArticleInfo::aiUndefined);
}
else
{
error("Could not terminate hanging download %s @ %s", articleDownloader->GetInfoName(),
articleDownloader->GetConnectionName());
}
articleDownloader->GetFileInfo()->SetActiveDownloads(articleDownloader->GetFileInfo()->GetActiveDownloads() - 1);
articleDownloader->GetFileInfo()->GetNzbInfo()->SetActiveDownloads(articleDownloader->GetFileInfo()->GetNzbInfo()->GetActiveDownloads() - 1);
articleDownloader->GetFileInfo()->GetNzbInfo()->SetDownloadedSize(articleDownloader->GetFileInfo()->GetNzbInfo()->GetDownloadedSize() + articleDownloader->GetDownloadedSize());
// it's not safe to destroy pArticleDownloader, because the state of object is unknown
delete articleDownloader;
return true;
}
return false;
}),
m_activeDownloads.end());
error("Cancelling hanging download %s @ %s", articleDownloader->GetInfoName(),
articleDownloader->GetConnectionName());
articleDownloader->Stop();
}
}
}
/*
@@ -1292,7 +1292,7 @@ void QueueCoordinator::DirectRenameCompleted(DownloadQueue* downloadQueue, NzbIn
{
for (FileInfo* fileInfo : nzbInfo->GetFileList())
{
if (g_Options->GetSaveQueue() && g_Options->GetServerMode() && !fileInfo->GetArticles()->empty())
if (g_Options->GetServerMode() && !fileInfo->GetArticles()->empty())
{
// save new file name into disk state file
g_DiskState->SaveFile(fileInfo);
@@ -1328,55 +1328,36 @@ void QueueCoordinator::DiscardDirectRename(DownloadQueue* downloadQueue, NzbInfo
for (FileInfo* fileInfo : nzbInfo->GetFileList())
{
if (fileInfo->GetParFile() && fileInfo->GetCompletedArticles() == 1 && fileInfo->GetActiveDownloads() == 0)
if (fileInfo->GetParFile() && fileInfo->GetCompletedArticles() == 1 &&
fileInfo->GetActiveDownloads() == 0)
{
// discard downloaded articles from partially downloaded par-files
discardedSize += fileInfo->GetSuccessSize();
discardedCount++;
nzbInfo->SetCurrentSuccessArticles(nzbInfo->GetCurrentSuccessArticles() - fileInfo->GetSuccessArticles());
nzbInfo->SetCurrentSuccessSize(nzbInfo->GetCurrentSuccessSize() - fileInfo->GetSuccessSize());
nzbInfo->SetParCurrentSuccessSize(nzbInfo->GetParCurrentSuccessSize() - fileInfo->GetSuccessSize());
fileInfo->SetSuccessSize(0);
fileInfo->SetSuccessArticles(0);
nzbInfo->SetCurrentFailedArticles(nzbInfo->GetCurrentFailedArticles() - fileInfo->GetFailedArticles());
nzbInfo->SetCurrentFailedSize(nzbInfo->GetCurrentFailedSize() - fileInfo->GetFailedSize());
nzbInfo->SetParCurrentFailedSize(nzbInfo->GetParCurrentFailedSize() - fileInfo->GetFailedSize());
fileInfo->SetFailedSize(0);
fileInfo->SetFailedArticles(0);
fileInfo->SetCompletedArticles(0);
fileInfo->SetRemainingSize(fileInfo->GetSize() - fileInfo->GetMissedSize());
// discard temporary files
DiscardTempFiles(fileInfo);
g_DiskState->DiscardFile(fileInfo->GetId(), false, true, false);
fileInfo->SetOutputFilename(nullptr);
fileInfo->SetOutputInitialized(false);
fileInfo->SetCachedArticles(0);
fileInfo->SetPartialChanged(false);
fileInfo->SetPartialState(FileInfo::psNone);
if (g_Options->GetSaveQueue() && g_Options->GetServerMode())
bool locked = false;
{
// free up memory used by articles if possible
fileInfo->GetArticles()->clear();
}
else
{
// reset article states if discarding isn't possible
for (ArticleInfo* articleInfo : fileInfo->GetArticles())
Guard contentGuard = g_ArticleCache->GuardContent();
locked = fileInfo->GetFlushLocked();
if (!locked)
{
articleInfo->SetStatus(ArticleInfo::aiUndefined);
articleInfo->SetResultFilename(nullptr);
articleInfo->DiscardSegment();
fileInfo->SetFlushLocked(true);
}
}
if (!locked)
{
// discard downloaded articles from partially downloaded par-files
discardedSize += fileInfo->GetSuccessSize();
discardedCount++;
DiscardDownloadedArticles(nzbInfo, fileInfo);
}
if (!locked)
{
Guard contentGuard = g_ArticleCache->GuardContent();
fileInfo->SetFlushLocked(false);
}
}
if (g_Options->GetSaveQueue() && g_Options->GetServerMode() &&
if (g_Options->GetServerMode() &&
!fileInfo->GetArticles()->empty() && g_Options->GetContinuePartial() &&
fileInfo->GetActiveDownloads() == 0 && fileInfo->GetCachedArticles() == 0)
{
@@ -1394,3 +1375,55 @@ void QueueCoordinator::DiscardDirectRename(DownloadQueue* downloadQueue, NzbInfo
*Util::FormatSize(discardedSize), discardedCount);
}
}
void QueueCoordinator::DiscardDownloadedArticles(NzbInfo* nzbInfo, FileInfo* fileInfo)
{
nzbInfo->SetRemainingSize(nzbInfo->GetRemainingSize() + fileInfo->GetSuccessSize() + fileInfo->GetFailedSize());
if (fileInfo->GetPaused())
{
nzbInfo->SetPausedSize(nzbInfo->GetPausedSize() + fileInfo->GetSuccessSize() + fileInfo->GetFailedSize());
}
nzbInfo->GetCurrentServerStats()->ListOp(fileInfo->GetServerStats(), ServerStatList::soSubtract);
fileInfo->GetServerStats()->clear();
nzbInfo->SetCurrentSuccessArticles(nzbInfo->GetCurrentSuccessArticles() - fileInfo->GetSuccessArticles());
nzbInfo->SetCurrentSuccessSize(nzbInfo->GetCurrentSuccessSize() - fileInfo->GetSuccessSize());
nzbInfo->SetParCurrentSuccessSize(nzbInfo->GetParCurrentSuccessSize() - fileInfo->GetSuccessSize());
fileInfo->SetSuccessSize(0);
fileInfo->SetSuccessArticles(0);
nzbInfo->SetCurrentFailedArticles(nzbInfo->GetCurrentFailedArticles() - fileInfo->GetFailedArticles());
nzbInfo->SetCurrentFailedSize(nzbInfo->GetCurrentFailedSize() - fileInfo->GetFailedSize());
nzbInfo->SetParCurrentFailedSize(nzbInfo->GetParCurrentFailedSize() - fileInfo->GetFailedSize());
fileInfo->SetFailedSize(0);
fileInfo->SetFailedArticles(0);
fileInfo->SetCompletedArticles(0);
fileInfo->SetRemainingSize(fileInfo->GetSize() - fileInfo->GetMissedSize());
// discard temporary files
DiscardTempFiles(fileInfo);
g_DiskState->DiscardFile(fileInfo->GetId(), false, true, false);
fileInfo->SetOutputFilename(nullptr);
fileInfo->SetOutputInitialized(false);
fileInfo->SetCachedArticles(0);
fileInfo->SetPartialChanged(false);
fileInfo->SetPartialState(FileInfo::psNone);
if (g_Options->GetServerMode())
{
// free up memory used by articles if possible
fileInfo->GetArticles()->clear();
}
else
{
// reset article states if discarding isn't possible
for (ArticleInfo* articleInfo : fileInfo->GetArticles())
{
articleInfo->SetStatus(ArticleInfo::aiUndefined);
articleInfo->SetResultFilename(nullptr);
articleInfo->DiscardSegment();
}
}
}

View File

@@ -72,6 +72,7 @@ private:
bool m_massEdit = false;
bool m_wantSave = false;
bool m_historyChanged = false;
bool m_stateChanged = false;
friend class QueueCoordinator;
};
@@ -102,6 +103,7 @@ private:
void DeleteFileInfo(DownloadQueue* downloadQueue, FileInfo* fileInfo, bool completed);
void DirectRenameCompleted(DownloadQueue* downloadQueue, NzbInfo* nzbInfo);
void DiscardDirectRename(DownloadQueue* downloadQueue, NzbInfo* nzbInfo);
void DiscardDownloadedArticles(NzbInfo* nzbInfo, FileInfo* fileInfo);
void CheckHealth(DownloadQueue* downloadQueue, FileInfo* fileInfo);
void ResetHangingDownloads();
void AdjustDownloadsLimit();
@@ -109,6 +111,7 @@ private:
void SaveAllPartialState();
void SavePartialState(FileInfo* fileInfo);
void LoadPartialState(FileInfo* fileInfo);
void SaveAllFileState();
void WaitJobs();
};

View File

@@ -650,7 +650,7 @@ void QueueEditor::PrepareList(ItemList* itemList, IdList* idList,
bool QueueEditor::BuildIdListFromNameList(IdList* idList, NameList* nameList, DownloadQueue::EMatchMode matchMode, DownloadQueue::EEditAction action)
{
#ifndef HAVE_REGEX_H
if (matchMode == mmRegEx)
if (matchMode == DownloadQueue::mmRegEx)
{
return false;
}
@@ -840,10 +840,7 @@ void QueueEditor::PausePars(RawFileList* fileList, bool extraParsOnly)
for (FileInfo* fileInfo : fileList)
{
BString<1024> loFileName = fileInfo->GetFilename();
for (char* p = loFileName; *p; p++) *p = tolower(*p); // convert string to lowercase
if (strstr(loFileName, ".par2"))
if (fileInfo->GetParFile())
{
if (!extraParsOnly)
{
@@ -851,6 +848,8 @@ void QueueEditor::PausePars(RawFileList* fileList, bool extraParsOnly)
}
else
{
BString<1024> loFileName = fileInfo->GetFilename();
for (char* p = loFileName; *p; p++) *p = tolower(*p); // convert string to lowercase
if (strstr(loFileName, ".vol"))
{
Vols.push_back(fileInfo);

View File

@@ -371,7 +371,10 @@ void Scanner::InitPPParameters(const char* category, NzbParameterList* parameter
}
}
parameters->SetParameter("*Unpack:", unpack ? "yes" : "no");
if (!parameters->Find("*Unpack:"))
{
parameters->SetParameter("*Unpack:", unpack ? "yes" : "no");
}
if (!Util::EmptyStr(extensions))
{
@@ -381,10 +384,12 @@ void Scanner::InitPPParameters(const char* category, NzbParameterList* parameter
{
for (ScriptConfig::Script& script : g_ScriptConfig->GetScripts())
{
BString<1024> paramName("%s:", scriptName);
if ((script.GetPostScript() || script.GetQueueScript()) &&
!parameters->Find(paramName) &&
FileSystem::SameFilename(scriptName, script.GetName()))
{
parameters->SetParameter(BString<1024>("%s:", scriptName), "yes");
parameters->SetParameter(paramName, "yes");
}
}
}

View File

@@ -158,8 +158,7 @@ void UrlCoordinator::Stop()
void UrlCoordinator::ResetHangingDownloads()
{
const int timeout = g_Options->GetTerminateTimeout();
if (timeout == 0)
if (g_Options->GetUrlTimeout() == 0)
{
return;
}
@@ -167,32 +166,15 @@ void UrlCoordinator::ResetHangingDownloads()
GuardedDownloadQueue guard = DownloadQueue::Guard();
time_t tm = Util::CurrentTime();
m_activeDownloads.erase(std::remove_if(m_activeDownloads.begin(), m_activeDownloads.end(),
[timeout, tm](UrlDownloader* urlDownloader)
for (UrlDownloader* urlDownloader: m_activeDownloads)
{
if (tm - urlDownloader->GetLastUpdateTime() > g_Options->GetUrlTimeout() + 10 &&
urlDownloader->GetStatus() == UrlDownloader::adRunning)
{
if (tm - urlDownloader->GetLastUpdateTime() > timeout &&
urlDownloader->GetStatus() == UrlDownloader::adRunning)
{
NzbInfo* nzbInfo = urlDownloader->GetNzbInfo();
debug("Terminating hanging download %s", urlDownloader->GetInfoName());
if (urlDownloader->Terminate())
{
error("Terminated hanging download %s", urlDownloader->GetInfoName());
nzbInfo->SetUrlStatus(NzbInfo::lsNone);
}
else
{
error("Could not terminate hanging download %s", urlDownloader->GetInfoName());
}
// it's not safe to destroy urlDownloader, because the state of object is unknown
delete urlDownloader;
return true;
}
return false;
}),
m_activeDownloads.end());
error("Cancelling hanging url download %s", urlDownloader->GetInfoName());
urlDownloader->Stop();
}
}
}
void UrlCoordinator::LogDebugInfo()

View File

@@ -871,7 +871,7 @@ void EditQueueBinCommand::Execute()
else
{
#ifndef HAVE_REGEX_H
if ((QueueEditor::EMatchMode)matchMode == QueueEditor::mmRegEx)
if ((DownloadQueue::EMatchMode)matchMode == DownloadQueue::mmRegEx)
{
SendBoolResponse(false, "Edit-Command failed: the program was compiled without RegEx-support");
return;

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@sourceforge.net>
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ void RemoteServer::Run()
m_connection = std::make_unique<Connection>(g_Options->GetControlIp(),
m_tls ? g_Options->GetSecurePort() : g_Options->GetControlPort(),
m_tls);
m_connection->SetTimeout(g_Options->GetUrlTimeout());
m_connection->SetTimeout(g_Options->GetRemoteTimeout());
m_connection->SetSuppressErrors(false);
bind = m_connection->Bind();
}
@@ -83,13 +83,19 @@ void RemoteServer::Run()
continue;
}
RequestProcessor* commandThread = new RequestProcessor();
commandThread->SetAutoDestroy(true);
commandThread->SetConnection(std::move(acceptedConnection));
if (!IsStopped())
{
RequestProcessor* commandThread = new RequestProcessor();
commandThread->SetAutoDestroy(true);
commandThread->SetConnection(std::move(acceptedConnection));
#ifndef DISABLE_TLS
commandThread->SetTls(m_tls);
commandThread->SetTls(m_tls);
#endif
commandThread->Start();
Guard guard(m_processorsMutex);
m_activeProcessors.push_back(commandThread);
commandThread->Attach(this);
commandThread->Start();
}
}
if (m_connection)
@@ -97,6 +103,19 @@ void RemoteServer::Run()
m_connection->Disconnect();
}
// waiting for request processors
debug("RemoteServer: waiting for request processor to complete");
bool completed = false;
while (!completed)
{
{
Guard guard(m_processorsMutex);
completed = m_activeProcessors.size() == 0;
}
usleep(100 * 1000);
}
debug("RemoteServer: request processor are completed");
debug("Exiting RemoteServer-loop");
}
@@ -106,11 +125,39 @@ void RemoteServer::Stop()
if (m_connection)
{
m_connection->SetSuppressErrors(true);
m_connection->SetForceClose(true);
m_connection->Cancel();
#ifdef WIN32
m_connection->Disconnect();
#endif
debug("Stopping RequestProcessors");
Guard guard(m_processorsMutex);
for (RequestProcessor* requestProcessor : m_activeProcessors)
{
requestProcessor->Stop();
}
debug("RequestProcessors are notified");
}
debug("RemoteServer stop end");
}
void RemoteServer::ForceStop()
{
debug("Killing RequestProcessors");
Guard guard(m_processorsMutex);
for (RequestProcessor* requestProcessor : m_activeProcessors)
{
requestProcessor->Kill();
}
m_activeProcessors.clear();
debug("RequestProcessors are killed");
}
void RemoteServer::Update(Subject* caller, void* aspect)
{
debug("Notification from RequestProcessor received");
RequestProcessor* requestProcessor = (RequestProcessor*)caller;
Guard guard(m_processorsMutex);
m_activeProcessors.erase(std::find(m_activeProcessors.begin(), m_activeProcessors.end(), requestProcessor));
}
//*****************************************************************
@@ -123,8 +170,22 @@ RequestProcessor::~RequestProcessor()
void RequestProcessor::Run()
{
bool ok = false;
Execute();
Notify(nullptr);
}
void RequestProcessor::Stop()
{
Thread::Stop();
#ifdef WIN32
m_connection->SetForceClose(true);
#endif
m_connection->Cancel();
}
void RequestProcessor::Execute()
{
bool ok = false;
m_connection->SetSuppressErrors(true);
#ifndef DISABLE_TLS
@@ -136,7 +197,7 @@ void RequestProcessor::Run()
#endif
// Read the first 4 bytes to determine request type
int signature = 0;
uint32 signature = 0;
if (!m_connection->Recv((char*)&signature, 4))
{
debug("Could not read request signature");
@@ -156,39 +217,18 @@ void RequestProcessor::Run()
!strncmp((char*)&signature, "OPTI", 4))
{
// HTTP request received
char buffer[1024];
if (m_connection->ReadLine(buffer, sizeof(buffer), nullptr))
ok = true;
while (ServWebRequest((char*)&signature))
{
WebProcessor::EHttpMethod httpMethod = WebProcessor::hmGet;
char* url = buffer;
if (!strncmp((char*)&signature, "POST", 4))
if (!m_connection->Recv((char*)&signature, 4))
{
httpMethod = WebProcessor::hmPost;
url++;
debug("Could not read request signature");
break;
}
if (!strncmp((char*)&signature, "OPTI", 4) && strlen(url) > 4)
{
httpMethod = WebProcessor::hmOptions;
url += 4;
}
if (char* p = strchr(url, ' '))
{
*p = '\0';
}
debug("url: %s", url);
WebProcessor processor;
processor.SetConnection(m_connection.get());
processor.SetUrl(url);
processor.SetHttpMethod(httpMethod);
processor.Execute();
m_connection->SetGracefull(true);
m_connection->Disconnect();
ok = true;
}
m_connection->SetGracefull(true);
m_connection->Disconnect();
}
if (!ok)
@@ -196,3 +236,45 @@ void RequestProcessor::Run()
warn("Non-nzbget request received on port %i from %s", m_tls ? g_Options->GetSecurePort() : g_Options->GetControlPort(), m_connection->GetRemoteAddr());
}
}
bool RequestProcessor::ServWebRequest(const char* signature)
{
// HTTP request received
char buffer[1024];
if (!m_connection->ReadLine(buffer, sizeof(buffer), nullptr))
{
return false;
}
WebProcessor::EHttpMethod httpMethod = WebProcessor::hmGet;
char* url = buffer;
if (!strncmp(signature, "POST", 4))
{
httpMethod = WebProcessor::hmPost;
url++;
}
else if (!strncmp(signature, "OPTI", 4) && strlen(url) > 4)
{
httpMethod = WebProcessor::hmOptions;
url += 4;
}
else if (!(!strncmp(signature, "GET ", 4)))
{
return false;
}
if (char* p = strchr(url, ' '))
{
*p = '\0';
}
debug("url: %s", url);
WebProcessor processor;
processor.SetConnection(m_connection.get());
processor.SetUrl(url);
processor.SetHttpMethod(httpMethod);
processor.Execute();
return processor.GetKeepAlive();
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2005 Bo Cordes Petersen <placebodk@users.sourceforge.net>
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,30 +24,43 @@
#include "Thread.h"
#include "Connection.h"
#include "Observer.h"
class RemoteServer : public Thread
class RequestProcessor;
class RemoteServer : public Thread, public Observer
{
public:
RemoteServer(bool tls) : m_tls(tls) {}
virtual void Run();
virtual void Stop();
void ForceStop();
void Update(Subject* caller, void* aspect);
private:
typedef std::deque<RequestProcessor*> RequestProcessors;
bool m_tls;
std::unique_ptr<Connection> m_connection;
RequestProcessors m_activeProcessors;
Mutex m_processorsMutex;
};
class RequestProcessor : public Thread
class RequestProcessor : public Thread, public Subject
{
public:
~RequestProcessor();
virtual void Run();
virtual void Stop();
void SetTls(bool tls) { m_tls = tls; }
void SetConnection(std::unique_ptr<Connection>&& connection) { m_connection = std::move(connection); }
private:
bool m_tls;
std::unique_ptr<Connection> m_connection;
bool ServWebRequest(const char* signature);
void Execute();
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2012-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2012-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,13 @@
#include "Util.h"
#include "FileSystem.h"
#ifndef DISABLE_PARCHECK
#include "par2cmdline.h"
#include "md5.h"
#endif
static const char* ERR_HTTP_OK = "200 OK";
static const char* ERR_HTTP_NOT_MODIFIED = "304 Not Modified";
static const char* ERR_HTTP_BAD_REQUEST = "400 Bad Request";
static const char* ERR_HTTP_NOT_FOUND = "404 Not Found";
static const char* ERR_HTTP_SERVICE_UNAVAILABLE = "503 Service Unavailable";
@@ -174,6 +181,14 @@ void WebProcessor::ParseHeaders()
{
m_forwardedFor = p + 17;
}
else if (!strncasecmp(p, "If-None-Match: ", 15))
{
m_oldETag = p + 15;
}
else if (!strncasecmp(p, "Connection: keep-alive", 22))
{
m_keepAlive = true;
}
else if (*p == '\0')
{
break;
@@ -268,10 +283,10 @@ bool WebProcessor::CheckCredentials()
}
else
{
warn("Request received on port %i from %s%s, but username or password invalid (%s:%s)",
warn("Request received on port %i from %s%s, but username (%s) or password invalid",
g_Options->GetControlPort(), m_connection->GetRemoteAddr(),
!m_forwardedFor.Empty() ? (char*)BString<1024>(" (forwarded for: %s)", *m_forwardedFor) : "",
m_authInfo, pw);
m_authInfo);
return false;
}
}
@@ -314,7 +329,7 @@ void WebProcessor::Dispatch()
processor.SetUserAccess((XmlRpcProcessor::EUserAccess)m_userAccess);
processor.SetUrl(m_url);
processor.Execute();
SendBodyResponse(processor.GetResponse(), strlen(processor.GetResponse()), processor.GetContentType());
SendBodyResponse(processor.GetResponse(), strlen(processor.GetResponse()), processor.GetContentType(), processor.IsSafeMethod());
return;
}
@@ -330,43 +345,42 @@ void WebProcessor::Dispatch()
return;
}
// for security reasons we allow only characters "0..9 A..Z a..z . - _ /" in the URLs
// for security reasons we allow only characters "0..9 A..Z a..z . - + _ / ?" in the URLs
// we also don't allow ".." in the URLs
for (char *p = m_url; *p; p++)
{
if (!((*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
*p == '.' || *p == '-' || *p == '_' || *p == '/') || (*p == '.' && p[1] == '.'))
*p == '.' || *p == '-' || *p == '+' || *p == '?' || *p == '_' || *p == '/') || (*p == '.' && p[1] == '.'))
{
SendErrorResponse(ERR_HTTP_NOT_FOUND, true);
return;
}
}
const char *defRes = "";
if (m_url[strlen(m_url)-1] == '/')
if (!strncmp(m_url, "/combined.", 10) && strchr(m_url, '?'))
{
// default file in directory (if not specified) is "index.html"
defRes = "index.html";
SendMultiFileResponse();
}
else
{
SendSingleFileResponse();
}
BString<1024> disk_filename("%s%s%s", g_Options->GetWebDir(), *m_url, defRes);
SendFileResponse(disk_filename);
}
void WebProcessor::SendAuthResponse()
{
const char* AUTH_RESPONSE_HEADER =
"HTTP/1.0 401 Unauthorized\r\n"
"HTTP/1.1 401 Unauthorized\r\n"
"%s"
"Connection: close\r\n"
"Connection: %s\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 0\r\n"
"Server: nzbget-%s\r\n"
"\r\n";
BString<1024> responseHeader(AUTH_RESPONSE_HEADER,
g_Options->GetFormAuth() ? "" : "WWW-Authenticate: Basic realm=\"NZBGet\"\r\n",
Util::VersionRevision());
m_keepAlive ? "keep-alive" : "close", Util::VersionRevision());
// Send the response answer
debug("ResponseHeader=%s", *responseHeader);
@@ -377,8 +391,9 @@ void WebProcessor::SendOptionsResponse()
{
const char* OPTIONS_RESPONSE_HEADER =
"HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
"Connection: %s\r\n"
//"Content-Type: plain/text\r\n"
"Content-Length: 0\r\n"
"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
"Access-Control-Allow-Origin: %s\r\n"
"Access-Control-Allow-Credentials: true\r\n"
@@ -387,6 +402,7 @@ void WebProcessor::SendOptionsResponse()
"Server: nzbget-%s\r\n"
"\r\n";
BString<1024> responseHeader(OPTIONS_RESPONSE_HEADER,
m_keepAlive ? "keep-alive" : "close",
m_origin.Str(), Util::VersionRevision());
// Send the response answer
@@ -397,8 +413,8 @@ void WebProcessor::SendOptionsResponse()
void WebProcessor::SendErrorResponse(const char* errCode, bool printWarning)
{
const char* RESPONSE_HEADER =
"HTTP/1.0 %s\r\n"
"Connection: close\r\n"
"HTTP/1.1 %s\r\n"
"Connection: %s\r\n"
"Content-Length: %i\r\n"
"Content-Type: text/html\r\n"
"Server: nzbget-%s\r\n"
@@ -413,7 +429,9 @@ void WebProcessor::SendErrorResponse(const char* errCode, bool printWarning)
errCode, errCode);
int pageContentLen = responseBody.Length();
BString<1024> responseHeader(RESPONSE_HEADER, errCode, pageContentLen, Util::VersionRevision());
BString<1024> responseHeader(RESPONSE_HEADER, errCode,
m_keepAlive ? "keep-alive" : "close",
pageContentLen, Util::VersionRevision());
// Send the response answer
m_connection->Send(responseHeader, responseHeader.Length());
@@ -423,36 +441,66 @@ void WebProcessor::SendErrorResponse(const char* errCode, bool printWarning)
void WebProcessor::SendRedirectResponse(const char* url)
{
const char* REDIRECT_RESPONSE_HEADER =
"HTTP/1.0 301 Moved Permanently\r\n"
"HTTP/1.1 301 Moved Permanently\r\n"
"Location: %s\r\n"
"Connection: close\r\n"
"Connection: %s\r\n"
"Content-Length: 0\r\n"
"Server: nzbget-%s\r\n"
"\r\n";
BString<1024> responseHeader(REDIRECT_RESPONSE_HEADER, url, Util::VersionRevision());
BString<1024> responseHeader(REDIRECT_RESPONSE_HEADER, url,
m_keepAlive ? "keep-alive" : "close", Util::VersionRevision());
// Send the response answer
debug("ResponseHeader=%s", *responseHeader);
m_connection->Send(responseHeader, responseHeader.Length());
}
void WebProcessor::SendBodyResponse(const char* body, int bodyLen, const char* contentType)
void WebProcessor::SendBodyResponse(const char* body, int bodyLen, const char* contentType, bool cachable)
{
const char* RESPONSE_HEADER =
"HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
"HTTP/1.1 %s\r\n"
"Connection: %s\r\n"
"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
"Access-Control-Allow-Origin: %s\r\n"
"Access-Control-Allow-Credentials: true\r\n"
"Access-Control-Max-Age: 86400\r\n"
"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
"Set-Cookie: Auth-Type=%s\r\n"
"Set-Cookie: Auth-Token=%s\r\n"
"Set-Cookie: Auth-Token=%s; HttpOnly\r\n"
"Content-Length: %i\r\n"
"%s" // Content-Type: xxx
"%s" // Content-Encoding: gzip
"%s" // ETag
"Server: nzbget-%s\r\n"
"\r\n";
BString<1024> eTagHeader;
bool unchanged = false;
if (cachable)
{
BString<1024> newETag;
#ifndef DISABLE_PARCHECK
Par2::MD5Hash hash;
Par2::MD5Context md5;
md5.Update(body, bodyLen);
md5.Final(hash);
newETag.Format("\"%s\"", hash.print().c_str());
#else
uint32 hash = Util::HashBJ96(body, bodyLen, 0);
newETag.Format("\"%x\"", hash);
#endif
unchanged = m_oldETag && !strcmp(newETag, m_oldETag);
if (unchanged)
{
body = "";
bodyLen = 0;
}
eTagHeader.Format("ETag: %s\r\n", *newETag);
}
#ifndef DISABLE_GZIP
CharBuffer gbuf;
bool gzip = m_gzip && bodyLen > MAX_UNCOMPRESSED_SIZE;
@@ -482,24 +530,39 @@ void WebProcessor::SendBodyResponse(const char* body, int bodyLen, const char* c
}
BString<1024> responseHeader(RESPONSE_HEADER,
unchanged ? ERR_HTTP_NOT_MODIFIED : ERR_HTTP_OK,
m_keepAlive ? "keep-alive" : "close",
m_origin.Str(),
g_Options->GetFormAuth() ? "form" : "http",
m_authorized ? m_serverAuthToken[m_userAccess] : "",
bodyLen, *contentTypeHeader,
bodyLen,
*contentTypeHeader,
gzip ? "Content-Encoding: gzip\r\n" : "",
cachable ? *eTagHeader : "",
Util::VersionRevision());
debug("[%s] (%s) %s", *m_url, *m_oldETag, *responseHeader);
// Send the request answer
m_connection->Send(responseHeader, responseHeader.Length());
m_connection->Send(body, bodyLen);
}
void WebProcessor::SendFileResponse(const char* filename)
void WebProcessor::SendSingleFileResponse()
{
debug("serving file: %s", filename);
const char *defRes = "";
if (m_url[strlen(m_url)-1] == '/')
{
// default file in directory (if not specified) is "index.html"
defRes = "index.html";
}
BString<1024> filename("%s%s%s", g_Options->GetWebDir(), *m_url, defRes);
debug("serving file: %s", *filename);
CharBuffer body;
if (!FileSystem::LoadFileIntoBuffer(filename, body, false))
if (!FileSystem::LoadFileIntoBuffer(filename, body, true))
{
// do not print warnings "404 not found" for certain files
bool ignorable = !strcmp(filename, "package-info.json") ||
@@ -510,7 +573,48 @@ void WebProcessor::SendFileResponse(const char* filename)
return;
}
SendBodyResponse(body, body.Size(), DetectContentType(filename));
const char* contentType = DetectContentType(filename);
int len = body.Size() - 1;
#ifdef DEBUG
if (contentType && !strcmp(contentType, "text/html"))
{
Util::ReduceStr(body, "<!-- %if-debug%", "");
Util::ReduceStr(body, "<!-- %if-not-debug% -->", "<!--");
Util::ReduceStr(body, "<!-- %end% -->", "-->");
Util::ReduceStr(body, "%end% -->", "");
len = strlen(body);
}
#endif
SendBodyResponse(body, len, contentType, true);
}
void WebProcessor::SendMultiFileResponse()
{
debug("serving multiple files: %s", *m_url);
StringBuilder response;
char* filelist = strchr(m_url, '?');
*filelist++ = '\0';
Tokenizer tok(filelist, "+");
while (const char* filename = tok.Next())
{
BString<1024> diskFilename("%s%c%s", g_Options->GetWebDir(), PATH_SEPARATOR, filename);
CharBuffer body;
if (!FileSystem::LoadFileIntoBuffer(diskFilename, body, true))
{
warn("Web-Server: %s, Resource: /%s", ERR_HTTP_NOT_FOUND, filename);
SendErrorResponse(ERR_HTTP_NOT_FOUND, false);
return;
}
response.Append(body);
}
SendBodyResponse(response, response.Length(), DetectContentType(m_url), true);
}
const char* WebProcessor::DetectContentType(const char* filename)

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2012-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2012-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,6 +39,7 @@ public:
void SetConnection(Connection* connection) { m_connection = connection; }
void SetUrl(const char* url) { m_url = url; }
void SetHttpMethod(EHttpMethod httpMethod) { m_httpMethod = httpMethod; }
bool GetKeepAlive() { return m_keepAlive; }
private:
enum EUserAccess
@@ -62,13 +63,16 @@ private:
char m_authToken[48+1];
static char m_serverAuthToken[3][48+1];
CString m_forwardedFor;
CString m_oldETag;
bool m_keepAlive = false;
void Dispatch();
void SendAuthResponse();
void SendOptionsResponse();
void SendErrorResponse(const char* errCode, bool printWarning);
void SendFileResponse(const char* filename);
void SendBodyResponse(const char* body, int bodyLen, const char* contentType);
void SendSingleFileResponse();
void SendMultiFileResponse();
void SendBodyResponse(const char* body, int bodyLen, const char* contentType, bool cachable);
void SendRedirectResponse(const char* url);
const char* DetectContentType(const char* filename);
bool IsAuthorizedIp(const char* remoteAddr);

View File

@@ -38,12 +38,19 @@
extern void ExitProc();
extern void Reload();
class SafeXmlCommand: public XmlCommand
{
public:
virtual bool IsSafeMethod() { return true; };
};
class ErrorXmlCommand: public XmlCommand
{
public:
ErrorXmlCommand(int errCode, const char* errText) :
m_errCode(errCode), m_errText(errText) {}
virtual void Execute();
virtual bool IsError() { return true; };
private:
int m_errCode;
@@ -87,13 +94,13 @@ public:
virtual void Execute();
};
class VersionXmlCommand: public XmlCommand
class VersionXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
};
class DumpDebugXmlCommand: public XmlCommand
class DumpDebugXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
@@ -105,13 +112,13 @@ public:
virtual void Execute();
};
class StatusXmlCommand: public XmlCommand
class StatusXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
};
class LogXmlCommand: public XmlCommand
class LogXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
@@ -122,14 +129,14 @@ protected:
virtual GuardedMessageList GuardMessages();
};
class NzbInfoXmlCommand: public XmlCommand
class NzbInfoXmlCommand: public SafeXmlCommand
{
protected:
void AppendNzbInfoFields(NzbInfo* nzbInfo);
void AppendPostInfoFields(PostInfo* postInfo, int logEntries, bool postQueue);
};
class ListFilesXmlCommand: public XmlCommand
class ListFilesXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
@@ -187,19 +194,19 @@ private:
const char* DetectStatus(HistoryInfo* historyInfo);
};
class UrlQueueXmlCommand: public XmlCommand
class UrlQueueXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
};
class ConfigXmlCommand: public XmlCommand
class ConfigXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
};
class LoadConfigXmlCommand: public XmlCommand
class LoadConfigXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
@@ -211,7 +218,7 @@ public:
virtual void Execute();
};
class ConfigTemplatesXmlCommand: public XmlCommand
class ConfigTemplatesXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
@@ -238,7 +245,7 @@ public:
virtual void Execute();
};
class ReadUrlXmlCommand: public XmlCommand
class ReadUrlXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
@@ -262,7 +269,7 @@ protected:
virtual GuardedMessageList GuardMessages();
};
class ServerVolumesXmlCommand: public XmlCommand
class ServerVolumesXmlCommand: public SafeXmlCommand
{
public:
virtual void Execute();
@@ -420,8 +427,17 @@ void XmlRpcProcessor::Dispatch()
command->SetHttpMethod(m_httpMethod);
command->SetUserAccess(m_userAccess);
command->PrepareParams();
command->Execute();
BuildResponse(command->GetResponse(), command->GetCallbackFunc(), command->GetFault(), requestId);
m_safeMethod = command->IsSafeMethod();
bool safeToExecute = m_safeMethod || m_httpMethod == XmlRpcProcessor::hmPost || m_protocol == XmlRpcProcessor::rpJsonPRpc;
if (safeToExecute || command->IsError())
{
command->Execute();
BuildResponse(command->GetResponse(), command->GetCallbackFunc(), command->GetFault(), requestId);
}
else
{
BuildErrorResponse(4, "Not safe procedure for HTTP-Method GET. Use Method POST instead");
}
}
}
@@ -452,6 +468,7 @@ void XmlRpcProcessor::MutliCall()
std::unique_ptr<XmlCommand> command = CreateCommand(methodName);
command->SetRequest(requestPtr);
m_safeMethod |= command->IsSafeMethod();
command->Execute();
debug("MutliCall, Response=%s", command->GetResponse());
@@ -476,12 +493,7 @@ void XmlRpcProcessor::MutliCall()
if (error)
{
ErrorXmlCommand command(4, "Parse error");
command.SetRequest(m_request);
command.SetProtocol(rpXmlRpc);
command.PrepareParams();
command.Execute();
BuildResponse(command.GetResponse(), "", command.GetFault(), nullptr);
BuildErrorResponse(4, "Parse error");
}
else
{
@@ -544,6 +556,16 @@ void XmlRpcProcessor::BuildResponse(const char* response, const char* callbackFu
m_contentType = xmlRpc ? "text/xml" : "application/json";
}
void XmlRpcProcessor::BuildErrorResponse(int errCode, const char* errText)
{
ErrorXmlCommand command(errCode, errText);
command.SetRequest(m_request);
command.SetProtocol(m_protocol);
command.PrepareParams();
command.Execute();
BuildResponse(command.GetResponse(), "", command.GetFault(), nullptr);
}
std::unique_ptr<XmlCommand> XmlRpcProcessor::CreateCommand(const char* methodName)
{
std::unique_ptr<XmlCommand> command;
@@ -1067,16 +1089,6 @@ void XmlCommand::DecodeStr(char* str)
}
}
bool XmlCommand::CheckSafeMethod()
{
bool safe = m_httpMethod == XmlRpcProcessor::hmPost || m_protocol == XmlRpcProcessor::rpJsonPRpc;
if (!safe)
{
BuildErrorResponse(4, "Not safe procedure for HTTP-Method GET. Use Method POST instead");
}
return safe;
}
//*****************************************************************
// Commands
@@ -1087,11 +1099,6 @@ void ErrorXmlCommand::Execute()
void PauseUnpauseXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
bool ok = true;
g_Options->SetResumeTime(0);
@@ -1120,11 +1127,6 @@ void PauseUnpauseXmlCommand::Execute()
// bool scheduleresume(int Seconds)
void ScheduleResumeXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
int seconds = 0;
if (!NextParamAsInt(&seconds) || seconds < 0)
{
@@ -1141,22 +1143,12 @@ void ScheduleResumeXmlCommand::Execute()
void ShutdownXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
BuildBoolResponse(true);
ExitProc();
}
void ReloadXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
BuildBoolResponse(true);
Reload();
}
@@ -1179,11 +1171,6 @@ void DumpDebugXmlCommand::Execute()
void SetDownloadRateXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
int rate = 0;
if (!NextParamAsInt(&rate) || rate < 0)
{
@@ -1365,8 +1352,8 @@ void StatusXmlCommand::Execute()
Util::SplitInt64(freeDiskSpace, &freeDiskSpaceHi, &freeDiskSpaceLo);
int freeDiskSpaceMB = (int)(freeDiskSpace / 1024 / 1024);
int serverTime = Util::CurrentTime();
int resumeTime = g_Options->GetResumeTime();
int serverTime = (int)Util::CurrentTime();
int resumeTime = (int)g_Options->GetResumeTime();
bool feedActive = g_FeedCoordinator->HasActiveDownloads();
int queuedScripts = g_QueueScriptCoordinator->GetQueueSize();
@@ -2091,11 +2078,6 @@ EditCommandEntry EditCommandNameMap[] = {
// bool editqueue(string Command, int Offset, string Args, int[] IDs)
void EditQueueXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
char* editCommand;
if (!NextParamAsStr(&editCommand))
{
@@ -2161,11 +2143,6 @@ void EditQueueXmlCommand::Execute()
// bool append(string NZBFilename, string Category, int Priority, bool AddToTop, string Content, bool AddPaused, string DupeKey, int DupeScore, string DupeMode)
void DownloadXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
bool v13 = true;
char* nzbFilename;
@@ -2378,11 +2355,6 @@ void PostQueueXmlCommand::Execute()
void WriteLogXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
char* kind;
char* text;
if (!NextParamAsStr(&kind) || !NextParamAsStr(&text))
@@ -2426,11 +2398,6 @@ void WriteLogXmlCommand::Execute()
void ClearLogXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
g_Log->Clear();
BuildBoolResponse(true);
@@ -2438,11 +2405,6 @@ void ClearLogXmlCommand::Execute()
void ScanXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
bool syncMode = false;
// optional parameter "SyncMode"
NextParamAsBool(&syncMode);
@@ -2948,11 +2910,6 @@ void ViewFeedXmlCommand::Execute()
// bool fetchfeed(int ID)
void FetchFeedXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
int id;
if (!NextParamAsInt(&id))
{
@@ -2968,11 +2925,6 @@ void FetchFeedXmlCommand::Execute()
// bool editserver(int ID, bool Active)
void EditServerXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
bool ok = false;
int first = true;
@@ -3092,11 +3044,6 @@ void CheckUpdatesXmlCommand::Execute()
// bool startupdate(string branch)
void StartUpdateXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
char* branchName;
if (!NextParamAsStr(&branchName))
{
@@ -3268,11 +3215,6 @@ void ServerVolumesXmlCommand::Execute()
// bool resetservervolume(int serverid, string counter);
void ResetServerVolumeXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
int serverId;
char* counter;
if (!NextParamAsInt(&serverId) || !NextParamAsStr(&counter))
@@ -3351,11 +3293,6 @@ void TestServerXmlCommand::Execute()
const char* XML_RESPONSE_STR_BODY = "<string>%s</string>";
const char* JSON_RESPONSE_STR_BODY = "\"%s\"";
if (!CheckSafeMethod())
{
return;
}
char* host;
int port;
char* username;
@@ -3378,6 +3315,17 @@ void TestServerXmlCommand::Execute()
connection.SetSuppressErrors(false);
bool ok = connection.Connect();
if (ok)
{
// generate a unique non-existent message-id since we don't want a real article to be returned
BString<1024> id;
while (id.Length() < 30)
{
id.AppendFmt("%i", rand());
}
const char* response = connection.Request(BString<1024>("ARTICLE <%s@nzbget.net>\r\n", *id));
ok = response && (*response == '4' || *response == '2');
}
BString<1024> content(IsJson() ? JSON_RESPONSE_STR_BODY : XML_RESPONSE_STR_BODY,
ok ? "" : m_errText.Empty() ? "Unknown error" : *m_errText);
@@ -3396,11 +3344,6 @@ void TestServerXmlCommand::PrintError(const char* errMsg)
// bool startscript(string script, string command, string context, struct[] options);
void StartScriptXmlCommand::Execute()
{
if (!CheckSafeMethod())
{
return;
}
char* script;
char* command;
char* context;

View File

@@ -59,6 +59,7 @@ public:
const char* GetResponse() { return m_response; }
const char* GetContentType() { return m_contentType; }
static bool IsRpcRequest(const char* url);
bool IsSafeMethod() { return m_safeMethod; };
private:
char* m_request = nullptr;
@@ -68,11 +69,13 @@ private:
EUserAccess m_userAccess;
CString m_url;
StringBuilder m_response;
bool m_safeMethod = false;
void Dispatch();
std::unique_ptr<XmlCommand> CreateCommand(const char* methodName);
void MutliCall();
void BuildResponse(const char* response, const char* callbackFunc, bool fault, const char* requestId);
void BuildErrorResponse(int errCode, const char* errText);
};
class XmlCommand
@@ -89,6 +92,8 @@ public:
const char* GetResponse() { return m_response; }
const char* GetCallbackFunc() { return m_callbackFunc; }
bool GetFault() { return m_fault; }
virtual bool IsSafeMethod() { return false; };
virtual bool IsError() { return false; };
protected:
char* m_request = nullptr;
@@ -107,7 +112,6 @@ protected:
void AppendFmtResponse(const char* format, ...);
void AppendCondResponse(const char* part, bool cond);
bool IsJson();
bool CheckSafeMethod();
bool NextParamAsInt(int* value);
bool NextParamAsBool(bool* value);
bool NextParamAsStr(char** valueBuf);

View File

@@ -428,7 +428,7 @@ CString FileSystem::MakeUniqueFilename(const char* destDir, const char* basename
if (extension && extension != basename)
{
BString<1024> filenameWithoutExt = basename;
int end = extension - basename;
int end = (int)(extension - basename);
filenameWithoutExt[end < 1024 ? end : 1024-1] = '\0';
if (!strcasecmp(extension, ".par2"))

View File

@@ -75,31 +75,55 @@ void Log::Filelog(const char* msg, ...)
if ((int)rawtime/86400 != (int)m_lastWritten/86400 && g_Options->GetWriteLog() == Options::wlRotate)
{
if (m_logFile)
{
m_logFile.reset();
}
RotateLog();
}
m_lastWritten = rawtime;
DiskFile file;
if (file.Open(m_logFilename, DiskFile::omAppend))
if (!m_logFile)
{
m_logFile = std::make_unique<DiskFile>();
if (!m_logFile->Open(m_logFilename, DiskFile::omAppend))
{
perror(m_logFilename);
m_logFile.reset();
return;
}
}
m_logFile->Seek(0, DiskFile::soEnd);
#ifdef WIN32
uint64 processId = GetCurrentProcessId();
uint64 threadId = GetCurrentThreadId();
uint64 processId = GetCurrentProcessId();
uint64 threadId = GetCurrentThreadId();
#else
uint64 processId = (uint64)getpid();
uint64 threadId = (uint64)pthread_self();
uint64 processId = (uint64)getpid();
uint64 threadId = (uint64)pthread_self();
#endif
#ifdef DEBUG
file.Print("%s\t%llu\t%llu\t%s%s", time, processId, threadId, tmp2, LINE_ENDING);
m_logFile->Print("%s\t%llu\t%llu\t%s%s", time, processId, threadId, tmp2, LINE_ENDING);
#else
file.Print("%s\t%s%s", time, tmp2, LINE_ENDING);
m_logFile->Print("%s\t%s%s", time, tmp2, LINE_ENDING);
#endif
file.Close();
}
else
m_logFile->Flush();
}
void Log::IntervalCheck()
{
// Close log-file on idle (if last write into log was more than a second ago)
if (m_logFile)
{
perror(m_logFilename);
time_t curTime = Util::CurrentTime() + g_Options->GetTimeCorrection();
if (std::abs(curTime - m_lastWritten) > 1)
{
Guard guard(m_logMutex);
m_logFile.reset();
}
}
}
@@ -111,6 +135,11 @@ void debug(const char* filename, const char* funcname, int lineNr, const char* m
void debug(const char* msg, ...)
#endif
{
if (!g_Log)
{
return;
}
char tmp1[1024];
va_list ap;
@@ -257,7 +286,7 @@ void Log::AddMessage(Message::EKind kind, const char * text)
if (m_optInit && g_Options)
{
while (m_messages.size() > (uint32)g_Options->GetLogBufferSize())
while (m_messages.size() > (uint32)g_Options->GetLogBuffer())
{
m_messages.pop_front();
}

View File

@@ -70,6 +70,7 @@ typedef std::deque<Message> MessageList;
typedef GuardedPtr<MessageList> GuardedMessageList;
class Debuggable;
class DiskFile;
class Log
{
@@ -83,6 +84,7 @@ public:
void RegisterDebuggable(Debuggable* debuggable);
void UnregisterDebuggable(Debuggable* debuggable);
void LogDebugInfo();
void IntervalCheck();
private:
typedef std::list<Debuggable*> Debuggables;
@@ -92,6 +94,7 @@ private:
Debuggables m_debuggables;
Mutex m_debugMutex;
CString m_logFilename;
std::unique_ptr<DiskFile> m_logFile;
uint32 m_idGen = 0;
time_t m_lastWritten = 0;
bool m_optInit = false;

View File

@@ -473,6 +473,8 @@ void ScriptController::StartProcess(int* pipein, int* pipeout)
cmdLine = cmdLineBuf;
}
debug("Starting process: %s", cmdLine);
WString wideWorkingDir = FileSystem::UtfPathToWidePath(workingDir);
if (strlen(workingDir) > 260 - 14)
{
@@ -582,6 +584,12 @@ void ScriptController::StartProcess(int* pipein, int* pipeout)
args.emplace_back(nullptr);
char* const* argdata = (char* const*)args.data();
debug("Starting process: %s", script);
for (const char* arg : m_args)
{
debug("arg: %s", arg);
}
debug("forking");
pid_t pid = fork();

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
#include "nzbget.h"
#include "Util.h"
#include "YEncode.h"
#ifndef WIN32
// function "code_revision" is automatically generated in file "code_revision.cpp" on each build
@@ -650,158 +651,6 @@ void Util::SetStandByMode(bool standBy)
#endif
}
static uint32 crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/* This is a modified version of chksum_crc() from
* crc32.c (http://www.koders.com/c/fid699AFE0A656F0022C9D6B9D1743E697B69CE5815.aspx)
* (c) 1999,2000 Krzysztof Dabrowski
* (c) 1999,2000 ElysiuM deeZine
*
* chksum_crc() -- to a given block, this one calculates the
* crc32-checksum until the length is
* reached. the crc32-checksum will be
* the result.
*/
uint32 Util::Crc32m(uint32 startCrc, uchar *block, uint32 length)
{
uint32 crc = startCrc;
for (uint32 i = 0; i < length; i++)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_tab[(crc ^ *block++) & 0xFF];
}
return crc;
}
uint32 Util::Crc32(uchar *block, uint32 length)
{
return Util::Crc32m(0xFFFFFFFF, block, length) ^ 0xFFFFFFFF;
}
/* From zlib/crc32.c (http://www.zlib.net/)
* Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
*/
#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
uint32 gf2_matrix_times(uint32 *mat, uint32 vec)
{
uint32 sum;
sum = 0;
while (vec) {
if (vec & 1)
sum ^= *mat;
vec >>= 1;
mat++;
}
return sum;
}
void gf2_matrix_square(uint32 *square, uint32 *mat)
{
int n;
for (n = 0; n < GF2_DIM; n++)
square[n] = gf2_matrix_times(mat, mat[n]);
}
uint32 Util::Crc32Combine(uint32 crc1, uint32 crc2, uint32 len2)
{
int n;
uint32 row;
uint32 even[GF2_DIM]; /* even-power-of-two zeros operator */
uint32 odd[GF2_DIM]; /* odd-power-of-two zeros operator */
/* degenerate case (also disallow negative lengths) */
if (len2 <= 0)
return crc1;
/* put operator for one zero bit in odd */
odd[0] = 0xedb88320UL; /* CRC-32 polynomial */
row = 1;
for (n = 1; n < GF2_DIM; n++) {
odd[n] = row;
row <<= 1;
}
/* put operator for two zero bits in even */
gf2_matrix_square(even, odd);
/* put operator for four zero bits in odd */
gf2_matrix_square(odd, even);
/* apply len2 zeros to crc1 (first square will put the operator for one
zero byte, eight zero bits, in even) */
do {
/* apply zeros operator for this bit of len2 */
gf2_matrix_square(even, odd);
if (len2 & 1)
crc1 = gf2_matrix_times(even, crc1);
len2 >>= 1;
/* if no more bits set, then done */
if (len2 == 0)
break;
/* another iteration of the loop with odd and even swapped */
gf2_matrix_square(odd, even);
if (len2 & 1)
crc1 = gf2_matrix_times(odd, crc1);
len2 >>= 1;
/* if no more bits set, then done */
} while (len2 != 0);
/* return combined crc */
crc1 ^= crc2;
return crc1;
}
int Util::NumberOfCpuCores()
{
#ifdef WIN32
@@ -1573,7 +1422,7 @@ void URL::ParseUrl()
return;
}
m_protocol.Set(m_address, protEnd - m_address);
m_protocol.Set(m_address, (int)(protEnd - m_address));
char* hostStart = protEnd + 3;
char* slash = strchr(hostStart, '/');
@@ -1607,7 +1456,7 @@ void URL::ParseUrl()
if (slash)
{
char* resEnd = m_address + strlen(m_address);
m_resource.Set(slash, resEnd - slash + 1);
m_resource.Set(slash, (int)(resEnd - slash + 1));
hostEnd = slash - 1;
}
@@ -1625,7 +1474,7 @@ void URL::ParseUrl()
m_port = atoi(colon + 1);
}
m_host.Set(hostStart, hostEnd - hostStart + 1);
m_host.Set(hostStart, (int)(hostEnd - hostStart + 1));
m_valid = true;
}
@@ -1687,7 +1536,7 @@ int RegEx::GetMatchStart(int index)
#ifdef HAVE_REGEX_H
return m_matches[index].rm_so;
#else
return nullptr;
return 0;
#endif
}
@@ -1732,14 +1581,14 @@ bool WildMask::Match(const char* text)
if (!qmark)
{
ExpandArray();
m_wildStart[m_wildCount-1] = str - text;
m_wildStart[m_wildCount-1] = (int)(str - text);
m_wildLen[m_wildCount-1] = 0;
qmark = true;
}
}
else if (m_wantsPositions && qmark)
{
m_wildLen[m_wildCount-1] = str - (text + m_wildStart[m_wildCount-1]);
m_wildLen[m_wildCount-1] = (int)(str - (text + m_wildStart[m_wildCount-1]));
qmark = false;
}
@@ -1754,7 +1603,7 @@ bool WildMask::Match(const char* text)
if (m_wantsPositions && qmark)
{
m_wildLen[m_wildCount-1] = str - (text + m_wildStart[m_wildCount-1]);
m_wildLen[m_wildCount-1] = (int)(str - (text + m_wildStart[m_wildCount-1]));
qmark = false;
}
@@ -1764,13 +1613,13 @@ bool WildMask::Match(const char* text)
{
if (m_wantsPositions && qmark)
{
m_wildLen[m_wildCount-1] = str - (text + m_wildStart[m_wildCount-1]);
m_wildLen[m_wildCount-1] = (int)(str - (text + m_wildStart[m_wildCount-1]));
qmark = false;
}
if (m_wantsPositions && !star)
{
ExpandArray();
m_wildStart[m_wildCount-1] = str - text;
m_wildStart[m_wildCount-1] = (int)(str - text);
m_wildLen[m_wildCount-1] = 0;
star = true;
}
@@ -1792,7 +1641,7 @@ bool WildMask::Match(const char* text)
if (m_wantsPositions && !qmark)
{
ExpandArray();
m_wildStart[m_wildCount-1] = str - text;
m_wildStart[m_wildCount-1] = (int)(str - text);
m_wildLen[m_wildCount-1] = 0;
qmark = true;
}
@@ -1804,12 +1653,12 @@ bool WildMask::Match(const char* text)
{
if (m_wantsPositions && qmark)
{
m_wildLen[m_wildCount-1] = str - (text + m_wildStart[m_wildCount-1]);
m_wildLen[m_wildCount-1] = (int)(str - (text + m_wildStart[m_wildCount-1]));
qmark = false;
}
else if (m_wantsPositions && star)
{
m_wildLen[m_wildCount-1] = str - (text + m_wildStart[m_wildCount-1]);
m_wildLen[m_wildCount-1] = (int)(str - (text + m_wildStart[m_wildCount-1]));
star = false;
}
@@ -1832,13 +1681,13 @@ bool WildMask::Match(const char* text)
if (m_wantsPositions && qmark)
{
m_wildLen[m_wildCount-1] = str - (text + m_wildStart[m_wildCount-1]);
m_wildLen[m_wildCount-1] = (int)(str - (text + m_wildStart[m_wildCount-1]));
}
if (*pat == '*' && m_wantsPositions && !star)
{
ExpandArray();
m_wildStart[m_wildCount-1] = str - text;
m_wildStart[m_wildCount-1] = (int)(str - text);
m_wildLen[m_wildCount-1] = strlen(str);
}
@@ -1987,3 +1836,101 @@ char* Tokenizer::Next()
}
return token;
}
void Crc32::Reset()
{
static_assert(sizeof(m_state) >= sizeof(YEncode::crc_state), "m_state has invalid size");
YEncode::crc_init((YEncode::crc_state*)State());
}
void Crc32::Append(uchar* block, uint32 length)
{
YEncode::crc_incr((YEncode::crc_state*)State(), block, length);
}
uint32 Crc32::Finish()
{
return YEncode::crc_finish((YEncode::crc_state*)State());
}
/* From zlib/crc32.c (http://www.zlib.net/)
* Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
*/
#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
uint32 gf2_matrix_times(uint32 *mat, uint32 vec)
{
uint32 sum;
sum = 0;
while (vec) {
if (vec & 1)
sum ^= *mat;
vec >>= 1;
mat++;
}
return sum;
}
void gf2_matrix_square(uint32 *square, uint32 *mat)
{
int n;
for (n = 0; n < GF2_DIM; n++)
square[n] = gf2_matrix_times(mat, mat[n]);
}
uint32 Crc32::Combine(uint32 crc1, uint32 crc2, uint32 len2)
{
int n;
uint32 row;
uint32 even[GF2_DIM]; /* even-power-of-two zeros operator */
uint32 odd[GF2_DIM]; /* odd-power-of-two zeros operator */
/* degenerate case (also disallow negative lengths) */
if (len2 <= 0)
return crc1;
/* put operator for one zero bit in odd */
odd[0] = 0xedb88320UL; /* CRC-32 polynomial */
row = 1;
for (n = 1; n < GF2_DIM; n++) {
odd[n] = row;
row <<= 1;
}
/* put operator for two zero bits in even */
gf2_matrix_square(even, odd);
/* put operator for four zero bits in odd */
gf2_matrix_square(odd, even);
/* apply len2 zeros to crc1 (first square will put the operator for one
zero byte, eight zero bits, in even) */
do {
/* apply zeros operator for this bit of len2 */
gf2_matrix_square(even, odd);
if (len2 & 1)
crc1 = gf2_matrix_times(even, crc1);
len2 >>= 1;
/* if no more bits set, then done */
if (len2 == 0)
break;
/* another iteration of the loop with odd and even swapped */
gf2_matrix_square(odd, even);
if (len2 & 1)
crc1 = gf2_matrix_times(odd, crc1);
len2 >>= 1;
/* if no more bits set, then done */
} while (len2 != 0);
/* return combined crc */
crc1 ^= crc2;
return crc1;
}

View File

@@ -86,10 +86,6 @@ public:
static void Init();
static uint32 Crc32(uchar *block, uint32 length);
static uint32 Crc32m(uint32 startCrc, uchar *block, uint32 length);
static uint32 Crc32Combine(uint32 crc1, uint32 crc2, uint32 len2);
/*
* Returns number of available CPU cores or -1 if it could not be determined
*/
@@ -317,4 +313,24 @@ private:
bool m_working = false;
};
class Crc32
{
public:
Crc32() { Reset(); }
void Reset();
void Append(uchar* block, uint32 length);
uint32 Finish();
static uint32 Combine(uint32 crc1, uint32 crc2, uint32 len2);
private:
#if defined(WIN32) && !defined(_WIN64)
// VC++ in 32 bit mode can not "alignas(16)" dynamically allocated objects
alignas(8) uint32_t m_state[4 * 5 + 8]; // = YEncode::crc_state
void* State() { void* p = &m_state; size_t s = sizeof(m_state); return std::align(16, 4 * 5, p, s); }
#else
alignas(16) uint32_t m_state[4 * 5]; // = YEncode::crc_state
void* State() { return &m_state; }
#endif
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2014-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2014-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -307,6 +307,7 @@ LRESULT WinConsole::TrayWndProc(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM l
return 0;
case UM_QUIT:
case WM_ENDSESSION:
ExitProc();
return 0;
@@ -456,12 +457,12 @@ void WinConsole::ShowAboutBox()
m_modal = false;
}
BOOL CALLBACK WinConsole::AboutDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
INT_PTR CALLBACK WinConsole::AboutDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return g_WinConsole->AboutDialogProc(hwndDlg, uMsg, wParam, lParam);
}
BOOL WinConsole::AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
INT_PTR WinConsole::AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
@@ -507,7 +508,7 @@ BOOL WinConsole::AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
(HWND)wParam == GetDlgItem(hwndDlg, IDC_ABOUT_GPL))
{
SetCursor(m_handCursor);
SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
return TRUE;
}
return FALSE;
@@ -529,12 +530,12 @@ void WinConsole::ShowPrefsDialog()
m_modal = false;
}
BOOL CALLBACK WinConsole::PrefsDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
INT_PTR CALLBACK WinConsole::PrefsDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return g_WinConsole->PrefsDialogProc(hwndDlg, uMsg, wParam, lParam);
}
BOOL WinConsole::PrefsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
INT_PTR WinConsole::PrefsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
@@ -691,7 +692,7 @@ void WinConsole::ShowRunningDialog()
HWND hTrayWindow = FindWindow("NZBGet tray window", nullptr);
m_running = true;
int result = DialogBox(m_instance, MAKEINTRESOURCE(IDD_RUNNINGDIALOG), m_trayWindow, RunningDialogProcStat);
INT_PTR result = DialogBox(m_instance, MAKEINTRESOURCE(IDD_RUNNINGDIALOG), m_trayWindow, RunningDialogProcStat);
switch (result)
{
@@ -710,12 +711,12 @@ void WinConsole::ShowRunningDialog()
}
}
BOOL CALLBACK WinConsole::RunningDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
INT_PTR CALLBACK WinConsole::RunningDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return g_WinConsole->RunningDialogProc(hwndDlg, uMsg, wParam, lParam);
}
BOOL WinConsole::RunningDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
INT_PTR WinConsole::RunningDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
@@ -913,7 +914,7 @@ void WinConsole::ShowFactoryResetDialog()
HWND hTrayWindow = FindWindow("NZBGet tray window", nullptr);
m_running = true;
int result = DialogBox(m_instance, MAKEINTRESOURCE(IDD_FACTORYRESETDIALOG), m_trayWindow, FactoryResetDialogProcStat);
INT_PTR result = DialogBox(m_instance, MAKEINTRESOURCE(IDD_FACTORYRESETDIALOG), m_trayWindow, FactoryResetDialogProcStat);
switch (result)
{
@@ -923,12 +924,12 @@ void WinConsole::ShowFactoryResetDialog()
}
}
BOOL CALLBACK WinConsole::FactoryResetDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
INT_PTR CALLBACK WinConsole::FactoryResetDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return g_WinConsole->FactoryResetDialogProc(hwndDlg, uMsg, wParam, lParam);
}
BOOL WinConsole::FactoryResetDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
INT_PTR WinConsole::FactoryResetDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget. See <http://nzbget.net>.
*
* Copyright (C) 2014-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2014-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -89,14 +89,14 @@ private:
static BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType);
static LRESULT CALLBACK TrayWndProcStat(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT TrayWndProc(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK AboutDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK PrefsDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL PrefsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK RunningDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL RunningDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK FactoryResetDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL FactoryResetDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK AboutDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK PrefsDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR PrefsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK RunningDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR RunningDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK FactoryResetDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT_PTR FactoryResetDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
#endif

View File

@@ -18,6 +18,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "nzbget.h"
#include <iostream>
#include "par2cmdline.h"
#ifdef _MSC_VER

View File

@@ -25,12 +25,6 @@
//#define snprintf _snprintf
#define stat _stat
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __PDP_ENDIAN 3412
#define __BYTE_ORDER __LITTLE_ENDIAN
namespace Par2
{
@@ -75,29 +69,6 @@ typedef unsigned long long u64;
#define _MAX_PATH 255
#if HAVE_ENDIAN_H
# include <endian.h>
# ifndef __LITTLE_ENDIAN
# ifdef _LITTLE_ENDIAN
# define __LITTLE_ENDIAN _LITTLE_ENDIAN
# define __LITTLE_ENDIAN _LITTLE_ENDIAN
# define __BIG_ENDIAN _BIG_ENDIAN
# define __PDP_ENDIAN _PDP_ENDIAN
# else
# error <endian.h> does not define __LITTLE_ENDIAN etc.
# endif
# endif
#else
# define __LITTLE_ENDIAN 1234
# define __BIG_ENDIAN 4321
# define __PDP_ENDIAN 3412
# if WORDS_BIGENDIAN
# define __BYTE_ORDER __BIG_ENDIAN
# else
# define __BYTE_ORDER __LITTLE_ENDIAN
# endif
#endif
#endif
#ifdef WIN32

View File

@@ -17,9 +17,6 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include <stdlib.h>
#include <iostream>
namespace Par2
{

102
lib/yencode/AcleCrc.cpp Normal file
View File

@@ -0,0 +1,102 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// inspired off https://github.com/jocover/crc32_armv8/blob/master/crc32_armv8.c
#include "nzbget.h"
#include "YEncode.h"
#ifdef __ARM_FEATURE_CRC32
#include <arm_acle.h>
#endif
namespace YEncode
{
#ifdef __ARM_FEATURE_CRC32
void crc_arm_init(crc_state *const s)
{
s->crc0[0] = ~0;
}
void crc_arm(crc_state *const s, const unsigned char *src, long len) {
uint32_t crc = s->crc0[0];
// initial alignment
if (len >= 16) { // 16 is an arbitrary number; it just needs to be >=8
if ((uintptr_t)src & sizeof(uint8_t)) {
crc = __crc32b(crc, *src);
src++;
len--;
}
if ((uintptr_t)src & sizeof(uint16_t)) {
crc = __crc32h(crc, *((uint16_t *)src));
src += sizeof(uint16_t);
len -= sizeof(uint16_t);
}
#ifdef __aarch64__
if ((uintptr_t)src & sizeof(uint32_t)) {
crc = __crc32w(crc, *((uint32_t *)src));
src += sizeof(uint32_t);
len -= sizeof(uint32_t);
}
}
while ((len -= sizeof(uint64_t)) >= 0) {
crc = __crc32d(crc, *((uint64_t *)src));
src += sizeof(uint64_t);
}
if (len & sizeof(uint32_t)) {
crc = __crc32w(crc, *((uint32_t *)src));
src += sizeof(uint32_t);
}
#else
}
while ((len -= sizeof(uint32_t)) >= 0) {
crc = __crc32w(crc, *((uint32_t *)src));
src += sizeof(uint32_t);
}
#endif
if (len & sizeof(uint16_t)) {
crc = __crc32h(crc, *((uint16_t *)src));
src += sizeof(uint16_t);
}
if (len & sizeof(uint8_t))
crc = __crc32b(crc, *src);
s->crc0[0] = crc;
}
uint32_t crc_arm_finish(crc_state *const s)
{
return ~s->crc0[0];
}
#endif
void init_crc_acle()
{
#ifdef __ARM_FEATURE_CRC32
crc_init = &crc_arm_init;
crc_incr = &crc_arm;
crc_finish = &crc_arm_finish;
crc_simd = true;
#endif
}
}

View File

@@ -0,0 +1,50 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* Copyright (C) 2017 Anime Tosho (animetosho)
* Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nzbget.h"
#include "YEncode.h"
#ifdef __ARM_NEON
#include <arm_neon.h>
#endif
namespace YEncode
{
namespace Neon
{
#ifdef __ARM_NEON
#define SIMD_DECODER
#include "SimdDecoder.cpp"
#endif
}
void init_decode_neon() {
#ifdef __ARM_NEON
decode = &YEncode::Neon::do_decode_simd<sizeof(uint8x16_t), YEncode::Neon::do_decode_neon>;
YEncode::Neon::decoder_init();
decode_simd = true;
#endif
}
}

471
lib/yencode/PclmulCrc.cpp Normal file
View File

@@ -0,0 +1,471 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// taken from zlib-ng / Intel's zlib patch, modified to remove zlib dependencies
/*
* Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ
* instruction.
*
* A white paper describing this algorithm can be found at:
* http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
*
* Copyright (C) 2013 Intel Corporation. All rights reserved.
* Authors:
* Wajdi Feghali <wajdi.k.feghali@intel.com>
* Jim Guilford <james.guilford@intel.com>
* Vinodh Gopal <vinodh.gopal@intel.com>
* Erdinc Ozturk <erdinc.ozturk@intel.com>
* Jim Kukunas <james.t.kukunas@linux.intel.com>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "nzbget.h"
#include "YEncode.h"
#ifdef __PCLMUL__
#include <immintrin.h>
#endif
namespace YEncode
{
#ifdef __PCLMUL__
void fold_1(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) {
const __m128i xmm_fold4 = _mm_set_epi32(
0x00000001, 0x54442bd4,
0x00000001, 0xc6e41596);
__m128i x_tmp3;
__m128 ps_crc0, ps_crc3, ps_res;
x_tmp3 = *xmm_crc3;
*xmm_crc3 = *xmm_crc0;
*xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01);
*xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10);
ps_crc0 = _mm_castsi128_ps(*xmm_crc0);
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
ps_res = _mm_xor_ps(ps_crc0, ps_crc3);
*xmm_crc0 = *xmm_crc1;
*xmm_crc1 = *xmm_crc2;
*xmm_crc2 = x_tmp3;
*xmm_crc3 = _mm_castps_si128(ps_res);
}
void fold_2(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) {
const __m128i xmm_fold4 = _mm_set_epi32(
0x00000001, 0x54442bd4,
0x00000001, 0xc6e41596);
__m128i x_tmp3, x_tmp2;
__m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res31, ps_res20;
x_tmp3 = *xmm_crc3;
x_tmp2 = *xmm_crc2;
*xmm_crc3 = *xmm_crc1;
*xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01);
*xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10);
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
ps_crc1 = _mm_castsi128_ps(*xmm_crc1);
ps_res31 = _mm_xor_ps(ps_crc3, ps_crc1);
*xmm_crc2 = *xmm_crc0;
*xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01);
*xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10);
ps_crc0 = _mm_castsi128_ps(*xmm_crc0);
ps_crc2 = _mm_castsi128_ps(*xmm_crc2);
ps_res20 = _mm_xor_ps(ps_crc0, ps_crc2);
*xmm_crc0 = x_tmp2;
*xmm_crc1 = x_tmp3;
*xmm_crc2 = _mm_castps_si128(ps_res20);
*xmm_crc3 = _mm_castps_si128(ps_res31);
}
void fold_3(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) {
const __m128i xmm_fold4 = _mm_set_epi32(
0x00000001, 0x54442bd4,
0x00000001, 0xc6e41596);
__m128i x_tmp3;
__m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res32, ps_res21, ps_res10;
x_tmp3 = *xmm_crc3;
*xmm_crc3 = *xmm_crc2;
*xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01);
*xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x10);
ps_crc2 = _mm_castsi128_ps(*xmm_crc2);
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
ps_res32 = _mm_xor_ps(ps_crc2, ps_crc3);
*xmm_crc2 = *xmm_crc1;
*xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01);
*xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x10);
ps_crc1 = _mm_castsi128_ps(*xmm_crc1);
ps_crc2 = _mm_castsi128_ps(*xmm_crc2);
ps_res21 = _mm_xor_ps(ps_crc1, ps_crc2);
*xmm_crc1 = *xmm_crc0;
*xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01);
*xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x10);
ps_crc0 = _mm_castsi128_ps(*xmm_crc0);
ps_crc1 = _mm_castsi128_ps(*xmm_crc1);
ps_res10 = _mm_xor_ps(ps_crc0, ps_crc1);
*xmm_crc0 = x_tmp3;
*xmm_crc1 = _mm_castps_si128(ps_res10);
*xmm_crc2 = _mm_castps_si128(ps_res21);
*xmm_crc3 = _mm_castps_si128(ps_res32);
}
void fold_4(__m128i *xmm_crc0, __m128i *xmm_crc1, __m128i *xmm_crc2, __m128i *xmm_crc3) {
const __m128i xmm_fold4 = _mm_set_epi32(
0x00000001, 0x54442bd4,
0x00000001, 0xc6e41596);
__m128i x_tmp0, x_tmp1, x_tmp2, x_tmp3;
__m128 ps_crc0, ps_crc1, ps_crc2, ps_crc3;
__m128 ps_t0, ps_t1, ps_t2, ps_t3;
__m128 ps_res0, ps_res1, ps_res2, ps_res3;
x_tmp0 = *xmm_crc0;
x_tmp1 = *xmm_crc1;
x_tmp2 = *xmm_crc2;
x_tmp3 = *xmm_crc3;
*xmm_crc0 = _mm_clmulepi64_si128(*xmm_crc0, xmm_fold4, 0x01);
x_tmp0 = _mm_clmulepi64_si128(x_tmp0, xmm_fold4, 0x10);
ps_crc0 = _mm_castsi128_ps(*xmm_crc0);
ps_t0 = _mm_castsi128_ps(x_tmp0);
ps_res0 = _mm_xor_ps(ps_crc0, ps_t0);
*xmm_crc1 = _mm_clmulepi64_si128(*xmm_crc1, xmm_fold4, 0x01);
x_tmp1 = _mm_clmulepi64_si128(x_tmp1, xmm_fold4, 0x10);
ps_crc1 = _mm_castsi128_ps(*xmm_crc1);
ps_t1 = _mm_castsi128_ps(x_tmp1);
ps_res1 = _mm_xor_ps(ps_crc1, ps_t1);
*xmm_crc2 = _mm_clmulepi64_si128(*xmm_crc2, xmm_fold4, 0x01);
x_tmp2 = _mm_clmulepi64_si128(x_tmp2, xmm_fold4, 0x10);
ps_crc2 = _mm_castsi128_ps(*xmm_crc2);
ps_t2 = _mm_castsi128_ps(x_tmp2);
ps_res2 = _mm_xor_ps(ps_crc2, ps_t2);
*xmm_crc3 = _mm_clmulepi64_si128(*xmm_crc3, xmm_fold4, 0x01);
x_tmp3 = _mm_clmulepi64_si128(x_tmp3, xmm_fold4, 0x10);
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
ps_t3 = _mm_castsi128_ps(x_tmp3);
ps_res3 = _mm_xor_ps(ps_crc3, ps_t3);
*xmm_crc0 = _mm_castps_si128(ps_res0);
*xmm_crc1 = _mm_castps_si128(ps_res1);
*xmm_crc2 = _mm_castps_si128(ps_res2);
*xmm_crc3 = _mm_castps_si128(ps_res3);
}
alignas(32) const unsigned pshufb_shf_table[60] = {
0x84838281, 0x88878685, 0x8c8b8a89, 0x008f8e8d, /* shl 15 (16 - 1)/shr1 */
0x85848382, 0x89888786, 0x8d8c8b8a, 0x01008f8e, /* shl 14 (16 - 3)/shr2 */
0x86858483, 0x8a898887, 0x8e8d8c8b, 0x0201008f, /* shl 13 (16 - 4)/shr3 */
0x87868584, 0x8b8a8988, 0x8f8e8d8c, 0x03020100, /* shl 12 (16 - 4)/shr4 */
0x88878685, 0x8c8b8a89, 0x008f8e8d, 0x04030201, /* shl 11 (16 - 5)/shr5 */
0x89888786, 0x8d8c8b8a, 0x01008f8e, 0x05040302, /* shl 10 (16 - 6)/shr6 */
0x8a898887, 0x8e8d8c8b, 0x0201008f, 0x06050403, /* shl 9 (16 - 7)/shr7 */
0x8b8a8988, 0x8f8e8d8c, 0x03020100, 0x07060504, /* shl 8 (16 - 8)/shr8 */
0x8c8b8a89, 0x008f8e8d, 0x04030201, 0x08070605, /* shl 7 (16 - 9)/shr9 */
0x8d8c8b8a, 0x01008f8e, 0x05040302, 0x09080706, /* shl 6 (16 -10)/shr10*/
0x8e8d8c8b, 0x0201008f, 0x06050403, 0x0a090807, /* shl 5 (16 -11)/shr11*/
0x8f8e8d8c, 0x03020100, 0x07060504, 0x0b0a0908, /* shl 4 (16 -12)/shr12*/
0x008f8e8d, 0x04030201, 0x08070605, 0x0c0b0a09, /* shl 3 (16 -13)/shr13*/
0x01008f8e, 0x05040302, 0x09080706, 0x0d0c0b0a, /* shl 2 (16 -14)/shr14*/
0x0201008f, 0x06050403, 0x0a090807, 0x0e0d0c0b /* shl 1 (16 -15)/shr15*/
};
void partial_fold(const size_t len, __m128i *xmm_crc0, __m128i *xmm_crc1,
__m128i *xmm_crc2, __m128i *xmm_crc3, __m128i *xmm_crc_part) {
const __m128i xmm_fold4 = _mm_set_epi32(
0x00000001, 0x54442bd4,
0x00000001, 0xc6e41596);
const __m128i xmm_mask3 = _mm_set1_epi32(0x80808080);
__m128i xmm_shl, xmm_shr, xmm_tmp1, xmm_tmp2, xmm_tmp3;
__m128i xmm_a0_0, xmm_a0_1;
__m128 ps_crc3, psa0_0, psa0_1, ps_res;
xmm_shl = _mm_load_si128((__m128i *)pshufb_shf_table + (len - 1));
xmm_shr = xmm_shl;
xmm_shr = _mm_xor_si128(xmm_shr, xmm_mask3);
xmm_a0_0 = _mm_shuffle_epi8(*xmm_crc0, xmm_shl);
*xmm_crc0 = _mm_shuffle_epi8(*xmm_crc0, xmm_shr);
xmm_tmp1 = _mm_shuffle_epi8(*xmm_crc1, xmm_shl);
*xmm_crc0 = _mm_or_si128(*xmm_crc0, xmm_tmp1);
*xmm_crc1 = _mm_shuffle_epi8(*xmm_crc1, xmm_shr);
xmm_tmp2 = _mm_shuffle_epi8(*xmm_crc2, xmm_shl);
*xmm_crc1 = _mm_or_si128(*xmm_crc1, xmm_tmp2);
*xmm_crc2 = _mm_shuffle_epi8(*xmm_crc2, xmm_shr);
xmm_tmp3 = _mm_shuffle_epi8(*xmm_crc3, xmm_shl);
*xmm_crc2 = _mm_or_si128(*xmm_crc2, xmm_tmp3);
*xmm_crc3 = _mm_shuffle_epi8(*xmm_crc3, xmm_shr);
*xmm_crc_part = _mm_shuffle_epi8(*xmm_crc_part, xmm_shl);
*xmm_crc3 = _mm_or_si128(*xmm_crc3, *xmm_crc_part);
xmm_a0_1 = _mm_clmulepi64_si128(xmm_a0_0, xmm_fold4, 0x10);
xmm_a0_0 = _mm_clmulepi64_si128(xmm_a0_0, xmm_fold4, 0x01);
ps_crc3 = _mm_castsi128_ps(*xmm_crc3);
psa0_0 = _mm_castsi128_ps(xmm_a0_0);
psa0_1 = _mm_castsi128_ps(xmm_a0_1);
ps_res = _mm_xor_ps(ps_crc3, psa0_0);
ps_res = _mm_xor_ps(ps_res, psa0_1);
*xmm_crc3 = _mm_castps_si128(ps_res);
}
alignas(16) const unsigned crc_k[] = {
0xccaa009e, 0x00000000, /* rk1 */
0x751997d0, 0x00000001, /* rk2 */
0xccaa009e, 0x00000000, /* rk5 */
0x63cd6124, 0x00000001, /* rk6 */
0xf7011640, 0x00000001, /* rk7 */
0xdb710640, 0x00000001 /* rk8 */
};
alignas(16) const unsigned crc_mask[4] = {
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000
};
alignas(16) const unsigned crc_mask2[4] = {
0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
};
#define CRC_LOAD(s) \
do { \
__m128i xmm_crc0 = _mm_loadu_si128((__m128i *)s->crc0 + 0);\
__m128i xmm_crc1 = _mm_loadu_si128((__m128i *)s->crc0 + 1);\
__m128i xmm_crc2 = _mm_loadu_si128((__m128i *)s->crc0 + 2);\
__m128i xmm_crc3 = _mm_loadu_si128((__m128i *)s->crc0 + 3);\
__m128i xmm_crc_part = _mm_loadu_si128((__m128i *)s->crc0 + 4);
#define CRC_SAVE(s) \
_mm_storeu_si128((__m128i *)s->crc0 + 0, xmm_crc0);\
_mm_storeu_si128((__m128i *)s->crc0 + 1, xmm_crc1);\
_mm_storeu_si128((__m128i *)s->crc0 + 2, xmm_crc2);\
_mm_storeu_si128((__m128i *)s->crc0 + 3, xmm_crc3);\
_mm_storeu_si128((__m128i *)s->crc0 + 4, xmm_crc_part);\
} while (0);
void crc_fold_init(crc_state *const s) {
CRC_LOAD(s)
xmm_crc0 = _mm_cvtsi32_si128(0x9db42487);
xmm_crc1 = _mm_setzero_si128();
xmm_crc2 = _mm_setzero_si128();
xmm_crc3 = _mm_setzero_si128();
CRC_SAVE(s)
}
void crc_fold(crc_state *const s, const unsigned char *src, long len) {
unsigned long algn_diff;
__m128i xmm_t0, xmm_t1, xmm_t2, xmm_t3;
CRC_LOAD(s)
if (len < 16) {
if (len == 0)
return;
xmm_crc_part = _mm_loadu_si128((__m128i *)src);
goto partial;
}
algn_diff = (0 - (uintptr_t)src) & 0xF;
if (algn_diff) {
xmm_crc_part = _mm_loadu_si128((__m128i *)src);
src += algn_diff;
len -= algn_diff;
partial_fold(algn_diff, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, &xmm_crc_part);
}
while ((len -= 64) >= 0) {
xmm_t0 = _mm_load_si128((__m128i *)src);
xmm_t1 = _mm_load_si128((__m128i *)src + 1);
xmm_t2 = _mm_load_si128((__m128i *)src + 2);
xmm_t3 = _mm_load_si128((__m128i *)src + 3);
fold_4(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3);
xmm_crc0 = _mm_xor_si128(xmm_crc0, xmm_t0);
xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t1);
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t2);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t3);
src += 64;
}
/*
* len = num bytes left - 64
*/
if (len + 16 >= 0) {
len += 16;
xmm_t0 = _mm_load_si128((__m128i *)src);
xmm_t1 = _mm_load_si128((__m128i *)src + 1);
xmm_t2 = _mm_load_si128((__m128i *)src + 2);
fold_3(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3);
xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_t0);
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t1);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t2);
if (len == 0)
goto done;
xmm_crc_part = _mm_load_si128((__m128i *)src + 3);
} else if (len + 32 >= 0) {
len += 32;
xmm_t0 = _mm_load_si128((__m128i *)src);
xmm_t1 = _mm_load_si128((__m128i *)src + 1);
fold_2(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3);
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_t0);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t1);
if (len == 0)
goto done;
xmm_crc_part = _mm_load_si128((__m128i *)src + 2);
} else if (len + 48 >= 0) {
len += 48;
xmm_t0 = _mm_load_si128((__m128i *)src);
fold_1(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_t0);
if (len == 0)
goto done;
xmm_crc_part = _mm_load_si128((__m128i *)src + 1);
} else {
len += 64;
if (len == 0)
goto done;
xmm_crc_part = _mm_load_si128((__m128i *)src);
}
partial:
partial_fold(len, &xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, &xmm_crc_part);
done:
CRC_SAVE(s)
}
uint32_t crc_fold_512to32(crc_state *const s) {
const __m128i xmm_mask = _mm_load_si128((__m128i *)crc_mask);
const __m128i xmm_mask2 = _mm_load_si128((__m128i *)crc_mask2);
uint32_t crc;
__m128i x_tmp0, x_tmp1, x_tmp2, crc_fold;
CRC_LOAD(s)
/*
* k1
*/
crc_fold = _mm_load_si128((__m128i *)crc_k);
x_tmp0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x10);
xmm_crc0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x01);
xmm_crc1 = _mm_xor_si128(xmm_crc1, x_tmp0);
xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_crc0);
x_tmp1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x10);
xmm_crc1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x01);
xmm_crc2 = _mm_xor_si128(xmm_crc2, x_tmp1);
xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_crc1);
x_tmp2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x10);
xmm_crc2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x01);
xmm_crc3 = _mm_xor_si128(xmm_crc3, x_tmp2);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
/*
* k5
*/
crc_fold = _mm_load_si128((__m128i *)crc_k + 1);
xmm_crc0 = xmm_crc3;
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0);
xmm_crc0 = _mm_srli_si128(xmm_crc0, 8);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0);
xmm_crc0 = xmm_crc3;
xmm_crc3 = _mm_slli_si128(xmm_crc3, 4);
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0);
xmm_crc3 = _mm_and_si128(xmm_crc3, xmm_mask2);
/*
* k7
*/
xmm_crc1 = xmm_crc3;
xmm_crc2 = xmm_crc3;
crc_fold = _mm_load_si128((__m128i *)crc_k + 2);
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
xmm_crc3 = _mm_and_si128(xmm_crc3, xmm_mask);
xmm_crc2 = xmm_crc3;
xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2);
xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc1);
crc = _mm_extract_epi32(xmm_crc3, 2);
return ~crc;
CRC_SAVE(s)
}
#endif
void init_crc_pclmul()
{
#ifdef __PCLMUL__
crc_init = &crc_fold_init;
crc_incr = &crc_fold;
crc_finish = &crc_fold_512to32;
crc_simd = true;
#endif
}
}

View File

@@ -0,0 +1,213 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* Copyright (C) 2017 Anime Tosho (animetosho)
* Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nzbget.h"
#include "YEncode.h"
namespace YEncode
{
// return values:
// - 0: no end sequence found
// - 1: \r\n=y sequence found, src points to byte after 'y'
// - 2: \r\n.\r\n sequence found, src points to byte after last '\n'
int decode_scalar(const unsigned char** src, unsigned char** dest, size_t len, YencDecoderState* state) {
const unsigned char *es = (*src) + len; // end source pointer
unsigned char *p = *dest; // destination pointer
long i = -(long)len; // input position
unsigned char c; // input character
if(len < 1) return 0;
#define YDEC_CHECK_END(s) if(i == 0) { \
*state = s; \
*src = es; \
*dest = p; \
return 0; \
}
if(state) switch(*state) {
case YDEC_STATE_CRLFEQ: do_decode_endable_scalar_ceq:
if(es[i] == 'y') {
*state = YDEC_STATE_NONE;
*src = es+i+1;
*dest = p;
return 1;
} // else fall thru and escape
case YDEC_STATE_EQ:
c = es[i];
*p++ = c - 42 - 64;
i++;
if(c != '\r') break;
YDEC_CHECK_END(YDEC_STATE_CR)
// fall through
case YDEC_STATE_CR:
if(es[i] != '\n') break;
i++;
YDEC_CHECK_END(YDEC_STATE_CRLF)
case YDEC_STATE_CRLF: do_decode_endable_scalar_c0:
if(es[i] == '.') {
i++;
YDEC_CHECK_END(YDEC_STATE_CRLFDT)
// fallthru
} else if(es[i] == '=') {
i++;
YDEC_CHECK_END(YDEC_STATE_CRLFEQ)
goto do_decode_endable_scalar_ceq;
} else
break;
case YDEC_STATE_CRLFDT:
if(es[i] == '\r') {
i++;
YDEC_CHECK_END(YDEC_STATE_CRLFDTCR)
// fallthru
} else if(es[i] == '=') { // check for dot-stuffed ending: \r\n.=y
i++;
YDEC_CHECK_END(YDEC_STATE_CRLFEQ)
goto do_decode_endable_scalar_ceq;
} else
break;
case YDEC_STATE_CRLFDTCR:
if(es[i] == '\n') {
*state = YDEC_STATE_CRLF;
*src = es + i + 1;
*dest = p;
return 2;
} else
break;
case YDEC_STATE_NONE: break; // silence compiler warning
} else // treat as YDEC_STATE_CRLF
goto do_decode_endable_scalar_c0;
for(; i < -2; i++) {
c = es[i];
switch(c) {
case '\r': {
if(es[i+1] == '\n') {
c = es[i+2];
if(c == '.') {
// skip past \r\n. sequences
i += 3;
YDEC_CHECK_END(YDEC_STATE_CRLFDT)
// check for end
if(es[i] == '\r') {
i++;
YDEC_CHECK_END(YDEC_STATE_CRLFDTCR)
if(es[i] == '\n') {
*src = es + i + 1;
*dest = p;
*state = YDEC_STATE_CRLF;
return 2;
} else i--;
} else if(es[i] == '=') {
i++;
YDEC_CHECK_END(YDEC_STATE_CRLFEQ)
if(es[i] == 'y') {
*src = es + i + 1;
*dest = p;
*state = YDEC_STATE_NONE;
return 1;
} else {
// escape char & continue
c = es[i];
*p++ = c - 42 - 64;
i -= (c == '\r');
}
} else i--;
}
else if(c == '=') {
i += 3;
YDEC_CHECK_END(YDEC_STATE_CRLFEQ)
if(es[i] == 'y') {
// ended
*src = es + i + 1;
*dest = p;
*state = YDEC_STATE_NONE;
return 1;
} else {
// escape char & continue
c = es[i];
*p++ = c - 42 - 64;
i -= (c == '\r');
}
}
}
} case '\n':
continue;
case '=':
c = es[i+1];
*p++ = c - 42 - 64;
i += (c != '\r'); // if we have a \r, reprocess character to deal with \r\n. case
continue;
default:
*p++ = c - 42;
}
}
if(state) *state = YDEC_STATE_NONE;
if(i == -2) { // 2nd last char
c = es[i];
switch(c) {
case '\r':
if(state && es[i+1] == '\n') {
*state = YDEC_STATE_CRLF;
*src = es;
*dest = p;
return 0;
}
case '\n':
break;
case '=':
c = es[i+1];
*p++ = c - 42 - 64;
i += (c != '\r');
break;
default:
*p++ = c - 42;
}
i++;
}
// do final char; we process this separately to prevent an overflow if the final char is '='
if(i == -1) {
c = es[i];
if(c != '\n' && c != '\r' && c != '=') {
*p++ = c - 42;
} else if(state) {
if(c == '=') *state = YDEC_STATE_EQ;
else if(c == '\r') *state = YDEC_STATE_CR;
else *state = YDEC_STATE_NONE;
}
}
#undef YDEC_CHECK_END
*src = es;
*dest = p;
return 0;
}
void init_decode_scalar() {
decode = decode_scalar;
}
}

674
lib/yencode/SimdDecoder.cpp Normal file
View File

@@ -0,0 +1,674 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* Copyright (C) 2017 Anime Tosho (animetosho)
* Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef SIMD_DECODER
// combine two 8-bit ints into a 16-bit one
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define UINT16_PACK(a, b) ((a) | ((b) << 8))
#define UINT32_PACK(a, b, c, d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
#else
#define UINT16_PACK(a, b) (((a) << 8) | (b))
#define UINT32_PACK(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
#endif
// table from http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
static const unsigned char BitsSetTable256[256] =
{
# define B2(n) n, n+1, n+1, n+2
# define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
# define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
B6(0), B6(1), B6(1), B6(2)
#undef B2
#undef B4
#undef B6
};
template<int width, void kernel(size_t&, const uint8_t*, unsigned char*&, unsigned char&, uint16_t&)>
int do_decode_simd(const unsigned char** src, unsigned char** dest, size_t len, YencDecoderState* state) {
if(len <= width*2) return decode_scalar(src, dest, len, state);
YencDecoderState tState = YDEC_STATE_CRLF;
YencDecoderState* pState = state ? state : &tState;
if((uintptr_t)(*src) & ((width-1))) {
// find source memory alignment
unsigned char* aSrc = (unsigned char*)(((uintptr_t)(*src) + (width-1)) & ~(width-1));
int amount = (int)(aSrc - *src);
len -= amount;
int ended = decode_scalar(src, dest, amount, pState);
if(ended) return ended;
}
size_t lenBuffer = width -1;
lenBuffer += 3 + 1;
if(len > lenBuffer) {
unsigned char *p = *dest; // destination pointer
unsigned char escFirst = 0; // input character; first char needs escaping
uint16_t nextMask = 0;
// handle finicky case of special sequences straddled across initial boundary
switch(*pState) {
case YDEC_STATE_CRLF:
if(**src == '.') {
nextMask = 1;
if(*(uint16_t*)(*src +1) == UINT16_PACK('\r','\n')) {
(*src) += 3;
*pState = YDEC_STATE_CRLF;
return 2;
}
if(*(uint16_t*)(*src +1) == UINT16_PACK('=','y')) {
(*src) += 3;
*pState = YDEC_STATE_NONE;
return 1;
}
}
else if(*(uint16_t*)(*src) == UINT16_PACK('=','y')) {
(*src) += 2;
*pState = YDEC_STATE_NONE;
return 1;
}
break;
case YDEC_STATE_CR:
if(*(uint16_t*)(*src) == UINT16_PACK('\n','.')) {
nextMask = 2;
if(*(uint16_t*)(*src +2) == UINT16_PACK('\r','\n')) {
(*src) += 4;
*pState = YDEC_STATE_CRLF;
return 2;
}
if(*(uint16_t*)(*src +2) == UINT16_PACK('=','y')) {
(*src) += 4;
*pState = YDEC_STATE_NONE;
return 1;
}
}
else if((*(uint32_t*)(*src) & 0xffffff) == UINT32_PACK('\n','=','y',0)) {
(*src) += 3;
*pState = YDEC_STATE_NONE;
return 1;
}
break;
case YDEC_STATE_CRLFDT:
if(*(uint16_t*)(*src) == UINT16_PACK('\r','\n')) {
(*src) += 2;
*pState = YDEC_STATE_CRLF;
return 2;
}
if(*(uint16_t*)(*src) == UINT16_PACK('=','y')) {
(*src) += 2;
*pState = YDEC_STATE_NONE;
return 1;
}
break;
case YDEC_STATE_CRLFDTCR:
if(**src == '\n') {
(*src) += 1;
*pState = YDEC_STATE_CRLF;
return 2;
}
break;
case YDEC_STATE_CRLFEQ:
if(**src == 'y') {
(*src) += 1;
*pState = YDEC_STATE_NONE;
return 1;
}
break;
default: break; // silence compiler warning
}
escFirst = (*pState == YDEC_STATE_EQ || *pState == YDEC_STATE_CRLFEQ);
// our algorithm may perform an aligned load on the next part, of which we consider 2 bytes (for \r\n. sequence checking)
size_t dLen = len - lenBuffer;
dLen = (dLen + (width-1)) & ~(width-1);
const uint8_t* dSrc = (const uint8_t*)(*src) + dLen;
kernel(dLen, dSrc, p, escFirst, nextMask);
if(escFirst) *pState = YDEC_STATE_EQ; // escape next character
else if(nextMask == 1) *pState = YDEC_STATE_CRLF; // next character is '.', where previous two were \r\n
else if(nextMask == 2) *pState = YDEC_STATE_CR; // next characters are '\n.', previous is \r
else *pState = YDEC_STATE_NONE;
*src += dLen;
len -= dLen;
*dest = p;
}
// end alignment
if(len)
return decode_scalar(src, dest, len, pState);
return 0;
}
alignas(32) static const uint8_t pshufb_combine_table[272] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x80,
0x00,0x01,0x02,0x03,0x04,0x05,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x80,0x80,
0x00,0x01,0x02,0x03,0x04,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x80,0x80,0x80,
0x00,0x01,0x02,0x03,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x80,0x80,0x80,0x80,
0x00,0x01,0x02,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x80,0x80,0x80,0x80,0x80,
0x00,0x01,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x80,0x80,0x80,0x80,0x80,0x80,
0x00,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
};
#ifdef __SSE2__
#define XMM_SIZE 16 /*== (signed int)sizeof(__m128i)*/
#if defined(__tune_core2__) || defined(__tune_atom__)
/* on older Intel CPUs, plus first gen Atom, it is faster to store XMM registers in half */
# define STOREU_XMM(dest, xmm) \
_mm_storel_epi64((__m128i*)(dest), xmm); \
_mm_storeh_pi(((__m64*)(dest) +1), _mm_castsi128_ps(xmm))
#else
# define STOREU_XMM(dest, xmm) \
_mm_storeu_si128((__m128i*)(dest), xmm)
#endif
#define LOAD_HALVES(a, b) _mm_castps_si128(_mm_loadh_pi( \
_mm_castsi128_ps(_mm_loadl_epi64((__m128i*)(a))), \
(b) \
))
uint8_t eqFixLUT[256];
alignas(32) __m64 eqAddLUT[256];
#ifdef __SSSE3__
alignas(32) __m64 unshufLUT[256];
#endif
template<bool use_ssse3>
static inline void do_decode_sse(size_t& dLen, const uint8_t* dSrc, unsigned char*& p, unsigned char& escFirst, uint16_t& nextMask) {
long dI = -(long)dLen;
for(; dI; dI += sizeof(__m128i)) {
const uint8_t* src = dSrc + dI;
__m128i data = _mm_load_si128((__m128i *)src);
// search for special chars
__m128i cmpEq = _mm_cmpeq_epi8(data, _mm_set1_epi8('=')),
#ifdef __AVX512VL__
cmp = _mm_ternarylogic_epi32(
_mm_cmpeq_epi8(data, _mm_set1_epi16(0x0a0d)),
_mm_cmpeq_epi8(data, _mm_set1_epi16(0x0d0a)),
cmpEq,
0xFE
);
#else
cmp = _mm_or_si128(
_mm_or_si128(
_mm_cmpeq_epi8(data, _mm_set1_epi16(0x0a0d)), // \r\n
_mm_cmpeq_epi8(data, _mm_set1_epi16(0x0d0a)) // \n\r
),
cmpEq
);
#endif
uint16_t mask = _mm_movemask_epi8(cmp); // not the most accurate mask if we have invalid sequences; we fix this up later
__m128i oData;
if(escFirst) { // rarely hit branch: seems to be faster to use 'if' than a lookup table, possibly due to values being able to be held in registers?
// first byte needs escaping due to preceeding = in last loop iteration
oData = _mm_sub_epi8(data, _mm_set_epi8(42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42+64));
mask &= ~1;
} else {
oData = _mm_sub_epi8(data, _mm_set1_epi8(42));
}
mask |= nextMask;
if (mask != 0) {
// a spec compliant encoder should never generate sequences: ==, =\n and =\r, but we'll handle them to be spec compliant
// the yEnc specification requires any character following = to be unescaped, not skipped over, so we'll deal with that
// firstly, resolve invalid sequences of = to deal with cases like '===='
uint16_t maskEq = _mm_movemask_epi8(cmpEq);
uint16_t tmp = eqFixLUT[(maskEq&0xff) & ~escFirst];
maskEq = (eqFixLUT[(maskEq>>8) & ~(tmp>>7)] << 8) | tmp;
unsigned char oldEscFirst = escFirst;
escFirst = (maskEq >> (sizeof(__m128i)-1));
// next, eliminate anything following a `=` from the special char mask; this eliminates cases of `=\r` so that they aren't removed
maskEq <<= 1;
mask &= ~maskEq;
// unescape chars following `=`
#if defined(__AVX512VL__) && defined(__AVX512BW__)
// GCC < 7 seems to generate rubbish assembly for this
oData = _mm_mask_add_epi8(
oData,
maskEq,
oData,
_mm_set1_epi8(-64)
);
#else
oData = _mm_add_epi8(
oData,
LOAD_HALVES(
eqAddLUT + (maskEq&0xff),
eqAddLUT + ((maskEq>>8)&0xff)
)
);
#endif
// handle \r\n. sequences
// RFC3977 requires the first dot on a line to be stripped, due to dot-stuffing
// find instances of \r\n
__m128i tmpData1, tmpData2, tmpData3, tmpData4;
#if defined(__SSSE3__) && !defined(__tune_btver1__)
if(use_ssse3) {
__m128i nextData = _mm_load_si128((__m128i *)src + 1);
tmpData1 = _mm_alignr_epi8(nextData, data, 1);
tmpData2 = _mm_alignr_epi8(nextData, data, 2);
tmpData3 = _mm_alignr_epi8(nextData, data, 3);
tmpData4 = _mm_alignr_epi8(nextData, data, 4);
} else {
#endif
tmpData1 = _mm_insert_epi16(_mm_srli_si128(data, 1), *(uint16_t*)(src + sizeof(__m128i)-1), 7);
tmpData2 = _mm_insert_epi16(_mm_srli_si128(data, 2), *(uint16_t*)(src + sizeof(__m128i)), 7);
tmpData3 = _mm_insert_epi16(_mm_srli_si128(tmpData1, 2), *(uint16_t*)(src + sizeof(__m128i)+1), 7);
tmpData4 = _mm_insert_epi16(_mm_srli_si128(tmpData2, 2), *(uint16_t*)(src + sizeof(__m128i)+2), 7);
#ifdef __SSSE3__
}
#endif
__m128i matchNl1 = _mm_cmpeq_epi16(data, _mm_set1_epi16(0x0a0d));
__m128i matchNl2 = _mm_cmpeq_epi16(tmpData1, _mm_set1_epi16(0x0a0d));
__m128i matchDots, matchNlDots;
uint16_t killDots;
matchDots = _mm_cmpeq_epi8(tmpData2, _mm_set1_epi8('.'));
// merge preparation (for non-raw, it doesn't matter if this is shifted or not)
matchNl1 = _mm_srli_si128(matchNl1, 1);
// merge matches of \r\n with those for .
#ifdef __AVX512VL__
matchNlDots = _mm_ternarylogic_epi32(matchDots, matchNl1, matchNl2, 0xE0);
#else
matchNlDots = _mm_and_si128(matchDots, _mm_or_si128(matchNl1, matchNl2));
#endif
killDots = _mm_movemask_epi8(matchNlDots);
__m128i cmpB1 = _mm_cmpeq_epi16(tmpData2, _mm_set1_epi16(0x793d)); // "=y"
__m128i cmpB2 = _mm_cmpeq_epi16(tmpData3, _mm_set1_epi16(0x793d));
if(killDots) {
// match instances of \r\n.\r\n and \r\n.=y
__m128i cmpC1 = _mm_cmpeq_epi16(tmpData3, _mm_set1_epi16(0x0a0d)); // "\r\n"
__m128i cmpC2 = _mm_cmpeq_epi16(tmpData4, _mm_set1_epi16(0x0a0d));
cmpC1 = _mm_or_si128(cmpC1, cmpB2);
cmpC2 = _mm_or_si128(cmpC2, _mm_cmpeq_epi16(tmpData4, _mm_set1_epi16(0x793d)));
cmpC2 = _mm_slli_si128(cmpC2, 1);
// prepare cmpB
cmpB1 = _mm_and_si128(cmpB1, matchNl1);
cmpB2 = _mm_and_si128(cmpB2, matchNl2);
// and w/ dots
#ifdef __AVX512VL__
cmpC1 = _mm_ternarylogic_epi32(cmpC1, cmpC2, matchNlDots, 0xA8);
cmpB1 = _mm_ternarylogic_epi32(cmpB1, cmpB2, cmpC1, 0xFE);
#else
cmpC1 = _mm_and_si128(_mm_or_si128(cmpC1, cmpC2), matchNlDots);
cmpB1 = _mm_or_si128(cmpC1, _mm_or_si128(
cmpB1, cmpB2
));
#endif
} else {
#ifdef __AVX512VL__
cmpB1 = _mm_ternarylogic_epi32(cmpB1, matchNl1, _mm_and_si128(cmpB2, matchNl2), 0xEA);
#else
cmpB1 = _mm_or_si128(
_mm_and_si128(cmpB1, matchNl1),
_mm_and_si128(cmpB2, matchNl2)
);
#endif
}
if(_mm_movemask_epi8(cmpB1)) {
// terminator found
// there's probably faster ways to do this, but reverting to scalar code should be good enough
escFirst = oldEscFirst;
dLen += dI;
return;
}
mask |= (killDots << 2) & 0xffff;
nextMask = killDots >> (sizeof(__m128i)-2);
// all that's left is to 'compress' the data (skip over masked chars)
#ifdef __SSSE3__
if(use_ssse3) {
# if defined(__POPCNT__) && (defined(__tune_znver1__) || defined(__tune_btver2__))
unsigned char skipped = _mm_popcnt_u32(mask & 0xff);
# else
unsigned char skipped = BitsSetTable256[mask & 0xff];
# endif
// lookup compress masks and shuffle
// load up two halves
__m128i shuf = LOAD_HALVES(unshufLUT + (mask&0xff), unshufLUT + (mask>>8));
// offset upper half by 8
shuf = _mm_add_epi8(shuf, _mm_set_epi32(0x08080808, 0x08080808, 0, 0));
// shift down upper half into lower
// TODO: consider using `mask & 0xff` in table instead of counting bits
shuf = _mm_shuffle_epi8(shuf, _mm_load_si128((const __m128i*)pshufb_combine_table + skipped));
// shuffle data
oData = _mm_shuffle_epi8(oData, shuf);
STOREU_XMM(p, oData);
// increment output position
# if defined(__POPCNT__) && !defined(__tune_btver1__)
p += XMM_SIZE - _mm_popcnt_u32(mask);
# else
p += XMM_SIZE - skipped - BitsSetTable256[mask >> 8];
# endif
} else {
#endif
alignas(32) uint32_t mmTmp[4];
_mm_store_si128((__m128i*)mmTmp, oData);
for(int j=0; j<4; j++) {
if(mask & 0xf) {
unsigned char* pMmTmp = (unsigned char*)(mmTmp + j);
unsigned int maskn = ~mask;
*p = pMmTmp[0];
p += (maskn & 1);
*p = pMmTmp[1];
p += (maskn & 2) >> 1;
*p = pMmTmp[2];
p += (maskn & 4) >> 2;
*p = pMmTmp[3];
p += (maskn & 8) >> 3;
} else {
*(uint32_t*)p = mmTmp[j];
p += 4;
}
mask >>= 4;
}
#ifdef __SSSE3__
}
#endif
} else {
STOREU_XMM(p, oData);
p += XMM_SIZE;
escFirst = 0;
nextMask = 0;
}
}
}
#endif
#ifdef __ARM_NEON
inline uint16_t neon_movemask(uint8x16_t in) {
uint8x16_t mask = vandq_u8(in, (uint8x16_t){1,2,4,8,16,32,64,128, 1,2,4,8,16,32,64,128});
# if defined(__aarch64__)
return (vaddv_u8(vget_high_u8(mask)) << 8) | vaddv_u8(vget_low_u8(mask));
# else
uint8x8_t res = vpadd_u8(vget_low_u8(mask), vget_high_u8(mask));
res = vpadd_u8(res, res);
res = vpadd_u8(res, res);
return vget_lane_u16(vreinterpret_u16_u8(res), 0);
# endif
}
uint8_t eqFixLUT[256];
alignas(32) uint8x8_t eqAddLUT[256];
alignas(32) uint8x8_t unshufLUT[256];
static inline void do_decode_neon(size_t& dLen, const uint8_t* dSrc, unsigned char*& p, unsigned char& escFirst, uint16_t& nextMask) {
long dI = -(long)dLen;
for(; dI; dI += sizeof(uint8x16_t)) {
const uint8_t* src = dSrc + dI;
uint8x16_t data = vld1q_u8(src);
// search for special chars
uint8x16_t cmpEq = vceqq_u8(data, vdupq_n_u8('=')),
cmp = vorrq_u8(
vorrq_u8(
vceqq_u8(data, vreinterpretq_u8_u16(vdupq_n_u16(0x0a0d))), // \r\n
vceqq_u8(data, vreinterpretq_u8_u16(vdupq_n_u16(0x0d0a))) // \n\r
),
cmpEq
);
uint16_t mask = neon_movemask(cmp); // not the most accurate mask if we have invalid sequences; we fix this up later
uint8x16_t oData;
if(escFirst) { // rarely hit branch: seems to be faster to use 'if' than a lookup table, possibly due to values being able to be held in registers?
// first byte needs escaping due to preceeding = in last loop iteration
oData = vsubq_u8(data, (uint8x16_t){42+64,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42});
mask &= ~1;
} else {
oData = vsubq_u8(data, vdupq_n_u8(42));
}
mask |= nextMask;
if (mask != 0) {
// a spec compliant encoder should never generate sequences: ==, =\n and =\r, but we'll handle them to be spec compliant
// the yEnc specification requires any character following = to be unescaped, not skipped over, so we'll deal with that
// firstly, resolve invalid sequences of = to deal with cases like '===='
uint16_t maskEq = neon_movemask(cmpEq);
uint16_t tmp = eqFixLUT[(maskEq&0xff) & ~escFirst];
maskEq = (eqFixLUT[(maskEq>>8) & ~(tmp>>7)] << 8) | tmp;
unsigned char oldEscFirst = escFirst;
escFirst = (maskEq >> (sizeof(uint8x16_t)-1));
// next, eliminate anything following a `=` from the special char mask; this eliminates cases of `=\r` so that they aren't removed
maskEq <<= 1;
mask &= ~maskEq;
// unescape chars following `=`
oData = vaddq_u8(
oData,
vcombine_u8(
vld1_u8((uint8_t*)(eqAddLUT + (maskEq&0xff))),
vld1_u8((uint8_t*)(eqAddLUT + ((maskEq>>8)&0xff)))
)
);
// handle \r\n. sequences
// RFC3977 requires the first dot on a line to be stripped, due to dot-stuffing
// find instances of \r\n
uint8x16_t tmpData1, tmpData2, tmpData3, tmpData4;
uint8x16_t nextData = vld1q_u8(src + sizeof(uint8x16_t));
tmpData1 = vextq_u8(data, nextData, 1);
tmpData2 = vextq_u8(data, nextData, 2);
tmpData3 = vextq_u8(data, nextData, 3);
tmpData4 = vextq_u8(data, nextData, 4);
uint8x16_t matchNl1 = vreinterpretq_u8_u16(vceqq_u16(vreinterpretq_u16_u8(data), vdupq_n_u16(0x0a0d)));
uint8x16_t matchNl2 = vreinterpretq_u8_u16(vceqq_u16(vreinterpretq_u16_u8(tmpData1), vdupq_n_u16(0x0a0d)));
uint8x16_t matchDots, matchNlDots;
uint16_t killDots;
matchDots = vceqq_u8(tmpData2, vdupq_n_u8('.'));
// merge preparation (for non-raw, it doesn't matter if this is shifted or not)
matchNl1 = vextq_u8(matchNl1, vdupq_n_u8(0), 1);
// merge matches of \r\n with those for .
matchNlDots = vandq_u8(matchDots, vorrq_u8(matchNl1, matchNl2));
killDots = neon_movemask(matchNlDots);
uint8x16_t cmpB1 = vreinterpretq_u8_u16(vceqq_u16(vreinterpretq_u16_u8(tmpData2), vdupq_n_u16(0x793d))); // "=y"
uint8x16_t cmpB2 = vreinterpretq_u8_u16(vceqq_u16(vreinterpretq_u16_u8(tmpData3), vdupq_n_u16(0x793d)));
if(killDots) {
// match instances of \r\n.\r\n and \r\n.=y
uint8x16_t cmpC1 = vreinterpretq_u8_u16(vceqq_u16(vreinterpretq_u16_u8(tmpData3), vdupq_n_u16(0x0a0d)));
uint8x16_t cmpC2 = vreinterpretq_u8_u16(vceqq_u16(vreinterpretq_u16_u8(tmpData4), vdupq_n_u16(0x0a0d)));
cmpC1 = vorrq_u8(cmpC1, cmpB2);
cmpC2 = vorrq_u8(cmpC2, vreinterpretq_u8_u16(vceqq_u16(vreinterpretq_u16_u8(tmpData4), vdupq_n_u16(0x793d))));
cmpC2 = vextq_u8(vdupq_n_u8(0), cmpC2, 15);
cmpC1 = vorrq_u8(cmpC1, cmpC2);
// and w/ dots
cmpC1 = vandq_u8(cmpC1, matchNlDots);
// then merge w/ cmpB
cmpB1 = vandq_u8(cmpB1, matchNl1);
cmpB2 = vandq_u8(cmpB2, matchNl2);
cmpB1 = vorrq_u8(cmpC1, vorrq_u8(
cmpB1, cmpB2
));
} else {
cmpB1 = vorrq_u8(
vandq_u8(cmpB1, matchNl1),
vandq_u8(cmpB2, matchNl2)
);
}
#ifdef __aarch64__
if(vget_lane_u64(vreinterpret_u64_u32(vqmovn_u64(vreinterpretq_u64_u8(cmpB1))), 0))
#else
uint32x4_t tmp1 = vreinterpretq_u32_u8(cmpB1);
uint32x2_t tmp2 = vorr_u32(vget_low_u32(tmp1), vget_high_u32(tmp1));
if(vget_lane_u32(vpmax_u32(tmp2, tmp2), 0))
#endif
{
// terminator found
// there's probably faster ways to do this, but reverting to scalar code should be good enough
escFirst = oldEscFirst;
dLen += dI;
return;
}
mask |= (killDots << 2) & 0xffff;
nextMask = killDots >> (sizeof(uint8x16_t)-2);
// all that's left is to 'compress' the data (skip over masked chars)
unsigned char skipped = BitsSetTable256[mask & 0xff];
// lookup compress masks and shuffle
oData = vcombine_u8(
vtbl1_u8(vget_low_u8(oData), vld1_u8((uint8_t*)(unshufLUT + (mask&0xff)))),
vtbl1_u8(vget_high_u8(oData), vld1_u8((uint8_t*)(unshufLUT + (mask>>8))))
);
// compact down
uint8x16_t compact = vld1q_u8(pshufb_combine_table + skipped*sizeof(uint8x16_t));
#ifdef __aarch64__
oData = vqtbl1q_u8(oData, compact);
#else
uint8x8x2_t dataH = {vget_low_u8(oData), vget_high_u8(oData)};
oData = vcombine_u8(vtbl2_u8(dataH, vget_low_u8(compact)),
vtbl2_u8(dataH, vget_high_u8(compact)));
#endif
vst1q_u8(p, oData);
// increment output position
p += sizeof(uint8x16_t) - skipped - BitsSetTable256[mask >> 8];
} else {
vst1q_u8(p, oData);
p += sizeof(uint8x16_t);
escFirst = 0;
nextMask = 0;
}
}
}
#endif
void decoder_init() {
#ifdef __SSE2__
for(int i=0; i<256; i++) {
int k = i;
uint8_t res[8];
int p = 0;
// fix LUT
k = i;
p = 0;
for(int j=0; j<8; j++) {
k = i >> j;
if(k & 1) {
p |= 1 << j;
j++;
}
}
eqFixLUT[i] = p;
// sub LUT
k = i;
for(int j=0; j<8; j++) {
res[j] = (k & 1) ? 192 /* == -64 */ : 0;
k >>= 1;
}
_mm_storel_epi64((__m128i*)(eqAddLUT + i), _mm_loadl_epi64((__m128i*)res));
}
#endif
#ifdef __SSSE3__
// generate unshuf LUT
for(int i=0; i<256; i++) {
int k = i;
uint8_t res[8];
int p = 0;
for(int j=0; j<8; j++) {
if(!(k & 1)) {
res[p++] = j;
}
k >>= 1;
}
for(; p<8; p++)
res[p] = 0;
_mm_storel_epi64((__m128i*)(unshufLUT + i), _mm_loadl_epi64((__m128i*)res));
}
#endif
#ifdef __ARM_NEON
for(int i=0; i<256; i++) {
int k = i;
uint8_t res[8];
int p = 0;
// fix LUT
k = i;
p = 0;
for(int j=0; j<8; j++) {
k = i >> j;
if(k & 1) {
p |= 1 << j;
j++;
}
}
eqFixLUT[i] = p;
// sub LUT
k = i;
for(int j=0; j<8; j++) {
res[j] = (k & 1) ? 192 /* == -64 */ : 0;
k >>= 1;
}
vst1_u8((uint8_t*)(eqAddLUT + i), vld1_u8(res));
k = i;
p = 0;
for(int j=0; j<8; j++) {
if(!(k & 1)) {
res[p++] = j;
}
k >>= 1;
}
for(; p<8; p++)
res[p] = 0;
vst1_u8((uint8_t*)(unshufLUT + i), vld1_u8(res));
}
#endif
}
#endif

129
lib/yencode/SimdInit.cpp Normal file
View File

@@ -0,0 +1,129 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* Copyright (C) 2017 Anime Tosho (animetosho)
* Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nzbget.h"
#if (defined(__i686__) || defined(__amd64__)) && !defined(WIN32)
#include <cpuid.h>
#endif
#include "YEncode.h"
namespace YEncode
{
int (*decode)(const unsigned char**, unsigned char**, size_t, YencDecoderState*) = nullptr;
extern void init_decode_scalar();
bool decode_simd = false;
void (*crc_init)(crc_state *const s) = nullptr;
void (*crc_incr)(crc_state *const s, const unsigned char *src, long len) = nullptr;
uint32_t (*crc_finish)(crc_state *const s) = nullptr;
extern void init_crc_slice();
bool crc_simd = false;
#if defined(__i686__) || defined(__amd64__)
extern void init_decode_sse2();
extern void init_decode_ssse3();
extern void init_crc_pclmul();
class CpuId
{
uint32_t regs[4];
public:
CpuId(unsigned level)
{
#ifdef WIN32
__cpuid((int *)regs, (int)level);
#else
__cpuid(level, regs[0], regs[1], regs[2], regs[3]);
#endif
}
const uint32_t &EAX() const {return regs[0];}
const uint32_t &EBX() const {return regs[1];}
const uint32_t &ECX() const {return regs[2];}
const uint32_t &EDX() const {return regs[3];}
};
#endif
#if defined(__arm__) || defined(__aarch64__)
extern void init_decode_neon();
extern void init_crc_acle();
#endif
void init()
{
init_decode_scalar();
init_crc_slice();
#if defined(__i686__) || defined(__amd64__)
CpuId cpuid(1);
bool cpu_supports_sse2 = cpuid.EDX() & 0x04000000;
bool cpu_supports_ssse3 = cpuid.ECX() & 0x00000200;
bool cpu_supports_sse41 = cpuid.ECX() & 0x00080000;
bool cpu_supports_pclmul = cpuid.ECX() & 0x00000002;
if (cpu_supports_sse2)
{
init_decode_sse2();
}
if (cpu_supports_ssse3)
{
init_decode_ssse3();
}
if (cpu_supports_sse41 && cpu_supports_pclmul)
{
init_crc_pclmul();
}
#endif
#if defined(__arm__) || defined(__aarch64__)
bool cpu_supports_neon = false;
bool cpu_supports_crc = false;
#ifdef __linux__
if (FILE* file = fopen("/proc/cpuinfo", "r"))
{
char buf[200];
while (fgets(buf, sizeof(buf), file))
{
cpu_supports_neon |= !strncasecmp(buf, "Features", 8) &&
(strstr(buf, " neon ") || strstr(buf, " asimd "));
cpu_supports_crc |= !strncasecmp(buf, "Features", 8) && strstr(buf, " crc32 ");
}
fclose(file);
}
#endif
if (cpu_supports_neon)
{
init_decode_neon();
}
if (cpu_supports_crc)
{
init_crc_acle();
}
#endif
}
}

227
lib/yencode/SliceCrc.cpp Normal file
View File

@@ -0,0 +1,227 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nzbget.h"
#include "YEncode.h"
namespace YEncode
{
// Crc32 implementation:
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
static uint32_t crc32_tab[4][256] =
{
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
},
{
0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3, 0x646CC504, 0x7D77F445, 0x565AA786, 0x4F4196C7,
0xC8D98A08, 0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB, 0xACB54F0C, 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF,
0x4AC21251, 0x53D92310, 0x78F470D3, 0x61EF4192, 0x2EAED755, 0x37B5E614, 0x1C98B5D7, 0x05838496,
0x821B9859, 0x9B00A918, 0xB02DFADB, 0xA936CB9A, 0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E,
0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761, 0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265,
0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69, 0x39316BAE, 0x202A5AEF, 0x0B07092C, 0x121C386D,
0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530, 0xBB2AF3F7, 0xA231C2B6, 0x891C9175, 0x9007A034,
0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38, 0x73F379FF, 0x6AE848BE, 0x41C51B7D, 0x58DE2A3C,
0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6, 0x94158A01, 0x8D0EBB40, 0xA623E883, 0xBF38D9C2,
0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE, 0x5CCC0009, 0x45D73148, 0x6EFA628B, 0x77E153CA,
0xBABB5D54, 0xA3A06C15, 0x888D3FD6, 0x91960E97, 0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93,
0x7262D75C, 0x6B79E61D, 0x4054B5DE, 0x594F849F, 0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B,
0x65FD6BA7, 0x7CE65AE6, 0x57CB0925, 0x4ED03864, 0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60,
0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C, 0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768,
0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35, 0x4B53BCF2, 0x52488DB3, 0x7965DE70, 0x607EEF31,
0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D, 0x838A36FA, 0x9A9107BB, 0xB1BC5478, 0xA8A76539,
0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88, 0x5FEF5D4F, 0x46F46C0E, 0x6DD93FCD, 0x74C20E8C,
0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180, 0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484,
0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9, 0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD,
0xB9980012, 0xA0833153, 0x8BAE6290, 0x92B553D1, 0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5,
0xAE07BCE9, 0xB71C8DA8, 0x9C31DE6B, 0x852AEF2A, 0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E,
0x66DE36E1, 0x7FC507A0, 0x54E85463, 0x4DF36522, 0x02B2F3E5, 0x1BA9C2A4, 0x30849167, 0x299FA026,
0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B, 0x80A96BBC, 0x99B25AFD, 0xB29F093E, 0xAB84387F,
0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773, 0x4870E1B4, 0x516BD0F5, 0x7A468336, 0x635DB277,
0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D, 0xAF96124A, 0xB68D230B, 0x9DA070C8, 0x84BB4189,
0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85, 0x674F9842, 0x7E54A903, 0x5579FAC0, 0x4C62CB81,
0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC, 0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8,
0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4, 0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0,
0x5E7EF3EC, 0x4765C2AD, 0x6C48916E, 0x7553A02F, 0x3A1236E8, 0x230907A9, 0x0824546A, 0x113F652B,
0x96A779E4, 0x8FBC48A5, 0xA4911B66, 0xBD8A2A27, 0xF2CBBCE0, 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23,
0x14BCE1BD, 0x0DA7D0FC, 0x268A833F, 0x3F91B27E, 0x70D024B9, 0x69CB15F8, 0x42E6463B, 0x5BFD777A,
0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876, 0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72,
},
{
0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59, 0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, 0x054F1685,
0x0E1351B8, 0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1, 0x091AF964, 0x08D89353, 0x0A9E2D0A, 0x0B5C473D,
0x1C26A370, 0x1DE4C947, 0x1FA2771E, 0x1E601D29, 0x1B2F0BAC, 0x1AED619B, 0x18ABDFC2, 0x1969B5F5,
0x1235F2C8, 0x13F798FF, 0x11B126A6, 0x10734C91, 0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D,
0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9, 0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065,
0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901, 0x3157BF84, 0x3095D5B3, 0x32D36BEA, 0x331101DD,
0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9, 0x23624D4C, 0x22A0277B, 0x20E69922, 0x2124F315,
0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71, 0x2D711CF4, 0x2CB376C3, 0x2EF5C89A, 0x2F37A2AD,
0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399, 0x7793251C, 0x76514F2B, 0x7417F172, 0x75D59B45,
0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221, 0x798074A4, 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD,
0x6CBC2EB0, 0x6D7E4487, 0x6F38FADE, 0x6EFA90E9, 0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835,
0x62AF7F08, 0x636D153F, 0x612BAB66, 0x60E9C151, 0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D,
0x48D7CB20, 0x4915A117, 0x4B531F4E, 0x4A917579, 0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5,
0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1, 0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D,
0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609, 0x53F8C08C, 0x523AAABB, 0x507C14E2, 0x51BE7ED5,
0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1, 0x5DEB9134, 0x5C29FB03, 0x5E6F455A, 0x5FAD2F6D,
0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9, 0xE63CB35C, 0xE7FED96B, 0xE5B86732, 0xE47A0D05,
0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461, 0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD,
0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9, 0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75,
0xF300E948, 0xF2C2837F, 0xF0843D26, 0xF1465711, 0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD,
0xD9785D60, 0xD8BA3757, 0xDAFC890E, 0xDB3EE339, 0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5,
0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6, 0xD52DB281, 0xD062A404, 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D,
0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049, 0xC25756CC, 0xC3953CFB, 0xC1D382A2, 0xC011E895,
0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1, 0xCC440774, 0xCD866D43, 0xCFC0D31A, 0xCE02B92D,
0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819, 0x96A63E9C, 0x976454AB, 0x9522EAF2, 0x94E080C5,
0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1, 0x98B56F24, 0x99770513, 0x9B31BB4A, 0x9AF3D17D,
0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69, 0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5,
0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1, 0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D,
0xA9E2D0A0, 0xA820BA97, 0xAA6604CE, 0xABA46EF9, 0xAEEB787C, 0xAF29124B, 0xAD6FAC12, 0xACADC625,
0xA7F18118, 0xA633EB2F, 0xA4755576, 0xA5B73F41, 0xA0F829C4, 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D,
0xB5C473D0, 0xB40619E7, 0xB640A7BE, 0xB782CD89, 0xB2CDDB0C, 0xB30FB13B, 0xB1490F62, 0xB08B6555,
0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31, 0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED,
},
{
0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE, 0x8F629757, 0x37DEF032, 0x256B5FDC, 0x9DD738B9,
0xC5B428EF, 0x7D084F8A, 0x6FBDE064, 0xD7018701, 0x4AD6BFB8, 0xF26AD8DD, 0xE0DF7733, 0x58631056,
0x5019579F, 0xE8A530FA, 0xFA109F14, 0x42ACF871, 0xDF7BC0C8, 0x67C7A7AD, 0x75720843, 0xCDCE6F26,
0x95AD7F70, 0x2D111815, 0x3FA4B7FB, 0x8718D09E, 0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9,
0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0, 0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787,
0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F, 0xEAE41086, 0x525877E3, 0x40EDD80D, 0xF851BF68,
0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F, 0x7F496FF6, 0xC7F50893, 0xD540A77D, 0x6DFCC018,
0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0, 0xBAFD4719, 0x0241207C, 0x10F48F92, 0xA848E8F7,
0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3, 0x1476CF6A, 0xACCAA80F, 0xBE7F07E1, 0x06C36084,
0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C, 0xD1C2E785, 0x697E80E0, 0x7BCB2F0E, 0xC377486B,
0xCB0D0FA2, 0x73B168C7, 0x6104C729, 0xD9B8A04C, 0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B,
0x0EB9274D, 0xB6054028, 0xA4B0EFC6, 0x1C0C88A3, 0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4,
0x3B26F703, 0x839A9066, 0x912F3F88, 0x299358ED, 0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA,
0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002, 0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755,
0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72, 0xE45D37CB, 0x5CE150AE, 0x4E54FF40, 0xF6E89825,
0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D, 0x21E91F24, 0x99557841, 0x8BE0D7AF, 0x335CB0CA,
0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5, 0x623B216C, 0xDA874609, 0xC832E9E7, 0x708E8E82,
0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A, 0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D,
0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A, 0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D,
0x78F4C94B, 0xC048AE2E, 0xD2FD01C0, 0x6A4166A5, 0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2,
0x4D6B1905, 0xF5D77E60, 0xE762D18E, 0x5FDEB6EB, 0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC,
0x88DF31EA, 0x3063568F, 0x22D6F961, 0x9A6A9E04, 0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, 0x15080953,
0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174, 0x9210D9CD, 0x2AACBEA8, 0x38191146, 0x80A57623,
0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B, 0x57A4F122, 0xEF189647, 0xFDAD39A9, 0x45115ECC,
0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8, 0xF92F7951, 0x41931E34, 0x5326B1DA, 0xEB9AD6BF,
0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907, 0x3C9B51BE, 0x842736DB, 0x96929935, 0x2E2EFE50,
0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677, 0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120,
0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98, 0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF,
0xD67F4138, 0x6EC3265D, 0x7C7689B3, 0xC4CAEED6, 0x591DD66F, 0xE1A1B10A, 0xF3141EE4, 0x4BA87981,
0x13CB69D7, 0xAB770EB2, 0xB9C2A15C, 0x017EC639, 0x9CA9FE80, 0x241599E5, 0x36A0360B, 0x8E1C516E,
0x866616A7, 0x3EDA71C2, 0x2C6FDE2C, 0x94D3B949, 0x090481F0, 0xB1B8E695, 0xA30D497B, 0x1BB12E1E,
0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6, 0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1,
}
};
void crc_slice_init(crc_state *const s)
{
s->crc0[0] = ~0;
}
// compute CRC32 (Slicing-by-4 algorithm)
void crc_slice(crc_state *const s, const unsigned char *src, long len)
{
uint32_t crc = s->crc0[0];
#if __BYTE_ORDER == __LITTLE_ENDIAN
// process first 1-3 bytes until input is aligned to 4 bytes
if ((uintptr_t)src & 3 && len >= 4)
{
int unaligned = 4 - (uintptr_t)src % 4;
while (unaligned-- != 0)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_tab[0][(crc ^ *src++) & 0xFF];
len--;
}
}
const uint32_t* current = (const uint32_t*)src;
// process four bytes at once (Slicing-by-4)
while (len >= 4)
{
uint32_t one = *current++ ^ crc;
crc = crc32_tab[0][(one >> 24) & 0xFF] ^
crc32_tab[1][(one >> 16) & 0xFF] ^
crc32_tab[2][(one >> 8) & 0xFF] ^
crc32_tab[3][one & 0xFF];
len -= 4;
}
// remaining 1 to 3 bytes (standard algorithm)
src = (uchar*)current;
#endif
while (len-- != 0)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_tab[0][(crc ^ *src++) & 0xFF];
}
s->crc0[0] = crc;
}
uint32_t crc_slice_finish(crc_state *const s)
{
return ~s->crc0[0];
}
void init_crc_slice()
{
crc_init = &crc_slice_init;
crc_incr = &crc_slice;
crc_finish = &crc_slice_finish;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* Copyright (C) 2017 Anime Tosho (animetosho)
* Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nzbget.h"
#include "YEncode.h"
#ifdef __SSE2__
#include <immintrin.h>
#endif
namespace YEncode
{
namespace Sse2
{
#ifdef __SSE2__
#define SIMD_DECODER
#include "SimdDecoder.cpp"
#endif
}
void init_decode_sse2() {
#ifdef __SSE2__
decode = &YEncode::Sse2::do_decode_simd<sizeof(__m128i), YEncode::Sse2::do_decode_sse<false>>;
YEncode::Sse2::decoder_init();
decode_simd = true;
#endif
}
}

View File

@@ -0,0 +1,50 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* Copyright (C) 2017 Anime Tosho (animetosho)
* Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nzbget.h"
#include "YEncode.h"
#ifdef __SSSE3__
#include <immintrin.h>
#endif
namespace YEncode
{
namespace Ssse3
{
#ifdef __SSSE3__
#define SIMD_DECODER
#include "SimdDecoder.cpp"
#endif
}
void init_decode_ssse3() {
#ifdef __SSSE3__
decode = &YEncode::Ssse3::do_decode_simd<sizeof(__m128i), YEncode::Ssse3::do_decode_sse<true>>;
YEncode::Ssse3::decoder_init();
decode_simd = true;
#endif
}
}

61
lib/yencode/YEncode.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* Based on node-yencode library by Anime Tosho:
* https://github.com/animetosho/node-yencode
*
* Copyright (C) 2017 Anime Tosho (animetosho)
* Copyright (C) 2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef YENCODE_H
#define YENCODE_H
namespace YEncode
{
void init();
typedef enum : char {
YDEC_STATE_CRLF, // default
YDEC_STATE_EQ,
YDEC_STATE_CR,
YDEC_STATE_NONE,
YDEC_STATE_CRLFDT,
YDEC_STATE_CRLFDTCR,
YDEC_STATE_CRLFEQ // may actually be "\r\n.=" in raw decoder
} YencDecoderState;
extern int (*decode)(const unsigned char** src, unsigned char** dest, size_t len, YencDecoderState* state);
extern int decode_scalar(const unsigned char** src, unsigned char** dest, size_t len, YencDecoderState* state);
extern bool decode_simd;
struct crc_state
{
#if defined(__i686__) || defined(__amd64__)
alignas(16) uint32_t crc0[4 * 5];
#else
uint32_t crc0[1];
#endif
};
extern void (*crc_init)(crc_state *const s);
extern void (*crc_incr)(crc_state *const s, const unsigned char *src, long len);
extern uint32_t (*crc_finish)(crc_state *const s);
extern bool crc_simd;
}
#endif

View File

@@ -30,15 +30,17 @@ Building toolchains
output - to store the results of build script;
setup - for extra files required for installer;
4. Build buildroot-toolchain for one CPU-architecture (see below);
4.1. Download Buildroot distribution archive from http://buildroot.uclibc.org/download.html
(currently using version "buildroot-2015.08.01");
4.2. Unpack the tarball into 'toolchain'-directory;
4.3. Rename the buildroot-directory according to the target CPU-architecture name;
Be careful here, after the toolchain is built the directory cannot be renamed
or moved, you will have to rebuild the toolchain if you want another name;
4.4. Run 'make nconfig';
4.5. Configure toolchain:
4. Build buildroot-toolchain for one CPU-architecture:
4.1. Download Buildroot distribution archive 'buildroot-2015.08.01' from
http://buildroot.uclibc.org/download.html.
If you choose other version the instructions may not apply exactly;
4.2. Unpack the tarball into 'toolchain'-directory;
4.3. Rename the buildroot-directory according to the target CPU-architecture name,
for example 'x86_64' or 'armhf'; Be careful here, after the toolchain is
built the directory cannot be renamed or moved, you will have to rebuild
the toolchain if you want another name;
4.4. Run 'make menuconfig';
4.5. Configure toolchain:
- Target architecture:
- choose your target architecture;
- Build options:
@@ -47,7 +49,8 @@ Building toolchains
- Kernel Headers (Manually specified Linux version);
- (2.6.32) linux version;
- Custom kernel headers series (2.6.x);
- uClibc C library Version (uClibc-ng);
- C library: glibc (for x86_64 and armhf) or uClibc (for all other architectures);
- uClibc library version (uClibc-ng);
- Enable large file (files > 2 GB) support;
- Enable IPv6 support;
- Enable toolchain locale/i18n support;
@@ -61,15 +64,44 @@ Building toolchains
- JSON/XML: libxml2;
- Text and terminal handling: ncurses;
- Save configuration and exit;
4.6. Do few extra manual adjustments:
- in the file '.config' in the buildroot directory activate define to
build 'ubacktrace';
4.6. Do few extra manual adjustments:
- in 'packages/ncurses/ncurses.mk' add extra configure parameters to
option 'NCURSES_CONF_OPTS (without quotation marks):
option 'NCURSES_CONF_OPTS (with quotation marks):
"--with-fallbacks=xterm xterm-color xterm-256color xterm-16color linux vt100 vt200";
- in 'packages/openssl/openssl.mk' replace 'zlib-dynamic' with 'zlib';
4.7. Run 'make' to build the toolchain. It may take an hour or so depending
on your hardware;
- in 'packages/glibc/glibc.mk' add extra configure parameter
'--enable-static-nss';
- in directory 'packages/glibc/2.20' create new file with name 'allocatestack-pax.patch'
with the following content; the patch fixes incompatibility with hardened kernels:
>>> START OF 'allocatestack-pax.patch' - this line marker is not part of the file >>>
--- a/nptl/allocatestack.c 2014-09-07 10:09:09.000000000 +0200
+++ b/nptl/allocatestack.c 2017-11-02 18:02:47.165016000 +0100
@@ -78,6 +78,7 @@
#ifndef STACK_ALIGN
# define STACK_ALIGN __alignof__ (long double)
#endif
+#define PF_X 0
/* Default value for minimal stack size after allocating thread
descriptor and guard. */
<<< END OF 'allocatestack-pax.patch' - this line marker is not part of the file <<<
4.7. Run 'make' to build the toolchain. It may take an hour or less depending
on your hardware;
4.8. If C library 'glibc' was chosen extra steps are needed to build proper
static libraries of OpenSSL in addition to already built dynamic
libraries (which are also required):
- delete directory 'output/build/openssl-x.x.x';
- in 'packages/openssl/openssl.mk' replace
'$(if $(BR2_STATIC_LIBS),no-shared,shared)' with
'$(if $(BR2_STATIC_LIBS),no-shared,no-shared)'
and replace '$(if $(BR2_STATIC_LIBS),no-dso,dso)' with
'$(if $(BR2_STATIC_LIBS),no-dso,no-dso)';
- from root directory of toolchain run 'make' again;
- openssl will be rebuilt without shared libraries support;
- installation step of openssl fails with message:
"chmod: cannot access ../lib/engines/lib*.so: No such file or directory";
- ignore the error, static libraries of openssl are already installed
and will be used by NZBGet;
5. Now you should have a working toolchain for one CPU-architecture, let's
test it.

View File

@@ -29,6 +29,7 @@ ALLTARGETS="dist i686 x86_64 armel armhf mipsel mipseb ppc6xx ppc500 x86_64-bsd"
ROOT=`pwd`
ROOTPATH=$PATH
OUTPUTDIR=$ROOT/output
CROSSCLANG="clang-4.0"
# Configuration
BUILD=no
@@ -246,15 +247,9 @@ ConstructArchParams()
mipseb)
ARCH=mips
;;
armhf)
ARCH=arm
;;
arm*)
ARCH=arm
;;
ppc500)
ARCH=powerpc
;;
ppc*)
ARCH=powerpc
;;
@@ -263,15 +258,16 @@ ConstructArchParams()
TOOLCHAIN_ROOT=$ROOT/toolchain/$TARGET$PLATSUFF
TOOLPATH=$TOOLCHAIN_ROOT/output/host/usr/bin
PATH=$TOOLPATH:$ROOTPATH
STAGING="$TOOLCHAIN_ROOT/output/staging/usr"
STAGING="$TOOLCHAIN_ROOT/output/staging"
case $PLATFORM in
linux)
TOOLKIND=buildroot
TOOLNAME=linux
;;
freebsd)
TOOLKIND=crossgcc
TOOLNAME=pc-freebsd9
TOOLKIND=crossclang
TOOLNAME=pc-freebsd
SYSROOT="$TOOLCHAIN_ROOT/sysroot"
;;
esac
}
@@ -288,11 +284,16 @@ ConfigureTarget()
DEBUG="-g"
fi
LUBACKTRACE=""
if [ -f "$STAGING/lib/libubacktrace.so.1" ] ; then
LUBACKTRACE="-lubacktrace"
fi
case "$TOOLKIND-$CONFIG" in
buildroot-debug|buildroot-debug-strip)
LDFLAGS="-static $STRIP" \
CXXFLAGS="-std=c++14 -g -fasynchronous-unwind-tables" \
LIBS="-lcrypto -ldl -lz -lubacktrace" \
LIBS="-lcrypto -ldl -lz $LUBACKTRACE" \
./configure --disable-dependency-tracking --host=$ARCH-$TOOLNAME --enable-debug
;;
buildroot-release|buildroot-release-nostrip)
@@ -301,17 +302,19 @@ ConfigureTarget()
LIBS="-lcrypto -ldl -lz" \
./configure --disable-dependency-tracking --host=$ARCH-$TOOLNAME
;;
crossgcc-debug|crossgcc-debug-strip)
LDFLAGS="-static $STRIP" \
CXXFLAGS="-std=c++14 -g -fasynchronous-unwind-tables -I$STAGING/include" \
PKG_CONFIG_LIBDIR="$STAGING/lib/pkgconfig" \
crossclang-debug|crossclang-debug-strip)
CXX="$CROSSCLANG" \
LDFLAGS="-static $STRIP -fuse-ld=lld --target=$ARCH-$TOOLNAME -lc++ -lm --sysroot=$SYSROOT" \
CXXFLAGS="-g --target=$ARCH-$TOOLNAME --sysroot=$SYSROOT -I$SYSROOT/usr/include/c++/v1" \
PKG_CONFIG_LIBDIR="$STAGING/usr/lib/pkgconfig" \
./configure --disable-dependency-tracking --host=$ARCH-$TOOLNAME --enable-debug
;;
crossgcc-release|crossgcc-release-nostrip)
LDFLAGS="-static $STRIP" \
CXXFLAGS="-std=c++14 -O2 $DEBUG -I$STAGING/include" \
PKG_CONFIG_LIBDIR="$STAGING/lib/pkgconfig" \
./configure --disable-dependency-tracking --host=$ARCH-$TOOLNAME
crossclang-release|crossclang-release-nostrip)
CXX="$CROSSCLANG" \
LDFLAGS="-static $STRIP -fuse-ld=lld --target=$ARCH-$TOOLNAME -lc++ -lm --sysroot=$SYSROOT" \
CXXFLAGS="-O2 $DEBUG --target=$ARCH-$TOOLNAME --sysroot=$SYSROOT -I$SYSROOT/usr/include/c++/v1" \
PKG_CONFIG_LIBDIR="$STAGING/usr/lib/pkgconfig" \
./configure --disable-dependency-tracking --host=$ARCH-$TOOLNAME --enable-debug
;;
esac
}
@@ -319,14 +322,14 @@ ConfigureTarget()
PrecompileHeaders()
{
rm -f nzbget.h.gch
if [ $PCH == "yes" ]; then
if [ $PCH == "yes" -a $TOOLKIND != "crossclang" ]; then
OPTIM=""
if [ $CONFIG == "release" -o $CONFIG == "release-nostrip" ]; then
OPTIM="-O2"
fi
$ARCH-$TOOLNAME-g++ -std=c++14 -DHAVE_CONFIG_H \
-I. -I$STAGING/include -I$STAGING/include/libxml2 \
-I. -I$STAGING/usr/include -I$STAGING/usr/include/libxml2 \
-g $OPTIM daemon/main/nzbget.h -o nzbget.h.gch
fi
}

View File

@@ -2,7 +2,7 @@
#
# This file is part of nzbget. See <http://nzbget.net>.
#
# Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
# Copyright (C) 2015-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -29,20 +29,13 @@ set -o errexit
#set -x
GNU_TARGET="x86_64-pc-freebsd9"
TARGET="x86_64-pc-freebsd"
# FreeBSD
FREEBSDIMAGE_URL="ftp://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/amd64/9.1-RELEASE/base.txz"
FREEBSDIMAGE_URL="https://download.freebsd.org/ftp/releases/amd64/10.1-RELEASE/base.txz"
# GCC
GCC_VERSION="5.3.0"
GCC_ARCHIVE="gcc-$GCC_VERSION.tar.bz2"
GCC_URL="ftp://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/$GCC_ARCHIVE"
# Binutils
BINUTILS_VERSION="2.25"
BINUTILS_ARCHIVE="binutils-$BINUTILS_VERSION.tar.bz2"
BINUTILS_URL="ftp://ftp.gnu.org/gnu/binutils/$BINUTILS_ARCHIVE"
# CLANG (must be already installed)
CLANG="clang-4.0"
# Libxml
LIBXML2_VERSION="2.9.2"
@@ -60,6 +53,7 @@ OPENSSL_URL="ftp://ftp.openssl.org/source/old/1.0.2/$OPENSSL_ARCHIVE"
ROOTDIR=`pwd`
rm -rf output
rm -rf sysroot
# Download all required tools
mkdir -p downloads
@@ -67,12 +61,6 @@ cd downloads
if [ ! -f base.txz ]; then
wget $FREEBSDIMAGE_URL
fi
if [ ! -f $GCC_ARCHIVE ]; then
wget $GCC_URL
fi
if [ ! -f $BINUTILS_ARCHIVE ]; then
wget $BINUTILS_URL
fi
if [ ! -f $LIBXML2_ARCHIVE ]; then
wget $LIBXML2_URL
fi
@@ -83,54 +71,50 @@ cd ..
# Creating sysroot for FreeBSD from official FreeBSD installation image.
# Our sysroot contains only a small set of files needed to compile NZBGet and dependent libraries
mkdir -p output/host/usr/$GNU_TARGET/sysroot
cd output/host/usr/$GNU_TARGET/sysroot
tar xvJf ../../../../../downloads/base.txz \
mkdir -p sysroot
cd sysroot
tar xf ../downloads/base.txz \
./lib \
./usr/include \
./usr/lib/crt1.o ./usr/lib/crti.o ./usr/lib/crtn.o ./usr/lib/crtbeginT.o \
./usr/lib/libc.a ./usr/lib/libm.a ./usr/lib/libz.a ./usr/lib/libncurses.a \
./usr/lib/libthr.a
ln -s libthr.a usr/lib/libpthread.a
cd ../../../../..
./usr/lib/crt1.o \
./usr/lib/crtbegin.o \
./usr/lib/crtbeginS.o \
./usr/lib/crtbeginT.o \
./usr/lib/crtend.o \
./usr/lib/crtendS.o \
./usr/lib/crti.o \
./usr/lib/crtn.o \
./usr/lib/libc++.a \
./usr/lib/libc.a \
./usr/lib/libcompiler_rt.a \
./usr/lib/libgcc.a \
./usr/lib/libgcc_eh.a \
./usr/lib/libgcc_s.so \
./usr/lib/libm.a \
./usr/lib/libncurses.a \
./usr/lib/libpthread.a \
./usr/lib/libthr.a \
./usr/lib/libz.a
# fix bad symlink
ln -s -f ../../lib/libgcc_s.so.1 usr/lib/libgcc_s.so
cd ..
mkdir -p output/build && cd output/build
# Unpack everything
tar xvjf ../../downloads/$BINUTILS_ARCHIVE
tar xvjf ../../downloads/$GCC_ARCHIVE
tar xvzf ../../downloads/$LIBXML2_ARCHIVE
tar xvzf ../../downloads/$OPENSSL_ARCHIVE
## Build binutils (5 minutes)
mkdir binutils-build && cd binutils-build
../binutils-$BINUTILS_VERSION/configure --with-gnu-as --with-gnu-ld --disable-libssp --disable-nls --disable-multilib --target=$GNU_TARGET --prefix=$ROOTDIR/output/host/usr --with-sysroot=$ROOTDIR/output/host/usr/$GNU_TARGET/sysroot
make -j 2
make install
cd ..
## Build GCC (30 minutes)
cd gcc-$GCC_VERSION
./contrib/download_prerequisites
rm isl
cd ..
mkdir gcc-build && cd gcc-build
../gcc-$GCC_VERSION/configure --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --disable-bootstrap --without-headers --disable-nls --disable-libssp --disable-libgomp --disable-libmudflap --disable-multilib --disable-decimal-float --disable-libffi --disable-libmudflap --disable-libquadmath --disable-shared --disable-host-shared --disable-multilib --disable-libsanitizer --target=$GNU_TARGET --prefix=$ROOTDIR/output/host/usr --with-sysroot=$ROOTDIR/output/host/usr/$GNU_TARGET/sysroot
make -j 2
make install
cd ..
PATH=$ROOTDIR/output/host/usr/bin:$PATH
tar xf ../../downloads/$LIBXML2_ARCHIVE
tar xf ../../downloads/$OPENSSL_ARCHIVE
# Build libxml2 (2 minutes)
cd libxml2-$LIBXML2_VERSION
./configure --host=$GNU_TARGET --prefix=$ROOTDIR/output/staging/usr --disable-shared --disable-dependency-tracking --without-zlib --without-lzma --without-python
CC="$CLANG" CFLAGS="--target=$TARGET --sysroot=$ROOTDIR/sysroot" LDFLAGS="-fuse-ld=lld -static --target=$TARGET --sysroot=$ROOTDIR/sysroot" ./configure --host=$TARGET --prefix=$ROOTDIR/output/staging/usr --disable-dependency-tracking --without-zlib --without-lzma --without-python --disable-shared
make -j2
make install
cd ..
# Build OpenSSL (5 minutes)
cd openssl-$OPENSSL_VERSION
CC=$GNU_TARGET-gcc LD=$GNU_TARGET-ld AS=$GNU_TARGET-ad AR=$GNU_TARGET-ar ./Configure --prefix=$ROOTDIR/output/staging/usr no-shared no-dso no-hw no-zlib no-unit-test BSD-x86_64
CC="$CLANG --target=$TARGET --sysroot=$ROOTDIR/sysroot" LD="$CLANG -fuse-ld=lld --target=$TARGET --sysroot=$ROOTDIR/sysroot" ./Configure --prefix=$ROOTDIR/output/staging/usr no-shared no-dso no-hw no-zlib no-unit-test BSD-x86_64
make -j2
make install_sw
cd ..

View File

@@ -2,7 +2,7 @@
#
# This file is part of nzbget. See <http://nzbget.net>.
#
# Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
# Copyright (C) 2015-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@ ALLTARGETS="i686 x86_64 armel armhf mipsel mipseb ppc6xx ppc500 x86_64-bsd"
ROOT=`pwd`
OUTPUTDIR=$ROOT/setup
BUILDDIR=temp
CROSSCLANG="clang-4.0"
echo "Usage:"
echo " $(basename $0) [targets] [clean] [unpacker]"
@@ -109,15 +110,18 @@ for TARGET in $TARGETS; do
if [[ $TARGET == *-bsd ]]; then
TARGET="${TARGET%-bsd}"
TOOLNAME=pc-freebsd9
TOOLKIND=crossclang
TOOLNAME=pc-freebsd
SYSROOT="$TOOLCHAIN_ROOT/sysroot"
PLATSUFF="-bsd"
else
TOOLKIND=buildroot
TOOLNAME=linux
PLATSUFF=""
fi
case $TARGET in
mipsel|i?86|x86_64)
mipsel|i?86|x86_64|aarch64)
ARCH=$TARGET
ENDIAN=little
;;
@@ -144,7 +148,7 @@ for TARGET in $TARGETS; do
cd unrar
sed 's:^CXX=:#CXX=:' -i makefile
sed 's:^STRIP=strip:#STRIP=strip:' -i makefile
sed 's:^LDFLAGS=:LDFLAGS=-static :' -i makefile
sed 's:^LDFLAGS=:#LDFLAGS=-static :' -i makefile
sed 's:^CXXFLAGS=-O2:#CXXFLAGS=-O2:' -i makefile
if [ "$ENDIAN" = "big" ]; then
sed 's:^DEFINES=:DEFINES=-DBIG_ENDIAN :' -i makefile
@@ -152,6 +156,7 @@ for TARGET in $TARGETS; do
if [ "$PLATSUFF" != "-bsd" ]; then
sed 's:^DEFINES=:DEFINES=-DUSE_FALLOCATE :' -i makefile
fi
sed 's:setlocale://setlocale:' -i rar.cpp
EXEDIR=
LICENSE=license.txt
@@ -168,6 +173,11 @@ for TARGET in $TARGETS; do
cp makefile.linux_any_cpu_gcc_4.X makefile.machine
sed 's:^CXX=g++:#CXX=g++:' -i makefile.machine
sed 's:^CC=gcc:#CC=gcc:' -i makefile.machine
if [ "$TOOLKIND" == "crossclang" ] ; then
sed 's:^PRE_COMPILED_HEADER=:#PRE_COMPILED_HEADER=:' -i makefile.machine
sed 's:^ALLFLAGS=${OPTFLAGS} -pipe -s:ALLFLAGS=${OPTFLAGS} -pipe ${CPPFLAGS}:' -i makefile.machine
fi
sed 's:setlocale(LC_ALL,"")://setlocale(LC_ALL,""):' -i CPP/myWindows/mySplitCommandLine.cpp
EXEDIR=bin/
LICENSE=DOC/License.txt
@@ -179,12 +189,23 @@ for TARGET in $TARGETS; do
make clean
CXX=$TOOLPATH/$ARCH-$TOOLNAME-g++ \
CC=$TOOLPATH/$ARCH-$TOOLNAME-gcc \
STRIP=$TOOLPATH/$ARCH-$TOOLNAME-strip \
CXXFLAGS=-O2 \
LDFLAGS=-static \
make -j $COREX $BUILDTARGET
if [ "$TOOLKIND" == "crossclang" ] ; then
CXX="$CROSSCLANG" \
CC="$CROSSCLANG" \
LDFLAGS="-static -fuse-ld=lld -lc++ -lm -lpthread --sysroot=$SYSROOT" \
CXXFLAGS="-O2 --target=$ARCH-$TOOLNAME --sysroot=$SYSROOT -I$SYSROOT/usr/include/c++/v1" \
CPPFLAGS="-O2 --target=$ARCH-$TOOLNAME --sysroot=$SYSROOT -I$SYSROOT/usr/include/c++/v1" \
STRIP=strip \
make -j $COREX $BUILDTARGET
else
CXX=$TOOLPATH/$ARCH-$TOOLNAME-g++ \
CC=$TOOLPATH/$ARCH-$TOOLNAME-gcc \
STRIP=$TOOLPATH/$ARCH-$TOOLNAME-strip \
CXXFLAGS=-O2 \
LDFLAGS=-static \
LIBS=-lpthread \
make -j $COREX $BUILDTARGET
fi
cp $EXEDIR$EXENAME ../../setup/$EXENAME-$TARGET$PLATSUFF
cp $LICENSE ../../setup/license-$UNPACKER.txt

View File

@@ -2,7 +2,7 @@
#
# This file is part of nzbget. See <http://nzbget.net>.
#
# Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
# Copyright (C) 2015-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -44,6 +44,7 @@ PRINTEDTITLE=no
JUSTUNPACK=no
UPDATE=no
VERIFY=yes
OS=""
Info()
{
@@ -60,11 +61,12 @@ Error()
ValidArch()
{
LIMARCH=`echo " $ALLARCHS " | sed "s/ $1 //"`
if test " $ALLARCHS " = "$LIMARCH"; then
return 1
fi
return 0
for TARG in $ALLARCHS; do
if test "$TARG" = "$1"; then
return 0
fi
done
return 1
}
PrintArch()
@@ -135,7 +137,7 @@ Verify()
if test "$REQSIZE" != "$ACTSIZE"; then
Error "Corrupted installer package detected: file size mismatch."
fi
# Checking checksum (MD5) of package payload, only if command 'md5sum' is available
ACTMD5=`dd "if=$0" bs=$HEADER skip=1 2>/dev/null | /bin/sh -c md5sum 2>/dev/null | cut -b-32 2>/dev/null | cat`
LEN=${#ACTMD5}
@@ -160,7 +162,7 @@ DetectEndianness()
DetectArch()
{
OS=`uname -s`
if test "(" "$PLATFORM" = "linux" -a "$OS" != "Linux" ")" -o \
if test "(" "$PLATFORM" = "linux" -a "$OS" != "Linux" -a "$OS" != "FreeBSD" ")" -o \
"(" "$PLATFORM" = "freebsd" -a "$OS" != "FreeBSD" ")" ; then
PrintHelp
Error "Operating system ($OS) isn't supported by this installer."
@@ -195,7 +197,7 @@ DetectArch()
esac
fi
if test "$PLATFORM" = "linux"; then
if test "$OS" = "Linux"; then
if test "$ARCH" = ""; then
MIPS=`cat /proc/cpuinfo | sed -n 's/.*:.*\(mips\).*/&/p'`
if test "$MIPS" != ""; then
@@ -258,7 +260,7 @@ Unpack()
rm -f "$OUTDIR/installer.tmp"
fi
# Rename unpacked binaries files and store arch selection
# Rename unpacked binary files and store arch selection
if test "$JUSTUNPACK" = "no" -a "$ARCH" != "all"; then
OLDDIR=`pwd`
cd "$OUTDIR"
@@ -339,6 +341,8 @@ ConfigureLinux()
sed 's:^WriteBuffer=.*:WriteBuffer=1024:' -i nzbget.conf
Info " Increasing par repair buffer (ParBuffer=100)"
sed 's:^ParBuffer=.*:ParBuffer=100:' -i nzbget.conf
Info " Activating direct rename (DirectRename=yes)"
sed 's:^DirectRename=.*:DirectRename=yes:' -i nzbget.conf
elif test $TOTALFREE -gt 25000 -o $MEMFREE -gt 25000 -o $MEMCACHED -gt 25000; then
Info " Increasing write buffer (WriteBuffer=256)"
sed 's:^WriteBuffer=.*:WriteBuffer=256:' -i nzbget.conf
@@ -366,6 +370,8 @@ ConfigureLinux()
sed 's:^ScriptPauseQueue=.*:ScriptPauseQueue=yes:' -i nzbget.conf
else
Info " Simultaneous download and post-processing is on"
Info " Activating direct unpack (DirectUnpack=yes)"
sed 's:^DirectUnpack=.*:DirectUnpack=yes:' -i nzbget.conf
fi
fi
}
@@ -373,7 +379,7 @@ ConfigureLinux()
ConfigureFreeBSD()
{
# Adjusting config file to current system
# No memory check, assuming all supported FreeBSD machines have enough memory
Info " Activating article cache (ArticleCache=100)"
@@ -382,6 +388,10 @@ ConfigureFreeBSD()
sed -i '' 's:^WriteBuffer=.*:WriteBuffer=1024:' nzbget.conf
Info " Increasing par repair buffer (ParBuffer=100)"
sed -i '' 's:^ParBuffer=.*:ParBuffer=100:' nzbget.conf
Info " Activating direct rename (DirectRename=yes)"
sed -i '' 's:^DirectRename=.*:DirectRename=yes:' nzbget.conf
Info " Activating direct unpack (DirectUnpack=yes)"
sed -i '' 's:^DirectUnpack=.*:DirectUnpack=yes:' nzbget.conf
}
Configure()
@@ -392,18 +402,43 @@ Configure()
if test ! -f nzbget.conf; then
cp ./webui/nzbget.conf.template nzbget.conf
if test "$PLATFORM" = "linux"; then
if test "$OS" = "Linux"; then
ConfigureLinux
fi
if test "$PLATFORM" = "freebsd"; then
if test "$OS" = "FreeBSD"; then
ConfigureFreeBSD
fi
QUICKHELP=yes
fi
}
Linux2FreeBSD()
{
if test "$PLATFORM" = "linux" -a "$OS" = "FreeBSD" ; then
# Using Linux installer on FreeBSD machine
if test "$1" = "brand" ; then
Info " Branding Linux binaries for use on FreeBSD"
brandelf -t Linux nzbget
brandelf -t Linux unrar
brandelf -t Linux 7za
fi
if test "$1" = "kernel-check" ; then
MODLINUX=`kldstat | sed -n 's/\(linux.ko\)/\1/p'`
if test "$ARCH" = "x86_64"; then
MODLINUX=`kldstat | sed -n 's/\(linux64.ko\)/\1/p'`
fi
if test "$MODLINUX" = ""; then
Info ""
Info "WARNING: Linux kernel module isn't loaded. See http://nzbget.net/installation-on-freebsd"
fi
fi
fi
}
# ParseCommandLine
while true
do
@@ -501,6 +536,7 @@ ABSOUTDIR=`cd "$OUTDIR"; pwd`
if test "$JUSTUNPACK" = "no"; then
Info "Configuring..."
Configure
Linux2FreeBSD "brand"
Info "Installation completed"
@@ -538,6 +574,7 @@ if test "$JUSTUNPACK" = "no"; then
Info "Successfully installed into $ABSOUTDIR"
fi
Info "For support please visit http://nzbget.net/forum"
Linux2FreeBSD "kernel-check"
else
Info "Unpacked into $ABSOUTDIR"
fi

View File

@@ -85,7 +85,7 @@ LockFile=${MainDir}/nzbget.lock
# Where to store log file, if it needs to be created.
#
# NOTE: See also option <WriteLog>.
LogFile=${DestDir}/nzbget.log
LogFile=${MainDir}/nzbget.log
# Configuration file template.
#
@@ -286,7 +286,7 @@ Server1.Notes=
# IP on which NZBGet server listen and which clients use to contact NZBGet.
#
# It could be a dns-hostname (e. g. "mypc") or an IP address (e. g. "192.168.1.2" or
# "127.0.0.1"). An IP-address is more effective because does not require dns-lookup.
# "127.0.0.1").
#
# Your computer may have multiple network interfaces and therefore multiple IP
# addresses. If you want NZBGet to listen to all interfaces and be available from
@@ -297,6 +297,10 @@ Server1.Notes=
#
# NOTE: If you set the option to "127.0.0.1" you will be able to connect to NZBGet
# only from the computer running NZBGet. This restriction applies to web-interface too.
#
# NOTE: NZBGet also supports listening on Unix domain sockets instead of TCP/IP
# sockets. To activate this mode set option <ControlIP> to a local path
# (e. g. "ControlIP=/var/sock").
ControlIP=0.0.0.0
# Port which NZBGet server and remote client use (1-65535).
@@ -389,9 +393,13 @@ SecureControl=no
SecurePort=6791
# Full path to certificate file for encrypted communication.
#
# In case of Let's Encrypt: full path to fullchain.pem.
SecureCert=
# Full path to key file for encrypted communication.
#
# In case of Let's Encrypt: full path to privkey.pem.
SecureKey=
# IP-addresses allowed to connect without authorization.
@@ -427,6 +435,13 @@ AuthorizedIP=
# NOTE: For more details visit http://nzbget.net/certificate-verification.
CertCheck=no
# Automatically check for new releases (none, stable, testing).
#
# None - do not show notifcations;
# Stable - show notifications about new stable releases;
# Testing - show notifications about new stable and testing releases.
UpdateCheck=stable
# User name for daemon-mode, POSIX only.
#
# Set the user that the daemon normally runs at (POSIX in daemon-mode only).
@@ -739,11 +754,6 @@ DupeCheck=yes
##############################################################################
### DOWNLOAD QUEUE ###
# Save download queue to disk (yes, no).
#
# This allows to reload it on next start.
SaveQueue=yes
# Flush download queue to disk (yes, no).
#
# Immediately flush file buffers for queue state file. This improves
@@ -755,9 +765,6 @@ SaveQueue=yes
# in that case. Keep the option enabled if your system often crashes.
FlushQueue=yes
# Reload download queue on start, if it exists (yes, no).
ReloadQueue=yes
# Continue download of partially downloaded files (yes, no).
#
# If active the current state (the info about what articles were already
@@ -778,15 +785,6 @@ ContinuePartial=yes
# after that they are downloaded.
PropagationDelay=0
# Decode articles (yes, no).
#
# yes - decode articles using internal decoder (supports yEnc and UU formats);
# no - articles will not be decoded/joined. Useful to look at article's source text.
#
# NOTE: This option is primary for debugging purposes. You should not
# disable it.
Decode=yes
# Memory limit for article cache (megabytes).
#
# Article cache helps to improve performance. First the amount of disk
@@ -837,7 +835,7 @@ ArticleCache=0
# without article cache.
DirectWrite=yes
# Memory limit for per article write buffer (kilobytes).
# Memory limit for per connection write buffer (kilobytes).
#
# When downloaded articles are written into disk the OS collects
# data in the internal buffer before flushing it into disk. This option
@@ -864,13 +862,6 @@ DirectWrite=yes
# NOTE: Also see option <ArticleCache>.
WriteBuffer=0
# Check CRC of downloaded and decoded articles (yes, no).
#
# Normally this option should be enabled for better detecting of download
# errors. However checking of CRC needs CPU time. On a fast connection and
# slow CPU disabling of CRC-Check may improve performance.
CrcCheck=yes
# How to name downloaded files (auto, article, nzb).
#
# Article - use file names stored in article metadata;
@@ -878,7 +869,7 @@ CrcCheck=yes
# Auto - prefer names from article metadata; for obfuscated files use
# names from nzb-file.
#
# NOTE: This option sets the naming convention for files listed in nzb. It has not
# NOTE: This option sets the naming convention for files listed in nzb. It has no
# effect on files extracted from archives.
FileNaming=auto
@@ -969,6 +960,27 @@ KeepHistory=30
# the feed history.
FeedHistory=7
# Discard downloaded data (do not write into disk) (yes, no).
#
# This option is for speed test purposes (benchmarking). When enabled the
# downloaded data is not written into disk. The destination files are still
# created but are either empty or contain zeros (depending on other
# options). The post-processing (unpack, repair, etc.) is also completely
# disabled.
#
# NOTE: This option is meant for development purposes. You should not
# activate it except maybe for speed tests.
SkipWrite=no
# Write article raw data (yes, no).
#
# When enabled the article content is written into disk in raw form without
# processing.
#
# NOTE: This option is meant for development purposes. You should not
# activate it.
RawArticle=no
##############################################################################
### CONNECTION ###
@@ -1009,11 +1021,10 @@ UrlInterval=10
# Connection timeout when fetching nzb-files via URLs and fetching RSS feeds.
UrlTimeout=60
# Timeout until a download-thread should be killed (seconds).
# Timeout for incoming connections (seconds).
#
# This can help on hanging downloads, but is dangerous.
# Do not use small values!
TerminateTimeout=600
# Set timeout for connections from clients (web-browsers and API clients).
RemoteTimeout=90
# Set the maximum download rate on program start (kilobytes/sec).
#
@@ -1022,24 +1033,6 @@ TerminateTimeout=600
# Value "0" means no speed control.
DownloadRate=0
# Accurate speed rate calculation (yes, no).
#
# During downloading using several connections the download threads may
# interfere with each other when updating statistical data for speed
# meter. This may cause small errors in current download speed reported
# by the program. The speed meter recovers automatically from such errors
# after max. 30 seconds (time window used for speed calculation).
#
# Enable the option to use thread synchronisation mechanisms in order to
# provide absolutely accurate speed calculations.
#
# NOTE: Thread synchronisation increases CPU load and therefore can
# decrease download speed. Do not activate this option on computers with
# limited CPU power. Before activating the option it is recommended to
# run tests to determine how the option affects the CPU usage and the
# download speed on a particular system.
AccurateRate=no
# Maximum number of simultaneous connections for nzb URL downloads (0-999).
#
# When NZB-files are added to queue via URL, the program downloads them
@@ -1113,9 +1106,8 @@ DetailTarget=log
# debug-mode: "./configure --enable-debug".
DebugTarget=log
# Number of messages stored in buffer and available for remote
# clients (messages).
LogBufferSize=1000
# Number of messages stored in screen buffer (messages).
LogBuffer=1000
# Create log for each downloaded nzb-file (yes, no).
#
@@ -1123,12 +1115,6 @@ LogBufferSize=1000
# at any time in download details dialog or history details dialog.
NzbLog=yes
# Create a log of all broken files (yes, no).
#
# It is a text file placed near downloaded files, which contains
# the names of broken files.
BrokenLog=yes
# Print call stack trace into log on program crash (Linux and Windows) (yes, no).
#
# Call stack traces are very helpful for debugging. Call stack traces can be
@@ -1289,6 +1275,12 @@ UpdateInterval=200
##############################################################################
### CHECK AND REPAIR ###
# Check CRC of downloaded and decoded articles (yes, no).
#
# Normally this option should be enabled for better detecting of download
# errors and for quick par-verification (option <ParQuick>).
CrcCheck=yes
# Whether and how par-verification must be performed (auto, always, force, manual).
#
# Auto - par-check is performed when needed. One par2-file is always
@@ -1557,7 +1549,7 @@ SevenZipCmd=7z
# characters * and ?.
#
# Example: .par2, .sfv
ExtCleanupDisk=.par2, .sfv, _brokenlog.txt
ExtCleanupDisk=.par2, .sfv
# Files to ignore during unpack.
#

122
nzbget.vcxproj Normal file → Executable file
View File

@@ -1,14 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{41BFB691-0127-4391-9629-F1BA6740DDFE}</ProjectGuid>
@@ -21,38 +29,58 @@
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>..\bin\</OutDir>
<IntDir>..\bin\Debug\</IntDir>
<LinkIncremental>true</LinkIncremental>
<IntDir>..\bin\Debug32\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>..\bin\</OutDir>
<IntDir>..\bin\Debug64\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>..\bin\</OutDir>
<IntDir>..\bin\Release\</IntDir>
<LinkIncremental />
<IntDir>..\bin\Release32\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>..\bin\</OutDir>
<IntDir>..\bin\Release64\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="19.1";_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\lib\yencode;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="20.0";_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -63,16 +91,36 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>WS2_32.lib;ole32.lib;OleAut32.Lib;comsuppwd.lib;Advapi32.lib;Winmm.lib;gdi32.lib;shell32.lib;dbghelp.lib;ssleay32MTd.lib;libeay32MTd.lib;regex.lib;zlib.lib</AdditionalDependencies>
<AdditionalDependencies>WS2_32.lib;ole32.lib;OleAut32.Lib;comsuppwd.lib;Advapi32.lib;Winmm.lib;gdi32.lib;shell32.lib;dbghelp.lib;ssleay32MTd.lib;libeay32MTd.lib;regex32MTd.lib;zlib32MTd.lib</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\lib\yencode;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="20.0";_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>nzbget.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>WS2_32.lib;ole32.lib;OleAut32.Lib;comsuppwd.lib;Advapi32.lib;Winmm.lib;gdi32.lib;shell32.lib;dbghelp.lib;ssleay32MTd.lib;libeay32MTd.lib;regex32MTd.lib;zlib32MTd.lib</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="19.1";NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\lib\yencode;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="20.0";NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
@@ -81,14 +129,53 @@
<PrecompiledHeaderFile>nzbget.h</PrecompiledHeaderFile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<Optimization>Full</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<WholeProgramOptimization>true</WholeProgramOptimization>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<AdditionalDependencies>WS2_32.lib;ole32.lib;OleAut32.Lib;comsuppwd.lib;Advapi32.lib;gdi32.lib;shell32.lib;Winmm.lib;ssleay32MT.lib;libeay32MT.lib;regex.lib;zlib.lib</AdditionalDependencies>
<AdditionalDependencies>WS2_32.lib;ole32.lib;OleAut32.Lib;comsuppwd.lib;Advapi32.lib;gdi32.lib;shell32.lib;Winmm.lib;ssleay32MT.lib;libeay32MT.lib;regex32MT.lib;zlib32MT.lib</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\lib\yencode;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="20.0";NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PrecompiledHeaderFile>nzbget.h</PrecompiledHeaderFile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<Optimization>Full</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<WholeProgramOptimization>true</WholeProgramOptimization>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<AdditionalDependencies>WS2_32.lib;ole32.lib;OleAut32.Lib;comsuppwd.lib;Advapi32.lib;gdi32.lib;shell32.lib;Winmm.lib;ssleay32MTd.lib;libeay32MTd.lib;regex32MT.lib;zlib32MT.lib</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@@ -166,8 +253,7 @@
<ClCompile Include="daemon\util\Util.cpp" />
<ClCompile Include="daemon\util\FileSystem.cpp" />
<ClCompile Include="daemon\windows\StdAfx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader >Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="daemon\windows\WinService.cpp" />
<ClCompile Include="daemon\windows\WinConsole.cpp" />
@@ -190,6 +276,12 @@
<ClCompile Include="lib\par2\reedsolomon.cpp" />
<ClCompile Include="lib\par2\verificationhashtable.cpp" />
<ClCompile Include="lib\par2\verificationpacket.cpp" />
<ClCompile Include="lib\yencode\SimdInit.cpp" />
<ClCompile Include="lib\yencode\ScalarDecoder.cpp" />
<ClCompile Include="lib\yencode\Sse2Decoder.cpp" />
<ClCompile Include="lib\yencode\Ssse3Decoder.cpp" />
<ClCompile Include="lib\yencode\SliceCrc.cpp" />
<ClCompile Include="lib\yencode\PclmulCrc.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="daemon\connect\Connection.h" />
@@ -290,6 +382,8 @@
<ClInclude Include="lib\par2\reedsolomon.h" />
<ClInclude Include="lib\par2\verificationhashtable.h" />
<ClInclude Include="lib\par2\verificationpacket.h" />
<ClInclude Include="lib\yencode\YEncode.h" />
<ClInclude Include="lib\yencode\SimdDecoder.cpp" />
<ClInclude Include="windows\resources\resource.h" />
</ItemGroup>
<ItemGroup>
@@ -304,4 +398,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@@ -25,7 +25,7 @@
<key>LSUIElement</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2007-2017 Andrey Prygunkov</string>
<string>Copyright © 2007-2018 Andrey Prygunkov</string>
<key>NSMainNibFile</key>
<string>MainApp</string>
<key>NSAppTransportSecurity</key>

813
posix/config.guess vendored
View File

File diff suppressed because it is too large Load Diff

403
posix/config.sub vendored
View File

@@ -1,44 +1,40 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
# Inc.
# Copyright 1992-2014 Free Software Foundation, Inc.
timestamp='2006-09-20'
timestamp='2014-12-03'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
# can handle that machine. It does not imply ALL GNU software can.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# the same distribution terms that you use for the rest of that
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
# Please send patches to <config-patches@gnu.org>.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
@@ -72,8 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Copyright 1992-2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -120,12 +115,18 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
android-linux)
os=-linux-android
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
;;
*)
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
if [ $basic_machine != $1 ]
@@ -148,10 +149,13 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple | -axis | -knuth | -cray)
-apple | -axis | -knuth | -cray | -microblaze*)
os=
basic_machine=$1
;;
-bluegene*)
os=-cnk
;;
-sim | -cisco | -oki | -wec | -winbond)
os=
basic_machine=$1
@@ -166,10 +170,10 @@ case $os in
os=-chorusos
basic_machine=$1
;;
-chorusrdb)
os=-chorusrdb
-chorusrdb)
os=-chorusrdb
basic_machine=$1
;;
;;
-hiux*)
os=-hiuxwe2
;;
@@ -214,6 +218,12 @@ case $os in
-isc*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-lynx*178)
os=-lynxos178
;;
-lynx*5)
os=-lynxos5
;;
-lynx*)
os=-lynxos
;;
@@ -238,59 +248,90 @@ case $basic_machine in
# Some are omitted here because they have special meanings below.
1750a | 580 \
| a29k \
| aarch64 | aarch64_be \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
| arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
| be32 | be64 \
| bfin \
| c4x | clipper \
| c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \
| fr30 | frv \
| epiphany \
| fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
| k1om \
| le32 | le64 \
| lm32 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
| maxq | mb | microblaze | mcore \
| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
| mips64vr | mips64vrel \
| mips64octeon | mips64octeonel \
| mips64orion | mips64orionel \
| mips64r5900 | mips64r5900el \
| mips64vr | mips64vrel \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
| mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa32r6 | mipsisa32r6el \
| mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64r6 | mipsisa64r6el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipsr5900 | mipsr5900el \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| moxie \
| mt \
| msp430 \
| nios | nios2 \
| nds32 | nds32le | nds32be \
| nios | nios2 | nios2eb | nios2el \
| ns16k | ns32k \
| or32 \
| open8 | or1k | or1knd | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
| riscv32 | riscv64 \
| rl78 | rx \
| score \
| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
| spu | strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| v850 | v850e \
| spu \
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| visium \
| we32k \
| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
| z8k)
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
basic_machine=$basic_machine-unknown
;;
m6811 | m68hc11 | m6812 | m68hc12)
# Motorola 68HC11/12.
c54x)
basic_machine=tic54x-unknown
;;
c55x)
basic_machine=tic55x-unknown
;;
c6x)
basic_machine=tic6x-unknown
;;
leon|leon[3-9])
basic_machine=sparc-$basic_machine
;;
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
@@ -300,6 +341,21 @@ case $basic_machine in
basic_machine=mt-unknown
;;
strongarm | thumb | xscale)
basic_machine=arm-unknown
;;
xgate)
basic_machine=$basic_machine-unknown
os=-none
;;
xscaleeb)
basic_machine=armeb-unknown
;;
xscaleel)
basic_machine=armel-unknown
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
@@ -314,64 +370,87 @@ case $basic_machine in
# Recognize the basic CPU types with company name.
580-* \
| a29k-* \
| aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
| clipper-* | craynv-* | cydra-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
| k1om-* \
| le32-* | le64-* \
| lm32-* \
| m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | maxq-* | mcore-* \
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
| microblaze-* | microblazeel-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
| mips64vr-* | mips64vrel-* \
| mips64octeon-* | mips64octeonel-* \
| mips64orion-* | mips64orionel-* \
| mips64r5900-* | mips64r5900el-* \
| mips64vr-* | mips64vrel-* \
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
| mips64vr5900-* | mips64vr5900el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa32r6-* | mipsisa32r6el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64r6-* | mipsisa64r6el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipsr5900-* | mipsr5900el-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
| nios-* | nios2-* \
| nds32-* | nds32le-* | nds32be-* \
| nios-* | nios2-* | nios2eb-* | nios2el-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| open8-* \
| or1k*-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
| romp-* | rs6000-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \
| tron-* \
| v850-* | v850e-* | vax-* \
| ubicom32-* \
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| visium-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
| xstormy16-* | xtensa-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
| ymp-* \
| z8k-*)
| z8k-* | z80-*)
;;
# Recognize the basic CPU types without company name, with glob match.
xtensa*)
basic_machine=$basic_machine-unknown
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
@@ -389,7 +468,7 @@ case $basic_machine in
basic_machine=a29k-amd
os=-udi
;;
abacus)
abacus)
basic_machine=abacus-unknown
;;
adobe68k)
@@ -435,6 +514,10 @@ case $basic_machine in
basic_machine=m68k-apollo
os=-bsd
;;
aros)
basic_machine=i386-pc
os=-aros
;;
aux)
basic_machine=m68k-apple
os=-aux
@@ -443,10 +526,35 @@ case $basic_machine in
basic_machine=ns32k-sequent
os=-dynix
;;
blackfin)
basic_machine=bfin-unknown
os=-linux
;;
blackfin-*)
basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
bluegene*)
basic_machine=powerpc-ibm
os=-cnk
;;
c54x-*)
basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c55x-*)
basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c6x-*)
basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c90)
basic_machine=c90-cray
os=-unicos
;;
cegcc)
basic_machine=arm-unknown
os=-cegcc
;;
convex-c1)
basic_machine=c1-convex
os=-bsd
@@ -475,8 +583,8 @@ case $basic_machine in
basic_machine=craynv-cray
os=-unicosmp
;;
cr16c)
basic_machine=cr16c-unknown
cr16 | cr16-*)
basic_machine=cr16-unknown
os=-elf
;;
crds | unos)
@@ -514,6 +622,10 @@ case $basic_machine in
basic_machine=m88k-motorola
os=-sysv3
;;
dicos)
basic_machine=i686-pc
os=-dicos
;;
djgpp)
basic_machine=i586-pc
os=-msdosdjgpp
@@ -629,7 +741,6 @@ case $basic_machine in
i370-ibm* | ibm*)
basic_machine=i370-ibm
;;
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
i*86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
@@ -668,6 +779,17 @@ case $basic_machine in
basic_machine=m68k-isi
os=-sysv
;;
leon-*|leon[3-9]-*)
basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
;;
m68knommu)
basic_machine=m68k-unknown
os=-linux
;;
m68knommu-*)
basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
m88k-omron*)
basic_machine=m88k-omron
;;
@@ -679,10 +801,21 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
microblaze*)
basic_machine=microblaze-xilinx
;;
mingw64)
basic_machine=x86_64-pc
os=-mingw64
;;
mingw32)
basic_machine=i386-pc
basic_machine=i686-pc
os=-mingw32
;;
mingw32ce)
basic_machine=arm-unknown
os=-mingw32ce
;;
miniframe)
basic_machine=m68000-convergent
;;
@@ -704,6 +837,10 @@ case $basic_machine in
basic_machine=powerpc-unknown
os=-morphos
;;
moxiebox)
basic_machine=moxie-unknown
os=-moxiebox
;;
msdos)
basic_machine=i386-pc
os=-msdos
@@ -711,10 +848,18 @@ case $basic_machine in
ms1-*)
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
msys)
basic_machine=i686-pc
os=-msys
;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
nacl)
basic_machine=le32-unknown
os=-nacl
;;
ncr3000)
basic_machine=i486-ncr
os=-sysv4
@@ -779,6 +924,12 @@ case $basic_machine in
np1)
basic_machine=np1-gould
;;
neo-tandem)
basic_machine=neo-tandem
;;
nse-tandem)
basic_machine=nse-tandem
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
@@ -809,6 +960,14 @@ case $basic_machine in
basic_machine=i860-intel
os=-osf
;;
parisc)
basic_machine=hppa-unknown
os=-linux
;;
parisc-*)
basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
pbd)
basic_machine=sparc-tti
;;
@@ -853,9 +1012,10 @@ case $basic_machine in
;;
power) basic_machine=power-ibm
;;
ppc) basic_machine=powerpc-unknown
ppc | ppcbe) basic_machine=powerpc-unknown
;;
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
@@ -880,7 +1040,11 @@ case $basic_machine in
basic_machine=i586-unknown
os=-pw32
;;
rdos)
rdos | rdos64)
basic_machine=x86_64-pc
os=-rdos
;;
rdos32)
basic_machine=i386-pc
os=-rdos
;;
@@ -925,6 +1089,9 @@ case $basic_machine in
basic_machine=sh-hitachi
os=-hms
;;
sh5el)
basic_machine=sh5le-unknown
;;
sh64)
basic_machine=sh64-unknown
;;
@@ -946,6 +1113,9 @@ case $basic_machine in
basic_machine=i860-stratus
os=-sysv4
;;
strongarm-* | thumb-*)
basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
sun2)
basic_machine=m68000-sun
;;
@@ -1002,17 +1172,9 @@ case $basic_machine in
basic_machine=t90-cray
os=-unicos
;;
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tic55x | c55x*)
basic_machine=tic55x-unknown
os=-coff
;;
tic6x | c6x*)
basic_machine=tic6x-unknown
os=-coff
tile*)
basic_machine=$basic_machine-unknown
os=-linux-gnu
;;
tx39)
basic_machine=mipstx39-unknown
@@ -1081,6 +1243,9 @@ case $basic_machine in
xps | xps100)
basic_machine=xps100-honeywell
;;
xscale-* | xscalee[bl]-*)
basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
;;
ymp)
basic_machine=ymp-cray
os=-unicos
@@ -1089,6 +1254,10 @@ case $basic_machine in
basic_machine=z8k-unknown
os=-sim
;;
z80-*-coff)
basic_machine=z80-unknown
os=-sim
;;
none)
basic_machine=none-none
os=-none
@@ -1127,7 +1296,7 @@ case $basic_machine in
we32k)
basic_machine=we32k-att
;;
sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
@@ -1174,9 +1343,12 @@ esac
if [ x"$os" != x"" ]
then
case $os in
# First match some system type aliases
# that might get confused with valid system types.
# First match some system type aliases
# that might get confused with valid system types.
# -solaris* is a basic system type, with this one exception.
-auroraux)
os=-auroraux
;;
-solaris1 | -solaris1.*)
os=`echo $os | sed -e 's|solaris1|sunos4|'`
;;
@@ -1197,29 +1369,31 @@ case $os in
# Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4.
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* \
| -aos* | -aros* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -openbsd* | -solidbsd* \
| -bitrig* | -openbsd* | -solidbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* \
| -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers*)
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1258,7 +1432,7 @@ case $os in
-opened*)
os=-openedition
;;
-os400*)
-os400*)
os=-os400
;;
-wince*)
@@ -1307,7 +1481,7 @@ case $os in
-sinix*)
os=-sysv4
;;
-tpf*)
-tpf*)
os=-tpf
;;
-triton*)
@@ -1343,12 +1517,14 @@ case $os in
-aros*)
os=-aros
;;
-kaos*)
os=-kaos
;;
-zvmoe)
os=-zvmoe
;;
-dicos*)
os=-dicos
;;
-nacl*)
;;
-none)
;;
*)
@@ -1371,10 +1547,10 @@ else
# system, and we'll never get to this point.
case $basic_machine in
score-*)
score-*)
os=-elf
;;
spu-*)
spu-*)
os=-elf
;;
*-acorn)
@@ -1386,8 +1562,23 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
c4x-* | tic4x-*)
os=-coff
c4x-* | tic4x-*)
os=-coff
;;
c8051-*)
os=-elf
;;
hexagon-*)
os=-elf
;;
tic54x-*)
os=-coff
;;
tic55x-*)
os=-coff
;;
tic6x-*)
os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
@@ -1407,13 +1598,13 @@ case $basic_machine in
;;
m68000-sun)
os=-sunos3
# This also exists in the configure program, but was not the
# default.
# os=-sunos4
;;
m68*-cisco)
os=-aout
;;
mep-*)
os=-elf
;;
mips*-cisco)
os=-elf
;;
@@ -1438,7 +1629,7 @@ case $basic_machine in
*-ibm)
os=-aix
;;
*-knuth)
*-knuth)
os=-mmixware
;;
*-wec)
@@ -1543,7 +1734,7 @@ case $basic_machine in
-sunos*)
vendor=sun
;;
-aix*)
-cnk*|-aix*)
vendor=ibm
;;
-beos*)

826
posix/depcomp vendored
View File

@@ -1,7 +1,9 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
# Copyright 1999, 2000 Free Software Foundation, Inc.
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,9 +16,7 @@
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -25,17 +25,112 @@
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# `libtool' can also be set to `yes' or `no'.
depfile=${depfile-`echo "$object" | sed 's,\([^/]*\)$,.deps/\1,;s/\.\([^.]*\)$/.P\1/'`}
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
@@ -47,9 +142,32 @@ if test "$depmode" = hp; then
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
@@ -57,10 +175,22 @@ gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -eq 0; then :
else
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
@@ -68,13 +198,17 @@ gcc3)
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
@@ -82,31 +216,31 @@ gcc)
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well.
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
@@ -124,8 +258,7 @@ sgi)
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
@@ -133,136 +266,302 @@ sgi)
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like `#:fec' to the end of the
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr '
' ' ' >> $depfile
echo >> $depfile
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> $depfile
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. This file always lives in the current directory.
# Also, the AIX compiler puts `$object:' at the start of each line;
# $object doesn't have directory information.
stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
tmpdepfile="$stripped.u"
outname="$stripped.o"
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
if test -f "$tmpdepfile"; then
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
icc)
# Must come before tru64.
# Intel's C compiler understands `-MD -MF file'. However
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want:
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed -e "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
sed -e "s,^[^:]*: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
tru64)
# The Tru64 AIX compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in `foo.d' instead, so we check for that too.
# Subdirectories are respected.
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
tmpdepfile1="$object.d"
tmpdepfile2=`echo "$object" | sed -e 's/.o$/.d/'`
if test "$libtool" = yes; then
"$@" -Wc,-MD
else
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
fi
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
if test -f "$tmpdepfile1"; then
tmpdepfile="$tmpdepfile1"
else
tmpdepfile="$tmpdepfile2"
fi
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a space and a tab in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
@@ -270,41 +569,49 @@ tru64)
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
test -z "$dashmflag" && dashmflag=-M
( IFS=" "
case " $* " in
*" --mode=compile "*) # this is libtool, let us make it quiet
for arg
do # cycle over the arguments
case "$arg" in
"--mode=compile")
# insert --quiet before "--mode=compile"
set fnord "$@" --quiet
shift # fnord
;;
esac
set fnord "$@" "$arg"
shift # fnord
shift # "$arg"
done
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
"$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
) &
proc=$!
"$@"
stat=$?
wait "$proc"
if test "$stat" != 0; then exit $stat; fi
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
@@ -315,74 +622,93 @@ dashXmstdout)
;;
makedepend)
# X makedepend
(
shift
cleared=no
for arg in "$@"; do
case $cleared in no)
set ""; shift
cleared=yes
esac
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift;;
-*)
;;
*)
set fnord "$@" "$arg"; shift;;
esac
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
obj_suffix="`echo $object | sed 's/^.*\././'`"
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@"
) &
proc=$!
"$@"
stat=$?
wait "$proc"
if test "$stat" != 0; then exit $stat; fi
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tail +3 "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
( IFS=" "
case " $* " in
*" --mode=compile "*)
for arg
do # cycle over the arguments
case $arg in
"--mode=compile")
# insert --quiet before "--mode=compile"
set fnord "$@" --quiet
shift # fnord
;;
esac
set fnord "$@" "$arg"
shift # fnord
shift # "$arg"
done
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
"$@" -E |
sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
) &
proc=$!
"$@"
stat=$?
wait "$proc"
if test "$stat" != 0; then exit $stat; fi
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
@@ -392,42 +718,56 @@ cpp)
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
( IFS=" "
case " $* " in
*" --mode=compile "*)
for arg
do # cycle over the arguments
case $arg in
"--mode=compile")
# insert --quiet before "--mode=compile"
set fnord "$@" --quiet
shift # fnord
;;
esac
set fnord "$@" "$arg"
shift # fnord
shift # "$arg"
done
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
"$@" -E |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
) &
proc=$!
"$@"
stat=$?
wait "$proc"
if test "$stat" != 0; then exit $stat; fi
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
echo " " >> "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
@@ -439,3 +779,13 @@ none)
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

719
posix/install-sh vendored
View File

@@ -1,276 +1,501 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
scriptversion=2013-12-25.23; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright 1991 by the Massachusetts Institute of Technology
# Copyright (C) 1994 X Consortium
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
# 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
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# set DOITPROG to echo to test this script
# Set DOITPROG to "echo" to test this script.
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
# put in absolute paths if you don't have them in your path; or use env. vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
posix_mkdir=
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
stripcmd=
while [ x"$1" != x ]; do
case $1 in
-c) instcmd=$cpprog
shift
continue;;
src=
dst=
dir_arg=
dst_arg=
-d) dir_arg=true
shift
continue;;
copy_on_change=false
is_target_a_directory=possibly
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
Options:
--help display this help and exit.
--version display version info and exit.
-s) stripcmd=$stripprog
shift
continue;;
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
while test $# -ne 0; do
case $1 in
-c) ;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
if [ x"$src" = x ]
then
echo "$0: no input file specified" >&2
exit 1
else
:
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d "$dst" ]; then
instcmd=:
chmodcmd=""
else
instcmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f "$src" ] || [ -d "$src" ]
then
:
else
echo "$0: $src does not exist" >&2
exit 1
fi
if [ x"$dst" = x ]
then
echo "$0: no destination specified" >&2
exit 1
else
:
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d "$dst" ]
then
dst=$dst/`basename "$src"`
else
:
fi
fi
## this sed command emulates the dirname command
dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-$defaultIFS}"
oIFS=$IFS
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS=$oIFS
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp=$pathcomp$1
shift
if [ ! -d "$pathcomp" ] ;
then
$mkdirprog "$pathcomp"
else
:
fi
pathcomp=$pathcomp/
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd "$dst" &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename "$dst"`
else
dstfile=`basename "$dst" $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename "$dst"`
else
:
fi
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/#inst.$$#
rmtmp=$dstdir/#rm.$$#
# Trap to clean up temp files at exit.
trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
trap '(exit $?); exit' 1 2 13 15
# Move or copy the file name to the temp name
$doit $instcmd "$src" "$dsttmp" &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
# Now remove or move aside any old file at destination location. We try this
# two ways since rm can't unlink itself on some systems and the destination
# file might be busy for other reasons. In this case, the final cleanup
# might fail but the new file should still install successfully.
{
if [ -f "$dstdir/$dstfile" ]
then
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
$doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
{
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
(exit 1); exit
}
else
:
fi
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
fi &&
# The final little trick to "correctly" pass the exit status to the exit trap.
{
(exit 0); exit
}
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

Some files were not shown because too many files have changed in this diff Show More